Blob Blame History Raw
From 9e64526a0671b52cdb6b6ad567153402a85d21bf Mon Sep 17 00:00:00 2001
From: Maxim Monastirsky <momonasmon@gmail.com>
Date: Sun, 7 Feb 2016 17:53:40 +0200
Subject: [PATCH 1/8] tdf#97665 Let's hope that over activation isn't really
 needed

- MenuBarManager::Activate has a check for duplicate activation,
  which makes the second activation attempt fail. Removing this
  check or deactivating after each activation will likely affect
  performance even more, but on the other hand should solve
  lp#1296715, which was the main reason of the over activation
  in the first place. So let's activate only one menu at a time,
  and do full activation only on the initial update.

- Unfortunately the HUD activation callback doesn't work, so
  we still have to keep active status listener for all menu
  items. (Which is BTW against the recommendation in
  XPopupMenuController::updatePopupMenu IDL doc. Fortunately
  the performance problem hardly noticeable on modern hw.)

Reviewed-on: https://gerrit.libreoffice.org/22369
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Maxim Monastirsky <momonasmon@gmail.com>
(cherry picked from commit 2abdcfd641883f246fe78f2fbe38499c9382c059)

Change-Id: I96affa72412f3f38160fdca4b6efd20ca68d059f
---
 framework/source/uielement/menubarmanager.cxx | 11 ++---
 include/vcl/menu.hxx                          |  9 +---
 vcl/inc/salmenu.hxx                           |  1 +
 vcl/inc/unx/gtk/gtksalmenu.hxx                |  4 +-
 vcl/source/window/menu.cxx                    | 46 +++-----------------
 vcl/unx/gtk/gloactiongroup.cxx                |  2 +-
 vcl/unx/gtk/gtkdata.cxx                       | 18 --------
 vcl/unx/gtk/gtksalmenu.cxx                    | 62 +++++++--------------------
 8 files changed, 31 insertions(+), 122 deletions(-)

diff --git a/framework/source/uielement/menubarmanager.cxx b/framework/source/uielement/menubarmanager.cxx
index 6a368a9..8ce02c6 100644
--- a/framework/source/uielement/menubarmanager.cxx
+++ b/framework/source/uielement/menubarmanager.cxx
@@ -386,10 +386,6 @@ throw ( RuntimeException, std::exception )
     OUString aFeatureURL = Event.FeatureURL.Complete;
 
     SolarMutexGuard aSolarGuard;
-    if ( m_bHasMenuBar )
-    {
-        vcl::MenuInvalidator::Invalidated();
-    }
     {
         if ( m_bDisposed )
             return;
@@ -488,6 +484,8 @@ throw ( RuntimeException, std::exception )
                 pMenuItemHandler->xMenuItemDispatch.clear();
             }
         }
+        if ( m_bHasMenuBar && !m_bActive )
+            m_pVCLMenu->UpdateNativeMenu();
     }
 }
 
@@ -895,9 +893,8 @@ IMPL_LINK_TYPED( MenuBarManager, Activate, Menu *, pMenu, bool )
                                 if ( !bPopupMenu )
                                 {
                                     xMenuItemDispatch->addStatusListener( static_cast< XStatusListener* >( this ), aTargetURL );
-                                    xMenuItemDispatch->removeStatusListener( static_cast< XStatusListener* >( this ), aTargetURL );
-                                    if ( m_bHasMenuBar )
-                                        xMenuItemDispatch->addStatusListener( static_cast< XStatusListener* >( this ), aTargetURL );
+                                    if ( !m_bHasMenuBar )
+                                        xMenuItemDispatch->removeStatusListener( static_cast< XStatusListener* >( this ), aTargetURL );
                                 }
                             }
                             else if ( !bPopupMenu )
