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