diff options
author | Robin Gareus <robin@gareus.org> | 2020-01-07 14:48:48 +0100 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2020-02-12 20:12:27 +0100 |
commit | 7c3e3d66d63f0dfd33902ab7541724cf2dc4cd76 (patch) | |
tree | 3b83b4e1dd45bde5c3aded090cdabe300a32ceb4 | |
parent | 87532252e2aa0ea15f6a97df76c51a93c1378b20 (diff) | |
download | suil-7c3e3d66d63f0dfd33902ab7541724cf2dc4cd76.tar.gz suil-7c3e3d66d63f0dfd33902ab7541724cf2dc4cd76.tar.bz2 suil-7c3e3d66d63f0dfd33902ab7541724cf2dc4cd76.zip |
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"
<https://specifications.freedesktop.org/xembed-spec/xembed-spec-latest.html#idm46049203496608>
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.
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | src/x11_in_gtk2.c | 39 |
2 files changed, 41 insertions, 1 deletions
@@ -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 <d@drobilla.net> Mon, 06 Jan 2020 15:12:38 +0000 + -- David Robillard <d@drobilla.net> 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 <gdk/gdkx.h> #include <gtk/gtk.h> #include <string.h> +#include <X11/Xatom.h> #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 |