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