diff --git a/include/vcl/menu.hxx b/include/vcl/menu.hxx
index ade703b..0d6e16a 100644
--- a/include/vcl/menu.hxx
+++ b/include/vcl/menu.hxx
@@ -313,6 +313,8 @@ public:
     void RemoveDisabledEntries( bool bCheckPopups = true, bool bRemoveEmptyPopups = false );
     bool HasValidEntries( bool bCheckPopups = true );
 
+    void UpdateNativeMenu();
+
     void SetItemText( sal_uInt16 nItemId, const OUString& rStr );
     OUString GetItemText( sal_uInt16 nItemId ) const;
 
@@ -407,13 +409,6 @@ public:
 };
 
 
-namespace vcl { namespace MenuInvalidator {
-
-VCL_DLLPUBLIC void AddMenuInvalidateListener(const Link<LinkParamNone*,void>&);
-VCL_DLLPUBLIC void Invalidated();
-
-}}
-
 class VCL_DLLPUBLIC MenuBar : public Menu
 {
     Link<void*,void> maCloseHdl;
diff --git a/vcl/inc/salmenu.hxx b/vcl/inc/salmenu.hxx
index 287e19e..468994a 100644
--- a/vcl/inc/salmenu.hxx
+++ b/vcl/inc/salmenu.hxx
@@ -80,6 +80,7 @@ public:
     virtual bool ShowNativePopupMenu(FloatingWindow * pWin, const Rectangle& rRect, FloatWinPopupFlags nFlags);
     virtual bool AddMenuBarButton( const SalMenuButtonItem& ); // return false if not implemented or failure
     virtual void RemoveMenuBarButton( sal_uInt16 nId );
+    virtual void Update() {}
 
     // TODO: implement show/hide for the Win/Mac VCL native backends
     virtual void ShowItem( unsigned nPos, bool bShow ) { EnableItem( nPos, bShow ); }
diff --git a/vcl/inc/unx/gtk/gtksalmenu.hxx b/vcl/inc/unx/gtk/gtksalmenu.hxx
index 5d9c262..8df2c1d 100644
--- a/vcl/inc/unx/gtk/gtksalmenu.hxx
+++ b/vcl/inc/unx/gtk/gtksalmenu.hxx
@@ -96,11 +96,11 @@ public:
     void                        NativeSetAccelerator( unsigned nSection, unsigned nItemPos, const vcl::KeyCode& rKeyCode, const OUString& rKeyName );
 
     void                        DispatchCommand( gint itemId, const gchar* aCommand );
-    void                        Activate();
+    void                        Activate( const gchar* aMenuCommand = nullptr );
     void                        Deactivate( const gchar* aMenuCommand );
     void                        Display( bool bVisible );
     bool                        PrepUpdate();
-    void                        Update();           // Update this menu only.
+    virtual void                Update() override;  // Update this menu only.
     void                        UpdateFull();       // Update full menu hierarchy from this menu.
 };
 
diff --git a/vcl/source/window/menu.cxx b/vcl/source/window/menu.cxx
index 3a6e54c..4aa7d41 100644
--- a/vcl/source/window/menu.cxx
+++ b/vcl/source/window/menu.cxx
@@ -2314,6 +2314,12 @@ sal_uLong Menu::DeactivateMenuBar(sal_uLong nFocusId)
     return nFocusId;
 }
 
+void Menu::UpdateNativeMenu()
+{
+    if ( ImplGetSalMenu() )
+        ImplGetSalMenu()->Update();
+}
+
 void Menu::MenuBarKeyInput(const KeyEvent&)
 {
 }
@@ -3251,44 +3257,4 @@ ImplMenuDelData::~ImplMenuDelData()
         const_cast< Menu* >( mpMenu )->ImplRemoveDel( *this );
 }
 
