diff options
author | Caolán McNamara <caolanm@redhat.com> | 2021-01-28 20:20:56 +0000 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2021-01-29 10:16:48 +0100 |
commit | 697399a78f17f5277d3e2962aa7b92e610619abe (patch) | |
tree | 76d979536fe698da151f314d6f8946ccc907b710 | |
parent | 6c30a605b1d59d31b9a46b6d33ac56a46621dec4 (diff) |
keep focus in GtkSalObject child on gtk_widget_hide
gtk will take the focus out on hiding the GtkSalObject's child widget,
we want to keep it in. e.g. writer's comments in margin feature put
cursor in a sidebar comment and scroll the page so the comment is
invisible, we want the focus to stay in the invisible widget, so its
there when we scroll back or on a keypress the widget gets the keystroke
and scrolls back to make it visible again
Change-Id: If200779ef1b9cdfa9c4b027c27eca0afd5013ac5
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/110094
Tested-by: Caolán McNamara <caolanm@redhat.com>
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
-rw-r--r-- | vcl/unx/gtk3/gtk3gtkframe.cxx | 5 | ||||
-rw-r--r-- | vcl/unx/gtk3/gtk3gtkinst.cxx | 10 | ||||
-rw-r--r-- | vcl/unx/gtk3/gtk3gtkobject.cxx | 30 |
3 files changed, 40 insertions, 5 deletions
diff --git a/vcl/unx/gtk3/gtk3gtkframe.cxx b/vcl/unx/gtk3/gtk3gtkframe.cxx index 4243763a3158..fb013d2a95ca 100644 --- a/vcl/unx/gtk3/gtk3gtkframe.cxx +++ b/vcl/unx/gtk3/gtk3gtkframe.cxx @@ -3188,6 +3188,11 @@ void GtkSalFrame::signalSetFocus(GtkWindow*, GtkWidget* pWidget, gpointer frame) else pGrabWidget = GTK_WIDGET(pThis->m_pFixedContainer); + GtkWidget* pTopLevel = gtk_widget_get_toplevel(pGrabWidget); + // see commentary in GtkSalObjectWidgetClip::Show + if (pTopLevel && g_object_get_data(G_OBJECT(pTopLevel), "g-lo-BlockFocusChange")) + return; + // tdf#129634 interpret losing focus as focus passing explicitly to another widget bool bLoseFocus = pWidget && pWidget != pGrabWidget; diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx index a42dbd5f4d8b..38708be5d273 100644 --- a/vcl/unx/gtk3/gtk3gtkinst.cxx +++ b/vcl/unx/gtk3/gtk3gtkinst.cxx @@ -1935,6 +1935,11 @@ protected: 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 @@ -1969,6 +1974,11 @@ protected: 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) diff --git a/vcl/unx/gtk3/gtk3gtkobject.cxx b/vcl/unx/gtk3/gtk3gtkobject.cxx index d9de95926611..5923088b79ee 100644 --- a/vcl/unx/gtk3/gtk3gtkobject.cxx +++ b/vcl/unx/gtk3/gtk3gtkobject.cxx @@ -415,12 +415,32 @@ void GtkSalObjectWidgetClip::Reparent(SalFrame* pFrame) void GtkSalObjectWidgetClip::Show( bool bVisible ) { - if( m_pSocket ) + if (!m_pSocket) + return; + bool bCurrentVis = gtk_widget_get_visible(m_pScrolledWindow); + if (bVisible == bCurrentVis) + return; + if( bVisible ) + gtk_widget_show(m_pScrolledWindow); + else { - if( bVisible ) - gtk_widget_show(m_pScrolledWindow); - else - gtk_widget_hide(m_pScrolledWindow); + // on hiding the widget, if a child has focus gtk will want to move the focus out of the widget + // but we want to keep the focus where it is, e.g. writer's comments in margin feature put + // cursor in a sidebar comment and scroll the page so the comment is invisible, we want the focus + // to stay in the invisible widget, so its there when we scroll back or on a keypress the widget + // gets the keystroke and scrolls back to make it visible again + GtkWidget* pTopLevel = gtk_widget_get_toplevel(m_pScrolledWindow); + GtkWidget* pOldFocus = GTK_IS_WINDOW(pTopLevel) ? gtk_window_get_focus(GTK_WINDOW(pTopLevel)) : nullptr; + + g_object_set_data(G_OBJECT(pTopLevel), "g-lo-BlockFocusChange", GINT_TO_POINTER(true) ); + + gtk_widget_hide(m_pScrolledWindow); + + GtkWidget* pNewFocus = GTK_IS_WINDOW(pTopLevel) ? gtk_window_get_focus(GTK_WINDOW(pTopLevel)) : nullptr; + if (pOldFocus && pOldFocus != pNewFocus) + gtk_widget_grab_focus(pOldFocus); + + g_object_set_data(G_OBJECT(pTopLevel), "g-lo-BlockFocusChange", GINT_TO_POINTER(false) ); } } |