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