include/vcl/event.hxx | 2 include/vcl/window.hxx | 1 sfx2/source/view/frame2.cxx | 34 +++++---- vcl/inc/salframe.hxx | 4 + vcl/source/window/dialog.cxx | 10 +- vcl/source/window/window.cxx | 5 + vcl/unx/gtk3/gtk3gtkinst.cxx | 149 ++++++++++++++++++++++++++++++++++++++++--- 7 files changed, 175 insertions(+), 30 deletions(-)
New commits: commit 009a9ebb7cc0de49cd51b11995cf60d0ca45e7d3 Author: Caolán McNamara <caol...@redhat.com> AuthorDate: Fri Jun 14 09:18:44 2019 +0100 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Tue Sep 17 16:14:36 2019 +0200 disable 'quit' menu entry when modal dialog waiting response Traditionally when a modal dialog is active, the quit menu entry of all LibreOffice toplevel frames, not just those which are themselves modal, is get disabled. This has come unstuck because its implemented by dialogs emitting MouseNotifyEvent::[END]EXECUTEDIALOG on its parent, and SfxFrameWindow_Impl listening for that event. But if the dialog parent is the toplevel parent of SfxFrameWindow_Impl then it doesn't get seen by the SfxFrameWindow_Impl child. Reviewed-on: https://gerrit.libreoffice.org/73975 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caol...@redhat.com> Tested-by: Caolán McNamara <caol...@redhat.com> (cherry picked from commit 252239ae30313142195b3da81aea45a89b2d6674) Conflicts: include/vcl/event.hxx include/vcl/window.hxx sfx2/source/view/frame2.cxx vcl/source/window/dialog.cxx vcl/source/window/window.cxx Change-Id: I0c4a5472d16d9169e68f6b0c230d039f1119489a Reviewed-on: https://gerrit.libreoffice.org/79040 Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> Tested-by: Michael Weghorn <m.wegh...@posteo.de> diff --git a/include/vcl/event.hxx b/include/vcl/event.hxx index 050e7199cc45..3a5122eb941a 100644 --- a/include/vcl/event.hxx +++ b/include/vcl/event.hxx @@ -290,8 +290,6 @@ enum class MouseNotifyEvent DESTROY = 9, INPUTENABLE = 10, INPUTDISABLE = 11, - EXECUTEDIALOG = 100, - ENDEXECUTEDIALOG = 101 }; class VCL_DLLPUBLIC NotifyEvent diff --git a/include/vcl/window.hxx b/include/vcl/window.hxx index 3a3ea99d2c0f..f0eaaff573f1 100644 --- a/include/vcl/window.hxx +++ b/include/vcl/window.hxx @@ -1605,6 +1605,7 @@ public: virtual bool IsChart() const { return false; } void SetHelpHdl(const Link<vcl::Window&, bool>& rLink); + void SetModalHierarchyHdl(const Link<bool, void>& rLink); }; } diff --git a/sfx2/source/view/frame2.cxx b/sfx2/source/view/frame2.cxx index 6fc3cff26a7d..e003d9697358 100644 --- a/sfx2/source/view/frame2.cxx +++ b/sfx2/source/view/frame2.cxx @@ -58,9 +58,9 @@ using namespace ::com::sun::star::container; using namespace ::com::sun::star::beans; using ::com::sun::star::frame::XComponentLoader; - class SfxFrameWindow_Impl : public vcl::Window { + DECL_LINK(ModalHierarchyHdl, bool, void); public: SfxFrame* pFrame; @@ -72,13 +72,21 @@ public: virtual bool EventNotify( NotifyEvent& rEvt ) override; virtual void Resize() override; virtual void GetFocus() override; + virtual void dispose() override; void DoResize(); }; -SfxFrameWindow_Impl::SfxFrameWindow_Impl( SfxFrame* pF, vcl::Window& i_rContainerWindow ) - : Window( &i_rContainerWindow, WB_BORDER | WB_CLIPCHILDREN | WB_NODIALOGCONTROL | WB_3DLOOK ) - , pFrame( pF ) +SfxFrameWindow_Impl::SfxFrameWindow_Impl(SfxFrame* pF, vcl::Window& i_rContainerWindow) + : Window(&i_rContainerWindow, WB_BORDER | WB_CLIPCHILDREN | WB_NODIALOGCONTROL | WB_3DLOOK) + , pFrame(pF) +{ + i_rContainerWindow.SetModalHierarchyHdl(LINK(this, SfxFrameWindow_Impl, ModalHierarchyHdl)); +} + +void SfxFrameWindow_Impl::dispose() { + GetParent()->SetModalHierarchyHdl(Link<bool, void>()); + vcl::Window::dispose(); } void SfxFrameWindow_Impl::DataChanged( const DataChangedEvent& rDCEvt ) @@ -116,20 +124,18 @@ bool SfxFrameWindow_Impl::EventNotify( NotifyEvent& rNEvt ) if ( pView->GetViewShell()->KeyInput( *rNEvt.GetKeyEvent() ) ) return true; } - else if ( rNEvt.GetType() == MouseNotifyEvent::EXECUTEDIALOG /*|| rNEvt.GetType() == MouseNotifyEvent::INPUTDISABLE*/ ) - { - pView->SetModalMode( true ); - return true; - } - else if ( rNEvt.GetType() == MouseNotifyEvent::ENDEXECUTEDIALOG /*|| rNEvt.GetType() == MouseNotifyEvent::INPUTENABLE*/ ) - { - pView->SetModalMode( false ); - return true; - } return Window::EventNotify( rNEvt ); } +IMPL_LINK(SfxFrameWindow_Impl, ModalHierarchyHdl, bool, bSetModal, void) +{ + SfxViewFrame* pView = pFrame->GetCurrentViewFrame(); + if (!pView || !pView->GetObjectShell()) + return; + pView->SetModalMode(bSetModal); +} + bool SfxFrameWindow_Impl::PreNotify( NotifyEvent& rNEvt ) { MouseNotifyEvent nType = rNEvt.GetType(); diff --git a/vcl/inc/salframe.hxx b/vcl/inc/salframe.hxx index e2662d415fc2..06d8b1835c03 100644 --- a/vcl/inc/salframe.hxx +++ b/vcl/inc/salframe.hxx @@ -108,6 +108,7 @@ private: // the VCL window corresponding to this frame VclPtr<vcl::Window> m_pWindow; SALFRAMEPROC m_pProc; + Link<bool, void> m_aModalHierarchyHdl; protected: mutable std::unique_ptr<weld::Window> m_xFrameWeld; public: @@ -273,6 +274,9 @@ public: // returns the instance set vcl::Window* GetWindow() const { return m_pWindow; } + void SetModalHierarchyHdl(const Link<bool, void>& rLink) { m_aModalHierarchyHdl = rLink; } + void NotifyModalHierarchy(bool bModal) { m_aModalHierarchyHdl.Call(bModal); } + // Call the callback set; this sometimes necessary for implementation classes // that should not know more than necessary about the SalFrame implementation // (e.g. input methods, printer update handlers). diff --git a/vcl/source/window/dialog.cxx b/vcl/source/window/dialog.cxx index a1d8cf1e6a6c..ef7dfe73c57e 100644 --- a/vcl/source/window/dialog.cxx +++ b/vcl/source/window/dialog.cxx @@ -913,11 +913,13 @@ bool Dialog::ImplStartExecuteModal() pSVData->maWinData.mpCaptureWin->ReleaseMouse(); EnableInput(); + if ( GetParent() ) { - NotifyEvent aNEvt( MouseNotifyEvent::EXECUTEDIALOG, this ); - GetParent()->CompatNotify( aNEvt ); + SalFrame* pFrame = GetParent()->ImplGetFrame(); + pFrame->NotifyModalHierarchy(true); } + mbInExecute = true; // no real modality in LibreOfficeKit if (!bKitActive) @@ -1119,8 +1121,8 @@ void Dialog::EndDialog( long nResult ) Hide(); if ( GetParent() ) { - NotifyEvent aNEvt( MouseNotifyEvent::ENDEXECUTEDIALOG, this ); - GetParent()->CompatNotify( aNEvt ); + SalFrame* pFrame = GetParent()->ImplGetFrame(); + pFrame->NotifyModalHierarchy(false); } mpDialogImpl->mnResult = nResult; diff --git a/vcl/source/window/window.cxx b/vcl/source/window/window.cxx index 3d7a5323227f..d15181288cf2 100644 --- a/vcl/source/window/window.cxx +++ b/vcl/source/window/window.cxx @@ -1760,6 +1760,11 @@ void Window::ImplNewInputContext() pFocusWin->ImplGetFrame()->SetInputContext( &aNewContext ); } +void Window::SetModalHierarchyHdl(const Link<bool, void>& rLink) +{ + ImplGetFrame()->SetModalHierarchyHdl(rLink); +} + void Window::doLazyDelete() { SystemWindow* pSysWin = dynamic_cast<SystemWindow*>(this); commit 330cf24731919c049db1ad18697306dc046de65a Author: Caolán McNamara <caol...@redhat.com> AuthorDate: Sun Sep 9 14:09:37 2018 +0100 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Tue Sep 17 16:14:33 2019 +0200 silence bogus -Wmaybe-uninitialized Change-Id: I702b4818f05a606da30a643e13bfcd2c98ba412a Reviewed-on: https://gerrit.libreoffice.org/60215 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caol...@redhat.com> Tested-by: Caolán McNamara <caol...@redhat.com> (cherry picked from commit b829325fb407250849d9508ed32176b08006dd0a) Reviewed-on: https://gerrit.libreoffice.org/79039 Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> Tested-by: Michael Weghorn <m.wegh...@posteo.de> diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx index 4cb75e50f695..955705cdc72a 100644 --- a/vcl/unx/gtk3/gtk3gtkinst.cxx +++ b/vcl/unx/gtk3/gtk3gtkinst.cxx @@ -1813,7 +1813,7 @@ public: } virtual void set_mode(VclSizeGroupMode eVclMode) override { - GtkSizeGroupMode eGtkMode; + GtkSizeGroupMode eGtkMode(GTK_SIZE_GROUP_NONE); switch (eVclMode) { case VclSizeGroupMode::NONE: commit 65c72516c9e3b915e123d6c715e86ef38ac46374 Author: Caolán McNamara <caol...@redhat.com> AuthorDate: Tue Nov 27 10:18:52 2018 +0000 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Tue Sep 17 16:14:27 2019 +0200 enable hiding gtk dialogs without ending their dialog loop we need this to support reshowing dialog after an intermediate range selection dialog executes Reviewed-on: https://gerrit.libreoffice.org/64100 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caol...@redhat.com> Tested-by: Caolán McNamara <caol...@redhat.com> (cherry picked from commit 471d6c3653b8b8006db022c5d94af7503adfdc56) Conflicts: vcl/unx/gtk3/gtk3gtkinst.cxx Change-Id: Ib6575e5d852bd1d29cc1a791a5dc2c19949b67a0 Reviewed-on: https://gerrit.libreoffice.org/79038 Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> Tested-by: Michael Weghorn <m.wegh...@posteo.de> diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx index 384f1d411e4d..4cb75e50f695 100644 --- a/vcl/unx/gtk3/gtk3gtkinst.cxx +++ b/vcl/unx/gtk3/gtk3gtkinst.cxx @@ -2029,10 +2029,117 @@ namespace } } +struct DialogRunner +{ + GtkDialog *m_pDialog; + gint m_nResponseId; + GMainLoop *m_pLoop; + VclPtr<vcl::Window> m_xFrameWindow; + + DialogRunner(GtkDialog* pDialog) + : m_pDialog(pDialog) + , m_nResponseId(GTK_RESPONSE_NONE) + , m_pLoop(nullptr) + { + GtkWindow* pParent = gtk_window_get_transient_for(GTK_WINDOW(m_pDialog)); + GtkSalFrame* pFrame = GtkSalFrame::getFromWindow(pParent); + m_xFrameWindow = pFrame ? pFrame->GetWindow() : nullptr; + } + + bool loop_is_running() const + { + return m_pLoop && g_main_loop_is_running(m_pLoop); + } + + void loop_quit() + { + if (g_main_loop_is_running(m_pLoop)) + g_main_loop_quit(m_pLoop); + } + + static void signal_response(GtkDialog*, gint nResponseId, gpointer data) + { + DialogRunner* pThis = static_cast<DialogRunner*>(data); + pThis->m_nResponseId = nResponseId; + pThis->loop_quit(); + } + + static gboolean signal_delete(GtkDialog*, GdkEventAny*, gpointer data) + { + DialogRunner* pThis = static_cast<DialogRunner*>(data); + pThis->loop_quit(); + return true; /* Do not destroy */ + } + + static void signal_destroy(GtkDialog*, gpointer data) + { + DialogRunner* pThis = static_cast<DialogRunner*>(data); + pThis->loop_quit(); + } + + void inc_modal_count() + { + if (m_xFrameWindow) + m_xFrameWindow->IncModalCount(); + } + + void dec_modal_count() + { + if (m_xFrameWindow) + m_xFrameWindow->DecModalCount(); + } + + // same as gtk_dialog_run except that unmap doesn't auto-respond + // so we can hide the dialog and restore it without a response getting + // triggered + gint run() + { + g_object_ref(m_pDialog); + + inc_modal_count(); + + bool bWasModal = gtk_window_get_modal(GTK_WINDOW(m_pDialog)); + if (!bWasModal) + gtk_window_set_modal(GTK_WINDOW(m_pDialog), true); + + if (!gtk_widget_get_visible(GTK_WIDGET(m_pDialog))) + gtk_widget_show(GTK_WIDGET(m_pDialog)); + + gulong nSignalResponseId = g_signal_connect(m_pDialog, "response", G_CALLBACK(signal_response), this); + gulong nSignalDeleteId = g_signal_connect(m_pDialog, "delete-event", G_CALLBACK(signal_delete), this); + gulong nSignalDestroyId = g_signal_connect(m_pDialog, "destroy", G_CALLBACK(signal_destroy), this); + + m_pLoop = g_main_loop_new(nullptr, false); + m_nResponseId = GTK_RESPONSE_NONE; + + gdk_threads_leave(); + g_main_loop_run(m_pLoop); + gdk_threads_enter(); + + g_main_loop_unref(m_pLoop); + + m_pLoop = nullptr; + + if (!bWasModal) + gtk_window_set_modal(GTK_WINDOW(m_pDialog), false); + + g_signal_handler_disconnect(m_pDialog, nSignalResponseId); + g_signal_handler_disconnect(m_pDialog, nSignalDeleteId); + g_signal_handler_disconnect(m_pDialog, nSignalDestroyId); + + dec_modal_count(); + + g_object_unref(m_pDialog); + + return m_nResponseId; + } +}; + class GtkInstanceDialog : public GtkInstanceWindow, public virtual weld::Dialog { private: GtkDialog* m_pDialog; + DialogRunner m_aDialogRun; std::shared_ptr<weld::DialogController> m_xDialogController; std::function<void(sal_Int32)> m_aFunc; gulong m_nCloseSignalId; @@ -2082,10 +2189,12 @@ private: m_aFunc = nullptr; m_xDialogController.reset(); } + public: GtkInstanceDialog(GtkDialog* pDialog, bool bTakeOwnership) : GtkInstanceWindow(GTK_WINDOW(pDialog), bTakeOwnership) , m_pDialog(pDialog) + , m_aDialogRun(pDialog) , m_nCloseSignalId(g_signal_connect(m_pDialog, "close", G_CALLBACK(signalClose), this)) , m_nResponseSignalId(0) { @@ -2115,16 +2224,9 @@ public: { sort_native_button_order(GTK_BOX(gtk_dialog_get_action_area(m_pDialog))); int ret; - GtkWindow* pParent = gtk_window_get_transient_for(GTK_WINDOW(m_pDialog)); - GtkSalFrame* pFrame = GtkSalFrame::getFromWindow(pParent); - vcl::Window* pFrameWindow = pFrame ? pFrame->GetWindow() : nullptr; while (true) { - if (pFrameWindow) - pFrameWindow->IncModalCount(); - ret = gtk_dialog_run(m_pDialog); - if (pFrameWindow) - pFrameWindow->DecModalCount(); + ret = m_aDialogRun.run(); if (ret == GTK_RESPONSE_HELP) { help(); @@ -2139,6 +2241,34 @@ public: return GtkToVcl(ret); } + virtual void hide() override + { + if (!gtk_widget_get_visible(m_pWidget)) + return; + gtk_widget_hide(m_pWidget); + // if we hide the dialog while its running, then decrement the parent LibreOffice window + // modal count, we expect the dialog to restored while its running and match up with + // the inc_modal_count of show() + // + // This hide while running case is for the calc/chart dialogs which put + // up an extra range chooser dialog, hides the original, the user can + // select a range of cells and on completion the original dialog is + // restored + if (m_aDialogRun.loop_is_running()) + m_aDialogRun.dec_modal_count(); + } + + virtual void show() override + { + if (gtk_widget_get_visible(m_pWidget)) + return; + sort_native_button_order(GTK_BOX(gtk_dialog_get_action_area(m_pDialog))); + gtk_widget_show(m_pWidget); + // see hide comment + if (m_aDialogRun.loop_is_running()) + m_aDialogRun.inc_modal_count(); + } + static int VclToGtk(int nResponse) { if (nResponse == RET_OK) @@ -2359,7 +2489,6 @@ static void crippled_viewport_class_init(GtkViewportClass *klass) /* GObject signals */ o_class->set_property = crippled_viewport_set_property; o_class->get_property = crippled_viewport_get_property; -// o_class->finalize = gtk_tree_view_finalize; /* Properties */ g_object_class_override_property(o_class, PROP_HADJUSTMENT, "hadjustment"); _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits