[weston,v2] dnd: Fix some mouse cursor issues

Submitted by Derek Foreman on Nov. 20, 2014, 9:32 p.m.

Details

Message ID 1416519160-11389-1-git-send-email-derekf@osg.samsung.com
State Accepted
Commit ba0f33dc2881006e206d32772fc7adda48fe18ac
Headers show

Not browsing as part of any series.

Commit Message

Derek Foreman Nov. 20, 2014, 9:32 p.m.
When ending a drag in the window the cursor will be wrong until the mouse
is moved again.  This is because the item being dragged isn't added
until after the enter event.

Also, when picking up an item while moving the mouse the cursor can switch
back to a non-drag cursor before the drag begins.  This is because of a
slight delay between button click and drag start.

Finally picking up or dropping an item under a second pointer could cause
that pointer to have the wrong cursor.

Closes one of the issues in bug 56298
https://bugs.freedesktop.org/show_bug.cgi?id=56298

Signed-off-by: Derek Foreman <derekf@osg.samsung.com>
---

Now with better multi-pointer handling.

 clients/dnd.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 80 insertions(+), 13 deletions(-)

Patch hide | download patch | download mbox

diff --git a/clients/dnd.c b/clients/dnd.c
index 956c306..e893d36 100644
--- a/clients/dnd.c
+++ b/clients/dnd.c
@@ -33,6 +33,7 @@ 
 #include <sys/time.h>
 #include <cairo.h>
 #include <sys/epoll.h>
+#include <stdbool.h>
 
 #include <wayland-client.h>
 #include <wayland-cursor.h>
@@ -42,6 +43,12 @@ 
 
 struct dnd_drag;
 
+struct pointer {
+	struct input *input;
+	bool dragging;
+	struct wl_list link;
+};
+
 struct dnd {
 	struct window *window;
 	struct widget *widget;
@@ -50,6 +57,7 @@  struct dnd {
 	struct item *items[16];
 	int self_only;
 	struct dnd_drag *current_drag;
+	struct wl_list pointers;
 };
 
 struct dnd_drag {
@@ -454,6 +462,40 @@  create_drag_source(struct dnd *dnd,
 		return -1;
 }
 
+static int
+lookup_cursor(struct dnd *dnd, int x, int y)
+{
+	struct item *item;
+
+	item = dnd_get_item(dnd, x, y);
+	if (item)
+		return CURSOR_HAND1;
+	else
+		return CURSOR_LEFT_PTR;
+}
+
+/* Update all the mouse pointers in the window appropriately.
+ * Optionally, skip one (which will be the current pointer just
+ * about to start a drag).  This is done here to save a scan
+ * through the pointer list.
+ */
+static void
+update_pointer_images_except(struct dnd *dnd, struct input *except)
+{
+	struct pointer *pointer;
+	int32_t x, y;
+
+	wl_list_for_each(pointer, &dnd->pointers, link) {
+		if (pointer->input == except) {
+			pointer->dragging = true;
+			continue;
+		}
+		input_get_position(pointer->input, &x, &y);
+		input_set_pointer_image(pointer->input,
+					lookup_cursor(dnd, x, y));
+	}
+}
+
 static void
 dnd_button_handler(struct widget *widget,
 		   struct input *input, uint32_t time,
@@ -466,8 +508,10 @@  dnd_button_handler(struct widget *widget,
 	input_get_position(input, &x, &y);
 	if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
 		input_ungrab(input);
-		if (create_drag_source(dnd, input, time, x, y) == 0)
+		if (create_drag_source(dnd, input, time, x, y) == 0) {
 			input_set_pointer_image(input, CURSOR_DRAGGING);
+			update_pointer_images_except(dnd, input);
+		}
 	}
 }
 
@@ -490,33 +534,52 @@  dnd_touch_down_handler(struct widget *widget,
 }
 
 static int
-lookup_cursor(struct dnd *dnd, int x, int y)
-{
-	struct item *item;
-
-	item = dnd_get_item(dnd, x, y);
-	if (item)
-		return CURSOR_HAND1;
-	else
-		return CURSOR_LEFT_PTR;
-}
-
-static int
 dnd_enter_handler(struct widget *widget,
 		  struct input *input, float x, float y, void *data)
 {
 	struct dnd *dnd = data;
+	struct pointer *new_pointer = malloc(sizeof *new_pointer);
 
 	dnd->current_drag = NULL;
 
+	if (new_pointer) {
+		new_pointer->input = input;
+		new_pointer->dragging = false;
+		wl_list_insert(dnd->pointers.prev, &new_pointer->link);
+	}
+
 	return lookup_cursor(dnd, x, y);
 }
 
+static void
+dnd_leave_handler(struct widget *widget,
+		  struct input *input, void *data)
+{
+	struct dnd *dnd = data;
+	struct pointer *pointer, *tmp;
+
+	wl_list_for_each_safe(pointer, tmp, &dnd->pointers, link)
+		if (pointer->input == input) {
+			wl_list_remove(&pointer->link);
+			free(pointer);
+		}
+}
+
 static int
 dnd_motion_handler(struct widget *widget,
 		   struct input *input, uint32_t time,
 		   float x, float y, void *data)
 {
+	struct dnd *dnd = data;
+	struct pointer *pointer;
+
+	wl_list_for_each(pointer, &dnd->pointers, link)
+		if (pointer->input == input) {
+			if (pointer->dragging)
+				return CURSOR_DRAGGING;
+			break;
+		}
+
 	return lookup_cursor(data, x, y);
 }
 
@@ -564,6 +627,7 @@  dnd_receive_func(void *data, size_t len, int32_t x, int32_t y, void *user_data)
 			   message->seed);
 
 	dnd_add_item(dnd, item);
+	update_pointer_images_except(dnd, NULL);
 	window_schedule_redraw(dnd->window);
 }
 
