vcl/unx/gtk3/gtkinst.cxx     |   22 +++++-
 vcl/unx/gtk4/convert3to4.cxx |  153 +++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 169 insertions(+), 6 deletions(-)

New commits:
commit 191a5bc8bce278d93d8e52d83771fcf59a0fbe9f
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Fri Jun 4 09:08:04 2021 +0100
Commit:     Caolán McNamara <caol...@redhat.com>
CommitDate: Fri Jun 4 13:07:27 2021 +0200

    gtk4: convert GtkMenu into GtkPopoverMenu
    
    and hook it up for GtkMenuButton
    
    Change-Id: I79efe7e25693deb40b59e960abc21807c9269172
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116687
    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 fd5470630762..9615c36dac09 100644
--- a/vcl/unx/gtk3/gtkinst.cxx
+++ b/vcl/unx/gtk3/gtkinst.cxx
@@ -9419,6 +9419,17 @@ public:
         (void)pMenuAlign;
 #endif
         m_pBox = formatMenuButton(m_pLabel);
+
+#if GTK_CHECK_VERSION(4, 0, 0)
+        static GActionEntry entries[] =
+        {
+            { "action", action_activated, "s", nullptr, nullptr }
+        };
+
+        GActionGroup* pActions = G_ACTION_GROUP(g_simple_action_group_new());
+        g_action_map_add_action_entries(G_ACTION_MAP(pActions), entries, 
SAL_N_ELEMENTS(entries), this);
+        gtk_widget_insert_action_group(GTK_WIDGET(m_pMenuButton), "menu", 
pActions);
+#endif
     }
 
     virtual void set_size_request(int nWidth, int nHeight) override
@@ -9599,7 +9610,16 @@ public:
 #endif
     }
 
