[Libreoffice-commits] core.git: include/vcl vcl/inc vcl/source vcl/unx

Maxim Monastirsky momonasmon at gmail.com
Wed Jun 13 22:47:00 UTC 2018


 include/vcl/toolbox.hxx        |    1 
 vcl/inc/toolbox.h              |    2 
 vcl/source/window/toolbox.cxx  |    4 -
 vcl/source/window/toolbox2.cxx |   27 ++----------
 vcl/unx/gtk/gtksalmenu.cxx     |   87 ++++++++++++++++++++++++++++-------------
 5 files changed, 65 insertions(+), 56 deletions(-)

New commits:
commit c3e552ac25be001a623469c549ee8d0719b98133
Author: Maxim Monastirsky <momonasmon at gmail.com>
Date:   Tue Jun 12 02:26:28 2018 +0300

    wayland: Make popup menus not show off-screen
    
    Depends on gtk 3.22 for gtk_menu_popup_at_rect.
    
    Had to rework the toolbar context menu to not execute async,
    as otherwise it just closes immediately. (Basically it's same
    as rhbz#1342823, except that I couldn't find a way to feed
    gtk_menu_popup_at_rect with the correct timestamp).
    
    Change-Id: I779d8803c80314d93a342f1294c7280f1adf4c98
    Reviewed-on: https://gerrit.libreoffice.org/55772
    Tested-by: Jenkins <ci at libreoffice.org>
    Reviewed-by: Maxim Monastirsky <momonasmon at gmail.com>

diff --git a/include/vcl/toolbox.hxx b/include/vcl/toolbox.hxx
index 7944fd950a82..58bf32bb0e26 100644
--- a/include/vcl/toolbox.hxx
+++ b/include/vcl/toolbox.hxx
@@ -210,7 +210,6 @@ private:
     SAL_DLLPRIVATE bool            ImplHasExternalMenubutton();
     SAL_DLLPRIVATE void            ImplDrawFloatwinBorder(vcl::RenderContext& rRenderContext, ImplToolItem const * pItem );
 
-    DECL_DLLPRIVATE_LINK(    ImplCallExecuteCustomMenu, void*, void );
     DECL_DLLPRIVATE_LINK(    ImplUpdateHdl, Timer*, void );
     DECL_DLLPRIVATE_LINK(    ImplCustomMenuListener, VclMenuEvent&, void );
     DECL_DLLPRIVATE_LINK(    ImplDropdownLongClickHdl, Timer*, void );
diff --git a/vcl/inc/toolbox.h b/vcl/inc/toolbox.h
index 9d928ce6a1ba..17c5585ef490 100644
--- a/vcl/inc/toolbox.h
+++ b/vcl/inc/toolbox.h
@@ -129,9 +129,7 @@ struct ImplToolBoxPrivateData
 
     // the optional custom menu
     VclPtr<PopupMenu>   mpMenu;
-    tools::Rectangle       maMenuRect;
     ToolBoxMenuType maMenuType;
-    ImplSVEvent *   mnEventId;
 
     // called when menu button is clicked and before the popup menu is executed
     Link<ToolBox *, void> maMenuButtonHdl;
