]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/app.cpp
fixed right click handling
[wxWidgets.git] / src / msw / app.cpp
index 903493b2f10080c36c3beaccad64e48009fe1ae5..ed4d7367887739ba8cb9c71fb08307ef66151cdd 100644 (file)
 // ---------------------------------------------------------------------------
 
 extern wxChar *wxBuffer;
-extern wxChar *wxOsVersion;
 extern wxList *wxWinHandleList;
 extern wxList WXDLLEXPORT wxPendingDelete;
 extern void wxSetKeyboardHook(bool doIt);
@@ -139,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;
@@ -153,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
 // ===========================================================================
@@ -161,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__
@@ -182,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
@@ -260,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
@@ -305,7 +337,7 @@ bool wxApp::RegisterWindowClasses()
 
     if ( !RegisterClass(&wndclass) )
     {
-        wxLogLastError("RegisterClass(frame)");
+        wxLogLastError(wxT("RegisterClass(frame)"));
 
         return FALSE;
     }
@@ -316,7 +348,7 @@ bool wxApp::RegisterWindowClasses()
 
     if ( !RegisterClass(&wndclass) )
     {
-        wxLogLastError("RegisterClass(no redraw frame)");
+        wxLogLastError(wxT("RegisterClass(no redraw frame)"));
 
         return FALSE;
     }
@@ -328,7 +360,7 @@ bool wxApp::RegisterWindowClasses()
 
     if ( !RegisterClass(&wndclass) )
     {
-        wxLogLastError("RegisterClass(MDI parent)");
+        wxLogLastError(wxT("RegisterClass(MDI parent)"));
 
         return FALSE;
     }
@@ -339,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;
     }
@@ -351,7 +383,7 @@ bool wxApp::RegisterWindowClasses()
 
     if ( !RegisterClass(&wndclass) )
     {
-        wxLogLastError("RegisterClass(MDI child)");
+        wxLogLastError(wxT("RegisterClass(MDI child)"));
 
         return FALSE;
     }
@@ -362,7 +394,7 @@ bool wxApp::RegisterWindowClasses()
 
     if ( !RegisterClass(&wndclass) )
     {
-        wxLogLastError("RegisterClass(no redraw MDI child)");
+        wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
 
         return FALSE;
     }
@@ -374,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;
     }
@@ -385,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;
     }
@@ -549,7 +601,9 @@ void wxApp::CleanUp()
 #if wxUSE_THREADS
     delete wxPendingEventsLocker;
     // If we don't do the following, we get an apparent memory leak.
+#if wxUSE_VALIDATORS
     ((wxEvtHandler&) wxDefaultValidator).ClearEventLocker();
+#endif
 #endif
 
     wxClassInfo::CleanUpClasses();
@@ -564,7 +618,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();
     }
@@ -577,6 +631,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
@@ -585,7 +660,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,
@@ -607,20 +684,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
@@ -643,7 +715,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
@@ -654,15 +726,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()
 
@@ -685,30 +775,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
@@ -718,12 +803,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
@@ -741,7 +828,7 @@ int wxEntry(WXHINSTANCE hInstance)
     wxTheApp->argc = 0;
     wxTheApp->argv = NULL;
 
-    wxTheApp->OnInitGui();
+    wxEntryInitGui();
 
     wxTheApp->OnInit();
 
@@ -790,8 +877,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
 }
@@ -814,7 +900,7 @@ bool wxApp::DoMessage()
     else if ( rc == -1 )
     {
         // should never happen, but let's test for it nevertheless
-        wxLogLastError("GetMessage");
+        wxLogLastError(wxT("GetMessage"));
     }
     else
     {
@@ -969,10 +1055,17 @@ 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) )
             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.
@@ -1122,7 +1215,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;
@@ -1151,11 +1244,7 @@ int wxApp::GetComCtl32Version()
                     FARPROC theProc = ::GetProcAddress
                                         (
                                          hModuleComCtl32,
-#if defined(__BORLANDC__) && (__BORLANDC__ <= 0x520)
                                          "InitCommonControlsEx"
-#else
-                                         _T("InitCommonControlsEx")
-#endif
                                         );
 
                     if ( !theProc )
@@ -1170,11 +1259,7 @@ int wxApp::GetComCtl32Version()
                         theProc = ::GetProcAddress
                                     (
                                      hModuleComCtl32,
-#if defined(__BORLANDC__) && (__BORLANDC__ <= 0x520)
                                      "InitializeFlatSB"
-#else
-                                     _T("InitializeFlatSB")
-#endif
                                     );
                         if ( !theProc )
                         {
@@ -1199,15 +1284,26 @@ 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;
@@ -1223,14 +1319,41 @@ 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"));
+       
+       (void)doit;
+    return FALSE;
+#endif
+}
+
 //-----------------------------------------------------------------------------
 // wxWakeUpIdle
 //-----------------------------------------------------------------------------
@@ -1247,7 +1370,7 @@ void wxWakeUpIdle()
         if ( !::PostMessage(GetHwndOf(topWindow), WM_NULL, 0, 0) )
         {
             // should never happen
-            wxLogLastError("PostMessage(WM_NULL)");
+            wxLogLastError(wxT("PostMessage(WM_NULL)"));
         }
     }
 }