-namespace vcl { namespace MenuInvalidator {
-
-struct MenuInvalidateListeners : public vcl::DeletionNotifier
-{
-    std::vector<Link<LinkParamNone*,void>>   m_aListeners;
-};
-
-static MenuInvalidateListeners* pMenuInvalidateListeners = nullptr;
-
-void AddMenuInvalidateListener(const Link<LinkParamNone*,void>& rLink)
-{
-    if(!pMenuInvalidateListeners)
-        pMenuInvalidateListeners = new MenuInvalidateListeners();
-    // ensure uniqueness
-    auto& rListeners = pMenuInvalidateListeners->m_aListeners;
-    if (std::find(rListeners.begin(), rListeners.end(), rLink) == rListeners.end())
-       rListeners.push_back( rLink );
-}
-
-void Invalidated()
-{
-    if(!pMenuInvalidateListeners)
-        return;
-
-    vcl::DeletionListener aDel( pMenuInvalidateListeners );
-
-    auto& rYieldListeners = pMenuInvalidateListeners->m_aListeners;
-    // Copy the list, because this can be destroyed when calling a Link...
-    std::vector<Link<LinkParamNone*,void>> aCopy( rYieldListeners );
-    for( Link<LinkParamNone*,void>& rLink : aCopy )
-    {
-        if (aDel.isDeleted()) break;
-        // check this hasn't been removed in some re-enterancy scenario fdo#47368
-        if( std::find(rYieldListeners.begin(), rYieldListeners.end(), rLink) != rYieldListeners.end() )
-            rLink.Call( nullptr );
-    }
-};
-
-} } // namespace vcl::MenuInvalidator
-
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk/gloactiongroup.cxx b/vcl/unx/gtk/gloactiongroup.cxx
index 8385388..e710809 100644
--- a/vcl/unx/gtk/gloactiongroup.cxx
+++ b/vcl/unx/gtk/gloactiongroup.cxx
@@ -201,7 +201,7 @@ g_lo_action_group_perform_submenu_action (GLOActionGroup *group,
         SAL_INFO("vcl.unity", "g_lo_action_group_perform_submenu_action on " << group << " to " << bState);
 
         if (bState)
-            pSalMenu->Activate();
+            pSalMenu->Activate (action_name);
         else
             pSalMenu->Deactivate (action_name);
     }
diff --git a/vcl/unx/gtk/gtkdata.cxx b/vcl/unx/gtk/gtkdata.cxx
index b5c64e0..9ea6dc9 100644
--- a/vcl/unx/gtk/gtkdata.cxx
+++ b/vcl/unx/gtk/gtkdata.cxx
@@ -1030,22 +1030,4 @@ void GtkSalDisplay::deregisterFrame( SalFrame* pFrame )
     SalGenericDisplay::deregisterFrame( pFrame );
 }
 
-#if GTK_CHECK_VERSION(3,0,0)
-void GtkSalDisplay::RefreshMenusUnity()
-{
-#ifdef ENABLE_GMENU_INTEGRATION
-    for(auto pSalFrame : m_aFrames) {
-        auto pGtkSalFrame( static_cast<GtkSalFrame*>(pSalFrame));
-        GtkSalMenu* pSalMenu = static_cast<GtkSalMenu*>(pGtkSalFrame->GetMenu());
-        if(pSalMenu) {
-            pSalMenu->Activate();
-            pSalMenu->UpdateFull();
-        }
-    }
-#else
-    (void) this;
-#endif
-}
-#endif
-
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/gtk/gtksalmenu.cxx b/vcl/unx/gtk/gtksalmenu.cxx
index a0cc977..fd29a25 100644
--- a/vcl/unx/gtk/gtksalmenu.cxx
+++ b/vcl/unx/gtk/gtksalmenu.cxx
@@ -372,54 +372,9 @@ void GtkSalMenu::SetSubMenu( SalMenuItem* pSalMenuItem, SalMenu* pSubMenu, unsig
     pItem->mpSubMenu = pGtkSubMenu;
 }
 
