[Libreoffice-commits] core.git: 2 commits - vcl/inc vcl/unx
Caolán McNamara (via logerrit)
logerrit at kemper.freedesktop.org
Fri Sep 10 16:58:15 UTC 2021
vcl/inc/unx/gtk/gtkframe.hxx | 3 -
vcl/unx/gtk3/gtkframe.cxx | 120 +++++++++++++++++++++++++++++++++++++++----
2 files changed, 113 insertions(+), 10 deletions(-)
New commits:
commit 3a87142bd2e810deb19c9562ba5a388fbc754c29
Author: Caolán McNamara <caolanm at redhat.com>
AuthorDate: Fri Sep 10 12:31:31 2021 +0100
Commit: Caolán McNamara <caolanm at redhat.com>
CommitDate: Fri Sep 10 18:57:50 2021 +0200
gtk4: use gtk_event_controller_key_forward to see if toplevel would use key
Change-Id: Ia0074daab6528f561169ecaf5544fa1c969a7103
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/121899
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm at redhat.com>
diff --git a/vcl/inc/unx/gtk/gtkframe.hxx b/vcl/inc/unx/gtk/gtkframe.hxx
index 685c2c306894..e07be386930f 100644
--- a/vcl/inc/unx/gtk/gtkframe.hxx
+++ b/vcl/inc/unx/gtk/gtkframe.hxx
@@ -311,9 +311,10 @@ class GtkSalFrame final : public SalFrame
bool WindowCloseRequest();
void DrawingAreaMotion(int nEventX, int nEventY, guint32 nTime, guint nState);
void DrawingAreaCrossing(SalEvent nEventType, int nEventX, int nEventY, guint32 nTime, guint nState);
- bool DrawingAreaKey(SalEvent nEventType, guint keyval, guint keycode, guint32 nTime, guint nState);
void DrawingAreaScroll(double delta_x, double delta_y, int nEventX, int nEventY, guint32 nTime, guint nState);
#if GTK_CHECK_VERSION(4, 0, 0)
+ bool DrawingAreaKey(GtkEventControllerKey* pController, SalEvent nEventType, guint keyval, guint keycode, guint nState);
+
static void signalMap(GtkWidget*, gpointer);
static void signalUnmap(GtkWidget*, gpointer);
diff --git a/vcl/unx/gtk3/gtkframe.cxx b/vcl/unx/gtk3/gtkframe.cxx
index 9a6e386d0588..97ba1f4ea380 100644
--- a/vcl/unx/gtk3/gtkframe.cxx
+++ b/vcl/unx/gtk3/gtkframe.cxx
@@ -3980,10 +3980,52 @@ gboolean GtkSalFrame::signalKey(GtkWidget* pWidget, GdkEventKey* pEvent, gpointe
}
#else
-bool GtkSalFrame::DrawingAreaKey(SalEvent nEventType, guint keyval, guint keycode, guint32 nTime, guint state)
+bool GtkSalFrame::DrawingAreaKey(GtkEventControllerKey* pController, SalEvent nEventType, guint keyval, guint keycode, guint state)
{
+ guint32 nTime = gdk_event_get_time(gtk_event_controller_get_current_event(GTK_EVENT_CONTROLLER(pController)));
UpdateLastInputEventTime(nTime);
+ bool bFocusInAnotherGtkWidget = false;
+
+ VclPtr<vcl::Window> xTopLevelInterimWindow;
+
+ if (GTK_IS_WINDOW(m_pWindow))
+ {
+ GtkWidget* pFocusWindow = gtk_window_get_focus(GTK_WINDOW(m_pWindow));
+ bFocusInAnotherGtkWidget = pFocusWindow && pFocusWindow != GTK_WIDGET(m_pFixedContainer);
+ if (bFocusInAnotherGtkWidget)
+ {
+ if (!gtk_widget_get_realized(pFocusWindow))
+ return true;
+ // if the focus is not in our main widget, see if there is a handler
+ // for this key stroke in GtkWindow first
+ bool bHandled = gtk_event_controller_key_forward(pController, m_pWindow);
+ if (bHandled)
+ return true;
+
+ // Is focus inside an InterimItemWindow? In which case find that
+ // InterimItemWindow and send unconsumed keystrokes to it to
+ // support ctrl-q etc shortcuts. Only bother to search for the
+ // InterimItemWindow if it is a toplevel that fills its frame, or
+ // the keystroke is sufficiently special its worth passing on,
+ // e.g. F6 to switch between task-panels or F5 to close a navigator
+ if (IsCycleFocusOutDisallowed() || IsFunctionKeyVal(keyval))
+ {
+ GtkWidget* pSearch = pFocusWindow;
+ while (pSearch)
+ {
+ void* pData = g_object_get_data(G_OBJECT(pSearch), "InterimWindowGlue");
+ if (pData)
+ {
+ xTopLevelInterimWindow = static_cast<vcl::Window*>(pData);
+ break;
+ }
+ pSearch = gtk_widget_get_parent(pSearch);
+ }
+ }
+ }
+ }
+
vcl::DeletionListener aDel(this);
bool bStopProcessingKey = false;
@@ -4062,6 +4104,32 @@ bool GtkSalFrame::DrawingAreaKey(SalEvent nEventType, guint keyval, guint keycod
}
else
{
+ bool bRestoreDisallowCycleFocusOut = false;
+
+ VclPtr<vcl::Window> xOrigFrameFocusWin;
+ VclPtr<vcl::Window> xOrigFocusWin;
+ if (xTopLevelInterimWindow)
+ {
+ // Focus is inside an InterimItemWindow so send unconsumed
+ // keystrokes to by setting it as the mpFocusWin
+ VclPtr<vcl::Window> xVclWindow = GetWindow();
+ ImplFrameData* pFrameData = xVclWindow->ImplGetWindowImpl()->mpFrameData;
+ xOrigFrameFocusWin = pFrameData->mpFocusWin;
+ pFrameData->mpFocusWin = xTopLevelInterimWindow;
+
+ ImplSVData* pSVData = ImplGetSVData();
+ xOrigFocusWin = pSVData->mpWinData->mpFocusWin;
+ pSVData->mpWinData->mpFocusWin = xTopLevelInterimWindow;
+
+ if (keyval == GDK_KEY_F6 && IsCycleFocusOutDisallowed())
+ {
+ // For F6, allow the focus to leave the InterimItemWindow
+ AllowCycleFocusOut();
+ bRestoreDisallowCycleFocusOut = true;
+ }
+ }
+
+
bStopProcessingKey = doKeyCallback(state,
keyval,
keycode,
@@ -4069,8 +4137,32 @@ bool GtkSalFrame::DrawingAreaKey(SalEvent nEventType, guint keyval, guint keycod
sal_Unicode(gdk_keyval_to_unicode(keyval)),
nEventType == SalEvent::KeyInput,
false);
+
if (!aDel.isDeleted())
+ {
m_nKeyModifiers = ModKeyFlags::NONE;
+
+ if (xTopLevelInterimWindow)
+ {
+ // Focus was inside an InterimItemWindow, restore the original
+ // focus win, unless the focus was changed away from the
+ // InterimItemWindow which should only be possible with F6
+ VclPtr<vcl::Window> xVclWindow = GetWindow();
+ ImplFrameData* pFrameData = xVclWindow->ImplGetWindowImpl()->mpFrameData;
+ if (pFrameData->mpFocusWin == xTopLevelInterimWindow)
+ pFrameData->mpFocusWin = xOrigFrameFocusWin;
+
+ ImplSVData* pSVData = ImplGetSVData();
+ if (pSVData->mpWinData->mpFocusWin == xTopLevelInterimWindow)
+ pSVData->mpWinData->mpFocusWin = xOrigFocusWin;
+
+ if (bRestoreDisallowCycleFocusOut)
+ {
+ // undo the above AllowCycleFocusOut for F6
+ DisallowCycleFocusOut();
+ }
+ }
+ }
}
if (m_pIMHandler)
@@ -4082,15 +4174,13 @@ bool GtkSalFrame::DrawingAreaKey(SalEvent nEventType, guint keyval, guint keycod
gboolean GtkSalFrame::signalKeyPressed(GtkEventControllerKey* pController, guint keyval, guint keycode, GdkModifierType state, gpointer frame)
{
GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
- GdkEvent* pEvent = gtk_event_controller_get_current_event(GTK_EVENT_CONTROLLER(pController));
- return pThis->DrawingAreaKey(SalEvent::KeyInput, keyval, keycode, gdk_event_get_time(pEvent), state);
+ return pThis->DrawingAreaKey(pController, SalEvent::KeyInput, keyval, keycode, state);
}
gboolean GtkSalFrame::signalKeyReleased(GtkEventControllerKey* pController, guint keyval, guint keycode, GdkModifierType state, gpointer frame)
{
GtkSalFrame* pThis = static_cast<GtkSalFrame*>(frame);
- GdkEvent* pEvent = gtk_event_controller_get_current_event(GTK_EVENT_CONTROLLER(pController));
- return pThis->DrawingAreaKey(SalEvent::KeyUp, keyval, keycode, gdk_event_get_time(pEvent), state);
+ return pThis->DrawingAreaKey(pController, SalEvent::KeyUp, keyval, keycode, state);
}
#endif
commit 0ce5ded132342d8420caab94e7376b0f33826f28
Author: Caolán McNamara <caolanm at redhat.com>
AuthorDate: Fri Sep 10 12:41:09 2021 +0100
Commit: Caolán McNamara <caolanm at redhat.com>
CommitDate: Fri Sep 10 18:57:35 2021 +0200
gtk4: we don't need to block the drawing area as a focus candidate
because we put that as a child of the overlay so its not a focus
candidate in the gtk4 version, and blocking the FixedContainer
in gtk4 means none of its children can have focus since gtk4 and
that the opposite of what we want to make focus traversal work
between native gtk widgets
Change-Id: Ide59e816189b5a89d13be9205d1fc9579ae33f92
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/121900
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm at redhat.com>
diff --git a/vcl/unx/gtk3/gtkframe.cxx b/vcl/unx/gtk3/gtkframe.cxx
index 807d5e8b5445..9a6e386d0588 100644
--- a/vcl/unx/gtk3/gtkframe.cxx
+++ b/vcl/unx/gtk3/gtkframe.cxx
@@ -1193,10 +1193,15 @@ void GtkSalFrame::DisallowCycleFocusOut()
g_signal_handler_disconnect(G_OBJECT(m_pWindow), m_nSetFocusSignalId);
m_nSetFocusSignalId = 0;
- // set container without can-focus and focus will tab between
+#if !GTK_CHECK_VERSION(4, 0, 0)
+ // gtk3: set container without can-focus and focus will tab between
// the native embedded widgets using the default gtk handling for
// that
+ // gtk4: no need because the native widgets are the only
+ // thing in the overlay and the drawing widget is underneath so
+ // the natural focus cycle is sufficient
gtk_widget_set_can_focus(GTK_WIDGET(m_pFixedContainer), false);
+#endif
}
bool GtkSalFrame::IsCycleFocusOutDisallowed() const
@@ -1216,10 +1221,15 @@ void GtkSalFrame::AllowCycleFocusOut()
m_nSetFocusSignalId = g_signal_connect(G_OBJECT(m_pWindow), "notify::focus-widget", G_CALLBACK(signalSetFocus), this);
#endif
+#if !GTK_CHECK_VERSION(4, 0, 0)
// set container without can-focus and focus will tab between
// the native embedded widgets using the default gtk handling for
// that
+ // gtk4: no need because the native widgets are the only
+ // thing in the overlay and the drawing widget is underneath so
+ // the natural focus cycle is sufficient
gtk_widget_set_can_focus(GTK_WIDGET(m_pFixedContainer), true);
+#endif
}
@@ -2877,14 +2887,14 @@ void GtkSalFrame::GrabFocus()
pGrabWidget = GTK_WIDGET(m_pWindow);
else
pGrabWidget = GTK_WIDGET(m_pFixedContainer);
-#else
- pGrabWidget = GTK_WIDGET(m_pFixedContainer);
-#endif
// m_nSetFocusSignalId is 0 for the DisallowCycleFocusOut case where
// we don't allow focus to enter the toplevel, but expect it to
// stay in some embedded native gtk widget
if (!gtk_widget_get_can_focus(pGrabWidget) && m_nSetFocusSignalId)
gtk_widget_set_can_focus(pGrabWidget, true);
+#else
+ pGrabWidget = GTK_WIDGET(m_pFixedContainer);
+#endif
if (!gtk_widget_has_focus(pGrabWidget))
{
gtk_widget_grab_focus(pGrabWidget);
@@ -3710,7 +3720,9 @@ void GtkSalFrame::signalSetFocus(GtkWindow*, GParamSpec*, gpointer frame)
// do not propagate focus get/lose if floats are open
pThis->CallCallbackExc(bLoseFocus ? SalEvent::LoseFocus : SalEvent::GetFocus, nullptr);
+#if !GTK_CHECK_VERSION(4, 0, 0)
gtk_widget_set_can_focus(GTK_WIDGET(pThis->m_pFixedContainer), !bLoseFocus);
+#endif
}
void GtkSalFrame::WindowMap()
More information about the Libreoffice-commits
mailing list