From 387a3b02e02d91da6c5d4331b667d835e32c83b0 Mon Sep 17 00:00:00 2001 From: Julian Smart Date: Mon, 12 Oct 1998 19:45:24 +0000 Subject: [PATCH] Session management changes for wxMSW. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@820 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- docs/latex/wx/app.tex | 74 +++++++++++++++++++++++++++++++++++--- docs/latex/wx/closeevt.tex | 46 +++++++++++++++++++++--- docs/latex/wx/window.tex | 70 +++++++++++++++++++++++++++++++++--- include/wx/defs.h | 2 +- include/wx/docmdi.h | 4 +-- include/wx/docview.h | 6 ++-- include/wx/event.h | 17 ++++++--- include/wx/msw/app.h | 2 ++ include/wx/msw/window.h | 3 ++ src/common/docmdi.cpp | 31 +++++++++++----- src/common/docview.cpp | 31 +++++++++++----- src/msw/app.cpp | 19 ++++++++++ src/msw/dialog.cpp | 16 +++++---- src/msw/frame.cpp | 2 ++ src/msw/window.cpp | 67 ++++++++++++++++++++++------------ 15 files changed, 317 insertions(+), 73 deletions(-) diff --git a/docs/latex/wx/app.tex b/docs/latex/wx/app.tex index c2464a6123..dccfc28567 100644 --- a/docs/latex/wx/app.tex +++ b/docs/latex/wx/app.tex @@ -238,6 +238,32 @@ goes idle again, when OnIdle is called, and so on. \helpref{wxWindow::OnIdle}{wxwindowonidle}, \helpref{wxIdleEvent}{wxidleevent},\rtfsp \helpref{wxWindow::SendIdleEvents}{wxappsendidleevents} +\membersection{wxApp::OnEndSession}\label{wxapponendsession} + +\func{void}{OnEndSession}{\param{wxCloseEvent\& }{event}} + +This is an event handler function called when the operating system or GUI session is +about to close down. The application has a chance to silently save information, +and can optionally close itself. + +Use the EVT\_END\_SESSION event table macro to handle query end session events. + +The default handler calls \helpref{wxWindow::Close}{wxwindowclose} with a TRUE argument +(forcing the application to close itself silently). + +\wxheading{Remarks} + +Under X, OnEndSession is called in response to the 'die' event. + +Under Windows, OnEndSession is called in response to the WM\_ENDSESSION message. + +\wxheading{See also} + +\helpref{wxWindow::Close}{wxwindowclose},\rtfsp +\helpref{wxWindow::OnCloseWindow}{wxwindowonclosewindow},\rtfsp +\helpref{wxCloseEvent}{wxcloseevent},\rtfsp +\helpref{wxApp::OnQueryEndSession}{wxappqueryonendsession} + \membersection{wxApp::OnInit}\label{wxapponinit} \func{bool}{OnInit}{\void} @@ -247,16 +273,43 @@ application's main window, calling \helpref{wxApp::SetTopWindow}{wxappsettopwind Return TRUE to continue processing, FALSE to exit the application. -\membersection{wxApp::Pending}\label{wxapppending} +\membersection{wxApp::OnQueryEndSession}\label{wxapponqueryendsession} -\func{bool}{Pending}{\void} +\func{void}{OnQueryEndSession}{\param{wxCloseEvent\& }{event}} -Returns TRUE if unprocessed events are in the window system event queue -(MS Windows and Motif). +This is an event handler function called when the operating system or GUI session is +about to close down. Typically, an application will try to save unsaved documents +at this point. + +If \helpref{wxCloseEvent::CanVeto}{wxcloseeventcanveto} returns TRUE, the application +is allowed to veto the shutdown by calling \helpref{wxCloseEvent::Veto}{wxcloseeventveto}. +The application might veto the shutdown after prompting for documents to be saved, and the +user has cancelled the save. + +Use the EVT\_QUERY\_END\_SESSION event table macro to handle query end session events. + +You should check whether the application is forcing the deletion of the window +using \helpref{wxCloseEvent::GetForce}{wxcloseeventgetforce}. If this is TRUE, +destroy the window using \helpref{wxWindow::Destroy}{wxwindowdestroy}. +If not, it is up to you whether you respond by destroying the window. + +The default handler calls \helpref{wxWindow::Close}{wxwindowclose} on the top-level window, +and vetoes the shutdown if Close returns FALSE. This will be sufficient for many applications. + +\wxheading{Remarks} + +Under X, OnQueryEndSession is called in response to the 'save session' event. + +Under Windows, OnQueryEndSession is called in response to the WM\_QUERYENDSESSION message. \wxheading{See also} -\helpref{wxApp::Dispatch}{wxappdispatch} +\helpref{wxWindow::Close}{wxwindowclose},\rtfsp +\helpref{wxWindow::OnCloseWindow}{wxwindowonclosewindow},\rtfsp +\helpref{wxCloseEvent}{wxcloseevent},\rtfsp +\helpref{wxApp::OnEndSession}{wxapponendsession} + +\membersection{wxWindow::OnScroll}\label{wxwindowonscroll} \membersection{wxApp::ProcessMessage}\label{wxappprocessmessage} @@ -282,6 +335,17 @@ BOOL CTheApp::PreTranslateMessage(MSG *msg) } \end{verbatim} +\membersection{wxApp::Pending}\label{wxapppending} + +\func{bool}{Pending}{\void} + +Returns TRUE if unprocessed events are in the window system event queue +(MS Windows and Motif). + +\wxheading{See also} + +\helpref{wxApp::Dispatch}{wxappdispatch} + \membersection{wxApp::SendIdleEvents}\label{wxappsendidleevents} \func{bool}{SendIdleEvents}{\void} diff --git a/docs/latex/wx/closeevt.tex b/docs/latex/wx/closeevt.tex index d41ff76c48..19576f9e7f 100644 --- a/docs/latex/wx/closeevt.tex +++ b/docs/latex/wx/closeevt.tex @@ -13,13 +13,20 @@ functions that take a wxCloseEvent argument. \twocolwidtha{7cm} \begin{twocollist}\itemsep=0pt -\twocolitem{{\bf EVT\_CLOSE(func)}}{Process a close event, supplying the member function.} +\twocolitem{{\bf EVT\_CLOSE(func)}}{Process a close event, supplying the member function. This +event applies to wxFrame and wxDialog classes.} +\twocolitem{{\bf EVT\_QUERY\_END\_SESSION(func)}}{Process a query end session event, supplying the member function. +This event applies to wxApp only.} +\twocolitem{{\bf EVT\__END\_SESSION(func)}}{Process an end session event, supplying the member function. +This event applies to wxApp only.} \end{twocollist}% \wxheading{See also} \helpref{wxWindow::OnCloseWindow}{wxwindowonclosewindow},\rtfsp \helpref{wxWindow::Close}{wxwindowclose},\rtfsp +\helpref{wxApp::OnQueryEndSession}{wxappqueryendsession},\rtfsp +\helpref{wxApp::OnEndSession}{wxappendsession},\rtfsp \helpref{Window deletion overview}{windowdeletionoverview} \latexignore{\rtfignore{\wxheading{Members}}} @@ -30,6 +37,14 @@ functions that take a wxCloseEvent argument. Constructor. +\membersection{wxCloseEvent::CanVeto}\label{wxcloseeventcanveto} + +\func{bool}{CanVeto}{\void} + +Returns TRUE if you can veto a system shutdown or a window close event. +Vetoing a window close event is not possible if the calling code wishes to +force the application to exit, and so this function must be called to check this. + \membersection{wxCloseEvent::GetLoggingOff}\label{wxcloseeventgetloggingoff} \constfunc{bool}{GetLoggingOff}{\void} @@ -44,14 +59,37 @@ Returns TRUE if the session is ending. \membersection{wxCloseEvent::GetForce}\label{wxcloseeventgetforce} -\constfunc{void}{GetForce}{\void} +\constfunc{bool}{GetForce}{\void} Returns TRUE if the application wishes to force the window to close. +This will shortly be obsolete, replaced by CanVeto. + +\membersection{wxCloseEvent::SetCanVeto}\label{wxcloseeventsetcanveto} + +\func{void}{SetCanVeto}{\param{bool}{ canVeto}} + +Sets the 'can veto' flag. + +\membersection{wxCloseEvent::SetForce}\label{wxcloseeventsetforce} + +\constfunc{void}{SetForce}{\param{bool}{ force}} + +Sets the 'force' flag. + +\membersection{wxCloseEvent::SetLoggingOff}\label{wxcloseeventsetloggingoff} + +\constfunc{void}{SetLoggingOff}{\param{bool}{ loggingOff}} + +Sets the 'logging off' flag. \membersection{wxCloseEvent::Veto}\label{wxcloseeventveto} -\func{void}{Veto}{\void} +\func{void}{Veto}{\param{bool}{ veto = TRUE}} + +Call this from your event handler to veto a system shutdown or to signal +to the calling application that a window close did not happen. -Call this from your event handler to veto a system shutdown. +You can only veto a shutdown if \helpref{wxCloseEvent::CanVeto}{wxcloseeventcanveto} returns +TRUE. diff --git a/docs/latex/wx/window.tex b/docs/latex/wx/window.tex index 1d5e99b96c..6576b10ada 100644 --- a/docs/latex/wx/window.tex +++ b/docs/latex/wx/window.tex @@ -185,6 +185,60 @@ Applies to managed windows (wxFrame and wxDialog classes) only. \helpref{wxWindow::Destroy}{wxwindowdestroy},\rtfsp \helpref{wxCloseEvent}{wxcloseevent} +\membersection{wxWindow::ConvertDialogToPixels}\label{wxwindowconvertdialogtopixels} + +\func{wxPoint}{ConvertDialogToPixels}{\param{const wxPoint\&}{ pt}} + +\func{wxSize}{ConvertDialogToPixels}{\param{const wxSize\&}{ sz}} + +Converts a point or size from dialog units to pixels. + +For the x dimension, the dialog units are multiplied by the average character width +and then divided by 4. + +For the y dimension, the dialog units are multiplied by the average character height +and then divided by 8. + +\wxheading{Remarks} + +Dialog units are used for maintaining a dialog's proportions even if the font changes. +Dialogs created using Dialog Editor optionally use dialog units. + +You can also use these functions programmatically. A convenience macro is defined: + +{\small +\begin{verbatim} +#define wxDLG_UNIT(parent, pt) parent->ConvertDialogToPixels(pt) +\end{verbatim} +} + +\wxheading{See also} + +\helpref{wxWindow::ConvertPixelsToDialog}{wxwindowconvertpixelstodialog} + +\membersection{wxWindow::ConvertPixelsToDialog}\label{wxwindowconvertpixelstodialog} + +\func{wxPoint}{ConvertPixelsToDialog}{\param{const wxPoint\&}{ pt}} + +\func{wxSize}{ConvertPixelsToDialog}{\param{const wxSize\&}{ sz}} + +Converts a point or size from pixels to dialog units. + +For the x dimension, the pixels are multiplied by 4 and then divided by the average +character width. + +For the y dimension, the pixels are multipled by 8 and then divided by the average +character height. + +\wxheading{Remarks} + +Dialog units are used for maintaining a dialog's proportions even if the font changes. +Dialogs created using Dialog Editor optionally use dialog units. + +\wxheading{See also} + +\helpref{wxWindow::ConvertDialogToPixels}{wxwindowconvertdialogtopixels} + \membersection{wxWindow::Destroy}\label{wxwindowdestroy} \func{virtual bool}{Destroy}{\void} @@ -811,7 +865,7 @@ you may delete other windows. \wxheading{Remarks} -Derive your own class to handle this message. The default handler returns FALSE. +Derive your own class to handle this message. The default handler returns TRUE. \wxheading{See also} @@ -836,6 +890,14 @@ using \helpref{wxCloseEvent::GetForce}{wxcloseeventgetforce}. If this is TRUE, destroy the window using \helpref{wxWindow::Destroy}{wxwindowdestroy}. If not, it is up to you whether you respond by destroying the window. +(Note: GetForce is now superceded by CanVeto. So to test whether forced destruction of +the window is required, test for the negative of CanVeto. If CanVeto returns FALSE, +it is not possible to skip window deletion.) + +If you don't destroy the window, you should call \helpref{wxCloseEvent::Veto}{wxcloseeventveto} to +let the calling code know that you did not destroy the window. This allows the \helpref{wxWindow::Close}{wxwindowclose} function +to return TRUE or FALSE depending on whether the close instruction was honoured or not. + \wxheading{Remarks} The \helpref{wxWindow::OnClose}{wxwindowonclose} virtual function remains @@ -849,7 +911,9 @@ destroying the window if it returns TRUE or if the close is being forced. \helpref{wxWindow::Close}{wxwindowclose},\rtfsp \helpref{wxWindow::OnClose}{wxwindowonclose},\rtfsp \helpref{wxWindow::Destroy}{wxwindowdestroy},\rtfsp -\helpref{wxCloseEvent}{wxcloseevent} +\helpref{wxCloseEvent}{wxcloseevent},\rtfsp +\helpref{wxApp::OnQueryEndSession}{wxapponqueryendsession},\rtfsp +\helpref{wxApp::OnEndSession}{wxapponendsession} \membersection{wxWindow::OnDropFiles}\label{wxwindowondropfiles} @@ -1124,8 +1188,6 @@ void MyWindow::OnPaint(wxPaintEvent& event) \helpref{wxPaintDC}{wxpaintdc},\rtfsp \helpref{Event handling overview}{eventhandlingoverview} -\membersection{wxWindow::OnScroll}\label{wxwindowonscroll} - \func{void}{OnScroll}{\param{wxScrollEvent\& }{event}} Called when a scroll event is received from one of the window's built-in scrollbars. diff --git a/include/wx/defs.h b/include/wx/defs.h index 3b47ec430b..694b31a7cd 100644 --- a/include/wx/defs.h +++ b/include/wx/defs.h @@ -850,7 +850,7 @@ enum { #define wxID_HIGHEST 5999 // Shortcut for easier dialog-unit-to-pixel conversion -#define wxDLG_UNIT(parent, pt) parent->ConvertDialogToPixel(pt) +#define wxDLG_UNIT(parent, pt) parent->ConvertDialogToPixels(pt) #ifdef __WXMSW__ // Stand-ins for Windows types, to avoid diff --git a/include/wx/docmdi.h b/include/wx/docmdi.h index 195b6126f7..43c4d9d871 100644 --- a/include/wx/docmdi.h +++ b/include/wx/docmdi.h @@ -31,7 +31,6 @@ class wxDocMDIParentFrame: public wxMDIParentFrame const wxString& title, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_FRAME_STYLE, const wxString& name = "frame"); - bool OnClose(void); // Extend event processing to search the document manager's event table virtual bool ProcessEvent(wxEvent& event); @@ -39,6 +38,7 @@ class wxDocMDIParentFrame: public wxMDIParentFrame void OnExit(wxCommandEvent& event); void OnMRUFile(wxCommandEvent& event); + void OnCloseWindow(wxCloseEvent& event); protected: wxDocManager *m_docManager; @@ -61,11 +61,11 @@ class WXDLLEXPORT wxDocMDIChildFrame: public wxMDIChildFrame long type = wxDEFAULT_FRAME_STYLE, const wxString& name = "frame"); ~wxDocMDIChildFrame(void); - bool OnClose(void); // Extend event processing to search the view's event table virtual bool ProcessEvent(wxEvent& event); void OnActivate(wxActivateEvent& event); + void OnCloseWindow(wxCloseEvent& event); inline wxDocument *GetDocument(void) const { return m_childDocument; } inline wxView *GetView(void) const { return m_childView; } diff --git a/include/wx/docview.h b/include/wx/docview.h index 160d51a50c..7e63ff80f4 100644 --- a/include/wx/docview.h +++ b/include/wx/docview.h @@ -372,12 +372,11 @@ class WXDLLEXPORT wxDocChildFrame: public wxFrame long type = wxDEFAULT_FRAME_STYLE, const wxString& name = "frame"); ~wxDocChildFrame(void); - bool OnClose(void); // Extend event processing to search the view's event table virtual bool ProcessEvent(wxEvent& event); -// void OldOnMenuCommand(int id); void OnActivate(wxActivateEvent& event); + void OnCloseWindow(wxCloseEvent& event); inline wxDocument *GetDocument(void) const { return m_childDocument; } inline wxView *GetView(void) const { return m_childView; } @@ -403,15 +402,14 @@ class WXDLLEXPORT wxDocParentFrame: public wxFrame const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long type = wxDEFAULT_FRAME, const wxString& name = "frame"); - bool OnClose(void); // Extend event processing to search the document manager's event table virtual bool ProcessEvent(wxEvent& event); -// void OldOnMenuCommand(int id); wxDocManager *GetDocumentManager(void) const { return m_docManager; } void OnExit(wxCommandEvent& event); void OnMRUFile(wxCommandEvent& event); + void OnCloseWindow(wxCloseEvent& event); protected: wxDocManager *m_docManager; diff --git a/include/wx/event.h b/include/wx/event.h index 8524f89390..280268fa71 100644 --- a/include/wx/event.h +++ b/include/wx/event.h @@ -680,22 +680,27 @@ class WXDLLEXPORT wxCloseEvent: public wxEvent public: inline wxCloseEvent(wxEventType type = wxEVT_NULL, int id = 0) - { m_eventType = type; m_sessionEnding = TRUE; m_loggingOff = TRUE; m_veto = FALSE; - m_id = id; m_force = FALSE; } + { m_eventType = type; m_loggingOff = TRUE; m_veto = FALSE; + m_id = id; m_force = FALSE; m_canVeto = FALSE; } - inline bool GetSessionEnding(void) const { return m_sessionEnding; } + inline void SetLoggingOff(bool logOff) { m_loggingOff = logOff; } inline bool GetLoggingOff(void) const { return m_loggingOff; } inline void Veto(bool veto = TRUE) { m_veto = veto; } + inline void SetCanVeto(bool canVeto) { m_canVeto = canVeto; } + inline bool CanVeto() const { return m_canVeto; } inline bool GetVeto(void) const { return m_veto; } + + // This is probably obsolete now, since we use CanVeto instead, in + // both OnCloseWindow and OnQueryEndSession. + // m_force == ! m_canVeto i.e., can't veto means we must force it to close. inline void SetForce(bool force) { m_force = force; } inline bool GetForce(void) const { return m_force; } protected: - bool m_sessionEnding; bool m_loggingOff; bool m_veto; bool m_force; - + bool m_canVeto; }; /* @@ -1121,6 +1126,8 @@ const wxEventTableEntry theClass::sm_eventTableEntries[] = { \ #define EVT_SIZE(func) { wxEVT_SIZE, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxSizeEventFunction) & func, (wxObject *) NULL }, #define EVT_MOVE(func) { wxEVT_MOVE, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxMoveEventFunction) & func, (wxObject *) NULL }, #define EVT_CLOSE(func) { wxEVT_CLOSE_WINDOW, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxCloseEventFunction) & func, (wxObject *) NULL }, +#define EVT_END_SESSION(func) { wxEVT_END_SESSION, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxCloseEventFunction) & func, (wxObject *) NULL }, +#define EVT_QUERY_END_SESSION(func) { wxEVT_QUERY_END_SESSION, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxCloseEventFunction) & func, (wxObject *) NULL }, #define EVT_PAINT(func) { wxEVT_PAINT, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxPaintEventFunction) & func, (wxObject *) NULL }, #define EVT_ERASE_BACKGROUND(func) { wxEVT_ERASE_BACKGROUND, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxEraseEventFunction) & func, (wxObject *) NULL }, #define EVT_CHAR(func) { wxEVT_CHAR, -1, -1, (wxObjectEventFunction) (wxEventFunction) (wxCharEventFunction) & func, (wxObject *) NULL }, diff --git a/include/wx/msw/app.h b/include/wx/msw/app.h index fd8fb8e815..4b17c47a42 100644 --- a/include/wx/msw/app.h +++ b/include/wx/msw/app.h @@ -54,6 +54,8 @@ class WXDLLEXPORT wxApp: public wxEvtHandler virtual void Dispatch() ; void OnIdle(wxIdleEvent& event); + void OnEndSession(wxCloseEvent& event); + void OnQueryEndSession(wxCloseEvent& event); // Generic virtual bool OnInit() { return FALSE; }; diff --git a/include/wx/msw/window.h b/include/wx/msw/window.h index 7573e0b6e2..1fc2958ab1 100644 --- a/include/wx/msw/window.h +++ b/include/wx/msw/window.h @@ -515,6 +515,9 @@ public: virtual void MSWOnMenuHighlight(WXWORD item, WXWORD flags, WXHMENU sysmenu); virtual void MSWOnInitMenuPopup(WXHMENU menu, int pos, bool isSystem); virtual bool MSWOnClose(void); + // Return TRUE to end session, FALSE to veto end session. + virtual bool MSWOnQueryEndSession(long logOff); + virtual bool MSWOnEndSession(bool endSession, long logOff); virtual bool MSWOnDestroy(void); virtual bool MSWOnSetFocus(WXHWND wnd); virtual bool MSWOnKillFocus(WXHWND wnd); diff --git a/src/common/docmdi.cpp b/src/common/docmdi.cpp index 4aba2cb488..0379f04ff8 100644 --- a/src/common/docmdi.cpp +++ b/src/common/docmdi.cpp @@ -41,6 +41,7 @@ IMPLEMENT_CLASS(wxDocMDIParentFrame, wxMDIParentFrame) BEGIN_EVENT_TABLE(wxDocMDIParentFrame, wxMDIParentFrame) EVT_MENU(wxID_EXIT, wxDocMDIParentFrame::OnExit) EVT_MENU_RANGE(wxID_FILE1, wxID_FILE9, wxDocMDIParentFrame::OnMRUFile) + EVT_CLOSE(wxDocMDIParentFrame::OnCloseWindow) END_EVENT_TABLE() wxDocMDIParentFrame::wxDocMDIParentFrame(wxDocManager *manager, wxFrame *frame, wxWindowID id, const wxString& title, @@ -72,11 +73,14 @@ bool wxDocMDIParentFrame::ProcessEvent(wxEvent& event) return TRUE; } -// Define the behaviour for the frame closing -// - must delete all frames except for the main one. -bool wxDocMDIParentFrame::OnClose(void) +void wxDocMDIParentFrame::OnCloseWindow(wxCloseEvent& event) { - return m_docManager->Clear(FALSE); + if (m_docManager->Clear(!event.CanVeto())) + { + this->Destroy(); + } + else + event.Veto(); } @@ -88,6 +92,7 @@ IMPLEMENT_CLASS(wxDocMDIChildFrame, wxMDIChildFrame) BEGIN_EVENT_TABLE(wxDocMDIChildFrame, wxMDIChildFrame) EVT_ACTIVATE(wxDocMDIChildFrame::OnActivate) + EVT_CLOSE(wxDocMDIChildFrame::OnCloseWindow) END_EVENT_TABLE() wxDocMDIChildFrame::wxDocMDIChildFrame(wxDocument *doc, wxView *view, wxMDIParentFrame *frame, wxWindowID id, @@ -128,24 +133,32 @@ void wxDocMDIChildFrame::OnActivate(wxActivateEvent& event) m_childView->Activate(event.GetActive()); } -bool wxDocMDIChildFrame::OnClose(void) +void wxDocMDIChildFrame::OnCloseWindow(wxCloseEvent& event) { // Close view but don't delete the frame while doing so! // ...since it will be deleted by wxWindows if we return TRUE. if (m_childView) { - bool ans = m_childView->Close(FALSE); // FALSE means don't delete associated window + bool ans = FALSE; + if (!event.CanVeto()) + ans = TRUE; // Must delete. + else + ans = m_childView->Close(FALSE); // FALSE means don't delete associated window + if (ans) { m_childView->Activate(FALSE); delete m_childView; m_childView = (wxView *) NULL; m_childDocument = (wxDocument *) NULL; + + this->Destroy(); } - - return ans; + else + event.Veto(); } - else return TRUE; + else + event.Veto(); } #endif diff --git a/src/common/docview.cpp b/src/common/docview.cpp index 24a1e59eac..bbfdf9ab3f 100644 --- a/src/common/docview.cpp +++ b/src/common/docview.cpp @@ -1313,6 +1313,7 @@ void wxDocManager::ActivateView(wxView *view, bool activate, bool WXUNUSED(delet BEGIN_EVENT_TABLE(wxDocChildFrame, wxFrame) EVT_ACTIVATE(wxDocChildFrame::OnActivate) + EVT_CLOSE(wxDocChildFrame::OnCloseWindow) END_EVENT_TABLE() wxDocChildFrame::wxDocChildFrame(wxDocument *doc, wxView *view, wxFrame *frame, wxWindowID id, const wxString& title, @@ -1355,24 +1356,30 @@ void wxDocChildFrame::OnActivate(wxActivateEvent& event) m_childView->Activate(event.GetActive()); } -bool wxDocChildFrame::OnClose(void) +void wxDocChildFrame::OnCloseWindow(wxCloseEvent& event) { - // Close view but don't delete the frame while doing so! - // ...since it will be deleted by wxWindows if we return TRUE. if (m_childView) { - bool ans = m_childView->Close(FALSE); // FALSE means don't delete associated window + bool ans = FALSE; + if (!event.CanVeto()) + ans = TRUE; // Must delete. + else + ans = m_childView->Close(FALSE); // FALSE means don't delete associated window + if (ans) { m_childView->Activate(FALSE); delete m_childView; m_childView = (wxView *) NULL; m_childDocument = (wxDocument *) NULL; + + this->Destroy(); } - - return ans; + else + event.Veto(); } - else return TRUE; + else + event.Veto(); } /* @@ -1382,6 +1389,7 @@ bool wxDocChildFrame::OnClose(void) BEGIN_EVENT_TABLE(wxDocParentFrame, wxFrame) EVT_MENU(wxID_EXIT, wxDocParentFrame::OnExit) EVT_MENU_RANGE(wxID_FILE1, wxID_FILE9, wxDocParentFrame::OnMRUFile) + EVT_CLOSE(wxDocParentFrame::OnCloseWindow) END_EVENT_TABLE() wxDocParentFrame::wxDocParentFrame(wxDocManager *manager, wxFrame *frame, wxWindowID id, const wxString& title, @@ -1415,9 +1423,14 @@ bool wxDocParentFrame::ProcessEvent(wxEvent& event) // Define the behaviour for the frame closing // - must delete all frames except for the main one. -bool wxDocParentFrame::OnClose(void) +void wxDocParentFrame::OnCloseWindow(wxCloseEvent& event) { - return m_docManager->Clear(FALSE); + if (m_docManager->Clear(!event.CanVeto())) + { + this->Destroy(); + } + else + event.Veto(); } #if wxUSE_PRINTING_ARCHITECTURE diff --git a/src/msw/app.cpp b/src/msw/app.cpp index 2af264ff65..b3a40f84c3 100644 --- a/src/msw/app.cpp +++ b/src/msw/app.cpp @@ -97,6 +97,8 @@ LRESULT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM); BEGIN_EVENT_TABLE(wxApp, wxEvtHandler) EVT_IDLE(wxApp::OnIdle) + EVT_END_SESSION(wxApp::OnEndSession) + EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession) END_EVENT_TABLE() #endif @@ -892,6 +894,23 @@ void wxApp::DeletePendingObjects() } } +void wxApp::OnEndSession(wxCloseEvent& event) +{ + if (GetTopWindow()) + GetTopWindow()->Close(TRUE); +} + +// Default behaviour: close the application with prompts. The +// user can veto the close, and therefore the end session. +void wxApp::OnQueryEndSession(wxCloseEvent& event) +{ + if (GetTopWindow()) + { + if (!GetTopWindow()->Close(!event.CanVeto())) + event.Veto(TRUE); + } +} + wxLog* wxApp::CreateLogTarget() { return new wxLogGui; diff --git a/src/msw/dialog.cpp b/src/msw/dialog.cpp index 06b2398406..8f5afe79e7 100644 --- a/src/msw/dialog.cpp +++ b/src/msw/dialog.cpp @@ -521,8 +521,8 @@ void wxDialog::OnOK(wxCommandEvent& event) EndModal(wxID_OK); else { - SetReturnCode(wxID_OK); - this->Show(FALSE); + SetReturnCode(wxID_OK); + this->Show(FALSE); } } } @@ -547,7 +547,7 @@ void wxDialog::OnCancel(wxCommandEvent& event) bool wxDialog::OnClose(void) { - // Behaviour changed in 2.0: we'll send a Cancel message by default, + // Behaviour changed in 2.0: we'll send a Cancel message by default, // which may close the dialog. // Check for looping if the Cancel event handler calls Close() @@ -558,13 +558,13 @@ bool wxDialog::OnClose(void) closing.Append(this); - wxCommandEvent cancelEvent(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL); - cancelEvent.SetEventObject( this ); - GetEventHandler()->ProcessEvent(cancelEvent); + wxCommandEvent cancelEvent(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL); + cancelEvent.SetEventObject( this ); + GetEventHandler()->ProcessEvent(cancelEvent); closing.DeleteObject(this); - return FALSE; + return FALSE; } void wxDialog::OnCloseWindow(wxCloseEvent& event) @@ -574,6 +574,8 @@ void wxDialog::OnCloseWindow(wxCloseEvent& event) { this->Destroy(); } + else + event.Veto(TRUE); } // Destroy the window (delayed, if a managed window) diff --git a/src/msw/frame.cpp b/src/msw/frame.cpp index 29e363328c..2f1ab01bf2 100644 --- a/src/msw/frame.cpp +++ b/src/msw/frame.cpp @@ -869,6 +869,8 @@ void wxFrame::OnCloseWindow(wxCloseEvent& event) { this->Destroy(); } + else + event.Veto(TRUE); } bool wxFrame::OnClose(void) diff --git a/src/msw/window.cpp b/src/msw/window.cpp index b851ac7919..39c8e6e127 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -1415,7 +1415,16 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam) case WM_QUERYENDSESSION: { // Same as WM_CLOSE, but inverted results. Thx Microsoft :-) - return MSWOnClose(); +// return MSWOnClose(); + + return MSWOnQueryEndSession(lParam); + break; + } + case WM_ENDSESSION: + { + // Same as WM_CLOSE, but inverted results. Thx Microsoft :-) + MSWOnEndSession((wParam != 0), lParam); + return 0L; break; } case WM_CLOSE: @@ -1583,6 +1592,38 @@ bool wxWindow::MSWOnClose(void) return FALSE; } +// Return TRUE to end session, FALSE to veto end session. +bool wxWindow::MSWOnQueryEndSession(long logOff) +{ + wxCloseEvent event(wxEVT_QUERY_END_SESSION, -1); + event.SetEventObject(wxTheApp); + event.SetCanVeto(TRUE); + event.SetLoggingOff( (logOff == ENDSESSION_LOGOFF) ); + if ((this == wxTheApp->GetTopWindow()) && // Only send once + wxTheApp->ProcessEvent(event) && event.GetVeto()) + { + return FALSE; // Veto! + } + else + { + return TRUE; // Don't veto + } +} + +bool wxWindow::MSWOnEndSession(bool endSession, long logOff) +{ + wxCloseEvent event(wxEVT_END_SESSION, -1); + event.SetEventObject(wxTheApp); + event.SetCanVeto(FALSE); + event.SetLoggingOff( (logOff == ENDSESSION_LOGOFF) ); + if (endSession && // No need to send if the session isn't ending + (this == wxTheApp->GetTopWindow()) && // Only send once + wxTheApp->ProcessEvent(event)) + { + } + return TRUE; +} + bool wxWindow::MSWOnDestroy(void) { #if WXDEBUG > 1 @@ -4102,32 +4143,12 @@ void wxWindow::GetPositionConstraint(int *x, int *y) const bool wxWindow::Close(bool force) { - // Let's generalise it to work the same for any window. -/* - if (!IsKindOf(CLASSINFO(wxDialog)) && !IsKindOf(CLASSINFO(wxFrame))) - { - this->Destroy(); - return TRUE; - } -*/ - wxCloseEvent event(wxEVT_CLOSE_WINDOW, m_windowId); event.SetEventObject(this); event.SetForce(force); + event.SetCanVeto(!force); - return GetEventHandler()->ProcessEvent(event); - -/* - if ( !force && event.GetVeto() ) - return FALSE; - - Show(FALSE); - - if (!wxPendingDelete.Member(this)) - wxPendingDelete.Append(this); - - return TRUE; -*/ + return (GetEventHandler()->ProcessEvent(event) && !event.GetVeto()); } wxObject* wxWindow::GetChild(int number) const -- 2.45.2