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