From a7b3401ed51899aa8a1634bcf1d8b222dbaffd4c Mon Sep 17 00:00:00 2001 From: unawarez Date: Wed, 12 Jun 2024 18:19:22 -0500 Subject: [PATCH] support Wayland GTK backend in Window.GetHandle This adds support for getting a Wayland `wl_surface` from `Window.GetHandle`. The behavior of the function is now to return either an X11 window ID or Wayland `wl_surface` if running a GTK build on those backends, return 0 on any other GTK backend, or else return the C++ `GetHandle` result unmodified. This is the simplest fix for the Wayland issue without worrying about breaking existing user code, as this function already failed for any non-X11 GTK build. Returning 0 on non-X11/Wayland GTK platforms sidesteps the issue of making sure e.g. GTK Mac GetHandle returns the same type as native Cocoa Mac GetHandle. --- etg/window.py | 10 ++++++++ src/window_ex.cpp | 64 ++++++++++++++++++++++++++++------------------- 2 files changed, 48 insertions(+), 26 deletions(-) diff --git a/etg/window.py b/etg/window.py index 0c035f146..8fb0b9559 100644 --- a/etg/window.py +++ b/etg/window.py @@ -136,6 +136,16 @@ def run(): m1.find('externalLeading').out = True c.find('GetHandle').type = 'wxUIntPtr*' + c.find('GetHandle').detailedDoc = [ + """The returned value differs from the C++ version of GetHandle when \ + running on the GTK port. When running on Wayland with GTK, this \ + function returns a `wl_surface` pointer for the native OS window \ + containing the widget. On X11 with GTK, this returns the X window \ + ID for the containing window. On any other backend with GTK, this \ + function returns 0.\n\n""" + + """On some platforms this may return 0 if the window has not yet been shown.""" + ] c.find('GetHandle').setCppCode("return new wxUIntPtr(wxPyGetWinHandle(self));") c.addCppMethod('void*', 'GetGtkWidget', '()', """\ diff --git a/src/window_ex.cpp b/src/window_ex.cpp index b5d100c9b..c4c6c8de6 100644 --- a/src/window_ex.cpp +++ b/src/window_ex.cpp @@ -1,32 +1,15 @@ - -#ifdef __WXMSW__ -#include -#endif - #ifdef __WXGTK__ -#include +#include #include -#ifdef __WXGTK3__ -// Unlike GDK_WINDOW_XWINDOW, GDK_WINDOW_XID can't handle a NULL, so check 1st -static XID GetXWindow(const wxWindow* wxwin) { - if ((wxwin)->m_wxwindow) { - if (gtk_widget_get_window((wxwin)->m_wxwindow)) - return GDK_WINDOW_XID(gtk_widget_get_window((wxwin)->m_wxwindow)); - return 0; - } - else { - if (gtk_widget_get_window((wxwin)->m_widget)) - return GDK_WINDOW_XID(gtk_widget_get_window((wxwin)->m_widget)); - return 0; - } -} -#else -#define GetXWindow(wxwin) (wxwin)->m_wxwindow ? \ - GDK_WINDOW_XWINDOW((wxwin)->m_wxwindow->window) : \ - GDK_WINDOW_XWINDOW((wxwin)->m_widget->window) + +#ifdef GDK_WINDOWING_X11 +#include #endif +#ifdef GDK_WINDOWING_WAYLAND +#include #endif +#endif // ifdef __WXGTK__ @@ -36,11 +19,40 @@ wxUIntPtr wxPyGetWinHandle(const wxWindow* win) #ifdef __WXMSW__ return (wxUIntPtr)win->GetHandle(); #endif -#if defined(__WXGTK__) || defined(__WXX11__) - return (wxUIntPtr)GetXWindow(win); + +#ifdef __WXX11__ + return (wxUIntPtr)win->GetHandle(); #endif + #ifdef __WXMAC__ return (wxUIntPtr)win->GetHandle(); #endif + +#ifdef __WXGTK__ + GtkWidget *gtk_widget = win->GetHandle(); + if (!gtk_widget) { + return 0; + }; + // gtk_widget_get_window disappears in GTK4; then it will be via + // gtk_widget_get_native() -> gtk_native_get_surface(). + GdkWindow *window = gtk_widget_get_window(gtk_widget); + if (!window) { + return 0; + } +#ifdef GDK_WINDOWING_X11 + if (GDK_IS_X11_WINDOW(window)) { + return (wxUIntPtr)gdk_x11_window_get_xid(window); + } +#endif +#ifdef GDK_WINDOWING_WAYLAND + if (GDK_IS_WAYLAND_WINDOW(window)) { + return (wxUIntPtr)gdk_wayland_window_get_wl_surface(window); + } +#endif + // Returning 0 on any other backend using GTK. + // This is less confusing than returning something else that might + // mismatch C++ GetHandle. +#endif + return 0; }