GithubHelp home page GithubHelp logo

tablet: Add output mapping about labwc HOT 1 CLOSED

jp7677 avatar jp7677 commented on September 25, 2024 1
tablet: Add output mapping

from labwc.

Comments (1)

jp7677 avatar jp7677 commented on September 25, 2024

So this is actually not that easy with my limited knowledge. The following patch is probably a start (edit: not really, see below).

Patch
diff --git a/include/config/rcxml.h b/include/config/rcxml.h
index d03e4a7..3b09f6d 100644
--- a/include/config/rcxml.h
+++ b/include/config/rcxml.h
@@ -89,6 +89,7 @@ struct rcxml {
 
 	/* graphics tablet */
 	struct tablet_config {
+		char *output_name;
 		struct wlr_fbox box;
 		enum rotation rotation;
 		uint16_t button_map_count;
diff --git a/include/input/tablet.h b/include/input/tablet.h
index df8537d..d02832f 100644
--- a/include/input/tablet.h
+++ b/include/input/tablet.h
@@ -3,12 +3,15 @@
 #define LABWC_TABLET_H
 
 #include <wayland-server-core.h>
+#include <labwc.h>
+
 struct seat;
 struct wlr_device;
 struct wlr_input_device;
 
 struct drawing_tablet {
 	struct seat *seat;
+	struct wlr_input_device *device;
 	struct wlr_tablet *tablet;
 	double x, y;
 	struct {
@@ -17,6 +20,7 @@ struct drawing_tablet {
 		struct wl_listener button;
 		struct wl_listener destroy;
 		// no interest in proximity events
+		struct wl_listener new_output;
 	} handlers;
 };
 
diff --git a/src/config/rcxml.c b/src/config/rcxml.c
index 1ff3766..be2197a 100644
--- a/src/config/rcxml.c
+++ b/src/config/rcxml.c
@@ -862,6 +862,8 @@ entry(xmlNode *node, char *nodename, char *content)
 		rc.tablet.box.width = tablet_get_dbl_if_positive(content, "width");
 	} else if (!strcasecmp(nodename, "height.area.tablet")) {
 		rc.tablet.box.height = tablet_get_dbl_if_positive(content, "height");
+	} else if (!strcasecmp(nodename, "mapToOutput.tablet")) {
+		rc.tablet.output_name = xstrdup(content);
 	} else if (!strcasecmp(nodename, "rotate.tablet")) {
 		rc.tablet.rotation = tablet_parse_rotation(atoi(content));
 	} else if (!strcasecmp(nodename, "button.map.tablet")) {
diff --git a/src/input/tablet.c b/src/input/tablet.c
index 0a24d61..5ce8640 100644
--- a/src/input/tablet.c
+++ b/src/input/tablet.c
@@ -138,23 +138,48 @@ handle_destroy(struct wl_listener *listener, void *data)
 {
 	struct drawing_tablet *tablet =
 		wl_container_of(listener, tablet, handlers.destroy);
+	wl_list_remove(&tablet->handlers.new_output.link);
 	free(tablet);
 }
 
+static void
+map_to_output(struct drawing_tablet *tablet)
+{
+       struct output *output = NULL;
+       wlr_log(WLR_INFO, "map tablet to output %s\n", rc.tablet.output_name);
+       if (rc.tablet.output_name) {
+               output = output_from_name(tablet->seat->server, rc.tablet.output_name);
+       }
+       wlr_cursor_map_input_to_output(tablet->seat->cursor, tablet->device,
+               output ? output->wlr_output : NULL);
+       wlr_cursor_map_input_to_region(tablet->seat->cursor, tablet->device, NULL);
+}
+
+static void
+handle_new_output(struct wl_listener *listener, void *data)
+{
+	struct drawing_tablet *tablet =
+		wl_container_of(listener, tablet, handlers.new_output);
+	map_to_output(tablet);
+}
+
 void
 tablet_init(struct seat *seat, struct wlr_input_device *wlr_device)
 {
 	wlr_log(WLR_DEBUG, "setting up tablet");
 	struct drawing_tablet *tablet = znew(*tablet);
 	tablet->seat = seat;
+	tablet->device = wlr_device;
 	tablet->tablet = wlr_tablet_from_input_device(wlr_device);
 	tablet->tablet->data = tablet;
 	tablet->x = 0.0;
 	tablet->y = 0.0;
 	wlr_log(WLR_INFO, "tablet dimensions: %.2fmm x %.2fmm",
 		tablet->tablet->width_mm, tablet->tablet->height_mm);
+	map_to_output(tablet);
 	CONNECT_SIGNAL(tablet->tablet, &tablet->handlers, axis);
 	CONNECT_SIGNAL(tablet->tablet, &tablet->handlers, tip);
 	CONNECT_SIGNAL(tablet->tablet, &tablet->handlers, button);
 	CONNECT_SIGNAL(wlr_device, &tablet->handlers, destroy);
+	CONNECT_SIGNAL(seat->server->backend, &tablet->handlers, new_output);
 }
diff --git a/src/seat.c b/src/seat.c
index b8fb636..e6214b7 100644
--- a/src/seat.c
+++ b/src/seat.c
@@ -284,6 +284,7 @@ new_tablet(struct seat *seat, struct wlr_input_device *dev)
 {
 	struct input *input = znew(*input);
 	input->wlr_input_device = dev;
+	wlr_cursor_attach_input_device(seat->cursor, dev);
 	tablet_init(seat, dev);
 
 	return input;

It handles startup, hot-plugging the tablet at runtime and also connecting the mapped output at runtime, but explodes horribly when disconnecting the mapped output. I don't know how to correctly handle destroying of outputs. Any idea how to listen to that? Also no idea if it is really a good idea to connect to new_ouput like I did in the patch.

On the good side, the mapping itself works fine, also together with coordinate transformation.

Edit: I guess above approach is pretty bad ;). Input to output mapping should still belong in seat. Something like this should be more promising (also no more fiddling with signals), but cannot test right now because second monitor had been claimed :)

Patch v2
diff --git a/include/config/rcxml.h b/include/config/rcxml.h
index d03e4a7..3b09f6d 100644
--- a/include/config/rcxml.h
+++ b/include/config/rcxml.h
@@ -89,6 +89,7 @@ struct rcxml {
 
 	/* graphics tablet */
 	struct tablet_config {
+		char *output_name;
 		struct wlr_fbox box;
 		enum rotation rotation;
 		uint16_t button_map_count;
diff --git a/include/labwc.h b/include/labwc.h
index 7c409f6..825b300 100644
--- a/include/labwc.h
+++ b/include/labwc.h
@@ -456,6 +456,7 @@ void seat_set_pressed(struct seat *seat, struct view *view,
 	struct wlr_scene_node *node, struct wlr_surface *surface,
 	struct wlr_surface *toplevel, uint32_t resize_edges);
 void seat_reset_pressed(struct seat *seat);
+void seat_outputs_changed(struct seat *seat);
 
 void interactive_begin(struct view *view, enum input_mode mode, uint32_t edges);
 void interactive_finish(struct view *view);
diff --git a/src/config/rcxml.c b/src/config/rcxml.c
index 1ff3766..be2197a 100644
--- a/src/config/rcxml.c
+++ b/src/config/rcxml.c
@@ -862,6 +862,8 @@ entry(xmlNode *node, char *nodename, char *content)
 		rc.tablet.box.width = tablet_get_dbl_if_positive(content, "width");
 	} else if (!strcasecmp(nodename, "height.area.tablet")) {
 		rc.tablet.box.height = tablet_get_dbl_if_positive(content, "height");
+	} else if (!strcasecmp(nodename, "mapToOutput.tablet")) {
+		rc.tablet.output_name = xstrdup(content);
 	} else if (!strcasecmp(nodename, "rotate.tablet")) {
 		rc.tablet.rotation = tablet_parse_rotation(atoi(content));
 	} else if (!strcasecmp(nodename, "button.map.tablet")) {
diff --git a/src/output.c b/src/output.c
index 833cb09..6051e43 100644
--- a/src/output.c
+++ b/src/output.c
@@ -85,6 +85,7 @@ output_destroy_notify(struct wl_listener *listener, void *data)
 	wl_list_remove(&output->frame.link);
 	wl_list_remove(&output->destroy.link);
 	wl_list_remove(&output->request_state.link);
+	seat_outputs_changed(&output->server->seat);
 
 	for (size_t i = 0; i < ARRAY_SIZE(output->layer_tree); i++) {
 		wlr_scene_node_destroy(&output->layer_tree[i]->node);
@@ -329,6 +330,7 @@ new_output_notify(struct wl_listener *listener, void *data)
 
 	server->pending_output_layout_change--;
 	do_output_layout_change(server);
+	seat_outputs_changed(&output->server->seat);
 }
 
 void
diff --git a/src/seat.c b/src/seat.c
index b8fb636..d3c069d 100644
--- a/src/seat.c
+++ b/src/seat.c
@@ -204,6 +204,17 @@ output_by_name(struct server *server, const char *name)
 	return NULL;
 }
 
+static void
+map_input_to_output(struct seat *seat, struct wlr_input_device *dev, char *output_name)
+{
+	struct wlr_output *output = NULL;
+	if (output_name) {
+		output = output_by_name(seat->server, output_name);
+	}
+	wlr_cursor_map_input_to_output(seat->cursor, dev, output);
+	wlr_cursor_map_input_to_region(seat->cursor, dev, NULL);
+}
+
 static struct input *
 new_pointer(struct seat *seat, struct wlr_input_device *dev)
 {
@@ -214,14 +225,9 @@ new_pointer(struct seat *seat, struct wlr_input_device *dev)
 
 	/* In support of running with WLR_WL_OUTPUTS set to >=2 */
 	if (dev->type == WLR_INPUT_DEVICE_POINTER) {
-		struct wlr_output *output = NULL;
 		struct wlr_pointer *pointer = wlr_pointer_from_input_device(dev);
 		wlr_log(WLR_INFO, "map pointer to output %s\n", pointer->output_name);
-		if (pointer->output_name) {
-			output = output_by_name(seat->server, pointer->output_name);
-		}
-		wlr_cursor_map_input_to_output(seat->cursor, dev, output);
-		wlr_cursor_map_input_to_region(seat->cursor, dev, NULL);
+		map_input_to_output(seat, dev, pointer->output_name);
 	}
 	return input;
 }
@@ -267,14 +273,9 @@ new_touch(struct seat *seat, struct wlr_input_device *dev)
 
 	/* In support of running with WLR_WL_OUTPUTS set to >=2 */
 	if (dev->type == WLR_INPUT_DEVICE_TOUCH) {
-		struct wlr_output *output = NULL;
 		struct wlr_touch *touch = wlr_touch_from_input_device(dev);
 		wlr_log(WLR_INFO, "map touch to output %s\n", touch->output_name);
-		if (touch->output_name) {
-			output = output_by_name(seat->server, touch->output_name);
-		}
-		wlr_cursor_map_input_to_output(seat->cursor, dev, output);
-		wlr_cursor_map_input_to_region(seat->cursor, dev, NULL);
+		map_input_to_output(seat, dev, touch->output_name);
 	}
 	return input;
 }
@@ -285,6 +286,9 @@ new_tablet(struct seat *seat, struct wlr_input_device *dev)
 	struct input *input = znew(*input);
 	input->wlr_input_device = dev;
 	tablet_init(seat, dev);
+	wlr_cursor_attach_input_device(seat->cursor, dev);
+	wlr_log(WLR_INFO, "map touch to output %s\n", rc.tablet.output_name);
+	map_input_to_output(seat, dev, rc.tablet.output_name);
 
 	return input;
 }
@@ -636,3 +640,14 @@ seat_reset_pressed(struct seat *seat)
 	seat->pressed.toplevel = NULL;
 	seat->pressed.resize_edges = 0;
 }
+
+void
+seat_outputs_changed(struct seat *seat)
+{
+	struct input *input = NULL;
+	wl_list_for_each(input, &seat->inputs, link) {
+		if (input->wlr_input_device->type == WLR_INPUT_DEVICE_TABLET_TOOL) {
+			map_input_to_output(seat, input->wlr_input_device, rc.tablet.output_name);
+		}
+	}
+}

Edit2: Yes, v2 works perfectly. With another small addition, I can also change the mapping on reconfigure. So if this direction is fine, I'll happily create a PR for this one.

from labwc.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.