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