solenv/sanitizers/ui/vcl.suppr |    1 
 vcl/inc/strings.hrc            |    2 +
 vcl/source/control/edit.cxx    |    2 +
 vcl/source/edit/vclmedit.cxx   |    4 ++
 vcl/uiconfig/ui/editmenu.ui    |    1 
 vcl/unx/gtk3/gtkinst.cxx       |   81 ++++++++++++++++++++++++++++-------------
 6 files changed, 65 insertions(+), 26 deletions(-)

New commits:
commit 930cb8440697d80df0a399d765dc85966732ddce
Author:     Caolán McNamara <caolan.mcnam...@collabora.com>
AuthorDate: Wed Aug 16 09:55:45 2023 +0100
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Wed Aug 16 18:12:26 2023 +0200

    Resolves: tdf#156751 add "Special Character..." to GtkEntry context menus
    
    translation exists so doesn't require additional translation
    
    Change-Id: Ibc5df15b9b8442307195d79c862c69e0506c4057
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155733
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>

diff --git a/solenv/sanitizers/ui/vcl.suppr b/solenv/sanitizers/ui/vcl.suppr
index a07c25780a76..52e3b4d86df5 100644
--- a/solenv/sanitizers/ui/vcl.suppr
+++ b/solenv/sanitizers/ui/vcl.suppr
@@ -7,6 +7,7 @@ vcl/uiconfig/ui/combobox.ui://GtkEntry[@id='entry'] 
no-labelled-by
 vcl/uiconfig/ui/combobox.ui://GtkToggleButton[@id='button'] button-no-label
 vcl/uiconfig/ui/combobox.ui://GtkMenuButton[@id='overlaybutton'] 
button-no-label
 vcl/uiconfig/ui/cupspassworddialog.ui://GtkLabel[@id='text'] orphan-label
+vcl/uiconfig/ui/editmenu.ui://GtkMenuItem[@id='specialchar'] button-no-label
 vcl/uiconfig/ui/menutogglebutton3.ui://GtkToggleButton[@id='togglebutton'] 
button-no-label
 vcl/uiconfig/ui/menutogglebutton3.ui://GtkButton[@id='menubutton'] 
button-no-label
 vcl/uiconfig/ui/menutogglebutton4.ui://GtkToggleButton[@id='togglebutton'] 
button-no-label
diff --git a/vcl/inc/strings.hrc b/vcl/inc/strings.hrc
index c2e95f20ceac..7f5699aae1d6 100644
--- a/vcl/inc/strings.hrc
+++ b/vcl/inc/strings.hrc
@@ -125,6 +125,8 @@
 
 #define STR_UNSAVED_DOCUMENTS                       
NC_("STR_UNSAVED_DOCUMENTS", "There are unsaved documents")
 
+#define STR_SPECIAL_CHARACTER_MENU_ENTRY            
NC_("editmenu|specialchar", "_Special Character...")
+
 #endif // INCLUDED_VCL_INC_STRINGS_HRC
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/control/edit.cxx b/vcl/source/control/edit.cxx
index 0db27e8a315a..92c03118727c 100644
--- a/vcl/source/control/edit.cxx
+++ b/vcl/source/control/edit.cxx
@@ -1978,6 +1978,8 @@ void Edit::Command( const CommandEvent& rCEvt )
         pPopup->EnableItem(pPopup->GetItemId(u"copy"), bEnableCopy);
         pPopup->EnableItem(pPopup->GetItemId(u"delete"), bEnableDelete);
         pPopup->EnableItem(pPopup->GetItemId(u"paste"), bEnablePaste);
