diff options
author | Caolán McNamara <caolanm@redhat.com> | 2020-10-21 12:23:57 +0100 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2020-10-22 15:06:48 +0200 |
commit | 606c65c90cb3e8abdd74540195b7cb01ba88adc8 (patch) | |
tree | 0942df8d5d5357e50fb13c59966c49dd54c0379b /vcl | |
parent | a87af93ff874a55b81e55b46b63798fde4cefc4f (diff) |
for DisallowCycleFocusOut forward unused keyevents to InterimItemWindow
for ctrl+q etc
Change-Id: Ie0ad94cf0e85693960428ffee5ae4a0ecffb7c6b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/104635
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/inc/unx/gtk/gtkframe.hxx | 2 | ||||
-rw-r--r-- | vcl/unx/gtk3/gtk3gtkframe.cxx | 77 | ||||
-rw-r--r-- | vcl/unx/gtk3/gtk3gtkinst.cxx | 43 |
3 files changed, 107 insertions, 15 deletions
diff --git a/vcl/inc/unx/gtk/gtkframe.hxx b/vcl/inc/unx/gtk/gtkframe.hxx index 27865f2efb12..820d796bf6e5 100644 --- a/vcl/inc/unx/gtk/gtkframe.hxx +++ b/vcl/inc/unx/gtk/gtkframe.hxx @@ -530,6 +530,8 @@ public: static OUString GetPreeditDetails(GtkIMContext* pIMContext, std::vector<ExtTextInputAttr>& rInputFlags, sal_Int32& rCursorPos, sal_uInt8& rCursorFlags); void DisallowCycleFocusOut(); + bool IsCycleFocusOutDisallowed() const; + void AllowCycleFocusOut(); }; #define OOO_TYPE_FIXED ooo_fixed_get_type() diff --git a/vcl/unx/gtk3/gtk3gtkframe.cxx b/vcl/unx/gtk3/gtk3gtkframe.cxx index 26c34a09c9d4..eb964a790533 100644 --- a/vcl/unx/gtk3/gtk3gtkframe.cxx +++ b/vcl/unx/gtk3/gtk3gtkframe.cxx @@ -1026,6 +1026,26 @@ void GtkSalFrame::DisallowCycleFocusOut() gtk_widget_set_can_focus(GTK_WIDGET(m_pFixedContainer), false); } +bool GtkSalFrame::IsCycleFocusOutDisallowed() const +{ + return m_nSetFocusSignalId == 0; +} + +void GtkSalFrame::AllowCycleFocusOut() +{ + if (m_nSetFocusSignalId) + return; + // enable/disable can-focus as control enters and leaves + // embedded native gtk widgets + m_nSetFocusSignalId = g_signal_connect(G_OBJECT(m_pWindow), "set-focus", G_CALLBACK(signalSetFocus), this); + + // set container without can-focus and focus will tab between + // the native embedded widgets using the default gtk handling for + // that + gtk_widget_set_can_focus(GTK_WIDGET(m_pFixedContainer), true); +} + + void GtkSalFrame::Init( SalFrame* pParent, SalFrameStyleFlags nStyle ) { if( nStyle & SalFrameStyleFlags::DEFAULT ) // ensure default style @@ -3198,6 +3218,8 @@ gboolean GtkSalFrame::signalKey(GtkWidget* pWidget, GdkEventKey* pEvent, gpointe bool bFocusInAnotherGtkWidget = false; + VclPtr<vcl::Window> xTopLevelInterimWindow; + if (GTK_IS_WINDOW(pThis->m_pWindow)) { GtkWidget* pFocusWindow = gtk_window_get_focus(GTK_WINDOW(pThis->m_pWindow)); @@ -3216,6 +3238,24 @@ gboolean GtkSalFrame::signalKey(GtkWidget* pWidget, GdkEventKey* pEvent, gpointe g_type_class_unref(pClass); if (bHandled) return true; + + // Is focus inside a full-app InterimItemWindow? In which case find + // that InterimItemWindow and send unconsumed keystrokes to it to + // support ctrl-q etc shortcuts + if (pThis->IsCycleFocusOutDisallowed()) + { + 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); + } + } } } @@ -3303,6 +3343,22 @@ gboolean GtkSalFrame::signalKey(GtkWidget* pWidget, GdkEventKey* pEvent, gpointe } else { + VclPtr<vcl::Window> xOrigFocusWin; + if (xTopLevelInterimWindow) + { + // Focus is inside a full-app InterimItemWindow send unconsumed + // keystrokes to by setting it as the mpFocusWin + VclPtr<vcl::Window> xVclWindow = pThis->GetWindow(); + ImplFrameData* pFrameData = xVclWindow->ImplGetWindowImpl()->mpFrameData; + xOrigFocusWin = pFrameData->mpFocusWin; + pFrameData->mpFocusWin = xTopLevelInterimWindow; + if (pEvent->keyval == GDK_KEY_F6) + { + // For F6, allow the focus to leave the InterimItemWindow + pThis->AllowCycleFocusOut(); + } + } + bStopProcessingKey = pThis->doKeyCallback(pEvent->state, pEvent->keyval, pEvent->hardware_keycode, @@ -3310,8 +3366,27 @@ gboolean GtkSalFrame::signalKey(GtkWidget* pWidget, GdkEventKey* pEvent, gpointe sal_Unicode(gdk_keyval_to_unicode( pEvent->keyval )), (pEvent->type == GDK_KEY_PRESS), false); - if( ! aDel.isDeleted() ) + if (!aDel.isDeleted()) + { pThis->m_nKeyModifiers = ModKeyFlags::NONE; + + if (xTopLevelInterimWindow) + { + // Focus was inside a full-app 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 = pThis->GetWindow(); + ImplFrameData* pFrameData = xVclWindow->ImplGetWindowImpl()->mpFrameData; + if (pFrameData->mpFocusWin == xTopLevelInterimWindow) + pFrameData->mpFocusWin = xOrigFocusWin; + if (pEvent->keyval == GDK_KEY_F6) + { + // undo the above AllowCycleFocusOut for F6 + pThis->DisallowCycleFocusOut(); + } + } + } + } if (!bFocusInAnotherGtkWidget && !aDel.isDeleted() && pThis->m_pIMHandler) diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx index 6448e3733256..13f97ceb7df9 100644 --- a/vcl/unx/gtk3/gtk3gtkinst.cxx +++ b/vcl/unx/gtk3/gtk3gtkinst.cxx @@ -16291,6 +16291,7 @@ private: std::vector<GtkLabel*> m_aMnemonicLabels; VclPtr<SystemChildWindow> m_xInterimGlue; + bool m_bAllowCycleFocusOut; void postprocess_widget(GtkWidget* pWidget) { @@ -16458,12 +16459,14 @@ private: pThis->postprocess_widget(GTK_WIDGET(pObject)); } public: - GtkInstanceBuilder(GtkWidget* pParent, const OUString& rUIRoot, const OUString& rUIFile, SystemChildWindow* pInterimGlue) + GtkInstanceBuilder(GtkWidget* pParent, const OUString& rUIRoot, const OUString& rUIFile, + SystemChildWindow* pInterimGlue, bool bAllowCycleFocusOut) : weld::Builder() , m_pStringReplace(Translate::GetReadStringHook()) , m_pParentWidget(pParent) , m_nNotifySignalId(0) , m_xInterimGlue(pInterimGlue) + , m_bAllowCycleFocusOut(bAllowCycleFocusOut) { OUString sHelpRoot(rUIFile); ensure_intercept_drawing_area_accessibility(); @@ -16495,6 +16498,17 @@ public: { assert(m_pParentWidget); g_object_set_data(G_OBJECT(m_pParentWidget), "InterimWindowGlue", m_xInterimGlue.get()); + + if (!m_bAllowCycleFocusOut) + { + GtkWidget* pTopLevel = gtk_widget_get_toplevel(m_pParentWidget); + assert(pTopLevel); + GtkSalFrame* pFrame = GtkSalFrame::getFromWindow(pTopLevel); + assert(pFrame); + // unhook handler and let gtk cycle its own way through this widget's + // children because it has no non-gtk siblings + pFrame->DisallowCycleFocusOut(); + } } } @@ -16555,6 +16569,18 @@ public: { g_slist_free(m_pObjectList); g_object_unref(m_pBuilder); + + if (m_xInterimGlue && !m_bAllowCycleFocusOut) + { + GtkWidget* pTopLevel = gtk_widget_get_toplevel(m_pParentWidget); + assert(pTopLevel); + GtkSalFrame* pFrame = GtkSalFrame::getFromWindow(pTopLevel); + assert(pFrame); + // rehook handler and let vcl cycle its own way through this widget's + // children + pFrame->AllowCycleFocusOut(); + } + m_xInterimGlue.disposeAndClear(); } @@ -17048,7 +17074,7 @@ weld::Builder* GtkInstance::CreateBuilder(weld::Widget* pParent, const OUString& if (pParent && !pParentWidget) //remove when complete return SalInstance::CreateBuilder(pParent, rUIRoot, rUIFile); GtkWidget* pBuilderParent = pParentWidget ? pParentWidget->getWidget() : nullptr; - return new GtkInstanceBuilder(pBuilderParent, rUIRoot, rUIFile, nullptr); + return new GtkInstanceBuilder(pBuilderParent, rUIRoot, rUIFile, nullptr, true); } // tdf#135965 for the case of native widgets inside a GtkSalFrame and F1 pressed, run help @@ -17122,19 +17148,8 @@ weld::Builder* GtkInstance::CreateInterimBuilder(vcl::Window* pParent, const OUS GtkWidget *pWindow = static_cast<GtkWidget*>(pEnvData->pWidget); gtk_widget_show_all(pWindow); - if (!bAllowCycleFocusOut) - { - GtkWidget* pTopLevel = gtk_widget_get_toplevel(pWindow); - assert(pTopLevel); - GtkSalFrame* pFrame = GtkSalFrame::getFromWindow(pTopLevel); - assert(pFrame); - // unhook handler and let gtk cycle its own way through this widget's - // children because it has no non-gtk siblings - pFrame->DisallowCycleFocusOut(); - } - // build the widget tree as a child of the GtkEventBox GtkGrid parent - return new GtkInstanceBuilder(pWindow, rUIRoot, rUIFile, xEmbedWindow.get()); + return new GtkInstanceBuilder(pWindow, rUIRoot, rUIFile, xEmbedWindow.get(), bAllowCycleFocusOut); } weld::MessageDialog* GtkInstance::CreateMessageDialog(weld::Widget* pParent, VclMessageType eMessageType, VclButtonsType eButtonsType, const OUString &rPrimaryMessage) |