[PATCH weston 1/2] relative-grab: first implementation

Philipp Brüschweiler blei42 at gmail.com
Mon Aug 27 11:56:28 PDT 2012


Support the relative_grab request introduced to wayland by a different
patch.

notify_motion is renamed to notify_motion_absolute; a new function
called notify_motion_relative is added. A data source (i.e. pointer
driver, be it evdev or an x11 pointer) should call the notify_motion
function that works with the "native" data the input source prodives.
E.g. the evdev driver natively returns relative pointer movements, so
it calls notify_motion_relative with the values it receives.

These functions look at the currently active pointer grab and decide
what to do based on whether the currently active grab is relative or
not. E.g. in the case where notify_motion_absolute is called while a
relative grab is in action, it computes the relative motion compared to
the last know pointer position and calls notify_motion_relative with
these values. This guarantees that each combination of input device/grab
type produces the expected effects.
---
 src/compositor-wayland.c |   6 +-
 src/compositor-x11.c     |  24 +++++--
 src/compositor.c         |  37 +++++++++--
 src/compositor.h         |   7 ++-
 src/evdev.c              |  12 ++--
 src/shell.c              | 159 +++++++++++++++++++++++++++++++++++++++++++++--
 6 Dateien geändert, 220 Zeilen hinzugefügt(+), 25 Zeilen entfernt(-)

diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c
index 4fc77f1..920abc9 100644
--- a/src/compositor-wayland.c
+++ b/src/compositor-wayland.c
@@ -592,9 +592,9 @@ input_handle_motion(void *data, struct wl_pointer *pointer,
 
 	check_focus(input, x, y);
 	if (input->focus)
-		notify_motion(&input->base, time,
-			      x - wl_fixed_from_int(c->border.left),
-			      y - wl_fixed_from_int(c->border.top));
+		notify_motion_absolute(&input->base, time,
+				       x - wl_fixed_from_int(c->border.left),
+				       y - wl_fixed_from_int(c->border.top));
 }
 
 static void
diff --git a/src/compositor-x11.c b/src/compositor-x11.c
index c02911d..946034b 100644
--- a/src/compositor-x11.c
+++ b/src/compositor-x11.c
@@ -398,6 +398,8 @@ x11_output_set_wm_protocols(struct x11_output *output)
 static void
 x11_output_change_state(struct x11_output *output, int add, xcb_atom_t state)
 {
+	xcb_void_cookie_t cookie;
+	xcb_generic_error_t *error;
 	xcb_client_message_event_t event;
 	struct x11_compositor *c =
 		(struct x11_compositor *) output->base.compositor;
@@ -420,10 +422,15 @@ x11_output_change_state(struct x11_output *output, int add, xcb_atom_t state)
 	event.data.data32[4] = 0;
 
 	iter = xcb_setup_roots_iterator(xcb_get_setup(c->conn));
-	xcb_send_event(c->conn, 0, iter.data->root,
+	cookie = xcb_send_event_checked(c->conn, 0, iter.data->root,
 		       XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
 		       XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
 		       (void *) &event);
+	error = xcb_request_check(c->conn, cookie);
+	if (error) {
+		weston_log("error changing x11 output state, code %u\n",
+			   error->error_code);
+	}
 }
 
 
@@ -878,8 +885,9 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data)
 			output = x11_compositor_find_output(c, motion_notify->event);
 			x = wl_fixed_from_int(output->base.x + motion_notify->event_x);
 			y = wl_fixed_from_int(output->base.y + motion_notify->event_y);
-			notify_motion(&c->core_seat,
-				      weston_compositor_get_time(), x, y);
+			notify_motion_absolute(&c->core_seat,
+					       weston_compositor_get_time(),
+					       x, y);
 			break;
 
 		case XCB_EXPOSE:
@@ -996,6 +1004,7 @@ x11_compositor_get_resources(struct x11_compositor *c)
 
 	xcb_intern_atom_cookie_t cookies[ARRAY_LENGTH(atoms)];
 	xcb_intern_atom_reply_t *reply;
+	xcb_generic_error_t *error;
 	xcb_pixmap_t pixmap;
 	xcb_gc_t gc;
 	unsigned int i;