diff --git a/vcl/source/window/toolbox.cxx b/vcl/source/window/toolbox.cxx
index 2df527a8cbd4..d1007d4badcd 100644
--- a/vcl/source/window/toolbox.cxx
+++ b/vcl/source/window/toolbox.cxx
@@ -1341,10 +1341,6 @@ ToolBox::~ToolBox()
 
 void ToolBox::dispose()
 {
-    // custom menu event still running?
-    if( mpData && mpData->mnEventId )
-        Application::RemoveUserEvent( mpData->mnEventId );
-
     // #103005# make sure our activate/deactivate balance is right
     while( mnActivateCount > 0 )
         Deactivate();
diff --git a/vcl/source/window/toolbox2.cxx b/vcl/source/window/toolbox2.cxx
index cc86b0d9a0f9..ab4c90ece48f 100644
--- a/vcl/source/window/toolbox2.cxx
+++ b/vcl/source/window/toolbox2.cxx
@@ -48,7 +48,6 @@ ImplToolBoxPrivateData::ImplToolBoxPrivateData() :
 {
     meButtonSize = ToolBoxButtonSize::DontCare;
     mpMenu = VclPtr<PopupMenu>::Create();
-    mnEventId = nullptr;
 
     maMenuType = ToolBoxMenuType::NONE;
     maMenubuttonItem.maItemSize = Size( TB_MENUBUTTON_SIZE+TB_MENUBUTTON_OFFSET, TB_MENUBUTTON_SIZE+TB_MENUBUTTON_OFFSET );
@@ -1621,9 +1620,6 @@ namespace
 void ToolBox::UpdateCustomMenu()
 {
     // fill clipped items into menu
-    if( !IsMenuEnabled() )
-        return;
-
     PopupMenu *pMenu = GetMenu();
     pMenu->Clear();
 
@@ -1680,12 +1676,13 @@ IMPL_LINK( ToolBox, ImplCustomMenuListener, VclMenuEvent&, rEvent, void )
     }
 }
 
-IMPL_LINK_NOARG(ToolBox, ImplCallExecuteCustomMenu, void*, void)
+void ToolBox::ExecuteCustomMenu( const tools::Rectangle& rRect )
 {
-    mpData->mnEventId = nullptr;
-    if( !IsMenuEnabled() )
+    if ( !IsMenuEnabled() || ImplIsInPopupMode() )
         return;
 
+    UpdateCustomMenu();
+
     if( GetMenuType() & ToolBoxMenuType::Customize )
         // call button handler to allow for menu customization
         mpData->maMenuButtonHdl.Call( this );
@@ -1700,8 +1697,7 @@ IMPL_LINK_NOARG(ToolBox, ImplCallExecuteCustomMenu, void*, void)
     bool bBorderDel = false;
 
     VclPtr<vcl::Window> pWin = this;
-    tools::Rectangle aMenuRect = mpData->maMenuRect;
-    mpData->maMenuRect.SetEmpty();
+    tools::Rectangle aMenuRect = rRect;
     VclPtr<ImplBorderWindow> pBorderWin;
     if( aMenuRect.IsEmpty() && IsFloatingMode() )
     {
@@ -1733,19 +1729,6 @@ IMPL_LINK_NOARG(ToolBox, ImplCallExecuteCustomMenu, void*, void)
 
     if( uId )
         GrabFocusToDocument();
-
-}
-
-void ToolBox::ExecuteCustomMenu( const tools::Rectangle& rRect )
-{
-    if ( IsMenuEnabled() && !ImplIsInPopupMode() )
-    {
-        UpdateCustomMenu();
-        // handle custom menu asynchronously
-        // to avoid problems if the toolbox is closed during menu execute
-        mpData->maMenuRect = rRect;
-        mpData->mnEventId = Application::PostUserEvent( LINK( this, ToolBox, ImplCallExecuteCustomMenu ), nullptr, true );
-    }
 }
 
 // checks override first, useful during calculation of sizes
diff --git a/vcl/unx/gtk/gtksalmenu.cxx b/vcl/unx/gtk/gtksalmenu.cxx
index 8fd2ea29636a..84add236d0be 100644
--- a/vcl/unx/gtk/gtksalmenu.cxx
+++ b/vcl/unx/gtk/gtksalmenu.cxx
@@ -410,33 +410,9 @@ bool GtkSalMenu::ShowNativePopupMenu(FloatingWindow* pWin, const tools::Rectangl
                                      FloatWinPopupFlags nFlags)
 {
 #if GTK_CHECK_VERSION(3,0,0)
-    guint nButton;
-    guint32 nTime;
-
-    //typically there is an event, and we can then distinguish if this was
-    //launched from the keyboard (gets auto-mnemoniced) or the mouse (which
-    //doesn't)
-    GdkEvent *pEvent = gtk_get_current_event();
-    if (pEvent)
-    {
-        gdk_event_get_button(pEvent, &nButton);
-        nTime = gdk_event_get_time(pEvent);
-    }
-    else
-    {
-        nButton = 0;
-        nTime = GtkSalFrame::GetLastInputEventTime();
-    }
-
     VclPtr<vcl::Window> xParent = pWin->ImplGetWindowImpl()->mpRealParent;
     mpFrame = static_cast<GtkSalFrame*>(xParent->ImplGetFrame());
 
-    // do the same strange semantics as vcl popup windows to arrive at a frame geometry
-    // in mirrored UI case; best done by actually executing the same code
-    sal_uInt16 nArrangeIndex;
-    Point aPos = FloatingWindow::ImplCalcPos(pWin, rRect, nFlags, nArrangeIndex);
-    aPos = FloatingWindow::ImplConvertToAbsPos(xParent, aPos);
-
     GLOActionGroup* pActionGroup = g_lo_action_group_new();
     mpActionGroup = G_ACTION_GROUP(pActionGroup);
     mpMenuModel = G_MENU_MODEL(g_lo_menu_new());
@@ -445,7 +421,6 @@ bool GtkSalMenu::ShowNativePopupMenu(FloatingWindow* pWin, const tools::Rectangl
 
     GtkWidget *pWidget = gtk_menu_new_from_model(mpMenuModel);
     gtk_menu_attach_to_widget(GTK_MENU(pWidget), mpFrame->getMouseEventWidget(), nullptr);
-
     gtk_widget_insert_action_group(mpFrame->getMouseEventWidget(), "win", mpActionGroup);
 
     //run in a sub main loop because we need to keep vcl PopupMenu alive to use
@@ -454,8 +429,66 @@ bool GtkSalMenu::ShowNativePopupMenu(FloatingWindow* pWin, const tools::Rectangl
     //until the gtk menu is destroyed
     GMainLoop* pLoop = g_main_loop_new(nullptr, true);
     g_signal_connect_swapped(G_OBJECT(pWidget), "deactivate", G_CALLBACK(g_main_loop_quit), pLoop);
-    gtk_menu_popup(GTK_MENU(pWidget), nullptr, nullptr, MenuPositionFunc,
-                   &aPos, nButton, nTime);
+
+#if GTK_CHECK_VERSION(3,22,0)
+    if (gtk_check_version(3, 22, 0) == nullptr)
+    {
+        GdkGravity rect_anchor = GDK_GRAVITY_SOUTH_WEST, menu_anchor = GDK_GRAVITY_NORTH_WEST;
+
+        if (nFlags & FloatWinPopupFlags::Left)
+        {
+            rect_anchor = GDK_GRAVITY_NORTH_WEST;
+            menu_anchor = GDK_GRAVITY_NORTH_EAST;
+        }
+        else if (nFlags & FloatWinPopupFlags::Up)
+        {
+            rect_anchor = GDK_GRAVITY_NORTH_WEST;
+            menu_anchor = GDK_GRAVITY_SOUTH_WEST;
+        }
+        else if (nFlags & FloatWinPopupFlags::Right)
+        {
+            rect_anchor = GDK_GRAVITY_NORTH_EAST;
+        }
+
+        tools::Rectangle aFloatRect = FloatingWindow::ImplConvertToAbsPos(xParent, rRect);
+        aFloatRect.Move(-mpFrame->maGeometry.nX, -mpFrame->maGeometry.nY);
+        GdkRectangle rect {static_cast<int>(aFloatRect.Left()), static_cast<int>(aFloatRect.Top()),
+                           static_cast<int>(aFloatRect.GetWidth()), static_cast<int>(aFloatRect.GetHeight())};
+
+        GdkWindow* gdkWindow = widget_get_window(mpFrame->getMouseEventWidget());
+        gtk_menu_popup_at_rect(GTK_MENU(pWidget), gdkWindow, &rect, rect_anchor, menu_anchor, nullptr);
+    }
+    else
+#endif
+    {
+        guint nButton;
+        guint32 nTime;
+
+        //typically there is an event, and we can then distinguish if this was
+        //launched from the keyboard (gets auto-mnemoniced) or the mouse (which
+        //doesn't)
+        GdkEvent *pEvent = gtk_get_current_event();
+        if (pEvent)
+        {
+            gdk_event_get_button(pEvent, &nButton);
+            nTime = gdk_event_get_time(pEvent);
+        }
+        else
+        {
+            nButton = 0;
+            nTime = GtkSalFrame::GetLastInputEventTime();
+        }
+
+        // do the same strange semantics as vcl popup windows to arrive at a frame geometry
+        // in mirrored UI case; best done by actually executing the same code
+        sal_uInt16 nArrangeIndex;
+        Point aPos = FloatingWindow::ImplCalcPos(pWin, rRect, nFlags, nArrangeIndex);
+        aPos = FloatingWindow::ImplConvertToAbsPos(xParent, aPos);
+
+        gtk_menu_popup(GTK_MENU(pWidget), nullptr, nullptr, MenuPositionFunc,
+                       &aPos, nButton, nTime);
+    }
+
     if (g_main_loop_is_running(pLoop))
     {
         gdk_threads_leave();


More information about the Libreoffice-commits mailing list