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