1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/msw/window.cpp
3 // Purpose:     wxWindowMSW
4 // Author:      Julian Smart
5 // Modified by: VZ on 13.05.99: no more Default(), MSWOnXXX() reorganisation
6 // Created:     04/01/98
7 // Copyright:   (c) Julian Smart
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 // ===========================================================================
12 // declarations
13 // ===========================================================================
14 
15 // ---------------------------------------------------------------------------
16 // headers
17 // ---------------------------------------------------------------------------
18 
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21 
22 
23 #include "wx/window.h"
24 
25 #ifndef WX_PRECOMP
26     #include "wx/msw/wrapwin.h"
27     #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
28     #include "wx/msw/missing.h"
29     #include "wx/accel.h"
30     #include "wx/menu.h"
31     #include "wx/dc.h"
32     #include "wx/dcclient.h"
33     #include "wx/dcmemory.h"
34     #include "wx/dialog.h"
35     #include "wx/utils.h"
36     #include "wx/app.h"
37     #include "wx/layout.h"
38     #include "wx/dialog.h"
39     #include "wx/frame.h"
40     #include "wx/listbox.h"
41     #include "wx/button.h"
42     #include "wx/msgdlg.h"
43     #include "wx/settings.h"
44     #include "wx/statbox.h"
45     #include "wx/sizer.h"
46     #include "wx/intl.h"
47     #include "wx/log.h"
48     #include "wx/textctrl.h"
49     #include "wx/menuitem.h"
50     #include "wx/module.h"
51     #include "wx/vector.h"
52 #endif
53 
54 #if wxUSE_OWNER_DRAWN && !defined(__WXUNIVERSAL__)
55     #include "wx/ownerdrw.h"
56 #endif
57 
58 #include "wx/evtloop.h"
59 #include "wx/hashmap.h"
60 #include "wx/popupwin.h"
61 #include "wx/power.h"
62 #include "wx/scopeguard.h"
63 #include "wx/sysopt.h"
64 
65 #if wxUSE_DRAG_AND_DROP
66     #include "wx/dnd.h"
67 #endif
68 
69 #if wxUSE_ACCESSIBILITY
70     #include "wx/access.h"
71     #include <ole2.h>
72     #include <oleacc.h>
73     #ifndef OBJID_CLIENT
74         #define OBJID_CLIENT 0xFFFFFFFC
75     #endif
76 #endif
77 
78 #include "wx/msw/private.h"
79 #include "wx/msw/private/keyboard.h"
80 #include "wx/msw/private/paint.h"
81 #include "wx/msw/private/winstyle.h"
82 #include "wx/msw/dcclient.h"
83 #include "wx/msw/seh.h"
84 #include "wx/private/textmeasure.h"
85 
86 #if wxUSE_TOOLTIPS
87     #include "wx/tooltip.h"
88 #endif
89 
90 #if wxUSE_CARET
91     #include "wx/caret.h"
92 #endif // wxUSE_CARET
93 
94 #if wxUSE_RADIOBOX
95     #include "wx/radiobox.h"
96 #endif // wxUSE_RADIOBOX
97 
98 #if wxUSE_SPINCTRL
99     #include "wx/spinctrl.h"
100 #endif // wxUSE_SPINCTRL
101 
102 #include "wx/notebook.h"
103 #include "wx/listctrl.h"
104 #include "wx/dynlib.h"
105 #include "wx/display.h"
106 
107 #include <string.h>
108 
109 #include <shellapi.h>
110 #include <mmsystem.h>
111 
112 #include <windowsx.h>
113 
114 #if wxUSE_UXTHEME
115     #include "wx/msw/uxtheme.h"
116 #endif
117 
118 #if wxUSE_DYNLIB_CLASS
119     #define HAVE_TRACKMOUSEEVENT
120 #endif // everything needed for TrackMouseEvent()
121 
122 #ifndef MAPVK_VK_TO_CHAR
123     // Contrary to MS claims that this is present starting with Win2k, it is
124     // missing from the SDK released for Windows 5.2 build 3790, aka XP 64-bit
125     // and also from tdm32-gcc-5.1.0.
126     #define MAPVK_VK_TO_CHAR 2
127 #endif
128 
129 // ---------------------------------------------------------------------------
130 // global variables
131 // ---------------------------------------------------------------------------
132 
133 #if wxUSE_MENUS_NATIVE
134 extern wxMenu *wxCurrentPopupMenu;
135 #endif
136 
137 #if wxUSE_POPUPWIN
138 extern wxPopupWindow* wxCurrentPopupWindow;
139 #endif // wxUSE_POPUPWIN
140 
141 #if wxUSE_UXTHEME
142 // This is a hack used by the owner-drawn wxButton implementation to ensure
143 // that the brush used for erasing its background is correctly aligned with the
144 // control.
145 wxWindowMSW *wxWindowBeingErased = NULL;
146 #endif // wxUSE_UXTHEME
147 
148 namespace
149 {
150 
151 // true if we had already created the std colour map, used by
152 // wxGetStdColourMap() and wxWindow::OnSysColourChanged()           (FIXME-MT)
153 bool gs_hasStdCmap = false;
154 
155 // last mouse event information we need to filter out the duplicates
156 struct MouseEventInfoDummy
157 {
158     // mouse position (in screen coordinates)
159     wxPoint pos;
160 
161     // last mouse event type
162     wxEventType type;
163 } gs_lastMouseEvent;
164 
165 // hash containing the registered handlers for the custom messages
166 WX_DECLARE_HASH_MAP(int, wxWindow::MSWMessageHandler,
167                     wxIntegerHash, wxIntegerEqual,
168                     MSWMessageHandlers);
169 
170 MSWMessageHandlers gs_messageHandlers;
171 
172 // hash containing all our windows, it uses HWND keys and wxWindow* values
173 WX_DECLARE_HASH_MAP(HWND, wxWindow *,
174                     wxPointerHash, wxPointerEqual,
175                     WindowHandles);
176 
177 WindowHandles gs_windowHandles;
178 
179 #ifdef wxHAS_MSW_BACKGROUND_ERASE_HOOK
180 
181 // temporary override for WM_ERASEBKGND processing: we don't store this in
182 // wxWindow itself as we don't need it during most of the time so don't
183 // increase the size of all window objects unnecessarily
184 WX_DECLARE_HASH_MAP(wxWindow *, wxWindow *,
185                     wxPointerHash, wxPointerEqual,
186                     EraseBgHooks);
187 
188 EraseBgHooks gs_eraseBgHooks;
189 
190 #endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK
191 
192 // If this variable is strictly positive, EVT_CHAR_HOOK is not generated for
193 // Escape key presses as it can't be intercepted because it's needed by some
194 // currently shown window, e.g. IME entry.
195 //
196 // This is currently global as we allow using UI from the main thread only
197 // anyhow but could be replaced with a thread-specific value in the future if
198 // needed.
199 int gs_modalEntryWindowCount = 0;
200 
201 // Indicates whether we are currently processing WM_CAPTURECHANGED message.
202 bool gs_insideCaptureChanged = false;
203 
204 } // anonymous namespace
205 
206 #ifdef WM_GESTURE
207 
208 namespace
209 {
210 
211 // Class used to dynamically load gestures related API functions.
212 class GestureFuncs
213 {
214 public:
215     // Must be called before using any other methods of this class (and they
216     // can't be used if this one returns false).
IsOk()217     static bool IsOk()
218     {
219         if ( !ms_gestureSymbolsLoaded )
220         {
221             ms_gestureSymbolsLoaded = true;
222             LoadGestureSymbols();
223         }
224 
225         return ms_pfnGetGestureInfo &&
226                 ms_pfnCloseGestureInfoHandle &&
227                     ms_pfnSetGestureConfig;
228     }
229 
230     typedef BOOL (WINAPI *GetGestureInfo_t)(HGESTUREINFO, PGESTUREINFO);
231 
GetGestureInfo()232     static GetGestureInfo_t GetGestureInfo()
233     {
234         return ms_pfnGetGestureInfo;
235     }
236 
237     typedef BOOL (WINAPI *CloseGestureInfoHandle_t)(HGESTUREINFO);
238 
CloseGestureInfoHandle()239     static CloseGestureInfoHandle_t CloseGestureInfoHandle()
240     {
241         return ms_pfnCloseGestureInfoHandle;
242     }
243 
244     typedef BOOL
245         (WINAPI *SetGestureConfig_t)(HWND, DWORD, UINT, PGESTURECONFIG, UINT);
246 
SetGestureConfig()247     static SetGestureConfig_t SetGestureConfig()
248     {
249         return ms_pfnSetGestureConfig;
250     }
251 
252 private:
LoadGestureSymbols()253     static void LoadGestureSymbols()
254     {
255         wxLoadedDLL dll(wxS("user32.dll"));
256 
257         wxDL_INIT_FUNC(ms_pfn, GetGestureInfo, dll);
258         wxDL_INIT_FUNC(ms_pfn, CloseGestureInfoHandle, dll);
259         wxDL_INIT_FUNC(ms_pfn, SetGestureConfig, dll);
260     }
261 
262     static GetGestureInfo_t ms_pfnGetGestureInfo;
263     static CloseGestureInfoHandle_t ms_pfnCloseGestureInfoHandle;
264     static SetGestureConfig_t ms_pfnSetGestureConfig;
265 
266     static bool ms_gestureSymbolsLoaded;
267 };
268 
269 GestureFuncs::GetGestureInfo_t
270     GestureFuncs::ms_pfnGetGestureInfo = NULL;
271 GestureFuncs::CloseGestureInfoHandle_t
272     GestureFuncs::ms_pfnCloseGestureInfoHandle = NULL;
273 GestureFuncs::SetGestureConfig_t
274     GestureFuncs::ms_pfnSetGestureConfig = NULL;
275 
276 bool GestureFuncs::ms_gestureSymbolsLoaded = false;
277 
278 } // anonymous namespace
279 
280 #endif // WM_GESTURE
281 
282 // ---------------------------------------------------------------------------
283 // private functions
284 // ---------------------------------------------------------------------------
285 
286 // the window proc for all our windows
287 LRESULT WXDLLEXPORT APIENTRY
288 wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
289 
290 #if wxDEBUG_LEVEL >= 2
291 const wxChar *wxGetMessageName(int message);
292 
293 inline
wxTraceMSWMessage(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)294 void wxTraceMSWMessage(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
295 {
296     // The casts to size_t allow to avoid having different code for Win32 and
297     // Win64 as size_t is of the right size in both cases, unlike int or long.
298     wxLogTrace("winmsg",
299                wxT("Processing %s(hWnd=%p, wParam=%zx, lParam=%zx)"),
300                wxGetMessageName(message),
301                hWnd,
302                static_cast<size_t>(wParam),
303                static_cast<size_t>(lParam));
304 }
305 #endif  // wxDEBUG_LEVEL >= 2
306 
307 void wxRemoveHandleAssociation(wxWindowMSW *win);
308 extern void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win);
309 
310 // get the text metrics for the current font
311 static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win);
312 
313 // wrapper around BringWindowToTop() API
wxBringWindowToTop(HWND hwnd)314 static inline void wxBringWindowToTop(HWND hwnd)
315 {
316     // raise top level parent to top of z order
317     if (!::SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE))
318     {
319         wxLogLastError(wxT("SetWindowPos"));
320     }
321 }
322 
323 // ensure that all our parent windows have WS_EX_CONTROLPARENT style
EnsureParentHasControlParentStyle(wxWindow * parent)324 static void EnsureParentHasControlParentStyle(wxWindow *parent)
325 {
326     /*
327        If we have WS_EX_CONTROLPARENT flag we absolutely *must* set it for our
328        parent as well as otherwise several Win32 functions using
329        GetNextDlgTabItem() to iterate over all controls such as
330        IsDialogMessage() or DefDlgProc() would enter an infinite loop: indeed,
331        all of them iterate over all the controls starting from the currently
332        focused one and stop iterating when they get back to the focus but
333        unless all parents have WS_EX_CONTROLPARENT bit set, they would never
334        get back to the initial (focused) window: as we do have this style,
335        GetNextDlgTabItem() will leave this window and continue in its parent,
336        but if the parent doesn't have it, it wouldn't recurse inside it later
337        on and so wouldn't have a chance of getting back to this window either.
338      */
339     while ( parent && !parent->IsTopLevel() )
340     {
341         // force the parent to have this style
342         wxMSWWinExStyleUpdater(GetHwndOf(parent)).TurnOn(WS_EX_CONTROLPARENT);
343 
344         parent = parent->GetParent();
345     }
346 }
347 
348 // GetCursorPos can return an error, so use this function
349 // instead.
350 // Error observed when using Remote Desktop to connect to XP.
wxGetCursorPosMSW(POINT * pt)351 void wxGetCursorPosMSW(POINT* pt)
352 {
353     if (!GetCursorPos(pt))
354     {
355         DWORD pos = GetMessagePos();
356         // the coordinates may be negative in multi-monitor systems
357         pt->x = GET_X_LPARAM(pos);
358         pt->y = GET_Y_LPARAM(pos);
359     }
360 }
361 
362 // ---------------------------------------------------------------------------
363 // event tables
364 // ---------------------------------------------------------------------------
365 
366 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
367 // method
368 #ifdef __WXUNIVERSAL__
369     wxIMPLEMENT_ABSTRACT_CLASS(wxWindowMSW, wxWindowBase);
370 #endif // __WXUNIVERSAL__
371 
wxBEGIN_EVENT_TABLE(wxWindowMSW,wxWindowBase)372 wxBEGIN_EVENT_TABLE(wxWindowMSW, wxWindowBase)
373     EVT_SYS_COLOUR_CHANGED(wxWindowMSW::OnSysColourChanged)
374 wxEND_EVENT_TABLE()
375 
376 // ===========================================================================
377 // implementation
378 // ===========================================================================
379 
380 // ---------------------------------------------------------------------------
381 // wxWindow utility functions
382 // ---------------------------------------------------------------------------
383 
384 // Find an item given the MS Windows id
385 wxWindow *wxWindowMSW::FindItem(long id, WXHWND hWnd) const
386 {
387     // First check for the control itself and its Windows-level children which
388     // are mapped to the same wxWindow at wx level.
389     wxWindow *wnd = MSWFindItem(id, hWnd);
390     if ( wnd )
391         return wnd;
392 
393     // Then check wx level children.
394     wxWindowList::compatibility_iterator current = GetChildren().GetFirst();
395     while (current)
396     {
397         wxWindow *childWin = current->GetData();
398 
399         wnd = childWin->FindItem(id, hWnd);
400         if ( wnd )
401             return wnd;
402 
403         current = current->GetNext();
404     }
405 
406     return NULL;
407 }
408 
409 // Find an item given the MS Windows handle
FindItemByHWND(WXHWND hWnd,bool controlOnly) const410 wxWindow *wxWindowMSW::FindItemByHWND(WXHWND hWnd, bool controlOnly) const
411 {
412     wxWindowList::compatibility_iterator current = GetChildren().GetFirst();
413     while (current)
414     {
415         wxWindow *parent = current->GetData();
416 
417         // Do a recursive search.
418         wxWindow *wnd = parent->FindItemByHWND(hWnd);
419         if ( wnd )
420             return wnd;
421 
422         if ( !controlOnly
423 #if wxUSE_CONTROLS
424                 || wxDynamicCast(parent, wxControl)
425 #endif // wxUSE_CONTROLS
426            )
427         {
428             wxWindow *item = current->GetData();
429             if ( item->GetHWND() == hWnd )
430                 return item;
431             else
432             {
433                 if ( item->ContainsHWND(hWnd) )
434                     return item;
435             }
436         }
437 
438         current = current->GetNext();
439     }
440     return NULL;
441 }
442 
443 // Default command handler
MSWCommand(WXUINT WXUNUSED (param),WXWORD WXUNUSED (id))444 bool wxWindowMSW::MSWCommand(WXUINT WXUNUSED(param), WXWORD WXUNUSED(id))
445 {
446     return false;
447 }
448 
449 // ----------------------------------------------------------------------------
450 // constructors and such
451 // ----------------------------------------------------------------------------
452 
Init()453 void wxWindowMSW::Init()
454 {
455     // MSW specific
456     m_oldWndProc = NULL;
457     m_mouseInWindow = false;
458     m_lastKeydownProcessed = false;
459 
460     m_hWnd = 0;
461 
462     m_xThumbSize = 0;
463     m_yThumbSize = 0;
464 
465 #if wxUSE_DEFERRED_SIZING
466     m_hDWP = 0;
467     m_pendingPosition = wxDefaultPosition;
468     m_pendingSize = wxDefaultSize;
469 #endif // wxUSE_DEFERRED_SIZING
470 
471 }
472 
473 // Destructor
~wxWindowMSW()474 wxWindowMSW::~wxWindowMSW()
475 {
476     SendDestroyEvent();
477 
478     // VS: destroy children first and _then_ detach *this from its parent.
479     //     If we did it the other way around, children wouldn't be able
480     //     find their parent frame.
481     DestroyChildren();
482 
483     if ( m_hWnd )
484     {
485         // VZ: test temp removed to understand what really happens here
486         //if (::IsWindow(GetHwnd()))
487         {
488             if ( !::DestroyWindow(GetHwnd()) )
489             {
490                 wxLogLastError(wxT("DestroyWindow"));
491             }
492         }
493 
494         // remove hWnd <-> wxWindow association
495         wxRemoveHandleAssociation(this);
496     }
497 
498 }
499 
GetMSWClassName(long style)500 const wxChar *wxWindowMSW::GetMSWClassName(long style)
501 {
502     return wxApp::GetRegisteredClassName
503                   (
504                     wxT("wxWindow"),
505                     COLOR_BTNFACE,
506                     0, // no special extra style
507                     (style & wxFULL_REPAINT_ON_RESIZE) ? wxApp::RegClass_Default
508                                                        : wxApp::RegClass_ReturnNR
509                   );
510 }
511 
512 // real construction (Init() must have been called before!)
CreateUsingMSWClass(const wxChar * classname,wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxString & name)513 bool wxWindowMSW::CreateUsingMSWClass(const wxChar* classname,
514                                       wxWindow *parent,
515                                       wxWindowID id,
516                                       const wxPoint& pos,
517                                       const wxSize& size,
518                                       long style,
519                                       const wxString& name)
520 {
521     wxCHECK_MSG( parent, false, wxT("can't create wxWindow without parent") );
522 
523     if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) )
524         return false;
525 
526     parent->AddChild(this);
527 
528     WXDWORD exstyle;
529     DWORD msflags = MSWGetCreateWindowFlags(&exstyle);
530 
531 #ifdef __WXUNIVERSAL__
532     // no borders, we draw them ourselves
533     exstyle &= ~(WS_EX_DLGMODALFRAME |
534                  WS_EX_STATICEDGE |
535                  WS_EX_CLIENTEDGE |
536                  WS_EX_WINDOWEDGE);
537     msflags &= ~WS_BORDER;
538 #endif // wxUniversal
539 
540     if ( IsShown() )
541     {
542         msflags |= WS_VISIBLE;
543     }
544 
545     if ( !MSWCreate(classname, NULL, pos, size, msflags, exstyle) )
546         return false;
547 
548     InheritAttributes();
549 
550     return true;
551 }
552 
SetId(wxWindowID winid)553 void wxWindowMSW::SetId(wxWindowID winid)
554 {
555     wxWindowBase::SetId(winid);
556 
557     // Also update the ID used at the Windows level to avoid nasty surprises
558     // when we can't find the control when handling messages for it after
559     // changing its ID because Windows still uses the old one.
560     if ( GetHwnd() )
561     {
562         ::SetLastError(0);
563 
564         if ( !::SetWindowLong(GetHwnd(), GWL_ID, winid) )
565         {
566             const DWORD err = ::GetLastError();
567             if ( err )
568                 wxLogApiError(wxT("SetWindowLong(GWL_ID)"), err);
569         }
570     }
571 }
572 
573 // ---------------------------------------------------------------------------
574 // basic operations
575 // ---------------------------------------------------------------------------
576 
SetFocus()577 void wxWindowMSW::SetFocus()
578 {
579     HWND hWnd = (HWND)MSWGetFocusHWND();
580     wxCHECK_RET( hWnd, wxT("can't set focus to invalid window") );
581 
582     ::SetLastError(0);
583 
584     if ( !::SetFocus(hWnd) )
585     {
586         // was there really an error?
587         DWORD dwRes = ::GetLastError();
588         if ( dwRes )
589         {
590             HWND hwndFocus = ::GetFocus();
591             if ( hwndFocus != hWnd )
592             {
593                 wxLogApiError(wxT("SetFocus"), dwRes);
594             }
595         }
596     }
597 }
598 
SetFocusFromKbd()599 void wxWindowMSW::SetFocusFromKbd()
600 {
601     HWND hWnd = (HWND)MSWGetFocusHWND();
602 
603     // when the focus is given to the control with DLGC_HASSETSEL style from
604     // keyboard its contents should be entirely selected: this is what
605     // ::IsDialogMessage() does and so we should do it as well to provide the
606     // same LNF as the native programs
607     if ( ::SendMessage(hWnd, WM_GETDLGCODE, 0, 0) & DLGC_HASSETSEL )
608     {
609         ::SendMessage(hWnd, EM_SETSEL, 0, -1);
610     }
611 
612     // do this after (maybe) setting the selection as like this when
613     // wxEVT_SET_FOCUS handler is called, the selection would have been already
614     // set correctly -- this may be important
615     wxWindowBase::SetFocusFromKbd();
616 }
617 
618 // Get the window with the focus
DoFindFocus()619 wxWindow *wxWindowBase::DoFindFocus()
620 {
621     HWND hWnd = ::GetFocus();
622     if ( hWnd )
623     {
624         return wxGetWindowFromHWND((WXHWND)hWnd);
625     }
626 
627     return NULL;
628 }
629 
DoEnable(bool enable)630 void wxWindowMSW::DoEnable( bool enable )
631 {
632     MSWEnableHWND(GetHwnd(), enable);
633 }
634 
MSWEnableHWND(WXHWND hWnd,bool enable)635 bool wxWindowMSW::MSWEnableHWND(WXHWND hWnd, bool enable)
636 {
637     if ( !hWnd )
638         return false;
639 
640     // If disabling focused control, we move focus to the next one, as if the
641     // user pressed Tab. That's because we can't keep focus on a disabled
642     // control, Tab-navigation would stop working then.
643     if ( !enable && ::GetFocus() == hWnd )
644         Navigate();
645 
646     return ::EnableWindow(hWnd, (BOOL)enable) != 0;
647 }
648 
Show(bool show)649 bool wxWindowMSW::Show(bool show)
650 {
651     if ( !wxWindowBase::Show(show) )
652         return false;
653 
654     HWND hWnd = GetHwnd();
655 
656     // we could be called before the underlying window is created (this is
657     // actually useful to prevent it from being initially shown), e.g.
658     //
659     //      wxFoo *foo = new wxFoo;
660     //      foo->Hide();
661     //      foo->Create(parent, ...);
662     //
663     // should work without errors
664     if ( hWnd )
665     {
666         ::ShowWindow(hWnd, show ? SW_SHOW : SW_HIDE);
667     }
668 
669     if ( IsFrozen() )
670     {
671         // DoFreeze/DoThaw don't do anything if the window is not shown, so
672         // we have to call them from here now
673         if ( show )
674             DoFreeze();
675         else
676             DoThaw();
677     }
678 
679     return true;
680 }
681 
682 bool
MSWShowWithEffect(bool show,wxShowEffect effect,unsigned timeout)683 wxWindowMSW::MSWShowWithEffect(bool show,
684                                wxShowEffect effect,
685                                unsigned timeout)
686 {
687 #if wxUSE_DYNLIB_CLASS
688     if ( effect == wxSHOW_EFFECT_NONE ||
689             (GetParent() && !GetParent()->IsShownOnScreen()) )
690         return Show(show);
691 
692     if ( !wxWindowBase::Show(show) )
693         return false;
694 
695     // Show() has a side effect of sending a WM_SIZE to the window, which helps
696     // ensuring that it's laid out correctly, but AnimateWindow() doesn't do
697     // this so send the event ourselves
698     SendSizeEvent();
699 
700     // prepare to use AnimateWindow()
701 
702     if ( !timeout )
703         timeout = 200; // this is the default animation timeout, per MSDN
704 
705     DWORD dwFlags = show ? 0 : AW_HIDE;
706 
707     switch ( effect )
708     {
709         case wxSHOW_EFFECT_ROLL_TO_LEFT:
710             dwFlags |= AW_HOR_NEGATIVE;
711             break;
712 
713         case wxSHOW_EFFECT_ROLL_TO_RIGHT:
714             dwFlags |= AW_HOR_POSITIVE;
715             break;
716 
717         case wxSHOW_EFFECT_ROLL_TO_TOP:
718             dwFlags |= AW_VER_NEGATIVE;
719             break;
720 
721         case wxSHOW_EFFECT_ROLL_TO_BOTTOM:
722             dwFlags |= AW_VER_POSITIVE;
723             break;
724 
725         case wxSHOW_EFFECT_SLIDE_TO_LEFT:
726             dwFlags |= AW_SLIDE | AW_HOR_NEGATIVE;
727             break;
728 
729         case wxSHOW_EFFECT_SLIDE_TO_RIGHT:
730             dwFlags |= AW_SLIDE | AW_HOR_POSITIVE;
731             break;
732 
733         case wxSHOW_EFFECT_SLIDE_TO_TOP:
734             dwFlags |= AW_SLIDE | AW_VER_NEGATIVE;
735             break;
736 
737         case wxSHOW_EFFECT_SLIDE_TO_BOTTOM:
738             dwFlags |= AW_SLIDE | AW_VER_POSITIVE;
739             break;
740 
741         case wxSHOW_EFFECT_BLEND:
742             dwFlags |= AW_BLEND;
743             break;
744 
745         case wxSHOW_EFFECT_EXPAND:
746             dwFlags |= AW_CENTER;
747             break;
748 
749 
750         case wxSHOW_EFFECT_MAX:
751             wxFAIL_MSG( wxT("invalid window show effect") );
752             return false;
753 
754         default:
755             wxFAIL_MSG( wxT("unknown window show effect") );
756             return false;
757     }
758 
759     if ( !::AnimateWindow(GetHwnd(), timeout, dwFlags) )
760     {
761         wxLogLastError(wxT("AnimateWindow"));
762 
763         return false;
764     }
765 
766     return true;
767 #else    // wxUSE_DYNLIB_CLASS
768     return Show(show);
769 #endif
770 }
771 
772 // Raise the window to the top of the Z order
Raise()773 void wxWindowMSW::Raise()
774 {
775     wxBringWindowToTop(GetHwnd());
776 }
777 
778 // Lower the window to the bottom of the Z order
Lower()779 void wxWindowMSW::Lower()
780 {
781     ::SetWindowPos(GetHwnd(), HWND_BOTTOM, 0, 0, 0, 0,
782                    SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
783 }
784 
DoCaptureMouse()785 void wxWindowMSW::DoCaptureMouse()
786 {
787     HWND hWnd = GetHwnd();
788     if ( hWnd )
789     {
790         ::SetCapture(hWnd);
791     }
792 }
793 
DoReleaseMouse()794 void wxWindowMSW::DoReleaseMouse()
795 {
796     if ( !::ReleaseCapture() )
797     {
798         wxLogLastError(wxT("ReleaseCapture"));
799     }
800 }
801 
GetCapture()802 /* static */ wxWindow *wxWindowBase::GetCapture()
803 {
804     // When we receive WM_CAPTURECHANGED message, ::GetCapture() still returns
805     // the HWND that is losing the mouse capture. But as we must not release
806     // the capture for it (it's going to happen anyhow), pretend that there is
807     // no capture any more.
808     if ( gs_insideCaptureChanged )
809         return NULL;
810 
811     HWND hwnd = ::GetCapture();
812     return hwnd ? wxFindWinFromHandle(hwnd) : NULL;
813 }
814 
SetFont(const wxFont & font)815 bool wxWindowMSW::SetFont(const wxFont& font)
816 {
817     if ( !wxWindowBase::SetFont(font) )
818     {
819         // nothing to do
820         return false;
821     }
822 
823     HWND hWnd = GetHwnd();
824     if ( hWnd != 0 )
825     {
826         // note the use of GetFont() instead of m_font: our own font could have
827         // just been reset and in this case we need to change the font used by
828         // the native window to the default for this class, i.e. exactly what
829         // GetFont() returns
830         wxSetWindowFont(hWnd, GetFont());
831     }
832 
833     return true;
834 }
835 
SetCursor(const wxCursor & cursor)836 bool wxWindowMSW::SetCursor(const wxCursor& cursor)
837 {
838     if ( !wxWindowBase::SetCursor(cursor) )
839     {
840         // no change
841         return false;
842     }
843 
844     // don't "overwrite" busy cursor
845     if ( wxIsBusy() )
846         return true;
847 
848     if ( m_cursor.IsOk() )
849     {
850         // normally we should change the cursor only if it's over this window
851         // but we should do it always if we capture the mouse currently
852         bool set = HasCapture();
853         if ( !set )
854         {
855             HWND hWnd = GetHwnd();
856 
857             POINT point;
858             ::wxGetCursorPosMSW(&point);
859 
860             RECT rect = wxGetWindowRect(hWnd);
861 
862             set = ::PtInRect(&rect, point) != 0;
863         }
864 
865         if ( set )
866         {
867             ::SetCursor(GetHcursorOf(m_cursor));
868         }
869         //else: will be set later when the mouse enters this window
870     }
871     else // Invalid cursor: this means reset to the default one.
872     {
873         // To revert to the correct cursor we need to find the window currently
874         // under the cursor and ask it to set its cursor itself as only it
875         // knows what it is.
876         POINT pt;
877         wxGetCursorPosMSW(&pt);
878 
879         const wxWindowMSW* win = wxFindWindowAtPoint(wxPoint(pt.x, pt.y));
880         if ( !win )
881             win = this;
882 
883         ::SendMessage(GetHwndOf(win), WM_SETCURSOR,
884                       (WPARAM)GetHwndOf(win),
885                       MAKELPARAM(HTCLIENT, WM_MOUSEMOVE));
886     }
887 
888     return true;
889 }
890 
WarpPointer(int x,int y)891 void wxWindowMSW::WarpPointer(int x, int y)
892 {
893     ClientToScreen(&x, &y);
894 
895     if ( !::SetCursorPos(x, y) )
896     {
897         wxLogLastError(wxT("SetCursorPos"));
898     }
899 }
900 
EnableTouchEvents(int eventsMask)901 bool wxWindowMSW::EnableTouchEvents(int eventsMask)
902 {
903 #ifdef WM_GESTURE
904     if ( GestureFuncs::IsOk() )
905     {
906         // Static struct used when we need to use just a single configuration.
907         GESTURECONFIG config = {0, 0, 0};
908 
909         GESTURECONFIG* ptrConfigs = &config;
910         UINT numConfigs = 1;
911 
912         // This is used only if we need to allocate the configurations
913         // dynamically.
914         wxVector<GESTURECONFIG> configs;
915 
916         // There are two simple cases: enabling or disabling all gestures.
917         if ( eventsMask == wxTOUCH_NONE )
918         {
919             config.dwBlock = GC_ALLGESTURES;
920         }
921         else if ( eventsMask == wxTOUCH_ALL_GESTURES )
922         {
923             config.dwWant = GC_ALLGESTURES;
924         }
925         else // Need to enable the individual gestures
926         {
927             int wantedPan = 0;
928             switch ( eventsMask & wxTOUCH_PAN_GESTURES )
929             {
930                 case wxTOUCH_VERTICAL_PAN_GESTURE:
931                     wantedPan = GC_PAN_WITH_SINGLE_FINGER_VERTICALLY;
932                     break;
933 
934                 case wxTOUCH_HORIZONTAL_PAN_GESTURE:
935                     wantedPan = GC_PAN_WITH_SINGLE_FINGER_HORIZONTALLY;
936                     break;
937 
938                 case wxTOUCH_PAN_GESTURES:
939                     wantedPan = GC_PAN;
940                     break;
941 
942                 case 0:
943                     // This is the only other possibility and wantedPan is
944                     // already initialized to 0 anyhow, so don't do anything,
945                     // just list it for completeness.
946                     break;
947             }
948 
949             if ( wantedPan )
950             {
951                 eventsMask &= ~wxTOUCH_PAN_GESTURES;
952 
953                 config.dwID = GID_PAN;
954                 config.dwWant = wantedPan;
955                 configs.push_back(config);
956             }
957 
958             if ( eventsMask & wxTOUCH_ZOOM_GESTURE )
959             {
960                 eventsMask &= ~wxTOUCH_ZOOM_GESTURE;
961 
962                 config.dwID = GID_ZOOM;
963                 config.dwWant = GC_ZOOM;
964                 configs.push_back(config);
965             }
966 
967             if ( eventsMask & wxTOUCH_ROTATE_GESTURE )
968             {
969                 eventsMask &= ~wxTOUCH_ROTATE_GESTURE;
970 
971                 config.dwID = GID_ROTATE;
972                 config.dwWant = GC_ROTATE;
973                 configs.push_back(config);
974             }
975 
976             if ( eventsMask & wxTOUCH_PRESS_GESTURES )
977             {
978                 eventsMask &= ~wxTOUCH_PRESS_GESTURES;
979 
980                 config.dwID = GID_TWOFINGERTAP;
981                 config.dwWant = GC_TWOFINGERTAP;
982                 configs.push_back(config);
983 
984                 config.dwID = GID_PRESSANDTAP;
985                 config.dwWant = GC_PRESSANDTAP;
986                 configs.push_back(config);
987             }
988 
989             // As we clear all the known bits if they're set in the code above,
990             // there should be nothing left.
991             wxCHECK_MSG( eventsMask == 0, false,
992                          wxS("Unknown touch event mask bit specified") );
993 
994             ptrConfigs = &configs[0];
995         }
996 
997         if ( !GestureFuncs::SetGestureConfig()
998              (
999                 m_hWnd,
1000                 wxRESERVED_PARAM,
1001                 numConfigs,             // Number of gesture configurations.
1002                 ptrConfigs,             // Pointer to the first one.
1003                 sizeof(GESTURECONFIG)   // Size of each configuration.
1004              )
1005            )
1006         {
1007             wxLogLastError("SetGestureConfig");
1008             return false;
1009         }
1010 
1011         return true;
1012     }
1013 #endif // WM_GESTURE
1014 
1015     return wxWindowBase::EnableTouchEvents(eventsMask);
1016 }
1017 
MSWUpdateUIState(int action,int state)1018 void wxWindowMSW::MSWUpdateUIState(int action, int state)
1019 {
1020     // we send WM_CHANGEUISTATE so if nothing needs changing then the system
1021     // won't send WM_UPDATEUISTATE
1022     ::SendMessage(GetHwnd(), WM_CHANGEUISTATE, MAKEWPARAM(action, state), 0);
1023 }
1024 
1025 // ---------------------------------------------------------------------------
1026 // scrolling stuff
1027 // ---------------------------------------------------------------------------
1028 
1029 namespace
1030 {
1031 
GetScrollPosition(HWND hWnd,int wOrient)1032 inline int GetScrollPosition(HWND hWnd, int wOrient)
1033 {
1034     WinStruct<SCROLLINFO> scrollInfo;
1035     scrollInfo.cbSize = sizeof(SCROLLINFO);
1036     scrollInfo.fMask = SIF_POS;
1037     ::GetScrollInfo(hWnd, wOrient, &scrollInfo );
1038 
1039     return scrollInfo.nPos;
1040 }
1041 
WXOrientToSB(int orient)1042 inline UINT WXOrientToSB(int orient)
1043 {
1044     return orient == wxHORIZONTAL ? SB_HORZ : SB_VERT;
1045 }
1046 
1047 } // anonymous namespace
1048 
GetScrollPos(int orient) const1049 int wxWindowMSW::GetScrollPos(int orient) const
1050 {
1051     HWND hWnd = GetHwnd();
1052     wxCHECK_MSG( hWnd, 0, wxT("no HWND in GetScrollPos") );
1053 
1054     return GetScrollPosition(hWnd, WXOrientToSB(orient));
1055 }
1056 
1057 // This now returns the whole range, not just the number
1058 // of positions that we can scroll.
GetScrollRange(int orient) const1059 int wxWindowMSW::GetScrollRange(int orient) const
1060 {
1061     int maxPos;
1062     HWND hWnd = GetHwnd();
1063     if ( !hWnd )
1064         return 0;
1065     WinStruct<SCROLLINFO> scrollInfo;
1066     scrollInfo.fMask = SIF_RANGE;
1067     if ( !::GetScrollInfo(hWnd, WXOrientToSB(orient), &scrollInfo) )
1068     {
1069         // Most of the time this is not really an error, since the return
1070         // value can also be zero when there is no scrollbar yet.
1071         // wxLogLastError(wxT("GetScrollInfo"));
1072     }
1073     maxPos = scrollInfo.nMax;
1074 
1075     // undo "range - 1" done in SetScrollbar()
1076     return maxPos + 1;
1077 }
1078 
GetScrollThumb(int orient) const1079 int wxWindowMSW::GetScrollThumb(int orient) const
1080 {
1081     return orient == wxHORIZONTAL ? m_xThumbSize : m_yThumbSize;
1082 }
1083 
SetScrollPos(int orient,int pos,bool refresh)1084 void wxWindowMSW::SetScrollPos(int orient, int pos, bool refresh)
1085 {
1086     HWND hWnd = GetHwnd();
1087     wxCHECK_RET( hWnd, wxT("SetScrollPos: no HWND") );
1088 
1089     WinStruct<SCROLLINFO> info;
1090     info.nPage = 0;
1091     info.nMin = 0;
1092     info.nPos = pos;
1093     info.fMask = SIF_POS;
1094     if ( HasFlag(wxALWAYS_SHOW_SB) )
1095     {
1096         // disable scrollbar instead of removing it then
1097         info.fMask |= SIF_DISABLENOSCROLL;
1098     }
1099 
1100     ::SetScrollInfo(hWnd, WXOrientToSB(orient), &info, refresh);
1101 }
1102 
1103 // New function that will replace some of the above.
SetScrollbar(int orient,int pos,int pageSize,int range,bool refresh)1104 void wxWindowMSW::SetScrollbar(int orient,
1105                                int pos,
1106                                int pageSize,
1107                                int range,
1108                                bool refresh)
1109 {
1110 #if wxUSE_DEFERRED_SIZING
1111     // Work around not documented, but reliably happening, at least under
1112     // Windows 7, but with changing the scrollbars in the middle of a deferred
1113     // positioning operation: the child windows of a window whose position is
1114     // deferred after changing the scrollbar get offset compared to their
1115     // correct position, somehow.
1116     //
1117     // Note that this scenario happens all the time with wxScrolledWindow as
1118     // its HandleOnSize(), which calls AdjustScrollbars() and hence this method
1119     // indirectly, gets called from WM_SIZE handler, which begins deferring
1120     // window positions, and calls Layout() which continues doing it after the
1121     // scrollbar update. So one way of reproducing the bug is to have a window
1122     // with children, such as wxStaticBox, inside a wxScrolledWindow whose size
1123     // gets changed.
1124     //
1125     // Fix this simply by "flushing" the pending windows positions and starting
1126     // a new deferring operation.
1127     if ( m_hDWP )
1128     {
1129         // Do reposition the children already moved.
1130         EndRepositioningChildren();
1131 
1132         // And restart another deferred positioning operation as any currently
1133         // existing ChildrenRepositioningGuard objects would be confused if we
1134         // just removed the HDWP from under them.
1135         //
1136         // Unfortunately we have to ignore BeginRepositioningChildren() return
1137         // value here, there is not much that we can do if it fails (but this
1138         // should never happen anyhow).
1139         BeginRepositioningChildren();
1140     }
1141 #endif // wxUSE_DEFERRED_SIZING
1142 
1143     // We have to set the variables here to make them valid in events
1144     // triggered by ::SetScrollInfo()
1145     *(orient == wxHORIZONTAL ? &m_xThumbSize : &m_yThumbSize) = pageSize;
1146 
1147     HWND hwnd = GetHwnd();
1148     if ( !hwnd )
1149         return;
1150 
1151     WinStruct<SCROLLINFO> info;
1152     if ( range != -1 )
1153     {
1154         info.nPage = pageSize;
1155         info.nMin = 0;              // range is nMax - nMin + 1
1156         info.nMax = range - 1;      //  as both nMax and nMax are inclusive
1157         info.nPos = pos;
1158 
1159         // We normally also reenable scrollbar in case it had been previously
1160         // disabled by specifying SIF_DISABLENOSCROLL below but we should only
1161         // do this if it has valid range, otherwise it would be enabled but not
1162         // do anything.
1163         if ( range >= pageSize )
1164         {
1165             ::EnableScrollBar(hwnd, WXOrientToSB(orient), ESB_ENABLE_BOTH);
1166         }
1167     }
1168     //else: leave all the fields to be 0
1169 
1170     info.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
1171     if ( HasFlag(wxALWAYS_SHOW_SB) || range == -1 )
1172     {
1173         // disable scrollbar instead of removing it then
1174         info.fMask |= SIF_DISABLENOSCROLL;
1175     }
1176 
1177     ::SetScrollInfo(hwnd, WXOrientToSB(orient), &info, refresh);
1178 }
1179 
ScrollWindow(int dx,int dy,const wxRect * prect)1180 void wxWindowMSW::ScrollWindow(int dx, int dy, const wxRect *prect)
1181 {
1182     if ( !dx && !dy )
1183         return;
1184 
1185     RECT rect;
1186     RECT *pr;
1187     if ( prect )
1188     {
1189         wxCopyRectToRECT(*prect, rect);
1190         pr = &rect;
1191     }
1192     else
1193     {
1194         pr = NULL;
1195 
1196     }
1197 
1198     ::ScrollWindow(GetHwnd(), dx, dy, pr, pr);
1199 }
1200 
ScrollVertically(HWND hwnd,int kind,int count)1201 static bool ScrollVertically(HWND hwnd, int kind, int count)
1202 {
1203     int posStart = GetScrollPosition(hwnd, SB_VERT);
1204 
1205     int pos = posStart;
1206     for ( int n = 0; n < count; n++ )
1207     {
1208         ::SendMessage(hwnd, WM_VSCROLL, kind, 0);
1209 
1210         int posNew = GetScrollPosition(hwnd, SB_VERT);
1211         if ( posNew == pos )
1212         {
1213             // don't bother to continue, we're already at top/bottom
1214             break;
1215         }
1216 
1217         pos = posNew;
1218     }
1219 
1220     return pos != posStart;
1221 }
1222 
ScrollLines(int lines)1223 bool wxWindowMSW::ScrollLines(int lines)
1224 {
1225     bool down = lines > 0;
1226 
1227     return ScrollVertically(GetHwnd(),
1228                             down ? SB_LINEDOWN : SB_LINEUP,
1229                             down ? lines : -lines);
1230 }
1231 
ScrollPages(int pages)1232 bool wxWindowMSW::ScrollPages(int pages)
1233 {
1234     bool down = pages > 0;
1235 
1236     return ScrollVertically(GetHwnd(),
1237                             down ? SB_PAGEDOWN : SB_PAGEUP,
1238                             down ? pages : -pages);
1239 }
1240 
1241 // ----------------------------------------------------------------------------
1242 // RTL support
1243 // ----------------------------------------------------------------------------
1244 
SetLayoutDirection(wxLayoutDirection dir)1245 void wxWindowMSW::SetLayoutDirection(wxLayoutDirection dir)
1246 {
1247     if ( wxUpdateLayoutDirection(GetHwnd(), dir) )
1248     {
1249         // Update layout: whether we have children or are drawing something, we
1250         // need to redo it with the new layout.
1251         SendSizeEvent();
1252         Refresh();
1253     }
1254 }
1255 
GetLayoutDirection() const1256 wxLayoutDirection wxWindowMSW::GetLayoutDirection() const
1257 {
1258     wxCHECK_MSG( GetHwnd(), wxLayout_Default, wxT("invalid window") );
1259 
1260     return wxHasWindowExStyle(this, WS_EX_LAYOUTRTL) ? wxLayout_RightToLeft
1261                                                      : wxLayout_LeftToRight;
1262 }
1263 
1264 wxCoord
AdjustForLayoutDirection(wxCoord x,wxCoord WXUNUSED (width),wxCoord WXUNUSED (widthTotal)) const1265 wxWindowMSW::AdjustForLayoutDirection(wxCoord x,
1266                                       wxCoord WXUNUSED(width),
1267                                       wxCoord WXUNUSED(widthTotal)) const
1268 {
1269     // Win32 mirrors the coordinates of RTL windows automatically, so don't
1270     // redo it ourselves
1271     return x;
1272 }
1273 
1274 // ---------------------------------------------------------------------------
1275 // subclassing
1276 // ---------------------------------------------------------------------------
1277 
SubclassWin(WXHWND hWnd)1278 void wxWindowMSW::SubclassWin(WXHWND hWnd)
1279 {
1280     wxASSERT_MSG( !m_oldWndProc, wxT("subclassing window twice?") );
1281 
1282     HWND hwnd = (HWND)hWnd;
1283     wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in SubclassWin") );
1284 
1285     SetHWND(hWnd);
1286 
1287     wxAssociateWinWithHandle(hwnd, this);
1288 
1289     m_oldWndProc = wxGetWindowProc((HWND)hWnd);
1290 
1291     // we don't need to subclass the window of our own class (in the Windows
1292     // sense of the word)
1293     if ( !wxCheckWindowWndProc(hWnd) )
1294     {
1295         wxSetWindowProc(hwnd, wxWndProc);
1296 
1297         // If the window didn't use our window proc during its creation, the
1298         // code in HandleCreate() hasn't been executed, so do it here.
1299         if ( wxHasWindowExStyle(this, WS_EX_CONTROLPARENT) )
1300             EnsureParentHasControlParentStyle(GetParent());
1301     }
1302     else
1303     {
1304         // don't bother restoring it either: this also makes it easy to
1305         // implement IsOfStandardClass() method which returns true for the
1306         // standard controls and false for the wxWidgets own windows as it can
1307         // simply check m_oldWndProc
1308         m_oldWndProc = NULL;
1309     }
1310 
1311     // we're officially created now, send the event
1312     wxWindowCreateEvent event((wxWindow *)this);
1313     (void)HandleWindowEvent(event);
1314 }
1315 
UnsubclassWin()1316 void wxWindowMSW::UnsubclassWin()
1317 {
1318     wxRemoveHandleAssociation(this);
1319 
1320     // Restore old Window proc
1321     HWND hwnd = GetHwnd();
1322     if ( hwnd )
1323     {
1324         SetHWND(0);
1325 
1326         wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in UnsubclassWin") );
1327 
1328         if ( m_oldWndProc )
1329         {
1330             if ( !wxCheckWindowWndProc((WXHWND)hwnd) )
1331             {
1332                 wxSetWindowProc(hwnd, m_oldWndProc);
1333             }
1334 
1335             m_oldWndProc = NULL;
1336         }
1337     }
1338 }
1339 
AssociateHandle(WXWidget handle)1340 void wxWindowMSW::AssociateHandle(WXWidget handle)
1341 {
1342     if ( m_hWnd )
1343     {
1344       if ( !::DestroyWindow(GetHwnd()) )
1345       {
1346         wxLogLastError(wxT("DestroyWindow"));
1347       }
1348     }
1349 
1350     WXHWND wxhwnd = (WXHWND)handle;
1351 
1352     // this also calls SetHWND(wxhwnd)
1353     SubclassWin(wxhwnd);
1354 }
1355 
DissociateHandle()1356 void wxWindowMSW::DissociateHandle()
1357 {
1358     // this also calls SetHWND(0) for us
1359     UnsubclassWin();
1360 }
1361 
1362 
wxCheckWindowWndProc(WXHWND hWnd,WXWNDPROC WXUNUSED (wndProc))1363 bool wxCheckWindowWndProc(WXHWND hWnd, WXWNDPROC WXUNUSED(wndProc))
1364 {
1365     const wxString str(wxGetWindowClass(hWnd));
1366 
1367     // TODO: get rid of wxTLWHiddenParent special case (currently it's not
1368     //       registered by wxApp but using ad hoc code in msw/toplevel.cpp);
1369     //       there is also a hidden window class used by sockets &c
1370     return wxApp::IsRegisteredClassName(str) || str == wxT("wxTLWHiddenParent");
1371 }
1372 
1373 // ----------------------------------------------------------------------------
1374 // Style handling
1375 // ----------------------------------------------------------------------------
1376 
SetWindowStyleFlag(long flags)1377 void wxWindowMSW::SetWindowStyleFlag(long flags)
1378 {
1379     long flagsOld = GetWindowStyleFlag();
1380     if ( flags == flagsOld )
1381         return;
1382 
1383     // update the internal variable
1384     wxWindowBase::SetWindowStyleFlag(flags);
1385 
1386     // and the real window flags
1387     MSWUpdateStyle(flagsOld, GetExtraStyle());
1388 }
1389 
SetExtraStyle(long exflags)1390 void wxWindowMSW::SetExtraStyle(long exflags)
1391 {
1392     long exflagsOld = GetExtraStyle();
1393     if ( exflags == exflagsOld )
1394         return;
1395 
1396     // update the internal variable
1397     wxWindowBase::SetExtraStyle(exflags);
1398 
1399     // and the real window flags
1400     MSWUpdateStyle(GetWindowStyleFlag(), exflagsOld);
1401 }
1402 
MSWUpdateStyle(long flagsOld,long exflagsOld)1403 void wxWindowMSW::MSWUpdateStyle(long flagsOld, long exflagsOld)
1404 {
1405     // now update the Windows style as well if needed - and if the window had
1406     // been already created
1407     if ( !GetHwnd() )
1408         return;
1409 
1410     // we may need to call SetWindowPos() when we change some styles
1411     bool callSWP = false;
1412 
1413     WXDWORD exstyle;
1414     long style = MSWGetStyle(GetWindowStyleFlag(), &exstyle);
1415 
1416     // this is quite a horrible hack but we need it because MSWGetStyle()
1417     // doesn't take exflags as parameter but uses GetExtraStyle() internally
1418     // and so we have to modify the window exflags temporarily to get the
1419     // correct exstyleOld
1420     long exflagsNew = GetExtraStyle();
1421     wxWindowBase::SetExtraStyle(exflagsOld);
1422 
1423     WXDWORD exstyleOld;
1424     long styleOld = MSWGetStyle(flagsOld, &exstyleOld);
1425 
1426     wxWindowBase::SetExtraStyle(exflagsNew);
1427 
1428 
1429     if ( style != styleOld )
1430     {
1431         // some flags (e.g. WS_VISIBLE or WS_DISABLED) should not be changed by
1432         // this function so instead of simply setting the style to the new
1433         // value we clear the bits which were set in styleOld but are set in
1434         // the new one and set the ones which were not set before
1435         wxMSWWinStyleUpdater updateStyle(GetHwnd());
1436         updateStyle.TurnOff(styleOld).TurnOn(style);
1437 
1438         // we need to call SetWindowPos() if any of the styles affecting the
1439         // frame appearance have changed
1440         callSWP = ((styleOld ^ style ) & (WS_BORDER |
1441                                       WS_THICKFRAME |
1442                                       WS_CAPTION |
1443                                       WS_DLGFRAME |
1444                                       WS_MAXIMIZEBOX |
1445                                       WS_MINIMIZEBOX |
1446                                       WS_SYSMENU) ) != 0;
1447     }
1448 
1449     // There is one extra complication with the extended style: we must never
1450     // reset WS_EX_CONTROLPARENT because it may break the invariant that the
1451     // parent of any window with this style bit set has it as well. We enforce
1452     // this invariant elsewhere and must not clear it here to avoid the fatal
1453     // problems (hangs) which happen if we break it, so ensure it is preserved.
1454     if ( exstyleOld & WS_EX_CONTROLPARENT )
1455         exstyle |= WS_EX_CONTROLPARENT;
1456 
1457     wxMSWWinExStyleUpdater updateExStyle(GetHwnd());
1458     if ( updateExStyle.TurnOff(exstyleOld).TurnOn(exstyle).Apply() )
1459     {
1460         // ex style changes don't take effect without calling SetWindowPos
1461         callSWP = true;
1462     }
1463 
1464     if ( callSWP )
1465     {
1466         // we must call SetWindowPos() to flush the cached extended style and
1467         // also to make the change to wxSTAY_ON_TOP style take effect: just
1468         // setting the style simply doesn't work
1469         if ( !::SetWindowPos(GetHwnd(),
1470                              updateExStyle.IsOn(WS_EX_TOPMOST) ? HWND_TOPMOST
1471                                                                : HWND_NOTOPMOST,
1472                              0, 0, 0, 0,
1473                              SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE |
1474                              SWP_FRAMECHANGED) )
1475         {
1476             wxLogLastError(wxT("SetWindowPos"));
1477         }
1478     }
1479 }
1480 
GetDefaultBorderForControl() const1481 wxBorder wxWindowMSW::GetDefaultBorderForControl() const
1482 {
1483     return wxBORDER_THEME;
1484 }
1485 
GetDefaultBorder() const1486 wxBorder wxWindowMSW::GetDefaultBorder() const
1487 {
1488     return wxWindowBase::GetDefaultBorder();
1489 }
1490 
1491 // Translate wxBORDER_THEME (and other border styles if necessary) to the value
1492 // that makes most sense for this Windows environment
TranslateBorder(wxBorder border) const1493 wxBorder wxWindowMSW::TranslateBorder(wxBorder border) const
1494 {
1495 #if wxUSE_UXTHEME
1496     if (border == wxBORDER_THEME)
1497     {
1498         if (CanApplyThemeBorder())
1499         {
1500             if ( wxUxThemeIsActive() )
1501                 return wxBORDER_THEME;
1502         }
1503         return wxBORDER_SUNKEN;
1504     }
1505 #endif
1506     return border;
1507 }
1508 
1509 
MSWGetStyle(long flags,WXDWORD * exstyle) const1510 WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const
1511 {
1512     // translate common wxWidgets styles to Windows ones
1513 
1514     // most of windows are child ones, those which are not (such as
1515     // wxTopLevelWindow) should remove WS_CHILD in their MSWGetStyle()
1516     WXDWORD style = WS_CHILD;
1517 
1518     if ( !IsThisEnabled() )
1519         style |= WS_DISABLED;
1520 
1521     // using this flag results in very significant reduction in flicker,
1522     // especially with controls inside the static boxes (as the interior of the
1523     // box is not redrawn twice), but sometimes results in redraw problems, so
1524     // optionally allow the old code to continue to use it provided a special
1525     // system option is turned on
1526     if ( !wxSystemOptions::GetOptionInt(wxT("msw.window.no-clip-children"))
1527             || (flags & wxCLIP_CHILDREN) )
1528         style |= WS_CLIPCHILDREN;
1529 
1530     // it doesn't seem useful to use WS_CLIPSIBLINGS here as we officially
1531     // don't support overlapping windows and it only makes sense for them and,
1532     // presumably, gives the system some extra work (to manage more clipping
1533     // regions), so avoid it altogether
1534 
1535 
1536     if ( flags & wxVSCROLL )
1537         style |= WS_VSCROLL;
1538 
1539     if ( flags & wxHSCROLL )
1540         style |= WS_HSCROLL;
1541 
1542     const wxBorder border = TranslateBorder(GetBorder(flags));
1543 
1544     // After translation, border is now optimized for the specific version of Windows
1545     // and theme engine presence.
1546 
1547     // WS_BORDER is only required for wxBORDER_SIMPLE
1548     if ( border == wxBORDER_SIMPLE )
1549         style |= WS_BORDER;
1550 
1551     // now deal with ext style if the caller wants it
1552     if ( exstyle )
1553     {
1554         *exstyle = 0;
1555 
1556         if ( flags & wxTRANSPARENT_WINDOW )
1557             *exstyle |= WS_EX_TRANSPARENT;
1558 
1559         switch ( border )
1560         {
1561             default:
1562             case wxBORDER_DEFAULT:
1563                 wxFAIL_MSG( wxT("unknown border style") );
1564                 wxFALLTHROUGH;
1565 
1566             case wxBORDER_NONE:
1567             case wxBORDER_SIMPLE:
1568             case wxBORDER_THEME:
1569                 break;
1570 
1571             case wxBORDER_STATIC:
1572                 *exstyle |= WS_EX_STATICEDGE;
1573                 break;
1574 
1575             case wxBORDER_RAISED:
1576                 *exstyle |= WS_EX_DLGMODALFRAME;
1577                 break;
1578 
1579             case wxBORDER_SUNKEN:
1580                 *exstyle |= WS_EX_CLIENTEDGE;
1581                 style &= ~WS_BORDER;
1582                 break;
1583 
1584 //            case wxBORDER_DOUBLE:
1585 //                *exstyle |= WS_EX_DLGMODALFRAME;
1586 //                break;
1587         }
1588 
1589         // wxUniv doesn't use Windows dialog navigation functions at all
1590 #if !defined(__WXUNIVERSAL__)
1591         // to make the dialog navigation work with the nested panels we must
1592         // use this style (top level windows such as dialogs don't need it)
1593         if ( (flags & wxTAB_TRAVERSAL) && !IsTopLevel() )
1594         {
1595             *exstyle |= WS_EX_CONTROLPARENT;
1596         }
1597 #endif // __WXUNIVERSAL__
1598     }
1599 
1600     return style;
1601 }
1602 
1603 // Setup background and foreground colours correctly
SetupColours()1604 void wxWindowMSW::SetupColours()
1605 {
1606     if ( GetParent() )
1607         SetBackgroundColour(GetParent()->GetBackgroundColour());
1608 }
1609 
IsMouseInWindow() const1610 bool wxWindowMSW::IsMouseInWindow() const
1611 {
1612     // get the mouse position
1613     POINT pt;
1614     wxGetCursorPosMSW(&pt);
1615 
1616     // find the window which currently has the cursor and go up the window
1617     // chain until we find this window - or exhaust it
1618     HWND hwnd = ::WindowFromPoint(pt);
1619     while ( hwnd && (hwnd != GetHwnd()) )
1620         hwnd = ::GetParent(hwnd);
1621 
1622     return hwnd != NULL;
1623 }
1624 
OnInternalIdle()1625 void wxWindowMSW::OnInternalIdle()
1626 {
1627 #ifndef HAVE_TRACKMOUSEEVENT
1628     // Check if we need to send a LEAVE event
1629     if ( m_mouseInWindow )
1630     {
1631         // note that we should generate the leave event whether the window has
1632         // or doesn't have mouse capture
1633         if ( !IsMouseInWindow() )
1634         {
1635             GenerateMouseLeave();
1636         }
1637     }
1638 #endif // !HAVE_TRACKMOUSEEVENT
1639 
1640     wxWindowBase::OnInternalIdle();
1641 }
1642 
1643 // Set this window to be the child of 'parent'.
Reparent(wxWindowBase * parent)1644 bool wxWindowMSW::Reparent(wxWindowBase *parent)
1645 {
1646     if ( !wxWindowBase::Reparent(parent) )
1647         return false;
1648 
1649     HWND hWndChild = GetHwnd();
1650     HWND hWndParent = GetParent() ? GetWinHwnd(GetParent()) : (HWND)0;
1651 
1652     ::SetParent(hWndChild, hWndParent);
1653 
1654     if ( wxHasWindowExStyle(this, WS_EX_CONTROLPARENT) )
1655     {
1656         EnsureParentHasControlParentStyle(GetParent());
1657     }
1658 
1659     return true;
1660 }
1661 
SendSetRedraw(HWND hwnd,bool on)1662 static inline void SendSetRedraw(HWND hwnd, bool on)
1663 {
1664     ::SendMessage(hwnd, WM_SETREDRAW, (WPARAM)on, 0);
1665 }
1666 
DoFreeze()1667 void wxWindowMSW::DoFreeze()
1668 {
1669     if ( !IsShown() )
1670         return; // no point in freezing hidden window
1671 
1672     SendSetRedraw(GetHwnd(), false);
1673 }
1674 
DoThaw()1675 void wxWindowMSW::DoThaw()
1676 {
1677     if ( !IsShown() )
1678         return; // hidden windows aren't frozen by DoFreeze
1679 
1680     SendSetRedraw(GetHwnd(), true);
1681 
1682     // we need to refresh everything or otherwise the invalidated area
1683     // is not going to be repainted
1684     Refresh();
1685 }
1686 
Refresh(bool eraseBack,const wxRect * rect)1687 void wxWindowMSW::Refresh(bool eraseBack, const wxRect *rect)
1688 {
1689     HWND hWnd = GetHwnd();
1690     if ( hWnd )
1691     {
1692         RECT mswRect;
1693         const RECT *pRect;
1694         if ( rect )
1695         {
1696             wxCopyRectToRECT(*rect, mswRect);
1697             pRect = &mswRect;
1698         }
1699         else
1700         {
1701             pRect = NULL;
1702         }
1703 
1704         UINT flags = RDW_INVALIDATE | RDW_ALLCHILDREN;
1705         if ( eraseBack )
1706             flags |= RDW_ERASE;
1707 
1708         ::RedrawWindow(hWnd, pRect, NULL, flags);
1709     }
1710 }
1711 
Update()1712 void wxWindowMSW::Update()
1713 {
1714     if ( !::UpdateWindow(GetHwnd()) )
1715     {
1716         wxLogLastError(wxT("UpdateWindow"));
1717     }
1718 
1719     // just calling UpdateWindow() is not enough, what we did in our WM_PAINT
1720     // handler needs to be really drawn right now
1721     (void)::GdiFlush();
1722 }
1723 
1724 // ---------------------------------------------------------------------------
1725 // drag and drop
1726 // ---------------------------------------------------------------------------
1727 
1728 #if wxUSE_DRAG_AND_DROP
1729 
1730 #if wxUSE_STATBOX
1731 
1732 // we need to lower the sibling static boxes so controls contained within can be
1733 // a drop target
AdjustStaticBoxZOrder(wxWindow * parent)1734 static void AdjustStaticBoxZOrder(wxWindow *parent)
1735 {
1736     // no sibling static boxes if we have no parent (ie TLW)
1737     if ( !parent )
1738         return;
1739 
1740     for ( wxWindowList::compatibility_iterator node = parent->GetChildren().GetFirst();
1741           node;
1742           node = node->GetNext() )
1743     {
1744         wxStaticBox *statbox = wxDynamicCast(node->GetData(), wxStaticBox);
1745         if ( statbox )
1746         {
1747             ::SetWindowPos(GetHwndOf(statbox), HWND_BOTTOM, 0, 0, 0, 0,
1748                            SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
1749         }
1750     }
1751 }
1752 
1753 #else // !wxUSE_STATBOX
1754 
AdjustStaticBoxZOrder(wxWindow * WXUNUSED (parent))1755 static inline void AdjustStaticBoxZOrder(wxWindow * WXUNUSED(parent))
1756 {
1757 }
1758 
1759 #endif // wxUSE_STATBOX/!wxUSE_STATBOX
1760 
SetDropTarget(wxDropTarget * pDropTarget)1761 void wxWindowMSW::SetDropTarget(wxDropTarget *pDropTarget)
1762 {
1763     if ( m_dropTarget != 0 ) {
1764         m_dropTarget->Revoke(m_hWnd);
1765         delete m_dropTarget;
1766     }
1767 
1768     m_dropTarget = pDropTarget;
1769     if ( m_dropTarget != 0 )
1770     {
1771         AdjustStaticBoxZOrder(GetParent());
1772         m_dropTarget->Register(m_hWnd);
1773     }
1774 }
1775 
1776 // old-style file manager drag&drop support: we retain the old-style
1777 // DragAcceptFiles in parallel with SetDropTarget.
DragAcceptFiles(bool accept)1778 void wxWindowMSW::DragAcceptFiles(bool accept)
1779 {
1780     HWND hWnd = GetHwnd();
1781     if ( hWnd )
1782     {
1783         AdjustStaticBoxZOrder(GetParent());
1784         ::DragAcceptFiles(hWnd, (BOOL)accept);
1785     }
1786 }
1787 #endif // wxUSE_DRAG_AND_DROP
1788 
1789 // ----------------------------------------------------------------------------
1790 // tooltips
1791 // ----------------------------------------------------------------------------
1792 
1793 #if wxUSE_TOOLTIPS
1794 
DoSetToolTip(wxToolTip * tooltip)1795 void wxWindowMSW::DoSetToolTip(wxToolTip *tooltip)
1796 {
1797     wxWindowBase::DoSetToolTip(tooltip);
1798 
1799     if ( m_tooltip )
1800         m_tooltip->SetWindow((wxWindow *)this);
1801 }
1802 
1803 #endif // wxUSE_TOOLTIPS
1804 
1805 // ---------------------------------------------------------------------------
1806 // moving and resizing
1807 // ---------------------------------------------------------------------------
1808 
IsSizeDeferred() const1809 bool wxWindowMSW::IsSizeDeferred() const
1810 {
1811 #if wxUSE_DEFERRED_SIZING
1812     if ( m_pendingPosition != wxDefaultPosition ||
1813          m_pendingSize     != wxDefaultSize )
1814         return true;
1815 #endif // wxUSE_DEFERRED_SIZING
1816 
1817     return false;
1818 }
1819 
1820 // Get total size
DoGetSize(int * x,int * y) const1821 void wxWindowMSW::DoGetSize(int *x, int *y) const
1822 {
1823 #if wxUSE_DEFERRED_SIZING
1824     // if SetSize() had been called at wx level but not realized at Windows
1825     // level yet (i.e. EndDeferWindowPos() not called), we still should return
1826     // the new and not the old position to the other wx code
1827     if ( m_pendingSize != wxDefaultSize )
1828     {
1829         if ( x )
1830             *x = m_pendingSize.x;
1831         if ( y )
1832             *y = m_pendingSize.y;
1833     }
1834     else // use current size
1835 #endif // wxUSE_DEFERRED_SIZING
1836     {
1837         RECT rect = wxGetWindowRect(GetHwnd());
1838 
1839         if ( x )
1840             *x = rect.right - rect.left;
1841         if ( y )
1842             *y = rect.bottom - rect.top;
1843     }
1844 }
1845 
1846 // Get size *available for subwindows* i.e. excluding menu bar etc.
DoGetClientSize(int * x,int * y) const1847 void wxWindowMSW::DoGetClientSize(int *x, int *y) const
1848 {
1849 #if wxUSE_DEFERRED_SIZING
1850     if ( m_pendingSize != wxDefaultSize )
1851     {
1852         // we need to calculate the client size corresponding to pending size
1853         //
1854         // FIXME: Unfortunately this doesn't work correctly for the maximized
1855         //        top level windows, the returned values are too small (e.g.
1856         //        under Windows 7 on a 1600*1200 screen with task bar on the
1857         //        right the pending size for a maximized window is 1538*1200
1858         //        and WM_NCCALCSIZE returns 1528*1172 even though the correct
1859         //        client size of such window is 1538*1182). No idea how to fix
1860         //        it though, setting WS_MAXIMIZE in GWL_STYLE before calling
1861         //        WM_NCCALCSIZE doesn't help and AdjustWindowRectEx() doesn't
1862         //        work in this direction neither. So we just have to live with
1863         //        the slightly wrong results and relayout the window when it
1864         //        gets finally shown in its maximized state (see #11762).
1865         RECT rect;
1866         rect.left = m_pendingPosition.x;
1867         rect.top = m_pendingPosition.y;
1868         rect.right = rect.left + m_pendingSize.x;
1869         rect.bottom = rect.top + m_pendingSize.y;
1870 
1871         ::SendMessage(GetHwnd(), WM_NCCALCSIZE, FALSE, (LPARAM)&rect);
1872 
1873         if ( x )
1874             *x = rect.right - rect.left;
1875         if ( y )
1876             *y = rect.bottom - rect.top;
1877     }
1878     else
1879 #endif // wxUSE_DEFERRED_SIZING
1880     {
1881         RECT rect = wxGetClientRect(GetHwnd());
1882 
1883         if ( x )
1884             *x = rect.right;
1885         if ( y )
1886             *y = rect.bottom;
1887     }
1888 
1889     // The size of the client window can't be negative but ::GetClientRect()
1890     // can return negative size for an extremely small (1x1) window with
1891     // borders so ensure that we correct it here as having negative sizes is
1892     // completely unexpected.
1893     if ( x && *x < 0 )
1894         *x = 0;
1895     if ( y && *y < 0 )
1896         *y = 0;
1897 }
1898 
DoGetPosition(int * x,int * y) const1899 void wxWindowMSW::DoGetPosition(int *x, int *y) const
1900 {
1901     wxWindow * const parent = GetParent();
1902 
1903     wxPoint pos;
1904 #if wxUSE_DEFERRED_SIZING
1905     if ( m_pendingPosition != wxDefaultPosition )
1906     {
1907         pos = m_pendingPosition;
1908     }
1909     else // use current position
1910 #endif // wxUSE_DEFERRED_SIZING
1911     {
1912         RECT rect = wxGetWindowRect(GetHwnd());
1913 
1914         // we do the adjustments with respect to the parent only for the "real"
1915         // children, not for the dialogs/frames
1916         if ( !IsTopLevel() )
1917         {
1918             // In RTL mode, we want the logical left x-coordinate,
1919             // which would be the physical right x-coordinate.
1920             ::MapWindowPoints(NULL, parent ? GetHwndOf(parent) : HWND_DESKTOP,
1921                               (LPPOINT)&rect, 2);
1922         }
1923 
1924         pos.x = rect.left;
1925         pos.y = rect.top;
1926     }
1927 
1928     // we also must adjust by the client area offset: a control which is just
1929     // under a toolbar could be at (0, 30) in Windows but at (0, 0) in wx
1930     if ( parent && !IsTopLevel() )
1931     {
1932         const wxPoint pt(parent->GetClientAreaOrigin());
1933         pos.x -= pt.x;
1934         pos.y -= pt.y;
1935     }
1936 
1937     if ( x )
1938         *x = pos.x;
1939     if ( y )
1940         *y = pos.y;
1941 }
1942 
1943 /* static */
MSWDoScreenToClient(WXHWND hWnd,int * x,int * y)1944 void wxWindowMSW::MSWDoScreenToClient(WXHWND hWnd, int *x, int *y)
1945 {
1946     POINT pt;
1947     if ( x )
1948         pt.x = *x;
1949     if ( y )
1950         pt.y = *y;
1951 
1952     ::ScreenToClient(hWnd, &pt);
1953 
1954     if ( x )
1955         *x = pt.x;
1956     if ( y )
1957         *y = pt.y;
1958 }
1959 
1960 /* static */
MSWDoClientToScreen(WXHWND hWnd,int * x,int * y)1961 void wxWindowMSW::MSWDoClientToScreen(WXHWND hWnd, int *x, int *y)
1962 {
1963     POINT pt;
1964     if ( x )
1965         pt.x = *x;
1966     if ( y )
1967         pt.y = *y;
1968 
1969     ::ClientToScreen(hWnd, &pt);
1970 
1971     if ( x )
1972         *x = pt.x;
1973     if ( y )
1974         *y = pt.y;
1975 }
1976 
DoScreenToClient(int * x,int * y) const1977 void wxWindowMSW::DoScreenToClient(int *x, int *y) const
1978 {
1979     MSWDoScreenToClient(GetHwnd(), x, y);
1980 }
1981 
DoClientToScreen(int * x,int * y) const1982 void wxWindowMSW::DoClientToScreen(int *x, int *y) const
1983 {
1984     MSWDoClientToScreen(GetHwnd(), x, y);
1985 }
1986 
1987 bool
DoMoveSibling(WXHWND hwnd,int x,int y,int width,int height)1988 wxWindowMSW::DoMoveSibling(WXHWND hwnd, int x, int y, int width, int height)
1989 {
1990     // toplevel window's coordinates are mirrored if the TLW is a child of another
1991     // RTL window and changing width without moving the position would enlarge the
1992     // window in the wrong direction, so we need to adjust for it
1993     if ( IsTopLevel() )
1994     {
1995         // note that this may be different from GetParent() for wxDialogs
1996         HWND tlwParent = ::GetParent((HWND)hwnd);
1997         if ( tlwParent && (::GetWindowLong(tlwParent, GWL_EXSTYLE) & WS_EX_LAYOUTRTL) != 0 )
1998         {
1999             RECT old;
2000             ::GetWindowRect((HWND) hwnd, &old);
2001             if ( old.left == x && old.right - old.left != width )
2002             {
2003                 x -= width - (old.right - old.left);
2004             }
2005             // else: not a simple resize
2006         }
2007     }
2008 
2009 #if wxUSE_DEFERRED_SIZING
2010     else if ( MSWIsPositionDirectlySupported(x, y) )
2011     {
2012         // if our parent had prepared a defer window handle for us, use it
2013         wxWindowMSW * const parent = GetParent();
2014 
2015         HDWP hdwp = parent ? (HDWP)parent->m_hDWP : NULL;
2016         if ( hdwp )
2017         {
2018             hdwp = ::DeferWindowPos(hdwp, (HWND)hwnd, NULL, x, y, width, height,
2019                                     SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE);
2020             if ( !hdwp )
2021             {
2022                 wxLogLastError(wxT("DeferWindowPos"));
2023             }
2024         }
2025 
2026         if ( parent )
2027         {
2028             // hdwp must be updated as it may have been changed
2029             parent->m_hDWP = (WXHANDLE)hdwp;
2030         }
2031 
2032         if ( hdwp )
2033         {
2034             // did deferred move, remember new coordinates of the window as they're
2035             // different from what Windows would return for it
2036             return true;
2037         }
2038 
2039         // otherwise (or if deferring failed) move the window in place immediately
2040     }
2041 #endif // wxUSE_DEFERRED_SIZING
2042 
2043     MSWMoveWindowToAnyPosition(hwnd, x, y, width, height, IsShown());
2044 
2045     // if wxUSE_DEFERRED_SIZING, indicates that we didn't use deferred move,
2046     // ignored otherwise
2047     return false;
2048 }
2049 
MSWMoveWindowToAnyPosition(WXHWND hwnd,int x,int y,int width,int height,bool bRepaint)2050 void wxWindowMSW::MSWMoveWindowToAnyPosition(WXHWND hwnd, int x, int y, int width, int height, bool bRepaint)
2051 {
2052     bool scroll = GetParent() && !MSWIsPositionDirectlySupported(x, y);
2053 
2054     if ( scroll )
2055     {
2056         // scroll to the actual position (looks like there is no need to Freeze() the parent)
2057         ::ScrollWindow(GetHwndOf(GetParent()), -x, -y, NULL, NULL);
2058     }
2059 
2060     // move to relative coordinates
2061     if ( !::MoveWindow(hwnd, (scroll ? 0 : x), (scroll ? 0 : y), width, height, bRepaint) )
2062     {
2063         wxLogLastError(wxT("MoveWindow"));
2064     }
2065 
2066     if ( scroll )
2067     {
2068         // scroll back
2069         ::ScrollWindow(GetHwndOf(GetParent()), x, y, NULL, NULL);
2070     }
2071 }
2072 
DoMoveWindow(int x,int y,int width,int height)2073 void wxWindowMSW::DoMoveWindow(int x, int y, int width, int height)
2074 {
2075     // TODO: is this consistent with other platforms?
2076     // Still, negative width or height shouldn't be allowed
2077     if (width < 0)
2078         width = 0;
2079     if (height < 0)
2080         height = 0;
2081 
2082     if ( DoMoveSibling(m_hWnd, x, y, width, height) )
2083     {
2084 #if wxUSE_DEFERRED_SIZING
2085         m_pendingPosition = wxPoint(x, y);
2086         m_pendingSize = wxSize(width, height);
2087     }
2088     else // window was moved immediately, without deferring it
2089     {
2090         m_pendingPosition = wxDefaultPosition;
2091         m_pendingSize = wxDefaultSize;
2092 #endif // wxUSE_DEFERRED_SIZING
2093     }
2094 }
2095 
2096 // set the size of the window: if the dimensions are positive, just use them,
2097 // but if any of them is equal to -1, it means that we must find the value for
2098 // it ourselves (unless sizeFlags contains wxSIZE_ALLOW_MINUS_ONE flag, in
2099 // which case -1 is a valid value for x and y)
2100 //
2101 // If sizeFlags contains wxSIZE_AUTO_WIDTH/HEIGHT flags (default), we calculate
2102 // the width/height to best suit our contents, otherwise we reuse the current
2103 // width/height
DoSetSize(int x,int y,int width,int height,int sizeFlags)2104 void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags)
2105 {
2106     // get the current size and position...
2107     int currentX, currentY;
2108     int currentW, currentH;
2109 
2110     GetPosition(&currentX, &currentY);
2111     GetSize(&currentW, &currentH);
2112 
2113     if ( x == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
2114         x = currentX;
2115     if ( y == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
2116         y = currentY;
2117 
2118     wxSize size = wxDefaultSize;
2119     if ( width == wxDefaultCoord )
2120     {
2121         if ( sizeFlags & wxSIZE_AUTO_WIDTH )
2122         {
2123             size = GetBestSize();
2124             width = size.x;
2125         }
2126         else
2127         {
2128             // just take the current one
2129             width = currentW;
2130         }
2131     }
2132 
2133     if ( height == wxDefaultCoord )
2134     {
2135         if ( sizeFlags & wxSIZE_AUTO_HEIGHT )
2136         {
2137             if ( size.x == wxDefaultCoord )
2138             {
2139                 size = GetBestSize();
2140             }
2141             //else: already called GetBestSize() above
2142 
2143             height = size.y;
2144         }
2145         else
2146         {
2147             // just take the current one
2148             height = currentH;
2149         }
2150     }
2151 
2152     // ... and don't do anything (avoiding flicker) if it's already ok unless
2153     // we're forced to resize the window
2154     if ( !(sizeFlags & wxSIZE_FORCE) )
2155     {
2156         if ( width == currentW && height == currentH )
2157         {
2158             // We need to send wxSizeEvent ourselves because Windows won't do
2159             // it if the size doesn't change.
2160             if ( sizeFlags & wxSIZE_FORCE_EVENT )
2161             {
2162                 wxSizeEvent event( wxSize(width,height), GetId() );
2163                 event.SetEventObject( this );
2164                 HandleWindowEvent( event );
2165             }
2166 
2167             // Still call DoMoveWindow() below if we need to change the
2168             // position, otherwise we're done.
2169             if ( x == currentX && y == currentY )
2170                 return;
2171         }
2172     }
2173 
2174     AdjustForParentClientOrigin(x, y, sizeFlags);
2175 
2176     DoMoveWindow(x, y, width, height);
2177 }
2178 
DoSetClientSize(int width,int height)2179 void wxWindowMSW::DoSetClientSize(int width, int height)
2180 {
2181     // setting the client size is less obvious than it could have been
2182     // because in the result of changing the total size the window scrollbar
2183     // may [dis]appear and/or its menubar may [un]wrap (and AdjustWindowRect()
2184     // doesn't take neither into account) and so the client size will not be
2185     // correct as the difference between the total and client size changes --
2186     // so we keep changing it until we get it right
2187     //
2188     // normally this loop shouldn't take more than 3 iterations (usually 1 but
2189     // if scrollbars [dis]appear as the result of the first call, then 2 and it
2190     // may become 3 if the window had 0 size originally and so we didn't
2191     // calculate the scrollbar correction correctly during the first iteration)
2192     // but just to be on the safe side we check for it instead of making it an
2193     // "infinite" loop (i.e. leaving break inside as the only way to get out)
2194     for ( int i = 0; i < 4; i++ )
2195     {
2196         RECT rectClient;
2197         ::GetClientRect(GetHwnd(), &rectClient);
2198 
2199         // if the size is already ok, stop here (NB: rectClient.left = top = 0)
2200         if ( (rectClient.right == width || width == wxDefaultCoord) &&
2201              (rectClient.bottom == height || height == wxDefaultCoord) )
2202         {
2203             break;
2204         }
2205 
2206         // Find the difference between the entire window (title bar and all)
2207         // and the client area; add this to the new client size to move the
2208         // window
2209         RECT rectWin;
2210         ::GetWindowRect(GetHwnd(), &rectWin);
2211 
2212         const int widthWin = rectWin.right - rectWin.left,
2213                   heightWin = rectWin.bottom - rectWin.top;
2214 
2215         if ( IsTopLevel() )
2216         {
2217             // toplevel window's coordinates are mirrored if the TLW is a child of another
2218             // RTL window and changing width without moving the position would enlarge the
2219             // window in the wrong direction, so we need to adjust for it
2220 
2221             // note that this may be different from GetParent() for wxDialogs
2222             HWND tlwParent = ::GetParent(GetHwnd());
2223             if ( tlwParent && (::GetWindowLong(tlwParent, GWL_EXSTYLE) & WS_EX_LAYOUTRTL) != 0 )
2224             {
2225                 const int diffWidth = width - (rectClient.right - rectClient.left);
2226                 rectWin.left -= diffWidth;
2227                 rectWin.right -= diffWidth;
2228             }
2229         }
2230         else
2231         {
2232             // MoveWindow positions the child windows relative to the parent, so
2233             // adjust if necessary
2234             wxWindow *parent = GetParent();
2235             if ( parent )
2236             {
2237                 ::ScreenToClient(GetHwndOf(parent), (POINT *)&rectWin);
2238             }
2239         }
2240 
2241         // don't call DoMoveWindow() because we want to move window immediately
2242         // and not defer it here as otherwise the value returned by
2243         // GetClient/WindowRect() wouldn't change as the window wouldn't be
2244         // really resized
2245         MSWMoveWindowToAnyPosition(GetHwnd(), rectWin.left, rectWin.top,
2246                                    width + widthWin - rectClient.right,
2247                                    height + heightWin - rectClient.bottom, true);
2248     }
2249 }
2250 
DoGetBorderSize() const2251 wxSize wxWindowMSW::DoGetBorderSize() const
2252 {
2253     wxCoord border;
2254     switch ( GetBorder() )
2255     {
2256         case wxBORDER_STATIC:
2257         case wxBORDER_SIMPLE:
2258             border = 1;
2259             break;
2260 
2261         case wxBORDER_SUNKEN:
2262         case wxBORDER_THEME:
2263             border = 2;
2264             break;
2265 
2266         case wxBORDER_RAISED:
2267             border = 3;
2268             break;
2269 
2270         default:
2271             wxFAIL_MSG( wxT("unknown border style") );
2272             wxFALLTHROUGH;
2273 
2274         case wxBORDER_NONE:
2275             border = 0;
2276     }
2277 
2278     return 2*wxSize(border, border);
2279 }
2280 
2281 // ---------------------------------------------------------------------------
2282 // text metrics
2283 // ---------------------------------------------------------------------------
2284 
GetCharHeight() const2285 int wxWindowMSW::GetCharHeight() const
2286 {
2287     return wxGetTextMetrics(this).tmHeight;
2288 }
2289 
GetCharWidth() const2290 int wxWindowMSW::GetCharWidth() const
2291 {
2292     // +1 is needed because Windows apparently adds it when calculating the
2293     // dialog units size in pixels
2294 #if wxDIALOG_UNIT_COMPATIBILITY
2295     return wxGetTextMetrics(this).tmAveCharWidth;
2296 #else
2297     return wxGetTextMetrics(this).tmAveCharWidth + 1;
2298 #endif
2299 }
2300 
DoGetTextExtent(const wxString & string,int * x,int * y,int * descent,int * externalLeading,const wxFont * fontToUse) const2301 void wxWindowMSW::DoGetTextExtent(const wxString& string,
2302                                   int *x, int *y,
2303                                   int *descent,
2304                                   int *externalLeading,
2305                                   const wxFont *fontToUse) const
2306 {
2307     // ensure we work with a valid font
2308     wxFont font;
2309     if ( !fontToUse || !fontToUse->IsOk() )
2310         font = GetFont();
2311     else
2312         font = *fontToUse;
2313 
2314     wxCHECK_RET( font.IsOk(), wxT("invalid font in GetTextExtent()") );
2315 
2316     const wxWindow* win = static_cast<const wxWindow*>(this);
2317     wxTextMeasure txm(win, &font);
2318     txm.GetTextExtent(string, x, y, descent, externalLeading);
2319 }
2320 
2321 // ---------------------------------------------------------------------------
2322 // popup menu
2323 // ---------------------------------------------------------------------------
2324 
2325 #if wxUSE_MENUS_NATIVE
2326 
2327 // yield for WM_COMMAND events only, i.e. process all WM_COMMANDs in the queue
2328 // immediately, without waiting for the next event loop iteration
2329 //
2330 // NB: this function should probably be made public later as it can almost
2331 //     surely replace wxYield() elsewhere as well
wxYieldForCommandsOnly()2332 static void wxYieldForCommandsOnly()
2333 {
2334     // peek all WM_COMMANDs (it will always return WM_QUIT too but we don't
2335     // want to process it here)
2336     MSG msg;
2337     while ( ::PeekMessage(&msg, (HWND)0, WM_COMMAND, WM_COMMAND, PM_REMOVE) )
2338     {
2339         if ( msg.message == WM_QUIT )
2340         {
2341             // if we retrieved a WM_QUIT, insert back into the message queue.
2342             ::PostQuitMessage(0);
2343             break;
2344         }
2345 
2346         // luckily (as we don't have access to wxEventLoopImpl method from here
2347         // anyhow...) we don't need to pre process WM_COMMANDs so dispatch it
2348         // immediately
2349         ::TranslateMessage(&msg);
2350         ::DispatchMessage(&msg);
2351     }
2352 }
2353 
DoPopupMenu(wxMenu * menu,int x,int y)2354 bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y)
2355 {
2356     wxPoint pt;
2357     if ( x == wxDefaultCoord && y == wxDefaultCoord )
2358     {
2359         pt = wxGetMousePosition();
2360     }
2361     else
2362     {
2363         pt = ClientToScreen(wxPoint(x, y));
2364     }
2365 
2366     // using TPM_RECURSE allows us to show a popup menu while another menu
2367     // is opened which can be useful and is supported by the other
2368     // platforms, so allow it under Windows too
2369     UINT flags = TPM_RIGHTBUTTON | TPM_RECURSE;
2370 
2371     ::TrackPopupMenu(GetHmenuOf(menu), flags, pt.x, pt.y, 0, GetHwnd(), NULL);
2372 
2373     // we need to do it right now as otherwise the events are never going to be
2374     // sent to wxCurrentPopupMenu from HandleCommand()
2375     //
2376     // note that even eliminating (ugly) wxCurrentPopupMenu global wouldn't
2377     // help and we'd still need wxYieldForCommandsOnly() as the menu may be
2378     // destroyed as soon as we return (it can be a local variable in the caller
2379     // for example) and so we do need to process the event immediately
2380     wxYieldForCommandsOnly();
2381 
2382     return true;
2383 }
2384 
2385 #endif // wxUSE_MENUS_NATIVE
2386 
2387 // ---------------------------------------------------------------------------
2388 // menu events
2389 // ---------------------------------------------------------------------------
2390 
2391 #if wxUSE_MENUS && !defined(__WXUNIVERSAL__)
2392 
2393 bool
HandleMenuSelect(WXWORD nItem,WXWORD flags,WXHMENU hMenu)2394 wxWindowMSW::HandleMenuSelect(WXWORD nItem, WXWORD flags, WXHMENU hMenu)
2395 {
2396     // Ignore the special messages generated when the menu is closed (this is
2397     // the only case when the flags are set to -1), in particular don't clear
2398     // the help string in the status bar when this happens as it had just been
2399     // restored by the base class code.
2400     if ( !hMenu && flags == 0xffff )
2401         return false;
2402 
2403     // sign extend to int from unsigned short we get from Windows
2404     int item = (signed short)nItem;
2405 
2406     // WM_MENUSELECT is generated for both normal items and menus, including
2407     // the top level menus of the menu bar, which can't be represented using
2408     // any valid identifier in wxMenuEvent so use an otherwise unused value for
2409     // them
2410     if ( flags & (MF_POPUP | MF_SEPARATOR) )
2411         item = wxID_NONE;
2412 
2413     wxMenu* menu = MSWFindMenuFromHMENU(hMenu);
2414     wxMenuEvent event(wxEVT_MENU_HIGHLIGHT, item, menu);
2415     if ( wxMenu::ProcessMenuEvent(menu, event, this) )
2416         return true;
2417 
2418     // by default, i.e. if the event wasn't handled above, clear the status bar
2419     // text when an item which can't have any associated help string in wx API
2420     // is selected
2421     if ( item == wxID_NONE )
2422     {
2423         wxFrame *frame = wxDynamicCast(wxGetTopLevelParent(this), wxFrame);
2424         if ( frame )
2425             frame->DoGiveHelp(wxEmptyString, true);
2426     }
2427 
2428     return false;
2429 }
2430 
2431 bool
DoSendMenuOpenCloseEvent(wxEventType evtType,wxMenu * menu)2432 wxWindowMSW::DoSendMenuOpenCloseEvent(wxEventType evtType, wxMenu* menu)
2433 {
2434     wxMenuEvent event(evtType, menu && !menu->IsAttached() ? wxID_ANY : 0, menu);
2435 
2436     return wxMenu::ProcessMenuEvent(menu, event, this);
2437 }
2438 
HandleMenuPopup(wxEventType evtType,WXHMENU hMenu)2439 bool wxWindowMSW::HandleMenuPopup(wxEventType evtType, WXHMENU hMenu)
2440 {
2441     wxMenu* const menu = MSWFindMenuFromHMENU(hMenu);
2442 
2443     return DoSendMenuOpenCloseEvent(evtType, menu);
2444 }
2445 
MSWFindMenuFromHMENU(WXHMENU hMenu)2446 wxMenu* wxWindowMSW::MSWFindMenuFromHMENU(WXHMENU hMenu)
2447 {
2448     if ( wxCurrentPopupMenu && wxCurrentPopupMenu->GetHMenu() == hMenu )
2449         return wxCurrentPopupMenu;
2450 
2451     return NULL;
2452 }
2453 
2454 #endif // wxUSE_MENUS && !defined(__WXUNIVERSAL__)
2455 
2456 // ===========================================================================
2457 // pre/post message processing
2458 // ===========================================================================
2459 
MSWDefWindowProc(WXUINT nMsg,WXWPARAM wParam,WXLPARAM lParam)2460 WXLRESULT wxWindowMSW::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
2461 {
2462     WXLRESULT rc;
2463     if ( m_oldWndProc )
2464         rc = ::CallWindowProc(m_oldWndProc, GetHwnd(), nMsg, wParam, lParam);
2465     else
2466         rc = ::DefWindowProc(GetHwnd(), nMsg, wParam, lParam);
2467 
2468     // Special hack used by wxTextEntry auto-completion only: this event is
2469     // sent after the normal keyboard processing so that its handler could use
2470     // the updated contents of the text control, after taking the key that was
2471     // pressed into account.
2472     if ( nMsg == WM_CHAR )
2473     {
2474         wxKeyEvent event(CreateCharEvent(wxEVT_AFTER_CHAR, wParam, lParam));
2475         HandleWindowEvent(event);
2476     }
2477 
2478     return rc;
2479 }
2480 
MSWProcessMessage(WXMSG * pMsg)2481 bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
2482 {
2483     // wxUniversal implements tab traversal itself
2484 #ifndef __WXUNIVERSAL__
2485     // Notice that we check for both wxTAB_TRAVERSAL and WS_EX_CONTROLPARENT
2486     // being set here. While normally the latter should always be set if the
2487     // former is, doing it like this also works if there is ever a bug that
2488     // results in wxTAB_TRAVERSAL being set but not WS_EX_CONTROLPARENT as we
2489     // must not call IsDialogMessage() then, it would simply hang (see #15458).
2490     if ( m_hWnd &&
2491             HasFlag(wxTAB_TRAVERSAL) &&
2492                 wxHasWindowExStyle(this, WS_EX_CONTROLPARENT) )
2493     {
2494         // intercept dialog navigation keys
2495         MSG *msg = (MSG *)pMsg;
2496 
2497         // here we try to do all the job which ::IsDialogMessage() usually does
2498         // internally
2499         if ( msg->message == WM_KEYDOWN )
2500         {
2501             bool bCtrlDown = wxIsCtrlDown();
2502             bool bShiftDown = wxIsShiftDown();
2503 
2504             // WM_GETDLGCODE: ask the control if it wants the key for itself,
2505             // don't process it if it's the case (except for Ctrl-Tab/Enter
2506             // combinations which are always processed)
2507             LONG lDlgCode = ::SendMessage(msg->hwnd, WM_GETDLGCODE, 0, 0);
2508 
2509             // surprisingly, DLGC_WANTALLKEYS bit mask doesn't contain the
2510             // DLGC_WANTTAB nor DLGC_WANTARROWS bits although, logically,
2511             // it, of course, implies them
2512             if ( lDlgCode & DLGC_WANTALLKEYS )
2513             {
2514                 lDlgCode |= DLGC_WANTTAB | DLGC_WANTARROWS;
2515             }
2516 
2517             bool bForward = true,
2518                  bWindowChange = false,
2519                  bFromTab = false;
2520 
2521             // should we process this message specially?
2522             bool bProcess = true;
2523             switch ( msg->wParam )
2524             {
2525                 case VK_TAB:
2526                     if ( (lDlgCode & DLGC_WANTTAB) && !bCtrlDown )
2527                     {
2528                         // let the control have the TAB
2529                         bProcess = false;
2530                     }
2531                     else // use it for navigation
2532                     {
2533                         // Ctrl-Tab cycles thru notebook pages
2534                         bWindowChange = bCtrlDown;
2535                         bForward = !bShiftDown;
2536                         bFromTab = true;
2537                     }
2538                     break;
2539 
2540                 case VK_UP:
2541                 case VK_LEFT:
2542                     if ( (lDlgCode & DLGC_WANTARROWS) || bCtrlDown )
2543                         bProcess = false;
2544                     else
2545                         bForward = false;
2546                     break;
2547 
2548                 case VK_DOWN:
2549                 case VK_RIGHT:
2550                     if ( (lDlgCode & DLGC_WANTARROWS) || bCtrlDown )
2551                         bProcess = false;
2552                     break;
2553 
2554                 case VK_PRIOR:
2555                     bForward = false;
2556                     wxFALLTHROUGH;
2557 
2558                 case VK_NEXT:
2559                     // we treat PageUp/Dn as arrows because chances are that
2560                     // a control which needs arrows also needs them for
2561                     // navigation (e.g. wxTextCtrl, wxListCtrl, ...)
2562                     if ( (lDlgCode & DLGC_WANTARROWS) && !bCtrlDown )
2563                         bProcess = false;
2564                     else // OTOH Ctrl-PageUp/Dn works as [Shift-]Ctrl-Tab
2565                         bWindowChange = true;
2566                     break;
2567 
2568                 case VK_RETURN:
2569                     {
2570 #if wxUSE_BUTTON
2571                         // currently active button should get enter press even
2572                         // if there is a default button elsewhere so check if
2573                         // this window is a button first
2574                         wxButton *btn = NULL;
2575                         if ( lDlgCode & DLGC_DEFPUSHBUTTON )
2576                         {
2577                             // let IsDialogMessage() handle this for all
2578                             // buttons except the owner-drawn ones which it
2579                             // just seems to ignore
2580                             long style = ::GetWindowLong(msg->hwnd, GWL_STYLE);
2581                             if ( (style & BS_OWNERDRAW) == BS_OWNERDRAW )
2582                             {
2583                                 btn = wxDynamicCast
2584                                       (
2585                                         wxFindWinFromHandle(msg->hwnd),
2586                                         wxButton
2587                                       );
2588                             }
2589                         }
2590                         else // not a button itself, do we have default button?
2591                         {
2592                             // check if this window or any of its ancestors
2593                             // wants the message for itself (we always reserve
2594                             // Ctrl-Enter for dialog navigation though)
2595                             wxWindow *win = this;
2596                             if ( !bCtrlDown )
2597                             {
2598                                 // this will contain the dialog code of this
2599                                 // window and all of its parent windows in turn
2600                                 LONG lDlgCode2 = lDlgCode;
2601 
2602                                 while ( win )
2603                                 {
2604                                     if ( lDlgCode2 & DLGC_WANTMESSAGE )
2605                                     {
2606                                         // as it wants to process Enter itself,
2607                                         // don't call IsDialogMessage() which
2608                                         // would consume it
2609                                         return false;
2610                                     }
2611 
2612                                     // don't propagate keyboard messages beyond
2613                                     // the first top level window parent
2614                                     if ( win->IsTopLevel() )
2615                                         break;
2616 
2617                                     win = win->GetParent();
2618 
2619                                     lDlgCode2 = ::SendMessage
2620                                                   (
2621                                                     GetHwndOf(win),
2622                                                     WM_GETDLGCODE,
2623                                                     0,
2624                                                     0
2625                                                   );
2626                                 }
2627                             }
2628 
2629                             btn = MSWGetDefaultButtonFor(win);
2630                         }
2631 
2632                         if ( MSWClickButtonIfPossible(btn) )
2633                             return true;
2634 
2635                         // This "Return" key press won't be actually used for
2636                         // navigation so don't generate wxNavigationKeyEvent
2637                         // for it but still pass it to IsDialogMessage() as it
2638                         // may handle it in some other way (e.g. by playing the
2639                         // default error sound).
2640                         bProcess = false;
2641 
2642 #endif // wxUSE_BUTTON
2643 
2644                     }
2645                     break;
2646 
2647                 default:
2648                     bProcess = false;
2649             }
2650 
2651             if ( bProcess )
2652             {
2653                 wxNavigationKeyEvent event;
2654                 event.SetDirection(bForward);
2655                 event.SetWindowChange(bWindowChange);
2656                 event.SetFromTab(bFromTab);
2657                 event.SetEventObject(this);
2658 
2659                 if ( HandleWindowEvent(event) )
2660                 {
2661                     // as we don't call IsDialogMessage(), which would take of
2662                     // this by default, we need to manually send this message
2663                     // so that controls can change their UI state if needed
2664                     MSWUpdateUIState(UIS_CLEAR, UISF_HIDEFOCUS);
2665 
2666                     return true;
2667                 }
2668             }
2669         }
2670 
2671         if ( MSWSafeIsDialogMessage(msg) )
2672         {
2673             // IsDialogMessage() did something...
2674             return true;
2675         }
2676     }
2677 #else // __WXUNIVERSAL__
2678     wxUnusedVar(pMsg);
2679 #endif // !__WXUNIVERSAL__/__WXUNIVERSAL__
2680 
2681 #if wxUSE_TOOLTIPS
2682     if ( m_tooltip )
2683     {
2684         // relay mouse move events to the tooltip control
2685         MSG *msg = (MSG *)pMsg;
2686         if ( msg->message == WM_MOUSEMOVE )
2687             wxToolTip::RelayEvent(pMsg);
2688     }
2689 #endif // wxUSE_TOOLTIPS
2690 
2691     return false;
2692 }
2693 
MSWTranslateMessage(WXMSG * pMsg)2694 bool wxWindowMSW::MSWTranslateMessage(WXMSG* pMsg)
2695 {
2696 #if wxUSE_ACCEL && !defined(__WXUNIVERSAL__)
2697     return m_acceleratorTable.Translate(this, pMsg);
2698 #else
2699     (void) pMsg;
2700     return false;
2701 #endif // wxUSE_ACCEL
2702 }
2703 
MSWShouldPreProcessMessage(WXMSG * WXUNUSED (msg))2704 bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* WXUNUSED(msg))
2705 {
2706     // We don't have any reason to not preprocess messages at this level.
2707     return true;
2708 }
2709 
2710 #ifndef __WXUNIVERSAL__
2711 
MSWSafeIsDialogMessage(WXMSG * msg)2712 bool wxWindowMSW::MSWSafeIsDialogMessage(WXMSG* msg)
2713 {
2714     // don't let IsDialogMessage() get VK_ESCAPE as it _always_ eats the
2715     // message even when there is no cancel button and when the message is
2716     // needed by the control itself: in particular, it prevents the tree in
2717     // place edit control from being closed with Escape in a dialog
2718     if ( msg->message == WM_KEYDOWN && msg->wParam == VK_ESCAPE )
2719     {
2720         return false;
2721     }
2722 
2723     // ::IsDialogMessage() is broken and may sometimes hang the application by
2724     // going into an infinite loop when it tries to find the control to give
2725     // focus to when Alt-<key> is pressed, so we try to detect [some of] the
2726     // situations when this may happen and not call it then
2727     if ( msg->message == WM_SYSCHAR )
2728     {
2729         HWND hwndFocus = ::GetFocus();
2730 
2731         // if the currently focused window itself has WS_EX_CONTROLPARENT style,
2732         // ::IsDialogMessage() will also enter an infinite loop, because it will
2733         // recursively check the child windows but not the window itself and so if
2734         // none of the children accepts focus it loops forever (as it only stops
2735         // when it gets back to the window it started from)
2736         //
2737         // while it is very unusual that a window with WS_EX_CONTROLPARENT
2738         // style has the focus, it can happen. One such possibility is if
2739         // all windows are either toplevel, wxDialog, wxPanel or static
2740         // controls and no window can actually accept keyboard input.
2741         if ( ::GetWindowLong(hwndFocus, GWL_EXSTYLE) & WS_EX_CONTROLPARENT )
2742         {
2743             // pessimistic by default
2744             bool canSafelyCallIsDlgMsg = false;
2745             for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
2746                   node;
2747                   node = node->GetNext() )
2748             {
2749                 wxWindow * const win = node->GetData();
2750                 if ( win->CanAcceptFocus() &&
2751                         !wxHasWindowExStyle(win, WS_EX_CONTROLPARENT) )
2752                 {
2753                     // it shouldn't hang...
2754                     canSafelyCallIsDlgMsg = true;
2755 
2756                     break;
2757                 }
2758             }
2759 
2760             if ( !canSafelyCallIsDlgMsg )
2761                 return false;
2762         }
2763 
2764         // ::IsDialogMessage() can enter in an infinite loop when the
2765         // currently focused window is disabled or hidden and its
2766         // parent has WS_EX_CONTROLPARENT style, so don't call it in
2767         // this case
2768         while ( hwndFocus )
2769         {
2770             if ( !::IsWindowEnabled(hwndFocus) ||
2771                     !::IsWindowVisible(hwndFocus) )
2772             {
2773                 // it would enter an infinite loop if we do this!
2774                 return false;
2775             }
2776 
2777             if ( !(::GetWindowLong(hwndFocus, GWL_STYLE) & WS_CHILD) )
2778             {
2779                 // it's a top level window, don't go further -- e.g. even
2780                 // if the parent of a dialog is disabled, this doesn't
2781                 // break navigation inside the dialog
2782                 break;
2783             }
2784 
2785             hwndFocus = ::GetParent(hwndFocus);
2786         }
2787     }
2788 
2789     return ::IsDialogMessage(GetHwnd(), msg) != 0;
2790 }
2791 
2792 #endif // __WXUNIVERSAL__
2793 
2794 /* static */
MSWGetDefaultButtonFor(wxWindow * win)2795 wxButton* wxWindowMSW::MSWGetDefaultButtonFor(wxWindow* win)
2796 {
2797 #if wxUSE_BUTTON
2798     win = wxGetTopLevelParent(win);
2799 
2800     wxTopLevelWindow *const tlw = wxDynamicCast(win, wxTopLevelWindow);
2801     if ( tlw )
2802         return wxDynamicCast(tlw->GetDefaultItem(), wxButton);
2803 #endif // wxUSE_BUTTON
2804 
2805     return NULL;
2806 }
2807 
2808 /* static */
MSWClickButtonIfPossible(wxButton * btn)2809 bool wxWindowMSW::MSWClickButtonIfPossible(wxButton* btn)
2810 {
2811 #if wxUSE_BUTTON
2812     if ( btn && btn->IsEnabled() && btn->IsShownOnScreen() )
2813     {
2814         btn->MSWCommand(BN_CLICKED, 0 /* unused */);
2815         return true;
2816     }
2817 #endif // wxUSE_BUTTON
2818 
2819     wxUnusedVar(btn);
2820 
2821     return false;
2822 }
2823 
2824 // ---------------------------------------------------------------------------
2825 // message params unpackers
2826 // ---------------------------------------------------------------------------
2827 
UnpackCommand(WXWPARAM wParam,WXLPARAM lParam,WORD * id,WXHWND * hwnd,WORD * cmd)2828 void wxWindowMSW::UnpackCommand(WXWPARAM wParam, WXLPARAM lParam,
2829                              WORD *id, WXHWND *hwnd, WORD *cmd)
2830 {
2831     *id = LOWORD(wParam);
2832     *hwnd = (WXHWND)lParam;
2833     *cmd = HIWORD(wParam);
2834 }
2835 
UnpackActivate(WXWPARAM wParam,WXLPARAM lParam,WXWORD * state,WXWORD * minimized,WXHWND * hwnd)2836 void wxWindowMSW::UnpackActivate(WXWPARAM wParam, WXLPARAM lParam,
2837                               WXWORD *state, WXWORD *minimized, WXHWND *hwnd)
2838 {
2839     *state = LOWORD(wParam);
2840     *minimized = HIWORD(wParam);
2841     *hwnd = (WXHWND)lParam;
2842 }
2843 
UnpackScroll(WXWPARAM wParam,WXLPARAM lParam,WXWORD * code,WXWORD * pos,WXHWND * hwnd)2844 void wxWindowMSW::UnpackScroll(WXWPARAM wParam, WXLPARAM lParam,
2845                             WXWORD *code, WXWORD *pos, WXHWND *hwnd)
2846 {
2847     *code = LOWORD(wParam);
2848     *pos = HIWORD(wParam);
2849     *hwnd = (WXHWND)lParam;
2850 }
2851 
UnpackCtlColor(WXWPARAM wParam,WXLPARAM lParam,WXHDC * hdc,WXHWND * hwnd)2852 void wxWindowMSW::UnpackCtlColor(WXWPARAM wParam, WXLPARAM lParam,
2853                                  WXHDC *hdc, WXHWND *hwnd)
2854 {
2855     *hwnd = (WXHWND)lParam;
2856     *hdc = (WXHDC)wParam;
2857 }
2858 
UnpackMenuSelect(WXWPARAM wParam,WXLPARAM lParam,WXWORD * item,WXWORD * flags,WXHMENU * hmenu)2859 void wxWindowMSW::UnpackMenuSelect(WXWPARAM wParam, WXLPARAM lParam,
2860                                 WXWORD *item, WXWORD *flags, WXHMENU *hmenu)
2861 {
2862     *item = (WXWORD)wParam;
2863     *flags = HIWORD(wParam);
2864     *hmenu = (WXHMENU)lParam;
2865 }
2866 
2867 // ---------------------------------------------------------------------------
2868 // Main wxWidgets window proc and the window proc for wxWindow
2869 // ---------------------------------------------------------------------------
2870 
2871 // Hook for new window just as it's being created, when the window isn't yet
2872 // associated with the handle
2873 static wxWindowMSW *gs_winBeingCreated = NULL;
2874 
2875 // implementation of wxWindowCreationHook class: it just sets gs_winBeingCreated to the
2876 // window being created and insures that it's always unset back later
wxWindowCreationHook(wxWindowMSW * winBeingCreated)2877 wxWindowCreationHook::wxWindowCreationHook(wxWindowMSW *winBeingCreated)
2878 {
2879     gs_winBeingCreated = winBeingCreated;
2880 }
2881 
~wxWindowCreationHook()2882 wxWindowCreationHook::~wxWindowCreationHook()
2883 {
2884     gs_winBeingCreated = NULL;
2885 }
2886 
2887 // Main window proc
2888 LRESULT WXDLLEXPORT APIENTRY
wxWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)2889 wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
2890 {
2891     // trace all messages: useful for the debugging but noticeably slows down
2892     // the code so don't do it by default
2893 #if wxDEBUG_LEVEL >= 2
2894     // We have to do this inside a helper function as wxLogTrace() constructs
2895     // an object internally, but objects can't be used in functions using __try
2896     // (expanded from wxSEH_TRY below) with MSVC.
2897     wxTraceMSWMessage(hWnd, message, wParam, lParam);
2898 #endif // wxDEBUG_LEVEL >= 2
2899 
2900     wxWindowMSW *wnd = wxFindWinFromHandle(hWnd);
2901 
2902     // when we get the first message for the HWND we just created, we associate
2903     // it with wxWindow stored in gs_winBeingCreated
2904     if ( !wnd && gs_winBeingCreated )
2905     {
2906         wxAssociateWinWithHandle(hWnd, gs_winBeingCreated);
2907         wnd = gs_winBeingCreated;
2908         gs_winBeingCreated = NULL;
2909         wnd->SetHWND((WXHWND)hWnd);
2910     }
2911 
2912     LRESULT rc;
2913 
2914     // We have to catch unhandled Win32 exceptions here because otherwise they
2915     // would be simply lost if we're called from a kernel callback (as it
2916     // happens when we process WM_PAINT, for example under WOW64: the 32 bit
2917     // exceptions can't pass through the 64 bit kernel in this case and so are
2918     // mostly just suppressed, although the exact behaviour differs across
2919     // Windows versions, see the "Remarks" section of WindowProc documentation
2920     // at https://msdn.microsoft.com/en-us/library/ms633573.aspx
2921     wxSEH_TRY
2922     {
2923         if ( wnd && wxGUIEventLoop::AllowProcessing(wnd) )
2924             rc = wnd->MSWWindowProc(message, wParam, lParam);
2925         else
2926             rc = ::DefWindowProc(hWnd, message, wParam, lParam);
2927     }
2928     wxSEH_HANDLE(0)
2929 
2930     return rc;
2931 }
2932 
2933 bool
MSWHandleMessage(WXLRESULT * result,WXUINT message,WXWPARAM wParam,WXLPARAM lParam)2934 wxWindowMSW::MSWHandleMessage(WXLRESULT *result,
2935                               WXUINT message,
2936                               WXWPARAM wParam,
2937                               WXLPARAM lParam)
2938 {
2939     // did we process the message?
2940     bool processed = false;
2941 
2942     // the return value
2943     union
2944     {
2945         bool        allow;
2946         WXLRESULT   result;
2947         WXHBRUSH    hBrush;
2948     } rc;
2949 
2950     // for most messages we should return 0 when we do process the message
2951     rc.result = 0;
2952 
2953     // Special hook for dismissing the current popup if it's active. It's a bit
2954     // ugly to have to do this here, but the only alternatives seem to be
2955     // installing a WH_CBT hook in wxPopupTransientWindow code, which is not
2956     // really much better.
2957 #if wxUSE_POPUPWIN
2958     // Note that we let the popup window, or its child, have the event if it
2959     // happens inside it -- it's supposed to react to it and we don't want to
2960     // dismiss it before it can do it.
2961     if ( wxCurrentPopupWindow && !wxCurrentPopupWindow->IsDescendant(this) )
2962     {
2963         switch ( message )
2964         {
2965             case WM_NCLBUTTONDOWN:
2966             case WM_NCRBUTTONDOWN:
2967             case WM_NCMBUTTONDOWN:
2968 
2969             case WM_LBUTTONDOWN:
2970             case WM_RBUTTONDOWN:
2971             case WM_MBUTTONDOWN:
2972 
2973             case WM_SETFOCUS:
2974             case WM_KILLFOCUS:
2975                 wxCurrentPopupWindow->MSWDismissUnfocusedPopup();
2976         }
2977     }
2978 #endif // wxUSE_POPUPWIN
2979 
2980     switch ( message )
2981     {
2982         case WM_CREATE:
2983             {
2984                 bool mayCreate;
2985                 processed = HandleCreate((WXLPCREATESTRUCT)lParam, &mayCreate);
2986                 if ( processed )
2987                 {
2988                     // return 0 to allow window creation
2989                     rc.result = mayCreate ? 0 : -1;
2990                 }
2991             }
2992             break;
2993 
2994         case WM_DESTROY:
2995             // never set processed to true and *always* pass WM_DESTROY to
2996             // DefWindowProc() as Windows may do some internal cleanup when
2997             // processing it and failing to pass the message along may cause
2998             // memory and resource leaks!
2999             (void)HandleDestroy();
3000             break;
3001 
3002         case WM_SIZE:
3003             processed = HandleSize(LOWORD(lParam), HIWORD(lParam), wParam);
3004             break;
3005 
3006         case WM_MOVE:
3007             processed = HandleMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
3008             break;
3009 
3010         case WM_MOVING:
3011             {
3012                 LPRECT pRect = (LPRECT)lParam;
3013                 wxRect rect;
3014                 rect.SetLeft(pRect->left);
3015                 rect.SetTop(pRect->top);
3016                 rect.SetRight(pRect->right);
3017                 rect.SetBottom(pRect->bottom);
3018                 processed = HandleMoving(rect);
3019                 if (processed) {
3020                     pRect->left = rect.GetLeft();
3021                     pRect->top = rect.GetTop();
3022                     pRect->right = rect.GetRight();
3023                     pRect->bottom = rect.GetBottom();
3024                 }
3025             }
3026             break;
3027 
3028         case WM_ENTERSIZEMOVE:
3029             {
3030                 processed = HandleEnterSizeMove();
3031             }
3032             break;
3033 
3034         case WM_EXITSIZEMOVE:
3035             {
3036                 processed = HandleExitSizeMove();
3037             }
3038             break;
3039 
3040         case WM_SIZING:
3041             {
3042                 LPRECT pRect = (LPRECT)lParam;
3043                 wxRect rect;
3044                 rect.SetLeft(pRect->left);
3045                 rect.SetTop(pRect->top);
3046                 rect.SetRight(pRect->right);
3047                 rect.SetBottom(pRect->bottom);
3048                 processed = HandleSizing(rect);
3049                 if (processed) {
3050                     pRect->left = rect.GetLeft();
3051                     pRect->top = rect.GetTop();
3052                     pRect->right = rect.GetRight();
3053                     pRect->bottom = rect.GetBottom();
3054                 }
3055             }
3056             break;
3057 
3058         case WM_ACTIVATEAPP:
3059             // This implicitly sends a wxEVT_ACTIVATE_APP event
3060             wxTheApp->SetActive(wParam != 0, FindFocus());
3061             break;
3062 
3063         case WM_ACTIVATE:
3064             {
3065                 WXWORD state, minimized;
3066                 WXHWND hwnd;
3067                 UnpackActivate(wParam, lParam, &state, &minimized, &hwnd);
3068 
3069                 processed = HandleActivate(state, minimized != 0, (WXHWND)hwnd);
3070             }
3071             break;
3072 
3073         case WM_SETFOCUS:
3074             processed = HandleSetFocus((WXHWND)wParam);
3075             break;
3076 
3077         case WM_KILLFOCUS:
3078             processed = HandleKillFocus((WXHWND)wParam);
3079             break;
3080 
3081         case WM_PRINTCLIENT:
3082             processed = HandlePrintClient((WXHDC)wParam);
3083             break;
3084 
3085         case WM_PAINT:
3086             if ( wParam )
3087             {
3088                 wxPaintDCEx dc((wxWindow *)this, (WXHDC)wParam);
3089 
3090                 processed = HandlePaint();
3091             }
3092             else // no DC given
3093             {
3094                 processed = HandlePaint();
3095             }
3096             break;
3097 
3098         case WM_CLOSE:
3099 #ifdef __WXUNIVERSAL__
3100             // Universal uses its own wxFrame/wxDialog, so we don't receive
3101             // close events unless we have this.
3102             Close();
3103 #endif // __WXUNIVERSAL__
3104 
3105             // don't let the DefWindowProc() destroy our window - we'll do it
3106             // ourselves in ~wxWindow
3107             processed = true;
3108             rc.result = TRUE;
3109             break;
3110 
3111         case WM_SHOWWINDOW:
3112             processed = HandleShow(wParam != 0, (int)lParam);
3113             break;
3114 
3115         case WM_MOUSEMOVE:
3116             processed = HandleMouseMove(GET_X_LPARAM(lParam),
3117                                         GET_Y_LPARAM(lParam),
3118                                         wParam);
3119             break;
3120 
3121 #ifdef HAVE_TRACKMOUSEEVENT
3122         case WM_MOUSELEAVE:
3123             // filter out excess WM_MOUSELEAVE events sent after PopupMenu()
3124             // (on XP at least)
3125             if ( m_mouseInWindow )
3126             {
3127                 GenerateMouseLeave();
3128             }
3129 
3130             // always pass processed back as false, this allows the window
3131             // manager to process the message too.  This is needed to
3132             // ensure windows XP themes work properly as the mouse moves
3133             // over widgets like buttons. So don't set processed to true here.
3134             break;
3135 #endif // HAVE_TRACKMOUSEEVENT
3136 
3137 #if wxUSE_MOUSEWHEEL
3138         case WM_MOUSEWHEEL:
3139             processed = HandleMouseWheel(wxMOUSE_WHEEL_VERTICAL, wParam, lParam);
3140             break;
3141 
3142         case WM_MOUSEHWHEEL:
3143             processed = HandleMouseWheel(wxMOUSE_WHEEL_HORIZONTAL, wParam, lParam);
3144             break;
3145 #endif // wxUSE_MOUSEWHEEL
3146 
3147         case WM_LBUTTONDOWN:
3148         case WM_LBUTTONUP:
3149         case WM_LBUTTONDBLCLK:
3150         case WM_RBUTTONDOWN:
3151         case WM_RBUTTONUP:
3152         case WM_RBUTTONDBLCLK:
3153         case WM_MBUTTONDOWN:
3154         case WM_MBUTTONUP:
3155         case WM_MBUTTONDBLCLK:
3156         case WM_XBUTTONDOWN:
3157         case WM_XBUTTONUP:
3158         case WM_XBUTTONDBLCLK:
3159             {
3160                 int x = GET_X_LPARAM(lParam),
3161                     y = GET_Y_LPARAM(lParam);
3162 
3163                 wxWindowMSW *win = this;
3164 
3165                 processed = win->HandleMouseEvent(message, x, y, wParam);
3166 
3167                 // if the app didn't eat the event, handle it in the default
3168                 // way, that is by giving this window the focus
3169                 if ( !processed )
3170                 {
3171                     // for the standard classes their WndProc sets the focus to
3172                     // them anyhow and doing it from here results in some weird
3173                     // problems, so don't do it for them (unnecessary anyhow)
3174                     if ( !win->IsOfStandardClass() )
3175                     {
3176                         if ( message == WM_LBUTTONDOWN && win->IsFocusable() )
3177                             win->SetFocus();
3178                     }
3179                 }
3180             }
3181             break;
3182 
3183 
3184         case WM_COMMAND:
3185             {
3186                 WORD id, cmd;
3187                 WXHWND hwnd;
3188                 UnpackCommand(wParam, lParam, &id, &hwnd, &cmd);
3189 
3190                 processed = HandleCommand(id, cmd, hwnd);
3191             }
3192             break;
3193 
3194         case WM_NOTIFY:
3195             processed = HandleNotify((int)wParam, lParam, &rc.result);
3196             break;
3197 
3198             // for these messages we must return true if process the message
3199 #ifdef WM_DRAWITEM
3200         case WM_DRAWITEM:
3201             processed = MSWOnDrawItem(wParam, (WXDRAWITEMSTRUCT *)lParam);
3202             if ( processed )
3203                 rc.result = TRUE;
3204             break;
3205 
3206         case WM_MEASUREITEM:
3207             processed = MSWOnMeasureItem(wParam, (WXMEASUREITEMSTRUCT *)lParam);
3208             if ( processed )
3209                 rc.result = TRUE;
3210             break;
3211 #endif // defined(WM_DRAWITEM)
3212 
3213         case WM_GETDLGCODE:
3214             if ( !IsOfStandardClass() || HasFlag(wxWANTS_CHARS) )
3215             {
3216                 // Get current input processing flags to retain flags like DLGC_HASSETSEL, etc.
3217                 rc.result = MSWDefWindowProc(WM_GETDLGCODE, 0, 0);
3218                 // we always want to get the char events
3219                 rc.result |= DLGC_WANTCHARS;
3220 
3221                 if ( HasFlag(wxWANTS_CHARS) )
3222                 {
3223                     // in fact, we want everything
3224                     rc.result |= DLGC_WANTARROWS |
3225                                  DLGC_WANTTAB |
3226                                  DLGC_WANTALLKEYS;
3227                 }
3228 
3229                 // Message is marked as processed so MSWDefWindowProc() will not be called once more.
3230                 processed = true;
3231             }
3232             //else: get the dlg code from the DefWindowProc()
3233             break;
3234 
3235         case WM_SYSKEYDOWN:
3236         case WM_KEYDOWN:
3237             // Generate the key down event in any case.
3238             m_lastKeydownProcessed = HandleKeyDown((WORD) wParam, lParam);
3239             if ( m_lastKeydownProcessed )
3240             {
3241                 // If it was processed by an event handler, we stop here,
3242                 // notably we intentionally don't generate char event then.
3243                 processed = true;
3244             }
3245             else // key down event not handled
3246             {
3247                 // Examine the event to decide whether we need to generate a
3248                 // char event for it ourselves or let Windows do it. Window
3249                 // mostly only does it for the keys which produce printable
3250                 // characters (although there are exceptions, e.g. VK_ESCAPE or
3251                 // VK_BACK (but not VK_DELETE)) while we do it for all keys
3252                 // except the modifier ones (the wisdom of this is debatable
3253                 // but by now this decision is enshrined forever due to
3254                 // backwards compatibility).
3255                 switch ( wParam )
3256                 {
3257                     // No wxEVT_CHAR events are generated for these keys at all.
3258                     case VK_SHIFT:
3259                     case VK_CONTROL:
3260                     case VK_MENU:
3261                     case VK_CAPITAL:
3262                     case VK_NUMLOCK:
3263                     case VK_SCROLL:
3264 
3265                     // Windows will send us WM_CHAR for these ones so we'll
3266                     // generate wxEVT_CHAR for them later when we get it.
3267                     case VK_ESCAPE:
3268                     case VK_SPACE:
3269                     case VK_RETURN:
3270                     case VK_BACK:
3271                     case VK_TAB:
3272                     case VK_ADD:
3273                     case VK_SUBTRACT:
3274                     case VK_MULTIPLY:
3275                     case VK_DIVIDE:
3276                     case VK_DECIMAL:
3277                     case VK_NUMPAD0:
3278                     case VK_NUMPAD1:
3279                     case VK_NUMPAD2:
3280                     case VK_NUMPAD3:
3281                     case VK_NUMPAD4:
3282                     case VK_NUMPAD5:
3283                     case VK_NUMPAD6:
3284                     case VK_NUMPAD7:
3285                     case VK_NUMPAD8:
3286                     case VK_NUMPAD9:
3287                     case VK_OEM_1:
3288                     case VK_OEM_2:
3289                     case VK_OEM_3:
3290                     case VK_OEM_4:
3291                     case VK_OEM_5:
3292                     case VK_OEM_6:
3293                     case VK_OEM_7:
3294                     case VK_OEM_8:
3295                     case VK_OEM_102:
3296                     case VK_OEM_PLUS:
3297                     case VK_OEM_COMMA:
3298                     case VK_OEM_MINUS:
3299                     case VK_OEM_PERIOD:
3300                         break;
3301 
3302                     default:
3303                         if ( (wParam >= '0' && wParam <= '9') ||
3304                                 (wParam >= 'A' && wParam <= 'Z') )
3305                         {
3306                             // We'll get WM_CHAR for those later too.
3307                             break;
3308                         }
3309 
3310                         // But for the rest we won't get WM_CHAR later so we do
3311                         // need to generate the event right now.
3312                         wxKeyEvent event(wxEVT_CHAR);
3313                         InitAnyKeyEvent(event, wParam, lParam);
3314 
3315                         // Set the "extended" bit in lParam because we want to
3316                         // generate CHAR events with WXK_HOME and not
3317                         // WXK_NUMPAD_HOME even if the "Home" key on numpad was
3318                         // pressed.
3319                         event.m_keyCode = wxMSWKeyboard::VKToWX
3320                                           (
3321                                             wParam,
3322                                             lParam | (KF_EXTENDED << 16)
3323                                           );
3324 
3325                         // Don't produce events without any valid character
3326                         // code (even if this shouldn't normally happen...).
3327                         if ( event.m_keyCode != WXK_NONE )
3328                             processed = HandleWindowEvent(event);
3329                 }
3330             }
3331             break;
3332 
3333         case WM_SYSKEYUP:
3334         case WM_KEYUP:
3335             processed = HandleKeyUp((WORD) wParam, lParam);
3336             break;
3337 
3338         case WM_SYSCHAR:
3339         case WM_CHAR: // Always an ASCII character
3340             if ( m_lastKeydownProcessed )
3341             {
3342                 // The key was handled in the EVT_KEY_DOWN and handling
3343                 // a key in an EVT_KEY_DOWN handler is meant, by
3344                 // design, to prevent EVT_CHARs from happening
3345                 m_lastKeydownProcessed = false;
3346                 processed = true;
3347             }
3348             else
3349             {
3350                 processed = HandleChar((WORD)wParam, lParam);
3351             }
3352             break;
3353 
3354         case WM_IME_STARTCOMPOSITION:
3355             // IME popup needs Escape as it should undo the changes in its
3356             // entry window instead of e.g. closing the dialog for which the
3357             // IME is used (and losing all the changes in the IME window).
3358             gs_modalEntryWindowCount++;
3359             break;
3360 
3361         case WM_IME_ENDCOMPOSITION:
3362             gs_modalEntryWindowCount--;
3363             break;
3364 
3365 #if wxUSE_HOTKEY
3366         case WM_HOTKEY:
3367             processed = HandleHotKey(wParam, lParam);
3368             break;
3369 #endif // wxUSE_HOTKEY
3370 
3371         case WM_CUT:
3372         case WM_COPY:
3373         case WM_PASTE:
3374             processed = HandleClipboardEvent(message);
3375             break;
3376 
3377         case WM_HSCROLL:
3378         case WM_VSCROLL:
3379             {
3380                 WXWORD code, pos;
3381                 WXHWND hwnd;
3382                 UnpackScroll(wParam, lParam, &code, &pos, &hwnd);
3383 
3384                 processed = MSWOnScroll(message == WM_HSCROLL ? wxHORIZONTAL
3385                                                               : wxVERTICAL,
3386                                         code, pos, hwnd);
3387             }
3388             break;
3389 
3390 #ifdef WM_GESTURE
3391         case WM_GESTURE:
3392         {
3393             if ( !GestureFuncs::IsOk() )
3394                 break;
3395 
3396             HGESTUREINFO hGestureInfo = reinterpret_cast<HGESTUREINFO>(lParam);
3397 
3398             WinStruct<GESTUREINFO> gestureInfo;
3399             if ( !GestureFuncs::GetGestureInfo()(hGestureInfo, &gestureInfo) )
3400             {
3401                 wxLogLastError("GetGestureInfo");
3402                 break;
3403             }
3404 
3405             if ( gestureInfo.hwndTarget != GetHWND() )
3406             {
3407                 wxLogDebug("This is Not the window targeted by this gesture!");
3408             }
3409 
3410             const wxPoint pt = ScreenToClient
3411                                (
3412                                     wxPoint(gestureInfo.ptsLocation.x,
3413                                             gestureInfo.ptsLocation.y)
3414                                );
3415 
3416             // dwID field is used to determine the type of gesture
3417             switch ( gestureInfo.dwID )
3418             {
3419                 case GID_PAN:
3420                     // Point contains the current position of the pan.
3421                     processed = HandlePanGesture(pt, gestureInfo.dwFlags);
3422                     break;
3423 
3424                 case GID_ZOOM:
3425                     // Point is the mid-point of 2 fingers and ullArgument
3426                     // contains the distance between the fingers in its lower
3427                     // half
3428                     processed = HandleZoomGesture
3429                                 (
3430                                     pt,
3431                                     static_cast<DWORD>(gestureInfo.ullArguments),
3432                                     gestureInfo.dwFlags
3433                                 );
3434                     break;
3435 
3436                 case GID_ROTATE:
3437                     // Point is the center point of rotation and ullArguments
3438                     // contains the angle of rotation
3439                     processed = HandleRotateGesture
3440                                 (
3441                                     pt,
3442                                     static_cast<DWORD>(gestureInfo.ullArguments),
3443                                     gestureInfo.dwFlags
3444                                 );
3445                     break;
3446 
3447                 case GID_TWOFINGERTAP:
3448                     processed = HandleTwoFingerTap(pt, gestureInfo.dwFlags);
3449                     break;
3450 
3451                 case GID_PRESSANDTAP:
3452                     processed = HandlePressAndTap(pt, gestureInfo.dwFlags);
3453                     break;
3454             }
3455 
3456             if ( processed )
3457             {
3458                 // If processed, we must call this to avoid memory leaks
3459                 if ( !GestureFuncs::CloseGestureInfoHandle()(hGestureInfo) )
3460                 {
3461                     wxLogLastError("CloseGestureInfoHandle");
3462                 }
3463             }
3464         }
3465         break;
3466 #endif // WM_GESTURE
3467 
3468         // CTLCOLOR messages are sent by children to query the parent for their
3469         // colors
3470         case WM_CTLCOLORMSGBOX:
3471         case WM_CTLCOLOREDIT:
3472         case WM_CTLCOLORLISTBOX:
3473         case WM_CTLCOLORBTN:
3474         case WM_CTLCOLORDLG:
3475         case WM_CTLCOLORSCROLLBAR:
3476         case WM_CTLCOLORSTATIC:
3477             {
3478                 WXHDC hdc;
3479                 WXHWND hwnd;
3480                 UnpackCtlColor(wParam, lParam, &hdc, &hwnd);
3481 
3482                 processed = HandleCtlColor(&rc.hBrush, (WXHDC)hdc, (WXHWND)hwnd);
3483             }
3484             break;
3485 
3486         case WM_SYSCOLORCHANGE:
3487             // the return value for this message is ignored
3488             processed = HandleSysColorChange();
3489             break;
3490 
3491         case WM_DISPLAYCHANGE:
3492             processed = HandleDisplayChange();
3493             break;
3494 
3495         case WM_PALETTECHANGED:
3496             processed = HandlePaletteChanged((WXHWND)wParam);
3497             break;
3498 
3499         case WM_CAPTURECHANGED:
3500             processed = HandleCaptureChanged((WXHWND)lParam);
3501             break;
3502 
3503         case WM_SETTINGCHANGE:
3504             processed = HandleSettingChange(wParam, lParam);
3505             break;
3506 
3507         case WM_QUERYNEWPALETTE:
3508             processed = HandleQueryNewPalette();
3509             break;
3510 
3511         case WM_ERASEBKGND:
3512             {
3513 #ifdef wxHAS_MSW_BACKGROUND_ERASE_HOOK
3514                 // check if an override was configured for this window
3515                 EraseBgHooks::const_iterator it = gs_eraseBgHooks.find(this);
3516                 if ( it != gs_eraseBgHooks.end() )
3517                     processed = it->second->MSWEraseBgHook((WXHDC)wParam);
3518                 else
3519 #endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK
3520                     processed = HandleEraseBkgnd((WXHDC)wParam);
3521             }
3522 
3523             if ( processed )
3524             {
3525                 // we processed the message, i.e. erased the background
3526                 rc.result = TRUE;
3527             }
3528             break;
3529 
3530         case WM_DROPFILES:
3531             processed = HandleDropFiles(wParam);
3532             break;
3533 
3534         case WM_INITDIALOG:
3535             processed = HandleInitDialog((WXHWND)wParam);
3536 
3537             if ( processed )
3538             {
3539                 // we never set focus from here
3540                 rc.result = FALSE;
3541             }
3542             break;
3543 
3544         case WM_QUERYENDSESSION:
3545             processed = HandleQueryEndSession(lParam, &rc.allow);
3546             break;
3547 
3548         case WM_ENDSESSION:
3549             processed = HandleEndSession(wParam != 0, lParam);
3550             break;
3551 
3552         case WM_GETMINMAXINFO:
3553             processed = HandleGetMinMaxInfo((MINMAXINFO*)lParam);
3554             break;
3555 
3556         case WM_SETCURSOR:
3557             processed = HandleSetCursor((WXHWND)wParam,
3558                                         LOWORD(lParam),     // hit test
3559                                         HIWORD(lParam));    // mouse msg
3560 
3561             if ( processed )
3562             {
3563                 // returning TRUE stops the DefWindowProc() from further
3564                 // processing this message - exactly what we need because we've
3565                 // just set the cursor.
3566                 rc.result = TRUE;
3567             }
3568             break;
3569 
3570 #if wxUSE_ACCESSIBILITY
3571         case WM_GETOBJECT:
3572             {
3573                 //WPARAM dwFlags = (WPARAM) (DWORD) wParam;
3574                 LPARAM dwObjId = (LPARAM) (DWORD) lParam;
3575 
3576                 if (dwObjId == (LPARAM)OBJID_CLIENT && GetOrCreateAccessible())
3577                 {
3578                     processed = true;
3579                     rc.result = LresultFromObject(IID_IAccessible, wParam, (IUnknown*) GetAccessible()->GetIAccessible());
3580                 }
3581                 break;
3582             }
3583 #endif
3584 
3585         case WM_HELP:
3586             {
3587                 // by default, WM_HELP is propagated by DefWindowProc() upwards
3588                 // to the window parent but as we do it ourselves already
3589                 // (wxHelpEvent is derived from wxCommandEvent), we don't want
3590                 // to get the other events if we process this message at all
3591                 processed = true;
3592 
3593                 // WM_HELP doesn't use lParam under CE
3594                 HELPINFO* info = (HELPINFO*) lParam;
3595                 if ( info->iContextType == HELPINFO_WINDOW )
3596                 {
3597                     wxHelpEvent helpEvent
3598                                 (
3599                                     wxEVT_HELP,
3600                                     GetId(),
3601                                     wxPoint(info->MousePos.x, info->MousePos.y)
3602                                 );
3603 
3604                     helpEvent.SetEventObject(this);
3605                     HandleWindowEvent(helpEvent);
3606                 }
3607                 else if ( info->iContextType == HELPINFO_MENUITEM )
3608                 {
3609                     wxHelpEvent helpEvent(wxEVT_HELP, info->iCtrlId);
3610                     helpEvent.SetEventObject(this);
3611                     HandleWindowEvent(helpEvent);
3612 
3613                 }
3614                 else // unknown help event?
3615                 {
3616                     processed = false;
3617                 }
3618             }
3619             break;
3620 
3621         case WM_CONTEXTMENU:
3622             {
3623                 // As with WM_HELP above, we need to avoid duplicate events due
3624                 // to wxContextMenuEvent being a (propagatable) wxCommandEvent
3625                 // at wx level but WM_CONTEXTMENU also being propagated upwards
3626                 // by DefWindowProc(). Unlike WM_HELP, we still need to pass
3627                 // this one to DefWindowProc() as it sometimes does useful
3628                 // things with it, e.g. displays the default context menu in
3629                 // EDIT controls. So we do let the default processing to take
3630                 // place but set this flag before calling into DefWindowProc()
3631                 // and don't do anything if we're called from inside it.
3632                 static bool s_propagatedByDefWndProc = false;
3633                 if ( s_propagatedByDefWndProc )
3634                 {
3635                     // We could also return false from here, it shouldn't
3636                     // matter, the important thing is to not send any events.
3637                     // But returning true prevents the message from bubbling up
3638                     // even further upwards and so seems to be better.
3639                     processed = true;
3640                     break;
3641                 }
3642 
3643                 // we don't convert from screen to client coordinates as
3644                 // the event may be handled by a parent window
3645                 wxPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
3646 
3647                 // we could have got an event from our child, reflect it back
3648                 // to it if this is the case
3649                 wxWindowMSW *win = NULL;
3650                 WXHWND hWnd = (WXHWND)wParam;
3651                 if ( hWnd != m_hWnd )
3652                 {
3653                     win = FindItemByHWND(hWnd);
3654                 }
3655 
3656                 if ( !win )
3657                     win = this;
3658 
3659                 processed = win->WXSendContextMenuEvent(pt);
3660 
3661                 if ( !processed )
3662                 {
3663                     // Temporarily set the flag before calling out.
3664                     s_propagatedByDefWndProc = true;
3665                     wxON_BLOCK_EXIT_SET(s_propagatedByDefWndProc, false);
3666 
3667                     // Now do whatever the default handling does, which could
3668                     // be nothing at all -- but we can't know this, so we still
3669                     // need to call it.
3670                     win->MSWDefWindowProc(message, wParam, lParam);
3671 
3672                     // And finally pretend that we processed the message in any
3673                     // case because otherwise DefWindowProc() that we're called
3674                     // from would pass the message to our parent resulting in
3675                     // duplicate events. As it is, we ensure that only one
3676                     // wxWindow ever gets this message for any given click.
3677                     processed = true;
3678                 }
3679             }
3680             break;
3681 
3682 #if wxUSE_MENUS && !defined(__WXUNIVERSAL__)
3683         case WM_MENUCHAR:
3684             // we're only interested in our own menus, not MF_SYSMENU
3685             if ( HIWORD(wParam) == MF_POPUP )
3686             {
3687                 // handle menu chars for ownerdrawn menu items
3688                 int i = HandleMenuChar(toupper(LOWORD(wParam)), lParam);
3689                 if ( i != wxNOT_FOUND )
3690                 {
3691                     rc.result = MAKELRESULT(i, MNC_EXECUTE);
3692                     processed = true;
3693                 }
3694             }
3695             break;
3696 
3697         case WM_INITMENUPOPUP:
3698             processed = HandleMenuPopup(wxEVT_MENU_OPEN, (WXHMENU)wParam);
3699             break;
3700 
3701         case WM_MENUSELECT:
3702             {
3703                 WXWORD item, flags;
3704                 WXHMENU hmenu;
3705                 UnpackMenuSelect(wParam, lParam, &item, &flags, &hmenu);
3706 
3707                 processed = HandleMenuSelect(item, flags, hmenu);
3708             }
3709             break;
3710 
3711         case WM_UNINITMENUPOPUP:
3712             processed = HandleMenuPopup(wxEVT_MENU_CLOSE, (WXHMENU)wParam);
3713             break;
3714 #endif // wxUSE_MENUS && !defined(__WXUNIVERSAL__)
3715 
3716         case WM_POWERBROADCAST:
3717             {
3718                 bool vetoed;
3719                 processed = HandlePower(wParam, lParam, &vetoed);
3720                 rc.result = processed && vetoed ? BROADCAST_QUERY_DENY : TRUE;
3721             }
3722             break;
3723 
3724 #if wxUSE_POPUPWIN
3725         case WM_NCACTIVATE:
3726             // When we're losing activation to our own popup window, we want to
3727             // retain the "active" appearance of the title bar, as dropping
3728             // down a combobox popup shouldn't deactivate the window containing
3729             // the combobox, for example. Explicitly calling DefWindowProc() to
3730             // draw the window as active seems to be the only way of achieving
3731             // this (thanks to Barmak Shemirani for suggesting it at
3732             // https://stackoverflow.com/a/52808753/15275).
3733             if ( !wParam &&
3734                     wxCurrentPopupWindow &&
3735                         wxCurrentPopupWindow->MSWGetOwner() == this )
3736             {
3737                 rc.result = MSWDefWindowProc(message, TRUE, lParam);
3738                 processed = true;
3739             }
3740             break;
3741 #endif
3742 
3743 #if wxUSE_UXTHEME
3744         // If we want the default themed border then we need to draw it ourselves
3745         case WM_NCCALCSIZE:
3746             {
3747                 const wxBorder border = TranslateBorder(GetBorder());
3748                 if (wxUxThemeIsActive() && border == wxBORDER_THEME)
3749                 {
3750                     // first ask the widget to calculate the border size
3751                     rc.result = MSWDefWindowProc(message, wParam, lParam);
3752                     processed = true;
3753 
3754                     // now alter the client size making room for drawing a
3755                     // themed border
3756                     RECT *rect;
3757                     NCCALCSIZE_PARAMS *csparam = NULL;
3758                     if ( wParam )
3759                     {
3760                         csparam = (NCCALCSIZE_PARAMS *)lParam;
3761                         rect = &csparam->rgrc[0];
3762                     }
3763                     else
3764                     {
3765                         rect = (RECT *)lParam;
3766                     }
3767 
3768                     wxUxThemeHandle hTheme((const wxWindow *)this, L"EDIT");
3769 
3770                     // There is no need to initialize rcClient: either it will
3771                     // be done by GetThemeBackgroundContentRect() or we'll do
3772                     // it below if it fails.
3773                     RECT rcClient;
3774 
3775                     wxClientDC dc((wxWindow *)this);
3776                     wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl();
3777 
3778                     if ( ::GetThemeBackgroundContentRect
3779                                 (
3780                                  hTheme,
3781                                  GetHdcOf(*impl),
3782                                  EP_EDITTEXT,
3783                                  IsEnabled() ? ETS_NORMAL : ETS_DISABLED,
3784                                  rect,
3785                                  &rcClient) != S_OK )
3786                     {
3787                         // If GetThemeBackgroundContentRect() failed, as can
3788                         // happen with at least some custom themes, just use
3789                         // the original client rectangle.
3790                         rcClient = *rect;
3791                     }
3792 
3793                     InflateRect(&rcClient, -1, -1);
3794                     if (wParam)
3795                         csparam->rgrc[0] = rcClient;
3796                     else
3797                         *((RECT*)lParam) = rcClient;
3798 
3799                     // WVR_REDRAW triggers a bug whereby child windows are moved up and left,
3800                     // so don't use.
3801                     // rc.result = WVR_REDRAW;
3802                 }
3803             }
3804             break;
3805 
3806         case WM_NCPAINT:
3807             {
3808                 const wxBorder border = TranslateBorder(GetBorder());
3809                 if (wxUxThemeIsActive() && border == wxBORDER_THEME)
3810                 {
3811                     // first ask the widget to paint its non-client area, such as scrollbars, etc.
3812                     rc.result = MSWDefWindowProc(message, wParam, lParam);
3813                     processed = true;
3814 
3815                     wxUxThemeHandle hTheme((const wxWindow *)this, L"EDIT");
3816                     wxWindowDC dc((wxWindow *)this);
3817                     wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl();
3818 
3819                     // Clip the DC so that you only draw on the non-client area
3820                     RECT rcBorder;
3821                     wxCopyRectToRECT(GetSize(), rcBorder);
3822 
3823                     RECT rcClient;
3824 
3825                     const int nState = IsEnabled() ? ETS_NORMAL : ETS_DISABLED;
3826 
3827                     if ( ::GetThemeBackgroundContentRect
3828                                 (
3829                                  hTheme,
3830                                  GetHdcOf(*impl),
3831                                  EP_EDITTEXT,
3832                                  nState,
3833                                  &rcBorder,
3834                                  &rcClient
3835                                 ) != S_OK )
3836                     {
3837                         // As above in WM_NCCALCSIZE, fall back on something
3838                         // reasonable for themes which don't implement this
3839                         // function.
3840                         rcClient = rcBorder;
3841                     }
3842 
3843                     InflateRect(&rcClient, -1, -1);
3844 
3845                     ::ExcludeClipRect(GetHdcOf(*impl), rcClient.left, rcClient.top,
3846                                       rcClient.right, rcClient.bottom);
3847 
3848                     // Make sure the background is in a proper state
3849                     if (::IsThemeBackgroundPartiallyTransparent(hTheme, EP_EDITTEXT, nState))
3850                     {
3851                         ::DrawThemeParentBackground(GetHwnd(), GetHdcOf(*impl), &rcBorder);
3852                     }
3853 
3854                     // Draw the border
3855                     ::DrawThemeBackground(hTheme, GetHdcOf(*impl), EP_EDITTEXT, nState, &rcBorder, NULL);
3856                 }
3857             }
3858             break;
3859 
3860 #endif // wxUSE_UXTHEME
3861 
3862         default:
3863             // try a custom message handler
3864             const MSWMessageHandlers::const_iterator
3865                 i = gs_messageHandlers.find(message);
3866             if ( i != gs_messageHandlers.end() )
3867             {
3868                 processed = (*i->second)(this, message, wParam, lParam);
3869             }
3870     }
3871 
3872     if ( !processed )
3873         return false;
3874 
3875     *result = rc.result;
3876 
3877     return true;
3878 }
3879 
MSWWindowProc(WXUINT message,WXWPARAM wParam,WXLPARAM lParam)3880 WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
3881 {
3882     WXLRESULT result;
3883     if ( !MSWHandleMessage(&result, message, wParam, lParam) )
3884     {
3885 #if wxDEBUG_LEVEL >= 2
3886         wxLogTrace("winmsg", wxT("Forwarding %s to DefWindowProc."),
3887                    wxGetMessageName(message));
3888 #endif // wxDEBUG_LEVEL >= 2
3889         result = MSWDefWindowProc(message, wParam, lParam);
3890     }
3891 
3892     return result;
3893 }
3894 
3895 // ----------------------------------------------------------------------------
3896 // wxWindow <-> HWND map
3897 // ----------------------------------------------------------------------------
3898 
wxFindWinFromHandle(HWND hwnd)3899 wxWindow *wxFindWinFromHandle(HWND hwnd)
3900 {
3901     WindowHandles::const_iterator i = gs_windowHandles.find(hwnd);
3902     return i == gs_windowHandles.end() ? NULL : i->second;
3903 }
3904 
wxAssociateWinWithHandle(HWND hwnd,wxWindowMSW * win)3905 void wxAssociateWinWithHandle(HWND hwnd, wxWindowMSW *win)
3906 {
3907     // adding NULL hwnd is (first) surely a result of an error and
3908     // (secondly) breaks menu command processing
3909     wxCHECK_RET( hwnd != (HWND)NULL,
3910                  wxT("attempt to add a NULL hwnd to window list ignored") );
3911 
3912 #if wxDEBUG_LEVEL
3913     WindowHandles::const_iterator i = gs_windowHandles.find(hwnd);
3914     if ( i != gs_windowHandles.end() )
3915     {
3916         if ( i->second != win )
3917         {
3918             wxFAIL_MSG(
3919                 wxString::Format(
3920                     wxT("HWND %p already associated with another window (%s)"),
3921                     hwnd, win->GetClassInfo()->GetClassName()
3922                 )
3923             );
3924         }
3925         //else: this actually happens currently because we associate the window
3926         //      with its HWND during creation (if we create it) and also when
3927         //      SubclassWin() is called later, this is ok
3928     }
3929 #endif // wxDEBUG_LEVEL
3930 
3931     gs_windowHandles[hwnd] = (wxWindow *)win;
3932 }
3933 
wxRemoveHandleAssociation(wxWindowMSW * win)3934 void wxRemoveHandleAssociation(wxWindowMSW *win)
3935 {
3936     gs_windowHandles.erase(GetHwndOf(win));
3937 }
3938 
3939 // ----------------------------------------------------------------------------
3940 // various MSW speciic class dependent functions
3941 // ----------------------------------------------------------------------------
3942 
3943 // Default destroyer - override if you destroy it in some other way
3944 // (e.g. with MDI child windows)
MSWDestroyWindow()3945 void wxWindowMSW::MSWDestroyWindow()
3946 {
3947 }
3948 
MSWGetCreateWindowCoords(const wxPoint & pos,const wxSize & size,int & x,int & y,int & w,int & h) const3949 void wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
3950                                            const wxSize& size,
3951                                            int& x, int& y,
3952                                            int& w, int& h) const
3953 {
3954     // CW_USEDEFAULT can't be used for child windows so just position them at
3955     // the origin by default
3956     x = pos.x == wxDefaultCoord ? 0 : pos.x;
3957     y = pos.y == wxDefaultCoord ? 0 : pos.y;
3958 
3959     AdjustForParentClientOrigin(x, y);
3960 
3961     // We don't have any clearly good choice for the size by default neither
3962     // but we must use something non-zero.
3963     w = WidthDefault(size.x);
3964     h = HeightDefault(size.y);
3965 
3966     /*
3967       NB: there used to be some code here which set the initial size of the
3968           window to the client size of the parent if no explicit size was
3969           specified. This was wrong because wxWidgets programs often assume
3970           that they get a WM_SIZE (EVT_SIZE) upon creation, however this broke
3971           it. To see why, you should understand that Windows sends WM_SIZE from
3972           inside ::CreateWindow() anyhow. However, ::CreateWindow() is called
3973           from some base class ctor and so this WM_SIZE is not processed in the
3974           real class' OnSize() (because it's not fully constructed yet and the
3975           event goes to some base class OnSize() instead). So the WM_SIZE we
3976           rely on is the one sent when the parent frame resizes its children
3977           but here is the problem: if the child already has just the right
3978           size, nothing will happen as both wxWidgets and Windows check for
3979           this and ignore any attempts to change the window size to the size it
3980           already has - so no WM_SIZE would be sent.
3981      */
3982 }
3983 
MSWGetParent() const3984 WXHWND wxWindowMSW::MSWGetParent() const
3985 {
3986     return m_parent ? m_parent->GetHWND() : WXHWND(NULL);
3987 }
3988 
MSWCreate(const wxChar * wclass,const wxChar * title,const wxPoint & pos,const wxSize & size,WXDWORD style,WXDWORD extendedStyle)3989 bool wxWindowMSW::MSWCreate(const wxChar *wclass,
3990                             const wxChar *title,
3991                             const wxPoint& pos,
3992                             const wxSize& size,
3993                             WXDWORD style,
3994                             WXDWORD extendedStyle)
3995 {
3996     // check a common bug in the user code: if the window is created with a
3997     // non-default ctor and Create() is called too, we'd create 2 HWND for a
3998     // single wxWindow object and this results in all sorts of trouble,
3999     // especially for wxTLWs
4000     wxCHECK_MSG( !m_hWnd, true, "window can't be recreated" );
4001 
4002     // this can happen if this function is called using the return value of
4003     // wxApp::GetRegisteredClassName() which failed
4004     wxCHECK_MSG( wclass, false, "failed to register window class?" );
4005 
4006 
4007     // choose the position/size for the new window
4008     int x, y, w, h;
4009     (void)MSWGetCreateWindowCoords(pos, size, x, y, w, h);
4010 
4011     // controlId is menu handle for the top level windows, so set it to 0
4012     // unless we're creating a child window
4013     int controlId = style & WS_CHILD ? GetId() : 0;
4014 
4015     // do create the window
4016     wxWindowCreationHook hook(this);
4017 
4018     m_hWnd = MSWCreateWindowAtAnyPosition
4019              (
4020               extendedStyle,
4021               wclass,
4022               title ? title : m_windowName.t_str(),
4023               style,
4024               x, y, w, h,
4025               MSWGetParent(),
4026               controlId
4027              );
4028 
4029     if ( !m_hWnd )
4030     {
4031         return false;
4032     }
4033 
4034     SubclassWin(m_hWnd);
4035 
4036     return true;
4037 }
4038 
MSWCreateWindowAtAnyPosition(WXDWORD exStyle,const wxChar * clName,const wxChar * title,WXDWORD style,int x,int y,int width,int height,WXHWND parent,wxWindowID id)4039 WXHWND wxWindowMSW::MSWCreateWindowAtAnyPosition(WXDWORD exStyle, const wxChar* clName,
4040                                                  const wxChar* title, WXDWORD style,
4041                                                  int x, int y, int width, int height,
4042                                                  WXHWND parent, wxWindowID id)
4043 {
4044     WXHWND hWnd = ::CreateWindowEx(exStyle, clName, title, style, x, y, width, height,
4045                                    parent, (HMENU)wxUIntToPtr(id), wxGetInstance(),
4046                                    NULL); // no extra data
4047 
4048     if ( !hWnd )
4049     {
4050         wxLogLastError(wxString::Format
4051         (
4052             wxT("CreateWindowEx(\"%s\", flags=%08lx, ex=%08lx)"),
4053             clName, style, exStyle
4054         ));
4055     }
4056     else if ( !IsTopLevel() && !MSWIsPositionDirectlySupported(x, y) )
4057     {
4058         // fix position if limited by Short range
4059         MSWMoveWindowToAnyPosition(hWnd, x, y, width, height, IsShown());
4060     }
4061 
4062     return hWnd;
4063 }
4064 
4065 // ===========================================================================
4066 // MSW message handlers
4067 // ===========================================================================
4068 
4069 // ---------------------------------------------------------------------------
4070 // WM_NOTIFY
4071 // ---------------------------------------------------------------------------
4072 
HandleNotify(int idCtrl,WXLPARAM lParam,WXLPARAM * result)4073 bool wxWindowMSW::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
4074 {
4075     LPNMHDR hdr = (LPNMHDR)lParam;
4076     HWND hWnd = hdr->hwndFrom;
4077     wxWindow *win = wxFindWinFromHandle(hWnd);
4078 
4079     // if the control is one of our windows, let it handle the message itself
4080     if ( win )
4081     {
4082         return win->MSWOnNotify(idCtrl, lParam, result);
4083     }
4084 
4085     // VZ: why did we do it? normally this is unnecessary and, besides, it
4086     //     breaks the message processing for the toolbars because the tooltip
4087     //     notifications were being forwarded to the toolbar child controls
4088     //     (if it had any) before being passed to the toolbar itself, so in my
4089     //     example the tooltip for the combobox was always shown instead of the
4090     //     correct button tooltips
4091 #if 0
4092     // try all our children
4093     wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
4094     while ( node )
4095     {
4096         wxWindow *child = node->GetData();
4097         if ( child->MSWOnNotify(idCtrl, lParam, result) )
4098         {
4099             return true;
4100         }
4101 
4102         node = node->GetNext();
4103     }
4104 #endif // 0
4105 
4106     // by default, handle it ourselves
4107     return MSWOnNotify(idCtrl, lParam, result);
4108 }
4109 
4110 #if wxUSE_TOOLTIPS
4111 
HandleTooltipNotify(WXUINT code,WXLPARAM lParam,const wxString & ttip)4112 bool wxWindowMSW::HandleTooltipNotify(WXUINT code,
4113                                       WXLPARAM lParam,
4114                                       const wxString& ttip)
4115 {
4116     // I don't know why it happens, but the versions of comctl32.dll starting
4117     // from 4.70 sometimes send TTN_NEEDTEXTW even to ANSI programs (normally,
4118     // this message is supposed to be sent to Unicode programs only) -- hence
4119     // we need to handle it as well, otherwise no tooltips will be shown in
4120     // this case
4121     if ( !(code == (WXUINT) TTN_NEEDTEXTA || code == (WXUINT) TTN_NEEDTEXTW)
4122             || ttip.empty() )
4123     {
4124         // not a tooltip message or no tooltip to show anyhow
4125         return false;
4126     }
4127 
4128     LPTOOLTIPTEXT ttText = (LPTOOLTIPTEXT)lParam;
4129 
4130     // We don't want to use the szText buffer because it has a limit of 80
4131     // bytes and this is not enough, especially for Unicode build where it
4132     // limits the tooltip string length to only 40 characters
4133     //
4134     // The best would be, of course, to not impose any length limitations at
4135     // all but then the buffer would have to be dynamic and someone would have
4136     // to free it and we don't have the tooltip owner object here any more, so
4137     // for now use our own static buffer with a higher fixed max length.
4138     //
4139     // Note that using a static buffer should not be a problem as only a single
4140     // tooltip can be shown at the same time anyhow.
4141 #if !wxUSE_UNICODE
4142     if ( code == (WXUINT) TTN_NEEDTEXTW )
4143     {
4144         // We need to convert tooltip from multi byte to Unicode on the fly.
4145         static wchar_t buf[513];
4146 
4147         // Truncate tooltip length if needed as otherwise we might not have
4148         // enough space for it in the buffer and MultiByteToWideChar() would
4149         // return an error
4150         size_t tipLength = wxMin(ttip.length(), WXSIZEOF(buf) - 1);
4151 
4152         // Convert to WideChar without adding the NULL character. The NULL
4153         // character is added afterwards (this is more efficient).
4154         int len = ::MultiByteToWideChar
4155                     (
4156                         CP_ACP,
4157                         0,                      // no flags
4158                         ttip.t_str(),
4159                         tipLength,
4160                         buf,
4161                         WXSIZEOF(buf) - 1
4162                     );
4163 
4164         if ( !len )
4165         {
4166             wxLogLastError(wxT("MultiByteToWideChar()"));
4167         }
4168 
4169         buf[len] = L'\0';
4170         ttText->lpszText = (LPSTR) buf;
4171     }
4172     else // TTN_NEEDTEXTA
4173 #endif // !wxUSE_UNICODE
4174     {
4175         // we get here if we got TTN_NEEDTEXTA (only happens in ANSI build) or
4176         // if we got TTN_NEEDTEXTW in Unicode build: in this case we just have
4177         // to copy the string we have into the buffer
4178         static wxChar buf[513];
4179         wxStrlcpy(buf, ttip.c_str(), WXSIZEOF(buf));
4180         ttText->lpszText = buf;
4181     }
4182 
4183     return true;
4184 }
4185 
4186 #endif // wxUSE_TOOLTIPS
4187 
MSWOnNotify(int WXUNUSED (idCtrl),WXLPARAM lParam,WXLPARAM * WXUNUSED (result))4188 bool wxWindowMSW::MSWOnNotify(int WXUNUSED(idCtrl),
4189                               WXLPARAM lParam,
4190                               WXLPARAM* WXUNUSED(result))
4191 {
4192 #if wxUSE_TOOLTIPS
4193     if ( m_tooltip )
4194     {
4195         NMHDR* hdr = (NMHDR *)lParam;
4196         if ( HandleTooltipNotify(hdr->code, lParam, m_tooltip->GetTip()))
4197         {
4198             // processed
4199             return true;
4200         }
4201     }
4202 #else
4203     wxUnusedVar(lParam);
4204 #endif // wxUSE_TOOLTIPS
4205 
4206     return false;
4207 }
4208 
4209 // ---------------------------------------------------------------------------
4210 // end session messages
4211 // ---------------------------------------------------------------------------
4212 
HandleQueryEndSession(long logOff,bool * mayEnd)4213 bool wxWindowMSW::HandleQueryEndSession(long logOff, bool *mayEnd)
4214 {
4215     wxCloseEvent event(wxEVT_QUERY_END_SESSION, wxID_ANY);
4216     event.SetEventObject(wxTheApp);
4217     event.SetCanVeto(true);
4218     event.SetLoggingOff(logOff == (long)ENDSESSION_LOGOFF);
4219 
4220     bool rc = wxTheApp->SafelyProcessEvent(event);
4221 
4222     if ( rc )
4223     {
4224         // we may end only if the app didn't veto session closing (double
4225         // negation...)
4226         *mayEnd = !event.GetVeto();
4227     }
4228 
4229     return rc;
4230 }
4231 
HandleEndSession(bool endSession,long logOff)4232 bool wxWindowMSW::HandleEndSession(bool endSession, long logOff)
4233 {
4234     // do nothing if the session isn't ending
4235     if ( !endSession )
4236         return false;
4237 
4238     // only send once
4239     if ( this != wxApp::GetMainTopWindow() )
4240         return false;
4241 
4242     wxCloseEvent event(wxEVT_END_SESSION, wxID_ANY);
4243     event.SetEventObject(wxTheApp);
4244     event.SetCanVeto(false);
4245     event.SetLoggingOff((logOff & ENDSESSION_LOGOFF) != 0);
4246 
4247     return wxTheApp->SafelyProcessEvent(event);
4248 }
4249 
4250 // ---------------------------------------------------------------------------
4251 // window creation/destruction
4252 // ---------------------------------------------------------------------------
4253 
HandleCreate(WXLPCREATESTRUCT cs,bool * mayCreate)4254 bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT cs,
4255                                bool *mayCreate)
4256 {
4257     if ( ((CREATESTRUCT *)cs)->dwExStyle & WS_EX_CONTROLPARENT )
4258         EnsureParentHasControlParentStyle(GetParent());
4259 
4260     *mayCreate = true;
4261 
4262     return true;
4263 }
4264 
HandleDestroy()4265 bool wxWindowMSW::HandleDestroy()
4266 {
4267     // delete our drop target if we've got one
4268 #if wxUSE_DRAG_AND_DROP
4269     if ( m_dropTarget != NULL )
4270     {
4271         m_dropTarget->Revoke(m_hWnd);
4272 
4273         wxDELETE(m_dropTarget);
4274     }
4275 #endif // wxUSE_DRAG_AND_DROP
4276 
4277     // WM_DESTROY handled
4278     return true;
4279 }
4280 
4281 // ---------------------------------------------------------------------------
4282 // activation/focus
4283 // ---------------------------------------------------------------------------
4284 
HandleActivate(int state,bool minimized,WXHWND WXUNUSED (activate))4285 bool wxWindowMSW::HandleActivate(int state,
4286                                  bool minimized,
4287                                  WXHWND WXUNUSED(activate))
4288 {
4289     if ( minimized )
4290     {
4291         // Getting activation event when the window is minimized, as happens
4292         // e.g. when the window task bar icon is clicked, is unexpected and
4293         // managed to even break the logic in wx itself (see #17128), so just
4294         // don't do it as there doesn't seem to be any need to be notified
4295         // about the activation of the window icon in the task bar in practice.
4296         return false;
4297     }
4298 
4299     if ( m_isBeingDeleted )
4300     {
4301         // Same goes for activation events sent to an already half-destroyed
4302         // window: this doesn't happen always, but can happen for a TLW using a
4303         // (still existent) hidden parent, see #18970.
4304         return false;
4305     }
4306 
4307     wxActivateEvent event(wxEVT_ACTIVATE,
4308                           (state == WA_ACTIVE) || (state == WA_CLICKACTIVE),
4309                           m_windowId,
4310                           state == WA_CLICKACTIVE
4311                             ? wxActivateEvent::Reason_Mouse
4312                             : wxActivateEvent::Reason_Unknown);
4313     event.SetEventObject(this);
4314 
4315     return HandleWindowEvent(event);
4316 }
4317 
HandleSetFocus(WXHWND hwnd)4318 bool wxWindowMSW::HandleSetFocus(WXHWND hwnd)
4319 {
4320     // Strangly enough, some controls get set focus events when they are being
4321     // deleted, even if they already had focus before.
4322     if ( m_isBeingDeleted )
4323     {
4324         return false;
4325     }
4326 
4327     if ( ContainsHWND(hwnd) )
4328     {
4329         // If another subwindow of this window already had focus before, this
4330         // window should already have focus at wx level, no need for another
4331         // event.
4332         return false;
4333     }
4334 
4335     // notify the parent keeping track of focus for the kbd navigation
4336     // purposes that we got it
4337     wxChildFocusEvent eventFocus((wxWindow *)this);
4338     (void)HandleWindowEvent(eventFocus);
4339 
4340 #if wxUSE_CARET
4341     // Deal with caret
4342     if ( m_caret )
4343     {
4344         m_caret->OnSetFocus();
4345     }
4346 #endif // wxUSE_CARET
4347 
4348     wxFocusEvent event(wxEVT_SET_FOCUS, m_windowId);
4349     event.SetEventObject(this);
4350 
4351     // wxFindWinFromHandle() may return NULL, it is ok
4352     event.SetWindow(wxFindWinFromHandle(hwnd));
4353 
4354     return HandleWindowEvent(event);
4355 }
4356 
HandleKillFocus(WXHWND hwnd)4357 bool wxWindowMSW::HandleKillFocus(WXHWND hwnd)
4358 {
4359     // Don't send the event when in the process of being deleted.  This can
4360     // only cause problems if the event handler tries to access the object.
4361     if ( m_isBeingDeleted )
4362     {
4363         return false;
4364     }
4365 
4366     if ( ContainsHWND(hwnd) )
4367     {
4368         // If the focus switches to another HWND which is part of the same
4369         // wxWindow, we must not generate a wxEVT_KILL_FOCUS.
4370         return false;
4371     }
4372 
4373 #if wxUSE_CARET
4374     // Deal with caret
4375     if ( m_caret )
4376     {
4377         m_caret->OnKillFocus();
4378     }
4379 #endif // wxUSE_CARET
4380 
4381     wxFocusEvent event(wxEVT_KILL_FOCUS, m_windowId);
4382     event.SetEventObject(this);
4383 
4384     // wxFindWinFromHandle() may return NULL, it is ok
4385     event.SetWindow(wxFindWinFromHandle(hwnd));
4386 
4387     return HandleWindowEvent(event);
4388 }
4389 
4390 // ---------------------------------------------------------------------------
4391 // labels
4392 // ---------------------------------------------------------------------------
4393 
SetLabel(const wxString & label)4394 void wxWindowMSW::SetLabel( const wxString& label)
4395 {
4396     SetWindowText(GetHwnd(), label.c_str());
4397 }
4398 
GetLabel() const4399 wxString wxWindowMSW::GetLabel() const
4400 {
4401     return wxGetWindowText(GetHWND());
4402 }
4403 
4404 // ---------------------------------------------------------------------------
4405 // miscellaneous
4406 // ---------------------------------------------------------------------------
4407 
HandleShow(bool show,int WXUNUSED (status))4408 bool wxWindowMSW::HandleShow(bool show, int WXUNUSED(status))
4409 {
4410     wxShowEvent event(GetId(), show);
4411     event.SetEventObject(this);
4412 
4413     return HandleWindowEvent(event);
4414 }
4415 
HandleInitDialog(WXHWND WXUNUSED (hWndFocus))4416 bool wxWindowMSW::HandleInitDialog(WXHWND WXUNUSED(hWndFocus))
4417 {
4418     wxInitDialogEvent event(GetId());
4419     event.SetEventObject(this);
4420 
4421     return HandleWindowEvent(event);
4422 }
4423 
HandleDropFiles(WXWPARAM wParam)4424 bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam)
4425 {
4426     HDROP hFilesInfo = (HDROP) wParam;
4427 
4428     // Get the total number of files dropped
4429     UINT gwFilesDropped = ::DragQueryFile
4430                             (
4431                                 (HDROP)hFilesInfo,
4432                                 (UINT)-1,
4433                                 (LPTSTR)0,
4434                                 (UINT)0
4435                             );
4436 
4437     wxString *files = new wxString[gwFilesDropped];
4438     for ( UINT wIndex = 0; wIndex < gwFilesDropped; wIndex++ )
4439     {
4440         // first get the needed buffer length (+1 for terminating NUL)
4441         size_t len = ::DragQueryFile(hFilesInfo, wIndex, NULL, 0) + 1;
4442 
4443         // and now get the file name
4444         ::DragQueryFile(hFilesInfo, wIndex,
4445                         wxStringBuffer(files[wIndex], len), len);
4446     }
4447 
4448     wxDropFilesEvent event(wxEVT_DROP_FILES, gwFilesDropped, files);
4449     event.SetEventObject(this);
4450 
4451     POINT dropPoint;
4452     DragQueryPoint(hFilesInfo, (LPPOINT) &dropPoint);
4453     event.m_pos.x = dropPoint.x;
4454     event.m_pos.y = dropPoint.y;
4455 
4456     DragFinish(hFilesInfo);
4457 
4458     return HandleWindowEvent(event);
4459 }
4460 
4461 
HandleSetCursor(WXHWND WXUNUSED (hWnd),short nHitTest,int WXUNUSED (mouseMsg))4462 bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd),
4463                                   short nHitTest,
4464                                   int WXUNUSED(mouseMsg))
4465 {
4466     // the logic is as follows:
4467     //  0. if we're busy, set the busy cursor (even for non client elements)
4468     //  1. don't set custom cursor for non client area of enabled windows
4469     //  2. ask user EVT_SET_CURSOR handler for the cursor
4470     //  3. if still no cursor but we're in a TLW, set the global cursor
4471 
4472     HCURSOR hcursor = 0;
4473 
4474     // Check for "business" is complicated by the fact that modal dialogs shown
4475     // while busy cursor is in effect shouldn't show it as they are active and
4476     // accept input from the user, unlike all the other windows.
4477     bool isBusy = false;
4478     if ( wxIsBusy() )
4479     {
4480         wxDialog* const
4481             dlg = wxDynamicCast(wxGetTopLevelParent((wxWindow *)this), wxDialog);
4482         if ( !dlg || !dlg->IsModal() )
4483             isBusy = true;
4484     }
4485 
4486     if ( isBusy )
4487     {
4488         hcursor = wxGetCurrentBusyCursor();
4489     }
4490     else // not busy
4491     {
4492         if ( nHitTest != HTCLIENT )
4493             return false;
4494 
4495         // first ask the user code - it may wish to set the cursor in some very
4496         // specific way (for example, depending on the current position)
4497         POINT pt;
4498         wxGetCursorPosMSW(&pt);
4499 
4500         int x = pt.x,
4501             y = pt.y;
4502         ScreenToClient(&x, &y);
4503         wxSetCursorEvent event(x, y);
4504         event.SetId(GetId());
4505         event.SetEventObject(this);
4506 
4507         bool processedEvtSetCursor = HandleWindowEvent(event);
4508         if ( processedEvtSetCursor && event.HasCursor() )
4509         {
4510             hcursor = GetHcursorOf(event.GetCursor());
4511         }
4512 
4513         if ( !hcursor )
4514         {
4515             // the test for processedEvtSetCursor is here to prevent using
4516             // m_cursor if the user code caught EVT_SET_CURSOR() and returned
4517             // nothing from it - this is a way to say that our cursor shouldn't
4518             // be used for this point
4519             if ( !processedEvtSetCursor && m_cursor.IsOk() )
4520             {
4521                 hcursor = GetHcursorOf(m_cursor);
4522             }
4523 
4524             if ( !hcursor && !GetParent() )
4525             {
4526                 const wxCursor *cursor = wxGetGlobalCursor();
4527                 if ( cursor && cursor->IsOk() )
4528                 {
4529                     hcursor = GetHcursorOf(*cursor);
4530                 }
4531             }
4532         }
4533     }
4534 
4535 
4536     if ( hcursor )
4537     {
4538         ::SetCursor(hcursor);
4539 
4540         // cursor set, stop here
4541         return true;
4542     }
4543 
4544     // pass up the window chain
4545     return false;
4546 }
4547 
HandlePower(WXWPARAM wParam,WXLPARAM WXUNUSED (lParam),bool * vetoed)4548 bool wxWindowMSW::HandlePower(WXWPARAM wParam,
4549                               WXLPARAM WXUNUSED(lParam),
4550                               bool *vetoed)
4551 {
4552     wxEventType evtType;
4553     switch ( wParam )
4554     {
4555         case PBT_APMQUERYSUSPEND:
4556             evtType = wxEVT_POWER_SUSPENDING;
4557             break;
4558 
4559         case PBT_APMQUERYSUSPENDFAILED:
4560             evtType = wxEVT_POWER_SUSPEND_CANCEL;
4561             break;
4562 
4563         case PBT_APMSUSPEND:
4564             evtType = wxEVT_POWER_SUSPENDED;
4565             break;
4566 
4567         case PBT_APMRESUMESUSPEND:
4568             evtType = wxEVT_POWER_RESUME;
4569             break;
4570 
4571         default:
4572             wxLogDebug(wxT("Unknown WM_POWERBROADCAST(%zd) event"), wParam);
4573             wxFALLTHROUGH;
4574 
4575         // these messages are currently not mapped to wx events
4576         case PBT_APMQUERYSTANDBY:
4577         case PBT_APMQUERYSTANDBYFAILED:
4578         case PBT_APMSTANDBY:
4579         case PBT_APMRESUMESTANDBY:
4580         case PBT_APMBATTERYLOW:
4581         case PBT_APMPOWERSTATUSCHANGE:
4582         case PBT_APMOEMEVENT:
4583         case PBT_APMRESUMECRITICAL:
4584         case PBT_APMRESUMEAUTOMATIC:
4585             evtType = wxEVT_NULL;
4586             break;
4587     }
4588 
4589     // don't handle unknown messages
4590     if ( evtType == wxEVT_NULL )
4591         return false;
4592 
4593     // TODO: notify about PBTF_APMRESUMEFROMFAILURE in case of resume events?
4594 
4595     wxPowerEvent event(evtType);
4596     if ( !HandleWindowEvent(event) )
4597         return false;
4598 
4599     *vetoed = event.IsVetoed();
4600 
4601     return true;
4602 }
4603 
IsDoubleBuffered() const4604 bool wxWindowMSW::IsDoubleBuffered() const
4605 {
4606     for ( const wxWindowMSW *win = this; win; win = win->GetParent() )
4607     {
4608         if ( wxHasWindowExStyle(win, WS_EX_COMPOSITED) )
4609             return true;
4610 
4611         if ( win->IsTopLevel() )
4612             break;
4613     }
4614 
4615     return false;
4616 }
4617 
SetDoubleBuffered(bool on)4618 void wxWindowMSW::SetDoubleBuffered(bool on)
4619 {
4620     wxMSWWinExStyleUpdater(GetHwnd()).TurnOnOrOff(on, WS_EX_COMPOSITED);
4621 }
4622 
4623 // ---------------------------------------------------------------------------
4624 // owner drawn stuff
4625 // ---------------------------------------------------------------------------
4626 
4627 #if (wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE) || \
4628         (wxUSE_CONTROLS && !defined(__WXUNIVERSAL__))
4629     #define WXUNUSED_UNLESS_ODRAWN(param) param
4630 #else
4631     #define WXUNUSED_UNLESS_ODRAWN(param)
4632 #endif
4633 
4634 bool
MSWOnDrawItem(int WXUNUSED_UNLESS_ODRAWN (id),WXDRAWITEMSTRUCT * WXUNUSED_UNLESS_ODRAWN (itemStruct))4635 wxWindowMSW::MSWOnDrawItem(int WXUNUSED_UNLESS_ODRAWN(id),
4636                            WXDRAWITEMSTRUCT * WXUNUSED_UNLESS_ODRAWN(itemStruct))
4637 {
4638 #if wxUSE_OWNER_DRAWN
4639 
4640 #if wxUSE_MENUS_NATIVE
4641     // is it a menu item?
4642     DRAWITEMSTRUCT *pDrawStruct = (DRAWITEMSTRUCT *)itemStruct;
4643     if ( id == 0 && pDrawStruct->CtlType == ODT_MENU )
4644     {
4645         wxMenuItem *pMenuItem = (wxMenuItem *)(pDrawStruct->itemData);
4646 
4647         // see comment before the same test in MSWOnMeasureItem() below
4648         if ( !pMenuItem )
4649             return false;
4650 
4651         wxCHECK_MSG( wxDynamicCast(pMenuItem, wxMenuItem),
4652                          false, wxT("MSWOnDrawItem: bad wxMenuItem pointer") );
4653 
4654         // prepare to call OnDrawItem(): notice using of wxDCTemp to prevent
4655         // the DC from being released
4656         wxDCTemp dc((WXHDC)pDrawStruct->hDC);
4657         wxRect rect(pDrawStruct->rcItem.left, pDrawStruct->rcItem.top,
4658                     pDrawStruct->rcItem.right - pDrawStruct->rcItem.left,
4659                     pDrawStruct->rcItem.bottom - pDrawStruct->rcItem.top);
4660 
4661         return pMenuItem->OnDrawItem
4662                (
4663                 dc,
4664                 rect,
4665                 (wxOwnerDrawn::wxODAction)pDrawStruct->itemAction,
4666                 (wxOwnerDrawn::wxODStatus)pDrawStruct->itemState
4667                );
4668     }
4669 #endif // wxUSE_MENUS_NATIVE
4670 
4671 #endif // USE_OWNER_DRAWN
4672 
4673 #if wxUSE_CONTROLS && !defined(__WXUNIVERSAL__)
4674 
4675 #if wxUSE_OWNER_DRAWN
4676     wxControl *item = wxDynamicCast(FindItem(id), wxControl);
4677 #else // !wxUSE_OWNER_DRAWN
4678     // we may still have owner-drawn buttons internally because we have to make
4679     // them owner-drawn to support colour change
4680     wxControl *item =
4681 #                     if wxUSE_BUTTON
4682                          wxDynamicCast(FindItem(id), wxButton)
4683 #                     else
4684                          NULL
4685 #                     endif
4686                     ;
4687 #endif // USE_OWNER_DRAWN
4688 
4689     if ( item )
4690     {
4691         return item->MSWOnDraw(itemStruct);
4692     }
4693 
4694 #endif // wxUSE_CONTROLS
4695 
4696     return false;
4697 }
4698 
4699 bool
MSWOnMeasureItem(int id,WXMEASUREITEMSTRUCT * itemStruct)4700 wxWindowMSW::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct)
4701 {
4702 #if wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE
4703     // is it a menu item?
4704     MEASUREITEMSTRUCT *pMeasureStruct = (MEASUREITEMSTRUCT *)itemStruct;
4705     if ( id == 0 && pMeasureStruct->CtlType == ODT_MENU )
4706     {
4707         wxMenuItem *pMenuItem = (wxMenuItem *)(pMeasureStruct->itemData);
4708 
4709         // according to Carsten Fuchs the pointer may be NULL under XP if an
4710         // MDI child frame is initially maximized, see this for more info:
4711         // http://article.gmane.org/gmane.comp.lib.wxwidgets.general/27745
4712         //
4713         // so silently ignore it instead of asserting
4714         if ( !pMenuItem )
4715             return false;
4716 
4717         wxCHECK_MSG( wxDynamicCast(pMenuItem, wxMenuItem),
4718                         false, wxT("MSWOnMeasureItem: bad wxMenuItem pointer") );
4719 
4720         size_t w, h;
4721         bool rc = pMenuItem->OnMeasureItem(&w, &h);
4722 
4723         pMeasureStruct->itemWidth = w;
4724         pMeasureStruct->itemHeight = h;
4725 
4726         return rc;
4727     }
4728 
4729     wxControl *item = wxDynamicCast(FindItem(id), wxControl);
4730     if ( item )
4731     {
4732         return item->MSWOnMeasure(itemStruct);
4733     }
4734 #else
4735     wxUnusedVar(id);
4736     wxUnusedVar(itemStruct);
4737 #endif // wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE
4738 
4739     return false;
4740 }
4741 
4742 // ---------------------------------------------------------------------------
4743 // DPI
4744 // ---------------------------------------------------------------------------
4745 
4746 namespace
4747 {
4748 
GetWindowDPI(HWND hwnd)4749 static wxSize GetWindowDPI(HWND hwnd)
4750 {
4751 #if wxUSE_DYNLIB_CLASS
4752     typedef UINT (WINAPI *GetDpiForWindow_t)(HWND hwnd);
4753     static GetDpiForWindow_t s_pfnGetDpiForWindow = NULL;
4754     static bool s_initDone = false;
4755 
4756     if ( !s_initDone )
4757     {
4758         wxLoadedDLL dllUser32("user32.dll");
4759         wxDL_INIT_FUNC(s_pfn, GetDpiForWindow, dllUser32);
4760         s_initDone = true;
4761     }
4762 
4763     if ( s_pfnGetDpiForWindow )
4764     {
4765         const int dpi = static_cast<int>(s_pfnGetDpiForWindow(hwnd));
4766         return wxSize(dpi, dpi);
4767     }
4768 #endif // wxUSE_DYNLIB_CLASS
4769 
4770     return wxSize();
4771 }
4772 
4773 }
4774 
4775 /*extern*/
wxGetSystemMetrics(int nIndex,const wxWindow * window)4776 int wxGetSystemMetrics(int nIndex, const wxWindow* window)
4777 {
4778 #if wxUSE_DYNLIB_CLASS
4779     if ( !window )
4780         window = wxApp::GetMainTopWindow();
4781 
4782     if ( window )
4783     {
4784         typedef int (WINAPI * GetSystemMetricsForDpi_t)(int nIndex, UINT dpi);
4785         static GetSystemMetricsForDpi_t s_pfnGetSystemMetricsForDpi = NULL;
4786         static bool s_initDone = false;
4787 
4788         if ( !s_initDone )
4789         {
4790             wxLoadedDLL dllUser32("user32.dll");
4791             wxDL_INIT_FUNC(s_pfn, GetSystemMetricsForDpi, dllUser32);
4792             s_initDone = true;
4793         }
4794 
4795         if ( s_pfnGetSystemMetricsForDpi )
4796         {
4797             const int dpi = window->GetDPI().y;
4798             return s_pfnGetSystemMetricsForDpi(nIndex, (UINT)dpi);
4799         }
4800     }
4801 #else
4802     wxUnusedVar(window);
4803 #endif // wxUSE_DYNLIB_CLASS
4804 
4805     return ::GetSystemMetrics(nIndex);
4806 }
4807 
4808 /*extern*/
wxSystemParametersInfo(UINT uiAction,UINT uiParam,PVOID pvParam,UINT fWinIni,const wxWindow * window)4809 bool wxSystemParametersInfo(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni, const wxWindow* window)
4810 {
4811     // Note that we can't use SystemParametersInfoForDpi() in non-Unicode build
4812     // because it always works with wide strings and we'd have to check for all
4813     // uiAction values corresponding to strings and use a temporary wide buffer
4814     // for them, and convert the returned value to ANSI after the call. Instead
4815     // of doing all this, just don't use it at all in the deprecated ANSI build.
4816 #if wxUSE_DYNLIB_CLASS && wxUSE_UNICODE
4817     if ( !window )
4818         window = wxApp::GetMainTopWindow();
4819 
4820     if ( window )
4821     {
4822         typedef int (WINAPI * SystemParametersInfoForDpi_t)(UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni, UINT dpi);
4823         static SystemParametersInfoForDpi_t s_pfnSystemParametersInfoForDpi = NULL;
4824         static bool s_initDone = false;
4825 
4826         if ( !s_initDone )
4827         {
4828             wxLoadedDLL dllUser32("user32.dll");
4829             wxDL_INIT_FUNC(s_pfn, SystemParametersInfoForDpi, dllUser32);
4830             s_initDone = true;
4831         }
4832 
4833         if ( s_pfnSystemParametersInfoForDpi )
4834         {
4835             const int dpi = window->GetDPI().y;
4836             if ( s_pfnSystemParametersInfoForDpi(uiAction, uiParam, pvParam, fWinIni, (UINT)dpi) == TRUE )
4837             {
4838                 return true;
4839             }
4840         }
4841     }
4842 #else
4843     wxUnusedVar(window);
4844 #endif // wxUSE_DYNLIB_CLASS
4845 
4846     return ::SystemParametersInfo(uiAction, uiParam, pvParam, fWinIni) == TRUE;
4847 }
4848 
GetDPI() const4849 wxSize wxWindowMSW::GetDPI() const
4850 {
4851     HWND hwnd = GetHwnd();
4852 
4853     if ( hwnd == NULL )
4854     {
4855         const wxWindow* topWin = wxGetTopLevelParent(const_cast<wxWindowMSW*>(this));
4856         if ( topWin )
4857         {
4858             hwnd = GetHwndOf(topWin);
4859         }
4860     }
4861 
4862     wxSize dpi = GetWindowDPI(hwnd);
4863 
4864     if ( !dpi.x || !dpi.y )
4865     {
4866         WindowHDC hdc(hwnd);
4867         dpi.x = ::GetDeviceCaps(hdc, LOGPIXELSX);
4868         dpi.y = ::GetDeviceCaps(hdc, LOGPIXELSY);
4869     }
4870 
4871     return dpi;
4872 }
4873 
GetDPIScaleFactor() const4874 double wxWindowMSW::GetDPIScaleFactor() const
4875 {
4876     return GetDPI().y / (double)wxDisplay::GetStdPPIValue();
4877 }
4878 
WXAdjustFontToOwnPPI(wxFont & font) const4879 void wxWindowMSW::WXAdjustFontToOwnPPI(wxFont& font) const
4880 {
4881     font.WXAdjustToPPI(GetDPI());
4882 }
4883 
MSWUpdateFontOnDPIChange(const wxSize & newDPI)4884 void wxWindowMSW::MSWUpdateFontOnDPIChange(const wxSize& newDPI)
4885 {
4886     if ( m_font.IsOk() )
4887     {
4888         m_font.WXAdjustToPPI(newDPI);
4889 
4890         // WXAdjustToPPI() changes the HFONT, so reassociate it with the window.
4891         wxSetWindowFont(GetHwnd(), m_font);
4892     }
4893 }
4894 
4895 // Helper function to update the given coordinate by the scaling factor if it
4896 // is set, i.e. different from wxDefaultCoord.
ScaleCoordIfSet(int & coord,float scaleFactor)4897 static void ScaleCoordIfSet(int& coord, float scaleFactor)
4898 {
4899     if ( coord != wxDefaultCoord )
4900     {
4901         const float coordScaled = coord * scaleFactor;
4902         coord = int(scaleFactor > 1 ? std::ceil(coordScaled) : std::floor(coordScaled));
4903     }
4904 }
4905 
4906 // Called from MSWUpdateonDPIChange() to recursively update the window
4907 // sizer and any child sizers and spacers.
UpdateSizerOnDPIChange(wxSizer * sizer,float scaleFactor)4908 static void UpdateSizerOnDPIChange(wxSizer* sizer, float scaleFactor)
4909 {
4910     if ( !sizer )
4911     {
4912         return;
4913     }
4914 
4915     for ( wxSizerItemList::compatibility_iterator
4916             node = sizer->GetChildren().GetFirst();
4917             node;
4918             node = node->GetNext() )
4919     {
4920         wxSizerItem* sizerItem = node->GetData();
4921 
4922         int border = sizerItem->GetBorder();
4923         ScaleCoordIfSet(border, scaleFactor);
4924         sizerItem->SetBorder(border);
4925 
4926         // only scale sizers and spacers, not windows
4927         if ( sizerItem->IsSizer() || sizerItem->IsSpacer() )
4928         {
4929             wxSize min = sizerItem->GetMinSize();
4930             ScaleCoordIfSet(min.x, scaleFactor);
4931             ScaleCoordIfSet(min.y, scaleFactor);
4932             sizerItem->SetMinSize(min);
4933 
4934             if ( sizerItem->IsSpacer() )
4935             {
4936                 wxSize size = sizerItem->GetSize();
4937                 ScaleCoordIfSet(size.x, scaleFactor);
4938                 ScaleCoordIfSet(size.y, scaleFactor);
4939                 sizerItem->SetDimension(wxDefaultPosition, size);
4940             }
4941 
4942             // Update any child sizers if this is a sizer
4943             UpdateSizerOnDPIChange(sizerItem->GetSizer(), scaleFactor);
4944         }
4945     }
4946 }
4947 
4948 void
MSWUpdateOnDPIChange(const wxSize & oldDPI,const wxSize & newDPI)4949 wxWindowMSW::MSWUpdateOnDPIChange(const wxSize& oldDPI, const wxSize& newDPI)
4950 {
4951     // update min and max size if necessary
4952     const float scaleFactor = (float)newDPI.y / oldDPI.y;
4953 
4954     ScaleCoordIfSet(m_minHeight, scaleFactor);
4955     ScaleCoordIfSet(m_minWidth, scaleFactor);
4956     ScaleCoordIfSet(m_maxHeight, scaleFactor);
4957     ScaleCoordIfSet(m_maxWidth, scaleFactor);
4958 
4959     InvalidateBestSize();
4960 
4961     // update font if necessary
4962     MSWUpdateFontOnDPIChange(newDPI);
4963 
4964     // update sizers
4965     UpdateSizerOnDPIChange(GetSizer(), scaleFactor);
4966 
4967     // update children
4968     for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
4969           node;
4970           node = node->GetNext() )
4971     {
4972         wxWindow *childWin = node->GetData();
4973         // Update all children, except other top-level windows.
4974         // These could be on a different monitor and will get their own
4975         // dpi-changed event.
4976         if ( childWin && !childWin->IsTopLevel() )
4977         {
4978             childWin->MSWUpdateOnDPIChange(oldDPI, newDPI);
4979         }
4980     }
4981 
4982     wxDPIChangedEvent event(oldDPI, newDPI);
4983     event.SetEventObject(this);
4984     HandleWindowEvent(event);
4985 }
4986 
4987 // ---------------------------------------------------------------------------
4988 // colours and palettes
4989 // ---------------------------------------------------------------------------
4990 
HandleSysColorChange()4991 bool wxWindowMSW::HandleSysColorChange()
4992 {
4993     wxSysColourChangedEvent event;
4994     event.SetEventObject(this);
4995 
4996     (void)HandleWindowEvent(event);
4997 
4998     // always let the system carry on the default processing to allow the
4999     // native controls to react to the colours update
5000     return false;
5001 }
5002 
HandleDisplayChange()5003 bool wxWindowMSW::HandleDisplayChange()
5004 {
5005     wxDisplayChangedEvent event;
5006     event.SetEventObject(this);
5007 
5008     return HandleWindowEvent(event);
5009 }
5010 
HandleCtlColor(WXHBRUSH * brush,WXHDC hDC,WXHWND hWnd)5011 bool wxWindowMSW::HandleCtlColor(WXHBRUSH *brush, WXHDC hDC, WXHWND hWnd)
5012 {
5013 #if !wxUSE_CONTROLS || defined(__WXUNIVERSAL__)
5014     wxUnusedVar(hDC);
5015     wxUnusedVar(hWnd);
5016 #else
5017     wxControl *item = wxDynamicCast(FindItemByHWND(hWnd, true), wxControl);
5018 
5019     if ( item )
5020         *brush = item->MSWControlColor(hDC, hWnd);
5021     else
5022 #endif // wxUSE_CONTROLS
5023         *brush = NULL;
5024 
5025     return *brush != NULL;
5026 }
5027 
HandlePaletteChanged(WXHWND hWndPalChange)5028 bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange)
5029 {
5030 #if wxUSE_PALETTE
5031     // same as below except we don't respond to our own messages
5032     if ( hWndPalChange != GetHWND() )
5033     {
5034         // check to see if we our our parents have a custom palette
5035         wxWindowMSW *win = this;
5036         while ( win && !win->HasCustomPalette() )
5037         {
5038             win = win->GetParent();
5039         }
5040 
5041         if ( win && win->HasCustomPalette() )
5042         {
5043             // realize the palette to see whether redrawing is needed
5044             HDC hdc = ::GetDC((HWND) hWndPalChange);
5045             win->m_palette.SetHPALETTE((WXHPALETTE)
5046                     ::SelectPalette(hdc, GetHpaletteOf(win->m_palette), FALSE));
5047 
5048             int result = ::RealizePalette(hdc);
5049 
5050             // restore the palette (before releasing the DC)
5051             win->m_palette.SetHPALETTE((WXHPALETTE)
5052                     ::SelectPalette(hdc, GetHpaletteOf(win->m_palette), FALSE));
5053             ::RealizePalette(hdc);
5054             ::ReleaseDC((HWND) hWndPalChange, hdc);
5055 
5056             // now check for the need to redraw
5057             if (result > 0)
5058                 ::InvalidateRect((HWND) hWndPalChange, NULL, TRUE);
5059         }
5060 
5061     }
5062 #endif // wxUSE_PALETTE
5063 
5064     wxPaletteChangedEvent event(GetId());
5065     event.SetEventObject(this);
5066     event.SetChangedWindow(wxFindWinFromHandle(hWndPalChange));
5067 
5068     return HandleWindowEvent(event);
5069 }
5070 
HandleCaptureChanged(WXHWND hWndGainedCapture)5071 bool wxWindowMSW::HandleCaptureChanged(WXHWND hWndGainedCapture)
5072 {
5073     // Ensure that wxWindow::GetCapture() returns NULL if called from the event
5074     // handlers invoked below. This is necessary to avoid wrongly calling
5075     // ReleaseMouse() when we're already losing the mouse capture anyhow.
5076     gs_insideCaptureChanged = true;
5077     wxON_BLOCK_EXIT_SET(gs_insideCaptureChanged, false);
5078 
5079     // notify windows on the capture stack about lost capture
5080     // (see http://sourceforge.net/tracker/index.php?func=detail&aid=1153662&group_id=9863&atid=109863):
5081     wxWindowBase::NotifyCaptureLost();
5082 
5083     wxWindow *win = wxFindWinFromHandle(hWndGainedCapture);
5084     wxMouseCaptureChangedEvent event(GetId(), win);
5085     event.SetEventObject(this);
5086     return HandleWindowEvent(event);
5087 }
5088 
HandleSettingChange(WXWPARAM wParam,WXLPARAM lParam)5089 bool wxWindowMSW::HandleSettingChange(WXWPARAM wParam, WXLPARAM lParam)
5090 {
5091     // despite MSDN saying "(This message cannot be sent directly to a window.)"
5092     // we need to send this to child windows (it is only sent to top-level
5093     // windows) so {list,tree}ctrls can adjust their font size if necessary
5094     // this is exactly how explorer does it to enable the font size changes
5095 
5096     wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
5097     while ( node )
5098     {
5099         // top-level windows already get this message from the system
5100         wxWindow *win = node->GetData();
5101         if ( !win->IsTopLevel() )
5102         {
5103             ::SendMessage(GetHwndOf(win), WM_SETTINGCHANGE, wParam, lParam);
5104         }
5105 
5106         node = node->GetNext();
5107     }
5108 
5109     // let the system handle it
5110     return false;
5111 }
5112 
HandleQueryNewPalette()5113 bool wxWindowMSW::HandleQueryNewPalette()
5114 {
5115 
5116 #if wxUSE_PALETTE
5117     // check to see if we our our parents have a custom palette
5118     wxWindowMSW *win = this;
5119     while (!win->HasCustomPalette() && win->GetParent()) win = win->GetParent();
5120     if (win->HasCustomPalette()) {
5121         /* realize the palette to see whether redrawing is needed */
5122         HDC hdc = ::GetDC((HWND) GetHWND());
5123         win->m_palette.SetHPALETTE( (WXHPALETTE)
5124              ::SelectPalette(hdc, (HPALETTE) win->m_palette.GetHPALETTE(), FALSE) );
5125 
5126         int result = ::RealizePalette(hdc);
5127         /* restore the palette (before releasing the DC) */
5128         win->m_palette.SetHPALETTE( (WXHPALETTE)
5129              ::SelectPalette(hdc, (HPALETTE) win->m_palette.GetHPALETTE(), TRUE) );
5130         ::RealizePalette(hdc);
5131         ::ReleaseDC((HWND) GetHWND(), hdc);
5132         /* now check for the need to redraw */
5133         if (result > 0)
5134             ::InvalidateRect((HWND) GetHWND(), NULL, TRUE);
5135         }
5136 #endif // wxUSE_PALETTE
5137 
5138     wxQueryNewPaletteEvent event(GetId());
5139     event.SetEventObject(this);
5140 
5141     return HandleWindowEvent(event) && event.GetPaletteRealized();
5142 }
5143 
5144 // Responds to colour changes: passes event on to children.
OnSysColourChanged(wxSysColourChangedEvent & WXUNUSED (event))5145 void wxWindowMSW::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event))
5146 {
5147     // the top level window also reset the standard colour map as it might have
5148     // changed (there is no need to do it for the non top level windows as we
5149     // only have to do it once)
5150     if ( IsTopLevel() )
5151     {
5152         // FIXME-MT
5153         gs_hasStdCmap = false;
5154     }
5155     wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
5156     while ( node )
5157     {
5158         // Only propagate to non-top-level windows because Windows already
5159         // sends this event to all top-level ones
5160         wxWindow *win = node->GetData();
5161         if ( !win->IsTopLevel() )
5162         {
5163             // we need to send the real WM_SYSCOLORCHANGE and not just trigger
5164             // EVT_SYS_COLOUR_CHANGED call because the latter wouldn't work for
5165             // the standard controls
5166             ::SendMessage(GetHwndOf(win), WM_SYSCOLORCHANGE, 0, 0);
5167         }
5168 
5169         node = node->GetNext();
5170     }
5171 }
5172 
wxGetStdColourMap()5173 extern wxCOLORMAP *wxGetStdColourMap()
5174 {
5175     static COLORREF s_stdColours[wxSTD_COL_MAX];
5176     static wxCOLORMAP s_cmap[wxSTD_COL_MAX];
5177 
5178     if ( !gs_hasStdCmap )
5179     {
5180         static bool s_coloursInit = false;
5181 
5182         if ( !s_coloursInit )
5183         {
5184             // When a bitmap is loaded, the RGB values can change (apparently
5185             // because Windows adjusts them to care for the old programs always
5186             // using 0xc0c0c0 while the transparent colour for the new Windows
5187             // versions is different). But we do this adjustment ourselves so
5188             // we want to avoid Windows' "help" and for this we need to have a
5189             // reference bitmap which can tell us what the RGB values change
5190             // to.
5191             wxLogNull logNo; // suppress error if we couldn't load the bitmap
5192             wxBitmap stdColourBitmap(wxT("wxBITMAP_STD_COLOURS"));
5193             if ( stdColourBitmap.IsOk() )
5194             {
5195                 // the pixels in the bitmap must correspond to wxSTD_COL_XXX!
5196                 wxASSERT_MSG( stdColourBitmap.GetWidth() == wxSTD_COL_MAX,
5197                               wxT("forgot to update wxBITMAP_STD_COLOURS!") );
5198 
5199                 wxMemoryDC memDC;
5200                 memDC.SelectObject(stdColourBitmap);
5201 
5202                 wxColour colour;
5203                 for ( size_t i = 0; i < WXSIZEOF(s_stdColours); i++ )
5204                 {
5205                     memDC.GetPixel(i, 0, &colour);
5206                     s_stdColours[i] = wxColourToRGB(colour);
5207                 }
5208             }
5209             else // wxBITMAP_STD_COLOURS couldn't be loaded
5210             {
5211                 s_stdColours[0] = RGB(000,000,000);     // black
5212                 s_stdColours[1] = RGB(128,128,128);     // dark grey
5213                 s_stdColours[2] = RGB(192,192,192);     // light grey
5214                 s_stdColours[3] = RGB(255,255,255);     // white
5215                 //s_stdColours[4] = RGB(000,000,255);     // blue
5216                 //s_stdColours[5] = RGB(255,000,255);     // magenta
5217             }
5218 
5219             s_coloursInit = true;
5220         }
5221 
5222         gs_hasStdCmap = true;
5223 
5224         // create the colour map
5225 #define INIT_CMAP_ENTRY(col) \
5226             s_cmap[wxSTD_COL_##col].from = s_stdColours[wxSTD_COL_##col]; \
5227             s_cmap[wxSTD_COL_##col].to = ::GetSysColor(COLOR_##col)
5228 
5229         INIT_CMAP_ENTRY(BTNTEXT);
5230         INIT_CMAP_ENTRY(BTNSHADOW);
5231         INIT_CMAP_ENTRY(BTNFACE);
5232         INIT_CMAP_ENTRY(BTNHIGHLIGHT);
5233 
5234 #undef INIT_CMAP_ENTRY
5235     }
5236 
5237     return s_cmap;
5238 }
5239 
5240 #if wxUSE_UXTHEME && !defined(TMT_FILLCOLOR)
5241     #define TMT_FILLCOLOR       3802
5242     #define TMT_TEXTCOLOR       3803
5243     #define TMT_BORDERCOLOR     3801
5244 #endif
5245 
MSWGetThemeColour(const wchar_t * themeName,int themePart,int themeState,MSWThemeColour themeColour,wxSystemColour fallback) const5246 wxColour wxWindowMSW::MSWGetThemeColour(const wchar_t *themeName,
5247                                         int themePart,
5248                                         int themeState,
5249                                         MSWThemeColour themeColour,
5250                                         wxSystemColour fallback) const
5251 {
5252 #if wxUSE_UXTHEME
5253     if ( wxUxThemeIsActive() )
5254     {
5255         int themeProperty = 0;
5256 
5257         // TODO: Convert this into a table? Sure would be faster.
5258         switch ( themeColour )
5259         {
5260             case ThemeColourBackground:
5261                 themeProperty = TMT_FILLCOLOR;
5262                 break;
5263             case ThemeColourText:
5264                 themeProperty = TMT_TEXTCOLOR;
5265                 break;
5266             case ThemeColourBorder:
5267                 themeProperty = TMT_BORDERCOLOR;
5268                 break;
5269             default:
5270                 wxFAIL_MSG(wxT("unsupported theme colour"));
5271         }
5272 
5273         wxUxThemeHandle hTheme((const wxWindow *)this, themeName);
5274         COLORREF col;
5275         HRESULT hr = ::GetThemeColor
5276                             (
5277                                 hTheme,
5278                                 themePart,
5279                                 themeState,
5280                                 themeProperty,
5281                                 &col
5282                             );
5283 
5284         if ( SUCCEEDED(hr) )
5285             return wxRGBToColour(col);
5286 
5287         wxLogApiError(
5288             wxString::Format(
5289                 "GetThemeColor(%s, %i, %i, %i)",
5290                 themeName, themePart, themeState, themeProperty),
5291             hr);
5292     }
5293 #else
5294     wxUnusedVar(themeName);
5295     wxUnusedVar(themePart);
5296     wxUnusedVar(themeState);
5297     wxUnusedVar(themeColour);
5298 #endif
5299     return wxSystemSettings::GetColour(fallback);
5300 }
5301 
5302 // ---------------------------------------------------------------------------
5303 // painting
5304 // ---------------------------------------------------------------------------
5305 
5306 // this variable is used to check that a paint event handler which processed
5307 // the event did create a wxPaintDC inside its code and called BeginPaint() to
5308 // validate the invalidated window area as otherwise we'd keep getting an
5309 // endless stream of WM_PAINT messages for this window resulting in a lot of
5310 // difficult to debug problems (e.g. impossibility to repaint other windows,
5311 // lack of timer and idle events and so on)
5312 wxStack<wxMSWImpl::PaintData> wxMSWImpl::paintStack;
5313 
HandlePaint()5314 bool wxWindowMSW::HandlePaint()
5315 {
5316     HRGN hRegion = ::CreateRectRgn(0, 0, 0, 0); // Dummy call to get a handle
5317     if ( !hRegion )
5318     {
5319         wxLogLastError(wxT("CreateRectRgn"));
5320     }
5321     if ( ::GetUpdateRgn(GetHwnd(), hRegion, FALSE) == ERROR )
5322     {
5323         wxLogLastError(wxT("GetUpdateRgn"));
5324     }
5325 
5326     m_updateRegion = wxRegion((WXHRGN) hRegion);
5327 
5328     using namespace wxMSWImpl;
5329 
5330     paintStack.push(PaintData(this));
5331 
5332     wxPaintEvent event(this);
5333 
5334     bool processed = HandleWindowEvent(event);
5335 
5336     const bool createdPaintDC = paintStack.top().createdPaintDC;
5337     if ( createdPaintDC && !processed )
5338     {
5339         // Event handler did paint something as wxPaintDC object was created
5340         // but then it must have skipped the event to indicate that default
5341         // handling should still take place, so call MSWDefWindowProc() right
5342         // now. It's important to do it before EndPaint() call below as that
5343         // would validate the window and MSWDefWindowProc(WM_PAINT) wouldn't do
5344         // anything if called after it.
5345         OnPaint(event);
5346     }
5347 
5348     // note that we must generate NC event after the normal one as otherwise
5349     // BeginPaint() will happily overwrite our decorations with the background
5350     // colour
5351     wxNcPaintEvent eventNc(this);
5352     HandleWindowEvent(eventNc);
5353 
5354     // don't keep an HRGN we don't need any longer (GetUpdateRegion() can only
5355     // be called from inside the event handlers called above)
5356     m_updateRegion.Clear();
5357 
5358     wxPaintDCImpl::EndPaint((wxWindow *)this);
5359 
5360     paintStack.pop();
5361 
5362     // It doesn't matter whether the event was actually processed or not here,
5363     // what matters is whether we already painted, and hence validated, the
5364     // window or not. If we did, either the event was processed or we called
5365     // OnPaint() above, so we should return true. If we did not, even the event
5366     // was processed, we must still call MSWDefWindowProc() to ensure that the
5367     // window is validated, i.e. to avoid the problem described in the comment
5368     // before paintStack definition above.
5369     return createdPaintDC;
5370 }
5371 
5372 // Can be called from an application's OnPaint handler
OnPaint(wxPaintEvent & event)5373 void wxWindowMSW::OnPaint(wxPaintEvent& event)
5374 {
5375 #ifdef __WXUNIVERSAL__
5376     event.Skip();
5377 #else
5378     HDC hDC = (HDC) wxPaintDCImpl::FindDCInCache((wxWindow*) event.GetEventObject());
5379     if (hDC != 0)
5380     {
5381         MSWDefWindowProc(WM_PAINT, (WPARAM) hDC, 0);
5382     }
5383 #endif
5384 }
5385 
HandleEraseBkgnd(WXHDC hdc)5386 bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc)
5387 {
5388     if ( IsBeingDeleted() )
5389     {
5390         // We can get WM_ERASEBKGND after starting the destruction of our top
5391         // level parent. Handling it in this case is unnecessary and can be
5392         // actually harmful as e.g. wxStaticBox::GetClientSize() doesn't work
5393         // without a valid TLW parent (because it uses dialog units internally
5394         // which use the dialog font), so just don't do anything then.
5395         return false;
5396     }
5397 
5398     switch ( GetBackgroundStyle() )
5399     {
5400         case wxBG_STYLE_ERASE:
5401         case wxBG_STYLE_COLOUR:
5402             // we need to generate an erase background event
5403             {
5404                 wxDCTemp dc(hdc, GetClientSize());
5405                 wxDCTempImpl *impl = (wxDCTempImpl*) dc.GetImpl();
5406 
5407                 impl->SetHDC(hdc);
5408                 impl->SetWindow((wxWindow *)this);
5409 
5410                 wxEraseEvent event(m_windowId, &dc);
5411                 event.SetEventObject(this);
5412                 bool rc = HandleWindowEvent(event);
5413 
5414                 // must be called manually as ~wxDC doesn't do anything for
5415                 // wxDCTemp
5416                 impl->SelectOldObjects(hdc);
5417 
5418                 if ( rc )
5419                 {
5420                     // background erased by the user-defined handler
5421                     return true;
5422                 }
5423             }
5424             wxFALLTHROUGH;
5425 
5426         case wxBG_STYLE_SYSTEM:
5427             if ( !DoEraseBackground(hdc) )
5428             {
5429                 // let the default processing to take place if we didn't erase
5430                 // the background ourselves
5431                 return false;
5432             }
5433             break;
5434 
5435         case wxBG_STYLE_PAINT:
5436         case wxBG_STYLE_TRANSPARENT:
5437             // no need to do anything here at all, background will be entirely
5438             // redrawn in WM_PAINT handler
5439             break;
5440 
5441         default:
5442             wxFAIL_MSG( "unknown background style" );
5443     }
5444 
5445     return true;
5446 }
5447 
5448 #ifdef wxHAS_MSW_BACKGROUND_ERASE_HOOK
5449 
MSWHasEraseBgHook() const5450 bool wxWindowMSW::MSWHasEraseBgHook() const
5451 {
5452     return gs_eraseBgHooks.find(const_cast<wxWindowMSW *>(this))
5453                 != gs_eraseBgHooks.end();
5454 }
5455 
MSWSetEraseBgHook(wxWindow * child)5456 void wxWindowMSW::MSWSetEraseBgHook(wxWindow *child)
5457 {
5458     if ( child )
5459     {
5460         if ( !gs_eraseBgHooks.insert(
5461                 EraseBgHooks::value_type(this, child)).second )
5462         {
5463             wxFAIL_MSG( wxT("Setting erase background hook twice?") );
5464         }
5465     }
5466     else // reset the hook
5467     {
5468         if ( gs_eraseBgHooks.erase(this) != 1 )
5469         {
5470             wxFAIL_MSG( wxT("Resetting erase background which was not set?") );
5471         }
5472     }
5473 }
5474 
5475 #endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK
5476 
DoEraseBackground(WXHDC hDC)5477 bool wxWindowMSW::DoEraseBackground(WXHDC hDC)
5478 {
5479     HBRUSH hbr = (HBRUSH)MSWGetBgBrush(hDC);
5480     if ( !hbr )
5481         return false;
5482 
5483     // erase just the client area of the window, this is important for the
5484     // frames to avoid drawing over the toolbar part of the window (you might
5485     // think using WS_CLIPCHILDREN would prevent this from happening, but it
5486     // clearly doesn't)
5487     RECT rc;
5488     wxCopyRectToRECT(GetClientRect(), rc);
5489     ::FillRect((HDC)hDC, &rc, hbr);
5490 
5491     return true;
5492 }
5493 
5494 WXHBRUSH
MSWGetBgBrushForChild(WXHDC hDC,wxWindowMSW * child)5495 wxWindowMSW::MSWGetBgBrushForChild(WXHDC hDC, wxWindowMSW *child)
5496 {
5497     // Test for the custom background brush first.
5498     WXHBRUSH hbrush = MSWGetCustomBgBrush();
5499     if ( hbrush )
5500     {
5501         // We assume that this is either a stipple or hatched brush and not a
5502         // solid one as otherwise it would have been enough to set the
5503         // background colour and such brushes need to be positioned correctly
5504         // in order to align when different windows are painted, so do it here.
5505         RECT rc;
5506         ::GetWindowRect(GetHwndOf(child), &rc);
5507 
5508         // It is important to pass both points to MapWindowPoints() as in
5509         // addition to converting them to our coordinate system, this function
5510         // will also exchange the left and right coordinates if this window
5511         // uses RTL layout, which is exactly what we need here as the child
5512         // window origin is its _right_ top corner in this case and not the
5513         // left one.
5514         ::MapWindowPoints(NULL, GetHwnd(), (POINT *)&rc, 2);
5515 
5516         int x = rc.left,
5517             y = rc.top;
5518         MSWAdjustBrushOrg(&x, &y);
5519 
5520         if ( !::SetBrushOrgEx((HDC)hDC, -x, -y, NULL) )
5521         {
5522             wxLogLastError(wxT("SetBrushOrgEx(bg brush)"));
5523         }
5524 
5525         return hbrush;
5526     }
5527 
5528     // Otherwise see if we have a custom background colour.
5529     if ( m_hasBgCol )
5530     {
5531         wxBrush *
5532             brush = wxTheBrushList->FindOrCreateBrush(GetBackgroundColour());
5533 
5534         return (WXHBRUSH)GetHbrushOf(*brush);
5535     }
5536 
5537     return 0;
5538 }
5539 
MSWGetBgBrush(WXHDC hDC)5540 WXHBRUSH wxWindowMSW::MSWGetBgBrush(WXHDC hDC)
5541 {
5542     // Use the special wxWindowBeingErased variable if it is set as the child
5543     // being erased.
5544     wxWindowMSW * const child =
5545 #if wxUSE_UXTHEME
5546                                 wxWindowBeingErased ? wxWindowBeingErased :
5547 #endif
5548                                 this;
5549 
5550     for ( wxWindowMSW *win = this; win; win = win->GetParent() )
5551     {
5552         WXHBRUSH hBrush = win->MSWGetBgBrushForChild(hDC, child);
5553         if ( hBrush )
5554             return hBrush;
5555 
5556         // don't use the parent background if we're not transparent
5557         if ( !win->HasTransparentBackground() )
5558             break;
5559 
5560         // background is not inherited beyond top level windows
5561         if ( win->IsTopLevel() )
5562             break;
5563     }
5564 
5565     return 0;
5566 }
5567 
HandlePrintClient(WXHDC hDC)5568 bool wxWindowMSW::HandlePrintClient(WXHDC hDC)
5569 {
5570     // we receive this message when DrawThemeParentBackground() is
5571     // called from def window proc of several controls under XP and we
5572     // must draw properly themed background here
5573     //
5574     // note that naively I'd expect filling the client rect with the
5575     // brush returned by MSWGetBgBrush() work -- but for some reason it
5576     // doesn't and we have to call parents MSWPrintChild() which is
5577     // supposed to call DrawThemeBackground() with appropriate params
5578     //
5579     // also note that in this case lParam == PRF_CLIENT but we're
5580     // clearly expected to paint the background and nothing else!
5581 
5582     if ( IsTopLevel() || InheritsBackgroundColour() )
5583         return false;
5584 
5585     // sometimes we don't want the parent to handle it at all, instead
5586     // return whatever value this window wants
5587     if ( !MSWShouldPropagatePrintChild() )
5588         return MSWPrintChild(hDC, (wxWindow *)this);
5589 
5590     for ( wxWindow *win = GetParent(); win; win = win->GetParent() )
5591     {
5592         if ( win->MSWPrintChild(hDC, (wxWindow *)this) )
5593             return true;
5594 
5595         if ( win->IsTopLevel() || win->InheritsBackgroundColour() )
5596             break;
5597     }
5598 
5599     return false;
5600 }
5601 
5602 // ---------------------------------------------------------------------------
5603 // moving and resizing
5604 // ---------------------------------------------------------------------------
5605 
HandleMinimize()5606 bool wxWindowMSW::HandleMinimize()
5607 {
5608     wxIconizeEvent event(m_windowId);
5609     event.SetEventObject(this);
5610 
5611     return HandleWindowEvent(event);
5612 }
5613 
HandleMaximize()5614 bool wxWindowMSW::HandleMaximize()
5615 {
5616     wxMaximizeEvent event(m_windowId);
5617     event.SetEventObject(this);
5618 
5619     return HandleWindowEvent(event);
5620 }
5621 
HandleMove(int x,int y)5622 bool wxWindowMSW::HandleMove(int x, int y)
5623 {
5624     wxPoint point(x,y);
5625     wxMoveEvent event(point, m_windowId);
5626     event.SetEventObject(this);
5627 
5628     return HandleWindowEvent(event);
5629 }
5630 
HandleMoving(wxRect & rect)5631 bool wxWindowMSW::HandleMoving(wxRect& rect)
5632 {
5633     wxMoveEvent event(rect, m_windowId);
5634     event.SetEventObject(this);
5635 
5636     bool rc = HandleWindowEvent(event);
5637     if (rc)
5638         rect = event.GetRect();
5639     return rc;
5640 }
5641 
HandleEnterSizeMove()5642 bool wxWindowMSW::HandleEnterSizeMove()
5643 {
5644     wxMoveEvent event(wxPoint(0,0), m_windowId);
5645     event.SetEventType(wxEVT_MOVE_START);
5646     event.SetEventObject(this);
5647 
5648     return HandleWindowEvent(event);
5649 }
5650 
HandleExitSizeMove()5651 bool wxWindowMSW::HandleExitSizeMove()
5652 {
5653     wxMoveEvent event(wxPoint(0,0), m_windowId);
5654     event.SetEventType(wxEVT_MOVE_END);
5655     event.SetEventObject(this);
5656 
5657     return HandleWindowEvent(event);
5658 }
5659 
5660 #if wxUSE_DEFERRED_SIZING
5661 
BeginRepositioningChildren()5662 bool wxWindowMSW::BeginRepositioningChildren()
5663 {
5664     int numChildren = 0;
5665     for ( HWND child = ::GetWindow(GetHwndOf(this), GW_CHILD);
5666           child;
5667           child = ::GetWindow(child, GW_HWNDNEXT) )
5668     {
5669         numChildren ++;
5670     }
5671 
5672     // Nothing is gained by deferring the repositioning of a single child.
5673     if ( numChildren < 2 )
5674         return false;
5675 
5676     // Protect against valid m_hDWP being overwritten
5677     if ( m_hDWP )
5678         return false;
5679 
5680     m_hDWP = (WXHANDLE)::BeginDeferWindowPos(numChildren);
5681     if ( !m_hDWP )
5682     {
5683         wxLogLastError(wxT("BeginDeferWindowPos"));
5684         return false;
5685     }
5686 
5687     // Return true to indicate that EndDeferWindowPos() should be called.
5688     return true;
5689 }
5690 
EndRepositioningChildren()5691 void wxWindowMSW::EndRepositioningChildren()
5692 {
5693     wxASSERT_MSG( m_hDWP, wxS("Shouldn't be called") );
5694 
5695     // reset m_hDWP to NULL so that child windows don't try to use our
5696     // m_hDWP after we call EndDeferWindowPos() on it (this shouldn't
5697     // happen anyhow normally but who knows what weird flow of control we
5698     // may have depending on what the users EVT_SIZE handler does...)
5699     HDWP hDWP = (HDWP)m_hDWP;
5700     m_hDWP = NULL;
5701 
5702     // do put all child controls in place at once
5703     if ( !::EndDeferWindowPos(hDWP) )
5704     {
5705         wxLogLastError(wxT("EndDeferWindowPos"));
5706     }
5707 
5708     // Reset our children's pending pos/size values.
5709     for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
5710           node;
5711           node = node->GetNext() )
5712     {
5713         wxWindowMSW * const child = node->GetData();
5714         child->MSWEndDeferWindowPos();
5715     }
5716 }
5717 
5718 #endif // wxUSE_DEFERRED_SIZING
5719 
HandleSize(int WXUNUSED (w),int WXUNUSED (h),WXUINT wParam)5720 bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam)
5721 {
5722     // when we resize this window, its children are probably going to be
5723     // repositioned as well, prepare to use DeferWindowPos() for them
5724     ChildrenRepositioningGuard repositionGuard(this);
5725 
5726     // update this window size
5727     bool processed = false;
5728     switch ( wParam )
5729     {
5730         default:
5731             wxFAIL_MSG( wxT("unexpected WM_SIZE parameter") );
5732             // fall through nevertheless
5733             wxFALLTHROUGH;
5734 
5735         case SIZE_MAXHIDE:
5736             wxFALLTHROUGH;
5737         case SIZE_MAXSHOW:
5738             // we're not interested in these messages at all
5739             break;
5740 
5741         case SIZE_MINIMIZED:
5742             processed = HandleMinimize();
5743             break;
5744 
5745         case SIZE_MAXIMIZED:
5746             /* processed = */ HandleMaximize();
5747             // fall through to send a normal size event as well
5748             wxFALLTHROUGH;
5749 
5750         case SIZE_RESTORED:
5751             // don't use w and h parameters as they specify the client size
5752             // while according to the docs EVT_SIZE handler is supposed to
5753             // receive the total size
5754             wxSizeEvent event(GetSize(), m_windowId);
5755             event.SetEventObject(this);
5756 
5757             processed = HandleWindowEvent(event);
5758             break;
5759     }
5760 
5761     return processed;
5762 }
5763 
HandleSizing(wxRect & rect)5764 bool wxWindowMSW::HandleSizing(wxRect& rect)
5765 {
5766     wxSizeEvent event(rect, m_windowId);
5767     event.SetEventObject(this);
5768 
5769     bool rc = HandleWindowEvent(event);
5770     if (rc)
5771         rect = event.GetRect();
5772     return rc;
5773 }
5774 
HandleGetMinMaxInfo(void * mmInfo)5775 bool wxWindowMSW::HandleGetMinMaxInfo(void *mmInfo)
5776 {
5777     MINMAXINFO *info = (MINMAXINFO *)mmInfo;
5778 
5779     bool rc = false;
5780 
5781     int minWidth = GetMinWidth(),
5782         minHeight = GetMinHeight(),
5783         maxWidth = GetMaxWidth(),
5784         maxHeight = GetMaxHeight();
5785 
5786     if ( minWidth != wxDefaultCoord )
5787     {
5788         info->ptMinTrackSize.x = minWidth;
5789         rc = true;
5790     }
5791 
5792     if ( minHeight != wxDefaultCoord )
5793     {
5794         info->ptMinTrackSize.y = minHeight;
5795         rc = true;
5796     }
5797 
5798     if ( maxWidth != wxDefaultCoord )
5799     {
5800         info->ptMaxTrackSize.x = maxWidth;
5801         rc = true;
5802     }
5803 
5804     if ( maxHeight != wxDefaultCoord )
5805     {
5806         info->ptMaxTrackSize.y = maxHeight;
5807         rc = true;
5808     }
5809 
5810     return rc;
5811 }
5812 
5813 // ---------------------------------------------------------------------------
5814 // command messages
5815 // ---------------------------------------------------------------------------
5816 
HandleCommand(WXWORD id_,WXWORD cmd,WXHWND control)5817 bool wxWindowMSW::HandleCommand(WXWORD id_, WXWORD cmd, WXHWND control)
5818 {
5819     // sign extend to int from short before comparing with the other int ids
5820     int id = (signed short)id_;
5821 
5822 #if wxUSE_MENUS_NATIVE
5823     if ( !cmd && wxCurrentPopupMenu )
5824     {
5825         wxMenu *popupMenu = wxCurrentPopupMenu;
5826         wxCurrentPopupMenu = NULL;
5827 
5828         return popupMenu->MSWCommand(cmd, id);
5829     }
5830 #endif // wxUSE_MENUS_NATIVE
5831 
5832     wxWindow *win = NULL;
5833 
5834     // first try to find it from HWND - this works even with the broken
5835     // programs using the same ids for different controls
5836     if ( control )
5837     {
5838         win = wxFindWinFromHandle(control);
5839     }
5840 
5841     // try the id
5842     if ( !win )
5843     {
5844         win = FindItem(id, control);
5845     }
5846 
5847     if ( win )
5848     {
5849         return win->MSWCommand(cmd, id);
5850     }
5851 
5852     // the messages sent from the in-place edit control used by the treectrl
5853     // for label editing have id == 0, but they should _not_ be treated as menu
5854     // messages (they are EN_XXX ones, in fact) so don't translate anything
5855     // coming from a control to wxEVT_MENU
5856     if ( !control )
5857     {
5858         wxCommandEvent event(wxEVT_MENU, id);
5859         event.SetEventObject(this);
5860         event.SetInt(id);
5861 
5862         return HandleWindowEvent(event);
5863     }
5864     else
5865     {
5866 #if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__)
5867         // the text ctrl which is logically part of wxSpinCtrl sends WM_COMMAND
5868         // notifications to its parent which we want to reflect back to
5869         // wxSpinCtrl
5870         wxSpinCtrl *spin = wxSpinCtrl::GetSpinForTextCtrl(control);
5871         if ( spin && spin->ProcessTextCommand(cmd, id) )
5872             return true;
5873 #endif // wxUSE_SPINCTRL
5874 
5875     }
5876 
5877     return false;
5878 }
5879 
5880 // ---------------------------------------------------------------------------
5881 // mouse events
5882 // ---------------------------------------------------------------------------
5883 
InitMouseEvent(wxMouseEvent & event,int x,int y,WXUINT flags)5884 void wxWindowMSW::InitMouseEvent(wxMouseEvent& event,
5885                                  int x, int y,
5886                                  WXUINT flags)
5887 {
5888     // our client coords are not quite the same as Windows ones
5889     wxPoint pt = GetClientAreaOrigin();
5890     event.m_x = x - pt.x;
5891     event.m_y = y - pt.y;
5892 
5893     event.m_shiftDown = (flags & MK_SHIFT) != 0;
5894     event.m_controlDown = (flags & MK_CONTROL) != 0;
5895     event.m_leftDown = (flags & MK_LBUTTON) != 0;
5896     event.m_middleDown = (flags & MK_MBUTTON) != 0;
5897     event.m_rightDown = (flags & MK_RBUTTON) != 0;
5898     event.m_aux1Down = (flags & MK_XBUTTON1) != 0;
5899     event.m_aux2Down = (flags & MK_XBUTTON2) != 0;
5900     event.m_altDown = ::wxIsAltDown();
5901 
5902     event.SetTimestamp(::GetMessageTime());
5903 
5904     event.SetEventObject(this);
5905     event.SetId(GetId());
5906 
5907     gs_lastMouseEvent.pos = ClientToScreen(wxPoint(x, y));
5908     gs_lastMouseEvent.type = event.GetEventType();
5909 }
5910 
HandleMouseEvent(WXUINT msg,int x,int y,WXUINT flags)5911 bool wxWindowMSW::HandleMouseEvent(WXUINT msg, int x, int y, WXUINT flags)
5912 {
5913     // the mouse events take consecutive IDs from WM_MOUSEFIRST to
5914     // WM_MOUSELAST, so it's enough to subtract WM_MOUSEMOVE == WM_MOUSEFIRST
5915     // from the message id and take the value in the table to get wxWin event
5916     // id
5917     static const wxEventType eventsMouse[] =
5918     {
5919         wxEVT_MOTION,
5920         wxEVT_LEFT_DOWN,
5921         wxEVT_LEFT_UP,
5922         wxEVT_LEFT_DCLICK,
5923         wxEVT_RIGHT_DOWN,
5924         wxEVT_RIGHT_UP,
5925         wxEVT_RIGHT_DCLICK,
5926         wxEVT_MIDDLE_DOWN,
5927         wxEVT_MIDDLE_UP,
5928         wxEVT_MIDDLE_DCLICK,
5929         0, // this one is for wxEVT_MOTION which is not used here
5930         wxEVT_AUX1_DOWN,
5931         wxEVT_AUX1_UP,
5932         wxEVT_AUX1_DCLICK,
5933         wxEVT_AUX2_DOWN,
5934         wxEVT_AUX2_UP,
5935         wxEVT_AUX2_DCLICK
5936     };
5937 
5938     // the same messages are used for both auxiliary mouse buttons so we need
5939     // to adjust the index manually
5940     switch ( msg )
5941     {
5942         case WM_XBUTTONDOWN:
5943         case WM_XBUTTONUP:
5944         case WM_XBUTTONDBLCLK:
5945             if (HIWORD(flags) == XBUTTON2)
5946                 msg += wxEVT_AUX2_DOWN - wxEVT_AUX1_DOWN;
5947     }
5948 
5949     wxMouseEvent event(eventsMouse[msg - WM_MOUSEMOVE]);
5950     InitMouseEvent(event, x, y, flags);
5951 
5952     return HandleWindowEvent(event);
5953 }
5954 
HandleMouseMove(int x,int y,WXUINT flags)5955 bool wxWindowMSW::HandleMouseMove(int x, int y, WXUINT flags)
5956 {
5957     if ( !m_mouseInWindow )
5958     {
5959         // it would be wrong to assume that just because we get a mouse move
5960         // event that the mouse is inside the window: although this is usually
5961         // true, it is not if we had captured the mouse, so we need to check
5962         // the mouse coordinates here
5963         if ( !HasCapture() || IsMouseInWindow() )
5964         {
5965             // Generate an ENTER event
5966             m_mouseInWindow = true;
5967 
5968 #ifdef HAVE_TRACKMOUSEEVENT
5969             typedef BOOL (WINAPI *_TrackMouseEvent_t)(LPTRACKMOUSEEVENT);
5970             static _TrackMouseEvent_t s_pfn_TrackMouseEvent;
5971             static bool s_initDone = false;
5972             if ( !s_initDone )
5973             {
5974                 // see comment in wxApp::GetComCtl32Version() explaining the
5975                 // use of wxLoadedDLL
5976                 wxLoadedDLL dllComCtl32(wxT("comctl32.dll"));
5977                 if ( dllComCtl32.IsLoaded() )
5978                 {
5979                     s_pfn_TrackMouseEvent = (_TrackMouseEvent_t)
5980                         dllComCtl32.RawGetSymbol(wxT("_TrackMouseEvent"));
5981                 }
5982 
5983                 s_initDone = true;
5984             }
5985 
5986             if ( s_pfn_TrackMouseEvent )
5987             {
5988                 WinStruct<TRACKMOUSEEVENT> trackinfo;
5989 
5990                 trackinfo.dwFlags = TME_LEAVE;
5991                 trackinfo.hwndTrack = GetHwnd();
5992 
5993                 (*s_pfn_TrackMouseEvent)(&trackinfo);
5994             }
5995 #endif // HAVE_TRACKMOUSEEVENT
5996 
5997             wxMouseEvent event(wxEVT_ENTER_WINDOW);
5998             InitMouseEvent(event, x, y, flags);
5999 
6000             (void)HandleWindowEvent(event);
6001         }
6002     }
6003 #ifdef HAVE_TRACKMOUSEEVENT
6004     else // mouse not in window
6005     {
6006         // Check if we need to send a LEAVE event
6007         // Windows doesn't send WM_MOUSELEAVE if the mouse has been captured so
6008         // send it here if we are using native mouse leave tracking
6009         if ( HasCapture() && !IsMouseInWindow() )
6010         {
6011             GenerateMouseLeave();
6012         }
6013     }
6014 #endif // HAVE_TRACKMOUSEEVENT
6015 
6016     // Windows often generates mouse events even if mouse position hasn't
6017     // changed (http://article.gmane.org/gmane.comp.lib.wxwidgets.devel/66576)
6018     //
6019     // Filter this out as it can result in unexpected behaviour compared to
6020     // other platforms
6021     if ( gs_lastMouseEvent.type == wxEVT_RIGHT_DOWN ||
6022          gs_lastMouseEvent.type == wxEVT_LEFT_DOWN ||
6023          gs_lastMouseEvent.type == wxEVT_MIDDLE_DOWN ||
6024          gs_lastMouseEvent.type == wxEVT_MOTION )
6025     {
6026         if ( ClientToScreen(wxPoint(x, y)) == gs_lastMouseEvent.pos )
6027         {
6028             gs_lastMouseEvent.type = wxEVT_MOTION;
6029 
6030             return false;
6031         }
6032     }
6033 
6034     return HandleMouseEvent(WM_MOUSEMOVE, x, y, flags);
6035 }
6036 
6037 
6038 bool
HandleMouseWheel(wxMouseWheelAxis axis,WXWPARAM wParam,WXLPARAM lParam)6039 wxWindowMSW::HandleMouseWheel(wxMouseWheelAxis axis,
6040                               WXWPARAM wParam, WXLPARAM lParam)
6041 {
6042 #if wxUSE_MOUSEWHEEL
6043     // notice that WM_MOUSEWHEEL position is in screen coords (as it's
6044     // forwarded up to the parent by DefWindowProc()) and not in the client
6045     // ones as all the other messages, translate them to the client coords for
6046     // consistency -- but do it using Windows function and not our own one
6047     // because InitMouseEvent() expects coordinates in Windows client
6048     // coordinates and not wx ones (the difference being the height of the
6049     // toolbar, if any).
6050     POINT pt;
6051     pt.x = GET_X_LPARAM(lParam);
6052     pt.y = GET_Y_LPARAM(lParam);
6053     ::ScreenToClient(GetHwnd(), &pt);
6054 
6055     wxMouseEvent event(wxEVT_MOUSEWHEEL);
6056     InitMouseEvent(event, pt.x, pt.y, LOWORD(wParam));
6057     event.m_wheelRotation = (short)HIWORD(wParam);
6058     event.m_wheelDelta = WHEEL_DELTA;
6059     event.m_wheelAxis = axis;
6060 
6061     static int s_linesPerRotation = -1;
6062     if ( s_linesPerRotation == -1 )
6063     {
6064         if ( !::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
6065                                      &s_linesPerRotation, 0))
6066         {
6067             // this is not supposed to happen
6068             wxLogLastError(wxT("SystemParametersInfo(GETWHEELSCROLLLINES)"));
6069 
6070             // the default is 3, so use it if SystemParametersInfo() failed
6071             s_linesPerRotation = 3;
6072         }
6073     }
6074 
6075     static int s_columnsPerRotation = -1;
6076     if ( s_columnsPerRotation == -1 )
6077     {
6078         if ( !::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0,
6079                                      &s_columnsPerRotation, 0))
6080         {
6081             // this setting is not supported on Windows 2000/XP, so use the value of 1
6082             // http://msdn.microsoft.com/en-us/library/ms997498.aspx
6083             s_columnsPerRotation = 1;
6084         }
6085     }
6086 
6087     event.m_linesPerAction = s_linesPerRotation;
6088     event.m_columnsPerAction = s_columnsPerRotation;
6089     return HandleWindowEvent(event);
6090 
6091 #else // !wxUSE_MOUSEWHEEL
6092     wxUnusedVar(wParam);
6093     wxUnusedVar(lParam);
6094 
6095     return false;
6096 #endif // wxUSE_MOUSEWHEEL/!wxUSE_MOUSEWHEEL
6097 }
6098 
GenerateMouseLeave()6099 void wxWindowMSW::GenerateMouseLeave()
6100 {
6101     m_mouseInWindow = false;
6102 
6103     int state = 0;
6104     if ( wxIsShiftDown() )
6105         state |= MK_SHIFT;
6106     if ( wxIsCtrlDown() )
6107         state |= MK_CONTROL;
6108 
6109     // Only the high-order bit should be tested
6110     if ( GetKeyState( VK_LBUTTON ) & (1<<15) )
6111         state |= MK_LBUTTON;
6112     if ( GetKeyState( VK_MBUTTON ) & (1<<15) )
6113         state |= MK_MBUTTON;
6114     if ( GetKeyState( VK_RBUTTON ) & (1<<15) )
6115         state |= MK_RBUTTON;
6116 
6117     POINT pt;
6118     wxGetCursorPosMSW(&pt);
6119 
6120     // we need to have client coordinates here for symmetry with
6121     // wxEVT_ENTER_WINDOW
6122     RECT rect = wxGetWindowRect(GetHwnd());
6123     pt.x -= rect.left;
6124     pt.y -= rect.top;
6125 
6126     wxMouseEvent event(wxEVT_LEAVE_WINDOW);
6127     InitMouseEvent(event, pt.x, pt.y, state);
6128 
6129     (void)HandleWindowEvent(event);
6130 }
6131 
6132 #ifdef WM_GESTURE
6133 // ---------------------------------------------------------------------------
6134 // Gesture events
6135 // ---------------------------------------------------------------------------
6136 
InitGestureEvent(wxGestureEvent & event,const wxPoint & pt,WXDWORD flags)6137 bool wxWindowMSW::InitGestureEvent(wxGestureEvent& event,
6138                                    const wxPoint& pt,
6139                                    WXDWORD flags)
6140 {
6141     event.SetEventObject(this);
6142     event.SetTimestamp(::GetMessageTime());
6143     event.SetPosition(pt);
6144 
6145     if ( flags & GF_BEGIN )
6146         event.SetGestureStart();
6147 
6148     if ( flags & GF_END )
6149         event.SetGestureEnd();
6150 
6151     return (flags & GF_BEGIN) != 0;
6152 }
6153 
HandlePanGesture(const wxPoint & pt,WXDWORD flags)6154 bool wxWindowMSW::HandlePanGesture(const wxPoint& pt, WXDWORD flags)
6155 {
6156     // wxEVT_GESTURE_PAN
6157     wxPanGestureEvent event(GetId());
6158 
6159     // This is used to calculate the pan delta.
6160     static wxPoint s_previousLocation;
6161 
6162     // If the gesture has just started, store the current point to determine
6163     // the pan delta later on.
6164     if ( InitGestureEvent(event, pt, flags) )
6165     {
6166         s_previousLocation = pt;
6167     }
6168 
6169     // Determine the horizontal and vertical changes
6170     event.SetDelta(pt - s_previousLocation);
6171 
6172     // Update the last gesture event point
6173     s_previousLocation = pt;
6174 
6175     return HandleWindowEvent(event);
6176 }
6177 
HandleZoomGesture(const wxPoint & pt,WXDWORD fingerDistance,WXDWORD flags)6178 bool wxWindowMSW::HandleZoomGesture(const wxPoint& pt,
6179                                     WXDWORD fingerDistance,
6180                                     WXDWORD flags)
6181 {
6182     // wxEVT_GESTURE_ZOOM
6183     wxZoomGestureEvent event(GetId());
6184 
6185     // These are used to calculate the center of the zoom and zoom factor
6186     static wxPoint s_previousLocation;
6187     static int s_intialFingerDistance;
6188 
6189     // This flag indicates that the gesture has just started, store the current
6190     // point and distance between the fingers for future calculations.
6191     if ( InitGestureEvent(event, pt, flags) )
6192     {
6193         s_previousLocation = pt;
6194         s_intialFingerDistance = fingerDistance;
6195     }
6196 
6197     // Calculate center point of the zoom. Human beings are not very good at
6198     // moving two fingers at exactly the same rate outwards/inwards and there
6199     // is usually some error, which can cause the center to shift slightly. So,
6200     // it is recommended to take the average of center of fingers in the
6201     // current and last positions.
6202     const wxPoint ptCenter = (s_previousLocation + pt)/2;
6203 
6204     const double zoomFactor = (double) fingerDistance / s_intialFingerDistance;
6205 
6206     event.SetZoomFactor(zoomFactor);
6207 
6208     event.SetPosition(ptCenter);
6209 
6210     // Update gesture event point
6211     s_previousLocation = pt;
6212 
6213     return HandleWindowEvent(event);
6214 }
6215 
HandleRotateGesture(const wxPoint & pt,WXDWORD angleArgument,WXDWORD flags)6216 bool wxWindowMSW::HandleRotateGesture(const wxPoint& pt,
6217                                       WXDWORD angleArgument,
6218                                       WXDWORD flags)
6219 {
6220     // wxEVT_GESTURE_ROTATE
6221     wxRotateGestureEvent event(GetId());
6222 
6223     if ( InitGestureEvent(event, pt, flags) )
6224     {
6225         event.SetRotationAngle(angleArgument);
6226     }
6227     else // Not the first event.
6228     {
6229         // Use angleArgument to obtain the cumulative angle since the gesture
6230         // was first started. This angle is in radians and MSW returns negative
6231         // angle for clockwise rotation and positive otherwise, so, multiply
6232         // angle by -1 for positive angle for clockwise and negative in case of
6233         // counterclockwise.
6234         double angle = -GID_ROTATE_ANGLE_FROM_ARGUMENT(angleArgument);
6235 
6236         // If the rotation is anti-clockwise convert the angle to its
6237         // corresponding positive value in a clockwise sense.
6238         if ( angle < 0 )
6239         {
6240             angle += 2 * M_PI;
6241         }
6242 
6243         // Set the angle
6244         event.SetRotationAngle(angle);
6245     }
6246 
6247     return HandleWindowEvent(event);
6248 }
6249 
HandleTwoFingerTap(const wxPoint & pt,WXDWORD flags)6250 bool wxWindowMSW::HandleTwoFingerTap(const wxPoint& pt, WXDWORD flags)
6251 {
6252     // wxEVT_TWO_FINGER_TAP
6253     wxTwoFingerTapEvent event(GetId());
6254 
6255     InitGestureEvent(event, pt, flags);
6256 
6257     return HandleWindowEvent(event);
6258 }
6259 
HandlePressAndTap(const wxPoint & pt,WXDWORD flags)6260 bool wxWindowMSW::HandlePressAndTap(const wxPoint& pt, WXDWORD flags)
6261 {
6262     wxPressAndTapEvent event(GetId());
6263 
6264     InitGestureEvent(event, pt, flags);
6265 
6266     return HandleWindowEvent(event);
6267 }
6268 #endif // WM_GESTURE
6269 
6270 // ---------------------------------------------------------------------------
6271 // keyboard handling
6272 // ---------------------------------------------------------------------------
6273 
6274 namespace
6275 {
6276 
6277 // Implementation of InitAnyKeyEvent() which can also be used when there is no
6278 // associated window: this can happen for the wxEVT_CHAR_HOOK events created by
6279 // the global keyboard hook (e.g. the event might have happened in a non-wx
6280 // window).
6281 void
MSWInitAnyKeyEvent(wxKeyEvent & event,WXWPARAM wParam,WXLPARAM lParam,const wxWindowBase * win)6282 MSWInitAnyKeyEvent(wxKeyEvent& event,
6283                    WXWPARAM wParam,
6284                    WXLPARAM lParam,
6285                    const wxWindowBase *win /* may be NULL */)
6286 {
6287     if ( win )
6288     {
6289         event.SetId(win->GetId());
6290         event.SetEventObject(const_cast<wxWindowBase *>(win));
6291     }
6292     else // No associated window.
6293     {
6294         // Use wxID_ANY for compatibility with the old code even if wxID_NONE
6295         // would arguably make more sense.
6296         event.SetId(wxID_ANY);
6297     }
6298 
6299     event.m_shiftDown = wxIsShiftDown();
6300     event.m_controlDown = wxIsCtrlDown();
6301     event.m_altDown = (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN;
6302 
6303     event.m_rawCode = (wxUint32) wParam;
6304     event.m_rawFlags = (wxUint32) lParam;
6305     event.SetTimestamp(::GetMessageTime());
6306 }
6307 
6308 } // anonymous namespace
6309 
6310 void
InitAnyKeyEvent(wxKeyEvent & event,WXWPARAM wParam,WXLPARAM lParam) const6311 wxWindowMSW::InitAnyKeyEvent(wxKeyEvent& event,
6312                              WXWPARAM wParam,
6313                              WXLPARAM lParam) const
6314 {
6315     MSWInitAnyKeyEvent(event, wParam, lParam, this);
6316 }
6317 
6318 wxKeyEvent
CreateKeyEvent(wxEventType evType,WXWPARAM wParam,WXLPARAM lParam) const6319 wxWindowMSW::CreateKeyEvent(wxEventType evType,
6320                             WXWPARAM wParam,
6321                             WXLPARAM lParam) const
6322 {
6323     // Catch any attempts to use this with WM_CHAR, it wouldn't work because
6324     // wParam is supposed to be a virtual key and not a character here.
6325     wxASSERT_MSG( evType != wxEVT_CHAR && evType != wxEVT_CHAR_HOOK,
6326                     "CreateKeyEvent() can't be used for char events" );
6327 
6328     wxKeyEvent event(evType);
6329     InitAnyKeyEvent(event, wParam, lParam);
6330 
6331     event.m_keyCode = wxMSWKeyboard::VKToWX
6332                                      (
6333                                         wParam,
6334                                         lParam
6335 #if wxUSE_UNICODE
6336                                         , &event.m_uniChar
6337 #endif // wxUSE_UNICODE
6338                                      );
6339 
6340     return event;
6341 }
6342 
6343 wxKeyEvent
CreateCharEvent(wxEventType evType,WXWPARAM wParam,WXLPARAM lParam) const6344 wxWindowMSW::CreateCharEvent(wxEventType evType,
6345                              WXWPARAM wParam,
6346                              WXLPARAM lParam) const
6347 {
6348     wxKeyEvent event(evType);
6349     InitAnyKeyEvent(event, wParam, lParam);
6350 
6351 #if wxUSE_UNICODE
6352     // TODO: wParam uses UTF-16 so this is incorrect for characters outside of
6353     //       the BMP, we should use WM_UNICHAR to handle them.
6354     event.m_uniChar = wParam;
6355 #endif // wxUSE_UNICODE
6356 
6357     // Set non-Unicode key code too for compatibility if possible.
6358     if ( wParam < 0x80 )
6359     {
6360         // It's an ASCII character, no need to translate it.
6361         event.m_keyCode = wParam;
6362     }
6363     else
6364     {
6365         // Check if this key can be represented (as a single character) in the
6366         // current locale.
6367         const wchar_t wc = wParam;
6368         char ch;
6369         if ( wxConvLibc.FromWChar(&ch, 1, &wc, 1) != wxCONV_FAILED )
6370         {
6371             // For compatibility continue to provide the key code in this field
6372             // even though using GetUnicodeKey() is recommended now.
6373             event.m_keyCode = static_cast<unsigned char>(ch);
6374         }
6375         //else: Key can't be represented in the current locale, leave m_keyCode
6376         //      as WXK_NONE and use GetUnicodeKey() to access the character.
6377     }
6378 
6379     // the alphanumeric keys produced by pressing AltGr+something on European
6380     // keyboards have both Ctrl and Alt modifiers which may confuse the user
6381     // code as, normally, keys with Ctrl and/or Alt don't result in anything
6382     // alphanumeric, so pretend that there are no modifiers at all (the
6383     // KEY_DOWN event would still have the correct modifiers if they're really
6384     // needed)
6385     if ( event.m_controlDown && event.m_altDown &&
6386             (event.m_keyCode >= 32 && event.m_keyCode < 256) )
6387     {
6388         event.m_controlDown =
6389         event.m_altDown = false;
6390     }
6391 
6392     return event;
6393 }
6394 
6395 // isASCII is true only when we're called from WM_CHAR handler and not from
6396 // WM_KEYDOWN one
HandleChar(WXWPARAM wParam,WXLPARAM lParam)6397 bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam)
6398 {
6399     wxKeyEvent event(CreateCharEvent(wxEVT_CHAR, wParam, lParam));
6400     return HandleWindowEvent(event);
6401 }
6402 
HandleKeyDown(WXWPARAM wParam,WXLPARAM lParam)6403 bool wxWindowMSW::HandleKeyDown(WXWPARAM wParam, WXLPARAM lParam)
6404 {
6405     wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_DOWN, wParam, lParam));
6406     return HandleWindowEvent(event);
6407 }
6408 
HandleKeyUp(WXWPARAM wParam,WXLPARAM lParam)6409 bool wxWindowMSW::HandleKeyUp(WXWPARAM wParam, WXLPARAM lParam)
6410 {
6411     wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_UP, wParam, lParam));
6412     return HandleWindowEvent(event);
6413 }
6414 
6415 #if wxUSE_MENUS
HandleMenuChar(int chAccel,WXLPARAM lParam)6416 int wxWindowMSW::HandleMenuChar(int chAccel,
6417                                 WXLPARAM lParam)
6418 {
6419     const HMENU hmenu = (HMENU)lParam;
6420 
6421     WinStruct<MENUITEMINFO> mii;
6422 
6423     // use MIIM_FTYPE to know if the item is ownerdrawn or not
6424     mii.fMask = MIIM_FTYPE | MIIM_DATA;
6425 
6426     // find if we have this letter in any owner drawn item
6427     const int count = ::GetMenuItemCount(hmenu);
6428     for ( int i = 0; i < count; i++ )
6429     {
6430         if ( ::GetMenuItemInfo(hmenu, i, TRUE, &mii) )
6431         {
6432             if ( mii.fType == MFT_OWNERDRAW )
6433             {
6434                 //  dwItemData member of the MENUITEMINFO is a
6435                 //  pointer to the associated wxMenuItem -- see the
6436                 //  menu creation code
6437                 wxMenuItem *item = (wxMenuItem*)mii.dwItemData;
6438 
6439                 const wxString label(item->GetItemLabel());
6440                 const wxChar *p = wxStrchr(label.t_str(), wxT('&'));
6441                 while ( p++ )
6442                 {
6443                     if ( *p == wxT('&') )
6444                     {
6445                         // this is not the accel char, find the real one
6446                         p = wxStrchr(p + 1, wxT('&'));
6447                     }
6448                     else // got the accel char
6449                     {
6450                         // FIXME-UNICODE: this comparison doesn't risk to work
6451                         // for non ASCII accelerator characters I'm afraid, but
6452                         // what can we do?
6453                         if ( (wchar_t)wxToupper(*p) == (wchar_t)chAccel )
6454                         {
6455                             return i;
6456                         }
6457                         else
6458                         {
6459                             // this one doesn't match
6460                             break;
6461                         }
6462                     }
6463                 }
6464             }
6465         }
6466         else // failed to get the menu text?
6467         {
6468             // it's not fatal, so don't show error, but still log it
6469             wxLogLastError(wxT("GetMenuItemInfo"));
6470         }
6471     }
6472     return wxNOT_FOUND;
6473 }
6474 
6475 #endif // wxUSE_MENUS
6476 
HandleClipboardEvent(WXUINT nMsg)6477 bool wxWindowMSW::HandleClipboardEvent(WXUINT nMsg)
6478 {
6479     const wxEventType type = nMsg == WM_CUT       ? wxEVT_TEXT_CUT
6480                            : nMsg == WM_COPY      ? wxEVT_TEXT_COPY
6481                            : /* nMsg == WM_PASTE */ wxEVT_TEXT_PASTE;
6482     wxClipboardTextEvent evt(type, GetId());
6483 
6484     evt.SetEventObject(this);
6485 
6486     return HandleWindowEvent(evt);
6487 }
6488 
6489 
6490 // ---------------------------------------------------------------------------
6491 // scrolling
6492 // ---------------------------------------------------------------------------
6493 
MSWOnScroll(int orientation,WXWORD wParam,WXWORD pos,WXHWND control)6494 bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam,
6495                               WXWORD pos, WXHWND control)
6496 {
6497     if ( control && control != m_hWnd ) // Prevent infinite recursion
6498     {
6499         wxWindow *child = wxFindWinFromHandle(control);
6500         if ( child )
6501             return child->MSWOnScroll(orientation, wParam, pos, control);
6502     }
6503 
6504     wxScrollWinEvent event;
6505     event.SetPosition(pos);
6506     event.SetOrientation(orientation);
6507     event.SetEventObject(this);
6508 
6509     switch ( wParam )
6510     {
6511     case SB_TOP:
6512         event.SetEventType(wxEVT_SCROLLWIN_TOP);
6513         break;
6514 
6515     case SB_BOTTOM:
6516         event.SetEventType(wxEVT_SCROLLWIN_BOTTOM);
6517         break;
6518 
6519     case SB_LINEUP:
6520         event.SetEventType(wxEVT_SCROLLWIN_LINEUP);
6521         break;
6522 
6523     case SB_LINEDOWN:
6524         event.SetEventType(wxEVT_SCROLLWIN_LINEDOWN);
6525         break;
6526 
6527     case SB_PAGEUP:
6528         event.SetEventType(wxEVT_SCROLLWIN_PAGEUP);
6529         break;
6530 
6531     case SB_PAGEDOWN:
6532         event.SetEventType(wxEVT_SCROLLWIN_PAGEDOWN);
6533         break;
6534 
6535     case SB_THUMBPOSITION:
6536     case SB_THUMBTRACK:
6537         // under Win32, the scrollbar range and position are 32 bit integers,
6538         // but WM_[HV]SCROLL only carry the low 16 bits of them, so we must
6539         // explicitly query the scrollbar for the correct position (this must
6540         // be done only for these two SB_ events as they are the only one
6541         // carrying the scrollbar position)
6542         {
6543             WinStruct<SCROLLINFO> scrollInfo;
6544             scrollInfo.fMask = SIF_TRACKPOS;
6545 
6546             if ( !::GetScrollInfo(GetHwnd(),
6547                                   WXOrientToSB(orientation),
6548                                   &scrollInfo) )
6549             {
6550                 // Not necessarily an error, if there are no scrollbars yet.
6551                 // wxLogLastError(wxT("GetScrollInfo"));
6552             }
6553 
6554             event.SetPosition(scrollInfo.nTrackPos);
6555         }
6556 
6557         event.SetEventType( wParam == SB_THUMBPOSITION
6558                                 ? wxEVT_SCROLLWIN_THUMBRELEASE
6559                                 : wxEVT_SCROLLWIN_THUMBTRACK );
6560         break;
6561 
6562     default:
6563         return false;
6564     }
6565 
6566     return HandleWindowEvent(event);
6567 }
6568 
6569 // ----------------------------------------------------------------------------
6570 // custom message handlers
6571 // ----------------------------------------------------------------------------
6572 
6573 /* static */ bool
MSWRegisterMessageHandler(int msg,MSWMessageHandler handler)6574 wxWindowMSW::MSWRegisterMessageHandler(int msg, MSWMessageHandler handler)
6575 {
6576     wxCHECK_MSG( gs_messageHandlers.find(msg) == gs_messageHandlers.end(),
6577                  false, wxT("registering handler for the same message twice") );
6578 
6579     gs_messageHandlers[msg] = handler;
6580     return true;
6581 }
6582 
6583 /* static */ void
MSWUnregisterMessageHandler(int msg,MSWMessageHandler handler)6584 wxWindowMSW::MSWUnregisterMessageHandler(int msg, MSWMessageHandler handler)
6585 {
6586     const MSWMessageHandlers::iterator i = gs_messageHandlers.find(msg);
6587     wxCHECK_RET( i != gs_messageHandlers.end() && i->second == handler,
6588                  wxT("unregistering non-registered handler?") );
6589 
6590     gs_messageHandlers.erase(i);
6591 }
6592 
6593 // ===========================================================================
6594 // global functions
6595 // ===========================================================================
6596 
wxGetCharSize(WXHWND wnd,int * x,int * y,const wxFont & the_font)6597 void wxGetCharSize(WXHWND wnd, int *x, int *y, const wxFont& the_font)
6598 {
6599     TEXTMETRIC tm;
6600     HDC dc = ::GetDC((HWND) wnd);
6601     HFONT was = 0;
6602 
6603     //    the_font.UseResource();
6604     //    the_font.RealizeResource();
6605     HFONT fnt = (HFONT)the_font.GetResourceHandle(); // const_cast
6606     if ( fnt )
6607         was = (HFONT) SelectObject(dc,fnt);
6608 
6609     GetTextMetrics(dc, &tm);
6610     if ( fnt && was )
6611     {
6612         SelectObject(dc,was);
6613     }
6614     ReleaseDC((HWND)wnd, dc);
6615 
6616     if ( x )
6617         *x = tm.tmAveCharWidth;
6618     if ( y )
6619         *y = tm.tmHeight + tm.tmExternalLeading;
6620 
6621     //   the_font.ReleaseResource();
6622 }
6623 
6624 // ----------------------------------------------------------------------------
6625 // keyboard codes
6626 // ----------------------------------------------------------------------------
6627 
6628 namespace wxMSWKeyboard
6629 {
6630 
6631 namespace
6632 {
6633 
6634 // use the "extended" bit of lParam to distinguish extended keys from normal
6635 // keys as the same virtual key code is sent for both by Windows
6636 inline
ChooseNormalOrExtended(int lParam,int keyNormal,int keyExtended)6637 int ChooseNormalOrExtended(int lParam, int keyNormal, int keyExtended)
6638 {
6639     // except that if lParam is 0, it means we don't have real lParam from
6640     // WM_KEYDOWN but are just translating just a VK constant (e.g. done from
6641     // msw/treectrl.cpp when processing TVN_KEYDOWN) -- then assume this is a
6642     // non-numpad (hence extended) key as this is a more common case
6643     return !lParam || (HIWORD(lParam) & KF_EXTENDED) ? keyExtended : keyNormal;
6644 }
6645 
6646 // this array contains the Windows virtual key codes which map one to one to
6647 // WXK_xxx constants and is used in wxMSWKeyboard::VKToWX/WXToVK() below
6648 //
6649 // note that keys having a normal and numpad version (e.g. WXK_HOME and
6650 // WXK_NUMPAD_HOME) are not included in this table as the mapping is not 1-to-1
6651 const struct wxKeyMapping
6652 {
6653     int vk;
6654     wxKeyCode wxk;
6655 } gs_specialKeys[] =
6656 {
6657     { VK_CANCEL,        WXK_CANCEL },
6658     { VK_BACK,          WXK_BACK },
6659     { VK_TAB,           WXK_TAB },
6660     { VK_CLEAR,         WXK_CLEAR },
6661     { VK_SHIFT,         WXK_SHIFT },
6662     { VK_CONTROL,       WXK_CONTROL },
6663     { VK_MENU ,         WXK_ALT },
6664     { VK_PAUSE,         WXK_PAUSE },
6665     { VK_CAPITAL,       WXK_CAPITAL },
6666     { VK_SPACE,         WXK_SPACE },
6667     { VK_ESCAPE,        WXK_ESCAPE },
6668     { VK_SELECT,        WXK_SELECT },
6669     { VK_PRINT,         WXK_PRINT },
6670     { VK_EXECUTE,       WXK_EXECUTE },
6671     { VK_SNAPSHOT,      WXK_SNAPSHOT },
6672     { VK_HELP,          WXK_HELP },
6673 
6674     { VK_NUMPAD0,       WXK_NUMPAD0 },
6675     { VK_NUMPAD1,       WXK_NUMPAD1 },
6676     { VK_NUMPAD2,       WXK_NUMPAD2 },
6677     { VK_NUMPAD3,       WXK_NUMPAD3 },
6678     { VK_NUMPAD4,       WXK_NUMPAD4 },
6679     { VK_NUMPAD5,       WXK_NUMPAD5 },
6680     { VK_NUMPAD6,       WXK_NUMPAD6 },
6681     { VK_NUMPAD7,       WXK_NUMPAD7 },
6682     { VK_NUMPAD8,       WXK_NUMPAD8 },
6683     { VK_NUMPAD9,       WXK_NUMPAD9 },
6684     { VK_MULTIPLY,      WXK_NUMPAD_MULTIPLY },
6685     { VK_ADD,           WXK_NUMPAD_ADD },
6686     { VK_SUBTRACT,      WXK_NUMPAD_SUBTRACT },
6687     { VK_DECIMAL,       WXK_NUMPAD_DECIMAL },
6688     { VK_DIVIDE,        WXK_NUMPAD_DIVIDE },
6689 
6690     { VK_F1,            WXK_F1 },
6691     { VK_F2,            WXK_F2 },
6692     { VK_F3,            WXK_F3 },
6693     { VK_F4,            WXK_F4 },
6694     { VK_F5,            WXK_F5 },
6695     { VK_F6,            WXK_F6 },
6696     { VK_F7,            WXK_F7 },
6697     { VK_F8,            WXK_F8 },
6698     { VK_F9,            WXK_F9 },
6699     { VK_F10,           WXK_F10 },
6700     { VK_F11,           WXK_F11 },
6701     { VK_F12,           WXK_F12 },
6702     { VK_F13,           WXK_F13 },
6703     { VK_F14,           WXK_F14 },
6704     { VK_F15,           WXK_F15 },
6705     { VK_F16,           WXK_F16 },
6706     { VK_F17,           WXK_F17 },
6707     { VK_F18,           WXK_F18 },
6708     { VK_F19,           WXK_F19 },
6709     { VK_F20,           WXK_F20 },
6710     { VK_F21,           WXK_F21 },
6711     { VK_F22,           WXK_F22 },
6712     { VK_F23,           WXK_F23 },
6713     { VK_F24,           WXK_F24 },
6714 
6715     { VK_NUMLOCK,       WXK_NUMLOCK },
6716     { VK_SCROLL,        WXK_SCROLL },
6717 
6718     { VK_LWIN,          WXK_WINDOWS_LEFT },
6719     { VK_RWIN,          WXK_WINDOWS_RIGHT },
6720     { VK_APPS,          WXK_WINDOWS_MENU },
6721 
6722     { VK_BROWSER_BACK,        WXK_BROWSER_BACK },
6723     { VK_BROWSER_FORWARD,     WXK_BROWSER_FORWARD },
6724     { VK_BROWSER_REFRESH,     WXK_BROWSER_REFRESH },
6725     { VK_BROWSER_STOP,        WXK_BROWSER_STOP },
6726     { VK_BROWSER_SEARCH,      WXK_BROWSER_SEARCH },
6727     { VK_BROWSER_FAVORITES,   WXK_BROWSER_FAVORITES },
6728     { VK_BROWSER_HOME,        WXK_BROWSER_HOME },
6729     { VK_VOLUME_MUTE,         WXK_VOLUME_MUTE },
6730     { VK_VOLUME_DOWN,         WXK_VOLUME_DOWN },
6731     { VK_VOLUME_UP,           WXK_VOLUME_UP },
6732     { VK_MEDIA_NEXT_TRACK,    WXK_MEDIA_NEXT_TRACK },
6733     { VK_MEDIA_PREV_TRACK,    WXK_MEDIA_PREV_TRACK },
6734     { VK_MEDIA_STOP,          WXK_MEDIA_STOP },
6735     { VK_MEDIA_PLAY_PAUSE,    WXK_MEDIA_PLAY_PAUSE },
6736     { VK_LAUNCH_MAIL,         WXK_LAUNCH_MAIL },
6737     { VK_LAUNCH_APP1,         WXK_LAUNCH_APP1 },
6738     { VK_LAUNCH_APP2,         WXK_LAUNCH_APP2 },
6739 };
6740 
6741 } // anonymous namespace
6742 
VKToWX(WXWORD vk,WXLPARAM lParam,wchar_t * uc)6743 int VKToWX(WXWORD vk, WXLPARAM lParam, wchar_t *uc)
6744 {
6745     int wxk;
6746 
6747     // check the table first
6748     for ( size_t n = 0; n < WXSIZEOF(gs_specialKeys); n++ )
6749     {
6750         if ( gs_specialKeys[n].vk == vk )
6751         {
6752             wxk = gs_specialKeys[n].wxk;
6753             if ( wxk < WXK_START )
6754             {
6755                 // Unicode code for this key is the same as its ASCII code.
6756                 if ( uc )
6757                     *uc = wxk;
6758             }
6759 
6760             return wxk;
6761         }
6762     }
6763 
6764     // keys requiring special handling
6765     switch ( vk )
6766     {
6767         case VK_OEM_1:
6768         case VK_OEM_PLUS:
6769         case VK_OEM_COMMA:
6770         case VK_OEM_MINUS:
6771         case VK_OEM_PERIOD:
6772         case VK_OEM_2:
6773         case VK_OEM_3:
6774         case VK_OEM_4:
6775         case VK_OEM_5:
6776         case VK_OEM_6:
6777         case VK_OEM_7:
6778         case VK_OEM_8:
6779         case VK_OEM_102:
6780             // MapVirtualKey() returns 0 if it fails to convert the virtual
6781             // key which nicely corresponds to our WXK_NONE.
6782             wxk = ::MapVirtualKey(vk, MAPVK_VK_TO_CHAR);
6783 
6784             if ( HIWORD(wxk) & 0x8000 )
6785             {
6786                 // It's a dead key and we don't return anything at all for them
6787                 // as we simply don't have any way to indicate the difference
6788                 // between e.g. a normal "'" and "'" as a dead key -- and
6789                 // generating the same events for them just doesn't seem like a
6790                 // good idea.
6791                 wxk = WXK_NONE;
6792             }
6793 
6794             // In any case return this as a Unicode character value.
6795             if ( uc )
6796                 *uc = wxk;
6797 
6798             // For compatibility with the old non-Unicode code we continue
6799             // returning key codes for Latin-1 characters directly
6800             // (normally it would really only make sense to do it for the
6801             // ASCII characters, not Latin-1 ones).
6802             if ( wxk > 255 )
6803             {
6804                 // But for anything beyond this we can only return the key
6805                 // value as a real Unicode character, not a wxKeyCode
6806                 // because this enum values clash with Unicode characters
6807                 // (e.g. WXK_LBUTTON also happens to be U+012C a.k.a.
6808                 // "LATIN CAPITAL LETTER I WITH BREVE").
6809                 wxk = WXK_NONE;
6810             }
6811             break;
6812 
6813         // handle extended keys
6814         case VK_PRIOR:
6815             wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_PAGEUP, WXK_PAGEUP);
6816             break;
6817 
6818         case VK_NEXT:
6819             wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_PAGEDOWN, WXK_PAGEDOWN);
6820             break;
6821 
6822         case VK_END:
6823             wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_END, WXK_END);
6824             break;
6825 
6826         case VK_HOME:
6827             wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_HOME, WXK_HOME);
6828             break;
6829 
6830         case VK_LEFT:
6831             wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_LEFT, WXK_LEFT);
6832             break;
6833 
6834         case VK_UP:
6835             wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_UP, WXK_UP);
6836             break;
6837 
6838         case VK_RIGHT:
6839             wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_RIGHT, WXK_RIGHT);
6840             break;
6841 
6842         case VK_DOWN:
6843             wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DOWN, WXK_DOWN);
6844             break;
6845 
6846         case VK_INSERT:
6847             wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_INSERT, WXK_INSERT);
6848             break;
6849 
6850         case VK_DELETE:
6851             wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DELETE, WXK_DELETE);
6852 
6853             if ( uc )
6854                 *uc = WXK_DELETE;
6855             break;
6856 
6857         case VK_RETURN:
6858             // don't use ChooseNormalOrExtended() here as the keys are reversed
6859             // here: numpad enter is the extended one
6860             wxk = HIWORD(lParam) & KF_EXTENDED ? WXK_NUMPAD_ENTER : WXK_RETURN;
6861 
6862             if ( uc )
6863                 *uc = WXK_RETURN;
6864             break;
6865 
6866         default:
6867             if ( (vk >= '0' && vk <= '9') || (vk >= 'A' && vk <= 'Z') )
6868             {
6869                 // A simple alphanumeric key and the values of them coincide in
6870                 // Windows and wx for both ASCII and Unicode codes.
6871                 wxk = vk;
6872             }
6873             else // Something we simply don't know about at all.
6874             {
6875                 wxk = WXK_NONE;
6876             }
6877 
6878             if ( uc )
6879                 *uc = vk;
6880     }
6881 
6882     return wxk;
6883 }
6884 
WXToVK(int wxk,bool * isExtended)6885 WXWORD WXToVK(int wxk, bool *isExtended)
6886 {
6887     // check the table first
6888     for ( size_t n = 0; n < WXSIZEOF(gs_specialKeys); n++ )
6889     {
6890         if ( gs_specialKeys[n].wxk == wxk )
6891         {
6892             // All extended keys (i.e. non-numpad versions of the keys that
6893             // exist both in the numpad and outside of it) are dealt with
6894             // below.
6895             if ( isExtended )
6896                 *isExtended = false;
6897 
6898             return gs_specialKeys[n].vk;
6899         }
6900     }
6901 
6902     // and then check for special keys not included in the table
6903     bool extended = false;
6904     WXWORD vk;
6905     switch ( wxk )
6906     {
6907         case WXK_PAGEUP:
6908             extended = true;
6909             wxFALLTHROUGH;
6910         case WXK_NUMPAD_PAGEUP:
6911             vk = VK_PRIOR;
6912             break;
6913 
6914         case WXK_PAGEDOWN:
6915             extended = true;
6916             wxFALLTHROUGH;
6917         case WXK_NUMPAD_PAGEDOWN:
6918             vk = VK_NEXT;
6919             break;
6920 
6921         case WXK_END:
6922             extended = true;
6923             wxFALLTHROUGH;
6924         case WXK_NUMPAD_END:
6925             vk = VK_END;
6926             break;
6927 
6928         case WXK_HOME:
6929             extended = true;
6930             wxFALLTHROUGH;
6931         case WXK_NUMPAD_HOME:
6932             vk = VK_HOME;
6933             break;
6934 
6935         case WXK_LEFT:
6936             extended = true;
6937             wxFALLTHROUGH;
6938         case WXK_NUMPAD_LEFT:
6939             vk = VK_LEFT;
6940             break;
6941 
6942         case WXK_UP:
6943             extended = true;
6944             wxFALLTHROUGH;
6945         case WXK_NUMPAD_UP:
6946             vk = VK_UP;
6947             break;
6948 
6949         case WXK_RIGHT:
6950             extended = true;
6951             wxFALLTHROUGH;
6952         case WXK_NUMPAD_RIGHT:
6953             vk = VK_RIGHT;
6954             break;
6955 
6956         case WXK_DOWN:
6957             extended = true;
6958             wxFALLTHROUGH;
6959         case WXK_NUMPAD_DOWN:
6960             vk = VK_DOWN;
6961             break;
6962 
6963         case WXK_INSERT:
6964             extended = true;
6965             wxFALLTHROUGH;
6966         case WXK_NUMPAD_INSERT:
6967             vk = VK_INSERT;
6968             break;
6969 
6970         case WXK_DELETE:
6971             extended = true;
6972             wxFALLTHROUGH;
6973         case WXK_NUMPAD_DELETE:
6974             vk = VK_DELETE;
6975             break;
6976 
6977         default:
6978             // check to see if its one of the OEM key codes.
6979             BYTE vks = LOBYTE(VkKeyScan(wxk));
6980             if ( vks != 0xff )
6981             {
6982                 vk = vks;
6983             }
6984             else
6985             {
6986                 vk = (WXWORD)wxk;
6987             }
6988             break;
6989     }
6990 
6991     if ( isExtended )
6992         *isExtended = extended;
6993 
6994     return vk;
6995 }
6996 
6997 } // namespace wxMSWKeyboard
6998 
6999 // small helper for wxGetKeyState() and wxGetMouseState()
wxIsKeyDown(WXWORD vk)7000 static inline bool wxIsKeyDown(WXWORD vk)
7001 {
7002     if ( vk == VK_LBUTTON || vk == VK_RBUTTON )
7003     {
7004         if ( ::GetSystemMetrics(SM_SWAPBUTTON) )
7005         {
7006             if ( vk == VK_LBUTTON )
7007                 vk = VK_RBUTTON;
7008             else // vk == VK_RBUTTON
7009                 vk = VK_LBUTTON;
7010         }
7011     }
7012 
7013     // the low order bit indicates whether the key was pressed since the last
7014     // call and the high order one indicates whether it is down right now and
7015     // we only want that one
7016     return (GetAsyncKeyState(vk) & (1<<15)) != 0;
7017 }
7018 
wxGetKeyState(wxKeyCode key)7019 bool wxGetKeyState(wxKeyCode key)
7020 {
7021     // although this does work under Windows, it is not supported under other
7022     // platforms so don't allow it, you must use wxGetMouseState() instead
7023     wxASSERT_MSG( key != VK_LBUTTON &&
7024                     key != VK_RBUTTON &&
7025                         key != VK_MBUTTON,
7026                     wxT("can't use wxGetKeyState() for mouse buttons") );
7027 
7028     const WXWORD vk = wxMSWKeyboard::WXToVK(key);
7029 
7030     // if the requested key is a LED key, return true if the led is pressed
7031     if ( key == WXK_NUMLOCK || key == WXK_CAPITAL || key == WXK_SCROLL )
7032     {
7033         // low order bit means LED is highlighted and high order one means the
7034         // key is down; for compatibility with the other ports return true if
7035         // either one is set
7036         return GetKeyState(vk) != 0;
7037 
7038     }
7039     else // normal key
7040     {
7041         return wxIsKeyDown(vk);
7042     }
7043 }
7044 
7045 
wxGetMouseState()7046 wxMouseState wxGetMouseState()
7047 {
7048     wxMouseState ms;
7049     POINT pt;
7050     wxGetCursorPosMSW(&pt);
7051 
7052     ms.SetX(pt.x);
7053     ms.SetY(pt.y);
7054     ms.SetLeftDown(wxIsKeyDown(VK_LBUTTON));
7055     ms.SetMiddleDown(wxIsKeyDown(VK_MBUTTON));
7056     ms.SetRightDown(wxIsKeyDown(VK_RBUTTON));
7057     ms.SetAux1Down(wxIsKeyDown(VK_XBUTTON1));
7058     ms.SetAux2Down(wxIsKeyDown(VK_XBUTTON2));
7059 
7060     ms.SetControlDown(wxIsCtrlDown ());
7061     ms.SetShiftDown  (wxIsShiftDown());
7062     ms.SetAltDown    (wxIsAltDown  ());
7063 //    ms.SetMetaDown();
7064 
7065     return ms;
7066 }
7067 
7068 
wxGetActiveWindow()7069 wxWindow *wxGetActiveWindow()
7070 {
7071     HWND hWnd = GetActiveWindow();
7072     if ( hWnd != 0 )
7073     {
7074         return wxFindWinFromHandle(hWnd);
7075     }
7076     return NULL;
7077 }
7078 
wxGetWindowFromHWND(WXHWND hWnd)7079 extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd)
7080 {
7081     HWND hwnd = (HWND)hWnd;
7082 
7083     // For a radiobutton, we get the radiobox from GWL_USERDATA (which is set
7084     // by code in msw/radiobox.cpp), for all the others we just search up the
7085     // window hierarchy
7086     wxWindow *win = NULL;
7087     if ( hwnd )
7088     {
7089         win = wxFindWinFromHandle(hwnd);
7090         if ( !win )
7091         {
7092 #if wxUSE_RADIOBOX && !defined(__WXUNIVERSAL__)
7093             // native radiobuttons return DLGC_RADIOBUTTON here and for any
7094             // wxWindow class which overrides WM_GETDLGCODE processing to
7095             // do it as well, win would be already non NULL
7096             if ( ::SendMessage(hwnd, WM_GETDLGCODE, 0, 0) & DLGC_RADIOBUTTON )
7097             {
7098                 win = wxRadioBox::GetFromRadioButtonHWND(hwnd);
7099             }
7100             //else: it's a wxRadioButton, not a radiobutton from wxRadioBox
7101 #endif // wxUSE_RADIOBOX
7102 
7103             // spin control text buddy window should be mapped to spin ctrl
7104             // itself so try it too
7105 #if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__)
7106             if ( !win )
7107             {
7108                 win = wxSpinCtrl::GetSpinForTextCtrl((WXHWND)hwnd);
7109             }
7110 #endif // wxUSE_SPINCTRL
7111         }
7112     }
7113 
7114     while ( hwnd && !win )
7115     {
7116         // this is a really ugly hack needed to avoid mistakenly returning the
7117         // parent frame wxWindow for the find/replace modeless dialog HWND -
7118         // this, in turn, is needed to call IsDialogMessage() from
7119         // wxApp::ProcessMessage() as for this we must return NULL from here
7120         //
7121         // FIXME: this is clearly not the best way to do it but I think we'll
7122         //        need to change HWND <-> wxWindow code more heavily than I can
7123         //        do it now to fix it
7124         if ( ::GetWindow(hwnd, GW_OWNER) )
7125         {
7126             // it's a dialog box, don't go upwards
7127             break;
7128         }
7129 
7130         hwnd = ::GetParent(hwnd);
7131         win = wxFindWinFromHandle(hwnd);
7132     }
7133 
7134     return win;
7135 }
7136 
7137 // Windows keyboard hook. Allows interception of e.g. F1, ESCAPE
7138 // in active frames and dialogs, regardless of where the focus is.
7139 static HHOOK wxTheKeyboardHook = 0;
7140 
7141 LRESULT APIENTRY
wxKeyboardHook(int nCode,WXWPARAM wParam,WXLPARAM lParam)7142 wxKeyboardHook(int nCode, WXWPARAM wParam, WXLPARAM lParam)
7143 {
7144     DWORD hiWord = HIWORD(lParam);
7145     if ( nCode != HC_NOREMOVE && ((hiWord & KF_UP) == 0) )
7146     {
7147         wchar_t uc = 0;
7148         int id = wxMSWKeyboard::VKToWX(wParam, lParam, &uc);
7149 
7150         // Don't intercept keyboard entry (notably Escape) if a modal window
7151         // (not managed by wx, e.g. IME one) is currently opened as more often
7152         // than not it needs all the keys for itself.
7153         //
7154         // Also don't catch it if a window currently captures the mouse as
7155         // Escape is normally used to release the mouse capture and if you
7156         // really need to catch all the keys in the window that has mouse
7157         // capture it can be easily done in its own EVT_CHAR handler as it is
7158         // certain to have focus while it has the capture.
7159         if ( !gs_modalEntryWindowCount && !::GetCapture() )
7160         {
7161             if ( id != WXK_NONE
7162 #if wxUSE_UNICODE
7163                     || static_cast<int>(uc) != WXK_NONE
7164 #endif // wxUSE_UNICODE
7165                     )
7166             {
7167                 wxWindow const* win = wxWindow::DoFindFocus();
7168                 if ( !win )
7169                 {
7170                     // Even if the focus got lost somehow, still send the event
7171                     // to the top level parent to allow a wxDialog to always
7172                     // close on Escape.
7173                     win = wxGetActiveWindow();
7174                 }
7175 
7176                 wxKeyEvent event(wxEVT_CHAR_HOOK);
7177                 MSWInitAnyKeyEvent(event, wParam, lParam, win);
7178 
7179                 event.m_keyCode = id;
7180 #if wxUSE_UNICODE
7181                 event.m_uniChar = uc;
7182 #endif // wxUSE_UNICODE
7183 
7184                 wxEvtHandler * const handler = win ? win->GetEventHandler()
7185                                                    : wxTheApp;
7186 
7187                 // Do not let exceptions propagate out of the hook, it's a
7188                 // module boundary.
7189                 if ( handler && handler->SafelyProcessEvent(event) )
7190                 {
7191                     if ( !event.IsNextEventAllowed() )
7192                     {
7193                         // Stop processing of this event.
7194                         return 1;
7195                     }
7196                 }
7197             }
7198         }
7199     }
7200 
7201     return (int)CallNextHookEx(wxTheKeyboardHook, nCode, wParam, lParam);
7202 }
7203 
wxSetKeyboardHook(bool doIt)7204 void wxSetKeyboardHook(bool doIt)
7205 {
7206     if ( doIt )
7207     {
7208         wxTheKeyboardHook = ::SetWindowsHookEx
7209                               (
7210                                 WH_KEYBOARD,
7211                                 wxKeyboardHook,
7212                                 NULL,   // must be NULL for process hook
7213                                 ::GetCurrentThreadId()
7214                               );
7215         if ( !wxTheKeyboardHook )
7216         {
7217             wxLogLastError(wxT("SetWindowsHookEx(wxKeyboardHook)"));
7218         }
7219     }
7220     else // uninstall
7221     {
7222         if ( wxTheKeyboardHook )
7223             ::UnhookWindowsHookEx(wxTheKeyboardHook);
7224     }
7225 }
7226 
7227 #if wxDEBUG_LEVEL >= 2
wxGetMessageName(int message)7228 const wxChar *wxGetMessageName(int message)
7229 {
7230     switch ( message )
7231     {
7232         case 0x0000: return wxT("WM_NULL");
7233         case 0x0001: return wxT("WM_CREATE");
7234         case 0x0002: return wxT("WM_DESTROY");
7235         case 0x0003: return wxT("WM_MOVE");
7236         case 0x0005: return wxT("WM_SIZE");
7237         case 0x0006: return wxT("WM_ACTIVATE");
7238         case 0x0007: return wxT("WM_SETFOCUS");
7239         case 0x0008: return wxT("WM_KILLFOCUS");
7240         case 0x000A: return wxT("WM_ENABLE");
7241         case 0x000B: return wxT("WM_SETREDRAW");
7242         case 0x000C: return wxT("WM_SETTEXT");
7243         case 0x000D: return wxT("WM_GETTEXT");
7244         case 0x000E: return wxT("WM_GETTEXTLENGTH");
7245         case 0x000F: return wxT("WM_PAINT");
7246         case 0x0010: return wxT("WM_CLOSE");
7247         case 0x0011: return wxT("WM_QUERYENDSESSION");
7248         case 0x0012: return wxT("WM_QUIT");
7249         case 0x0013: return wxT("WM_QUERYOPEN");
7250         case 0x0014: return wxT("WM_ERASEBKGND");
7251         case 0x0015: return wxT("WM_SYSCOLORCHANGE");
7252         case 0x0016: return wxT("WM_ENDSESSION");
7253         case 0x0017: return wxT("WM_SYSTEMERROR");
7254         case 0x0018: return wxT("WM_SHOWWINDOW");
7255         case 0x0019: return wxT("WM_CTLCOLOR");
7256         case 0x001A: return wxT("WM_WININICHANGE");
7257         case 0x001B: return wxT("WM_DEVMODECHANGE");
7258         case 0x001C: return wxT("WM_ACTIVATEAPP");
7259         case 0x001D: return wxT("WM_FONTCHANGE");
7260         case 0x001E: return wxT("WM_TIMECHANGE");
7261         case 0x001F: return wxT("WM_CANCELMODE");
7262         case 0x0020: return wxT("WM_SETCURSOR");
7263         case 0x0021: return wxT("WM_MOUSEACTIVATE");
7264         case 0x0022: return wxT("WM_CHILDACTIVATE");
7265         case 0x0023: return wxT("WM_QUEUESYNC");
7266         case 0x0024: return wxT("WM_GETMINMAXINFO");
7267         case 0x0026: return wxT("WM_PAINTICON");
7268         case 0x0027: return wxT("WM_ICONERASEBKGND");
7269         case 0x0028: return wxT("WM_NEXTDLGCTL");
7270         case 0x002A: return wxT("WM_SPOOLERSTATUS");
7271         case 0x002B: return wxT("WM_DRAWITEM");
7272         case 0x002C: return wxT("WM_MEASUREITEM");
7273         case 0x002D: return wxT("WM_DELETEITEM");
7274         case 0x002E: return wxT("WM_VKEYTOITEM");
7275         case 0x002F: return wxT("WM_CHARTOITEM");
7276         case 0x0030: return wxT("WM_SETFONT");
7277         case 0x0031: return wxT("WM_GETFONT");
7278         case 0x0037: return wxT("WM_QUERYDRAGICON");
7279         case 0x0039: return wxT("WM_COMPAREITEM");
7280         case 0x0041: return wxT("WM_COMPACTING");
7281         case 0x0044: return wxT("WM_COMMNOTIFY");
7282         case 0x0046: return wxT("WM_WINDOWPOSCHANGING");
7283         case 0x0047: return wxT("WM_WINDOWPOSCHANGED");
7284         case 0x0048: return wxT("WM_POWER");
7285 
7286         case 0x004A: return wxT("WM_COPYDATA");
7287         case 0x004B: return wxT("WM_CANCELJOURNAL");
7288         case 0x004E: return wxT("WM_NOTIFY");
7289         case 0x0050: return wxT("WM_INPUTLANGCHANGEREQUEST");
7290         case 0x0051: return wxT("WM_INPUTLANGCHANGE");
7291         case 0x0052: return wxT("WM_TCARD");
7292         case 0x0053: return wxT("WM_HELP");
7293         case 0x0054: return wxT("WM_USERCHANGED");
7294         case 0x0055: return wxT("WM_NOTIFYFORMAT");
7295         case 0x007B: return wxT("WM_CONTEXTMENU");
7296         case 0x007C: return wxT("WM_STYLECHANGING");
7297         case 0x007D: return wxT("WM_STYLECHANGED");
7298         case 0x007E: return wxT("WM_DISPLAYCHANGE");
7299         case 0x007F: return wxT("WM_GETICON");
7300         case 0x0080: return wxT("WM_SETICON");
7301 
7302         case 0x0081: return wxT("WM_NCCREATE");
7303         case 0x0082: return wxT("WM_NCDESTROY");
7304         case 0x0083: return wxT("WM_NCCALCSIZE");
7305         case 0x0084: return wxT("WM_NCHITTEST");
7306         case 0x0085: return wxT("WM_NCPAINT");
7307         case 0x0086: return wxT("WM_NCACTIVATE");
7308         case 0x0087: return wxT("WM_GETDLGCODE");
7309         case 0x00A0: return wxT("WM_NCMOUSEMOVE");
7310         case 0x00A1: return wxT("WM_NCLBUTTONDOWN");
7311         case 0x00A2: return wxT("WM_NCLBUTTONUP");
7312         case 0x00A3: return wxT("WM_NCLBUTTONDBLCLK");
7313         case 0x00A4: return wxT("WM_NCRBUTTONDOWN");
7314         case 0x00A5: return wxT("WM_NCRBUTTONUP");
7315         case 0x00A6: return wxT("WM_NCRBUTTONDBLCLK");
7316         case 0x00A7: return wxT("WM_NCMBUTTONDOWN");
7317         case 0x00A8: return wxT("WM_NCMBUTTONUP");
7318         case 0x00A9: return wxT("WM_NCMBUTTONDBLCLK");
7319 
7320         case 0x00B0: return wxT("EM_GETSEL");
7321         case 0x00B1: return wxT("EM_SETSEL");
7322         case 0x00B2: return wxT("EM_GETRECT");
7323         case 0x00B3: return wxT("EM_SETRECT");
7324         case 0x00B4: return wxT("EM_SETRECTNP");
7325         case 0x00B5: return wxT("EM_SCROLL");
7326         case 0x00B6: return wxT("EM_LINESCROLL");
7327         case 0x00B7: return wxT("EM_SCROLLCARET");
7328         case 0x00B8: return wxT("EM_GETMODIFY");
7329         case 0x00B9: return wxT("EM_SETMODIFY");
7330         case 0x00BA: return wxT("EM_GETLINECOUNT");
7331         case 0x00BB: return wxT("EM_LINEINDEX");
7332         case 0x00BC: return wxT("EM_SETHANDLE");
7333         case 0x00BD: return wxT("EM_GETHANDLE");
7334         case 0x00BE: return wxT("EM_GETTHUMB");
7335         case 0x00C1: return wxT("EM_LINELENGTH");
7336         case 0x00C2: return wxT("EM_REPLACESEL");
7337         case 0x00C4: return wxT("EM_GETLINE");
7338         case 0x00C5: return wxT("EM_LIMITTEXT/EM_SETLIMITTEXT"); /* ;win40 Name change */
7339         case 0x00C6: return wxT("EM_CANUNDO");
7340         case 0x00C7: return wxT("EM_UNDO");
7341         case 0x00C8: return wxT("EM_FMTLINES");
7342         case 0x00C9: return wxT("EM_LINEFROMCHAR");
7343         case 0x00CB: return wxT("EM_SETTABSTOPS");
7344         case 0x00CC: return wxT("EM_SETPASSWORDCHAR");
7345         case 0x00CD: return wxT("EM_EMPTYUNDOBUFFER");
7346         case 0x00CE: return wxT("EM_GETFIRSTVISIBLELINE");
7347         case 0x00CF: return wxT("EM_SETREADONLY");
7348         case 0x00D0: return wxT("EM_SETWORDBREAKPROC");
7349         case 0x00D1: return wxT("EM_GETWORDBREAKPROC");
7350         case 0x00D2: return wxT("EM_GETPASSWORDCHAR");
7351         case 0x00D3: return wxT("EM_SETMARGINS");
7352         case 0x00D4: return wxT("EM_GETMARGINS");
7353         case 0x00D5: return wxT("EM_GETLIMITTEXT");
7354         case 0x00D6: return wxT("EM_POSFROMCHAR");
7355         case 0x00D7: return wxT("EM_CHARFROMPOS");
7356         case 0x00D8: return wxT("EM_SETIMESTATUS");
7357         case 0x00D9: return wxT("EM_GETIMESTATUS");
7358 
7359         case 0x0100: return wxT("WM_KEYDOWN");
7360         case 0x0101: return wxT("WM_KEYUP");
7361         case 0x0102: return wxT("WM_CHAR");
7362         case 0x0103: return wxT("WM_DEADCHAR");
7363         case 0x0104: return wxT("WM_SYSKEYDOWN");
7364         case 0x0105: return wxT("WM_SYSKEYUP");
7365         case 0x0106: return wxT("WM_SYSCHAR");
7366         case 0x0107: return wxT("WM_SYSDEADCHAR");
7367         case 0x0108: return wxT("WM_KEYLAST");
7368 
7369         case 0x010D: return wxT("WM_IME_STARTCOMPOSITION");
7370         case 0x010E: return wxT("WM_IME_ENDCOMPOSITION");
7371         case 0x010F: return wxT("WM_IME_COMPOSITION");
7372 
7373         case 0x0110: return wxT("WM_INITDIALOG");
7374         case 0x0111: return wxT("WM_COMMAND");
7375         case 0x0112: return wxT("WM_SYSCOMMAND");
7376         case 0x0113: return wxT("WM_TIMER");
7377         case 0x0114: return wxT("WM_HSCROLL");
7378         case 0x0115: return wxT("WM_VSCROLL");
7379         case 0x0116: return wxT("WM_INITMENU");
7380         case 0x0117: return wxT("WM_INITMENUPOPUP");
7381         case 0x011F: return wxT("WM_MENUSELECT");
7382         case 0x0120: return wxT("WM_MENUCHAR");
7383         case 0x0121: return wxT("WM_ENTERIDLE");
7384 
7385         case 0x0127: return wxT("WM_CHANGEUISTATE");
7386         case 0x0128: return wxT("WM_UPDATEUISTATE");
7387         case 0x0129: return wxT("WM_QUERYUISTATE");
7388 
7389         case 0x0132: return wxT("WM_CTLCOLORMSGBOX");
7390         case 0x0133: return wxT("WM_CTLCOLOREDIT");
7391         case 0x0134: return wxT("WM_CTLCOLORLISTBOX");
7392         case 0x0135: return wxT("WM_CTLCOLORBTN");
7393         case 0x0136: return wxT("WM_CTLCOLORDLG");
7394         case 0x0137: return wxT("WM_CTLCOLORSCROLLBAR");
7395         case 0x0138: return wxT("WM_CTLCOLORSTATIC");
7396         case 0x01E1: return wxT("MN_GETHMENU");
7397 
7398         case 0x0200: return wxT("WM_MOUSEMOVE");
7399         case 0x0201: return wxT("WM_LBUTTONDOWN");
7400         case 0x0202: return wxT("WM_LBUTTONUP");
7401         case 0x0203: return wxT("WM_LBUTTONDBLCLK");
7402         case 0x0204: return wxT("WM_RBUTTONDOWN");
7403         case 0x0205: return wxT("WM_RBUTTONUP");
7404         case 0x0206: return wxT("WM_RBUTTONDBLCLK");
7405         case 0x0207: return wxT("WM_MBUTTONDOWN");
7406         case 0x0208: return wxT("WM_MBUTTONUP");
7407         case 0x0209: return wxT("WM_MBUTTONDBLCLK");
7408         case 0x020A: return wxT("WM_MOUSEWHEEL");
7409         case 0x020B: return wxT("WM_XBUTTONDOWN");
7410         case 0x020C: return wxT("WM_XBUTTONUP");
7411         case 0x020D: return wxT("WM_XBUTTONDBLCLK");
7412         case 0x0210: return wxT("WM_PARENTNOTIFY");
7413         case 0x0211: return wxT("WM_ENTERMENULOOP");
7414         case 0x0212: return wxT("WM_EXITMENULOOP");
7415 
7416         case 0x0213: return wxT("WM_NEXTMENU");
7417         case 0x0214: return wxT("WM_SIZING");
7418         case 0x0215: return wxT("WM_CAPTURECHANGED");
7419         case 0x0216: return wxT("WM_MOVING");
7420         case 0x0218: return wxT("WM_POWERBROADCAST");
7421         case 0x0219: return wxT("WM_DEVICECHANGE");
7422 
7423         case 0x0220: return wxT("WM_MDICREATE");
7424         case 0x0221: return wxT("WM_MDIDESTROY");
7425         case 0x0222: return wxT("WM_MDIACTIVATE");
7426         case 0x0223: return wxT("WM_MDIRESTORE");
7427         case 0x0224: return wxT("WM_MDINEXT");
7428         case 0x0225: return wxT("WM_MDIMAXIMIZE");
7429         case 0x0226: return wxT("WM_MDITILE");
7430         case 0x0227: return wxT("WM_MDICASCADE");
7431         case 0x0228: return wxT("WM_MDIICONARRANGE");
7432         case 0x0229: return wxT("WM_MDIGETACTIVE");
7433         case 0x0230: return wxT("WM_MDISETMENU");
7434         case 0x0233: return wxT("WM_DROPFILES");
7435 
7436         case 0x0281: return wxT("WM_IME_SETCONTEXT");
7437         case 0x0282: return wxT("WM_IME_NOTIFY");
7438         case 0x0283: return wxT("WM_IME_CONTROL");
7439         case 0x0284: return wxT("WM_IME_COMPOSITIONFULL");
7440         case 0x0285: return wxT("WM_IME_SELECT");
7441         case 0x0286: return wxT("WM_IME_CHAR");
7442         case 0x0290: return wxT("WM_IME_KEYDOWN");
7443         case 0x0291: return wxT("WM_IME_KEYUP");
7444 
7445         case 0x02A0: return wxT("WM_NCMOUSEHOVER");
7446         case 0x02A1: return wxT("WM_MOUSEHOVER");
7447         case 0x02A2: return wxT("WM_NCMOUSELEAVE");
7448         case 0x02A3: return wxT("WM_MOUSELEAVE");
7449 
7450         case 0x0300: return wxT("WM_CUT");
7451         case 0x0301: return wxT("WM_COPY");
7452         case 0x0302: return wxT("WM_PASTE");
7453         case 0x0303: return wxT("WM_CLEAR");
7454         case 0x0304: return wxT("WM_UNDO");
7455         case 0x0305: return wxT("WM_RENDERFORMAT");
7456         case 0x0306: return wxT("WM_RENDERALLFORMATS");
7457         case 0x0307: return wxT("WM_DESTROYCLIPBOARD");
7458         case 0x0308: return wxT("WM_DRAWCLIPBOARD");
7459         case 0x0309: return wxT("WM_PAINTCLIPBOARD");
7460         case 0x030A: return wxT("WM_VSCROLLCLIPBOARD");
7461         case 0x030B: return wxT("WM_SIZECLIPBOARD");
7462         case 0x030C: return wxT("WM_ASKCBFORMATNAME");
7463         case 0x030D: return wxT("WM_CHANGECBCHAIN");
7464         case 0x030E: return wxT("WM_HSCROLLCLIPBOARD");
7465         case 0x030F: return wxT("WM_QUERYNEWPALETTE");
7466         case 0x0310: return wxT("WM_PALETTEISCHANGING");
7467         case 0x0311: return wxT("WM_PALETTECHANGED");
7468         case 0x0312: return wxT("WM_HOTKEY");
7469 
7470         case 0x0317: return wxT("WM_PRINT");
7471         case 0x0318: return wxT("WM_PRINTCLIENT");
7472 
7473         // common controls messages - although they're not strictly speaking
7474         // standard, it's nice to decode them nevertheless
7475 
7476         // listview
7477         case 0x1000 + 0: return wxT("LVM_GETBKCOLOR");
7478         case 0x1000 + 1: return wxT("LVM_SETBKCOLOR");
7479         case 0x1000 + 2: return wxT("LVM_GETIMAGELIST");
7480         case 0x1000 + 3: return wxT("LVM_SETIMAGELIST");
7481         case 0x1000 + 4: return wxT("LVM_GETITEMCOUNT");
7482         case 0x1000 + 5: return wxT("LVM_GETITEMA");
7483         case 0x1000 + 75: return wxT("LVM_GETITEMW");
7484         case 0x1000 + 6: return wxT("LVM_SETITEMA");
7485         case 0x1000 + 76: return wxT("LVM_SETITEMW");
7486         case 0x1000 + 7: return wxT("LVM_INSERTITEMA");
7487         case 0x1000 + 77: return wxT("LVM_INSERTITEMW");
7488         case 0x1000 + 8: return wxT("LVM_DELETEITEM");
7489         case 0x1000 + 9: return wxT("LVM_DELETEALLITEMS");
7490         case 0x1000 + 10: return wxT("LVM_GETCALLBACKMASK");
7491         case 0x1000 + 11: return wxT("LVM_SETCALLBACKMASK");
7492         case 0x1000 + 12: return wxT("LVM_GETNEXTITEM");
7493         case 0x1000 + 13: return wxT("LVM_FINDITEMA");
7494         case 0x1000 + 83: return wxT("LVM_FINDITEMW");
7495         case 0x1000 + 14: return wxT("LVM_GETITEMRECT");
7496         case 0x1000 + 15: return wxT("LVM_SETITEMPOSITION");
7497         case 0x1000 + 16: return wxT("LVM_GETITEMPOSITION");
7498         case 0x1000 + 17: return wxT("LVM_GETSTRINGWIDTHA");
7499         case 0x1000 + 87: return wxT("LVM_GETSTRINGWIDTHW");
7500         case 0x1000 + 18: return wxT("LVM_HITTEST");
7501         case 0x1000 + 19: return wxT("LVM_ENSUREVISIBLE");
7502         case 0x1000 + 20: return wxT("LVM_SCROLL");
7503         case 0x1000 + 21: return wxT("LVM_REDRAWITEMS");
7504         case 0x1000 + 22: return wxT("LVM_ARRANGE");
7505         case 0x1000 + 23: return wxT("LVM_EDITLABELA");
7506         case 0x1000 + 118: return wxT("LVM_EDITLABELW");
7507         case 0x1000 + 24: return wxT("LVM_GETEDITCONTROL");
7508         case 0x1000 + 25: return wxT("LVM_GETCOLUMNA");
7509         case 0x1000 + 95: return wxT("LVM_GETCOLUMNW");
7510         case 0x1000 + 26: return wxT("LVM_SETCOLUMNA");
7511         case 0x1000 + 96: return wxT("LVM_SETCOLUMNW");
7512         case 0x1000 + 27: return wxT("LVM_INSERTCOLUMNA");
7513         case 0x1000 + 97: return wxT("LVM_INSERTCOLUMNW");
7514         case 0x1000 + 28: return wxT("LVM_DELETECOLUMN");
7515         case 0x1000 + 29: return wxT("LVM_GETCOLUMNWIDTH");
7516         case 0x1000 + 30: return wxT("LVM_SETCOLUMNWIDTH");
7517         case 0x1000 + 31: return wxT("LVM_GETHEADER");
7518         case 0x1000 + 33: return wxT("LVM_CREATEDRAGIMAGE");
7519         case 0x1000 + 34: return wxT("LVM_GETVIEWRECT");
7520         case 0x1000 + 35: return wxT("LVM_GETTEXTCOLOR");
7521         case 0x1000 + 36: return wxT("LVM_SETTEXTCOLOR");
7522         case 0x1000 + 37: return wxT("LVM_GETTEXTBKCOLOR");
7523         case 0x1000 + 38: return wxT("LVM_SETTEXTBKCOLOR");
7524         case 0x1000 + 39: return wxT("LVM_GETTOPINDEX");
7525         case 0x1000 + 40: return wxT("LVM_GETCOUNTPERPAGE");
7526         case 0x1000 + 41: return wxT("LVM_GETORIGIN");
7527         case 0x1000 + 42: return wxT("LVM_UPDATE");
7528         case 0x1000 + 43: return wxT("LVM_SETITEMSTATE");
7529         case 0x1000 + 44: return wxT("LVM_GETITEMSTATE");
7530         case 0x1000 + 45: return wxT("LVM_GETITEMTEXTA");
7531         case 0x1000 + 115: return wxT("LVM_GETITEMTEXTW");
7532         case 0x1000 + 46: return wxT("LVM_SETITEMTEXTA");
7533         case 0x1000 + 116: return wxT("LVM_SETITEMTEXTW");
7534         case 0x1000 + 47: return wxT("LVM_SETITEMCOUNT");
7535         case 0x1000 + 48: return wxT("LVM_SORTITEMS");
7536         case 0x1000 + 49: return wxT("LVM_SETITEMPOSITION32");
7537         case 0x1000 + 50: return wxT("LVM_GETSELECTEDCOUNT");
7538         case 0x1000 + 51: return wxT("LVM_GETITEMSPACING");
7539         case 0x1000 + 52: return wxT("LVM_GETISEARCHSTRINGA");
7540         case 0x1000 + 117: return wxT("LVM_GETISEARCHSTRINGW");
7541         case 0x1000 + 53: return wxT("LVM_SETICONSPACING");
7542         case 0x1000 + 54: return wxT("LVM_SETEXTENDEDLISTVIEWSTYLE");
7543         case 0x1000 + 55: return wxT("LVM_GETEXTENDEDLISTVIEWSTYLE");
7544         case 0x1000 + 56: return wxT("LVM_GETSUBITEMRECT");
7545         case 0x1000 + 57: return wxT("LVM_SUBITEMHITTEST");
7546         case 0x1000 + 58: return wxT("LVM_SETCOLUMNORDERARRAY");
7547         case 0x1000 + 59: return wxT("LVM_GETCOLUMNORDERARRAY");
7548         case 0x1000 + 60: return wxT("LVM_SETHOTITEM");
7549         case 0x1000 + 61: return wxT("LVM_GETHOTITEM");
7550         case 0x1000 + 62: return wxT("LVM_SETHOTCURSOR");
7551         case 0x1000 + 63: return wxT("LVM_GETHOTCURSOR");
7552         case 0x1000 + 64: return wxT("LVM_APPROXIMATEVIEWRECT");
7553         case 0x1000 + 65: return wxT("LVM_SETWORKAREA");
7554 
7555         // tree view
7556         case 0x1100 + 0: return wxT("TVM_INSERTITEMA");
7557         case 0x1100 + 50: return wxT("TVM_INSERTITEMW");
7558         case 0x1100 + 1: return wxT("TVM_DELETEITEM");
7559         case 0x1100 + 2: return wxT("TVM_EXPAND");
7560         case 0x1100 + 4: return wxT("TVM_GETITEMRECT");
7561         case 0x1100 + 5: return wxT("TVM_GETCOUNT");
7562         case 0x1100 + 6: return wxT("TVM_GETINDENT");
7563         case 0x1100 + 7: return wxT("TVM_SETINDENT");
7564         case 0x1100 + 8: return wxT("TVM_GETIMAGELIST");
7565         case 0x1100 + 9: return wxT("TVM_SETIMAGELIST");
7566         case 0x1100 + 10: return wxT("TVM_GETNEXTITEM");
7567         case 0x1100 + 11: return wxT("TVM_SELECTITEM");
7568         case 0x1100 + 12: return wxT("TVM_GETITEMA");
7569         case 0x1100 + 62: return wxT("TVM_GETITEMW");
7570         case 0x1100 + 13: return wxT("TVM_SETITEMA");
7571         case 0x1100 + 63: return wxT("TVM_SETITEMW");
7572         case 0x1100 + 14: return wxT("TVM_EDITLABELA");
7573         case 0x1100 + 65: return wxT("TVM_EDITLABELW");
7574         case 0x1100 + 15: return wxT("TVM_GETEDITCONTROL");
7575         case 0x1100 + 16: return wxT("TVM_GETVISIBLECOUNT");
7576         case 0x1100 + 17: return wxT("TVM_HITTEST");
7577         case 0x1100 + 18: return wxT("TVM_CREATEDRAGIMAGE");
7578         case 0x1100 + 19: return wxT("TVM_SORTCHILDREN");
7579         case 0x1100 + 20: return wxT("TVM_ENSUREVISIBLE");
7580         case 0x1100 + 21: return wxT("TVM_SORTCHILDRENCB");
7581         case 0x1100 + 22: return wxT("TVM_ENDEDITLABELNOW");
7582         case 0x1100 + 23: return wxT("TVM_GETISEARCHSTRINGA");
7583         case 0x1100 + 64: return wxT("TVM_GETISEARCHSTRINGW");
7584         case 0x1100 + 24: return wxT("TVM_SETTOOLTIPS");
7585         case 0x1100 + 25: return wxT("TVM_GETTOOLTIPS");
7586 
7587         // header
7588         case 0x1200 + 0: return wxT("HDM_GETITEMCOUNT");
7589         case 0x1200 + 1: return wxT("HDM_INSERTITEMA");
7590         case 0x1200 + 10: return wxT("HDM_INSERTITEMW");
7591         case 0x1200 + 2: return wxT("HDM_DELETEITEM");
7592         case 0x1200 + 3: return wxT("HDM_GETITEMA");
7593         case 0x1200 + 11: return wxT("HDM_GETITEMW");
7594         case 0x1200 + 4: return wxT("HDM_SETITEMA");
7595         case 0x1200 + 12: return wxT("HDM_SETITEMW");
7596         case 0x1200 + 5: return wxT("HDM_LAYOUT");
7597         case 0x1200 + 6: return wxT("HDM_HITTEST");
7598         case 0x1200 + 7: return wxT("HDM_GETITEMRECT");
7599         case 0x1200 + 8: return wxT("HDM_SETIMAGELIST");
7600         case 0x1200 + 9: return wxT("HDM_GETIMAGELIST");
7601         case 0x1200 + 15: return wxT("HDM_ORDERTOINDEX");
7602         case 0x1200 + 16: return wxT("HDM_CREATEDRAGIMAGE");
7603         case 0x1200 + 17: return wxT("HDM_GETORDERARRAY");
7604         case 0x1200 + 18: return wxT("HDM_SETORDERARRAY");
7605         case 0x1200 + 19: return wxT("HDM_SETHOTDIVIDER");
7606 
7607         // tab control
7608         case 0x1300 + 2: return wxT("TCM_GETIMAGELIST");
7609         case 0x1300 + 3: return wxT("TCM_SETIMAGELIST");
7610         case 0x1300 + 4: return wxT("TCM_GETITEMCOUNT");
7611         case 0x1300 + 5: return wxT("TCM_GETITEMA");
7612         case 0x1300 + 60: return wxT("TCM_GETITEMW");
7613         case 0x1300 + 6: return wxT("TCM_SETITEMA");
7614         case 0x1300 + 61: return wxT("TCM_SETITEMW");
7615         case 0x1300 + 7: return wxT("TCM_INSERTITEMA");
7616         case 0x1300 + 62: return wxT("TCM_INSERTITEMW");
7617         case 0x1300 + 8: return wxT("TCM_DELETEITEM");
7618         case 0x1300 + 9: return wxT("TCM_DELETEALLITEMS");
7619         case 0x1300 + 10: return wxT("TCM_GETITEMRECT");
7620         case 0x1300 + 11: return wxT("TCM_GETCURSEL");
7621         case 0x1300 + 12: return wxT("TCM_SETCURSEL");
7622         case 0x1300 + 13: return wxT("TCM_HITTEST");
7623         case 0x1300 + 14: return wxT("TCM_SETITEMEXTRA");
7624         case 0x1300 + 40: return wxT("TCM_ADJUSTRECT");
7625         case 0x1300 + 41: return wxT("TCM_SETITEMSIZE");
7626         case 0x1300 + 42: return wxT("TCM_REMOVEIMAGE");
7627         case 0x1300 + 43: return wxT("TCM_SETPADDING");
7628         case 0x1300 + 44: return wxT("TCM_GETROWCOUNT");
7629         case 0x1300 + 45: return wxT("TCM_GETTOOLTIPS");
7630         case 0x1300 + 46: return wxT("TCM_SETTOOLTIPS");
7631         case 0x1300 + 47: return wxT("TCM_GETCURFOCUS");
7632         case 0x1300 + 48: return wxT("TCM_SETCURFOCUS");
7633         case 0x1300 + 49: return wxT("TCM_SETMINTABWIDTH");
7634         case 0x1300 + 50: return wxT("TCM_DESELECTALL");
7635 
7636         // toolbar
7637         case WM_USER+1: return wxT("TB_ENABLEBUTTON");
7638         case WM_USER+2: return wxT("TB_CHECKBUTTON");
7639         case WM_USER+3: return wxT("TB_PRESSBUTTON");
7640         case WM_USER+4: return wxT("TB_HIDEBUTTON");
7641         case WM_USER+5: return wxT("TB_INDETERMINATE");
7642         case WM_USER+9: return wxT("TB_ISBUTTONENABLED");
7643         case WM_USER+10: return wxT("TB_ISBUTTONCHECKED");
7644         case WM_USER+11: return wxT("TB_ISBUTTONPRESSED");
7645         case WM_USER+12: return wxT("TB_ISBUTTONHIDDEN");
7646         case WM_USER+13: return wxT("TB_ISBUTTONINDETERMINATE");
7647         case WM_USER+17: return wxT("TB_SETSTATE");
7648         case WM_USER+18: return wxT("TB_GETSTATE");
7649         case WM_USER+19: return wxT("TB_ADDBITMAP");
7650         case WM_USER+20: return wxT("TB_ADDBUTTONS");
7651         case WM_USER+21: return wxT("TB_INSERTBUTTON");
7652         case WM_USER+22: return wxT("TB_DELETEBUTTON");
7653         case WM_USER+23: return wxT("TB_GETBUTTON");
7654         case WM_USER+24: return wxT("TB_BUTTONCOUNT");
7655         case WM_USER+25: return wxT("TB_COMMANDTOINDEX");
7656         case WM_USER+26: return wxT("TB_SAVERESTOREA");
7657         case WM_USER+76: return wxT("TB_SAVERESTOREW");
7658         case WM_USER+27: return wxT("TB_CUSTOMIZE");
7659         case WM_USER+28: return wxT("TB_ADDSTRINGA");
7660         case WM_USER+77: return wxT("TB_ADDSTRINGW");
7661         case WM_USER+29: return wxT("TB_GETITEMRECT");
7662         case WM_USER+30: return wxT("TB_BUTTONSTRUCTSIZE");
7663         case WM_USER+31: return wxT("TB_SETBUTTONSIZE");
7664         case WM_USER+32: return wxT("TB_SETBITMAPSIZE");
7665         case WM_USER+33: return wxT("TB_AUTOSIZE");
7666         case WM_USER+35: return wxT("TB_GETTOOLTIPS");
7667         case WM_USER+36: return wxT("TB_SETTOOLTIPS");
7668         case WM_USER+37: return wxT("TB_SETPARENT");
7669         case WM_USER+39: return wxT("TB_SETROWS");
7670         case WM_USER+40: return wxT("TB_GETROWS");
7671         case WM_USER+42: return wxT("TB_SETCMDID");
7672         case WM_USER+43: return wxT("TB_CHANGEBITMAP");
7673         case WM_USER+44: return wxT("TB_GETBITMAP");
7674         case WM_USER+45: return wxT("TB_GETBUTTONTEXTA");
7675         case WM_USER+75: return wxT("TB_GETBUTTONTEXTW");
7676         case WM_USER+46: return wxT("TB_REPLACEBITMAP");
7677         case WM_USER+47: return wxT("TB_SETINDENT");
7678         case WM_USER+48: return wxT("TB_SETIMAGELIST");
7679         case WM_USER+49: return wxT("TB_GETIMAGELIST");
7680         case WM_USER+50: return wxT("TB_LOADIMAGES");
7681         case WM_USER+51: return wxT("TB_GETRECT");
7682         case WM_USER+52: return wxT("TB_SETHOTIMAGELIST");
7683         case WM_USER+53: return wxT("TB_GETHOTIMAGELIST");
7684         case WM_USER+54: return wxT("TB_SETDISABLEDIMAGELIST");
7685         case WM_USER+55: return wxT("TB_GETDISABLEDIMAGELIST");
7686         case WM_USER+56: return wxT("TB_SETSTYLE");
7687         case WM_USER+57: return wxT("TB_GETSTYLE");
7688         case WM_USER+58: return wxT("TB_GETBUTTONSIZE");
7689         case WM_USER+59: return wxT("TB_SETBUTTONWIDTH");
7690         case WM_USER+60: return wxT("TB_SETMAXTEXTROWS");
7691         case WM_USER+61: return wxT("TB_GETTEXTROWS");
7692         case WM_USER+41: return wxT("TB_GETBITMAPFLAGS");
7693 
7694         default:
7695             static wxString s_szBuf;
7696             s_szBuf.Printf(wxT("<unknown message = %d>"), message);
7697             return s_szBuf.c_str();
7698     }
7699 }
7700 #endif // wxDEBUG_LEVEL >= 2
7701 
wxGetTextMetrics(const wxWindowMSW * win)7702 static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win)
7703 {
7704     // prepare the DC
7705     TEXTMETRIC tm;
7706     HWND hwnd = GetHwndOf(win);
7707     HDC hdc = ::GetDC(hwnd);
7708 
7709 #if !wxDIALOG_UNIT_COMPATIBILITY
7710     // and select the current font into it
7711 
7712     // Note that it's important to extend the lifetime of the possibly
7713     // temporary wxFont returned by GetFont() to ensure that its HFONT remains
7714     // valid.
7715     const wxFont& f(win->GetFont());
7716     HFONT hfont = GetHfontOf(f);
7717     if ( hfont )
7718     {
7719         hfont = (HFONT)::SelectObject(hdc, hfont);
7720     }
7721 #endif
7722 
7723     // finally retrieve the text metrics from it
7724     GetTextMetrics(hdc, &tm);
7725 
7726 #if !wxDIALOG_UNIT_COMPATIBILITY
7727     // and clean up
7728     if ( hfont )
7729     {
7730         (void)::SelectObject(hdc, hfont);
7731     }
7732 #endif
7733 
7734     ::ReleaseDC(hwnd, hdc);
7735 
7736     return tm;
7737 }
7738 
7739 // Find the wxWindow at the current mouse position, returning the mouse
7740 // position.
wxFindWindowAtPointer(wxPoint & pt)7741 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
7742 {
7743     pt = wxGetMousePosition();
7744     return wxFindWindowAtPoint(pt);
7745 }
7746 
wxFindWindowAtPoint(const wxPoint & pt)7747 wxWindow* wxFindWindowAtPoint(const wxPoint& pt)
7748 {
7749     POINT pt2;
7750     pt2.x = pt.x;
7751     pt2.y = pt.y;
7752 
7753     HWND hWnd = ::WindowFromPoint(pt2);
7754     if ( hWnd )
7755     {
7756         // WindowFromPoint() ignores the disabled children but we're supposed
7757         // to take them into account, so check if we have a child at this
7758         // coordinate using ChildWindowFromPointEx().
7759         for ( ;; )
7760         {
7761             pt2.x = pt.x;
7762             pt2.y = pt.y;
7763             ::ScreenToClient(hWnd, &pt2);
7764             HWND child = ::ChildWindowFromPointEx(hWnd, pt2, CWP_SKIPINVISIBLE);
7765             if ( child == hWnd || !child )
7766                 break;
7767 
7768             // ChildWindowFromPointEx() only examines the immediate children
7769             // but we want to get the deepest (top in Z-order) one, so continue
7770             // iterating for as long as it finds anything.
7771             hWnd = child;
7772         }
7773     }
7774 
7775     return wxGetWindowFromHWND((WXHWND)hWnd);
7776 }
7777 
7778 // Get the current mouse position.
wxGetMousePosition()7779 wxPoint wxGetMousePosition()
7780 {
7781     POINT pt;
7782     wxGetCursorPosMSW(&pt);
7783 
7784     return wxPoint(pt.x, pt.y);
7785 }
7786 
7787 #if wxUSE_HOTKEY
7788 
RegisterHotKey(int hotkeyId,int modifiers,int keycode)7789 bool wxWindowMSW::RegisterHotKey(int hotkeyId, int modifiers, int keycode)
7790 {
7791     UINT win_modifiers=0;
7792     if ( modifiers & wxMOD_ALT )
7793         win_modifiers |= MOD_ALT;
7794     if ( modifiers & wxMOD_SHIFT )
7795         win_modifiers |= MOD_SHIFT;
7796     if ( modifiers & wxMOD_CONTROL )
7797         win_modifiers |= MOD_CONTROL;
7798     if ( modifiers & wxMOD_WIN )
7799         win_modifiers |= MOD_WIN;
7800 
7801     // Special compatibility hack: the initial version of this function didn't
7802     // use wxMSWKeyboard::WXToVK() at all, which was wrong as the user code is
7803     // expected to use WXK_XXX constants and not VK_XXX ones, but as people had
7804     // no choice but to use the latter with the previous version of wxWidgets,
7805     // now we have to continue accepting VK_XXX here too. So we assume that the
7806     // argument is a VK constant and not a WXK one if it looks like this should
7807     // be the case based on its value. It helps that all of WXK constants
7808     // before WXK_START have the same value as the corresponding VK constants,
7809     // with the only exception of WXK_DELETE which is equal to VK_F16 -- and we
7810     // consider that the latter is unlikely to be used.
7811     if ( keycode >= WXK_START || keycode == WXK_DELETE )
7812         keycode = wxMSWKeyboard::WXToVK(keycode);
7813     //else: leave it unchanged because it looks like it's a VK constant (which
7814     //      includes ASCII digits and upper case letters)
7815 
7816     if ( !::RegisterHotKey(GetHwnd(), hotkeyId, win_modifiers, keycode) )
7817     {
7818         wxLogLastError(wxT("RegisterHotKey"));
7819 
7820         return false;
7821     }
7822 
7823     return true;
7824 }
7825 
UnregisterHotKey(int hotkeyId)7826 bool wxWindowMSW::UnregisterHotKey(int hotkeyId)
7827 {
7828     if ( !::UnregisterHotKey(GetHwnd(), hotkeyId) )
7829     {
7830         wxLogLastError(wxT("UnregisterHotKey"));
7831 
7832         return false;
7833     }
7834 
7835     return true;
7836 }
7837 
HandleHotKey(WXWPARAM wParam,WXLPARAM lParam)7838 bool wxWindowMSW::HandleHotKey(WXWPARAM wParam, WXLPARAM lParam)
7839 {
7840     int win_modifiers = LOWORD(lParam);
7841 
7842     wxKeyEvent event(CreateKeyEvent(wxEVT_HOTKEY, HIWORD(lParam)));
7843     event.SetId(wParam);
7844     event.m_shiftDown = (win_modifiers & MOD_SHIFT) != 0;
7845     event.m_controlDown = (win_modifiers & MOD_CONTROL) != 0;
7846     event.m_altDown = (win_modifiers & MOD_ALT) != 0;
7847     event.m_metaDown = (win_modifiers & MOD_WIN) != 0;
7848 
7849     return HandleWindowEvent(event);
7850 }
7851 
7852 #endif // wxUSE_HOTKEY
7853 
7854 // this class installs a message hook which really wakes up our idle processing
7855 // each time a message is handled, even if we're sitting inside a local modal
7856 // loop (e.g. a menu is opened or scrollbar is being dragged or even inside
7857 // ::MessageBox()) and so don't control message dispatching otherwise
7858 class wxIdleWakeUpModule : public wxModule
7859 {
7860 public:
OnInit()7861     virtual bool OnInit() wxOVERRIDE
7862     {
7863         ms_hMsgHookProc = ::SetWindowsHookEx
7864                             (
7865                              WH_GETMESSAGE,
7866                              &wxIdleWakeUpModule::MsgHookProc,
7867                              NULL,
7868                              GetCurrentThreadId()
7869                             );
7870 
7871         if ( !ms_hMsgHookProc )
7872         {
7873             wxLogLastError(wxT("SetWindowsHookEx(WH_GETMESSAGE)"));
7874 
7875             return false;
7876         }
7877 
7878         return true;
7879     }
7880 
OnExit()7881     virtual void OnExit() wxOVERRIDE
7882     {
7883         ::UnhookWindowsHookEx(wxIdleWakeUpModule::ms_hMsgHookProc);
7884     }
7885 
MsgHookProc(int nCode,WPARAM wParam,LPARAM lParam)7886     static LRESULT CALLBACK MsgHookProc(int nCode, WPARAM wParam, LPARAM lParam)
7887     {
7888         // Don't process idle events unless the message is going to be really
7889         // handled, i.e. removed from the queue, as it seems wrong to do it
7890         // just because someone called PeekMessage(PM_NOREMOVE).
7891         if ( wParam == PM_REMOVE )
7892             wxTheApp->MSWProcessPendingEventsIfNeeded();
7893 
7894         return CallNextHookEx(ms_hMsgHookProc, nCode, wParam, lParam);
7895     }
7896 
7897 private:
7898     static HHOOK ms_hMsgHookProc;
7899 
7900     wxDECLARE_DYNAMIC_CLASS(wxIdleWakeUpModule);
7901 };
7902 
7903 HHOOK wxIdleWakeUpModule::ms_hMsgHookProc = 0;
7904 
7905 wxIMPLEMENT_DYNAMIC_CLASS(wxIdleWakeUpModule, wxModule);
7906