Switched over to using wxEventLoop.
[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 #endif
37
38 #include "wx/log.h"
39 #include "wx/module.h"
40
41 #include "wx/os2/private.h"
42
43 #ifdef __EMX__
44
45 #include <sys/ioctl.h>
46 #include <sys/select.h>
47
48 #else
49
50 #include <nerrno.h>
51 #include <sys/ioctl.h>
52 #include <sys/select.h>
53 #include <sys/time.h>
54
55 #endif //
56
57 #ifndef __EMX__
58
59 #define select(a,b,c,d,e) bsdselect(a,b,c,d,e)
60 extern "C" int _System bsdselect(int,
61 struct fd_set *,
62 struct fd_set *,
63 struct fd_set *,
64 struct timeval *);
65 #endif
66
67 #if wxUSE_THREADS
68 #include "wx/thread.h"
69 #endif // wxUSE_THREADS
70
71 #if wxUSE_TOOLTIPS
72 #include "wx/tooltip.h"
73 #endif // wxUSE_TOOLTIPS
74
75 #include <string.h>
76 #include <ctype.h>
77
78 // ---------------------------------------------------------------------------
79 // global variables
80 // ---------------------------------------------------------------------------
81
82 extern wxChar* wxBuffer;
83 extern wxList* wxWinHandleList;
84 extern wxList WXDLLEXPORT wxPendingDelete;
85 extern wxCursor* g_globalCursor;
86
87 HAB vHabmain = NULLHANDLE;
88
89
90 HICON wxSTD_FRAME_ICON = (HICON) NULL;
91 HICON wxSTD_MDICHILDFRAME_ICON = (HICON) NULL;
92 HICON wxSTD_MDIPARENTFRAME_ICON = (HICON) NULL;
93
94 HICON wxDEFAULT_FRAME_ICON = (HICON) NULL;
95 HICON wxDEFAULT_MDICHILDFRAME_ICON = (HICON) NULL;
96 HICON wxDEFAULT_MDIPARENTFRAME_ICON = (HICON) NULL;
97
98 HBRUSH wxDisableButtonBrush = (HBRUSH) 0;
99
100 MRESULT EXPENTRY wxWndProc( HWND hWnd,ULONG message,MPARAM mp1,MPARAM mp2);
101 MRESULT EXPENTRY wxFrameWndProc( HWND hWnd,ULONG message,MPARAM mp1,MPARAM mp2);
102
103 // ===========================================================================
104 // implementation
105 // ===========================================================================
106
107 // ---------------------------------------------------------------------------
108 // helper struct and functions for socket handling
109 // ---------------------------------------------------------------------------
110
111 struct GsocketCallbackInfo{
112 void (*proc)(void *);
113 int type;
114 int handle;
115 void* gsock;
116 };
117
118 // These defines and wrapper functions are used here and in gsockpm.c
119 #define wxSockReadMask 0x01
120 #define wxSockWriteMask 0x02
121
122 #ifdef __EMX__
123 extern "C"
124 int wxAppAddSocketHandler(int handle, int mask,
125 void (*callback)(void*), void * gsock)
126 {
127 return wxTheApp->AddSocketHandler(handle, mask, callback, gsock);
128 }
129 extern "C"
130 void wxAppRemoveSocketHandler(int handle)
131 {
132 wxTheApp->RemoveSocketHandler(handle);
133 }
134 #else
135 // Linkage mode problems using callbacks with extern C in a .cpp module
136 int wxAppAddSocketHandler(int handle, int mask,
137 void (*callback)(void*), void * gsock)
138 {
139 return wxTheApp->AddSocketHandler(handle, mask, callback, gsock);
140 }
141 void wxAppRemoveSocketHandler(int handle)
142 {
143 wxTheApp->RemoveSocketHandler(handle);
144 }
145 #endif
146
147 void wxApp::HandleSockets()
148 {
149 bool pendingEvent = FALSE;
150
151 // Check whether it's time for Gsocket operation
152 if (m_maxSocketHandles > 0 && m_maxSocketNr > 0)
153 {
154 fd_set readfds = m_readfds;
155 fd_set writefds = m_writefds;
156 struct timeval timeout;
157 int i;
158 struct GsocketCallbackInfo
159 *CallbackInfo = (struct GsocketCallbackInfo *)m_sockCallbackInfo;
160 timeout.tv_sec = 0;
161 timeout.tv_usec = 0;
162 if ( select(m_maxSocketNr, &readfds, &writefds, 0, &timeout) > 0)
163 {
164 for (i = m_lastUsedHandle + 1; i != m_lastUsedHandle;
165 (i < m_maxSocketNr - 1) ? i++ : (i = 0))
166 {
167 if (FD_ISSET(i, &readfds))
168 {
169 int r;
170 for (r = 0; r < m_maxSocketHandles; r++){
171 if(CallbackInfo[r].handle == i &&
172 CallbackInfo[r].type == wxSockReadMask)
173 break;
174 }
175 if (r < m_maxSocketHandles)
176 {
177 CallbackInfo[r].proc(CallbackInfo[r].gsock);
178 pendingEvent = TRUE;
179 }
180 }
181 if (FD_ISSET(i, &writefds))
182 {
183 int r;
184 for (r = 0; r < m_maxSocketHandles; r++)
185 if(CallbackInfo[r].handle == i &&
186 CallbackInfo[r].type == wxSockWriteMask)
187 break;
188 if (r < m_maxSocketHandles)
189 {
190 CallbackInfo[r].proc(CallbackInfo[r].gsock);
191 pendingEvent = TRUE;
192 }
193 }
194 }
195 m_lastUsedHandle = i;
196 }
197 if (pendingEvent)
198 ProcessPendingEvents();
199 }
200 }
201 // ---------------------------------------------------------------------------
202 // wxApp
203 // ---------------------------------------------------------------------------
204
205 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
206
207 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
208 EVT_IDLE(wxApp::OnIdle)
209 EVT_END_SESSION(wxApp::OnEndSession)
210 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
211 END_EVENT_TABLE()
212
213 //
214 // Initialize
215 //
216 bool wxApp::Initialize(int& argc, wxChar **argv)
217 {
218 if ( !wxAppBase::Initialize(argc, argv) )
219 return false;
220
221 #if defined(wxUSE_CONSOLEDEBUG)
222 #if wxUSE_CONSOLEDEBUG
223 /***********************************************/
224 /* Code for using stdout debug */
225 /* To use it you mast link app as "Window" - EK*/
226 /***********************************************/
227 {
228 PPIB pib;
229 PTIB tib;
230
231 printf("In console\n");
232
233 DosGetInfoBlocks(&tib, &pib);
234 /* Try morphing into a PM application. */
235 // if(pib->pib_ultype == 2) /* VIO */
236 pib->pib_ultype = 3;
237 }
238 /**********************************************/
239 /**********************************************/
240 #endif //wxUSE_CONSOLEDEBUG
241 #endif
242
243 //
244 // OS2 has to have an anchorblock
245 //
246 vHabmain = WinInitialize(0);
247
248 if (!vHabmain)
249 {
250 // TODO: at least give some error message here...
251 wxAppBase::CleanUp();
252
253 return FALSE;
254 }
255
256 wxBuffer = new wxChar[1500]; // FIXME; why?
257
258 // Some people may wish to use this, but
259 // probably it shouldn't be here by default.
260 #ifdef __WXDEBUG__
261 // wxRedirectIOToConsole();
262 #endif
263
264 wxWinHandleList = new wxList(wxKEY_INTEGER);
265
266 // This is to foil optimizations in Visual C++ that throw out dummy.obj.
267 // PLEASE DO NOT ALTER THIS.
268 #if !defined(WXMAKINGDLL) && defined(__VISAGECPP__)
269 extern char wxDummyChar;
270 if (wxDummyChar) wxDummyChar++;
271 #endif
272
273 // wxSetKeyboardHook(TRUE);
274
275 RegisterWindowClasses(vHabmain);
276
277 return TRUE;
278 } // end of wxApp::Initialize
279
280 const char* CANTREGISTERCLASS = " Can't register Class ";
281 // ---------------------------------------------------------------------------
282 // RegisterWindowClasses
283 // ---------------------------------------------------------------------------
284
285 bool wxApp::RegisterWindowClasses(
286 HAB vHab
287 )
288 {
289 ERRORID vError = 0L;
290 wxString sError;
291
292 if (!::WinRegisterClass( vHab
293 ,wxFrameClassName
294 ,wxFrameWndProc
295 ,CS_SIZEREDRAW | CS_SYNCPAINT
296 ,sizeof(ULONG)
297 ))
298 {
299 vError = ::WinGetLastError(vHab);
300 sError = wxPMErrorToStr(vError);
301 wxLogLastError(sError);
302 return FALSE;
303 }
304
305 if (!::WinRegisterClass( vHab
306 ,wxFrameClassNameNoRedraw
307 ,wxWndProc
308 ,0
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 ,wxMDIFrameClassName
320 ,wxWndProc
321 ,CS_SIZEREDRAW | CS_MOVENOTIFY | CS_SYNCPAINT
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 ,wxMDIFrameClassNameNoRedraw
333 ,wxWndProc
334 ,0
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 ,wxMDIChildFrameClassName
346 ,wxWndProc
347 ,CS_MOVENOTIFY | CS_SIZEREDRAW | CS_SYNCPAINT | CS_HITTEST
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 ,wxMDIChildFrameClassNameNoRedraw
359 ,wxWndProc
360 ,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 ,wxPanelClassName
372 ,wxWndProc
373 ,CS_MOVENOTIFY | CS_SIZEREDRAW | CS_HITTEST | CS_SAVEBITS | CS_SYNCPAINT
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 ,wxCanvasClassName
385 ,wxWndProc
386 ,CS_SIZEREDRAW | CS_HITTEST | CS_SYNCPAINT
387 ,sizeof(ULONG)
388 ))
389 {
390 vError = ::WinGetLastError(vHab);
391 sError = wxPMErrorToStr(vError);
392 wxLogLastError(sError);
393 return FALSE;
394 }
395 if (!::WinRegisterClass( vHab
396 ,wxCanvasClassNameNR
397 ,wxWndProc
398 ,CS_HITTEST | CS_SYNCPAINT
399 ,sizeof(ULONG)
400 ))
401 {
402 vError = ::WinGetLastError(vHab);
403 sError = wxPMErrorToStr(vError);
404 wxLogLastError(sError);
405 return FALSE;
406 }
407 return TRUE;
408 } // end of wxApp::RegisterWindowClasses
409
410 //
411 // Cleans up any wxWindows internal structures left lying around
412 //
413 void wxApp::CleanUp()
414 {
415 delete[] wxBuffer;
416 wxBuffer = NULL;
417
418 //
419 // PM-SPECIFIC CLEANUP
420 //
421
422 // wxSetKeyboardHook(FALSE);
423
424 if (wxSTD_FRAME_ICON)
425 ::WinFreeFileIcon(wxSTD_FRAME_ICON);
426 if (wxSTD_MDICHILDFRAME_ICON)
427 ::WinFreeFileIcon(wxSTD_MDICHILDFRAME_ICON);
428 if (wxSTD_MDIPARENTFRAME_ICON)
429 ::WinFreeFileIcon(wxSTD_MDIPARENTFRAME_ICON);
430
431 if (wxDEFAULT_FRAME_ICON)
432 ::WinFreeFileIcon(wxDEFAULT_FRAME_ICON);
433 if (wxDEFAULT_MDICHILDFRAME_ICON)
434 ::WinFreeFileIcon(wxDEFAULT_MDICHILDFRAME_ICON);
435 if (wxDEFAULT_MDIPARENTFRAME_ICON)
436 ::WinFreeFileIcon(wxDEFAULT_MDIPARENTFRAME_ICON);
437
438 if ( wxDisableButtonBrush )
439 {
440 // TODO: ::DeleteObject( wxDisableButtonBrush );
441 }
442
443 if (wxWinHandleList)
444 delete wxWinHandleList;
445
446 // Delete Message queue
447 if (wxTheApp->m_hMq)
448 ::WinDestroyMsgQueue(wxTheApp->m_hMq);
449
450 wxAppBase::CleanUp();
451 } // end of wxApp::CleanUp
452
453 bool wxApp::OnInitGui()
454 {
455 ERRORID vError;
456 wxString sError;
457
458 if (!wxAppBase::OnInitGui())
459 return FALSE;
460
461 m_hMq = ::WinCreateMsgQueue(vHabmain, 0);
462 if (!m_hMq)
463 {
464 vError = ::WinGetLastError(vHabmain);
465 sError = wxPMErrorToStr(vError);
466 wxLogDebug(sError);
467 return FALSE;
468 }
469
470 return TRUE;
471 } // end of wxApp::OnInitGui
472
473 wxApp::wxApp()
474 {
475 argc = 0;
476 argv = NULL;
477 m_nPrintMode = wxPRINT_WINDOWS;
478 m_hMq = 0;
479 m_maxSocketHandles = 0;
480 m_maxSocketNr = 0;
481 m_sockCallbackInfo = 0;
482 } // end of wxApp::wxApp
483
484 wxApp::~wxApp()
485 {
486 //
487 // Delete command-line args
488 //
489 #if wxUSE_UNICODE
490 int i;
491
492 for (i = 0; i < argc; i++)
493 {
494 delete[] argv[i];
495 }
496 delete[] argv;
497 #endif
498 } // end of wxApp::~wxApp
499
500 bool wxApp::Initialized()
501 {
502 if (GetTopWindow())
503 return TRUE;
504 else
505 return FALSE;
506 } // end of wxApp::Initialized
507
508 bool gbInOnIdle = FALSE;
509
510 void wxApp::OnIdle(
511 wxIdleEvent& rEvent
512 )
513 {
514
515 //
516 // Avoid recursion (via ProcessEvent default case)
517 //
518 if (gbInOnIdle)
519 return;
520
521 gbInOnIdle = TRUE;
522
523 wxAppBase::OnIdle(rEvent);
524
525 #if wxUSE_DC_CACHEING
526 // automated DC cache management: clear the cached DCs and bitmap
527 // if it's likely that the app has finished with them, that is, we
528 // get an idle event and we're not dragging anything.
529 if (!::WinGetKeyState(HWND_DESKTOP, VK_BUTTON1) &&
530 !::WinGetKeyState(HWND_DESKTOP, VK_BUTTON3) &&
531 !::WinGetKeyState(HWND_DESKTOP, VK_BUTTON2))
532 wxDC::ClearCache();
533 #endif // wxUSE_DC_CACHEING
534
535 gbInOnIdle = FALSE;
536 } // end of wxApp::OnIdle
537
538 void wxApp::OnEndSession(
539 wxCloseEvent& WXUNUSED(rEvent))
540 {
541 if (GetTopWindow())
542 GetTopWindow()->Close(TRUE);
543 } // end of wxApp::OnEndSession
544
545 //
546 // Default behaviour: close the application with prompts. The
547 // user can veto the close, and therefore the end session.
548 //
549 void wxApp::OnQueryEndSession(
550 wxCloseEvent& rEvent
551 )
552 {
553 if (GetTopWindow())
554 {
555 if (!GetTopWindow()->Close(!rEvent.CanVeto()))
556 rEvent.Veto(TRUE);
557 }
558 } // end of wxApp::OnQueryEndSession
559
560 //
561 // Yield to incoming messages
562 //
563 bool wxApp::Yield(bool onlyIfNeeded)
564 {
565 static bool s_inYield = FALSE;
566
567 if ( s_inYield )
568 {
569 if ( !onlyIfNeeded )
570 {
571 wxFAIL_MSG( _T("wxYield() called recursively") );
572 }
573
574 return FALSE;
575 }
576
577 HAB vHab = 0;
578 QMSG vMsg;
579
580 //
581 // Disable log flushing from here because a call to wxYield() shouldn't
582 // normally result in message boxes popping up &c
583 //
584 wxLog::Suspend();
585
586 s_inYield = TRUE;
587
588 //
589 // We want to go back to the main message loop
590 // if we see a WM_QUIT. (?)
591 //
592 while (::WinPeekMsg(vHab, &vMsg, (HWND)NULL, 0, 0, PM_NOREMOVE) && vMsg.msg != WM_QUIT)
593 {
594 #if wxUSE_THREADS
595 wxMutexGuiLeaveOrEnter();
596 #endif // wxUSE_THREADS
597 if (!wxTheApp->Dispatch())
598 break;
599 }
600 //
601 // If they are pending events, we must process them.
602 //
603 if (wxTheApp)
604 wxTheApp->ProcessPendingEvents();
605
606 HandleSockets();
607 //
608 // Let the logs be flashed again
609 //
610 wxLog::Resume();
611 s_inYield = FALSE;
612 return TRUE;
613 } // end of wxYield
614
615 int wxApp::AddSocketHandler(int handle, int mask,
616 void (*callback)(void*), void * gsock)
617 {
618 int find;
619 struct GsocketCallbackInfo
620 *CallbackInfo = (struct GsocketCallbackInfo *)m_sockCallbackInfo;
621
622 for (find = 0; find < m_maxSocketHandles; find++)
623 if (CallbackInfo[find].handle == -1)
624 break;
625 if (find == m_maxSocketHandles)
626 {
627 // Allocate new memory
628 m_sockCallbackInfo = realloc(m_sockCallbackInfo,
629 (m_maxSocketHandles+=10)*
630 sizeof(struct GsocketCallbackInfo));
631 CallbackInfo = (struct GsocketCallbackInfo *)m_sockCallbackInfo;
632 for (find = m_maxSocketHandles - 10; find < m_maxSocketHandles; find++)
633 CallbackInfo[find].handle = -1;
634 find = m_maxSocketHandles - 10;
635 }
636 CallbackInfo[find].proc = callback;
637 CallbackInfo[find].type = mask;
638 CallbackInfo[find].handle = handle;
639 CallbackInfo[find].gsock = gsock;
640 if (mask & wxSockReadMask)
641 FD_SET(handle, &m_readfds);
642 if (mask & wxSockWriteMask)
643 FD_SET(handle, &m_writefds);
644 if (handle >= m_maxSocketNr)
645 m_maxSocketNr = handle + 1;
646 return find;
647 }
648
649 void wxApp::RemoveSocketHandler(int handle)
650 {
651 struct GsocketCallbackInfo
652 *CallbackInfo = (struct GsocketCallbackInfo *)m_sockCallbackInfo;
653 if (handle < m_maxSocketHandles)
654 {
655 if (CallbackInfo[handle].type & wxSockReadMask)
656 FD_CLR(CallbackInfo[handle].handle, &m_readfds);
657 if (CallbackInfo[handle].type & wxSockWriteMask)
658 FD_CLR(CallbackInfo[handle].handle, &m_writefds);
659 CallbackInfo[handle].handle = -1;
660 }
661 }
662
663 //-----------------------------------------------------------------------------
664 // wxWakeUpIdle
665 //-----------------------------------------------------------------------------
666
667 void wxApp::WakeUpIdle()
668 {
669 //
670 // Send the top window a dummy message so idle handler processing will
671 // start up again. Doing it this way ensures that the idle handler
672 // wakes up in the right thread (see also wxWakeUpMainThread() which does
673 // the same for the main app thread only)
674 //
675 wxWindow* pTopWindow = wxTheApp->GetTopWindow();
676
677 if (pTopWindow)
678 {
679 if ( !::WinPostMsg(GetHwndOf(pTopWindow), WM_NULL, (MPARAM)0, (MPARAM)0))
680 {
681 //
682 // Should never happen
683 //
684 wxLogLastError("PostMessage(WM_NULL)");
685 }
686 }
687 } // end of wxWakeUpIdle
688
689 HAB wxGetInstance()
690 {
691 return vHabmain;
692 }
693
694 void wxSetInstance(
695 HAB vHab
696 )
697 {
698 vHabmain = vHab;
699 }
700