]> git.saurik.com Git - wxWidgets.git/commitdiff
the app doesn't exit any more if a dialog is shown (and destroyed) while
authorVadim Zeitlin <vadim@wxwidgets.org>
Thu, 15 Aug 2002 20:42:07 +0000 (20:42 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Thu, 15 Aug 2002 20:42:07 +0000 (20:42 +0000)
the flow of control is still in OnInit()

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@16523 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

docs/latex/wx/app.tex
docs/latex/wx/tapp.tex
include/wx/app.h
include/wx/toplevel.h
src/common/appcmn.cpp
src/common/toplvcmn.cpp
src/gtk/toplevel.cpp
src/gtk1/toplevel.cpp
src/msw/app.cpp
src/msw/toplevel.cpp

index f082563254c3b16856c4946f061177ecf115c08c..2a73956ac3e3a0916938652347cf9f15cf0d7148 100644 (file)
@@ -137,7 +137,8 @@ otherwise.
 
 \wxheading{See also}
 
-\helpref{wxApp::SetExitOnFrameDelete}{wxappsetexitonframedelete}
+\helpref{wxApp::SetExitOnFrameDelete}{wxappsetexitonframedelete},\\
+\helpref{wxApp shutdown overview}{wxappshutdownoverview}
 
 \membersection{wxApp::GetTopWindow}\label{wxappgettopwindow}
 
@@ -550,6 +551,11 @@ top-level frame is deleted.
 \docparam{flag}{If TRUE (the default), the application will exit when the top-level frame is
 deleted. If FALSE, the application will continue to run.}
 
+\wxheading{See also}
+
+\helpref{wxApp::GetExitOnFrameDelete}{wxappgetexitonframedelete},\\
+\helpref{wxApp shutdown overview}{wxappshutdownoverview}
+
 \membersection{wxApp::SetTopWindow}\label{wxappsettopwindow}
 
 \func{void}{SetTopWindow}{\param{wxWindow* }{window}}
index 563b3d085bc3ca3a4ab609b0996692da79ac6df4..9deac1d1bacc1810272d84271753a6f1d79ed200 100644 (file)
@@ -22,7 +22,8 @@ is to explicitly delete child frames in the top-level frame's \helpref{wxCloseEv
 handler.
 
 In emergencies the \helpref{wxExit}{wxexit} function can be called to kill the
-application.
+application however normally the applications shuts down automatically, 
+\helpref{see below}{wxappshutdownoverview}.
 
 An example of defining an application follows:
 
@@ -55,11 +56,25 @@ construction time.
 You can also use DECLARE\_APP(appClass) in a header file to declare the wxGetApp function which returns
 a reference to the application object.
 
-\subsection{Application shutdown}
-
-\helpref{OnExit}{wxapponexit} is called when the application exits but {\it before}
-wxWindows cleans its internal structures. Your should delete all wxWindows object that
-your created by the time OnExit finishes. In particular, do {\bf not} destroy them
+\subsection{Application shutdown}\label{wxappshutdownoverview}
+
+The application normally shuts down when the last of its top level windows is
+closed. This is normally the expected behaviour and means that it is enough to
+call \helpref{Close()}{wxwindowclose} in response to the {\tt "Exit"} menu
+command if your program has a single top level window. If this behaviour is not
+desirable \helpref{wxApp::SetExitOnFrameDelete}{wxappsetexitonframedelete} can
+be called to change it. Note that starting from wxWindows 2.3.3 such logic
+doesn't apply for the windows shown before the program enters the main loop: in
+other words, you can safely show a dialog from 
+\helpref{wxApp::OnInit}{wxapponinit} and not be afraid that your application
+terminates when this dialog -- which is the last top level window for the
+moment -- is closed.
+
+
+Another aspect of the application shutdown is the \helpref{OnExit}{wxapponexit} 
+which is called when the application exits but {\it before} wxWindows cleans up
+its internal structures. Your should delete all wxWindows object that your
+created by the time OnExit finishes. In particular, do {\bf not} destroy them
 from application class' destructor!
 
 For example, this code may crash:
index 8324651d6017f190a53491ed532e98b24ee68950..8b17fc42aa4affdafc86d76fe38a555eed957652 100644 (file)
@@ -128,7 +128,7 @@ public:
         //
         // Override: rarely in GUI applications, always in console ones.
 #if wxUSE_GUI
-    virtual int OnRun() { return MainLoop(); };
+    virtual int OnRun();
 #else // !GUI
     virtual int OnRun() = 0;
 #endif // wxUSE_GUI
@@ -236,11 +236,13 @@ public:
 
         // control the exit behaviour: by default, the program will exit the
         // main loop (and so, usually, terminate) when the last top-level
-        // program window is deleted. Beware that if you disabel this (with
-        // SetExitOnFrameDelete(FALSE)), you'll have to call ExitMainLoop()
-        // explicitly from somewhere.
-    void SetExitOnFrameDelete(bool flag) { m_exitOnFrameDelete = flag; }
-    bool GetExitOnFrameDelete() const { return m_exitOnFrameDelete; }
+        // program window is deleted. Beware that if you disable this behaviour
+        // (with SetExitOnFrameDelete(FALSE)), you'll have to call
+        // ExitMainLoop() explicitly from somewhere.
+    void SetExitOnFrameDelete(bool flag)
+        { m_exitOnFrameDelete = flag ? Yes : No; }
+    bool GetExitOnFrameDelete() const
+        { return m_exitOnFrameDelete == Yes; }
 
 #endif // wxUSE_GUI
 
@@ -392,8 +394,16 @@ protected:
     // the main top level window - may be NULL
     wxWindow *m_topWindow;
 
-    // if TRUE, exit the main loop when the last top level window is deleted
-    bool m_exitOnFrameDelete;
+    // if Yes, exit the main loop when the last top level window is deleted, if
+    // No don't do it and if Later -- only do it once we reach our OnRun()
+    //
+    // the explanation for using this strange scheme is given in appcmn.cpp
+    enum
+    {
+        Later = -1,
+        No,
+        Yes
+    } m_exitOnFrameDelete;
 
     // TRUE if the apps whats to use the best visual on systems where
     // more than one are available (Sun, SGI, XFree86 4.0 ?)
index ce058932b0810beda4176889de312a315b5f4530..84ac5bffeb70f827c8d8f47da0213d6b6062e4e2 100644 (file)
@@ -135,16 +135,21 @@ protected:
     virtual void DoClientToScreen(int *x, int *y) const;
     virtual void DoScreenToClient(int *x, int *y) const;
 
+    // test whether this window makes part of the frame
+    // (menubar, toolbar and statusbar are excluded from automatic layout)
+    virtual bool IsOneOfBars(const wxWindow *WXUNUSED(win)) const
+        { return FALSE; }
+
+    // check if we should exit the program after deleting another top level
+    // window (this is used in common dtor and wxMSW code)
+    static bool IsLastBeforeExit();
+
     // send the iconize event, return TRUE if processed
     bool SendIconizeEvent(bool iconized = TRUE);
 
     // the frame icon
     wxIconBundle m_icons;
 
-    // test whether this window makes part of the frame
-    // (menubar, toolbar and statusbar are excluded from automatic layout)
-    virtual bool IsOneOfBars(const wxWindow *WXUNUSED(win)) const { return FALSE; }
-
     DECLARE_EVENT_TABLE()
 };
 
