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