-static bool bInvalidMenus = false;
-static gboolean RefreshMenusUnity(gpointer)
-{
-    SolarMutexGuard g;
-#if GTK_CHECK_VERSION(3,0,0)
-    GetGtkSalData()->GetGtkDisplay()->RefreshMenusUnity();
-#else
-    SalDisplay* pSalDisplay = vcl_sal::getSalDisplay(GetGenericData());
-    std::list< SalFrame* >::const_iterator pSalFrame = pSalDisplay->getFrames().begin();
-    std::list< SalFrame* >::const_iterator pEndSalFrame = pSalDisplay->getFrames().end();
-    for(; pSalFrame != pEndSalFrame; ++pSalFrame) {
-        const GtkSalFrame* pGtkSalFrame = static_cast< const GtkSalFrame* >( *pSalFrame );
-        GtkSalFrame* pFrameNonConst = const_cast<GtkSalFrame*>(pGtkSalFrame);
-        GtkSalMenu* pSalMenu = static_cast<GtkSalMenu*>(pFrameNonConst->GetMenu());
-        if(pSalMenu) {
-            pSalMenu->Activate();
-            pSalMenu->UpdateFull();
-        }
-    }
-#endif
-    bInvalidMenus = false;
-    return FALSE;
-}
-
-static void RefreshMenusUnity(void*, LinkParamNone*)
-{
-    if(!bInvalidMenus) {
-        g_timeout_add(10, &RefreshMenusUnity, nullptr);
-        bInvalidMenus = true;
-    }
-}
-
-static Link<LinkParamNone*,void>* getRefreshLinkInstance()
-{
-    static Link<LinkParamNone*,void>* pLink = nullptr;
-    if(!pLink) {
-        pLink = new Link<LinkParamNone*,void>(nullptr, &RefreshMenusUnity);
-    }
-    return pLink;
-}
-
 void GtkSalMenu::SetFrame( const SalFrame* pFrame )
 {
     SolarMutexGuard aGuard;
-    {
-        vcl::MenuInvalidator::AddMenuInvalidateListener(*getRefreshLinkInstance());
-    }
-
     assert(mbMenuBar);
     SAL_INFO("vcl.unity", "GtkSalMenu set to frame");
     mpFrame = static_cast< const GtkSalFrame* >( pFrame );
@@ -674,6 +629,7 @@ void GtkSalMenu::DispatchCommand( gint itemId, const gchar *aCommand )
 void GtkSalMenu::ActivateAllSubmenus(MenuBar* pMenuBar)
 {
     pMenuBar->HandleMenuActivateEvent(mpVCLMenu);
+    pMenuBar->HandleMenuDeActivateEvent(mpVCLMenu);
     for ( size_t nPos = 0; nPos < maItems.size(); nPos++ )
     {
         GtkSalMenuItem *pSalItem = maItems[ nPos ];
@@ -685,11 +641,23 @@ void GtkSalMenu::ActivateAllSubmenus(MenuBar* pMenuBar)
     }
 }
 
-void GtkSalMenu::Activate()
+void GtkSalMenu::Activate( const gchar* aMenuCommand )
 {
     if ( !mbMenuBar )
         return;
-    ActivateAllSubmenus(static_cast<MenuBar*>(mpVCLMenu));
+
+    if ( !aMenuCommand ) {
+        ActivateAllSubmenus( static_cast< MenuBar* >( mpVCLMenu ) );
+        return;
+    }
+
+    GtkSalMenu* pSalSubMenu = GetMenuForItemCommand( const_cast<gchar*>(aMenuCommand), TRUE );
+
+    if ( pSalSubMenu != nullptr ) {
+        MenuBar* pMenuBar = static_cast< MenuBar* >( mpVCLMenu );
+        pMenuBar->HandleMenuActivateEvent( pSalSubMenu->mpVCLMenu );
+        pSalSubMenu->Update();
+    }
 }
 
 void GtkSalMenu::Deactivate( const gchar* aMenuCommand )
-- 
2.7.1