X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/3b415ba4cdee694574d7235ff0b8341f105cddfe..211cc8dc907ee50ca6d383b8df16bba9a4d3ce2d:/src/msw/app.cpp diff --git a/src/msw/app.cpp b/src/msw/app.cpp index 073c53e737..72d8437e63 100644 --- a/src/msw/app.cpp +++ b/src/msw/app.cpp @@ -86,11 +86,13 @@ #include #include -#if defined(__WIN95__) && !(defined(__GNUWIN32_OLD__) || defined(__TWIN32__)) +#if defined(__WIN95__) && !((defined(__GNUWIN32_OLD__) || defined(__TWIN32__) || defined(__WXMICROWIN__)) && !defined(__CYGWIN10__)) #include #endif +#ifndef __WXMICROWIN__ #include "wx/msw/msvcrt.h" +#endif // ---------------------------------------------------------------------------- // conditional compilation @@ -113,7 +115,8 @@ #define _WIN32_IE 0x0200 #endif -#if _WIN32_IE >= 0x0300 +#if _WIN32_IE >= 0x0300 \ + && !( defined(__MINGW32__) && !wxCHECK_W32API_VERSION( 1, 0 ) ) #include #endif @@ -122,10 +125,11 @@ // --------------------------------------------------------------------------- extern wxChar *wxBuffer; -extern wxChar *wxOsVersion; extern wxList *wxWinHandleList; extern wxList WXDLLEXPORT wxPendingDelete; +#ifndef __WXMICROWIN__ extern void wxSetKeyboardHook(bool doIt); +#endif MSG s_currentMsg; wxApp *wxTheApp = NULL; @@ -155,6 +159,16 @@ 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 @@ -167,17 +181,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__ @@ -188,10 +223,6 @@ bool wxApp::Initialize() wxClassInfo::InitializeClasses(); -#if wxUSE_RESOURCES - wxGetResource(wxT("wxWindows"), wxT("OsVersion"), &wxOsVersion); -#endif - #if wxUSE_THREADS wxPendingEventsLocker = new wxCriticalSection; #endif @@ -208,12 +239,11 @@ bool wxApp::Initialize() wxBitmap::InitStandardHandlers(); -#if defined(__WIN95__) +#if defined(__WIN95__) && !defined(__WXMICROWIN__) InitCommonControls(); - #endif // __WIN95__ -#if wxUSE_OLE +#if wxUSE_OLE || wxUSE_DRAG_AND_DROP #ifdef __WIN16__ // for OLE, enlarge message queue to be as large as possible @@ -221,9 +251,11 @@ bool wxApp::Initialize() while (!SetMessageQueue(iMsg) && (iMsg -= 8)) ; #endif // Win16 + // we need to initialize OLE library if ( FAILED(::OleInitialize(NULL)) ) wxLogError(_("Cannot initialize OLE")); + #endif // wxUSE_OLE #if wxUSE_CTL3D @@ -231,7 +263,7 @@ bool wxApp::Initialize() wxLogError(wxT("Cannot register CTL3D")); Ctl3dAutoSubclass(wxhInstance); -#endif +#endif // wxUSE_CTL3D // VZ: these icons are not in wx.rc anyhow (but should they?)! #if 0 @@ -246,6 +278,7 @@ bool wxApp::Initialize() RegisterWindowClasses(); +#ifndef __WXMICROWIN__ // Create the brush for disabling bitmap buttons LOGBRUSH lb; @@ -257,6 +290,7 @@ bool wxApp::Initialize() ::DeleteObject( (HGDIOBJ)lb.lbHatch ); } //else: wxWindows resources are probably not linked in +#endif #if wxUSE_PENWINDOWS wxRegisterPenWin(); @@ -266,12 +300,14 @@ 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 +#ifndef __WXMICROWIN__ wxSetKeyboardHook(TRUE); +#endif wxModule::RegisterModules(); if (!wxModule::InitializeModules()) @@ -311,7 +347,7 @@ bool wxApp::RegisterWindowClasses() if ( !RegisterClass(&wndclass) ) { - wxLogLastError("RegisterClass(frame)"); + wxLogLastError(wxT("RegisterClass(frame)")); return FALSE; } @@ -322,7 +358,7 @@ bool wxApp::RegisterWindowClasses() if ( !RegisterClass(&wndclass) ) { - wxLogLastError("RegisterClass(no redraw frame)"); + wxLogLastError(wxT("RegisterClass(no redraw frame)")); return FALSE; } @@ -334,7 +370,7 @@ bool wxApp::RegisterWindowClasses() if ( !RegisterClass(&wndclass) ) { - wxLogLastError("RegisterClass(MDI parent)"); + wxLogLastError(wxT("RegisterClass(MDI parent)")); return FALSE; } @@ -345,7 +381,7 @@ bool wxApp::RegisterWindowClasses() if ( !RegisterClass(&wndclass) ) { - wxLogLastError("RegisterClass(no redraw MDI parent frame)"); + wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)")); return FALSE; } @@ -357,7 +393,7 @@ bool wxApp::RegisterWindowClasses() if ( !RegisterClass(&wndclass) ) { - wxLogLastError("RegisterClass(MDI child)"); + wxLogLastError(wxT("RegisterClass(MDI child)")); return FALSE; } @@ -368,7 +404,7 @@ bool wxApp::RegisterWindowClasses() if ( !RegisterClass(&wndclass) ) { - wxLogLastError("RegisterClass(no redraw MDI child)"); + wxLogLastError(wxT("RegisterClass(no redraw MDI child)")); return FALSE; } @@ -380,7 +416,7 @@ bool wxApp::RegisterWindowClasses() if ( !RegisterClass(&wndclass) ) { - wxLogLastError("RegisterClass(panel)"); + wxLogLastError(wxT("RegisterClass(panel)")); return FALSE; } @@ -391,7 +427,7 @@ bool wxApp::RegisterWindowClasses() if ( !RegisterClass(&wndclass) ) { - wxLogLastError("RegisterClass(no redraw panel)"); + wxLogLastError(wxT("RegisterClass(no redraw panel)")); return FALSE; } @@ -402,7 +438,7 @@ bool wxApp::RegisterWindowClasses() if ( !RegisterClass(&wndclass) ) { - wxLogLastError("RegisterClass(canvas)"); + wxLogLastError(wxT("RegisterClass(canvas)")); return FALSE; } @@ -411,7 +447,7 @@ bool wxApp::RegisterWindowClasses() wndclass.style = styleNoRedraw; if ( !RegisterClass(&wndclass) ) { - wxLogLastError("RegisterClass(no redraw canvas)"); + wxLogLastError(wxT("RegisterClass(no redraw canvas)")); return FALSE; } @@ -535,7 +571,9 @@ void wxApp::CleanUp() //// WINDOWS-SPECIFIC CLEANUP +#ifndef __WXMICROWIN__ wxSetKeyboardHook(FALSE); +#endif #if wxUSE_PENWINDOWS wxCleanUpPenWin(); @@ -572,11 +610,14 @@ void wxApp::CleanUp() // GL: I'm annoyed ... I don't know where to put this and I don't want to // create a module for that as it's part of the core. delete wxPendingEvents; + #if wxUSE_THREADS delete wxPendingEventsLocker; - // If we don't do the following, we get an apparent memory leak. + // If we don't do the following, we get an apparent memory leak +#if wxUSE_VALIDATORS ((wxEvtHandler&) wxDefaultValidator).ClearEventLocker(); -#endif +#endif // wxUSE_VALIDATORS +#endif // wxUSE_THREADS wxClassInfo::CleanUpClasses(); @@ -607,15 +648,14 @@ void wxApp::CleanUp() // Entry point helpers, used by wxPython //---------------------------------------------------------------------- -int WXDLLEXPORT wxEntryStart( int WXUNUSED(argc), char** WXUNUSED(argv) ) +int WXDLLEXPORT wxEntryStart( int WXUNUSED(argc), char** WXUNUSED(argv) ) { return wxApp::Initialize(); } -int WXDLLEXPORT wxEntryInitGui() +int WXDLLEXPORT wxEntryInitGui() { - wxTheApp->OnInitGui(); - return 0; + return wxTheApp->OnInitGui(); } void WXDLLEXPORT wxEntryCleanup() @@ -644,7 +684,10 @@ int wxEntry(WXHINSTANCE hInstance, // do check for memory leaks on program exit // (another useful flag is _CRTDBG_DELAY_FREE_MEM_DF which doesn't free // deallocated memory which may be used to simulate low-memory condition) +#ifndef __WXMICROWIN__ wxCrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF); +#endif + #ifdef __MWERKS__ #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT // This seems to be necessary since there are 'rogue' @@ -659,10 +702,6 @@ int wxEntry(WXHINSTANCE hInstance, // take everything into a try-except block to be able to call // OnFatalException() if necessary - - // 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 wxUSE_ON_FATAL_EXCEPTION __try { #endif @@ -680,7 +719,7 @@ int wxEntry(WXHINSTANCE hInstance, wxCHECK_MSG( wxApp::GetInitializerFunction(), 0, wxT("No initializer - use IMPLEMENT_APP macro.") ); - wxTheApp = (*wxApp::GetInitializerFunction()) (); + wxTheApp = (wxApp*) (*wxApp::GetInitializerFunction()) (); } wxCHECK_MSG( wxTheApp, 0, wxT("You have to define an instance of wxApp!") ); @@ -689,10 +728,6 @@ int wxEntry(WXHINSTANCE hInstance, wxTheApp->ConvertToStandardCommandArgs(lpCmdLine); wxTheApp->m_nCmdShow = nCmdShow; - // GUI-specific initialisation. In fact on Windows we don't have any, - // but this call is provided for compatibility across platforms. - 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 // line in the source. So VC++ at least, let's have a sensible default. @@ -702,15 +737,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 = wxEntryInitGui() && 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() @@ -742,14 +795,10 @@ int wxEntry(WXHINSTANCE hInstance, __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() @@ -810,14 +859,9 @@ wxAppInitializerFunction wxAppBase::m_appInitFn = (wxAppInitializerFunction) NUL wxApp::wxApp() { - m_topWindow = NULL; - wxTheApp = this; - m_wantDebugOutput = TRUE; - argc = 0; argv = NULL; m_printMode = wxPRINT_WINDOWS; - m_exitOnFrameDelete = TRUE; m_auto3D = TRUE; } @@ -862,7 +906,7 @@ bool wxApp::DoMessage() else if ( rc == -1 ) { // should never happen, but let's test for it nevertheless - wxLogLastError("GetMessage"); + wxLogLastError(wxT("GetMessage")); } else { @@ -919,16 +963,21 @@ bool wxApp::DoMessage() #endif // wxUSE_THREADS // Process the message - if ( !ProcessMessage((WXMSG *)&s_currentMsg) ) - { - ::TranslateMessage(&s_currentMsg); - ::DispatchMessage(&s_currentMsg); - } + DoMessage((WXMSG *)&s_currentMsg); } return TRUE; } +void wxApp::DoMessage(WXMSG *pMsg) +{ + if ( !ProcessMessage(pMsg) ) + { + ::TranslateMessage((MSG *)pMsg); + ::DispatchMessage((MSG *)pMsg); + } +} + /* * Keep trying to process messages until WM_QUIT * received. @@ -998,13 +1047,29 @@ void wxApp::Dispatch() bool wxApp::ProcessMessage(WXMSG *wxmsg) { MSG *msg = (MSG *)wxmsg; - HWND hWnd = msg->hwnd; - wxWindow *wndThis = wxGetWindowFromHWND((WXHWND)hWnd); + HWND hwnd = msg->hwnd; + wxWindow *wndThis = wxGetWindowFromHWND((WXHWND)hwnd); + + // this may happen if the event occured in a standard modeless dialog (the + // only example of which I know of is the find/replace dialog) - then call + // IsDialogMessage() to make TAB navigation in it work + if ( !wndThis ) + { + // we need to find the dialog containing this control as + // IsDialogMessage() just eats all the messages (i.e. returns TRUE for + // them) if we call it for the control itself + while ( ::GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD ) + { + hwnd = ::GetParent(hwnd); + } + + return ::IsDialogMessage(hwnd, msg) != 0; + } #if wxUSE_TOOLTIPS // we must relay WM_MOUSEMOVE events to the tooltip ctrl if we want it to // popup the tooltip bubbles - if ( wndThis && (msg->message == WM_MOUSEMOVE) ) + if ( (msg->message == WM_MOUSEMOVE) ) { wxToolTip *tt = wndThis->GetToolTip(); if ( tt ) @@ -1014,22 +1079,39 @@ bool wxApp::ProcessMessage(WXMSG *wxmsg) } #endif // wxUSE_TOOLTIPS - // Try translations first; find the youngest window with - // a translation table. + // allow the window to prevent certain messages from being + // translated/processed (this is currently used by wxTextCtrl to always + // grab Ctrl-C/V/X, even if they are also accelerators in some parent) + if ( !wndThis->MSWShouldPreProcessMessage(wxmsg) ) + { + return FALSE; + } + + // try translations first: the accelerators override everything wxWindow *wnd; + for ( wnd = wndThis; wnd; wnd = wnd->GetParent() ) { - if ( wnd->MSWTranslateMessage(wxmsg) ) + if ( wnd->MSWTranslateMessage(wxmsg)) return TRUE; + + // stop at first top level window, i.e. don't try to process the key + // strokes originating in a dialog using the accelerators of the parent + // frame - this doesn't make much sense + if ( wnd->IsTopLevel() ) + break; } - // Anyone for a non-translation message? Try youngest descendants first. - for ( wnd = wndThis; wnd; wnd = wnd->GetParent() ) + // now try the other hooks (kbd navigation is handled here): we start from + // wndThis->GetParent() because wndThis->MSWProcessMessage() was already + // called above + for ( wnd = wndThis->GetParent(); wnd; wnd = wnd->GetParent() ) { if ( wnd->MSWProcessMessage(wxmsg) ) return TRUE; } + // no special preprocessing for this message, dispatch it normally return FALSE; } @@ -1060,6 +1142,14 @@ void wxApp::OnIdle(wxIdleEvent& event) wxLog::FlushActive(); #endif // wxUSE_LOG +#if wxUSE_DC_CACHEING + // automated DC cache management: clear the cached DCs and bitmap + // if it's likely that the app has finished with them, that is, we + // get an idle event and we're not dragging anything. + if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON)) + wxDC::ClearCache(); +#endif // wxUSE_DC_CACHEING + // Send OnIdle events to all windows if ( SendIdleEvents() ) { @@ -1150,6 +1240,9 @@ void wxApp::OnQueryEndSession(wxCloseEvent& event) /* static */ int wxApp::GetComCtl32Version() { +#ifdef __WXMICROWIN__ + return 0; +#else // cache the result static int s_verComCtl32 = -1; @@ -1170,7 +1263,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; @@ -1199,11 +1292,7 @@ int wxApp::GetComCtl32Version() FARPROC theProc = ::GetProcAddress ( hModuleComCtl32, -#if defined(__BORLANDC__) && (__BORLANDC__ <= 0x520) "InitCommonControlsEx" -#else - _T("InitCommonControlsEx") -#endif ); if ( !theProc ) @@ -1218,11 +1307,7 @@ int wxApp::GetComCtl32Version() theProc = ::GetProcAddress ( hModuleComCtl32, -#if defined(__BORLANDC__) && (__BORLANDC__ <= 0x520) "InitializeFlatSB" -#else - _T("InitializeFlatSB") -#endif ); if ( !theProc ) { @@ -1240,6 +1325,7 @@ int wxApp::GetComCtl32Version() } return s_verComCtl32; +#endif } void wxExit() @@ -1251,12 +1337,22 @@ void wxExit() } // 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; @@ -1278,9 +1374,20 @@ bool wxYield() // 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 @@ -1290,7 +1397,8 @@ bool wxHandleFatalExceptions(bool doit) return TRUE; #else wxFAIL_MSG(_T("set wxUSE_ON_FATAL_EXCEPTION to 1 to sue this function")); - + + (void)doit; return FALSE; #endif } @@ -1311,7 +1419,7 @@ void wxWakeUpIdle() if ( !::PostMessage(GetHwndOf(topWindow), WM_NULL, 0, 0) ) { // should never happen - wxLogLastError("PostMessage(WM_NULL)"); + wxLogLastError(wxT("PostMessage(WM_NULL)")); } } }