1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
21 #pragma implementation "app.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
27 #if defined(__BORLANDC__)
35 #include "wx/gdicmn.h"
38 #include "wx/cursor.h"
40 #include "wx/palette.h"
42 #include "wx/dialog.h"
43 #include "wx/msgdlg.h"
45 #include "wx/dynarray.h"
46 #include "wx/wxchar.h"
51 #include "wx/module.h"
53 #include "wx/msw/private.h"
56 #include "wx/thread.h"
58 // define the array of MSG strutures
59 WX_DECLARE_OBJARRAY(MSG
, wxMsgArray
);
61 #include "wx/arrimpl.cpp"
63 WX_DEFINE_OBJARRAY(wxMsgArray
);
64 #endif // wxUSE_THREADS
66 #if wxUSE_WX_RESOURCES
67 #include "wx/resource.h"
71 #include "wx/tooltip.h"
72 #endif // wxUSE_TOOLTIPS
74 // OLE is used for drag-and-drop, clipboard, OLE Automation..., but some
75 // compilers don't support it (missing headers, libs, ...)
76 #if defined(__GNUWIN32_OLD__) || defined(__SC__) || defined(__SALFORDC__)
80 #endif // broken compilers
89 #if defined(__WIN95__) && !(defined(__GNUWIN32_OLD__) || defined(__TWIN32__))
93 #include "wx/msw/msvcrt.h"
95 // ----------------------------------------------------------------------------
96 // conditional compilation
97 // ----------------------------------------------------------------------------
99 // The macro _WIN32_IE is defined by commctrl.h (unless it had already been
100 // defined before) and shows us what common control features are available
101 // during the compile time (it doesn't mean that they will be available during
102 // the run-time, use GetComCtl32Version() to test for them!). The possible
105 // 0x0200 for comctl32.dll 4.00 shipped with Win95/NT 4.0
106 // 0x0300 4.70 IE 3.x
107 // 0x0400 4.71 IE 4.0
108 // 0x0401 4.72 IE 4.01 and Win98
109 // 0x0500 5.00 IE 5.x and NT 5.0 (Win2000)
112 // minimal set of features by default
113 #define _WIN32_IE 0x0200
116 #if _WIN32_IE >= 0x0300
120 // ---------------------------------------------------------------------------
122 // ---------------------------------------------------------------------------
124 extern wxChar
*wxBuffer
;
125 extern wxChar
*wxOsVersion
;
126 extern wxList
*wxWinHandleList
;
127 extern wxList WXDLLEXPORT wxPendingDelete
;
128 extern void wxSetKeyboardHook(bool doIt
);
131 wxApp
*wxTheApp
= NULL
;
133 // NB: all "NoRedraw" classes must have the same names as the "normal" classes
134 // with NR suffix - wxWindow::MSWCreate() supposes this
135 const wxChar
*wxFrameClassName
= wxT("wxFrameClass");
136 const wxChar
*wxFrameClassNameNoRedraw
= wxT("wxFrameClassNR");
137 const wxChar
*wxMDIFrameClassName
= wxT("wxMDIFrameClass");
138 const wxChar
*wxMDIFrameClassNameNoRedraw
= wxT("wxMDIFrameClassNR");
139 const wxChar
*wxMDIChildFrameClassName
= wxT("wxMDIChildFrameClass");
140 const wxChar
*wxMDIChildFrameClassNameNoRedraw
= wxT("wxMDIChildFrameClassNR");
141 const wxChar
*wxPanelClassName
= wxT("wxPanelClass");
142 const wxChar
*wxPanelClassNameNR
= wxT("wxPanelClassNR");
143 const wxChar
*wxCanvasClassName
= wxT("wxCanvasClass");
144 const wxChar
*wxCanvasClassNameNR
= wxT("wxCanvasClassNR");
146 HICON wxSTD_FRAME_ICON
= (HICON
) NULL
;
147 HICON wxSTD_MDICHILDFRAME_ICON
= (HICON
) NULL
;
148 HICON wxSTD_MDIPARENTFRAME_ICON
= (HICON
) NULL
;
150 HICON wxDEFAULT_FRAME_ICON
= (HICON
) NULL
;
151 HICON wxDEFAULT_MDICHILDFRAME_ICON
= (HICON
) NULL
;
152 HICON wxDEFAULT_MDIPARENTFRAME_ICON
= (HICON
) NULL
;
154 HBRUSH wxDisableButtonBrush
= (HBRUSH
) 0;
156 LRESULT WXDLLEXPORT APIENTRY
wxWndProc(HWND
, UINT
, WPARAM
, LPARAM
);
158 // ===========================================================================
160 // ===========================================================================
162 // ---------------------------------------------------------------------------
164 // ---------------------------------------------------------------------------
166 IMPLEMENT_DYNAMIC_CLASS(wxApp
, wxEvtHandler
)
168 BEGIN_EVENT_TABLE(wxApp
, wxEvtHandler
)
169 EVT_IDLE(wxApp::OnIdle
)
170 EVT_END_SESSION(wxApp::OnEndSession
)
171 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession
)
175 bool wxApp::Initialize()
177 // Some people may wish to use this, but
178 // probably it shouldn't be here by default.
180 // wxRedirectIOToConsole();
183 wxBuffer
= new wxChar
[1500]; // FIXME
185 wxClassInfo::InitializeClasses();
188 wxGetResource(wxT("wxWindows"), wxT("OsVersion"), &wxOsVersion
);
192 wxPendingEventsLocker
= new wxCriticalSection
;
195 wxTheColourDatabase
= new wxColourDatabase(wxKEY_STRING
);
196 wxTheColourDatabase
->Initialize();
198 wxInitializeStockLists();
199 wxInitializeStockObjects();
201 #if wxUSE_WX_RESOURCES
202 wxInitializeResourceSystem();
205 wxBitmap::InitStandardHandlers();
207 #if defined(__WIN95__)
208 InitCommonControls();
215 // for OLE, enlarge message queue to be as large as possible
217 while (!SetMessageQueue(iMsg
) && (iMsg
-= 8))
220 // we need to initialize OLE library
221 if ( FAILED(::OleInitialize(NULL
)) )
222 wxLogError(_("Cannot initialize OLE"));
226 if (!Ctl3dRegister(wxhInstance
))
227 wxLogError(wxT("Cannot register CTL3D"));
229 Ctl3dAutoSubclass(wxhInstance
);
232 // VZ: these icons are not in wx.rc anyhow (but should they?)!
234 wxSTD_FRAME_ICON
= LoadIcon(wxhInstance
, wxT("wxSTD_FRAME"));
235 wxSTD_MDIPARENTFRAME_ICON
= LoadIcon(wxhInstance
, wxT("wxSTD_MDIPARENTFRAME"));
236 wxSTD_MDICHILDFRAME_ICON
= LoadIcon(wxhInstance
, wxT("wxSTD_MDICHILDFRAME"));
238 wxDEFAULT_FRAME_ICON
= LoadIcon(wxhInstance
, wxT("wxDEFAULT_FRAME"));
239 wxDEFAULT_MDIPARENTFRAME_ICON
= LoadIcon(wxhInstance
, wxT("wxDEFAULT_MDIPARENTFRAME"));
240 wxDEFAULT_MDICHILDFRAME_ICON
= LoadIcon(wxhInstance
, wxT("wxDEFAULT_MDICHILDFRAME"));
243 RegisterWindowClasses();
245 // Create the brush for disabling bitmap buttons
248 lb
.lbStyle
= BS_PATTERN
;
249 lb
.lbHatch
= (int)LoadBitmap( wxhInstance
, wxT("wxDISABLE_BUTTON_BITMAP") );
252 wxDisableButtonBrush
= ::CreateBrushIndirect( & lb
);
253 ::DeleteObject( (HGDIOBJ
)lb
.lbHatch
);
255 //else: wxWindows resources are probably not linked in
261 wxWinHandleList
= new wxList(wxKEY_INTEGER
);
263 // This is to foil optimizations in Visual C++ that throw out dummy.obj.
264 // PLEASE DO NOT ALTER THIS.
265 #if defined(__VISUALC__) && !defined(WXMAKINGDLL)
266 extern char wxDummyChar
;
267 if (wxDummyChar
) wxDummyChar
++;
270 wxSetKeyboardHook(TRUE
);
272 wxModule::RegisterModules();
273 if (!wxModule::InitializeModules())
278 // ---------------------------------------------------------------------------
279 // RegisterWindowClasses
280 // ---------------------------------------------------------------------------
282 // TODO we should only register classes really used by the app. For this it
283 // would be enough to just delay the class registration until an attempt
284 // to create a window of this class is made.
285 bool wxApp::RegisterWindowClasses()
289 // for each class we register one with CS_(V|H)REDRAW style and one
290 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
291 static const long styleNormal
= CS_HREDRAW
| CS_VREDRAW
| CS_DBLCLKS
;
292 static const long styleNoRedraw
= CS_DBLCLKS
;
294 // the fields which are common to all classes
295 wndclass
.lpfnWndProc
= (WNDPROC
)wxWndProc
;
296 wndclass
.cbClsExtra
= 0;
297 wndclass
.cbWndExtra
= sizeof( DWORD
); // VZ: what is this DWORD used for?
298 wndclass
.hInstance
= wxhInstance
;
299 wndclass
.hIcon
= (HICON
) NULL
;
300 wndclass
.hCursor
= ::LoadCursor((HINSTANCE
)NULL
, IDC_ARROW
);
301 wndclass
.lpszMenuName
= NULL
;
303 // Register the frame window class.
304 wndclass
.hbrBackground
= (HBRUSH
)(COLOR_APPWORKSPACE
+ 1);
305 wndclass
.lpszClassName
= wxFrameClassName
;
306 wndclass
.style
= styleNormal
;
308 if ( !RegisterClass(&wndclass
) )
310 wxLogLastError("RegisterClass(frame)");
316 wndclass
.lpszClassName
= wxFrameClassNameNoRedraw
;
317 wndclass
.style
= styleNoRedraw
;
319 if ( !RegisterClass(&wndclass
) )
321 wxLogLastError("RegisterClass(no redraw frame)");
326 // Register the MDI frame window class.
327 wndclass
.hbrBackground
= (HBRUSH
)NULL
; // paint MDI frame ourselves
328 wndclass
.lpszClassName
= wxMDIFrameClassName
;
329 wndclass
.style
= styleNormal
;
331 if ( !RegisterClass(&wndclass
) )
333 wxLogLastError("RegisterClass(MDI parent)");
338 // "no redraw" MDI frame
339 wndclass
.lpszClassName
= wxMDIFrameClassNameNoRedraw
;
340 wndclass
.style
= styleNoRedraw
;
342 if ( !RegisterClass(&wndclass
) )
344 wxLogLastError("RegisterClass(no redraw MDI parent frame)");
349 // Register the MDI child frame window class.
350 wndclass
.hbrBackground
= (HBRUSH
)(COLOR_WINDOW
+ 1);
351 wndclass
.lpszClassName
= wxMDIChildFrameClassName
;
352 wndclass
.style
= styleNormal
;
354 if ( !RegisterClass(&wndclass
) )
356 wxLogLastError("RegisterClass(MDI child)");
361 // "no redraw" MDI child frame
362 wndclass
.lpszClassName
= wxMDIChildFrameClassNameNoRedraw
;
363 wndclass
.style
= styleNoRedraw
;
365 if ( !RegisterClass(&wndclass
) )
367 wxLogLastError("RegisterClass(no redraw MDI child)");
372 // Register the panel window class.
373 wndclass
.hbrBackground
= (HBRUSH
) GetStockObject( LTGRAY_BRUSH
);
374 wndclass
.lpszClassName
= wxPanelClassName
;
375 wndclass
.style
= styleNormal
;
377 if ( !RegisterClass(&wndclass
) )
379 wxLogLastError("RegisterClass(panel)");
384 // Register the no redraw panel window class.
385 wndclass
.lpszClassName
= wxPanelClassNameNR
;
386 wndclass
.style
= styleNoRedraw
;
388 if ( !RegisterClass(&wndclass
) )
390 wxLogLastError("RegisterClass(no redraw panel)");
395 // Register the canvas and textsubwindow class name
396 wndclass
.hbrBackground
= (HBRUSH
)NULL
;
397 wndclass
.lpszClassName
= wxCanvasClassName
;
399 if ( !RegisterClass(&wndclass
) )
401 wxLogLastError("RegisterClass(canvas)");
406 wndclass
.lpszClassName
= wxCanvasClassNameNR
;
407 wndclass
.style
= styleNoRedraw
;
408 if ( !RegisterClass(&wndclass
) )
410 wxLogLastError("RegisterClass(no redraw canvas)");
418 // ---------------------------------------------------------------------------
419 // Convert Windows to argc, argv style
420 // ---------------------------------------------------------------------------
422 void wxApp::ConvertToStandardCommandArgs(char* lpCmdLine
)
426 wxString
cmdLine(lpCmdLine
);
429 // Get application name
430 wxChar name
[260]; // 260 is MAX_PATH value from windef.h
431 ::GetModuleFileName(wxhInstance
, name
, WXSIZEOF(name
));
436 wxStrcpy(name
, wxFileNameFromPath(name
));
437 wxStripExtension(name
);
438 wxTheApp
->SetAppName(name
);
441 // Treat strings enclosed in double-quotes as single arguments
443 int len
= cmdLine
.Length();
447 while ((i
< len
) && wxIsspace(cmdLine
.GetChar(i
)))
452 if (cmdLine
.GetChar(i
) == wxT('"')) // We found the start of a string
456 while ((i
< len
) && (cmdLine
.GetChar(i
) != wxT('"')))
459 wxString
arg(cmdLine
.Mid(first
, (i
- first
)));
465 i
++; // Skip past 2nd quote
467 else // Unquoted argument
470 while ((i
< len
) && !wxIsspace(cmdLine
.GetChar(i
)))
473 wxString
arg(cmdLine
.Mid(first
, (i
- first
)));
481 wxTheApp
->argv
= new wxChar
*[count
+ 1];
482 for (i
= 0; i
< count
; i
++)
484 wxString
arg(args
[i
]);
485 wxTheApp
->argv
[i
] = copystring((const wxChar
*)arg
);
487 wxTheApp
->argv
[count
] = NULL
; // argv[] is a NULL-terminated list
488 wxTheApp
->argc
= count
;
491 //// Cleans up any wxWindows internal structures left lying around
493 void wxApp::CleanUp()
498 // flush the logged messages if any and install a 'safer' log target: the
499 // default one (wxLogGui) can't be used after the resources are freed just
500 // below and the user suppliedo ne might be even more unsafe (using any
501 // wxWindows GUI function is unsafe starting from now)
502 wxLog::DontCreateOnDemand();
504 // this will flush the old messages if any
505 delete wxLog::SetActiveTarget(new wxLogStderr
);
508 // One last chance for pending objects to be cleaned up
509 wxTheApp
->DeletePendingObjects();
511 wxModule::CleanUpModules();
513 #if wxUSE_WX_RESOURCES
514 wxCleanUpResourceSystem();
516 // wxDefaultResourceTable->ClearTable();
519 wxDeleteStockObjects();
521 // Destroy all GDI lists, etc.
522 wxDeleteStockLists();
524 delete wxTheColourDatabase
;
525 wxTheColourDatabase
= NULL
;
527 wxBitmap::CleanUpHandlers();
532 //// WINDOWS-SPECIFIC CLEANUP
534 wxSetKeyboardHook(FALSE
);
540 if (wxSTD_FRAME_ICON
)
541 DestroyIcon(wxSTD_FRAME_ICON
);
542 if (wxSTD_MDICHILDFRAME_ICON
)
543 DestroyIcon(wxSTD_MDICHILDFRAME_ICON
);
544 if (wxSTD_MDIPARENTFRAME_ICON
)
545 DestroyIcon(wxSTD_MDIPARENTFRAME_ICON
);
547 if (wxDEFAULT_FRAME_ICON
)
548 DestroyIcon(wxDEFAULT_FRAME_ICON
);
549 if (wxDEFAULT_MDICHILDFRAME_ICON
)
550 DestroyIcon(wxDEFAULT_MDICHILDFRAME_ICON
);
551 if (wxDEFAULT_MDIPARENTFRAME_ICON
)
552 DestroyIcon(wxDEFAULT_MDIPARENTFRAME_ICON
);
554 if ( wxDisableButtonBrush
)
555 ::DeleteObject( wxDisableButtonBrush
);
562 Ctl3dUnregister(wxhInstance
);
566 delete wxWinHandleList
;
568 // GL: I'm annoyed ... I don't know where to put this and I don't want to
569 // create a module for that as it's part of the core.
570 delete wxPendingEvents
;
572 delete wxPendingEventsLocker
;
573 // If we don't do the following, we get an apparent memory leak.
574 ((wxEvtHandler
&) wxDefaultValidator
).ClearEventLocker();
577 wxClassInfo::CleanUpClasses();
582 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
583 // At this point we want to check if there are any memory
584 // blocks that aren't part of the wxDebugContext itself,
585 // as a special case. Then when dumping we need to ignore
586 // wxDebugContext, too.
587 if (wxDebugContext::CountObjectsLeft(TRUE
) > 0)
589 wxLogMessage(wxT("There were memory leaks."));
590 wxDebugContext::Dump();
591 wxDebugContext::PrintStatistics();
593 // wxDebugContext::SetStream(NULL, NULL);
597 // do it as the very last thing because everything else can log messages
598 delete wxLog::SetActiveTarget(NULL
);
602 //----------------------------------------------------------------------
603 // Entry point helpers, used by wxPython
604 //----------------------------------------------------------------------
606 int WXDLLEXPORT
wxEntryStart( int WXUNUSED(argc
), char** WXUNUSED(argv
) )
608 return wxApp::Initialize();
611 int WXDLLEXPORT
wxEntryInitGui()
613 wxTheApp
->OnInitGui();
617 void WXDLLEXPORT
wxEntryCleanup()
623 #if !defined(_WINDLL) || (defined(_WINDLL) && defined(WXMAKINGDLL))
625 // temporarily disable this warning which would be generated in release builds
628 #pragma warning(disable: 4715) // not all control paths return a value
631 //----------------------------------------------------------------------
632 // Main wxWindows entry point
633 //----------------------------------------------------------------------
634 int wxEntry(WXHINSTANCE hInstance
,
635 WXHINSTANCE
WXUNUSED(hPrevInstance
),
640 // do check for memory leaks on program exit
641 // (another useful flag is _CRTDBG_DELAY_FREE_MEM_DF which doesn't free
642 // deallocated memory which may be used to simulate low-memory condition)
643 wxCrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF
);
645 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
646 // This seems to be necessary since there are 'rogue'
647 // objects present at this point (perhaps global objects?)
648 // Setting a checkpoint will ignore them as far as the
649 // memory checking facility is concerned.
650 // Of course you may argue that memory allocated in globals should be
651 // checked, but this is a reasonable compromise.
652 wxDebugContext::SetCheckpoint();
655 // take everything into a try-except block in release build
656 // FIXME other compilers must support Win32 SEH (structured exception
657 // handling) too, just find the appropriate keyword in their docs!
658 // Please note that it's _not_ the same as C++ exceptions!
659 #if !defined(__WXDEBUG__) && defined(__VISUALC__)
660 #define CATCH_PROGRAM_EXCEPTIONS
664 #undef CATCH_PROGRAM_EXCEPTIONS
666 wxhInstance
= (HINSTANCE
) hInstance
;
668 if (!wxEntryStart(0,0))
671 // create the application object or ensure that one already exists
674 // The app may have declared a global application object, but we recommend
675 // the IMPLEMENT_APP macro is used instead, which sets an initializer
676 // function for delayed, dynamic app object construction.
677 wxCHECK_MSG( wxApp::GetInitializerFunction(), 0,
678 wxT("No initializer - use IMPLEMENT_APP macro.") );
680 wxTheApp
= (*wxApp::GetInitializerFunction()) ();
683 wxCHECK_MSG( wxTheApp
, 0, wxT("You have to define an instance of wxApp!") );
685 // save the WinMain() parameters
686 wxTheApp
->ConvertToStandardCommandArgs(lpCmdLine
);
687 wxTheApp
->m_nCmdShow
= nCmdShow
;
689 // GUI-specific initialisation. In fact on Windows we don't have any,
690 // but this call is provided for compatibility across platforms.
693 // We really don't want timestamps by default, because it means
694 // we can't simply double-click on the error message and get to that
695 // line in the source. So VC++ at least, let's have a sensible default.
697 wxLog::SetTimestamp(NULL
);
702 if ( wxTheApp
->OnInit() )
706 retValue
= wxTheApp
->OnRun();
709 // We want to initialize, but not run or exit immediately.
712 //else: app initialization failed, so we skipped OnRun()
714 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
717 // Forcibly delete the window.
718 if ( topWindow
->IsKindOf(CLASSINFO(wxFrame
)) ||
719 topWindow
->IsKindOf(CLASSINFO(wxDialog
)) )
721 topWindow
->Close(TRUE
);
722 wxTheApp
->DeletePendingObjects();
727 wxTheApp
->SetTopWindow(NULL
);
737 #ifdef CATCH_PROGRAM_EXCEPTIONS
739 __except ( EXCEPTION_EXECUTE_HANDLER
) {
742 wxTheApp->OnFatalException();
745 // using wxLog would be unsafe here
747 _("Unrecoverable program error detected: "
748 " the application will terminate."),
750 MB_APPLMODAL
| MB_ICONSTOP
| MB_OK
);
752 ::ExitProcess(3); // the same exit code as abort()
756 #endif // CATCH_PROGRAM_EXCEPTIONS
759 // restore warning state
761 #pragma warning(default: 4715) // not all control paths return a value
766 //----------------------------------------------------------------------
767 // Entry point for wxWindows + the App in a DLL
768 //----------------------------------------------------------------------
770 int wxEntry(WXHINSTANCE hInstance
)
772 wxhInstance
= (HINSTANCE
) hInstance
;
775 // The app may have declared a global application object, but we recommend
776 // the IMPLEMENT_APP macro is used instead, which sets an initializer function
777 // for delayed, dynamic app object construction.
780 wxCHECK_MSG( wxApp::GetInitializerFunction(), 0,
781 "No initializer - use IMPLEMENT_APP macro." );
783 wxTheApp
= (* wxApp::GetInitializerFunction()) ();
786 wxCHECK_MSG( wxTheApp
, 0, "You have to define an instance of wxApp!" );
789 wxTheApp
->argv
= NULL
;
795 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
796 if ( topWindow
&& topWindow
->GetHWND())
798 topWindow
->Show(TRUE
);
805 //// Static member initialization
807 wxAppInitializerFunction
wxAppBase::m_appInitFn
= (wxAppInitializerFunction
) NULL
;
813 m_wantDebugOutput
= TRUE
;
817 m_printMode
= wxPRINT_WINDOWS
;
818 m_exitOnFrameDelete
= TRUE
;
824 // Delete command-line args
826 for (i
= 0; i
< argc
; i
++)
833 bool wxApp::Initialized()
841 #ifdef _WINDLL // Assume initialized if DLL (no way of telling)
847 * Get and process a message, returning FALSE if WM_QUIT
848 * received (and also set the flag telling the app to exit the main loop)
851 bool wxApp::DoMessage()
853 BOOL rc
= ::GetMessage(&s_currentMsg
, (HWND
) NULL
, 0, 0);
863 // should never happen, but let's test for it nevertheless
864 wxLogLastError("GetMessage");
869 wxASSERT_MSG( wxThread::IsMain(),
870 wxT("only the main thread can process Windows messages") );
872 static bool s_hadGuiLock
= TRUE
;
873 static wxMsgArray s_aSavedMessages
;
875 // if a secondary thread owns is doing GUI calls, save all messages for
876 // later processing - we can't process them right now because it will
877 // lead to recursive library calls (and we're not reentrant)
878 if ( !wxGuiOwnedByMainThread() )
880 s_hadGuiLock
= FALSE
;
882 // leave out WM_COMMAND messages: too dangerous, sometimes
883 // the message will be processed twice
884 if ( !wxIsWaitingForThread() ||
885 s_currentMsg
.message
!= WM_COMMAND
)
887 s_aSavedMessages
.Add(s_currentMsg
);
894 // have we just regained the GUI lock? if so, post all of the saved
897 // FIXME of course, it's not _exactly_ the same as processing the
898 // messages normally - expect some things to break...
903 size_t count
= s_aSavedMessages
.Count();
904 for ( size_t n
= 0; n
< count
; n
++ )
906 MSG
& msg
= s_aSavedMessages
[n
];
908 if ( !ProcessMessage((WXMSG
*)&msg
) )
910 ::TranslateMessage(&msg
);
911 ::DispatchMessage(&msg
);
915 s_aSavedMessages
.Empty();
918 #endif // wxUSE_THREADS
920 // Process the message
921 if ( !ProcessMessage((WXMSG
*)&s_currentMsg
) )
923 ::TranslateMessage(&s_currentMsg
);
924 ::DispatchMessage(&s_currentMsg
);
932 * Keep trying to process messages until WM_QUIT
935 * If there are messages to be processed, they will all be
936 * processed and OnIdle will not be called.
937 * When there are no more messages, OnIdle is called.
938 * If OnIdle requests more time,
939 * it will be repeatedly called so long as there are no pending messages.
940 * A 'feature' of this is that once OnIdle has decided that no more processing
941 * is required, then it won't get processing time until further messages
942 * are processed (it'll sit in DoMessage).
945 int wxApp::MainLoop()
949 while ( m_keepGoing
)
952 wxMutexGuiLeaveOrEnter();
953 #endif // wxUSE_THREADS
955 while ( !Pending() && ProcessIdle() )
958 // a message came or no more idle processing to do
962 return s_currentMsg
.wParam
;
965 // Returns TRUE if more time is needed.
966 bool wxApp::ProcessIdle()
969 event
.SetEventObject(this);
972 return event
.MoreRequested();
975 void wxApp::ExitMainLoop()
977 // VZ: why not ::PostQuitMessage()?
981 bool wxApp::Pending()
983 return ::PeekMessage(&s_currentMsg
, 0, 0, 0, PM_NOREMOVE
) != 0;
986 void wxApp::Dispatch()
992 * Give all windows a chance to preprocess
993 * the message. Some may have accelerator tables, or have
997 bool wxApp::ProcessMessage(WXMSG
*wxmsg
)
999 MSG
*msg
= (MSG
*)wxmsg
;
1000 HWND hWnd
= msg
->hwnd
;
1001 wxWindow
*wndThis
= wxGetWindowFromHWND((WXHWND
)hWnd
);
1004 // we must relay WM_MOUSEMOVE events to the tooltip ctrl if we want it to
1005 // popup the tooltip bubbles
1006 if ( wndThis
&& (msg
->message
== WM_MOUSEMOVE
) )
1008 wxToolTip
*tt
= wndThis
->GetToolTip();
1011 tt
->RelayEvent(wxmsg
);
1014 #endif // wxUSE_TOOLTIPS
1016 // Try translations first; find the youngest window with
1017 // a translation table.
1019 for ( wnd
= wndThis
; wnd
; wnd
= wnd
->GetParent() )
1021 if ( wnd
->MSWTranslateMessage(wxmsg
) )
1025 // Anyone for a non-translation message? Try youngest descendants first.
1026 for ( wnd
= wndThis
; wnd
; wnd
= wnd
->GetParent() )
1028 if ( wnd
->MSWProcessMessage(wxmsg
) )
1035 void wxApp::OnIdle(wxIdleEvent
& event
)
1037 static bool s_inOnIdle
= FALSE
;
1039 // Avoid recursion (via ProcessEvent default case)
1045 // If there are pending events, we must process them: pending events
1046 // are either events to the threads other than main or events posted
1047 // with wxPostEvent() functions
1048 // GRG: I have moved this here so that all pending events are processed
1049 // before starting to delete any objects. This behaves better (in
1050 // particular, wrt wxPostEvent) and is coherent with wxGTK's current
1051 // behaviour. Changed Feb/2000 before 2.1.14
1052 ProcessPendingEvents();
1054 // 'Garbage' collection of windows deleted with Close().
1055 DeletePendingObjects();
1058 // flush the logged messages if any
1059 wxLog::FlushActive();
1062 // Send OnIdle events to all windows
1063 if ( SendIdleEvents() )
1065 // SendIdleEvents() returns TRUE if at least one window requested more
1067 event
.RequestMore(TRUE
);
1073 // Send idle event to all top-level windows
1074 bool wxApp::SendIdleEvents()
1076 bool needMore
= FALSE
;
1078 wxWindowList::Node
* node
= wxTopLevelWindows
.GetFirst();
1081 wxWindow
* win
= node
->GetData();
1082 if (SendIdleEvents(win
))
1084 node
= node
->GetNext();
1090 // Send idle event to window and all subwindows
1091 bool wxApp::SendIdleEvents(wxWindow
* win
)
1093 bool needMore
= FALSE
;
1096 event
.SetEventObject(win
);
1097 win
->GetEventHandler()->ProcessEvent(event
);
1099 if (event
.MoreRequested())
1102 wxNode
* node
= win
->GetChildren().First();
1105 wxWindow
* win
= (wxWindow
*) node
->Data();
1106 if (SendIdleEvents(win
))
1109 node
= node
->Next();
1114 void wxApp::DeletePendingObjects()
1116 wxNode
*node
= wxPendingDelete
.First();
1119 wxObject
*obj
= (wxObject
*)node
->Data();
1123 if (wxPendingDelete
.Member(obj
))
1126 // Deleting one object may have deleted other pending
1127 // objects, so start from beginning of list again.
1128 node
= wxPendingDelete
.First();
1132 void wxApp::OnEndSession(wxCloseEvent
& WXUNUSED(event
))
1135 GetTopWindow()->Close(TRUE
);
1138 // Default behaviour: close the application with prompts. The
1139 // user can veto the close, and therefore the end session.
1140 void wxApp::OnQueryEndSession(wxCloseEvent
& event
)
1144 if (!GetTopWindow()->Close(!event
.CanVeto()))
1150 int wxApp::GetComCtl32Version()
1153 static int s_verComCtl32
= -1;
1155 wxCRIT_SECT_DECLARE(csComCtl32
);
1156 wxCRIT_SECT_LOCKER(lock
, csComCtl32
);
1158 if ( s_verComCtl32
== -1 )
1160 // initally assume no comctl32.dll at all
1164 HMODULE hModuleComCtl32
= ::GetModuleHandle(wxT("COMCTL32"));
1166 // if so, then we can check for the version
1167 if ( hModuleComCtl32
)
1169 // try to use DllGetVersion() if available in _headers_
1170 #ifdef DLLVER_PLATFORM_WINDOWS // defined in shlwapi.h
1171 DLLGETVERSIONPROC pfnDllGetVersion
= (DLLGETVERSIONPROC
)
1172 ::GetProcAddress(hModuleComCtl32
, _T("DllGetVersion"));
1173 if ( pfnDllGetVersion
)
1176 dvi
.cbSize
= sizeof(dvi
);
1178 HRESULT hr
= (*pfnDllGetVersion
)(&dvi
);
1181 wxLogApiError(_T("DllGetVersion"), hr
);
1185 // this is incompatible with _WIN32_IE values, but
1186 // compatible with the other values returned by
1187 // GetComCtl32Version()
1188 s_verComCtl32
= 100*dvi
.dwMajorVersion
+
1193 // DllGetVersion() unavailable either during compile or
1194 // run-time, try to guess the version otherwise
1195 if ( !s_verComCtl32
)
1197 // InitCommonControlsEx is unique to 4.70 and later
1198 FARPROC theProc
= ::GetProcAddress
1201 #if defined(__BORLANDC__) && (__BORLANDC__ <= 0x520)
1202 "InitCommonControlsEx"
1204 _T("InitCommonControlsEx")
1210 // not found, must be 4.00
1211 s_verComCtl32
= 400;
1215 // many symbols appeared in comctl32 4.71, could use
1216 // any of them except may be DllInstall
1217 theProc
= ::GetProcAddress
1220 #if defined(__BORLANDC__) && (__BORLANDC__ <= 0x520)
1223 _T("InitializeFlatSB")
1228 // not found, must be 4.70
1229 s_verComCtl32
= 470;
1233 // found, must be 4.71
1234 s_verComCtl32
= 471;
1241 return s_verComCtl32
;
1246 wxLogError(_("Fatal error: exiting"));
1252 // Yield to incoming messages
1255 // disable log flushing from here because a call to wxYield() shouldn't
1256 // normally result in message boxes popping up &c
1259 // we don't want to process WM_QUIT from here - it should be processed in
1260 // the main event loop in order to stop it
1262 while ( PeekMessage(&msg
, (HWND
)0, 0, 0, PM_NOREMOVE
) &&
1263 msg
.message
!= WM_QUIT
)
1266 wxMutexGuiLeaveOrEnter();
1267 #endif // wxUSE_THREADS
1269 if ( !wxTheApp
->DoMessage() )
1273 // If they are pending events, we must process them.
1275 wxTheApp
->ProcessPendingEvents();
1277 // let the logs be flashed again
1283 //-----------------------------------------------------------------------------
1285 //-----------------------------------------------------------------------------
1289 // Send the top window a dummy message so idle handler processing will
1290 // start up again. Doing it this way ensures that the idle handler
1291 // wakes up in the right thread (see also wxWakeUpMainThread() which does
1292 // the same for the main app thread only)
1293 wxWindow
*topWindow
= wxTheApp
->GetTopWindow();
1296 if ( !::PostMessage(GetHwndOf(topWindow
), WM_NULL
, 0, 0) )
1298 // should never happen
1299 wxLogLastError("PostMessage(WM_NULL)");
1304 //-----------------------------------------------------------------------------
1307 wxApp::GetStdIcon(int which
) const
1311 case wxICON_INFORMATION
:
1312 return wxIcon("wxICON_INFO");
1314 case wxICON_QUESTION
:
1315 return wxIcon("wxICON_QUESTION");
1317 case wxICON_EXCLAMATION
:
1318 return wxIcon("wxICON_WARNING");
1321 wxFAIL_MSG(wxT("requested non existent standard icon"));
1322 // still fall through
1325 return wxIcon("wxICON_ERROR");
1329 // For some reason, with MSVC++ 1.5, WinMain isn't linked in properly
1330 // if in a separate file. So include it here to ensure it's linked.
1331 #if (defined(__VISUALC__) && !defined(__WIN32__)) || (defined(__GNUWIN32__) && !defined(__TWIN32__) && !defined(WXMAKINGDLL))