diff options
author | Caolán McNamara <caolanm@redhat.com> | 2021-02-18 14:56:01 +0000 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2021-02-18 21:04:32 +0100 |
commit | c56e0c791a79dc414108e1b2fbf0f7eb38657f10 (patch) | |
tree | 902ac8d87e5e8021353720467dbe379fbc46f546 | |
parent | 28557f54caf924240e6d698a9d2f1e2bc1cf3ab4 (diff) |
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 <caolanm@redhat.com>
-rw-r--r-- | formula/source/ui/dlg/funcutl.cxx | 48 | ||||
-rw-r--r-- | include/formula/funcutl.hxx | 13 | ||||
-rw-r--r-- | vcl/unx/gtk3/gtk3gtkinst.cxx | 73 |
3 files changed, 70 insertions, 64 deletions
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 915152466174..e94f29115068 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; @@ -49,10 +53,15 @@ private: DECL_LINK( UpdateHdl, Timer*, void ); 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(); + protected: virtual bool KeyInput(const KeyEvent& rKEvt); diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx index 9a9f80ef9f46..a8191a29a2ed 100644 --- a/vcl/unx/gtk3/gtk3gtkinst.cxx +++ b/vcl/unx/gtk3/gtk3gtkinst.cxx @@ -1941,34 +1941,22 @@ 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() - { - GtkWidget* pTopLevel = gtk_widget_get_toplevel(m_pWidget); - // see commentary in GtkSalObjectWidgetClip::Show - if (pTopLevel && g_object_get_data(G_OBJECT(pTopLevel), "g-lo-BlockFocusChange")) - return; - - // 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; } void signal_focus_in() { + GtkWidget* pTopLevel = gtk_widget_get_toplevel(m_pWidget); + // see commentary in GtkSalObjectWidgetClip::Show + if (pTopLevel && g_object_get_data(G_OBJECT(pTopLevel), "g-lo-BlockFocusChange")) + return; + m_aFocusInHdl.Call(*this); } @@ -1984,25 +1972,11 @@ protected: return m_aMnemonicActivateHdl.Call(*this); } - void launch_signal_focus_out() - { - GtkWidget* pTopLevel = gtk_widget_get_toplevel(m_pWidget); - // see commentary in GtkSalObjectWidgetClip::Show - if (pTopLevel && g_object_get_data(G_OBJECT(pTopLevel), "g-lo-BlockFocusChange")) - return; - - // 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; } @@ -2017,6 +1991,11 @@ protected: void signal_focus_out() { + GtkWidget* pTopLevel = gtk_widget_get_toplevel(m_pWidget); + // see commentary in GtkSalObjectWidgetClip::Show + if (pTopLevel && g_object_get_data(G_OBJECT(pTopLevel), "g-lo-BlockFocusChange")) + return; + m_aFocusOutHdl.Call(*this); } @@ -2094,8 +2073,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; @@ -2467,8 +2444,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)) @@ -3058,10 +3033,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) @@ -3235,18 +3206,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; @@ -15862,15 +15821,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 |