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