data-device: Implement compositor-chosen actions
authorCarlos Garnacho <carlosg@gnome.org>
Fri, 15 Jan 2016 20:14:26 +0000 (21:14 +0100)
committerJonas Ådahl <jadahl@gmail.com>
Tue, 19 Jan 2016 04:34:36 +0000 (12:34 +0800)
Set up a keyboard grab during drag-and-drop, so we can translate
modifiers into preferred actions. The compositor chosen action
is stored in the current weston_data_source in order to make it
accessible to the source/offer at the time of calculating the new
action, but would conceptually be part of weston_drag.

The mapping has been made similar to what GTK+/QT usually do, the
shift key defaults to "move" and ctrl defaults to "copy".

Changes since v2:
  - Use enum types and values for the compositor action. Fix
    code formatting issues.

Changes since v1:
  - Handle the keyboard grab being cancelled. Initialize new
    wl_data_source fields.

Signed-off-by: Carlos Garnacho <carlosg@gnome.org>
Reviewed-by: Jonas Ådahl <jadahl@gmail.com>
Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
src/compositor.h
src/data-device.c

index 8303a5f3fbfceca3b48a8b7714d97f03d6205c68..58ae94bc5ff6355d06d73e17bdbc3fb892cc06a8 100644 (file)
@@ -336,6 +336,7 @@ struct weston_data_source {
        bool actions_set;
        uint32_t dnd_actions;
        enum wl_data_device_manager_dnd_action current_dnd_action;
+       enum wl_data_device_manager_dnd_action compositor_action;
 
        void (*accept)(struct weston_data_source *source,
                       uint32_t serial, const char *mime_type);
index 75a4424a3d4548f45e24a4877b403b285571a515..2cfdcfe2196c73356ac51653e97b4216206ce6b9 100644 (file)
@@ -44,6 +44,7 @@ struct weston_drag {
        struct weston_view *icon;
        struct wl_listener icon_destroy_listener;
        int32_t dx, dy;
+       struct weston_keyboard_grab keyboard_grab;
 };
 
 struct weston_pointer_drag {
@@ -139,6 +140,10 @@ data_offer_choose_action(struct weston_data_offer *offer)
        if (!available_actions)
                return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
 
+       if (offer->source->seat &&
+           offer->source->compositor_action & available_actions)
+               return offer->source->compositor_action;
+
        /* If the dest side has a preferred DnD action, use it */
        if ((preferred_action & available_actions) != 0)
                return preferred_action;
@@ -611,9 +616,11 @@ static void
 data_device_end_pointer_drag_grab(struct weston_pointer_drag *drag)
 {
        struct weston_pointer *pointer = drag->grab.pointer;
+       struct weston_keyboard *keyboard = drag->base.keyboard_grab.keyboard;
 
        data_device_end_drag_grab(&drag->base, pointer->seat);
        weston_pointer_end_grab(pointer);
+       weston_keyboard_end_grab(keyboard);
        free(drag);
 }
 
@@ -706,9 +713,11 @@ static void
 data_device_end_touch_drag_grab(struct weston_touch_drag *drag)
 {
        struct weston_touch *touch = drag->grab.touch;
+       struct weston_keyboard *keyboard = drag->base.keyboard_grab.keyboard;
 
        data_device_end_drag_grab(&drag->base, touch->seat);
        weston_touch_end_grab(touch);
+       weston_keyboard_end_grab(keyboard);
        free(drag);
 }
 
@@ -799,6 +808,61 @@ static const struct weston_touch_grab_interface touch_drag_grab_interface = {
        drag_grab_touch_cancel
 };
 
+static void
+drag_grab_keyboard_key(struct weston_keyboard_grab *grab,
+                      uint32_t time, uint32_t key, uint32_t state)
+{
+}
+
+static void
+drag_grab_keyboard_modifiers(struct weston_keyboard_grab *grab,
+                            uint32_t serial, uint32_t mods_depressed,
+                            uint32_t mods_latched,
+                            uint32_t mods_locked, uint32_t group)
+{
+       struct weston_keyboard *keyboard = grab->keyboard;
+       struct weston_drag *drag =
+               container_of(grab, struct weston_drag, keyboard_grab);
+       uint32_t compositor_action;
+
+       if (mods_depressed & (1 << keyboard->xkb_info->shift_mod))
+               compositor_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
+       else if (mods_depressed & (1 << keyboard->xkb_info->ctrl_mod))
+               compositor_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
+       else
+               compositor_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
+
+       drag->data_source->compositor_action = compositor_action;
+
+       if (drag->data_source->offer)
+               data_offer_update_action(drag->data_source->offer);
+}
+
+static void
+drag_grab_keyboard_cancel(struct weston_keyboard_grab *grab)
+{
+       struct weston_drag *drag =
+               container_of(grab, struct weston_drag, keyboard_grab);
+       struct weston_pointer *pointer = grab->keyboard->seat->pointer_state;
+       struct weston_touch *touch = grab->keyboard->seat->touch_state;
+
+       if (pointer && pointer->grab->interface == &pointer_drag_grab_interface) {
+               struct weston_touch_drag *touch_drag =
+                       (struct weston_touch_drag *) drag;
+               drag_grab_touch_cancel(&touch_drag->grab);
+       } else if (touch && touch->grab->interface == &touch_drag_grab_interface) {
+               struct weston_pointer_drag *pointer_drag =
+                       (struct weston_pointer_drag *) drag;
+               drag_grab_cancel(&pointer_drag->grab);
+       }
+}
+
+static const struct weston_keyboard_grab_interface keyboard_drag_grab_interface = {
+       drag_grab_keyboard_key,
+       drag_grab_keyboard_modifiers,
+       drag_grab_keyboard_cancel
+};
+
 static void
 destroy_pointer_data_device_source(struct wl_listener *listener, void *data)
 {
@@ -824,12 +888,15 @@ weston_pointer_start_drag(struct weston_pointer *pointer,
                       struct wl_client *client)
 {
        struct weston_pointer_drag *drag;
+       struct weston_keyboard *keyboard =
+               weston_seat_get_keyboard(pointer->seat);
 
        drag = zalloc(sizeof *drag);
        if (drag == NULL)
                return -1;
 
        drag->grab.interface = &pointer_drag_grab_interface;
+       drag->base.keyboard_grab.interface = &keyboard_drag_grab_interface;
        drag->base.client = client;
        drag->base.data_source = source;
 
@@ -859,7 +926,10 @@ weston_pointer_start_drag(struct weston_pointer *pointer,
        }
 
        weston_pointer_clear_focus(pointer);
+       weston_keyboard_set_focus(keyboard, NULL);
+
        weston_pointer_start_grab(pointer, &drag->grab);
+       weston_keyboard_start_grab(keyboard, &drag->base.keyboard_grab);
 
        return 0;
 }
@@ -880,6 +950,8 @@ weston_touch_start_drag(struct weston_touch *touch,
                       struct wl_client *client)
 {
        struct weston_touch_drag *drag;
+       struct weston_keyboard *keyboard =
+               weston_seat_get_keyboard(touch->seat);
 
        drag = zalloc(sizeof *drag);
        if (drag == NULL)
@@ -914,7 +986,10 @@ weston_touch_start_drag(struct weston_touch *touch,
                              &drag->base.data_source_listener);
        }
 
+       weston_keyboard_set_focus(keyboard, NULL);
+
        weston_touch_start_grab(touch, &drag->grab);
+       weston_keyboard_start_grab(keyboard, &drag->base.keyboard_grab);
 
        drag_grab_touch_focus(drag);
 
@@ -1172,6 +1247,7 @@ create_data_source(struct wl_client *client,
        source->actions_set = false;
        source->dnd_actions = 0;
        source->current_dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
+       source->compositor_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
 
        wl_array_init(&source->mime_types);