formula/source/ui/dlg/funcutl.cxx |   48 ++++++++++++++++++++++++++++++----
 include/formula/funcutl.hxx       |   13 +++++++--
 vcl/unx/gtk3/gtk3gtkinst.cxx      |   53 ++++----------------------------------
 3 files changed, 60 insertions(+), 54 deletions(-)

New commits:
commit 9dd52c920703b41072d82e8a1ea5c45931684bf0
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Thu Feb 18 14:56:01 2021 +0000
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Tue Aug 10 19:56:51 2021 +0200

    move async focus-in/focus-out workaround to known client that needs it
    
    and for the normal case process immediately. Use-case is the
    bibliography editor, modified uncommitted entry, click in browser
    column margin area to select a new row, the entry should commit its
    old contents to the old row before filling from the new row
    
    Change-Id: Ib41d96afcfa86bcd1075b9512d4cfab593afa66d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111152
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caol...@redhat.com>
    (cherry picked from commit c56e0c791a79dc414108e1b2fbf0f7eb38657f10)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/120078
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/formula/source/ui/dlg/funcutl.cxx 
b/formula/source/ui/dlg/funcutl.cxx
index f64b6aff9bd5..361ec4c9ebaa 100644
--- a/formula/source/ui/dlg/funcutl.cxx
+++ b/formula/source/ui/dlg/funcutl.cxx
@@ -21,6 +21,7 @@
 
 #include <formula/funcutl.hxx>
 #include <formula/IControlReferenceHandler.hxx>
+#include <vcl/svapp.hxx>
 #include "ControlHelper.hxx"
 #include "parawin.hxx"
 #include <strings.hrc>
@@ -265,9 +266,11 @@ RefEdit::RefEdit(std::unique_ptr<weld::Entry> xControl)
     , aIdle("formula RefEdit Idle")
     , pAnyRefDlg(nullptr)
     , pLabelWidget(nullptr)
+    , mpFocusInEvent(nullptr)
+    , mpFocusOutEvent(nullptr)
 {
-    xEntry->connect_focus_in(LINK(this, RefEdit, GetFocus));
-    xEntry->connect_focus_out(LINK(this, RefEdit, LoseFocus));
+    xEntry->connect_focus_in(LINK(this, RefEdit, GetFocusHdl));
+    xEntry->connect_focus_out(LINK(this, RefEdit, LoseFocusHdl));
     xEntry->connect_key_press(LINK(this, RefEdit, KeyInputHdl));
     xEntry->connect_changed(LINK(this, RefEdit, Modify));
     aIdle.SetInvokeHandler( LINK( this, RefEdit, UpdateHdl ) );
@@ -275,6 +278,10 @@ RefEdit::RefEdit(std::unique_ptr<weld::Entry> xControl)
 
 RefEdit::~RefEdit()
 {
+    if (mpFocusInEvent)
+        Application::RemoveUserEvent(mpFocusInEvent);
+    if (mpFocusOutEvent)
+        Application::RemoveUserEvent(mpFocusOutEvent);
     aIdle.ClearInvokeHandler();
     aIdle.Stop();
 }
@@ -355,22 +362,53 @@ void RefEdit::GrabFocus()
     bool bHadFocus = xEntry->has_focus();
     xEntry->grab_focus();
     if (!bHadFocus && xEntry->has_focus())
-        GetFocus(*xEntry);
+        GetFocus();
 }
 
-IMPL_LINK_NOARG(RefEdit, GetFocus, weld::Widget&, void)
+void RefEdit::GetFocus()
 {
     maGetFocusHdl.Call(*this);
     StartUpdateData();
 }
 
-IMPL_LINK_NOARG(RefEdit, LoseFocus, weld::Widget&, void)
+void RefEdit::LoseFocus()
 {
     maLoseFocusHdl.Call(*this);
     if( pAnyRefDlg )
         pAnyRefDlg->HideReference();
 }
 
