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