[Libreoffice-commits] core.git: vcl/source vcl/unx

Caolán McNamara (via logerrit) logerrit at kemper.freedesktop.org
Fri May 17 09:00:42 UTC 2019


 vcl/source/window/dialog.cxx |   18 +++++
 vcl/unx/gtk3/gtk3gtkinst.cxx |  141 +++++++++++++++++++++++++++++--------------
 2 files changed, 114 insertions(+), 45 deletions(-)

New commits:
commit 644ca26af744aec1e66c8dd4199d1228e0f780be
Author:     Caolán McNamara <caolanm at redhat.com>
AuthorDate: Tue May 14 21:50:36 2019 +0100
Commit:     Caolán McNamara <caolanm at redhat.com>
CommitDate: Fri May 17 10:59:44 2019 +0200

    allow closing welded dialogs to be cancelled
    
    from both directions of window manager close button and esc
    
    Change-Id: I3c7bd6f67e3100f5dd3ab04456ad9aa5100c472c
    Reviewed-on: https://gerrit.libreoffice.org/72319
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>
    Tested-by: Caolán McNamara <caolanm at redhat.com>

diff --git a/vcl/source/window/dialog.cxx b/vcl/source/window/dialog.cxx
index 21957995644e..5348e206f2c0 100644
--- a/vcl/source/window/dialog.cxx
+++ b/vcl/source/window/dialog.cxx
@@ -835,8 +835,26 @@ bool Dialog::Close()
     if ( mpWindowImpl->mxWindowPeer.is() && IsCreatedWithToolkit() && !IsInExecute() )
         return false;
 
+    // If there's a cancel button with a custom handler, then always give it a chance to
+    // handle Dialog::Close
+    PushButton* pCustomCancelButton;
+    PushButton* pCancelButton = dynamic_cast<PushButton*>(get_widget_for_response(RET_CANCEL));
+    if (!mbInClose && pCancelButton && pCancelButton->GetClickHdl().IsSet())
+        pCustomCancelButton = pCancelButton;
+    else
+        pCustomCancelButton = nullptr;
+
     mbInClose = true;
 
+    if (pCustomCancelButton)
+    {
+        pCustomCancelButton->Click();
+        if (xWindow->IsDisposed())
+            return true;
+        mbInClose = false;
+        return false;
+    }
+
     if ( !(GetStyle() & WB_CLOSEABLE) )
     {
         bool bRet = true;
diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
index dac1bccae151..0d60969bff8d 100644
--- a/vcl/unx/gtk3/gtk3gtkinst.cxx
+++ b/vcl/unx/gtk3/gtk3gtkinst.cxx
@@ -2995,6 +2995,8 @@ namespace
     }
 }
 
+class GtkInstanceButton;
+
 class GtkInstanceDialog : public GtkInstanceWindow, public virtual weld::Dialog
 {
 private:
@@ -3006,6 +3008,7 @@ private:
     std::function<void(sal_Int32)> m_aFunc;
     gulong m_nCloseSignalId;
     gulong m_nResponseSignalId;
+    gulong m_nSignalDeleteId;
 
     // for calc ref dialog that shrink to range selection widgets and resize back
     GtkWidget* m_pRefEdit;
@@ -3014,10 +3017,12 @@ private:
     int m_nOldEditWidthReq; // Original width request of the input field
     int m_nOldBorderWidth; // border width for expanded dialog
 
+    void signal_close();
+
     static void signalClose(GtkWidget*, gpointer widget)
     {
         GtkInstanceDialog* pThis = static_cast<GtkInstanceDialog*>(widget);
-        pThis->response(RET_CANCEL);
+        pThis->signal_close();
     }
 
     static void signalAsyncResponse(GtkWidget*, gint ret, gpointer widget)
@@ -3026,6 +3031,11 @@ private:
         pThis->asyncresponse(ret);
     }
 
+    static gboolean signalAsyncDelete(GtkDialog*, GdkEventAny*, gpointer)
+    {
+        return true; /* Do not destroy */
+    }
+
     static int GtkToVcl(int ret)
     {
         if (ret == GTK_RESPONSE_OK)
@@ -3043,24 +3053,7 @@ private:
         return ret;
     }
 
-    void asyncresponse(gint ret)
-    {
-        if (ret == GTK_RESPONSE_HELP)
-        {
-            help();
-            return;
-        }
-        else if (has_click_handler(ret))
-            return;
-
-        hide();
-        m_aFunc(GtkToVcl(ret));
-        m_aFunc = nullptr;
-        // move the self pointer, otherwise it might be de-allocated by time we try to reset it
-        std::shared_ptr<GtkInstanceDialog> me = std::move(m_xRunAsyncSelf);
-        m_xDialogController.reset();
-        me.reset();
-    }
+    void asyncresponse(gint ret);
 
 public:
     GtkInstanceDialog(GtkDialog* pDialog, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
@@ -3069,6 +3062,7 @@ public:
         , m_aDialogRun(pDialog)
         , m_nCloseSignalId(g_signal_connect(m_pDialog, "close", G_CALLBACK(signalClose), this))
         , m_nResponseSignalId(0)
+        , m_nSignalDeleteId(0)
         , m_pRefEdit(nullptr)
         , m_nOldEditWidth(0)
         , m_nOldEditWidthReq(0)
@@ -3086,6 +3080,7 @@ public:
         show();
 
         m_nResponseSignalId = g_signal_connect(m_pDialog, "response", G_CALLBACK(signalAsyncResponse), this);
+        m_nSignalDeleteId = g_signal_connect(m_pDialog, "delete-event", G_CALLBACK(signalAsyncDelete), this);
 
         return true;
     }