index 2398dad313fc922cc080d3a163589646bd27d010..19ddb1965c59f9a25e24a2cbfa380ec716bdac97 100644 (file)
@@ -84,8 +84,21 @@ wxAppBase::wxAppBase()
 #if wxUSE_GUI
     m_topWindow = (wxWindow *)NULL;
     m_useBestVisual = FALSE;
-    m_exitOnFrameDelete = TRUE;
     m_isActive = TRUE;
+
+    // We don't want to exit the app if the user code shows a dialog from its
+    // OnInit() -- but this is what would happen if we set m_exitOnFrameDelete
+    // to Yes initially as this dialog would be the last top level window.
+    // OTOH, if we set it to No initially we'll have to overwrite it with Yes
+    // when we enter our OnRun() because we do want the default behaviour from
+    // then on. But this would be a problem if the user code calls
+    // SetExitOnFrameDelete(FALSE) from OnInit().
+    //
+    // So we use the special "Later" value which is such that
+    // GetExitOnFrameDelete() returns FALSE for it but which we know we can
+    // safely (i.e. without losing the effect of the users SetExitOnFrameDelete
+    // call) overwrite in OnRun()
+    m_exitOnFrameDelete = Later;
 #endif // wxUSE_GUI
 
 #ifdef __WXDEBUG__
