Kaydet (Commit) 644ca26a authored tarafından Caolán McNamara's avatar Caolán McNamara

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/72319Reviewed-by: 's avatarCaolán McNamara <caolanm@redhat.com>
Tested-by: 's avatarCaolán McNamara <caolanm@redhat.com>
üst dc17f247
...@@ -835,8 +835,26 @@ bool Dialog::Close() ...@@ -835,8 +835,26 @@ bool Dialog::Close()
if ( mpWindowImpl->mxWindowPeer.is() && IsCreatedWithToolkit() && !IsInExecute() ) if ( mpWindowImpl->mxWindowPeer.is() && IsCreatedWithToolkit() && !IsInExecute() )
return false; 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; mbInClose = true;
if (pCustomCancelButton)
{
pCustomCancelButton->Click();
if (xWindow->IsDisposed())
return true;
mbInClose = false;
return false;
}
if ( !(GetStyle() & WB_CLOSEABLE) ) if ( !(GetStyle() & WB_CLOSEABLE) )
{ {
bool bRet = true; bool bRet = true;
......
...@@ -2995,6 +2995,8 @@ namespace ...@@ -2995,6 +2995,8 @@ namespace
} }
} }
class GtkInstanceButton;
class GtkInstanceDialog : public GtkInstanceWindow, public virtual weld::Dialog class GtkInstanceDialog : public GtkInstanceWindow, public virtual weld::Dialog
{ {
private: private:
...@@ -3006,6 +3008,7 @@ private: ...@@ -3006,6 +3008,7 @@ private:
std::function<void(sal_Int32)> m_aFunc; std::function<void(sal_Int32)> m_aFunc;
gulong m_nCloseSignalId; gulong m_nCloseSignalId;
gulong m_nResponseSignalId; gulong m_nResponseSignalId;
gulong m_nSignalDeleteId;
// for calc ref dialog that shrink to range selection widgets and resize back // for calc ref dialog that shrink to range selection widgets and resize back
GtkWidget* m_pRefEdit; GtkWidget* m_pRefEdit;
...@@ -3014,10 +3017,12 @@ private: ...@@ -3014,10 +3017,12 @@ private:
int m_nOldEditWidthReq; // Original width request of the input field int m_nOldEditWidthReq; // Original width request of the input field
int m_nOldBorderWidth; // border width for expanded dialog int m_nOldBorderWidth; // border width for expanded dialog
void signal_close();
static void signalClose(GtkWidget*, gpointer widget) static void signalClose(GtkWidget*, gpointer widget)
{ {
GtkInstanceDialog* pThis = static_cast<GtkInstanceDialog*>(widget); GtkInstanceDialog* pThis = static_cast<GtkInstanceDialog*>(widget);
pThis->response(RET_CANCEL); pThis->signal_close();
} }
static void signalAsyncResponse(GtkWidget*, gint ret, gpointer widget) static void signalAsyncResponse(GtkWidget*, gint ret, gpointer widget)
...@@ -3026,6 +3031,11 @@ private: ...@@ -3026,6 +3031,11 @@ private:
pThis->asyncresponse(ret); pThis->asyncresponse(ret);
} }
static gboolean signalAsyncDelete(GtkDialog*, GdkEventAny*, gpointer)
{
return true; /* Do not destroy */
}
static int GtkToVcl(int ret) static int GtkToVcl(int ret)
{ {
if (ret == GTK_RESPONSE_OK) if (ret == GTK_RESPONSE_OK)
...@@ -3043,24 +3053,7 @@ private: ...@@ -3043,24 +3053,7 @@ private:
return ret; return ret;
} }
void asyncresponse(gint 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();
}
public: public:
GtkInstanceDialog(GtkDialog* pDialog, GtkInstanceBuilder* pBuilder, bool bTakeOwnership) GtkInstanceDialog(GtkDialog* pDialog, GtkInstanceBuilder* pBuilder, bool bTakeOwnership)
...@@ -3069,6 +3062,7 @@ public: ...@@ -3069,6 +3062,7 @@ public:
, m_aDialogRun(pDialog) , m_aDialogRun(pDialog)
, m_nCloseSignalId(g_signal_connect(m_pDialog, "close", G_CALLBACK(signalClose), this)) , m_nCloseSignalId(g_signal_connect(m_pDialog, "close", G_CALLBACK(signalClose), this))
, m_nResponseSignalId(0) , m_nResponseSignalId(0)
, m_nSignalDeleteId(0)
, m_pRefEdit(nullptr) , m_pRefEdit(nullptr)
, m_nOldEditWidth(0) , m_nOldEditWidth(0)
, m_nOldEditWidthReq(0) , m_nOldEditWidthReq(0)
...@@ -3086,6 +3080,7 @@ public: ...@@ -3086,6 +3080,7 @@ public:
show(); show();
m_nResponseSignalId = g_signal_connect(m_pDialog, "response", G_CALLBACK(signalAsyncResponse), this); 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; return true;
} }
...@@ -3100,32 +3095,14 @@ public: ...@@ -3100,32 +3095,14 @@ public:
show(); show();
m_nResponseSignalId = g_signal_connect(m_pDialog, "response", G_CALLBACK(signalAsyncResponse), this); 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; return true;
} }
bool has_click_handler(int nResponse); GtkInstanceButton* has_click_handler(int nResponse);
virtual int run() override 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 void show() override virtual void show() override
{ {
...@@ -3295,6 +3272,8 @@ public: ...@@ -3295,6 +3272,8 @@ public:
g_signal_handler_disconnect(m_pDialog, m_nCloseSignalId); g_signal_handler_disconnect(m_pDialog, m_nCloseSignalId);
if (m_nResponseSignalId) if (m_nResponseSignalId)
g_signal_handler_disconnect(m_pDialog, 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: ...@@ -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) weld::Button* GtkInstanceDialog::get_widget_for_response(int nResponse)
{ {
GtkButton* pButton = GTK_BUTTON(gtk_dialog_get_widget_for_response(m_pDialog, VclToGtk(nResponse))); GtkButton* pButton = GTK_BUTTON(gtk_dialog_get_widget_for_response(m_pDialog, VclToGtk(nResponse)));
...@@ -4631,15 +4664,33 @@ void GtkInstanceDialog::response(int nResponse) ...@@ -4631,15 +4664,33 @@ void GtkInstanceDialog::response(int nResponse)
gtk_dialog_response(m_pDialog, VclToGtk(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"); void* pData = g_object_get_data(G_OBJECT(pWidget), "g-lo-GtkInstanceButton");
GtkInstanceButton* pButton = static_cast<GtkInstanceButton*>(pData); pButton = static_cast<GtkInstanceButton*>(pData);
return pButton && pButton->has_click_handler(); if (pButton && !pButton->has_click_handler())
pButton = nullptr;
} }
return false; return pButton;
} }
class GtkInstanceToggleButton : public GtkInstanceButton, public virtual weld::ToggleButton class GtkInstanceToggleButton : public GtkInstanceButton, public virtual weld::ToggleButton
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment