From 561833334b470fd668c38b32e327660cba29e829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 8 Dec 2015 18:19:33 +0800 Subject: [PATCH] wayland: Implement DND icon hotspot API In Wayland, the hotspot of a DND icon is set using the buffer offset in wl_buffer.attach. To implement this, add a private API to cause the next wl_surface.attach to offset the new buffer with a given offset. Setting a DND icon hotspot sets this offset while also queuing a redraw of the window to trigger the wl_surface.attach. https://bugzilla.gnome.org/show_bug.cgi?id=759168 --- gdk/wayland/gdkdnd-wayland.c | 16 ++++++++++++++-- gdk/wayland/gdkprivate-wayland.h | 4 ++++ gdk/wayland/gdkwindow-wayland.c | 22 +++++++++++++++++++++- 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/gdk/wayland/gdkdnd-wayland.c b/gdk/wayland/gdkdnd-wayland.c index f20a0e7ab0..fd0d0a3c06 100644 --- a/gdk/wayland/gdkdnd-wayland.c +++ b/gdk/wayland/gdkdnd-wayland.c @@ -306,8 +306,20 @@ gdk_wayland_drag_context_set_hotspot (GdkDragContext *context, gint hot_x, gint hot_y) { - GDK_WAYLAND_DRAG_CONTEXT (context)->hot_x = hot_x; - GDK_WAYLAND_DRAG_CONTEXT (context)->hot_y = hot_y; + GdkWaylandDragContext *context_wayland = GDK_WAYLAND_DRAG_CONTEXT (context); + gint prev_hot_x = context_wayland->hot_x; + gint prev_hot_y = context_wayland->hot_y; + const GdkRectangle damage_rect = { .width = 1, .height = 1 }; + + context_wayland->hot_x = hot_x; + context_wayland->hot_y = hot_y; + + if (prev_hot_x == hot_x && prev_hot_y == hot_y) + return; + + _gdk_wayland_window_offset_next_wl_buffer (context_wayland->dnd_window, + -hot_x, -hot_y); + gdk_window_invalidate_rect (context_wayland->dnd_window, &damage_rect, FALSE); } static void diff --git a/gdk/wayland/gdkprivate-wayland.h b/gdk/wayland/gdkprivate-wayland.h index 00db37f3b1..c4b5185643 100644 --- a/gdk/wayland/gdkprivate-wayland.h +++ b/gdk/wayland/gdkprivate-wayland.h @@ -104,6 +104,10 @@ void _gdk_wayland_window_register_dnd (GdkWindow *window); GdkDragContext *_gdk_wayland_window_drag_begin (GdkWindow *window, GdkDevice *device, GList *targets); +void _gdk_wayland_window_offset_next_wl_buffer (GdkWindow *window, + int x, + int y); + GdkDragContext * _gdk_wayland_drop_context_new (struct wl_data_device *data_device); void _gdk_wayland_drag_context_set_source_window (GdkDragContext *context, GdkWindow *window); diff --git a/gdk/wayland/gdkwindow-wayland.c b/gdk/wayland/gdkwindow-wayland.c index 60dfc59c9c..9354c0d350 100644 --- a/gdk/wayland/gdkwindow-wayland.c +++ b/gdk/wayland/gdkwindow-wayland.c @@ -121,6 +121,8 @@ struct _GdkWindowImplWayland GdkWindow *transient_for; cairo_surface_t *cairo_surface; + int pending_buffer_offset_x; + int pending_buffer_offset_y; gchar *title; @@ -564,7 +566,10 @@ gdk_wayland_window_attach_image (GdkWindow *window) /* Attach this new buffer to the surface */ wl_surface_attach (impl->surface, _gdk_wayland_shm_surface_get_wl_buffer (impl->cairo_surface), - 0, 0); + impl->pending_buffer_offset_x, + impl->pending_buffer_offset_y); + impl->pending_buffer_offset_x = 0; + impl->pending_buffer_offset_y = 0; /* Only set the buffer scale if supported by the compositor */ display = GDK_WAYLAND_DISPLAY (gdk_window_get_display (window)); @@ -2742,3 +2747,18 @@ gdk_wayland_window_set_dbus_properties_libgtk_only (GdkWindow *window, maybe_set_gtk_surface_dbus_properties (window); } + +void +_gdk_wayland_window_offset_next_wl_buffer (GdkWindow *window, + int x, + int y) +{ + GdkWindowImplWayland *impl; + + g_return_if_fail (GDK_IS_WAYLAND_WINDOW (window)); + + impl = GDK_WINDOW_IMPL_WAYLAND (window->impl); + + impl->pending_buffer_offset_x = x; + impl->pending_buffer_offset_y = y; +}