@@ -1007,8 +1016,13 @@ x11_compositor_get_resources(struct x11_compositor *c)
 					      atoms[i].name);
 
 	for (i = 0; i < ARRAY_LENGTH(atoms); i++) {
-		reply = xcb_intern_atom_reply (c->conn, cookies[i], NULL);
-		*(xcb_atom_t *) ((char *) c + atoms[i].offset) = reply->atom;
+		error = NULL;
+		reply = xcb_intern_atom_reply (c->conn, cookies[i], &error);
+		if (error)
+			weston_log("error interning atom %s, code %u\n",
+				   atoms[i].name, error->error_code);
+		else
+			*(xcb_atom_t *) ((char *) c + atoms[i].offset) = reply->atom;
 		free(reply);
 	}
 
diff --git a/src/compositor.c b/src/compositor.c
index 1bf7c96..8226f4f 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -1743,23 +1743,52 @@ clip_pointer_motion(struct weston_seat *seat, wl_fixed_t *fx, wl_fixed_t *fy)
 }
 
 WL_EXPORT void
-notify_motion(struct weston_seat *seat, uint32_t time, wl_fixed_t x, wl_fixed_t y)
+notify_motion_relative(struct weston_seat *seat, uint32_t time,
+		       wl_fixed_t dx, wl_fixed_t dy)
+{
+	struct wl_pointer *pointer = seat->seat.pointer;
+	struct weston_compositor *ec = seat->compositor;
+
+	if (!pointer->grab->is_relative) {
+		notify_motion_absolute(seat, time, pointer->x + dx,
+				       pointer->y + dy);
+		return;
+	}
+
+	weston_compositor_activity(ec);
+
+	pointer->grab->interface->motion(pointer->grab,
+					 time, dx, dy);
+}
+
+WL_EXPORT void
+notify_motion_absolute(struct weston_seat *seat, uint32_t time,
+		       wl_fixed_t x, wl_fixed_t y)
 {
 	const struct wl_pointer_grab_interface *interface;
 	struct weston_compositor *ec = seat->compositor;
 	struct weston_output *output;
 	struct wl_pointer *pointer = seat->seat.pointer;
+	wl_fixed_t dx, dy;
 	int32_t ix, iy;
 
-	weston_compositor_activity(ec);
-
 	clip_pointer_motion(seat, &x, &y);
 
-	weston_seat_update_drag_surface(seat, x - pointer->x, y - pointer->y);
+	dx = x - pointer->x;
+	dy = y - pointer->y;
 
 	pointer->x = x;
 	pointer->y = y;
 
+	if (pointer->grab->is_relative) {
+		notify_motion_relative(seat, time, dx, dy);
+		return;
+	}
+
+	weston_compositor_activity(ec);
+
+	weston_seat_update_drag_surface(seat, dx, dy);
+
 	ix = wl_fixed_to_int(x);
 	iy = wl_fixed_to_int(y);
 
diff --git a/src/compositor.h b/src/compositor.h
index b8e767d..7b6102c 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -501,8 +501,11 @@ weston_surface_draw(struct weston_surface *es,
 		    struct weston_output *output, pixman_region32_t *damage);
 
 void
-notify_motion(struct weston_seat *seat, uint32_t time,
-	      wl_fixed_t x, wl_fixed_t y);
+notify_motion_relative(struct weston_seat *seat, uint32_t time,
+		       wl_fixed_t x, wl_fixed_t y);
+void
+notify_motion_absolute(struct weston_seat *seat, uint32_t time,
+		       wl_fixed_t x, wl_fixed_t y);
 void
 notify_button(struct weston_seat *seat, uint32_t time, int32_t button,
 	      enum wl_pointer_button_state state);
diff --git a/src/evdev.c b/src/evdev.c
index 8848736..8227a27 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -217,9 +217,9 @@ evdev_flush_motion(struct evdev_device *device, uint32_t time)
 		return;
 
 	if (device->pending_events & EVDEV_RELATIVE_MOTION) {
-		notify_motion(master, time,
-			      master->seat.pointer->x + device->rel.dx,
-			      master->seat.pointer->y + device->rel.dy);
+		notify_motion_relative(master, time,
+				       device->rel.dx,
+				       device->rel.dy);
 		device->pending_events &= ~EVDEV_RELATIVE_MOTION;
 		device->rel.dx = 0;
 		device->rel.dy = 0;
@@ -248,9 +248,9 @@ evdev_flush_motion(struct evdev_device *device, uint32_t time)
 		device->pending_events &= ~EVDEV_ABSOLUTE_MT_UP;
 	}
 	if (device->pending_events & EVDEV_ABSOLUTE_MOTION) {
-		notify_motion(master, time,
-			      wl_fixed_from_int(device->abs.x),
-			      wl_fixed_from_int(device->abs.y));
+		notify_motion_absolute(master, time,
+				       wl_fixed_from_int(device->abs.x),
+				       wl_fixed_from_int(device->abs.y));
 		device->pending_events &= ~EVDEV_ABSOLUTE_MOTION;
 	}
 }
