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

Caolán McNamara (via logerrit) logerrit at kemper.freedesktop.org
Thu Oct 22 13:07:35 UTC 2020


 vcl/inc/unx/gtk/gtkframe.hxx  |    2 +
 vcl/unx/gtk3/gtk3gtkframe.cxx |   77 +++++++++++++++++++++++++++++++++++++++++-
 vcl/unx/gtk3/gtk3gtkinst.cxx  |   43 +++++++++++++++--------
 3 files changed, 107 insertions(+), 15 deletions(-)

New commits:
commit 606c65c90cb3e8abdd74540195b7cb01ba88adc8
Author:     Caolán McNamara <caolanm at redhat.com>
AuthorDate: Wed Oct 21 12:23:57 2020 +0100
Commit:     Caolán McNamara <caolanm at redhat.com>
CommitDate: Thu Oct 22 15:06:48 2020 +0200

    for DisallowCycleFocusOut forward unused keyevents to InterimItemWindow
    
    for ctrl+q etc
    
    Change-Id: Ie0ad94cf0e85693960428ffee5ae4a0ecffb7c6b
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/104635
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>

diff --git a/vcl/inc/unx/gtk/gtkframe.hxx b/vcl/inc/unx/gtk/gtkframe.hxx
index 27865f2efb12..820d796bf6e5 100644
--- a/vcl/inc/unx/gtk/gtkframe.hxx
+++ b/vcl/inc/unx/gtk/gtkframe.hxx
@@ -530,6 +530,8 @@ public:
     static OUString             GetPreeditDetails(GtkIMContext* pIMContext, std::vector<ExtTextInputAttr>& rInputFlags, sal_Int32& rCursorPos, sal_uInt8& rCursorFlags);
 
     void DisallowCycleFocusOut();
+    bool IsCycleFocusOutDisallowed() const;
+    void AllowCycleFocusOut();
 };
 
 #define OOO_TYPE_FIXED ooo_fixed_get_type()
diff --git a/vcl/unx/gtk3/gtk3gtkframe.cxx b/vcl/unx/gtk3/gtk3gtkframe.cxx
index 26c34a09c9d4..eb964a790533 100644
--- a/vcl/unx/gtk3/gtk3gtkframe.cxx
+++ b/vcl/unx/gtk3/gtk3gtkframe.cxx
@@ -1026,6 +1026,26 @@ void GtkSalFrame::DisallowCycleFocusOut()
     gtk_widget_set_can_focus(GTK_WIDGET(m_pFixedContainer), false);
 }
 
