From b3f08597cd725ef8136fb3cfb2808be990a6fce8 Mon Sep 17 00:00:00 2001
From: Tudor Brindus <me@tbrindus.ca>
Date: Thu, 18 Jun 2020 22:26:27 -0400
Subject: input: disable events for map_to_output devices when output not
 present

Fixes #3449.
---
 sway/config/output.c       |  9 +--------
 sway/input/input-manager.c | 25 ++++++++++++++++++-------
 sway/input/libinput.c      | 18 +++++++++++++++++-
 sway/tree/output.c         |  5 +++++
 4 files changed, 41 insertions(+), 16 deletions(-)

(limited to 'sway')

diff --git a/sway/config/output.c b/sway/config/output.c
index 713cd219..68aafbe1 100644
--- a/sway/config/output.c
+++ b/sway/config/output.c
@@ -481,14 +481,7 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
 	// Reconfigure all devices, since input config may have been applied before
 	// this output came online, and some config items (like map_to_output) are
 	// dependent on an output being present.
-	struct sway_input_device *input_device = NULL;
-	wl_list_for_each(input_device, &server.input->devices, link) {
-		struct sway_seat *seat = NULL;
-		wl_list_for_each(seat, &server.input->seats, link) {
-			seat_configure_device(seat, input_device);
-		}
-	}
-
+	input_manager_configure_all_inputs();
 	return true;
 }
 
diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c
index b900f666..69342c73 100644
--- a/sway/input/input-manager.c
+++ b/sway/input/input-manager.c
@@ -521,6 +521,22 @@ static void retranslate_keysyms(struct input_config *input_config) {
 	}
 }
 
+static void input_manager_configure_input(
+		struct sway_input_device *input_device) {
+	sway_input_configure_libinput_device(input_device);
+	struct sway_seat *seat = NULL;
+	wl_list_for_each(seat, &server.input->seats, link) {
+		seat_configure_device(seat, input_device);
+	}
+}
+
+void input_manager_configure_all_inputs(void) {
+	struct sway_input_device *input_device = NULL;
+	wl_list_for_each(input_device, &server.input->devices, link) {
+		input_manager_configure_input(input_device);
+	}
+}
+
 void input_manager_apply_input_config(struct input_config *input_config) {
 	struct sway_input_device *input_device = NULL;
 	bool wildcard = strcmp(input_config->identifier, "*") == 0;
@@ -531,11 +547,7 @@ void input_manager_apply_input_config(struct input_config *input_config) {
 		if (strcmp(input_device->identifier, input_config->identifier) == 0
 				|| wildcard
 				|| type_matches) {
-			sway_input_configure_libinput_device(input_device);
-			struct sway_seat *seat = NULL;
-			wl_list_for_each(seat, &server.input->seats, link) {
-				seat_configure_device(seat, input_device);
-			}
+			input_manager_configure_input(input_device);
 		}
 	}
 
@@ -550,7 +562,7 @@ void input_manager_reset_input(struct sway_input_device *input_device) {
 	}
 }
 
-void input_manager_reset_all_inputs() {
+void input_manager_reset_all_inputs(void) {
 	struct sway_input_device *input_device = NULL;
 	wl_list_for_each(input_device, &server.input->devices, link) {
 		input_manager_reset_input(input_device);
@@ -568,7 +580,6 @@ void input_manager_reset_all_inputs() {
 	}
 }
 
-
 void input_manager_apply_seat_config(struct seat_config *seat_config) {
 	sway_log(SWAY_DEBUG, "applying seat config for seat %s", seat_config->name);
 	if (strcmp(seat_config->name, "*") == 0) {
diff --git a/sway/input/libinput.c b/sway/input/libinput.c
index caaba5a1..4ec72882 100644
--- a/sway/input/libinput.c
+++ b/sway/input/libinput.c
@@ -4,6 +4,7 @@
 #include <wlr/backend/libinput.h>
 #include "log.h"
 #include "sway/config.h"
+#include "sway/output.h"
 #include "sway/input/input-manager.h"
 #include "sway/ipc-server.h"
 
@@ -190,9 +191,24 @@ static bool config_libinput_pointer(struct libinput_device *device,
 	sway_log(SWAY_DEBUG, "config_libinput_pointer('%s' on  '%s')",
 			ic->identifier, device_id);
 	bool changed = false;
-	if (ic->send_events != INT_MIN) {
+
+	if (ic->mapped_to_output &&
+			!output_by_name_or_id(ic->mapped_to_output)) {
+		sway_log(SWAY_DEBUG,
+				"Pointer '%s' is mapped to offline output '%s'; disabling input",
+				ic->identifier, ic->mapped_to_output);
+		changed |= set_send_events(device,
+			LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
+	} else if (ic->send_events != INT_MIN) {
 		changed |= set_send_events(device, ic->send_events);
+	} else {
+		// Have to reset to the default mode here, otherwise if ic->send_events
+		// is unset and a mapped output just came online after being disabled,
+		// we'd remain stuck sending no events.
+		changed |= set_send_events(device,
+			libinput_device_config_send_events_get_default_mode(device));
 	}
+
 	if (ic->tap != INT_MIN) {
 		changed |= set_tap(device, ic->tap);
 	}
diff --git a/sway/tree/output.c b/sway/tree/output.c
index c96c3187..9a10c6a8 100644
--- a/sway/tree/output.c
+++ b/sway/tree/output.c
@@ -266,6 +266,11 @@ void output_disable(struct sway_output *output) {
 	output->current_mode = NULL;
 
 	arrange_root();
+
+	// Reconfigure all devices, since devices with map_to_output directives for
+	// an output that goes offline should stop sending events as long as the
+	// output remains offline.
+	input_manager_configure_all_inputs();
 }
 
 void output_begin_destroy(struct sway_output *output) {
-- 
cgit v1.2.3