+        pPopup->SetItemText(pPopup->GetItemId(u"specialchar"),
+            
BuilderUtils::convertMnemonicMarkup(VclResId(STR_SPECIAL_CHARACTER_MENU_ENTRY)));
         pPopup->EnableItem(pPopup->GetItemId(u"specialchar"), 
bEnableSpecialChar);
         pPopup->EnableItem(
             pPopup->GetItemId(u"undo"),
diff --git a/vcl/source/edit/vclmedit.cxx b/vcl/source/edit/vclmedit.cxx
index 541d6bfc20c8..d5197358591d 100644
--- a/vcl/source/edit/vclmedit.cxx
+++ b/vcl/source/edit/vclmedit.cxx
@@ -41,6 +41,8 @@
 #include <vcl/weld.hxx>
 #include <osl/diagnose.h>
 #include <tools/json_writer.hxx>
+#include <strings.hrc>
+#include <svdata.hxx>
 
 class ImpVclMEdit : public SfxListener
 {
@@ -789,6 +791,8 @@ void TextWindow::Command( const CommandEvent& rCEvt )
         pPopup->EnableItem(pPopup->GetItemId(u"copy"), bEnableCopy);
         pPopup->EnableItem(pPopup->GetItemId(u"delete"), bEnableDelete);
         pPopup->EnableItem(pPopup->GetItemId(u"paste"), bEnablePaste);
+        pPopup->SetItemText(pPopup->GetItemId(u"specialchar"),
+            
BuilderUtils::convertMnemonicMarkup(VclResId(STR_SPECIAL_CHARACTER_MENU_ENTRY)));
         pPopup->EnableItem(pPopup->GetItemId(u"specialchar"), 
bEnableSpecialChar);
         pPopup->EnableItem(pPopup->GetItemId(u"undo"), bEnableUndo);
         pPopup->ShowItem(pPopup->GetItemId(u"specialchar"), 
!vcl::GetGetSpecialCharsFunction());
diff --git a/vcl/uiconfig/ui/editmenu.ui b/vcl/uiconfig/ui/editmenu.ui
index 8c025d4f1a94..e0d55fb8cca0 100644
--- a/vcl/uiconfig/ui/editmenu.ui
+++ b/vcl/uiconfig/ui/editmenu.ui
@@ -69,7 +69,6 @@
       <object class="GtkMenuItem" id="specialchar">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
-        <property name="label" translatable="yes" 
context="editmenu|specialchar">_Special Character...</property>
         <property name="use_underline">True</property>
       </object>
     </child>
diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx
index 2cfd0d6b203a..141039dfb79c 100644
--- a/vcl/unx/gtk3/gtkinst.cxx
+++ b/vcl/unx/gtk3/gtkinst.cxx
@@ -19024,41 +19024,67 @@ void 
GtkInstanceDrawingArea::im_context_set_cursor_location(const tools::Rectang
 }
 
 #if !GTK_CHECK_VERSION(4, 0, 0)
-static gboolean signalEntryInsertSpecialCharKeyPress(GtkEntry* pEntry, 
GdkEventKey* pEvent, gpointer)
+
+static void InsertSpecialChar(GtkEntry *pEntry)
 {
-    if ((pEvent->keyval == GDK_KEY_S || pEvent->keyval == GDK_KEY_s) &&
-        (pEvent->state & GDK_MODIFIER_MASK) == 
static_cast<GdkModifierType>(GDK_SHIFT_MASK|GDK_CONTROL_MASK))
+    if (auto pImplFncGetSpecialChars = vcl::GetGetSpecialCharsFunction())
     {
-        if (auto pImplFncGetSpecialChars = vcl::GetGetSpecialCharsFunction())
-        {
-            weld::Window* pDialogParent = nullptr;
+        weld::Window* pDialogParent = nullptr;
 
-            GtkWidget* pTopLevel = widget_get_toplevel(GTK_WIDGET(pEntry));
-            if (GtkSalFrame* pFrame = pTopLevel ? 
GtkSalFrame::getFromWindow(pTopLevel) : nullptr)
-                pDialogParent = pFrame->GetFrameWeld();
+        GtkWidget* pTopLevel = widget_get_toplevel(GTK_WIDGET(pEntry));
+        if (GtkSalFrame* pFrame = pTopLevel ? 
GtkSalFrame::getFromWindow(pTopLevel) : nullptr)
+            pDialogParent = pFrame->GetFrameWeld();
 
-            std::unique_ptr<GtkInstanceWindow> xFrameWeld;
-            if (!pDialogParent && pTopLevel)
-            {
-                xFrameWeld.reset(new GtkInstanceWindow(GTK_WINDOW(pTopLevel), 
nullptr, false));
-                pDialogParent = xFrameWeld.get();
-            }
+        std::unique_ptr<GtkInstanceWindow> xFrameWeld;
+        if (!pDialogParent && pTopLevel)
+        {
+            xFrameWeld.reset(new GtkInstanceWindow(GTK_WINDOW(pTopLevel), 
nullptr, false));
+            pDialogParent = xFrameWeld.get();
+        }
 
-            OUString aChars = pImplFncGetSpecialChars(pDialogParent, 
::get_font(GTK_WIDGET(pEntry)));
-            if (!aChars.isEmpty())
-            {
-                gtk_editable_delete_selection(GTK_EDITABLE(pEntry));
-                gint position = 
gtk_editable_get_position(GTK_EDITABLE(pEntry));
-                OString sText(OUStringToOString(aChars, 
RTL_TEXTENCODING_UTF8));
-                gtk_editable_insert_text(GTK_EDITABLE(pEntry), sText.getStr(), 
sText.getLength(),
-                                         &position);
-                gtk_editable_set_position(GTK_EDITABLE(pEntry), position);
-            }
+        OUString aChars = pImplFncGetSpecialChars(pDialogParent, 
::get_font(GTK_WIDGET(pEntry)));
+        if (!aChars.isEmpty())
+        {
+            gtk_editable_delete_selection(GTK_EDITABLE(pEntry));
+            gint position = gtk_editable_get_position(GTK_EDITABLE(pEntry));
+            OString sText(OUStringToOString(aChars, RTL_TEXTENCODING_UTF8));
+            gtk_editable_insert_text(GTK_EDITABLE(pEntry), sText.getStr(), 
sText.getLength(),
+                                     &position);
+            gtk_editable_set_position(GTK_EDITABLE(pEntry), position);
         }
+    }
+}
+
+static gboolean signalEntryInsertSpecialCharKeyPress(GtkEntry* pEntry, 
GdkEventKey* pEvent, gpointer)
+{
+    if ((pEvent->keyval == GDK_KEY_S || pEvent->keyval == GDK_KEY_s) &&
+        (pEvent->state & GDK_MODIFIER_MASK) == 
static_cast<GdkModifierType>(GDK_SHIFT_MASK|GDK_CONTROL_MASK))
+    {
+        InsertSpecialChar(pEntry);
         return true;
     }
     return false;
 }
+
+static void signalActivateEntryInsertSpecialChar(GtkEntry *pEntry)
+{
+    InsertSpecialChar(pEntry);
+}
+
+static void signalEntryPopulatePopup(GtkEntry* pEntry, GtkWidget* pMenu, 
gpointer)
+{
+    if (!GTK_IS_MENU(pMenu))
+        return;
+
+    if (!vcl::GetGetSpecialCharsFunction())
+        return;
+
+    GtkWidget *item = 
gtk_menu_item_new_with_mnemonic(MapToGtkAccelerator(VclResId(STR_SPECIAL_CHARACTER_MENU_ENTRY)).getStr());
+    gtk_widget_show(item);
+    g_signal_connect_swapped(item, "activate", 
G_CALLBACK(signalActivateEntryInsertSpecialChar), pEntry);
+    gtk_menu_shell_append(GTK_MENU_SHELL(pMenu), item);
+}
+
 #endif
 
 namespace {
@@ -20970,6 +20996,7 @@ private:
     gulong m_nEntryFocusInSignalId;
     gulong m_nEntryFocusOutSignalId;
     gulong m_nEntryKeyPressEventSignalId;
+    gulong m_nEntryPopulatePopupMenuSignalId;
     guint m_nAutoCompleteIdleId;
     gint m_nNonCustomLineHeight;
     gint m_nPrePopupCursorPos;
@@ -22071,6 +22098,7 @@ public:
             m_nEntryFocusInSignalId = g_signal_connect(m_pEntry, 
"focus-in-event", G_CALLBACK(signalEntryFocusIn), this);
             m_nEntryFocusOutSignalId = g_signal_connect(m_pEntry, 
"focus-out-event", G_CALLBACK(signalEntryFocusOut), this);
             m_nEntryKeyPressEventSignalId = g_signal_connect(m_pEntry, 
"key-press-event", G_CALLBACK(signalEntryKeyPress), this);
+            m_nEntryPopulatePopupMenuSignalId = g_signal_connect(m_pEntry, 
"populate-popup", G_CALLBACK(signalEntryPopulatePopup), nullptr);
             m_nKeyPressEventSignalId = 0;
         }
         else
@@ -22116,6 +22144,7 @@ public:
             m_nEntryFocusInSignalId = 0;
             m_nEntryFocusOutSignalId = 0;
             m_nEntryKeyPressEventSignalId = 0;
+            m_nEntryPopulatePopupMenuSignalId = 0;
             m_nKeyPressEventSignalId = g_signal_connect(m_pToggleButton, 
"key-press-event", G_CALLBACK(signalKeyPress), this);
         }
 
@@ -22711,6 +22740,7 @@ public:
             g_signal_handler_disconnect(m_pEntry, m_nEntryFocusInSignalId);
             g_signal_handler_disconnect(m_pEntry, m_nEntryFocusOutSignalId);
             g_signal_handler_disconnect(m_pEntry, 
m_nEntryKeyPressEventSignalId);
+            g_signal_handler_disconnect(m_pEntry, 
m_nEntryPopulatePopupMenuSignalId);
         }
         else
             g_signal_handler_disconnect(m_pToggleButton, 
m_nKeyPressEventSignalId);
@@ -23835,6 +23865,7 @@ private:
         else if (GTK_IS_ENTRY(pWidget))
         {
             g_signal_connect(pWidget, "key-press-event", 
G_CALLBACK(signalEntryInsertSpecialCharKeyPress), nullptr);
+            g_signal_connect(pWidget, "populate-popup", 
G_CALLBACK(signalEntryPopulatePopup), nullptr);
         }
 #endif
         else if (GTK_IS_WINDOW(pWidget))

Reply via email to