removed duplicate wxTheApp and m_appInitFn definitions from all ports, not just MSW
[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 #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 #ifndef WX_PRECOMP
20 #include "wx/frame.h"
21 #include "wx/app.h"
22 #include "wx/utils.h"
23 #include "wx/gdicmn.h"
24 #include "wx/pen.h"
25 #include "wx/brush.h"
26 #include "wx/cursor.h"
27 #include "wx/icon.h"
28 #include "wx/palette.h"
29 #include "wx/dc.h"
30 #include "wx/dialog.h"
31 #include "wx/msgdlg.h"
32 #include "wx/intl.h"
33 #include "wx/dynarray.h"
34 #include "wx/wxchar.h"
35 #include "wx/icon.h"
36 #include "wx/timer.h"
37 #endif
38
39 #include "wx/log.h"
40 #include "wx/module.h"
41
42 #include "wx/os2/private.h"
43
44 #ifdef __EMX__
45
46 #include <sys/ioctl.h>
47 #include <sys/select.h>
48
49 #else
50
51 #include <nerrno.h>
52 #include <sys/ioctl.h>
53 #include <sys/select.h>
54 #include <sys/time.h>
55
56 #endif //
57
58 #ifndef __EMX__
59
60 #define select(a,b,c,d,e) bsdselect(a,b,c,d,e)
61 extern "C" int _System bsdselect(int,
62 struct fd_set *,
63 struct fd_set *,
64 struct fd_set *,
65 struct timeval *);
66 #endif
67
68 #if wxUSE_THREADS
69 #include "wx/thread.h"
70
71 // define the array of QMSG strutures
72 WX_DECLARE_OBJARRAY(QMSG, wxMsgArray);
73
74 #include "wx/arrimpl.cpp"
75
76 WX_DEFINE_OBJARRAY(wxMsgArray);
77 #endif // wxUSE_THREADS
78
79 #if wxUSE_TOOLTIPS
80 #include "wx/tooltip.h"
81 #endif // wxUSE_TOOLTIPS
82
83 #include <string.h>
84 #include <ctype.h>
85
86 // ---------------------------------------------------------------------------
87 // global variables
88 // ---------------------------------------------------------------------------
89
90 extern wxChar* wxBuffer;
91 extern wxList* wxWinHandleList;
92 extern wxList WXDLLEXPORT wxPendingDelete;
93 extern wxCursor* g_globalCursor;
94
95 HAB vHabmain = NULLHANDLE;
96 QMSG svCurrentMsg;
97
98
99 HICON wxSTD_FRAME_ICON = (HICON) NULL;
100 HICON wxSTD_MDICHILDFRAME_ICON = (HICON) NULL;
101 HICON wxSTD_MDIPARENTFRAME_ICON = (HICON) NULL;
102
103 HICON wxDEFAULT_FRAME_ICON = (HICON) NULL;
104 HICON wxDEFAULT_MDICHILDFRAME_ICON = (HICON) NULL;
105 HICON wxDEFAULT_MDIPARENTFRAME_ICON = (HICON) NULL;
106
107 HBRUSH wxDisableButtonBrush = (HBRUSH) 0;
108
109 MRESULT EXPENTRY wxWndProc( HWND hWnd,ULONG message,MPARAM mp1,MPARAM mp2);
110 MRESULT EXPENTRY wxFrameWndProc( HWND hWnd,ULONG message,MPARAM mp1,MPARAM mp2);
111
112 // ===========================================================================
113 // implementation
114 // ===========================================================================
115
116 // ---------------------------------------------------------------------------
117 // helper struct and functions for socket handling
118 // ---------------------------------------------------------------------------
119
120 struct GsocketCallbackInfo{
121 void (*proc)(void *);
122 int type;
123 int handle;
124 void* gsock;
125 };
126
127 // These defines and wrapper functions are used here and in gsockpm.c
128 #define wxSockReadMask 0x01
129 #define wxSockWriteMask 0x02
130
131 #ifdef __EMX__
132 extern "C"
133 int wxAppAddSocketHandler(int handle, int mask,
134 void (*callback)(void*), void * gsock)
135 {
136 return wxTheApp->AddSocketHandler(handle, mask, callback, gsock);
137 }
138 extern "C"
139 void wxAppRemoveSocketHandler(int handle)
140 {
141 wxTheApp->RemoveSocketHandler(handle);
142 }
143 #else
144 // Linkage mode problems using callbacks with extern C in a .cpp module
145 int wxAppAddSocketHandler(int handle, int mask,
146 void (*callback)(void*), void * gsock)
147 {
148 return wxTheApp->AddSocketHandler(handle, mask, callback, gsock);
149 }
150 void wxAppRemoveSocketHandler(int handle)
151 {
152 wxTheApp->RemoveSocketHandler(handle);
153 }
154 #endif
155
156 void wxApp::HandleSockets()
157 {
158 bool pendingEvent = FALSE;
159
160 // Check whether it's time for Gsocket operation
161 if (m_maxSocketHandles > 0 && m_maxSocketNr > 0)
162 {
163 fd_set readfds = m_readfds;
164 fd_set writefds = m_writefds;
165 struct timeval timeout;
166 int i;
167 struct GsocketCallbackInfo
168 *CallbackInfo = (struct GsocketCallbackInfo *)m_sockCallbackInfo;
169 int r = 0;
170 timeout.tv_sec = 0;
171 timeout.tv_usec = 0;
172 if ( select(m_maxSocketNr, &readfds, &writefds, 0, &timeout) > 0)
173 {
174 for (i = m_lastUsedHandle + 1; i != m_lastUsedHandle; i++)
175 {
176 if (i == m_maxSocketNr)
177 i = 0;
178 if (FD_ISSET(i, &readfds))
179 {
180 int r;
181 for (r = 0; r < m_maxSocketHandles; r++){
182 if(CallbackInfo[r].handle == i &&
183 CallbackInfo[r].type == wxSockReadMask)
184 break;
185 }
186 if (r < m_maxSocketHandles)
187 {
188 CallbackInfo[r].proc(CallbackInfo[r].gsock);
189 pendingEvent = TRUE;
190 wxYield();
191 }
192 }
193 if (FD_ISSET(i, &writefds))
194 {
195 int r;
196 for (r = 0; r < m_maxSocketHandles; r++)
197 if(CallbackInfo[r].handle == i &&
198 CallbackInfo[r].type == wxSockWriteMask)
199 break;
200 if (r < m_maxSocketHandles)
201 {
202 CallbackInfo[r].proc(CallbackInfo[r].gsock);
203 pendingEvent = TRUE;
204 wxYield();
205 }
206 }
207 }
208 m_lastUsedHandle = i;
209 }
210 if (pendingEvent)
211 wxYield();
212 }
213 }
214 // ---------------------------------------------------------------------------
215 // wxApp
216 // ---------------------------------------------------------------------------
217
218 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
219
220 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
221 EVT_IDLE(wxApp::OnIdle)
222 EVT_END_SESSION(wxApp::OnEndSession)
223 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
224 END_EVENT_TABLE()
225
226 //
227 // Initialize
228 //
229 bool wxApp::Initialize(
230 HAB vHab
231 )
232 {
233 #if defined(wxUSE_CONSOLEDEBUG)
234 #if wxUSE_CONSOLEDEBUG
235 /***********************************************/
236 /* Code for using stdout debug */
237 /* To use it you mast link app as "Window" - EK*/
238 /***********************************************/
239 {
240 PPIB pib;
241 PTIB tib;
242
243 printf("In console\n");
244
245 DosGetInfoBlocks(&tib, &pib);
246 /* Try morphing into a PM application. */
247 // if(pib->pib_ultype == 2) /* VIO */
248 pib->pib_ultype = 3;
249 }
250 /**********************************************/
251 /**********************************************/
252 #endif //wxUSE_CONSOLEDEBUG
253 #endif
254
255 wxBuffer = new wxChar[1500]; // FIXME; why?
256
257 wxClassInfo::InitializeClasses();
258
259 #if wxUSE_THREADS
260 wxPendingEventsLocker = new wxCriticalSection;
261 #endif
262
263 wxTheColourDatabase = new wxColourDatabase(wxKEY_STRING);
264 wxTheColourDatabase->Initialize();
265
266 wxInitializeStockLists();
267 wxInitializeStockObjects();
268
269 wxBitmap::InitStandardHandlers();
270
271 //
272 // OS2 has to have an anchorblock
273 //
274 vHab = WinInitialize(0);
275
276 if (!vHab)
277 return FALSE;
278 else
279 vHabmain = vHab;
280
281 // Some people may wish to use this, but
282 // probably it shouldn't be here by default.
283 #ifdef __WXDEBUG__
284 // wxRedirectIOToConsole();
285 #endif
286
287 wxWinHandleList = new wxList(wxKEY_INTEGER);
288
289 // This is to foil optimizations in Visual C++ that throw out dummy.obj.
290 // PLEASE DO NOT ALTER THIS.
291 #if !defined(WXMAKINGDLL) && defined(__VISAGECPP__)
292 extern char wxDummyChar;
293 if (wxDummyChar) wxDummyChar++;
294 #endif
295
296 // wxSetKeyboardHook(TRUE);
297
298 wxModule::RegisterModules();
299 if (!wxModule::InitializeModules())
300 return FALSE;
301 RegisterWindowClasses(vHab);
302 return TRUE;
303 } // end of wxApp::Initialize
304
305 const char* CANTREGISTERCLASS = " Can't register Class ";
306 // ---------------------------------------------------------------------------
307 // RegisterWindowClasses
308 // ---------------------------------------------------------------------------
309
310 bool wxApp::RegisterWindowClasses(
311 HAB vHab
312 )
313 {
314 ERRORID vError = 0L;
315 wxString sError;
316
317 if (!::WinRegisterClass( vHab
318 ,wxFrameClassName
319 ,wxFrameWndProc
320 ,CS_SIZEREDRAW | CS_SYNCPAINT
321 ,sizeof(ULONG)
322 ))
323 {
324 vError = ::WinGetLastError(vHab);
325 sError = wxPMErrorToStr(vError);
326 wxLogLastError(sError);
327 return FALSE;
328 }
329
330 if (!::WinRegisterClass( vHab
331 ,wxFrameClassNameNoRedraw
332 ,wxWndProc
333 ,0
334 ,sizeof(ULONG)
335 ))
336 {
337 vError = ::WinGetLastError(vHab);
338 sError = wxPMErrorToStr(vError);
339 wxLogLastError(sError);
340 return FALSE;
341 }
342
343 if (!::WinRegisterClass( vHab
344 ,wxMDIFrameClassName
345 ,wxWndProc
346 ,CS_SIZEREDRAW | CS_MOVENOTIFY | CS_SYNCPAINT
347 ,sizeof(ULONG)
348 ))
349 {
350 vError = ::WinGetLastError(vHab);
351 sError = wxPMErrorToStr(vError);
352 wxLogLastError(sError);
353 return FALSE;
354 }
355
356 if (!::WinRegisterClass( vHab
357 ,wxMDIFrameClassNameNoRedraw
358 ,wxWndProc
359 ,0
360 ,sizeof(ULONG)
361 ))
362 {
363 vError = ::WinGetLastError(vHab);
364 sError = wxPMErrorToStr(vError);
365 wxLogLastError(sError);
366 return FALSE;
367 }
368
369 if (!::WinRegisterClass( vHab
370 ,wxMDIChildFrameClassName
371 ,wxWndProc
372 ,CS_MOVENOTIFY | CS_SIZEREDRAW | CS_SYNCPAINT | CS_HITTEST
373 ,sizeof(ULONG)
374 ))
375 {
376 vError = ::WinGetLastError(vHab);
377 sError = wxPMErrorToStr(vError);
378 wxLogLastError(sError);
379 return FALSE;
380 }
381
382 if (!::WinRegisterClass( vHab
383 ,wxMDIChildFrameClassNameNoRedraw
384 ,wxWndProc
385 ,CS_HITTEST
386 ,sizeof(ULONG)
387 ))
388 {
389 vError = ::WinGetLastError(vHab);
390 sError = wxPMErrorToStr(vError);
391 wxLogLastError(sError);
392 return FALSE;
393 }
394
395 if (!::WinRegisterClass( vHab
396 ,wxPanelClassName
397 ,wxWndProc
398 ,CS_MOVENOTIFY | CS_SIZEREDRAW | CS_HITTEST | CS_SAVEBITS | CS_SYNCPAINT
399 ,sizeof(ULONG)
400 ))
401 {
402 vError = ::WinGetLastError(vHab);
403 sError = wxPMErrorToStr(vError);
404 wxLogLastError(sError);
405 return FALSE;
406 }
407
408 if (!::WinRegisterClass( vHab
409 ,wxCanvasClassName
410 ,wxWndProc
411 ,CS_SIZEREDRAW | CS_HITTEST | CS_SYNCPAINT
412 ,sizeof(ULONG)
413 ))
414 {
415 vError = ::WinGetLastError(vHab);
416 sError = wxPMErrorToStr(vError);
417 wxLogLastError(sError);
418 return FALSE;
419 }
420 if (!::WinRegisterClass( vHab
421 ,wxCanvasClassNameNR
422 ,wxWndProc
423 ,CS_HITTEST | CS_SYNCPAINT
424 ,sizeof(ULONG)
425 ))
426 {
427 vError = ::WinGetLastError(vHab);
428 sError = wxPMErrorToStr(vError);
429 wxLogLastError(sError);
430 return FALSE;
431 }
432 return TRUE;
433 } // end of wxApp::RegisterWindowClasses
434
435 //
436 // Cleans up any wxWindows internal structures left lying around
437 //
438 void wxApp::CleanUp()
439 {
440 //
441 // COMMON CLEANUP
442 //
443
444 #if wxUSE_LOG
445
446 //
447 // Flush the logged messages if any and install a 'safer' log target: the
448 // default one (wxLogGui) can't be used after the resources are freed just
449 // below and the user suppliedo ne might be even more unsafe (using any
450 // wxWindows GUI function is unsafe starting from now)
451 //
452 wxLog::DontCreateOnDemand();
453
454 //
455 // This will flush the old messages if any
456 //
457 delete wxLog::SetActiveTarget(new wxLogStderr);
458 #endif // wxUSE_LOG
459
460 //
461 // One last chance for pending objects to be cleaned up
462 //
463 wxTheApp->DeletePendingObjects();
464
465 wxModule::CleanUpModules();
466
467 wxDeleteStockObjects();
468
469 //
470 // Destroy all GDI lists, etc.
471 //
472 wxDeleteStockLists();
473
474 delete wxTheColourDatabase;
475 wxTheColourDatabase = NULL;
476
477 wxBitmap::CleanUpHandlers();
478
479 delete[] wxBuffer;
480 wxBuffer = NULL;
481
482 //
483 // PM-SPECIFIC CLEANUP
484 //
485
486 // wxSetKeyboardHook(FALSE);
487
488 if (wxSTD_FRAME_ICON)
489 ::WinFreeFileIcon(wxSTD_FRAME_ICON);
490 if (wxSTD_MDICHILDFRAME_ICON)
491 ::WinFreeFileIcon(wxSTD_MDICHILDFRAME_ICON);
492 if (wxSTD_MDIPARENTFRAME_ICON)
493 ::WinFreeFileIcon(wxSTD_MDIPARENTFRAME_ICON);
494
495 if (wxDEFAULT_FRAME_ICON)
496 ::WinFreeFileIcon(wxDEFAULT_FRAME_ICON);
497 if (wxDEFAULT_MDICHILDFRAME_ICON)
498 ::WinFreeFileIcon(wxDEFAULT_MDICHILDFRAME_ICON);
499 if (wxDEFAULT_MDIPARENTFRAME_ICON)
500 ::WinFreeFileIcon(wxDEFAULT_MDIPARENTFRAME_ICON);
501
502 if ( wxDisableButtonBrush )
503 {
504 // TODO: ::DeleteObject( wxDisableButtonBrush );
505 }
506
507 if (wxWinHandleList)
508 delete wxWinHandleList;
509
510 delete wxPendingEvents;
511 #if wxUSE_THREADS
512 delete wxPendingEventsLocker;
513 // If we don't do the following, we get an apparent memory leak.
514 ((wxEvtHandler&) wxDefaultValidator).ClearEventLocker();
515 #endif
516
517 wxClassInfo::CleanUpClasses();
518
519 // Delete Message queue
520 if (wxTheApp->m_hMq)
521 ::WinDestroyMsgQueue(wxTheApp->m_hMq);
522
523 delete wxTheApp;
524 wxTheApp = NULL;
525
526 #if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT
527 // At this point we want to check if there are any memory
528 // blocks that aren't part of the wxDebugContext itself,
529 // as a special case. Then when dumping we need to ignore
530 // wxDebugContext, too.
531 if (wxDebugContext::CountObjectsLeft(TRUE) > 0)
532 {
533 wxLogDebug(wxT("There were memory leaks."));
534 wxDebugContext::Dump();
535 wxDebugContext::PrintStatistics();
536 }
537 // wxDebugContext::SetStream(NULL, NULL);
538 #endif
539
540 #if wxUSE_LOG
541 // do it as the very last thing because everything else can log messages
542 delete wxLog::SetActiveTarget(NULL);
543 #endif // wxUSE_LOG
544 } // end of wxApp::CleanUp
545
546 //----------------------------------------------------------------------
547 // Main wxWindows entry point
548 //----------------------------------------------------------------------
549 int wxEntry(
550 int argc
551 , char* argv[]
552 )
553 {
554 HAB vHab = 0;
555
556 if (!wxApp::Initialize(vHab))
557 return 0;
558
559 //
560 // create the application object or ensure that one already exists
561 //
562 if (!wxTheApp)
563 {
564 // The app may have declared a global application object, but we recommend
565 // the IMPLEMENT_APP macro is used instead, which sets an initializer
566 // function for delayed, dynamic app object construction.
567 wxCHECK_MSG( wxApp::GetInitializerFunction(), 0,
568 wxT("No initializer - use IMPLEMENT_APP macro.") );
569 wxTheApp = (*wxApp::GetInitializerFunction()) ();
570 }
571 wxCHECK_MSG( wxTheApp, 0, wxT("You have to define an instance of wxApp!") );
572 wxTheApp->argc = argc;
573
574 #if wxUSE_UNICODE
575 wxTheApp->argv = new wxChar*[argc+1];
576
577 int nArgc = 0;
578
579 while (nArgc < argc)
580 {
581 wxTheApp->argv[nArgc] = wxStrdup(wxConvLibc.cMB2WX(argv[nArgc]));
582 nArgc++;
583 }
584 wxTheApp->argv[nArgc] = (wxChar *)NULL;
585 #else
586 wxTheApp->argv = argv;
587 #endif
588
589 wxString sName(wxFileNameFromPath(argv[0]));
590
591 wxStripExtension(sName);
592 wxTheApp->SetAppName(sName);
593
594 int nRetValue = 0;
595
596 if (!wxTheApp->OnInitGui())
597 nRetValue = -1;
598
599 if (nRetValue == 0)
600 {
601 if (wxTheApp->OnInit())
602 {
603 wxTheApp->OnRun();
604 }
605 // Normal exit
606 wxWindow* pTopWindow = wxTheApp->GetTopWindow();
607 if (pTopWindow)
608 {
609 // Forcibly delete the window.
610 if (pTopWindow->IsKindOf(CLASSINFO(wxFrame)) ||
611 pTopWindow->IsKindOf(CLASSINFO(wxDialog)) )
612 {
613 pTopWindow->Close(TRUE);
614 wxTheApp->DeletePendingObjects();
615 }
616 else
617 {
618 delete pTopWindow;
619 wxTheApp->SetTopWindow(NULL);
620 }
621 }
622 }
623 else // app initialization failed
624 {
625 wxLogLastError(" Gui initialization failed, exitting");
626 }
627 #if wxUSE_CONSOLEDEBUG
628 printf("wxTheApp->OnExit ");
629 fflush(stdout);
630 #endif
631 nRetValue = wxTheApp->OnExit();
632 #if wxUSE_CONSOLEDEBUG
633 printf("wxApp::CleanUp ");
634 fflush(stdout);
635 #endif
636 wxApp::CleanUp();
637 #if wxUSE_CONSOLEDEBUG
638 printf("return %i ", nRetValue);
639 fflush(stdout);
640 #endif
641 return(nRetValue);
642 } // end of wxEntry
643
644 bool wxApp::OnInitGui()
645 {
646 ERRORID vError;
647 wxString sError;
648
649 if (!wxAppBase::OnInitGui())
650 return FALSE;
651
652 m_hMq = ::WinCreateMsgQueue(vHabmain, 0);
653 if (!m_hMq)
654 {
655 vError = ::WinGetLastError(vHabmain);
656 sError = wxPMErrorToStr(vError);
657 wxLogDebug(sError);
658 return FALSE;
659 }
660
661 return TRUE;
662 } // end of wxApp::OnInitGui
663
664 wxApp::wxApp()
665 {
666 m_topWindow = NULL;
667 wxTheApp = this;
668
669 argc = 0;
670 argv = NULL;
671 m_nPrintMode = wxPRINT_WINDOWS;
672 m_bAuto3D = TRUE;
673 m_hMq = 0;
674 m_maxSocketHandles = 0;
675 m_maxSocketNr = 0;
676 m_sockCallbackInfo = 0;
677 } // end of wxApp::wxApp
678
679 wxApp::~wxApp()
680 {
681 //
682 // Delete command-line args
683 //
684 #if wxUSE_UNICODE
685 int i;
686
687 for (i = 0; i < argc; i++)
688 {
689 delete[] argv[i];
690 }
691 delete[] argv;
692 #endif
693 } // end of wxApp::~wxApp
694
695 bool wxApp::Initialized()
696 {
697 if (GetTopWindow())
698 return TRUE;
699 else
700 return FALSE;
701 } // end of wxApp::Initialized
702
703 //
704 // Get and process a message, returning FALSE if WM_QUIT
705 // received (and also set the flag telling the app to exit the main loop)
706 //
707
708 bool wxApp::DoMessage()
709 {
710 BOOL bRc = ::WinGetMsg(vHabmain, &svCurrentMsg, HWND(NULL), 0, 0);
711
712 if (bRc == 0)
713 {
714 // got WM_QUIT
715 m_bKeepGoing = FALSE;
716 return FALSE;
717 }
718 else if (bRc == -1)
719 {
720 // should never happen, but let's test for it nevertheless
721 wxLogLastError("GetMessage");
722 }
723 else
724 {
725 #if wxUSE_THREADS
726 wxASSERT_MSG( wxThread::IsMain()
727 ,wxT("only the main thread can process Windows messages")
728 );
729
730 static bool sbHadGuiLock = TRUE;
731 static wxMsgArray svSavedMessages;
732
733 //
734 // If a secondary thread owns is doing GUI calls, save all messages for
735 // later processing - we can't process them right now because it will
736 // lead to recursive library calls (and we're not reentrant)
737 //
738 if (!wxGuiOwnedByMainThread())
739 {
740 sbHadGuiLock = FALSE;
741
742 //
743 // Leave out WM_COMMAND messages: too dangerous, sometimes
744 // the message will be processed twice
745 //
746 if ( !wxIsWaitingForThread() ||
747 svCurrentMsg.msg != WM_COMMAND )
748 {
749 svSavedMessages.Add(svCurrentMsg);
750 }
751 return TRUE;
752 }
753 else
754 {
755 //
756 // Have we just regained the GUI lock? if so, post all of the saved
757 // messages
758 //
759 if (!sbHadGuiLock )
760 {
761 sbHadGuiLock = TRUE;
762
763 size_t nCount = svSavedMessages.Count();
764
765 for (size_t n = 0; n < nCount; n++)
766 {
767 QMSG vMsg = svSavedMessages[n];
768
769 DoMessage((WXMSG*)&vMsg);
770 }
771 svSavedMessages.Empty();
772 }
773 }
774 #endif // wxUSE_THREADS
775
776 //
777 // Process the message
778 //
779 DoMessage((WXMSG *)&svCurrentMsg);
780 }
781 return TRUE;
782 } // end of wxApp::DoMessage
783
784 void wxApp::DoMessage(
785 WXMSG* pMsg
786 )
787 {
788 if (!ProcessMessage((WXMSG *)&svCurrentMsg))
789 {
790 ::WinDispatchMsg(vHabmain, (PQMSG)&svCurrentMsg);
791 }
792 } // end of wxApp::DoMessage
793
794 //////////////////////////////////////////////////////////////////////////////
795 //
796 // Keep trying to process messages until WM_QUIT
797 // received.
798 //
799 // If there are messages to be processed, they will all be
800 // processed and OnIdle will not be called.
801 // When there are no more messages, OnIdle is called.
802 // If OnIdle requests more time,
803 // it will be repeatedly called so long as there are no pending messages.
804 // A 'feature' of this is that once OnIdle has decided that no more processing
805 // is required, then it won't get processing time until further messages
806 // are processed (it'll sit in DoMessage).
807 //
808 //////////////////////////////////////////////////////////////////////////////
809 int wxApp::MainLoop()
810 {
811 m_bKeepGoing = TRUE;
812
813 while (m_bKeepGoing)
814 {
815 #if wxUSE_THREADS
816 wxMutexGuiLeaveOrEnter();
817 #endif // wxUSE_THREADS
818 while (!Pending() && ProcessIdle())
819 {
820 HandleSockets();
821 wxUsleep(10000);
822 }
823 HandleSockets();
824 if (Pending())
825 DoMessage();
826 else
827 wxUsleep(10000);
828
829 }
830 return (int)svCurrentMsg.mp1;
831 } // end of wxApp::MainLoop
832
833 //
834 // Returns TRUE if more time is needed.
835 //
836 bool wxApp::ProcessIdle()
837 {
838 wxIdleEvent vEvent;
839
840 vEvent.SetEventObject(this);
841 ProcessEvent(vEvent);
842 return vEvent.MoreRequested();
843 } // end of wxApp::ProcessIdle
844
845 void wxApp::ExitMainLoop()
846 {
847 ::WinPostMsg(NULL, WM_QUIT, 0, 0);
848 } // end of wxApp::ExitMainLoop
849
850 bool wxApp::Pending()
851 {
852 return (::WinPeekMsg(vHabmain, (PQMSG)&svCurrentMsg, (HWND)NULL, 0, 0, PM_NOREMOVE) != 0);
853 } // end of wxApp::Pending
854
855 void wxApp::Dispatch()
856 {
857 DoMessage();
858 }
859
860 //////////////////////////////////////////////////////////////////////////////
861 //
862 // Give all windows a chance to preprocess
863 // the message. Some may have accelerator tables, or have
864 // MDI complications.
865 //
866 //////////////////////////////////////////////////////////////////////////////
867 bool wxApp::ProcessMessage(
868 WXMSG* pWxmsg
869 )
870 {
871 QMSG* pMsg = (PQMSG)pWxmsg;
872 HWND hWnd = pMsg->hwnd;
873 wxWindow* pWndThis = wxFindWinFromHandle((WXHWND)hWnd);
874 wxWindow* pWnd;
875
876 //
877 // Pass non-system timer messages to the wxTimerProc
878 //
879 if (pMsg->msg == WM_TIMER &&
880 (SHORT1FROMMP(pMsg->mp1) != TID_CURSOR &&
881 SHORT1FROMMP(pMsg->mp1) != TID_FLASHWINDOW &&
882 SHORT1FROMMP(pMsg->mp1) != TID_SCROLL &&
883 SHORT1FROMMP(pMsg->mp1) != 0x0000
884 ))
885 wxTimerProc(NULL, 0, (int)pMsg->mp1, 0);
886
887 //
888 // Allow the window to prevent certain messages from being
889 // translated/processed (this is currently used by wxTextCtrl to always
890 // grab Ctrl-C/V/X, even if they are also accelerators in some parent)
891 //
892 if (pWndThis && !pWndThis->OS2ShouldPreProcessMessage(pWxmsg))
893 {
894 return FALSE;
895 }
896
897 //
898 // For some composite controls (like a combobox), wndThis might be NULL
899 // because the subcontrol is not a wxWindow, but only the control itself
900 // is - try to catch this case
901 //
902 while (hWnd && !pWndThis)
903 {
904 hWnd = ::WinQueryWindow(hWnd, QW_PARENT);
905 pWndThis = wxFindWinFromHandle((WXHWND)hWnd);
906 }
907
908 //
909 // Try translations first; find the youngest window with
910 // a translation table. OS/2 has case sensative accels, so
911 // this block, coded by BK, removes that and helps make them
912 // case insensative.
913 //
914 if(pMsg->msg == WM_CHAR)
915 {
916 PBYTE pChmsg = (PBYTE)&(pMsg->msg);
917 USHORT uSch = CHARMSG(pChmsg)->chr;
918 bool bRc;
919
920 //
921 // Do not process keyup events
922 //
923 if(!(CHARMSG(pChmsg)->fs & KC_KEYUP))
924 {
925 if((CHARMSG(pChmsg)->fs & (KC_ALT | KC_CTRL)) && CHARMSG(pChmsg)->chr != 0)
926 CHARMSG(pChmsg)->chr = (USHORT)wxToupper((UCHAR)uSch);
927
928
929 for(pWnd = pWndThis; pWnd; pWnd = pWnd->GetParent() )
930 {
931 if((bRc = pWnd->OS2TranslateMessage(pWxmsg)) == TRUE)
932 break;
933 }
934
935 if(!bRc) // untranslated, should restore original value
936 CHARMSG(pChmsg)->chr = uSch;
937 }
938 }
939 //
940 // Anyone for a non-translation message? Try youngest descendants first.
941 //
942 // for (pWnd = pWndThis; pWnd; pWnd = pWnd->GetParent())
943 // {
944 // if (pWnd->OS2ProcessMessage(pWxmsg))
945 // return TRUE;
946 // }
947 return FALSE;
948 } // end of wxApp::ProcessMessage
949
950 bool gbInOnIdle = FALSE;
951
952 void wxApp::OnIdle(
953 wxIdleEvent& rEvent
954 )
955 {
956
957 //
958 // Avoid recursion (via ProcessEvent default case)
959 //
960 if (gbInOnIdle)
961 return;
962
963 gbInOnIdle = TRUE;
964
965 //
966 // If there are pending events, we must process them: pending events
967 // are either events to the threads other than main or events posted
968 // with wxPostEvent() functions
969 //
970 ProcessPendingEvents();
971
972 //
973 // 'Garbage' collection of windows deleted with Close().
974 //
975 DeletePendingObjects();
976
977 #if wxUSE_LOG
978 //
979 // Flush the logged messages if any
980 //
981 wxLog::FlushActive();
982 #endif // wxUSE_LOG
983
984 #if wxUSE_DC_CACHEING
985 // automated DC cache management: clear the cached DCs and bitmap
986 // if it's likely that the app has finished with them, that is, we
987 // get an idle event and we're not dragging anything.
988 if (!::WinGetKeyState(HWND_DESKTOP, VK_BUTTON1) &&
989 !::WinGetKeyState(HWND_DESKTOP, VK_BUTTON3) &&
990 !::WinGetKeyState(HWND_DESKTOP, VK_BUTTON2))
991 wxDC::ClearCache();
992 #endif // wxUSE_DC_CACHEING
993
994 //
995 // Send OnIdle events to all windows
996 //
997 if (SendIdleEvents())
998 {
999 //
1000 // SendIdleEvents() returns TRUE if at least one window requested more
1001 // idle events
1002 //
1003 rEvent.RequestMore(TRUE);
1004 }
1005 gbInOnIdle = FALSE;
1006 } // end of wxApp::OnIdle
1007
1008 // Send idle event to all top-level windows
1009 bool wxApp::SendIdleEvents()
1010 {
1011 bool bNeedMore = FALSE;
1012 wxWindowList::Node* pNode = wxTopLevelWindows.GetFirst();
1013
1014 while (pNode)
1015 {
1016 wxWindow* pWin = pNode->GetData();
1017
1018 if (SendIdleEvents(pWin))
1019 bNeedMore = TRUE;
1020 pNode = pNode->GetNext();
1021 }
1022 return bNeedMore;
1023 } // end of wxApp::SendIdleEvents
1024
1025 //
1026 // Send idle event to window and all subwindows
1027 //
1028 bool wxApp::SendIdleEvents(
1029 wxWindow* pWin
1030 )
1031 {
1032 bool bNeedMore = FALSE;
1033 wxIdleEvent vEvent;
1034
1035 vEvent.SetEventObject(pWin);
1036 pWin->GetEventHandler()->ProcessEvent(vEvent);
1037
1038 if (vEvent.MoreRequested())
1039 bNeedMore = TRUE;
1040
1041 wxNode* pNode = pWin->GetChildren().First();
1042
1043 while (pNode)
1044 {
1045 wxWindow* pWin = (wxWindow*) pNode->Data();
1046
1047 if (SendIdleEvents(pWin))
1048 bNeedMore = TRUE;
1049 pNode = pNode->Next();
1050 }
1051 return bNeedMore;
1052 } // end of wxApp::SendIdleEvents
1053
1054 void wxApp::DeletePendingObjects()
1055 {
1056 wxNode* pNode = wxPendingDelete.First();
1057
1058 while (pNode)
1059 {
1060 wxObject* pObj = (wxObject *)pNode->Data();
1061
1062 delete pObj;
1063
1064 if (wxPendingDelete.Member(pObj))
1065 delete pNode;
1066
1067 //
1068 // Deleting one object may have deleted other pending
1069 // objects, so start from beginning of list again.
1070 //
1071 pNode = wxPendingDelete.First();
1072 }
1073 } // end of wxApp::DeletePendingObjects
1074
1075 void wxApp::OnEndSession(
1076 wxCloseEvent& WXUNUSED(rEvent))
1077 {
1078 if (GetTopWindow())
1079 GetTopWindow()->Close(TRUE);
1080 } // end of wxApp::OnEndSession
1081
1082 //
1083 // Default behaviour: close the application with prompts. The
1084 // user can veto the close, and therefore the end session.
1085 //
1086 void wxApp::OnQueryEndSession(
1087 wxCloseEvent& rEvent
1088 )
1089 {
1090 if (GetTopWindow())
1091 {
1092 if (!GetTopWindow()->Close(!rEvent.CanVeto()))
1093 rEvent.Veto(TRUE);
1094 }
1095 } // end of wxApp::OnQueryEndSession
1096
1097 void wxApp::Exit()
1098 {
1099 wxApp::CleanUp();
1100
1101 // VZ: must really exit somehow, insert appropriate OS/2 syscall (FIXME)
1102 wxAppConsole::Exit();
1103 } // end of wxExit
1104
1105 //
1106 // Yield to incoming messages
1107 //
1108 bool wxApp::Yield(bool onlyIfNeeded)
1109 {
1110 static bool s_inYield = FALSE;
1111
1112 if ( s_inYield )
1113 {
1114 if ( !onlyIfNeeded )
1115 {
1116 wxFAIL_MSG( _T("wxYield() called recursively") );
1117 }
1118
1119 return FALSE;
1120 }
1121
1122 HAB vHab = 0;
1123 QMSG vMsg;
1124
1125 //
1126 // Disable log flushing from here because a call to wxYield() shouldn't
1127 // normally result in message boxes popping up &c
1128 //
1129 wxLog::Suspend();
1130
1131 s_inYield = TRUE;
1132
1133 //
1134 // We want to go back to the main message loop
1135 // if we see a WM_QUIT. (?)
1136 //
1137 while (::WinPeekMsg(vHab, &vMsg, (HWND)NULL, 0, 0, PM_NOREMOVE) && vMsg.msg != WM_QUIT)
1138 {
1139 #if wxUSE_THREADS
1140 wxMutexGuiLeaveOrEnter();
1141 #endif // wxUSE_THREADS
1142 if (!wxTheApp->DoMessage())
1143 break;
1144 }
1145 //
1146 // If they are pending events, we must process them.
1147 //
1148 if (wxTheApp)
1149 wxTheApp->ProcessPendingEvents();
1150
1151 //
1152 // Let the logs be flashed again
1153 //
1154 wxLog::Resume();
1155 s_inYield = FALSE;
1156 return TRUE;
1157 } // end of wxYield
1158
1159 int wxApp::AddSocketHandler(int handle, int mask,
1160 void (*callback)(void*), void * gsock)
1161 {
1162 int find;
1163 struct GsocketCallbackInfo
1164 *CallbackInfo = (struct GsocketCallbackInfo *)m_sockCallbackInfo;
1165
1166 for (find = 0; find < m_maxSocketHandles; find++)
1167 if (CallbackInfo[find].handle == -1)
1168 break;
1169 if (find == m_maxSocketHandles)
1170 {
1171 // Allocate new memory
1172 m_sockCallbackInfo = realloc(m_sockCallbackInfo,
1173 (m_maxSocketHandles+=10)*
1174 sizeof(struct GsocketCallbackInfo));
1175 CallbackInfo = (struct GsocketCallbackInfo *)m_sockCallbackInfo;
1176 for (find = m_maxSocketHandles - 10; find < m_maxSocketHandles; find++)
1177 CallbackInfo[find].handle = -1;
1178 find = m_maxSocketHandles - 10;
1179 }
1180 CallbackInfo[find].proc = callback;
1181 CallbackInfo[find].type = mask;
1182 CallbackInfo[find].handle = handle;
1183 CallbackInfo[find].gsock = gsock;
1184 if (mask & wxSockReadMask)
1185 FD_SET(handle, &m_readfds);
1186 if (mask & wxSockWriteMask)
1187 FD_SET(handle, &m_writefds);
1188 if (handle >= m_maxSocketNr)
1189 m_maxSocketNr = handle + 1;
1190 return find;
1191 }
1192
1193 void wxApp::RemoveSocketHandler(int handle)
1194 {
1195 struct GsocketCallbackInfo
1196 *CallbackInfo = (struct GsocketCallbackInfo *)m_sockCallbackInfo;
1197 if (handle < m_maxSocketHandles)
1198 {
1199 if (CallbackInfo[handle].type & wxSockReadMask)
1200 FD_CLR(CallbackInfo[handle].handle, &m_readfds);
1201 if (CallbackInfo[handle].type & wxSockWriteMask)
1202 FD_CLR(CallbackInfo[handle].handle, &m_writefds);
1203 CallbackInfo[handle].handle = -1;
1204 }
1205 }
1206
1207 //-----------------------------------------------------------------------------
1208 // wxWakeUpIdle
1209 //-----------------------------------------------------------------------------
1210
1211 void wxApp::WakeUpIdle()
1212 {
1213 //
1214 // Send the top window a dummy message so idle handler processing will
1215 // start up again. Doing it this way ensures that the idle handler
1216 // wakes up in the right thread (see also wxWakeUpMainThread() which does
1217 // the same for the main app thread only)
1218 //
1219 wxWindow* pTopWindow = wxTheApp->GetTopWindow();
1220
1221 if (pTopWindow)
1222 {
1223 if ( !::WinPostMsg(GetHwndOf(pTopWindow), WM_NULL, (MPARAM)0, (MPARAM)0))
1224 {
1225 //
1226 // Should never happen
1227 //
1228 wxLogLastError("PostMessage(WM_NULL)");
1229 }
1230 }
1231 } // end of wxWakeUpIdle
1232
1233 HAB wxGetInstance()
1234 {
1235 return vHabmain;
1236 }
1237
1238 void wxSetInstance(
1239 HAB vHab
1240 )
1241 {
1242 vHabmain = vHab;
1243 }
1244