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