]> git.saurik.com Git - wxWidgets.git/blob - src/msw/window.cpp
Expose the Apple menu so it can be setup manually.
[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 state == WA_CLICKACTIVE
4054 ? wxActivateEvent::Reason_Mouse
4055 : wxActivateEvent::Reason_Unknown);
4056 event.SetEventObject(this);
4057
4058 return HandleWindowEvent(event);
4059 }
4060
4061 bool wxWindowMSW::HandleSetFocus(WXHWND hwnd)
4062 {
4063 // Strangly enough, some controls get set focus events when they are being
4064 // deleted, even if they already had focus before.
4065 if ( m_isBeingDeleted )
4066 {
4067 return false;
4068 }
4069
4070 // notify the parent keeping track of focus for the kbd navigation
4071 // purposes that we got it
4072 wxChildFocusEvent eventFocus((wxWindow *)this);
4073 (void)HandleWindowEvent(eventFocus);
4074
4075 #if wxUSE_CARET
4076 // Deal with caret
4077 if ( m_caret )
4078 {
4079 m_caret->OnSetFocus();
4080 }
4081 #endif // wxUSE_CARET
4082
4083 wxFocusEvent event(wxEVT_SET_FOCUS, m_windowId);
4084 event.SetEventObject(this);
4085
4086 // wxFindWinFromHandle() may return NULL, it is ok
4087 event.SetWindow(wxFindWinFromHandle(hwnd));
4088
4089 return HandleWindowEvent(event);
4090 }
4091
4092 bool wxWindowMSW::HandleKillFocus(WXHWND hwnd)
4093 {
4094 #if wxUSE_CARET
4095 // Deal with caret
4096 if ( m_caret )
4097 {
4098 m_caret->OnKillFocus();
4099 }
4100 #endif // wxUSE_CARET
4101
4102 // Don't send the event when in the process of being deleted. This can
4103 // only cause problems if the event handler tries to access the object.
4104 if ( m_isBeingDeleted )
4105 {
4106 return false;
4107 }
4108
4109 wxFocusEvent event(wxEVT_KILL_FOCUS, m_windowId);
4110 event.SetEventObject(this);
4111
4112 // wxFindWinFromHandle() may return NULL, it is ok
4113 event.SetWindow(wxFindWinFromHandle(hwnd));
4114
4115 return HandleWindowEvent(event);
4116 }
4117
4118 // ---------------------------------------------------------------------------
4119 // labels
4120 // ---------------------------------------------------------------------------
4121
4122 void wxWindowMSW::SetLabel( const wxString& label)
4123 {
4124 SetWindowText(GetHwnd(), label.c_str());
4125 }
4126
4127 wxString wxWindowMSW::GetLabel() const
4128 {
4129 return wxGetWindowText(GetHWND());
4130 }
4131
4132 // ---------------------------------------------------------------------------
4133 // miscellaneous
4134 // ---------------------------------------------------------------------------
4135
4136 bool wxWindowMSW::HandleShow(bool show, int WXUNUSED(status))
4137 {
4138 wxShowEvent event(GetId(), show);
4139 event.SetEventObject(this);
4140
4141 return HandleWindowEvent(event);
4142 }
4143
4144 bool wxWindowMSW::HandleInitDialog(WXHWND WXUNUSED(hWndFocus))
4145 {
4146 wxInitDialogEvent event(GetId());
4147 event.SetEventObject(this);
4148
4149 return HandleWindowEvent(event);
4150 }
4151
4152 bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam)
4153 {
4154 #if defined (__WXMICROWIN__) || defined(__WXWINCE__)
4155 wxUnusedVar(wParam);
4156 return false;
4157 #else // __WXMICROWIN__
4158 HDROP hFilesInfo = (HDROP) wParam;
4159
4160 // Get the total number of files dropped
4161 UINT gwFilesDropped = ::DragQueryFile
4162 (
4163 (HDROP)hFilesInfo,
4164 (UINT)-1,
4165 (LPTSTR)0,
4166 (UINT)0
4167 );
4168
4169 wxString *files = new wxString[gwFilesDropped];
4170 for ( UINT wIndex = 0; wIndex < gwFilesDropped; wIndex++ )
4171 {
4172 // first get the needed buffer length (+1 for terminating NUL)
4173 size_t len = ::DragQueryFile(hFilesInfo, wIndex, NULL, 0) + 1;
4174
4175 // and now get the file name
4176 ::DragQueryFile(hFilesInfo, wIndex,
4177 wxStringBuffer(files[wIndex], len), len);
4178 }
4179
4180 wxDropFilesEvent event(wxEVT_DROP_FILES, gwFilesDropped, files);
4181 event.SetEventObject(this);
4182
4183 POINT dropPoint;
4184 DragQueryPoint(hFilesInfo, (LPPOINT) &dropPoint);
4185 event.m_pos.x = dropPoint.x;
4186 event.m_pos.y = dropPoint.y;
4187
4188 DragFinish(hFilesInfo);
4189
4190 return HandleWindowEvent(event);
4191 #endif
4192 }
4193
4194
4195 bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd),
4196 short nHitTest,
4197 int WXUNUSED(mouseMsg))
4198 {
4199 #ifndef __WXMICROWIN__
4200 // the logic is as follows:
4201 // 0. if we're busy, set the busy cursor (even for non client elements)
4202 // 1. don't set custom cursor for non client area of enabled windows
4203 // 2. ask user EVT_SET_CURSOR handler for the cursor
4204 // 3. if still no cursor but we're in a TLW, set the global cursor
4205
4206 HCURSOR hcursor = 0;
4207 if ( wxIsBusy() )
4208 {
4209 hcursor = wxGetCurrentBusyCursor();
4210 }
4211 else // not busy
4212 {
4213 if ( nHitTest != HTCLIENT )
4214 return false;
4215
4216 // first ask the user code - it may wish to set the cursor in some very
4217 // specific way (for example, depending on the current position)
4218 POINT pt;
4219 wxGetCursorPosMSW(&pt);
4220
4221 int x = pt.x,
4222 y = pt.y;
4223 ScreenToClient(&x, &y);
4224 wxSetCursorEvent event(x, y);
4225 event.SetId(GetId());
4226 event.SetEventObject(this);
4227
4228 bool processedEvtSetCursor = HandleWindowEvent(event);
4229 if ( processedEvtSetCursor && event.HasCursor() )
4230 {
4231 hcursor = GetHcursorOf(event.GetCursor());
4232 }
4233
4234 if ( !hcursor )
4235 {
4236 // the test for processedEvtSetCursor is here to prevent using
4237 // m_cursor if the user code caught EVT_SET_CURSOR() and returned
4238 // nothing from it - this is a way to say that our cursor shouldn't
4239 // be used for this point
4240 if ( !processedEvtSetCursor && m_cursor.IsOk() )
4241 {
4242 hcursor = GetHcursorOf(m_cursor);
4243 }
4244
4245 if ( !hcursor && !GetParent() )
4246 {
4247 const wxCursor *cursor = wxGetGlobalCursor();
4248 if ( cursor && cursor->IsOk() )
4249 {
4250 hcursor = GetHcursorOf(*cursor);
4251 }
4252 }
4253 }
4254 }
4255
4256
4257 if ( hcursor )
4258 {
4259 ::SetCursor(hcursor);
4260
4261 // cursor set, stop here
4262 return true;
4263 }
4264 #endif // __WXMICROWIN__
4265
4266 // pass up the window chain
4267 return false;
4268 }
4269
4270 bool wxWindowMSW::HandlePower(WXWPARAM WXUNUSED_IN_WINCE(wParam),
4271 WXLPARAM WXUNUSED(lParam),
4272 bool *WXUNUSED_IN_WINCE(vetoed))
4273 {
4274 #ifdef __WXWINCE__
4275 // FIXME
4276 return false;
4277 #else
4278 wxEventType evtType;
4279 switch ( wParam )
4280 {
4281 case PBT_APMQUERYSUSPEND:
4282 evtType = wxEVT_POWER_SUSPENDING;
4283 break;
4284
4285 case PBT_APMQUERYSUSPENDFAILED:
4286 evtType = wxEVT_POWER_SUSPEND_CANCEL;
4287 break;
4288
4289 case PBT_APMSUSPEND:
4290 evtType = wxEVT_POWER_SUSPENDED;
4291 break;
4292
4293 case PBT_APMRESUMESUSPEND:
4294 evtType = wxEVT_POWER_RESUME;
4295 break;
4296
4297 default:
4298 wxLogDebug(wxT("Unknown WM_POWERBROADCAST(%d) event"), wParam);
4299 // fall through
4300
4301 // these messages are currently not mapped to wx events
4302 case PBT_APMQUERYSTANDBY:
4303 case PBT_APMQUERYSTANDBYFAILED:
4304 case PBT_APMSTANDBY:
4305 case PBT_APMRESUMESTANDBY:
4306 case PBT_APMBATTERYLOW:
4307 case PBT_APMPOWERSTATUSCHANGE:
4308 case PBT_APMOEMEVENT:
4309 case PBT_APMRESUMECRITICAL:
4310 #ifdef PBT_APMRESUMEAUTOMATIC
4311 case PBT_APMRESUMEAUTOMATIC:
4312 #endif
4313 evtType = wxEVT_NULL;
4314 break;
4315 }
4316
4317 // don't handle unknown messages
4318 if ( evtType == wxEVT_NULL )
4319 return false;
4320
4321 // TODO: notify about PBTF_APMRESUMEFROMFAILURE in case of resume events?
4322
4323 wxPowerEvent event(evtType);
4324 if ( !HandleWindowEvent(event) )
4325 return false;
4326
4327 *vetoed = event.IsVetoed();
4328
4329 return true;
4330 #endif
4331 }
4332
4333 bool wxWindowMSW::IsDoubleBuffered() const
4334 {
4335 for ( const wxWindowMSW *win = this; win; win = win->GetParent() )
4336 {
4337 if ( wxHasWindowExStyle(win, WS_EX_COMPOSITED) )
4338 return true;
4339
4340 if ( win->IsTopLevel() )
4341 break;
4342 }
4343
4344 return false;
4345 }
4346
4347 void wxWindowMSW::SetDoubleBuffered(bool on)
4348 {
4349 // Get the current extended style bits
4350 long exstyle = wxGetWindowExStyle(this);
4351
4352 // Twiddle the bit as needed
4353 if ( on )
4354 exstyle |= WS_EX_COMPOSITED;
4355 else
4356 exstyle &= ~WS_EX_COMPOSITED;
4357
4358 // put it back
4359 wxSetWindowExStyle(this, exstyle);
4360 }
4361
4362 // ---------------------------------------------------------------------------
4363 // owner drawn stuff
4364 // ---------------------------------------------------------------------------
4365
4366 #if (wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE) || \
4367 (wxUSE_CONTROLS && !defined(__WXUNIVERSAL__))
4368 #define WXUNUSED_UNLESS_ODRAWN(param) param
4369 #else
4370 #define WXUNUSED_UNLESS_ODRAWN(param)
4371 #endif
4372
4373 bool
4374 wxWindowMSW::MSWOnDrawItem(int WXUNUSED_UNLESS_ODRAWN(id),
4375 WXDRAWITEMSTRUCT * WXUNUSED_UNLESS_ODRAWN(itemStruct))
4376 {
4377 #if wxUSE_OWNER_DRAWN
4378
4379 #if wxUSE_MENUS_NATIVE
4380 // is it a menu item?
4381 DRAWITEMSTRUCT *pDrawStruct = (DRAWITEMSTRUCT *)itemStruct;
4382 if ( id == 0 && pDrawStruct->CtlType == ODT_MENU )
4383 {
4384 wxMenuItem *pMenuItem = (wxMenuItem *)(pDrawStruct->itemData);
4385
4386 // see comment before the same test in MSWOnMeasureItem() below
4387 if ( !pMenuItem )
4388 return false;
4389
4390 wxCHECK_MSG( wxDynamicCast(pMenuItem, wxMenuItem),
4391 false, wxT("MSWOnDrawItem: bad wxMenuItem pointer") );
4392
4393 // prepare to call OnDrawItem(): notice using of wxDCTemp to prevent
4394 // the DC from being released
4395 wxDCTemp dc((WXHDC)pDrawStruct->hDC);
4396 wxRect rect(pDrawStruct->rcItem.left, pDrawStruct->rcItem.top,
4397 pDrawStruct->rcItem.right - pDrawStruct->rcItem.left,
4398 pDrawStruct->rcItem.bottom - pDrawStruct->rcItem.top);
4399
4400 return pMenuItem->OnDrawItem
4401 (
4402 dc,
4403 rect,
4404 (wxOwnerDrawn::wxODAction)pDrawStruct->itemAction,
4405 (wxOwnerDrawn::wxODStatus)pDrawStruct->itemState
4406 );
4407 }
4408 #endif // wxUSE_MENUS_NATIVE
4409
4410 #endif // USE_OWNER_DRAWN
4411
4412 #if wxUSE_CONTROLS && !defined(__WXUNIVERSAL__)
4413
4414 #if wxUSE_OWNER_DRAWN
4415 wxControl *item = wxDynamicCast(FindItem(id), wxControl);
4416 #else // !wxUSE_OWNER_DRAWN
4417 // we may still have owner-drawn buttons internally because we have to make
4418 // them owner-drawn to support colour change
4419 wxControl *item =
4420 # if wxUSE_BUTTON
4421 wxDynamicCast(FindItem(id), wxButton)
4422 # else
4423 NULL
4424 # endif
4425 ;
4426 #endif // USE_OWNER_DRAWN
4427
4428 if ( item )
4429 {
4430 return item->MSWOnDraw(itemStruct);
4431 }
4432
4433 #endif // wxUSE_CONTROLS
4434
4435 return false;
4436 }
4437
4438 bool
4439 wxWindowMSW::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct)
4440 {
4441 #if wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE
4442 // is it a menu item?
4443 MEASUREITEMSTRUCT *pMeasureStruct = (MEASUREITEMSTRUCT *)itemStruct;
4444 if ( id == 0 && pMeasureStruct->CtlType == ODT_MENU )
4445 {
4446 wxMenuItem *pMenuItem = (wxMenuItem *)(pMeasureStruct->itemData);
4447
4448 // according to Carsten Fuchs the pointer may be NULL under XP if an
4449 // MDI child frame is initially maximized, see this for more info:
4450 // http://article.gmane.org/gmane.comp.lib.wxwidgets.general/27745
4451 //
4452 // so silently ignore it instead of asserting
4453 if ( !pMenuItem )
4454 return false;
4455
4456 wxCHECK_MSG( wxDynamicCast(pMenuItem, wxMenuItem),
4457 false, wxT("MSWOnMeasureItem: bad wxMenuItem pointer") );
4458
4459 size_t w, h;
4460 bool rc = pMenuItem->OnMeasureItem(&w, &h);
4461
4462 pMeasureStruct->itemWidth = w;
4463 pMeasureStruct->itemHeight = h;
4464
4465 return rc;
4466 }
4467
4468 wxControl *item = wxDynamicCast(FindItem(id), wxControl);
4469 if ( item )
4470 {
4471 return item->MSWOnMeasure(itemStruct);
4472 }
4473 #else
4474 wxUnusedVar(id);
4475 wxUnusedVar(itemStruct);
4476 #endif // wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE
4477
4478 return false;
4479 }
4480
4481 // ---------------------------------------------------------------------------
4482 // colours and palettes
4483 // ---------------------------------------------------------------------------
4484
4485 bool wxWindowMSW::HandleSysColorChange()
4486 {
4487 wxSysColourChangedEvent event;
4488 event.SetEventObject(this);
4489
4490 (void)HandleWindowEvent(event);
4491
4492 // always let the system carry on the default processing to allow the
4493 // native controls to react to the colours update
4494 return false;
4495 }
4496
4497 bool wxWindowMSW::HandleDisplayChange()
4498 {
4499 wxDisplayChangedEvent event;
4500 event.SetEventObject(this);
4501
4502 return HandleWindowEvent(event);
4503 }
4504
4505 #ifndef __WXMICROWIN__
4506
4507 bool wxWindowMSW::HandleCtlColor(WXHBRUSH *brush, WXHDC hDC, WXHWND hWnd)
4508 {
4509 #if !wxUSE_CONTROLS || defined(__WXUNIVERSAL__)
4510 wxUnusedVar(hDC);
4511 wxUnusedVar(hWnd);
4512 #else
4513 wxControl *item = wxDynamicCast(FindItemByHWND(hWnd, true), wxControl);
4514
4515 if ( item )
4516 *brush = item->MSWControlColor(hDC, hWnd);
4517 else
4518 #endif // wxUSE_CONTROLS
4519 *brush = NULL;
4520
4521 return *brush != NULL;
4522 }
4523
4524 #endif // __WXMICROWIN__
4525
4526 bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange)
4527 {
4528 #if wxUSE_PALETTE
4529 // same as below except we don't respond to our own messages
4530 if ( hWndPalChange != GetHWND() )
4531 {
4532 // check to see if we our our parents have a custom palette
4533 wxWindowMSW *win = this;
4534 while ( win && !win->HasCustomPalette() )
4535 {
4536 win = win->GetParent();
4537 }
4538
4539 if ( win && win->HasCustomPalette() )
4540 {
4541 // realize the palette to see whether redrawing is needed
4542 HDC hdc = ::GetDC((HWND) hWndPalChange);
4543 win->m_palette.SetHPALETTE((WXHPALETTE)
4544 ::SelectPalette(hdc, GetHpaletteOf(win->m_palette), FALSE));
4545
4546 int result = ::RealizePalette(hdc);
4547
4548 // restore the palette (before releasing the DC)
4549 win->m_palette.SetHPALETTE((WXHPALETTE)
4550 ::SelectPalette(hdc, GetHpaletteOf(win->m_palette), FALSE));
4551 ::RealizePalette(hdc);
4552 ::ReleaseDC((HWND) hWndPalChange, hdc);
4553
4554 // now check for the need to redraw
4555 if (result > 0)
4556 ::InvalidateRect((HWND) hWndPalChange, NULL, TRUE);
4557 }
4558
4559 }
4560 #endif // wxUSE_PALETTE
4561
4562 wxPaletteChangedEvent event(GetId());
4563 event.SetEventObject(this);
4564 event.SetChangedWindow(wxFindWinFromHandle(hWndPalChange));
4565
4566 return HandleWindowEvent(event);
4567 }
4568
4569 bool wxWindowMSW::HandleCaptureChanged(WXHWND hWndGainedCapture)
4570 {
4571 // Ensure that wxWindow::GetCapture() returns NULL if called from the event
4572 // handlers invoked below. This is necessary to avoid wrongly calling
4573 // ReleaseMouse() when we're already losing the mouse capture anyhow.
4574 gs_insideCaptureChanged = true;
4575 wxON_BLOCK_EXIT_SET(gs_insideCaptureChanged, false);
4576
4577 // notify windows on the capture stack about lost capture
4578 // (see http://sourceforge.net/tracker/index.php?func=detail&aid=1153662&group_id=9863&atid=109863):
4579 wxWindowBase::NotifyCaptureLost();
4580
4581 wxWindow *win = wxFindWinFromHandle(hWndGainedCapture);
4582 wxMouseCaptureChangedEvent event(GetId(), win);
4583 event.SetEventObject(this);
4584 return HandleWindowEvent(event);
4585 }
4586
4587 bool wxWindowMSW::HandleSettingChange(WXWPARAM wParam, WXLPARAM lParam)
4588 {
4589 // despite MSDN saying "(This message cannot be sent directly to a window.)"
4590 // we need to send this to child windows (it is only sent to top-level
4591 // windows) so {list,tree}ctrls can adjust their font size if necessary
4592 // this is exactly how explorer does it to enable the font size changes
4593
4594 wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
4595 while ( node )
4596 {
4597 // top-level windows already get this message from the system
4598 wxWindow *win = node->GetData();
4599 if ( !win->IsTopLevel() )
4600 {
4601 ::SendMessage(GetHwndOf(win), WM_SETTINGCHANGE, wParam, lParam);
4602 }
4603
4604 node = node->GetNext();
4605 }
4606
4607 // let the system handle it
4608 return false;
4609 }
4610
4611 bool wxWindowMSW::HandleQueryNewPalette()
4612 {
4613
4614 #if wxUSE_PALETTE
4615 // check to see if we our our parents have a custom palette
4616 wxWindowMSW *win = this;
4617 while (!win->HasCustomPalette() && win->GetParent()) win = win->GetParent();
4618 if (win->HasCustomPalette()) {
4619 /* realize the palette to see whether redrawing is needed */
4620 HDC hdc = ::GetDC((HWND) GetHWND());
4621 win->m_palette.SetHPALETTE( (WXHPALETTE)
4622 ::SelectPalette(hdc, (HPALETTE) win->m_palette.GetHPALETTE(), FALSE) );
4623
4624 int result = ::RealizePalette(hdc);
4625 /* restore the palette (before releasing the DC) */
4626 win->m_palette.SetHPALETTE( (WXHPALETTE)
4627 ::SelectPalette(hdc, (HPALETTE) win->m_palette.GetHPALETTE(), TRUE) );
4628 ::RealizePalette(hdc);
4629 ::ReleaseDC((HWND) GetHWND(), hdc);
4630 /* now check for the need to redraw */
4631 if (result > 0)
4632 ::InvalidateRect((HWND) GetHWND(), NULL, TRUE);
4633 }
4634 #endif // wxUSE_PALETTE
4635
4636 wxQueryNewPaletteEvent event(GetId());
4637 event.SetEventObject(this);
4638
4639 return HandleWindowEvent(event) && event.GetPaletteRealized();
4640 }
4641
4642 // Responds to colour changes: passes event on to children.
4643 void wxWindowMSW::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event))
4644 {
4645 // the top level window also reset the standard colour map as it might have
4646 // changed (there is no need to do it for the non top level windows as we
4647 // only have to do it once)
4648 if ( IsTopLevel() )
4649 {
4650 // FIXME-MT
4651 gs_hasStdCmap = false;
4652 }
4653 wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
4654 while ( node )
4655 {
4656 // Only propagate to non-top-level windows because Windows already
4657 // sends this event to all top-level ones
4658 wxWindow *win = node->GetData();
4659 if ( !win->IsTopLevel() )
4660 {
4661 // we need to send the real WM_SYSCOLORCHANGE and not just trigger
4662 // EVT_SYS_COLOUR_CHANGED call because the latter wouldn't work for
4663 // the standard controls
4664 ::SendMessage(GetHwndOf(win), WM_SYSCOLORCHANGE, 0, 0);
4665 }
4666
4667 node = node->GetNext();
4668 }
4669 }
4670
4671 extern wxCOLORMAP *wxGetStdColourMap()
4672 {
4673 static COLORREF s_stdColours[wxSTD_COL_MAX];
4674 static wxCOLORMAP s_cmap[wxSTD_COL_MAX];
4675
4676 if ( !gs_hasStdCmap )
4677 {
4678 static bool s_coloursInit = false;
4679
4680 if ( !s_coloursInit )
4681 {
4682 // When a bitmap is loaded, the RGB values can change (apparently
4683 // because Windows adjusts them to care for the old programs always
4684 // using 0xc0c0c0 while the transparent colour for the new Windows
4685 // versions is different). But we do this adjustment ourselves so
4686 // we want to avoid Windows' "help" and for this we need to have a
4687 // reference bitmap which can tell us what the RGB values change
4688 // to.
4689 wxLogNull logNo; // suppress error if we couldn't load the bitmap
4690 wxBitmap stdColourBitmap(wxT("wxBITMAP_STD_COLOURS"));
4691 if ( stdColourBitmap.IsOk() )
4692 {
4693 // the pixels in the bitmap must correspond to wxSTD_COL_XXX!
4694 wxASSERT_MSG( stdColourBitmap.GetWidth() == wxSTD_COL_MAX,
4695 wxT("forgot to update wxBITMAP_STD_COLOURS!") );
4696
4697 wxMemoryDC memDC;
4698 memDC.SelectObject(stdColourBitmap);
4699
4700 wxColour colour;
4701 for ( size_t i = 0; i < WXSIZEOF(s_stdColours); i++ )
4702 {
4703 memDC.GetPixel(i, 0, &colour);
4704 s_stdColours[i] = wxColourToRGB(colour);
4705 }
4706 }
4707 else // wxBITMAP_STD_COLOURS couldn't be loaded
4708 {
4709 s_stdColours[0] = RGB(000,000,000); // black
4710 s_stdColours[1] = RGB(128,128,128); // dark grey
4711 s_stdColours[2] = RGB(192,192,192); // light grey
4712 s_stdColours[3] = RGB(255,255,255); // white
4713 //s_stdColours[4] = RGB(000,000,255); // blue
4714 //s_stdColours[5] = RGB(255,000,255); // magenta
4715 }
4716
4717 s_coloursInit = true;
4718 }
4719
4720 gs_hasStdCmap = true;
4721
4722 // create the colour map
4723 #define INIT_CMAP_ENTRY(col) \
4724 s_cmap[wxSTD_COL_##col].from = s_stdColours[wxSTD_COL_##col]; \
4725 s_cmap[wxSTD_COL_##col].to = ::GetSysColor(COLOR_##col)
4726
4727 INIT_CMAP_ENTRY(BTNTEXT);
4728 INIT_CMAP_ENTRY(BTNSHADOW);
4729 INIT_CMAP_ENTRY(BTNFACE);
4730 INIT_CMAP_ENTRY(BTNHIGHLIGHT);
4731
4732 #undef INIT_CMAP_ENTRY
4733 }
4734
4735 return s_cmap;
4736 }
4737
4738 #if wxUSE_UXTHEME && !defined(TMT_FILLCOLOR)
4739 #define TMT_FILLCOLOR 3802
4740 #define TMT_TEXTCOLOR 3803
4741 #define TMT_BORDERCOLOR 3801
4742 #endif
4743
4744 wxColour wxWindowMSW::MSWGetThemeColour(const wchar_t *themeName,
4745 int themePart,
4746 int themeState,
4747 MSWThemeColour themeColour,
4748 wxSystemColour fallback) const
4749 {
4750 #if wxUSE_UXTHEME
4751 const wxUxThemeEngine* theme = wxUxThemeEngine::GetIfActive();
4752 if ( theme )
4753 {
4754 int themeProperty = 0;
4755
4756 // TODO: Convert this into a table? Sure would be faster.
4757 switch ( themeColour )
4758 {
4759 case ThemeColourBackground:
4760 themeProperty = TMT_FILLCOLOR;
4761 break;
4762 case ThemeColourText:
4763 themeProperty = TMT_TEXTCOLOR;
4764 break;
4765 case ThemeColourBorder:
4766 themeProperty = TMT_BORDERCOLOR;
4767 break;
4768 default:
4769 wxFAIL_MSG(wxT("unsupported theme colour"));
4770 };
4771
4772 wxUxThemeHandle hTheme((const wxWindow *)this, themeName);
4773 COLORREF col;
4774 HRESULT hr = theme->GetThemeColor
4775 (
4776 hTheme,
4777 themePart,
4778 themeState,
4779 themeProperty,
4780 &col
4781 );
4782
4783 if ( SUCCEEDED(hr) )
4784 return wxRGBToColour(col);
4785
4786 wxLogApiError(
4787 wxString::Format(
4788 "GetThemeColor(%s, %i, %i, %i)",
4789 themeName, themePart, themeState, themeProperty),
4790 hr);
4791 }
4792 #else
4793 wxUnusedVar(themeName);
4794 wxUnusedVar(themePart);
4795 wxUnusedVar(themeState);
4796 wxUnusedVar(themeColour);
4797 #endif
4798 return wxSystemSettings::GetColour(fallback);
4799 }
4800
4801 // ---------------------------------------------------------------------------
4802 // painting
4803 // ---------------------------------------------------------------------------
4804
4805 // this variable is used to check that a paint event handler which processed
4806 // the event did create a wxPaintDC inside its code and called BeginPaint() to
4807 // validate the invalidated window area as otherwise we'd keep getting an
4808 // endless stream of WM_PAINT messages for this window resulting in a lot of
4809 // difficult to debug problems (e.g. impossibility to repaint other windows,
4810 // lack of timer and idle events and so on)
4811 extern bool wxDidCreatePaintDC;
4812 bool wxDidCreatePaintDC = false;
4813
4814 bool wxWindowMSW::HandlePaint()
4815 {
4816 HRGN hRegion = ::CreateRectRgn(0, 0, 0, 0); // Dummy call to get a handle
4817 if ( !hRegion )
4818 {
4819 wxLogLastError(wxT("CreateRectRgn"));
4820 }
4821 if ( ::GetUpdateRgn(GetHwnd(), hRegion, FALSE) == ERROR )
4822 {
4823 wxLogLastError(wxT("GetUpdateRgn"));
4824 }
4825
4826 m_updateRegion = wxRegion((WXHRGN) hRegion);
4827
4828 wxDidCreatePaintDC = false;
4829
4830 wxPaintEvent event(m_windowId);
4831 event.SetEventObject(this);
4832
4833 bool processed = HandleWindowEvent(event);
4834
4835 if ( processed && !wxDidCreatePaintDC )
4836 {
4837 // do call MSWDefWindowProc() to validate the update region to avoid
4838 // the problems mentioned above
4839 processed = false;
4840 }
4841
4842 // note that we must generate NC event after the normal one as otherwise
4843 // BeginPaint() will happily overwrite our decorations with the background
4844 // colour
4845 wxNcPaintEvent eventNc(m_windowId);
4846 eventNc.SetEventObject(this);
4847 HandleWindowEvent(eventNc);
4848
4849 // don't keep an HRGN we don't need any longer (GetUpdateRegion() can only
4850 // be called from inside the event handlers called above)
4851 m_updateRegion.Clear();
4852
4853 wxPaintDCImpl::EndPaint((wxWindow *)this);
4854
4855 return processed;
4856 }
4857
4858 // Can be called from an application's OnPaint handler
4859 void wxWindowMSW::OnPaint(wxPaintEvent& event)
4860 {
4861 #ifdef __WXUNIVERSAL__
4862 event.Skip();
4863 #else
4864 HDC hDC = (HDC) wxPaintDCImpl::FindDCInCache((wxWindow*) event.GetEventObject());
4865 if (hDC != 0)
4866 {
4867 MSWDefWindowProc(WM_PAINT, (WPARAM) hDC, 0);
4868 }
4869 #endif
4870 }
4871
4872 bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc)
4873 {
4874 if ( IsBeingDeleted() )
4875 {
4876 // We can get WM_ERASEBKGND after starting the destruction of our top
4877 // level parent. Handling it in this case is unnecessary and can be
4878 // actually harmful as e.g. wxStaticBox::GetClientSize() doesn't work
4879 // without a valid TLW parent (because it uses dialog units internally
4880 // which use the dialog font), so just don't do anything then.
4881 return false;
4882 }
4883
4884 switch ( GetBackgroundStyle() )
4885 {
4886 case wxBG_STYLE_ERASE:
4887 case wxBG_STYLE_COLOUR:
4888 // we need to generate an erase background event
4889 {
4890 wxDCTemp dc(hdc, GetClientSize());
4891 wxDCTempImpl *impl = (wxDCTempImpl*) dc.GetImpl();
4892
4893 impl->SetHDC(hdc);
4894 impl->SetWindow((wxWindow *)this);
4895
4896 wxEraseEvent event(m_windowId, &dc);
4897 event.SetEventObject(this);
4898 bool rc = HandleWindowEvent(event);
4899
4900 // must be called manually as ~wxDC doesn't do anything for
4901 // wxDCTemp
4902 impl->SelectOldObjects(hdc);
4903
4904 if ( rc )
4905 {
4906 // background erased by the user-defined handler
4907 return true;
4908 }
4909 }
4910 // fall through
4911
4912 case wxBG_STYLE_SYSTEM:
4913 if ( !DoEraseBackground(hdc) )
4914 {
4915 // let the default processing to take place if we didn't erase
4916 // the background ourselves
4917 return false;
4918 }
4919 break;
4920
4921 case wxBG_STYLE_PAINT:
4922 case wxBG_STYLE_TRANSPARENT:
4923 // no need to do anything here at all, background will be entirely
4924 // redrawn in WM_PAINT handler
4925 break;
4926
4927 default:
4928 wxFAIL_MSG( "unknown background style" );
4929 }
4930
4931 return true;
4932 }
4933
4934 #ifdef wxHAS_MSW_BACKGROUND_ERASE_HOOK
4935
4936 bool wxWindowMSW::MSWHasEraseBgHook() const
4937 {
4938 return gs_eraseBgHooks.find(const_cast<wxWindowMSW *>(this))
4939 != gs_eraseBgHooks.end();
4940 }
4941
4942 void wxWindowMSW::MSWSetEraseBgHook(wxWindow *child)
4943 {
4944 if ( child )
4945 {
4946 if ( !gs_eraseBgHooks.insert(
4947 EraseBgHooks::value_type(this, child)).second )
4948 {
4949 wxFAIL_MSG( wxT("Setting erase background hook twice?") );
4950 }
4951 }
4952 else // reset the hook
4953 {
4954 if ( gs_eraseBgHooks.erase(this) != 1 )
4955 {
4956 wxFAIL_MSG( wxT("Resetting erase background which was not set?") );
4957 }
4958 }
4959 }
4960
4961 #endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK
4962
4963 bool wxWindowMSW::DoEraseBackground(WXHDC hDC)
4964 {
4965 HBRUSH hbr = (HBRUSH)MSWGetBgBrush(hDC);
4966 if ( !hbr )
4967 return false;
4968
4969 // erase just the client area of the window, this is important for the
4970 // frames to avoid drawing over the toolbar part of the window (you might
4971 // think using WS_CLIPCHILDREN would prevent this from happening, but it
4972 // clearly doesn't)
4973 RECT rc;
4974 wxCopyRectToRECT(GetClientRect(), rc);
4975 ::FillRect((HDC)hDC, &rc, hbr);
4976
4977 return true;
4978 }
4979
4980 WXHBRUSH
4981 wxWindowMSW::MSWGetBgBrushForChild(WXHDC hDC, wxWindowMSW *child)
4982 {
4983 // Test for the custom background brush first.
4984 WXHBRUSH hbrush = MSWGetCustomBgBrush();
4985 if ( hbrush )
4986 {
4987 // We assume that this is either a stipple or hatched brush and not a
4988 // solid one as otherwise it would have been enough to set the
4989 // background colour and such brushes need to be positioned correctly
4990 // in order to align when different windows are painted, so do it here.
4991 RECT rc;
4992 ::GetWindowRect(GetHwndOf(child), &rc);
4993
4994 ::MapWindowPoints(NULL, GetHwnd(), (POINT *)&rc, 1);
4995
4996 int x = rc.left,
4997 y = rc.top;
4998 MSWAdjustBrushOrg(&x, &y);
4999
5000 if ( !::SetBrushOrgEx((HDC)hDC, -x, -y, NULL) )
5001 {
5002 wxLogLastError(wxT("SetBrushOrgEx(bg brush)"));
5003 }
5004
5005 return hbrush;
5006 }
5007
5008 // Otherwise see if we have a custom background colour.
5009 if ( m_hasBgCol )
5010 {
5011 wxBrush *
5012 brush = wxTheBrushList->FindOrCreateBrush(GetBackgroundColour());
5013
5014 return (WXHBRUSH)GetHbrushOf(*brush);
5015 }
5016
5017 return 0;
5018 }
5019
5020 WXHBRUSH wxWindowMSW::MSWGetBgBrush(WXHDC hDC)
5021 {
5022 // Use the special wxWindowBeingErased variable if it is set as the child
5023 // being erased.
5024 wxWindowMSW * const child =
5025 #if wxUSE_UXTHEME
5026 wxWindowBeingErased ? wxWindowBeingErased :
5027 #endif
5028 this;
5029
5030 for ( wxWindowMSW *win = this; win; win = win->GetParent() )
5031 {
5032 WXHBRUSH hBrush = win->MSWGetBgBrushForChild(hDC, child);
5033 if ( hBrush )
5034 return hBrush;
5035
5036 // don't use the parent background if we're not transparent
5037 if ( !win->HasTransparentBackground() )
5038 break;
5039
5040 // background is not inherited beyond top level windows
5041 if ( win->IsTopLevel() )
5042 break;
5043 }
5044
5045 return 0;
5046 }
5047
5048 bool wxWindowMSW::HandlePrintClient(WXHDC hDC)
5049 {
5050 // we receive this message when DrawThemeParentBackground() is
5051 // called from def window proc of several controls under XP and we
5052 // must draw properly themed background here
5053 //
5054 // note that naively I'd expect filling the client rect with the
5055 // brush returned by MSWGetBgBrush() work -- but for some reason it
5056 // doesn't and we have to call parents MSWPrintChild() which is
5057 // supposed to call DrawThemeBackground() with appropriate params
5058 //
5059 // also note that in this case lParam == PRF_CLIENT but we're
5060 // clearly expected to paint the background and nothing else!
5061
5062 if ( IsTopLevel() || InheritsBackgroundColour() )
5063 return false;
5064
5065 // sometimes we don't want the parent to handle it at all, instead
5066 // return whatever value this window wants
5067 if ( !MSWShouldPropagatePrintChild() )
5068 return MSWPrintChild(hDC, (wxWindow *)this);
5069
5070 for ( wxWindow *win = GetParent(); win; win = win->GetParent() )
5071 {
5072 if ( win->MSWPrintChild(hDC, (wxWindow *)this) )
5073 return true;
5074
5075 if ( win->IsTopLevel() || win->InheritsBackgroundColour() )
5076 break;
5077 }
5078
5079 return false;
5080 }
5081
5082 // ---------------------------------------------------------------------------
5083 // moving and resizing
5084 // ---------------------------------------------------------------------------
5085
5086 bool wxWindowMSW::HandleMinimize()
5087 {
5088 wxIconizeEvent event(m_windowId);
5089 event.SetEventObject(this);
5090
5091 return HandleWindowEvent(event);
5092 }
5093
5094 bool wxWindowMSW::HandleMaximize()
5095 {
5096 wxMaximizeEvent event(m_windowId);
5097 event.SetEventObject(this);
5098
5099 return HandleWindowEvent(event);
5100 }
5101
5102 bool wxWindowMSW::HandleMove(int x, int y)
5103 {
5104 wxPoint point(x,y);
5105 wxMoveEvent event(point, m_windowId);
5106 event.SetEventObject(this);
5107
5108 return HandleWindowEvent(event);
5109 }
5110
5111 bool wxWindowMSW::HandleMoving(wxRect& rect)
5112 {
5113 wxMoveEvent event(rect, m_windowId);
5114 event.SetEventObject(this);
5115
5116 bool rc = HandleWindowEvent(event);
5117 if (rc)
5118 rect = event.GetRect();
5119 return rc;
5120 }
5121
5122 bool wxWindowMSW::HandleEnterSizeMove()
5123 {
5124 wxMoveEvent event(wxPoint(0,0), m_windowId);
5125 event.SetEventType(wxEVT_MOVE_START);
5126 event.SetEventObject(this);
5127
5128 return HandleWindowEvent(event);
5129 }
5130
5131 bool wxWindowMSW::HandleExitSizeMove()
5132 {
5133 wxMoveEvent event(wxPoint(0,0), m_windowId);
5134 event.SetEventType(wxEVT_MOVE_END);
5135 event.SetEventObject(this);
5136
5137 return HandleWindowEvent(event);
5138 }
5139
5140 bool wxWindowMSW::BeginRepositioningChildren()
5141 {
5142 #if wxUSE_DEFERRED_SIZING
5143 int numChildren = 0;
5144 for ( HWND child = ::GetWindow(GetHwndOf(this), GW_CHILD);
5145 child;
5146 child = ::GetWindow(child, GW_HWNDNEXT) )
5147 {
5148 numChildren ++;
5149 }
5150
5151 // Nothing is gained by deferring the repositioning of a single child.
5152 if ( numChildren < 2 )
5153 return false;
5154
5155 // Protect against valid m_hDWP being overwritten
5156 if ( m_hDWP )
5157 return false;
5158
5159 m_hDWP = (WXHANDLE)::BeginDeferWindowPos(numChildren);
5160 if ( !m_hDWP )
5161 {
5162 wxLogLastError(wxT("BeginDeferWindowPos"));
5163 return false;
5164 }
5165
5166 // Return true to indicate that EndDeferWindowPos() should be called.
5167 return true;
5168 #endif // wxUSE_DEFERRED_SIZING
5169 }
5170
5171 void wxWindowMSW::EndRepositioningChildren()
5172 {
5173 #if wxUSE_DEFERRED_SIZING
5174 wxASSERT_MSG( m_hDWP, wxS("Shouldn't be called") );
5175
5176 // reset m_hDWP to NULL so that child windows don't try to use our
5177 // m_hDWP after we call EndDeferWindowPos() on it (this shouldn't
5178 // happen anyhow normally but who knows what weird flow of control we
5179 // may have depending on what the users EVT_SIZE handler does...)
5180 HDWP hDWP = (HDWP)m_hDWP;
5181 m_hDWP = NULL;
5182
5183 // do put all child controls in place at once
5184 if ( !::EndDeferWindowPos(hDWP) )
5185 {
5186 wxLogLastError(wxT("EndDeferWindowPos"));
5187 }
5188
5189 // Reset our children's pending pos/size values.
5190 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
5191 node;
5192 node = node->GetNext() )
5193 {
5194 wxWindowMSW * const child = node->GetData();
5195 child->MSWEndDeferWindowPos();
5196 }
5197 #endif // wxUSE_DEFERRED_SIZING
5198 }
5199
5200 bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam)
5201 {
5202 // when we resize this window, its children are probably going to be
5203 // repositioned as well, prepare to use DeferWindowPos() for them
5204 ChildrenRepositioningGuard repositionGuard(this);
5205
5206 // update this window size
5207 bool processed = false;
5208 switch ( wParam )
5209 {
5210 default:
5211 wxFAIL_MSG( wxT("unexpected WM_SIZE parameter") );
5212 // fall through nevertheless
5213
5214 case SIZE_MAXHIDE:
5215 case SIZE_MAXSHOW:
5216 // we're not interested in these messages at all
5217 break;
5218
5219 case SIZE_MINIMIZED:
5220 processed = HandleMinimize();
5221 break;
5222
5223 case SIZE_MAXIMIZED:
5224 /* processed = */ HandleMaximize();
5225 // fall through to send a normal size event as well
5226
5227 case SIZE_RESTORED:
5228 // don't use w and h parameters as they specify the client size
5229 // while according to the docs EVT_SIZE handler is supposed to
5230 // receive the total size
5231 wxSizeEvent event(GetSize(), m_windowId);
5232 event.SetEventObject(this);
5233
5234 processed = HandleWindowEvent(event);
5235 }
5236
5237 return processed;
5238 }
5239
5240 bool wxWindowMSW::HandleSizing(wxRect& rect)
5241 {
5242 wxSizeEvent event(rect, m_windowId);
5243 event.SetEventObject(this);
5244
5245 bool rc = HandleWindowEvent(event);
5246 if (rc)
5247 rect = event.GetRect();
5248 return rc;
5249 }
5250
5251 bool wxWindowMSW::HandleGetMinMaxInfo(void *WXUNUSED_IN_WINCE(mmInfo))
5252 {
5253 #ifdef __WXWINCE__
5254 return false;
5255 #else
5256 MINMAXINFO *info = (MINMAXINFO *)mmInfo;
5257
5258 bool rc = false;
5259
5260 int minWidth = GetMinWidth(),
5261 minHeight = GetMinHeight(),
5262 maxWidth = GetMaxWidth(),
5263 maxHeight = GetMaxHeight();
5264
5265 if ( minWidth != wxDefaultCoord )
5266 {
5267 info->ptMinTrackSize.x = minWidth;
5268 rc = true;
5269 }
5270
5271 if ( minHeight != wxDefaultCoord )
5272 {
5273 info->ptMinTrackSize.y = minHeight;
5274 rc = true;
5275 }
5276
5277 if ( maxWidth != wxDefaultCoord )
5278 {
5279 info->ptMaxTrackSize.x = maxWidth;
5280 rc = true;
5281 }
5282
5283 if ( maxHeight != wxDefaultCoord )
5284 {
5285 info->ptMaxTrackSize.y = maxHeight;
5286 rc = true;
5287 }
5288
5289 return rc;
5290 #endif
5291 }
5292
5293 // ---------------------------------------------------------------------------
5294 // command messages
5295 // ---------------------------------------------------------------------------
5296
5297 bool wxWindowMSW::HandleCommand(WXWORD id_, WXWORD cmd, WXHWND control)
5298 {
5299 // sign extend to int from short before comparing with the other int ids
5300 int id = (signed short)id_;
5301
5302 #if wxUSE_MENUS_NATIVE
5303 if ( !cmd && wxCurrentPopupMenu )
5304 {
5305 wxMenu *popupMenu = wxCurrentPopupMenu;
5306 wxCurrentPopupMenu = NULL;
5307
5308 return popupMenu->MSWCommand(cmd, id);
5309 }
5310 #endif // wxUSE_MENUS_NATIVE
5311
5312 wxWindow *win = NULL;
5313
5314 // first try to find it from HWND - this works even with the broken
5315 // programs using the same ids for different controls
5316 if ( control )
5317 {
5318 win = wxFindWinFromHandle(control);
5319 }
5320
5321 // try the id
5322 if ( !win )
5323 {
5324 win = FindItem(id);
5325 }
5326
5327 if ( win )
5328 {
5329 return win->MSWCommand(cmd, id);
5330 }
5331
5332 // the messages sent from the in-place edit control used by the treectrl
5333 // for label editing have id == 0, but they should _not_ be treated as menu
5334 // messages (they are EN_XXX ones, in fact) so don't translate anything
5335 // coming from a control to wxEVT_MENU
5336 if ( !control )
5337 {
5338 wxCommandEvent event(wxEVT_MENU, id);
5339 event.SetEventObject(this);
5340 event.SetInt(id);
5341
5342 return HandleWindowEvent(event);
5343 }
5344 else
5345 {
5346 #if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__)
5347 // the text ctrl which is logically part of wxSpinCtrl sends WM_COMMAND
5348 // notifications to its parent which we want to reflect back to
5349 // wxSpinCtrl
5350 wxSpinCtrl *spin = wxSpinCtrl::GetSpinForTextCtrl(control);
5351 if ( spin && spin->ProcessTextCommand(cmd, id) )
5352 return true;
5353 #endif // wxUSE_SPINCTRL
5354
5355 #if wxUSE_CHOICE && defined(__SMARTPHONE__)
5356 // the listbox ctrl which is logically part of wxChoice sends WM_COMMAND
5357 // notifications to its parent which we want to reflect back to
5358 // wxChoice
5359 wxChoice *choice = wxChoice::GetChoiceForListBox(control);
5360 if ( choice && choice->MSWCommand(cmd, id) )
5361 return true;
5362 #endif
5363 }
5364
5365 return false;
5366 }
5367
5368 // ---------------------------------------------------------------------------
5369 // mouse events
5370 // ---------------------------------------------------------------------------
5371
5372 void wxWindowMSW::InitMouseEvent(wxMouseEvent& event,
5373 int x, int y,
5374 WXUINT flags)
5375 {
5376 // our client coords are not quite the same as Windows ones
5377 wxPoint pt = GetClientAreaOrigin();
5378 event.m_x = x - pt.x;
5379 event.m_y = y - pt.y;
5380
5381 event.m_shiftDown = (flags & MK_SHIFT) != 0;
5382 event.m_controlDown = (flags & MK_CONTROL) != 0;
5383 event.m_leftDown = (flags & MK_LBUTTON) != 0;
5384 event.m_middleDown = (flags & MK_MBUTTON) != 0;
5385 event.m_rightDown = (flags & MK_RBUTTON) != 0;
5386 #ifdef wxHAS_XBUTTON
5387 event.m_aux1Down = (flags & MK_XBUTTON1) != 0;
5388 event.m_aux2Down = (flags & MK_XBUTTON2) != 0;
5389 #endif // wxHAS_XBUTTON
5390 event.m_altDown = ::wxIsAltDown();
5391
5392 #ifndef __WXWINCE__
5393 event.SetTimestamp(::GetMessageTime());
5394 #endif
5395
5396 event.SetEventObject(this);
5397 event.SetId(GetId());
5398
5399 #if wxUSE_MOUSEEVENT_HACK
5400 gs_lastMouseEvent.pos = ClientToScreen(wxPoint(x, y));
5401 gs_lastMouseEvent.type = event.GetEventType();
5402 #endif // wxUSE_MOUSEEVENT_HACK
5403 }
5404
5405 #ifdef __WXWINCE__
5406 // Windows doesn't send the mouse events to the static controls (which are
5407 // transparent in the sense that their WM_NCHITTEST handler returns
5408 // HTTRANSPARENT) at all but we want all controls to receive the mouse events
5409 // and so we manually check if we don't have a child window under mouse and if
5410 // we do, send the event to it instead of the window Windows had sent WM_XXX
5411 // to.
5412 //
5413 // Notice that this is not done for the mouse move events because this could
5414 // (would?) be too slow, but only for clicks which means that the static texts
5415 // still don't get move, enter nor leave events.
5416 static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y)
5417 {
5418 wxCHECK_MSG( x && y, win, wxT("NULL pointer in FindWindowForMouseEvent") );
5419
5420 // first try to find a non transparent child: this allows us to send events
5421 // to a static text which is inside a static box, for example
5422 POINT pt = { *x, *y };
5423 HWND hwnd = GetHwndOf(win),
5424 hwndUnderMouse;
5425
5426 #ifdef __WXWINCE__
5427 hwndUnderMouse = ::ChildWindowFromPoint
5428 (
5429 hwnd,
5430 pt
5431 );
5432 #else
5433 hwndUnderMouse = ::ChildWindowFromPointEx
5434 (
5435 hwnd,
5436 pt,
5437 CWP_SKIPINVISIBLE |
5438 CWP_SKIPDISABLED |
5439 CWP_SKIPTRANSPARENT
5440 );
5441 #endif
5442
5443 if ( !hwndUnderMouse || hwndUnderMouse == hwnd )
5444 {
5445 // now try any child window at all
5446 hwndUnderMouse = ::ChildWindowFromPoint(hwnd, pt);
5447 }
5448
5449 // check that we have a child window which is susceptible to receive mouse
5450 // events: for this it must be shown and enabled
5451 if ( hwndUnderMouse &&
5452 hwndUnderMouse != hwnd &&
5453 ::IsWindowVisible(hwndUnderMouse) &&
5454 ::IsWindowEnabled(hwndUnderMouse) )
5455 {
5456 wxWindow *winUnderMouse = wxFindWinFromHandle(hwndUnderMouse);
5457 if ( winUnderMouse )
5458 {
5459 // translate the mouse coords to the other window coords
5460 win->ClientToScreen(x, y);
5461 winUnderMouse->ScreenToClient(x, y);
5462
5463 win = winUnderMouse;
5464 }
5465 }
5466
5467 return win;
5468 }
5469 #endif // __WXWINCE__
5470
5471 bool wxWindowMSW::HandleMouseEvent(WXUINT msg, int x, int y, WXUINT flags)
5472 {
5473 // the mouse events take consecutive IDs from WM_MOUSEFIRST to
5474 // WM_MOUSELAST, so it's enough to subtract WM_MOUSEMOVE == WM_MOUSEFIRST
5475 // from the message id and take the value in the table to get wxWin event
5476 // id
5477 static const wxEventType eventsMouse[] =
5478 {
5479 wxEVT_MOTION,
5480 wxEVT_LEFT_DOWN,
5481 wxEVT_LEFT_UP,
5482 wxEVT_LEFT_DCLICK,
5483 wxEVT_RIGHT_DOWN,
5484 wxEVT_RIGHT_UP,
5485 wxEVT_RIGHT_DCLICK,
5486 wxEVT_MIDDLE_DOWN,
5487 wxEVT_MIDDLE_UP,
5488 wxEVT_MIDDLE_DCLICK,
5489 0, // this one is for wxEVT_MOTION which is not used here
5490 wxEVT_AUX1_DOWN,
5491 wxEVT_AUX1_UP,
5492 wxEVT_AUX1_DCLICK,
5493 wxEVT_AUX2_DOWN,
5494 wxEVT_AUX2_UP,
5495 wxEVT_AUX2_DCLICK
5496 };
5497
5498 #ifdef wxHAS_XBUTTON
5499 // the same messages are used for both auxiliary mouse buttons so we need
5500 // to adjust the index manually
5501 switch ( msg )
5502 {
5503 case WM_XBUTTONDOWN:
5504 case WM_XBUTTONUP:
5505 case WM_XBUTTONDBLCLK:
5506 if ( flags & MK_XBUTTON2 )
5507 msg += wxEVT_AUX2_DOWN - wxEVT_AUX1_DOWN;
5508 }
5509 #endif // wxHAS_XBUTTON
5510
5511 wxMouseEvent event(eventsMouse[msg - WM_MOUSEMOVE]);
5512 InitMouseEvent(event, x, y, flags);
5513
5514 return HandleWindowEvent(event);
5515 }
5516
5517 bool wxWindowMSW::HandleMouseMove(int x, int y, WXUINT flags)
5518 {
5519 if ( !m_mouseInWindow )
5520 {
5521 // it would be wrong to assume that just because we get a mouse move
5522 // event that the mouse is inside the window: although this is usually
5523 // true, it is not if we had captured the mouse, so we need to check
5524 // the mouse coordinates here
5525 if ( !HasCapture() || IsMouseInWindow() )
5526 {
5527 // Generate an ENTER event
5528 m_mouseInWindow = true;
5529
5530 #ifdef HAVE_TRACKMOUSEEVENT
5531 typedef BOOL (WINAPI *_TrackMouseEvent_t)(LPTRACKMOUSEEVENT);
5532 #ifdef __WXWINCE__
5533 static const _TrackMouseEvent_t
5534 s_pfn_TrackMouseEvent = _TrackMouseEvent;
5535 #else // !__WXWINCE__
5536 static _TrackMouseEvent_t s_pfn_TrackMouseEvent;
5537 static bool s_initDone = false;
5538 if ( !s_initDone )
5539 {
5540 // see comment in wxApp::GetComCtl32Version() explaining the
5541 // use of wxLoadedDLL
5542 wxLoadedDLL dllComCtl32(wxT("comctl32.dll"));
5543 if ( dllComCtl32.IsLoaded() )
5544 {
5545 s_pfn_TrackMouseEvent = (_TrackMouseEvent_t)
5546 dllComCtl32.RawGetSymbol(wxT("_TrackMouseEvent"));
5547 }
5548
5549 s_initDone = true;
5550 }
5551
5552 if ( s_pfn_TrackMouseEvent )
5553 #endif // __WXWINCE__/!__WXWINCE__
5554 {
5555 WinStruct<TRACKMOUSEEVENT> trackinfo;
5556
5557 trackinfo.dwFlags = TME_LEAVE;
5558 trackinfo.hwndTrack = GetHwnd();
5559
5560 (*s_pfn_TrackMouseEvent)(&trackinfo);
5561 }
5562 #endif // HAVE_TRACKMOUSEEVENT
5563
5564 wxMouseEvent event(wxEVT_ENTER_WINDOW);
5565 InitMouseEvent(event, x, y, flags);
5566
5567 (void)HandleWindowEvent(event);
5568 }
5569 }
5570 #ifdef HAVE_TRACKMOUSEEVENT
5571 else // mouse not in window
5572 {
5573 // Check if we need to send a LEAVE event
5574 // Windows doesn't send WM_MOUSELEAVE if the mouse has been captured so
5575 // send it here if we are using native mouse leave tracking
5576 if ( HasCapture() && !IsMouseInWindow() )
5577 {
5578 GenerateMouseLeave();
5579 }
5580 }
5581 #endif // HAVE_TRACKMOUSEEVENT
5582
5583 #if wxUSE_MOUSEEVENT_HACK
5584 // Windows often generates mouse events even if mouse position hasn't
5585 // changed (http://article.gmane.org/gmane.comp.lib.wxwidgets.devel/66576)
5586 //
5587 // Filter this out as it can result in unexpected behaviour compared to
5588 // other platforms
5589 if ( gs_lastMouseEvent.type == wxEVT_RIGHT_DOWN ||
5590 gs_lastMouseEvent.type == wxEVT_LEFT_DOWN ||
5591 gs_lastMouseEvent.type == wxEVT_MIDDLE_DOWN ||
5592 gs_lastMouseEvent.type == wxEVT_MOTION )
5593 {
5594 if ( ClientToScreen(wxPoint(x, y)) == gs_lastMouseEvent.pos )
5595 {
5596 gs_lastMouseEvent.type = wxEVT_MOTION;
5597
5598 return false;
5599 }
5600 }
5601 #endif // wxUSE_MOUSEEVENT_HACK
5602
5603 return HandleMouseEvent(WM_MOUSEMOVE, x, y, flags);
5604 }
5605
5606
5607 bool
5608 wxWindowMSW::HandleMouseWheel(wxMouseWheelAxis axis,
5609 WXWPARAM wParam, WXLPARAM lParam)
5610 {
5611 #if wxUSE_MOUSEWHEEL
5612 // notice that WM_MOUSEWHEEL position is in screen coords (as it's
5613 // forwarded up to the parent by DefWindowProc()) and not in the client
5614 // ones as all the other messages, translate them to the client coords for
5615 // consistency
5616 const wxPoint
5617 pt = ScreenToClient(wxPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
5618 wxMouseEvent event(wxEVT_MOUSEWHEEL);
5619 InitMouseEvent(event, pt.x, pt.y, LOWORD(wParam));
5620 event.m_wheelRotation = (short)HIWORD(wParam);
5621 event.m_wheelDelta = WHEEL_DELTA;
5622 event.m_wheelAxis = axis;
5623
5624 static int s_linesPerRotation = -1;
5625 if ( s_linesPerRotation == -1 )
5626 {
5627 if ( !::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
5628 &s_linesPerRotation, 0))
5629 {
5630 // this is not supposed to happen
5631 wxLogLastError(wxT("SystemParametersInfo(GETWHEELSCROLLLINES)"));
5632
5633 // the default is 3, so use it if SystemParametersInfo() failed
5634 s_linesPerRotation = 3;
5635 }
5636 }
5637
5638 static int s_columnsPerRotation = -1;
5639 if ( s_columnsPerRotation == -1 )
5640 {
5641 if ( !::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0,
5642 &s_columnsPerRotation, 0))
5643 {
5644 // this setting is not supported on Windows 2000/XP, so use the value of 1
5645 // http://msdn.microsoft.com/en-us/library/ms997498.aspx
5646 s_columnsPerRotation = 1;
5647 }
5648 }
5649
5650 event.m_linesPerAction = s_linesPerRotation;
5651 event.m_columnsPerAction = s_columnsPerRotation;
5652 return HandleWindowEvent(event);
5653
5654 #else // !wxUSE_MOUSEWHEEL
5655 wxUnusedVar(wParam);
5656 wxUnusedVar(lParam);
5657
5658 return false;
5659 #endif // wxUSE_MOUSEWHEEL/!wxUSE_MOUSEWHEEL
5660 }
5661
5662 void wxWindowMSW::GenerateMouseLeave()
5663 {
5664 m_mouseInWindow = false;
5665
5666 int state = 0;
5667 if ( wxIsShiftDown() )
5668 state |= MK_SHIFT;
5669 if ( wxIsCtrlDown() )
5670 state |= MK_CONTROL;
5671
5672 // Only the high-order bit should be tested
5673 if ( GetKeyState( VK_LBUTTON ) & (1<<15) )
5674 state |= MK_LBUTTON;
5675 if ( GetKeyState( VK_MBUTTON ) & (1<<15) )
5676 state |= MK_MBUTTON;
5677 if ( GetKeyState( VK_RBUTTON ) & (1<<15) )
5678 state |= MK_RBUTTON;
5679
5680 POINT pt;
5681 wxGetCursorPosMSW(&pt);
5682
5683 // we need to have client coordinates here for symmetry with
5684 // wxEVT_ENTER_WINDOW
5685 RECT rect = wxGetWindowRect(GetHwnd());
5686 pt.x -= rect.left;
5687 pt.y -= rect.top;
5688
5689 wxMouseEvent event(wxEVT_LEAVE_WINDOW);
5690 InitMouseEvent(event, pt.x, pt.y, state);
5691
5692 (void)HandleWindowEvent(event);
5693 }
5694
5695 // ---------------------------------------------------------------------------
5696 // keyboard handling
5697 // ---------------------------------------------------------------------------
5698
5699 namespace
5700 {
5701
5702 // Implementation of InitAnyKeyEvent() which can also be used when there is no
5703 // associated window: this can happen for the wxEVT_CHAR_HOOK events created by
5704 // the global keyboard hook (e.g. the event might have happened in a non-wx
5705 // window).
5706 void
5707 MSWInitAnyKeyEvent(wxKeyEvent& event,
5708 WXWPARAM wParam,
5709 WXLPARAM lParam,
5710 const wxWindowBase *win /* may be NULL */)
5711 {
5712 if ( win )
5713 {
5714 event.SetId(win->GetId());
5715 event.SetEventObject(const_cast<wxWindowBase *>(win));
5716 }
5717 else // No associated window.
5718 {
5719 // Use wxID_ANY for compatibility with the old code even if wxID_NONE
5720 // would arguably make more sense.
5721 event.SetId(wxID_ANY);
5722 }
5723
5724 event.m_shiftDown = wxIsShiftDown();
5725 event.m_controlDown = wxIsCtrlDown();
5726 event.m_altDown = (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN;
5727
5728 event.m_rawCode = (wxUint32) wParam;
5729 event.m_rawFlags = (wxUint32) lParam;
5730 #ifndef __WXWINCE__
5731 event.SetTimestamp(::GetMessageTime());
5732 #endif
5733 }
5734
5735 } // anonymous namespace
5736
5737 void
5738 wxWindowMSW::InitAnyKeyEvent(wxKeyEvent& event,
5739 WXWPARAM wParam,
5740 WXLPARAM lParam) const
5741 {
5742 MSWInitAnyKeyEvent(event, wParam, lParam, this);
5743 }
5744
5745 wxKeyEvent
5746 wxWindowMSW::CreateKeyEvent(wxEventType evType,
5747 WXWPARAM wParam,
5748 WXLPARAM lParam) const
5749 {
5750 // Catch any attempts to use this with WM_CHAR, it wouldn't work because
5751 // wParam is supposed to be a virtual key and not a character here.
5752 wxASSERT_MSG( evType != wxEVT_CHAR && evType != wxEVT_CHAR_HOOK,
5753 "CreateKeyEvent() can't be used for char events" );
5754
5755 wxKeyEvent event(evType);
5756 InitAnyKeyEvent(event, wParam, lParam);
5757
5758 event.m_keyCode = wxMSWKeyboard::VKToWX
5759 (
5760 wParam,
5761 lParam
5762 #if wxUSE_UNICODE
5763 , &event.m_uniChar
5764 #endif // wxUSE_UNICODE
5765 );
5766
5767 return event;
5768 }
5769
5770 wxKeyEvent
5771 wxWindowMSW::CreateCharEvent(wxEventType evType,
5772 WXWPARAM wParam,
5773 WXLPARAM lParam) const
5774 {
5775 wxKeyEvent event(evType);
5776 InitAnyKeyEvent(event, wParam, lParam);
5777
5778 #if wxUSE_UNICODE
5779 // TODO: wParam uses UTF-16 so this is incorrect for characters outside of
5780 // the BMP, we should use WM_UNICHAR to handle them.
5781 event.m_uniChar = wParam;
5782 #endif // wxUSE_UNICODE
5783
5784 // Set non-Unicode key code too for compatibility if possible.
5785 if ( wParam < 0x80 )
5786 {
5787 // It's an ASCII character, no need to translate it.
5788 event.m_keyCode = wParam;
5789 }
5790 else
5791 {
5792 // Check if this key can be represented (as a single character) in the
5793 // current locale.
5794 const wchar_t wc = wParam;
5795 char ch;
5796 if ( wxConvLibc.FromWChar(&ch, 1, &wc, 1) != wxCONV_FAILED )
5797 {
5798 // For compatibility continue to provide the key code in this field
5799 // even though using GetUnicodeKey() is recommended now.
5800 event.m_keyCode = static_cast<unsigned char>(ch);
5801 }
5802 //else: Key can't be represented in the current locale, leave m_keyCode
5803 // as WXK_NONE and use GetUnicodeKey() to access the character.
5804 }
5805
5806 // the alphanumeric keys produced by pressing AltGr+something on European
5807 // keyboards have both Ctrl and Alt modifiers which may confuse the user
5808 // code as, normally, keys with Ctrl and/or Alt don't result in anything
5809 // alphanumeric, so pretend that there are no modifiers at all (the
5810 // KEY_DOWN event would still have the correct modifiers if they're really
5811 // needed)
5812 if ( event.m_controlDown && event.m_altDown &&
5813 (event.m_keyCode >= 32 && event.m_keyCode < 256) )
5814 {
5815 event.m_controlDown =
5816 event.m_altDown = false;
5817 }
5818
5819 return event;
5820 }
5821
5822 // isASCII is true only when we're called from WM_CHAR handler and not from
5823 // WM_KEYDOWN one
5824 bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam)
5825 {
5826 wxKeyEvent event(CreateCharEvent(wxEVT_CHAR, wParam, lParam));
5827 return HandleWindowEvent(event);
5828 }
5829
5830 bool wxWindowMSW::HandleKeyDown(WXWPARAM wParam, WXLPARAM lParam)
5831 {
5832 wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_DOWN, wParam, lParam));
5833 return HandleWindowEvent(event);
5834 }
5835
5836 bool wxWindowMSW::HandleKeyUp(WXWPARAM wParam, WXLPARAM lParam)
5837 {
5838 wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_UP, wParam, lParam));
5839 return HandleWindowEvent(event);
5840 }
5841
5842 #if wxUSE_MENUS
5843 int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel),
5844 WXLPARAM WXUNUSED_IN_WINCE(lParam))
5845 {
5846 // FIXME: implement GetMenuItemCount for WinCE, possibly
5847 // in terms of GetMenuItemInfo
5848 #ifndef __WXWINCE__
5849 const HMENU hmenu = (HMENU)lParam;
5850
5851 WinStruct<MENUITEMINFO> mii;
5852
5853 // we could use MIIM_FTYPE here as we only need to know if the item is
5854 // ownerdrawn or not and not dwTypeData which MIIM_TYPE also returns, but
5855 // MIIM_FTYPE is not supported under Win95
5856 mii.fMask = MIIM_TYPE | MIIM_DATA;
5857
5858 // find if we have this letter in any owner drawn item
5859 const int count = ::GetMenuItemCount(hmenu);
5860 for ( int i = 0; i < count; i++ )
5861 {
5862 // previous loop iteration could modify it, reset it back before
5863 // calling GetMenuItemInfo() to prevent it from overflowing dwTypeData
5864 mii.cch = 0;
5865
5866 if ( ::GetMenuItemInfo(hmenu, i, TRUE, &mii) )
5867 {
5868 if ( mii.fType == MFT_OWNERDRAW )
5869 {
5870 // dwItemData member of the MENUITEMINFO is a
5871 // pointer to the associated wxMenuItem -- see the
5872 // menu creation code
5873 wxMenuItem *item = (wxMenuItem*)mii.dwItemData;
5874
5875 const wxString label(item->GetItemLabel());
5876 const wxChar *p = wxStrchr(label.t_str(), wxT('&'));
5877 while ( p++ )
5878 {
5879 if ( *p == wxT('&') )
5880 {
5881 // this is not the accel char, find the real one
5882 p = wxStrchr(p + 1, wxT('&'));
5883 }
5884 else // got the accel char
5885 {
5886 // FIXME-UNICODE: this comparison doesn't risk to work
5887 // for non ASCII accelerator characters I'm afraid, but
5888 // what can we do?
5889 if ( (wchar_t)wxToupper(*p) == (wchar_t)chAccel )
5890 {
5891 return i;
5892 }
5893 else
5894 {
5895 // this one doesn't match
5896 break;
5897 }
5898 }
5899 }
5900 }
5901 }
5902 else // failed to get the menu text?
5903 {
5904 // it's not fatal, so don't show error, but still log it
5905 wxLogLastError(wxT("GetMenuItemInfo"));
5906 }
5907 }
5908 #endif
5909 return wxNOT_FOUND;
5910 }
5911
5912 #endif // wxUSE_MENUS
5913
5914 bool wxWindowMSW::HandleClipboardEvent(WXUINT nMsg)
5915 {
5916 const wxEventType type = nMsg == WM_CUT ? wxEVT_TEXT_CUT
5917 : nMsg == WM_COPY ? wxEVT_TEXT_COPY
5918 : /* nMsg == WM_PASTE */ wxEVT_TEXT_PASTE;
5919 wxClipboardTextEvent evt(type, GetId());
5920
5921 evt.SetEventObject(this);
5922
5923 return HandleWindowEvent(evt);
5924 }
5925
5926 // ---------------------------------------------------------------------------
5927 // joystick
5928 // ---------------------------------------------------------------------------
5929
5930 bool wxWindowMSW::HandleJoystickEvent(WXUINT msg, int x, int y, WXUINT flags)
5931 {
5932 #ifdef JOY_BUTTON1
5933 int change = 0;
5934 if ( flags & JOY_BUTTON1CHG )
5935 change = wxJOY_BUTTON1;
5936 if ( flags & JOY_BUTTON2CHG )
5937 change = wxJOY_BUTTON2;
5938 if ( flags & JOY_BUTTON3CHG )
5939 change = wxJOY_BUTTON3;
5940 if ( flags & JOY_BUTTON4CHG )
5941 change = wxJOY_BUTTON4;
5942
5943 int buttons = 0;
5944 if ( flags & JOY_BUTTON1 )
5945 buttons |= wxJOY_BUTTON1;
5946 if ( flags & JOY_BUTTON2 )
5947 buttons |= wxJOY_BUTTON2;
5948 if ( flags & JOY_BUTTON3 )
5949 buttons |= wxJOY_BUTTON3;
5950 if ( flags & JOY_BUTTON4 )
5951 buttons |= wxJOY_BUTTON4;
5952
5953 // the event ids aren't consecutive so we can't use table based lookup
5954 int joystick;
5955 wxEventType eventType;
5956 switch ( msg )
5957 {
5958 case MM_JOY1MOVE:
5959 joystick = 1;
5960 eventType = wxEVT_JOY_MOVE;
5961 break;
5962
5963 case MM_JOY2MOVE:
5964 joystick = 2;
5965 eventType = wxEVT_JOY_MOVE;
5966 break;
5967
5968 case MM_JOY1ZMOVE:
5969 joystick = 1;
5970 eventType = wxEVT_JOY_ZMOVE;
5971 break;
5972
5973 case MM_JOY2ZMOVE:
5974 joystick = 2;
5975 eventType = wxEVT_JOY_ZMOVE;
5976 break;
5977
5978 case MM_JOY1BUTTONDOWN:
5979 joystick = 1;
5980 eventType = wxEVT_JOY_BUTTON_DOWN;
5981 break;
5982
5983 case MM_JOY2BUTTONDOWN:
5984 joystick = 2;
5985 eventType = wxEVT_JOY_BUTTON_DOWN;
5986 break;
5987
5988 case MM_JOY1BUTTONUP:
5989 joystick = 1;
5990 eventType = wxEVT_JOY_BUTTON_UP;
5991 break;
5992
5993 case MM_JOY2BUTTONUP:
5994 joystick = 2;
5995 eventType = wxEVT_JOY_BUTTON_UP;
5996 break;
5997
5998 default:
5999 wxFAIL_MSG(wxT("no such joystick event"));
6000
6001 return false;
6002 }
6003
6004 wxJoystickEvent event(eventType, buttons, joystick, change);
6005 if ( eventType == wxEVT_JOY_ZMOVE )
6006 event.SetZPosition(x);
6007 else
6008 event.SetPosition(wxPoint(x, y));
6009 event.SetEventObject(this);
6010
6011 return HandleWindowEvent(event);
6012 #else
6013 wxUnusedVar(msg);
6014 wxUnusedVar(x);
6015 wxUnusedVar(y);
6016 wxUnusedVar(flags);
6017 return false;
6018 #endif
6019 }
6020
6021 // ---------------------------------------------------------------------------
6022 // scrolling
6023 // ---------------------------------------------------------------------------
6024
6025 bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam,
6026 WXWORD pos, WXHWND control)
6027 {
6028 if ( control && control != m_hWnd ) // Prevent infinite recursion
6029 {
6030 wxWindow *child = wxFindWinFromHandle(control);
6031 if ( child )
6032 return child->MSWOnScroll(orientation, wParam, pos, control);
6033 }
6034
6035 wxScrollWinEvent event;
6036 event.SetPosition(pos);
6037 event.SetOrientation(orientation);
6038 event.SetEventObject(this);
6039
6040 switch ( wParam )
6041 {
6042 case SB_TOP:
6043 event.SetEventType(wxEVT_SCROLLWIN_TOP);
6044 break;
6045
6046 case SB_BOTTOM:
6047 event.SetEventType(wxEVT_SCROLLWIN_BOTTOM);
6048 break;
6049
6050 case SB_LINEUP:
6051 event.SetEventType(wxEVT_SCROLLWIN_LINEUP);
6052 break;
6053
6054 case SB_LINEDOWN:
6055 event.SetEventType(wxEVT_SCROLLWIN_LINEDOWN);
6056 break;
6057
6058 case SB_PAGEUP:
6059 event.SetEventType(wxEVT_SCROLLWIN_PAGEUP);
6060 break;
6061
6062 case SB_PAGEDOWN:
6063 event.SetEventType(wxEVT_SCROLLWIN_PAGEDOWN);
6064 break;
6065
6066 case SB_THUMBPOSITION:
6067 case SB_THUMBTRACK:
6068 // under Win32, the scrollbar range and position are 32 bit integers,
6069 // but WM_[HV]SCROLL only carry the low 16 bits of them, so we must
6070 // explicitly query the scrollbar for the correct position (this must
6071 // be done only for these two SB_ events as they are the only one
6072 // carrying the scrollbar position)
6073 {
6074 WinStruct<SCROLLINFO> scrollInfo;
6075 scrollInfo.fMask = SIF_TRACKPOS;
6076
6077 if ( !::GetScrollInfo(GetHwnd(),
6078 WXOrientToSB(orientation),
6079 &scrollInfo) )
6080 {
6081 // Not necessarily an error, if there are no scrollbars yet.
6082 // wxLogLastError(wxT("GetScrollInfo"));
6083 }
6084
6085 event.SetPosition(scrollInfo.nTrackPos);
6086 }
6087
6088 event.SetEventType( wParam == SB_THUMBPOSITION
6089 ? wxEVT_SCROLLWIN_THUMBRELEASE
6090 : wxEVT_SCROLLWIN_THUMBTRACK );
6091 break;
6092
6093 default:
6094 return false;
6095 }
6096
6097 return HandleWindowEvent(event);
6098 }
6099
6100 // ----------------------------------------------------------------------------
6101 // custom message handlers
6102 // ----------------------------------------------------------------------------
6103
6104 /* static */ bool
6105 wxWindowMSW::MSWRegisterMessageHandler(int msg, MSWMessageHandler handler)
6106 {
6107 wxCHECK_MSG( gs_messageHandlers.find(msg) == gs_messageHandlers.end(),
6108 false, wxT("registering handler for the same message twice") );
6109
6110 gs_messageHandlers[msg] = handler;
6111 return true;
6112 }
6113
6114 /* static */ void
6115 wxWindowMSW::MSWUnregisterMessageHandler(int msg, MSWMessageHandler handler)
6116 {
6117 const MSWMessageHandlers::iterator i = gs_messageHandlers.find(msg);
6118 wxCHECK_RET( i != gs_messageHandlers.end() && i->second == handler,
6119 wxT("unregistering non-registered handler?") );
6120
6121 gs_messageHandlers.erase(i);
6122 }
6123
6124 // ===========================================================================
6125 // global functions
6126 // ===========================================================================
6127
6128 void wxGetCharSize(WXHWND wnd, int *x, int *y, const wxFont& the_font)
6129 {
6130 TEXTMETRIC tm;
6131 HDC dc = ::GetDC((HWND) wnd);
6132 HFONT was = 0;
6133
6134 // the_font.UseResource();
6135 // the_font.RealizeResource();
6136 HFONT fnt = (HFONT)the_font.GetResourceHandle(); // const_cast
6137 if ( fnt )
6138 was = (HFONT) SelectObject(dc,fnt);
6139
6140 GetTextMetrics(dc, &tm);
6141 if ( fnt && was )
6142 {
6143 SelectObject(dc,was);
6144 }
6145 ReleaseDC((HWND)wnd, dc);
6146
6147 if ( x )
6148 *x = tm.tmAveCharWidth;
6149 if ( y )
6150 *y = tm.tmHeight + tm.tmExternalLeading;
6151
6152 // the_font.ReleaseResource();
6153 }
6154
6155 // ----------------------------------------------------------------------------
6156 // keyboard codes
6157 // ----------------------------------------------------------------------------
6158
6159 namespace wxMSWKeyboard
6160 {
6161
6162 namespace
6163 {
6164
6165 // use the "extended" bit of lParam to distinguish extended keys from normal
6166 // keys as the same virtual key code is sent for both by Windows
6167 inline
6168 int ChooseNormalOrExtended(int lParam, int keyNormal, int keyExtended)
6169 {
6170 // except that if lParam is 0, it means we don't have real lParam from
6171 // WM_KEYDOWN but are just translating just a VK constant (e.g. done from
6172 // msw/treectrl.cpp when processing TVN_KEYDOWN) -- then assume this is a
6173 // non-numpad (hence extended) key as this is a more common case
6174 return !lParam || (HIWORD(lParam) & KF_EXTENDED) ? keyExtended : keyNormal;
6175 }
6176
6177 // this array contains the Windows virtual key codes which map one to one to
6178 // WXK_xxx constants and is used in wxMSWKeyboard::VKToWX/WXToVK() below
6179 //
6180 // note that keys having a normal and numpad version (e.g. WXK_HOME and
6181 // WXK_NUMPAD_HOME) are not included in this table as the mapping is not 1-to-1
6182 const struct wxKeyMapping
6183 {
6184 int vk;
6185 wxKeyCode wxk;
6186 } gs_specialKeys[] =
6187 {
6188 { VK_CANCEL, WXK_CANCEL },
6189 { VK_BACK, WXK_BACK },
6190 { VK_TAB, WXK_TAB },
6191 { VK_CLEAR, WXK_CLEAR },
6192 { VK_SHIFT, WXK_SHIFT },
6193 { VK_CONTROL, WXK_CONTROL },
6194 { VK_MENU , WXK_ALT },
6195 { VK_PAUSE, WXK_PAUSE },
6196 { VK_CAPITAL, WXK_CAPITAL },
6197 { VK_SPACE, WXK_SPACE },
6198 { VK_ESCAPE, WXK_ESCAPE },
6199 { VK_SELECT, WXK_SELECT },
6200 { VK_PRINT, WXK_PRINT },
6201 { VK_EXECUTE, WXK_EXECUTE },
6202 { VK_SNAPSHOT, WXK_SNAPSHOT },
6203 { VK_HELP, WXK_HELP },
6204
6205 { VK_NUMPAD0, WXK_NUMPAD0 },
6206 { VK_NUMPAD1, WXK_NUMPAD1 },
6207 { VK_NUMPAD2, WXK_NUMPAD2 },
6208 { VK_NUMPAD3, WXK_NUMPAD3 },
6209 { VK_NUMPAD4, WXK_NUMPAD4 },
6210 { VK_NUMPAD5, WXK_NUMPAD5 },
6211 { VK_NUMPAD6, WXK_NUMPAD6 },
6212 { VK_NUMPAD7, WXK_NUMPAD7 },
6213 { VK_NUMPAD8, WXK_NUMPAD8 },
6214 { VK_NUMPAD9, WXK_NUMPAD9 },
6215 { VK_MULTIPLY, WXK_NUMPAD_MULTIPLY },
6216 { VK_ADD, WXK_NUMPAD_ADD },
6217 { VK_SUBTRACT, WXK_NUMPAD_SUBTRACT },
6218 { VK_DECIMAL, WXK_NUMPAD_DECIMAL },
6219 { VK_DIVIDE, WXK_NUMPAD_DIVIDE },
6220
6221 { VK_F1, WXK_F1 },
6222 { VK_F2, WXK_F2 },
6223 { VK_F3, WXK_F3 },
6224 { VK_F4, WXK_F4 },
6225 { VK_F5, WXK_F5 },
6226 { VK_F6, WXK_F6 },
6227 { VK_F7, WXK_F7 },
6228 { VK_F8, WXK_F8 },
6229 { VK_F9, WXK_F9 },
6230 { VK_F10, WXK_F10 },
6231 { VK_F11, WXK_F11 },
6232 { VK_F12, WXK_F12 },
6233 { VK_F13, WXK_F13 },
6234 { VK_F14, WXK_F14 },
6235 { VK_F15, WXK_F15 },
6236 { VK_F16, WXK_F16 },
6237 { VK_F17, WXK_F17 },
6238 { VK_F18, WXK_F18 },
6239 { VK_F19, WXK_F19 },
6240 { VK_F20, WXK_F20 },
6241 { VK_F21, WXK_F21 },
6242 { VK_F22, WXK_F22 },
6243 { VK_F23, WXK_F23 },
6244 { VK_F24, WXK_F24 },
6245
6246 { VK_NUMLOCK, WXK_NUMLOCK },
6247 { VK_SCROLL, WXK_SCROLL },
6248
6249 #ifdef VK_APPS
6250 { VK_LWIN, WXK_WINDOWS_LEFT },
6251 { VK_RWIN, WXK_WINDOWS_RIGHT },
6252 { VK_APPS, WXK_WINDOWS_MENU },
6253 #endif // VK_APPS defined
6254 };
6255
6256 } // anonymous namespace
6257
6258 int VKToWX(WXWORD vk, WXLPARAM lParam, wchar_t *uc)
6259 {
6260 int wxk;
6261
6262 // check the table first
6263 for ( size_t n = 0; n < WXSIZEOF(gs_specialKeys); n++ )
6264 {
6265 if ( gs_specialKeys[n].vk == vk )
6266 {
6267 wxk = gs_specialKeys[n].wxk;
6268 if ( wxk < WXK_START )
6269 {
6270 // Unicode code for this key is the same as its ASCII code.
6271 if ( uc )
6272 *uc = wxk;
6273 }
6274
6275 return wxk;
6276 }
6277 }
6278
6279 // keys requiring special handling
6280 switch ( vk )
6281 {
6282 case VK_OEM_1:
6283 case VK_OEM_PLUS:
6284 case VK_OEM_COMMA:
6285 case VK_OEM_MINUS:
6286 case VK_OEM_PERIOD:
6287 case VK_OEM_2:
6288 case VK_OEM_3:
6289 case VK_OEM_4:
6290 case VK_OEM_5:
6291 case VK_OEM_6:
6292 case VK_OEM_7:
6293 case VK_OEM_102:
6294 // MapVirtualKey() returns 0 if it fails to convert the virtual
6295 // key which nicely corresponds to our WXK_NONE.
6296 wxk = ::MapVirtualKey(vk, MAPVK_VK_TO_CHAR);
6297
6298 if ( HIWORD(wxk) & 0x8000 )
6299 {
6300 // It's a dead key and we don't return anything at all for them
6301 // as we simply don't have any way to indicate the difference
6302 // between e.g. a normal "'" and "'" as a dead key -- and
6303 // generating the same events for them just doesn't seem like a
6304 // good idea.
6305 wxk = WXK_NONE;
6306 }
6307
6308 // In any case return this as a Unicode character value.
6309 if ( uc )
6310 *uc = wxk;
6311
6312 // For compatibility with the old non-Unicode code we continue
6313 // returning key codes for Latin-1 characters directly
6314 // (normally it would really only make sense to do it for the
6315 // ASCII characters, not Latin-1 ones).
6316 if ( wxk > 255 )
6317 {
6318 // But for anything beyond this we can only return the key
6319 // value as a real Unicode character, not a wxKeyCode
6320 // because this enum values clash with Unicode characters
6321 // (e.g. WXK_LBUTTON also happens to be U+012C a.k.a.
6322 // "LATIN CAPITAL LETTER I WITH BREVE").
6323 wxk = WXK_NONE;
6324 }
6325 break;
6326
6327 // handle extended keys
6328 case VK_PRIOR:
6329 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_PAGEUP, WXK_PAGEUP);
6330 break;
6331
6332 case VK_NEXT:
6333 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_PAGEDOWN, WXK_PAGEDOWN);
6334 break;
6335
6336 case VK_END:
6337 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_END, WXK_END);
6338 break;
6339
6340 case VK_HOME:
6341 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_HOME, WXK_HOME);
6342 break;
6343
6344 case VK_LEFT:
6345 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_LEFT, WXK_LEFT);
6346 break;
6347
6348 case VK_UP:
6349 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_UP, WXK_UP);
6350 break;
6351
6352 case VK_RIGHT:
6353 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_RIGHT, WXK_RIGHT);
6354 break;
6355
6356 case VK_DOWN:
6357 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DOWN, WXK_DOWN);
6358 break;
6359
6360 case VK_INSERT:
6361 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_INSERT, WXK_INSERT);
6362 break;
6363
6364 case VK_DELETE:
6365 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DELETE, WXK_DELETE);
6366
6367 if ( uc )
6368 *uc = WXK_DELETE;
6369 break;
6370
6371 case VK_RETURN:
6372 // don't use ChooseNormalOrExtended() here as the keys are reversed
6373 // here: numpad enter is the extended one
6374 wxk = HIWORD(lParam) & KF_EXTENDED ? WXK_NUMPAD_ENTER : WXK_RETURN;
6375
6376 if ( uc )
6377 *uc = WXK_RETURN;
6378 break;
6379
6380 default:
6381 if ( (vk >= '0' && vk <= '9') || (vk >= 'A' && vk <= 'Z') )
6382 {
6383 // A simple alphanumeric key and the values of them coincide in
6384 // Windows and wx for both ASCII and Unicode codes.
6385 wxk = vk;
6386 }
6387 else // Something we simply don't know about at all.
6388 {
6389 wxk = WXK_NONE;
6390 }
6391
6392 if ( uc )
6393 *uc = vk;
6394 }
6395
6396 return wxk;
6397 }
6398
6399 WXWORD WXToVK(int wxk, bool *isExtended)
6400 {
6401 // check the table first
6402 for ( size_t n = 0; n < WXSIZEOF(gs_specialKeys); n++ )
6403 {
6404 if ( gs_specialKeys[n].wxk == wxk )
6405 {
6406 // All extended keys (i.e. non-numpad versions of the keys that
6407 // exist both in the numpad and outside of it) are dealt with
6408 // below.
6409 if ( isExtended )
6410 *isExtended = false;
6411
6412 return gs_specialKeys[n].vk;
6413 }
6414 }
6415
6416 // and then check for special keys not included in the table
6417 bool extended = false;
6418 WXWORD vk;
6419 switch ( wxk )
6420 {
6421 case WXK_PAGEUP:
6422 extended = true;
6423 case WXK_NUMPAD_PAGEUP:
6424 vk = VK_PRIOR;
6425 break;
6426
6427 case WXK_PAGEDOWN:
6428 extended = true;
6429 case WXK_NUMPAD_PAGEDOWN:
6430 vk = VK_NEXT;
6431 break;
6432
6433 case WXK_END:
6434 extended = true;
6435 case WXK_NUMPAD_END:
6436 vk = VK_END;
6437 break;
6438
6439 case WXK_HOME:
6440 extended = true;
6441 case WXK_NUMPAD_HOME:
6442 vk = VK_HOME;
6443 break;
6444
6445 case WXK_LEFT:
6446 extended = true;
6447 case WXK_NUMPAD_LEFT:
6448 vk = VK_LEFT;
6449 break;
6450
6451 case WXK_UP:
6452 extended = true;
6453 case WXK_NUMPAD_UP:
6454 vk = VK_UP;
6455 break;
6456
6457 case WXK_RIGHT:
6458 extended = true;
6459 case WXK_NUMPAD_RIGHT:
6460 vk = VK_RIGHT;
6461 break;
6462
6463 case WXK_DOWN:
6464 extended = true;
6465 case WXK_NUMPAD_DOWN:
6466 vk = VK_DOWN;
6467 break;
6468
6469 case WXK_INSERT:
6470 extended = true;
6471 case WXK_NUMPAD_INSERT:
6472 vk = VK_INSERT;
6473 break;
6474
6475 case WXK_DELETE:
6476 extended = true;
6477 case WXK_NUMPAD_DELETE:
6478 vk = VK_DELETE;
6479 break;
6480
6481 default:
6482 // no VkKeyScan() under CE unfortunately, we need to test how does
6483 // it handle OEM keys
6484 #ifndef __WXWINCE__
6485 // check to see if its one of the OEM key codes.
6486 BYTE vks = LOBYTE(VkKeyScan(wxk));
6487 if ( vks != 0xff )
6488 {
6489 vk = vks;
6490 }
6491 else
6492 #endif // !__WXWINCE__
6493 {
6494 vk = (WXWORD)wxk;
6495 }
6496 }
6497
6498 if ( isExtended )
6499 *isExtended = extended;
6500
6501 return vk;
6502 }
6503
6504 } // namespace wxMSWKeyboard
6505
6506 // small helper for wxGetKeyState() and wxGetMouseState()
6507 static inline bool wxIsKeyDown(WXWORD vk)
6508 {
6509 // SM_SWAPBUTTON is not available under CE, so don't swap buttons there
6510 #ifdef SM_SWAPBUTTON
6511 if ( vk == VK_LBUTTON || vk == VK_RBUTTON )
6512 {
6513 if ( ::GetSystemMetrics(SM_SWAPBUTTON) )
6514 {
6515 if ( vk == VK_LBUTTON )
6516 vk = VK_RBUTTON;
6517 else // vk == VK_RBUTTON
6518 vk = VK_LBUTTON;
6519 }
6520 }
6521 #endif // SM_SWAPBUTTON
6522
6523 // the low order bit indicates whether the key was pressed since the last
6524 // call and the high order one indicates whether it is down right now and
6525 // we only want that one
6526 return (GetAsyncKeyState(vk) & (1<<15)) != 0;
6527 }
6528
6529 bool wxGetKeyState(wxKeyCode key)
6530 {
6531 // although this does work under Windows, it is not supported under other
6532 // platforms so don't allow it, you must use wxGetMouseState() instead
6533 wxASSERT_MSG( key != VK_LBUTTON &&
6534 key != VK_RBUTTON &&
6535 key != VK_MBUTTON,
6536 wxT("can't use wxGetKeyState() for mouse buttons") );
6537
6538 const WXWORD vk = wxMSWKeyboard::WXToVK(key);
6539
6540 // if the requested key is a LED key, return true if the led is pressed
6541 if ( key == WXK_NUMLOCK || key == WXK_CAPITAL || key == WXK_SCROLL )
6542 {
6543 // low order bit means LED is highlighted and high order one means the
6544 // key is down; for compatibility with the other ports return true if
6545 // either one is set
6546 return GetKeyState(vk) != 0;
6547
6548 }
6549 else // normal key
6550 {
6551 return wxIsKeyDown(vk);
6552 }
6553 }
6554
6555
6556 wxMouseState wxGetMouseState()
6557 {
6558 wxMouseState ms;
6559 POINT pt;
6560 wxGetCursorPosMSW(&pt);
6561
6562 ms.SetX(pt.x);
6563 ms.SetY(pt.y);
6564 ms.SetLeftDown(wxIsKeyDown(VK_LBUTTON));
6565 ms.SetMiddleDown(wxIsKeyDown(VK_MBUTTON));
6566 ms.SetRightDown(wxIsKeyDown(VK_RBUTTON));
6567 #ifdef wxHAS_XBUTTON
6568 ms.SetAux1Down(wxIsKeyDown(VK_XBUTTON1));
6569 ms.SetAux2Down(wxIsKeyDown(VK_XBUTTON2));
6570 #endif // wxHAS_XBUTTON
6571
6572 ms.SetControlDown(wxIsCtrlDown ());
6573 ms.SetShiftDown (wxIsShiftDown());
6574 ms.SetAltDown (wxIsAltDown ());
6575 // ms.SetMetaDown();
6576
6577 return ms;
6578 }
6579
6580
6581 wxWindow *wxGetActiveWindow()
6582 {
6583 HWND hWnd = GetActiveWindow();
6584 if ( hWnd != 0 )
6585 {
6586 return wxFindWinFromHandle(hWnd);
6587 }
6588 return NULL;
6589 }
6590
6591 extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd)
6592 {
6593 HWND hwnd = (HWND)hWnd;
6594
6595 // For a radiobutton, we get the radiobox from GWL_USERDATA (which is set
6596 // by code in msw/radiobox.cpp), for all the others we just search up the
6597 // window hierarchy
6598 wxWindow *win = NULL;
6599 if ( hwnd )
6600 {
6601 win = wxFindWinFromHandle(hwnd);
6602 if ( !win )
6603 {
6604 #if wxUSE_RADIOBOX && !defined(__WXUNIVERSAL__)
6605 // native radiobuttons return DLGC_RADIOBUTTON here and for any
6606 // wxWindow class which overrides WM_GETDLGCODE processing to
6607 // do it as well, win would be already non NULL
6608 if ( ::SendMessage(hwnd, WM_GETDLGCODE, 0, 0) & DLGC_RADIOBUTTON )
6609 {
6610 win = wxRadioBox::GetFromRadioButtonHWND(hwnd);
6611 }
6612 //else: it's a wxRadioButton, not a radiobutton from wxRadioBox
6613 #endif // wxUSE_RADIOBOX
6614
6615 // spin control text buddy window should be mapped to spin ctrl
6616 // itself so try it too
6617 #if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__)
6618 if ( !win )
6619 {
6620 win = wxSpinCtrl::GetSpinForTextCtrl((WXHWND)hwnd);
6621 }
6622 #endif // wxUSE_SPINCTRL
6623 }
6624 }
6625
6626 while ( hwnd && !win )
6627 {
6628 // this is a really ugly hack needed to avoid mistakenly returning the
6629 // parent frame wxWindow for the find/replace modeless dialog HWND -
6630 // this, in turn, is needed to call IsDialogMessage() from
6631 // wxApp::ProcessMessage() as for this we must return NULL from here
6632 //
6633 // FIXME: this is clearly not the best way to do it but I think we'll
6634 // need to change HWND <-> wxWindow code more heavily than I can
6635 // do it now to fix it
6636 #ifndef __WXMICROWIN__
6637 if ( ::GetWindow(hwnd, GW_OWNER) )
6638 {
6639 // it's a dialog box, don't go upwards
6640 break;
6641 }
6642 #endif
6643
6644 hwnd = ::GetParent(hwnd);
6645 win = wxFindWinFromHandle(hwnd);
6646 }
6647
6648 return win;
6649 }
6650
6651 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
6652
6653 // Windows keyboard hook. Allows interception of e.g. F1, ESCAPE
6654 // in active frames and dialogs, regardless of where the focus is.
6655 static HHOOK wxTheKeyboardHook = 0;
6656
6657 int APIENTRY
6658 wxKeyboardHook(int nCode, WORD wParam, DWORD lParam)
6659 {
6660 DWORD hiWord = HIWORD(lParam);
6661 if ( nCode != HC_NOREMOVE && ((hiWord & KF_UP) == 0) )
6662 {
6663 wchar_t uc = 0;
6664 int id = wxMSWKeyboard::VKToWX(wParam, lParam, &uc);
6665
6666 // Don't intercept keyboard entry (notably Escape) if a modal window
6667 // (not managed by wx, e.g. IME one) is currently opened as more often
6668 // than not it needs all the keys for itself.
6669 //
6670 // Also don't catch it if a window currently captures the mouse as
6671 // Escape is normally used to release the mouse capture and if you
6672 // really need to catch all the keys in the window that has mouse
6673 // capture it can be easily done in its own EVT_CHAR handler as it is
6674 // certain to have focus while it has the capture.
6675 if ( !gs_modalEntryWindowCount && !::GetCapture() )
6676 {
6677 if ( id != WXK_NONE
6678 #if wxUSE_UNICODE
6679 || static_cast<int>(uc) != WXK_NONE
6680 #endif // wxUSE_UNICODE
6681 )
6682 {
6683 wxWindow const* win = wxWindow::DoFindFocus();
6684 if ( !win )
6685 {
6686 // Even if the focus got lost somehow, still send the event
6687 // to the top level parent to allow a wxDialog to always
6688 // close on Escape.
6689 win = wxGetActiveWindow();
6690 }
6691
6692 wxKeyEvent event(wxEVT_CHAR_HOOK);
6693 MSWInitAnyKeyEvent(event, wParam, lParam, win);
6694
6695 event.m_keyCode = id;
6696 #if wxUSE_UNICODE
6697 event.m_uniChar = uc;
6698 #endif // wxUSE_UNICODE
6699
6700 wxEvtHandler * const handler = win ? win->GetEventHandler()
6701 : wxTheApp;
6702
6703 if ( handler && handler->ProcessEvent(event) )
6704 {
6705 if ( !event.IsNextEventAllowed() )
6706 {
6707 // Stop processing of this event.
6708 return 1;
6709 }
6710 }
6711 }
6712 }
6713 }
6714
6715 return (int)CallNextHookEx(wxTheKeyboardHook, nCode, wParam, lParam);
6716 }
6717
6718 void wxSetKeyboardHook(bool doIt)
6719 {
6720 if ( doIt )
6721 {
6722 wxTheKeyboardHook = ::SetWindowsHookEx
6723 (
6724 WH_KEYBOARD,
6725 (HOOKPROC)wxKeyboardHook,
6726 NULL, // must be NULL for process hook
6727 ::GetCurrentThreadId()
6728 );
6729 if ( !wxTheKeyboardHook )
6730 {
6731 wxLogLastError(wxT("SetWindowsHookEx(wxKeyboardHook)"));
6732 }
6733 }
6734 else // uninstall
6735 {
6736 if ( wxTheKeyboardHook )
6737 ::UnhookWindowsHookEx(wxTheKeyboardHook);
6738 }
6739 }
6740
6741 #endif // !__WXMICROWIN__
6742
6743 #if wxDEBUG_LEVEL >= 2
6744 const wxChar *wxGetMessageName(int message)
6745 {
6746 switch ( message )
6747 {
6748 case 0x0000: return wxT("WM_NULL");
6749 case 0x0001: return wxT("WM_CREATE");
6750 case 0x0002: return wxT("WM_DESTROY");
6751 case 0x0003: return wxT("WM_MOVE");
6752 case 0x0005: return wxT("WM_SIZE");
6753 case 0x0006: return wxT("WM_ACTIVATE");
6754 case 0x0007: return wxT("WM_SETFOCUS");
6755 case 0x0008: return wxT("WM_KILLFOCUS");
6756 case 0x000A: return wxT("WM_ENABLE");
6757 case 0x000B: return wxT("WM_SETREDRAW");
6758 case 0x000C: return wxT("WM_SETTEXT");
6759 case 0x000D: return wxT("WM_GETTEXT");
6760 case 0x000E: return wxT("WM_GETTEXTLENGTH");
6761 case 0x000F: return wxT("WM_PAINT");
6762 case 0x0010: return wxT("WM_CLOSE");
6763 case 0x0011: return wxT("WM_QUERYENDSESSION");
6764 case 0x0012: return wxT("WM_QUIT");
6765 case 0x0013: return wxT("WM_QUERYOPEN");
6766 case 0x0014: return wxT("WM_ERASEBKGND");
6767 case 0x0015: return wxT("WM_SYSCOLORCHANGE");
6768 case 0x0016: return wxT("WM_ENDSESSION");
6769 case 0x0017: return wxT("WM_SYSTEMERROR");
6770 case 0x0018: return wxT("WM_SHOWWINDOW");
6771 case 0x0019: return wxT("WM_CTLCOLOR");
6772 case 0x001A: return wxT("WM_WININICHANGE");
6773 case 0x001B: return wxT("WM_DEVMODECHANGE");
6774 case 0x001C: return wxT("WM_ACTIVATEAPP");
6775 case 0x001D: return wxT("WM_FONTCHANGE");
6776 case 0x001E: return wxT("WM_TIMECHANGE");
6777 case 0x001F: return wxT("WM_CANCELMODE");
6778 case 0x0020: return wxT("WM_SETCURSOR");
6779 case 0x0021: return wxT("WM_MOUSEACTIVATE");
6780 case 0x0022: return wxT("WM_CHILDACTIVATE");
6781 case 0x0023: return wxT("WM_QUEUESYNC");
6782 case 0x0024: return wxT("WM_GETMINMAXINFO");
6783 case 0x0026: return wxT("WM_PAINTICON");
6784 case 0x0027: return wxT("WM_ICONERASEBKGND");
6785 case 0x0028: return wxT("WM_NEXTDLGCTL");
6786 case 0x002A: return wxT("WM_SPOOLERSTATUS");
6787 case 0x002B: return wxT("WM_DRAWITEM");
6788 case 0x002C: return wxT("WM_MEASUREITEM");
6789 case 0x002D: return wxT("WM_DELETEITEM");
6790 case 0x002E: return wxT("WM_VKEYTOITEM");
6791 case 0x002F: return wxT("WM_CHARTOITEM");
6792 case 0x0030: return wxT("WM_SETFONT");
6793 case 0x0031: return wxT("WM_GETFONT");
6794 case 0x0037: return wxT("WM_QUERYDRAGICON");
6795 case 0x0039: return wxT("WM_COMPAREITEM");
6796 case 0x0041: return wxT("WM_COMPACTING");
6797 case 0x0044: return wxT("WM_COMMNOTIFY");
6798 case 0x0046: return wxT("WM_WINDOWPOSCHANGING");
6799 case 0x0047: return wxT("WM_WINDOWPOSCHANGED");
6800 case 0x0048: return wxT("WM_POWER");
6801
6802 case 0x004A: return wxT("WM_COPYDATA");
6803 case 0x004B: return wxT("WM_CANCELJOURNAL");
6804 case 0x004E: return wxT("WM_NOTIFY");
6805 case 0x0050: return wxT("WM_INPUTLANGCHANGEREQUEST");
6806 case 0x0051: return wxT("WM_INPUTLANGCHANGE");
6807 case 0x0052: return wxT("WM_TCARD");
6808 case 0x0053: return wxT("WM_HELP");
6809 case 0x0054: return wxT("WM_USERCHANGED");
6810 case 0x0055: return wxT("WM_NOTIFYFORMAT");
6811 case 0x007B: return wxT("WM_CONTEXTMENU");
6812 case 0x007C: return wxT("WM_STYLECHANGING");
6813 case 0x007D: return wxT("WM_STYLECHANGED");
6814 case 0x007E: return wxT("WM_DISPLAYCHANGE");
6815 case 0x007F: return wxT("WM_GETICON");
6816 case 0x0080: return wxT("WM_SETICON");
6817
6818 case 0x0081: return wxT("WM_NCCREATE");
6819 case 0x0082: return wxT("WM_NCDESTROY");
6820 case 0x0083: return wxT("WM_NCCALCSIZE");
6821 case 0x0084: return wxT("WM_NCHITTEST");
6822 case 0x0085: return wxT("WM_NCPAINT");
6823 case 0x0086: return wxT("WM_NCACTIVATE");
6824 case 0x0087: return wxT("WM_GETDLGCODE");
6825 case 0x00A0: return wxT("WM_NCMOUSEMOVE");
6826 case 0x00A1: return wxT("WM_NCLBUTTONDOWN");
6827 case 0x00A2: return wxT("WM_NCLBUTTONUP");
6828 case 0x00A3: return wxT("WM_NCLBUTTONDBLCLK");
6829 case 0x00A4: return wxT("WM_NCRBUTTONDOWN");
6830 case 0x00A5: return wxT("WM_NCRBUTTONUP");
6831 case 0x00A6: return wxT("WM_NCRBUTTONDBLCLK");
6832 case 0x00A7: return wxT("WM_NCMBUTTONDOWN");
6833 case 0x00A8: return wxT("WM_NCMBUTTONUP");
6834 case 0x00A9: return wxT("WM_NCMBUTTONDBLCLK");
6835
6836 case 0x00B0: return wxT("EM_GETSEL");
6837 case 0x00B1: return wxT("EM_SETSEL");
6838 case 0x00B2: return wxT("EM_GETRECT");
6839 case 0x00B3: return wxT("EM_SETRECT");
6840 case 0x00B4: return wxT("EM_SETRECTNP");
6841 case 0x00B5: return wxT("EM_SCROLL");
6842 case 0x00B6: return wxT("EM_LINESCROLL");
6843 case 0x00B7: return wxT("EM_SCROLLCARET");
6844 case 0x00B8: return wxT("EM_GETMODIFY");
6845 case 0x00B9: return wxT("EM_SETMODIFY");
6846 case 0x00BA: return wxT("EM_GETLINECOUNT");
6847 case 0x00BB: return wxT("EM_LINEINDEX");
6848 case 0x00BC: return wxT("EM_SETHANDLE");
6849 case 0x00BD: return wxT("EM_GETHANDLE");
6850 case 0x00BE: return wxT("EM_GETTHUMB");
6851 case 0x00C1: return wxT("EM_LINELENGTH");
6852 case 0x00C2: return wxT("EM_REPLACESEL");
6853 case 0x00C4: return wxT("EM_GETLINE");
6854 case 0x00C5: return wxT("EM_LIMITTEXT/EM_SETLIMITTEXT"); /* ;win40 Name change */
6855 case 0x00C6: return wxT("EM_CANUNDO");
6856 case 0x00C7: return wxT("EM_UNDO");
6857 case 0x00C8: return wxT("EM_FMTLINES");
6858 case 0x00C9: return wxT("EM_LINEFROMCHAR");
6859 case 0x00CB: return wxT("EM_SETTABSTOPS");
6860 case 0x00CC: return wxT("EM_SETPASSWORDCHAR");
6861 case 0x00CD: return wxT("EM_EMPTYUNDOBUFFER");
6862 case 0x00CE: return wxT("EM_GETFIRSTVISIBLELINE");
6863 case 0x00CF: return wxT("EM_SETREADONLY");
6864 case 0x00D0: return wxT("EM_SETWORDBREAKPROC");
6865 case 0x00D1: return wxT("EM_GETWORDBREAKPROC");
6866 case 0x00D2: return wxT("EM_GETPASSWORDCHAR");
6867 case 0x00D3: return wxT("EM_SETMARGINS");
6868 case 0x00D4: return wxT("EM_GETMARGINS");
6869 case 0x00D5: return wxT("EM_GETLIMITTEXT");
6870 case 0x00D6: return wxT("EM_POSFROMCHAR");
6871 case 0x00D7: return wxT("EM_CHARFROMPOS");
6872 case 0x00D8: return wxT("EM_SETIMESTATUS");
6873 case 0x00D9: return wxT("EM_GETIMESTATUS");
6874
6875 case 0x0100: return wxT("WM_KEYDOWN");
6876 case 0x0101: return wxT("WM_KEYUP");
6877 case 0x0102: return wxT("WM_CHAR");
6878 case 0x0103: return wxT("WM_DEADCHAR");
6879 case 0x0104: return wxT("WM_SYSKEYDOWN");
6880 case 0x0105: return wxT("WM_SYSKEYUP");
6881 case 0x0106: return wxT("WM_SYSCHAR");
6882 case 0x0107: return wxT("WM_SYSDEADCHAR");
6883 case 0x0108: return wxT("WM_KEYLAST");
6884
6885 case 0x010D: return wxT("WM_IME_STARTCOMPOSITION");
6886 case 0x010E: return wxT("WM_IME_ENDCOMPOSITION");
6887 case 0x010F: return wxT("WM_IME_COMPOSITION");
6888
6889 case 0x0110: return wxT("WM_INITDIALOG");
6890 case 0x0111: return wxT("WM_COMMAND");
6891 case 0x0112: return wxT("WM_SYSCOMMAND");
6892 case 0x0113: return wxT("WM_TIMER");
6893 case 0x0114: return wxT("WM_HSCROLL");
6894 case 0x0115: return wxT("WM_VSCROLL");
6895 case 0x0116: return wxT("WM_INITMENU");
6896 case 0x0117: return wxT("WM_INITMENUPOPUP");
6897 case 0x011F: return wxT("WM_MENUSELECT");
6898 case 0x0120: return wxT("WM_MENUCHAR");
6899 case 0x0121: return wxT("WM_ENTERIDLE");
6900
6901 case 0x0127: return wxT("WM_CHANGEUISTATE");
6902 case 0x0128: return wxT("WM_UPDATEUISTATE");
6903 case 0x0129: return wxT("WM_QUERYUISTATE");
6904
6905 case 0x0132: return wxT("WM_CTLCOLORMSGBOX");
6906 case 0x0133: return wxT("WM_CTLCOLOREDIT");
6907 case 0x0134: return wxT("WM_CTLCOLORLISTBOX");
6908 case 0x0135: return wxT("WM_CTLCOLORBTN");
6909 case 0x0136: return wxT("WM_CTLCOLORDLG");
6910 case 0x0137: return wxT("WM_CTLCOLORSCROLLBAR");
6911 case 0x0138: return wxT("WM_CTLCOLORSTATIC");
6912 case 0x01E1: return wxT("MN_GETHMENU");
6913
6914 case 0x0200: return wxT("WM_MOUSEMOVE");
6915 case 0x0201: return wxT("WM_LBUTTONDOWN");
6916 case 0x0202: return wxT("WM_LBUTTONUP");
6917 case 0x0203: return wxT("WM_LBUTTONDBLCLK");
6918 case 0x0204: return wxT("WM_RBUTTONDOWN");
6919 case 0x0205: return wxT("WM_RBUTTONUP");
6920 case 0x0206: return wxT("WM_RBUTTONDBLCLK");
6921 case 0x0207: return wxT("WM_MBUTTONDOWN");
6922 case 0x0208: return wxT("WM_MBUTTONUP");
6923 case 0x0209: return wxT("WM_MBUTTONDBLCLK");
6924 case 0x020A: return wxT("WM_MOUSEWHEEL");
6925 case 0x020B: return wxT("WM_XBUTTONDOWN");
6926 case 0x020C: return wxT("WM_XBUTTONUP");
6927 case 0x020D: return wxT("WM_XBUTTONDBLCLK");
6928 case 0x0210: return wxT("WM_PARENTNOTIFY");
6929 case 0x0211: return wxT("WM_ENTERMENULOOP");
6930 case 0x0212: return wxT("WM_EXITMENULOOP");
6931
6932 case 0x0213: return wxT("WM_NEXTMENU");
6933 case 0x0214: return wxT("WM_SIZING");
6934 case 0x0215: return wxT("WM_CAPTURECHANGED");
6935 case 0x0216: return wxT("WM_MOVING");
6936 case 0x0218: return wxT("WM_POWERBROADCAST");
6937 case 0x0219: return wxT("WM_DEVICECHANGE");
6938
6939 case 0x0220: return wxT("WM_MDICREATE");
6940 case 0x0221: return wxT("WM_MDIDESTROY");
6941 case 0x0222: return wxT("WM_MDIACTIVATE");
6942 case 0x0223: return wxT("WM_MDIRESTORE");
6943 case 0x0224: return wxT("WM_MDINEXT");
6944 case 0x0225: return wxT("WM_MDIMAXIMIZE");
6945 case 0x0226: return wxT("WM_MDITILE");
6946 case 0x0227: return wxT("WM_MDICASCADE");
6947 case 0x0228: return wxT("WM_MDIICONARRANGE");
6948 case 0x0229: return wxT("WM_MDIGETACTIVE");
6949 case 0x0230: return wxT("WM_MDISETMENU");
6950 case 0x0233: return wxT("WM_DROPFILES");
6951
6952 case 0x0281: return wxT("WM_IME_SETCONTEXT");
6953 case 0x0282: return wxT("WM_IME_NOTIFY");
6954 case 0x0283: return wxT("WM_IME_CONTROL");
6955 case 0x0284: return wxT("WM_IME_COMPOSITIONFULL");
6956 case 0x0285: return wxT("WM_IME_SELECT");
6957 case 0x0286: return wxT("WM_IME_CHAR");
6958 case 0x0290: return wxT("WM_IME_KEYDOWN");
6959 case 0x0291: return wxT("WM_IME_KEYUP");
6960
6961 case 0x02A0: return wxT("WM_NCMOUSEHOVER");
6962 case 0x02A1: return wxT("WM_MOUSEHOVER");
6963 case 0x02A2: return wxT("WM_NCMOUSELEAVE");
6964 case 0x02A3: return wxT("WM_MOUSELEAVE");
6965
6966 case 0x0300: return wxT("WM_CUT");
6967 case 0x0301: return wxT("WM_COPY");
6968 case 0x0302: return wxT("WM_PASTE");
6969 case 0x0303: return wxT("WM_CLEAR");
6970 case 0x0304: return wxT("WM_UNDO");
6971 case 0x0305: return wxT("WM_RENDERFORMAT");
6972 case 0x0306: return wxT("WM_RENDERALLFORMATS");
6973 case 0x0307: return wxT("WM_DESTROYCLIPBOARD");
6974 case 0x0308: return wxT("WM_DRAWCLIPBOARD");
6975 case 0x0309: return wxT("WM_PAINTCLIPBOARD");
6976 case 0x030A: return wxT("WM_VSCROLLCLIPBOARD");
6977 case 0x030B: return wxT("WM_SIZECLIPBOARD");
6978 case 0x030C: return wxT("WM_ASKCBFORMATNAME");
6979 case 0x030D: return wxT("WM_CHANGECBCHAIN");
6980 case 0x030E: return wxT("WM_HSCROLLCLIPBOARD");
6981 case 0x030F: return wxT("WM_QUERYNEWPALETTE");
6982 case 0x0310: return wxT("WM_PALETTEISCHANGING");
6983 case 0x0311: return wxT("WM_PALETTECHANGED");
6984 case 0x0312: return wxT("WM_HOTKEY");
6985
6986 case 0x0317: return wxT("WM_PRINT");
6987 case 0x0318: return wxT("WM_PRINTCLIENT");
6988
6989 // common controls messages - although they're not strictly speaking
6990 // standard, it's nice to decode them nevertheless
6991
6992 // listview
6993 case 0x1000 + 0: return wxT("LVM_GETBKCOLOR");
6994 case 0x1000 + 1: return wxT("LVM_SETBKCOLOR");
6995 case 0x1000 + 2: return wxT("LVM_GETIMAGELIST");
6996 case 0x1000 + 3: return wxT("LVM_SETIMAGELIST");
6997 case 0x1000 + 4: return wxT("LVM_GETITEMCOUNT");
6998 case 0x1000 + 5: return wxT("LVM_GETITEMA");
6999 case 0x1000 + 75: return wxT("LVM_GETITEMW");
7000 case 0x1000 + 6: return wxT("LVM_SETITEMA");
7001 case 0x1000 + 76: return wxT("LVM_SETITEMW");
7002 case 0x1000 + 7: return wxT("LVM_INSERTITEMA");
7003 case 0x1000 + 77: return wxT("LVM_INSERTITEMW");
7004 case 0x1000 + 8: return wxT("LVM_DELETEITEM");
7005 case 0x1000 + 9: return wxT("LVM_DELETEALLITEMS");
7006 case 0x1000 + 10: return wxT("LVM_GETCALLBACKMASK");
7007 case 0x1000 + 11: return wxT("LVM_SETCALLBACKMASK");
7008 case 0x1000 + 12: return wxT("LVM_GETNEXTITEM");
7009 case 0x1000 + 13: return wxT("LVM_FINDITEMA");
7010 case 0x1000 + 83: return wxT("LVM_FINDITEMW");
7011 case 0x1000 + 14: return wxT("LVM_GETITEMRECT");
7012 case 0x1000 + 15: return wxT("LVM_SETITEMPOSITION");
7013 case 0x1000 + 16: return wxT("LVM_GETITEMPOSITION");
7014 case 0x1000 + 17: return wxT("LVM_GETSTRINGWIDTHA");
7015 case 0x1000 + 87: return wxT("LVM_GETSTRINGWIDTHW");
7016 case 0x1000 + 18: return wxT("LVM_HITTEST");
7017 case 0x1000 + 19: return wxT("LVM_ENSUREVISIBLE");
7018 case 0x1000 + 20: return wxT("LVM_SCROLL");
7019 case 0x1000 + 21: return wxT("LVM_REDRAWITEMS");
7020 case 0x1000 + 22: return wxT("LVM_ARRANGE");
7021 case 0x1000 + 23: return wxT("LVM_EDITLABELA");
7022 case 0x1000 + 118: return wxT("LVM_EDITLABELW");
7023 case 0x1000 + 24: return wxT("LVM_GETEDITCONTROL");
7024 case 0x1000 + 25: return wxT("LVM_GETCOLUMNA");
7025 case 0x1000 + 95: return wxT("LVM_GETCOLUMNW");
7026 case 0x1000 + 26: return wxT("LVM_SETCOLUMNA");
7027 case 0x1000 + 96: return wxT("LVM_SETCOLUMNW");
7028 case 0x1000 + 27: return wxT("LVM_INSERTCOLUMNA");
7029 case 0x1000 + 97: return wxT("LVM_INSERTCOLUMNW");
7030 case 0x1000 + 28: return wxT("LVM_DELETECOLUMN");
7031 case 0x1000 + 29: return wxT("LVM_GETCOLUMNWIDTH");
7032 case 0x1000 + 30: return wxT("LVM_SETCOLUMNWIDTH");
7033 case 0x1000 + 31: return wxT("LVM_GETHEADER");
7034 case 0x1000 + 33: return wxT("LVM_CREATEDRAGIMAGE");
7035 case 0x1000 + 34: return wxT("LVM_GETVIEWRECT");
7036 case 0x1000 + 35: return wxT("LVM_GETTEXTCOLOR");
7037 case 0x1000 + 36: return wxT("LVM_SETTEXTCOLOR");
7038 case 0x1000 + 37: return wxT("LVM_GETTEXTBKCOLOR");
7039 case 0x1000 + 38: return wxT("LVM_SETTEXTBKCOLOR");
7040 case 0x1000 + 39: return wxT("LVM_GETTOPINDEX");
7041 case 0x1000 + 40: return wxT("LVM_GETCOUNTPERPAGE");
7042 case 0x1000 + 41: return wxT("LVM_GETORIGIN");
7043 case 0x1000 + 42: return wxT("LVM_UPDATE");
7044 case 0x1000 + 43: return wxT("LVM_SETITEMSTATE");
7045 case 0x1000 + 44: return wxT("LVM_GETITEMSTATE");
7046 case 0x1000 + 45: return wxT("LVM_GETITEMTEXTA");
7047 case 0x1000 + 115: return wxT("LVM_GETITEMTEXTW");
7048 case 0x1000 + 46: return wxT("LVM_SETITEMTEXTA");
7049 case 0x1000 + 116: return wxT("LVM_SETITEMTEXTW");
7050 case 0x1000 + 47: return wxT("LVM_SETITEMCOUNT");
7051 case 0x1000 + 48: return wxT("LVM_SORTITEMS");
7052 case 0x1000 + 49: return wxT("LVM_SETITEMPOSITION32");
7053 case 0x1000 + 50: return wxT("LVM_GETSELECTEDCOUNT");
7054 case 0x1000 + 51: return wxT("LVM_GETITEMSPACING");
7055 case 0x1000 + 52: return wxT("LVM_GETISEARCHSTRINGA");
7056 case 0x1000 + 117: return wxT("LVM_GETISEARCHSTRINGW");
7057 case 0x1000 + 53: return wxT("LVM_SETICONSPACING");
7058 case 0x1000 + 54: return wxT("LVM_SETEXTENDEDLISTVIEWSTYLE");
7059 case 0x1000 + 55: return wxT("LVM_GETEXTENDEDLISTVIEWSTYLE");
7060 case 0x1000 + 56: return wxT("LVM_GETSUBITEMRECT");
7061 case 0x1000 + 57: return wxT("LVM_SUBITEMHITTEST");
7062 case 0x1000 + 58: return wxT("LVM_SETCOLUMNORDERARRAY");
7063 case 0x1000 + 59: return wxT("LVM_GETCOLUMNORDERARRAY");
7064 case 0x1000 + 60: return wxT("LVM_SETHOTITEM");
7065 case 0x1000 + 61: return wxT("LVM_GETHOTITEM");
7066 case 0x1000 + 62: return wxT("LVM_SETHOTCURSOR");
7067 case 0x1000 + 63: return wxT("LVM_GETHOTCURSOR");
7068 case 0x1000 + 64: return wxT("LVM_APPROXIMATEVIEWRECT");
7069 case 0x1000 + 65: return wxT("LVM_SETWORKAREA");
7070
7071 // tree view
7072 case 0x1100 + 0: return wxT("TVM_INSERTITEMA");
7073 case 0x1100 + 50: return wxT("TVM_INSERTITEMW");
7074 case 0x1100 + 1: return wxT("TVM_DELETEITEM");
7075 case 0x1100 + 2: return wxT("TVM_EXPAND");
7076 case 0x1100 + 4: return wxT("TVM_GETITEMRECT");
7077 case 0x1100 + 5: return wxT("TVM_GETCOUNT");
7078 case 0x1100 + 6: return wxT("TVM_GETINDENT");
7079 case 0x1100 + 7: return wxT("TVM_SETINDENT");
7080 case 0x1100 + 8: return wxT("TVM_GETIMAGELIST");
7081 case 0x1100 + 9: return wxT("TVM_SETIMAGELIST");
7082 case 0x1100 + 10: return wxT("TVM_GETNEXTITEM");
7083 case 0x1100 + 11: return wxT("TVM_SELECTITEM");
7084 case 0x1100 + 12: return wxT("TVM_GETITEMA");
7085 case 0x1100 + 62: return wxT("TVM_GETITEMW");
7086 case 0x1100 + 13: return wxT("TVM_SETITEMA");
7087 case 0x1100 + 63: return wxT("TVM_SETITEMW");
7088 case 0x1100 + 14: return wxT("TVM_EDITLABELA");
7089 case 0x1100 + 65: return wxT("TVM_EDITLABELW");
7090 case 0x1100 + 15: return wxT("TVM_GETEDITCONTROL");
7091 case 0x1100 + 16: return wxT("TVM_GETVISIBLECOUNT");
7092 case 0x1100 + 17: return wxT("TVM_HITTEST");
7093 case 0x1100 + 18: return wxT("TVM_CREATEDRAGIMAGE");
7094 case 0x1100 + 19: return wxT("TVM_SORTCHILDREN");
7095 case 0x1100 + 20: return wxT("TVM_ENSUREVISIBLE");
7096 case 0x1100 + 21: return wxT("TVM_SORTCHILDRENCB");
7097 case 0x1100 + 22: return wxT("TVM_ENDEDITLABELNOW");
7098 case 0x1100 + 23: return wxT("TVM_GETISEARCHSTRINGA");
7099 case 0x1100 + 64: return wxT("TVM_GETISEARCHSTRINGW");
7100 case 0x1100 + 24: return wxT("TVM_SETTOOLTIPS");
7101 case 0x1100 + 25: return wxT("TVM_GETTOOLTIPS");
7102
7103 // header
7104 case 0x1200 + 0: return wxT("HDM_GETITEMCOUNT");
7105 case 0x1200 + 1: return wxT("HDM_INSERTITEMA");
7106 case 0x1200 + 10: return wxT("HDM_INSERTITEMW");
7107 case 0x1200 + 2: return wxT("HDM_DELETEITEM");
7108 case 0x1200 + 3: return wxT("HDM_GETITEMA");
7109 case 0x1200 + 11: return wxT("HDM_GETITEMW");
7110 case 0x1200 + 4: return wxT("HDM_SETITEMA");
7111 case 0x1200 + 12: return wxT("HDM_SETITEMW");
7112 case 0x1200 + 5: return wxT("HDM_LAYOUT");
7113 case 0x1200 + 6: return wxT("HDM_HITTEST");
7114 case 0x1200 + 7: return wxT("HDM_GETITEMRECT");
7115 case 0x1200 + 8: return wxT("HDM_SETIMAGELIST");
7116 case 0x1200 + 9: return wxT("HDM_GETIMAGELIST");
7117 case 0x1200 + 15: return wxT("HDM_ORDERTOINDEX");
7118 case 0x1200 + 16: return wxT("HDM_CREATEDRAGIMAGE");
7119 case 0x1200 + 17: return wxT("HDM_GETORDERARRAY");
7120 case 0x1200 + 18: return wxT("HDM_SETORDERARRAY");
7121 case 0x1200 + 19: return wxT("HDM_SETHOTDIVIDER");
7122
7123 // tab control
7124 case 0x1300 + 2: return wxT("TCM_GETIMAGELIST");
7125 case 0x1300 + 3: return wxT("TCM_SETIMAGELIST");
7126 case 0x1300 + 4: return wxT("TCM_GETITEMCOUNT");
7127 case 0x1300 + 5: return wxT("TCM_GETITEMA");
7128 case 0x1300 + 60: return wxT("TCM_GETITEMW");
7129 case 0x1300 + 6: return wxT("TCM_SETITEMA");
7130 case 0x1300 + 61: return wxT("TCM_SETITEMW");
7131 case 0x1300 + 7: return wxT("TCM_INSERTITEMA");
7132 case 0x1300 + 62: return wxT("TCM_INSERTITEMW");
7133 case 0x1300 + 8: return wxT("TCM_DELETEITEM");
7134 case 0x1300 + 9: return wxT("TCM_DELETEALLITEMS");
7135 case 0x1300 + 10: return wxT("TCM_GETITEMRECT");
7136 case 0x1300 + 11: return wxT("TCM_GETCURSEL");
7137 case 0x1300 + 12: return wxT("TCM_SETCURSEL");
7138 case 0x1300 + 13: return wxT("TCM_HITTEST");
7139 case 0x1300 + 14: return wxT("TCM_SETITEMEXTRA");
7140 case 0x1300 + 40: return wxT("TCM_ADJUSTRECT");
7141 case 0x1300 + 41: return wxT("TCM_SETITEMSIZE");
7142 case 0x1300 + 42: return wxT("TCM_REMOVEIMAGE");
7143 case 0x1300 + 43: return wxT("TCM_SETPADDING");
7144 case 0x1300 + 44: return wxT("TCM_GETROWCOUNT");
7145 case 0x1300 + 45: return wxT("TCM_GETTOOLTIPS");
7146 case 0x1300 + 46: return wxT("TCM_SETTOOLTIPS");
7147 case 0x1300 + 47: return wxT("TCM_GETCURFOCUS");
7148 case 0x1300 + 48: return wxT("TCM_SETCURFOCUS");
7149 case 0x1300 + 49: return wxT("TCM_SETMINTABWIDTH");
7150 case 0x1300 + 50: return wxT("TCM_DESELECTALL");
7151
7152 // toolbar
7153 case WM_USER+1: return wxT("TB_ENABLEBUTTON");
7154 case WM_USER+2: return wxT("TB_CHECKBUTTON");
7155 case WM_USER+3: return wxT("TB_PRESSBUTTON");
7156 case WM_USER+4: return wxT("TB_HIDEBUTTON");
7157 case WM_USER+5: return wxT("TB_INDETERMINATE");
7158 case WM_USER+9: return wxT("TB_ISBUTTONENABLED");
7159 case WM_USER+10: return wxT("TB_ISBUTTONCHECKED");
7160 case WM_USER+11: return wxT("TB_ISBUTTONPRESSED");
7161 case WM_USER+12: return wxT("TB_ISBUTTONHIDDEN");
7162 case WM_USER+13: return wxT("TB_ISBUTTONINDETERMINATE");
7163 case WM_USER+17: return wxT("TB_SETSTATE");
7164 case WM_USER+18: return wxT("TB_GETSTATE");
7165 case WM_USER+19: return wxT("TB_ADDBITMAP");
7166 case WM_USER+20: return wxT("TB_ADDBUTTONS");
7167 case WM_USER+21: return wxT("TB_INSERTBUTTON");
7168 case WM_USER+22: return wxT("TB_DELETEBUTTON");
7169 case WM_USER+23: return wxT("TB_GETBUTTON");
7170 case WM_USER+24: return wxT("TB_BUTTONCOUNT");
7171 case WM_USER+25: return wxT("TB_COMMANDTOINDEX");
7172 case WM_USER+26: return wxT("TB_SAVERESTOREA");
7173 case WM_USER+76: return wxT("TB_SAVERESTOREW");
7174 case WM_USER+27: return wxT("TB_CUSTOMIZE");
7175 case WM_USER+28: return wxT("TB_ADDSTRINGA");
7176 case WM_USER+77: return wxT("TB_ADDSTRINGW");
7177 case WM_USER+29: return wxT("TB_GETITEMRECT");
7178 case WM_USER+30: return wxT("TB_BUTTONSTRUCTSIZE");
7179 case WM_USER+31: return wxT("TB_SETBUTTONSIZE");
7180 case WM_USER+32: return wxT("TB_SETBITMAPSIZE");
7181 case WM_USER+33: return wxT("TB_AUTOSIZE");
7182 case WM_USER+35: return wxT("TB_GETTOOLTIPS");
7183 case WM_USER+36: return wxT("TB_SETTOOLTIPS");
7184 case WM_USER+37: return wxT("TB_SETPARENT");
7185 case WM_USER+39: return wxT("TB_SETROWS");
7186 case WM_USER+40: return wxT("TB_GETROWS");
7187 case WM_USER+42: return wxT("TB_SETCMDID");
7188 case WM_USER+43: return wxT("TB_CHANGEBITMAP");
7189 case WM_USER+44: return wxT("TB_GETBITMAP");
7190 case WM_USER+45: return wxT("TB_GETBUTTONTEXTA");
7191 case WM_USER+75: return wxT("TB_GETBUTTONTEXTW");
7192 case WM_USER+46: return wxT("TB_REPLACEBITMAP");
7193 case WM_USER+47: return wxT("TB_SETINDENT");
7194 case WM_USER+48: return wxT("TB_SETIMAGELIST");
7195 case WM_USER+49: return wxT("TB_GETIMAGELIST");
7196 case WM_USER+50: return wxT("TB_LOADIMAGES");
7197 case WM_USER+51: return wxT("TB_GETRECT");
7198 case WM_USER+52: return wxT("TB_SETHOTIMAGELIST");
7199 case WM_USER+53: return wxT("TB_GETHOTIMAGELIST");
7200 case WM_USER+54: return wxT("TB_SETDISABLEDIMAGELIST");
7201 case WM_USER+55: return wxT("TB_GETDISABLEDIMAGELIST");
7202 case WM_USER+56: return wxT("TB_SETSTYLE");
7203 case WM_USER+57: return wxT("TB_GETSTYLE");
7204 case WM_USER+58: return wxT("TB_GETBUTTONSIZE");
7205 case WM_USER+59: return wxT("TB_SETBUTTONWIDTH");
7206 case WM_USER+60: return wxT("TB_SETMAXTEXTROWS");
7207 case WM_USER+61: return wxT("TB_GETTEXTROWS");
7208 case WM_USER+41: return wxT("TB_GETBITMAPFLAGS");
7209
7210 default:
7211 static wxString s_szBuf;
7212 s_szBuf.Printf(wxT("<unknown message = %d>"), message);
7213 return s_szBuf.c_str();
7214 }
7215 }
7216 #endif // wxDEBUG_LEVEL >= 2
7217
7218 static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win)
7219 {
7220 // prepare the DC
7221 TEXTMETRIC tm;
7222 HWND hwnd = GetHwndOf(win);
7223 HDC hdc = ::GetDC(hwnd);
7224
7225 #if !wxDIALOG_UNIT_COMPATIBILITY
7226 // and select the current font into it
7227 HFONT hfont = GetHfontOf(win->GetFont());
7228 if ( hfont )
7229 {
7230 hfont = (HFONT)::SelectObject(hdc, hfont);
7231 }
7232 #endif
7233
7234 // finally retrieve the text metrics from it
7235 GetTextMetrics(hdc, &tm);
7236
7237 #if !wxDIALOG_UNIT_COMPATIBILITY
7238 // and clean up
7239 if ( hfont )
7240 {
7241 (void)::SelectObject(hdc, hfont);
7242 }
7243 #endif
7244
7245 ::ReleaseDC(hwnd, hdc);
7246
7247 return tm;
7248 }
7249
7250 // Find the wxWindow at the current mouse position, returning the mouse
7251 // position.
7252 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
7253 {
7254 pt = wxGetMousePosition();
7255 return wxFindWindowAtPoint(pt);
7256 }
7257
7258 wxWindow* wxFindWindowAtPoint(const wxPoint& pt)
7259 {
7260 POINT pt2;
7261 pt2.x = pt.x;
7262 pt2.y = pt.y;
7263
7264 HWND hWnd = ::WindowFromPoint(pt2);
7265 if ( hWnd )
7266 {
7267 // WindowFromPoint() ignores the disabled children but we're supposed
7268 // to take them into account, so check if we have a child at this
7269 // coordinate using ChildWindowFromPointEx().
7270 for ( ;; )
7271 {
7272 pt2.x = pt.x;
7273 pt2.y = pt.y;
7274 ::ScreenToClient(hWnd, &pt2);
7275 HWND child = ::ChildWindowFromPointEx(hWnd, pt2, CWP_SKIPINVISIBLE);
7276 if ( child == hWnd || !child )
7277 break;
7278
7279 // ChildWindowFromPointEx() only examines the immediate children
7280 // but we want to get the deepest (top in Z-order) one, so continue
7281 // iterating for as long as it finds anything.
7282 hWnd = child;
7283 }
7284 }
7285
7286 return wxGetWindowFromHWND((WXHWND)hWnd);
7287 }
7288
7289 // Get the current mouse position.
7290 wxPoint wxGetMousePosition()
7291 {
7292 POINT pt;
7293 wxGetCursorPosMSW(&pt);
7294
7295 return wxPoint(pt.x, pt.y);
7296 }
7297
7298 #if wxUSE_HOTKEY
7299
7300 #if defined(__SMARTPHONE__) || defined(__POCKETPC__)
7301 static void WinCEUnregisterHotKey(int modifiers, int id)
7302 {
7303 // Register hotkeys for the hardware buttons
7304 HINSTANCE hCoreDll;
7305 typedef BOOL (WINAPI *UnregisterFunc1Proc)(UINT, UINT);
7306
7307 UnregisterFunc1Proc procUnregisterFunc;
7308 hCoreDll = LoadLibrary(wxT("coredll.dll"));
7309 if (hCoreDll)
7310 {
7311 procUnregisterFunc = (UnregisterFunc1Proc)GetProcAddress(hCoreDll, wxT("UnregisterFunc1"));
7312 if (procUnregisterFunc)
7313 procUnregisterFunc(modifiers, id);
7314 FreeLibrary(hCoreDll);
7315 }
7316 }
7317 #endif
7318
7319 bool wxWindowMSW::RegisterHotKey(int hotkeyId, int modifiers, int keycode)
7320 {
7321 UINT win_modifiers=0;
7322 if ( modifiers & wxMOD_ALT )
7323 win_modifiers |= MOD_ALT;
7324 if ( modifiers & wxMOD_SHIFT )
7325 win_modifiers |= MOD_SHIFT;
7326 if ( modifiers & wxMOD_CONTROL )
7327 win_modifiers |= MOD_CONTROL;
7328 if ( modifiers & wxMOD_WIN )
7329 win_modifiers |= MOD_WIN;
7330
7331 #if defined(__SMARTPHONE__) || defined(__POCKETPC__)
7332 // Required for PPC and Smartphone hardware buttons
7333 if (keycode >= WXK_SPECIAL1 && keycode <= WXK_SPECIAL20)
7334 WinCEUnregisterHotKey(win_modifiers, hotkeyId);
7335 #endif
7336
7337 if ( !::RegisterHotKey(GetHwnd(), hotkeyId, win_modifiers, keycode) )
7338 {
7339 wxLogLastError(wxT("RegisterHotKey"));
7340
7341 return false;
7342 }
7343
7344 return true;
7345 }
7346
7347 bool wxWindowMSW::UnregisterHotKey(int hotkeyId)
7348 {
7349 #if defined(__SMARTPHONE__) || defined(__POCKETPC__)
7350 WinCEUnregisterHotKey(MOD_WIN, hotkeyId);
7351 #endif
7352
7353 if ( !::UnregisterHotKey(GetHwnd(), hotkeyId) )
7354 {
7355 wxLogLastError(wxT("UnregisterHotKey"));
7356
7357 return false;
7358 }
7359
7360 return true;
7361 }
7362
7363 bool wxWindowMSW::HandleHotKey(WXWPARAM wParam, WXLPARAM lParam)
7364 {
7365 int win_modifiers = LOWORD(lParam);
7366
7367 wxKeyEvent event(CreateKeyEvent(wxEVT_HOTKEY, HIWORD(lParam)));
7368 event.SetId(wParam);
7369 event.m_shiftDown = (win_modifiers & MOD_SHIFT) != 0;
7370 event.m_controlDown = (win_modifiers & MOD_CONTROL) != 0;
7371 event.m_altDown = (win_modifiers & MOD_ALT) != 0;
7372 event.m_metaDown = (win_modifiers & MOD_WIN) != 0;
7373
7374 return HandleWindowEvent(event);
7375 }
7376
7377 #endif // wxUSE_HOTKEY
7378
7379 // Not tested under WinCE
7380 #ifndef __WXWINCE__
7381
7382 // this class installs a message hook which really wakes up our idle processing
7383 // each time a WM_NULL is received (wxWakeUpIdle does this), even if we're
7384 // sitting inside a local modal loop (e.g. a menu is opened or scrollbar is
7385 // being dragged or even inside ::MessageBox()) and so don't control message
7386 // dispatching otherwise
7387 class wxIdleWakeUpModule : public wxModule
7388 {
7389 public:
7390 virtual bool OnInit()
7391 {
7392 ms_hMsgHookProc = ::SetWindowsHookEx
7393 (
7394 WH_GETMESSAGE,
7395 &wxIdleWakeUpModule::MsgHookProc,
7396 NULL,
7397 GetCurrentThreadId()
7398 );
7399
7400 if ( !ms_hMsgHookProc )
7401 {
7402 wxLogLastError(wxT("SetWindowsHookEx(WH_GETMESSAGE)"));
7403
7404 return false;
7405 }
7406
7407 return true;
7408 }
7409
7410 virtual void OnExit()
7411 {
7412 ::UnhookWindowsHookEx(wxIdleWakeUpModule::ms_hMsgHookProc);
7413 }
7414
7415 static LRESULT CALLBACK MsgHookProc(int nCode, WPARAM wParam, LPARAM lParam)
7416 {
7417 MSG *msg = (MSG*)lParam;
7418
7419 // only process the message if it is actually going to be removed from
7420 // the message queue, this prevents that the same event from being
7421 // processed multiple times if now someone just called PeekMessage()
7422 if ( msg->message == WM_NULL && wParam == PM_REMOVE )
7423 {
7424 wxTheApp->ProcessPendingEvents();
7425 }
7426
7427 return CallNextHookEx(ms_hMsgHookProc, nCode, wParam, lParam);
7428 }
7429
7430 private:
7431 static HHOOK ms_hMsgHookProc;
7432
7433 DECLARE_DYNAMIC_CLASS(wxIdleWakeUpModule)
7434 };
7435
7436 HHOOK wxIdleWakeUpModule::ms_hMsgHookProc = 0;
7437
7438 IMPLEMENT_DYNAMIC_CLASS(wxIdleWakeUpModule, wxModule)
7439
7440 #endif // __WXWINCE__
7441
7442 #ifdef __WXWINCE__
7443
7444 #if wxUSE_STATBOX
7445 static void wxAdjustZOrder(wxWindow* parent)
7446 {
7447 if (wxDynamicCast(parent, wxStaticBox))
7448 {
7449 // Set the z-order correctly
7450 SetWindowPos((HWND) parent->GetHWND(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
7451 }
7452
7453 wxWindowList::compatibility_iterator current = parent->GetChildren().GetFirst();
7454 while (current)
7455 {
7456 wxWindow *childWin = current->GetData();
7457 wxAdjustZOrder(childWin);
7458 current = current->GetNext();
7459 }
7460 }
7461 #endif
7462
7463 // We need to adjust the z-order of static boxes in WinCE, to
7464 // make 'contained' controls visible
7465 void wxWindowMSW::OnInitDialog( wxInitDialogEvent& event )
7466 {
7467 #if wxUSE_STATBOX
7468 wxAdjustZOrder(this);
7469 #endif
7470
7471 event.Skip();
7472 }
7473 #endif