From 387a3b02e02d91da6c5d4331b667d835e32c83b0 Mon Sep 17 00:00:00 2001
From: Julian Smart <julian@anthemion.co.uk>
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.50.0

