]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/utilsexc.cpp
we do want arrows even in a read only text ctrl
[wxWidgets.git] / src / msw / utilsexc.cpp
index e550fca890a1276545555fb6dcb8c5a5a7505a1f..58b26f2c07d29002db2f71e2bff58235f6a86b1c 100644 (file)
     #include "wx/utils.h"
     #include "wx/app.h"
     #include "wx/intl.h"
+    #include "wx/log.h"
+    #if wxUSE_GUI // See 'dirty hack' below.
+        #include "wx/frame.h"
+    #endif
 #endif
 
-#include "wx/log.h"
-
 #ifdef __WIN32__
     #include "wx/stream.h"
     #include "wx/process.h"
@@ -260,7 +262,7 @@ private:
 // thread function for the thread monitoring the process termination
 static DWORD __stdcall wxExecuteThread(void *arg)
 {
-    wxExecuteData *data = (wxExecuteData*)arg;
+    wxExecuteData * const data = (wxExecuteData *)arg;
 
     if ( ::WaitForSingleObject(data->hProcess, INFINITE) != WAIT_OBJECT_0 )
     {
@@ -291,7 +293,7 @@ LRESULT APIENTRY _EXPORT wxExecuteWindowCbk(HWND hWnd, UINT message,
     {
         DestroyWindow(hWnd);    // we don't need it any more
 
-        wxExecuteData *data = (wxExecuteData *)lParam;
+        wxExecuteData * const data = (wxExecuteData *)lParam;
         if ( data->handler )
         {
             data->handler->OnTerminate((int)data->dwProcessId,
@@ -314,7 +316,7 @@ LRESULT APIENTRY _EXPORT wxExecuteWindowCbk(HWND hWnd, UINT message,
     }
     else
     {
-        return DefWindowProc(hWnd, message, wParam, lParam);
+        return ::DefWindowProc(hWnd, message, wParam, lParam);
     }
 }
 
@@ -845,12 +847,44 @@ long wxExecute(const wxString& cmd, int flags, wxProcess *handler)
         return pi.dwProcessId;
     }
 
-    // waiting until command executed (disable everything while doing it)
+    // disable all app windows while waiting for the child process to finish
 #if wxUSE_GUI
+
+    /*
+       We use a dirty hack here to disable all application windows (which we
+       must do because otherwise the calls to wxYield() could lead to some very
+       unexpected reentrancies in the users code) but to avoid losing
+       focus/activation entirely when the child process terminates which would
+       happen if we simply disabled everything using wxWindowDisabler. Indeed,
+       remember that Windows will never activate a disabled window and when the
+       last childs window is closed and Windows looks for a window to activate
+       all our windows are still disabled. There is no way to enable them in
+       time because we don't know when the childs windows are going to be
+       closed, so the solution we use here is to keep one special tiny frame
+       enabled all the time. Then when the child terminates it will get
+       activated and when we close it below -- after reenabling all the other
+       windows! -- the previously active window becomes activated again and
+       everything is ok.
+     */
+    wxWindow *winActive;
     {
         wxBusyCursor bc;
 
+        // first disable all existing windows
         wxWindowDisabler wd;
+
+        // then create an "invisible" frame: it has minimal size, is positioned
+        // (hopefully) outside the screen and doesn't appear on the taskbar
+        winActive = new wxFrame
+                        (
+                            wxTheApp->GetTopWindow(),
+                            -1,
+                            _T(""),
+                            wxPoint(32600, 32600),
+                            wxSize(1, 1),
+                            wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR
+                        );
+        winActive->Show();
 #endif // wxUSE_GUI
 
         // wait until the child process terminates
@@ -865,12 +899,24 @@ long wxExecute(const wxString& cmd, int flags, wxProcess *handler)
             // real async IO which we don't have for the moment
             ::Sleep(50);
 
+#if wxUSE_GUI
             // repaint the GUI
             wxYield();
+#else // !GUI
+            // dispatch the messages to the hidden window so that it could
+            // process the wxWM_PROC_TERMINATED notification
+            MSG msg;
+            ::PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE);
+#endif // GUI/!GUI
         }
 
 #if wxUSE_GUI
     }
+
+    // finally delete the dummy frame and, as wd has been already destroyed and
+    // the other windows reenabled, the activation is going to return to the
+    // window which had it before
+    winActive->Destroy();
 #endif // wxUSE_GUI
 
     DWORD dwExitCode = data->dwExitCode;