Added wxFrameBase::OnMenuOpen, and wxUSE_IDLEMENUUPDATES in platform.h
[wxWidgets.git] / src / msw / app.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: app.cpp
3 // Purpose: wxApp
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ===========================================================================
13 // declarations
14 // ===========================================================================
15
16 // ---------------------------------------------------------------------------
17 // headers
18 // ---------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "app.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #if defined(__BORLANDC__)
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #include "wx/frame.h"
33 #include "wx/app.h"
34 #include "wx/utils.h"
35 #include "wx/gdicmn.h"
36 #include "wx/pen.h"
37 #include "wx/brush.h"
38 #include "wx/cursor.h"
39 #include "wx/icon.h"
40 #include "wx/palette.h"
41 #include "wx/dc.h"
42 #include "wx/dialog.h"
43 #include "wx/msgdlg.h"
44 #include "wx/intl.h"
45 #include "wx/dynarray.h"
46 #include "wx/wxchar.h"
47 #include "wx/icon.h"
48 #include "wx/log.h"
49 #endif
50
51 #include "wx/apptrait.h"
52 #include "wx/filename.h"
53 #include "wx/module.h"
54
55 #include "wx/msw/private.h"
56
57 #if wxUSE_THREADS
58 #include "wx/thread.h"
59
60 // define the array of MSG strutures
61 WX_DECLARE_OBJARRAY(MSG, wxMsgArray);
62
63 #include "wx/arrimpl.cpp"
64
65 WX_DEFINE_OBJARRAY(wxMsgArray);
66 #endif // wxUSE_THREADS
67
68 #if wxUSE_TOOLTIPS
69 #include "wx/tooltip.h"
70 #endif // wxUSE_TOOLTIPS
71
72 // OLE is used for drag-and-drop, clipboard, OLE Automation..., but some
73 // compilers don't support it (missing headers, libs, ...)
74 #if defined(__GNUWIN32_OLD__) || defined(__SYMANTEC__) || defined(__SALFORDC__)
75 #undef wxUSE_OLE
76
77 #define wxUSE_OLE 0
78 #endif // broken compilers
79
80 #if wxUSE_OLE
81 #include <ole2.h>
82 #endif
83
84 #include <string.h>
85 #include <ctype.h>
86
87 #if defined(__WIN95__) && !((defined(__GNUWIN32_OLD__) || defined(__WXMICROWIN__)) && !defined(__CYGWIN10__))
88 #include <commctrl.h>
89 #endif
90
91 // ----------------------------------------------------------------------------
92 // conditional compilation
93 // ----------------------------------------------------------------------------
94
95 // The macro _WIN32_IE is defined by commctrl.h (unless it had already been
96 // defined before) and shows us what common control features are available
97 // during the compile time (it doesn't mean that they will be available during
98 // the run-time, use GetComCtl32Version() to test for them!). The possible
99 // values are:
100 //
101 // 0x0200 for comctl32.dll 4.00 shipped with Win95/NT 4.0
102 // 0x0300 4.70 IE 3.x
103 // 0x0400 4.71 IE 4.0
104 // 0x0401 4.72 IE 4.01 and Win98
105 // 0x0500 5.00 IE 5.x and NT 5.0 (Win2000)
106
107 #ifndef _WIN32_IE
108 // minimal set of features by default
109 #define _WIN32_IE 0x0200
110 #endif
111
112 #if _WIN32_IE >= 0x0300 && \
113 (!defined(__MINGW32__) || wxCHECK_W32API_VERSION( 2, 0 )) && \
114 !defined(__CYGWIN__)
115 #include <shlwapi.h>
116 #endif
117
118 // ---------------------------------------------------------------------------
119 // global variables
120 // ---------------------------------------------------------------------------
121
122 extern wxList WXDLLEXPORT wxPendingDelete;
123 #ifndef __WXMICROWIN__
124 extern void wxSetKeyboardHook(bool doIt);
125 #endif
126
127 MSG s_currentMsg;
128
129 // NB: all "NoRedraw" classes must have the same names as the "normal" classes
130 // with NR suffix - wxWindow::MSWCreate() supposes this
131 const wxChar *wxCanvasClassName = wxT("wxWindowClass");
132 const wxChar *wxCanvasClassNameNR = wxT("wxWindowClassNR");
133 const wxChar *wxMDIFrameClassName = wxT("wxMDIFrameClass");
134 const wxChar *wxMDIFrameClassNameNoRedraw = wxT("wxMDIFrameClassNR");
135 const wxChar *wxMDIChildFrameClassName = wxT("wxMDIChildFrameClass");
136 const wxChar *wxMDIChildFrameClassNameNoRedraw = wxT("wxMDIChildFrameClassNR");
137
138 HBRUSH wxDisableButtonBrush = (HBRUSH) 0;
139
140 // ----------------------------------------------------------------------------
141 // private functions
142 // ----------------------------------------------------------------------------
143
144 LRESULT WXDLLEXPORT APIENTRY wxWndProc(HWND, UINT, WPARAM, LPARAM);
145
146 // ===========================================================================
147 // wxGUIAppTraits implementation
148 // ===========================================================================
149
150 // private class which we use to pass parameters from BeforeChildWaitLoop() to
151 // AfterChildWaitLoop()
152 struct ChildWaitLoopData
153 {
154 ChildWaitLoopData(wxWindowDisabler *wd_, wxWindow *winActive_)
155 {
156 wd = wd_;
157 winActive = winActive_;
158 }
159
160 wxWindowDisabler *wd;
161 wxWindow *winActive;
162 };
163
164 void *wxGUIAppTraits::BeforeChildWaitLoop()
165 {
166 /*
167 We use a dirty hack here to disable all application windows (which we
168 must do because otherwise the calls to wxYield() could lead to some very
169 unexpected reentrancies in the users code) but to avoid losing
170 focus/activation entirely when the child process terminates which would
171 happen if we simply disabled everything using wxWindowDisabler. Indeed,
172 remember that Windows will never activate a disabled window and when the
173 last childs window is closed and Windows looks for a window to activate
174 all our windows are still disabled. There is no way to enable them in
175 time because we don't know when the childs windows are going to be
176 closed, so the solution we use here is to keep one special tiny frame
177 enabled all the time. Then when the child terminates it will get
178 activated and when we close it below -- after reenabling all the other
179 windows! -- the previously active window becomes activated again and
180 everything is ok.
181 */
182 wxBeginBusyCursor();
183
184 // first disable all existing windows
185 wxWindowDisabler *wd = new wxWindowDisabler;
186
187 // then create an "invisible" frame: it has minimal size, is positioned
188 // (hopefully) outside the screen and doesn't appear on the taskbar
189 wxWindow *winActive = new wxFrame
190 (
191 wxTheApp->GetTopWindow(),
192 -1,
193 _T(""),
194 wxPoint(32600, 32600),
195 wxSize(1, 1),
196 wxDEFAULT_FRAME_STYLE | wxFRAME_NO_TASKBAR
197 );
198 winActive->Show();
199
200 return new ChildWaitLoopData(wd, winActive);
201 }
202
203 void wxGUIAppTraits::AlwaysYield()
204 {
205 wxYield();
206 }
207
208 void wxGUIAppTraits::AfterChildWaitLoop(void *dataOrig)
209 {
210 wxEndBusyCursor();
211
212 const ChildWaitLoopData * const data = (ChildWaitLoopData *)dataOrig;
213
214 delete data->wd;
215
216 // finally delete the dummy frame and, as wd has been already destroyed and
217 // the other windows reenabled, the activation is going to return to the
218 // window which had had it before
219 data->winActive->Destroy();
220 }
221
222 bool wxGUIAppTraits::DoMessageFromThreadWait()
223 {
224 return !wxTheApp || wxTheApp->DoMessage();
225 }
226
227 // ===========================================================================
228 // wxApp implementation
229 // ===========================================================================
230
231 int wxApp::m_nCmdShow = SW_SHOWNORMAL;
232
233 // ---------------------------------------------------------------------------
234 // wxWin macros
235 // ---------------------------------------------------------------------------
236
237 IMPLEMENT_DYNAMIC_CLASS(wxApp, wxEvtHandler)
238
239 BEGIN_EVENT_TABLE(wxApp, wxEvtHandler)
240 EVT_IDLE(wxApp::OnIdle)
241 EVT_END_SESSION(wxApp::OnEndSession)
242 EVT_QUERY_END_SESSION(wxApp::OnQueryEndSession)
243 END_EVENT_TABLE()
244
245 // class to ensure that wxAppBase::CleanUp() is called if our Initialize()
246 // fails
247 class wxCallBaseCleanup
248 {
249 public:
250 wxCallBaseCleanup(wxApp *app) : m_app(app) { }
251 ~wxCallBaseCleanup() { if ( m_app ) m_app->wxAppBase::CleanUp(); }
252
253 void Dismiss() { m_app = NULL; }
254
255 private:
256 wxApp *m_app;
257 };
258
259 //// Initialize
260 bool wxApp::Initialize(int& argc, wxChar **argv)
261 {
262 if ( !wxAppBase::Initialize(argc, argv) )
263 return false;
264
265 // ensure that base cleanup is done if we return too early
266 wxCallBaseCleanup callBaseCleanup(this);
267
268 // the first thing to do is to check if we're trying to run an Unicode
269 // program under Win9x w/o MSLU emulation layer - if so, abort right now
270 // as it has no chance to work
271 #if wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
272 if ( wxGetOsVersion() != wxWINDOWS_NT )
273 {
274 // note that we can use MessageBoxW() as it's implemented even under
275 // Win9x - OTOH, we can't use wxGetTranslation() because the file APIs
276 // used by wxLocale are not
277 ::MessageBox
278 (
279 NULL,
280 _T("This program uses Unicode and requires Windows NT/2000/XP.\nProgram aborted."),
281 _T("wxWindows Fatal Error"),
282 MB_ICONERROR | MB_OK
283 );
284
285 return FALSE;
286 }
287 #endif // wxUSE_UNICODE && !wxUSE_UNICODE_MSLU
288
289 #if defined(__WIN95__) && !defined(__WXMICROWIN__)
290 InitCommonControls();
291 #endif // __WIN95__
292
293 #if wxUSE_OLE || wxUSE_DRAG_AND_DROP
294
295 #ifdef __WIN16__
296 // for OLE, enlarge message queue to be as large as possible
297 int iMsg = 96;
298 while (!SetMessageQueue(iMsg) && (iMsg -= 8))
299 ;
300 #endif // Win16
301
302 #if wxUSE_OLE
303 // we need to initialize OLE library
304 if ( FAILED(::OleInitialize(NULL)) )
305 wxLogError(_("Cannot initialize OLE"));
306 #endif
307
308 #endif // wxUSE_OLE
309
310 #if wxUSE_CTL3D
311 if (!Ctl3dRegister(wxhInstance))
312 wxLogError(wxT("Cannot register CTL3D"));
313
314 Ctl3dAutoSubclass(wxhInstance);
315 #endif // wxUSE_CTL3D
316
317 RegisterWindowClasses();
318
319 #ifndef __WXMICROWIN__
320 // Create the brush for disabling bitmap buttons
321
322 LOGBRUSH lb;
323 lb.lbStyle = BS_PATTERN;
324 lb.lbColor = 0;
325 lb.lbHatch = (int)LoadBitmap( wxhInstance, wxT("wxDISABLE_BUTTON_BITMAP") );
326 if ( lb.lbHatch )
327 {
328 wxDisableButtonBrush = ::CreateBrushIndirect( & lb );
329 ::DeleteObject( (HGDIOBJ)lb.lbHatch );
330 }
331 //else: wxWindows resources are probably not linked in
332 #endif
333
334 #if wxUSE_PENWINDOWS
335 wxRegisterPenWin();
336 #endif
337
338 wxWinHandleHash = new wxWinHashTable(wxKEY_INTEGER, 100);
339
340 // This is to foil optimizations in Visual C++ that throw out dummy.obj.
341 // PLEASE DO NOT ALTER THIS.
342 #if defined(__VISUALC__) && defined(__WIN16__) && !defined(WXMAKINGDLL)
343 extern char wxDummyChar;
344 if (wxDummyChar) wxDummyChar++;
345 #endif
346
347 #ifndef __WXMICROWIN__
348 wxSetKeyboardHook(TRUE);
349 #endif
350
351 callBaseCleanup.Dismiss();
352
353 return true;
354 }
355
356 // ---------------------------------------------------------------------------
357 // RegisterWindowClasses
358 // ---------------------------------------------------------------------------
359
360 // TODO we should only register classes really used by the app. For this it
361 // would be enough to just delay the class registration until an attempt
362 // to create a window of this class is made.
363 bool wxApp::RegisterWindowClasses()
364 {
365 WNDCLASS wndclass;
366 wxZeroMemory(wndclass);
367
368 // for each class we register one with CS_(V|H)REDRAW style and one
369 // without for windows created with wxNO_FULL_REDRAW_ON_REPAINT flag
370 static const long styleNormal = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
371 static const long styleNoRedraw = CS_DBLCLKS;
372
373 // the fields which are common to all classes
374 wndclass.lpfnWndProc = (WNDPROC)wxWndProc;
375 wndclass.hInstance = wxhInstance;
376 wndclass.hCursor = ::LoadCursor((HINSTANCE)NULL, IDC_ARROW);
377
378 // Register the frame window class.
379 wndclass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE + 1);
380 wndclass.lpszClassName = wxCanvasClassName;
381 wndclass.style = styleNormal;
382
383 if ( !RegisterClass(&wndclass) )
384 {
385 wxLogLastError(wxT("RegisterClass(frame)"));
386 }
387
388 // "no redraw" frame
389 wndclass.lpszClassName = wxCanvasClassNameNR;
390 wndclass.style = styleNoRedraw;
391
392 if ( !RegisterClass(&wndclass) )
393 {
394 wxLogLastError(wxT("RegisterClass(no redraw frame)"));
395 }
396
397 // Register the MDI frame window class.
398 wndclass.hbrBackground = (HBRUSH)NULL; // paint MDI frame ourselves
399 wndclass.lpszClassName = wxMDIFrameClassName;
400 wndclass.style = styleNormal;
401
402 if ( !RegisterClass(&wndclass) )
403 {
404 wxLogLastError(wxT("RegisterClass(MDI parent)"));
405 }
406
407 // "no redraw" MDI frame
408 wndclass.lpszClassName = wxMDIFrameClassNameNoRedraw;
409 wndclass.style = styleNoRedraw;
410
411 if ( !RegisterClass(&wndclass) )
412 {
413 wxLogLastError(wxT("RegisterClass(no redraw MDI parent frame)"));
414 }
415
416 // Register the MDI child frame window class.
417 wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
418 wndclass.lpszClassName = wxMDIChildFrameClassName;
419 wndclass.style = styleNormal;
420
421 if ( !RegisterClass(&wndclass) )
422 {
423 wxLogLastError(wxT("RegisterClass(MDI child)"));
424 }
425
426 // "no redraw" MDI child frame
427 wndclass.lpszClassName = wxMDIChildFrameClassNameNoRedraw;
428 wndclass.style = styleNoRedraw;
429
430 if ( !RegisterClass(&wndclass) )
431 {
432 wxLogLastError(wxT("RegisterClass(no redraw MDI child)"));
433 }
434
435 return TRUE;
436 }
437
438 // ---------------------------------------------------------------------------
439 // UnregisterWindowClasses
440 // ---------------------------------------------------------------------------
441
442 bool wxApp::UnregisterWindowClasses()
443 {
444 bool retval = TRUE;
445
446 #ifndef __WXMICROWIN__
447 // MDI frame window class.
448 if ( !::UnregisterClass(wxMDIFrameClassName, wxhInstance) )
449 {
450 wxLogLastError(wxT("UnregisterClass(MDI parent)"));
451
452 retval = FALSE;
453 }
454
455 // "no redraw" MDI frame
456 if ( !::UnregisterClass(wxMDIFrameClassNameNoRedraw, wxhInstance) )
457 {
458 wxLogLastError(wxT("UnregisterClass(no redraw MDI parent frame)"));
459
460 retval = FALSE;
461 }
462
463 // MDI child frame window class.
464 if ( !::UnregisterClass(wxMDIChildFrameClassName, wxhInstance) )
465 {
466 wxLogLastError(wxT("UnregisterClass(MDI child)"));
467
468 retval = FALSE;
469 }
470
471 // "no redraw" MDI child frame
472 if ( !::UnregisterClass(wxMDIChildFrameClassNameNoRedraw, wxhInstance) )
473 {
474 wxLogLastError(wxT("UnregisterClass(no redraw MDI child)"));
475
476 retval = FALSE;
477 }
478
479 // canvas class name
480 if ( !::UnregisterClass(wxCanvasClassName, wxhInstance) )
481 {
482 wxLogLastError(wxT("UnregisterClass(canvas)"));
483
484 retval = FALSE;
485 }
486
487 if ( !::UnregisterClass(wxCanvasClassNameNR, wxhInstance) )
488 {
489 wxLogLastError(wxT("UnregisterClass(no redraw canvas)"));
490
491 retval = FALSE;
492 }
493 #endif // __WXMICROWIN__
494
495 return retval;
496 }
497
498 void wxApp::CleanUp()
499 {
500 #ifndef __WXMICROWIN__
501 wxSetKeyboardHook(FALSE);
502 #endif
503
504 #if wxUSE_PENWINDOWS
505 wxCleanUpPenWin();
506 #endif
507
508 if ( wxDisableButtonBrush )
509 ::DeleteObject( wxDisableButtonBrush );
510
511 #if wxUSE_OLE
512 ::OleUninitialize();
513 #endif
514
515 // for an EXE the classes are unregistered when it terminates but DLL may
516 // be loaded several times (load/unload/load) into the same process in
517 // which case the registration will fail after the first time if we don't
518 // unregister the classes now
519 UnregisterWindowClasses();
520
521 #if wxUSE_CTL3D
522 Ctl3dUnregister(wxhInstance);
523 #endif
524
525 delete wxWinHandleHash;
526 wxWinHandleHash = NULL;
527
528 wxAppBase::CleanUp();
529 }
530
531 // ----------------------------------------------------------------------------
532 // wxApp ctor/dtor
533 // ----------------------------------------------------------------------------
534
535 wxApp::wxApp()
536 {
537 m_printMode = wxPRINT_WINDOWS;
538 }
539
540 wxApp::~wxApp()
541 {
542 // our cmd line arguments are allocated inside wxEntry(HINSTANCE), they
543 // don't come from main(), so we have to free them
544
545 while ( argc )
546 {
547 // m_argv elements were allocated by wxStrdup()
548 free(argv[--argc]);
549 }
550
551 // but m_argv itself -- using new[]
552 delete [] argv;
553 }
554
555 bool wxApp::Initialized()
556 {
557 #ifndef _WINDLL
558 if (GetTopWindow())
559 return TRUE;
560 else
561 return FALSE;
562 #else // Assume initialized if DLL (no way of telling)
563 return TRUE;
564 #endif
565 }
566
567 /*
568 * Get and process a message, returning FALSE if WM_QUIT
569 * received (and also set the flag telling the app to exit the main loop)
570 *
571 */
572 bool wxApp::DoMessage()
573 {
574 BOOL rc = ::GetMessage(&s_currentMsg, (HWND) NULL, 0, 0);
575 if ( rc == 0 )
576 {
577 // got WM_QUIT
578 m_keepGoing = FALSE;
579
580 return FALSE;
581 }
582 else if ( rc == -1 )
583 {
584 // should never happen, but let's test for it nevertheless
585 wxLogLastError(wxT("GetMessage"));
586 }
587 else
588 {
589 #if wxUSE_THREADS
590 wxASSERT_MSG( wxThread::IsMain(),
591 wxT("only the main thread can process Windows messages") );
592
593 static bool s_hadGuiLock = TRUE;
594 static wxMsgArray s_aSavedMessages;
595
596 // if a secondary thread owns is doing GUI calls, save all messages for
597 // later processing - we can't process them right now because it will
598 // lead to recursive library calls (and we're not reentrant)
599 if ( !wxGuiOwnedByMainThread() )
600 {
601 s_hadGuiLock = FALSE;
602
603 // leave out WM_COMMAND messages: too dangerous, sometimes
604 // the message will be processed twice
605 if ( !wxIsWaitingForThread() ||
606 s_currentMsg.message != WM_COMMAND )
607 {
608 s_aSavedMessages.Add(s_currentMsg);
609 }
610
611 return TRUE;
612 }
613 else
614 {
615 // have we just regained the GUI lock? if so, post all of the saved
616 // messages
617 //
618 // FIXME of course, it's not _exactly_ the same as processing the
619 // messages normally - expect some things to break...
620 if ( !s_hadGuiLock )
621 {
622 s_hadGuiLock = TRUE;
623
624 size_t count = s_aSavedMessages.GetCount();
625 for ( size_t n = 0; n < count; n++ )
626 {
627 MSG& msg = s_aSavedMessages[n];
628
629 DoMessage((WXMSG *)&msg);
630 }
631
632 s_aSavedMessages.Empty();
633 }
634 }
635 #endif // wxUSE_THREADS
636
637 // Process the message
638 DoMessage((WXMSG *)&s_currentMsg);
639 }
640
641 return TRUE;
642 }
643
644 void wxApp::DoMessage(WXMSG *pMsg)
645 {
646 if ( !ProcessMessage(pMsg) )
647 {
648 ::TranslateMessage((MSG *)pMsg);
649 ::DispatchMessage((MSG *)pMsg);
650 }
651 }
652
653 /*
654 * Keep trying to process messages until WM_QUIT
655 * received.
656 *
657 * If there are messages to be processed, they will all be
658 * processed and OnIdle will not be called.
659 * When there are no more messages, OnIdle is called.
660 * If OnIdle requests more time,
661 * it will be repeatedly called so long as there are no pending messages.
662 * A 'feature' of this is that once OnIdle has decided that no more processing
663 * is required, then it won't get processing time until further messages
664 * are processed (it'll sit in DoMessage).
665 */
666
667 int wxApp::MainLoop()
668 {
669 m_keepGoing = TRUE;
670
671 while ( m_keepGoing )
672 {
673 #if wxUSE_THREADS
674 wxMutexGuiLeaveOrEnter();
675 #endif // wxUSE_THREADS
676
677 while ( !Pending() && ProcessIdle() )
678 ;
679
680 // a message came or no more idle processing to do
681 DoMessage();
682 }
683
684 return s_currentMsg.wParam;
685 }
686
687 // Returns TRUE if more time is needed.
688 bool wxApp::ProcessIdle()
689 {
690 wxIdleEvent event;
691 event.SetEventObject(this);
692 ProcessEvent(event);
693
694 wxUpdateUIEvent::ResetUpdateTime();
695
696 return event.MoreRequested();
697 }
698
699 void wxApp::ExitMainLoop()
700 {
701 // this will set m_keepGoing to FALSE a bit later
702 ::PostQuitMessage(0);
703 }
704
705 bool wxApp::Pending()
706 {
707 return ::PeekMessage(&s_currentMsg, 0, 0, 0, PM_NOREMOVE) != 0;
708 }
709
710 void wxApp::Dispatch()
711 {
712 DoMessage();
713 }
714
715 /*
716 * Give all windows a chance to preprocess
717 * the message. Some may have accelerator tables, or have
718 * MDI complications.
719 */
720
721 bool wxApp::ProcessMessage(WXMSG *wxmsg)
722 {
723 MSG *msg = (MSG *)wxmsg;
724 HWND hwnd = msg->hwnd;
725 wxWindow *wndThis = wxGetWindowFromHWND((WXHWND)hwnd);
726
727 // this may happen if the event occured in a standard modeless dialog (the
728 // only example of which I know of is the find/replace dialog) - then call
729 // IsDialogMessage() to make TAB navigation in it work
730 if ( !wndThis )
731 {
732 // we need to find the dialog containing this control as
733 // IsDialogMessage() just eats all the messages (i.e. returns TRUE for
734 // them) if we call it for the control itself
735 while ( hwnd && ::GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD )
736 {
737 hwnd = ::GetParent(hwnd);
738 }
739
740 return hwnd && ::IsDialogMessage(hwnd, msg) != 0;
741 }
742
743 #if wxUSE_TOOLTIPS
744 // we must relay WM_MOUSEMOVE events to the tooltip ctrl if we want it to
745 // popup the tooltip bubbles
746 if ( (msg->message == WM_MOUSEMOVE) )
747 {
748 wxToolTip *tt = wndThis->GetToolTip();
749 if ( tt )
750 {
751 tt->RelayEvent(wxmsg);
752 }
753 }
754 #endif // wxUSE_TOOLTIPS
755
756 // allow the window to prevent certain messages from being
757 // translated/processed (this is currently used by wxTextCtrl to always
758 // grab Ctrl-C/V/X, even if they are also accelerators in some parent)
759 if ( !wndThis->MSWShouldPreProcessMessage(wxmsg) )
760 {
761 return FALSE;
762 }
763
764 // try translations first: the accelerators override everything
765 wxWindow *wnd;
766
767 for ( wnd = wndThis; wnd; wnd = wnd->GetParent() )
768 {
769 if ( wnd->MSWTranslateMessage(wxmsg))
770 return TRUE;
771
772 // stop at first top level window, i.e. don't try to process the key
773 // strokes originating in a dialog using the accelerators of the parent
774 // frame - this doesn't make much sense
775 if ( wnd->IsTopLevel() )
776 break;
777 }
778
779 // now try the other hooks (kbd navigation is handled here): we start from
780 // wndThis->GetParent() because wndThis->MSWProcessMessage() was already
781 // called above
782 for ( wnd = wndThis->GetParent(); wnd; wnd = wnd->GetParent() )
783 {
784 if ( wnd->MSWProcessMessage(wxmsg) )
785 return TRUE;
786 }
787
788 // no special preprocessing for this message, dispatch it normally
789 return FALSE;
790 }
791
792 // this is a temporary hack and will be replaced by using wxEventLoop in the
793 // future
794 //
795 // it is needed to allow other event loops (currently only one: the modal
796 // dialog one) to reset the OnIdle() semaphore because otherwise OnIdle()
797 // wouldn't do anything while a modal dialog shown from OnIdle() call is shown.
798 bool wxIsInOnIdleFlag = FALSE;
799
800 void wxApp::OnIdle(wxIdleEvent& event)
801 {
802 // Avoid recursion (via ProcessEvent default case)
803 if ( wxIsInOnIdleFlag )
804 return;
805
806 wxIsInOnIdleFlag = TRUE;
807
808 // If there are pending events, we must process them: pending events
809 // are either events to the threads other than main or events posted
810 // with wxPostEvent() functions
811 // GRG: I have moved this here so that all pending events are processed
812 // before starting to delete any objects. This behaves better (in
813 // particular, wrt wxPostEvent) and is coherent with wxGTK's current
814 // behaviour. Changed Feb/2000 before 2.1.14
815 ProcessPendingEvents();
816
817 // 'Garbage' collection of windows deleted with Close().
818 DeletePendingObjects();
819
820 #if wxUSE_LOG
821 // flush the logged messages if any
822 wxLog::FlushActive();
823 #endif // wxUSE_LOG
824
825 #if wxUSE_DC_CACHEING
826 // automated DC cache management: clear the cached DCs and bitmap
827 // if it's likely that the app has finished with them, that is, we
828 // get an idle event and we're not dragging anything.
829 if (!::GetKeyState(MK_LBUTTON) && !::GetKeyState(MK_MBUTTON) && !::GetKeyState(MK_RBUTTON))
830 wxDC::ClearCache();
831 #endif // wxUSE_DC_CACHEING
832
833 // Send OnIdle events to all windows
834 if ( SendIdleEvents() )
835 {
836 // SendIdleEvents() returns TRUE if at least one window requested more
837 // idle events
838 event.RequestMore(TRUE);
839 }
840
841 wxIsInOnIdleFlag = FALSE;
842 }
843
844 // Send idle event to all top-level windows
845 bool wxApp::SendIdleEvents()
846 {
847 bool needMore = FALSE;
848
849 wxWindowList::Node* node = wxTopLevelWindows.GetFirst();
850 while (node)
851 {
852 wxWindow* win = node->GetData();
853 if (SendIdleEvents(win))
854 needMore = TRUE;
855 node = node->GetNext();
856 }
857
858 return needMore;
859 }
860
861 // Send idle event to window and all subwindows
862 bool wxApp::SendIdleEvents(wxWindow* win)
863 {
864 wxIdleEvent event;
865 event.SetEventObject(win);
866 win->GetEventHandler()->ProcessEvent(event);
867
868 bool needMore = event.MoreRequested();
869
870 wxWindowList::Node *node = win->GetChildren().GetFirst();
871 while ( node )
872 {
873 wxWindow *win = node->GetData();
874 if (SendIdleEvents(win))
875 needMore = TRUE;
876
877 node = node->GetNext();
878 }
879
880 return needMore;
881 }
882
883 void wxApp::WakeUpIdle()
884 {
885 // Send the top window a dummy message so idle handler processing will
886 // start up again. Doing it this way ensures that the idle handler
887 // wakes up in the right thread (see also wxWakeUpMainThread() which does
888 // the same for the main app thread only)
889 wxWindow *topWindow = wxTheApp->GetTopWindow();
890 if ( topWindow )
891 {
892 if ( !::PostMessage(GetHwndOf(topWindow), WM_NULL, 0, 0) )
893 {
894 // should never happen
895 wxLogLastError(wxT("PostMessage(WM_NULL)"));
896 }
897 }
898 }
899
900 void wxApp::OnEndSession(wxCloseEvent& WXUNUSED(event))
901 {
902 if (GetTopWindow())
903 GetTopWindow()->Close(TRUE);
904 }
905
906 // Default behaviour: close the application with prompts. The
907 // user can veto the close, and therefore the end session.
908 void wxApp::OnQueryEndSession(wxCloseEvent& event)
909 {
910 if (GetTopWindow())
911 {
912 if (!GetTopWindow()->Close(!event.CanVeto()))
913 event.Veto(TRUE);
914 }
915 }
916
917 typedef struct _WXADllVersionInfo
918 {
919 DWORD cbSize;
920 DWORD dwMajorVersion; // Major version
921 DWORD dwMinorVersion; // Minor version
922 DWORD dwBuildNumber; // Build number
923 DWORD dwPlatformID; // DLLVER_PLATFORM_*
924 } WXADLLVERSIONINFO;
925
926 typedef HRESULT (CALLBACK* WXADLLGETVERSIONPROC)(WXADLLVERSIONINFO *);
927
928 /* static */
929 int wxApp::GetComCtl32Version()
930 {
931 #ifdef __WXMICROWIN__
932 return 0;
933 #else
934 // cache the result
935 static int s_verComCtl32 = -1;
936
937 wxCRIT_SECT_DECLARE(csComCtl32);
938 wxCRIT_SECT_LOCKER(lock, csComCtl32);
939
940 if ( s_verComCtl32 == -1 )
941 {
942 // initally assume no comctl32.dll at all
943 s_verComCtl32 = 0;
944
945 // do we have it?
946 HMODULE hModuleComCtl32 = ::GetModuleHandle(wxT("COMCTL32"));
947 BOOL bFreeComCtl32 = FALSE ;
948 if(!hModuleComCtl32)
949 {
950 hModuleComCtl32 = ::LoadLibrary(wxT("COMCTL32.DLL")) ;
951 if(hModuleComCtl32)
952 {
953 bFreeComCtl32 = TRUE ;
954 }
955 }
956
957 // if so, then we can check for the version
958 if ( hModuleComCtl32 )
959 {
960 // try to use DllGetVersion() if available in _headers_
961 WXADLLGETVERSIONPROC pfnDllGetVersion = (WXADLLGETVERSIONPROC)
962 ::GetProcAddress(hModuleComCtl32, "DllGetVersion");
963 if ( pfnDllGetVersion )
964 {
965 WXADLLVERSIONINFO dvi;
966 dvi.cbSize = sizeof(dvi);
967
968 HRESULT hr = (*pfnDllGetVersion)(&dvi);
969 if ( FAILED(hr) )
970 {
971 wxLogApiError(_T("DllGetVersion"), hr);
972 }
973 else
974 {
975 // this is incompatible with _WIN32_IE values, but
976 // compatible with the other values returned by
977 // GetComCtl32Version()
978 s_verComCtl32 = 100*dvi.dwMajorVersion +
979 dvi.dwMinorVersion;
980 }
981 }
982 // DllGetVersion() unavailable either during compile or
983 // run-time, try to guess the version otherwise
984 if ( !s_verComCtl32 )
985 {
986 // InitCommonControlsEx is unique to 4.70 and later
987 FARPROC theProc = ::GetProcAddress
988 (
989 hModuleComCtl32,
990 "InitCommonControlsEx"
991 );
992
993 if ( !theProc )
994 {
995 // not found, must be 4.00
996 s_verComCtl32 = 400;
997 }
998 else
999 {
1000 // many symbols appeared in comctl32 4.71, could use
1001 // any of them except may be DllInstall
1002 theProc = ::GetProcAddress
1003 (
1004 hModuleComCtl32,
1005 "InitializeFlatSB"
1006 );
1007 if ( !theProc )
1008 {
1009 // not found, must be 4.70
1010 s_verComCtl32 = 470;
1011 }
1012 else
1013 {
1014 // found, must be 4.71
1015 s_verComCtl32 = 471;
1016 }
1017 }
1018 }
1019 }
1020
1021 if(bFreeComCtl32)
1022 {
1023 ::FreeLibrary(hModuleComCtl32) ;
1024 }
1025 }
1026
1027 return s_verComCtl32;
1028 #endif
1029 }
1030
1031 // Yield to incoming messages
1032
1033 bool wxApp::Yield(bool onlyIfNeeded)
1034 {
1035 // MT-FIXME
1036 static bool s_inYield = FALSE;
1037
1038 #if wxUSE_LOG
1039 // disable log flushing from here because a call to wxYield() shouldn't
1040 // normally result in message boxes popping up &c
1041 wxLog::Suspend();
1042 #endif // wxUSE_LOG
1043
1044 if ( s_inYield )
1045 {
1046 if ( !onlyIfNeeded )
1047 {
1048 wxFAIL_MSG( wxT("wxYield called recursively" ) );
1049 }
1050
1051 return FALSE;
1052 }
1053
1054 s_inYield = TRUE;
1055
1056 // we don't want to process WM_QUIT from here - it should be processed in
1057 // the main event loop in order to stop it
1058 MSG msg;
1059 while ( PeekMessage(&msg, (HWND)0, 0, 0, PM_NOREMOVE) &&
1060 msg.message != WM_QUIT )
1061 {
1062 #if wxUSE_THREADS
1063 wxMutexGuiLeaveOrEnter();
1064 #endif // wxUSE_THREADS
1065
1066 if ( !wxTheApp->DoMessage() )
1067 break;
1068 }
1069
1070 // if there are pending events, we must process them.
1071 ProcessPendingEvents();
1072
1073 #if wxUSE_LOG
1074 // let the logs be flashed again
1075 wxLog::Resume();
1076 #endif // wxUSE_LOG
1077
1078 s_inYield = FALSE;
1079
1080 return TRUE;
1081 }
1082