extracted common initialization/cleanup functions in common/init.cpp; standardized...
[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(int argc, wxChar **argv)
230 {
231 if ( !wxAppBase::Initialize(argc, argv) )
232 return false;
233
234 #if defined(wxUSE_CONSOLEDEBUG)
235 #if wxUSE_CONSOLEDEBUG
236 /***********************************************/
237 /* Code for using stdout debug */
238 /* To use it you mast link app as "Window" - EK*/
239 /***********************************************/
240 {
241 PPIB pib;
242 PTIB tib;
243
244 printf("In console\n");
245
246 DosGetInfoBlocks(&tib, &pib);
247 /* Try morphing into a PM application. */
248 // if(pib->pib_ultype == 2) /* VIO */
249 pib->pib_ultype = 3;
250 }
251 /**********************************************/
252 /**********************************************/
253 #endif //wxUSE_CONSOLEDEBUG
254 #endif
255
256 //
257 // OS2 has to have an anchorblock
258 //
259 vHabmain = WinInitialize(0);
260
261 if (!vHabmain)
262 {
263 // TODO: at least give some error message here...
264 wxAppBase::CleanUp();
265
266 return FALSE;
267 }
268
269 wxBuffer = new wxChar[1500]; // FIXME; why?
270
271 // Some people may wish to use this, but
272 // probably it shouldn't be here by default.
273 #ifdef __WXDEBUG__
274 // wxRedirectIOToConsole();
275 #endif
276
277 wxWinHandleList = new wxList(wxKEY_INTEGER);
278
279 // This is to foil optimizations in Visual C++ that throw out dummy.obj.
280 // PLEASE DO NOT ALTER THIS.
281 #if !defined(WXMAKINGDLL) && defined(__VISAGECPP__)
282 extern char wxDummyChar;
283 if (wxDummyChar) wxDummyChar++;
284 #endif
285
286 // wxSetKeyboardHook(TRUE);
287
288 RegisterWindowClasses(vHab);
289
290 return TRUE;
291 } // end of wxApp::Initialize
292
293 const char* CANTREGISTERCLASS = " Can't register Class ";
294 // ---------------------------------------------------------------------------
295 // RegisterWindowClasses
296 // ---------------------------------------------------------------------------
297
298 bool wxApp::RegisterWindowClasses(
299 HAB vHab
300 )
301 {
302 ERRORID vError = 0L;
303 wxString sError;
304
305 if (!::WinRegisterClass( vHab
306 ,wxFrameClassName
307 ,wxFrameWndProc
308 ,CS_SIZEREDRAW | CS_SYNCPAINT
309 ,sizeof(ULONG)
310 ))
311 {
312 vError = ::WinGetLastError(vHab);
313 sError = wxPMErrorToStr(vError);
314 wxLogLastError(sError);
315 return FALSE;
316 }
317
318 if (!::WinRegisterClass( vHab
319 ,wxFrameClassNameNoRedraw
320 ,wxWndProc
321 ,0
322 ,sizeof(ULONG)
323 ))
324 {
325 vError = ::WinGetLastError(vHab);
326 sError = wxPMErrorToStr(vError);
327 wxLogLastError(sError);
328 return FALSE;
329 }
330
331 if (!::WinRegisterClass( vHab
332 ,wxMDIFrameClassName
333 ,wxWndProc
334 ,CS_SIZEREDRAW | CS_MOVENOTIFY | CS_SYNCPAINT
335 ,sizeof(ULONG)
336 ))
337 {
338 vError = ::WinGetLastError(vHab);
339 sError = wxPMErrorToStr(vError);
340 wxLogLastError(sError);
341 return FALSE;
342 }
343
344 if (!::WinRegisterClass( vHab
345 ,wxMDIFrameClassNameNoRedraw
346 ,wxWndProc
347 ,0
348 ,sizeof(ULONG)
349 ))
350 {
351 vError = ::WinGetLastError(vHab);
352 sError = wxPMErrorToStr(vError);
353 wxLogLastError(sError);
354 return FALSE;
355 }
356
357 if (!::WinRegisterClass( vHab
358 ,wxMDIChildFrameClassName
359 ,wxWndProc
360 ,CS_MOVENOTIFY | CS_SIZEREDRAW | CS_SYNCPAINT | CS_HITTEST
361 ,sizeof(ULONG)
362 ))
363 {
364 vError = ::WinGetLastError(vHab);
365 sError = wxPMErrorToStr(vError);
366 wxLogLastError(sError);
367 return FALSE;
368 }
369
370 if (!::WinRegisterClass( vHab
371 ,wxMDIChildFrameClassNameNoRedraw
372 ,wxWndProc
373 ,CS_HITTEST
374 ,sizeof(ULONG)
375 ))
376 {
377 vError = ::WinGetLastError(vHab);
378 sError = wxPMErrorToStr(vError);
379 wxLogLastError(sError);
380 return FALSE;
381 }
382
383 if (!::WinRegisterClass( vHab
384 ,wxPanelClassName
385 ,wxWndProc
386 ,CS_MOVENOTIFY | CS_SIZEREDRAW | CS_HITTEST | CS_SAVEBITS | CS_SYNCPAINT
387 ,sizeof(ULONG)
388 ))
389 {
390 vError = ::WinGetLastError(vHab);
391 sError = wxPMErrorToStr(vError);
392 wxLogLastError(sError);
393 return FALSE;
394 }
395
396 if (!::WinRegisterClass( vHab
397 ,wxCanvasClassName
398 ,wxWndProc
399 ,CS_SIZEREDRAW | CS_HITTEST | CS_SYNCPAINT
400 ,sizeof(ULONG)
401 ))
402 {
403 vError = ::WinGetLastError(vHab);
404 sError = wxPMErrorToStr(vError);
405 wxLogLastError(sError);
406 return FALSE;
407 }
408 if (!::WinRegisterClass( vHab
409 ,wxCanvasClassNameNR
410 ,wxWndProc
411 ,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 return TRUE;
421 } // end of wxApp::RegisterWindowClasses
422
423 //
424 // Cleans up any wxWindows internal structures left lying around
425 //
426 void wxApp::CleanUp()
427 {
428 delete[] wxBuffer;
429 wxBuffer = NULL;
430
431 //
432 // PM-SPECIFIC CLEANUP
433 //
434
435 // wxSetKeyboardHook(FALSE);
436
437 if (wxSTD_FRAME_ICON)
438 ::WinFreeFileIcon(wxSTD_FRAME_ICON);
439 if (wxSTD_MDICHILDFRAME_ICON)
440 ::WinFreeFileIcon(wxSTD_MDICHILDFRAME_ICON);
441 if (wxSTD_MDIPARENTFRAME_ICON)
442 ::WinFreeFileIcon(wxSTD_MDIPARENTFRAME_ICON);
443
444 if (wxDEFAULT_FRAME_ICON)
445 ::WinFreeFileIcon(wxDEFAULT_FRAME_ICON);
446 if (wxDEFAULT_MDICHILDFRAME_ICON)
447 ::WinFreeFileIcon(wxDEFAULT_MDICHILDFRAME_ICON);
448 if (wxDEFAULT_MDIPARENTFRAME_ICON)
449 ::WinFreeFileIcon(wxDEFAULT_MDIPARENTFRAME_ICON);
450
451 if ( wxDisableButtonBrush )
452 {
453 // TODO: ::DeleteObject( wxDisableButtonBrush );
454 }
455
456 if (wxWinHandleList)
457 delete wxWinHandleList;
458
459 delete wxPendingEvents;
460 #if wxUSE_THREADS
461 delete wxPendingEventsLocker;
462 // If we don't do the following, we get an apparent memory leak.
463 ((wxEvtHandler&) wxDefaultValidator).ClearEventLocker();
464 #endif
465
466 // Delete Message queue
467 if (wxTheApp->m_hMq)
468 ::WinDestroyMsgQueue(wxTheApp->m_hMq);
469
470 wxAppBase::CleanUp();
471 } // end of wxApp::CleanUp
472
473 //----------------------------------------------------------------------
474 // Main wxWindows entry point
475 //----------------------------------------------------------------------
476 int wxEntry(
477 int argc
478 , char* argv[]
479 )
480 {
481 HAB vHab = 0;
482
483 if (!wxApp::Initialize(vHab))
484 return 0;
485
486 //
487 // create the application object or ensure that one already exists
488 //
489 if (!wxTheApp)
490 {
491 // The app may have declared a global application object, but we recommend
492 // the IMPLEMENT_APP macro is used instead, which sets an initializer
493 // function for delayed, dynamic app object construction.
494 wxCHECK_MSG( wxApp::GetInitializerFunction(), 0,
495 wxT("No initializer - use IMPLEMENT_APP macro.") );
496 wxTheApp = (*wxApp::GetInitializerFunction()) ();
497 }
498 wxCHECK_MSG( wxTheApp, 0, wxT("You have to define an instance of wxApp!") );
499 wxTheApp->argc = argc;
500
501 #if wxUSE_UNICODE
502 wxTheApp->argv = new wxChar*[argc+1];
503
504 int nArgc = 0;
505
506 while (nArgc < argc)
507 {
508 wxTheApp->argv[nArgc] = wxStrdup(wxConvLibc.cMB2WX(argv[nArgc]));
509 nArgc++;
510 }
511 wxTheApp->argv[nArgc] = (wxChar *)NULL;
512 #else
513 wxTheApp->argv = argv;
514 #endif
515
516 wxString sName(wxFileNameFromPath(argv[0]));
517
518 wxStripExtension(sName);
519 wxTheApp->SetAppName(sName);
520
521 int nRetValue = 0;
522
523 if (!wxTheApp->OnInitGui())
524 nRetValue = -1;
525
526 if (nRetValue == 0)
527 {
528 if (wxTheApp->OnInit())
529 {
530 wxTheApp->OnRun();
531 }
532 // Normal exit
533 wxWindow* pTopWindow = wxTheApp->GetTopWindow();
534 if (pTopWindow)
535 {
536 // Forcibly delete the window.
537 if (pTopWindow->IsKindOf(CLASSINFO(wxFrame)) ||
538 pTopWindow->IsKindOf(CLASSINFO(wxDialog)) )
539 {
540 pTopWindow->Close(TRUE);
541 wxTheApp->DeletePendingObjects();
542 }
543 else
544 {
545 delete pTopWindow;
546 wxTheApp->SetTopWindow(NULL);
547 }
548 }
549 }
550 else // app initialization failed
551 {
552 wxLogLastError(" Gui initialization failed, exitting");
553 }
554 #if wxUSE_CONSOLEDEBUG
555 printf("wxTheApp->OnExit ");
556 fflush(stdout);
557 #endif
558 nRetValue = wxTheApp->OnExit();
559 #if wxUSE_CONSOLEDEBUG
560 printf("wxApp::CleanUp ");
561 fflush(stdout);
562 #endif
563 wxApp::CleanUp();
564 #if wxUSE_CONSOLEDEBUG
565 printf("return %i ", nRetValue);
566 fflush(stdout);
567 #endif
568 return(nRetValue);
569 } // end of wxEntry
570
571 bool wxApp::OnInitGui()
572 {
573 ERRORID vError;
574 wxString sError;
575
576 if (!wxAppBase::OnInitGui())
577 return FALSE;
578
579 m_hMq = ::WinCreateMsgQueue(vHabmain, 0);
580 if (!m_hMq)
581 {
582 vError = ::WinGetLastError(vHabmain);
583 sError = wxPMErrorToStr(vError);
584 wxLogDebug(sError);
585 return FALSE;
586 }
587
588 return TRUE;
589 } // end of wxApp::OnInitGui
590
591 wxApp::wxApp()
592 {
593 m_topWindow = NULL;
594 wxTheApp = this;
595
596 argc = 0;
597 argv = NULL;
598 m_nPrintMode = wxPRINT_WINDOWS;
599 m_bAuto3D = TRUE;
600 m_hMq = 0;
601 m_maxSocketHandles = 0;
602 m_maxSocketNr = 0;
603 m_sockCallbackInfo = 0;
604 } // end of wxApp::wxApp
605
606 wxApp::~wxApp()
607 {
608 //
609 // Delete command-line args
610 //
611 #if wxUSE_UNICODE
612 int i;
613
614 for (i = 0; i < argc; i++)
615 {
616 delete[] argv[i];
617 }
618 delete[] argv;
619 #endif
620 } // end of wxApp::~wxApp
621
622 bool wxApp::Initialized()
623 {
624 if (GetTopWindow())
625 return TRUE;
626 else
627 return FALSE;
628 } // end of wxApp::Initialized
629
630 //
631 // Get and process a message, returning FALSE if WM_QUIT
632 // received (and also set the flag telling the app to exit the main loop)
633 //
634
635 bool wxApp::DoMessage()
636 {
637 BOOL bRc = ::WinGetMsg(vHabmain, &svCurrentMsg, HWND(NULL), 0, 0);
638
639 if (bRc == 0)
640 {
641 // got WM_QUIT
642 m_bKeepGoing = FALSE;
643 return FALSE;
644 }
645 else if (bRc == -1)
646 {
647 // should never happen, but let's test for it nevertheless
648 wxLogLastError("GetMessage");
649 }
650 else
651 {
652 #if wxUSE_THREADS
653 wxASSERT_MSG( wxThread::IsMain()
654 ,wxT("only the main thread can process Windows messages")
655 );
656
657 static bool sbHadGuiLock = TRUE;
658 static wxMsgArray svSavedMessages;
659
660 //
661 // If a secondary thread owns is doing GUI calls, save all messages for
662 // later processing - we can't process them right now because it will
663 // lead to recursive library calls (and we're not reentrant)
664 //
665 if (!wxGuiOwnedByMainThread())
666 {
667 sbHadGuiLock = FALSE;
668
669 //
670 // Leave out WM_COMMAND messages: too dangerous, sometimes
671 // the message will be processed twice
672 //
673 if ( !wxIsWaitingForThread() ||
674 svCurrentMsg.msg != WM_COMMAND )
675 {
676 svSavedMessages.Add(svCurrentMsg);
677 }
678 return TRUE;
679 }
680 else
681 {
682 //
683 // Have we just regained the GUI lock? if so, post all of the saved
684 // messages
685 //
686 if (!sbHadGuiLock )
687 {
688 sbHadGuiLock = TRUE;
689
690 size_t nCount = svSavedMessages.Count();
691
692 for (size_t n = 0; n < nCount; n++)
693 {
694 QMSG vMsg = svSavedMessages[n];
695
696 DoMessage((WXMSG*)&vMsg);
697 }
698 svSavedMessages.Empty();
699 }
700 }
701 #endif // wxUSE_THREADS
702
703 //
704 // Process the message
705 //
706 DoMessage((WXMSG *)&svCurrentMsg);
707 }
708 return TRUE;
709 } // end of wxApp::DoMessage
710
711 void wxApp::DoMessage(
712 WXMSG* pMsg
713 )
714 {
715 if (!ProcessMessage((WXMSG *)&svCurrentMsg))
716 {
717 ::WinDispatchMsg(vHabmain, (PQMSG)&svCurrentMsg);
718 }
719 } // end of wxApp::DoMessage
720
721 //////////////////////////////////////////////////////////////////////////////
722 //
723 // Keep trying to process messages until WM_QUIT
724 // received.
725 //
726 // If there are messages to be processed, they will all be
727 // processed and OnIdle will not be called.
728 // When there are no more messages, OnIdle is called.
729 // If OnIdle requests more time,
730 // it will be repeatedly called so long as there are no pending messages.
731 // A 'feature' of this is that once OnIdle has decided that no more processing
732 // is required, then it won't get processing time until further messages
733 // are processed (it'll sit in DoMessage).
734 //
735 //////////////////////////////////////////////////////////////////////////////
736 int wxApp::MainLoop()
737 {
738 m_bKeepGoing = TRUE;
739
740 while (m_bKeepGoing)
741 {
742 #if wxUSE_THREADS
743 wxMutexGuiLeaveOrEnter();
744 #endif // wxUSE_THREADS
745 while (!Pending() && ProcessIdle())
746 {
747 HandleSockets();
748 wxUsleep(10000);
749 }
750 HandleSockets();
751 if (Pending())
752 DoMessage();
753 else
754 wxUsleep(10000);
755
756 }
757 return (int)svCurrentMsg.mp1;
758 } // end of wxApp::MainLoop
759
760 //
761 // Returns TRUE if more time is needed.
762 //
763 bool wxApp::ProcessIdle()
764 {
765 wxIdleEvent vEvent;
766
767 vEvent.SetEventObject(this);
768 ProcessEvent(vEvent);
769 return vEvent.MoreRequested();
770 } // end of wxApp::ProcessIdle
771
772 void wxApp::ExitMainLoop()
773 {
774 ::WinPostMsg(NULL, WM_QUIT, 0, 0);
775 } // end of wxApp::ExitMainLoop
776
777 bool wxApp::Pending()
778 {
779 return (::WinPeekMsg(vHabmain, (PQMSG)&svCurrentMsg, (HWND)NULL, 0, 0, PM_NOREMOVE) != 0);
780 } // end of wxApp::Pending
781
782 void wxApp::Dispatch()
783 {
784 DoMessage();
785 }
786
787 //////////////////////////////////////////////////////////////////////////////
788 //
789 // Give all windows a chance to preprocess
790 // the message. Some may have accelerator tables, or have
791 // MDI complications.
792 //
793 //////////////////////////////////////////////////////////////////////////////
794 bool wxApp::ProcessMessage(
795 WXMSG* pWxmsg
796 )
797 {
798 QMSG* pMsg = (PQMSG)pWxmsg;
799 HWND hWnd = pMsg->hwnd;
800 wxWindow* pWndThis = wxFindWinFromHandle((WXHWND)hWnd);
801 wxWindow* pWnd;
802
803 //
804 // Pass non-system timer messages to the wxTimerProc
805 //
806 if (pMsg->msg == WM_TIMER &&
807 (SHORT1FROMMP(pMsg->mp1) != TID_CURSOR &&
808 SHORT1FROMMP(pMsg->mp1) != TID_FLASHWINDOW &&
809 SHORT1FROMMP(pMsg->mp1) != TID_SCROLL &&
810 SHORT1FROMMP(pMsg->mp1) != 0x0000
811 ))
812 wxTimerProc(NULL, 0, (int)pMsg->mp1, 0);
813
814 //
815 // Allow the window to prevent certain messages from being
816 // translated/processed (this is currently used by wxTextCtrl to always
817 // grab Ctrl-C/V/X, even if they are also accelerators in some parent)
818 //
819 if (pWndThis && !pWndThis->OS2ShouldPreProcessMessage(pWxmsg))
820 {
821 return FALSE;
822 }
823
824 //
825 // For some composite controls (like a combobox), wndThis might be NULL
826 // because the subcontrol is not a wxWindow, but only the control itself
827 // is - try to catch this case
828 //
829 while (hWnd && !pWndThis)
830 {
831 hWnd = ::WinQueryWindow(hWnd, QW_PARENT);
832 pWndThis = wxFindWinFromHandle((WXHWND)hWnd);
833 }
834
835 //
836 // Try translations first; find the youngest window with
837 // a translation table. OS/2 has case sensative accels, so
838 // this block, coded by BK, removes that and helps make them
839 // case insensative.
840 //
841 if(pMsg->msg == WM_CHAR)
842 {
843 PBYTE pChmsg = (PBYTE)&(pMsg->msg);
844 USHORT uSch = CHARMSG(pChmsg)->chr;
845 bool bRc;
846
847 //
848 // Do not process keyup events
849 //
850 if(!(CHARMSG(pChmsg)->fs & KC_KEYUP))
851 {
852 if((CHARMSG(pChmsg)->fs & (KC_ALT | KC_CTRL)) && CHARMSG(pChmsg)->chr != 0)
853 CHARMSG(pChmsg)->chr = (USHORT)wxToupper((UCHAR)uSch);
854
855
856 for(pWnd = pWndThis; pWnd; pWnd = pWnd->GetParent() )
857 {
858 if((bRc = pWnd->OS2TranslateMessage(pWxmsg)) == TRUE)
859 break;
860 }
861
862 if(!bRc) // untranslated, should restore original value
863 CHARMSG(pChmsg)->chr = uSch;
864 }
865 }
866 //
867 // Anyone for a non-translation message? Try youngest descendants first.
868 //
869 // for (pWnd = pWndThis; pWnd; pWnd = pWnd->GetParent())
870 // {
871 // if (pWnd->OS2ProcessMessage(pWxmsg))
872 // return TRUE;
873 // }
874 return FALSE;
875 } // end of wxApp::ProcessMessage
876
877 bool gbInOnIdle = FALSE;
878
879 void wxApp::OnIdle(
880 wxIdleEvent& rEvent
881 )
882 {
883
884 //
885 // Avoid recursion (via ProcessEvent default case)
886 //
887 if (gbInOnIdle)
888 return;
889
890 gbInOnIdle = TRUE;
891
892 //
893 // If there are pending events, we must process them: pending events
894 // are either events to the threads other than main or events posted
895 // with wxPostEvent() functions
896 //
897 ProcessPendingEvents();
898
899 //
900 // 'Garbage' collection of windows deleted with Close().
901 //
902 DeletePendingObjects();
903
904 #if wxUSE_LOG
905 //
906 // Flush the logged messages if any
907 //
908 wxLog::FlushActive();
909 #endif // wxUSE_LOG
910
911 #if wxUSE_DC_CACHEING
912 // automated DC cache management: clear the cached DCs and bitmap
913 // if it's likely that the app has finished with them, that is, we
914 // get an idle event and we're not dragging anything.
915 if (!::WinGetKeyState(HWND_DESKTOP, VK_BUTTON1) &&
916 !::WinGetKeyState(HWND_DESKTOP, VK_BUTTON3) &&
917 !::WinGetKeyState(HWND_DESKTOP, VK_BUTTON2))
918 wxDC::ClearCache();
919 #endif // wxUSE_DC_CACHEING
920
921 //
922 // Send OnIdle events to all windows
923 //
924 if (SendIdleEvents())
925 {
926 //
927 // SendIdleEvents() returns TRUE if at least one window requested more
928 // idle events
929 //
930 rEvent.RequestMore(TRUE);
931 }
932 gbInOnIdle = FALSE;
933 } // end of wxApp::OnIdle
934
935 // Send idle event to all top-level windows
936 bool wxApp::SendIdleEvents()
937 {
938 bool bNeedMore = FALSE;
939 wxWindowList::Node* pNode = wxTopLevelWindows.GetFirst();
940
941 while (pNode)
942 {
943 wxWindow* pWin = pNode->GetData();
944
945 if (SendIdleEvents(pWin))
946 bNeedMore = TRUE;
947 pNode = pNode->GetNext();
948 }
949 return bNeedMore;
950 } // end of wxApp::SendIdleEvents
951
952 //
953 // Send idle event to window and all subwindows
954 //
955 bool wxApp::SendIdleEvents(
956 wxWindow* pWin
957 )
958 {
959 bool bNeedMore = FALSE;
960 wxIdleEvent vEvent;
961
962 vEvent.SetEventObject(pWin);
963 pWin->GetEventHandler()->ProcessEvent(vEvent);
964
965 if (vEvent.MoreRequested())
966 bNeedMore = TRUE;
967
968 wxNode* pNode = pWin->GetChildren().First();
969
970 while (pNode)
971 {
972 wxWindow* pWin = (wxWindow*) pNode->Data();
973
974 if (SendIdleEvents(pWin))
975 bNeedMore = TRUE;
976 pNode = pNode->Next();
977 }
978 return bNeedMore;
979 } // end of wxApp::SendIdleEvents
980
981 void wxApp::OnEndSession(
982 wxCloseEvent& WXUNUSED(rEvent))
983 {
984 if (GetTopWindow())
985 GetTopWindow()->Close(TRUE);
986 } // end of wxApp::OnEndSession
987
988 //
989 // Default behaviour: close the application with prompts. The
990 // user can veto the close, and therefore the end session.
991 //
992 void wxApp::OnQueryEndSession(
993 wxCloseEvent& rEvent
994 )
995 {
996 if (GetTopWindow())
997 {
998 if (!GetTopWindow()->Close(!rEvent.CanVeto()))
999 rEvent.Veto(TRUE);
1000 }
1001 } // end of wxApp::OnQueryEndSession
1002
1003 void wxApp::Exit()
1004 {
1005 wxApp::CleanUp();
1006
1007 // VZ: must really exit somehow, insert appropriate OS/2 syscall (FIXME)
1008 wxAppConsole::Exit();
1009 } // end of wxExit
1010
1011 //
1012 // Yield to incoming messages
1013 //
1014 bool wxApp::Yield(bool onlyIfNeeded)
1015 {
1016 static bool s_inYield = FALSE;
1017
1018 if ( s_inYield )
1019 {
1020 if ( !onlyIfNeeded )
1021 {
1022 wxFAIL_MSG( _T("wxYield() called recursively") );
1023 }
1024
1025 return FALSE;
1026 }
1027
1028 HAB vHab = 0;
1029 QMSG vMsg;
1030
1031 //
1032 // Disable log flushing from here because a call to wxYield() shouldn't
1033 // normally result in message boxes popping up &c
1034 //
1035 wxLog::Suspend();
1036
1037 s_inYield = TRUE;
1038
1039 //
1040 // We want to go back to the main message loop
1041 // if we see a WM_QUIT. (?)
1042 //
1043 while (::WinPeekMsg(vHab, &vMsg, (HWND)NULL, 0, 0, PM_NOREMOVE) && vMsg.msg != WM_QUIT)
1044 {
1045 #if wxUSE_THREADS
1046 wxMutexGuiLeaveOrEnter();
1047 #endif // wxUSE_THREADS
1048 if (!wxTheApp->DoMessage())
1049 break;
1050 }
1051 //
1052 // If they are pending events, we must process them.
1053 //
1054 if (wxTheApp)
1055 wxTheApp->ProcessPendingEvents();
1056
1057 //
1058 // Let the logs be flashed again
1059 //
1060 wxLog::Resume();
1061 s_inYield = FALSE;
1062 return TRUE;
1063 } // end of wxYield
1064
1065 int wxApp::AddSocketHandler(int handle, int mask,
1066 void (*callback)(void*), void * gsock)
1067 {
1068 int find;
1069 struct GsocketCallbackInfo
1070 *CallbackInfo = (struct GsocketCallbackInfo *)m_sockCallbackInfo;
1071
1072 for (find = 0; find < m_maxSocketHandles; find++)
1073 if (CallbackInfo[find].handle == -1)
1074 break;
1075 if (find == m_maxSocketHandles)
1076 {
1077 // Allocate new memory
1078 m_sockCallbackInfo = realloc(m_sockCallbackInfo,
1079 (m_maxSocketHandles+=10)*
1080 sizeof(struct GsocketCallbackInfo));
1081 CallbackInfo = (struct GsocketCallbackInfo *)m_sockCallbackInfo;
1082 for (find = m_maxSocketHandles - 10; find < m_maxSocketHandles; find++)
1083 CallbackInfo[find].handle = -1;
1084 find = m_maxSocketHandles - 10;
1085 }
1086 CallbackInfo[find].proc = callback;
1087 CallbackInfo[find].type = mask;
1088 CallbackInfo[find].handle = handle;
1089 CallbackInfo[find].gsock = gsock;
1090 if (mask & wxSockReadMask)
1091 FD_SET(handle, &m_readfds);
1092 if (mask & wxSockWriteMask)
1093 FD_SET(handle, &m_writefds);
1094 if (handle >= m_maxSocketNr)
1095 m_maxSocketNr = handle + 1;
1096 return find;
1097 }
1098
1099 void wxApp::RemoveSocketHandler(int handle)
1100 {
1101 struct GsocketCallbackInfo
1102 *CallbackInfo = (struct GsocketCallbackInfo *)m_sockCallbackInfo;
1103 if (handle < m_maxSocketHandles)
1104 {
1105 if (CallbackInfo[handle].type & wxSockReadMask)
1106 FD_CLR(CallbackInfo[handle].handle, &m_readfds);
1107 if (CallbackInfo[handle].type & wxSockWriteMask)
1108 FD_CLR(CallbackInfo[handle].handle, &m_writefds);
1109 CallbackInfo[handle].handle = -1;
1110 }
1111 }
1112
1113 //-----------------------------------------------------------------------------
1114 // wxWakeUpIdle
1115 //-----------------------------------------------------------------------------
1116
1117 void wxApp::WakeUpIdle()
1118 {
1119 //
1120 // Send the top window a dummy message so idle handler processing will
1121 // start up again. Doing it this way ensures that the idle handler
1122 // wakes up in the right thread (see also wxWakeUpMainThread() which does
1123 // the same for the main app thread only)
1124 //
1125 wxWindow* pTopWindow = wxTheApp->GetTopWindow();
1126
1127 if (pTopWindow)
1128 {
1129 if ( !::WinPostMsg(GetHwndOf(pTopWindow), WM_NULL, (MPARAM)0, (MPARAM)0))
1130 {
1131 //
1132 // Should never happen
1133 //
1134 wxLogLastError("PostMessage(WM_NULL)");
1135 }
1136 }
1137 } // end of wxWakeUpIdle
1138
1139 HAB wxGetInstance()
1140 {
1141 return vHabmain;
1142 }
1143
1144 void wxSetInstance(
1145 HAB vHab
1146 )
1147 {
1148 vHabmain = vHab;
1149 }
1150