diff --git a/panda/src/display/graphicsWindow.cxx b/panda/src/display/graphicsWindow.cxx index 1d94997747..808c949549 100644 --- a/panda/src/display/graphicsWindow.cxx +++ b/panda/src/display/graphicsWindow.cxx @@ -205,6 +205,53 @@ get_window_event() const { return result; } +//////////////////////////////////////////////////////////////////// +// Function: GraphicsWindow::set_close_request_event +// Access: Published +// Description: Sets the event that is triggered when the user +// requests to close the window, e.g. via alt-F4, or +// clicking on the close box. +// +// The default for each window is for this event to be +// the empty string, which means the window-close +// request is handled immediately by Panda (and the +// window will be closed without the app getting a +// chance to intervene). If you set this to a nonempty +// string, then the window is not closed, but instead +// the event is thrown. It is then up to the app to +// respond appropriately, for instance by presenting an +// "are you sure?" dialog box, and eventually calling +// close_window() when the user is sure. +// +// It is considered poor form to set this string and +// then not handle the event. This can frustrate the +// user by making it difficult for him to cleanly shut +// down the application (and may force the user to +// hard-kill the app, or reboot the machine). +//////////////////////////////////////////////////////////////////// +void GraphicsWindow:: +set_close_request_event(const string &close_request_event) { + MutexHolder holder(_properties_lock); + _close_request_event = close_request_event; +} + +//////////////////////////////////////////////////////////////////// +// Function: GraphicsWindow::get_close_request_event +// Access: Published +// Description: Returns the name of the event set via +// set_close_request_event(). If this string is +// nonempty, then when the user requests to close +// window, this event will be generated instead. See +// set_close_request_event(). +//////////////////////////////////////////////////////////////////// +string GraphicsWindow:: +get_close_request_event() const { + string result; + MutexHolder holder(_properties_lock); + result = _close_request_event; + return result; +} + //////////////////////////////////////////////////////////////////// // Function: GraphicsWindow::get_num_input_devices // Access: Published diff --git a/panda/src/display/graphicsWindow.h b/panda/src/display/graphicsWindow.h index 63373fe0f6..0d432fa614 100644 --- a/panda/src/display/graphicsWindow.h +++ b/panda/src/display/graphicsWindow.h @@ -57,6 +57,9 @@ PUBLISHED: void set_window_event(const string &window_event); string get_window_event() const; + void set_close_request_event(const string &close_request_event); + string get_close_request_event() const; + // Mouse and keyboard routines int get_num_input_devices() const; string get_input_device_name(int device) const; @@ -114,6 +117,7 @@ private: WindowProperties _requested_properties; WindowProperties _rejected_properties; string _window_event; + string _close_request_event; public: static TypeHandle get_class_type() { diff --git a/panda/src/glxdisplay/glxGraphicsWindow.cxx b/panda/src/glxdisplay/glxGraphicsWindow.cxx index 77db55b420..ec45c8a2fd 100644 --- a/panda/src/glxdisplay/glxGraphicsWindow.cxx +++ b/panda/src/glxdisplay/glxGraphicsWindow.cxx @@ -28,6 +28,7 @@ #include "clockObject.h" #include "pStatTimer.h" #include "textEncoder.h" +#include "throw_event.h" #include #include @@ -351,13 +352,23 @@ process_events() { case ClientMessage: if ((Atom)(event.xclient.data.l[0]) == _wm_delete_window) { // This is a message from the window manager indicating that - // the user has requested to close the window. Honor the - // request. - // TODO: don't call release_gsg() in the window thread. - release_gsg(); - close_window(); - properties.set_open(false); - system_changed_properties(properties); + // the user has requested to close the window. + string close_request_event = get_close_request_event(); + if (!close_request_event.empty()) { + // In this case, the app has indicated a desire to intercept + // the request and process it directly. + throw_event(close_request_event); + + } else { + // In this case, the default case, the app does not intend + // to service the request, so we do by closing the window. + + // TODO: don't call release_gsg() in the window thread. + release_gsg(); + close_window(); + properties.set_open(false); + system_changed_properties(properties); + } } break;