diff --git a/src/shell.c b/src/shell.c
index 4d6bc4f..685bb94 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -221,6 +221,15 @@ struct rotate_grab {
 	} center;
 };
 
+struct relative_grab {
+	struct shell_grab base;
+	bool grab_active;
+	struct wl_resource *resource;
+	struct wl_listener keyboard_focus_listener;
+
+	wl_fixed_t x, y;
+};
+
 static void
 activate(struct desktop_shell *shell, struct weston_surface *es,
 	 struct weston_seat *seat);
@@ -267,11 +276,13 @@ shell_grab_start(struct shell_grab *grab,
 		 const struct wl_pointer_grab_interface *interface,
 		 struct shell_surface *shsurf,
 		 struct wl_pointer *pointer,
-		 enum desktop_shell_cursor cursor)
+		 enum desktop_shell_cursor cursor,
+		 int is_relative)
 {
 	struct desktop_shell *shell = shsurf->shell;
 
 	grab->grab.interface = interface;
+	grab->grab.is_relative = is_relative;
 	grab->shsurf = shsurf;
 	grab->shsurf_destroy_listener.notify = destroy_shell_grab_shsurf;
 	wl_signal_add(&shsurf->resource.destroy_signal,
@@ -821,7 +832,7 @@ surface_move(struct shell_surface *shsurf, struct weston_seat *ws)
 			ws->seat.pointer->grab_y;
 
 	shell_grab_start(&move->base, &move_grab_interface, shsurf,
-			 ws->seat.pointer, DESKTOP_SHELL_CURSOR_MOVE);
+			 ws->seat.pointer, DESKTOP_SHELL_CURSOR_MOVE, 0);
 
 	return 0;
 }
@@ -842,6 +853,143 @@ shell_surface_move(struct wl_client *client, struct wl_resource *resource,
 		wl_resource_post_no_memory(resource);
 }
 
