From 3ab9d96623bc30678cbffc3bf9ec5133e714e87c 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 | 26 +++++++++++++++++++++++-- gdk/wayland/gdkprivate-wayland.h | 4 ++++ gdk/wayland/gdkwindow-wayland.c | 33 +++++++++++++++++++++++++++++++- 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/gdk/wayland/gdkdnd-wayland.c b/gdk/wayland/gdkdnd-wayland.c index f20a0e7ab0..0bb32793f1 100644 --- a/gdk/wayland/gdkdnd-wayland.c +++ b/gdk/wayland/gdkdnd-wayland.c @@ -24,6 +24,7 @@ #include "gdkproperty.h" #include "gdkprivate-wayland.h" #include "gdkdisplay-wayland.h" +#include "gdkwaylandwindow.h" #include "gdkdeviceprivate.h" @@ -48,6 +49,8 @@ struct _GdkWaylandDragContext uint32_t serial; gdouble x; gdouble y; + gint prev_hot_x; + gint prev_hot_y; gint hot_x; gint hot_y; }; @@ -306,8 +309,27 @@ 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); + + context_wayland->prev_hot_x = context_wayland->hot_x; + context_wayland->prev_hot_y = context_wayland->hot_x; + context_wayland->hot_x = hot_x; + context_wayland->hot_y = hot_y; + + if (context_wayland->prev_hot_x == hot_x && + context_wayland->prev_hot_x == hot_x) + return; + + _gdk_wayland_window_offset_next_wl_buffer (context_wayland->dnd_window, + -hot_x, -hot_y); + gdk_window_invalidate_rect (context_wayland->dnd_window, + &(GdkRectangle) { + .x = 0, + .y = 0, + .width = 1, + .height = 1, + }, + 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..9a01d42ff7 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)); @@ -2564,6 +2569,32 @@ gdk_wayland_window_get_wl_surface (GdkWindow *window) return GDK_WINDOW_IMPL_WAYLAND (window->impl)->surface; } +/** + * gdk_wayland_window_offset_next_wl_buffer: + * @window (type GdkWaylandWindow): a #GdkWindow + * @x: x offset which the next buffer should be attached at + * @y: y offset which the next buffer should be attached at + * + * Make GDK attach the next buffer at the given offset. This is useful for + * DND icons which may have a hotspot other than (0, 0). + * + * Since: 3.20 + */ +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; +} + static struct wl_egl_window * gdk_wayland_window_get_wl_egl_window (GdkWindow *window) {