@@ -3100,32 +3095,14 @@ public:
         show();
 
         m_nResponseSignalId = g_signal_connect(m_pDialog, "response", G_CALLBACK(signalAsyncResponse), this);
+        m_nSignalDeleteId = g_signal_connect(m_pDialog, "delete-event", G_CALLBACK(signalAsyncDelete), this);
 
         return true;
     }
 
-    bool has_click_handler(int nResponse);
+    GtkInstanceButton* has_click_handler(int nResponse);
 
-    virtual int run() override
-    {
-        sort_native_button_order(GTK_BOX(gtk_dialog_get_action_area(m_pDialog)));
-        int ret;
-        while (true)
-        {
-            ret = m_aDialogRun.run();
-            if (ret == GTK_RESPONSE_HELP)
-            {
-                help();
-                continue;
-            }
-            else if (has_click_handler(ret))
-                continue;
-
-            break;
-        }
-        hide();
-        return GtkToVcl(ret);
-    }
+    virtual int run() override;
 
     virtual void show() override
     {
@@ -3295,6 +3272,8 @@ public:
         g_signal_handler_disconnect(m_pDialog, m_nCloseSignalId);
         if (m_nResponseSignalId)
             g_signal_handler_disconnect(m_pDialog, m_nResponseSignalId);
+        if (m_nSignalDeleteId)
+            g_signal_handler_disconnect(m_pDialog, m_nSignalDeleteId);
     }
 };
 
@@ -4610,6 +4589,60 @@ public:
     }
 };
 
+void GtkInstanceDialog::asyncresponse(gint ret)
+{
+    if (ret == GTK_RESPONSE_HELP)
+    {
+        help();
+        return;
+    }
+
+    GtkInstanceButton* pClickHandler = has_click_handler(ret);
+    if (pClickHandler)
+    {
+        // make GTK_RESPONSE_DELETE_EVENT act as if cancel button was pressed
+        if (ret == GTK_RESPONSE_DELETE_EVENT)
+            pClickHandler->clicked();
+        return;
+    }
+
+    hide();
+    m_aFunc(GtkToVcl(ret));
+    m_aFunc = nullptr;
+    // move the self pointer, otherwise it might be de-allocated by time we try to reset it
+    std::shared_ptr<GtkInstanceDialog> me = std::move(m_xRunAsyncSelf);
+    m_xDialogController.reset();
+    me.reset();
+}
+
+int GtkInstanceDialog::run()
+{
+    sort_native_button_order(GTK_BOX(gtk_dialog_get_action_area(m_pDialog)));
+    int ret;
+    while (true)
+    {
+        ret = m_aDialogRun.run();
+        if (ret == GTK_RESPONSE_HELP)
+        {
+            help();
+            continue;
+        }
+
+        GtkInstanceButton* pClickHandler = has_click_handler(ret);
+        if (pClickHandler)
+        {
+            // make GTK_RESPONSE_DELETE_EVENT act as if cancel button was pressed
+            if (ret == GTK_RESPONSE_DELETE_EVENT)
+                pClickHandler->clicked();
+            continue;
+        }
+
+        break;
+    }
+    hide();
+    return GtkToVcl(ret);
+}
+
 weld::Button* GtkInstanceDialog::get_widget_for_response(int nResponse)
 {
     GtkButton* pButton = GTK_BUTTON(gtk_dialog_get_widget_for_response(m_pDialog, VclToGtk(nResponse)));
@@ -4631,15 +4664,33 @@ void GtkInstanceDialog::response(int nResponse)
     gtk_dialog_response(m_pDialog, VclToGtk(nResponse));
 }
 
-bool GtkInstanceDialog::has_click_handler(int nResponse)
+
+void GtkInstanceDialog::signal_close()
 {
-    if (GtkWidget* pWidget = gtk_dialog_get_widget_for_response(m_pDialog, VclToGtk(nResponse)))
+    GtkInstanceButton* pClickHandler = has_click_handler(GTK_RESPONSE_CANCEL);
+    if (pClickHandler)
+    {
+        g_signal_stop_emission_by_name(m_pDialog, "close");
+        // make esc act as if cancel button was pressed
+        pClickHandler->clicked();
+        return;
+    }
+    response(RET_CANCEL);
+}
+
+GtkInstanceButton* GtkInstanceDialog::has_click_handler(int nResponse)
+{
+    GtkInstanceButton* pButton = nullptr;
+    // e.g. map GTK_RESPONSE_DELETE_EVENT to GTK_RESPONSE_CANCEL
+    nResponse = VclToGtk(GtkToVcl(nResponse));
+    if (GtkWidget* pWidget = gtk_dialog_get_widget_for_response(m_pDialog, nResponse))
     {
         void* pData = g_object_get_data(G_OBJECT(pWidget), "g-lo-GtkInstanceButton");
-        GtkInstanceButton* pButton = static_cast<GtkInstanceButton*>(pData);
-        return pButton && pButton->has_click_handler();
+        pButton = static_cast<GtkInstanceButton*>(pData);
+        if (pButton && !pButton->has_click_handler())
+            pButton = nullptr;
     }
-    return false;
+    return pButton;
 }
 
 class GtkInstanceToggleButton : public GtkInstanceButton, public virtual weld::ToggleButton


More information about the Libreoffice-commits mailing list