From 0c72ce94ead36cbf61acb3962f4ea74aab77c4e4 Mon Sep 17 00:00:00 2001 From: Luca Bacci Date: Wed, 13 Dec 2023 12:23:43 +0100 Subject: [PATCH 1/3] GdkWindow: check for same impl class in set_transient_for () Checking for offscreen windows with gdk_window_is_offscreen () is not enough in this case. What we want here is that the impl classes match, as backends are meant to know only about their windows. Instead gdk_window_is_offscreen () checks whether the GdkWindow.window_type field is GDK_WINDOW_OFFSCREEN. In the case of child windows in offscreen windows, the window type is GDK_WINDOW_CHILD, even though their impl is still GdkOffscreenWindow. So actually check whether GDK_WINDOW_IMPL_GET_CLASS (window) matches GDK_WINDOW_IMPL_GET_CLASS (parent). We may also consider getting the toplevels from child windows, as transient-for relationships are really about toplevels, but child windows doesn't seem to cause problems in practice. --- gdk/gdkwindow.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index 62d488d759..62e0cf816f 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -10542,9 +10542,8 @@ void gdk_window_set_transient_for (GdkWindow *window, GdkWindow *parent) { - if (!gdk_window_is_offscreen (window) && - parent != NULL && - gdk_window_is_offscreen (parent)) + if (parent != NULL && + GDK_WINDOW_IMPL_GET_CLASS (window->impl) != GDK_WINDOW_IMPL_GET_CLASS (parent->impl)) { return; } From 6982415c9f3a4c72d8a49b8666b08c800d5c9ba3 Mon Sep 17 00:00:00 2001 From: Luca Bacci Date: Wed, 13 Dec 2023 12:27:32 +0100 Subject: [PATCH 2/3] gdk_display_get_monitor_at_window: Check for offscreen windows And get the embedder before continuing, as the backend-specific get_monitor_at_window () only knows about its own windows. In order to check for offscreen windows, we introduce a new function gdk_window_is_impl_offscreen (). Unlike gdk_window_is_offscreen (), it doesn't rely on the window_type field, but actually checks whether GDK_WINDOW_IMPL_GET_CLASS (window->impl) is GdkOffscreenWindow. See previous commit for informations. --- gdk/gdk-private.h | 2 ++ gdk/gdkdisplay.c | 3 +++ gdk/gdkoffscreenwindow.c | 9 +++++++++ 3 files changed, 14 insertions(+) diff --git a/gdk/gdk-private.h b/gdk/gdk-private.h index 4b616370b7..e962fc9751 100644 --- a/gdk/gdk-private.h +++ b/gdk/gdk-private.h @@ -31,6 +31,8 @@ gboolean gdk_display_get_debug_updates (GdkDisplay *display); void gdk_display_set_debug_updates (GdkDisplay *display, gboolean debug_updates); +gboolean gdk_window_is_impl_offscreen (GdkWindow *window); + const gchar * gdk_get_desktop_startup_id (void); const gchar * gdk_get_desktop_autostart_id (void); diff --git a/gdk/gdkdisplay.c b/gdk/gdkdisplay.c index 748f54860c..fd5e9ea195 100644 --- a/gdk/gdkdisplay.c +++ b/gdk/gdkdisplay.c @@ -2710,6 +2710,9 @@ gdk_display_get_monitor_at_window (GdkDisplay *display, g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL); + if (window && gdk_window_is_impl_offscreen (window)) + window = gdk_offscreen_window_get_embedder (window); + class = GDK_DISPLAY_GET_CLASS (display); if (class->get_monitor_at_window) { diff --git a/gdk/gdkoffscreenwindow.c b/gdk/gdkoffscreenwindow.c index 860df11eba..4d48f55ce5 100644 --- a/gdk/gdkoffscreenwindow.c +++ b/gdk/gdkoffscreenwindow.c @@ -780,3 +780,12 @@ gdk_offscreen_window_class_init (GdkOffscreenWindowClass *klass) impl_class->delete_property = NULL; impl_class->get_scale_factor = gdk_offscreen_window_get_scale_factor; } + +gboolean +gdk_window_is_impl_offscreen (GdkWindow *window) +{ + g_return_val_if_fail (GDK_IS_WINDOW (window), FALSE); + + return GDK_IS_OFFSCREEN_WINDOW (window->impl); +} + From e1d664da630ee32c4068c8ead4101bce94e7e24a Mon Sep 17 00:00:00 2001 From: Luca Bacci Date: Wed, 13 Dec 2023 12:33:15 +0100 Subject: [PATCH 3/3] GtkMenu: Fix positioning when attached to offscreen windows In order to do that, we have to make gdk_window_is_impl_offscreen () accessible from GTK via GdkPrivateVTable. --- gdk/gdk-private.c | 1 + gdk/gdk-private.h | 2 ++ gtk/gtkmenu.c | 5 +++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/gdk/gdk-private.c b/gdk/gdk-private.c index 0a7438162c..463619bdad 100644 --- a/gdk/gdk-private.c +++ b/gdk/gdk-private.c @@ -24,6 +24,7 @@ gdk__private__ (void) gdk_profiler_start, gdk_profiler_stop, gdk_window_titlebar_gesture, + gdk_window_is_impl_offscreen, }; return &table; diff --git a/gdk/gdk-private.h b/gdk/gdk-private.h index e962fc9751..687ba061e9 100644 --- a/gdk/gdk-private.h +++ b/gdk/gdk-private.h @@ -71,6 +71,8 @@ typedef struct { gboolean (* gdk_window_titlebar_gesture) (GdkWindow *window, GdkTitlebarGesture gesture); + + gboolean (* gdk_window_is_impl_offscreen) (GdkWindow *window); } GdkPrivateVTable; GDK_AVAILABLE_IN_ALL diff --git a/gtk/gtkmenu.c b/gtk/gtkmenu.c index 3f1a7bc9fa..18bef6957d 100644 --- a/gtk/gtkmenu.c +++ b/gtk/gtkmenu.c @@ -5218,7 +5218,8 @@ gtk_menu_position (GtkMenu *menu, rect_anchor_dx = priv->rect_anchor_dx; rect_anchor_dy = priv->rect_anchor_dy; - if (priv->rect_window) + if (priv->rect_window && + !GDK_PRIVATE_CALL (gdk_window_is_impl_offscreen (priv->rect_window))) { rect_window = priv->rect_window; rect = priv->rect; @@ -5264,7 +5265,7 @@ gtk_menu_position (GtkMenu *menu, } if (rect_window != NULL && - GDK_WINDOW_TYPE (rect_window) == GDK_WINDOW_OFFSCREEN) + GDK_PRIVATE_CALL (gdk_window_is_impl_offscreen (rect_window))) { GdkWindow *effective = gdk_offscreen_window_get_embedder (rect_window);