+IMPL_LINK_NOARG(RefEdit, GetFocusHdl, weld::Widget&, void)
+{
+    // in e.g. function wizard RefEdits we want to select all when we get focus
+    // but in the gtk case there are pending gtk handlers which change 
selection
+    // after our handler, so post our focus in event to happen after those 
complete
+    if (mpFocusInEvent)
+        Application::RemoveUserEvent(mpFocusInEvent);
+    mpFocusInEvent = Application::PostUserEvent(LINK(this, RefEdit, 
AsyncFocusInHdl));
+}
+
+IMPL_LINK_NOARG(RefEdit, LoseFocusHdl, weld::Widget&, void)
+{
+    // tdf#127262 because focus in is async, focus out must not appear out
+    // of sequence to focus in
+    if (mpFocusOutEvent)
+        Application::RemoveUserEvent(mpFocusOutEvent);
+    mpFocusOutEvent = Application::PostUserEvent(LINK(this, RefEdit, 
AsyncFocusOutHdl));
+}
+
+IMPL_LINK_NOARG(RefEdit, AsyncFocusInHdl, void*, void)
+{
+    mpFocusInEvent = nullptr;
+    GetFocus();
+}
+
+IMPL_LINK_NOARG(RefEdit, AsyncFocusOutHdl, void*, void)
+{
+    mpFocusOutEvent = nullptr;
+    LoseFocus();
+}
+
 IMPL_LINK_NOARG(RefEdit, UpdateHdl, Timer *, void)
 {
     if( pAnyRefDlg )
diff --git a/include/formula/funcutl.hxx b/include/formula/funcutl.hxx
index 0a14e62db159..4e008181eae7 100644
--- a/include/formula/funcutl.hxx
+++ b/include/formula/funcutl.hxx
@@ -27,6 +27,7 @@
 #include <vcl/weld.hxx>
 
 class KeyEvent;
+struct ImplSVEvent;
 
 namespace formula {
 
@@ -41,6 +42,9 @@ private:
     Idle aIdle;
     IControlReferenceHandler* pAnyRefDlg; // parent dialog
     weld::Label* pLabelWidget;
+    ImplSVEvent* mpFocusInEvent;
+    ImplSVEvent* mpFocusOutEvent;
+
     Link<RefEdit&,void> maGetFocusHdl;
     Link<RefEdit&,void> maLoseFocusHdl;
     Link<RefEdit&,void> maModifyHdl;
@@ -50,10 +54,15 @@ private:
 
 protected:
     DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
-    DECL_LINK(GetFocus, weld::Widget&, void);
-    DECL_LINK(LoseFocus, weld::Widget&, void);
+    DECL_LINK(GetFocusHdl, weld::Widget&, void);
+    DECL_LINK(LoseFocusHdl, weld::Widget&, void);
+    DECL_LINK(AsyncFocusInHdl, void*, void);
+    DECL_LINK(AsyncFocusOutHdl, void*, void);
     DECL_LINK(Modify, weld::Entry&, void);
 
+    void GetFocus();
+    void LoseFocus();
+
     virtual bool KeyInput(const KeyEvent& rKEvt);
 
 public:
diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
index 6b2e557c35bf..f8cc467b5e0e 100644
--- a/vcl/unx/gtk3/gtk3gtkinst.cxx
+++ b/vcl/unx/gtk3/gtk3gtkinst.cxx
@@ -1906,24 +1906,12 @@ protected:
     GtkWidget* m_pMouseEventBox;
     GtkInstanceBuilder* m_pBuilder;
 
-    DECL_LINK(async_signal_focus_in, void*, void);
-    DECL_LINK(async_signal_focus_out, void*, void);
     DECL_LINK(async_drag_cancel, void*, void);
 
-    void launch_signal_focus_in()
-    {
-        // in e.g. function wizard RefEdits we want to select all when we get 
focus
-        // but there are pending gtk handlers which change selection after our 
handler
-        // post our focus in event to happen after those finish
-        if (m_pFocusInEvent)
-            Application::RemoveUserEvent(m_pFocusInEvent);
-        m_pFocusInEvent = Application::PostUserEvent(LINK(this, 
GtkInstanceWidget, async_signal_focus_in));
-    }
-
     static gboolean signalFocusIn(GtkWidget*, GdkEvent*, gpointer widget)
     {
         GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
-        pThis->launch_signal_focus_in();
+        pThis->signal_focus_in();
         return false;
     }
 
@@ -1944,20 +1932,11 @@ protected:
         return m_aMnemonicActivateHdl.Call(*this);
     }
 
-    void launch_signal_focus_out()
-    {
-        // tdf#127262 because focus in is async, focus out must not appear out
-        // of sequence to focus in
-        if (m_pFocusOutEvent)
-            Application::RemoveUserEvent(m_pFocusOutEvent);
-        m_pFocusOutEvent = Application::PostUserEvent(LINK(this, 
GtkInstanceWidget, async_signal_focus_out));
-    }
-
     static gboolean signalFocusOut(GtkWidget*, GdkEvent*, gpointer widget)
     {
         GtkInstanceWidget* pThis = static_cast<GtkInstanceWidget*>(widget);
         SolarMutexGuard aGuard;
-        pThis->launch_signal_focus_out();
+        pThis->signal_focus_out();
         return false;
     }
 
@@ -2052,8 +2031,6 @@ private:
     int m_nPressedButton;
     int m_nPressStartX;
     int m_nPressStartY;
-    ImplSVEvent* m_pFocusInEvent;
-    ImplSVEvent* m_pFocusOutEvent;
     ImplSVEvent* m_pDragCancelEvent;
     GtkCssProvider* m_pBgCssProvider;
     GdkDragAction m_eDragAction;
@@ -2431,8 +2408,6 @@ public:
         , m_nPressedButton(-1)
         , m_nPressStartX(-1)
         , m_nPressStartY(-1)
-        , m_pFocusInEvent(nullptr)
-        , m_pFocusOutEvent(nullptr)
         , m_pDragCancelEvent(nullptr)
         , m_pBgCssProvider(nullptr)
         , m_eDragAction(GdkDragAction(0))
@@ -3027,10 +3002,6 @@ public:
 
     virtual ~GtkInstanceWidget() override
     {
-        if (m_pFocusInEvent)
-            Application::RemoveUserEvent(m_pFocusInEvent);
-        if (m_pFocusOutEvent)
-            Application::RemoveUserEvent(m_pFocusOutEvent);
         if (m_pDragCancelEvent)
             Application::RemoveUserEvent(m_pDragCancelEvent);
         if (m_nDragMotionSignalId)
@@ -3204,18 +3175,6 @@ public:
 
 }
 
-IMPL_LINK_NOARG(GtkInstanceWidget, async_signal_focus_in, void*, void)
-{
-    m_pFocusInEvent = nullptr;
-    signal_focus_in();
-}
-
-IMPL_LINK_NOARG(GtkInstanceWidget, async_signal_focus_out, void*, void)
-{
-    m_pFocusOutEvent = nullptr;
-    signal_focus_out();
-}
-
 IMPL_LINK(GtkInstanceWidget, async_drag_cancel, void*, arg, void)
 {
     m_pDragCancelEvent = nullptr;
@@ -15671,15 +15630,15 @@ public:
     virtual void connect_focus_in(const Link<Widget&, void>& rLink) override
     {
         if (!m_nToggleFocusInSignalId)
-            m_nToggleFocusInSignalId = g_signal_connect(m_pToggleButton, 
"focus-in-event", G_CALLBACK(signalFocusIn), this);
-        weld::Widget::connect_focus_in(rLink);
+            m_nToggleFocusInSignalId = g_signal_connect_after(m_pToggleButton, 
"focus-in-event", G_CALLBACK(signalFocusIn), this);
+        GtkInstanceContainer::connect_focus_in(rLink);
     }
 
     virtual void connect_focus_out(const Link<Widget&, void>& rLink) override
     {
         if (!m_nToggleFocusOutSignalId)
-            m_nToggleFocusOutSignalId = g_signal_connect(m_pToggleButton, 
"focus-out-event", G_CALLBACK(signalFocusOut), this);
-        weld::Widget::connect_focus_out(rLink);
+            m_nToggleFocusOutSignalId = 
g_signal_connect_after(m_pToggleButton, "focus-out-event", 
G_CALLBACK(signalFocusOut), this);
+        GtkInstanceContainer::connect_focus_out(rLink);
     }
 
     virtual void grab_focus() override

Reply via email to