@@ -113,6 +126,19 @@ bool wxAppBase::OnInitGui()
 }
 #endif // wxUSE_GUI
 
+int wxAppBase::OnRun()
+{
+    // see the comment in ctor: if the initial value hasn't been changed, use
+    // the default Yes from now on
+    if ( m_exitOnFrameDelete == Later )
+    {
+        m_exitOnFrameDelete = Yes;
+    }
+    //else: it has been changed, assume the user knows what he is doing
+
+    return MainLoop();
+}
+
 int wxAppBase::OnExit()
 {
 #if wxUSE_CONFIG
index da1e1cb9e086ed55a758f89f0541612d9a7b31dc..fd659ac2b6dc471d135492165aaf4d30632538ce 100644 (file)
@@ -60,7 +60,19 @@ wxTopLevelWindowBase::wxTopLevelWindowBase()
 
 wxTopLevelWindowBase::~wxTopLevelWindowBase()
 {
-    // this destructor is required for Darwin
+    // don't let wxTheApp keep any stale pointers to us
+    if ( wxTheApp && wxTheApp->GetTopWindow() == this )
+        wxTheApp->SetTopWindow(NULL);
+
+    bool shouldExit = IsLastBeforeExit();
+
+    wxTopLevelWindows.DeleteObject(this);
+
+    if ( shouldExit )
+    {
+        // then do it
+        wxTheApp->ExitMainLoop();
+    }
 }
 
 bool wxTopLevelWindowBase::Destroy()
@@ -73,6 +85,19 @@ bool wxTopLevelWindowBase::Destroy()
     return TRUE;
 }
 
+/* static */
+bool wxTopLevelWindowBase::IsLastBeforeExit()
+{
+    // we exit the application if there are no more top level windows left
+    // normally but wxApp can prevent this from happening
+    return (wxTopLevelWindows.GetCount() == 1) &&
+            wxTheApp && wxTheApp->GetExitOnFrameDelete();
+}
+
+// ----------------------------------------------------------------------------
+// wxTopLevelWindow geometry
+// ----------------------------------------------------------------------------
+
 wxSize wxTopLevelWindowBase::GetMaxSize() const
 {
     wxSize  size( GetMaxWidth(), GetMaxHeight() );
index f2005c8c5dc1153913d3685d793764d6c5366cfa..73fc746c0b1e2b4a01fa878e56901382be4965e5 100644 (file)
@@ -483,7 +483,7 @@ wxTopLevelWindowGTK::~wxTopLevelWindowGTK()
         wxASSERT_MSG( FALSE, _T("Window still grabbed"));
         RemoveGrab();
     }
-    
+
     m_isBeingDeleted = TRUE;
 
     // it may also be GtkScrolledWindow in the case of an MDI child
@@ -491,17 +491,6 @@ wxTopLevelWindowGTK::~wxTopLevelWindowGTK()
     {
         gtk_window_set_focus( GTK_WINDOW(m_widget), NULL );
     }
-
-    wxTopLevelWindows.DeleteObject( this );
-
-    if (wxTheApp->GetTopWindow() == this)
-        wxTheApp->SetTopWindow( (wxWindow*) NULL );
-
-    if ((wxTopLevelWindows.Number() == 0) &&
-        (wxTheApp->GetExitOnFrameDelete()))
-    {
-        wxTheApp->ExitMainLoop();
-    }
 }
 
 
@@ -522,11 +511,11 @@ static void wx_win_hints_set_layer(GtkWidget *window, int layer)
     XEvent xev;
     GdkWindowPrivate *priv;
     gint prev_error;
-  
+
     prev_error = gdk_error_warnings;
     gdk_error_warnings = 0;
     priv = (GdkWindowPrivate*)(GTK_WIDGET(window)->window);
