vcl/unx/gtk3/gtkinst.cxx | 77 ++++++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 37 deletions(-)
New commits: commit 601dc3ef9bd74b1948274c104c6c2ec877bc812c Author: Caolán McNamara <caolan.mcnam...@collabora.com> AuthorDate: Sun Mar 31 11:32:22 2024 +0100 Commit: Caolán McNamara <caolan.mcnam...@collabora.com> CommitDate: Sun Mar 31 18:00:16 2024 +0200 Resolves: tdf#152438 constrain popups from MenuButtons with toplevel parent if the toplevel parent is the application window, then under wayland constrain the popup within the toplevel window, but allow it to escape if the parent isn't the application, e.g. a dialog Change-Id: I8d5c423a2c8e034464f110e51df04dee587f40dd Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165590 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx index f966496b9ff7..ea58dd62b659 100644 --- a/vcl/unx/gtk3/gtkinst.cxx +++ b/vcl/unx/gtk3/gtkinst.cxx @@ -10532,6 +10532,37 @@ void MoveWindowContentsToPopover(GtkWindow* pMenuHack, GtkWidget* pPopover, GtkW } } +// tdf#153885/tdf#152438 for wayland if the popover window is the application +// window, constrain it within the application window so it won't be cut off +// screen. Leave dialog hosted ones alone, like format, watermark, which are +// likely presented in the middle of the screen and are too small to constrain +// the popover inside. +void ConstrainApplicationWindowPopovers(GtkWidget* pItem) +{ +#if defined(GDK_WINDOWING_WAYLAND) + GdkDisplay *pDisplay = gtk_widget_get_display(pItem); + if (DLSYM_GDK_IS_WAYLAND_DISPLAY(pDisplay) && GTK_IS_MENU_BUTTON(pItem)) + { + GtkMenuButton* pMenuButton = GTK_MENU_BUTTON(pItem); + if (GtkPopover* pPopover = gtk_menu_button_get_popover(pMenuButton)) + { + if (gtk_popover_get_constrain_to(pPopover) == GTK_POPOVER_CONSTRAINT_NONE) + { + GtkWidget* pTopLevel = widget_get_toplevel(pItem); + GtkSalFrame* pFrame = pTopLevel ? GtkSalFrame::getFromWindow(pTopLevel) : nullptr; + if (pFrame) + { + // the toplevel is an application window + gtk_popover_set_constrain_to(pPopover, GTK_POPOVER_CONSTRAINT_WINDOW); + } + } + } + } +#else + (void)pItem; +#endif +} + #endif /* four types of uses of this @@ -10573,9 +10604,14 @@ private: #endif #if !GTK_CHECK_VERSION(4, 0, 0) - static void signalMenuButtonToggled(GtkWidget*, gpointer widget) + static void signalMenuButtonToggled(GtkWidget* pItem, gpointer widget) { GtkInstanceMenuButton* pThis = static_cast<GtkInstanceMenuButton*>(widget); + if (!pThis->m_pMenuHack) + { + ConstrainApplicationWindowPopovers(pItem); + return; + } SolarMutexGuard aGuard; pThis->menu_toggled(); } @@ -10584,8 +10620,6 @@ private: #if !GTK_CHECK_VERSION(4, 0, 0) void menu_toggled() { - if (!m_pMenuHack) - return; if (!get_active()) { m_nButtonPressSeen = false; @@ -10916,6 +10950,8 @@ public: return; } + m_nSignalId = g_signal_connect(GTK_TOGGLE_BUTTON(m_pMenuButton), "toggled", G_CALLBACK(signalMenuButtonToggled), this); + if (!m_pMenuHack) { //under wayland a Popover will work to "escape" the parent dialog, not @@ -10928,7 +10964,6 @@ public: // See writer "format, watermark" for true here. Can't interact with the replacement popover otherwise. gtk_window_set_modal(m_pMenuHack, true); gtk_window_set_resizable(m_pMenuHack, false); - m_nSignalId = g_signal_connect(GTK_TOGGLE_BUTTON(m_pMenuButton), "toggled", G_CALLBACK(signalMenuButtonToggled), this); g_signal_connect(m_pMenuHack, "key-press-event", G_CALLBACK(keyPress), this); g_signal_connect(m_pMenuHack, "grab-broken-event", G_CALLBACK(signalGrabBroken), this); g_signal_connect(m_pMenuHack, "button-press-event", G_CALLBACK(signalButtonPress), this); @@ -11794,38 +11829,6 @@ public: #endif return eRet; } - - // tdf#153885 for wayland if the popover window is the application - // window, constrain it within the application window so it won't - // be cut off screen. Leave dialog hosted ones alone, like - // format, watermark, which are likely presented in the middle - // of the screen and are too small to constrain the popover inside. - void ConstrainApplicationWindowPopovers(GtkToggleButton* pItem) - { -#if defined(GDK_WINDOWING_WAYLAND) - GdkDisplay *pDisplay = gtk_widget_get_display(GTK_WIDGET(pItem)); - if (DLSYM_GDK_IS_WAYLAND_DISPLAY(pDisplay) && GTK_IS_MENU_BUTTON(pItem)) - { - GtkMenuButton* pMenuButton = GTK_MENU_BUTTON(pItem); - if (GtkPopover* pPopover = gtk_menu_button_get_popover(pMenuButton)) - { - if (gtk_popover_get_constrain_to(pPopover) == GTK_POPOVER_CONSTRAINT_NONE) - { - GtkWidget* pTopLevel = widget_get_toplevel(GTK_WIDGET(pItem)); - GtkSalFrame* pFrame = pTopLevel ? GtkSalFrame::getFromWindow(pTopLevel) : nullptr; - if (pFrame) - { - // the toplevel is an application window - gtk_popover_set_constrain_to(pPopover, GTK_POPOVER_CONSTRAINT_WINDOW); - } - } - } - } -#else - (void)pItem; -#endif - } - #endif } @@ -11985,7 +11988,7 @@ private: static void signalItemToggled(GtkToggleButton* pItem, gpointer widget) { #if !GTK_CHECK_VERSION(4, 0, 0) - ConstrainApplicationWindowPopovers(pItem); + ConstrainApplicationWindowPopovers(GTK_WIDGET(pItem)); #endif GtkInstanceToolbar* pThis = static_cast<GtkInstanceToolbar*>(widget); SolarMutexGuard aGuard;