From 75a5f7476ad1a84c9bee0f11a90e66a8e93dab27 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 29 May 2012 10:58:26 +0300 Subject: [PATCH] data-device: implement drags with no data source for self-dnd Properly handle a drag with no data source, i.e., don't crash and send events only to the client that initiated the drag. This way a client can do self drag and drop without offering anything to other clients. --- TODO | 4 --- protocol/wayland.xml | 26 +++++++++++++------- src/data-device.c | 58 ++++++++++++++++++++++++++++---------------- src/wayland-server.h | 1 + 4 files changed, 55 insertions(+), 34 deletions(-) diff --git a/TODO b/TODO index abdab310..12f22a74 100644 --- a/TODO +++ b/TODO @@ -78,10 +78,6 @@ EWMH - window move and resize functionality for kb and touch. - - dnd loose ends: self-dnd: initiate dnd with a null data-source, - compositor will not offer to other clients, client has to know - internally what's offered and how to transfer data. no fd passing. - - Protocol for specifying title bar rectangle (for moving unresponsive apps). Rectangle for close button, so we can popup force-close dialog if application doesn't respond to ping event diff --git a/protocol/wayland.xml b/protocol/wayland.xml index 8f5f6af5..3979d97c 100644 --- a/protocol/wayland.xml +++ b/protocol/wayland.xml @@ -317,15 +317,23 @@ This request asks the compositor to start a drag and drop - operation on behalf of the client. The source argument is the - data source that provides the data for the eventual data - transfer. The origin surface is the surface where the drag - originates and the client must have an active implicit grab - that matches the serial. The icon surface is an optional - (can be nil) surface that provides an icon to be moved around - with the cursor. Initially, the top-left corner of the icon - surface is placed at the cursor hotspot, but subsequent - surface.attach request can move the relative position. + operation on behalf of the client. + + The source argument is the data source that provides the data + for the eventual data transfer. If source is NULL, enter, leave + and motion events are sent only to the client that initiated the + drag and the client is expected to handle the data passing + internally. + + The origin surface is the surface where the drag originates and + the client must have an active implicit grab that matches the + serial. + + The icon surface is an optional (can be nil) surface that + provides an icon to be moved around with the cursor. Initially, + the top-left corner of the icon surface is placed at the cursor + hotspot, but subsequent surface.attach request can move the + relative position. diff --git a/src/data-device.c b/src/data-device.c index a7fc6d2f..a6d465fc 100644 --- a/src/data-device.c +++ b/src/data-device.c @@ -180,7 +180,7 @@ drag_grab_focus(struct wl_pointer_grab *grab, struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y) { struct wl_seat *seat = container_of(grab, struct wl_seat, drag_grab); - struct wl_resource *resource, *offer; + struct wl_resource *resource, *offer = NULL; struct wl_display *display; uint32_t serial; @@ -191,26 +191,34 @@ drag_grab_focus(struct wl_pointer_grab *grab, seat->drag_focus = NULL; } - if (surface) - resource = find_resource(&seat->drag_resource_list, - surface->resource.client); - if (surface && resource) { - display = wl_client_get_display(resource->client); - serial = wl_display_next_serial(display); + if (!surface) + return; + if (!seat->drag_data_source && + surface->resource.client != seat->drag_client) + return; + + resource = find_resource(&seat->drag_resource_list, + surface->resource.client); + if (!resource) + return; + + display = wl_client_get_display(resource->client); + serial = wl_display_next_serial(display); + + if (seat->drag_data_source) offer = wl_data_source_send_offer(seat->drag_data_source, resource); - wl_data_device_send_enter(resource, serial, &surface->resource, - x, y, offer); + wl_data_device_send_enter(resource, serial, &surface->resource, + x, y, offer); - seat->drag_focus = surface; - seat->drag_focus_listener.notify = destroy_drag_focus; - wl_signal_add(&resource->destroy_signal, - &seat->drag_focus_listener); - seat->drag_focus_resource = resource; - grab->focus = surface; - } + seat->drag_focus = surface; + seat->drag_focus_listener.notify = destroy_drag_focus; + wl_signal_add(&resource->destroy_signal, + &seat->drag_focus_listener); + seat->drag_focus_resource = resource; + grab->focus = surface; } static void @@ -247,6 +255,7 @@ data_device_end_drag_grab(struct wl_seat *seat) seat->drag_data_source = NULL; seat->drag_surface = NULL; + seat->drag_client = NULL; } static void @@ -261,7 +270,8 @@ drag_grab_button(struct wl_pointer_grab *grab, if (seat->pointer->button_count == 0 && state == 0) { data_device_end_drag_grab(seat); - wl_list_remove(&seat->drag_data_source_listener.link); + if (seat->drag_data_source) + wl_list_remove(&seat->drag_data_source_listener.link); } } @@ -304,10 +314,16 @@ data_device_start_drag(struct wl_client *client, struct wl_resource *resource, seat->drag_grab.interface = &drag_grab_interface; - seat->drag_data_source = source_resource->data; - seat->drag_data_source_listener.notify = destroy_data_device_source; - wl_signal_add(&source_resource->destroy_signal, - &seat->drag_data_source_listener); + seat->drag_client = client; + seat->drag_data_source = NULL; + + if (source_resource) { + seat->drag_data_source = source_resource->data; + seat->drag_data_source_listener.notify = + destroy_data_device_source; + wl_signal_add(&source_resource->destroy_signal, + &seat->drag_data_source_listener); + } if (icon_resource) { seat->drag_surface = icon_resource->data; diff --git a/src/wayland-server.h b/src/wayland-server.h index 31f6fe5f..731be00b 100644 --- a/src/wayland-server.h +++ b/src/wayland-server.h @@ -297,6 +297,7 @@ struct wl_seat { struct wl_signal selection_signal; struct wl_list drag_resource_list; + struct wl_client *drag_client; struct wl_data_source *drag_data_source; struct wl_listener drag_data_source_listener; struct wl_surface *drag_focus;