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