-  
+
     if (GTK_WIDGET_MAPPED(window))
     {
         xev.type = ClientMessage;
@@ -536,14 +525,14 @@ static void wx_win_hints_set_layer(GtkWidget *window, int layer)
         xev.xclient.format = 32;
         xev.xclient.data.l[0] = (long)layer;
         xev.xclient.data.l[1] = gdk_time_get();
-      
+
         XSendEvent(GDK_DISPLAY(), GDK_ROOT_WINDOW(), False,
             SubstructureNotifyMask, (XEvent*) &xev);
     }
     else
     {
         long data[1];
-      
+
         data[0] = layer;
         XChangeProperty(GDK_DISPLAY(), priv->xwindow, gs_XA_WIN_LAYER,
               XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1);
@@ -574,14 +563,14 @@ bool wxTopLevelWindowGTK::ShowFullScreen(bool show, long style )
 
         int screen_width,screen_height;
         wxDisplaySize( &screen_width, &screen_height );
-        
+
                gint client_x, client_y, root_x, root_y;
                gint width, height;
 
                gdk_window_get_origin (m_widget->window, &root_x, &root_y);
                gdk_window_get_geometry (m_widget->window, &client_x, &client_y,
                                         &width, &height, NULL);
-                     
+
         wx_win_hints_set_layer( m_widget, WIN_LAYER_ABOVE_DOCK );
 
                gdk_window_move_resize (m_widget->window, -client_x, -client_y,
@@ -590,7 +579,7 @@ bool wxTopLevelWindowGTK::ShowFullScreen(bool show, long style )
     else
     {
         wx_win_hints_set_layer( m_widget, WIN_LAYER_NORMAL );
-        
+
         SetSize( m_fsSaveFrame.x, m_fsSaveFrame.y, m_fsSaveFrame.width, m_fsSaveFrame.height );
     }
 
@@ -778,7 +767,7 @@ void wxTopLevelWindowGTK::GtkOnSize( int WXUNUSED(x), int WXUNUSED(y),
             // Gtk-WARNING **: gtk_widget_size_allocate():
             //       attempt to allocate widget with width 65535 and height 600
             // but I don't have time to track them all now..
-            // 
+            //
             // Really we need to encapulate all this height/width business and
             // stop any old method from ripping at the members directly and
             // scattering -1's without regard for who might resolve them later.
index f2005c8c5dc1153913d3685d793764d6c5366cfa..73fc746c0b1e2b4a01fa878e56901382be4965e5 100644 (file)
@@ -483,7 +483,7 @@ wxTopLevelWindowGTK::~wxTopLevelWindowGTK()
         wxASSERT_MSG( FALSE, _T("Window still grabbed"));
         RemoveGrab();
     }
-    
+
     m_isBeingDeleted = TRUE;
 
     // it may also be GtkScrolledWindow in the case of an MDI child
@@ -491,17 +491,6 @@ wxTopLevelWindowGTK::~wxTopLevelWindowGTK()
     {
         gtk_window_set_focus( GTK_WINDOW(m_widget), NULL );
     }
-
-    wxTopLevelWindows.DeleteObject( this );
-
-    if (wxTheApp->GetTopWindow() == this)
-        wxTheApp->SetTopWindow( (wxWindow*) NULL );
-
-    if ((wxTopLevelWindows.Number() == 0) &&
-        (wxTheApp->GetExitOnFrameDelete()))
-    {
-        wxTheApp->ExitMainLoop();
-    }
 }
 
 
@@ -522,11 +511,11 @@ static void wx_win_hints_set_layer(GtkWidget *window, int layer)
     XEvent xev;
     GdkWindowPrivate *priv;
     gint prev_error;
-  
+
     prev_error = gdk_error_warnings;
     gdk_error_warnings = 0;
     priv = (GdkWindowPrivate*)(GTK_WIDGET(window)->window);
-  
+
     if (GTK_WIDGET_MAPPED(window))
     {
         xev.type = ClientMessage;
@@ -536,14 +525,14 @@ static void wx_win_hints_set_layer(GtkWidget *window, int layer)
         xev.xclient.format = 32;
         xev.xclient.data.l[0] = (long)layer;
         xev.xclient.data.l[1] = gdk_time_get();
-      
+
         XSendEvent(GDK_DISPLAY(), GDK_ROOT_WINDOW(), False,
             SubstructureNotifyMask, (XEvent*) &xev);
     }
     else
     {
         long data[1];
-      
+
         data[0] = layer;
         XChangeProperty(GDK_DISPLAY(), priv->xwindow, gs_XA_WIN_LAYER,
               XA_CARDINAL, 32, PropModeReplace, (unsigned char *)data, 1);
@@ -574,14 +563,14 @@ bool wxTopLevelWindowGTK::ShowFullScreen(bool show, long style )
 
         int screen_width,screen_height;
         wxDisplaySize( &screen_width, &screen_height );
-        
+
                gint client_x, client_y, root_x, root_y;
                gint width, height;
 
                gdk_window_get_origin (m_widget->window, &root_x, &root_y);
                gdk_window_get_geometry (m_widget->window, &client_x, &client_y,
                                         &width, &height, NULL);
-                     
+
         wx_win_hints_set_layer( m_widget, WIN_LAYER_ABOVE_DOCK );
 
                gdk_window_move_resize (m_widget->window, -client_x, -client_y,
@@ -590,7 +579,7 @@ bool wxTopLevelWindowGTK::ShowFullScreen(bool show, long style )
     else
     {
         wx_win_hints_set_layer( m_widget, WIN_LAYER_NORMAL );
-        
+
         SetSize( m_fsSaveFrame.x, m_fsSaveFrame.y, m_fsSaveFrame.width, m_fsSaveFrame.height );
     }
 
@@ -778,7 +767,7 @@ void wxTopLevelWindowGTK::GtkOnSize( int WXUNUSED(x), int WXUNUSED(y),
             // Gtk-WARNING **: gtk_widget_size_allocate():
             //       attempt to allocate widget with width 65535 and height 600
             // but I don't have time to track them all now..
-            // 
+            //
             // Really we need to encapulate all this height/width business and
             // stop any old method from ripping at the members directly and
             // scattering -1's without regard for who might resolve them later.
index c4808f1b359199b939dcd21c9c29600a36b3a5ef..a6ba1ee020db779c6967d83b57bc7e9c6723d706 100644 (file)
@@ -701,22 +701,8 @@ int wxEntry(WXHINSTANCE hInstance,
         wxLog::SetTimestamp(NULL);
 #endif
 
-        int retValue = 0;
-
-        // it is common to create a modal dialog in OnInit() (to ask/notify the
-        // user about something) but it wouldn't work if we don't change the
-        // "exit on delete last frame" flag here as when this dialog is
-        // deleted, the app would terminate (it was the last top level window
-        // as the main frame wasn't created yet!), so disable this behaviour
-        // temproarily
-        bool exitOnLastFrameDelete = wxTheApp->GetExitOnFrameDelete();
-        wxTheApp->SetExitOnFrameDelete(FALSE);
-
         // init the app
-        retValue = wxEntryInitGui() && wxTheApp->OnInit() ? 0 : -1;
-
-        // restore the old flag value
-        wxTheApp->SetExitOnFrameDelete(exitOnLastFrameDelete);
+        int retValue = wxEntryInitGui() && wxTheApp->OnInit() ? 0 : -1;
 
         if ( retValue == 0 )
         {
@@ -986,8 +972,8 @@ bool wxApp::ProcessIdle()
 
 void wxApp::ExitMainLoop()
 {
-    // VZ: why not ::PostQuitMessage()?
-    m_keepGoing = FALSE;
+    // this will set m_keepGoing to FALSE a bit later
+    ::PostQuitMessage(0);
 }
 
 bool wxApp::Pending()
index 9ce65687c60bacaa7596f83965b0c199a7e4c5ea..1e6fc3de12e88a800a3a4d5d0d8cc55be44a2436 100644 (file)
@@ -454,12 +454,12 @@ wxTopLevelWindowMSW::~wxTopLevelWindowMSW()
     if ( this == ms_hiddenParent )
     {
         // stop [infinite] recursion which would otherwise happen when we do
-        // "delete ms_hiddenParent" below
+        // "delete ms_hiddenParent" below -- and we're not interested in doing
+        // anything of the rest below for that window because the rest of
+        // wxWindows doesn't even know about it
         return;
     }
 
-    wxTopLevelWindows.DeleteObject(this);
-
     if ( wxModelessWindows.Find(this) )
         wxModelessWindows.DeleteObject(this);
 
@@ -476,21 +476,15 @@ wxTopLevelWindowMSW::~wxTopLevelWindowMSW()
         }
     }
 
-    // If this is the last top-level window, exit.
-    if ( wxTheApp && (wxTopLevelWindows.Number() == 0) )
+    // if this is the last top-level window, we're going to exit and we should
+    // delete ms_hiddenParent now to avoid leaking it
+    if ( IsLastBeforeExit() )
     {
         if ( ms_hiddenParent )
         {
             delete ms_hiddenParent;
             ms_hiddenParent = NULL;
         }
-
-        wxTheApp->SetTopWindow(NULL);
-
-        if ( wxTheApp->GetExitOnFrameDelete() )
-        {
-            ::PostQuitMessage(0);
-        }
     }
 }