From 65e9c89ed9bf2d8cc6d4d5b76884ace85149be58 Mon Sep 17 00:00:00 2001 From: Hyungwon Hwang Date: Mon, 2 Jan 2017 23:12:34 +0900 Subject: [PATCH] dnd: Implement DnD handling code in Wayland No XDnD events which notify DnD status change comes in Wayland. To emulate XDnD behavior, MetaDnd checks whether there is a grab or not when the modal window starts showing. When there is a grab, it processes the raw events from compositor, and emits DnD signals for plugin. https://bugzilla.gnome.org/show_bug.cgi?id=765003 --- src/backends/meta-dnd-private.h | 4 + src/compositor/compositor.c | 3 + src/compositor/meta-dnd.c | 120 ++++++++++++++++++++++++- src/wayland/meta-wayland-data-device.c | 14 +++ src/wayland/meta-wayland-data-device.h | 6 ++ 5 files changed, 146 insertions(+), 1 deletion(-) diff --git a/src/backends/meta-dnd-private.h b/src/backends/meta-dnd-private.h index 41aa2a0d7..3026d65ac 100644 --- a/src/backends/meta-dnd-private.h +++ b/src/backends/meta-dnd-private.h @@ -27,4 +27,8 @@ gboolean meta_dnd_handle_xdnd_event (MetaBackend *backend, MetaDisplay *display, XEvent *xev); +#ifdef HAVE_WAYLAND +void meta_dnd_wayland_handle_begin_modal (MetaCompositor *compositor); +#endif + #endif /* META_DND_PRIVATE_H */ diff --git a/src/compositor/compositor.c b/src/compositor/compositor.c index a1c83dba1..fc4371399 100644 --- a/src/compositor/compositor.c +++ b/src/compositor/compositor.c @@ -71,6 +71,7 @@ #include "window-private.h" /* to check window->hidden */ #include "display-private.h" /* for meta_display_lookup_x_window() and meta_display_cancel_touch() */ #include "util-private.h" +#include "backends/meta-dnd-private.h" #include "frame.h" #include #include @@ -386,6 +387,8 @@ meta_begin_modal_for_plugin (MetaCompositor *compositor, { meta_display_sync_wayland_input_focus (display); meta_display_cancel_touch (display); + + meta_dnd_wayland_handle_begin_modal (compositor); } return TRUE; diff --git a/src/compositor/meta-dnd.c b/src/compositor/meta-dnd.c index fa294902d..2ba69c449 100644 --- a/src/compositor/meta-dnd.c +++ b/src/compositor/meta-dnd.c @@ -33,12 +33,34 @@ struct _MetaDndClass GObjectClass parent_class; }; +#ifdef HAVE_WAYLAND +#include "wayland/meta-wayland-private.h" +#include "wayland/meta-wayland-data-device.h" +#endif + +typedef struct _MetaDndPrivate MetaDndPrivate; + +struct _MetaDndPrivate +{ +#ifdef HAVE_WAYLAND + gulong handler_id[3]; + + MetaCompositor *compositor; + MetaWaylandCompositor *wl_compositor; +#else + /* to avoid warnings (g_type_class_add_private: assertion `private_size > 0' failed) */ + gchar dummy; +#endif +}; + struct _MetaDnd { GObject parent; + + MetaDndPrivate *priv; }; -G_DEFINE_TYPE (MetaDnd, meta_dnd, G_TYPE_OBJECT); +G_DEFINE_TYPE_WITH_PRIVATE (MetaDnd, meta_dnd, G_TYPE_OBJECT); enum { @@ -169,3 +191,99 @@ meta_dnd_handle_xdnd_event (MetaBackend *backend, return FALSE; } + +#ifdef HAVE_WAYLAND +static void +meta_dnd_wayland_on_motion_event (ClutterActor *actor, + ClutterEvent *event, + MetaDnd *dnd) +{ + MetaDndPrivate *priv = meta_dnd_get_instance_private (dnd); + MetaWaylandDragGrab *current_grab; + gfloat event_x, event_y; + + g_return_if_fail (event != NULL); + + clutter_event_get_coords (event, &event_x, &event_y); + meta_dnd_notify_dnd_position_change (dnd, (int)event_x, (int)event_y); + + current_grab = meta_wayland_data_device_get_current_grab (&priv->wl_compositor->seat->data_device); + if (current_grab) + meta_wayland_drag_grab_update_feedback_actor (current_grab, event); +} + +static void +meta_dnd_wayland_end_notify (ClutterActor *actor, + ClutterEvent *event, + MetaDnd *dnd) +{ + MetaDndPrivate *priv = meta_dnd_get_instance_private (dnd); + unsigned int i; + + meta_wayland_data_device_end_drag (&priv->wl_compositor->seat->data_device); + + for (i = 0; i < G_N_ELEMENTS (priv->handler_id); i++) + { + g_signal_handler_disconnect (priv->compositor->stage, priv->handler_id[i]); + priv->handler_id[i] = 0; + } + + priv->compositor = NULL; + priv->wl_compositor = NULL; + + meta_dnd_notify_dnd_leave (dnd); +} + +static void +meta_dnd_wayland_on_button_released (ClutterActor *actor, + ClutterEvent *event, + MetaDnd *dnd) +{ + meta_dnd_wayland_end_notify (actor, event, dnd); +} + +static void +meta_dnd_wayland_on_key_pressed (ClutterActor *actor, + ClutterEvent *event, + MetaDnd *dnd) +{ + guint key = clutter_event_get_key_symbol (event); + + if (key != CLUTTER_KEY_Escape) + return; + + meta_dnd_wayland_end_notify (actor, event, dnd); +} + +void +meta_dnd_wayland_handle_begin_modal (MetaCompositor *compositor) +{ + MetaWaylandCompositor *wl_compositor = meta_wayland_compositor_get_default (); + MetaDnd *dnd = meta_backend_get_dnd (meta_get_backend ()); + MetaDndPrivate *priv = meta_dnd_get_instance_private (dnd); + + if (priv->handler_id[0] == 0 && + meta_wayland_data_device_get_current_grab (&wl_compositor->seat->data_device) != NULL) + { + priv->compositor = compositor; + priv->wl_compositor = wl_compositor; + + priv->handler_id[0] = g_signal_connect (compositor->stage, + "motion-event", + G_CALLBACK (meta_dnd_wayland_on_motion_event), + dnd); + + priv->handler_id[1] = g_signal_connect (compositor->stage, + "button-release-event", + G_CALLBACK (meta_dnd_wayland_on_button_released), + dnd); + + priv->handler_id[2] = g_signal_connect (compositor->stage, + "key-press-event", + G_CALLBACK (meta_dnd_wayland_on_key_pressed), + dnd); + + meta_dnd_notify_dnd_enter (dnd); + } +} +#endif diff --git a/src/wayland/meta-wayland-data-device.c b/src/wayland/meta-wayland-data-device.c index 4a2584462..06356c1c2 100644 --- a/src/wayland/meta-wayland-data-device.c +++ b/src/wayland/meta-wayland-data-device.c @@ -816,6 +816,14 @@ meta_wayland_drag_grab_get_focus (MetaWaylandDragGrab *drag_grab) return drag_grab->drag_focus; } +void +meta_wayland_drag_grab_update_feedback_actor (MetaWaylandDragGrab *drag_grab, + ClutterEvent *event) +{ + meta_feedback_actor_update (META_FEEDBACK_ACTOR (drag_grab->feedback_actor), + event); +} + static void drag_grab_focus (MetaWaylandPointerGrab *grab, MetaWaylandSurface *surface) @@ -1899,6 +1907,12 @@ meta_wayland_data_device_is_dnd_surface (MetaWaylandDataDevice *data_device, data_device->current_grab->drag_surface == surface; } +MetaWaylandDragGrab * +meta_wayland_data_device_get_current_grab (MetaWaylandDataDevice *data_device) +{ + return data_device->current_grab; +} + gboolean meta_wayland_data_source_has_mime_type (const MetaWaylandDataSource *source, const gchar *mime_type) diff --git a/src/wayland/meta-wayland-data-device.h b/src/wayland/meta-wayland-data-device.h index f48b13578..326a59809 100644 --- a/src/wayland/meta-wayland-data-device.h +++ b/src/wayland/meta-wayland-data-device.h @@ -27,6 +27,7 @@ #include #include "meta-wayland-types.h" +#include "clutter/clutter.h" typedef struct _MetaWaylandDragGrab MetaWaylandDragGrab; typedef struct _MetaWaylandDataSourceFuncs MetaWaylandDataSourceFuncs; @@ -79,6 +80,9 @@ void meta_wayland_data_device_set_keyboard_focus (MetaWaylandDataDevice *data_de gboolean meta_wayland_data_device_is_dnd_surface (MetaWaylandDataDevice *data_device, MetaWaylandSurface *surface); +MetaWaylandDragGrab * + meta_wayland_data_device_get_current_grab (MetaWaylandDataDevice *data_device); + void meta_wayland_data_device_set_dnd_source (MetaWaylandDataDevice *data_device, MetaWaylandDataSource *source); void meta_wayland_data_device_set_selection (MetaWaylandDataDevice *data_device, @@ -133,5 +137,7 @@ void meta_wayland_drag_grab_set_focus (MetaWaylandDragGrab MetaWaylandSurface *surface); MetaWaylandSurface * meta_wayland_drag_grab_get_focus (MetaWaylandDragGrab *drag_grab); +void meta_wayland_drag_grab_update_feedback_actor (MetaWaylandDragGrab *drag_grab, + ClutterEvent *event); #endif /* META_WAYLAND_DATA_DEVICE_H */