@@ -610,6 +674,8 @@  dnd_create(struct display *display)
 	dnd->display = display;
 	dnd->key = 100;
 
+	wl_list_init(&dnd->pointers);
+
 	for (i = 0; i < ARRAY_LENGTH(dnd->items); i++) {
 		x = (i % 4) * (item_width + item_padding) + item_padding;
 		y = (i / 4) * (item_height + item_padding) + item_padding;
@@ -627,6 +693,7 @@  dnd_create(struct display *display)
 
 	widget_set_redraw_handler(dnd->widget, dnd_redraw_handler);
 	widget_set_enter_handler(dnd->widget, dnd_enter_handler);
+	widget_set_leave_handler(dnd->widget, dnd_leave_handler);
 	widget_set_motion_handler(dnd->widget, dnd_motion_handler);
 	widget_set_button_handler(dnd->widget, dnd_button_handler);
 	widget_set_touch_down_handler(dnd->widget, dnd_touch_down_handler);

Comments

On Thu, 20 Nov 2014 15:32:40 -0600
Derek Foreman <derekf@osg.samsung.com> wrote:

> When ending a drag in the window the cursor will be wrong until the mouse
> is moved again.  This is because the item being dragged isn't added
> until after the enter event.
> 
> Also, when picking up an item while moving the mouse the cursor can switch
> back to a non-drag cursor before the drag begins.  This is because of a
> slight delay between button click and drag start.
> 
> Finally picking up or dropping an item under a second pointer could cause
> that pointer to have the wrong cursor.
> 
> Closes one of the issues in bug 56298
> https://bugs.freedesktop.org/show_bug.cgi?id=56298
> 
> Signed-off-by: Derek Foreman <derekf@osg.samsung.com>
> ---
> 
> Now with better multi-pointer handling.
> 
>  clients/dnd.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++---------
>  1 file changed, 80 insertions(+), 13 deletions(-)

Works for me, pushed.

Thanks,
pq