]> git.saurik.com Git - wxWidgets.git/blob - src/msw/app.cpp
b3a40f84c392b78dc6c4fdc9a4fe7cc7370012fc
[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 // FIXME this code should be rewritten (use wxArrayString instead...)
348 void wxApp::ConvertToStandardCommandArgs(char* lpCmdLine)
349 {
350 // Split command line into tokens, as in usual main(argc, argv)
351 char **command = new char*[50]; // VZ: sure? why not 25 or 73 and a half??
352
353 int count = 0;
354 char *buf = new char[strlen(lpCmdLine) + 1];
355
356 /* Model independent strcpy */
357 int i;
358 for (i = 0; (buf[i] = lpCmdLine[i]) != 0; i++)
359 {
360 /* loop */;
361 }
362
363 // Get application name
364 char name[260]; // 260 is MAX_PATH value from windef.h
365 ::GetModuleFileName(wxhInstance, name, WXSIZEOF(name));
366
367 // Is it only 16-bit Borland that already copies the program name
368 // to the first argv index?
369 #if !defined(__GNUWIN32__)
370 // #if ! (defined(__BORLANDC__) && !defined(__WIN32__))
371 command[count++] = copystring(name);
372 // #endif
373 #endif
374
375 strcpy(name, wxFileNameFromPath(name));
376 wxStripExtension(name);
377 wxTheApp->SetAppName(name);
378
379 /* Break up string */
380 // Treat strings enclosed in double-quotes as single arguments
381 char* str = buf;
382 while (*str)
383 {
384 /*
385 if ( count == WXSIZEOF(command) )
386 {
387 wxFAIL_MSG("too many command line args.");
388 break;
389 }
390 */
391 while ( *str && isspace(*str) ) // skip whitespace
392 str++;
393
394 if (*str == '"')
395 {
396 str++;
397 command[count++] = str;
398 while (*str && *str != '"')
399 str++;
400 }
401 else if (*str)
402 {
403 command[count++] = str;
404 while (*str && !isspace(*str))
405 str++;
406 }
407 if (*str)
408 *str++ = '\0';
409 }
410
411 wxTheApp->argv = new char*[count + 1];
412 wxTheApp->argv[count] = NULL; /* argv[] is NULL terminated list! */
413 wxTheApp->argc = count;
414
415 for (i = 0; i < count; i++)
416 {
417 wxTheApp->argv[i] = copystring(command[i]);
418
419 delete [] command[i];
420 }
421
422 delete [] command;
423 delete [] buf;
424 }
425
426 //// Cleans up any wxWindows internal structures left lying around
427
428 void wxApp::CleanUp()
429 {
430 //// COMMON CLEANUP
431 wxModule::CleanUpModules();
432
433 #if wxUSE_WX_RESOURCES
434 wxCleanUpResourceSystem();
435
436 // wxDefaultResourceTable->ClearTable();
437 #endif
438
439 // Indicate that the cursor can be freed,
440 // so that cursor won't be deleted by deleting
441 // the bitmap list before g_globalCursor goes out
442 // of scope (double deletion of the cursor).
443 wxSetCursor(wxNullCursor);
444 delete g_globalCursor;
445
446 wxDeleteStockObjects() ;
447
448 // Destroy all GDI lists, etc.
449 wxDeleteStockLists();
450
451 delete wxTheColourDatabase;
452 wxTheColourDatabase = NULL;
453
454 wxBitmap::CleanUpHandlers();
455
456 delete[] wxBuffer;
457 wxBuffer = NULL;
458
459 //// WINDOWS-SPECIFIC CLEANUP
460
461 wxSetKeyboardHook(FALSE);
462
463 #ifdef __WIN95__
464 if (gs_hRichEdit != NULL)
465 FreeLibrary(gs_hRichEdit);
466 #endif
467
468 #if wxUSE_PENWINDOWS
469 wxCleanUpPenWin();
470 #endif
471
472 if (wxSTD_FRAME_ICON)
473 DestroyIcon(wxSTD_FRAME_ICON);
474 if (wxSTD_MDICHILDFRAME_ICON)
475 DestroyIcon(wxSTD_MDICHILDFRAME_ICON);
476 if (wxSTD_MDIPARENTFRAME_ICON)
477 DestroyIcon(wxSTD_MDIPARENTFRAME_ICON);
478
479 if (wxDEFAULT_FRAME_ICON)
480 DestroyIcon(wxDEFAULT_FRAME_ICON);
481 if (wxDEFAULT_MDICHILDFRAME_ICON)
482 DestroyIcon(wxDEFAULT_MDICHILDFRAME_ICON);
483 if (wxDEFAULT_MDIPARENTFRAME_ICON)
484 DestroyIcon(wxDEFAULT_MDIPARENTFRAME_ICON);
485
486 if ( wxDisableButtonBrush )
487 ::DeleteObject( wxDisableButtonBrush ) ;
488
489 #if defined(WX_DRAG_DROP)
490 ::OleUninitialize();
491 #endif
492
493 #if CTL3D
494 Ctl3dUnregister(wxhInstance);
495 #endif
496
497 if (wxWinHandleList)
498 delete wxWinHandleList ;
499
500 wxClassInfo::CleanUpClasses();
501
502 // do it as the very last thing because everything else can log messages
503 wxLog::DontCreateOnDemand();
504 delete wxLog::SetActiveTarget(NULL);
505 }
506
507 #if !defined(_WINDLL) || (defined(_WINDLL) && defined(WXMAKINGDLL))
508
509 //// Main wxWindows entry point
510 int wxEntry(WXHINSTANCE hInstance,
511 WXHINSTANCE WXUNUSED(hPrevInstance),
512 char *lpCmdLine,
513 int nCmdShow,
514 bool enterLoop)
515 {
516 #ifndef __WXDEBUG__ // take everything into a try-except block in release build
517 try {
518 #endif
519
520 wxhInstance = (HINSTANCE) hInstance;
521
522 if (!wxApp::Initialize())
523 return 0;
524
525 // create the application object or ensure that one already exists
526 if (!wxTheApp)
527 {
528 // The app may have declared a global application object, but we recommend
529 // the IMPLEMENT_APP macro is used instead, which sets an initializer
530 // function for delayed, dynamic app object construction.
531 wxCHECK_MSG( wxApp::GetInitializerFunction(), 0,
532 "No initializer - use IMPLEMENT_APP macro." );
533
534 wxTheApp = (*wxApp::GetInitializerFunction()) ();
535 }
536
537 wxCHECK_MSG( wxTheApp, 0, "You have to define an instance of wxApp!" );
538
539 // save the WinMain() parameters
540 wxTheApp->ConvertToStandardCommandArgs(lpCmdLine);
541 wxTheApp->m_nCmdShow = nCmdShow;
542
543 // GUI-specific initialisation. In fact on Windows we don't have any,
544 // but this call is provided for compatibility across platforms.
545 wxTheApp->OnInitGui() ;
546
547 int retValue = 0;
548
549 if ( wxTheApp->OnInit() )
550 {
551 if ( enterLoop )
552 {
553 retValue = wxTheApp->OnRun();
554 }
555 }
556 //else: app initialization failed, so we skipped OnRun()
557
558 wxWindow *topWindow = wxTheApp->GetTopWindow();
559 if ( topWindow )
560 {
561 // Forcibly delete the window.
562 if ( topWindow->IsKindOf(CLASSINFO(wxFrame)) ||
563 topWindow->IsKindOf(CLASSINFO(wxDialog)) )
564 {
565 topWindow->Close(TRUE);
566 wxTheApp->DeletePendingObjects();
567 }
568 else
569 {
570 delete topWindow;
571 wxTheApp->SetTopWindow(NULL);
572 }
573 }
574
575 wxTheApp->OnExit();
576 wxApp::CleanUp();
577
578 delete wxTheApp;
579 wxTheApp = NULL;
580
581 #if (WXDEBUG && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
582 // At this point we want to check if there are any memory
583 // blocks that aren't part of the wxDebugContext itself,
584 // as a special case. Then when dumping we need to ignore
585 // wxDebugContext, too.
586 if (wxDebugContext::CountObjectsLeft() > 0)
587 {
588 wxTrace("There were memory leaks.\n");
589 wxDebugContext::Dump();
590 wxDebugContext::PrintStatistics();
591 }
592 wxDebugContext::SetStream(NULL, NULL);
593 #endif
594
595 return retValue;
596 #ifndef __WXDEBUG__ // catch exceptions only in release build
597 }
598 except ( EXCEPTION_EXECUTE_HANDLER ) {
599 /*
600 if ( wxTheApp )
601 wxTheApp->OnFatalException();
602 */
603
604 ::ExitProcess(3); // the same exit code as abort()
605 }
606 #endif //debug
607 }
608
609 #else /* _WINDLL */
610
611 //// Entry point for DLLs
612
613 int wxEntry(WXHINSTANCE hInstance)
614 {
615 wxhInstance = (HINSTANCE) hInstance;
616 wxApp::Initialize();
617
618 // The app may have declared a global application object, but we recommend
619 // the IMPLEMENT_APP macro is used instead, which sets an initializer function
620 // for delayed, dynamic app object construction.
621
622 if (!wxTheApp)
623 {
624 if (!wxApp::GetInitializerFunction())
625 {
626 MessageBox(NULL, "No initializer - use IMPLEMENT_APP macro.", "wxWindows Error", MB_APPLMODAL | MB_ICONSTOP | MB_OK);
627 return 0;
628 }
629
630 wxTheApp = (* wxApp::GetInitializerFunction()) ();
631 }
632
633 if (!wxTheApp) {
634 MessageBox(NULL, "You have to define an instance of wxApp!", "wxWindows Error", MB_APPLMODAL | MB_ICONSTOP | MB_OK);
635 return 0;
636 }
637
638 wxTheApp->argc = 0;
639 wxTheApp->argv = NULL;
640
641 wxTheApp->OnInitGui();
642
643 wxTheApp->OnInit();
644
645 if (wxTheApp->GetTopWindow() && wxTheApp->GetTopWindow()->GetHWND()) {
646 wxTheApp->GetTopWindow()->Show(TRUE);
647 }
648
649 return 1;
650 }
651 #endif // _WINDLL
652
653 //// Static member initialization
654
655 wxAppInitializerFunction wxApp::m_appInitFn = (wxAppInitializerFunction) NULL;
656
657 wxApp::wxApp()
658 {
659 m_topWindow = NULL;
660 wxTheApp = this;
661 m_className = "";
662 m_wantDebugOutput = TRUE ;
663 m_appName = "";
664 argc = 0;
665 argv = NULL;
666 #ifdef __WXMSW__
667 m_printMode = wxPRINT_WINDOWS;
668 #else
669 m_printMode = wxPRINT_POSTSCRIPT;
670 #endif
671 m_exitOnFrameDelete = TRUE;
672 m_auto3D = TRUE;
673 }
674
675 wxApp::~wxApp()
676 {
677 // Delete command-line args
678 int i;
679 for (i = 0; i < argc; i++)
680 {
681 delete[] argv[i];
682 }
683 delete argv;
684 }
685
686 bool wxApp::Initialized()
687 {
688 #ifndef _WINDLL
689 if (GetTopWindow())
690 return TRUE;
691 else
692 return FALSE;
693 #endif
694 #ifdef _WINDLL // Assume initialized if DLL (no way of telling)
695 return TRUE;
696 #endif
697 }
698
699 /*
700 * Get and process a message, returning FALSE if WM_QUIT
701 * received.
702 *
703 */
704 bool wxApp::DoMessage()
705 {
706 if (!::GetMessage(&s_currentMsg, (HWND) NULL, 0, 0))
707 {
708 return FALSE;
709 }
710
711 // Process the message
712 if (!ProcessMessage((WXMSG *)&s_currentMsg))
713 {
714 ::TranslateMessage(&s_currentMsg);
715 wxApp::sm_lastMessageTime = s_currentMsg.time; /* MATTHEW: timeStamp impl. */
716 ::DispatchMessage(&s_currentMsg);
717 }
718 return TRUE;
719 }
720
721 /*
722 * Keep trying to process messages until WM_QUIT
723 * received.
724 *
725 * If there are messages to be processed, they will all be
726 * processed and OnIdle will not be called.
727 * When there are no more messages, OnIdle is called.
728 * If OnIdle requests more time,
729 * it will be repeatedly called so long as there are no pending messages.
730 * A 'feature' of this is that once OnIdle has decided that no more processing
731 * is required, then it won't get processing time until further messages
732 * are processed (it'll sit in DoMessage).
733 */
734
735 int wxApp::MainLoop()
736 {
737 m_keepGoing = TRUE;
738 while (m_keepGoing)
739 {
740 while (!::PeekMessage(&s_currentMsg, 0, 0, 0, PM_NOREMOVE) &&
741 ProcessIdle()) {}
742 if (!DoMessage())
743 m_keepGoing = FALSE;
744 }
745
746 return s_currentMsg.wParam;
747 }
748
749 // Returns TRUE if more time is needed.
750 bool wxApp::ProcessIdle()
751 {
752 wxIdleEvent event;
753 event.SetEventObject(this);
754 ProcessEvent(event);
755
756 return event.MoreRequested();
757 }
758
759 void wxApp::ExitMainLoop()
760 {
761 m_keepGoing = FALSE;
762 }
763
764 bool wxApp::Pending()
765 {
766 return (::PeekMessage(&s_currentMsg, 0, 0, 0, PM_NOREMOVE) != 0) ;
767 }
768
769 void wxApp::Dispatch()
770 {
771 if (!DoMessage())
772 m_keepGoing = FALSE;
773 }
774
775 /*
776 * Give all windows a chance to preprocess
777 * the message. Some may have accelerator tables, or have
778 * MDI complications.
779 */
780 bool wxApp::ProcessMessage(WXMSG *Msg)
781 {
782 MSG *msg = (MSG *)Msg;
783
784 HWND hWnd;
785
786 // Try translations first; find the youngest window with
787 // a translation table.
788 for (hWnd = msg->hwnd; hWnd != NULL; hWnd = ::GetParent(hWnd))
789 {
790 wxWindow *wnd = wxFindWinFromHandle((WXHWND) hWnd);
791 if (wnd)
792 {
793 if (wnd->MSWTranslateMessage(Msg))
794 return TRUE;
795 }
796 }
797
798 // Anyone for a non-translation message? Try youngest descendants first.
799 for (hWnd = msg->hwnd; hWnd != NULL; hWnd = ::GetParent(hWnd))
800 {
801 wxWindow *wnd = wxFindWinFromHandle((WXHWND) hWnd);
802 if (wnd)
803 {
804 if (wnd->MSWProcessMessage(Msg))
805 return TRUE;
806 }
807 }
808 return FALSE;
809 }
810
811 void wxApp::OnIdle(wxIdleEvent& event)
812 {
813 static bool inOnIdle = FALSE;
814
815 // Avoid recursion (via ProcessEvent default case)
816 if (inOnIdle)
817 return;
818
819 inOnIdle = TRUE;
820
821 // 'Garbage' collection of windows deleted with Close().
822 DeletePendingObjects();
823
824 // flush the logged messages if any
825 wxLog *pLog = wxLog::GetActiveTarget();
826 if ( pLog != NULL && pLog->HasPendingMessages() )
827 pLog->Flush();
828
829 // Send OnIdle events to all windows
830 bool needMore = SendIdleEvents();
831 // bool needMore = FALSE;
832
833 if (needMore)
834 event.RequestMore(TRUE);
835
836 inOnIdle = FALSE;
837 }
838
839 // Send idle event to all top-level windows
840 bool wxApp::SendIdleEvents()
841 {
842 bool needMore = FALSE;
843 wxNode* node = wxTopLevelWindows.First();
844 while (node)
845 {
846 wxWindow* win = (wxWindow*) node->Data();
847 if (SendIdleEvents(win))
848 needMore = TRUE;
849
850 node = node->Next();
851 }
852 return needMore;
853 }
854
855 // Send idle event to window and all subwindows
856 bool wxApp::SendIdleEvents(wxWindow* win)
857 {
858 bool needMore = FALSE;
859
860 wxIdleEvent event;
861 event.SetEventObject(win);
862 win->ProcessEvent(event);
863
864 if (event.MoreRequested())
865 needMore = TRUE;
866
867 wxNode* node = win->GetChildren()->First();
868 while (node)
869 {
870 wxWindow* win = (wxWindow*) node->Data();
871 if (SendIdleEvents(win))
872 needMore = TRUE;
873
874 node = node->Next();
875 }
876 return needMore ;
877 }
878
879 void wxApp::DeletePendingObjects()
880 {
881 wxNode *node = wxPendingDelete.First();
882 while (node)
883 {
884 wxObject *obj = (wxObject *)node->Data();
885
886 delete obj;
887
888 if (wxPendingDelete.Member(obj))
889 delete node;
890
891 // Deleting one object may have deleted other pending
892 // objects, so start from beginning of list again.
893 node = wxPendingDelete.First();
894 }
895 }
896
897 void wxApp::OnEndSession(wxCloseEvent& event)
898 {
899 if (GetTopWindow())
900 GetTopWindow()->Close(TRUE);
901 }
902
903 // Default behaviour: close the application with prompts. The
904 // user can veto the close, and therefore the end session.
905 void wxApp::OnQueryEndSession(wxCloseEvent& event)
906 {
907 if (GetTopWindow())
908 {
909 if (!GetTopWindow()->Close(!event.CanVeto()))
910 event.Veto(TRUE);
911 }
912 }
913
914 wxLog* wxApp::CreateLogTarget()
915 {
916 return new wxLogGui;
917 }
918
919 wxWindow* wxApp::GetTopWindow() const
920 {
921 if (m_topWindow)
922 return m_topWindow;
923 else if (wxTopLevelWindows.Number() > 0)
924 return (wxWindow*) wxTopLevelWindows.First()->Data();
925 else
926 return NULL;
927 }
928
929 int wxApp::GetComCtl32Version() const
930 {
931 // have we loaded COMCTL32 yet?
932 HMODULE theModule = ::GetModuleHandle("COMCTL32");
933 int version = 0;
934
935 // if so, then we can check for the version
936 if (theModule)
937 {
938 // InitCommonControlsEx is unique to 4.7 and later
939 FARPROC theProc = ::GetProcAddress(theModule, "InitCommonControlsEx");
940
941 if (! theProc)
942 { // not found, must be 4.00
943 version = 400;
944 }
945 else
946 {
947 // The following symbol are unique to 4.71
948 // DllInstall
949 // FlatSB_EnableScrollBar FlatSB_GetScrollInfo FlatSB_GetScrollPos
950 // FlatSB_GetScrollProp FlatSB_GetScrollRange FlatSB_SetScrollInfo
951 // FlatSB_SetScrollPos FlatSB_SetScrollProp FlatSB_SetScrollRange
952 // FlatSB_ShowScrollBar
953 // _DrawIndirectImageList _DuplicateImageList
954 // InitializeFlatSB
955 // UninitializeFlatSB
956 // we could check for any of these - I chose DllInstall
957 FARPROC theProc = ::GetProcAddress(theModule, "DllInstall");
958 if (! theProc)
959 {
960 // not found, must be 4.70
961 version = 470;
962 }
963 else
964 { // found, must be 4.71
965 version = 471;
966 }
967 }
968 }
969 return version;
970 }
971
972 void wxExit()
973 {
974 wxApp::CleanUp();
975 FatalAppExit(0, "Fatal error: exiting");
976 }
977
978 // Yield to incoming messages
979 bool wxYield()
980 {
981 MSG msg;
982 // We want to go back to the main message loop
983 // if we see a WM_QUIT. (?)
984 while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) && msg.message != WM_QUIT)
985 {
986 if (!wxTheApp->DoMessage())
987 break;
988 }
989
990 return TRUE;
991 }
992
993 HINSTANCE wxGetInstance()
994 {
995 return wxhInstance;
996 }
997
998 // For some reason, with MSVC++ 1.5, WinMain isn't linked in properly
999 // if in a separate file. So include it here to ensure it's linked.
1000 #if (defined(_MSC_VER) && !defined(__WIN32__)) || defined(__GNUWIN32__)
1001 #include "main.cpp"
1002 #endif