From 7c3e3d66d63f0dfd33902ab7541724cf2dc4cd76 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Tue, 7 Jan 2020 14:48:48 +0100 Subject: Fix drag and drop for X11 in Gtk "XDND drag-and-drop does not work with reparented external windows, since messages are exchanged with the toplevel window only" To address this, the XDND specification allows events to be proxied to child windows: https://www.freedesktop.org/wiki/Specifications/XDND/ This commit does so in suil so that drag and drop works with embedded plugin UIs. --- NEWS | 3 ++- src/x11_in_gtk2.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 28d0708..2f86caa 100644 --- a/NEWS +++ b/NEWS @@ -1,8 +1,9 @@ suil (0.10.7) unstable; * Fix compilation on MacOS older than 10.12 + * Fix drag and drop for X11 in Gtk - -- David Robillard Mon, 06 Jan 2020 15:12:38 +0000 + -- David Robillard Wed, 12 Feb 2020 19:12:01 +0000 suil (0.10.6) stable; diff --git a/src/x11_in_gtk2.c b/src/x11_in_gtk2.c index 69fbc17..d8f9578 100644 --- a/src/x11_in_gtk2.c +++ b/src/x11_in_gtk2.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "lv2/options/options.h" #include "lv2/urid/urid.h" @@ -89,6 +90,25 @@ x_window_is_valid(SuilX11Wrapper* socket) return false; } +static Window +get_parent_window(Display* display, Window child) +{ + Window root = 0; + Window parent = 0; + Window* children = NULL; + unsigned count = 0; + + if (child) { + if (XQueryTree(display, child, &root, &parent, &children, &count)) { + if (children) { + XFree(children); + } + } + } + + return (parent == root) ? 0 : parent; +} + static gboolean on_plug_removed(GtkSocket* sock, gpointer data) { @@ -133,6 +153,25 @@ suil_x11_wrapper_realize(GtkWidget* w) gtk_widget_set_sensitive(GTK_WIDGET(wrap->plug), TRUE); gtk_widget_set_can_focus(GTK_WIDGET(wrap->plug), TRUE); gtk_widget_grab_focus(GTK_WIDGET(wrap->plug)); + + // Setup drag/drop proxy from parent/grandparent window + GdkWindow* gwindow = gtk_widget_get_window(GTK_WIDGET(wrap->plug)); + Window xwindow = GDK_WINDOW_XID(gwindow); + Atom xdnd_proxy_atom = gdk_x11_get_xatom_by_name("XdndProxy"); + Window plugin = (Window)wrap->instance->ui_widget; + + while (xwindow) { + XChangeProperty(GDK_WINDOW_XDISPLAY(gwindow), + xwindow, + xdnd_proxy_atom, + XA_WINDOW, + 32, + PropModeReplace, + (unsigned char*)&plugin, + 1); + + xwindow = get_parent_window(GDK_WINDOW_XDISPLAY(gwindow), xwindow); + } } static void -- cgit v1.2.1