summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaolán McNamara <caolanm@redhat.com>2021-02-18 14:56:01 +0000
committerCaolán McNamara <caolanm@redhat.com>2021-02-18 21:04:32 +0100
commitc56e0c791a79dc414108e1b2fbf0f7eb38657f10 (patch)
tree902ac8d87e5e8021353720467dbe379fbc46f546
parent28557f54caf924240e6d698a9d2f1e2bc1cf3ab4 (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.cxx48
-rw-r--r--include/formula/funcutl.hxx13
-rw-r--r--vcl/unx/gtk3/gtk3gtkinst.cxx73
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