]> git.saurik.com Git - wxWidgets.git/blob - src/msw/app.cpp
Enabled the wxUSE_VC_CRTDBG to be optional even if it would otherwise
[wxWidgets.git] / src / msw / app.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: app.cpp
3 // Purpose: wxApp
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "app.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #if defined(__BORLANDC__)
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include "wx/frame.h"
25 #include "wx/app.h"
26 #include "wx/utils.h"
27 #include "wx/gdicmn.h"
28 #include "wx/pen.h"
29 #include "wx/brush.h"
30 #include "wx/cursor.h"
31 #include "wx/icon.h"
32 #include "wx/palette.h"
33 #include "wx/dc.h"
34 #include "wx/dialog.h"
35 #include "wx/msgdlg.h"
36 #endif
37
38 #include "wx/msw/private.h"
39 #include "wx/log.h"
40 #include "wx/module.h"
41
42 #if wxUSE_WX_RESOURCES
43 #include "wx/resource.h"
44 #endif
45
46 #include <string.h>
47 #include <ctype.h>
48
49 #if defined(__WIN95__) && !defined(__GNUWIN32__)
50 #include <commctrl.h>
51 #endif
52
53 // use debug CRT functions for memory leak detections in VC++ if we're not
54 // using wxWindows own methods
55 #if defined(__WXDEBUG__) && defined(_MSC_VER) && !wxUSE_GLOBAL_MEMORY_OPERATORS && !defined(__NO_VC_CRTDBG__)
56 #define wxUSE_VC_CRTDBG
57 #else
58 #undef wxUSE_VC_CRTDBG
59 #endif
60
61 #ifdef wxUSE_VC_CRTDBG
62 // VC++ uses this macro as debug/release mode indicator
63 #ifndef _DEBUG
64 #define _DEBUG
65 #endif
66
67 #include <crtdbg.h>
68 #endif
69
70 extern char *wxBuffer;
71 extern char *wxOsVersion;
72 extern wxList *wxWinHandleList;
73 extern wxList wxPendingDelete;
74 extern void wxSetKeyboardHook(bool doIt);
75 extern wxCursor *g_globalCursor;
76
77 HINSTANCE wxhInstance = 0;
78 static MSG s_currentMsg;
79 wxApp *wxTheApp = NULL;
80
81 // @@ why not const? and not static?
82 char wxFrameClassName[] = "wxFrameClass";
83 char wxMDIFrameClassName[] = "wxMDIFrameClass";
84 char wxMDIChildFrameClassName[] = "wxMDIChildFrameClass";
85 char wxPanelClassName[] = "wxPanelClass";
86 char wxCanvasClassName[] = "wxCanvasClass";
87
88 HICON wxSTD_FRAME_ICON = NULL;
89 HICON wxSTD_MDICHILDFRAME_ICON = NULL;
90 HICON wxSTD_MDIPARENTFRAME_ICON = NULL;
91
92 HICON wxDEFAULT_FRAME_ICON = NULL;
93 HICON wxDEFAULT_MDICHILDFRAME_ICON = NULL;
94 HICON wxDEFAULT_MDIPARENTFRAME_ICON = NULL;
95
96 HBRUSH wxDisableButtonBrush = 0;
97
98 LRESULT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM);
99
100 #if !USE_SHARED_LIBRARY
101 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
102
103 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
104 EVT_IDLE(wxApp::OnIdle)
105 EVT_END_SESSION(wxApp::OnEndSession)
106 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
107 END_EVENT_TABLE()
108 #endif
109
110 long wxApp::sm_lastMessageTime = 0;
111
112 #ifdef __WIN95__
113 static HINSTANCE gs_hRichEdit = NULL;
114 #endif
115
116 //// Initialize
117
118 bool wxApp::Initialize()
119 {
120 wxBuffer = new char[1500];
121
122 #ifdef wxUSE_VC_CRTDBG
123 // do check for memory leaks on program exit
124 // (another useful flag is _CRTDBG_DELAY_FREE_MEM_DF which doesn't free
125 // deallocated memory which may be used to simulate low-memory condition)
126 _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
127 #endif // debug build under MS VC++
128
129 wxClassInfo::InitializeClasses();
130
131 #if wxUSE_RESOURCES
132 wxGetResource("wxWindows", "OsVersion", &wxOsVersion);
133 #endif
134
135 wxTheColourDatabase = new wxColourDatabase(wxKEY_STRING);
136 wxTheColourDatabase->Initialize();
137
138 wxInitializeStockLists();
139 wxInitializeStockObjects();
140
141 #if wxUSE_WX_RESOURCES
142 wxInitializeResourceSystem();
143 #endif
144
145 wxBitmap::InitStandardHandlers();
146
147 #if defined(__WIN95__)
148 InitCommonControls();
149 gs_hRichEdit = LoadLibrary("RICHED32.DLL");
150
151 if (gs_hRichEdit == NULL)
152 {
153 wxMessageBox("Could not initialise Rich Edit DLL");
154 }
155 #endif
156
157 #if defined(WX_DRAG_DROP)
158 // we need to initialize OLE library
159 if ( FAILED(::OleInitialize(NULL)) )
160 wxFatalError(_("Cannot initialize OLE"));
161 #endif
162
163 #if CTL3D
164 if (!Ctl3dRegister(wxhInstance))
165 wxFatalError("Cannot register CTL3D");
166
167 Ctl3dAutoSubclass(wxhInstance);
168 #endif
169
170 g_globalCursor = new wxCursor;
171
172 wxSTD_FRAME_ICON = LoadIcon(wxhInstance, "wxSTD_FRAME");
173 wxSTD_MDIPARENTFRAME_ICON = LoadIcon(wxhInstance, "wxSTD_MDIPARENTFRAME");
174 wxSTD_MDICHILDFRAME_ICON = LoadIcon(wxhInstance, "wxSTD_MDICHILDFRAME");
175
176 wxDEFAULT_FRAME_ICON = LoadIcon(wxhInstance, "wxDEFAULT_FRAME");
177 wxDEFAULT_MDIPARENTFRAME_ICON = LoadIcon(wxhInstance, "wxDEFAULT_MDIPARENTFRAME");
178 wxDEFAULT_MDICHILDFRAME_ICON = LoadIcon(wxhInstance, "wxDEFAULT_MDICHILDFRAME");
179
180 RegisterWindowClasses();
181
182 // Create the brush for disabling bitmap buttons
183
184 LOGBRUSH lb ;
185 lb.lbStyle = BS_PATTERN;
186 lb.lbHatch = (int)LoadBitmap( wxhInstance, "wxDISABLE_BUTTON_BITMAP" ) ;
187 wxDisableButtonBrush = ::CreateBrushIndirect( & lb ) ;
188 ::DeleteObject( (HGDIOBJ)lb.lbHatch ) ;
189
190 #if wxUSE_PENWINDOWS
191 wxRegisterPenWin();
192 #endif
193
194 wxWinHandleList = new wxList(wxKEY_INTEGER);
195
196 // This is to foil optimizations in Visual C++ that
197 // throw out dummy.obj.
198 #if (_MSC_VER >= 800) && !defined(WXMAKINGDLL)
199 extern char wxDummyChar;
200 if (wxDummyChar) wxDummyChar++;
201 #endif
202
203 wxSetKeyboardHook(TRUE);
204
205 wxModule::RegisterModules();
206 if (!wxModule::InitializeModules())
207 return FALSE;
208 return TRUE;
209 }
210
211 //// RegisterWindowClasses
212
213 bool wxApp::RegisterWindowClasses()
214 {
215 ///////////////////////////////////////////////////////////////////////
216 // Register the frame window class.
217 WNDCLASS wndclass; // Structure used to register Windows class.
218
219 wndclass.style = CS_HREDRAW | CS_VREDRAW;
220 wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
221 wndclass.cbClsExtra = 0;
222 wndclass.cbWndExtra = sizeof( DWORD ); // was 4
223 wndclass.hInstance = wxhInstance;
224 wndclass.hIcon = NULL; // wxSTD_FRAME_ICON;
225 wndclass.hCursor = LoadCursor( NULL, IDC_ARROW );
226 wndclass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE+1) ;
227 // wndclass.hbrBackground = GetStockObject( WHITE_BRUSH );
228 wndclass.lpszMenuName = NULL;
229 #ifdef _MULTIPLE_INSTANCES
230 sprintf( wxFrameClassName,"wxFrameClass%d", wxhInstance );
231 #endif
232 wndclass.lpszClassName = wxFrameClassName;
233
234 if (!RegisterClass( &wndclass ))
235 {
236 // wxFatalError("Can't register Frame Window class");
237 }
238
239 ///////////////////////////////////////////////////////////////////////
240 // Register the MDI frame window class.
241 WNDCLASS wndclass1; // Structure used to register Windows class.
242
243 wndclass1.style = CS_HREDRAW | CS_VREDRAW;
244 wndclass1.lpfnWndProc = (WNDPROC)wxWndProc;
245 wndclass1.cbClsExtra = 0;
246 wndclass1.cbWndExtra = sizeof( DWORD ); // was 4
247 wndclass1.hInstance = wxhInstance;
248 wndclass1.hIcon = NULL; // wxSTD_MDIPARENTFRAME_ICON;
249 wndclass1.hCursor = LoadCursor( NULL, IDC_ARROW );
250 // wndclass1.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE+1) ;
251 wndclass1.hbrBackground = NULL;
252 wndclass1.lpszMenuName = NULL;
253
254 wndclass1.lpszClassName = wxMDIFrameClassName;
255 if (!RegisterClass( &wndclass1 ))
256 {
257 // wxFatalError("Can't register MDI Frame window class");
258 // return FALSE;
259 }
260
261 ///////////////////////////////////////////////////////////////////////
262 // Register the MDI child frame window class.
263 WNDCLASS wndclass4; // Structure used to register Windows class.
264
265 wndclass4.style = CS_HREDRAW | CS_VREDRAW;
266 wndclass4.lpfnWndProc = (WNDPROC)wxWndProc;
267 wndclass4.cbClsExtra = 0;
268 wndclass4.cbWndExtra = sizeof( DWORD ); // was 4
269 wndclass4.hInstance = wxhInstance;
270 wndclass4.hIcon = NULL; // wxSTD_MDICHILDFRAME_ICON;
271 wndclass4.hCursor = LoadCursor( NULL, IDC_ARROW );
272 // TODO: perhaps this should be NULL so that Windows doesn't
273 // paint the background itself (would OnEraseBackground duplicate
274 // this?)
275 wndclass4.hbrBackground = (HBRUSH)(COLOR_WINDOW+1) ;
276 // wndclass4.hbrBackground = NULL;
277 wndclass4.lpszMenuName = NULL;
278 wndclass4.lpszClassName = wxMDIChildFrameClassName;
279
280 if (!RegisterClass( &wndclass4 ))
281 {
282 // wxFatalError("Can't register MDI child frame window class");
283 // return FALSE;
284 }
285
286 ///////////////////////////////////////////////////////////////////////
287 // Register the panel window class.
288 WNDCLASS wndclass2; // Structure used to register Windows class.
289 memset(&wndclass2, 0, sizeof(WNDCLASS)); // start with NULL defaults
290 // Use CS_OWNDC to avoid messing about restoring the context
291 // for every graphic operation.
292 wndclass2.style = CS_HREDRAW | CS_VREDRAW;
293 wndclass2.lpfnWndProc = (WNDPROC)wxWndProc;
294 wndclass2.cbClsExtra = 0;
295 wndclass2.cbWndExtra = sizeof( DWORD ); // was 4
296 wndclass2.hInstance = wxhInstance;
297 wndclass2.hIcon = NULL;
298 wndclass2.hCursor = NULL;
299 // wndclass2.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1) ;
300 wndclass2.hbrBackground = (HBRUSH) GetStockObject( LTGRAY_BRUSH );
301 wndclass2.lpszMenuName = NULL;
302 wndclass2.lpszClassName = wxPanelClassName;
303 if (!RegisterClass( &wndclass2 ))
304 {
305 // wxFatalError("Can't register Panel Window class");
306 // return FALSE;
307 }
308
309 ///////////////////////////////////////////////////////////////////////
310 // Register the canvas and textsubwindow class name
311 WNDCLASS wndclass3; // Structure used to register Windows class.
312 memset(&wndclass3, 0, sizeof(WNDCLASS)); // start with NULL defaults
313 // Use CS_OWNDC to avoid messing about restoring the context
314 // for every graphic operation.
315 // wndclass3.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS ;
316 // wxWin 2.0
317 wndclass3.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS ;
318 wndclass3.lpfnWndProc = (WNDPROC)wxWndProc;
319 wndclass3.cbClsExtra = 0;
320 wndclass3.cbWndExtra = sizeof( DWORD ); // was 4
321 wndclass3.hInstance = wxhInstance;
322 wndclass3.hIcon = NULL;
323 wndclass3.hCursor = NULL;
324 // wndclass3.hbrBackground = (HBRUSH)(COLOR_WINDOW+1) ;
325 wndclass3.hbrBackground = NULL;
326 wndclass3.lpszMenuName = NULL;
327 wndclass3.lpszClassName = wxCanvasClassName;
328 if (!RegisterClass( &wndclass3))
329 {
330 // wxFatalError("Can't register Canvas class");
331 // return FALSE;
332 }
333
334 return TRUE;
335 }
336
337 //// Convert Windows to argc, argv style
338
339 void wxApp::ConvertToStandardCommandArgs(char* lpCmdLine)
340 {
341 wxStringList args;
342
343 wxString cmdLine(lpCmdLine);
344 int count = 0;
345
346 // Get application name
347 char name[260]; // 260 is MAX_PATH value from windef.h
348 ::GetModuleFileName(wxhInstance, name, WXSIZEOF(name));
349
350 // GNUWIN32 already fills in the first arg with the application name.
351 #if !defined(__GNUWIN32__)
352 args.Add(name);
353 count ++;
354 #endif
355
356 strcpy(name, wxFileNameFromPath(name));
357 wxStripExtension(name);
358 wxTheApp->SetAppName(name);
359
360 // Break up string
361 // Treat strings enclosed in double-quotes as single arguments
362 int i = 0;
363 int len = cmdLine.Length();
364 while (i < len)
365 {
366 // Skip whitespace
367 while ((i < len) && isspace(cmdLine.GetChar(i)))
368 i ++;
369
370 if (i < len)
371 {
372 if (cmdLine.GetChar(i) == '"') // We found the start of a string
373 {
374 i ++;
375 int first = i;
376 while ((i < len) && (cmdLine.GetChar(i) != '"'))
377 i ++;
378
379 wxString arg(cmdLine.Mid(first, (i - first)));
380
381 args.Add(arg);
382 count ++;
383
384 if (i < len)
385 i ++; // Skip past 2nd quote
386 }
387 else // Unquoted argument
388 {
389 int first = i;
390 while ((i < len) && !isspace(cmdLine.GetChar(i)))
391 i ++;
392
393 wxString arg(cmdLine.Mid(first, (i - first)));
394
395 args.Add(arg);
396 count ++;
397 }
398 }
399 }
400
401 wxTheApp->argv = new char*[count + 1];
402 for (i = 0; i < count; i++)
403 {
404 wxString arg(args[i]);
405 wxTheApp->argv[i] = copystring((const char*)arg);
406 }
407 wxTheApp->argv[count] = NULL; // argv[] is a NULL-terminated list
408 wxTheApp->argc = count;
409 }
410
411 //// Cleans up any wxWindows internal structures left lying around
412
413 void wxApp::CleanUp()
414 {
415 //// COMMON CLEANUP
416 wxModule::CleanUpModules();
417
418 #if wxUSE_WX_RESOURCES
419 wxCleanUpResourceSystem();
420
421 // wxDefaultResourceTable->ClearTable();
422 #endif
423
424 // Indicate that the cursor can be freed,
425 // so that cursor won't be deleted by deleting
426 // the bitmap list before g_globalCursor goes out
427 // of scope (double deletion of the cursor).
428 wxSetCursor(wxNullCursor);
429 delete g_globalCursor;
430
431 wxDeleteStockObjects() ;
432
433 // Destroy all GDI lists, etc.
434 wxDeleteStockLists();
435
436 delete wxTheColourDatabase;
437 wxTheColourDatabase = NULL;
438
439 wxBitmap::CleanUpHandlers();
440
441 delete[] wxBuffer;
442 wxBuffer = NULL;
443
444 //// WINDOWS-SPECIFIC CLEANUP
445
446 wxSetKeyboardHook(FALSE);
447
448 #ifdef __WIN95__
449 if (gs_hRichEdit != NULL)
450 FreeLibrary(gs_hRichEdit);
451 #endif
452
453 #if wxUSE_PENWINDOWS
454 wxCleanUpPenWin();
455 #endif
456
457 if (wxSTD_FRAME_ICON)
458 DestroyIcon(wxSTD_FRAME_ICON);
459 if (wxSTD_MDICHILDFRAME_ICON)
460 DestroyIcon(wxSTD_MDICHILDFRAME_ICON);
461 if (wxSTD_MDIPARENTFRAME_ICON)
462 DestroyIcon(wxSTD_MDIPARENTFRAME_ICON);
463
464 if (wxDEFAULT_FRAME_ICON)
465 DestroyIcon(wxDEFAULT_FRAME_ICON);
466 if (wxDEFAULT_MDICHILDFRAME_ICON)
467 DestroyIcon(wxDEFAULT_MDICHILDFRAME_ICON);
468 if (wxDEFAULT_MDIPARENTFRAME_ICON)
469 DestroyIcon(wxDEFAULT_MDIPARENTFRAME_ICON);
470
471 if ( wxDisableButtonBrush )
472 ::DeleteObject( wxDisableButtonBrush ) ;
473
474 #if defined(WX_DRAG_DROP)
475 ::OleUninitialize();
476 #endif
477
478 #if CTL3D
479 Ctl3dUnregister(wxhInstance);
480 #endif
481
482 if (wxWinHandleList)
483 delete wxWinHandleList ;
484
485 wxClassInfo::CleanUpClasses();
486
487 delete wxTheApp;
488 wxTheApp = NULL;
489
490 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
491 // At this point we want to check if there are any memory
492 // blocks that aren't part of the wxDebugContext itself,
493 // as a special case. Then when dumping we need to ignore
494 // wxDebugContext, too.
495 if (wxDebugContext::CountObjectsLeft() > 0)
496 {
497 wxLogDebug("There were memory leaks.");
498 wxDebugContext::Dump();
499 wxDebugContext::PrintStatistics();
500 }
501 // wxDebugContext::SetStream(NULL, NULL);
502 #endif
503
504 // do it as the very last thing because everything else can log messages
505 wxLog::DontCreateOnDemand();
506 delete wxLog::SetActiveTarget(NULL);
507 }
508
509 #if !defined(_WINDLL) || (defined(_WINDLL) && defined(WXMAKINGDLL))
510
511 //// Main wxWindows entry point
512 int wxEntry(WXHINSTANCE hInstance,
513 WXHINSTANCE WXUNUSED(hPrevInstance),
514 char *lpCmdLine,
515 int nCmdShow,
516 bool enterLoop)
517 {
518 #ifndef __WXDEBUG__ // take everything into a try-except block in release build
519 try {
520 #endif
521
522 wxhInstance = (HINSTANCE) hInstance;
523
524 if (!wxApp::Initialize())
525 return 0;
526
527 // create the application object or ensure that one already exists
528 if (!wxTheApp)
529 {
530 // The app may have declared a global application object, but we recommend
531 // the IMPLEMENT_APP macro is used instead, which sets an initializer
532 // function for delayed, dynamic app object construction.
533 wxCHECK_MSG( wxApp::GetInitializerFunction(), 0,
534 "No initializer - use IMPLEMENT_APP macro." );
535
536 wxTheApp = (*wxApp::GetInitializerFunction()) ();
537 }
538
539 wxCHECK_MSG( wxTheApp, 0, "You have to define an instance of wxApp!" );
540
541 // save the WinMain() parameters
542 wxTheApp->ConvertToStandardCommandArgs(lpCmdLine);
543 wxTheApp->m_nCmdShow = nCmdShow;
544
545 // GUI-specific initialisation. In fact on Windows we don't have any,
546 // but this call is provided for compatibility across platforms.
547 wxTheApp->OnInitGui() ;
548
549 int retValue = 0;
550
551 if ( wxTheApp->OnInit() )
552 {
553 if ( enterLoop )
554 {
555 retValue = wxTheApp->OnRun();
556 }
557 }
558 //else: app initialization failed, so we skipped OnRun()
559
560 wxWindow *topWindow = wxTheApp->GetTopWindow();
561 if ( topWindow )
562 {
563 // Forcibly delete the window.
564 if ( topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
565 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
566 {
567 topWindow->Close(TRUE);
568 wxTheApp->DeletePendingObjects();
569 }
570 else
571 {
572 delete topWindow;
573 wxTheApp->SetTopWindow(NULL);
574 }
575 }
576
577 wxTheApp->OnExit();
578
579 // flush the logged messages if any
580 wxLog *pLog = wxLog::GetActiveTarget();
581 if ( pLog != NULL && pLog->HasPendingMessages() )
582 pLog->Flush();
583
584
585 wxApp::CleanUp();
586
587 return retValue;
588 #ifndef __WXDEBUG__ // catch exceptions only in release build
589 }
590 except ( EXCEPTION_EXECUTE_HANDLER ) {
591 /*
592 if ( wxTheApp )
593 wxTheApp->OnFatalException();
594 */
595
596 ::ExitProcess(3); // the same exit code as abort()
597 }
598 #endif //debug
599 }
600
601 #else /* _WINDLL */
602
603 //// Entry point for DLLs
604
605 int wxEntry(WXHINSTANCE hInstance)
606 {
607 wxhInstance = (HINSTANCE) hInstance;
608 wxApp::Initialize();
609
610 // The app may have declared a global application object, but we recommend
611 // the IMPLEMENT_APP macro is used instead, which sets an initializer function
612 // for delayed, dynamic app object construction.
613
614 if (!wxTheApp)
615 {
616 if (!wxApp::GetInitializerFunction())
617 {
618 MessageBox(NULL, "No initializer - use IMPLEMENT_APP macro.", "wxWindows Error", MB_APPLMODAL | MB_ICONSTOP | MB_OK);
619 return 0;
620 }
621
622 wxTheApp = (* wxApp::GetInitializerFunction()) ();
623 }
624
625 if (!wxTheApp) {
626 MessageBox(NULL, "You have to define an instance of wxApp!", "wxWindows Error", MB_APPLMODAL | MB_ICONSTOP | MB_OK);
627 return 0;
628 }
629
630 wxTheApp->argc = 0;
631 wxTheApp->argv = NULL;
632
633 wxTheApp->OnInitGui();
634
635 wxTheApp->OnInit();
636
637 if (wxTheApp->GetTopWindow() && wxTheApp->GetTopWindow()->GetHWND()) {
638 wxTheApp->GetTopWindow()->Show(TRUE);
639 }
640
641 return 1;
642 }
643 #endif // _WINDLL
644
645 //// Static member initialization
646
647 wxAppInitializerFunction wxApp::m_appInitFn = (wxAppInitializerFunction) NULL;
648
649 wxApp::wxApp()
650 {
651 m_topWindow = NULL;
652 wxTheApp = this;
653 m_className = "";
654 m_wantDebugOutput = TRUE ;
655 m_appName = "";
656 argc = 0;
657 argv = NULL;
658 #ifdef __WXMSW__
659 m_printMode = wxPRINT_WINDOWS;
660 #else
661 m_printMode = wxPRINT_POSTSCRIPT;
662 #endif
663 m_exitOnFrameDelete = TRUE;
664 m_auto3D = TRUE;
665 }
666
667 wxApp::~wxApp()
668 {
669 // Delete command-line args
670 int i;
671 for (i = 0; i < argc; i++)
672 {
673 delete[] argv[i];
674 }
675 delete[] argv;
676 }
677
678 bool wxApp::Initialized()
679 {
680 #ifndef _WINDLL
681 if (GetTopWindow())
682 return TRUE;
683 else
684 return FALSE;
685 #endif
686 #ifdef _WINDLL // Assume initialized if DLL (no way of telling)
687 return TRUE;
688 #endif
689 }
690
691 /*
692 * Get and process a message, returning FALSE if WM_QUIT
693 * received.
694 *
695 */
696 bool wxApp::DoMessage()
697 {
698 if (!::GetMessage(&s_currentMsg, (HWND) NULL, 0, 0))
699 {
700 return FALSE;
701 }
702
703 // Process the message
704 if (!ProcessMessage((WXMSG *)&s_currentMsg))
705 {
706 ::TranslateMessage(&s_currentMsg);
707 wxApp::sm_lastMessageTime = s_currentMsg.time; /* MATTHEW: timeStamp impl. */
708 ::DispatchMessage(&s_currentMsg);
709 }
710 return TRUE;
711 }
712
713 /*
714 * Keep trying to process messages until WM_QUIT
715 * received.
716 *
717 * If there are messages to be processed, they will all be
718 * processed and OnIdle will not be called.
719 * When there are no more messages, OnIdle is called.
720 * If OnIdle requests more time,
721 * it will be repeatedly called so long as there are no pending messages.
722 * A 'feature' of this is that once OnIdle has decided that no more processing
723 * is required, then it won't get processing time until further messages
724 * are processed (it'll sit in DoMessage).
725 */
726
727 int wxApp::MainLoop()
728 {
729 m_keepGoing = TRUE;
730 while (m_keepGoing)
731 {
732 while (!::PeekMessage(&s_currentMsg, 0, 0, 0, PM_NOREMOVE) &&
733 ProcessIdle()) {}
734 if (!DoMessage())
735 m_keepGoing = FALSE;
736 }
737
738 return s_currentMsg.wParam;
739 }
740
741 // Returns TRUE if more time is needed.
742 bool wxApp::ProcessIdle()
743 {
744 wxIdleEvent event;
745 event.SetEventObject(this);
746 ProcessEvent(event);
747
748 return event.MoreRequested();
749 }
750
751 void wxApp::ExitMainLoop()
752 {
753 m_keepGoing = FALSE;
754 }
755
756 bool wxApp::Pending()
757 {
758 return (::PeekMessage(&s_currentMsg, 0, 0, 0, PM_NOREMOVE) != 0) ;
759 }
760
761 void wxApp::Dispatch()
762 {
763 if (!DoMessage())
764 m_keepGoing = FALSE;
765 }
766
767 /*
768 * Give all windows a chance to preprocess
769 * the message. Some may have accelerator tables, or have
770 * MDI complications.
771 */
772 bool wxApp::ProcessMessage(WXMSG *Msg)
773 {
774 MSG *msg = (MSG *)Msg;
775
776 HWND hWnd;
777
778 // Try translations first; find the youngest window with
779 // a translation table.
780 for (hWnd = msg->hwnd; hWnd != NULL; hWnd = ::GetParent(hWnd))
781 {
782 wxWindow *wnd = wxFindWinFromHandle((WXHWND) hWnd);
783 if (wnd)
784 {
785 if (wnd->MSWTranslateMessage(Msg))
786 return TRUE;
787 }
788 }
789
790 // Anyone for a non-translation message? Try youngest descendants first.
791 for (hWnd = msg->hwnd; hWnd != NULL; hWnd = ::GetParent(hWnd))
792 {
793 wxWindow *wnd = wxFindWinFromHandle((WXHWND) hWnd);
794 if (wnd)
795 {
796 if (wnd->MSWProcessMessage(Msg))
797 return TRUE;
798 }
799 }
800 return FALSE;
801 }
802
803 void wxApp::OnIdle(wxIdleEvent& event)
804 {
805 static bool inOnIdle = FALSE;
806
807 // Avoid recursion (via ProcessEvent default case)
808 if (inOnIdle)
809 return;
810
811 inOnIdle = TRUE;
812
813 // 'Garbage' collection of windows deleted with Close().
814 DeletePendingObjects();
815
816 // flush the logged messages if any
817 wxLog *pLog = wxLog::GetActiveTarget();
818 if ( pLog != NULL && pLog->HasPendingMessages() )
819 pLog->Flush();
820
821 // Send OnIdle events to all windows
822 bool needMore = SendIdleEvents();
823 // bool needMore = FALSE;
824
825 if (needMore)
826 event.RequestMore(TRUE);
827
828 inOnIdle = FALSE;
829 }
830
831 // Send idle event to all top-level windows
832 bool wxApp::SendIdleEvents()
833 {
834 bool needMore = FALSE;
835 wxNode* node = wxTopLevelWindows.First();
836 while (node)
837 {
838 wxWindow* win = (wxWindow*) node->Data();
839 if (SendIdleEvents(win))
840 needMore = TRUE;
841
842 node = node->Next();
843 }
844 return needMore;
845 }
846
847 // Send idle event to window and all subwindows
848 bool wxApp::SendIdleEvents(wxWindow* win)
849 {
850 bool needMore = FALSE;
851
852 wxIdleEvent event;
853 event.SetEventObject(win);
854 win->GetEventHandler()->ProcessEvent(event);
855
856 if (event.MoreRequested())
857 needMore = TRUE;
858
859 wxNode* node = win->GetChildren()->First();
860 while (node)
861 {
862 wxWindow* win = (wxWindow*) node->Data();
863 if (SendIdleEvents(win))
864 needMore = TRUE;
865
866 node = node->Next();
867 }
868 return needMore ;
869 }
870
871 void wxApp::DeletePendingObjects()
872 {
873 wxNode *node = wxPendingDelete.First();
874 while (node)
875 {
876 wxObject *obj = (wxObject *)node->Data();
877
878 delete obj;
879
880 if (wxPendingDelete.Member(obj))
881 delete node;
882
883 // Deleting one object may have deleted other pending
884 // objects, so start from beginning of list again.
885 node = wxPendingDelete.First();
886 }
887 }
888
889 void wxApp::OnEndSession(wxCloseEvent& event)
890 {
891 if (GetTopWindow())
892 GetTopWindow()->Close(TRUE);
893 }
894
895 // Default behaviour: close the application with prompts. The
896 // user can veto the close, and therefore the end session.
897 void wxApp::OnQueryEndSession(wxCloseEvent& event)
898 {
899 if (GetTopWindow())
900 {
901 if (!GetTopWindow()->Close(!event.CanVeto()))
902 event.Veto(TRUE);
903 }
904 }
905
906 wxLog* wxApp::CreateLogTarget()
907 {
908 return new wxLogGui;
909 }
910
911 wxWindow* wxApp::GetTopWindow() const
912 {
913 if (m_topWindow)
914 return m_topWindow;
915 else if (wxTopLevelWindows.Number() > 0)
916 return (wxWindow*) wxTopLevelWindows.First()->Data();
917 else
918 return NULL;
919 }
920
921 int wxApp::GetComCtl32Version() const
922 {
923 // have we loaded COMCTL32 yet?
924 HMODULE theModule = ::GetModuleHandle("COMCTL32");
925 int version = 0;
926
927 // if so, then we can check for the version
928 if (theModule)
929 {
930 // InitCommonControlsEx is unique to 4.7 and later
931 FARPROC theProc = ::GetProcAddress(theModule, "InitCommonControlsEx");
932
933 if (! theProc)
934 { // not found, must be 4.00
935 version = 400;
936 }
937 else
938 {
939 // The following symbol are unique to 4.71
940 // DllInstall
941 // FlatSB_EnableScrollBar FlatSB_GetScrollInfo FlatSB_GetScrollPos
942 // FlatSB_GetScrollProp FlatSB_GetScrollRange FlatSB_SetScrollInfo
943 // FlatSB_SetScrollPos FlatSB_SetScrollProp FlatSB_SetScrollRange
944 // FlatSB_ShowScrollBar
945 // _DrawIndirectImageList _DuplicateImageList
946 // InitializeFlatSB
947 // UninitializeFlatSB
948 // we could check for any of these - I chose DllInstall
949 FARPROC theProc = ::GetProcAddress(theModule, "DllInstall");
950 if (! theProc)
951 {
952 // not found, must be 4.70
953 version = 470;
954 }
955 else
956 { // found, must be 4.71
957 version = 471;
958 }
959 }
960 }
961 return version;
962 }
963
964 void wxExit()
965 {
966 wxApp::CleanUp();
967 FatalAppExit(0, "Fatal error: exiting");
968 }
969
970 // Yield to incoming messages
971 bool wxYield()
972 {
973 MSG msg;
974 // We want to go back to the main message loop
975 // if we see a WM_QUIT. (?)
976 while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) && msg.message != WM_QUIT)
977 {
978 if (!wxTheApp->DoMessage())
979 break;
980 }
981
982 return TRUE;
983 }
984
985 HINSTANCE wxGetInstance()
986 {
987 return wxhInstance;
988 }
989
990 // For some reason, with MSVC++ 1.5, WinMain isn't linked in properly
991 // if in a separate file. So include it here to ensure it's linked.
992 #if (defined(_MSC_VER) && !defined(__WIN32__)) || defined(__GNUWIN32__)
993 #include "main.cpp"
994 #endif