+static void
+relative_grab_motion(struct wl_pointer_grab *grab,
+		     uint32_t time, wl_fixed_t dx, wl_fixed_t dy)
+{
+	struct relative_grab *relative_grab = (struct relative_grab *) grab;
+
+	wl_relative_grab_send_motion(relative_grab->resource,
+				     time, dx, dy);
+}
+
+static void
+relative_grab_button(struct wl_pointer_grab *grab,
+		     uint32_t time, uint32_t button, uint32_t state_w)
+{
+	struct relative_grab *relative_grab = (struct relative_grab *) grab;
+	struct wl_resource *resource;
+	uint32_t serial;
+
+	resource = relative_grab->base.pointer->focus_resource;
+	assert(resource);
+
+	serial = wl_display_next_serial(
+	    wl_client_get_display(resource->client));
+
+	wl_pointer_send_button(resource, serial, time, button, state_w);
+}
+
+static const struct wl_pointer_grab_interface relative_grab_interface = {
+	noop_grab_focus,
+	relative_grab_motion,
+	relative_grab_button,
+};
+
+static void
+relative_grab_ungrab(struct relative_grab *relative_grab)
+{
+	wl_list_remove(&relative_grab->keyboard_focus_listener.link);
+	shell_grab_end(&relative_grab->base);
+	relative_grab->grab_active = false;
+}
+
+static void
+relative_grab_keyboard_focus_listener(struct wl_listener *listener,
+				      void *data)
+{
+	struct wl_keyboard *keyboard = data;
+	struct relative_grab *relative_grab =
+		container_of(listener, struct relative_grab,
+			     keyboard_focus_listener);
+
+	if (relative_grab->base.shsurf == NULL) {
+		/* shsurf has been destroyed */
+		relative_grab_ungrab(relative_grab);
+		return;
+	}
+
+	if (keyboard->focus != &relative_grab->base.shsurf->surface->surface) {
+		relative_grab_ungrab(relative_grab);
+		wl_relative_grab_send_destroy_me(relative_grab->resource);
+	}
+}
+
+static void
+relative_grab_destroy(struct wl_client *client, struct wl_resource *resource) {
+	struct relative_grab *relative_grab = resource->data;
+
+	wl_resource_destroy(resource);
+	if (relative_grab->grab_active)
+		relative_grab_ungrab(relative_grab);
+
+	free(relative_grab);
+}
+
+static const struct wl_relative_grab_interface relative_grab_listener = {
+	relative_grab_destroy,
+};
+
+static void
+shell_surface_relative_grab(struct wl_client *client,
+			    struct wl_resource *resource, uint32_t id,
+			    struct wl_resource *seat_resource, uint32_t serial)
+{
+	struct weston_seat *ws = seat_resource->data;
+	struct shell_surface *shsurf = resource->data;
+	struct relative_grab *relative_grab;
+	struct wl_resource *grab_resource;
+
+	/*
+	 * TODO: check that only one grab is active
+	if (shsurf->relative_grab.resource) {
+		wl_resource_post_error(resource,
+				       WL_DISPLAY_ERROR_INVALID_OBJECT,
+				       "shell_surface::relative_grab already requested");
+		return;
+	}
+	*/
+
+	relative_grab = calloc(1, sizeof *relative_grab);
+	if (relative_grab == NULL) {
+		wl_resource_post_no_memory(resource);
+		return;
+	}
+
+	grab_resource = wl_client_add_object(client,
+					     &wl_relative_grab_interface,
+					     &relative_grab_listener,
+					     id, relative_grab);
+	if (!grab_resource)
+		return;
+
+	relative_grab->resource = grab_resource;
+
+	/* Only grant grab when reacting to recent event and focused. */
+	if (ws->seat.pointer->grab_serial != serial ||
+	    ws->seat.pointer->focus != &shsurf->surface->surface) {
+
+		wl_relative_grab_send_destroy_me(grab_resource);
+		return;
+	}
+
+	relative_grab->keyboard_focus_listener.notify =
+		relative_grab_keyboard_focus_listener;
+	wl_signal_add(&ws->seat.keyboard->focus_signal,
+		      &relative_grab->keyboard_focus_listener);
+
+	relative_grab->x = ws->seat.pointer->x;
+	relative_grab->y = ws->seat.pointer->y;
+	relative_grab->grab_active = true;
+
+	shell_grab_start(&relative_grab->base,
+			 &relative_grab_interface,
+			 shsurf,
+			 ws->seat.pointer,
+			 DESKTOP_SHELL_CURSOR_NONE,
+			 1);
+}
+
 struct weston_resize_grab {
 	struct shell_grab base;
 	uint32_t edges;
@@ -943,7 +1091,7 @@ surface_resize(struct shell_surface *shsurf,
 	resize->height = shsurf->surface->geometry.height;
 
 	shell_grab_start(&resize->base, &resize_grab_interface, shsurf,
-			 ws->seat.pointer, edges);
+			 ws->seat.pointer, edges, 0);
 
 	return 0;
 }
@@ -1020,7 +1168,7 @@ set_busy_cursor(struct shell_surface *shsurf, struct wl_pointer *pointer)
 		return;
 
 	shell_grab_start(grab, &busy_cursor_grab_interface, shsurf, pointer,
-			 DESKTOP_SHELL_CURSOR_BUSY);
+			 DESKTOP_SHELL_CURSOR_BUSY, 0);
 }
 
 static void
@@ -1666,6 +1814,7 @@ shell_surface_set_popup(struct wl_client *client,
 static const struct wl_shell_surface_interface shell_surface_implementation = {
 	shell_surface_pong,
 	shell_surface_move,
+	shell_surface_relative_grab,
 	shell_surface_resize,
 	shell_surface_set_toplevel,
 	shell_surface_set_transient,
@@ -2367,7 +2516,7 @@ rotate_binding(struct wl_seat *seat, uint32_t time, uint32_t button,
 	}
 
 	shell_grab_start(&rotate->base, &rotate_grab_interface, surface,
-			 seat->pointer, DESKTOP_SHELL_CURSOR_ARROW);
+			 seat->pointer, DESKTOP_SHELL_CURSOR_ARROW, 0);
 }
 
 static void
-- 
1.7.12



More information about the wayland-devel mailing list