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

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Tue Oct 9 18:44:14 UTC 2018


 vcl/unx/gtk3/gtk3gtkinst.cxx |   63 ++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 59 insertions(+), 4 deletions(-)

New commits:
commit 4e819ba343fea588236e78fd71952756a670fa23
Author:     Caolán McNamara <caolanm at redhat.com>
AuthorDate: Tue Oct 9 15:51:48 2018 +0100
Commit:     Caolán McNamara <caolanm at redhat.com>
CommitDate: Tue Oct 9 20:43:48 2018 +0200

    bruteforce typeahead into combobox menus
    
    Change-Id: I2cf75773f380c3a53d3e091e7e72beb62a4ff119
    Reviewed-on: https://gerrit.libreoffice.org/61593
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>
    Tested-by: Caolán McNamara <caolanm at redhat.com>

diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
index cef3d1d04e40..a03682d46bba 100644
--- a/vcl/unx/gtk3/gtk3gtkinst.cxx
+++ b/vcl/unx/gtk3/gtk3gtkinst.cxx
@@ -4793,6 +4793,7 @@ class GtkInstanceComboBox : public GtkInstanceContainer, public vcl::ISearchable
 {
 private:
     GtkComboBox* m_pComboBox;
+    GtkMenu* m_pMenu;
     std::unique_ptr<comphelper::string::NaturalStringSorter> m_xSorter;
     vcl::QuickSelectionEngine m_aQuickSelectionEngine;
     gboolean m_bPopupActive;
@@ -4816,6 +4817,7 @@ private:
 
     void signal_popup_shown()
     {
+        m_aQuickSelectionEngine.Reset();
         gboolean bIsShown(false);
         g_object_get(m_pComboBox, "popup-shown", &bIsShown, nullptr);
         if (m_bPopupActive != bIsShown)
@@ -4903,7 +4905,8 @@ private:
         g_object_unref(pCompletion);
     }
 
-    // support typeahead for the case where there is no entry widget, typing ahead
+    // in the absence of a built-in solution for https://gitlab.gnome.org/GNOME/gtk/issues/310
+    // a) support typeahead for the case where there is no entry widget, typing ahead
     // into the button itself will select via the vcl selection engine, a matching
     // entry
     static gboolean signalKeyPress(GtkWidget*, GdkEventKey* pEvent, gpointer widget)
@@ -4959,9 +4962,34 @@ private:
         return reinterpret_cast<sal_Int64>(entry) - 1;
     }
 
+    int get_selected_entry() const
+    {
+        if (m_bPopupActive && m_pMenu)
+        {
+            GList* pChildren = gtk_container_get_children(GTK_CONTAINER(m_pMenu));
+            auto nRet = g_list_index(pChildren, gtk_menu_shell_get_selected_item(GTK_MENU_SHELL(m_pMenu)));
+            g_list_free(pChildren);
+            return nRet;
+        }
+        else
+            return get_active();
+    }
+
+    void set_selected_entry(int nSelect)
+    {
+        if (m_bPopupActive && m_pMenu)
+        {
+            GList* pChildren = gtk_container_get_children(GTK_CONTAINER(m_pMenu));
+            gtk_menu_shell_select_item(GTK_MENU_SHELL(m_pMenu), GTK_WIDGET(g_list_nth_data(pChildren, nSelect)));
+            g_list_free(pChildren);
+        }
+        else
+            set_active(nSelect);
+    }
+
     virtual vcl::StringEntryIdentifier CurrentEntry(OUString& out_entryText) const override
     {
-        int nCurrentPos = get_active();
+        int nCurrentPos = get_selected_entry();
         return typeahead_getEntry((nCurrentPos == -1) ? 0 : nCurrentPos, out_entryText);
     }
 
@@ -4974,7 +5002,7 @@ private:
     virtual void SelectEntry(vcl::StringEntryIdentifier entry) override
     {
         int nSelect = typeahead_getEntryPos(entry);
-        if (nSelect == get_active())
+        if (nSelect == get_selected_entry())
         {
             // ignore that. This method is a callback from the QuickSelectionEngine, which means the user attempted
             // to select the given entry by typing its starting letters. No need to act.
@@ -4986,13 +5014,39 @@ private:
         if (nSelect >= nCount)
             nSelect = nCount ? nCount-1 : -1;
 
-        set_active(nSelect);
+        set_selected_entry(nSelect);
+    }
+
+    // b) support typeahead for the menu itself, typing into the menu will
+    // select via the vcl selection engine, a matching entry. Clearly
+    // this is cheating, brittle and not a long term solution.
+    void install_menu_typeahead()
+    {
+        AtkObject* pAtkObj = gtk_combo_box_get_popup_accessible(m_pComboBox);
+        if (!pAtkObj)
+            return;
+        if (!GTK_IS_ACCESSIBLE(pAtkObj))
+            return;
+        GtkWidget* pWidget = gtk_accessible_get_widget(GTK_ACCESSIBLE(pAtkObj));
+        if (!pWidget)
+            return;
+        if (!GTK_IS_MENU(pWidget))
+            return;
+        m_pMenu = GTK_MENU(pWidget);
+
+        guint nSignalId = g_signal_lookup("key-press-event", GTK_TYPE_MENU);
+        gulong nOriginalMenuKeyPressEventId = g_signal_handler_find(m_pMenu, G_SIGNAL_MATCH_DATA, nSignalId, 0,
+                                                                    nullptr, nullptr, m_pComboBox);
+
+        g_signal_handler_block(m_pMenu, nOriginalMenuKeyPressEventId);
+        g_signal_connect(m_pMenu, "key-press-event", G_CALLBACK(signalKeyPress), this);
     }
 
 public:
     GtkInstanceComboBox(GtkComboBox* pComboBox, bool bTakeOwnership)
         : GtkInstanceContainer(GTK_CONTAINER(pComboBox), bTakeOwnership)
         , m_pComboBox(pComboBox)
+        , m_pMenu(nullptr)
         , m_aQuickSelectionEngine(*this)
         , m_bPopupActive(false)
         , m_nChangedSignalId(g_signal_connect(m_pComboBox, "changed", G_CALLBACK(signalChanged), this))
@@ -5034,6 +5088,7 @@ public:
             m_nEntryActivateSignalId = 0;
             m_nKeyPressEventSignalId = g_signal_connect(m_pWidget, "key-press-event", G_CALLBACK(signalKeyPress), this);
         }
+        install_menu_typeahead();
     }
 
     virtual int get_active() const override


More information about the Libreoffice-commits mailing list