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
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ===========================================================================
14 // ===========================================================================
16 // ---------------------------------------------------------------------------
18 // ---------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
27 #include "wx/window.h"
30 #include "wx/msw/wrapwin.h"
31 #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
32 #include "wx/msw/missing.h"
36 #include "wx/dcclient.h"
37 #include "wx/dcmemory.h"
40 #include "wx/layout.h"
41 #include "wx/dialog.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"
51 #include "wx/textctrl.h"
52 #include "wx/menuitem.h"
53 #include "wx/module.h"
56 #if wxUSE_OWNER_DRAWN && !defined(__WXUNIVERSAL__)
57 #include "wx/ownerdrw.h"
60 #include "wx/hashmap.h"
61 #include "wx/evtloop.h"
63 #include "wx/sysopt.h"
65 #if wxUSE_DRAG_AND_DROP
69 #if wxUSE_ACCESSIBILITY
70 #include "wx/access.h"
74 #define WM_GETOBJECT 0x003D
77 #define OBJID_CLIENT 0xFFFFFFFC
81 #include "wx/msw/private.h"
82 #include "wx/msw/private/keyboard.h"
83 #include "wx/msw/dcclient.h"
86 #include "wx/tooltip.h"
94 #include "wx/radiobox.h"
95 #endif // wxUSE_RADIOBOX
98 #include "wx/spinctrl.h"
99 #endif // wxUSE_SPINCTRL
101 #include "wx/notebook.h"
102 #include "wx/listctrl.h"
103 #include "wx/dynlib.h"
107 #if (!defined(__GNUWIN32_OLD__) && !defined(__WXMICROWIN__) /* && !defined(__WXWINCE__) */ ) || defined(__CYGWIN10__)
108 #include <shellapi.h>
109 #include <mmsystem.h>
113 #include <windowsx.h>
116 #if !defined __WXWINCE__ && !defined NEED_PBT_H
120 #if defined(__WXWINCE__)
121 #include "wx/msw/wince/missing.h"
124 #include <shellapi.h>
126 #include <aygshell.h>
131 #include "wx/msw/uxtheme.h"
132 #define EP_EDITTEXT 1
135 #define ETS_SELECTED 3
136 #define ETS_DISABLED 4
137 #define ETS_FOCUSED 5
138 #define ETS_READONLY 6
142 // define the constants used by AnimateWindow() if our SDK doesn't have them
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
155 #if defined(TME_LEAVE) && defined(WM_MOUSELEAVE) && wxUSE_DYNLIB_CLASS
156 #define HAVE_TRACKMOUSEEVENT
157 #endif // everything needed for TrackMouseEvent()
159 // set this to 1 to filter out duplicate mouse events, e.g. mouse move events
160 // when mouse position didnd't change
162 #define wxUSE_MOUSEEVENT_HACK 0
164 #define wxUSE_MOUSEEVENT_HACK 1
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
173 #ifndef MAPVK_VK_TO_CHAR
174 #define MAPVK_VK_TO_CHAR 2
177 // ---------------------------------------------------------------------------
179 // ---------------------------------------------------------------------------
181 #if wxUSE_MENUS_NATIVE
182 extern wxMenu
*wxCurrentPopupMenu
;
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;
192 // last mouse event information we need to filter out the duplicates
193 #if wxUSE_MOUSEEVENT_HACK
194 struct MouseEventInfoDummy
196 // mouse position (in screen coordinates)
199 // last mouse event type
202 #endif // wxUSE_MOUSEEVENT_HACK
204 // hash containing the registered handlers for the custom messages
205 WX_DECLARE_HASH_MAP(int, wxWindow::MSWMessageHandler
,
206 wxIntegerHash
, wxIntegerEqual
,
209 MSWMessageHandlers gs_messageHandlers
;
211 // hash containing all our windows, it uses HWND keys and wxWindow* values
212 WX_DECLARE_HASH_MAP(HWND
, wxWindow
*,
213 wxPointerHash
, wxPointerEqual
,
216 WindowHandles gs_windowHandles
;
218 #ifdef wxHAS_MSW_BACKGROUND_ERASE_HOOK
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
,
227 EraseBgHooks gs_eraseBgHooks
;
229 #endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK
231 } // anonymous namespace
233 // ---------------------------------------------------------------------------
235 // ---------------------------------------------------------------------------
237 // the window proc for all our windows
238 LRESULT WXDLLEXPORT APIENTRY _EXPORT
wxWndProc(HWND hWnd
, UINT message
,
239 WPARAM wParam
, LPARAM lParam
);
242 #if wxDEBUG_LEVEL >= 2
243 const wxChar
*wxGetMessageName(int message
);
244 #endif // wxDEBUG_LEVEL >= 2
246 void wxRemoveHandleAssociation(wxWindowMSW
*win
);
247 extern void wxAssociateWinWithHandle(HWND hWnd
, wxWindowMSW
*win
);
249 // get the text metrics for the current font
250 static TEXTMETRIC
wxGetTextMetrics(const wxWindowMSW
*win
);
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__
257 // wrapper around BringWindowToTop() API
258 static inline void wxBringWindowToTop(HWND hwnd
)
260 #ifdef __WXMICROWIN__
261 // It seems that MicroWindows brings the _parent_ of the window to the top,
262 // which can be the wrong one.
264 // activate (set focus to) specified window
268 // raise top level parent to top of z order
269 if (!::SetWindowPos(hwnd
, HWND_TOP
, 0, 0, 0, 0, SWP_NOMOVE
| SWP_NOSIZE
))
271 wxLogLastError(wxT("SetWindowPos"));
277 // ensure that all our parent windows have WS_EX_CONTROLPARENT style
278 static void EnsureParentHasControlParentStyle(wxWindow
*parent
)
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.
293 while ( parent
&& !parent
->IsTopLevel() )
295 LONG exStyle
= wxGetWindowExStyle(parent
);
296 if ( !(exStyle
& WS_EX_CONTROLPARENT
) )
298 // force the parent to have this style
299 wxSetWindowExStyle(parent
, exStyle
| WS_EX_CONTROLPARENT
);
302 parent
= parent
->GetParent();
306 #endif // !__WXWINCE__
309 // On Windows CE, GetCursorPos can return an error, so use this function
311 bool GetCursorPosWinCE(POINT
* pt
)
313 if (!GetCursorPos(pt
))
315 DWORD pos
= GetMessagePos();
323 // ---------------------------------------------------------------------------
325 // ---------------------------------------------------------------------------
327 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
329 #ifdef __WXUNIVERSAL__
330 IMPLEMENT_ABSTRACT_CLASS(wxWindowMSW
, wxWindowBase
)
331 #endif // __WXUNIVERSAL__
333 BEGIN_EVENT_TABLE(wxWindowMSW
, wxWindowBase
)
334 EVT_SYS_COLOUR_CHANGED(wxWindowMSW::OnSysColourChanged
)
336 EVT_INIT_DIALOG(wxWindowMSW::OnInitDialog
)
340 // ===========================================================================
342 // ===========================================================================
344 // ---------------------------------------------------------------------------
345 // wxWindow utility functions
346 // ---------------------------------------------------------------------------
348 // Find an item given the MS Windows id
349 wxWindow
*wxWindowMSW::FindItem(long id
) const
352 wxControl
*item
= wxDynamicCastThis(wxControl
);
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__
365 #endif // wxUSE_CONTROLS
367 wxWindowList::compatibility_iterator current
= GetChildren().GetFirst();
370 wxWindow
*childWin
= current
->GetData();
372 wxWindow
*wnd
= childWin
->FindItem(id
);
376 current
= current
->GetNext();
382 // Find an item given the MS Windows handle
383 wxWindow
*wxWindowMSW::FindItemByHWND(WXHWND hWnd
, bool controlOnly
) const
385 wxWindowList::compatibility_iterator current
= GetChildren().GetFirst();
388 wxWindow
*parent
= current
->GetData();
390 // Do a recursive search.
391 wxWindow
*wnd
= parent
->FindItemByHWND(hWnd
);
397 || parent
->IsKindOf(CLASSINFO(wxControl
))
398 #endif // wxUSE_CONTROLS
401 wxWindow
*item
= current
->GetData();
402 if ( item
->GetHWND() == hWnd
)
406 if ( item
->ContainsHWND(hWnd
) )
411 current
= current
->GetNext();
416 // Default command handler
417 bool wxWindowMSW::MSWCommand(WXUINT
WXUNUSED(param
), WXWORD
WXUNUSED(id
))
422 // ----------------------------------------------------------------------------
423 // constructors and such
424 // ----------------------------------------------------------------------------
426 void wxWindowMSW::Init()
430 m_mouseInWindow
= false;
431 m_lastKeydownProcessed
= false;
438 #if wxUSE_DEFERRED_SIZING
440 m_pendingPosition
= wxDefaultPosition
;
441 m_pendingSize
= wxDefaultSize
;
442 #endif // wxUSE_DEFERRED_SIZING
445 m_contextMenuEnabled
= false;
450 wxWindowMSW::~wxWindowMSW()
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() )
458 wxTopLevelWindow
*frame
= wxDynamicCast(win
, wxTopLevelWindow
);
461 if ( frame
->GetLastFocus() == this )
463 frame
->SetLastFocus(NULL
);
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
473 #endif // __WXUNIVERSAL__
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).
482 // VZ: test temp removed to understand what really happens here
483 //if (::IsWindow(GetHwnd()))
485 if ( !::DestroyWindow(GetHwnd()) )
487 wxLogLastError(wxT("DestroyWindow"));
491 // remove hWnd <-> wxWindow association
492 wxRemoveHandleAssociation(this);
498 const wxChar
*wxWindowMSW::MSWGetRegisteredClassName()
500 return wxApp::GetRegisteredClassName(wxT("wxWindow"), COLOR_BTNFACE
);
503 // real construction (Init() must have been called before!)
504 bool wxWindowMSW::Create(wxWindow
*parent
,
509 const wxString
& name
)
511 wxCHECK_MSG( parent
, false, wxT("can't create wxWindow without parent") );
513 if ( !CreateBase(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
) )
516 parent
->AddChild(this);
519 DWORD msflags
= MSWGetCreateWindowFlags(&exstyle
);
521 #ifdef __WXUNIVERSAL__
522 // no borders, we draw them ourselves
523 exstyle
&= ~(WS_EX_DLGMODALFRAME
|
527 msflags
&= ~WS_BORDER
;
528 #endif // wxUniversal
532 msflags
|= WS_VISIBLE
;
535 if ( !MSWCreate(MSWGetRegisteredClassName(),
536 NULL
, pos
, size
, msflags
, exstyle
) )
544 // ---------------------------------------------------------------------------
546 // ---------------------------------------------------------------------------
548 void wxWindowMSW::SetFocus()
550 HWND hWnd
= GetHwnd();
551 wxCHECK_RET( hWnd
, wxT("can't set focus to invalid window") );
553 #if !defined(__WXWINCE__)
557 if ( !::SetFocus(hWnd
) )
559 // was there really an error?
560 DWORD dwRes
= ::GetLastError();
563 HWND hwndFocus
= ::GetFocus();
564 if ( hwndFocus
!= hWnd
)
566 wxLogApiError(wxT("SetFocus"), dwRes
);
572 void wxWindowMSW::SetFocusFromKbd()
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
)
580 ::SendMessage(GetHwnd(), EM_SETSEL
, 0, -1);
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();
589 // Get the window with the focus
590 wxWindow
*wxWindowBase::DoFindFocus()
592 HWND hWnd
= ::GetFocus();
595 return wxGetWindowFromHWND((WXHWND
)hWnd
);
601 void wxWindowMSW::DoEnable( bool enable
)
603 MSWEnableHWND(GetHwnd(), enable
);
606 bool wxWindowMSW::MSWEnableHWND(WXHWND hWnd
, bool enable
)
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
)
617 return ::EnableWindow(hWnd
, (BOOL
)enable
) != 0;
620 bool wxWindowMSW::Show(bool show
)
622 if ( !wxWindowBase::Show(show
) )
625 HWND hWnd
= GetHwnd();
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.
630 // wxFoo *foo = new wxFoo;
632 // foo->Create(parent, ...);
634 // should work without errors
637 ::ShowWindow(hWnd
, show
? SW_SHOW
: SW_HIDE
);
642 // DoFreeze/DoThaw don't do anything if the window is not shown, so
643 // we have to call them from here now
654 wxWindowMSW::MSWShowWithEffect(bool show
,
658 if ( effect
== wxSHOW_EFFECT_NONE
)
661 if ( !wxWindowBase::Show(show
) )
664 typedef BOOL (WINAPI
*AnimateWindow_t
)(HWND
, DWORD
, DWORD
);
666 static AnimateWindow_t s_pfnAnimateWindow
= NULL
;
667 static bool s_initDone
= false;
670 wxDynamicLibrary
dllUser32(wxT("user32.dll"), wxDL_VERBATIM
| wxDL_QUIET
);
671 wxDL_INIT_FUNC(s_pfn
, AnimateWindow
, dllUser32
);
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
679 if ( !s_pfnAnimateWindow
)
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
687 // prepare to use AnimateWindow()
690 timeout
= 200; // this is the default animation timeout, per MSDN
692 DWORD dwFlags
= show
? 0 : AW_HIDE
;
696 case wxSHOW_EFFECT_ROLL_TO_LEFT
:
697 dwFlags
|= AW_HOR_NEGATIVE
;
700 case wxSHOW_EFFECT_ROLL_TO_RIGHT
:
701 dwFlags
|= AW_HOR_POSITIVE
;
704 case wxSHOW_EFFECT_ROLL_TO_TOP
:
705 dwFlags
|= AW_VER_NEGATIVE
;
708 case wxSHOW_EFFECT_ROLL_TO_BOTTOM
:
709 dwFlags
|= AW_VER_POSITIVE
;
712 case wxSHOW_EFFECT_SLIDE_TO_LEFT
:
713 dwFlags
|= AW_SLIDE
| AW_HOR_NEGATIVE
;
716 case wxSHOW_EFFECT_SLIDE_TO_RIGHT
:
717 dwFlags
|= AW_SLIDE
| AW_HOR_POSITIVE
;
720 case wxSHOW_EFFECT_SLIDE_TO_TOP
:
721 dwFlags
|= AW_SLIDE
| AW_VER_NEGATIVE
;
724 case wxSHOW_EFFECT_SLIDE_TO_BOTTOM
:
725 dwFlags
|= AW_SLIDE
| AW_VER_POSITIVE
;
728 case wxSHOW_EFFECT_BLEND
:
732 case wxSHOW_EFFECT_EXPAND
:
733 dwFlags
|= AW_CENTER
;
737 case wxSHOW_EFFECT_MAX
:
738 wxFAIL_MSG( wxT("invalid window show effect") );
742 wxFAIL_MSG( wxT("unknown window show effect") );
746 if ( !(*s_pfnAnimateWindow
)(GetHwnd(), timeout
, dwFlags
) )
748 wxLogLastError(wxT("AnimateWindow"));
756 // Raise the window to the top of the Z order
757 void wxWindowMSW::Raise()
759 wxBringWindowToTop(GetHwnd());
762 // Lower the window to the bottom of the Z order
763 void wxWindowMSW::Lower()
765 ::SetWindowPos(GetHwnd(), HWND_BOTTOM
, 0, 0, 0, 0,
766 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
769 void wxWindowMSW::DoCaptureMouse()
771 HWND hWnd
= GetHwnd();
778 void wxWindowMSW::DoReleaseMouse()
780 if ( !::ReleaseCapture() )
782 wxLogLastError(wxT("ReleaseCapture"));
786 /* static */ wxWindow
*wxWindowBase::GetCapture()
788 HWND hwnd
= ::GetCapture();
789 return hwnd
? wxFindWinFromHandle(hwnd
) : NULL
;
792 bool wxWindowMSW::SetFont(const wxFont
& font
)
794 if ( !wxWindowBase::SetFont(font
) )
800 HWND hWnd
= GetHwnd();
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
807 WXHANDLE hFont
= GetFont().GetResourceHandle();
809 wxASSERT_MSG( hFont
, wxT("should have valid font") );
811 ::SendMessage(hWnd
, WM_SETFONT
, (WPARAM
)hFont
, MAKELPARAM(TRUE
, 0));
816 bool wxWindowMSW::SetCursor(const wxCursor
& cursor
)
818 if ( !wxWindowBase::SetCursor(cursor
) )
824 // don't "overwrite" busy cursor
825 if ( m_cursor
.Ok() && !wxIsBusy() )
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();
832 HWND hWnd
= GetHwnd();
836 ::GetCursorPosWinCE(&point
);
838 ::GetCursorPos(&point
);
841 RECT rect
= wxGetWindowRect(hWnd
);
843 set
= ::PtInRect(&rect
, point
) != 0;
848 ::SetCursor(GetHcursorOf(m_cursor
));
850 //else: will be set later when the mouse enters this window
856 void wxWindowMSW::WarpPointer(int x
, int y
)
858 ClientToScreen(&x
, &y
);
860 if ( !::SetCursorPos(x
, y
) )
862 wxLogLastError(wxT("SetCursorPos"));
866 void wxWindowMSW::MSWUpdateUIState(int action
, int state
)
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 )
874 s_needToUpdate
= wxGetOsVersion(&verMaj
, &verMin
) == wxOS_WINDOWS_NT
&&
878 if ( s_needToUpdate
)
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);
886 // ---------------------------------------------------------------------------
888 // ---------------------------------------------------------------------------
893 inline int GetScrollPosition(HWND hWnd
, int wOrient
)
895 #ifdef __WXMICROWIN__
896 return ::GetScrollPosWX(hWnd
, wOrient
);
898 WinStruct
<SCROLLINFO
> scrollInfo
;
899 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
900 scrollInfo
.fMask
= SIF_POS
;
901 ::GetScrollInfo(hWnd
, wOrient
, &scrollInfo
);
903 return scrollInfo
.nPos
;
908 inline UINT
WXOrientToSB(int orient
)
910 return orient
== wxHORIZONTAL
? SB_HORZ
: SB_VERT
;
913 } // anonymous namespace
915 int wxWindowMSW::GetScrollPos(int orient
) const
917 HWND hWnd
= GetHwnd();
918 wxCHECK_MSG( hWnd
, 0, wxT("no HWND in GetScrollPos") );
920 return GetScrollPosition(hWnd
, WXOrientToSB(orient
));
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
928 HWND hWnd
= GetHwnd();
931 WinStruct
<SCROLLINFO
> scrollInfo
;
932 scrollInfo
.fMask
= SIF_RANGE
;
933 if ( !::GetScrollInfo(hWnd
, WXOrientToSB(orient
), &scrollInfo
) )
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"));
939 maxPos
= scrollInfo
.nMax
;
941 // undo "range - 1" done in SetScrollbar()
945 int wxWindowMSW::GetScrollThumb(int orient
) const
947 return orient
== wxHORIZONTAL
? m_xThumbSize
: m_yThumbSize
;
950 void wxWindowMSW::SetScrollPos(int orient
, int pos
, bool refresh
)
952 HWND hWnd
= GetHwnd();
953 wxCHECK_RET( hWnd
, wxT("SetScrollPos: no HWND") );
955 WinStruct
<SCROLLINFO
> info
;
959 info
.fMask
= SIF_POS
;
960 if ( HasFlag(wxALWAYS_SHOW_SB
) )
962 // disable scrollbar instead of removing it then
963 info
.fMask
|= SIF_DISABLENOSCROLL
;
966 ::SetScrollInfo(hWnd
, WXOrientToSB(orient
), &info
, refresh
);
969 // New function that will replace some of the above.
970 void wxWindowMSW::SetScrollbar(int orient
,
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
;
980 HWND hwnd
= GetHwnd();
984 WinStruct
<SCROLLINFO
> info
;
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
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
996 if ( range
>= pageSize
)
998 ::EnableScrollBar(hwnd
, WXOrientToSB(orient
), ESB_ENABLE_BOTH
);
1001 //else: leave all the fields to be 0
1003 info
.fMask
= SIF_RANGE
| SIF_PAGE
| SIF_POS
;
1004 if ( HasFlag(wxALWAYS_SHOW_SB
) || range
== -1 )
1006 // disable scrollbar instead of removing it then
1007 info
.fMask
|= SIF_DISABLENOSCROLL
;
1010 ::SetScrollInfo(hwnd
, WXOrientToSB(orient
), &info
, refresh
);
1013 void wxWindowMSW::ScrollWindow(int dx
, int dy
, const wxRect
*prect
)
1019 wxCopyRectToRECT(*prect
, rect
);
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
);
1032 ::ScrollWindow(GetHwnd(), dx
, dy
, pr
, pr
);
1036 static bool ScrollVertically(HWND hwnd
, int kind
, int count
)
1038 int posStart
= GetScrollPosition(hwnd
, SB_VERT
);
1041 for ( int n
= 0; n
< count
; n
++ )
1043 ::SendMessage(hwnd
, WM_VSCROLL
, kind
, 0);
1045 int posNew
= GetScrollPosition(hwnd
, SB_VERT
);
1046 if ( posNew
== pos
)
1048 // don't bother to continue, we're already at top/bottom
1055 return pos
!= posStart
;
1058 bool wxWindowMSW::ScrollLines(int lines
)
1060 bool down
= lines
> 0;
1062 return ScrollVertically(GetHwnd(),
1063 down
? SB_LINEDOWN
: SB_LINEUP
,
1064 down
? lines
: -lines
);
1067 bool wxWindowMSW::ScrollPages(int pages
)
1069 bool down
= pages
> 0;
1071 return ScrollVertically(GetHwnd(),
1072 down
? SB_PAGEDOWN
: SB_PAGEUP
,
1073 down
? pages
: -pages
);
1076 // ----------------------------------------------------------------------------
1078 // ----------------------------------------------------------------------------
1080 void wxWindowMSW::SetLayoutDirection(wxLayoutDirection dir
)
1085 wxCHECK_RET( GetHwnd(),
1086 wxT("layout direction must be set after window creation") );
1088 LONG styleOld
= wxGetWindowExStyle(this);
1090 LONG styleNew
= styleOld
;
1093 case wxLayout_LeftToRight
:
1094 styleNew
&= ~WS_EX_LAYOUTRTL
;
1097 case wxLayout_RightToLeft
:
1098 styleNew
|= WS_EX_LAYOUTRTL
;
1102 wxFAIL_MSG(wxT("unsupported layout direction"));
1106 if ( styleNew
!= styleOld
)
1108 wxSetWindowExStyle(this, styleNew
);
1113 wxLayoutDirection
wxWindowMSW::GetLayoutDirection() const
1116 return wxLayout_Default
;
1118 wxCHECK_MSG( GetHwnd(), wxLayout_Default
, wxT("invalid window") );
1120 return wxHasWindowExStyle(this, WS_EX_LAYOUTRTL
) ? wxLayout_RightToLeft
1121 : wxLayout_LeftToRight
;
1126 wxWindowMSW::AdjustForLayoutDirection(wxCoord x
,
1127 wxCoord
WXUNUSED(width
),
1128 wxCoord
WXUNUSED(widthTotal
)) const
1130 // Win32 mirrors the coordinates of RTL windows automatically, so don't
1131 // redo it ourselves
1135 // ---------------------------------------------------------------------------
1137 // ---------------------------------------------------------------------------
1139 void wxWindowMSW::SubclassWin(WXHWND hWnd
)
1141 wxASSERT_MSG( !m_oldWndProc
, wxT("subclassing window twice?") );
1143 HWND hwnd
= (HWND
)hWnd
;
1144 wxCHECK_RET( ::IsWindow(hwnd
), wxT("invalid HWND in SubclassWin") );
1148 wxAssociateWinWithHandle(hwnd
, this);
1150 m_oldWndProc
= (WXFARPROC
)wxGetWindowProc((HWND
)hWnd
);
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
) )
1156 wxSetWindowProc(hwnd
, wxWndProc
);
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
;
1167 // we're officially created now, send the event
1168 wxWindowCreateEvent
event((wxWindow
*)this);
1169 (void)HandleWindowEvent(event
);
1172 void wxWindowMSW::UnsubclassWin()
1174 wxRemoveHandleAssociation(this);
1176 // Restore old Window proc
1177 HWND hwnd
= GetHwnd();
1182 wxCHECK_RET( ::IsWindow(hwnd
), wxT("invalid HWND in UnsubclassWin") );
1186 if ( !wxCheckWindowWndProc((WXHWND
)hwnd
, m_oldWndProc
) )
1188 wxSetWindowProc(hwnd
, (WNDPROC
)m_oldWndProc
);
1191 m_oldWndProc
= NULL
;
1196 void wxWindowMSW::AssociateHandle(WXWidget handle
)
1200 if ( !::DestroyWindow(GetHwnd()) )
1202 wxLogLastError(wxT("DestroyWindow"));
1206 WXHWND wxhwnd
= (WXHWND
)handle
;
1208 // this also calls SetHWND(wxhwnd)
1209 SubclassWin(wxhwnd
);
1212 void wxWindowMSW::DissociateHandle()
1214 // this also calls SetHWND(0) for us
1219 bool wxCheckWindowWndProc(WXHWND hWnd
,
1220 WXFARPROC
WXUNUSED(wndProc
))
1222 const wxString
str(wxGetWindowClass(hWnd
));
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");
1230 // ----------------------------------------------------------------------------
1232 // ----------------------------------------------------------------------------
1234 void wxWindowMSW::SetWindowStyleFlag(long flags
)
1236 long flagsOld
= GetWindowStyleFlag();
1237 if ( flags
== flagsOld
)
1240 // update the internal variable
1241 wxWindowBase::SetWindowStyleFlag(flags
);
1243 // and the real window flags
1244 MSWUpdateStyle(flagsOld
, GetExtraStyle());
1247 void wxWindowMSW::SetExtraStyle(long exflags
)
1249 long exflagsOld
= GetExtraStyle();
1250 if ( exflags
== exflagsOld
)
1253 // update the internal variable
1254 wxWindowBase::SetExtraStyle(exflags
);
1256 // and the real window flags
1257 MSWUpdateStyle(GetWindowStyleFlag(), exflagsOld
);
1260 void wxWindowMSW::MSWUpdateStyle(long flagsOld
, long exflagsOld
)
1262 // now update the Windows style as well if needed - and if the window had
1263 // been already created
1267 // we may need to call SetWindowPos() when we change some styles
1268 bool callSWP
= false;
1271 long style
= MSWGetStyle(GetWindowStyleFlag(), &exstyle
);
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
);
1281 long styleOld
= MSWGetStyle(flagsOld
, &exstyleOld
);
1283 wxWindowBase::SetExtraStyle(exflagsNew
);
1286 if ( style
!= styleOld
)
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
;
1296 ::SetWindowLong(GetHwnd(), GWL_STYLE
, styleReal
);
1298 // we need to call SetWindowPos() if any of the styles affecting the
1299 // frame appearance have changed
1300 callSWP
= ((styleOld
^ style
) & (WS_BORDER
|
1309 // and the extended style
1310 long exstyleReal
= wxGetWindowExStyle(this);
1312 if ( exstyle
!= exstyleOld
)
1314 exstyleReal
&= ~exstyleOld
;
1315 exstyleReal
|= exstyle
;
1317 wxSetWindowExStyle(this, exstyleReal
);
1319 // ex style changes don't take effect without calling SetWindowPos
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
1332 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
|
1335 wxLogLastError(wxT("SetWindowPos"));
1340 wxBorder
wxWindowMSW::GetDefaultBorderForControl() const
1342 return wxBORDER_THEME
;
1345 wxBorder
wxWindowMSW::GetDefaultBorder() const
1347 return wxWindowBase::GetDefaultBorder();
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
1354 #if defined(__POCKETPC__) || defined(__SMARTPHONE__)
1355 if (border
== wxBORDER_THEME
|| border
== wxBORDER_SUNKEN
|| border
== wxBORDER_SIMPLE
)
1356 return wxBORDER_SIMPLE
;
1358 return wxBORDER_NONE
;
1361 if (border
== wxBORDER_THEME
)
1363 if (CanApplyThemeBorder())
1365 wxUxThemeEngine
* theme
= wxUxThemeEngine::GetIfActive();
1367 return wxBORDER_THEME
;
1369 return wxBORDER_SUNKEN
;
1377 WXDWORD
wxWindowMSW::MSWGetStyle(long flags
, WXDWORD
*exstyle
) const
1379 // translate common wxWidgets styles to Windows ones
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
;
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
;
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
1400 if ( flags
& wxVSCROLL
)
1401 style
|= WS_VSCROLL
;
1403 if ( flags
& wxHSCROLL
)
1404 style
|= WS_HSCROLL
;
1406 const wxBorder border
= TranslateBorder(GetBorder(flags
));
1408 // After translation, border is now optimized for the specific version of Windows
1409 // and theme engine presence.
1411 // WS_BORDER is only required for wxBORDER_SIMPLE
1412 if ( border
== wxBORDER_SIMPLE
)
1415 // now deal with ext style if the caller wants it
1421 if ( flags
& wxTRANSPARENT_WINDOW
)
1422 *exstyle
|= WS_EX_TRANSPARENT
;
1428 case wxBORDER_DEFAULT
:
1429 wxFAIL_MSG( wxT("unknown border style") );
1433 case wxBORDER_SIMPLE
:
1434 case wxBORDER_THEME
:
1437 case wxBORDER_STATIC
:
1438 *exstyle
|= WS_EX_STATICEDGE
;
1441 case wxBORDER_RAISED
:
1442 *exstyle
|= WS_EX_DLGMODALFRAME
;
1445 case wxBORDER_SUNKEN
:
1446 *exstyle
|= WS_EX_CLIENTEDGE
;
1447 style
&= ~WS_BORDER
;
1450 // case wxBORDER_DOUBLE:
1451 // *exstyle |= WS_EX_DLGMODALFRAME;
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() )
1461 *exstyle
|= WS_EX_CONTROLPARENT
;
1463 #endif // __WXUNIVERSAL__
1469 // Setup background and foreground colours correctly
1470 void wxWindowMSW::SetupColours()
1473 SetBackgroundColour(GetParent()->GetBackgroundColour());
1476 bool wxWindowMSW::IsMouseInWindow() const
1478 // get the mouse position
1481 ::GetCursorPosWinCE(&pt
);
1483 ::GetCursorPos(&pt
);
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
);
1492 return hwnd
!= NULL
;
1495 void wxWindowMSW::OnInternalIdle()
1497 #ifndef HAVE_TRACKMOUSEEVENT
1498 // Check if we need to send a LEAVE event
1499 if ( m_mouseInWindow
)
1501 // note that we should generate the leave event whether the window has
1502 // or doesn't have mouse capture
1503 if ( !IsMouseInWindow() )
1505 GenerateMouseLeave();
1508 #endif // !HAVE_TRACKMOUSEEVENT
1510 if (wxUpdateUIEvent::CanUpdate(this) && IsShownOnScreen())
1511 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
1514 // Set this window to be the child of 'parent'.
1515 bool wxWindowMSW::Reparent(wxWindowBase
*parent
)
1517 if ( !wxWindowBase::Reparent(parent
) )
1520 HWND hWndChild
= GetHwnd();
1521 HWND hWndParent
= GetParent() ? GetWinHwnd(GetParent()) : (HWND
)0;
1523 ::SetParent(hWndChild
, hWndParent
);
1526 if ( wxHasWindowExStyle(this, WS_EX_CONTROLPARENT
) )
1528 EnsureParentHasControlParentStyle(GetParent());
1530 #endif // !__WXWINCE__
1535 static inline void SendSetRedraw(HWND hwnd
, bool on
)
1537 #ifndef __WXMICROWIN__
1538 ::SendMessage(hwnd
, WM_SETREDRAW
, (WPARAM
)on
, 0);
1542 void wxWindowMSW::DoFreeze()
1545 return; // no point in freezing hidden window
1547 SendSetRedraw(GetHwnd(), false);
1550 void wxWindowMSW::DoThaw()
1553 return; // hidden windows aren't frozen by DoFreeze
1555 SendSetRedraw(GetHwnd(), true);
1557 // we need to refresh everything or otherwise the invalidated area
1558 // is not going to be repainted
1562 void wxWindowMSW::Refresh(bool eraseBack
, const wxRect
*rect
)
1564 HWND hWnd
= GetHwnd();
1571 wxCopyRectToRECT(*rect
, mswRect
);
1579 // RedrawWindow not available on SmartPhone or eVC++ 3
1580 #if !defined(__SMARTPHONE__) && !(defined(_WIN32_WCE) && _WIN32_WCE < 400)
1581 UINT flags
= RDW_INVALIDATE
| RDW_ALLCHILDREN
;
1585 ::RedrawWindow(hWnd
, pRect
, NULL
, flags
);
1587 ::InvalidateRect(hWnd
, pRect
, eraseBack
);
1592 void wxWindowMSW::Update()
1594 if ( !::UpdateWindow(GetHwnd()) )
1596 wxLogLastError(wxT("UpdateWindow"));
1599 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
1600 // just calling UpdateWindow() is not enough, what we did in our WM_PAINT
1601 // handler needs to be really drawn right now
1606 // ---------------------------------------------------------------------------
1608 // ---------------------------------------------------------------------------
1610 #if wxUSE_DRAG_AND_DROP || !defined(__WXWINCE__)
1614 // we need to lower the sibling static boxes so controls contained within can be
1616 static void AdjustStaticBoxZOrder(wxWindow
*parent
)
1618 // no sibling static boxes if we have no parent (ie TLW)
1622 for ( wxWindowList::compatibility_iterator node
= parent
->GetChildren().GetFirst();
1624 node
= node
->GetNext() )
1626 wxStaticBox
*statbox
= wxDynamicCast(node
->GetData(), wxStaticBox
);
1629 ::SetWindowPos(GetHwndOf(statbox
), HWND_BOTTOM
, 0, 0, 0, 0,
1630 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
1635 #else // !wxUSE_STATBOX
1637 static inline void AdjustStaticBoxZOrder(wxWindow
* WXUNUSED(parent
))
1641 #endif // wxUSE_STATBOX/!wxUSE_STATBOX
1643 #endif // drag and drop is used
1645 #if wxUSE_DRAG_AND_DROP
1646 void wxWindowMSW::SetDropTarget(wxDropTarget
*pDropTarget
)
1648 if ( m_dropTarget
!= 0 ) {
1649 m_dropTarget
->Revoke(m_hWnd
);
1650 delete m_dropTarget
;
1653 m_dropTarget
= pDropTarget
;
1654 if ( m_dropTarget
!= 0 )
1656 AdjustStaticBoxZOrder(GetParent());
1657 m_dropTarget
->Register(m_hWnd
);
1660 #endif // wxUSE_DRAG_AND_DROP
1662 // old-style file manager drag&drop support: we retain the old-style
1663 // DragAcceptFiles in parallel with SetDropTarget.
1664 void wxWindowMSW::DragAcceptFiles(bool WXUNUSED_IN_WINCE(accept
))
1667 HWND hWnd
= GetHwnd();
1670 AdjustStaticBoxZOrder(GetParent());
1671 ::DragAcceptFiles(hWnd
, (BOOL
)accept
);
1676 // ----------------------------------------------------------------------------
1678 // ----------------------------------------------------------------------------
1682 void wxWindowMSW::DoSetToolTip(wxToolTip
*tooltip
)
1684 wxWindowBase::DoSetToolTip(tooltip
);
1687 m_tooltip
->SetWindow((wxWindow
*)this);
1690 #endif // wxUSE_TOOLTIPS
1692 // ---------------------------------------------------------------------------
1693 // moving and resizing
1694 // ---------------------------------------------------------------------------
1696 bool wxWindowMSW::IsSizeDeferred() const
1698 #if wxUSE_DEFERRED_SIZING
1699 if ( m_pendingPosition
!= wxDefaultPosition
||
1700 m_pendingSize
!= wxDefaultSize
)
1702 #endif // wxUSE_DEFERRED_SIZING
1708 void wxWindowMSW::DoGetSize(int *x
, int *y
) const
1710 #if wxUSE_DEFERRED_SIZING
1711 // if SetSize() had been called at wx level but not realized at Windows
1712 // level yet (i.e. EndDeferWindowPos() not called), we still should return
1713 // the new and not the old position to the other wx code
1714 if ( m_pendingSize
!= wxDefaultSize
)
1717 *x
= m_pendingSize
.x
;
1719 *y
= m_pendingSize
.y
;
1721 else // use current size
1722 #endif // wxUSE_DEFERRED_SIZING
1724 RECT rect
= wxGetWindowRect(GetHwnd());
1727 *x
= rect
.right
- rect
.left
;
1729 *y
= rect
.bottom
- rect
.top
;
1733 // Get size *available for subwindows* i.e. excluding menu bar etc.
1734 void wxWindowMSW::DoGetClientSize(int *x
, int *y
) const
1736 #if wxUSE_DEFERRED_SIZING
1737 if ( m_pendingSize
!= wxDefaultSize
)
1739 // we need to calculate the client size corresponding to pending size
1741 // FIXME: Unfortunately this doesn't work correctly for the maximized
1742 // top level windows, the returned values are too small (e.g.
1743 // under Windows 7 on a 1600*1200 screen with task bar on the
1744 // right the pending size for a maximized window is 1538*1200
1745 // and WM_NCCALCSIZE returns 1528*1172 even though the correct
1746 // client size of such window is 1538*1182). No idea how to fix
1747 // it though, setting WS_MAXIMIZE in GWL_STYLE before calling
1748 // WM_NCCALCSIZE doesn't help and AdjustWindowRectEx() doesn't
1749 // work in this direction neither. So we just have to live with
1750 // the slightly wrong results and relayout the window when it
1751 // gets finally shown in its maximized state (see #11762).
1753 rect
.left
= m_pendingPosition
.x
;
1754 rect
.top
= m_pendingPosition
.y
;
1755 rect
.right
= rect
.left
+ m_pendingSize
.x
;
1756 rect
.bottom
= rect
.top
+ m_pendingSize
.y
;
1758 ::SendMessage(GetHwnd(), WM_NCCALCSIZE
, FALSE
, (LPARAM
)&rect
);
1761 *x
= rect
.right
- rect
.left
;
1763 *y
= rect
.bottom
- rect
.top
;
1766 #endif // wxUSE_DEFERRED_SIZING
1768 RECT rect
= wxGetClientRect(GetHwnd());
1777 void wxWindowMSW::DoGetPosition(int *x
, int *y
) const
1779 wxWindow
* const parent
= GetParent();
1782 #if wxUSE_DEFERRED_SIZING
1783 if ( m_pendingPosition
!= wxDefaultPosition
)
1785 pos
= m_pendingPosition
;
1787 else // use current position
1788 #endif // wxUSE_DEFERRED_SIZING
1790 RECT rect
= wxGetWindowRect(GetHwnd());
1793 point
.x
= rect
.left
;
1796 // we do the adjustments with respect to the parent only for the "real"
1797 // children, not for the dialogs/frames
1798 if ( !IsTopLevel() )
1800 if ( wxTheApp
->GetLayoutDirection() == wxLayout_RightToLeft
)
1802 // In RTL mode, we want the logical left x-coordinate,
1803 // which would be the physical right x-coordinate.
1804 point
.x
= rect
.right
;
1807 // Since we now have the absolute screen coords, if there's a
1808 // parent we must subtract its top left corner
1811 ::ScreenToClient(GetHwndOf(parent
), &point
);
1819 // we also must adjust by the client area offset: a control which is just
1820 // under a toolbar could be at (0, 30) in Windows but at (0, 0) in wx
1821 if ( parent
&& !IsTopLevel() )
1823 const wxPoint
pt(parent
->GetClientAreaOrigin());
1834 void wxWindowMSW::DoScreenToClient(int *x
, int *y
) const
1842 ::ScreenToClient(GetHwnd(), &pt
);
1850 void wxWindowMSW::DoClientToScreen(int *x
, int *y
) const
1858 ::ClientToScreen(GetHwnd(), &pt
);
1867 wxWindowMSW::DoMoveSibling(WXHWND hwnd
, int x
, int y
, int width
, int height
)
1869 #if wxUSE_DEFERRED_SIZING
1870 // if our parent had prepared a defer window handle for us, use it (unless
1871 // we are a top level window)
1872 wxWindowMSW
* const parent
= IsTopLevel() ? NULL
: GetParent();
1874 HDWP hdwp
= parent
? (HDWP
)parent
->m_hDWP
: NULL
;
1877 hdwp
= ::DeferWindowPos(hdwp
, (HWND
)hwnd
, NULL
, x
, y
, width
, height
,
1878 SWP_NOZORDER
| SWP_NOOWNERZORDER
| SWP_NOACTIVATE
);
1881 wxLogLastError(wxT("DeferWindowPos"));
1887 // hdwp must be updated as it may have been changed
1888 parent
->m_hDWP
= (WXHANDLE
)hdwp
;
1893 // did deferred move, remember new coordinates of the window as they're
1894 // different from what Windows would return for it
1898 // otherwise (or if deferring failed) move the window in place immediately
1899 #endif // wxUSE_DEFERRED_SIZING
1900 if ( !::MoveWindow((HWND
)hwnd
, x
, y
, width
, height
, IsShown()) )
1902 wxLogLastError(wxT("MoveWindow"));
1905 // if wxUSE_DEFERRED_SIZING, indicates that we didn't use deferred move,
1906 // ignored otherwise
1910 void wxWindowMSW::DoMoveWindow(int x
, int y
, int width
, int height
)
1912 // TODO: is this consistent with other platforms?
1913 // Still, negative width or height shouldn't be allowed
1919 if ( DoMoveSibling(m_hWnd
, x
, y
, width
, height
) )
1921 #if wxUSE_DEFERRED_SIZING
1922 m_pendingPosition
= wxPoint(x
, y
);
1923 m_pendingSize
= wxSize(width
, height
);
1925 else // window was moved immediately, without deferring it
1927 m_pendingPosition
= wxDefaultPosition
;
1928 m_pendingSize
= wxDefaultSize
;
1929 #endif // wxUSE_DEFERRED_SIZING
1933 // set the size of the window: if the dimensions are positive, just use them,
1934 // but if any of them is equal to -1, it means that we must find the value for
1935 // it ourselves (unless sizeFlags contains wxSIZE_ALLOW_MINUS_ONE flag, in
1936 // which case -1 is a valid value for x and y)
1938 // If sizeFlags contains wxSIZE_AUTO_WIDTH/HEIGHT flags (default), we calculate
1939 // the width/height to best suit our contents, otherwise we reuse the current
1941 void wxWindowMSW::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
1943 // get the current size and position...
1944 int currentX
, currentY
;
1945 int currentW
, currentH
;
1947 GetPosition(¤tX
, ¤tY
);
1948 GetSize(¤tW
, ¤tH
);
1950 // ... and don't do anything (avoiding flicker) if it's already ok unless
1951 // we're forced to resize the window
1952 if ( x
== currentX
&& y
== currentY
&&
1953 width
== currentW
&& height
== currentH
&&
1954 !(sizeFlags
& wxSIZE_FORCE
) )
1956 if (sizeFlags
& wxSIZE_FORCE_EVENT
)
1958 wxSizeEvent
event( wxSize(width
,height
), GetId() );
1959 event
.SetEventObject( this );
1960 HandleWindowEvent( event
);
1965 if ( x
== wxDefaultCoord
&& !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) )
1967 if ( y
== wxDefaultCoord
&& !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) )
1970 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
1972 wxSize size
= wxDefaultSize
;
1973 if ( width
== wxDefaultCoord
)
1975 if ( sizeFlags
& wxSIZE_AUTO_WIDTH
)
1977 size
= GetBestSize();
1982 // just take the current one
1987 if ( height
== wxDefaultCoord
)
1989 if ( sizeFlags
& wxSIZE_AUTO_HEIGHT
)
1991 if ( size
.x
== wxDefaultCoord
)
1993 size
= GetBestSize();
1995 //else: already called GetBestSize() above
2001 // just take the current one
2006 DoMoveWindow(x
, y
, width
, height
);
2009 void wxWindowMSW::DoSetClientSize(int width
, int height
)
2011 // setting the client size is less obvious than it could have been
2012 // because in the result of changing the total size the window scrollbar
2013 // may [dis]appear and/or its menubar may [un]wrap (and AdjustWindowRect()
2014 // doesn't take neither into account) and so the client size will not be
2015 // correct as the difference between the total and client size changes --
2016 // so we keep changing it until we get it right
2018 // normally this loop shouldn't take more than 3 iterations (usually 1 but
2019 // if scrollbars [dis]appear as the result of the first call, then 2 and it
2020 // may become 3 if the window had 0 size originally and so we didn't
2021 // calculate the scrollbar correction correctly during the first iteration)
2022 // but just to be on the safe side we check for it instead of making it an
2023 // "infinite" loop (i.e. leaving break inside as the only way to get out)
2024 for ( int i
= 0; i
< 4; i
++ )
2027 ::GetClientRect(GetHwnd(), &rectClient
);
2029 // if the size is already ok, stop here (NB: rectClient.left = top = 0)
2030 if ( (rectClient
.right
== width
|| width
== wxDefaultCoord
) &&
2031 (rectClient
.bottom
== height
|| height
== wxDefaultCoord
) )
2036 // Find the difference between the entire window (title bar and all)
2037 // and the client area; add this to the new client size to move the
2040 ::GetWindowRect(GetHwnd(), &rectWin
);
2042 const int widthWin
= rectWin
.right
- rectWin
.left
,
2043 heightWin
= rectWin
.bottom
- rectWin
.top
;
2045 // MoveWindow positions the child windows relative to the parent, so
2046 // adjust if necessary
2047 if ( !IsTopLevel() )
2049 wxWindow
*parent
= GetParent();
2052 ::ScreenToClient(GetHwndOf(parent
), (POINT
*)&rectWin
);
2056 // don't call DoMoveWindow() because we want to move window immediately
2057 // and not defer it here as otherwise the value returned by
2058 // GetClient/WindowRect() wouldn't change as the window wouldn't be
2060 if ( !::MoveWindow(GetHwnd(),
2063 width
+ widthWin
- rectClient
.right
,
2064 height
+ heightWin
- rectClient
.bottom
,
2067 wxLogLastError(wxT("MoveWindow"));
2072 wxSize
wxWindowMSW::DoGetBorderSize() const
2075 switch ( GetBorder() )
2077 case wxBORDER_STATIC
:
2078 case wxBORDER_SIMPLE
:
2082 case wxBORDER_SUNKEN
:
2086 case wxBORDER_RAISED
:
2087 case wxBORDER_DOUBLE
:
2092 wxFAIL_MSG( wxT("unknown border style") );
2099 return 2*wxSize(border
, border
);
2102 // ---------------------------------------------------------------------------
2104 // ---------------------------------------------------------------------------
2106 int wxWindowMSW::GetCharHeight() const
2108 return wxGetTextMetrics(this).tmHeight
;
2111 int wxWindowMSW::GetCharWidth() const
2113 // +1 is needed because Windows apparently adds it when calculating the
2114 // dialog units size in pixels
2115 #if wxDIALOG_UNIT_COMPATIBILITY
2116 return wxGetTextMetrics(this).tmAveCharWidth
;
2118 return wxGetTextMetrics(this).tmAveCharWidth
+ 1;
2122 void wxWindowMSW::DoGetTextExtent(const wxString
& string
,
2125 int *externalLeading
,
2126 const wxFont
*fontToUse
) const
2128 wxASSERT_MSG( !fontToUse
|| fontToUse
->Ok(),
2129 wxT("invalid font in GetTextExtent()") );
2133 hfontToUse
= GetHfontOf(*fontToUse
);
2135 hfontToUse
= GetHfontOf(GetFont());
2137 WindowHDC
hdc(GetHwnd());
2138 SelectInHDC
selectFont(hdc
, hfontToUse
);
2142 ::GetTextExtentPoint32(hdc
, string
.wx_str(), string
.length(), &sizeRect
);
2143 GetTextMetrics(hdc
, &tm
);
2150 *descent
= tm
.tmDescent
;
2151 if ( externalLeading
)
2152 *externalLeading
= tm
.tmExternalLeading
;
2155 // ---------------------------------------------------------------------------
2157 // ---------------------------------------------------------------------------
2159 #if wxUSE_MENUS_NATIVE
2161 // yield for WM_COMMAND events only, i.e. process all WM_COMMANDs in the queue
2162 // immediately, without waiting for the next event loop iteration
2164 // NB: this function should probably be made public later as it can almost
2165 // surely replace wxYield() elsewhere as well
2166 static void wxYieldForCommandsOnly()
2168 // peek all WM_COMMANDs (it will always return WM_QUIT too but we don't
2169 // want to process it here)
2171 while ( ::PeekMessage(&msg
, (HWND
)0, WM_COMMAND
, WM_COMMAND
, PM_REMOVE
) )
2173 if ( msg
.message
== WM_QUIT
)
2175 // if we retrieved a WM_QUIT, insert back into the message queue.
2176 ::PostQuitMessage(0);
2180 // luckily (as we don't have access to wxEventLoopImpl method from here
2181 // anyhow...) we don't need to pre process WM_COMMANDs so dispatch it
2183 ::TranslateMessage(&msg
);
2184 ::DispatchMessage(&msg
);
2188 bool wxWindowMSW::DoPopupMenu(wxMenu
*menu
, int x
, int y
)
2192 if ( x
== wxDefaultCoord
&& y
== wxDefaultCoord
)
2194 wxPoint mouse
= ScreenToClient(wxGetMousePosition());
2195 x
= mouse
.x
; y
= mouse
.y
;
2198 HWND hWnd
= GetHwnd();
2199 HMENU hMenu
= GetHmenuOf(menu
);
2203 ::ClientToScreen(hWnd
, &point
);
2204 #if defined(__WXWINCE__)
2205 static const UINT flags
= 0;
2206 #else // !__WXWINCE__
2207 UINT flags
= TPM_RIGHTBUTTON
;
2208 // NT4 doesn't support TPM_RECURSE and simply doesn't show the menu at all
2209 // when it's use, I'm not sure about Win95/98 but prefer to err on the safe
2210 // side and not to use it there neither -- modify the test if it does work
2212 if ( wxGetWinVersion() >= wxWinVersion_5
)
2214 // using TPM_RECURSE allows us to show a popup menu while another menu
2215 // is opened which can be useful and is supported by the other
2216 // platforms, so allow it under Windows too
2217 flags
|= TPM_RECURSE
;
2219 #endif // __WXWINCE__/!__WXWINCE__
2221 ::TrackPopupMenu(hMenu
, flags
, point
.x
, point
.y
, 0, hWnd
, NULL
);
2223 // we need to do it right now as otherwise the events are never going to be
2224 // sent to wxCurrentPopupMenu from HandleCommand()
2226 // note that even eliminating (ugly) wxCurrentPopupMenu global wouldn't
2227 // help and we'd still need wxYieldForCommandsOnly() as the menu may be
2228 // destroyed as soon as we return (it can be a local variable in the caller
2229 // for example) and so we do need to process the event immediately
2230 wxYieldForCommandsOnly();
2235 #endif // wxUSE_MENUS_NATIVE
2237 // ===========================================================================
2238 // pre/post message processing
2239 // ===========================================================================
2241 WXLRESULT
wxWindowMSW::MSWDefWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
)
2244 return ::CallWindowProc(CASTWNDPROC m_oldWndProc
, GetHwnd(), (UINT
) nMsg
, (WPARAM
) wParam
, (LPARAM
) lParam
);
2246 return ::DefWindowProc(GetHwnd(), nMsg
, wParam
, lParam
);
2249 bool wxWindowMSW::MSWProcessMessage(WXMSG
* pMsg
)
2251 // wxUniversal implements tab traversal itself
2252 #ifndef __WXUNIVERSAL__
2253 if ( m_hWnd
!= 0 && (GetWindowStyleFlag() & wxTAB_TRAVERSAL
) )
2255 // intercept dialog navigation keys
2256 MSG
*msg
= (MSG
*)pMsg
;
2258 // here we try to do all the job which ::IsDialogMessage() usually does
2260 if ( msg
->message
== WM_KEYDOWN
)
2262 bool bCtrlDown
= wxIsCtrlDown();
2263 bool bShiftDown
= wxIsShiftDown();
2265 // WM_GETDLGCODE: ask the control if it wants the key for itself,
2266 // don't process it if it's the case (except for Ctrl-Tab/Enter
2267 // combinations which are always processed)
2268 LONG lDlgCode
= ::SendMessage(msg
->hwnd
, WM_GETDLGCODE
, 0, 0);
2270 // surprisingly, DLGC_WANTALLKEYS bit mask doesn't contain the
2271 // DLGC_WANTTAB nor DLGC_WANTARROWS bits although, logically,
2272 // it, of course, implies them
2273 if ( lDlgCode
& DLGC_WANTALLKEYS
)
2275 lDlgCode
|= DLGC_WANTTAB
| DLGC_WANTARROWS
;
2278 bool bForward
= true,
2279 bWindowChange
= false,
2282 // should we process this message specially?
2283 bool bProcess
= true;
2284 switch ( msg
->wParam
)
2287 if ( (lDlgCode
& DLGC_WANTTAB
) && !bCtrlDown
)
2289 // let the control have the TAB
2292 else // use it for navigation
2294 // Ctrl-Tab cycles thru notebook pages
2295 bWindowChange
= bCtrlDown
;
2296 bForward
= !bShiftDown
;
2303 if ( (lDlgCode
& DLGC_WANTARROWS
) || bCtrlDown
)
2311 if ( (lDlgCode
& DLGC_WANTARROWS
) || bCtrlDown
)
2320 // we treat PageUp/Dn as arrows because chances are that
2321 // a control which needs arrows also needs them for
2322 // navigation (e.g. wxTextCtrl, wxListCtrl, ...)
2323 if ( (lDlgCode
& DLGC_WANTARROWS
) && !bCtrlDown
)
2325 else // OTOH Ctrl-PageUp/Dn works as [Shift-]Ctrl-Tab
2326 bWindowChange
= true;
2332 // currently active button should get enter press even
2333 // if there is a default button elsewhere so check if
2334 // this window is a button first
2335 wxWindow
*btn
= NULL
;
2336 if ( lDlgCode
& DLGC_DEFPUSHBUTTON
)
2338 // let IsDialogMessage() handle this for all
2339 // buttons except the owner-drawn ones which it
2340 // just seems to ignore
2341 long style
= ::GetWindowLong(msg
->hwnd
, GWL_STYLE
);
2342 if ( (style
& BS_OWNERDRAW
) == BS_OWNERDRAW
)
2344 // emulate the button click
2345 btn
= wxFindWinFromHandle(msg
->hwnd
);
2350 else // not a button itself, do we have default button?
2352 // check if this window or any of its ancestors
2353 // wants the message for itself (we always reserve
2354 // Ctrl-Enter for dialog navigation though)
2355 wxWindow
*win
= this;
2358 // this will contain the dialog code of this
2359 // window and all of its parent windows in turn
2360 LONG lDlgCode2
= lDlgCode
;
2364 if ( lDlgCode2
& DLGC_WANTMESSAGE
)
2366 // as it wants to process Enter itself,
2367 // don't call IsDialogMessage() which
2372 // don't propagate keyboard messages beyond
2373 // the first top level window parent
2374 if ( win
->IsTopLevel() )
2377 win
= win
->GetParent();
2379 lDlgCode2
= ::SendMessage
2390 win
= wxGetTopLevelParent(win
);
2393 wxTopLevelWindow
* const
2394 tlw
= wxDynamicCast(win
, wxTopLevelWindow
);
2397 btn
= wxDynamicCast(tlw
->GetDefaultItem(),
2402 if ( btn
&& btn
->IsEnabled() )
2404 btn
->MSWCommand(BN_CLICKED
, 0 /* unused */);
2408 #endif // wxUSE_BUTTON
2411 // map Enter presses into button presses on PDAs
2412 wxJoystickEvent
event(wxEVT_JOY_BUTTON_DOWN
);
2413 event
.SetEventObject(this);
2414 if ( HandleWindowEvent(event
) )
2416 #endif // __WXWINCE__
2426 wxNavigationKeyEvent event
;
2427 event
.SetDirection(bForward
);
2428 event
.SetWindowChange(bWindowChange
);
2429 event
.SetFromTab(bFromTab
);
2430 event
.SetEventObject(this);
2432 if ( HandleWindowEvent(event
) )
2434 // as we don't call IsDialogMessage(), which would take of
2435 // this by default, we need to manually send this message
2436 // so that controls can change their UI state if needed
2437 MSWUpdateUIState(UIS_CLEAR
, UISF_HIDEFOCUS
);
2444 if ( ::IsDialogMessage(GetHwnd(), msg
) )
2446 // IsDialogMessage() did something...
2450 #endif // __WXUNIVERSAL__
2455 // relay mouse move events to the tooltip control
2456 MSG
*msg
= (MSG
*)pMsg
;
2457 if ( msg
->message
== WM_MOUSEMOVE
)
2458 wxToolTip::RelayEvent(pMsg
);
2460 #endif // wxUSE_TOOLTIPS
2465 bool wxWindowMSW::MSWTranslateMessage(WXMSG
* pMsg
)
2467 #if wxUSE_ACCEL && !defined(__WXUNIVERSAL__)
2468 return m_acceleratorTable
.Translate(this, pMsg
);
2472 #endif // wxUSE_ACCEL
2475 bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG
* msg
)
2477 // all tests below have to deal with various bugs/misfeatures of
2478 // IsDialogMessage(): we have to prevent it from being called from our
2479 // MSWProcessMessage() in some situations
2481 // don't let IsDialogMessage() get VK_ESCAPE as it _always_ eats the
2482 // message even when there is no cancel button and when the message is
2483 // needed by the control itself: in particular, it prevents the tree in
2484 // place edit control from being closed with Escape in a dialog
2485 if ( msg
->message
== WM_KEYDOWN
&& msg
->wParam
== VK_ESCAPE
)
2490 // ::IsDialogMessage() is broken and may sometimes hang the application by
2491 // going into an infinite loop when it tries to find the control to give
2492 // focus to when Alt-<key> is pressed, so we try to detect [some of] the
2493 // situations when this may happen and not call it then
2494 if ( msg
->message
!= WM_SYSCHAR
)
2497 // assume we can call it by default
2498 bool canSafelyCallIsDlgMsg
= true;
2500 HWND hwndFocus
= ::GetFocus();
2502 // if the currently focused window itself has WS_EX_CONTROLPARENT style,
2503 // ::IsDialogMessage() will also enter an infinite loop, because it will
2504 // recursively check the child windows but not the window itself and so if
2505 // none of the children accepts focus it loops forever (as it only stops
2506 // when it gets back to the window it started from)
2508 // while it is very unusual that a window with WS_EX_CONTROLPARENT
2509 // style has the focus, it can happen. One such possibility is if
2510 // all windows are either toplevel, wxDialog, wxPanel or static
2511 // controls and no window can actually accept keyboard input.
2512 #if !defined(__WXWINCE__)
2513 if ( ::GetWindowLong(hwndFocus
, GWL_EXSTYLE
) & WS_EX_CONTROLPARENT
)
2515 // pessimistic by default
2516 canSafelyCallIsDlgMsg
= false;
2517 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
2519 node
= node
->GetNext() )
2521 wxWindow
* const win
= node
->GetData();
2522 if ( win
->CanAcceptFocus() &&
2523 !wxHasWindowExStyle(win
, WS_EX_CONTROLPARENT
) )
2525 // it shouldn't hang...
2526 canSafelyCallIsDlgMsg
= true;
2532 #endif // !__WXWINCE__
2534 if ( canSafelyCallIsDlgMsg
)
2536 // ::IsDialogMessage() can enter in an infinite loop when the
2537 // currently focused window is disabled or hidden and its
2538 // parent has WS_EX_CONTROLPARENT style, so don't call it in
2542 if ( !::IsWindowEnabled(hwndFocus
) ||
2543 !::IsWindowVisible(hwndFocus
) )
2545 // it would enter an infinite loop if we do this!
2546 canSafelyCallIsDlgMsg
= false;
2551 if ( !(::GetWindowLong(hwndFocus
, GWL_STYLE
) & WS_CHILD
) )
2553 // it's a top level window, don't go further -- e.g. even
2554 // if the parent of a dialog is disabled, this doesn't
2555 // break navigation inside the dialog
2559 hwndFocus
= ::GetParent(hwndFocus
);
2563 return canSafelyCallIsDlgMsg
;
2566 // ---------------------------------------------------------------------------
2567 // message params unpackers
2568 // ---------------------------------------------------------------------------
2570 void wxWindowMSW::UnpackCommand(WXWPARAM wParam
, WXLPARAM lParam
,
2571 WORD
*id
, WXHWND
*hwnd
, WORD
*cmd
)
2573 *id
= LOWORD(wParam
);
2574 *hwnd
= (WXHWND
)lParam
;
2575 *cmd
= HIWORD(wParam
);
2578 void wxWindowMSW::UnpackActivate(WXWPARAM wParam
, WXLPARAM lParam
,
2579 WXWORD
*state
, WXWORD
*minimized
, WXHWND
*hwnd
)
2581 *state
= LOWORD(wParam
);
2582 *minimized
= HIWORD(wParam
);
2583 *hwnd
= (WXHWND
)lParam
;
2586 void wxWindowMSW::UnpackScroll(WXWPARAM wParam
, WXLPARAM lParam
,
2587 WXWORD
*code
, WXWORD
*pos
, WXHWND
*hwnd
)
2589 *code
= LOWORD(wParam
);
2590 *pos
= HIWORD(wParam
);
2591 *hwnd
= (WXHWND
)lParam
;
2594 void wxWindowMSW::UnpackCtlColor(WXWPARAM wParam
, WXLPARAM lParam
,
2595 WXHDC
*hdc
, WXHWND
*hwnd
)
2597 *hwnd
= (WXHWND
)lParam
;
2598 *hdc
= (WXHDC
)wParam
;
2601 void wxWindowMSW::UnpackMenuSelect(WXWPARAM wParam
, WXLPARAM lParam
,
2602 WXWORD
*item
, WXWORD
*flags
, WXHMENU
*hmenu
)
2604 *item
= (WXWORD
)wParam
;
2605 *flags
= HIWORD(wParam
);
2606 *hmenu
= (WXHMENU
)lParam
;
2609 // ---------------------------------------------------------------------------
2610 // Main wxWidgets window proc and the window proc for wxWindow
2611 // ---------------------------------------------------------------------------
2613 // Hook for new window just as it's being created, when the window isn't yet
2614 // associated with the handle
2615 static wxWindowMSW
*gs_winBeingCreated
= NULL
;
2617 // implementation of wxWindowCreationHook class: it just sets gs_winBeingCreated to the
2618 // window being created and insures that it's always unset back later
2619 wxWindowCreationHook::wxWindowCreationHook(wxWindowMSW
*winBeingCreated
)
2621 gs_winBeingCreated
= winBeingCreated
;
2624 wxWindowCreationHook::~wxWindowCreationHook()
2626 gs_winBeingCreated
= NULL
;
2630 LRESULT WXDLLEXPORT APIENTRY _EXPORT
wxWndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
2632 // trace all messages: useful for the debugging but noticeably slows down
2633 // the code so don't do it by default
2634 #if wxDEBUG_LEVEL >= 2
2635 // notice that we cast wParam and lParam to long to avoid mismatch with
2636 // format specifiers in 64 bit builds where they are both int64 quantities
2638 // casting like this loses information, of course, but it shouldn't matter
2639 // much for this diagnostic code and it keeps the code simple
2640 wxLogTrace("winmsg",
2641 wxT("Processing %s(hWnd=%p, wParam=%08lx, lParam=%08lx)"),
2642 wxGetMessageName(message
), hWnd
, (long)wParam
, (long)lParam
);
2643 #endif // wxDEBUG_LEVEL >= 2
2645 wxWindowMSW
*wnd
= wxFindWinFromHandle(hWnd
);
2647 // when we get the first message for the HWND we just created, we associate
2648 // it with wxWindow stored in gs_winBeingCreated
2649 if ( !wnd
&& gs_winBeingCreated
)
2651 wxAssociateWinWithHandle(hWnd
, gs_winBeingCreated
);
2652 wnd
= gs_winBeingCreated
;
2653 gs_winBeingCreated
= NULL
;
2654 wnd
->SetHWND((WXHWND
)hWnd
);
2659 if ( wnd
&& wxGUIEventLoop::AllowProcessing(wnd
) )
2660 rc
= wnd
->MSWWindowProc(message
, wParam
, lParam
);
2662 rc
= ::DefWindowProc(hWnd
, message
, wParam
, lParam
);
2667 WXLRESULT
wxWindowMSW::MSWWindowProc(WXUINT message
, WXWPARAM wParam
, WXLPARAM lParam
)
2669 // did we process the message?
2670 bool processed
= false;
2680 // for most messages we should return 0 when we do process the message
2688 processed
= HandleCreate((WXLPCREATESTRUCT
)lParam
, &mayCreate
);
2691 // return 0 to allow window creation
2692 rc
.result
= mayCreate
? 0 : -1;
2698 // never set processed to true and *always* pass WM_DESTROY to
2699 // DefWindowProc() as Windows may do some internal cleanup when
2700 // processing it and failing to pass the message along may cause
2701 // memory and resource leaks!
2702 (void)HandleDestroy();
2706 processed
= HandleSize(LOWORD(lParam
), HIWORD(lParam
), wParam
);
2710 processed
= HandleMove(GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
));
2713 #if !defined(__WXWINCE__)
2716 LPRECT pRect
= (LPRECT
)lParam
;
2718 rc
.SetLeft(pRect
->left
);
2719 rc
.SetTop(pRect
->top
);
2720 rc
.SetRight(pRect
->right
);
2721 rc
.SetBottom(pRect
->bottom
);
2722 processed
= HandleMoving(rc
);
2724 pRect
->left
= rc
.GetLeft();
2725 pRect
->top
= rc
.GetTop();
2726 pRect
->right
= rc
.GetRight();
2727 pRect
->bottom
= rc
.GetBottom();
2732 case WM_ENTERSIZEMOVE
:
2734 processed
= HandleEnterSizeMove();
2738 case WM_EXITSIZEMOVE
:
2740 processed
= HandleExitSizeMove();
2746 LPRECT pRect
= (LPRECT
)lParam
;
2748 rc
.SetLeft(pRect
->left
);
2749 rc
.SetTop(pRect
->top
);
2750 rc
.SetRight(pRect
->right
);
2751 rc
.SetBottom(pRect
->bottom
);
2752 processed
= HandleSizing(rc
);
2754 pRect
->left
= rc
.GetLeft();
2755 pRect
->top
= rc
.GetTop();
2756 pRect
->right
= rc
.GetRight();
2757 pRect
->bottom
= rc
.GetBottom();
2761 #endif // !__WXWINCE__
2763 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
2764 case WM_ACTIVATEAPP
:
2765 // This implicitly sends a wxEVT_ACTIVATE_APP event
2766 wxTheApp
->SetActive(wParam
!= 0, FindFocus());
2772 WXWORD state
, minimized
;
2774 UnpackActivate(wParam
, lParam
, &state
, &minimized
, &hwnd
);
2776 processed
= HandleActivate(state
, minimized
!= 0, (WXHWND
)hwnd
);
2781 processed
= HandleSetFocus((WXHWND
)wParam
);
2785 processed
= HandleKillFocus((WXHWND
)wParam
);
2788 case WM_PRINTCLIENT
:
2789 processed
= HandlePrintClient((WXHDC
)wParam
);
2795 wxPaintDCEx
dc((wxWindow
*)this, (WXHDC
)wParam
);
2797 processed
= HandlePaint();
2801 processed
= HandlePaint();
2806 #ifdef __WXUNIVERSAL__
2807 // Universal uses its own wxFrame/wxDialog, so we don't receive
2808 // close events unless we have this.
2810 #endif // __WXUNIVERSAL__
2812 // don't let the DefWindowProc() destroy our window - we'll do it
2813 // ourselves in ~wxWindow
2819 processed
= HandleShow(wParam
!= 0, (int)lParam
);
2823 processed
= HandleMouseMove(GET_X_LPARAM(lParam
),
2824 GET_Y_LPARAM(lParam
),
2828 #ifdef HAVE_TRACKMOUSEEVENT
2830 // filter out excess WM_MOUSELEAVE events sent after PopupMenu()
2832 if ( m_mouseInWindow
)
2834 GenerateMouseLeave();
2837 // always pass processed back as false, this allows the window
2838 // manager to process the message too. This is needed to
2839 // ensure windows XP themes work properly as the mouse moves
2840 // over widgets like buttons. So don't set processed to true here.
2842 #endif // HAVE_TRACKMOUSEEVENT
2844 #if wxUSE_MOUSEWHEEL
2846 processed
= HandleMouseWheel(wParam
, lParam
);
2850 case WM_LBUTTONDOWN
:
2852 case WM_LBUTTONDBLCLK
:
2853 case WM_RBUTTONDOWN
:
2855 case WM_RBUTTONDBLCLK
:
2856 case WM_MBUTTONDOWN
:
2858 case WM_MBUTTONDBLCLK
:
2859 #ifdef wxHAS_XBUTTON
2860 case WM_XBUTTONDOWN
:
2862 case WM_XBUTTONDBLCLK
:
2863 #endif // wxHAS_XBUTTON
2865 #ifdef __WXMICROWIN__
2866 // MicroWindows seems to ignore the fact that a window is
2867 // disabled. So catch mouse events and throw them away if
2869 wxWindowMSW
* win
= this;
2872 if (!win
->IsEnabled())
2878 win
= win
->GetParent();
2879 if ( !win
|| win
->IsTopLevel() )
2886 #endif // __WXMICROWIN__
2887 int x
= GET_X_LPARAM(lParam
),
2888 y
= GET_Y_LPARAM(lParam
);
2891 // redirect the event to a static control if necessary by
2892 // finding one under mouse because under CE the static controls
2893 // don't generate mouse events (even with SS_NOTIFY)
2895 if ( GetCapture() == this )
2897 // but don't do it if the mouse is captured by this window
2898 // because then it should really get this event itself
2903 win
= FindWindowForMouseEvent(this, &x
, &y
);
2905 // this should never happen
2906 wxCHECK_MSG( win
, 0,
2907 wxT("FindWindowForMouseEvent() returned NULL") );
2910 if (IsContextMenuEnabled() && message
== WM_LBUTTONDOWN
)
2912 SHRGINFO shrgi
= {0};
2914 shrgi
.cbSize
= sizeof(SHRGINFO
);
2915 shrgi
.hwndClient
= (HWND
) GetHWND();
2919 shrgi
.dwFlags
= SHRG_RETURNCMD
;
2920 // shrgi.dwFlags = SHRG_NOTIFYPARENT;
2922 if (GN_CONTEXTMENU
== ::SHRecognizeGesture(&shrgi
))
2925 pt
= ClientToScreen(pt
);
2927 wxContextMenuEvent
evtCtx(wxEVT_CONTEXT_MENU
, GetId(), pt
);
2929 evtCtx
.SetEventObject(this);
2930 if (HandleWindowEvent(evtCtx
))
2939 #else // !__WXWINCE__
2940 wxWindowMSW
*win
= this;
2941 #endif // __WXWINCE__/!__WXWINCE__
2943 processed
= win
->HandleMouseEvent(message
, x
, y
, wParam
);
2945 // if the app didn't eat the event, handle it in the default
2946 // way, that is by giving this window the focus
2949 // for the standard classes their WndProc sets the focus to
2950 // them anyhow and doing it from here results in some weird
2951 // problems, so don't do it for them (unnecessary anyhow)
2952 if ( !win
->IsOfStandardClass() )
2954 if ( message
== WM_LBUTTONDOWN
&& win
->IsFocusable() )
2966 case MM_JOY1BUTTONDOWN
:
2967 case MM_JOY2BUTTONDOWN
:
2968 case MM_JOY1BUTTONUP
:
2969 case MM_JOY2BUTTONUP
:
2970 processed
= HandleJoystickEvent(message
,
2971 GET_X_LPARAM(lParam
),
2972 GET_Y_LPARAM(lParam
),
2975 #endif // __WXMICROWIN__
2981 UnpackCommand(wParam
, lParam
, &id
, &hwnd
, &cmd
);
2983 processed
= HandleCommand(id
, cmd
, hwnd
);
2988 processed
= HandleNotify((int)wParam
, lParam
, &rc
.result
);
2991 // we only need to reply to WM_NOTIFYFORMAT manually when using MSLU,
2992 // otherwise DefWindowProc() does it perfectly fine for us, but MSLU
2993 // apparently doesn't always behave properly and needs some help
2994 #if wxUSE_UNICODE_MSLU && defined(NF_QUERY)
2995 case WM_NOTIFYFORMAT
:
2996 if ( lParam
== NF_QUERY
)
2999 rc
.result
= NFR_UNICODE
;
3002 #endif // wxUSE_UNICODE_MSLU
3004 // for these messages we must return true if process the message
3007 processed
= MSWOnDrawItem(wParam
, (WXDRAWITEMSTRUCT
*)lParam
);
3012 case WM_MEASUREITEM
:
3013 processed
= MSWOnMeasureItem(wParam
, (WXMEASUREITEMSTRUCT
*)lParam
);
3017 #endif // defined(WM_DRAWITEM)
3020 if ( !IsOfStandardClass() || HasFlag(wxWANTS_CHARS
) )
3022 // we always want to get the char events
3023 rc
.result
= DLGC_WANTCHARS
;
3025 if ( HasFlag(wxWANTS_CHARS
) )
3027 // in fact, we want everything
3028 rc
.result
|= DLGC_WANTARROWS
|
3035 //else: get the dlg code from the DefWindowProc()
3040 // Generate the key down event in any case.
3041 m_lastKeydownProcessed
= HandleKeyDown((WORD
) wParam
, lParam
);
3042 if ( m_lastKeydownProcessed
)
3044 // If it was processed by an event handler, we stop here,
3045 // notably we intentionally don't generate char event then.
3048 else // key down event not handled
3050 // Examine the event to decide whether we need to generate a
3051 // char event for it ourselves or let Windows do it. Window
3052 // mostly only does it for the keys which produce printable
3053 // characters (although there are exceptions, e.g. VK_ESCAPE or
3054 // VK_BACK (but not VK_DELETE)) while we do it for all keys
3055 // except the modifier ones (the wisdom of this is debatable
3056 // but by now this decision is enshrined forever due to
3057 // backwards compatibility).
3060 // No wxEVT_CHAR events are generated for these keys at all.
3068 // Windows will send us WM_CHAR for these ones so we'll
3069 // generate wxEVT_CHAR for them later when we get it.
3104 // special case of VK_APPS: treat it the same as right mouse
3105 // click because both usually pop up a context menu
3107 processed
= HandleMouseEvent(WM_RBUTTONDOWN
, -1, -1, 0);
3112 if ( (wParam
>= '0' && wParam
<= '9') ||
3113 (wParam
>= 'A' && wParam
<= 'Z') )
3115 // We'll get WM_CHAR for those later too.
3119 // But for the rest we won't get WM_CHAR later so we do
3120 // need to generate the event right now.
3121 wxKeyEvent
event(wxEVT_CHAR
);
3122 InitAnyKeyEvent(event
, wParam
, lParam
);
3124 // Set the "extended" bit in lParam because we want to
3125 // generate CHAR events with WXK_HOME and not
3126 // WXK_NUMPAD_HOME even if the "Home" key on numpad was
3128 event
.m_keyCode
= wxMSWKeyboard::VKToWX
3131 lParam
| (KF_EXTENDED
<< 16)
3134 // Don't produce events without any valid character
3135 // code (even if this shouldn't normally happen...).
3136 if ( event
.m_keyCode
!= WXK_NONE
)
3137 processed
= HandleWindowEvent(event
);
3140 if (message
== WM_SYSKEYDOWN
) // Let Windows still handle the SYSKEYs
3147 // special case of VK_APPS: treat it the same as right mouse button
3148 if ( wParam
== VK_APPS
)
3150 processed
= HandleMouseEvent(WM_RBUTTONUP
, -1, -1, 0);
3155 processed
= HandleKeyUp((WORD
) wParam
, lParam
);
3160 case WM_CHAR
: // Always an ASCII character
3161 if ( m_lastKeydownProcessed
)
3163 // The key was handled in the EVT_KEY_DOWN and handling
3164 // a key in an EVT_KEY_DOWN handler is meant, by
3165 // design, to prevent EVT_CHARs from happening
3166 m_lastKeydownProcessed
= false;
3171 processed
= HandleChar((WORD
)wParam
, lParam
);
3177 processed
= HandleHotKey((WORD
)wParam
, lParam
);
3179 #endif // wxUSE_HOTKEY
3184 processed
= HandleClipboardEvent(message
);
3192 UnpackScroll(wParam
, lParam
, &code
, &pos
, &hwnd
);
3194 processed
= MSWOnScroll(message
== WM_HSCROLL
? wxHORIZONTAL
3200 // CTLCOLOR messages are sent by children to query the parent for their
3202 #ifndef __WXMICROWIN__
3203 case WM_CTLCOLORMSGBOX
:
3204 case WM_CTLCOLOREDIT
:
3205 case WM_CTLCOLORLISTBOX
:
3206 case WM_CTLCOLORBTN
:
3207 case WM_CTLCOLORDLG
:
3208 case WM_CTLCOLORSCROLLBAR
:
3209 case WM_CTLCOLORSTATIC
:
3213 UnpackCtlColor(wParam
, lParam
, &hdc
, &hwnd
);
3215 processed
= HandleCtlColor(&rc
.hBrush
, (WXHDC
)hdc
, (WXHWND
)hwnd
);
3218 #endif // !__WXMICROWIN__
3220 case WM_SYSCOLORCHANGE
:
3221 // the return value for this message is ignored
3222 processed
= HandleSysColorChange();
3225 #if !defined(__WXWINCE__)
3226 case WM_DISPLAYCHANGE
:
3227 processed
= HandleDisplayChange();
3231 case WM_PALETTECHANGED
:
3232 processed
= HandlePaletteChanged((WXHWND
)wParam
);
3235 case WM_CAPTURECHANGED
:
3236 processed
= HandleCaptureChanged((WXHWND
)lParam
);
3239 case WM_SETTINGCHANGE
:
3240 processed
= HandleSettingChange(wParam
, lParam
);
3243 case WM_QUERYNEWPALETTE
:
3244 processed
= HandleQueryNewPalette();
3249 #ifdef wxHAS_MSW_BACKGROUND_ERASE_HOOK
3250 // check if an override was configured for this window
3251 EraseBgHooks::const_iterator it
= gs_eraseBgHooks
.find(this);
3252 if ( it
!= gs_eraseBgHooks
.end() )
3253 processed
= it
->second
->MSWEraseBgHook((WXHDC
)wParam
);
3255 #endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK
3256 processed
= HandleEraseBkgnd((WXHDC
)wParam
);
3261 // we processed the message, i.e. erased the background
3266 #if !defined(__WXWINCE__)
3268 processed
= HandleDropFiles(wParam
);
3273 processed
= HandleInitDialog((WXHWND
)wParam
);
3277 // we never set focus from here
3282 #if !defined(__WXWINCE__)
3283 case WM_QUERYENDSESSION
:
3284 processed
= HandleQueryEndSession(lParam
, &rc
.allow
);
3288 processed
= HandleEndSession(wParam
!= 0, lParam
);
3291 case WM_GETMINMAXINFO
:
3292 processed
= HandleGetMinMaxInfo((MINMAXINFO
*)lParam
);
3297 processed
= HandleSetCursor((WXHWND
)wParam
,
3298 LOWORD(lParam
), // hit test
3299 HIWORD(lParam
)); // mouse msg
3303 // returning TRUE stops the DefWindowProc() from further
3304 // processing this message - exactly what we need because we've
3305 // just set the cursor.
3310 #if wxUSE_ACCESSIBILITY
3313 //WPARAM dwFlags = (WPARAM) (DWORD) wParam;
3314 LPARAM dwObjId
= (LPARAM
) (DWORD
) lParam
;
3316 if (dwObjId
== (LPARAM
)OBJID_CLIENT
&& GetOrCreateAccessible())
3318 return LresultFromObject(IID_IAccessible
, wParam
, (IUnknown
*) GetAccessible()->GetIAccessible());
3324 #if defined(WM_HELP)
3327 // by default, WM_HELP is propagated by DefWindowProc() upwards
3328 // to the window parent but as we do it ourselves already
3329 // (wxHelpEvent is derived from wxCommandEvent), we don't want
3330 // to get the other events if we process this message at all
3333 // WM_HELP doesn't use lParam under CE
3335 HELPINFO
* info
= (HELPINFO
*) lParam
;
3336 if ( info
->iContextType
== HELPINFO_WINDOW
)
3338 #endif // !__WXWINCE__
3339 wxHelpEvent helpEvent
3344 wxGetMousePosition() // what else?
3346 wxPoint(info
->MousePos
.x
, info
->MousePos
.y
)
3350 helpEvent
.SetEventObject(this);
3351 HandleWindowEvent(helpEvent
);
3354 else if ( info
->iContextType
== HELPINFO_MENUITEM
)
3356 wxHelpEvent
helpEvent(wxEVT_HELP
, info
->iCtrlId
);
3357 helpEvent
.SetEventObject(this);
3358 HandleWindowEvent(helpEvent
);
3361 else // unknown help event?
3365 #endif // !__WXWINCE__
3370 #if !defined(__WXWINCE__)
3371 case WM_CONTEXTMENU
:
3373 // we don't convert from screen to client coordinates as
3374 // the event may be handled by a parent window
3375 wxPoint
pt(GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
));
3377 wxContextMenuEvent
evtCtx(wxEVT_CONTEXT_MENU
, GetId(), pt
);
3379 // we could have got an event from our child, reflect it back
3380 // to it if this is the case
3381 wxWindowMSW
*win
= NULL
;
3382 WXHWND hWnd
= (WXHWND
)wParam
;
3383 if ( hWnd
!= m_hWnd
)
3385 win
= FindItemByHWND(hWnd
);
3391 evtCtx
.SetEventObject(win
);
3392 processed
= win
->HandleWindowEvent(evtCtx
);
3399 // we're only interested in our own menus, not MF_SYSMENU
3400 if ( HIWORD(wParam
) == MF_POPUP
)
3402 // handle menu chars for ownerdrawn menu items
3403 int i
= HandleMenuChar(toupper(LOWORD(wParam
)), lParam
);
3404 if ( i
!= wxNOT_FOUND
)
3406 rc
.result
= MAKELRESULT(i
, MNC_EXECUTE
);
3411 #endif // wxUSE_MENUS
3414 case WM_POWERBROADCAST
:
3417 processed
= HandlePower(wParam
, lParam
, &vetoed
);
3418 rc
.result
= processed
&& vetoed
? BROADCAST_QUERY_DENY
: TRUE
;
3421 #endif // __WXWINCE__
3424 // If we want the default themed border then we need to draw it ourselves
3427 wxUxThemeEngine
* theme
= wxUxThemeEngine::GetIfActive();
3428 const wxBorder border
= TranslateBorder(GetBorder());
3429 if (theme
&& border
== wxBORDER_THEME
)
3431 // first ask the widget to calculate the border size
3432 rc
.result
= MSWDefWindowProc(message
, wParam
, lParam
);
3435 // now alter the client size making room for drawing a
3438 NCCALCSIZE_PARAMS
*csparam
= NULL
;
3441 csparam
= (NCCALCSIZE_PARAMS
*)lParam
;
3442 rect
= &csparam
->rgrc
[0];
3446 rect
= (RECT
*)lParam
;
3449 wxUxThemeHandle
hTheme((const wxWindow
*)this, L
"EDIT");
3450 RECT rcClient
= { 0, 0, 0, 0 };
3451 wxClientDC
dc((wxWindow
*)this);
3452 wxMSWDCImpl
*impl
= (wxMSWDCImpl
*) dc
.GetImpl();
3454 if ( theme
->GetThemeBackgroundContentRect
3461 &rcClient
) == S_OK
)
3463 InflateRect(&rcClient
, -1, -1);
3465 csparam
->rgrc
[0] = rcClient
;
3467 *((RECT
*)lParam
) = rcClient
;
3469 // WVR_REDRAW triggers a bug whereby child windows are moved up and left,
3471 // rc.result = WVR_REDRAW;
3479 wxUxThemeEngine
* theme
= wxUxThemeEngine::GetIfActive();
3480 const wxBorder border
= TranslateBorder(GetBorder());
3481 if (theme
&& border
== wxBORDER_THEME
)
3483 // first ask the widget to paint its non-client area, such as scrollbars, etc.
3484 rc
.result
= MSWDefWindowProc(message
, wParam
, lParam
);
3487 wxUxThemeHandle
hTheme((const wxWindow
*)this, L
"EDIT");
3488 wxWindowDC
dc((wxWindow
*)this);
3489 wxMSWDCImpl
*impl
= (wxMSWDCImpl
*) dc
.GetImpl();
3491 // Clip the DC so that you only draw on the non-client area
3493 wxCopyRectToRECT(GetSize(), rcBorder
);
3496 theme
->GetThemeBackgroundContentRect(
3497 hTheme
, GetHdcOf(*impl
), EP_EDITTEXT
, ETS_NORMAL
, &rcBorder
, &rcClient
);
3498 InflateRect(&rcClient
, -1, -1);
3500 ::ExcludeClipRect(GetHdcOf(*impl
), rcClient
.left
, rcClient
.top
,
3501 rcClient
.right
, rcClient
.bottom
);
3503 // Make sure the background is in a proper state
3504 if (theme
->IsThemeBackgroundPartiallyTransparent(hTheme
, EP_EDITTEXT
, ETS_NORMAL
))
3506 theme
->DrawThemeParentBackground(GetHwnd(), GetHdcOf(*impl
), &rcBorder
);
3512 nState
= ETS_DISABLED
;
3513 // should we check this?
3514 //else if ( ::GetWindowLong(GetHwnd(), GWL_STYLE) & ES_READONLY)
3515 // nState = ETS_READONLY;
3517 nState
= ETS_NORMAL
;
3518 theme
->DrawThemeBackground(hTheme
, GetHdcOf(*impl
), EP_EDITTEXT
, nState
, &rcBorder
, NULL
);
3523 #endif // wxUSE_UXTHEME
3526 // try a custom message handler
3527 const MSWMessageHandlers::const_iterator
3528 i
= gs_messageHandlers
.find(message
);
3529 if ( i
!= gs_messageHandlers
.end() )
3531 processed
= (*i
->second
)(this, message
, wParam
, lParam
);
3537 #if wxDEBUG_LEVEL >= 2
3538 wxLogTrace("winmsg", wxT("Forwarding %s to DefWindowProc."),
3539 wxGetMessageName(message
));
3540 #endif // wxDEBUG_LEVEL >= 2
3541 rc
.result
= MSWDefWindowProc(message
, wParam
, lParam
);
3547 // ----------------------------------------------------------------------------
3548 // wxWindow <-> HWND map
3549 // ----------------------------------------------------------------------------
3551 wxWindow
*wxFindWinFromHandle(HWND hwnd
)
3553 WindowHandles::const_iterator i
= gs_windowHandles
.find(hwnd
);
3554 return i
== gs_windowHandles
.end() ? NULL
: i
->second
;
3557 void wxAssociateWinWithHandle(HWND hwnd
, wxWindowMSW
*win
)
3559 // adding NULL hwnd is (first) surely a result of an error and
3560 // (secondly) breaks menu command processing
3561 wxCHECK_RET( hwnd
!= (HWND
)NULL
,
3562 wxT("attempt to add a NULL hwnd to window list ignored") );
3565 WindowHandles::const_iterator i
= gs_windowHandles
.find(hwnd
);
3566 if ( i
!= gs_windowHandles
.end() )
3568 if ( i
->second
!= win
)
3572 wxT("HWND %p already associated with another window (%s)"),
3573 hwnd
, win
->GetClassInfo()->GetClassName()
3577 //else: this actually happens currently because we associate the window
3578 // with its HWND during creation (if we create it) and also when
3579 // SubclassWin() is called later, this is ok
3581 #endif // wxDEBUG_LEVEL
3583 gs_windowHandles
[hwnd
] = (wxWindow
*)win
;
3586 void wxRemoveHandleAssociation(wxWindowMSW
*win
)
3588 gs_windowHandles
.erase(GetHwndOf(win
));
3591 // ----------------------------------------------------------------------------
3592 // various MSW speciic class dependent functions
3593 // ----------------------------------------------------------------------------
3595 // Default destroyer - override if you destroy it in some other way
3596 // (e.g. with MDI child windows)
3597 void wxWindowMSW::MSWDestroyWindow()
3601 void wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint
& pos
,
3604 int& w
, int& h
) const
3606 // CW_USEDEFAULT can't be used for child windows so just position them at
3607 // the origin by default
3608 x
= pos
.x
== wxDefaultCoord
? 0 : pos
.x
;
3609 y
= pos
.y
== wxDefaultCoord
? 0 : pos
.y
;
3611 AdjustForParentClientOrigin(x
, y
);
3613 // We don't have any clearly good choice for the size by default neither
3614 // but we must use something non-zero.
3615 w
= WidthDefault(size
.x
);
3616 h
= HeightDefault(size
.y
);
3619 NB: there used to be some code here which set the initial size of the
3620 window to the client size of the parent if no explicit size was
3621 specified. This was wrong because wxWidgets programs often assume
3622 that they get a WM_SIZE (EVT_SIZE) upon creation, however this broke
3623 it. To see why, you should understand that Windows sends WM_SIZE from
3624 inside ::CreateWindow() anyhow. However, ::CreateWindow() is called
3625 from some base class ctor and so this WM_SIZE is not processed in the
3626 real class' OnSize() (because it's not fully constructed yet and the
3627 event goes to some base class OnSize() instead). So the WM_SIZE we
3628 rely on is the one sent when the parent frame resizes its children
3629 but here is the problem: if the child already has just the right
3630 size, nothing will happen as both wxWidgets and Windows check for
3631 this and ignore any attempts to change the window size to the size it
3632 already has - so no WM_SIZE would be sent.
3636 WXHWND
wxWindowMSW::MSWGetParent() const
3638 return m_parent
? m_parent
->GetHWND() : WXHWND(NULL
);
3641 bool wxWindowMSW::MSWCreate(const wxChar
*wclass
,
3642 const wxChar
*title
,
3646 WXDWORD extendedStyle
)
3648 // check a common bug in the user code: if the window is created with a
3649 // non-default ctor and Create() is called too, we'd create 2 HWND for a
3650 // single wxWindow object and this results in all sorts of trouble,
3651 // especially for wxTLWs
3652 wxCHECK_MSG( !m_hWnd
, true, "window can't be recreated" );
3654 // this can happen if this function is called using the return value of
3655 // wxApp::GetRegisteredClassName() which failed
3656 wxCHECK_MSG( wclass
, false, "failed to register window class?" );
3659 // choose the position/size for the new window
3661 (void)MSWGetCreateWindowCoords(pos
, size
, x
, y
, w
, h
);
3663 // controlId is menu handle for the top level windows, so set it to 0
3664 // unless we're creating a child window
3665 int controlId
= style
& WS_CHILD
? GetId() : 0;
3667 // for each class "Foo" we have we also have "FooNR" ("no repaint") class
3668 // which is the same but without CS_[HV]REDRAW class styles so using it
3669 // ensures that the window is not fully repainted on each resize
3670 wxString
className(wclass
);
3671 if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE
) )
3673 className
+= wxApp::GetNoRedrawClassSuffix();
3676 // do create the window
3677 wxWindowCreationHook
hook(this);
3679 m_hWnd
= (WXHWND
)::CreateWindowEx
3683 title
? title
: m_windowName
.wx_str(),
3686 (HWND
)MSWGetParent(),
3687 (HMENU
)wxUIntToPtr(controlId
),
3689 NULL
// no extra data
3694 wxLogSysError(_("Can't create window of class %s"), className
.c_str());
3699 SubclassWin(m_hWnd
);
3704 // ===========================================================================
3705 // MSW message handlers
3706 // ===========================================================================
3708 // ---------------------------------------------------------------------------
3710 // ---------------------------------------------------------------------------
3712 bool wxWindowMSW::HandleNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM
*result
)
3714 #ifndef __WXMICROWIN__
3715 LPNMHDR hdr
= (LPNMHDR
)lParam
;
3716 HWND hWnd
= hdr
->hwndFrom
;
3717 wxWindow
*win
= wxFindWinFromHandle(hWnd
);
3719 // if the control is one of our windows, let it handle the message itself
3722 return win
->MSWOnNotify(idCtrl
, lParam
, result
);
3725 // VZ: why did we do it? normally this is unnecessary and, besides, it
3726 // breaks the message processing for the toolbars because the tooltip
3727 // notifications were being forwarded to the toolbar child controls
3728 // (if it had any) before being passed to the toolbar itself, so in my
3729 // example the tooltip for the combobox was always shown instead of the
3730 // correct button tooltips
3732 // try all our children
3733 wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3736 wxWindow
*child
= node
->GetData();
3737 if ( child
->MSWOnNotify(idCtrl
, lParam
, result
) )
3742 node
= node
->GetNext();
3746 // by default, handle it ourselves
3747 return MSWOnNotify(idCtrl
, lParam
, result
);
3748 #else // __WXMICROWIN__
3755 bool wxWindowMSW::HandleTooltipNotify(WXUINT code
,
3757 const wxString
& ttip
)
3759 // I don't know why it happens, but the versions of comctl32.dll starting
3760 // from 4.70 sometimes send TTN_NEEDTEXTW even to ANSI programs (normally,
3761 // this message is supposed to be sent to Unicode programs only) -- hence
3762 // we need to handle it as well, otherwise no tooltips will be shown in
3765 if ( !(code
== (WXUINT
) TTN_NEEDTEXTA
|| code
== (WXUINT
) TTN_NEEDTEXTW
)
3768 // not a tooltip message or no tooltip to show anyhow
3773 LPTOOLTIPTEXT ttText
= (LPTOOLTIPTEXT
)lParam
;
3775 // We don't want to use the szText buffer because it has a limit of 80
3776 // bytes and this is not enough, especially for Unicode build where it
3777 // limits the tooltip string length to only 40 characters
3779 // The best would be, of course, to not impose any length limitations at
3780 // all but then the buffer would have to be dynamic and someone would have
3781 // to free it and we don't have the tooltip owner object here any more, so
3782 // for now use our own static buffer with a higher fixed max length.
3784 // Note that using a static buffer should not be a problem as only a single
3785 // tooltip can be shown at the same time anyhow.
3787 if ( code
== (WXUINT
) TTN_NEEDTEXTW
)
3789 // We need to convert tooltip from multi byte to Unicode on the fly.
3790 static wchar_t buf
[513];
3792 // Truncate tooltip length if needed as otherwise we might not have
3793 // enough space for it in the buffer and MultiByteToWideChar() would
3795 size_t tipLength
= wxMin(ttip
.length(), WXSIZEOF(buf
) - 1);
3797 // Convert to WideChar without adding the NULL character. The NULL
3798 // character is added afterwards (this is more efficient).
3799 int len
= ::MultiByteToWideChar
3811 wxLogLastError(wxT("MultiByteToWideChar()"));
3815 ttText
->lpszText
= (LPSTR
) buf
;
3817 else // TTN_NEEDTEXTA
3818 #endif // !wxUSE_UNICODE
3820 // we get here if we got TTN_NEEDTEXTA (only happens in ANSI build) or
3821 // if we got TTN_NEEDTEXTW in Unicode build: in this case we just have
3822 // to copy the string we have into the buffer
3823 static wxChar buf
[513];
3824 wxStrlcpy(buf
, ttip
.c_str(), WXSIZEOF(buf
));
3825 ttText
->lpszText
= buf
;
3831 #endif // wxUSE_TOOLTIPS
3833 bool wxWindowMSW::MSWOnNotify(int WXUNUSED(idCtrl
),
3835 WXLPARAM
* WXUNUSED(result
))
3840 NMHDR
* hdr
= (NMHDR
*)lParam
;
3841 if ( HandleTooltipNotify(hdr
->code
, lParam
, m_tooltip
->GetTip()))
3848 wxUnusedVar(lParam
);
3849 #endif // wxUSE_TOOLTIPS
3854 // ---------------------------------------------------------------------------
3855 // end session messages
3856 // ---------------------------------------------------------------------------
3858 bool wxWindowMSW::HandleQueryEndSession(long logOff
, bool *mayEnd
)
3860 #ifdef ENDSESSION_LOGOFF
3861 wxCloseEvent
event(wxEVT_QUERY_END_SESSION
, wxID_ANY
);
3862 event
.SetEventObject(wxTheApp
);
3863 event
.SetCanVeto(true);
3864 event
.SetLoggingOff(logOff
== (long)ENDSESSION_LOGOFF
);
3866 bool rc
= wxTheApp
->ProcessEvent(event
);
3870 // we may end only if the app didn't veto session closing (double
3872 *mayEnd
= !event
.GetVeto();
3877 wxUnusedVar(logOff
);
3878 wxUnusedVar(mayEnd
);
3883 bool wxWindowMSW::HandleEndSession(bool endSession
, long logOff
)
3885 #ifdef ENDSESSION_LOGOFF
3886 // do nothing if the session isn't ending
3891 if ( (this != wxTheApp
->GetTopWindow()) )
3894 wxCloseEvent
event(wxEVT_END_SESSION
, wxID_ANY
);
3895 event
.SetEventObject(wxTheApp
);
3896 event
.SetCanVeto(false);
3897 event
.SetLoggingOff((logOff
& ENDSESSION_LOGOFF
) != 0);
3899 return wxTheApp
->ProcessEvent(event
);
3901 wxUnusedVar(endSession
);
3902 wxUnusedVar(logOff
);
3907 // ---------------------------------------------------------------------------
3908 // window creation/destruction
3909 // ---------------------------------------------------------------------------
3911 bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT
WXUNUSED_IN_WINCE(cs
),
3914 // VZ: why is this commented out for WinCE? If it doesn't support
3915 // WS_EX_CONTROLPARENT at all it should be somehow handled globally,
3916 // not with multiple #ifdef's!
3918 if ( ((CREATESTRUCT
*)cs
)->dwExStyle
& WS_EX_CONTROLPARENT
)
3919 EnsureParentHasControlParentStyle(GetParent());
3920 #endif // !__WXWINCE__
3927 bool wxWindowMSW::HandleDestroy()
3929 // delete our drop target if we've got one
3930 #if wxUSE_DRAG_AND_DROP
3931 if ( m_dropTarget
!= NULL
)
3933 m_dropTarget
->Revoke(m_hWnd
);
3935 wxDELETE(m_dropTarget
);
3937 #endif // wxUSE_DRAG_AND_DROP
3939 // WM_DESTROY handled
3943 // ---------------------------------------------------------------------------
3945 // ---------------------------------------------------------------------------
3947 bool wxWindowMSW::HandleActivate(int state
,
3948 bool WXUNUSED(minimized
),
3949 WXHWND
WXUNUSED(activate
))
3951 wxActivateEvent
event(wxEVT_ACTIVATE
,
3952 (state
== WA_ACTIVE
) || (state
== WA_CLICKACTIVE
),
3954 event
.SetEventObject(this);
3956 return HandleWindowEvent(event
);
3959 bool wxWindowMSW::HandleSetFocus(WXHWND hwnd
)
3961 // Strangly enough, some controls get set focus events when they are being
3962 // deleted, even if they already had focus before.
3963 if ( m_isBeingDeleted
)
3968 // notify the parent keeping track of focus for the kbd navigation
3969 // purposes that we got it
3970 wxChildFocusEvent
eventFocus((wxWindow
*)this);
3971 (void)HandleWindowEvent(eventFocus
);
3977 m_caret
->OnSetFocus();
3979 #endif // wxUSE_CARET
3981 wxFocusEvent
event(wxEVT_SET_FOCUS
, m_windowId
);
3982 event
.SetEventObject(this);
3984 // wxFindWinFromHandle() may return NULL, it is ok
3985 event
.SetWindow(wxFindWinFromHandle(hwnd
));
3987 return HandleWindowEvent(event
);
3990 bool wxWindowMSW::HandleKillFocus(WXHWND hwnd
)
3996 m_caret
->OnKillFocus();
3998 #endif // wxUSE_CARET
4000 // Don't send the event when in the process of being deleted. This can
4001 // only cause problems if the event handler tries to access the object.
4002 if ( m_isBeingDeleted
)
4007 wxFocusEvent
event(wxEVT_KILL_FOCUS
, m_windowId
);
4008 event
.SetEventObject(this);
4010 // wxFindWinFromHandle() may return NULL, it is ok
4011 event
.SetWindow(wxFindWinFromHandle(hwnd
));
4013 return HandleWindowEvent(event
);
4016 // ---------------------------------------------------------------------------
4018 // ---------------------------------------------------------------------------
4020 void wxWindowMSW::SetLabel( const wxString
& label
)
4022 SetWindowText(GetHwnd(), label
.c_str());
4025 wxString
wxWindowMSW::GetLabel() const
4027 return wxGetWindowText(GetHWND());
4030 // ---------------------------------------------------------------------------
4032 // ---------------------------------------------------------------------------
4034 bool wxWindowMSW::HandleShow(bool show
, int WXUNUSED(status
))
4036 wxShowEvent
event(GetId(), show
);
4037 event
.SetEventObject(this);
4039 return HandleWindowEvent(event
);
4042 bool wxWindowMSW::HandleInitDialog(WXHWND
WXUNUSED(hWndFocus
))
4044 wxInitDialogEvent
event(GetId());
4045 event
.SetEventObject(this);
4047 return HandleWindowEvent(event
);
4050 bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam
)
4052 #if defined (__WXMICROWIN__) || defined(__WXWINCE__)
4053 wxUnusedVar(wParam
);
4055 #else // __WXMICROWIN__
4056 HDROP hFilesInfo
= (HDROP
) wParam
;
4058 // Get the total number of files dropped
4059 UINT gwFilesDropped
= ::DragQueryFile
4067 wxString
*files
= new wxString
[gwFilesDropped
];
4068 for ( UINT wIndex
= 0; wIndex
< gwFilesDropped
; wIndex
++ )
4070 // first get the needed buffer length (+1 for terminating NUL)
4071 size_t len
= ::DragQueryFile(hFilesInfo
, wIndex
, NULL
, 0) + 1;
4073 // and now get the file name
4074 ::DragQueryFile(hFilesInfo
, wIndex
,
4075 wxStringBuffer(files
[wIndex
], len
), len
);
4078 wxDropFilesEvent
event(wxEVT_DROP_FILES
, gwFilesDropped
, files
);
4079 event
.SetEventObject(this);
4082 DragQueryPoint(hFilesInfo
, (LPPOINT
) &dropPoint
);
4083 event
.m_pos
.x
= dropPoint
.x
;
4084 event
.m_pos
.y
= dropPoint
.y
;
4086 DragFinish(hFilesInfo
);
4088 return HandleWindowEvent(event
);
4093 bool wxWindowMSW::HandleSetCursor(WXHWND
WXUNUSED(hWnd
),
4095 int WXUNUSED(mouseMsg
))
4097 #ifndef __WXMICROWIN__
4098 // the logic is as follows:
4099 // 0. if we're busy, set the busy cursor (even for non client elements)
4100 // 1. don't set custom cursor for non client area of enabled windows
4101 // 2. ask user EVT_SET_CURSOR handler for the cursor
4102 // 3. if still no cursor but we're in a TLW, set the global cursor
4104 HCURSOR hcursor
= 0;
4107 hcursor
= wxGetCurrentBusyCursor();
4111 if ( nHitTest
!= HTCLIENT
)
4114 // first ask the user code - it may wish to set the cursor in some very
4115 // specific way (for example, depending on the current position)
4118 if ( !::GetCursorPosWinCE(&pt
))
4120 if ( !::GetCursorPos(&pt
) )
4123 wxLogLastError(wxT("GetCursorPos"));
4128 ScreenToClient(&x
, &y
);
4129 wxSetCursorEvent
event(x
, y
);
4130 event
.SetId(GetId());
4131 event
.SetEventObject(this);
4133 bool processedEvtSetCursor
= HandleWindowEvent(event
);
4134 if ( processedEvtSetCursor
&& event
.HasCursor() )
4136 hcursor
= GetHcursorOf(event
.GetCursor());
4141 // the test for processedEvtSetCursor is here to prevent using
4142 // m_cursor if the user code caught EVT_SET_CURSOR() and returned
4143 // nothing from it - this is a way to say that our cursor shouldn't
4144 // be used for this point
4145 if ( !processedEvtSetCursor
&& m_cursor
.Ok() )
4147 hcursor
= GetHcursorOf(m_cursor
);
4150 if ( !hcursor
&& !GetParent() )
4152 const wxCursor
*cursor
= wxGetGlobalCursor();
4153 if ( cursor
&& cursor
->Ok() )
4155 hcursor
= GetHcursorOf(*cursor
);
4164 ::SetCursor(hcursor
);
4166 // cursor set, stop here
4169 #endif // __WXMICROWIN__
4171 // pass up the window chain
4175 bool wxWindowMSW::HandlePower(WXWPARAM
WXUNUSED_IN_WINCE(wParam
),
4176 WXLPARAM
WXUNUSED(lParam
),
4177 bool *WXUNUSED_IN_WINCE(vetoed
))
4183 wxEventType evtType
;
4186 case PBT_APMQUERYSUSPEND
:
4187 evtType
= wxEVT_POWER_SUSPENDING
;
4190 case PBT_APMQUERYSUSPENDFAILED
:
4191 evtType
= wxEVT_POWER_SUSPEND_CANCEL
;
4194 case PBT_APMSUSPEND
:
4195 evtType
= wxEVT_POWER_SUSPENDED
;
4198 case PBT_APMRESUMESUSPEND
:
4199 evtType
= wxEVT_POWER_RESUME
;
4203 wxLogDebug(wxT("Unknown WM_POWERBROADCAST(%d) event"), wParam
);
4206 // these messages are currently not mapped to wx events
4207 case PBT_APMQUERYSTANDBY
:
4208 case PBT_APMQUERYSTANDBYFAILED
:
4209 case PBT_APMSTANDBY
:
4210 case PBT_APMRESUMESTANDBY
:
4211 case PBT_APMBATTERYLOW
:
4212 case PBT_APMPOWERSTATUSCHANGE
:
4213 case PBT_APMOEMEVENT
:
4214 case PBT_APMRESUMECRITICAL
:
4215 #ifdef PBT_APMRESUMEAUTOMATIC
4216 case PBT_APMRESUMEAUTOMATIC
:
4218 evtType
= wxEVT_NULL
;
4222 // don't handle unknown messages
4223 if ( evtType
== wxEVT_NULL
)
4226 // TODO: notify about PBTF_APMRESUMEFROMFAILURE in case of resume events?
4228 wxPowerEvent
event(evtType
);
4229 if ( !HandleWindowEvent(event
) )
4232 *vetoed
= event
.IsVetoed();
4238 bool wxWindowMSW::IsDoubleBuffered() const
4240 for ( const wxWindowMSW
*win
= this; win
; win
= win
->GetParent() )
4242 if ( wxHasWindowExStyle(win
, WS_EX_COMPOSITED
) )
4245 if ( win
->IsTopLevel() )
4252 void wxWindowMSW::SetDoubleBuffered(bool on
)
4254 // Get the current extended style bits
4255 long exstyle
= wxGetWindowExStyle(this);
4257 // Twiddle the bit as needed
4259 exstyle
|= WS_EX_COMPOSITED
;
4261 exstyle
&= ~WS_EX_COMPOSITED
;
4264 wxSetWindowExStyle(this, exstyle
);
4267 // ---------------------------------------------------------------------------
4268 // owner drawn stuff
4269 // ---------------------------------------------------------------------------
4271 #if (wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE) || \
4272 (wxUSE_CONTROLS && !defined(__WXUNIVERSAL__))
4273 #define WXUNUSED_UNLESS_ODRAWN(param) param
4275 #define WXUNUSED_UNLESS_ODRAWN(param)
4279 wxWindowMSW::MSWOnDrawItem(int WXUNUSED_UNLESS_ODRAWN(id
),
4280 WXDRAWITEMSTRUCT
* WXUNUSED_UNLESS_ODRAWN(itemStruct
))
4282 #if wxUSE_OWNER_DRAWN
4284 #if wxUSE_MENUS_NATIVE
4285 // is it a menu item?
4286 DRAWITEMSTRUCT
*pDrawStruct
= (DRAWITEMSTRUCT
*)itemStruct
;
4287 if ( id
== 0 && pDrawStruct
->CtlType
== ODT_MENU
)
4289 wxMenuItem
*pMenuItem
= (wxMenuItem
*)(pDrawStruct
->itemData
);
4291 // see comment before the same test in MSWOnMeasureItem() below
4295 wxCHECK_MSG( wxDynamicCast(pMenuItem
, wxMenuItem
),
4296 false, wxT("MSWOnDrawItem: bad wxMenuItem pointer") );
4298 // prepare to call OnDrawItem(): notice using of wxDCTemp to prevent
4299 // the DC from being released
4300 wxDCTemp
dc((WXHDC
)pDrawStruct
->hDC
);
4301 wxRect
rect(pDrawStruct
->rcItem
.left
, pDrawStruct
->rcItem
.top
,
4302 pDrawStruct
->rcItem
.right
- pDrawStruct
->rcItem
.left
,
4303 pDrawStruct
->rcItem
.bottom
- pDrawStruct
->rcItem
.top
);
4305 return pMenuItem
->OnDrawItem
4309 (wxOwnerDrawn::wxODAction
)pDrawStruct
->itemAction
,
4310 (wxOwnerDrawn::wxODStatus
)pDrawStruct
->itemState
4313 #endif // wxUSE_MENUS_NATIVE
4315 #endif // USE_OWNER_DRAWN
4317 #if wxUSE_CONTROLS && !defined(__WXUNIVERSAL__)
4319 #if wxUSE_OWNER_DRAWN
4320 wxControl
*item
= wxDynamicCast(FindItem(id
), wxControl
);
4321 #else // !wxUSE_OWNER_DRAWN
4322 // we may still have owner-drawn buttons internally because we have to make
4323 // them owner-drawn to support colour change
4326 wxDynamicCast(FindItem(id
), wxButton
)
4331 #endif // USE_OWNER_DRAWN
4335 return item
->MSWOnDraw(itemStruct
);
4338 #endif // wxUSE_CONTROLS
4344 wxWindowMSW::MSWOnMeasureItem(int id
, WXMEASUREITEMSTRUCT
*itemStruct
)
4346 #if wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE
4347 // is it a menu item?
4348 MEASUREITEMSTRUCT
*pMeasureStruct
= (MEASUREITEMSTRUCT
*)itemStruct
;
4349 if ( id
== 0 && pMeasureStruct
->CtlType
== ODT_MENU
)
4351 wxMenuItem
*pMenuItem
= (wxMenuItem
*)(pMeasureStruct
->itemData
);
4353 // according to Carsten Fuchs the pointer may be NULL under XP if an
4354 // MDI child frame is initially maximized, see this for more info:
4355 // http://article.gmane.org/gmane.comp.lib.wxwidgets.general/27745
4357 // so silently ignore it instead of asserting
4361 wxCHECK_MSG( wxDynamicCast(pMenuItem
, wxMenuItem
),
4362 false, wxT("MSWOnMeasureItem: bad wxMenuItem pointer") );
4365 bool rc
= pMenuItem
->OnMeasureItem(&w
, &h
);
4367 pMeasureStruct
->itemWidth
= w
;
4368 pMeasureStruct
->itemHeight
= h
;
4373 wxControl
*item
= wxDynamicCast(FindItem(id
), wxControl
);
4376 return item
->MSWOnMeasure(itemStruct
);
4380 wxUnusedVar(itemStruct
);
4381 #endif // wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE
4386 // ---------------------------------------------------------------------------
4387 // colours and palettes
4388 // ---------------------------------------------------------------------------
4390 bool wxWindowMSW::HandleSysColorChange()
4392 wxSysColourChangedEvent event
;
4393 event
.SetEventObject(this);
4395 (void)HandleWindowEvent(event
);
4397 // always let the system carry on the default processing to allow the
4398 // native controls to react to the colours update
4402 bool wxWindowMSW::HandleDisplayChange()
4404 wxDisplayChangedEvent event
;
4405 event
.SetEventObject(this);
4407 return HandleWindowEvent(event
);
4410 #ifndef __WXMICROWIN__
4412 bool wxWindowMSW::HandleCtlColor(WXHBRUSH
*brush
, WXHDC hDC
, WXHWND hWnd
)
4414 #if !wxUSE_CONTROLS || defined(__WXUNIVERSAL__)
4418 wxControl
*item
= wxDynamicCast(FindItemByHWND(hWnd
, true), wxControl
);
4421 *brush
= item
->MSWControlColor(hDC
, hWnd
);
4423 #endif // wxUSE_CONTROLS
4426 return *brush
!= NULL
;
4429 #endif // __WXMICROWIN__
4431 bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange
)
4434 // same as below except we don't respond to our own messages
4435 if ( hWndPalChange
!= GetHWND() )
4437 // check to see if we our our parents have a custom palette
4438 wxWindowMSW
*win
= this;
4439 while ( win
&& !win
->HasCustomPalette() )
4441 win
= win
->GetParent();
4444 if ( win
&& win
->HasCustomPalette() )
4446 // realize the palette to see whether redrawing is needed
4447 HDC hdc
= ::GetDC((HWND
) hWndPalChange
);
4448 win
->m_palette
.SetHPALETTE((WXHPALETTE
)
4449 ::SelectPalette(hdc
, GetHpaletteOf(win
->m_palette
), FALSE
));
4451 int result
= ::RealizePalette(hdc
);
4453 // restore the palette (before releasing the DC)
4454 win
->m_palette
.SetHPALETTE((WXHPALETTE
)
4455 ::SelectPalette(hdc
, GetHpaletteOf(win
->m_palette
), FALSE
));
4456 ::RealizePalette(hdc
);
4457 ::ReleaseDC((HWND
) hWndPalChange
, hdc
);
4459 // now check for the need to redraw
4461 ::InvalidateRect((HWND
) hWndPalChange
, NULL
, TRUE
);
4465 #endif // wxUSE_PALETTE
4467 wxPaletteChangedEvent
event(GetId());
4468 event
.SetEventObject(this);
4469 event
.SetChangedWindow(wxFindWinFromHandle(hWndPalChange
));
4471 return HandleWindowEvent(event
);
4474 bool wxWindowMSW::HandleCaptureChanged(WXHWND hWndGainedCapture
)
4476 // notify windows on the capture stack about lost capture
4477 // (see http://sourceforge.net/tracker/index.php?func=detail&aid=1153662&group_id=9863&atid=109863):
4478 wxWindowBase::NotifyCaptureLost();
4480 wxWindow
*win
= wxFindWinFromHandle(hWndGainedCapture
);
4481 wxMouseCaptureChangedEvent
event(GetId(), win
);
4482 event
.SetEventObject(this);
4483 return HandleWindowEvent(event
);
4486 bool wxWindowMSW::HandleSettingChange(WXWPARAM wParam
, WXLPARAM lParam
)
4488 // despite MSDN saying "(This message cannot be sent directly to a window.)"
4489 // we need to send this to child windows (it is only sent to top-level
4490 // windows) so {list,tree}ctrls can adjust their font size if necessary
4491 // this is exactly how explorer does it to enable the font size changes
4493 wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
4496 // top-level windows already get this message from the system
4497 wxWindow
*win
= node
->GetData();
4498 if ( !win
->IsTopLevel() )
4500 ::SendMessage(GetHwndOf(win
), WM_SETTINGCHANGE
, wParam
, lParam
);
4503 node
= node
->GetNext();
4506 // let the system handle it
4510 bool wxWindowMSW::HandleQueryNewPalette()
4514 // check to see if we our our parents have a custom palette
4515 wxWindowMSW
*win
= this;
4516 while (!win
->HasCustomPalette() && win
->GetParent()) win
= win
->GetParent();
4517 if (win
->HasCustomPalette()) {
4518 /* realize the palette to see whether redrawing is needed */
4519 HDC hdc
= ::GetDC((HWND
) GetHWND());
4520 win
->m_palette
.SetHPALETTE( (WXHPALETTE
)
4521 ::SelectPalette(hdc
, (HPALETTE
) win
->m_palette
.GetHPALETTE(), FALSE
) );
4523 int result
= ::RealizePalette(hdc
);
4524 /* restore the palette (before releasing the DC) */
4525 win
->m_palette
.SetHPALETTE( (WXHPALETTE
)
4526 ::SelectPalette(hdc
, (HPALETTE
) win
->m_palette
.GetHPALETTE(), TRUE
) );
4527 ::RealizePalette(hdc
);
4528 ::ReleaseDC((HWND
) GetHWND(), hdc
);
4529 /* now check for the need to redraw */
4531 ::InvalidateRect((HWND
) GetHWND(), NULL
, TRUE
);
4533 #endif // wxUSE_PALETTE
4535 wxQueryNewPaletteEvent
event(GetId());
4536 event
.SetEventObject(this);
4538 return HandleWindowEvent(event
) && event
.GetPaletteRealized();
4541 // Responds to colour changes: passes event on to children.
4542 void wxWindowMSW::OnSysColourChanged(wxSysColourChangedEvent
& WXUNUSED(event
))
4544 // the top level window also reset the standard colour map as it might have
4545 // changed (there is no need to do it for the non top level windows as we
4546 // only have to do it once)
4550 gs_hasStdCmap
= false;
4552 wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
4555 // Only propagate to non-top-level windows because Windows already
4556 // sends this event to all top-level ones
4557 wxWindow
*win
= node
->GetData();
4558 if ( !win
->IsTopLevel() )
4560 // we need to send the real WM_SYSCOLORCHANGE and not just trigger
4561 // EVT_SYS_COLOUR_CHANGED call because the latter wouldn't work for
4562 // the standard controls
4563 ::SendMessage(GetHwndOf(win
), WM_SYSCOLORCHANGE
, 0, 0);
4566 node
= node
->GetNext();
4570 extern wxCOLORMAP
*wxGetStdColourMap()
4572 static COLORREF s_stdColours
[wxSTD_COL_MAX
];
4573 static wxCOLORMAP s_cmap
[wxSTD_COL_MAX
];
4575 if ( !gs_hasStdCmap
)
4577 static bool s_coloursInit
= false;
4579 if ( !s_coloursInit
)
4581 // When a bitmap is loaded, the RGB values can change (apparently
4582 // because Windows adjusts them to care for the old programs always
4583 // using 0xc0c0c0 while the transparent colour for the new Windows
4584 // versions is different). But we do this adjustment ourselves so
4585 // we want to avoid Windows' "help" and for this we need to have a
4586 // reference bitmap which can tell us what the RGB values change
4588 wxLogNull logNo
; // suppress error if we couldn't load the bitmap
4589 wxBitmap
stdColourBitmap(wxT("wxBITMAP_STD_COLOURS"));
4590 if ( stdColourBitmap
.Ok() )
4592 // the pixels in the bitmap must correspond to wxSTD_COL_XXX!
4593 wxASSERT_MSG( stdColourBitmap
.GetWidth() == wxSTD_COL_MAX
,
4594 wxT("forgot to update wxBITMAP_STD_COLOURS!") );
4597 memDC
.SelectObject(stdColourBitmap
);
4600 for ( size_t i
= 0; i
< WXSIZEOF(s_stdColours
); i
++ )
4602 memDC
.GetPixel(i
, 0, &colour
);
4603 s_stdColours
[i
] = wxColourToRGB(colour
);
4606 else // wxBITMAP_STD_COLOURS couldn't be loaded
4608 s_stdColours
[0] = RGB(000,000,000); // black
4609 s_stdColours
[1] = RGB(128,128,128); // dark grey
4610 s_stdColours
[2] = RGB(192,192,192); // light grey
4611 s_stdColours
[3] = RGB(255,255,255); // white
4612 //s_stdColours[4] = RGB(000,000,255); // blue
4613 //s_stdColours[5] = RGB(255,000,255); // magenta
4616 s_coloursInit
= true;
4619 gs_hasStdCmap
= true;
4621 // create the colour map
4622 #define INIT_CMAP_ENTRY(col) \
4623 s_cmap[wxSTD_COL_##col].from = s_stdColours[wxSTD_COL_##col]; \
4624 s_cmap[wxSTD_COL_##col].to = ::GetSysColor(COLOR_##col)
4626 INIT_CMAP_ENTRY(BTNTEXT
);
4627 INIT_CMAP_ENTRY(BTNSHADOW
);
4628 INIT_CMAP_ENTRY(BTNFACE
);
4629 INIT_CMAP_ENTRY(BTNHIGHLIGHT
);
4631 #undef INIT_CMAP_ENTRY
4637 #if wxUSE_UXTHEME && !defined(TMT_FILLCOLOR)
4638 #define TMT_FILLCOLOR 3802
4639 #define TMT_TEXTCOLOR 3803
4640 #define TMT_BORDERCOLOR 3801
4643 wxColour
wxWindowMSW::MSWGetThemeColour(const wchar_t *themeName
,
4646 MSWThemeColour themeColour
,
4647 wxSystemColour fallback
) const
4650 const wxUxThemeEngine
* theme
= wxUxThemeEngine::GetIfActive();
4653 int themeProperty
= 0;
4655 // TODO: Convert this into a table? Sure would be faster.
4656 switch ( themeColour
)
4658 case ThemeColourBackground
:
4659 themeProperty
= TMT_FILLCOLOR
;
4661 case ThemeColourText
:
4662 themeProperty
= TMT_TEXTCOLOR
;
4664 case ThemeColourBorder
:
4665 themeProperty
= TMT_BORDERCOLOR
;
4668 wxFAIL_MSG(wxT("unsupported theme colour"));
4671 wxUxThemeHandle
hTheme((const wxWindow
*)this, themeName
);
4673 HRESULT hr
= theme
->GetThemeColor
4682 if ( SUCCEEDED(hr
) )
4683 return wxRGBToColour(col
);
4687 "GetThemeColor(%s, %i, %i, %i)",
4688 themeName
, themePart
, themeState
, themeProperty
),
4692 wxUnusedVar(themeName
);
4693 wxUnusedVar(themePart
);
4694 wxUnusedVar(themeState
);
4695 wxUnusedVar(themeColour
);
4697 return wxSystemSettings::GetColour(fallback
);
4700 // ---------------------------------------------------------------------------
4702 // ---------------------------------------------------------------------------
4704 // this variable is used to check that a paint event handler which processed
4705 // the event did create a wxPaintDC inside its code and called BeginPaint() to
4706 // validate the invalidated window area as otherwise we'd keep getting an
4707 // endless stream of WM_PAINT messages for this window resulting in a lot of
4708 // difficult to debug problems (e.g. impossibility to repaint other windows,
4709 // lack of timer and idle events and so on)
4710 extern bool wxDidCreatePaintDC
;
4711 bool wxDidCreatePaintDC
= false;
4713 bool wxWindowMSW::HandlePaint()
4715 HRGN hRegion
= ::CreateRectRgn(0, 0, 0, 0); // Dummy call to get a handle
4718 wxLogLastError(wxT("CreateRectRgn"));
4720 if ( ::GetUpdateRgn(GetHwnd(), hRegion
, FALSE
) == ERROR
)
4722 wxLogLastError(wxT("GetUpdateRgn"));
4725 m_updateRegion
= wxRegion((WXHRGN
) hRegion
);
4727 wxDidCreatePaintDC
= false;
4729 wxPaintEvent
event(m_windowId
);
4730 event
.SetEventObject(this);
4732 bool processed
= HandleWindowEvent(event
);
4734 if ( processed
&& !wxDidCreatePaintDC
)
4736 // do call MSWDefWindowProc() to validate the update region to avoid
4737 // the problems mentioned above
4741 // note that we must generate NC event after the normal one as otherwise
4742 // BeginPaint() will happily overwrite our decorations with the background
4744 wxNcPaintEvent
eventNc(m_windowId
);
4745 eventNc
.SetEventObject(this);
4746 HandleWindowEvent(eventNc
);
4748 // don't keep an HRGN we don't need any longer (GetUpdateRegion() can only
4749 // be called from inside the event handlers called above)
4750 m_updateRegion
.Clear();
4755 // Can be called from an application's OnPaint handler
4756 void wxWindowMSW::OnPaint(wxPaintEvent
& event
)
4758 #ifdef __WXUNIVERSAL__
4761 HDC hDC
= (HDC
) wxPaintDCImpl::FindDCInCache((wxWindow
*) event
.GetEventObject());
4764 MSWDefWindowProc(WM_PAINT
, (WPARAM
) hDC
, 0);
4769 bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc
)
4771 switch ( GetBackgroundStyle() )
4773 case wxBG_STYLE_ERASE
:
4774 case wxBG_STYLE_COLOUR
:
4775 // we need to generate an erase background event
4777 wxDCTemp
dc(hdc
, GetClientSize());
4778 wxDCTempImpl
*impl
= (wxDCTempImpl
*) dc
.GetImpl();
4781 impl
->SetWindow((wxWindow
*)this);
4783 wxEraseEvent
event(m_windowId
, &dc
);
4784 event
.SetEventObject(this);
4785 bool rc
= HandleWindowEvent(event
);
4787 // must be called manually as ~wxDC doesn't do anything for
4789 impl
->SelectOldObjects(hdc
);
4793 // background erased by the user-defined handler
4799 case wxBG_STYLE_SYSTEM
:
4800 if ( !DoEraseBackground(hdc
) )
4802 // let the default processing to take place if we didn't erase
4803 // the background ourselves
4808 case wxBG_STYLE_PAINT
:
4809 case wxBG_STYLE_TRANSPARENT
:
4810 // no need to do anything here at all, background will be entirely
4811 // redrawn in WM_PAINT handler
4815 wxFAIL_MSG( "unknown background style" );
4821 #ifdef wxHAS_MSW_BACKGROUND_ERASE_HOOK
4823 bool wxWindowMSW::MSWHasEraseBgHook() const
4825 return gs_eraseBgHooks
.find(const_cast<wxWindowMSW
*>(this))
4826 != gs_eraseBgHooks
.end();
4829 void wxWindowMSW::MSWSetEraseBgHook(wxWindow
*child
)
4833 if ( !gs_eraseBgHooks
.insert(
4834 EraseBgHooks::value_type(this, child
)).second
)
4836 wxFAIL_MSG( wxT("Setting erase background hook twice?") );
4839 else // reset the hook
4841 if ( gs_eraseBgHooks
.erase(this) != 1 )
4843 wxFAIL_MSG( wxT("Resetting erase background which was not set?") );
4848 #endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK
4850 bool wxWindowMSW::DoEraseBackground(WXHDC hDC
)
4852 HBRUSH hbr
= (HBRUSH
)MSWGetBgBrush(hDC
);
4856 // erase just the client area of the window, this is important for the
4857 // frames to avoid drawing over the toolbar part of the window (you might
4858 // think using WS_CLIPCHILDREN would prevent this from happening, but it
4861 wxCopyRectToRECT(GetClientRect(), rc
);
4862 ::FillRect((HDC
)hDC
, &rc
, hbr
);
4868 wxWindowMSW::MSWGetBgBrushForChild(WXHDC
WXUNUSED(hDC
),
4869 wxWindowMSW
* WXUNUSED(child
))
4874 brush
= wxTheBrushList
->FindOrCreateBrush(GetBackgroundColour());
4876 return (WXHBRUSH
)GetHbrushOf(*brush
);
4882 WXHBRUSH
wxWindowMSW::MSWGetBgBrush(WXHDC hDC
)
4884 for ( wxWindowMSW
*win
= this; win
; win
= win
->GetParent() )
4886 WXHBRUSH hBrush
= win
->MSWGetBgBrushForChild(hDC
, this);
4890 // don't use the parent background if we're not transparent
4891 if ( !win
->HasTransparentBackground() )
4894 // background is not inherited beyond top level windows
4895 if ( win
->IsTopLevel() )
4902 bool wxWindowMSW::HandlePrintClient(WXHDC hDC
)
4904 // we receive this message when DrawThemeParentBackground() is
4905 // called from def window proc of several controls under XP and we
4906 // must draw properly themed background here
4908 // note that naively I'd expect filling the client rect with the
4909 // brush returned by MSWGetBgBrush() work -- but for some reason it
4910 // doesn't and we have to call parents MSWPrintChild() which is
4911 // supposed to call DrawThemeBackground() with appropriate params
4913 // also note that in this case lParam == PRF_CLIENT but we're
4914 // clearly expected to paint the background and nothing else!
4916 if ( IsTopLevel() || InheritsBackgroundColour() )
4919 // sometimes we don't want the parent to handle it at all, instead
4920 // return whatever value this window wants
4921 if ( !MSWShouldPropagatePrintChild() )
4922 return MSWPrintChild(hDC
, (wxWindow
*)this);
4924 for ( wxWindow
*win
= GetParent(); win
; win
= win
->GetParent() )
4926 if ( win
->MSWPrintChild(hDC
, (wxWindow
*)this) )
4929 if ( win
->IsTopLevel() || win
->InheritsBackgroundColour() )
4936 // ---------------------------------------------------------------------------
4937 // moving and resizing
4938 // ---------------------------------------------------------------------------
4940 bool wxWindowMSW::HandleMinimize()
4942 wxIconizeEvent
event(m_windowId
);
4943 event
.SetEventObject(this);
4945 return HandleWindowEvent(event
);
4948 bool wxWindowMSW::HandleMaximize()
4950 wxMaximizeEvent
event(m_windowId
);
4951 event
.SetEventObject(this);
4953 return HandleWindowEvent(event
);
4956 bool wxWindowMSW::HandleMove(int x
, int y
)
4959 wxMoveEvent
event(point
, m_windowId
);
4960 event
.SetEventObject(this);
4962 return HandleWindowEvent(event
);
4965 bool wxWindowMSW::HandleMoving(wxRect
& rect
)
4967 wxMoveEvent
event(rect
, m_windowId
);
4968 event
.SetEventObject(this);
4970 bool rc
= HandleWindowEvent(event
);
4972 rect
= event
.GetRect();
4976 bool wxWindowMSW::HandleEnterSizeMove()
4978 wxMoveEvent
event(wxPoint(0,0), m_windowId
);
4979 event
.SetEventType(wxEVT_MOVE_START
);
4980 event
.SetEventObject(this);
4982 return HandleWindowEvent(event
);
4985 bool wxWindowMSW::HandleExitSizeMove()
4987 wxMoveEvent
event(wxPoint(0,0), m_windowId
);
4988 event
.SetEventType(wxEVT_MOVE_END
);
4989 event
.SetEventObject(this);
4991 return HandleWindowEvent(event
);
4994 bool wxWindowMSW::HandleSize(int WXUNUSED(w
), int WXUNUSED(h
), WXUINT wParam
)
4996 #if wxUSE_DEFERRED_SIZING
4997 // when we resize this window, its children are probably going to be
4998 // repositioned as well, prepare to use DeferWindowPos() for them
4999 int numChildren
= 0;
5000 for ( HWND child
= ::GetWindow(GetHwndOf(this), GW_CHILD
);
5002 child
= ::GetWindow(child
, GW_HWNDNEXT
) )
5007 // Protect against valid m_hDWP being overwritten
5008 bool useDefer
= false;
5010 if ( numChildren
> 1 )
5014 m_hDWP
= (WXHANDLE
)::BeginDeferWindowPos(numChildren
);
5017 wxLogLastError(wxT("BeginDeferWindowPos"));
5023 #endif // wxUSE_DEFERRED_SIZING
5025 // update this window size
5026 bool processed
= false;
5030 wxFAIL_MSG( wxT("unexpected WM_SIZE parameter") );
5031 // fall through nevertheless
5035 // we're not interested in these messages at all
5038 case SIZE_MINIMIZED
:
5039 processed
= HandleMinimize();
5042 case SIZE_MAXIMIZED
:
5043 /* processed = */ HandleMaximize();
5044 // fall through to send a normal size event as well
5047 // don't use w and h parameters as they specify the client size
5048 // while according to the docs EVT_SIZE handler is supposed to
5049 // receive the total size
5050 wxSizeEvent
event(GetSize(), m_windowId
);
5051 event
.SetEventObject(this);
5053 processed
= HandleWindowEvent(event
);
5056 #if wxUSE_DEFERRED_SIZING
5057 // and finally change the positions of all child windows at once
5058 if ( useDefer
&& m_hDWP
)
5060 // reset m_hDWP to NULL so that child windows don't try to use our
5061 // m_hDWP after we call EndDeferWindowPos() on it (this shouldn't
5062 // happen anyhow normally but who knows what weird flow of control we
5063 // may have depending on what the users EVT_SIZE handler does...)
5064 HDWP hDWP
= (HDWP
)m_hDWP
;
5067 // do put all child controls in place at once
5068 if ( !::EndDeferWindowPos(hDWP
) )
5070 wxLogLastError(wxT("EndDeferWindowPos"));
5073 // Reset our children's pending pos/size values.
5074 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
5076 node
= node
->GetNext() )
5078 wxWindowMSW
* const child
= node
->GetData();
5079 child
->MSWEndDeferWindowPos();
5082 #endif // wxUSE_DEFERRED_SIZING
5087 bool wxWindowMSW::HandleSizing(wxRect
& rect
)
5089 wxSizeEvent
event(rect
, m_windowId
);
5090 event
.SetEventObject(this);
5092 bool rc
= HandleWindowEvent(event
);
5094 rect
= event
.GetRect();
5098 bool wxWindowMSW::HandleGetMinMaxInfo(void *WXUNUSED_IN_WINCE(mmInfo
))
5103 MINMAXINFO
*info
= (MINMAXINFO
*)mmInfo
;
5107 int minWidth
= GetMinWidth(),
5108 minHeight
= GetMinHeight(),
5109 maxWidth
= GetMaxWidth(),
5110 maxHeight
= GetMaxHeight();
5112 if ( minWidth
!= wxDefaultCoord
)
5114 info
->ptMinTrackSize
.x
= minWidth
;
5118 if ( minHeight
!= wxDefaultCoord
)
5120 info
->ptMinTrackSize
.y
= minHeight
;
5124 if ( maxWidth
!= wxDefaultCoord
)
5126 info
->ptMaxTrackSize
.x
= maxWidth
;
5130 if ( maxHeight
!= wxDefaultCoord
)
5132 info
->ptMaxTrackSize
.y
= maxHeight
;
5140 // ---------------------------------------------------------------------------
5142 // ---------------------------------------------------------------------------
5144 bool wxWindowMSW::HandleCommand(WXWORD id_
, WXWORD cmd
, WXHWND control
)
5146 // sign extend to int from short before comparing with the other int ids
5147 int id
= (signed short)id_
;
5149 #if wxUSE_MENUS_NATIVE
5150 if ( !cmd
&& wxCurrentPopupMenu
)
5152 wxMenu
*popupMenu
= wxCurrentPopupMenu
;
5153 wxCurrentPopupMenu
= NULL
;
5155 return popupMenu
->MSWCommand(cmd
, id
);
5157 #endif // wxUSE_MENUS_NATIVE
5159 wxWindow
*win
= NULL
;
5161 // first try to find it from HWND - this works even with the broken
5162 // programs using the same ids for different controls
5165 win
= wxFindWinFromHandle(control
);
5176 return win
->MSWCommand(cmd
, id
);
5179 // the messages sent from the in-place edit control used by the treectrl
5180 // for label editing have id == 0, but they should _not_ be treated as menu
5181 // messages (they are EN_XXX ones, in fact) so don't translate anything
5182 // coming from a control to wxEVT_COMMAND_MENU_SELECTED
5185 wxCommandEvent
event(wxEVT_COMMAND_MENU_SELECTED
, id
);
5186 event
.SetEventObject(this);
5189 return HandleWindowEvent(event
);
5193 #if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__)
5194 // the text ctrl which is logically part of wxSpinCtrl sends WM_COMMAND
5195 // notifications to its parent which we want to reflect back to
5197 wxSpinCtrl
*spin
= wxSpinCtrl::GetSpinForTextCtrl(control
);
5198 if ( spin
&& spin
->ProcessTextCommand(cmd
, id
) )
5200 #endif // wxUSE_SPINCTRL
5202 #if wxUSE_CHOICE && defined(__SMARTPHONE__)
5203 // the listbox ctrl which is logically part of wxChoice sends WM_COMMAND
5204 // notifications to its parent which we want to reflect back to
5206 wxChoice
*choice
= wxChoice::GetChoiceForListBox(control
);
5207 if ( choice
&& choice
->MSWCommand(cmd
, id
) )
5215 // ---------------------------------------------------------------------------
5217 // ---------------------------------------------------------------------------
5219 void wxWindowMSW::InitMouseEvent(wxMouseEvent
& event
,
5223 // our client coords are not quite the same as Windows ones
5224 wxPoint pt
= GetClientAreaOrigin();
5225 event
.m_x
= x
- pt
.x
;
5226 event
.m_y
= y
- pt
.y
;
5228 event
.m_shiftDown
= (flags
& MK_SHIFT
) != 0;
5229 event
.m_controlDown
= (flags
& MK_CONTROL
) != 0;
5230 event
.m_leftDown
= (flags
& MK_LBUTTON
) != 0;
5231 event
.m_middleDown
= (flags
& MK_MBUTTON
) != 0;
5232 event
.m_rightDown
= (flags
& MK_RBUTTON
) != 0;
5233 #ifdef wxHAS_XBUTTON
5234 event
.m_aux1Down
= (flags
& MK_XBUTTON1
) != 0;
5235 event
.m_aux2Down
= (flags
& MK_XBUTTON2
) != 0;
5236 #endif // wxHAS_XBUTTON
5237 event
.m_altDown
= ::wxIsAltDown();
5240 event
.SetTimestamp(::GetMessageTime());
5243 event
.SetEventObject(this);
5244 event
.SetId(GetId());
5246 #if wxUSE_MOUSEEVENT_HACK
5247 gs_lastMouseEvent
.pos
= ClientToScreen(wxPoint(x
, y
));
5248 gs_lastMouseEvent
.type
= event
.GetEventType();
5249 #endif // wxUSE_MOUSEEVENT_HACK
5253 // Windows doesn't send the mouse events to the static controls (which are
5254 // transparent in the sense that their WM_NCHITTEST handler returns
5255 // HTTRANSPARENT) at all but we want all controls to receive the mouse events
5256 // and so we manually check if we don't have a child window under mouse and if
5257 // we do, send the event to it instead of the window Windows had sent WM_XXX
5260 // Notice that this is not done for the mouse move events because this could
5261 // (would?) be too slow, but only for clicks which means that the static texts
5262 // still don't get move, enter nor leave events.
5263 static wxWindowMSW
*FindWindowForMouseEvent(wxWindowMSW
*win
, int *x
, int *y
)
5265 wxCHECK_MSG( x
&& y
, win
, wxT("NULL pointer in FindWindowForMouseEvent") );
5267 // first try to find a non transparent child: this allows us to send events
5268 // to a static text which is inside a static box, for example
5269 POINT pt
= { *x
, *y
};
5270 HWND hwnd
= GetHwndOf(win
),
5274 hwndUnderMouse
= ::ChildWindowFromPoint
5280 hwndUnderMouse
= ::ChildWindowFromPointEx
5290 if ( !hwndUnderMouse
|| hwndUnderMouse
== hwnd
)
5292 // now try any child window at all
5293 hwndUnderMouse
= ::ChildWindowFromPoint(hwnd
, pt
);
5296 // check that we have a child window which is susceptible to receive mouse
5297 // events: for this it must be shown and enabled
5298 if ( hwndUnderMouse
&&
5299 hwndUnderMouse
!= hwnd
&&
5300 ::IsWindowVisible(hwndUnderMouse
) &&
5301 ::IsWindowEnabled(hwndUnderMouse
) )
5303 wxWindow
*winUnderMouse
= wxFindWinFromHandle(hwndUnderMouse
);
5304 if ( winUnderMouse
)
5306 // translate the mouse coords to the other window coords
5307 win
->ClientToScreen(x
, y
);
5308 winUnderMouse
->ScreenToClient(x
, y
);
5310 win
= winUnderMouse
;
5316 #endif // __WXWINCE__
5318 bool wxWindowMSW::HandleMouseEvent(WXUINT msg
, int x
, int y
, WXUINT flags
)
5320 // the mouse events take consecutive IDs from WM_MOUSEFIRST to
5321 // WM_MOUSELAST, so it's enough to subtract WM_MOUSEMOVE == WM_MOUSEFIRST
5322 // from the message id and take the value in the table to get wxWin event
5324 static const wxEventType eventsMouse
[] =
5335 wxEVT_MIDDLE_DCLICK
,
5336 0, // this one is for wxEVT_MOTION which is not used here
5345 #ifdef wxHAS_XBUTTON
5346 // the same messages are used for both auxillary mouse buttons so we need
5347 // to adjust the index manually
5350 case WM_XBUTTONDOWN
:
5352 case WM_XBUTTONDBLCLK
:
5353 if ( flags
& MK_XBUTTON2
)
5354 msg
+= wxEVT_AUX2_DOWN
- wxEVT_AUX1_DOWN
;
5356 #endif // wxHAS_XBUTTON
5358 wxMouseEvent
event(eventsMouse
[msg
- WM_MOUSEMOVE
]);
5359 InitMouseEvent(event
, x
, y
, flags
);
5361 return HandleWindowEvent(event
);
5364 bool wxWindowMSW::HandleMouseMove(int x
, int y
, WXUINT flags
)
5366 if ( !m_mouseInWindow
)
5368 // it would be wrong to assume that just because we get a mouse move
5369 // event that the mouse is inside the window: although this is usually
5370 // true, it is not if we had captured the mouse, so we need to check
5371 // the mouse coordinates here
5372 if ( !HasCapture() || IsMouseInWindow() )
5374 // Generate an ENTER event
5375 m_mouseInWindow
= true;
5377 #ifdef HAVE_TRACKMOUSEEVENT
5378 typedef BOOL (WINAPI
*_TrackMouseEvent_t
)(LPTRACKMOUSEEVENT
);
5380 static const _TrackMouseEvent_t
5381 s_pfn_TrackMouseEvent
= _TrackMouseEvent
;
5382 #else // !__WXWINCE__
5383 static _TrackMouseEvent_t s_pfn_TrackMouseEvent
;
5384 static bool s_initDone
= false;
5387 // see comment in wxApp::GetComCtl32Version() explaining the
5388 // use of wxLoadedDLL
5389 wxLoadedDLL
dllComCtl32(wxT("comctl32.dll"));
5390 if ( dllComCtl32
.IsLoaded() )
5392 s_pfn_TrackMouseEvent
= (_TrackMouseEvent_t
)
5393 dllComCtl32
.RawGetSymbol(wxT("_TrackMouseEvent"));
5399 if ( s_pfn_TrackMouseEvent
)
5400 #endif // __WXWINCE__/!__WXWINCE__
5402 WinStruct
<TRACKMOUSEEVENT
> trackinfo
;
5404 trackinfo
.dwFlags
= TME_LEAVE
;
5405 trackinfo
.hwndTrack
= GetHwnd();
5407 (*s_pfn_TrackMouseEvent
)(&trackinfo
);
5409 #endif // HAVE_TRACKMOUSEEVENT
5411 wxMouseEvent
event(wxEVT_ENTER_WINDOW
);
5412 InitMouseEvent(event
, x
, y
, flags
);
5414 (void)HandleWindowEvent(event
);
5417 #ifdef HAVE_TRACKMOUSEEVENT
5418 else // mouse not in window
5420 // Check if we need to send a LEAVE event
5421 // Windows doesn't send WM_MOUSELEAVE if the mouse has been captured so
5422 // send it here if we are using native mouse leave tracking
5423 if ( HasCapture() && !IsMouseInWindow() )
5425 GenerateMouseLeave();
5428 #endif // HAVE_TRACKMOUSEEVENT
5430 #if wxUSE_MOUSEEVENT_HACK
5431 // Windows often generates mouse events even if mouse position hasn't
5432 // changed (http://article.gmane.org/gmane.comp.lib.wxwidgets.devel/66576)
5434 // Filter this out as it can result in unexpected behaviour compared to
5436 if ( gs_lastMouseEvent
.type
== wxEVT_RIGHT_DOWN
||
5437 gs_lastMouseEvent
.type
== wxEVT_LEFT_DOWN
||
5438 gs_lastMouseEvent
.type
== wxEVT_MIDDLE_DOWN
||
5439 gs_lastMouseEvent
.type
== wxEVT_MOTION
)
5441 if ( ClientToScreen(wxPoint(x
, y
)) == gs_lastMouseEvent
.pos
)
5443 gs_lastMouseEvent
.type
= wxEVT_MOTION
;
5448 #endif // wxUSE_MOUSEEVENT_HACK
5450 return HandleMouseEvent(WM_MOUSEMOVE
, x
, y
, flags
);
5454 bool wxWindowMSW::HandleMouseWheel(WXWPARAM wParam
, WXLPARAM lParam
)
5456 #if wxUSE_MOUSEWHEEL
5457 // notice that WM_MOUSEWHEEL position is in screen coords (as it's
5458 // forwarded up to the parent by DefWindowProc()) and not in the client
5459 // ones as all the other messages, translate them to the client coords for
5462 pt
= ScreenToClient(wxPoint(GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
)));
5463 wxMouseEvent
event(wxEVT_MOUSEWHEEL
);
5464 InitMouseEvent(event
, pt
.x
, pt
.y
, LOWORD(wParam
));
5465 event
.m_wheelRotation
= (short)HIWORD(wParam
);
5466 event
.m_wheelDelta
= WHEEL_DELTA
;
5468 static int s_linesPerRotation
= -1;
5469 if ( s_linesPerRotation
== -1 )
5471 if ( !::SystemParametersInfo(SPI_GETWHEELSCROLLLINES
, 0,
5472 &s_linesPerRotation
, 0))
5474 // this is not supposed to happen
5475 wxLogLastError(wxT("SystemParametersInfo(GETWHEELSCROLLLINES)"));
5477 // the default is 3, so use it if SystemParametersInfo() failed
5478 s_linesPerRotation
= 3;
5482 event
.m_linesPerAction
= s_linesPerRotation
;
5483 return HandleWindowEvent(event
);
5485 #else // !wxUSE_MOUSEWHEEL
5486 wxUnusedVar(wParam
);
5487 wxUnusedVar(lParam
);
5490 #endif // wxUSE_MOUSEWHEEL/!wxUSE_MOUSEWHEEL
5493 void wxWindowMSW::GenerateMouseLeave()
5495 m_mouseInWindow
= false;
5498 if ( wxIsShiftDown() )
5500 if ( wxIsCtrlDown() )
5501 state
|= MK_CONTROL
;
5503 // Only the high-order bit should be tested
5504 if ( GetKeyState( VK_LBUTTON
) & (1<<15) )
5505 state
|= MK_LBUTTON
;
5506 if ( GetKeyState( VK_MBUTTON
) & (1<<15) )
5507 state
|= MK_MBUTTON
;
5508 if ( GetKeyState( VK_RBUTTON
) & (1<<15) )
5509 state
|= MK_RBUTTON
;
5513 if ( !::GetCursorPosWinCE(&pt
) )
5515 if ( !::GetCursorPos(&pt
) )
5518 wxLogLastError(wxT("GetCursorPos"));
5521 // we need to have client coordinates here for symmetry with
5522 // wxEVT_ENTER_WINDOW
5523 RECT rect
= wxGetWindowRect(GetHwnd());
5527 wxMouseEvent
event(wxEVT_LEAVE_WINDOW
);
5528 InitMouseEvent(event
, pt
.x
, pt
.y
, state
);
5530 (void)HandleWindowEvent(event
);
5533 // ---------------------------------------------------------------------------
5534 // keyboard handling
5535 // ---------------------------------------------------------------------------
5540 // Implementation of InitAnyKeyEvent() which can also be used when there is no
5541 // associated window: this can happen for the wxEVT_CHAR_HOOK events created by
5542 // the global keyboard hook (e.g. the event might have happened in a non-wx
5545 MSWInitAnyKeyEvent(wxKeyEvent
& event
,
5548 const wxWindowBase
*win
/* may be NULL */)
5552 event
.SetId(win
->GetId());
5553 event
.SetEventObject(const_cast<wxWindowBase
*>(win
));
5555 else // No associated window.
5557 // Use wxID_ANY for compatibility with the old code even if wxID_NONE
5558 // would arguably make more sense.
5559 event
.SetId(wxID_ANY
);
5562 event
.m_shiftDown
= wxIsShiftDown();
5563 event
.m_controlDown
= wxIsCtrlDown();
5564 event
.m_altDown
= (HIWORD(lParam
) & KF_ALTDOWN
) == KF_ALTDOWN
;
5566 event
.m_rawCode
= (wxUint32
) wParam
;
5567 event
.m_rawFlags
= (wxUint32
) lParam
;
5569 event
.SetTimestamp(::GetMessageTime());
5572 // Event coordinates must be in window client coordinates system which
5573 // doesn't make sense if there is no window.
5575 // We could use screen coordinates for such events but this would make the
5576 // logic of the event handlers more complicated: you'd need to test for the
5577 // event object and interpret the coordinates differently according to
5578 // whether it's NULL or not so unless somebody really asks for this let's
5579 // just avoid the issue.
5582 const wxPoint mousePos
= win
->ScreenToClient(wxGetMousePosition());
5583 event
.m_x
= mousePos
.x
;
5584 event
.m_y
= mousePos
.y
;
5588 } // anonymous namespace
5591 wxWindowMSW::InitAnyKeyEvent(wxKeyEvent
& event
,
5593 WXLPARAM lParam
) const
5595 MSWInitAnyKeyEvent(event
, wParam
, lParam
, this);
5599 wxWindowMSW::CreateKeyEvent(wxEventType evType
,
5601 WXLPARAM lParam
) const
5603 // Catch any attempts to use this with WM_CHAR, it wouldn't work because
5604 // wParam is supposed to be a virtual key and not a character here.
5605 wxASSERT_MSG( evType
!= wxEVT_CHAR
&& evType
!= wxEVT_CHAR_HOOK
,
5606 "CreateKeyEvent() can't be used for char events" );
5608 wxKeyEvent
event(evType
);
5609 InitAnyKeyEvent(event
, wParam
, lParam
);
5611 event
.m_keyCode
= wxMSWKeyboard::VKToWX
5617 #endif // wxUSE_UNICODE
5623 // isASCII is true only when we're called from WM_CHAR handler and not from
5625 bool wxWindowMSW::HandleChar(WXWPARAM wParam
, WXLPARAM lParam
)
5627 wxKeyEvent
event(wxEVT_CHAR
);
5628 InitAnyKeyEvent(event
, wParam
, lParam
);
5631 // TODO: wParam uses UTF-16 so this is incorrect for characters outside of
5632 // the BMP, we should use WM_UNICHAR to handle them.
5633 event
.m_uniChar
= wParam
;
5634 #endif // wxUSE_UNICODE
5636 // Set non-Unicode key code too for compatibility if possible.
5637 if ( wParam
< 0x80 )
5639 // It's an ASCII character, no need to translate it.
5640 event
.m_keyCode
= wParam
;
5644 // Check if this key can be represented (as a single character) in the
5646 const wchar_t wc
= wParam
;
5648 if ( wxConvLibc
.FromWChar(&ch
, 1, &wc
, 1) != wxCONV_FAILED
)
5650 // For compatibility continue to provide the key code in this field
5651 // even though using GetUnicodeKey() is recommended now.
5652 event
.m_keyCode
= static_cast<unsigned char>(ch
);
5654 //else: Key can't be represented in the current locale, leave m_keyCode
5655 // as WXK_NONE and use GetUnicodeKey() to access the character.
5658 // the alphanumeric keys produced by pressing AltGr+something on European
5659 // keyboards have both Ctrl and Alt modifiers which may confuse the user
5660 // code as, normally, keys with Ctrl and/or Alt don't result in anything
5661 // alphanumeric, so pretend that there are no modifiers at all (the
5662 // KEY_DOWN event would still have the correct modifiers if they're really
5664 if ( event
.m_controlDown
&& event
.m_altDown
&&
5665 (event
.m_keyCode
>= 32 && event
.m_keyCode
< 256) )
5667 event
.m_controlDown
=
5668 event
.m_altDown
= false;
5671 return HandleWindowEvent(event
);
5674 bool wxWindowMSW::HandleKeyDown(WXWPARAM wParam
, WXLPARAM lParam
)
5676 wxKeyEvent
event(CreateKeyEvent(wxEVT_KEY_DOWN
, wParam
, lParam
));
5677 return HandleWindowEvent(event
);
5680 bool wxWindowMSW::HandleKeyUp(WXWPARAM wParam
, WXLPARAM lParam
)
5682 wxKeyEvent
event(CreateKeyEvent(wxEVT_KEY_UP
, wParam
, lParam
));
5683 return HandleWindowEvent(event
);
5687 int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel
),
5688 WXLPARAM
WXUNUSED_IN_WINCE(lParam
))
5690 // FIXME: implement GetMenuItemCount for WinCE, possibly
5691 // in terms of GetMenuItemInfo
5693 const HMENU hmenu
= (HMENU
)lParam
;
5697 mii
.cbSize
= sizeof(MENUITEMINFO
);
5699 // we could use MIIM_FTYPE here as we only need to know if the item is
5700 // ownerdrawn or not and not dwTypeData which MIIM_TYPE also returns, but
5701 // MIIM_FTYPE is not supported under Win95
5702 mii
.fMask
= MIIM_TYPE
| MIIM_DATA
;
5704 // find if we have this letter in any owner drawn item
5705 const int count
= ::GetMenuItemCount(hmenu
);
5706 for ( int i
= 0; i
< count
; i
++ )
5708 // previous loop iteration could modify it, reset it back before
5709 // calling GetMenuItemInfo() to prevent it from overflowing dwTypeData
5712 if ( ::GetMenuItemInfo(hmenu
, i
, TRUE
, &mii
) )
5714 if ( mii
.fType
== MFT_OWNERDRAW
)
5716 // dwItemData member of the MENUITEMINFO is a
5717 // pointer to the associated wxMenuItem -- see the
5718 // menu creation code
5719 wxMenuItem
*item
= (wxMenuItem
*)mii
.dwItemData
;
5721 const wxString
label(item
->GetItemLabel());
5722 const wxChar
*p
= wxStrchr(label
.wx_str(), wxT('&'));
5725 if ( *p
== wxT('&') )
5727 // this is not the accel char, find the real one
5728 p
= wxStrchr(p
+ 1, wxT('&'));
5730 else // got the accel char
5732 // FIXME-UNICODE: this comparison doesn't risk to work
5733 // for non ASCII accelerator characters I'm afraid, but
5735 if ( (wchar_t)wxToupper(*p
) == (wchar_t)chAccel
)
5741 // this one doesn't match
5748 else // failed to get the menu text?
5750 // it's not fatal, so don't show error, but still log it
5751 wxLogLastError(wxT("GetMenuItemInfo"));
5758 #endif // wxUSE_MENUS
5760 bool wxWindowMSW::HandleClipboardEvent(WXUINT nMsg
)
5762 const wxEventType type
= nMsg
== WM_CUT
? wxEVT_COMMAND_TEXT_CUT
5763 : nMsg
== WM_COPY
? wxEVT_COMMAND_TEXT_COPY
5764 : /* nMsg == WM_PASTE */ wxEVT_COMMAND_TEXT_PASTE
;
5765 wxClipboardTextEvent
evt(type
, GetId());
5767 evt
.SetEventObject(this);
5769 return HandleWindowEvent(evt
);
5772 // ---------------------------------------------------------------------------
5774 // ---------------------------------------------------------------------------
5776 bool wxWindowMSW::HandleJoystickEvent(WXUINT msg
, int x
, int y
, WXUINT flags
)
5780 if ( flags
& JOY_BUTTON1CHG
)
5781 change
= wxJOY_BUTTON1
;
5782 if ( flags
& JOY_BUTTON2CHG
)
5783 change
= wxJOY_BUTTON2
;
5784 if ( flags
& JOY_BUTTON3CHG
)
5785 change
= wxJOY_BUTTON3
;
5786 if ( flags
& JOY_BUTTON4CHG
)
5787 change
= wxJOY_BUTTON4
;
5790 if ( flags
& JOY_BUTTON1
)
5791 buttons
|= wxJOY_BUTTON1
;
5792 if ( flags
& JOY_BUTTON2
)
5793 buttons
|= wxJOY_BUTTON2
;
5794 if ( flags
& JOY_BUTTON3
)
5795 buttons
|= wxJOY_BUTTON3
;
5796 if ( flags
& JOY_BUTTON4
)
5797 buttons
|= wxJOY_BUTTON4
;
5799 // the event ids aren't consecutive so we can't use table based lookup
5801 wxEventType eventType
;
5806 eventType
= wxEVT_JOY_MOVE
;
5811 eventType
= wxEVT_JOY_MOVE
;
5816 eventType
= wxEVT_JOY_ZMOVE
;
5821 eventType
= wxEVT_JOY_ZMOVE
;
5824 case MM_JOY1BUTTONDOWN
:
5826 eventType
= wxEVT_JOY_BUTTON_DOWN
;
5829 case MM_JOY2BUTTONDOWN
:
5831 eventType
= wxEVT_JOY_BUTTON_DOWN
;
5834 case MM_JOY1BUTTONUP
:
5836 eventType
= wxEVT_JOY_BUTTON_UP
;
5839 case MM_JOY2BUTTONUP
:
5841 eventType
= wxEVT_JOY_BUTTON_UP
;
5845 wxFAIL_MSG(wxT("no such joystick event"));
5850 wxJoystickEvent
event(eventType
, buttons
, joystick
, change
);
5851 event
.SetPosition(wxPoint(x
, y
));
5852 event
.SetEventObject(this);
5854 return HandleWindowEvent(event
);
5864 // ---------------------------------------------------------------------------
5866 // ---------------------------------------------------------------------------
5868 bool wxWindowMSW::MSWOnScroll(int orientation
, WXWORD wParam
,
5869 WXWORD pos
, WXHWND control
)
5871 if ( control
&& control
!= m_hWnd
) // Prevent infinite recursion
5873 wxWindow
*child
= wxFindWinFromHandle(control
);
5875 return child
->MSWOnScroll(orientation
, wParam
, pos
, control
);
5878 wxScrollWinEvent event
;
5879 event
.SetPosition(pos
);
5880 event
.SetOrientation(orientation
);
5881 event
.SetEventObject(this);
5886 event
.SetEventType(wxEVT_SCROLLWIN_TOP
);
5890 event
.SetEventType(wxEVT_SCROLLWIN_BOTTOM
);
5894 event
.SetEventType(wxEVT_SCROLLWIN_LINEUP
);
5898 event
.SetEventType(wxEVT_SCROLLWIN_LINEDOWN
);
5902 event
.SetEventType(wxEVT_SCROLLWIN_PAGEUP
);
5906 event
.SetEventType(wxEVT_SCROLLWIN_PAGEDOWN
);
5909 case SB_THUMBPOSITION
:
5911 // under Win32, the scrollbar range and position are 32 bit integers,
5912 // but WM_[HV]SCROLL only carry the low 16 bits of them, so we must
5913 // explicitly query the scrollbar for the correct position (this must
5914 // be done only for these two SB_ events as they are the only one
5915 // carrying the scrollbar position)
5917 WinStruct
<SCROLLINFO
> scrollInfo
;
5918 scrollInfo
.fMask
= SIF_TRACKPOS
;
5920 if ( !::GetScrollInfo(GetHwnd(),
5921 WXOrientToSB(orientation
),
5924 // Not necessarily an error, if there are no scrollbars yet.
5925 // wxLogLastError(wxT("GetScrollInfo"));
5928 event
.SetPosition(scrollInfo
.nTrackPos
);
5931 event
.SetEventType( wParam
== SB_THUMBPOSITION
5932 ? wxEVT_SCROLLWIN_THUMBRELEASE
5933 : wxEVT_SCROLLWIN_THUMBTRACK
);
5940 return HandleWindowEvent(event
);
5943 // ----------------------------------------------------------------------------
5944 // custom message handlers
5945 // ----------------------------------------------------------------------------
5948 wxWindowMSW::MSWRegisterMessageHandler(int msg
, MSWMessageHandler handler
)
5950 wxCHECK_MSG( gs_messageHandlers
.find(msg
) == gs_messageHandlers
.end(),
5951 false, wxT("registering handler for the same message twice") );
5953 gs_messageHandlers
[msg
] = handler
;
5958 wxWindowMSW::MSWUnregisterMessageHandler(int msg
, MSWMessageHandler handler
)
5960 const MSWMessageHandlers::iterator i
= gs_messageHandlers
.find(msg
);
5961 wxCHECK_RET( i
!= gs_messageHandlers
.end() && i
->second
== handler
,
5962 wxT("unregistering non-registered handler?") );
5964 gs_messageHandlers
.erase(i
);
5967 // ===========================================================================
5969 // ===========================================================================
5971 void wxGetCharSize(WXHWND wnd
, int *x
, int *y
, const wxFont
& the_font
)
5974 HDC dc
= ::GetDC((HWND
) wnd
);
5977 // the_font.UseResource();
5978 // the_font.RealizeResource();
5979 HFONT fnt
= (HFONT
)the_font
.GetResourceHandle(); // const_cast
5981 was
= (HFONT
) SelectObject(dc
,fnt
);
5983 GetTextMetrics(dc
, &tm
);
5986 SelectObject(dc
,was
);
5988 ReleaseDC((HWND
)wnd
, dc
);
5991 *x
= tm
.tmAveCharWidth
;
5993 *y
= tm
.tmHeight
+ tm
.tmExternalLeading
;
5995 // the_font.ReleaseResource();
5998 // ----------------------------------------------------------------------------
6000 // ----------------------------------------------------------------------------
6002 namespace wxMSWKeyboard
6008 // use the "extended" bit of lParam to distinguish extended keys from normal
6009 // keys as the same virtual key code is sent for both by Windows
6011 int ChooseNormalOrExtended(int lParam
, int keyNormal
, int keyExtended
)
6013 // except that if lParam is 0, it means we don't have real lParam from
6014 // WM_KEYDOWN but are just translating just a VK constant (e.g. done from
6015 // msw/treectrl.cpp when processing TVN_KEYDOWN) -- then assume this is a
6016 // non-numpad (hence extended) key as this is a more common case
6017 return !lParam
|| (HIWORD(lParam
) & KF_EXTENDED
) ? keyExtended
: keyNormal
;
6020 // this array contains the Windows virtual key codes which map one to one to
6021 // WXK_xxx constants and is used in wxMSWKeyboard::VKToWX/WXToVK() below
6023 // note that keys having a normal and numpad version (e.g. WXK_HOME and
6024 // WXK_NUMPAD_HOME) are not included in this table as the mapping is not 1-to-1
6025 const struct wxKeyMapping
6029 } gs_specialKeys
[] =
6031 { VK_CANCEL
, WXK_CANCEL
},
6032 { VK_BACK
, WXK_BACK
},
6033 { VK_TAB
, WXK_TAB
},
6034 { VK_CLEAR
, WXK_CLEAR
},
6035 { VK_SHIFT
, WXK_SHIFT
},
6036 { VK_CONTROL
, WXK_CONTROL
},
6037 { VK_MENU
, WXK_ALT
},
6038 { VK_PAUSE
, WXK_PAUSE
},
6039 { VK_CAPITAL
, WXK_CAPITAL
},
6040 { VK_SPACE
, WXK_SPACE
},
6041 { VK_ESCAPE
, WXK_ESCAPE
},
6042 { VK_SELECT
, WXK_SELECT
},
6043 { VK_PRINT
, WXK_PRINT
},
6044 { VK_EXECUTE
, WXK_EXECUTE
},
6045 { VK_SNAPSHOT
, WXK_SNAPSHOT
},
6046 { VK_HELP
, WXK_HELP
},
6048 { VK_NUMPAD0
, WXK_NUMPAD0
},
6049 { VK_NUMPAD1
, WXK_NUMPAD1
},
6050 { VK_NUMPAD2
, WXK_NUMPAD2
},
6051 { VK_NUMPAD3
, WXK_NUMPAD3
},
6052 { VK_NUMPAD4
, WXK_NUMPAD4
},
6053 { VK_NUMPAD5
, WXK_NUMPAD5
},
6054 { VK_NUMPAD6
, WXK_NUMPAD6
},
6055 { VK_NUMPAD7
, WXK_NUMPAD7
},
6056 { VK_NUMPAD8
, WXK_NUMPAD8
},
6057 { VK_NUMPAD9
, WXK_NUMPAD9
},
6058 { VK_MULTIPLY
, WXK_NUMPAD_MULTIPLY
},
6059 { VK_ADD
, WXK_NUMPAD_ADD
},
6060 { VK_SUBTRACT
, WXK_NUMPAD_SUBTRACT
},
6061 { VK_DECIMAL
, WXK_NUMPAD_DECIMAL
},
6062 { VK_DIVIDE
, WXK_NUMPAD_DIVIDE
},
6073 { VK_F10
, WXK_F10
},
6074 { VK_F11
, WXK_F11
},
6075 { VK_F12
, WXK_F12
},
6076 { VK_F13
, WXK_F13
},
6077 { VK_F14
, WXK_F14
},
6078 { VK_F15
, WXK_F15
},
6079 { VK_F16
, WXK_F16
},
6080 { VK_F17
, WXK_F17
},
6081 { VK_F18
, WXK_F18
},
6082 { VK_F19
, WXK_F19
},
6083 { VK_F20
, WXK_F20
},
6084 { VK_F21
, WXK_F21
},
6085 { VK_F22
, WXK_F22
},
6086 { VK_F23
, WXK_F23
},
6087 { VK_F24
, WXK_F24
},
6089 { VK_NUMLOCK
, WXK_NUMLOCK
},
6090 { VK_SCROLL
, WXK_SCROLL
},
6093 { VK_LWIN
, WXK_WINDOWS_LEFT
},
6094 { VK_RWIN
, WXK_WINDOWS_RIGHT
},
6095 { VK_APPS
, WXK_WINDOWS_MENU
},
6096 #endif // VK_APPS defined
6099 } // anonymous namespace
6101 int VKToWX(WXWORD vk
, WXLPARAM lParam
, wchar_t *uc
)
6105 // check the table first
6106 for ( size_t n
= 0; n
< WXSIZEOF(gs_specialKeys
); n
++ )
6108 if ( gs_specialKeys
[n
].vk
== vk
)
6110 wxk
= gs_specialKeys
[n
].wxk
;
6111 if ( wxk
< WXK_START
)
6113 // Unicode code for this key is the same as its ASCII code.
6122 // keys requiring special handling
6136 // MapVirtualKey() returns 0 if it fails to convert the virtual
6137 // key which nicely corresponds to our WXK_NONE.
6138 wxk
= ::MapVirtualKey(vk
, MAPVK_VK_TO_CHAR
);
6140 if ( HIWORD(wxk
) & 0x8000 )
6142 // It's a dead key and we don't return anything at all for them
6143 // as we simply don't have any way to indicate the difference
6144 // between e.g. a normal "'" and "'" as a dead key -- and
6145 // generating the same events for them just doesn't seem like a
6150 // In any case return this as a Unicode character value.
6154 // For compatibility with the old non-Unicode code we continue
6155 // returning key codes for Latin-1 characters directly
6156 // (normally it would really only make sense to do it for the
6157 // ASCII characters, not Latin-1 ones).
6160 // But for anything beyond this we can only return the key
6161 // value as a real Unicode character, not a wxKeyCode
6162 // because this enum values clash with Unicode characters
6163 // (e.g. WXK_LBUTTON also happens to be U+012C a.k.a.
6164 // "LATIN CAPITAL LETTER I WITH BREVE").
6169 // handle extended keys
6171 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_PAGEUP
, WXK_PAGEUP
);
6175 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_PAGEDOWN
, WXK_PAGEDOWN
);
6179 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_END
, WXK_END
);
6183 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_HOME
, WXK_HOME
);
6187 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_LEFT
, WXK_LEFT
);
6191 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_UP
, WXK_UP
);
6195 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_RIGHT
, WXK_RIGHT
);
6199 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_DOWN
, WXK_DOWN
);
6203 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_INSERT
, WXK_INSERT
);
6207 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_DELETE
, WXK_DELETE
);
6211 // don't use ChooseNormalOrExtended() here as the keys are reversed
6212 // here: numpad enter is the extended one
6213 wxk
= HIWORD(lParam
) & KF_EXTENDED
? WXK_NUMPAD_ENTER
: WXK_RETURN
;
6217 if ( (vk
>= '0' && vk
<= '9') || (vk
>= 'A' && vk
<= 'Z') )
6219 // A simple alphanumeric key and the values of them coincide in
6220 // Windows and wx for both ASCII and Unicode codes.
6223 else // Something we simply don't know about at all.
6235 WXWORD
WXToVK(int wxk
, bool *isExtended
)
6237 // check the table first
6238 for ( size_t n
= 0; n
< WXSIZEOF(gs_specialKeys
); n
++ )
6240 if ( gs_specialKeys
[n
].wxk
== wxk
)
6242 // All extended keys (i.e. non-numpad versions of the keys that
6243 // exist both in the numpad and outside of it) are dealt with
6246 *isExtended
= false;
6248 return gs_specialKeys
[n
].vk
;
6252 // and then check for special keys not included in the table
6253 bool extended
= false;
6259 case WXK_NUMPAD_PAGEUP
:
6265 case WXK_NUMPAD_PAGEDOWN
:
6271 case WXK_NUMPAD_END
:
6277 case WXK_NUMPAD_HOME
:
6283 case WXK_NUMPAD_LEFT
:
6295 case WXK_NUMPAD_RIGHT
:
6301 case WXK_NUMPAD_DOWN
:
6307 case WXK_NUMPAD_INSERT
:
6313 case WXK_NUMPAD_DELETE
:
6318 // no VkKeyScan() under CE unfortunately, we need to test how does
6319 // it handle OEM keys
6321 // check to see if its one of the OEM key codes.
6322 BYTE vks
= LOBYTE(VkKeyScan(wxk
));
6328 #endif // !__WXWINCE__
6335 *isExtended
= extended
;
6340 } // namespace wxMSWKeyboard
6342 // small helper for wxGetKeyState() and wxGetMouseState()
6343 static inline bool wxIsKeyDown(WXWORD vk
)
6345 // SM_SWAPBUTTON is not available under CE, so don't swap buttons there
6346 #ifdef SM_SWAPBUTTON
6347 if ( vk
== VK_LBUTTON
|| vk
== VK_RBUTTON
)
6349 if ( ::GetSystemMetrics(SM_SWAPBUTTON
) )
6351 if ( vk
== VK_LBUTTON
)
6353 else // vk == VK_RBUTTON
6357 #endif // SM_SWAPBUTTON
6359 // the low order bit indicates whether the key was pressed since the last
6360 // call and the high order one indicates whether it is down right now and
6361 // we only want that one
6362 return (GetAsyncKeyState(vk
) & (1<<15)) != 0;
6365 bool wxGetKeyState(wxKeyCode key
)
6367 // although this does work under Windows, it is not supported under other
6368 // platforms so don't allow it, you must use wxGetMouseState() instead
6369 wxASSERT_MSG( key
!= VK_LBUTTON
&&
6370 key
!= VK_RBUTTON
&&
6372 wxT("can't use wxGetKeyState() for mouse buttons") );
6374 const WXWORD vk
= wxMSWKeyboard::WXToVK(key
);
6376 // if the requested key is a LED key, return true if the led is pressed
6377 if ( key
== WXK_NUMLOCK
|| key
== WXK_CAPITAL
|| key
== WXK_SCROLL
)
6379 // low order bit means LED is highlighted and high order one means the
6380 // key is down; for compatibility with the other ports return true if
6381 // either one is set
6382 return GetKeyState(vk
) != 0;
6387 return wxIsKeyDown(vk
);
6392 wxMouseState
wxGetMouseState()
6396 GetCursorPos( &pt
);
6400 ms
.SetLeftDown(wxIsKeyDown(VK_LBUTTON
));
6401 ms
.SetMiddleDown(wxIsKeyDown(VK_MBUTTON
));
6402 ms
.SetRightDown(wxIsKeyDown(VK_RBUTTON
));
6403 #ifdef wxHAS_XBUTTON
6404 ms
.SetAux1Down(wxIsKeyDown(VK_XBUTTON1
));
6405 ms
.SetAux2Down(wxIsKeyDown(VK_XBUTTON2
));
6406 #endif // wxHAS_XBUTTON
6408 ms
.SetControlDown(wxIsCtrlDown ());
6409 ms
.SetShiftDown (wxIsShiftDown());
6410 ms
.SetAltDown (wxIsAltDown ());
6411 // ms.SetMetaDown();
6417 wxWindow
*wxGetActiveWindow()
6419 HWND hWnd
= GetActiveWindow();
6422 return wxFindWinFromHandle(hWnd
);
6427 extern wxWindow
*wxGetWindowFromHWND(WXHWND hWnd
)
6429 HWND hwnd
= (HWND
)hWnd
;
6431 // For a radiobutton, we get the radiobox from GWL_USERDATA (which is set
6432 // by code in msw/radiobox.cpp), for all the others we just search up the
6434 wxWindow
*win
= NULL
;
6437 win
= wxFindWinFromHandle(hwnd
);
6440 #if wxUSE_RADIOBOX && !defined(__WXUNIVERSAL__)
6441 // native radiobuttons return DLGC_RADIOBUTTON here and for any
6442 // wxWindow class which overrides WM_GETDLGCODE processing to
6443 // do it as well, win would be already non NULL
6444 if ( ::SendMessage(hwnd
, WM_GETDLGCODE
, 0, 0) & DLGC_RADIOBUTTON
)
6446 win
= wxRadioBox::GetFromRadioButtonHWND(hwnd
);
6448 //else: it's a wxRadioButton, not a radiobutton from wxRadioBox
6449 #endif // wxUSE_RADIOBOX
6451 // spin control text buddy window should be mapped to spin ctrl
6452 // itself so try it too
6453 #if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__)
6456 win
= wxSpinCtrl::GetSpinForTextCtrl((WXHWND
)hwnd
);
6458 #endif // wxUSE_SPINCTRL
6462 while ( hwnd
&& !win
)
6464 // this is a really ugly hack needed to avoid mistakenly returning the
6465 // parent frame wxWindow for the find/replace modeless dialog HWND -
6466 // this, in turn, is needed to call IsDialogMessage() from
6467 // wxApp::ProcessMessage() as for this we must return NULL from here
6469 // FIXME: this is clearly not the best way to do it but I think we'll
6470 // need to change HWND <-> wxWindow code more heavily than I can
6471 // do it now to fix it
6472 #ifndef __WXMICROWIN__
6473 if ( ::GetWindow(hwnd
, GW_OWNER
) )
6475 // it's a dialog box, don't go upwards
6480 hwnd
= ::GetParent(hwnd
);
6481 win
= wxFindWinFromHandle(hwnd
);
6487 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
6489 // Windows keyboard hook. Allows interception of e.g. F1, ESCAPE
6490 // in active frames and dialogs, regardless of where the focus is.
6491 static HHOOK wxTheKeyboardHook
= 0;
6494 wxKeyboardHook(int nCode
, WORD wParam
, DWORD lParam
)
6496 DWORD hiWord
= HIWORD(lParam
);
6497 if ( nCode
!= HC_NOREMOVE
&& ((hiWord
& KF_UP
) == 0) )
6500 int id
= wxMSWKeyboard::VKToWX(wParam
, lParam
, &uc
);
6503 || static_cast<int>(uc
) != WXK_NONE
6504 #endif // wxUSE_UNICODE
6507 const wxWindow
* const win
= wxGetActiveWindow();
6509 wxKeyEvent
event(wxEVT_CHAR_HOOK
);
6510 MSWInitAnyKeyEvent(event
, wParam
, lParam
, win
);
6512 event
.m_keyCode
= id
;
6514 event
.m_uniChar
= uc
;
6515 #endif // wxUSE_UNICODE
6517 wxEvtHandler
* const handler
= win
? win
->GetEventHandler()
6520 if ( handler
&& handler
->ProcessEvent(event
) )
6528 return (int)CallNextHookEx(wxTheKeyboardHook
, nCode
, wParam
, lParam
);
6531 void wxSetKeyboardHook(bool doIt
)
6535 wxTheKeyboardHook
= ::SetWindowsHookEx
6538 (HOOKPROC
)wxKeyboardHook
,
6539 NULL
, // must be NULL for process hook
6540 ::GetCurrentThreadId()
6542 if ( !wxTheKeyboardHook
)
6544 wxLogLastError(wxT("SetWindowsHookEx(wxKeyboardHook)"));
6549 if ( wxTheKeyboardHook
)
6550 ::UnhookWindowsHookEx(wxTheKeyboardHook
);
6554 #endif // !__WXMICROWIN__
6556 #if wxDEBUG_LEVEL >= 2
6557 const wxChar
*wxGetMessageName(int message
)
6561 case 0x0000: return wxT("WM_NULL");
6562 case 0x0001: return wxT("WM_CREATE");
6563 case 0x0002: return wxT("WM_DESTROY");
6564 case 0x0003: return wxT("WM_MOVE");
6565 case 0x0005: return wxT("WM_SIZE");
6566 case 0x0006: return wxT("WM_ACTIVATE");
6567 case 0x0007: return wxT("WM_SETFOCUS");
6568 case 0x0008: return wxT("WM_KILLFOCUS");
6569 case 0x000A: return wxT("WM_ENABLE");
6570 case 0x000B: return wxT("WM_SETREDRAW");
6571 case 0x000C: return wxT("WM_SETTEXT");
6572 case 0x000D: return wxT("WM_GETTEXT");
6573 case 0x000E: return wxT("WM_GETTEXTLENGTH");
6574 case 0x000F: return wxT("WM_PAINT");
6575 case 0x0010: return wxT("WM_CLOSE");
6576 case 0x0011: return wxT("WM_QUERYENDSESSION");
6577 case 0x0012: return wxT("WM_QUIT");
6578 case 0x0013: return wxT("WM_QUERYOPEN");
6579 case 0x0014: return wxT("WM_ERASEBKGND");
6580 case 0x0015: return wxT("WM_SYSCOLORCHANGE");
6581 case 0x0016: return wxT("WM_ENDSESSION");
6582 case 0x0017: return wxT("WM_SYSTEMERROR");
6583 case 0x0018: return wxT("WM_SHOWWINDOW");
6584 case 0x0019: return wxT("WM_CTLCOLOR");
6585 case 0x001A: return wxT("WM_WININICHANGE");
6586 case 0x001B: return wxT("WM_DEVMODECHANGE");
6587 case 0x001C: return wxT("WM_ACTIVATEAPP");
6588 case 0x001D: return wxT("WM_FONTCHANGE");
6589 case 0x001E: return wxT("WM_TIMECHANGE");
6590 case 0x001F: return wxT("WM_CANCELMODE");
6591 case 0x0020: return wxT("WM_SETCURSOR");
6592 case 0x0021: return wxT("WM_MOUSEACTIVATE");
6593 case 0x0022: return wxT("WM_CHILDACTIVATE");
6594 case 0x0023: return wxT("WM_QUEUESYNC");
6595 case 0x0024: return wxT("WM_GETMINMAXINFO");
6596 case 0x0026: return wxT("WM_PAINTICON");
6597 case 0x0027: return wxT("WM_ICONERASEBKGND");
6598 case 0x0028: return wxT("WM_NEXTDLGCTL");
6599 case 0x002A: return wxT("WM_SPOOLERSTATUS");
6600 case 0x002B: return wxT("WM_DRAWITEM");
6601 case 0x002C: return wxT("WM_MEASUREITEM");
6602 case 0x002D: return wxT("WM_DELETEITEM");
6603 case 0x002E: return wxT("WM_VKEYTOITEM");
6604 case 0x002F: return wxT("WM_CHARTOITEM");
6605 case 0x0030: return wxT("WM_SETFONT");
6606 case 0x0031: return wxT("WM_GETFONT");
6607 case 0x0037: return wxT("WM_QUERYDRAGICON");
6608 case 0x0039: return wxT("WM_COMPAREITEM");
6609 case 0x0041: return wxT("WM_COMPACTING");
6610 case 0x0044: return wxT("WM_COMMNOTIFY");
6611 case 0x0046: return wxT("WM_WINDOWPOSCHANGING");
6612 case 0x0047: return wxT("WM_WINDOWPOSCHANGED");
6613 case 0x0048: return wxT("WM_POWER");
6615 case 0x004A: return wxT("WM_COPYDATA");
6616 case 0x004B: return wxT("WM_CANCELJOURNAL");
6617 case 0x004E: return wxT("WM_NOTIFY");
6618 case 0x0050: return wxT("WM_INPUTLANGCHANGEREQUEST");
6619 case 0x0051: return wxT("WM_INPUTLANGCHANGE");
6620 case 0x0052: return wxT("WM_TCARD");
6621 case 0x0053: return wxT("WM_HELP");
6622 case 0x0054: return wxT("WM_USERCHANGED");
6623 case 0x0055: return wxT("WM_NOTIFYFORMAT");
6624 case 0x007B: return wxT("WM_CONTEXTMENU");
6625 case 0x007C: return wxT("WM_STYLECHANGING");
6626 case 0x007D: return wxT("WM_STYLECHANGED");
6627 case 0x007E: return wxT("WM_DISPLAYCHANGE");
6628 case 0x007F: return wxT("WM_GETICON");
6629 case 0x0080: return wxT("WM_SETICON");
6631 case 0x0081: return wxT("WM_NCCREATE");
6632 case 0x0082: return wxT("WM_NCDESTROY");
6633 case 0x0083: return wxT("WM_NCCALCSIZE");
6634 case 0x0084: return wxT("WM_NCHITTEST");
6635 case 0x0085: return wxT("WM_NCPAINT");
6636 case 0x0086: return wxT("WM_NCACTIVATE");
6637 case 0x0087: return wxT("WM_GETDLGCODE");
6638 case 0x00A0: return wxT("WM_NCMOUSEMOVE");
6639 case 0x00A1: return wxT("WM_NCLBUTTONDOWN");
6640 case 0x00A2: return wxT("WM_NCLBUTTONUP");
6641 case 0x00A3: return wxT("WM_NCLBUTTONDBLCLK");
6642 case 0x00A4: return wxT("WM_NCRBUTTONDOWN");
6643 case 0x00A5: return wxT("WM_NCRBUTTONUP");
6644 case 0x00A6: return wxT("WM_NCRBUTTONDBLCLK");
6645 case 0x00A7: return wxT("WM_NCMBUTTONDOWN");
6646 case 0x00A8: return wxT("WM_NCMBUTTONUP");
6647 case 0x00A9: return wxT("WM_NCMBUTTONDBLCLK");
6649 case 0x00B0: return wxT("EM_GETSEL");
6650 case 0x00B1: return wxT("EM_SETSEL");
6651 case 0x00B2: return wxT("EM_GETRECT");
6652 case 0x00B3: return wxT("EM_SETRECT");
6653 case 0x00B4: return wxT("EM_SETRECTNP");
6654 case 0x00B5: return wxT("EM_SCROLL");
6655 case 0x00B6: return wxT("EM_LINESCROLL");
6656 case 0x00B7: return wxT("EM_SCROLLCARET");
6657 case 0x00B8: return wxT("EM_GETMODIFY");
6658 case 0x00B9: return wxT("EM_SETMODIFY");
6659 case 0x00BA: return wxT("EM_GETLINECOUNT");
6660 case 0x00BB: return wxT("EM_LINEINDEX");
6661 case 0x00BC: return wxT("EM_SETHANDLE");
6662 case 0x00BD: return wxT("EM_GETHANDLE");
6663 case 0x00BE: return wxT("EM_GETTHUMB");
6664 case 0x00C1: return wxT("EM_LINELENGTH");
6665 case 0x00C2: return wxT("EM_REPLACESEL");
6666 case 0x00C4: return wxT("EM_GETLINE");
6667 case 0x00C5: return wxT("EM_LIMITTEXT/EM_SETLIMITTEXT"); /* ;win40 Name change */
6668 case 0x00C6: return wxT("EM_CANUNDO");
6669 case 0x00C7: return wxT("EM_UNDO");
6670 case 0x00C8: return wxT("EM_FMTLINES");
6671 case 0x00C9: return wxT("EM_LINEFROMCHAR");
6672 case 0x00CB: return wxT("EM_SETTABSTOPS");
6673 case 0x00CC: return wxT("EM_SETPASSWORDCHAR");
6674 case 0x00CD: return wxT("EM_EMPTYUNDOBUFFER");
6675 case 0x00CE: return wxT("EM_GETFIRSTVISIBLELINE");
6676 case 0x00CF: return wxT("EM_SETREADONLY");
6677 case 0x00D0: return wxT("EM_SETWORDBREAKPROC");
6678 case 0x00D1: return wxT("EM_GETWORDBREAKPROC");
6679 case 0x00D2: return wxT("EM_GETPASSWORDCHAR");
6680 case 0x00D3: return wxT("EM_SETMARGINS");
6681 case 0x00D4: return wxT("EM_GETMARGINS");
6682 case 0x00D5: return wxT("EM_GETLIMITTEXT");
6683 case 0x00D6: return wxT("EM_POSFROMCHAR");
6684 case 0x00D7: return wxT("EM_CHARFROMPOS");
6685 case 0x00D8: return wxT("EM_SETIMESTATUS");
6686 case 0x00D9: return wxT("EM_GETIMESTATUS");
6688 case 0x0100: return wxT("WM_KEYDOWN");
6689 case 0x0101: return wxT("WM_KEYUP");
6690 case 0x0102: return wxT("WM_CHAR");
6691 case 0x0103: return wxT("WM_DEADCHAR");
6692 case 0x0104: return wxT("WM_SYSKEYDOWN");
6693 case 0x0105: return wxT("WM_SYSKEYUP");
6694 case 0x0106: return wxT("WM_SYSCHAR");
6695 case 0x0107: return wxT("WM_SYSDEADCHAR");
6696 case 0x0108: return wxT("WM_KEYLAST");
6698 case 0x010D: return wxT("WM_IME_STARTCOMPOSITION");
6699 case 0x010E: return wxT("WM_IME_ENDCOMPOSITION");
6700 case 0x010F: return wxT("WM_IME_COMPOSITION");
6702 case 0x0110: return wxT("WM_INITDIALOG");
6703 case 0x0111: return wxT("WM_COMMAND");
6704 case 0x0112: return wxT("WM_SYSCOMMAND");
6705 case 0x0113: return wxT("WM_TIMER");
6706 case 0x0114: return wxT("WM_HSCROLL");
6707 case 0x0115: return wxT("WM_VSCROLL");
6708 case 0x0116: return wxT("WM_INITMENU");
6709 case 0x0117: return wxT("WM_INITMENUPOPUP");
6710 case 0x011F: return wxT("WM_MENUSELECT");
6711 case 0x0120: return wxT("WM_MENUCHAR");
6712 case 0x0121: return wxT("WM_ENTERIDLE");
6714 case 0x0127: return wxT("WM_CHANGEUISTATE");
6715 case 0x0128: return wxT("WM_UPDATEUISTATE");
6716 case 0x0129: return wxT("WM_QUERYUISTATE");
6718 case 0x0132: return wxT("WM_CTLCOLORMSGBOX");
6719 case 0x0133: return wxT("WM_CTLCOLOREDIT");
6720 case 0x0134: return wxT("WM_CTLCOLORLISTBOX");
6721 case 0x0135: return wxT("WM_CTLCOLORBTN");
6722 case 0x0136: return wxT("WM_CTLCOLORDLG");
6723 case 0x0137: return wxT("WM_CTLCOLORSCROLLBAR");
6724 case 0x0138: return wxT("WM_CTLCOLORSTATIC");
6725 case 0x01E1: return wxT("MN_GETHMENU");
6727 case 0x0200: return wxT("WM_MOUSEMOVE");
6728 case 0x0201: return wxT("WM_LBUTTONDOWN");
6729 case 0x0202: return wxT("WM_LBUTTONUP");
6730 case 0x0203: return wxT("WM_LBUTTONDBLCLK");
6731 case 0x0204: return wxT("WM_RBUTTONDOWN");
6732 case 0x0205: return wxT("WM_RBUTTONUP");
6733 case 0x0206: return wxT("WM_RBUTTONDBLCLK");
6734 case 0x0207: return wxT("WM_MBUTTONDOWN");
6735 case 0x0208: return wxT("WM_MBUTTONUP");
6736 case 0x0209: return wxT("WM_MBUTTONDBLCLK");
6737 case 0x020A: return wxT("WM_MOUSEWHEEL");
6738 case 0x020B: return wxT("WM_XBUTTONDOWN");
6739 case 0x020C: return wxT("WM_XBUTTONUP");
6740 case 0x020D: return wxT("WM_XBUTTONDBLCLK");
6741 case 0x0210: return wxT("WM_PARENTNOTIFY");
6742 case 0x0211: return wxT("WM_ENTERMENULOOP");
6743 case 0x0212: return wxT("WM_EXITMENULOOP");
6745 case 0x0213: return wxT("WM_NEXTMENU");
6746 case 0x0214: return wxT("WM_SIZING");
6747 case 0x0215: return wxT("WM_CAPTURECHANGED");
6748 case 0x0216: return wxT("WM_MOVING");
6749 case 0x0218: return wxT("WM_POWERBROADCAST");
6750 case 0x0219: return wxT("WM_DEVICECHANGE");
6752 case 0x0220: return wxT("WM_MDICREATE");
6753 case 0x0221: return wxT("WM_MDIDESTROY");
6754 case 0x0222: return wxT("WM_MDIACTIVATE");
6755 case 0x0223: return wxT("WM_MDIRESTORE");
6756 case 0x0224: return wxT("WM_MDINEXT");
6757 case 0x0225: return wxT("WM_MDIMAXIMIZE");
6758 case 0x0226: return wxT("WM_MDITILE");
6759 case 0x0227: return wxT("WM_MDICASCADE");
6760 case 0x0228: return wxT("WM_MDIICONARRANGE");
6761 case 0x0229: return wxT("WM_MDIGETACTIVE");
6762 case 0x0230: return wxT("WM_MDISETMENU");
6763 case 0x0233: return wxT("WM_DROPFILES");
6765 case 0x0281: return wxT("WM_IME_SETCONTEXT");
6766 case 0x0282: return wxT("WM_IME_NOTIFY");
6767 case 0x0283: return wxT("WM_IME_CONTROL");
6768 case 0x0284: return wxT("WM_IME_COMPOSITIONFULL");
6769 case 0x0285: return wxT("WM_IME_SELECT");
6770 case 0x0286: return wxT("WM_IME_CHAR");
6771 case 0x0290: return wxT("WM_IME_KEYDOWN");
6772 case 0x0291: return wxT("WM_IME_KEYUP");
6774 case 0x02A0: return wxT("WM_NCMOUSEHOVER");
6775 case 0x02A1: return wxT("WM_MOUSEHOVER");
6776 case 0x02A2: return wxT("WM_NCMOUSELEAVE");
6777 case 0x02A3: return wxT("WM_MOUSELEAVE");
6779 case 0x0300: return wxT("WM_CUT");
6780 case 0x0301: return wxT("WM_COPY");
6781 case 0x0302: return wxT("WM_PASTE");
6782 case 0x0303: return wxT("WM_CLEAR");
6783 case 0x0304: return wxT("WM_UNDO");
6784 case 0x0305: return wxT("WM_RENDERFORMAT");
6785 case 0x0306: return wxT("WM_RENDERALLFORMATS");
6786 case 0x0307: return wxT("WM_DESTROYCLIPBOARD");
6787 case 0x0308: return wxT("WM_DRAWCLIPBOARD");
6788 case 0x0309: return wxT("WM_PAINTCLIPBOARD");
6789 case 0x030A: return wxT("WM_VSCROLLCLIPBOARD");
6790 case 0x030B: return wxT("WM_SIZECLIPBOARD");
6791 case 0x030C: return wxT("WM_ASKCBFORMATNAME");
6792 case 0x030D: return wxT("WM_CHANGECBCHAIN");
6793 case 0x030E: return wxT("WM_HSCROLLCLIPBOARD");
6794 case 0x030F: return wxT("WM_QUERYNEWPALETTE");
6795 case 0x0310: return wxT("WM_PALETTEISCHANGING");
6796 case 0x0311: return wxT("WM_PALETTECHANGED");
6797 case 0x0312: return wxT("WM_HOTKEY");
6799 case 0x0317: return wxT("WM_PRINT");
6800 case 0x0318: return wxT("WM_PRINTCLIENT");
6802 // common controls messages - although they're not strictly speaking
6803 // standard, it's nice to decode them nevertheless
6806 case 0x1000 + 0: return wxT("LVM_GETBKCOLOR");
6807 case 0x1000 + 1: return wxT("LVM_SETBKCOLOR");
6808 case 0x1000 + 2: return wxT("LVM_GETIMAGELIST");
6809 case 0x1000 + 3: return wxT("LVM_SETIMAGELIST");
6810 case 0x1000 + 4: return wxT("LVM_GETITEMCOUNT");
6811 case 0x1000 + 5: return wxT("LVM_GETITEMA");
6812 case 0x1000 + 75: return wxT("LVM_GETITEMW");
6813 case 0x1000 + 6: return wxT("LVM_SETITEMA");
6814 case 0x1000 + 76: return wxT("LVM_SETITEMW");
6815 case 0x1000 + 7: return wxT("LVM_INSERTITEMA");
6816 case 0x1000 + 77: return wxT("LVM_INSERTITEMW");
6817 case 0x1000 + 8: return wxT("LVM_DELETEITEM");
6818 case 0x1000 + 9: return wxT("LVM_DELETEALLITEMS");
6819 case 0x1000 + 10: return wxT("LVM_GETCALLBACKMASK");
6820 case 0x1000 + 11: return wxT("LVM_SETCALLBACKMASK");
6821 case 0x1000 + 12: return wxT("LVM_GETNEXTITEM");
6822 case 0x1000 + 13: return wxT("LVM_FINDITEMA");
6823 case 0x1000 + 83: return wxT("LVM_FINDITEMW");
6824 case 0x1000 + 14: return wxT("LVM_GETITEMRECT");
6825 case 0x1000 + 15: return wxT("LVM_SETITEMPOSITION");
6826 case 0x1000 + 16: return wxT("LVM_GETITEMPOSITION");
6827 case 0x1000 + 17: return wxT("LVM_GETSTRINGWIDTHA");
6828 case 0x1000 + 87: return wxT("LVM_GETSTRINGWIDTHW");
6829 case 0x1000 + 18: return wxT("LVM_HITTEST");
6830 case 0x1000 + 19: return wxT("LVM_ENSUREVISIBLE");
6831 case 0x1000 + 20: return wxT("LVM_SCROLL");
6832 case 0x1000 + 21: return wxT("LVM_REDRAWITEMS");
6833 case 0x1000 + 22: return wxT("LVM_ARRANGE");
6834 case 0x1000 + 23: return wxT("LVM_EDITLABELA");
6835 case 0x1000 + 118: return wxT("LVM_EDITLABELW");
6836 case 0x1000 + 24: return wxT("LVM_GETEDITCONTROL");
6837 case 0x1000 + 25: return wxT("LVM_GETCOLUMNA");
6838 case 0x1000 + 95: return wxT("LVM_GETCOLUMNW");
6839 case 0x1000 + 26: return wxT("LVM_SETCOLUMNA");
6840 case 0x1000 + 96: return wxT("LVM_SETCOLUMNW");
6841 case 0x1000 + 27: return wxT("LVM_INSERTCOLUMNA");
6842 case 0x1000 + 97: return wxT("LVM_INSERTCOLUMNW");
6843 case 0x1000 + 28: return wxT("LVM_DELETECOLUMN");
6844 case 0x1000 + 29: return wxT("LVM_GETCOLUMNWIDTH");
6845 case 0x1000 + 30: return wxT("LVM_SETCOLUMNWIDTH");
6846 case 0x1000 + 31: return wxT("LVM_GETHEADER");
6847 case 0x1000 + 33: return wxT("LVM_CREATEDRAGIMAGE");
6848 case 0x1000 + 34: return wxT("LVM_GETVIEWRECT");
6849 case 0x1000 + 35: return wxT("LVM_GETTEXTCOLOR");
6850 case 0x1000 + 36: return wxT("LVM_SETTEXTCOLOR");
6851 case 0x1000 + 37: return wxT("LVM_GETTEXTBKCOLOR");
6852 case 0x1000 + 38: return wxT("LVM_SETTEXTBKCOLOR");
6853 case 0x1000 + 39: return wxT("LVM_GETTOPINDEX");
6854 case 0x1000 + 40: return wxT("LVM_GETCOUNTPERPAGE");
6855 case 0x1000 + 41: return wxT("LVM_GETORIGIN");
6856 case 0x1000 + 42: return wxT("LVM_UPDATE");
6857 case 0x1000 + 43: return wxT("LVM_SETITEMSTATE");
6858 case 0x1000 + 44: return wxT("LVM_GETITEMSTATE");
6859 case 0x1000 + 45: return wxT("LVM_GETITEMTEXTA");
6860 case 0x1000 + 115: return wxT("LVM_GETITEMTEXTW");
6861 case 0x1000 + 46: return wxT("LVM_SETITEMTEXTA");
6862 case 0x1000 + 116: return wxT("LVM_SETITEMTEXTW");
6863 case 0x1000 + 47: return wxT("LVM_SETITEMCOUNT");
6864 case 0x1000 + 48: return wxT("LVM_SORTITEMS");
6865 case 0x1000 + 49: return wxT("LVM_SETITEMPOSITION32");
6866 case 0x1000 + 50: return wxT("LVM_GETSELECTEDCOUNT");
6867 case 0x1000 + 51: return wxT("LVM_GETITEMSPACING");
6868 case 0x1000 + 52: return wxT("LVM_GETISEARCHSTRINGA");
6869 case 0x1000 + 117: return wxT("LVM_GETISEARCHSTRINGW");
6870 case 0x1000 + 53: return wxT("LVM_SETICONSPACING");
6871 case 0x1000 + 54: return wxT("LVM_SETEXTENDEDLISTVIEWSTYLE");
6872 case 0x1000 + 55: return wxT("LVM_GETEXTENDEDLISTVIEWSTYLE");
6873 case 0x1000 + 56: return wxT("LVM_GETSUBITEMRECT");
6874 case 0x1000 + 57: return wxT("LVM_SUBITEMHITTEST");
6875 case 0x1000 + 58: return wxT("LVM_SETCOLUMNORDERARRAY");
6876 case 0x1000 + 59: return wxT("LVM_GETCOLUMNORDERARRAY");
6877 case 0x1000 + 60: return wxT("LVM_SETHOTITEM");
6878 case 0x1000 + 61: return wxT("LVM_GETHOTITEM");
6879 case 0x1000 + 62: return wxT("LVM_SETHOTCURSOR");
6880 case 0x1000 + 63: return wxT("LVM_GETHOTCURSOR");
6881 case 0x1000 + 64: return wxT("LVM_APPROXIMATEVIEWRECT");
6882 case 0x1000 + 65: return wxT("LVM_SETWORKAREA");
6885 case 0x1100 + 0: return wxT("TVM_INSERTITEMA");
6886 case 0x1100 + 50: return wxT("TVM_INSERTITEMW");
6887 case 0x1100 + 1: return wxT("TVM_DELETEITEM");
6888 case 0x1100 + 2: return wxT("TVM_EXPAND");
6889 case 0x1100 + 4: return wxT("TVM_GETITEMRECT");
6890 case 0x1100 + 5: return wxT("TVM_GETCOUNT");
6891 case 0x1100 + 6: return wxT("TVM_GETINDENT");
6892 case 0x1100 + 7: return wxT("TVM_SETINDENT");
6893 case 0x1100 + 8: return wxT("TVM_GETIMAGELIST");
6894 case 0x1100 + 9: return wxT("TVM_SETIMAGELIST");
6895 case 0x1100 + 10: return wxT("TVM_GETNEXTITEM");
6896 case 0x1100 + 11: return wxT("TVM_SELECTITEM");
6897 case 0x1100 + 12: return wxT("TVM_GETITEMA");
6898 case 0x1100 + 62: return wxT("TVM_GETITEMW");
6899 case 0x1100 + 13: return wxT("TVM_SETITEMA");
6900 case 0x1100 + 63: return wxT("TVM_SETITEMW");
6901 case 0x1100 + 14: return wxT("TVM_EDITLABELA");
6902 case 0x1100 + 65: return wxT("TVM_EDITLABELW");
6903 case 0x1100 + 15: return wxT("TVM_GETEDITCONTROL");
6904 case 0x1100 + 16: return wxT("TVM_GETVISIBLECOUNT");
6905 case 0x1100 + 17: return wxT("TVM_HITTEST");
6906 case 0x1100 + 18: return wxT("TVM_CREATEDRAGIMAGE");
6907 case 0x1100 + 19: return wxT("TVM_SORTCHILDREN");
6908 case 0x1100 + 20: return wxT("TVM_ENSUREVISIBLE");
6909 case 0x1100 + 21: return wxT("TVM_SORTCHILDRENCB");
6910 case 0x1100 + 22: return wxT("TVM_ENDEDITLABELNOW");
6911 case 0x1100 + 23: return wxT("TVM_GETISEARCHSTRINGA");
6912 case 0x1100 + 64: return wxT("TVM_GETISEARCHSTRINGW");
6913 case 0x1100 + 24: return wxT("TVM_SETTOOLTIPS");
6914 case 0x1100 + 25: return wxT("TVM_GETTOOLTIPS");
6917 case 0x1200 + 0: return wxT("HDM_GETITEMCOUNT");
6918 case 0x1200 + 1: return wxT("HDM_INSERTITEMA");
6919 case 0x1200 + 10: return wxT("HDM_INSERTITEMW");
6920 case 0x1200 + 2: return wxT("HDM_DELETEITEM");
6921 case 0x1200 + 3: return wxT("HDM_GETITEMA");
6922 case 0x1200 + 11: return wxT("HDM_GETITEMW");
6923 case 0x1200 + 4: return wxT("HDM_SETITEMA");
6924 case 0x1200 + 12: return wxT("HDM_SETITEMW");
6925 case 0x1200 + 5: return wxT("HDM_LAYOUT");
6926 case 0x1200 + 6: return wxT("HDM_HITTEST");
6927 case 0x1200 + 7: return wxT("HDM_GETITEMRECT");
6928 case 0x1200 + 8: return wxT("HDM_SETIMAGELIST");
6929 case 0x1200 + 9: return wxT("HDM_GETIMAGELIST");
6930 case 0x1200 + 15: return wxT("HDM_ORDERTOINDEX");
6931 case 0x1200 + 16: return wxT("HDM_CREATEDRAGIMAGE");
6932 case 0x1200 + 17: return wxT("HDM_GETORDERARRAY");
6933 case 0x1200 + 18: return wxT("HDM_SETORDERARRAY");
6934 case 0x1200 + 19: return wxT("HDM_SETHOTDIVIDER");
6937 case 0x1300 + 2: return wxT("TCM_GETIMAGELIST");
6938 case 0x1300 + 3: return wxT("TCM_SETIMAGELIST");
6939 case 0x1300 + 4: return wxT("TCM_GETITEMCOUNT");
6940 case 0x1300 + 5: return wxT("TCM_GETITEMA");
6941 case 0x1300 + 60: return wxT("TCM_GETITEMW");
6942 case 0x1300 + 6: return wxT("TCM_SETITEMA");
6943 case 0x1300 + 61: return wxT("TCM_SETITEMW");
6944 case 0x1300 + 7: return wxT("TCM_INSERTITEMA");
6945 case 0x1300 + 62: return wxT("TCM_INSERTITEMW");
6946 case 0x1300 + 8: return wxT("TCM_DELETEITEM");
6947 case 0x1300 + 9: return wxT("TCM_DELETEALLITEMS");
6948 case 0x1300 + 10: return wxT("TCM_GETITEMRECT");
6949 case 0x1300 + 11: return wxT("TCM_GETCURSEL");
6950 case 0x1300 + 12: return wxT("TCM_SETCURSEL");
6951 case 0x1300 + 13: return wxT("TCM_HITTEST");
6952 case 0x1300 + 14: return wxT("TCM_SETITEMEXTRA");
6953 case 0x1300 + 40: return wxT("TCM_ADJUSTRECT");
6954 case 0x1300 + 41: return wxT("TCM_SETITEMSIZE");
6955 case 0x1300 + 42: return wxT("TCM_REMOVEIMAGE");
6956 case 0x1300 + 43: return wxT("TCM_SETPADDING");
6957 case 0x1300 + 44: return wxT("TCM_GETROWCOUNT");
6958 case 0x1300 + 45: return wxT("TCM_GETTOOLTIPS");
6959 case 0x1300 + 46: return wxT("TCM_SETTOOLTIPS");
6960 case 0x1300 + 47: return wxT("TCM_GETCURFOCUS");
6961 case 0x1300 + 48: return wxT("TCM_SETCURFOCUS");
6962 case 0x1300 + 49: return wxT("TCM_SETMINTABWIDTH");
6963 case 0x1300 + 50: return wxT("TCM_DESELECTALL");
6966 case WM_USER
+1: return wxT("TB_ENABLEBUTTON");
6967 case WM_USER
+2: return wxT("TB_CHECKBUTTON");
6968 case WM_USER
+3: return wxT("TB_PRESSBUTTON");
6969 case WM_USER
+4: return wxT("TB_HIDEBUTTON");
6970 case WM_USER
+5: return wxT("TB_INDETERMINATE");
6971 case WM_USER
+9: return wxT("TB_ISBUTTONENABLED");
6972 case WM_USER
+10: return wxT("TB_ISBUTTONCHECKED");
6973 case WM_USER
+11: return wxT("TB_ISBUTTONPRESSED");
6974 case WM_USER
+12: return wxT("TB_ISBUTTONHIDDEN");
6975 case WM_USER
+13: return wxT("TB_ISBUTTONINDETERMINATE");
6976 case WM_USER
+17: return wxT("TB_SETSTATE");
6977 case WM_USER
+18: return wxT("TB_GETSTATE");
6978 case WM_USER
+19: return wxT("TB_ADDBITMAP");
6979 case WM_USER
+20: return wxT("TB_ADDBUTTONS");
6980 case WM_USER
+21: return wxT("TB_INSERTBUTTON");
6981 case WM_USER
+22: return wxT("TB_DELETEBUTTON");
6982 case WM_USER
+23: return wxT("TB_GETBUTTON");
6983 case WM_USER
+24: return wxT("TB_BUTTONCOUNT");
6984 case WM_USER
+25: return wxT("TB_COMMANDTOINDEX");
6985 case WM_USER
+26: return wxT("TB_SAVERESTOREA");
6986 case WM_USER
+76: return wxT("TB_SAVERESTOREW");
6987 case WM_USER
+27: return wxT("TB_CUSTOMIZE");
6988 case WM_USER
+28: return wxT("TB_ADDSTRINGA");
6989 case WM_USER
+77: return wxT("TB_ADDSTRINGW");
6990 case WM_USER
+29: return wxT("TB_GETITEMRECT");
6991 case WM_USER
+30: return wxT("TB_BUTTONSTRUCTSIZE");
6992 case WM_USER
+31: return wxT("TB_SETBUTTONSIZE");
6993 case WM_USER
+32: return wxT("TB_SETBITMAPSIZE");
6994 case WM_USER
+33: return wxT("TB_AUTOSIZE");
6995 case WM_USER
+35: return wxT("TB_GETTOOLTIPS");
6996 case WM_USER
+36: return wxT("TB_SETTOOLTIPS");
6997 case WM_USER
+37: return wxT("TB_SETPARENT");
6998 case WM_USER
+39: return wxT("TB_SETROWS");
6999 case WM_USER
+40: return wxT("TB_GETROWS");
7000 case WM_USER
+42: return wxT("TB_SETCMDID");
7001 case WM_USER
+43: return wxT("TB_CHANGEBITMAP");
7002 case WM_USER
+44: return wxT("TB_GETBITMAP");
7003 case WM_USER
+45: return wxT("TB_GETBUTTONTEXTA");
7004 case WM_USER
+75: return wxT("TB_GETBUTTONTEXTW");
7005 case WM_USER
+46: return wxT("TB_REPLACEBITMAP");
7006 case WM_USER
+47: return wxT("TB_SETINDENT");
7007 case WM_USER
+48: return wxT("TB_SETIMAGELIST");
7008 case WM_USER
+49: return wxT("TB_GETIMAGELIST");
7009 case WM_USER
+50: return wxT("TB_LOADIMAGES");
7010 case WM_USER
+51: return wxT("TB_GETRECT");
7011 case WM_USER
+52: return wxT("TB_SETHOTIMAGELIST");
7012 case WM_USER
+53: return wxT("TB_GETHOTIMAGELIST");
7013 case WM_USER
+54: return wxT("TB_SETDISABLEDIMAGELIST");
7014 case WM_USER
+55: return wxT("TB_GETDISABLEDIMAGELIST");
7015 case WM_USER
+56: return wxT("TB_SETSTYLE");
7016 case WM_USER
+57: return wxT("TB_GETSTYLE");
7017 case WM_USER
+58: return wxT("TB_GETBUTTONSIZE");
7018 case WM_USER
+59: return wxT("TB_SETBUTTONWIDTH");
7019 case WM_USER
+60: return wxT("TB_SETMAXTEXTROWS");
7020 case WM_USER
+61: return wxT("TB_GETTEXTROWS");
7021 case WM_USER
+41: return wxT("TB_GETBITMAPFLAGS");
7024 static wxString s_szBuf
;
7025 s_szBuf
.Printf(wxT("<unknown message = %d>"), message
);
7026 return s_szBuf
.c_str();
7029 #endif // wxDEBUG_LEVEL >= 2
7031 static TEXTMETRIC
wxGetTextMetrics(const wxWindowMSW
*win
)
7035 HWND hwnd
= GetHwndOf(win
);
7036 HDC hdc
= ::GetDC(hwnd
);
7038 #if !wxDIALOG_UNIT_COMPATIBILITY
7039 // and select the current font into it
7040 HFONT hfont
= GetHfontOf(win
->GetFont());
7043 hfont
= (HFONT
)::SelectObject(hdc
, hfont
);
7047 // finally retrieve the text metrics from it
7048 GetTextMetrics(hdc
, &tm
);
7050 #if !wxDIALOG_UNIT_COMPATIBILITY
7054 (void)::SelectObject(hdc
, hfont
);
7058 ::ReleaseDC(hwnd
, hdc
);
7063 // Find the wxWindow at the current mouse position, returning the mouse
7065 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
7067 pt
= wxGetMousePosition();
7068 return wxFindWindowAtPoint(pt
);
7071 wxWindow
* wxFindWindowAtPoint(const wxPoint
& pt
)
7077 HWND hWnd
= ::WindowFromPoint(pt2
);
7079 return wxGetWindowFromHWND((WXHWND
)hWnd
);
7082 // Get the current mouse position.
7083 wxPoint
wxGetMousePosition()
7087 GetCursorPosWinCE(&pt
);
7089 GetCursorPos( & pt
);
7092 return wxPoint(pt
.x
, pt
.y
);
7097 #if defined(__SMARTPHONE__) || defined(__POCKETPC__)
7098 static void WinCEUnregisterHotKey(int modifiers
, int id
)
7100 // Register hotkeys for the hardware buttons
7102 typedef BOOL (WINAPI
*UnregisterFunc1Proc
)(UINT
, UINT
);
7104 UnregisterFunc1Proc procUnregisterFunc
;
7105 hCoreDll
= LoadLibrary(wxT("coredll.dll"));
7108 procUnregisterFunc
= (UnregisterFunc1Proc
)GetProcAddress(hCoreDll
, wxT("UnregisterFunc1"));
7109 if (procUnregisterFunc
)
7110 procUnregisterFunc(modifiers
, id
);
7111 FreeLibrary(hCoreDll
);
7116 bool wxWindowMSW::RegisterHotKey(int hotkeyId
, int modifiers
, int keycode
)
7118 UINT win_modifiers
=0;
7119 if ( modifiers
& wxMOD_ALT
)
7120 win_modifiers
|= MOD_ALT
;
7121 if ( modifiers
& wxMOD_SHIFT
)
7122 win_modifiers
|= MOD_SHIFT
;
7123 if ( modifiers
& wxMOD_CONTROL
)
7124 win_modifiers
|= MOD_CONTROL
;
7125 if ( modifiers
& wxMOD_WIN
)
7126 win_modifiers
|= MOD_WIN
;
7128 #if defined(__SMARTPHONE__) || defined(__POCKETPC__)
7129 // Required for PPC and Smartphone hardware buttons
7130 if (keycode
>= WXK_SPECIAL1
&& keycode
<= WXK_SPECIAL20
)
7131 WinCEUnregisterHotKey(win_modifiers
, hotkeyId
);
7134 if ( !::RegisterHotKey(GetHwnd(), hotkeyId
, win_modifiers
, keycode
) )
7136 wxLogLastError(wxT("RegisterHotKey"));
7144 bool wxWindowMSW::UnregisterHotKey(int hotkeyId
)
7146 #if defined(__SMARTPHONE__) || defined(__POCKETPC__)
7147 WinCEUnregisterHotKey(MOD_WIN
, hotkeyId
);
7150 if ( !::UnregisterHotKey(GetHwnd(), hotkeyId
) )
7152 wxLogLastError(wxT("UnregisterHotKey"));
7162 bool wxWindowMSW::HandleHotKey(WXWPARAM wParam
, WXLPARAM lParam
)
7164 int win_modifiers
= LOWORD(lParam
);
7166 wxKeyEvent
event(CreateKeyEvent(wxEVT_HOTKEY
, HIWORD(lParam
)));
7167 event
.SetId(wParam
);
7168 event
.m_shiftDown
= (win_modifiers
& MOD_SHIFT
) != 0;
7169 event
.m_controlDown
= (win_modifiers
& MOD_CONTROL
) != 0;
7170 event
.m_altDown
= (win_modifiers
& MOD_ALT
) != 0;
7171 event
.m_metaDown
= (win_modifiers
& MOD_WIN
) != 0;
7173 return HandleWindowEvent(event
);
7176 #endif // wxUSE_ACCEL
7178 #endif // wxUSE_HOTKEY
7180 // Not tested under WinCE
7183 // this class installs a message hook which really wakes up our idle processing
7184 // each time a WM_NULL is received (wxWakeUpIdle does this), even if we're
7185 // sitting inside a local modal loop (e.g. a menu is opened or scrollbar is
7186 // being dragged or even inside ::MessageBox()) and so don't control message
7187 // dispatching otherwise
7188 class wxIdleWakeUpModule
: public wxModule
7191 virtual bool OnInit()
7193 ms_hMsgHookProc
= ::SetWindowsHookEx
7196 &wxIdleWakeUpModule::MsgHookProc
,
7198 GetCurrentThreadId()
7201 if ( !ms_hMsgHookProc
)
7203 wxLogLastError(wxT("SetWindowsHookEx(WH_GETMESSAGE)"));
7211 virtual void OnExit()
7213 ::UnhookWindowsHookEx(wxIdleWakeUpModule::ms_hMsgHookProc
);
7216 static LRESULT CALLBACK
MsgHookProc(int nCode
, WPARAM wParam
, LPARAM lParam
)
7218 MSG
*msg
= (MSG
*)lParam
;
7220 // only process the message if it is actually going to be removed from
7221 // the message queue, this prevents that the same event from being
7222 // processed multiple times if now someone just called PeekMessage()
7223 if ( msg
->message
== WM_NULL
&& wParam
== PM_REMOVE
)
7225 wxTheApp
->ProcessPendingEvents();
7228 return CallNextHookEx(ms_hMsgHookProc
, nCode
, wParam
, lParam
);
7232 static HHOOK ms_hMsgHookProc
;
7234 DECLARE_DYNAMIC_CLASS(wxIdleWakeUpModule
)
7237 HHOOK
wxIdleWakeUpModule::ms_hMsgHookProc
= 0;
7239 IMPLEMENT_DYNAMIC_CLASS(wxIdleWakeUpModule
, wxModule
)
7241 #endif // __WXWINCE__
7246 static void wxAdjustZOrder(wxWindow
* parent
)
7248 if (parent
->IsKindOf(CLASSINFO(wxStaticBox
)))
7250 // Set the z-order correctly
7251 SetWindowPos((HWND
) parent
->GetHWND(), HWND_BOTTOM
, 0, 0, 0, 0, SWP_NOMOVE
|SWP_NOSIZE
);
7254 wxWindowList::compatibility_iterator current
= parent
->GetChildren().GetFirst();
7257 wxWindow
*childWin
= current
->GetData();
7258 wxAdjustZOrder(childWin
);
7259 current
= current
->GetNext();
7264 // We need to adjust the z-order of static boxes in WinCE, to
7265 // make 'contained' controls visible
7266 void wxWindowMSW::OnInitDialog( wxInitDialogEvent
& event
)
7269 wxAdjustZOrder(this);