-#if !GTK_CHECK_VERSION(4, 0, 0)
+#if GTK_CHECK_VERSION(4, 0, 0)
+    static void action_activated(GSimpleAction*, GVariant* pParameter, 
gpointer widget)
+    {
+        gsize nLength;
+        const gchar* pStr = g_variant_get_string(pParameter, &nLength);
+        OString aStr(pStr, nLength);
+        GtkInstanceMenuButton* pThis = 
static_cast<GtkInstanceMenuButton*>(widget);
+        pThis->signal_selected(aStr);
+    }
+#else
     virtual void signal_activate(GtkMenuItem* pItem) override
     {
         signal_selected(::get_buildable_id(GTK_BUILDABLE(pItem)));
diff --git a/vcl/unx/gtk4/convert3to4.cxx b/vcl/unx/gtk4/convert3to4.cxx
index 1c0ba41f585b..c2c2872b0897 100644
--- a/vcl/unx/gtk4/convert3to4.cxx
+++ b/vcl/unx/gtk4/convert3to4.cxx
@@ -113,6 +113,106 @@ void AddBorderAsMargins(const 
css::uno::Reference<css::xml::dom::XNode>& xNode,
     xNode->insertBefore(CreateProperty(xDoc, "margin-start", rBorderWidth), 
xMarginEnd);
 }
 
+css::uno::Reference<css::xml::dom::XNode>
+ConvertMenu(const css::uno::Reference<css::xml::dom::XNode>& xMenu,
+            const css::uno::Reference<css::xml::dom::XNode>& xNode)
+{
+    css::uno::Reference<css::xml::dom::XNode> xPropertyLabel;
+
+    css::uno::Reference<css::xml::dom::XNode> xChild = xNode->getFirstChild();
+    while (xChild.is())
+    {
+        if (xChild->getNodeName() == "property")
+        {
+            css::uno::Reference<css::xml::dom::XNamedNodeMap> xMap = 
xChild->getAttributes();
+            css::uno::Reference<css::xml::dom::XNode> xName = 
xMap->getNamedItem("name");
+            OUString sName(xName->getNodeValue().replace('_', '-'));
+
+            if (sName == "label")
+            {
+                xPropertyLabel = xChild;
+            }
+        }
+
+        auto xNextChild = xChild->getNextSibling();
+
+        css::uno::Reference<css::xml::dom::XNode> xChildPropertyLabel;
+        if (xChild->hasChildNodes())
+        {
+            xChildPropertyLabel = ConvertMenu(xMenu, xChild);
+        }
+
+        if (xChild->getNodeName() == "object")
+        {
+            auto xDoc = xChild->getOwnerDocument();
+
+            css::uno::Reference<css::xml::dom::XNamedNodeMap> xMap = 
xChild->getAttributes();
+            css::uno::Reference<css::xml::dom::XNode> xClass = 
xMap->getNamedItem("class");
+            OUString sClass(xClass->getNodeValue());
+
+            if (sClass == "GtkMenuItem")
+            {
+                /*
+                  <item>
+                    <attribute name='label' 
translatable='yes'>whatever</attribute>
+                    <attribute name='action'>menu.action</attribute>
+                    <attribute name='target'>id</attribute>
+                  </item>
+                */
+                css::uno::Reference<css::xml::dom::XElement> xItem = 
xDoc->createElement("item");
+                xMenu->appendChild(xItem);
+
+                if (xChildPropertyLabel)
+                {
+                    css::uno::Reference<css::xml::dom::XElement> 
xChildPropertyElem(
+                        xChildPropertyLabel, css::uno::UNO_QUERY_THROW);
+
+                    css::uno::Reference<css::xml::dom::XElement> xLabelAttr
+                        = xDoc->createElement("attribute");
+
+                    css::uno::Reference<css::xml::dom::XNamedNodeMap> xLabelMap
+                        = xChildPropertyLabel->getAttributes();
+                    while (xLabelMap->getLength())
+                    {
+                        css::uno::Reference<css::xml::dom::XAttr> 
xAttr(xLabelMap->item(0),
+                                                                        
css::uno::UNO_QUERY_THROW);
+                        xLabelAttr->setAttributeNode(
+                            xChildPropertyElem->removeAttributeNode(xAttr));
+                    }
+                    xLabelAttr->appendChild(
+                        
xChildPropertyLabel->removeChild(xChildPropertyLabel->getFirstChild()));
+
+                    
xChildPropertyLabel->getParentNode()->removeChild(xChildPropertyLabel);
+                    xItem->appendChild(xLabelAttr);
+                }
+
+                css::uno::Reference<css::xml::dom::XElement> xActionAttr
+                    = xDoc->createElement("attribute");
+                css::uno::Reference<css::xml::dom::XAttr> xActionName
+                    = xDoc->createAttribute("name");
+                xActionName->setValue("action");
+                xActionAttr->setAttributeNode(xActionName);
+                xActionAttr->appendChild(xDoc->createTextNode("menu.action"));
+                xItem->appendChild(xActionAttr);
+
+                css::uno::Reference<css::xml::dom::XElement> xTargetAttr
+                    = xDoc->createElement("attribute");
+                css::uno::Reference<css::xml::dom::XAttr> xTargetName
+                    = xDoc->createAttribute("name");
+                xTargetName->setValue("target");
+                xTargetAttr->setAttributeNode(xTargetName);
+                css::uno::Reference<css::xml::dom::XNode> xId = 
xMap->getNamedItem("id");
+                
xTargetAttr->appendChild(xDoc->createTextNode(xId->getNodeValue()));
+                xItem->appendChild(xTargetAttr);
+            }
+        }
+
+        xChild = xNextChild;
+    }
+
+    return xPropertyLabel;
+}
+
 struct ConvertResult
 {
     bool m_bChildCanFocus;
@@ -380,6 +480,18 @@ ConvertResult Convert3To4(const 
css::uno::Reference<css::xml::dom::XNode>& xNode
                 }
             }
 
+            if (sName == "popup")
+            {
+                if (GetParentObjectType(xChild) == "GtkMenuButton")
+                {
+                    OUString sMenuName = 
xChild->getFirstChild()->getNodeValue();
+                    auto xDoc = xChild->getOwnerDocument();
+                    auto xPopover = CreateProperty(xDoc, "popover", sMenuName);
+                    xChild->getParentNode()->insertBefore(xPopover, xChild);
+                    xRemoveList.push_back(xChild);
+                }
+            }
+
             if (sName == "image")
             {
                 if (GetParentObjectType(xChild) == "GtkButton")
@@ -609,11 +721,11 @@ ConvertResult Convert3To4(const 
css::uno::Reference<css::xml::dom::XNode>& xNode
             auto xInternalChildCandidate = xChild->getParentNode();
             css::uno::Reference<css::xml::dom::XNamedNodeMap> 
xInternalChildCandidateMap
                 = xInternalChildCandidate->getAttributes();
-            css::uno::Reference<css::xml::dom::XNode> xId
+            css::uno::Reference<css::xml::dom::XNode> xInternalChild
                 = xInternalChildCandidateMap->getNamedItem("internal-child");
 
             // turn default gtk3 invisibility for widget objects into explicit 
invisible, but ignore internal-children
-            if (!bChildHasVisible && !xId)
+            if (!bChildHasVisible && !xInternalChild)
             {
                 if (sClass == "GtkBox" || sClass == "GtkButton" || sClass == 
"GtkCalendar"
                     || sClass == "GtkCheckButton" || sClass == "GtkRadioButton"
@@ -640,7 +752,8 @@ ConvertResult Convert3To4(const 
css::uno::Reference<css::xml::dom::XNode>& xNode
 
             if (sClass == "GtkButtonBox")
             {
-                if (xId && xId->getNodeValue() == "action_area" && 
!ToplevelIsMessageDialog(xChild))
+                if (xInternalChild && xInternalChild->getNodeValue() == 
"action_area"
+                    && !ToplevelIsMessageDialog(xChild))
                 {
                     xClass->setNodeValue("GtkHeaderBar");
                     auto xSpacingNode = CreateProperty(xDoc, 
"show-title-buttons", "False");
@@ -783,6 +896,36 @@ ConvertResult Convert3To4(const 
css::uno::Reference<css::xml::dom::XNode>& xNode
                 else
                     xChild->appendChild(xVisible);
             }
+            else if (sClass == "GtkMenu")
+            {
+                css::uno::Reference<css::xml::dom::XNode> xId = 
xMap->getNamedItem("id");
+                OUString sId(xId->getNodeValue() + "-menu-model");
+
+                // <menu id='menubar'>
+                css::uno::Reference<css::xml::dom::XElement> xMenu = 
xDoc->createElement("menu");
+                css::uno::Reference<css::xml::dom::XAttr> xIdAttr = 
xDoc->createAttribute("id");
+                xIdAttr->setValue(sId);
+                xMenu->setAttributeNode(xIdAttr);
+                xChild->getParentNode()->insertBefore(xMenu, xChild);
+
+                ConvertMenu(xMenu, xChild);
+
+                // now remove GtkMenu contents
+                while (true)
+                {
+                    auto xFirstChild = xChild->getFirstChild();
+                    if (!xFirstChild.is())
+                        break;
+                    xChild->removeChild(xFirstChild);
+                }
+
+                // change to GtkPopoverMenu
+                xClass->setNodeValue("GtkPopoverMenu");
+
+                // <property name="menu-model">
+                xChild->appendChild(CreateProperty(xDoc, "menu-model", sId));
+                xChild->appendChild(CreateProperty(xDoc, "visible", "False"));
+            }
 
             if (bChildAlwaysShowImage)
             {
@@ -856,13 +999,13 @@ void builder_add_from_gtk3_file(GtkBuilder* pBuilder, 
const OUString& rUri)
     Convert3To4(xDocument);
 
     css::uno::Reference<css::beans::XPropertySet> 
xTempFile(css::io::TempFile::create(xContext),
-                                                            
css::uno::UNO_QUERY);
+                                                            
css::uno::UNO_QUERY_THROW);
     css::uno::Reference<css::io::XStream> xTempStream(xTempFile, 
css::uno::UNO_QUERY_THROW);
     xTempFile->setPropertyValue("RemoveFile", css::uno::makeAny(false));
 
     // serialize it back to xml
     css::uno::Reference<css::xml::sax::XSAXSerializable> xSerializer(xDocument,
-                                                                     
css::uno::UNO_QUERY);
+                                                                     
css::uno::UNO_QUERY_THROW);
     css::uno::Reference<css::xml::sax::XWriter> xWriter = 
css::xml::sax::Writer::create(xContext);
     css::uno::Reference<css::io::XOutputStream> xTempOut = 
xTempStream->getOutputStream();
     xWriter->setOutputStream(xTempOut);
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to