X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/c42404a58eac2c9eb0557565a471a794c387a715..c97e7fa8dbda704c9c9cdb61c22ebdf9b692e114:/src/msw/app.cpp diff --git a/src/msw/app.cpp b/src/msw/app.cpp index cb05b27011..36dedf8627 100644 --- a/src/msw/app.cpp +++ b/src/msw/app.cpp @@ -122,11 +122,9 @@ // --------------------------------------------------------------------------- extern wxChar *wxBuffer; -extern wxChar *wxOsVersion; extern wxList *wxWinHandleList; extern wxList WXDLLEXPORT wxPendingDelete; extern void wxSetKeyboardHook(bool doIt); -extern wxCursor *g_globalCursor; MSG s_currentMsg; wxApp *wxTheApp = NULL; @@ -140,7 +138,9 @@ const wxChar *wxMDIFrameClassNameNoRedraw = wxT("wxMDIFrameClassNR"); const wxChar *wxMDIChildFrameClassName = wxT("wxMDIChildFrameClass"); const wxChar *wxMDIChildFrameClassNameNoRedraw = wxT("wxMDIChildFrameClassNR"); const wxChar *wxPanelClassName = wxT("wxPanelClass"); +const wxChar *wxPanelClassNameNR = wxT("wxPanelClassNR"); const wxChar *wxCanvasClassName = wxT("wxCanvasClass"); +const wxChar *wxCanvasClassNameNR = wxT("wxCanvasClassNR"); HICON wxSTD_FRAME_ICON = (HICON) NULL; HICON wxSTD_MDICHILDFRAME_ICON = (HICON) NULL; @@ -154,6 +154,20 @@ HBRUSH wxDisableButtonBrush = (HBRUSH) 0; LRESULT WXDLLEXPORT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM); +// FIXME wxUSE_ON_FATAL_EXCEPTION is only supported for VC++ now because it +// needs compiler support for Win32 SEH. Others (especially Borland) +// probably have it too, but I'm not sure about how it works +// JACS: get 'Cannot use __try in functions that require unwinding +// in Unicode mode, so disabling. +#if !defined(__VISUALC__) || defined(__WIN16__) || defined(UNICODE) + #undef wxUSE_ON_FATAL_EXCEPTION + #define wxUSE_ON_FATAL_EXCEPTION 0 +#endif // VC++ + +#if wxUSE_ON_FATAL_EXCEPTION + static bool gs_handleExceptions = FALSE; +#endif + // =========================================================================== // implementation // =========================================================================== @@ -162,17 +176,38 @@ LRESULT WXDLLEXPORT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM); // wxApp // --------------------------------------------------------------------------- - IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler) +IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler) - BEGIN_EVENT_TABLE(wxApp, wxEvtHandler) - EVT_IDLE(wxApp::OnIdle) - EVT_END_SESSION(wxApp::OnEndSession) - EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession) - END_EVENT_TABLE() +BEGIN_EVENT_TABLE(wxApp, wxEvtHandler) + EVT_IDLE(wxApp::OnIdle) + EVT_END_SESSION(wxApp::OnEndSession) + EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession) +END_EVENT_TABLE() //// Initialize bool wxApp::Initialize() { + // the first thing to do is to check if we're trying to run an Unicode + // program under Win9x - if so, abort right now as it has no chance to + // work +#if wxUSE_UNICODE + if ( wxGetOsVersion() != wxWINDOWS_NT ) + { + // note that we can use MessageBoxW() as it's implemented even under + // Win9x - OTOH, we can't use wxGetTranslation() because the file APIs + // used by wxLocale are not + ::MessageBox + ( + NULL, + _T("This program uses Unicode and requires Windows NT/2000.\nProgram aborted."), + _T("wxWindows Fatal Error"), + MB_ICONERROR | MB_OK + ); + + return FALSE; + } +#endif // wxUSE_UNICODE + // Some people may wish to use this, but // probably it shouldn't be here by default. #ifdef __WXDEBUG__ @@ -183,10 +218,6 @@ bool wxApp::Initialize() wxClassInfo::InitializeClasses(); -#if wxUSE_RESOURCES - wxGetResource(wxT("wxWindows"), wxT("OsVersion"), &wxOsVersion); -#endif - #if wxUSE_THREADS wxPendingEventsLocker = new wxCriticalSection; #endif @@ -228,8 +259,6 @@ bool wxApp::Initialize() Ctl3dAutoSubclass(wxhInstance); #endif - g_globalCursor = new wxCursor; - // VZ: these icons are not in wx.rc anyhow (but should they?)! #if 0 wxSTD_FRAME_ICON = LoadIcon(wxhInstance, wxT("wxSTD_FRAME")); @@ -263,7 +292,7 @@ bool wxApp::Initialize() // This is to foil optimizations in Visual C++ that throw out dummy.obj. // PLEASE DO NOT ALTER THIS. -#if defined(__VISUALC__) && !defined(WXMAKINGDLL) +#if defined(__VISUALC__) && defined(__WIN16__) && !defined(WXMAKINGDLL) extern char wxDummyChar; if (wxDummyChar) wxDummyChar++; #endif @@ -308,7 +337,7 @@ bool wxApp::RegisterWindowClasses() if ( !RegisterClass(&wndclass) ) { - wxLogLastError("RegisterClass(frame)"); + wxLogLastError(wxT("RegisterClass(frame)")); return FALSE; } @@ -319,7 +348,7 @@ bool wxApp::RegisterWindowClasses() if ( !RegisterClass(&wndclass) ) { - wxLogLastError("RegisterClass(no redraw frame)"); + wxLogLastError(wxT("RegisterClass(no redraw frame)")); return FALSE; } @@ -331,7 +360,7 @@ bool wxApp::RegisterWindowClasses() if ( !RegisterClass(&wndclass) ) { - wxLogLastError("RegisterClass(MDI parent)"); + wxLogLastError(wxT("RegisterClass(MDI parent)")); return FALSE; } @@ -342,7 +371,7 @@ bool wxApp::RegisterWindowClasses() if ( !RegisterClass(&wndclass) ) { - wxLogLastError("RegisterClass(no redraw MDI parent frame)"); + wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)")); return FALSE; } @@ -354,7 +383,7 @@ bool wxApp::RegisterWindowClasses() if ( !RegisterClass(&wndclass) ) { - wxLogLastError("RegisterClass(MDI child)"); + wxLogLastError(wxT("RegisterClass(MDI child)")); return FALSE; } @@ -365,7 +394,7 @@ bool wxApp::RegisterWindowClasses() if ( !RegisterClass(&wndclass) ) { - wxLogLastError("RegisterClass(no redraw MDI child)"); + wxLogLastError(wxT("RegisterClass(no redraw MDI child)")); return FALSE; } @@ -377,7 +406,18 @@ bool wxApp::RegisterWindowClasses() if ( !RegisterClass(&wndclass) ) { - wxLogLastError("RegisterClass(panel)"); + wxLogLastError(wxT("RegisterClass(panel)")); + + return FALSE; + } + + // Register the no redraw panel window class. + wndclass.lpszClassName = wxPanelClassNameNR; + wndclass.style = styleNoRedraw; + + if ( !RegisterClass(&wndclass) ) + { + wxLogLastError(wxT("RegisterClass(no redraw panel)")); return FALSE; } @@ -388,7 +428,16 @@ bool wxApp::RegisterWindowClasses() if ( !RegisterClass(&wndclass) ) { - wxLogLastError("RegisterClass(canvas)"); + wxLogLastError(wxT("RegisterClass(canvas)")); + + return FALSE; + } + + wndclass.lpszClassName = wxCanvasClassNameNR; + wndclass.style = styleNoRedraw; + if ( !RegisterClass(&wndclass) ) + { + wxLogLastError(wxT("RegisterClass(no redraw canvas)")); return FALSE; } @@ -497,13 +546,6 @@ void wxApp::CleanUp() // wxDefaultResourceTable->ClearTable(); #endif - // Indicate that the cursor can be freed, so that cursor won't be deleted - // by deleting the bitmap list before g_globalCursor goes out of scope - // (double deletion of the cursor). - wxSetCursor(wxNullCursor); - delete g_globalCursor; - g_globalCursor = NULL; - wxDeleteStockObjects(); // Destroy all GDI lists, etc. @@ -574,7 +616,7 @@ void wxApp::CleanUp() // wxDebugContext, too. if (wxDebugContext::CountObjectsLeft(TRUE) > 0) { - wxLogDebug(wxT("There were memory leaks.")); + wxLogMessage(wxT("There were memory leaks.")); wxDebugContext::Dump(); wxDebugContext::PrintStatistics(); } @@ -587,6 +629,27 @@ void wxApp::CleanUp() #endif // wxUSE_LOG } +//---------------------------------------------------------------------- +// Entry point helpers, used by wxPython +//---------------------------------------------------------------------- + +int WXDLLEXPORT wxEntryStart( int WXUNUSED(argc), char** WXUNUSED(argv) ) +{ + return wxApp::Initialize(); +} + +int WXDLLEXPORT wxEntryInitGui() +{ + wxTheApp->OnInitGui(); + return 0; +} + +void WXDLLEXPORT wxEntryCleanup() +{ + wxApp::CleanUp(); +} + + #if !defined(_WINDLL) || (defined(_WINDLL) && defined(WXMAKINGDLL)) // temporarily disable this warning which would be generated in release builds @@ -595,7 +658,9 @@ void wxApp::CleanUp() #pragma warning(disable: 4715) // not all control paths return a value #endif // Visual C++ -//// Main wxWindows entry point +//---------------------------------------------------------------------- +// Main wxWindows entry point +//---------------------------------------------------------------------- int wxEntry(WXHINSTANCE hInstance, WXHINSTANCE WXUNUSED(hPrevInstance), char *lpCmdLine, @@ -617,20 +682,15 @@ int wxEntry(WXHINSTANCE hInstance, wxDebugContext::SetCheckpoint(); #endif #endif - // take everything into a try-except block in release build - // FIXME other compilers must support Win32 SEH (structured exception - // handling) too, just find the appropriate keyword in their docs! - // Please note that it's _not_ the same as C++ exceptions! -#if !defined(__WXDEBUG__) && defined(__VISUALC__) - #define CATCH_PROGRAM_EXCEPTIONS + // take everything into a try-except block to be able to call + // OnFatalException() if necessary +#if wxUSE_ON_FATAL_EXCEPTION __try { -#else - #undef CATCH_PROGRAM_EXCEPTIONS #endif wxhInstance = (HINSTANCE) hInstance; - if (!wxApp::Initialize()) + if (!wxEntryStart(0,0)) return 0; // create the application object or ensure that one already exists @@ -653,7 +713,7 @@ int wxEntry(WXHINSTANCE hInstance, // GUI-specific initialisation. In fact on Windows we don't have any, // but this call is provided for compatibility across platforms. - wxTheApp->OnInitGui(); + wxEntryInitGui(); // We really don't want timestamps by default, because it means // we can't simply double-click on the error message and get to that @@ -664,15 +724,33 @@ int wxEntry(WXHINSTANCE hInstance, int retValue = 0; - if ( wxTheApp->OnInit() ) + // 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 = wxTheApp->OnInit() ? 0 : -1; + + // restore the old flag value + wxTheApp->SetExitOnFrameDelete(exitOnLastFrameDelete); + + if ( retValue == 0 ) { if ( enterLoop ) { + // run the main loop retValue = wxTheApp->OnRun(); } else - // We want to initialize, but not run or exit immediately. + { + // we want to initialize, but not run or exit immediately. return 1; + } } //else: app initialization failed, so we skipped OnRun() @@ -695,30 +773,25 @@ int wxEntry(WXHINSTANCE hInstance, wxTheApp->OnExit(); - wxApp::CleanUp(); + wxEntryCleanup(); return retValue; -#ifdef CATCH_PROGRAM_EXCEPTIONS +#if wxUSE_ON_FATAL_EXCEPTION } - __except ( EXCEPTION_EXECUTE_HANDLER ) { - /* - if ( wxTheApp ) + __except ( gs_handleExceptions ? EXCEPTION_EXECUTE_HANDLER + : EXCEPTION_CONTINUE_SEARCH ) { + if ( wxTheApp ) + { + // give the user a chance to do something special about this wxTheApp->OnFatalException(); - */ - - // using wxLog would be unsafe here - ::MessageBox(NULL, - _("Unrecoverable program error detected: " - " the application will terminate."), - _("Fatal Error"), - MB_APPLMODAL | MB_ICONSTOP | MB_OK); + } ::ExitProcess(3); // the same exit code as abort() // NOTREACHED } -#endif // CATCH_PROGRAM_EXCEPTIONS +#endif // wxUSE_ON_FATAL_EXCEPTION } // restore warning state @@ -728,12 +801,14 @@ int wxEntry(WXHINSTANCE hInstance, #else /* _WINDLL */ -//// Entry point for DLLs +//---------------------------------------------------------------------- +// Entry point for wxWindows + the App in a DLL +//---------------------------------------------------------------------- int wxEntry(WXHINSTANCE hInstance) { wxhInstance = (HINSTANCE) hInstance; - wxApp::Initialize(); + wxEntryStart(0, 0); // The app may have declared a global application object, but we recommend // the IMPLEMENT_APP macro is used instead, which sets an initializer function @@ -751,7 +826,7 @@ int wxEntry(WXHINSTANCE hInstance) wxTheApp->argc = 0; wxTheApp->argv = NULL; - wxTheApp->OnInitGui(); + wxEntryInitGui(); wxTheApp->OnInit(); @@ -800,8 +875,7 @@ bool wxApp::Initialized() return TRUE; else return FALSE; -#endif -#ifdef _WINDLL // Assume initialized if DLL (no way of telling) +#else // Assume initialized if DLL (no way of telling) return TRUE; #endif } @@ -824,7 +898,7 @@ bool wxApp::DoMessage() else if ( rc == -1 ) { // should never happen, but let's test for it nevertheless - wxLogLastError("GetMessage"); + wxLogLastError(wxT("GetMessage")); } else { @@ -979,6 +1053,7 @@ bool wxApp::ProcessMessage(WXMSG *wxmsg) // Try translations first; find the youngest window with // a translation table. wxWindow *wnd; + for ( wnd = wndThis; wnd; wnd = wnd->GetParent() ) { if ( wnd->MSWTranslateMessage(wxmsg) ) @@ -1005,14 +1080,21 @@ void wxApp::OnIdle(wxIdleEvent& event) s_inOnIdle = TRUE; + // If there are pending events, we must process them: pending events + // are either events to the threads other than main or events posted + // with wxPostEvent() functions + // GRG: I have moved this here so that all pending events are processed + // before starting to delete any objects. This behaves better (in + // particular, wrt wxPostEvent) and is coherent with wxGTK's current + // behaviour. Changed Feb/2000 before 2.1.14 + ProcessPendingEvents(); + // 'Garbage' collection of windows deleted with Close(). DeletePendingObjects(); #if wxUSE_LOG // flush the logged messages if any - wxLog *pLog = wxLog::GetActiveTarget(); - if ( pLog != NULL && pLog->HasPendingMessages() ) - pLog->Flush(); + wxLog::FlushActive(); #endif // wxUSE_LOG // Send OnIdle events to all windows @@ -1023,11 +1105,6 @@ void wxApp::OnIdle(wxIdleEvent& event) event.RequestMore(TRUE); } - // If they are pending events, we must process them: pending events are - // either events to the threads other than main or events posted with - // wxPostEvent() functions - ProcessPendingEvents(); - s_inOnIdle = FALSE; } @@ -1130,7 +1207,7 @@ int wxApp::GetComCtl32Version() // try to use DllGetVersion() if available in _headers_ #ifdef DLLVER_PLATFORM_WINDOWS // defined in shlwapi.h DLLGETVERSIONPROC pfnDllGetVersion = (DLLGETVERSIONPROC) - ::GetProcAddress(hModuleComCtl32, _T("DllGetVersion")); + ::GetProcAddress(hModuleComCtl32, "DllGetVersion"); if ( pfnDllGetVersion ) { DLLVERSIONINFO dvi; @@ -1159,11 +1236,7 @@ int wxApp::GetComCtl32Version() FARPROC theProc = ::GetProcAddress ( hModuleComCtl32, -#if defined(__BORLANDC__) && (__BORLANDC__ <= 0x520) "InitCommonControlsEx" -#else - _T("InitCommonControlsEx") -#endif ); if ( !theProc ) @@ -1178,11 +1251,7 @@ int wxApp::GetComCtl32Version() theProc = ::GetProcAddress ( hModuleComCtl32, -#if defined(__BORLANDC__) && (__BORLANDC__ <= 0x520) "InitializeFlatSB" -#else - _T("InitializeFlatSB") -#endif ); if ( !theProc ) { @@ -1207,14 +1276,28 @@ void wxExit() wxLogError(_("Fatal error: exiting")); wxApp::CleanUp(); + exit(0); } // Yield to incoming messages + +static bool gs_inYield = FALSE; + bool wxYield() { + // disable log flushing from here because a call to wxYield() shouldn't + // normally result in message boxes popping up &c + wxLog::Suspend(); + +#ifdef __WXDEBUG__ + if (gs_inYield) + wxFAIL_MSG( wxT("wxYield called recursively" ) ); +#endif + + gs_inYield = TRUE; + // we don't want to process WM_QUIT from here - it should be processed in // the main event loop in order to stop it - MSG msg; while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) && msg.message != WM_QUIT ) @@ -1228,9 +1311,38 @@ bool wxYield() } // If they are pending events, we must process them. - wxTheApp->ProcessPendingEvents(); + if (wxTheApp) + wxTheApp->ProcessPendingEvents(); + + // let the logs be flashed again + wxLog::Resume(); + + gs_inYield = FALSE; + + return TRUE; +} + +// Yield to incoming messages; but fail silently if recursion is detected. +bool wxYieldIfNeeded() +{ + if (gs_inYield) + return FALSE; + + return wxYield(); +} + +bool wxHandleFatalExceptions(bool doit) +{ +#if wxUSE_ON_FATAL_EXCEPTION + // assume this can only be called from the main thread + gs_handleExceptions = doit; return TRUE; +#else + wxFAIL_MSG(_T("set wxUSE_ON_FATAL_EXCEPTION to 1 to sue this function")); + + return FALSE; +#endif } //----------------------------------------------------------------------------- @@ -1249,7 +1361,7 @@ void wxWakeUpIdle() if ( !::PostMessage(GetHwndOf(topWindow), WM_NULL, 0, 0) ) { // should never happen - wxLogLastError("PostMessage(WM_NULL)"); + wxLogLastError(wxT("PostMessage(WM_NULL)")); } } }