+bool GtkSalFrame::IsCycleFocusOutDisallowed() const
+{
+    return m_nSetFocusSignalId == 0;
+}
+
+void GtkSalFrame::AllowCycleFocusOut()
+{
+    if (m_nSetFocusSignalId)
+        return;
+    // enable/disable can-focus as control enters and leaves
+    // embedded native gtk widgets
+    m_nSetFocusSignalId = g_signal_connect(G_OBJECT(m_pWindow), "set-focus", G_CALLBACK(signalSetFocus), this);
+
+    // set container without can-focus and focus will tab between
+    // the native embedded widgets using the default gtk handling for
+    // that
+    gtk_widget_set_can_focus(GTK_WIDGET(m_pFixedContainer), true);
+}
+
+
 void GtkSalFrame::Init( SalFrame* pParent, SalFrameStyleFlags nStyle )
 {
     if( nStyle & SalFrameStyleFlags::DEFAULT ) // ensure default style
@@ -3198,6 +3218,8 @@ gboolean GtkSalFrame::signalKey(GtkWidget* pWidget, GdkEventKey* pEvent, gpointe
 
     bool bFocusInAnotherGtkWidget = false;
 
+    VclPtr<vcl::Window> xTopLevelInterimWindow;
+
     if (GTK_IS_WINDOW(pThis->m_pWindow))
     {
         GtkWidget* pFocusWindow = gtk_window_get_focus(GTK_WINDOW(pThis->m_pWindow));
@@ -3216,6 +3238,24 @@ gboolean GtkSalFrame::signalKey(GtkWidget* pWidget, GdkEventKey* pEvent, gpointe
             g_type_class_unref(pClass);
             if (bHandled)
                 return true;
+
+            // Is focus inside a full-app InterimItemWindow? In which case find
+            // that InterimItemWindow and send unconsumed keystrokes to it to
+            // support ctrl-q etc shortcuts
+            if (pThis->IsCycleFocusOutDisallowed())
+            {
+                GtkWidget* pSearch = pFocusWindow;
+                while (pSearch)
+                {
+                    void* pData = g_object_get_data(G_OBJECT(pSearch), "InterimWindowGlue");
+                    if (pData)
+                    {
+                        xTopLevelInterimWindow = static_cast<vcl::Window*>(pData);
+                        break;
+                    }
+                    pSearch = gtk_widget_get_parent(pSearch);
+                }
+            }
         }
     }
 
@@ -3303,6 +3343,22 @@ gboolean GtkSalFrame::signalKey(GtkWidget* pWidget, GdkEventKey* pEvent, gpointe
     }
     else
     {
+        VclPtr<vcl::Window> xOrigFocusWin;
+        if (xTopLevelInterimWindow)
+        {
+            // Focus is inside a full-app InterimItemWindow send unconsumed
+            // keystrokes to by setting it as the mpFocusWin
+            VclPtr<vcl::Window> xVclWindow = pThis->GetWindow();
+            ImplFrameData* pFrameData = xVclWindow->ImplGetWindowImpl()->mpFrameData;
+            xOrigFocusWin = pFrameData->mpFocusWin;
+            pFrameData->mpFocusWin = xTopLevelInterimWindow;
+            if (pEvent->keyval == GDK_KEY_F6)
+            {
+                // For F6, allow the focus to leave the InterimItemWindow
+                pThis->AllowCycleFocusOut();
+            }
+        }
+
         bStopProcessingKey = pThis->doKeyCallback(pEvent->state,
                                                   pEvent->keyval,
                                                   pEvent->hardware_keycode,
@@ -3310,8 +3366,27 @@ gboolean GtkSalFrame::signalKey(GtkWidget* pWidget, GdkEventKey* pEvent, gpointe
                                                   sal_Unicode(gdk_keyval_to_unicode( pEvent->keyval )),
                                                   (pEvent->type == GDK_KEY_PRESS),
                                                   false);
-        if( ! aDel.isDeleted() )
+        if (!aDel.isDeleted())
+        {
             pThis->m_nKeyModifiers = ModKeyFlags::NONE;
+
+            if (xTopLevelInterimWindow)
+            {
+                // Focus was inside a full-app InterimItemWindow, restore the original
+                // focus win, unless the focus was changed away from the InterimItemWindow
+                // which should only be possible with F6
+                VclPtr<vcl::Window> xVclWindow = pThis->GetWindow();
+                ImplFrameData* pFrameData = xVclWindow->ImplGetWindowImpl()->mpFrameData;
+                if (pFrameData->mpFocusWin == xTopLevelInterimWindow)
+                    pFrameData->mpFocusWin = xOrigFocusWin;
+                if (pEvent->keyval == GDK_KEY_F6)
+                {
+                    // undo the above AllowCycleFocusOut for F6
+                    pThis->DisallowCycleFocusOut();
+                }
+            }
+        }
+
     }
 
     if (!bFocusInAnotherGtkWidget && !aDel.isDeleted() && pThis->m_pIMHandler)
diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
index 6448e3733256..13f97ceb7df9 100644
--- a/vcl/unx/gtk3/gtk3gtkinst.cxx
+++ b/vcl/unx/gtk3/gtk3gtkinst.cxx
@@ -16291,6 +16291,7 @@ private:
     std::vector<GtkLabel*> m_aMnemonicLabels;
 
     VclPtr<SystemChildWindow> m_xInterimGlue;
+    bool m_bAllowCycleFocusOut;
 
     void postprocess_widget(GtkWidget* pWidget)
     {
@@ -16458,12 +16459,14 @@ private:
         pThis->postprocess_widget(GTK_WIDGET(pObject));
     }
 public:
-    GtkInstanceBuilder(GtkWidget* pParent, const OUString& rUIRoot, const OUString& rUIFile, SystemChildWindow* pInterimGlue)
+    GtkInstanceBuilder(GtkWidget* pParent, const OUString& rUIRoot, const OUString& rUIFile,
+                       SystemChildWindow* pInterimGlue, bool bAllowCycleFocusOut)
         : weld::Builder()
         , m_pStringReplace(Translate::GetReadStringHook())
         , m_pParentWidget(pParent)
         , m_nNotifySignalId(0)
         , m_xInterimGlue(pInterimGlue)
+        , m_bAllowCycleFocusOut(bAllowCycleFocusOut)
     {
         OUString sHelpRoot(rUIFile);
         ensure_intercept_drawing_area_accessibility();
@@ -16495,6 +16498,17 @@ public:
         {
             assert(m_pParentWidget);
             g_object_set_data(G_OBJECT(m_pParentWidget), "InterimWindowGlue", m_xInterimGlue.get());
+
+            if (!m_bAllowCycleFocusOut)
+            {
+                GtkWidget* pTopLevel = gtk_widget_get_toplevel(m_pParentWidget);
+                assert(pTopLevel);
+                GtkSalFrame* pFrame = GtkSalFrame::getFromWindow(pTopLevel);
+                assert(pFrame);
+                // unhook handler and let gtk cycle its own way through this widget's
+                // children because it has no non-gtk siblings
+                pFrame->DisallowCycleFocusOut();
+            }
         }
     }
 
@@ -16555,6 +16569,18 @@ public:
     {
         g_slist_free(m_pObjectList);
         g_object_unref(m_pBuilder);
+
+        if (m_xInterimGlue && !m_bAllowCycleFocusOut)
+        {
+            GtkWidget* pTopLevel = gtk_widget_get_toplevel(m_pParentWidget);
+            assert(pTopLevel);
+            GtkSalFrame* pFrame = GtkSalFrame::getFromWindow(pTopLevel);
+            assert(pFrame);
+            // rehook handler and let vcl cycle its own way through this widget's
+            // children
+            pFrame->AllowCycleFocusOut();
+        }
+
         m_xInterimGlue.disposeAndClear();
     }
 
@@ -17048,7 +17074,7 @@ weld::Builder* GtkInstance::CreateBuilder(weld::Widget* pParent, const OUString&
     if (pParent && !pParentWidget) //remove when complete
         return SalInstance::CreateBuilder(pParent, rUIRoot, rUIFile);
     GtkWidget* pBuilderParent = pParentWidget ? pParentWidget->getWidget() : nullptr;
-    return new GtkInstanceBuilder(pBuilderParent, rUIRoot, rUIFile, nullptr);
+    return new GtkInstanceBuilder(pBuilderParent, rUIRoot, rUIFile, nullptr, true);
 }
 
 // tdf#135965 for the case of native widgets inside a GtkSalFrame and F1 pressed, run help
@@ -17122,19 +17148,8 @@ weld::Builder* GtkInstance::CreateInterimBuilder(vcl::Window* pParent, const OUS
     GtkWidget *pWindow = static_cast<GtkWidget*>(pEnvData->pWidget);
     gtk_widget_show_all(pWindow);
 
-    if (!bAllowCycleFocusOut)
-    {
-        GtkWidget* pTopLevel = gtk_widget_get_toplevel(pWindow);
-        assert(pTopLevel);
-        GtkSalFrame* pFrame = GtkSalFrame::getFromWindow(pTopLevel);
-        assert(pFrame);
-        // unhook handler and let gtk cycle its own way through this widget's
-        // children because it has no non-gtk siblings
-        pFrame->DisallowCycleFocusOut();
-    }
-
     // build the widget tree as a child of the GtkEventBox GtkGrid parent
-    return new GtkInstanceBuilder(pWindow, rUIRoot, rUIFile, xEmbedWindow.get());
+    return new GtkInstanceBuilder(pWindow, rUIRoot, rUIFile, xEmbedWindow.get(), bAllowCycleFocusOut);
 }
 
 weld::MessageDialog* GtkInstance::CreateMessageDialog(weld::Widget* pParent, VclMessageType eMessageType, VclButtonsType eButtonsType, const OUString &rPrimaryMessage)


More information about the Libreoffice-commits mailing list