vcl/unx/gtk3/gtkinst.cxx |   67 ++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 60 insertions(+), 7 deletions(-)

New commits:
commit 513b54df70b5b9cde8d6ca2304378949256eea1d
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Fri Jun 11 14:03:02 2021 +0100
Commit:     Caolán McNamara <caol...@redhat.com>
CommitDate: Fri Jun 11 17:22:32 2021 +0200

    gtk4: support separators via manipulating menu sections
    
    Change-Id: Iaade04dd5a4fa89ef74a22a19ebe5e37655fc61a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/117058
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caol...@redhat.com>

diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx
index acc35bc28542..dbdd56994b71 100644
--- a/vcl/unx/gtk3/gtkinst.cxx
+++ b/vcl/unx/gtk3/gtkinst.cxx
@@ -9610,6 +9610,38 @@ public:
 
 #endif
 
+#if GTK_CHECK_VERSION(4, 0, 0)
+    /* LibreOffice likes to think of separators between menu entries, while 
gtk likes
+       to think of sections of menus with separators drawn between sections. 
We always
+       arrange to have a section in a menua so toplevel menumodels comprise of
+       sections and we move entries between sections on pretending to insert 
separators */
+    static std::pair<GMenuModel*, int> get_section_and_pos_for(GMenuModel* 
pMenuModel, int pos)
+    {
+        int nSectionCount = g_menu_model_get_n_items(pMenuModel);
+        assert(nSectionCount);
+
+        GMenuModel* pSectionModel = nullptr;
+        int nIndexWithinSection = 0;
+
+        int nExternalPos = 0;
+        for (int nSection = 0; nSection < nSectionCount; ++nSection)
+        {
+            pSectionModel = g_menu_model_get_item_link(pMenuModel, nSection, 
G_MENU_LINK_SECTION);
+            assert(pSectionModel);
+            int nCount = g_menu_model_get_n_items(pSectionModel);
+            for (nIndexWithinSection = 0; nIndexWithinSection < nCount; 
++nIndexWithinSection)
+            {
+                if (pos == nExternalPos)
+                    break;
+                ++nExternalPos;
+            }
+            ++nExternalPos;
+        }
+
+        return std::make_pair(pSectionModel, nIndexWithinSection);
+    }
+#endif
+
     virtual void insert_item(int pos, const OUString& rId, const OUString& 
rStr,
                         const OUString* pIconName, VirtualDevice* 
pImageSurface, TriState eCheckRadioFalse) override
     {
@@ -9623,7 +9655,8 @@ public:
                                      
gtk_popover_menu_get_menu_model(GTK_POPOVER_MENU(pPopover)) :
                                      nullptr)
         {
-            GMenu* pMenu = G_MENU(pMenuModel);
+            auto aSectionAndPos = get_section_and_pos_for(pMenuModel, pos);
+            GMenu* pMenu = G_MENU(aSectionAndPos.first);
             // action with a target value ... the action name and target value 
are separated by a double
             // colon ... For example: "app.action::target"
             OUString sActionAndTarget;
@@ -9631,7 +9664,7 @@ public:
                 sActionAndTarget = "menu.normal." + rId + "::" + rId;
             else
                 sActionAndTarget = "menu.radio." + rId + "::" + rId;
-            g_menu_insert(pMenu, pos, MapToGtkAccelerator(rStr).getStr(), 
sActionAndTarget.toUtf8().getStr());
+            g_menu_insert(pMenu, aSectionAndPos.second, 
MapToGtkAccelerator(rStr).getStr(), sActionAndTarget.toUtf8().getStr());
 
             assert(eCheckRadioFalse == TRISTATE_INDET); // come back to this 
later
 
@@ -9646,15 +9679,33 @@ public:
 #if !GTK_CHECK_VERSION(4, 0, 0)
         MenuHelper::insert_separator(pos, rId);
 #else
-        (void)rId;
-
         GtkPopover* pPopover = gtk_menu_button_get_popover(m_pMenuButton);
         if (GMenuModel* pMenuModel = GTK_IS_POPOVER_MENU(pPopover) ?
                                      
gtk_popover_menu_get_menu_model(GTK_POPOVER_MENU(pPopover)) :
                                      nullptr)
         {
-            GMenu* pMenu = G_MENU(pMenuModel);
-            g_menu_insert(pMenu, pos, "SEPARATOR", "menu.action");
+            auto aSectionAndPos = get_section_and_pos_for(pMenuModel, pos);
+
+            for (int nSection = 0, nSectionCount = 
g_menu_model_get_n_items(pMenuModel); nSection < nSectionCount; ++nSection)
+            {
+                GMenuModel* pSectionModel = 
g_menu_model_get_item_link(pMenuModel, nSection, G_MENU_LINK_SECTION);
+                assert(pSectionModel);
+                if (aSectionAndPos.first == pSectionModel)
+                {
+                    GMenu* pNewSection = g_menu_new();
+                    GMenuItem* pSectionItem = g_menu_item_new_section(nullptr, 
G_MENU_MODEL(pNewSection));
+                    OUString sActionAndTarget = "menu.separator." + rId + "::" 
+ rId;
+                    g_menu_item_set_detailed_action(pSectionItem, 
sActionAndTarget.toUtf8().getStr());
+                    g_menu_insert_item(G_MENU(pMenuModel), nSection + 1, 
pSectionItem);
+                    int nOldSectionCount = 
g_menu_model_get_n_items(pSectionModel);
+                    for (int i = nOldSectionCount - 1; i >= 
aSectionAndPos.second; --i)
+                    {
+                        GMenuItem* pMenuItem = 
g_menu_item_new_from_model(pSectionModel, i);
+                        g_menu_prepend_item(pNewSection, pMenuItem);
+                        g_menu_remove(G_MENU(pSectionModel), i);
+                    }
+                }
+            }
         }
 
 #endif
@@ -9678,7 +9729,9 @@ public:
                                      
gtk_popover_menu_get_menu_model(GTK_POPOVER_MENU(pPopover)) :
                                      nullptr)
         {
-            g_menu_remove_all(G_MENU(pMenuModel));
+            GMenu* pMenu = G_MENU(pMenuModel);
+            g_menu_remove_all(pMenu);
+            g_menu_insert_section(pMenu, 0, nullptr, 
G_MENU_MODEL(g_menu_new()));
             update_action_group_from_popover_model();
         }
 #else
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to