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/dcclient.h"
85 #include "wx/tooltip.h"
93 #include "wx/spinctrl.h"
94 #endif // wxUSE_SPINCTRL
96 #include "wx/notebook.h"
97 #include "wx/listctrl.h"
98 #include "wx/dynlib.h"
102 #if (!defined(__GNUWIN32_OLD__) && !defined(__WXMICROWIN__) /* && !defined(__WXWINCE__) */ ) || defined(__CYGWIN10__)
103 #include <shellapi.h>
104 #include <mmsystem.h>
108 #include <windowsx.h>
111 #if !defined __WXWINCE__ && !defined NEED_PBT_H
115 #if defined(__WXWINCE__)
116 #include "wx/msw/wince/missing.h"
119 #include <shellapi.h>
121 #include <aygshell.h>
126 #include "wx/msw/uxtheme.h"
127 #define EP_EDITTEXT 1
130 #define ETS_SELECTED 3
131 #define ETS_DISABLED 4
132 #define ETS_FOCUSED 5
133 #define ETS_READONLY 6
137 // define the constants used by AnimateWindow() if our SDK doesn't have them
139 #define AW_HOR_POSITIVE 0x00000001
140 #define AW_HOR_NEGATIVE 0x00000002
141 #define AW_VER_POSITIVE 0x00000004
142 #define AW_VER_NEGATIVE 0x00000008
143 #define AW_CENTER 0x00000010
144 #define AW_HIDE 0x00010000
145 #define AW_ACTIVATE 0x00020000
146 #define AW_SLIDE 0x00040000
147 #define AW_BLEND 0x00080000
150 #if defined(TME_LEAVE) && defined(WM_MOUSELEAVE) && wxUSE_DYNLIB_CLASS
151 #define HAVE_TRACKMOUSEEVENT
152 #endif // everything needed for TrackMouseEvent()
154 // if this is set to 1, we use deferred window sizing to reduce flicker when
155 // resizing complicated window hierarchies, but this can in theory result in
156 // different behaviour than the old code so we keep the possibility to use it
157 // by setting this to 0 (in the future this should be removed completely)
159 #define USE_DEFERRED_SIZING 0
161 #define USE_DEFERRED_SIZING 1
164 // set this to 1 to filter out duplicate mouse events, e.g. mouse move events
165 // when mouse position didnd't change
167 #define wxUSE_MOUSEEVENT_HACK 0
169 #define wxUSE_MOUSEEVENT_HACK 1
172 // not all compilers/platforms have X button related declarations (notably
173 // Windows CE doesn't, and probably some old SDKs don't neither)
174 #ifdef WM_XBUTTONDOWN
175 #define wxHAS_XBUTTON
178 // ---------------------------------------------------------------------------
180 // ---------------------------------------------------------------------------
182 #if wxUSE_MENUS_NATIVE
183 extern wxMenu
*wxCurrentPopupMenu
;
186 // true if we had already created the std colour map, used by
187 // wxGetStdColourMap() and wxWindow::OnSysColourChanged() (FIXME-MT)
188 static bool gs_hasStdCmap
= false;
190 // last mouse event information we need to filter out the duplicates
191 #if wxUSE_MOUSEEVENT_HACK
192 static struct MouseEventInfoDummy
194 // mouse position (in screen coordinates)
197 // last mouse event type
200 #endif // wxUSE_MOUSEEVENT_HACK
202 // hash containing the registered handlers for the custom messages
203 WX_DECLARE_HASH_MAP(int, wxWindow::MSWMessageHandler
,
204 wxIntegerHash
, wxIntegerEqual
,
207 static MSWMessageHandlers gs_messageHandlers
;
209 // hash containing all our windows, it uses HWND keys and wxWindow* values
210 WX_DECLARE_HASH_MAP(HWND
, wxWindow
*,
211 wxPointerHash
, wxPointerEqual
,
214 static WindowHandles gs_windowHandles
;
216 // ---------------------------------------------------------------------------
218 // ---------------------------------------------------------------------------
220 // the window proc for all our windows
221 LRESULT WXDLLEXPORT APIENTRY _EXPORT
wxWndProc(HWND hWnd
, UINT message
,
222 WPARAM wParam
, LPARAM lParam
);
226 const wxChar
*wxGetMessageName(int message
);
229 void wxRemoveHandleAssociation(wxWindowMSW
*win
);
230 extern void wxAssociateWinWithHandle(HWND hWnd
, wxWindowMSW
*win
);
232 // get the text metrics for the current font
233 static TEXTMETRIC
wxGetTextMetrics(const wxWindowMSW
*win
);
236 // find the window for the mouse event at the specified position
237 static wxWindowMSW
*FindWindowForMouseEvent(wxWindowMSW
*win
, int *x
, int *y
);
238 #endif // __WXWINCE__
240 // wrapper around BringWindowToTop() API
241 static inline void wxBringWindowToTop(HWND hwnd
)
243 #ifdef __WXMICROWIN__
244 // It seems that MicroWindows brings the _parent_ of the window to the top,
245 // which can be the wrong one.
247 // activate (set focus to) specified window
251 // raise top level parent to top of z order
252 if (!::SetWindowPos(hwnd
, HWND_TOP
, 0, 0, 0, 0, SWP_NOMOVE
| SWP_NOSIZE
))
254 wxLogLastError(_T("SetWindowPos"));
260 // ensure that all our parent windows have WS_EX_CONTROLPARENT style
261 static void EnsureParentHasControlParentStyle(wxWindow
*parent
)
264 If we have WS_EX_CONTROLPARENT flag we absolutely *must* set it for our
265 parent as well as otherwise several Win32 functions using
266 GetNextDlgTabItem() to iterate over all controls such as
267 IsDialogMessage() or DefDlgProc() would enter an infinite loop: indeed,
268 all of them iterate over all the controls starting from the currently
269 focused one and stop iterating when they get back to the focus but
270 unless all parents have WS_EX_CONTROLPARENT bit set, they would never
271 get back to the initial (focused) window: as we do have this style,
272 GetNextDlgTabItem() will leave this window and continue in its parent,
273 but if the parent doesn't have it, it wouldn't recurse inside it later
274 on and so wouldn't have a chance of getting back to this window either.
276 while ( parent
&& !parent
->IsTopLevel() )
278 LONG exStyle
= wxGetWindowExStyle(parent
);
279 if ( !(exStyle
& WS_EX_CONTROLPARENT
) )
281 // force the parent to have this style
282 wxSetWindowExStyle(parent
, exStyle
| WS_EX_CONTROLPARENT
);
285 parent
= parent
->GetParent();
289 #endif // !__WXWINCE__
292 // On Windows CE, GetCursorPos can return an error, so use this function
294 bool GetCursorPosWinCE(POINT
* pt
)
296 if (!GetCursorPos(pt
))
298 DWORD pos
= GetMessagePos();
306 // ---------------------------------------------------------------------------
308 // ---------------------------------------------------------------------------
310 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
312 #ifdef __WXUNIVERSAL__
313 IMPLEMENT_ABSTRACT_CLASS(wxWindowMSW
, wxWindowBase
)
315 #if wxUSE_EXTENDED_RTTI
317 // windows that are created from a parent window during its Create method, eg. spin controls in a calendar controls
318 // must never been streamed out separately otherwise chaos occurs. Right now easiest is to test for negative ids, as
319 // windows with negative ids never can be recreated anyway
321 bool wxWindowStreamingCallback( const wxObject
*object
, wxWriter
* , wxPersister
* , wxxVariantArray
& )
323 const wxWindow
* win
= dynamic_cast<const wxWindow
*>(object
) ;
324 if ( win
&& win
->GetId() < 0 )
329 IMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxWindow
, wxWindowBase
,"wx/window.h", wxWindowStreamingCallback
)
331 // make wxWindowList known before the property is used
333 wxCOLLECTION_TYPE_INFO( wxWindow
* , wxWindowList
) ;
335 template<> void wxCollectionToVariantArray( wxWindowList
const &theList
, wxxVariantArray
&value
)
337 wxListCollectionToVariantArray
<wxWindowList::compatibility_iterator
>( theList
, value
) ;
340 WX_DEFINE_FLAGS( wxWindowStyle
)
342 wxBEGIN_FLAGS( wxWindowStyle
)
343 // new style border flags, we put them first to
344 // use them for streaming out
346 wxFLAGS_MEMBER(wxBORDER_SIMPLE
)
347 wxFLAGS_MEMBER(wxBORDER_SUNKEN
)
348 wxFLAGS_MEMBER(wxBORDER_DOUBLE
)
349 wxFLAGS_MEMBER(wxBORDER_RAISED
)
350 wxFLAGS_MEMBER(wxBORDER_STATIC
)
351 wxFLAGS_MEMBER(wxBORDER_NONE
)
353 // old style border flags
354 wxFLAGS_MEMBER(wxSIMPLE_BORDER
)
355 wxFLAGS_MEMBER(wxSUNKEN_BORDER
)
356 wxFLAGS_MEMBER(wxDOUBLE_BORDER
)
357 wxFLAGS_MEMBER(wxRAISED_BORDER
)
358 wxFLAGS_MEMBER(wxSTATIC_BORDER
)
359 wxFLAGS_MEMBER(wxBORDER
)
361 // standard window styles
362 wxFLAGS_MEMBER(wxTAB_TRAVERSAL
)
363 wxFLAGS_MEMBER(wxCLIP_CHILDREN
)
364 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
)
365 wxFLAGS_MEMBER(wxWANTS_CHARS
)
366 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
)
367 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB
)
368 wxFLAGS_MEMBER(wxVSCROLL
)
369 wxFLAGS_MEMBER(wxHSCROLL
)
371 wxEND_FLAGS( wxWindowStyle
)
373 wxBEGIN_PROPERTIES_TABLE(wxWindow
)
374 wxEVENT_PROPERTY( Close
, wxEVT_CLOSE_WINDOW
, wxCloseEvent
)
375 wxEVENT_PROPERTY( Create
, wxEVT_CREATE
, wxWindowCreateEvent
)
376 wxEVENT_PROPERTY( Destroy
, wxEVT_DESTROY
, wxWindowDestroyEvent
)
377 // Always constructor Properties first
379 wxREADONLY_PROPERTY( Parent
,wxWindow
*, GetParent
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
380 wxPROPERTY( Id
,wxWindowID
, SetId
, GetId
, -1 /*wxID_ANY*/ , 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
381 wxPROPERTY( Position
,wxPoint
, SetPosition
, GetPosition
, wxDefaultPosition
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // pos
382 wxPROPERTY( Size
,wxSize
, SetSize
, GetSize
, wxDefaultSize
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // size
383 wxPROPERTY( WindowStyle
, long , SetWindowStyleFlag
, GetWindowStyleFlag
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
385 // Then all relations of the object graph
387 wxREADONLY_PROPERTY_COLLECTION( Children
, wxWindowList
, wxWindowBase
* , GetWindowChildren
, wxPROP_OBJECT_GRAPH
/*flags*/ , wxT("Helpstring") , wxT("group"))
389 // and finally all other properties
391 wxPROPERTY( ExtraStyle
, long , SetExtraStyle
, GetExtraStyle
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // extstyle
392 wxPROPERTY( BackgroundColour
, wxColour
, SetBackgroundColour
, GetBackgroundColour
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // bg
393 wxPROPERTY( ForegroundColour
, wxColour
, SetForegroundColour
, GetForegroundColour
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // fg
394 wxPROPERTY( Enabled
, bool , Enable
, IsEnabled
, wxxVariant((bool)true) , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
395 wxPROPERTY( Shown
, bool , Show
, IsShown
, wxxVariant((bool)true) , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
397 // possible property candidates (not in xrc) or not valid in all subclasses
398 wxPROPERTY( Title
,wxString
, SetTitle
, GetTitle
, wxEmptyString
)
399 wxPROPERTY( Font
, wxFont
, SetFont
, GetWindowFont
, )
400 wxPROPERTY( Label
,wxString
, SetLabel
, GetLabel
, wxEmptyString
)
401 // MaxHeight, Width , MinHeight , Width
402 // TODO switch label to control and title to toplevels
404 wxPROPERTY( ThemeEnabled
, bool , SetThemeEnabled
, GetThemeEnabled
, )
405 //wxPROPERTY( Cursor , wxCursor , SetCursor , GetCursor , )
406 // wxPROPERTY( ToolTip , wxString , SetToolTip , GetToolTipText , )
407 wxPROPERTY( AutoLayout
, bool , SetAutoLayout
, GetAutoLayout
, )
412 wxEND_PROPERTIES_TABLE()
414 wxBEGIN_HANDLERS_TABLE(wxWindow
)
415 wxEND_HANDLERS_TABLE()
417 wxCONSTRUCTOR_DUMMY(wxWindow
)
420 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
422 #endif // __WXUNIVERSAL__/__WXMSW__
424 BEGIN_EVENT_TABLE(wxWindowMSW
, wxWindowBase
)
425 EVT_SYS_COLOUR_CHANGED(wxWindowMSW::OnSysColourChanged
)
426 EVT_ERASE_BACKGROUND(wxWindowMSW::OnEraseBackground
)
428 EVT_INIT_DIALOG(wxWindowMSW::OnInitDialog
)
432 // ===========================================================================
434 // ===========================================================================
436 // ---------------------------------------------------------------------------
437 // wxWindow utility functions
438 // ---------------------------------------------------------------------------
440 // Find an item given the MS Windows id
441 wxWindow
*wxWindowMSW::FindItem(long id
) const
444 wxControl
*item
= wxDynamicCastThis(wxControl
);
447 // is it us or one of our "internal" children?
448 if ( item
->GetId() == id
449 #ifndef __WXUNIVERSAL__
450 || (item
->GetSubcontrols().Index(id
) != wxNOT_FOUND
)
451 #endif // __WXUNIVERSAL__
457 #endif // wxUSE_CONTROLS
459 wxWindowList::compatibility_iterator current
= GetChildren().GetFirst();
462 wxWindow
*childWin
= current
->GetData();
464 wxWindow
*wnd
= childWin
->FindItem(id
);
468 current
= current
->GetNext();
474 // Find an item given the MS Windows handle
475 wxWindow
*wxWindowMSW::FindItemByHWND(WXHWND hWnd
, bool controlOnly
) const
477 wxWindowList::compatibility_iterator current
= GetChildren().GetFirst();
480 wxWindow
*parent
= current
->GetData();
482 // Do a recursive search.
483 wxWindow
*wnd
= parent
->FindItemByHWND(hWnd
);
489 || parent
->IsKindOf(CLASSINFO(wxControl
))
490 #endif // wxUSE_CONTROLS
493 wxWindow
*item
= current
->GetData();
494 if ( item
->GetHWND() == hWnd
)
498 if ( item
->ContainsHWND(hWnd
) )
503 current
= current
->GetNext();
508 // Default command handler
509 bool wxWindowMSW::MSWCommand(WXUINT
WXUNUSED(param
), WXWORD
WXUNUSED(id
))
514 // ----------------------------------------------------------------------------
515 // constructors and such
516 // ----------------------------------------------------------------------------
518 void wxWindowMSW::Init()
522 m_mouseInWindow
= false;
523 m_lastKeydownProcessed
= false;
531 m_pendingPosition
= wxDefaultPosition
;
532 m_pendingSize
= wxDefaultSize
;
535 m_contextMenuEnabled
= false;
540 wxWindowMSW::~wxWindowMSW()
544 #ifndef __WXUNIVERSAL__
545 // VS: make sure there's no wxFrame with last focus set to us:
546 for ( wxWindow
*win
= GetParent(); win
; win
= win
->GetParent() )
548 wxTopLevelWindow
*frame
= wxDynamicCast(win
, wxTopLevelWindow
);
551 if ( frame
->GetLastFocus() == this )
553 frame
->SetLastFocus(NULL
);
556 // apparently sometimes we can end up with our grand parent
557 // pointing to us as well: this is surely a bug in focus handling
558 // code but it's not clear where it happens so for now just try to
559 // fix it here by not breaking out of the loop
563 #endif // __WXUNIVERSAL__
565 // VS: destroy children first and _then_ detach *this from its parent.
566 // If we did it the other way around, children wouldn't be able
567 // find their parent frame (see above).
572 // VZ: test temp removed to understand what really happens here
573 //if (::IsWindow(GetHwnd()))
575 if ( !::DestroyWindow(GetHwnd()) )
576 wxLogLastError(wxT("DestroyWindow"));
579 // remove hWnd <-> wxWindow association
580 wxRemoveHandleAssociation(this);
586 const wxChar
*wxWindowMSW::MSWGetRegisteredClassName()
588 return wxApp::GetRegisteredClassName(_T("wxWindow"), COLOR_BTNFACE
);
591 // real construction (Init() must have been called before!)
592 bool wxWindowMSW::Create(wxWindow
*parent
,
597 const wxString
& name
)
599 wxCHECK_MSG( parent
, false, wxT("can't create wxWindow without parent") );
601 if ( !CreateBase(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
) )
604 parent
->AddChild(this);
607 DWORD msflags
= MSWGetCreateWindowFlags(&exstyle
);
609 #ifdef __WXUNIVERSAL__
610 // no borders, we draw them ourselves
611 exstyle
&= ~(WS_EX_DLGMODALFRAME
|
615 msflags
&= ~WS_BORDER
;
616 #endif // wxUniversal
620 msflags
|= WS_VISIBLE
;
623 if ( !MSWCreate(MSWGetRegisteredClassName(),
624 NULL
, pos
, size
, msflags
, exstyle
) )
632 // ---------------------------------------------------------------------------
634 // ---------------------------------------------------------------------------
636 void wxWindowMSW::SetFocus()
638 HWND hWnd
= GetHwnd();
639 wxCHECK_RET( hWnd
, _T("can't set focus to invalid window") );
641 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
645 if ( !::SetFocus(hWnd
) )
647 #if defined(__WXDEBUG__) && !defined(__WXMICROWIN__)
648 // was there really an error?
649 DWORD dwRes
= ::GetLastError();
652 HWND hwndFocus
= ::GetFocus();
653 if ( hwndFocus
!= hWnd
)
655 wxLogApiError(_T("SetFocus"), dwRes
);
662 void wxWindowMSW::SetFocusFromKbd()
664 // when the focus is given to the control with DLGC_HASSETSEL style from
665 // keyboard its contents should be entirely selected: this is what
666 // ::IsDialogMessage() does and so we should do it as well to provide the
667 // same LNF as the native programs
668 if ( ::SendMessage(GetHwnd(), WM_GETDLGCODE
, 0, 0) & DLGC_HASSETSEL
)
670 ::SendMessage(GetHwnd(), EM_SETSEL
, 0, -1);
673 // do this after (maybe) setting the selection as like this when
674 // wxEVT_SET_FOCUS handler is called, the selection would have been already
675 // set correctly -- this may be important
676 wxWindowBase::SetFocusFromKbd();
679 // Get the window with the focus
680 wxWindow
*wxWindowBase::DoFindFocus()
682 HWND hWnd
= ::GetFocus();
685 return wxGetWindowFromHWND((WXHWND
)hWnd
);
691 void wxWindowMSW::DoEnable( bool enable
)
693 HWND hWnd
= GetHwnd();
695 ::EnableWindow(hWnd
, (BOOL
)enable
);
698 bool wxWindowMSW::Show(bool show
)
700 if ( !wxWindowBase::Show(show
) )
703 HWND hWnd
= GetHwnd();
705 // we could be called before the underlying window is created (this is
706 // actually useful to prevent it from being initially shown), e.g.
708 // wxFoo *foo = new wxFoo;
710 // foo->Create(parent, ...);
712 // should work without errors
715 ::ShowWindow(hWnd
, show
? SW_SHOW
: SW_HIDE
);
720 // DoFreeze/DoThaw don't do anything if the window is not shown, so
721 // we have to call them from here now
732 wxWindowMSW::MSWShowWithEffect(bool show
,
736 if ( !wxWindowBase::Show(show
) )
739 typedef BOOL (WINAPI
*AnimateWindow_t
)(HWND
, DWORD
, DWORD
);
741 static AnimateWindow_t s_pfnAnimateWindow
= NULL
;
742 static bool s_initDone
= false;
745 wxDynamicLibrary
dllUser32(_T("user32.dll"), wxDL_VERBATIM
| wxDL_QUIET
);
746 wxDL_INIT_FUNC(s_pfn
, AnimateWindow
, dllUser32
);
750 // notice that it's ok to unload user32.dll here as it won't be really
751 // unloaded, being still in use because we link to it statically too
754 if ( !s_pfnAnimateWindow
)
757 // Show() has a side effect of sending a WM_SIZE to the window, which helps
758 // ensuring that it's laid out correctly, but AnimateWindow() doesn't do
759 // this so send the event ourselves
762 // prepare to use AnimateWindow()
765 timeout
= 200; // this is the default animation timeout, per MSDN
767 DWORD dwFlags
= show
? 0 : AW_HIDE
;
771 case wxSHOW_EFFECT_ROLL_TO_LEFT
:
772 dwFlags
|= AW_HOR_NEGATIVE
;
775 case wxSHOW_EFFECT_ROLL_TO_RIGHT
:
776 dwFlags
|= AW_HOR_POSITIVE
;
779 case wxSHOW_EFFECT_ROLL_TO_TOP
:
780 dwFlags
|= AW_VER_NEGATIVE
;
783 case wxSHOW_EFFECT_ROLL_TO_BOTTOM
:
784 dwFlags
|= AW_VER_POSITIVE
;
787 case wxSHOW_EFFECT_SLIDE_TO_LEFT
:
788 dwFlags
|= AW_SLIDE
| AW_HOR_NEGATIVE
;
791 case wxSHOW_EFFECT_SLIDE_TO_RIGHT
:
792 dwFlags
|= AW_SLIDE
| AW_HOR_POSITIVE
;
795 case wxSHOW_EFFECT_SLIDE_TO_TOP
:
796 dwFlags
|= AW_SLIDE
| AW_VER_NEGATIVE
;
799 case wxSHOW_EFFECT_SLIDE_TO_BOTTOM
:
800 dwFlags
|= AW_SLIDE
| AW_VER_POSITIVE
;
803 case wxSHOW_EFFECT_BLEND
:
807 case wxSHOW_EFFECT_EXPAND
:
808 dwFlags
|= AW_CENTER
;
812 case wxSHOW_EFFECT_MAX
:
813 wxFAIL_MSG( _T("invalid window show effect") );
817 wxFAIL_MSG( _T("unknown window show effect") );
821 if ( !(*s_pfnAnimateWindow
)(GetHwnd(), timeout
, dwFlags
) )
823 wxLogLastError(_T("AnimateWindow"));
831 // Raise the window to the top of the Z order
832 void wxWindowMSW::Raise()
834 wxBringWindowToTop(GetHwnd());
837 // Lower the window to the bottom of the Z order
838 void wxWindowMSW::Lower()
840 ::SetWindowPos(GetHwnd(), HWND_BOTTOM
, 0, 0, 0, 0,
841 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
844 void wxWindowMSW::DoCaptureMouse()
846 HWND hWnd
= GetHwnd();
853 void wxWindowMSW::DoReleaseMouse()
855 if ( !::ReleaseCapture() )
857 wxLogLastError(_T("ReleaseCapture"));
861 /* static */ wxWindow
*wxWindowBase::GetCapture()
863 HWND hwnd
= ::GetCapture();
864 return hwnd
? wxFindWinFromHandle(hwnd
) : NULL
;
867 bool wxWindowMSW::SetFont(const wxFont
& font
)
869 if ( !wxWindowBase::SetFont(font
) )
875 HWND hWnd
= GetHwnd();
878 // note the use of GetFont() instead of m_font: our own font could have
879 // just been reset and in this case we need to change the font used by
880 // the native window to the default for this class, i.e. exactly what
882 WXHANDLE hFont
= GetFont().GetResourceHandle();
884 wxASSERT_MSG( hFont
, wxT("should have valid font") );
886 ::SendMessage(hWnd
, WM_SETFONT
, (WPARAM
)hFont
, MAKELPARAM(TRUE
, 0));
891 bool wxWindowMSW::SetCursor(const wxCursor
& cursor
)
893 if ( !wxWindowBase::SetCursor(cursor
) )
899 // don't "overwrite" busy cursor
900 if ( m_cursor
.Ok() && !wxIsBusy() )
902 // normally we should change the cursor only if it's over this window
903 // but we should do it always if we capture the mouse currently
904 bool set
= HasCapture();
907 HWND hWnd
= GetHwnd();
911 ::GetCursorPosWinCE(&point
);
913 ::GetCursorPos(&point
);
916 RECT rect
= wxGetWindowRect(hWnd
);
918 set
= ::PtInRect(&rect
, point
) != 0;
923 ::SetCursor(GetHcursorOf(m_cursor
));
925 //else: will be set later when the mouse enters this window
931 void wxWindowMSW::WarpPointer(int x
, int y
)
933 ClientToScreen(&x
, &y
);
935 if ( !::SetCursorPos(x
, y
) )
937 wxLogLastError(_T("SetCursorPos"));
941 void wxWindowMSW::MSWUpdateUIState(int action
, int state
)
943 // WM_CHANGEUISTATE only appeared in Windows 2000 so it can do us no good
944 // to use it on older systems -- and could possibly do some harm
945 static int s_needToUpdate
= -1;
946 if ( s_needToUpdate
== -1 )
949 s_needToUpdate
= wxGetOsVersion(&verMaj
, &verMin
) == wxOS_WINDOWS_NT
&&
953 if ( s_needToUpdate
)
955 // we send WM_CHANGEUISTATE so if nothing needs changing then the system
956 // won't send WM_UPDATEUISTATE
957 ::SendMessage(GetHwnd(), WM_CHANGEUISTATE
, MAKEWPARAM(action
, state
), 0);
961 // ---------------------------------------------------------------------------
963 // ---------------------------------------------------------------------------
968 inline int GetScrollPosition(HWND hWnd
, int wOrient
)
970 #ifdef __WXMICROWIN__
971 return ::GetScrollPosWX(hWnd
, wOrient
);
973 WinStruct
<SCROLLINFO
> scrollInfo
;
974 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
975 scrollInfo
.fMask
= SIF_POS
;
976 ::GetScrollInfo(hWnd
, wOrient
, &scrollInfo
);
978 return scrollInfo
.nPos
;
983 inline UINT
WXOrientToSB(int orient
)
985 return orient
== wxHORIZONTAL
? SB_HORZ
: SB_VERT
;
988 } // anonymous namespace
990 int wxWindowMSW::GetScrollPos(int orient
) const
992 HWND hWnd
= GetHwnd();
993 wxCHECK_MSG( hWnd
, 0, _T("no HWND in GetScrollPos") );
995 return GetScrollPosition(hWnd
, WXOrientToSB(orient
));
998 // This now returns the whole range, not just the number
999 // of positions that we can scroll.
1000 int wxWindowMSW::GetScrollRange(int orient
) const
1003 HWND hWnd
= GetHwnd();
1006 WinStruct
<SCROLLINFO
> scrollInfo
;
1007 scrollInfo
.fMask
= SIF_RANGE
;
1008 if ( !::GetScrollInfo(hWnd
, WXOrientToSB(orient
), &scrollInfo
) )
1010 // Most of the time this is not really an error, since the return
1011 // value can also be zero when there is no scrollbar yet.
1012 // wxLogLastError(_T("GetScrollInfo"));
1014 maxPos
= scrollInfo
.nMax
;
1016 // undo "range - 1" done in SetScrollbar()
1020 int wxWindowMSW::GetScrollThumb(int orient
) const
1022 return orient
== wxHORIZONTAL
? m_xThumbSize
: m_yThumbSize
;
1025 void wxWindowMSW::SetScrollPos(int orient
, int pos
, bool refresh
)
1027 HWND hWnd
= GetHwnd();
1028 wxCHECK_RET( hWnd
, _T("SetScrollPos: no HWND") );
1030 WinStruct
<SCROLLINFO
> info
;
1034 info
.fMask
= SIF_POS
;
1035 if ( HasFlag(wxALWAYS_SHOW_SB
) )
1037 // disable scrollbar instead of removing it then
1038 info
.fMask
|= SIF_DISABLENOSCROLL
;
1041 ::SetScrollInfo(hWnd
, WXOrientToSB(orient
), &info
, refresh
);
1044 // New function that will replace some of the above.
1045 void wxWindowMSW::SetScrollbar(int orient
,
1051 // We have to set the variables here to make them valid in events
1052 // triggered by ::SetScrollInfo()
1053 *(orient
== wxHORIZONTAL
? &m_xThumbSize
: &m_yThumbSize
) = pageSize
;
1055 HWND hwnd
= GetHwnd();
1059 WinStruct
<SCROLLINFO
> info
;
1062 info
.nPage
= pageSize
;
1063 info
.nMin
= 0; // range is nMax - nMin + 1
1064 info
.nMax
= range
- 1; // as both nMax and nMax are inclusive
1067 // enable the scrollbar if it had been disabled before by specifying
1068 // SIF_DISABLENOSCROLL below: as we can't know whether this had been
1069 // done or not just do it always
1070 ::EnableScrollBar(hwnd
, WXOrientToSB(orient
), ESB_ENABLE_BOTH
);
1072 //else: leave all the fields to be 0
1074 info
.fMask
= SIF_RANGE
| SIF_PAGE
| SIF_POS
;
1075 if ( HasFlag(wxALWAYS_SHOW_SB
) || range
== -1 )
1077 // disable scrollbar instead of removing it then
1078 info
.fMask
|= SIF_DISABLENOSCROLL
;
1081 ::SetScrollInfo(hwnd
, WXOrientToSB(orient
), &info
, refresh
);
1084 void wxWindowMSW::ScrollWindow(int dx
, int dy
, const wxRect
*prect
)
1090 wxCopyRectToRECT(*prect
, rect
);
1100 // FIXME: is this the exact equivalent of the line below?
1101 ::ScrollWindowEx(GetHwnd(), dx
, dy
, pr
, pr
, 0, 0, SW_SCROLLCHILDREN
|SW_ERASE
|SW_INVALIDATE
);
1103 ::ScrollWindow(GetHwnd(), dx
, dy
, pr
, pr
);
1107 static bool ScrollVertically(HWND hwnd
, int kind
, int count
)
1109 int posStart
= GetScrollPosition(hwnd
, SB_VERT
);
1112 for ( int n
= 0; n
< count
; n
++ )
1114 ::SendMessage(hwnd
, WM_VSCROLL
, kind
, 0);
1116 int posNew
= GetScrollPosition(hwnd
, SB_VERT
);
1117 if ( posNew
== pos
)
1119 // don't bother to continue, we're already at top/bottom
1126 return pos
!= posStart
;
1129 bool wxWindowMSW::ScrollLines(int lines
)
1131 bool down
= lines
> 0;
1133 return ScrollVertically(GetHwnd(),
1134 down
? SB_LINEDOWN
: SB_LINEUP
,
1135 down
? lines
: -lines
);
1138 bool wxWindowMSW::ScrollPages(int pages
)
1140 bool down
= pages
> 0;
1142 return ScrollVertically(GetHwnd(),
1143 down
? SB_PAGEDOWN
: SB_PAGEUP
,
1144 down
? pages
: -pages
);
1147 // ----------------------------------------------------------------------------
1149 // ----------------------------------------------------------------------------
1151 void wxWindowMSW::SetLayoutDirection(wxLayoutDirection dir
)
1156 wxCHECK_RET( GetHwnd(),
1157 _T("layout direction must be set after window creation") );
1159 LONG styleOld
= wxGetWindowExStyle(this);
1161 LONG styleNew
= styleOld
;
1164 case wxLayout_LeftToRight
:
1165 styleNew
&= ~WS_EX_LAYOUTRTL
;
1168 case wxLayout_RightToLeft
:
1169 styleNew
|= WS_EX_LAYOUTRTL
;
1173 wxFAIL_MSG(_T("unsupported layout direction"));
1177 if ( styleNew
!= styleOld
)
1179 wxSetWindowExStyle(this, styleNew
);
1184 wxLayoutDirection
wxWindowMSW::GetLayoutDirection() const
1187 return wxLayout_Default
;
1189 wxCHECK_MSG( GetHwnd(), wxLayout_Default
, _T("invalid window") );
1191 return wxHasWindowExStyle(this, WS_EX_LAYOUTRTL
) ? wxLayout_RightToLeft
1192 : wxLayout_LeftToRight
;
1197 wxWindowMSW::AdjustForLayoutDirection(wxCoord x
,
1198 wxCoord
WXUNUSED(width
),
1199 wxCoord
WXUNUSED(widthTotal
)) const
1201 // Win32 mirrors the coordinates of RTL windows automatically, so don't
1202 // redo it ourselves
1206 // ---------------------------------------------------------------------------
1208 // ---------------------------------------------------------------------------
1210 void wxWindowMSW::SubclassWin(WXHWND hWnd
)
1212 wxASSERT_MSG( !m_oldWndProc
, wxT("subclassing window twice?") );
1214 HWND hwnd
= (HWND
)hWnd
;
1215 wxCHECK_RET( ::IsWindow(hwnd
), wxT("invalid HWND in SubclassWin") );
1219 wxAssociateWinWithHandle(hwnd
, this);
1221 m_oldWndProc
= (WXFARPROC
)wxGetWindowProc((HWND
)hWnd
);
1223 // we don't need to subclass the window of our own class (in the Windows
1224 // sense of the word)
1225 if ( !wxCheckWindowWndProc(hWnd
, (WXFARPROC
)wxWndProc
) )
1227 wxSetWindowProc(hwnd
, wxWndProc
);
1231 // don't bother restoring it either: this also makes it easy to
1232 // implement IsOfStandardClass() method which returns true for the
1233 // standard controls and false for the wxWidgets own windows as it can
1234 // simply check m_oldWndProc
1235 m_oldWndProc
= NULL
;
1238 // we're officially created now, send the event
1239 wxWindowCreateEvent
event((wxWindow
*)this);
1240 (void)HandleWindowEvent(event
);
1243 void wxWindowMSW::UnsubclassWin()
1245 wxRemoveHandleAssociation(this);
1247 // Restore old Window proc
1248 HWND hwnd
= GetHwnd();
1253 wxCHECK_RET( ::IsWindow(hwnd
), wxT("invalid HWND in UnsubclassWin") );
1257 if ( !wxCheckWindowWndProc((WXHWND
)hwnd
, m_oldWndProc
) )
1259 wxSetWindowProc(hwnd
, (WNDPROC
)m_oldWndProc
);
1262 m_oldWndProc
= NULL
;
1267 void wxWindowMSW::AssociateHandle(WXWidget handle
)
1271 if ( !::DestroyWindow(GetHwnd()) )
1272 wxLogLastError(wxT("DestroyWindow"));
1275 WXHWND wxhwnd
= (WXHWND
)handle
;
1277 // this also calls SetHWND(wxhwnd)
1278 SubclassWin(wxhwnd
);
1281 void wxWindowMSW::DissociateHandle()
1283 // this also calls SetHWND(0) for us
1288 bool wxCheckWindowWndProc(WXHWND hWnd
,
1289 WXFARPROC
WXUNUSED(wndProc
))
1291 const wxString
str(wxGetWindowClass(hWnd
));
1293 // TODO: get rid of wxTLWHiddenParent special case (currently it's not
1294 // registered by wxApp but using ad hoc code in msw/toplevel.cpp);
1295 // there is also a hidden window class used by sockets &c
1296 return wxApp::IsRegisteredClassName(str
) || str
== _T("wxTLWHiddenParent");
1299 // ----------------------------------------------------------------------------
1301 // ----------------------------------------------------------------------------
1303 void wxWindowMSW::SetWindowStyleFlag(long flags
)
1305 long flagsOld
= GetWindowStyleFlag();
1306 if ( flags
== flagsOld
)
1309 // update the internal variable
1310 wxWindowBase::SetWindowStyleFlag(flags
);
1312 // and the real window flags
1313 MSWUpdateStyle(flagsOld
, GetExtraStyle());
1316 void wxWindowMSW::SetExtraStyle(long exflags
)
1318 long exflagsOld
= GetExtraStyle();
1319 if ( exflags
== exflagsOld
)
1322 // update the internal variable
1323 wxWindowBase::SetExtraStyle(exflags
);
1325 // and the real window flags
1326 MSWUpdateStyle(GetWindowStyleFlag(), exflagsOld
);
1329 void wxWindowMSW::MSWUpdateStyle(long flagsOld
, long exflagsOld
)
1331 // now update the Windows style as well if needed - and if the window had
1332 // been already created
1336 // we may need to call SetWindowPos() when we change some styles
1337 bool callSWP
= false;
1340 long style
= MSWGetStyle(GetWindowStyleFlag(), &exstyle
);
1342 // this is quite a horrible hack but we need it because MSWGetStyle()
1343 // doesn't take exflags as parameter but uses GetExtraStyle() internally
1344 // and so we have to modify the window exflags temporarily to get the
1345 // correct exstyleOld
1346 long exflagsNew
= GetExtraStyle();
1347 wxWindowBase::SetExtraStyle(exflagsOld
);
1350 long styleOld
= MSWGetStyle(flagsOld
, &exstyleOld
);
1352 wxWindowBase::SetExtraStyle(exflagsNew
);
1355 if ( style
!= styleOld
)
1357 // some flags (e.g. WS_VISIBLE or WS_DISABLED) should not be changed by
1358 // this function so instead of simply setting the style to the new
1359 // value we clear the bits which were set in styleOld but are set in
1360 // the new one and set the ones which were not set before
1361 long styleReal
= ::GetWindowLong(GetHwnd(), GWL_STYLE
);
1362 styleReal
&= ~styleOld
;
1365 ::SetWindowLong(GetHwnd(), GWL_STYLE
, styleReal
);
1367 // we need to call SetWindowPos() if any of the styles affecting the
1368 // frame appearance have changed
1369 callSWP
= ((styleOld
^ style
) & (WS_BORDER
|
1378 // and the extended style
1379 long exstyleReal
= wxGetWindowExStyle(this);
1381 if ( exstyle
!= exstyleOld
)
1383 exstyleReal
&= ~exstyleOld
;
1384 exstyleReal
|= exstyle
;
1386 wxSetWindowExStyle(this, exstyleReal
);
1388 // ex style changes don't take effect without calling SetWindowPos
1394 // we must call SetWindowPos() to flush the cached extended style and
1395 // also to make the change to wxSTAY_ON_TOP style take effect: just
1396 // setting the style simply doesn't work
1397 if ( !::SetWindowPos(GetHwnd(),
1398 exstyleReal
& WS_EX_TOPMOST
? HWND_TOPMOST
1401 SWP_NOMOVE
| SWP_NOSIZE
| SWP_FRAMECHANGED
) )
1403 wxLogLastError(_T("SetWindowPos"));
1408 wxBorder
wxWindowMSW::GetDefaultBorderForControl() const
1410 return wxBORDER_THEME
;
1413 wxBorder
wxWindowMSW::GetDefaultBorder() const
1415 return wxWindowBase::GetDefaultBorder();
1418 // Translate wxBORDER_THEME (and other border styles if necessary) to the value
1419 // that makes most sense for this Windows environment
1420 wxBorder
wxWindowMSW::TranslateBorder(wxBorder border
) const
1422 #if defined(__POCKETPC__) || defined(__SMARTPHONE__)
1423 if (border
== wxBORDER_THEME
|| border
== wxBORDER_SUNKEN
|| border
== wxBORDER_SIMPLE
)
1424 return wxBORDER_SIMPLE
;
1426 return wxBORDER_NONE
;
1429 if (border
== wxBORDER_THEME
)
1431 if (CanApplyThemeBorder())
1433 wxUxThemeEngine
* theme
= wxUxThemeEngine::GetIfActive();
1435 return wxBORDER_THEME
;
1437 return wxBORDER_SUNKEN
;
1445 WXDWORD
wxWindowMSW::MSWGetStyle(long flags
, WXDWORD
*exstyle
) const
1447 // translate common wxWidgets styles to Windows ones
1449 // most of windows are child ones, those which are not (such as
1450 // wxTopLevelWindow) should remove WS_CHILD in their MSWGetStyle()
1451 WXDWORD style
= WS_CHILD
;
1453 // using this flag results in very significant reduction in flicker,
1454 // especially with controls inside the static boxes (as the interior of the
1455 // box is not redrawn twice), but sometimes results in redraw problems, so
1456 // optionally allow the old code to continue to use it provided a special
1457 // system option is turned on
1458 if ( !wxSystemOptions::GetOptionInt(wxT("msw.window.no-clip-children"))
1459 || (flags
& wxCLIP_CHILDREN
) )
1460 style
|= WS_CLIPCHILDREN
;
1462 // it doesn't seem useful to use WS_CLIPSIBLINGS here as we officially
1463 // don't support overlapping windows and it only makes sense for them and,
1464 // presumably, gives the system some extra work (to manage more clipping
1465 // regions), so avoid it alltogether
1468 if ( flags
& wxVSCROLL
)
1469 style
|= WS_VSCROLL
;
1471 if ( flags
& wxHSCROLL
)
1472 style
|= WS_HSCROLL
;
1474 const wxBorder border
= TranslateBorder(GetBorder(flags
));
1476 // After translation, border is now optimized for the specific version of Windows
1477 // and theme engine presence.
1479 // WS_BORDER is only required for wxBORDER_SIMPLE
1480 if ( border
== wxBORDER_SIMPLE
)
1483 // now deal with ext style if the caller wants it
1489 if ( flags
& wxTRANSPARENT_WINDOW
)
1490 *exstyle
|= WS_EX_TRANSPARENT
;
1496 case wxBORDER_DEFAULT
:
1497 wxFAIL_MSG( _T("unknown border style") );
1501 case wxBORDER_SIMPLE
:
1502 case wxBORDER_THEME
:
1505 case wxBORDER_STATIC
:
1506 *exstyle
|= WS_EX_STATICEDGE
;
1509 case wxBORDER_RAISED
:
1510 *exstyle
|= WS_EX_DLGMODALFRAME
;
1513 case wxBORDER_SUNKEN
:
1514 *exstyle
|= WS_EX_CLIENTEDGE
;
1515 style
&= ~WS_BORDER
;
1518 // case wxBORDER_DOUBLE:
1519 // *exstyle |= WS_EX_DLGMODALFRAME;
1523 // wxUniv doesn't use Windows dialog navigation functions at all
1524 #if !defined(__WXUNIVERSAL__) && !defined(__WXWINCE__)
1525 // to make the dialog navigation work with the nested panels we must
1526 // use this style (top level windows such as dialogs don't need it)
1527 if ( (flags
& wxTAB_TRAVERSAL
) && !IsTopLevel() )
1529 *exstyle
|= WS_EX_CONTROLPARENT
;
1531 #endif // __WXUNIVERSAL__
1537 // Setup background and foreground colours correctly
1538 void wxWindowMSW::SetupColours()
1541 SetBackgroundColour(GetParent()->GetBackgroundColour());
1544 bool wxWindowMSW::IsMouseInWindow() const
1546 // get the mouse position
1549 ::GetCursorPosWinCE(&pt
);
1551 ::GetCursorPos(&pt
);
1554 // find the window which currently has the cursor and go up the window
1555 // chain until we find this window - or exhaust it
1556 HWND hwnd
= ::WindowFromPoint(pt
);
1557 while ( hwnd
&& (hwnd
!= GetHwnd()) )
1558 hwnd
= ::GetParent(hwnd
);
1560 return hwnd
!= NULL
;
1563 void wxWindowMSW::OnInternalIdle()
1565 #ifndef HAVE_TRACKMOUSEEVENT
1566 // Check if we need to send a LEAVE event
1567 if ( m_mouseInWindow
)
1569 // note that we should generate the leave event whether the window has
1570 // or doesn't have mouse capture
1571 if ( !IsMouseInWindow() )
1573 GenerateMouseLeave();
1576 #endif // !HAVE_TRACKMOUSEEVENT
1578 if (wxUpdateUIEvent::CanUpdate(this) && IsShownOnScreen())
1579 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
1582 // Set this window to be the child of 'parent'.
1583 bool wxWindowMSW::Reparent(wxWindowBase
*parent
)
1585 if ( !wxWindowBase::Reparent(parent
) )
1588 HWND hWndChild
= GetHwnd();
1589 HWND hWndParent
= GetParent() ? GetWinHwnd(GetParent()) : (HWND
)0;
1591 ::SetParent(hWndChild
, hWndParent
);
1594 if ( wxHasWindowExStyle(this, WS_EX_CONTROLPARENT
) )
1596 EnsureParentHasControlParentStyle(GetParent());
1598 #endif // !__WXWINCE__
1603 static inline void SendSetRedraw(HWND hwnd
, bool on
)
1605 #ifndef __WXMICROWIN__
1606 ::SendMessage(hwnd
, WM_SETREDRAW
, (WPARAM
)on
, 0);
1610 void wxWindowMSW::DoFreeze()
1613 return; // no point in freezing hidden window
1615 SendSetRedraw(GetHwnd(), false);
1618 void wxWindowMSW::DoThaw()
1621 return; // hidden windows aren't frozen by DoFreeze
1623 SendSetRedraw(GetHwnd(), true);
1625 // we need to refresh everything or otherwise the invalidated area
1626 // is not going to be repainted
1630 void wxWindowMSW::Refresh(bool eraseBack
, const wxRect
*rect
)
1632 HWND hWnd
= GetHwnd();
1639 wxCopyRectToRECT(*rect
, mswRect
);
1647 // RedrawWindow not available on SmartPhone or eVC++ 3
1648 #if !defined(__SMARTPHONE__) && !(defined(_WIN32_WCE) && _WIN32_WCE < 400)
1649 UINT flags
= RDW_INVALIDATE
| RDW_ALLCHILDREN
;
1653 ::RedrawWindow(hWnd
, pRect
, NULL
, flags
);
1655 ::InvalidateRect(hWnd
, pRect
, eraseBack
);
1660 void wxWindowMSW::Update()
1662 if ( !::UpdateWindow(GetHwnd()) )
1664 wxLogLastError(_T("UpdateWindow"));
1667 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
1668 // just calling UpdateWindow() is not enough, what we did in our WM_PAINT
1669 // handler needs to be really drawn right now
1674 // ---------------------------------------------------------------------------
1676 // ---------------------------------------------------------------------------
1678 #if wxUSE_DRAG_AND_DROP || !defined(__WXWINCE__)
1682 // we need to lower the sibling static boxes so controls contained within can be
1684 static void AdjustStaticBoxZOrder(wxWindow
*parent
)
1686 // no sibling static boxes if we have no parent (ie TLW)
1690 for ( wxWindowList::compatibility_iterator node
= parent
->GetChildren().GetFirst();
1692 node
= node
->GetNext() )
1694 wxStaticBox
*statbox
= wxDynamicCast(node
->GetData(), wxStaticBox
);
1697 ::SetWindowPos(GetHwndOf(statbox
), HWND_BOTTOM
, 0, 0, 0, 0,
1698 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
1703 #else // !wxUSE_STATBOX
1705 static inline void AdjustStaticBoxZOrder(wxWindow
* WXUNUSED(parent
))
1709 #endif // wxUSE_STATBOX/!wxUSE_STATBOX
1711 #endif // drag and drop is used
1713 #if wxUSE_DRAG_AND_DROP
1714 void wxWindowMSW::SetDropTarget(wxDropTarget
*pDropTarget
)
1716 if ( m_dropTarget
!= 0 ) {
1717 m_dropTarget
->Revoke(m_hWnd
);
1718 delete m_dropTarget
;
1721 m_dropTarget
= pDropTarget
;
1722 if ( m_dropTarget
!= 0 )
1724 AdjustStaticBoxZOrder(GetParent());
1725 m_dropTarget
->Register(m_hWnd
);
1728 #endif // wxUSE_DRAG_AND_DROP
1730 // old-style file manager drag&drop support: we retain the old-style
1731 // DragAcceptFiles in parallel with SetDropTarget.
1732 void wxWindowMSW::DragAcceptFiles(bool WXUNUSED_IN_WINCE(accept
))
1735 HWND hWnd
= GetHwnd();
1738 AdjustStaticBoxZOrder(GetParent());
1739 ::DragAcceptFiles(hWnd
, (BOOL
)accept
);
1744 // ----------------------------------------------------------------------------
1746 // ----------------------------------------------------------------------------
1750 void wxWindowMSW::DoSetToolTip(wxToolTip
*tooltip
)
1752 wxWindowBase::DoSetToolTip(tooltip
);
1755 m_tooltip
->SetWindow((wxWindow
*)this);
1758 #endif // wxUSE_TOOLTIPS
1760 // ---------------------------------------------------------------------------
1761 // moving and resizing
1762 // ---------------------------------------------------------------------------
1764 bool wxWindowMSW::IsSizeDeferred() const
1766 #if USE_DEFERRED_SIZING
1767 if ( m_pendingPosition
!= wxDefaultPosition
||
1768 m_pendingSize
!= wxDefaultSize
)
1770 #endif // USE_DEFERRED_SIZING
1776 void wxWindowMSW::DoGetSize(int *x
, int *y
) const
1778 #if USE_DEFERRED_SIZING
1779 // if SetSize() had been called at wx level but not realized at Windows
1780 // level yet (i.e. EndDeferWindowPos() not called), we still should return
1781 // the new and not the old position to the other wx code
1782 if ( m_pendingSize
!= wxDefaultSize
)
1785 *x
= m_pendingSize
.x
;
1787 *y
= m_pendingSize
.y
;
1789 else // use current size
1790 #endif // USE_DEFERRED_SIZING
1792 RECT rect
= wxGetWindowRect(GetHwnd());
1795 *x
= rect
.right
- rect
.left
;
1797 *y
= rect
.bottom
- rect
.top
;
1801 // Get size *available for subwindows* i.e. excluding menu bar etc.
1802 void wxWindowMSW::DoGetClientSize(int *x
, int *y
) const
1804 #if USE_DEFERRED_SIZING
1805 if ( m_pendingSize
!= wxDefaultSize
)
1807 // we need to calculate the client size corresponding to pending size
1809 rect
.left
= m_pendingPosition
.x
;
1810 rect
.top
= m_pendingPosition
.y
;
1811 rect
.right
= rect
.left
+ m_pendingSize
.x
;
1812 rect
.bottom
= rect
.top
+ m_pendingSize
.y
;
1814 ::SendMessage(GetHwnd(), WM_NCCALCSIZE
, FALSE
, (LPARAM
)&rect
);
1817 *x
= rect
.right
- rect
.left
;
1819 *y
= rect
.bottom
- rect
.top
;
1822 #endif // USE_DEFERRED_SIZING
1824 RECT rect
= wxGetClientRect(GetHwnd());
1833 void wxWindowMSW::DoGetPosition(int *x
, int *y
) const
1835 wxWindow
* const parent
= GetParent();
1838 if ( m_pendingPosition
!= wxDefaultPosition
)
1840 pos
= m_pendingPosition
;
1842 else // use current position
1844 RECT rect
= wxGetWindowRect(GetHwnd());
1847 point
.x
= rect
.left
;
1850 // we do the adjustments with respect to the parent only for the "real"
1851 // children, not for the dialogs/frames
1852 if ( !IsTopLevel() )
1854 if ( wxTheApp
->GetLayoutDirection() == wxLayout_RightToLeft
)
1856 // In RTL mode, we want the logical left x-coordinate,
1857 // which would be the physical right x-coordinate.
1858 point
.x
= rect
.right
;
1861 // Since we now have the absolute screen coords, if there's a
1862 // parent we must subtract its top left corner
1865 ::ScreenToClient(GetHwndOf(parent
), &point
);
1873 // we also must adjust by the client area offset: a control which is just
1874 // under a toolbar could be at (0, 30) in Windows but at (0, 0) in wx
1875 if ( parent
&& !IsTopLevel() )
1877 const wxPoint
pt(parent
->GetClientAreaOrigin());
1888 void wxWindowMSW::DoScreenToClient(int *x
, int *y
) const
1896 ::ScreenToClient(GetHwnd(), &pt
);
1904 void wxWindowMSW::DoClientToScreen(int *x
, int *y
) const
1912 ::ClientToScreen(GetHwnd(), &pt
);
1921 wxWindowMSW::DoMoveSibling(WXHWND hwnd
, int x
, int y
, int width
, int height
)
1923 #if USE_DEFERRED_SIZING
1924 // if our parent had prepared a defer window handle for us, use it (unless
1925 // we are a top level window)
1926 wxWindowMSW
* const parent
= IsTopLevel() ? NULL
: GetParent();
1928 HDWP hdwp
= parent
? (HDWP
)parent
->m_hDWP
: NULL
;
1931 hdwp
= ::DeferWindowPos(hdwp
, (HWND
)hwnd
, NULL
, x
, y
, width
, height
,
1932 SWP_NOZORDER
| SWP_NOOWNERZORDER
| SWP_NOACTIVATE
);
1935 wxLogLastError(_T("DeferWindowPos"));
1941 // hdwp must be updated as it may have been changed
1942 parent
->m_hDWP
= (WXHANDLE
)hdwp
;
1947 // did deferred move, remember new coordinates of the window as they're
1948 // different from what Windows would return for it
1952 // otherwise (or if deferring failed) move the window in place immediately
1953 #endif // USE_DEFERRED_SIZING
1954 if ( !::MoveWindow((HWND
)hwnd
, x
, y
, width
, height
, IsShown()) )
1956 wxLogLastError(wxT("MoveWindow"));
1959 // if USE_DEFERRED_SIZING, indicates that we didn't use deferred move,
1960 // ignored otherwise
1964 void wxWindowMSW::DoMoveWindow(int x
, int y
, int width
, int height
)
1966 // TODO: is this consistent with other platforms?
1967 // Still, negative width or height shouldn't be allowed
1973 if ( DoMoveSibling(m_hWnd
, x
, y
, width
, height
) )
1975 #if USE_DEFERRED_SIZING
1976 m_pendingPosition
= wxPoint(x
, y
);
1977 m_pendingSize
= wxSize(width
, height
);
1979 else // window was moved immediately, without deferring it
1981 m_pendingPosition
= wxDefaultPosition
;
1982 m_pendingSize
= wxDefaultSize
;
1983 #endif // USE_DEFERRED_SIZING
1987 // set the size of the window: if the dimensions are positive, just use them,
1988 // but if any of them is equal to -1, it means that we must find the value for
1989 // it ourselves (unless sizeFlags contains wxSIZE_ALLOW_MINUS_ONE flag, in
1990 // which case -1 is a valid value for x and y)
1992 // If sizeFlags contains wxSIZE_AUTO_WIDTH/HEIGHT flags (default), we calculate
1993 // the width/height to best suit our contents, otherwise we reuse the current
1995 void wxWindowMSW::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
1997 // get the current size and position...
1998 int currentX
, currentY
;
1999 int currentW
, currentH
;
2001 GetPosition(¤tX
, ¤tY
);
2002 GetSize(¤tW
, ¤tH
);
2004 // ... and don't do anything (avoiding flicker) if it's already ok unless
2005 // we're forced to resize the window
2006 if ( x
== currentX
&& y
== currentY
&&
2007 width
== currentW
&& height
== currentH
&&
2008 !(sizeFlags
& wxSIZE_FORCE
) )
2013 if ( x
== wxDefaultCoord
&& !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) )
2015 if ( y
== wxDefaultCoord
&& !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) )
2018 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2020 wxSize size
= wxDefaultSize
;
2021 if ( width
== wxDefaultCoord
)
2023 if ( sizeFlags
& wxSIZE_AUTO_WIDTH
)
2025 size
= DoGetBestSize();
2030 // just take the current one
2035 if ( height
== wxDefaultCoord
)
2037 if ( sizeFlags
& wxSIZE_AUTO_HEIGHT
)
2039 if ( size
.x
== wxDefaultCoord
)
2041 size
= DoGetBestSize();
2043 //else: already called DoGetBestSize() above
2049 // just take the current one
2054 DoMoveWindow(x
, y
, width
, height
);
2057 void wxWindowMSW::DoSetClientSize(int width
, int height
)
2059 // setting the client size is less obvious than it could have been
2060 // because in the result of changing the total size the window scrollbar
2061 // may [dis]appear and/or its menubar may [un]wrap (and AdjustWindowRect()
2062 // doesn't take neither into account) and so the client size will not be
2063 // correct as the difference between the total and client size changes --
2064 // so we keep changing it until we get it right
2066 // normally this loop shouldn't take more than 3 iterations (usually 1 but
2067 // if scrollbars [dis]appear as the result of the first call, then 2 and it
2068 // may become 3 if the window had 0 size originally and so we didn't
2069 // calculate the scrollbar correction correctly during the first iteration)
2070 // but just to be on the safe side we check for it instead of making it an
2071 // "infinite" loop (i.e. leaving break inside as the only way to get out)
2072 for ( int i
= 0; i
< 4; i
++ )
2075 ::GetClientRect(GetHwnd(), &rectClient
);
2077 // if the size is already ok, stop here (NB: rectClient.left = top = 0)
2078 if ( (rectClient
.right
== width
|| width
== wxDefaultCoord
) &&
2079 (rectClient
.bottom
== height
|| height
== wxDefaultCoord
) )
2084 // Find the difference between the entire window (title bar and all)
2085 // and the client area; add this to the new client size to move the
2088 ::GetWindowRect(GetHwnd(), &rectWin
);
2090 const int widthWin
= rectWin
.right
- rectWin
.left
,
2091 heightWin
= rectWin
.bottom
- rectWin
.top
;
2093 // MoveWindow positions the child windows relative to the parent, so
2094 // adjust if necessary
2095 if ( !IsTopLevel() )
2097 wxWindow
*parent
= GetParent();
2100 ::ScreenToClient(GetHwndOf(parent
), (POINT
*)&rectWin
);
2104 // don't call DoMoveWindow() because we want to move window immediately
2105 // and not defer it here as otherwise the value returned by
2106 // GetClient/WindowRect() wouldn't change as the window wouldn't be
2108 if ( !::MoveWindow(GetHwnd(),
2111 width
+ widthWin
- rectClient
.right
,
2112 height
+ heightWin
- rectClient
.bottom
,
2115 wxLogLastError(_T("MoveWindow"));
2120 // ---------------------------------------------------------------------------
2122 // ---------------------------------------------------------------------------
2124 int wxWindowMSW::GetCharHeight() const
2126 return wxGetTextMetrics(this).tmHeight
;
2129 int wxWindowMSW::GetCharWidth() const
2131 // +1 is needed because Windows apparently adds it when calculating the
2132 // dialog units size in pixels
2133 #if wxDIALOG_UNIT_COMPATIBILITY
2134 return wxGetTextMetrics(this).tmAveCharWidth
;
2136 return wxGetTextMetrics(this).tmAveCharWidth
+ 1;
2140 void wxWindowMSW::GetTextExtent(const wxString
& string
,
2142 int *descent
, int *externalLeading
,
2143 const wxFont
*fontToUse
) const
2145 wxASSERT_MSG( !fontToUse
|| fontToUse
->Ok(),
2146 _T("invalid font in GetTextExtent()") );
2150 hfontToUse
= GetHfontOf(*fontToUse
);
2152 hfontToUse
= GetHfontOf(GetFont());
2154 WindowHDC
hdc(GetHwnd());
2155 SelectInHDC
selectFont(hdc
, hfontToUse
);
2159 ::GetTextExtentPoint32(hdc
, string
.wx_str(), string
.length(), &sizeRect
);
2160 GetTextMetrics(hdc
, &tm
);
2167 *descent
= tm
.tmDescent
;
2168 if ( externalLeading
)
2169 *externalLeading
= tm
.tmExternalLeading
;
2172 // ---------------------------------------------------------------------------
2174 // ---------------------------------------------------------------------------
2176 #if wxUSE_MENUS_NATIVE
2178 // yield for WM_COMMAND events only, i.e. process all WM_COMMANDs in the queue
2179 // immediately, without waiting for the next event loop iteration
2181 // NB: this function should probably be made public later as it can almost
2182 // surely replace wxYield() elsewhere as well
2183 static void wxYieldForCommandsOnly()
2185 // peek all WM_COMMANDs (it will always return WM_QUIT too but we don't
2186 // want to process it here)
2188 while ( ::PeekMessage(&msg
, (HWND
)0, WM_COMMAND
, WM_COMMAND
, PM_REMOVE
) )
2190 if ( msg
.message
== WM_QUIT
)
2192 // if we retrieved a WM_QUIT, insert back into the message queue.
2193 ::PostQuitMessage(0);
2197 // luckily (as we don't have access to wxEventLoopImpl method from here
2198 // anyhow...) we don't need to pre process WM_COMMANDs so dispatch it
2200 ::TranslateMessage(&msg
);
2201 ::DispatchMessage(&msg
);
2205 bool wxWindowMSW::DoPopupMenu(wxMenu
*menu
, int x
, int y
)
2207 menu
->SetInvokingWindow(this);
2210 if ( x
== wxDefaultCoord
&& y
== wxDefaultCoord
)
2212 wxPoint mouse
= ScreenToClient(wxGetMousePosition());
2213 x
= mouse
.x
; y
= mouse
.y
;
2216 HWND hWnd
= GetHwnd();
2217 HMENU hMenu
= GetHmenuOf(menu
);
2221 ::ClientToScreen(hWnd
, &point
);
2222 #if defined(__WXWINCE__)
2223 static const UINT flags
= 0;
2224 #else // !__WXWINCE__
2225 UINT flags
= TPM_RIGHTBUTTON
;
2226 // NT4 doesn't support TPM_RECURSE and simply doesn't show the menu at all
2227 // when it's use, I'm not sure about Win95/98 but prefer to err on the safe
2228 // side and not to use it there neither -- modify the test if it does work
2230 if ( wxGetWinVersion() >= wxWinVersion_5
)
2232 // using TPM_RECURSE allows us to show a popup menu while another menu
2233 // is opened which can be useful and is supported by the other
2234 // platforms, so allow it under Windows too
2235 flags
|= TPM_RECURSE
;
2237 #endif // __WXWINCE__/!__WXWINCE__
2239 ::TrackPopupMenu(hMenu
, flags
, point
.x
, point
.y
, 0, hWnd
, NULL
);
2241 // we need to do it right now as otherwise the events are never going to be
2242 // sent to wxCurrentPopupMenu from HandleCommand()
2244 // note that even eliminating (ugly) wxCurrentPopupMenu global wouldn't
2245 // help and we'd still need wxYieldForCommandsOnly() as the menu may be
2246 // destroyed as soon as we return (it can be a local variable in the caller
2247 // for example) and so we do need to process the event immediately
2248 wxYieldForCommandsOnly();
2250 menu
->SetInvokingWindow(NULL
);
2255 #endif // wxUSE_MENUS_NATIVE
2257 // ===========================================================================
2258 // pre/post message processing
2259 // ===========================================================================
2261 WXLRESULT
wxWindowMSW::MSWDefWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
)
2264 return ::CallWindowProc(CASTWNDPROC m_oldWndProc
, GetHwnd(), (UINT
) nMsg
, (WPARAM
) wParam
, (LPARAM
) lParam
);
2266 return ::DefWindowProc(GetHwnd(), nMsg
, wParam
, lParam
);
2269 bool wxWindowMSW::MSWProcessMessage(WXMSG
* pMsg
)
2271 // wxUniversal implements tab traversal itself
2272 #ifndef __WXUNIVERSAL__
2273 if ( m_hWnd
!= 0 && (GetWindowStyleFlag() & wxTAB_TRAVERSAL
) )
2275 // intercept dialog navigation keys
2276 MSG
*msg
= (MSG
*)pMsg
;
2278 // here we try to do all the job which ::IsDialogMessage() usually does
2280 if ( msg
->message
== WM_KEYDOWN
)
2282 bool bCtrlDown
= wxIsCtrlDown();
2283 bool bShiftDown
= wxIsShiftDown();
2285 // WM_GETDLGCODE: ask the control if it wants the key for itself,
2286 // don't process it if it's the case (except for Ctrl-Tab/Enter
2287 // combinations which are always processed)
2288 LONG lDlgCode
= ::SendMessage(msg
->hwnd
, WM_GETDLGCODE
, 0, 0);
2290 // surprizingly, DLGC_WANTALLKEYS bit mask doesn't contain the
2291 // DLGC_WANTTAB nor DLGC_WANTARROWS bits although, logically,
2292 // it, of course, implies them
2293 if ( lDlgCode
& DLGC_WANTALLKEYS
)
2295 lDlgCode
|= DLGC_WANTTAB
| DLGC_WANTARROWS
;
2298 bool bForward
= true,
2299 bWindowChange
= false,
2302 // should we process this message specially?
2303 bool bProcess
= true;
2304 switch ( msg
->wParam
)
2307 if ( (lDlgCode
& DLGC_WANTTAB
) && !bCtrlDown
)
2309 // let the control have the TAB
2312 else // use it for navigation
2314 // Ctrl-Tab cycles thru notebook pages
2315 bWindowChange
= bCtrlDown
;
2316 bForward
= !bShiftDown
;
2323 if ( (lDlgCode
& DLGC_WANTARROWS
) || bCtrlDown
)
2331 if ( (lDlgCode
& DLGC_WANTARROWS
) || bCtrlDown
)
2340 // we treat PageUp/Dn as arrows because chances are that
2341 // a control which needs arrows also needs them for
2342 // navigation (e.g. wxTextCtrl, wxListCtrl, ...)
2343 if ( (lDlgCode
& DLGC_WANTARROWS
) && !bCtrlDown
)
2345 else // OTOH Ctrl-PageUp/Dn works as [Shift-]Ctrl-Tab
2346 bWindowChange
= true;
2352 // currently active button should get enter press even
2353 // if there is a default button elsewhere so check if
2354 // this window is a button first
2355 wxWindow
*btn
= NULL
;
2356 if ( lDlgCode
& DLGC_DEFPUSHBUTTON
)
2358 // let IsDialogMessage() handle this for all
2359 // buttons except the owner-drawn ones which it
2360 // just seems to ignore
2361 long style
= ::GetWindowLong(msg
->hwnd
, GWL_STYLE
);
2362 if ( (style
& BS_OWNERDRAW
) == BS_OWNERDRAW
)
2364 // emulate the button click
2365 btn
= wxFindWinFromHandle(msg
->hwnd
);
2370 else // not a button itself, do we have default button?
2372 // check if this window or any of its ancestors
2373 // wants the message for itself (we always reserve
2374 // Ctrl-Enter for dialog navigation though)
2375 wxWindow
*win
= this;
2378 // this will contain the dialog code of this
2379 // window and all of its parent windows in turn
2380 LONG lDlgCode2
= lDlgCode
;
2384 if ( lDlgCode2
& DLGC_WANTMESSAGE
)
2386 // as it wants to process Enter itself,
2387 // don't call IsDialogMessage() which
2392 // don't propagate keyboard messages beyond
2393 // the first top level window parent
2394 if ( win
->IsTopLevel() )
2397 win
= win
->GetParent();
2399 lDlgCode2
= ::SendMessage
2410 win
= wxGetTopLevelParent(win
);
2413 wxTopLevelWindow
* const
2414 tlw
= wxDynamicCast(win
, wxTopLevelWindow
);
2417 btn
= wxDynamicCast(tlw
->GetDefaultItem(),
2422 if ( btn
&& btn
->IsEnabled() )
2424 btn
->MSWCommand(BN_CLICKED
, 0 /* unused */);
2428 #endif // wxUSE_BUTTON
2431 // map Enter presses into button presses on PDAs
2432 wxJoystickEvent
event(wxEVT_JOY_BUTTON_DOWN
);
2433 event
.SetEventObject(this);
2434 if ( HandleWindowEvent(event
) )
2436 #endif // __WXWINCE__
2446 wxNavigationKeyEvent event
;
2447 event
.SetDirection(bForward
);
2448 event
.SetWindowChange(bWindowChange
);
2449 event
.SetFromTab(bFromTab
);
2450 event
.SetEventObject(this);
2452 if ( HandleWindowEvent(event
) )
2454 // as we don't call IsDialogMessage(), which would take of
2455 // this by default, we need to manually send this message
2456 // so that controls can change their UI state if needed
2457 MSWUpdateUIState(UIS_CLEAR
, UISF_HIDEFOCUS
);
2464 if ( ::IsDialogMessage(GetHwnd(), msg
) )
2466 // IsDialogMessage() did something...
2470 #endif // __WXUNIVERSAL__
2475 // relay mouse move events to the tooltip control
2476 MSG
*msg
= (MSG
*)pMsg
;
2477 if ( msg
->message
== WM_MOUSEMOVE
)
2478 wxToolTip::RelayEvent(pMsg
);
2480 #endif // wxUSE_TOOLTIPS
2485 bool wxWindowMSW::MSWTranslateMessage(WXMSG
* pMsg
)
2487 #if wxUSE_ACCEL && !defined(__WXUNIVERSAL__)
2488 return m_acceleratorTable
.Translate(this, pMsg
);
2492 #endif // wxUSE_ACCEL
2495 bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG
* msg
)
2497 // all tests below have to deal with various bugs/misfeatures of
2498 // IsDialogMessage(): we have to prevent it from being called from our
2499 // MSWProcessMessage() in some situations
2501 // don't let IsDialogMessage() get VK_ESCAPE as it _always_ eats the
2502 // message even when there is no cancel button and when the message is
2503 // needed by the control itself: in particular, it prevents the tree in
2504 // place edit control from being closed with Escape in a dialog
2505 if ( msg
->message
== WM_KEYDOWN
&& msg
->wParam
== VK_ESCAPE
)
2510 // ::IsDialogMessage() is broken and may sometimes hang the application by
2511 // going into an infinite loop when it tries to find the control to give
2512 // focus to when Alt-<key> is pressed, so we try to detect [some of] the
2513 // situations when this may happen and not call it then
2514 if ( msg
->message
!= WM_SYSCHAR
)
2517 // assume we can call it by default
2518 bool canSafelyCallIsDlgMsg
= true;
2520 HWND hwndFocus
= ::GetFocus();
2522 // if the currently focused window itself has WS_EX_CONTROLPARENT style,
2523 // ::IsDialogMessage() will also enter an infinite loop, because it will
2524 // recursively check the child windows but not the window itself and so if
2525 // none of the children accepts focus it loops forever (as it only stops
2526 // when it gets back to the window it started from)
2528 // while it is very unusual that a window with WS_EX_CONTROLPARENT
2529 // style has the focus, it can happen. One such possibility is if
2530 // all windows are either toplevel, wxDialog, wxPanel or static
2531 // controls and no window can actually accept keyboard input.
2532 #if !defined(__WXWINCE__)
2533 if ( ::GetWindowLong(hwndFocus
, GWL_EXSTYLE
) & WS_EX_CONTROLPARENT
)
2535 // pessimistic by default
2536 canSafelyCallIsDlgMsg
= false;
2537 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
2539 node
= node
->GetNext() )
2541 wxWindow
* const win
= node
->GetData();
2542 if ( win
->CanAcceptFocus() &&
2543 !wxHasWindowExStyle(win
, WS_EX_CONTROLPARENT
) )
2545 // it shouldn't hang...
2546 canSafelyCallIsDlgMsg
= true;
2552 #endif // !__WXWINCE__
2554 if ( canSafelyCallIsDlgMsg
)
2556 // ::IsDialogMessage() can enter in an infinite loop when the
2557 // currently focused window is disabled or hidden and its
2558 // parent has WS_EX_CONTROLPARENT style, so don't call it in
2562 if ( !::IsWindowEnabled(hwndFocus
) ||
2563 !::IsWindowVisible(hwndFocus
) )
2565 // it would enter an infinite loop if we do this!
2566 canSafelyCallIsDlgMsg
= false;
2571 if ( !(::GetWindowLong(hwndFocus
, GWL_STYLE
) & WS_CHILD
) )
2573 // it's a top level window, don't go further -- e.g. even
2574 // if the parent of a dialog is disabled, this doesn't
2575 // break navigation inside the dialog
2579 hwndFocus
= ::GetParent(hwndFocus
);
2583 return canSafelyCallIsDlgMsg
;
2586 // ---------------------------------------------------------------------------
2587 // message params unpackers
2588 // ---------------------------------------------------------------------------
2590 void wxWindowMSW::UnpackCommand(WXWPARAM wParam
, WXLPARAM lParam
,
2591 WORD
*id
, WXHWND
*hwnd
, WORD
*cmd
)
2593 *id
= LOWORD(wParam
);
2594 *hwnd
= (WXHWND
)lParam
;
2595 *cmd
= HIWORD(wParam
);
2598 void wxWindowMSW::UnpackActivate(WXWPARAM wParam
, WXLPARAM lParam
,
2599 WXWORD
*state
, WXWORD
*minimized
, WXHWND
*hwnd
)
2601 *state
= LOWORD(wParam
);
2602 *minimized
= HIWORD(wParam
);
2603 *hwnd
= (WXHWND
)lParam
;
2606 void wxWindowMSW::UnpackScroll(WXWPARAM wParam
, WXLPARAM lParam
,
2607 WXWORD
*code
, WXWORD
*pos
, WXHWND
*hwnd
)
2609 *code
= LOWORD(wParam
);
2610 *pos
= HIWORD(wParam
);
2611 *hwnd
= (WXHWND
)lParam
;
2614 void wxWindowMSW::UnpackCtlColor(WXWPARAM wParam
, WXLPARAM lParam
,
2615 WXHDC
*hdc
, WXHWND
*hwnd
)
2617 *hwnd
= (WXHWND
)lParam
;
2618 *hdc
= (WXHDC
)wParam
;
2621 void wxWindowMSW::UnpackMenuSelect(WXWPARAM wParam
, WXLPARAM lParam
,
2622 WXWORD
*item
, WXWORD
*flags
, WXHMENU
*hmenu
)
2624 *item
= (WXWORD
)wParam
;
2625 *flags
= HIWORD(wParam
);
2626 *hmenu
= (WXHMENU
)lParam
;
2629 // ---------------------------------------------------------------------------
2630 // Main wxWidgets window proc and the window proc for wxWindow
2631 // ---------------------------------------------------------------------------
2633 // Hook for new window just as it's being created, when the window isn't yet
2634 // associated with the handle
2635 static wxWindowMSW
*gs_winBeingCreated
= NULL
;
2637 // implementation of wxWindowCreationHook class: it just sets gs_winBeingCreated to the
2638 // window being created and insures that it's always unset back later
2639 wxWindowCreationHook::wxWindowCreationHook(wxWindowMSW
*winBeingCreated
)
2641 gs_winBeingCreated
= winBeingCreated
;
2644 wxWindowCreationHook::~wxWindowCreationHook()
2646 gs_winBeingCreated
= NULL
;
2650 LRESULT WXDLLEXPORT APIENTRY _EXPORT
wxWndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
2652 // trace all messages - useful for the debugging
2654 wxLogTrace(wxTraceMessages
,
2655 wxT("Processing %s(hWnd=%p, wParam=%08lx, lParam=%08lx)"),
2656 wxGetMessageName(message
), hWnd
, (long)wParam
, lParam
);
2657 #endif // __WXDEBUG__
2659 wxWindowMSW
*wnd
= wxFindWinFromHandle(hWnd
);
2661 // when we get the first message for the HWND we just created, we associate
2662 // it with wxWindow stored in gs_winBeingCreated
2663 if ( !wnd
&& gs_winBeingCreated
)
2665 wxAssociateWinWithHandle(hWnd
, gs_winBeingCreated
);
2666 wnd
= gs_winBeingCreated
;
2667 gs_winBeingCreated
= NULL
;
2668 wnd
->SetHWND((WXHWND
)hWnd
);
2673 if ( wnd
&& wxGUIEventLoop::AllowProcessing(wnd
) )
2674 rc
= wnd
->MSWWindowProc(message
, wParam
, lParam
);
2676 rc
= ::DefWindowProc(hWnd
, message
, wParam
, lParam
);
2681 WXLRESULT
wxWindowMSW::MSWWindowProc(WXUINT message
, WXWPARAM wParam
, WXLPARAM lParam
)
2683 // did we process the message?
2684 bool processed
= false;
2694 // for most messages we should return 0 when we do process the message
2702 processed
= HandleCreate((WXLPCREATESTRUCT
)lParam
, &mayCreate
);
2705 // return 0 to allow window creation
2706 rc
.result
= mayCreate
? 0 : -1;
2712 // never set processed to true and *always* pass WM_DESTROY to
2713 // DefWindowProc() as Windows may do some internal cleanup when
2714 // processing it and failing to pass the message along may cause
2715 // memory and resource leaks!
2716 (void)HandleDestroy();
2720 processed
= HandleSize(LOWORD(lParam
), HIWORD(lParam
), wParam
);
2724 processed
= HandleMove(GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
));
2727 #if !defined(__WXWINCE__)
2730 LPRECT pRect
= (LPRECT
)lParam
;
2732 rc
.SetLeft(pRect
->left
);
2733 rc
.SetTop(pRect
->top
);
2734 rc
.SetRight(pRect
->right
);
2735 rc
.SetBottom(pRect
->bottom
);
2736 processed
= HandleMoving(rc
);
2738 pRect
->left
= rc
.GetLeft();
2739 pRect
->top
= rc
.GetTop();
2740 pRect
->right
= rc
.GetRight();
2741 pRect
->bottom
= rc
.GetBottom();
2746 case WM_ENTERSIZEMOVE
:
2748 processed
= HandleEnterSizeMove();
2752 case WM_EXITSIZEMOVE
:
2754 processed
= HandleExitSizeMove();
2760 LPRECT pRect
= (LPRECT
)lParam
;
2762 rc
.SetLeft(pRect
->left
);
2763 rc
.SetTop(pRect
->top
);
2764 rc
.SetRight(pRect
->right
);
2765 rc
.SetBottom(pRect
->bottom
);
2766 processed
= HandleSizing(rc
);
2768 pRect
->left
= rc
.GetLeft();
2769 pRect
->top
= rc
.GetTop();
2770 pRect
->right
= rc
.GetRight();
2771 pRect
->bottom
= rc
.GetBottom();
2775 #endif // !__WXWINCE__
2777 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
2778 case WM_ACTIVATEAPP
:
2779 // This implicitly sends a wxEVT_ACTIVATE_APP event
2780 wxTheApp
->SetActive(wParam
!= 0, FindFocus());
2786 WXWORD state
, minimized
;
2788 UnpackActivate(wParam
, lParam
, &state
, &minimized
, &hwnd
);
2790 processed
= HandleActivate(state
, minimized
!= 0, (WXHWND
)hwnd
);
2795 processed
= HandleSetFocus((WXHWND
)wParam
);
2799 processed
= HandleKillFocus((WXHWND
)wParam
);
2802 case WM_PRINTCLIENT
:
2803 processed
= HandlePrintClient((WXHDC
)wParam
);
2809 wxPaintDCEx
dc((wxWindow
*)this, (WXHDC
)wParam
);
2811 processed
= HandlePaint();
2815 processed
= HandlePaint();
2820 #ifdef __WXUNIVERSAL__
2821 // Universal uses its own wxFrame/wxDialog, so we don't receive
2822 // close events unless we have this.
2824 #endif // __WXUNIVERSAL__
2826 // don't let the DefWindowProc() destroy our window - we'll do it
2827 // ourselves in ~wxWindow
2833 processed
= HandleShow(wParam
!= 0, (int)lParam
);
2837 processed
= HandleMouseMove(GET_X_LPARAM(lParam
),
2838 GET_Y_LPARAM(lParam
),
2842 #ifdef HAVE_TRACKMOUSEEVENT
2844 // filter out excess WM_MOUSELEAVE events sent after PopupMenu()
2846 if ( m_mouseInWindow
)
2848 GenerateMouseLeave();
2851 // always pass processed back as false, this allows the window
2852 // manager to process the message too. This is needed to
2853 // ensure windows XP themes work properly as the mouse moves
2854 // over widgets like buttons. So don't set processed to true here.
2856 #endif // HAVE_TRACKMOUSEEVENT
2858 #if wxUSE_MOUSEWHEEL
2860 processed
= HandleMouseWheel(wParam
, lParam
);
2864 case WM_LBUTTONDOWN
:
2866 case WM_LBUTTONDBLCLK
:
2867 case WM_RBUTTONDOWN
:
2869 case WM_RBUTTONDBLCLK
:
2870 case WM_MBUTTONDOWN
:
2872 case WM_MBUTTONDBLCLK
:
2873 #ifdef wxHAS_XBUTTON
2874 case WM_XBUTTONDOWN
:
2876 case WM_XBUTTONDBLCLK
:
2877 #endif // wxHAS_XBUTTON
2879 #ifdef __WXMICROWIN__
2880 // MicroWindows seems to ignore the fact that a window is
2881 // disabled. So catch mouse events and throw them away if
2883 wxWindowMSW
* win
= this;
2886 if (!win
->IsEnabled())
2892 win
= win
->GetParent();
2893 if ( !win
|| win
->IsTopLevel() )
2900 #endif // __WXMICROWIN__
2901 int x
= GET_X_LPARAM(lParam
),
2902 y
= GET_Y_LPARAM(lParam
);
2905 // redirect the event to a static control if necessary by
2906 // finding one under mouse because under CE the static controls
2907 // don't generate mouse events (even with SS_NOTIFY)
2909 if ( GetCapture() == this )
2911 // but don't do it if the mouse is captured by this window
2912 // because then it should really get this event itself
2917 win
= FindWindowForMouseEvent(this, &x
, &y
);
2919 // this should never happen
2920 wxCHECK_MSG( win
, 0,
2921 _T("FindWindowForMouseEvent() returned NULL") );
2924 if (IsContextMenuEnabled() && message
== WM_LBUTTONDOWN
)
2926 SHRGINFO shrgi
= {0};
2928 shrgi
.cbSize
= sizeof(SHRGINFO
);
2929 shrgi
.hwndClient
= (HWND
) GetHWND();
2933 shrgi
.dwFlags
= SHRG_RETURNCMD
;
2934 // shrgi.dwFlags = SHRG_NOTIFYPARENT;
2936 if (GN_CONTEXTMENU
== ::SHRecognizeGesture(&shrgi
))
2939 pt
= ClientToScreen(pt
);
2941 wxContextMenuEvent
evtCtx(wxEVT_CONTEXT_MENU
, GetId(), pt
);
2943 evtCtx
.SetEventObject(this);
2944 if (HandleWindowEvent(evtCtx
))
2953 #else // !__WXWINCE__
2954 wxWindowMSW
*win
= this;
2955 #endif // __WXWINCE__/!__WXWINCE__
2957 processed
= win
->HandleMouseEvent(message
, x
, y
, wParam
);
2959 // if the app didn't eat the event, handle it in the default
2960 // way, that is by giving this window the focus
2963 // for the standard classes their WndProc sets the focus to
2964 // them anyhow and doing it from here results in some weird
2965 // problems, so don't do it for them (unnecessary anyhow)
2966 if ( !win
->IsOfStandardClass() )
2968 if ( message
== WM_LBUTTONDOWN
&& win
->IsFocusable() )
2980 case MM_JOY1BUTTONDOWN
:
2981 case MM_JOY2BUTTONDOWN
:
2982 case MM_JOY1BUTTONUP
:
2983 case MM_JOY2BUTTONUP
:
2984 processed
= HandleJoystickEvent(message
,
2985 GET_X_LPARAM(lParam
),
2986 GET_Y_LPARAM(lParam
),
2989 #endif // __WXMICROWIN__
2995 UnpackCommand(wParam
, lParam
, &id
, &hwnd
, &cmd
);
2997 processed
= HandleCommand(id
, cmd
, hwnd
);
3002 processed
= HandleNotify((int)wParam
, lParam
, &rc
.result
);
3005 // we only need to reply to WM_NOTIFYFORMAT manually when using MSLU,
3006 // otherwise DefWindowProc() does it perfectly fine for us, but MSLU
3007 // apparently doesn't always behave properly and needs some help
3008 #if wxUSE_UNICODE_MSLU && defined(NF_QUERY)
3009 case WM_NOTIFYFORMAT
:
3010 if ( lParam
== NF_QUERY
)
3013 rc
.result
= NFR_UNICODE
;
3016 #endif // wxUSE_UNICODE_MSLU
3018 // for these messages we must return true if process the message
3021 processed
= MSWOnDrawItem(wParam
, (WXDRAWITEMSTRUCT
*)lParam
);
3026 case WM_MEASUREITEM
:
3027 processed
= MSWOnMeasureItem(wParam
, (WXMEASUREITEMSTRUCT
*)lParam
);
3031 #endif // defined(WM_DRAWITEM)
3034 if ( !IsOfStandardClass() || HasFlag(wxWANTS_CHARS
) )
3036 // we always want to get the char events
3037 rc
.result
= DLGC_WANTCHARS
;
3039 if ( HasFlag(wxWANTS_CHARS
) )
3041 // in fact, we want everything
3042 rc
.result
|= DLGC_WANTARROWS
|
3049 //else: get the dlg code from the DefWindowProc()
3054 // If this has been processed by an event handler, return 0 now
3055 // (we've handled it).
3056 m_lastKeydownProcessed
= HandleKeyDown((WORD
) wParam
, lParam
);
3057 if ( m_lastKeydownProcessed
)
3066 // we consider these messages "not interesting" to OnChar, so
3067 // just don't do anything more with them
3077 // avoid duplicate messages to OnChar for these ASCII keys:
3078 // they will be translated by TranslateMessage() and received
3110 // but set processed to false, not true to still pass them
3111 // to the control's default window proc - otherwise
3112 // built-in keyboard handling won't work
3117 // special case of VK_APPS: treat it the same as right mouse
3118 // click because both usually pop up a context menu
3120 processed
= HandleMouseEvent(WM_RBUTTONDOWN
, -1, -1, 0);
3125 // do generate a CHAR event
3126 processed
= HandleChar((WORD
)wParam
, lParam
);
3129 if (message
== WM_SYSKEYDOWN
) // Let Windows still handle the SYSKEYs
3136 // special case of VK_APPS: treat it the same as right mouse button
3137 if ( wParam
== VK_APPS
)
3139 processed
= HandleMouseEvent(WM_RBUTTONUP
, -1, -1, 0);
3144 processed
= HandleKeyUp((WORD
) wParam
, lParam
);
3149 case WM_CHAR
: // Always an ASCII character
3150 if ( m_lastKeydownProcessed
)
3152 // The key was handled in the EVT_KEY_DOWN and handling
3153 // a key in an EVT_KEY_DOWN handler is meant, by
3154 // design, to prevent EVT_CHARs from happening
3155 m_lastKeydownProcessed
= false;
3160 processed
= HandleChar((WORD
)wParam
, lParam
, true);
3166 processed
= HandleHotKey((WORD
)wParam
, lParam
);
3168 #endif // wxUSE_HOTKEY
3173 processed
= HandleClipboardEvent(message
);
3181 UnpackScroll(wParam
, lParam
, &code
, &pos
, &hwnd
);
3183 processed
= MSWOnScroll(message
== WM_HSCROLL
? wxHORIZONTAL
3189 // CTLCOLOR messages are sent by children to query the parent for their
3191 #ifndef __WXMICROWIN__
3192 case WM_CTLCOLORMSGBOX
:
3193 case WM_CTLCOLOREDIT
:
3194 case WM_CTLCOLORLISTBOX
:
3195 case WM_CTLCOLORBTN
:
3196 case WM_CTLCOLORDLG
:
3197 case WM_CTLCOLORSCROLLBAR
:
3198 case WM_CTLCOLORSTATIC
:
3202 UnpackCtlColor(wParam
, lParam
, &hdc
, &hwnd
);
3204 processed
= HandleCtlColor(&rc
.hBrush
, (WXHDC
)hdc
, (WXHWND
)hwnd
);
3207 #endif // !__WXMICROWIN__
3209 case WM_SYSCOLORCHANGE
:
3210 // the return value for this message is ignored
3211 processed
= HandleSysColorChange();
3214 #if !defined(__WXWINCE__)
3215 case WM_DISPLAYCHANGE
:
3216 processed
= HandleDisplayChange();
3220 case WM_PALETTECHANGED
:
3221 processed
= HandlePaletteChanged((WXHWND
)wParam
);
3224 case WM_CAPTURECHANGED
:
3225 processed
= HandleCaptureChanged((WXHWND
)lParam
);
3228 case WM_SETTINGCHANGE
:
3229 processed
= HandleSettingChange(wParam
, lParam
);
3232 case WM_QUERYNEWPALETTE
:
3233 processed
= HandleQueryNewPalette();
3237 processed
= HandleEraseBkgnd((WXHDC
)wParam
);
3240 // we processed the message, i.e. erased the background
3245 #if !defined(__WXWINCE__)
3247 processed
= HandleDropFiles(wParam
);
3252 processed
= HandleInitDialog((WXHWND
)wParam
);
3256 // we never set focus from here
3261 #if !defined(__WXWINCE__)
3262 case WM_QUERYENDSESSION
:
3263 processed
= HandleQueryEndSession(lParam
, &rc
.allow
);
3267 processed
= HandleEndSession(wParam
!= 0, lParam
);
3270 case WM_GETMINMAXINFO
:
3271 processed
= HandleGetMinMaxInfo((MINMAXINFO
*)lParam
);
3276 processed
= HandleSetCursor((WXHWND
)wParam
,
3277 LOWORD(lParam
), // hit test
3278 HIWORD(lParam
)); // mouse msg
3282 // returning TRUE stops the DefWindowProc() from further
3283 // processing this message - exactly what we need because we've
3284 // just set the cursor.
3289 #if wxUSE_ACCESSIBILITY
3292 //WPARAM dwFlags = (WPARAM) (DWORD) wParam;
3293 LPARAM dwObjId
= (LPARAM
) (DWORD
) lParam
;
3295 if (dwObjId
== (LPARAM
)OBJID_CLIENT
&& GetOrCreateAccessible())
3297 return LresultFromObject(IID_IAccessible
, wParam
, (IUnknown
*) GetAccessible()->GetIAccessible());
3303 #if defined(WM_HELP)
3306 // by default, WM_HELP is propagated by DefWindowProc() upwards
3307 // to the window parent but as we do it ourselves already
3308 // (wxHelpEvent is derived from wxCommandEvent), we don't want
3309 // to get the other events if we process this message at all
3312 // WM_HELP doesn't use lParam under CE
3314 HELPINFO
* info
= (HELPINFO
*) lParam
;
3315 if ( info
->iContextType
== HELPINFO_WINDOW
)
3317 #endif // !__WXWINCE__
3318 wxHelpEvent helpEvent
3323 wxGetMousePosition() // what else?
3325 wxPoint(info
->MousePos
.x
, info
->MousePos
.y
)
3329 helpEvent
.SetEventObject(this);
3330 HandleWindowEvent(helpEvent
);
3333 else if ( info
->iContextType
== HELPINFO_MENUITEM
)
3335 wxHelpEvent
helpEvent(wxEVT_HELP
, info
->iCtrlId
);
3336 helpEvent
.SetEventObject(this);
3337 HandleWindowEvent(helpEvent
);
3340 else // unknown help event?
3344 #endif // !__WXWINCE__
3349 #if !defined(__WXWINCE__)
3350 case WM_CONTEXTMENU
:
3352 // we don't convert from screen to client coordinates as
3353 // the event may be handled by a parent window
3354 wxPoint
pt(GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
));
3356 wxContextMenuEvent
evtCtx(wxEVT_CONTEXT_MENU
, GetId(), pt
);
3358 // we could have got an event from our child, reflect it back
3359 // to it if this is the case
3360 wxWindowMSW
*win
= NULL
;
3361 WXHWND hWnd
= (WXHWND
)wParam
;
3362 if ( hWnd
!= m_hWnd
)
3364 win
= FindItemByHWND(hWnd
);
3370 evtCtx
.SetEventObject(win
);
3371 processed
= win
->HandleWindowEvent(evtCtx
);
3378 // we're only interested in our own menus, not MF_SYSMENU
3379 if ( HIWORD(wParam
) == MF_POPUP
)
3381 // handle menu chars for ownerdrawn menu items
3382 int i
= HandleMenuChar(toupper(LOWORD(wParam
)), lParam
);
3383 if ( i
!= wxNOT_FOUND
)
3385 rc
.result
= MAKELRESULT(i
, MNC_EXECUTE
);
3390 #endif // wxUSE_MENUS
3393 case WM_POWERBROADCAST
:
3396 processed
= HandlePower(wParam
, lParam
, &vetoed
);
3397 rc
.result
= processed
&& vetoed
? BROADCAST_QUERY_DENY
: TRUE
;
3400 #endif // __WXWINCE__
3403 // If we want the default themed border then we need to draw it ourselves
3406 wxUxThemeEngine
* theme
= wxUxThemeEngine::GetIfActive();
3407 const wxBorder border
= TranslateBorder(GetBorder());
3408 if (theme
&& border
== wxBORDER_THEME
)
3410 // first ask the widget to calculate the border size
3411 rc
.result
= MSWDefWindowProc(message
, wParam
, lParam
);
3414 // now alter the client size making room for drawing a
3419 NCCALCSIZE_PARAMS
*csparam
= (NCCALCSIZE_PARAMS
*)lParam
;
3420 rect
= &csparam
->rgrc
[0];
3424 rect
= (RECT
*)lParam
;
3427 wxUxThemeHandle
hTheme((const wxWindow
*)this, L
"EDIT");
3428 RECT rcClient
= { 0, 0, 0, 0 };
3429 wxClientDC
dc((wxWindow
*)this);
3430 wxMSWDCImpl
*impl
= (wxMSWDCImpl
*) dc
.GetImpl();
3432 if ( theme
->GetThemeBackgroundContentRect
3439 &rcClient
) == S_OK
)
3441 InflateRect(&rcClient
, -1, -1);
3443 rc
.result
= WVR_REDRAW
;
3451 wxUxThemeEngine
* theme
= wxUxThemeEngine::GetIfActive();
3452 const wxBorder border
= TranslateBorder(GetBorder());
3453 if (theme
&& border
== wxBORDER_THEME
)
3455 // first ask the widget to paint its non-client area, such as scrollbars, etc.
3456 rc
.result
= MSWDefWindowProc(message
, wParam
, lParam
);
3459 wxUxThemeHandle
hTheme((const wxWindow
*)this, L
"EDIT");
3460 wxWindowDC
dc((wxWindow
*)this);
3461 wxMSWDCImpl
*impl
= (wxMSWDCImpl
*) dc
.GetImpl();
3463 // Clip the DC so that you only draw on the non-client area
3465 wxCopyRectToRECT(GetSize(), rcBorder
);
3468 theme
->GetThemeBackgroundContentRect(
3469 hTheme
, GetHdcOf(*impl
), EP_EDITTEXT
, ETS_NORMAL
, &rcBorder
, &rcClient
);
3470 InflateRect(&rcClient
, -1, -1);
3472 ::ExcludeClipRect(GetHdcOf(*impl
), rcClient
.left
, rcClient
.top
,
3473 rcClient
.right
, rcClient
.bottom
);
3475 // Make sure the background is in a proper state
3476 if (theme
->IsThemeBackgroundPartiallyTransparent(hTheme
, EP_EDITTEXT
, ETS_NORMAL
))
3478 theme
->DrawThemeParentBackground(GetHwnd(), GetHdcOf(*impl
), &rcBorder
);
3484 nState
= ETS_DISABLED
;
3485 // should we check this?
3486 //else if ( ::GetWindowLong(GetHwnd(), GWL_STYLE) & ES_READONLY)
3487 // nState = ETS_READONLY;
3489 nState
= ETS_NORMAL
;
3490 theme
->DrawThemeBackground(hTheme
, GetHdcOf(*impl
), EP_EDITTEXT
, nState
, &rcBorder
, NULL
);
3495 #endif // wxUSE_UXTHEME
3498 // try a custom message handler
3499 const MSWMessageHandlers::const_iterator
3500 i
= gs_messageHandlers
.find(message
);
3501 if ( i
!= gs_messageHandlers
.end() )
3503 processed
= (*i
->second
)(this, message
, wParam
, lParam
);
3510 wxLogTrace(wxTraceMessages
, wxT("Forwarding %s to DefWindowProc."),
3511 wxGetMessageName(message
));
3512 #endif // __WXDEBUG__
3513 rc
.result
= MSWDefWindowProc(message
, wParam
, lParam
);
3519 // ----------------------------------------------------------------------------
3520 // wxWindow <-> HWND map
3521 // ----------------------------------------------------------------------------
3523 wxWindow
*wxFindWinFromHandle(HWND hwnd
)
3525 WindowHandles::const_iterator i
= gs_windowHandles
.find(hwnd
);
3526 return i
== gs_windowHandles
.end() ? NULL
: i
->second
;
3529 void wxAssociateWinWithHandle(HWND hwnd
, wxWindowMSW
*win
)
3531 // adding NULL hwnd is (first) surely a result of an error and
3532 // (secondly) breaks menu command processing
3533 wxCHECK_RET( hwnd
!= (HWND
)NULL
,
3534 wxT("attempt to add a NULL hwnd to window list ignored") );
3537 WindowHandles::const_iterator i
= gs_windowHandles
.find(hwnd
);
3538 if ( i
!= gs_windowHandles
.end() )
3540 if ( i
->second
!= win
)
3542 wxLogDebug(wxT("HWND %p already associated with another window (%s)"),
3543 hwnd
, win
->GetClassInfo()->GetClassName());
3545 //else: this actually happens currently because we associate the window
3546 // with its HWND during creation (if we create it) and also when
3547 // SubclassWin() is called later, this is ok
3549 #endif // __WXDEBUG__
3551 gs_windowHandles
[hwnd
] = (wxWindow
*)win
;
3554 void wxRemoveHandleAssociation(wxWindowMSW
*win
)
3556 gs_windowHandles
.erase(GetHwndOf(win
));
3559 // ----------------------------------------------------------------------------
3560 // various MSW speciic class dependent functions
3561 // ----------------------------------------------------------------------------
3563 // Default destroyer - override if you destroy it in some other way
3564 // (e.g. with MDI child windows)
3565 void wxWindowMSW::MSWDestroyWindow()
3569 bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint
& pos
,
3572 int& w
, int& h
) const
3574 // yes, those are just some arbitrary hardcoded numbers
3575 static const int DEFAULT_Y
= 200;
3577 bool nonDefault
= false;
3579 if ( pos
.x
== wxDefaultCoord
)
3581 // if x is set to CW_USEDEFAULT, y parameter is ignored anyhow so we
3582 // can just as well set it to CW_USEDEFAULT as well
3588 // OTOH, if x is not set to CW_USEDEFAULT, y shouldn't be set to it
3589 // neither because it is not handled as a special value by Windows then
3590 // and so we have to choose some default value for it
3592 y
= pos
.y
== wxDefaultCoord
? DEFAULT_Y
: pos
.y
;
3598 NB: there used to be some code here which set the initial size of the
3599 window to the client size of the parent if no explicit size was
3600 specified. This was wrong because wxWidgets programs often assume
3601 that they get a WM_SIZE (EVT_SIZE) upon creation, however this broke
3602 it. To see why, you should understand that Windows sends WM_SIZE from
3603 inside ::CreateWindow() anyhow. However, ::CreateWindow() is called
3604 from some base class ctor and so this WM_SIZE is not processed in the
3605 real class' OnSize() (because it's not fully constructed yet and the
3606 event goes to some base class OnSize() instead). So the WM_SIZE we
3607 rely on is the one sent when the parent frame resizes its children
3608 but here is the problem: if the child already has just the right
3609 size, nothing will happen as both wxWidgets and Windows check for
3610 this and ignore any attempts to change the window size to the size it
3611 already has - so no WM_SIZE would be sent.
3615 // we don't use CW_USEDEFAULT here for several reasons:
3617 // 1. it results in huge frames on modern screens (1000*800 is not
3618 // uncommon on my 1280*1024 screen) which is way too big for a half
3619 // empty frame of most of wxWidgets samples for example)
3621 // 2. it is buggy for frames with wxFRAME_TOOL_WINDOW style for which
3622 // the default is for whatever reason 8*8 which breaks client <->
3623 // window size calculations (it would be nice if it didn't, but it
3624 // does and the simplest way to fix it seemed to change the broken
3625 // default size anyhow)
3627 // 3. there is just no advantage in doing it: with x and y it is
3628 // possible that [future versions of] Windows position the new top
3629 // level window in some smart way which we can't do, but we can
3630 // guess a reasonably good size for a new window just as well
3633 // However, on PocketPC devices, we must use the default
3634 // size if possible.
3636 if (size
.x
== wxDefaultCoord
)
3640 if (size
.y
== wxDefaultCoord
)
3645 if ( size
.x
== wxDefaultCoord
|| size
.y
== wxDefaultCoord
)
3649 w
= WidthDefault(size
.x
);
3650 h
= HeightDefault(size
.y
);
3653 AdjustForParentClientOrigin(x
, y
);
3658 WXHWND
wxWindowMSW::MSWGetParent() const
3660 return m_parent
? m_parent
->GetHWND() : WXHWND(NULL
);
3663 bool wxWindowMSW::MSWCreate(const wxChar
*wclass
,
3664 const wxChar
*title
,
3668 WXDWORD extendedStyle
)
3670 // check a common bug in the user code: if the window is created with a
3671 // non-default ctor and Create() is called too, we'd create 2 HWND for a
3672 // single wxWindow object and this results in all sorts of trouble,
3673 // especially for wxTLWs
3674 wxCHECK_MSG( !m_hWnd
, true, "window can't be recreated" );
3676 // this can happen if this function is called using the return value of
3677 // wxApp::GetRegisteredClassName() which failed
3678 wxCHECK_MSG( wclass
, false, "failed to register window class?" );
3681 // choose the position/size for the new window
3683 (void)MSWGetCreateWindowCoords(pos
, size
, x
, y
, w
, h
);
3685 // controlId is menu handle for the top level windows, so set it to 0
3686 // unless we're creating a child window
3687 int controlId
= style
& WS_CHILD
? GetId() : 0;
3689 // for each class "Foo" we have we also have "FooNR" ("no repaint") class
3690 // which is the same but without CS_[HV]REDRAW class styles so using it
3691 // ensures that the window is not fully repainted on each resize
3692 wxString
className(wclass
);
3693 if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE
) )
3695 className
+= wxApp::GetNoRedrawClassSuffix();
3698 // do create the window
3699 wxWindowCreationHook
hook(this);
3701 m_hWnd
= (WXHWND
)::CreateWindowEx
3705 title
? title
: m_windowName
.wx_str(),
3708 (HWND
)MSWGetParent(),
3709 (HMENU
)wxUIntToPtr(controlId
),
3711 NULL
// no extra data
3716 wxLogSysError(_("Can't create window of class %s"), className
.c_str());
3721 SubclassWin(m_hWnd
);
3726 // ===========================================================================
3727 // MSW message handlers
3728 // ===========================================================================
3730 // ---------------------------------------------------------------------------
3732 // ---------------------------------------------------------------------------
3734 bool wxWindowMSW::HandleNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM
*result
)
3736 #ifndef __WXMICROWIN__
3737 LPNMHDR hdr
= (LPNMHDR
)lParam
;
3738 HWND hWnd
= hdr
->hwndFrom
;
3739 wxWindow
*win
= wxFindWinFromHandle(hWnd
);
3741 // if the control is one of our windows, let it handle the message itself
3744 return win
->MSWOnNotify(idCtrl
, lParam
, result
);
3747 // VZ: why did we do it? normally this is unnecessary and, besides, it
3748 // breaks the message processing for the toolbars because the tooltip
3749 // notifications were being forwarded to the toolbar child controls
3750 // (if it had any) before being passed to the toolbar itself, so in my
3751 // example the tooltip for the combobox was always shown instead of the
3752 // correct button tooltips
3754 // try all our children
3755 wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3758 wxWindow
*child
= node
->GetData();
3759 if ( child
->MSWOnNotify(idCtrl
, lParam
, result
) )
3764 node
= node
->GetNext();
3768 // by default, handle it ourselves
3769 return MSWOnNotify(idCtrl
, lParam
, result
);
3770 #else // __WXMICROWIN__
3777 bool wxWindowMSW::HandleTooltipNotify(WXUINT code
,
3779 const wxString
& ttip
)
3781 // I don't know why it happens, but the versions of comctl32.dll starting
3782 // from 4.70 sometimes send TTN_NEEDTEXTW even to ANSI programs (normally,
3783 // this message is supposed to be sent to Unicode programs only) -- hence
3784 // we need to handle it as well, otherwise no tooltips will be shown in
3787 if ( !(code
== (WXUINT
) TTN_NEEDTEXTA
|| code
== (WXUINT
) TTN_NEEDTEXTW
)
3790 // not a tooltip message or no tooltip to show anyhow
3795 LPTOOLTIPTEXT ttText
= (LPTOOLTIPTEXT
)lParam
;
3797 // We don't want to use the szText buffer because it has a limit of 80
3798 // bytes and this is not enough, especially for Unicode build where it
3799 // limits the tooltip string length to only 40 characters
3801 // The best would be, of course, to not impose any length limitations at
3802 // all but then the buffer would have to be dynamic and someone would have
3803 // to free it and we don't have the tooltip owner object here any more, so
3804 // for now use our own static buffer with a higher fixed max length.
3806 // Note that using a static buffer should not be a problem as only a single
3807 // tooltip can be shown at the same time anyhow.
3809 if ( code
== (WXUINT
) TTN_NEEDTEXTW
)
3811 // We need to convert tooltip from multi byte to Unicode on the fly.
3812 static wchar_t buf
[513];
3814 // Truncate tooltip length if needed as otherwise we might not have
3815 // enough space for it in the buffer and MultiByteToWideChar() would
3817 size_t tipLength
= wxMin(ttip
.length(), WXSIZEOF(buf
) - 1);
3819 // Convert to WideChar without adding the NULL character. The NULL
3820 // character is added afterwards (this is more efficient).
3821 int len
= ::MultiByteToWideChar
3833 wxLogLastError(_T("MultiByteToWideChar()"));
3837 ttText
->lpszText
= (LPSTR
) buf
;
3839 else // TTN_NEEDTEXTA
3840 #endif // !wxUSE_UNICODE
3842 // we get here if we got TTN_NEEDTEXTA (only happens in ANSI build) or
3843 // if we got TTN_NEEDTEXTW in Unicode build: in this case we just have
3844 // to copy the string we have into the buffer
3845 static wxChar buf
[513];
3846 wxStrlcpy(buf
, ttip
.c_str(), WXSIZEOF(buf
));
3847 ttText
->lpszText
= buf
;
3853 #endif // wxUSE_TOOLTIPS
3855 bool wxWindowMSW::MSWOnNotify(int WXUNUSED(idCtrl
),
3857 WXLPARAM
* WXUNUSED(result
))
3862 NMHDR
* hdr
= (NMHDR
*)lParam
;
3863 if ( HandleTooltipNotify(hdr
->code
, lParam
, m_tooltip
->GetTip()))
3870 wxUnusedVar(lParam
);
3871 #endif // wxUSE_TOOLTIPS
3876 // ---------------------------------------------------------------------------
3877 // end session messages
3878 // ---------------------------------------------------------------------------
3880 bool wxWindowMSW::HandleQueryEndSession(long logOff
, bool *mayEnd
)
3882 #ifdef ENDSESSION_LOGOFF
3883 wxCloseEvent
event(wxEVT_QUERY_END_SESSION
, wxID_ANY
);
3884 event
.SetEventObject(wxTheApp
);
3885 event
.SetCanVeto(true);
3886 event
.SetLoggingOff(logOff
== (long)ENDSESSION_LOGOFF
);
3888 bool rc
= wxTheApp
->ProcessEvent(event
);
3892 // we may end only if the app didn't veto session closing (double
3894 *mayEnd
= !event
.GetVeto();
3899 wxUnusedVar(logOff
);
3900 wxUnusedVar(mayEnd
);
3905 bool wxWindowMSW::HandleEndSession(bool endSession
, long logOff
)
3907 #ifdef ENDSESSION_LOGOFF
3908 // do nothing if the session isn't ending
3913 if ( (this != wxTheApp
->GetTopWindow()) )
3916 wxCloseEvent
event(wxEVT_END_SESSION
, wxID_ANY
);
3917 event
.SetEventObject(wxTheApp
);
3918 event
.SetCanVeto(false);
3919 event
.SetLoggingOff((logOff
& ENDSESSION_LOGOFF
) != 0);
3921 return wxTheApp
->ProcessEvent(event
);
3923 wxUnusedVar(endSession
);
3924 wxUnusedVar(logOff
);
3929 // ---------------------------------------------------------------------------
3930 // window creation/destruction
3931 // ---------------------------------------------------------------------------
3933 bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT
WXUNUSED_IN_WINCE(cs
),
3936 // VZ: why is this commented out for WinCE? If it doesn't support
3937 // WS_EX_CONTROLPARENT at all it should be somehow handled globally,
3938 // not with multiple #ifdef's!
3940 if ( ((CREATESTRUCT
*)cs
)->dwExStyle
& WS_EX_CONTROLPARENT
)
3941 EnsureParentHasControlParentStyle(GetParent());
3942 #endif // !__WXWINCE__
3949 bool wxWindowMSW::HandleDestroy()
3951 // delete our drop target if we've got one
3952 #if wxUSE_DRAG_AND_DROP
3953 if ( m_dropTarget
!= NULL
)
3955 m_dropTarget
->Revoke(m_hWnd
);
3957 delete m_dropTarget
;
3958 m_dropTarget
= NULL
;
3960 #endif // wxUSE_DRAG_AND_DROP
3962 // WM_DESTROY handled
3966 // ---------------------------------------------------------------------------
3968 // ---------------------------------------------------------------------------
3970 bool wxWindowMSW::HandleActivate(int state
,
3971 bool WXUNUSED(minimized
),
3972 WXHWND
WXUNUSED(activate
))
3974 wxActivateEvent
event(wxEVT_ACTIVATE
,
3975 (state
== WA_ACTIVE
) || (state
== WA_CLICKACTIVE
),
3977 event
.SetEventObject(this);
3979 return HandleWindowEvent(event
);
3982 bool wxWindowMSW::HandleSetFocus(WXHWND hwnd
)
3984 // Strangly enough, some controls get set focus events when they are being
3985 // deleted, even if they already had focus before.
3986 if ( m_isBeingDeleted
)
3991 // notify the parent keeping track of focus for the kbd navigation
3992 // purposes that we got it
3993 wxChildFocusEvent
eventFocus((wxWindow
*)this);
3994 (void)HandleWindowEvent(eventFocus
);
4000 m_caret
->OnSetFocus();
4002 #endif // wxUSE_CARET
4004 wxFocusEvent
event(wxEVT_SET_FOCUS
, m_windowId
);
4005 event
.SetEventObject(this);
4007 // wxFindWinFromHandle() may return NULL, it is ok
4008 event
.SetWindow(wxFindWinFromHandle(hwnd
));
4010 return HandleWindowEvent(event
);
4013 bool wxWindowMSW::HandleKillFocus(WXHWND hwnd
)
4019 m_caret
->OnKillFocus();
4021 #endif // wxUSE_CARET
4023 // Don't send the event when in the process of being deleted. This can
4024 // only cause problems if the event handler tries to access the object.
4025 if ( m_isBeingDeleted
)
4030 wxFocusEvent
event(wxEVT_KILL_FOCUS
, m_windowId
);
4031 event
.SetEventObject(this);
4033 // wxFindWinFromHandle() may return NULL, it is ok
4034 event
.SetWindow(wxFindWinFromHandle(hwnd
));
4036 return HandleWindowEvent(event
);
4039 // ---------------------------------------------------------------------------
4041 // ---------------------------------------------------------------------------
4043 void wxWindowMSW::SetLabel( const wxString
& label
)
4045 SetWindowText(GetHwnd(), label
.c_str());
4048 wxString
wxWindowMSW::GetLabel() const
4050 return wxGetWindowText(GetHWND());
4053 // ---------------------------------------------------------------------------
4055 // ---------------------------------------------------------------------------
4057 bool wxWindowMSW::HandleShow(bool show
, int WXUNUSED(status
))
4059 wxShowEvent
event(GetId(), show
);
4060 event
.SetEventObject(this);
4062 return HandleWindowEvent(event
);
4065 bool wxWindowMSW::HandleInitDialog(WXHWND
WXUNUSED(hWndFocus
))
4067 wxInitDialogEvent
event(GetId());
4068 event
.SetEventObject(this);
4070 return HandleWindowEvent(event
);
4073 bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam
)
4075 #if defined (__WXMICROWIN__) || defined(__WXWINCE__)
4076 wxUnusedVar(wParam
);
4078 #else // __WXMICROWIN__
4079 HDROP hFilesInfo
= (HDROP
) wParam
;
4081 // Get the total number of files dropped
4082 UINT gwFilesDropped
= ::DragQueryFile
4090 wxString
*files
= new wxString
[gwFilesDropped
];
4091 for ( UINT wIndex
= 0; wIndex
< gwFilesDropped
; wIndex
++ )
4093 // first get the needed buffer length (+1 for terminating NUL)
4094 size_t len
= ::DragQueryFile(hFilesInfo
, wIndex
, NULL
, 0) + 1;
4096 // and now get the file name
4097 ::DragQueryFile(hFilesInfo
, wIndex
,
4098 wxStringBuffer(files
[wIndex
], len
), len
);
4101 wxDropFilesEvent
event(wxEVT_DROP_FILES
, gwFilesDropped
, files
);
4102 event
.SetEventObject(this);
4105 DragQueryPoint(hFilesInfo
, (LPPOINT
) &dropPoint
);
4106 event
.m_pos
.x
= dropPoint
.x
;
4107 event
.m_pos
.y
= dropPoint
.y
;
4109 DragFinish(hFilesInfo
);
4111 return HandleWindowEvent(event
);
4116 bool wxWindowMSW::HandleSetCursor(WXHWND
WXUNUSED(hWnd
),
4118 int WXUNUSED(mouseMsg
))
4120 #ifndef __WXMICROWIN__
4121 // the logic is as follows:
4122 // 0. if we're busy, set the busy cursor (even for non client elements)
4123 // 1. don't set custom cursor for non client area of enabled windows
4124 // 2. ask user EVT_SET_CURSOR handler for the cursor
4125 // 3. if still no cursor but we're in a TLW, set the global cursor
4127 HCURSOR hcursor
= 0;
4130 hcursor
= wxGetCurrentBusyCursor();
4134 if ( nHitTest
!= HTCLIENT
)
4137 // first ask the user code - it may wish to set the cursor in some very
4138 // specific way (for example, depending on the current position)
4141 if ( !::GetCursorPosWinCE(&pt
))
4143 if ( !::GetCursorPos(&pt
) )
4146 wxLogLastError(wxT("GetCursorPos"));
4151 ScreenToClient(&x
, &y
);
4152 wxSetCursorEvent
event(x
, y
);
4154 bool processedEvtSetCursor
= HandleWindowEvent(event
);
4155 if ( processedEvtSetCursor
&& event
.HasCursor() )
4157 hcursor
= GetHcursorOf(event
.GetCursor());
4162 // the test for processedEvtSetCursor is here to prevent using
4163 // m_cursor if the user code caught EVT_SET_CURSOR() and returned
4164 // nothing from it - this is a way to say that our cursor shouldn't
4165 // be used for this point
4166 if ( !processedEvtSetCursor
&& m_cursor
.Ok() )
4168 hcursor
= GetHcursorOf(m_cursor
);
4171 if ( !hcursor
&& !GetParent() )
4173 const wxCursor
*cursor
= wxGetGlobalCursor();
4174 if ( cursor
&& cursor
->Ok() )
4176 hcursor
= GetHcursorOf(*cursor
);
4185 ::SetCursor(hcursor
);
4187 // cursor set, stop here
4190 #endif // __WXMICROWIN__
4192 // pass up the window chain
4196 bool wxWindowMSW::HandlePower(WXWPARAM
WXUNUSED_IN_WINCE(wParam
),
4197 WXLPARAM
WXUNUSED(lParam
),
4198 bool *WXUNUSED_IN_WINCE(vetoed
))
4204 wxEventType evtType
;
4207 case PBT_APMQUERYSUSPEND
:
4208 evtType
= wxEVT_POWER_SUSPENDING
;
4211 case PBT_APMQUERYSUSPENDFAILED
:
4212 evtType
= wxEVT_POWER_SUSPEND_CANCEL
;
4215 case PBT_APMSUSPEND
:
4216 evtType
= wxEVT_POWER_SUSPENDED
;
4219 case PBT_APMRESUMESUSPEND
:
4220 evtType
= wxEVT_POWER_RESUME
;
4224 wxLogDebug(_T("Unknown WM_POWERBROADCAST(%d) event"), wParam
);
4227 // these messages are currently not mapped to wx events
4228 case PBT_APMQUERYSTANDBY
:
4229 case PBT_APMQUERYSTANDBYFAILED
:
4230 case PBT_APMSTANDBY
:
4231 case PBT_APMRESUMESTANDBY
:
4232 case PBT_APMBATTERYLOW
:
4233 case PBT_APMPOWERSTATUSCHANGE
:
4234 case PBT_APMOEMEVENT
:
4235 case PBT_APMRESUMECRITICAL
:
4236 #ifdef PBT_APMRESUMEAUTOMATIC
4237 case PBT_APMRESUMEAUTOMATIC
:
4239 evtType
= wxEVT_NULL
;
4243 // don't handle unknown messages
4244 if ( evtType
== wxEVT_NULL
)
4247 // TODO: notify about PBTF_APMRESUMEFROMFAILURE in case of resume events?
4249 wxPowerEvent
event(evtType
);
4250 if ( !HandleWindowEvent(event
) )
4253 *vetoed
= event
.IsVetoed();
4259 bool wxWindowMSW::IsDoubleBuffered() const
4261 for ( const wxWindowMSW
*win
= this; win
; win
= win
->GetParent() )
4263 if ( wxHasWindowExStyle(win
, WS_EX_COMPOSITED
) )
4266 if ( win
->IsTopLevel() )
4273 void wxWindowMSW::SetDoubleBuffered(bool on
)
4275 // Get the current extended style bits
4276 long exstyle
= wxGetWindowExStyle(this);
4278 // Twiddle the bit as needed
4280 exstyle
|= WS_EX_COMPOSITED
;
4282 exstyle
&= ~WS_EX_COMPOSITED
;
4285 wxSetWindowExStyle(this, exstyle
);
4288 // ---------------------------------------------------------------------------
4289 // owner drawn stuff
4290 // ---------------------------------------------------------------------------
4292 #if (wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE) || \
4293 (wxUSE_CONTROLS && !defined(__WXUNIVERSAL__))
4294 #define WXUNUSED_UNLESS_ODRAWN(param) param
4296 #define WXUNUSED_UNLESS_ODRAWN(param)
4300 wxWindowMSW::MSWOnDrawItem(int WXUNUSED_UNLESS_ODRAWN(id
),
4301 WXDRAWITEMSTRUCT
* WXUNUSED_UNLESS_ODRAWN(itemStruct
))
4303 #if wxUSE_OWNER_DRAWN
4305 #if wxUSE_MENUS_NATIVE
4306 // is it a menu item?
4307 DRAWITEMSTRUCT
*pDrawStruct
= (DRAWITEMSTRUCT
*)itemStruct
;
4308 if ( id
== 0 && pDrawStruct
->CtlType
== ODT_MENU
)
4310 wxMenuItem
*pMenuItem
= (wxMenuItem
*)(pDrawStruct
->itemData
);
4312 // see comment before the same test in MSWOnMeasureItem() below
4316 wxCHECK_MSG( wxDynamicCast(pMenuItem
, wxMenuItem
),
4317 false, _T("MSWOnDrawItem: bad wxMenuItem pointer") );
4319 // prepare to call OnDrawItem(): notice using of wxDCTemp to prevent
4320 // the DC from being released
4321 wxDCTemp
dc((WXHDC
)pDrawStruct
->hDC
);
4322 wxRect
rect(pDrawStruct
->rcItem
.left
, pDrawStruct
->rcItem
.top
,
4323 pDrawStruct
->rcItem
.right
- pDrawStruct
->rcItem
.left
,
4324 pDrawStruct
->rcItem
.bottom
- pDrawStruct
->rcItem
.top
);
4326 return pMenuItem
->OnDrawItem
4330 (wxOwnerDrawn::wxODAction
)pDrawStruct
->itemAction
,
4331 (wxOwnerDrawn::wxODStatus
)pDrawStruct
->itemState
4334 #endif // wxUSE_MENUS_NATIVE
4336 #endif // USE_OWNER_DRAWN
4338 #if wxUSE_CONTROLS && !defined(__WXUNIVERSAL__)
4340 #if wxUSE_OWNER_DRAWN
4341 wxControl
*item
= wxDynamicCast(FindItem(id
), wxControl
);
4342 #else // !wxUSE_OWNER_DRAWN
4343 // we may still have owner-drawn buttons internally because we have to make
4344 // them owner-drawn to support colour change
4347 wxDynamicCast(FindItem(id
), wxButton
)
4352 #endif // USE_OWNER_DRAWN
4356 return item
->MSWOnDraw(itemStruct
);
4359 #endif // wxUSE_CONTROLS
4365 wxWindowMSW::MSWOnMeasureItem(int id
, WXMEASUREITEMSTRUCT
*itemStruct
)
4367 #if wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE
4368 // is it a menu item?
4369 MEASUREITEMSTRUCT
*pMeasureStruct
= (MEASUREITEMSTRUCT
*)itemStruct
;
4370 if ( id
== 0 && pMeasureStruct
->CtlType
== ODT_MENU
)
4372 wxMenuItem
*pMenuItem
= (wxMenuItem
*)(pMeasureStruct
->itemData
);
4374 // according to Carsten Fuchs the pointer may be NULL under XP if an
4375 // MDI child frame is initially maximized, see this for more info:
4376 // http://article.gmane.org/gmane.comp.lib.wxwidgets.general/27745
4378 // so silently ignore it instead of asserting
4382 wxCHECK_MSG( wxDynamicCast(pMenuItem
, wxMenuItem
),
4383 false, _T("MSWOnMeasureItem: bad wxMenuItem pointer") );
4386 bool rc
= pMenuItem
->OnMeasureItem(&w
, &h
);
4388 pMeasureStruct
->itemWidth
= w
;
4389 pMeasureStruct
->itemHeight
= h
;
4394 wxControl
*item
= wxDynamicCast(FindItem(id
), wxControl
);
4397 return item
->MSWOnMeasure(itemStruct
);
4401 wxUnusedVar(itemStruct
);
4402 #endif // wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE
4407 // ---------------------------------------------------------------------------
4408 // colours and palettes
4409 // ---------------------------------------------------------------------------
4411 bool wxWindowMSW::HandleSysColorChange()
4413 wxSysColourChangedEvent event
;
4414 event
.SetEventObject(this);
4416 (void)HandleWindowEvent(event
);
4418 // always let the system carry on the default processing to allow the
4419 // native controls to react to the colours update
4423 bool wxWindowMSW::HandleDisplayChange()
4425 wxDisplayChangedEvent event
;
4426 event
.SetEventObject(this);
4428 return HandleWindowEvent(event
);
4431 #ifndef __WXMICROWIN__
4433 bool wxWindowMSW::HandleCtlColor(WXHBRUSH
*brush
, WXHDC hDC
, WXHWND hWnd
)
4435 #if !wxUSE_CONTROLS || defined(__WXUNIVERSAL__)
4439 wxControl
*item
= wxDynamicCast(FindItemByHWND(hWnd
, true), wxControl
);
4442 *brush
= item
->MSWControlColor(hDC
, hWnd
);
4444 #endif // wxUSE_CONTROLS
4447 return *brush
!= NULL
;
4450 #endif // __WXMICROWIN__
4452 bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange
)
4455 // same as below except we don't respond to our own messages
4456 if ( hWndPalChange
!= GetHWND() )
4458 // check to see if we our our parents have a custom palette
4459 wxWindowMSW
*win
= this;
4460 while ( win
&& !win
->HasCustomPalette() )
4462 win
= win
->GetParent();
4465 if ( win
&& win
->HasCustomPalette() )
4467 // realize the palette to see whether redrawing is needed
4468 HDC hdc
= ::GetDC((HWND
) hWndPalChange
);
4469 win
->m_palette
.SetHPALETTE((WXHPALETTE
)
4470 ::SelectPalette(hdc
, GetHpaletteOf(win
->m_palette
), FALSE
));
4472 int result
= ::RealizePalette(hdc
);
4474 // restore the palette (before releasing the DC)
4475 win
->m_palette
.SetHPALETTE((WXHPALETTE
)
4476 ::SelectPalette(hdc
, GetHpaletteOf(win
->m_palette
), FALSE
));
4477 ::RealizePalette(hdc
);
4478 ::ReleaseDC((HWND
) hWndPalChange
, hdc
);
4480 // now check for the need to redraw
4482 ::InvalidateRect((HWND
) hWndPalChange
, NULL
, TRUE
);
4486 #endif // wxUSE_PALETTE
4488 wxPaletteChangedEvent
event(GetId());
4489 event
.SetEventObject(this);
4490 event
.SetChangedWindow(wxFindWinFromHandle(hWndPalChange
));
4492 return HandleWindowEvent(event
);
4495 bool wxWindowMSW::HandleCaptureChanged(WXHWND hWndGainedCapture
)
4497 // notify windows on the capture stack about lost capture
4498 // (see http://sourceforge.net/tracker/index.php?func=detail&aid=1153662&group_id=9863&atid=109863):
4499 wxWindowBase::NotifyCaptureLost();
4501 wxWindow
*win
= wxFindWinFromHandle(hWndGainedCapture
);
4502 wxMouseCaptureChangedEvent
event(GetId(), win
);
4503 event
.SetEventObject(this);
4504 return HandleWindowEvent(event
);
4507 bool wxWindowMSW::HandleSettingChange(WXWPARAM wParam
, WXLPARAM lParam
)
4509 // despite MSDN saying "(This message cannot be sent directly to a window.)"
4510 // we need to send this to child windows (it is only sent to top-level
4511 // windows) so {list,tree}ctrls can adjust their font size if necessary
4512 // this is exactly how explorer does it to enable the font size changes
4514 wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
4517 // top-level windows already get this message from the system
4518 wxWindow
*win
= node
->GetData();
4519 if ( !win
->IsTopLevel() )
4521 ::SendMessage(GetHwndOf(win
), WM_SETTINGCHANGE
, wParam
, lParam
);
4524 node
= node
->GetNext();
4527 // let the system handle it
4531 bool wxWindowMSW::HandleQueryNewPalette()
4535 // check to see if we our our parents have a custom palette
4536 wxWindowMSW
*win
= this;
4537 while (!win
->HasCustomPalette() && win
->GetParent()) win
= win
->GetParent();
4538 if (win
->HasCustomPalette()) {
4539 /* realize the palette to see whether redrawing is needed */
4540 HDC hdc
= ::GetDC((HWND
) GetHWND());
4541 win
->m_palette
.SetHPALETTE( (WXHPALETTE
)
4542 ::SelectPalette(hdc
, (HPALETTE
) win
->m_palette
.GetHPALETTE(), FALSE
) );
4544 int result
= ::RealizePalette(hdc
);
4545 /* restore the palette (before releasing the DC) */
4546 win
->m_palette
.SetHPALETTE( (WXHPALETTE
)
4547 ::SelectPalette(hdc
, (HPALETTE
) win
->m_palette
.GetHPALETTE(), TRUE
) );
4548 ::RealizePalette(hdc
);
4549 ::ReleaseDC((HWND
) GetHWND(), hdc
);
4550 /* now check for the need to redraw */
4552 ::InvalidateRect((HWND
) GetHWND(), NULL
, TRUE
);
4554 #endif // wxUSE_PALETTE
4556 wxQueryNewPaletteEvent
event(GetId());
4557 event
.SetEventObject(this);
4559 return HandleWindowEvent(event
) && event
.GetPaletteRealized();
4562 // Responds to colour changes: passes event on to children.
4563 void wxWindowMSW::OnSysColourChanged(wxSysColourChangedEvent
& WXUNUSED(event
))
4565 // the top level window also reset the standard colour map as it might have
4566 // changed (there is no need to do it for the non top level windows as we
4567 // only have to do it once)
4571 gs_hasStdCmap
= false;
4573 wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
4576 // Only propagate to non-top-level windows because Windows already
4577 // sends this event to all top-level ones
4578 wxWindow
*win
= node
->GetData();
4579 if ( !win
->IsTopLevel() )
4581 // we need to send the real WM_SYSCOLORCHANGE and not just trigger
4582 // EVT_SYS_COLOUR_CHANGED call because the latter wouldn't work for
4583 // the standard controls
4584 ::SendMessage(GetHwndOf(win
), WM_SYSCOLORCHANGE
, 0, 0);
4587 node
= node
->GetNext();
4591 extern wxCOLORMAP
*wxGetStdColourMap()
4593 static COLORREF s_stdColours
[wxSTD_COL_MAX
];
4594 static wxCOLORMAP s_cmap
[wxSTD_COL_MAX
];
4596 if ( !gs_hasStdCmap
)
4598 static bool s_coloursInit
= false;
4600 if ( !s_coloursInit
)
4602 // When a bitmap is loaded, the RGB values can change (apparently
4603 // because Windows adjusts them to care for the old programs always
4604 // using 0xc0c0c0 while the transparent colour for the new Windows
4605 // versions is different). But we do this adjustment ourselves so
4606 // we want to avoid Windows' "help" and for this we need to have a
4607 // reference bitmap which can tell us what the RGB values change
4609 wxLogNull logNo
; // suppress error if we couldn't load the bitmap
4610 wxBitmap
stdColourBitmap(_T("wxBITMAP_STD_COLOURS"));
4611 if ( stdColourBitmap
.Ok() )
4613 // the pixels in the bitmap must correspond to wxSTD_COL_XXX!
4614 wxASSERT_MSG( stdColourBitmap
.GetWidth() == wxSTD_COL_MAX
,
4615 _T("forgot to update wxBITMAP_STD_COLOURS!") );
4618 memDC
.SelectObject(stdColourBitmap
);
4621 for ( size_t i
= 0; i
< WXSIZEOF(s_stdColours
); i
++ )
4623 memDC
.GetPixel(i
, 0, &colour
);
4624 s_stdColours
[i
] = wxColourToRGB(colour
);
4627 else // wxBITMAP_STD_COLOURS couldn't be loaded
4629 s_stdColours
[0] = RGB(000,000,000); // black
4630 s_stdColours
[1] = RGB(128,128,128); // dark grey
4631 s_stdColours
[2] = RGB(192,192,192); // light grey
4632 s_stdColours
[3] = RGB(255,255,255); // white
4633 //s_stdColours[4] = RGB(000,000,255); // blue
4634 //s_stdColours[5] = RGB(255,000,255); // magenta
4637 s_coloursInit
= true;
4640 gs_hasStdCmap
= true;
4642 // create the colour map
4643 #define INIT_CMAP_ENTRY(col) \
4644 s_cmap[wxSTD_COL_##col].from = s_stdColours[wxSTD_COL_##col]; \
4645 s_cmap[wxSTD_COL_##col].to = ::GetSysColor(COLOR_##col)
4647 INIT_CMAP_ENTRY(BTNTEXT
);
4648 INIT_CMAP_ENTRY(BTNSHADOW
);
4649 INIT_CMAP_ENTRY(BTNFACE
);
4650 INIT_CMAP_ENTRY(BTNHIGHLIGHT
);
4652 #undef INIT_CMAP_ENTRY
4658 // ---------------------------------------------------------------------------
4660 // ---------------------------------------------------------------------------
4662 bool wxWindowMSW::HandlePaint()
4664 HRGN hRegion
= ::CreateRectRgn(0, 0, 0, 0); // Dummy call to get a handle
4666 wxLogLastError(wxT("CreateRectRgn"));
4667 if ( ::GetUpdateRgn(GetHwnd(), hRegion
, FALSE
) == ERROR
)
4668 wxLogLastError(wxT("GetUpdateRgn"));
4670 m_updateRegion
= wxRegion((WXHRGN
) hRegion
);
4672 wxPaintEvent
event(m_windowId
);
4673 event
.SetEventObject(this);
4675 bool processed
= HandleWindowEvent(event
);
4677 // note that we must generate NC event after the normal one as otherwise
4678 // BeginPaint() will happily overwrite our decorations with the background
4680 wxNcPaintEvent
eventNc(m_windowId
);
4681 eventNc
.SetEventObject(this);
4682 HandleWindowEvent(eventNc
);
4684 // don't keep an HRGN we don't need any longer (GetUpdateRegion() can only
4685 // be called from inside the event handlers called above)
4686 m_updateRegion
.Clear();
4691 // Can be called from an application's OnPaint handler
4692 void wxWindowMSW::OnPaint(wxPaintEvent
& event
)
4694 #ifdef __WXUNIVERSAL__
4697 HDC hDC
= (HDC
) wxPaintDCImpl::FindDCInCache((wxWindow
*) event
.GetEventObject());
4700 MSWDefWindowProc(WM_PAINT
, (WPARAM
) hDC
, 0);
4705 bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc
)
4707 wxDCTemp
dc(hdc
, GetClientSize());
4708 wxDCTempImpl
*impl
= (wxDCTempImpl
*) dc
.GetImpl();
4711 impl
->SetWindow((wxWindow
*)this);
4713 wxEraseEvent
event(m_windowId
, &dc
);
4714 event
.SetEventObject(this);
4715 bool rc
= HandleWindowEvent(event
);
4717 // must be called manually as ~wxDC doesn't do anything for wxDCTemp
4718 impl
->SelectOldObjects(hdc
);
4723 void wxWindowMSW::OnEraseBackground(wxEraseEvent
& event
)
4725 // standard non top level controls (i.e. except the dialogs) always erase
4726 // their background themselves in HandleCtlColor() or have some control-
4727 // specific ways to set the colours (common controls)
4728 if ( IsOfStandardClass() && !IsTopLevel() )
4734 if ( GetBackgroundStyle() == wxBG_STYLE_CUSTOM
)
4736 // don't skip the event here, custom background means that the app
4737 // is drawing it itself in its OnPaint(), so don't draw it at all
4738 // now to avoid flicker
4742 wxDC
*dc
= event
.GetDC();
4744 wxMSWDCImpl
*impl
= (wxMSWDCImpl
*) dc
->GetImpl();
4746 // do default background painting
4747 if ( !DoEraseBackground(GetHdcOf(*impl
)) )
4749 // let the system paint the background
4754 bool wxWindowMSW::DoEraseBackground(WXHDC hDC
)
4756 HBRUSH hbr
= (HBRUSH
)MSWGetBgBrush(hDC
);
4760 wxFillRect(GetHwnd(), (HDC
)hDC
, hbr
);
4766 wxWindowMSW::MSWGetBgBrushForChild(WXHDC
WXUNUSED(hDC
), WXHWND hWnd
)
4770 // our background colour applies to:
4771 // 1. this window itself, always
4772 // 2. all children unless the colour is "not inheritable"
4773 // 3. even if it is not inheritable, our immediate transparent
4774 // children should still inherit it -- but not any transparent
4775 // children because it would look wrong if a child of non
4776 // transparent child would show our bg colour when the child itself
4778 wxWindow
*win
= wxFindWinFromHandle(hWnd
);
4781 (win
&& win
->HasTransparentBackground() &&
4782 win
->GetParent() == this) )
4784 // draw children with the same colour as the parent
4786 brush
= wxTheBrushList
->FindOrCreateBrush(GetBackgroundColour());
4788 return (WXHBRUSH
)GetHbrushOf(*brush
);
4795 WXHBRUSH
wxWindowMSW::MSWGetBgBrush(WXHDC hDC
, WXHWND hWndToPaint
)
4798 hWndToPaint
= GetHWND();
4800 for ( wxWindowMSW
*win
= this; win
; win
= win
->GetParent() )
4802 WXHBRUSH hBrush
= win
->MSWGetBgBrushForChild(hDC
, hWndToPaint
);
4806 // background is not inherited beyond top level windows
4807 if ( win
->IsTopLevel() )
4814 bool wxWindowMSW::HandlePrintClient(WXHDC hDC
)
4816 // we receive this message when DrawThemeParentBackground() is
4817 // called from def window proc of several controls under XP and we
4818 // must draw properly themed background here
4820 // note that naively I'd expect filling the client rect with the
4821 // brush returned by MSWGetBgBrush() work -- but for some reason it
4822 // doesn't and we have to call parents MSWPrintChild() which is
4823 // supposed to call DrawThemeBackground() with appropriate params
4825 // also note that in this case lParam == PRF_CLIENT but we're
4826 // clearly expected to paint the background and nothing else!
4828 if ( IsTopLevel() || InheritsBackgroundColour() )
4831 // sometimes we don't want the parent to handle it at all, instead
4832 // return whatever value this window wants
4833 if ( !MSWShouldPropagatePrintChild() )
4834 return MSWPrintChild(hDC
, (wxWindow
*)this);
4836 for ( wxWindow
*win
= GetParent(); win
; win
= win
->GetParent() )
4838 if ( win
->MSWPrintChild(hDC
, (wxWindow
*)this) )
4841 if ( win
->IsTopLevel() || win
->InheritsBackgroundColour() )
4848 // ---------------------------------------------------------------------------
4849 // moving and resizing
4850 // ---------------------------------------------------------------------------
4852 bool wxWindowMSW::HandleMinimize()
4854 wxIconizeEvent
event(m_windowId
);
4855 event
.SetEventObject(this);
4857 return HandleWindowEvent(event
);
4860 bool wxWindowMSW::HandleMaximize()
4862 wxMaximizeEvent
event(m_windowId
);
4863 event
.SetEventObject(this);
4865 return HandleWindowEvent(event
);
4868 bool wxWindowMSW::HandleMove(int x
, int y
)
4871 wxMoveEvent
event(point
, m_windowId
);
4872 event
.SetEventObject(this);
4874 return HandleWindowEvent(event
);
4877 bool wxWindowMSW::HandleMoving(wxRect
& rect
)
4879 wxMoveEvent
event(rect
, m_windowId
);
4880 event
.SetEventObject(this);
4882 bool rc
= HandleWindowEvent(event
);
4884 rect
= event
.GetRect();
4888 bool wxWindowMSW::HandleEnterSizeMove()
4890 wxMoveEvent
event(wxPoint(0,0), m_windowId
);
4891 event
.SetEventType(wxEVT_MOVE_START
);
4892 event
.SetEventObject(this);
4894 return HandleWindowEvent(event
);
4897 bool wxWindowMSW::HandleExitSizeMove()
4899 wxMoveEvent
event(wxPoint(0,0), m_windowId
);
4900 event
.SetEventType(wxEVT_MOVE_END
);
4901 event
.SetEventObject(this);
4903 return HandleWindowEvent(event
);
4906 bool wxWindowMSW::HandleSize(int WXUNUSED(w
), int WXUNUSED(h
), WXUINT wParam
)
4908 #if USE_DEFERRED_SIZING
4909 // when we resize this window, its children are probably going to be
4910 // repositioned as well, prepare to use DeferWindowPos() for them
4911 int numChildren
= 0;
4912 for ( HWND child
= ::GetWindow(GetHwndOf(this), GW_CHILD
);
4914 child
= ::GetWindow(child
, GW_HWNDNEXT
) )
4919 // Protect against valid m_hDWP being overwritten
4920 bool useDefer
= false;
4922 if ( numChildren
> 1 )
4926 m_hDWP
= (WXHANDLE
)::BeginDeferWindowPos(numChildren
);
4929 wxLogLastError(_T("BeginDeferWindowPos"));
4935 #endif // USE_DEFERRED_SIZING
4937 // update this window size
4938 bool processed
= false;
4942 wxFAIL_MSG( _T("unexpected WM_SIZE parameter") );
4943 // fall through nevertheless
4947 // we're not interested in these messages at all
4950 case SIZE_MINIMIZED
:
4951 processed
= HandleMinimize();
4954 case SIZE_MAXIMIZED
:
4955 /* processed = */ HandleMaximize();
4956 // fall through to send a normal size event as well
4959 // don't use w and h parameters as they specify the client size
4960 // while according to the docs EVT_SIZE handler is supposed to
4961 // receive the total size
4962 wxSizeEvent
event(GetSize(), m_windowId
);
4963 event
.SetEventObject(this);
4965 processed
= HandleWindowEvent(event
);
4968 #if USE_DEFERRED_SIZING
4969 // and finally change the positions of all child windows at once
4970 if ( useDefer
&& m_hDWP
)
4972 // reset m_hDWP to NULL so that child windows don't try to use our
4973 // m_hDWP after we call EndDeferWindowPos() on it (this shouldn't
4974 // happen anyhow normally but who knows what weird flow of control we
4975 // may have depending on what the users EVT_SIZE handler does...)
4976 HDWP hDWP
= (HDWP
)m_hDWP
;
4979 // do put all child controls in place at once
4980 if ( !::EndDeferWindowPos(hDWP
) )
4982 wxLogLastError(_T("EndDeferWindowPos"));
4985 // Reset our children's pending pos/size values.
4986 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
4988 node
= node
->GetNext() )
4990 wxWindowMSW
*child
= node
->GetData();
4991 child
->m_pendingPosition
= wxDefaultPosition
;
4992 child
->m_pendingSize
= wxDefaultSize
;
4995 #endif // USE_DEFERRED_SIZING
5000 bool wxWindowMSW::HandleSizing(wxRect
& rect
)
5002 wxSizeEvent
event(rect
, m_windowId
);
5003 event
.SetEventObject(this);
5005 bool rc
= HandleWindowEvent(event
);
5007 rect
= event
.GetRect();
5011 bool wxWindowMSW::HandleGetMinMaxInfo(void *WXUNUSED_IN_WINCE(mmInfo
))
5016 MINMAXINFO
*info
= (MINMAXINFO
*)mmInfo
;
5020 int minWidth
= GetMinWidth(),
5021 minHeight
= GetMinHeight(),
5022 maxWidth
= GetMaxWidth(),
5023 maxHeight
= GetMaxHeight();
5025 if ( minWidth
!= wxDefaultCoord
)
5027 info
->ptMinTrackSize
.x
= minWidth
;
5031 if ( minHeight
!= wxDefaultCoord
)
5033 info
->ptMinTrackSize
.y
= minHeight
;
5037 if ( maxWidth
!= wxDefaultCoord
)
5039 info
->ptMaxTrackSize
.x
= maxWidth
;
5043 if ( maxHeight
!= wxDefaultCoord
)
5045 info
->ptMaxTrackSize
.y
= maxHeight
;
5053 // ---------------------------------------------------------------------------
5055 // ---------------------------------------------------------------------------
5057 bool wxWindowMSW::HandleCommand(WXWORD id_
, WXWORD cmd
, WXHWND control
)
5059 // sign extend to int from short before comparing with the other int ids
5060 int id
= (signed short)id_
;
5062 #if wxUSE_MENUS_NATIVE
5063 if ( !cmd
&& wxCurrentPopupMenu
)
5065 wxMenu
*popupMenu
= wxCurrentPopupMenu
;
5066 wxCurrentPopupMenu
= NULL
;
5068 return popupMenu
->MSWCommand(cmd
, id
);
5070 #endif // wxUSE_MENUS_NATIVE
5072 wxWindow
*win
= NULL
;
5074 // first try to find it from HWND - this works even with the broken
5075 // programs using the same ids for different controls
5078 win
= wxFindWinFromHandle(control
);
5089 return win
->MSWCommand(cmd
, id
);
5092 // the messages sent from the in-place edit control used by the treectrl
5093 // for label editing have id == 0, but they should _not_ be treated as menu
5094 // messages (they are EN_XXX ones, in fact) so don't translate anything
5095 // coming from a control to wxEVT_COMMAND_MENU_SELECTED
5098 wxCommandEvent
event(wxEVT_COMMAND_MENU_SELECTED
, id
);
5099 event
.SetEventObject(this);
5102 return HandleWindowEvent(event
);
5106 #if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__)
5107 // the text ctrl which is logically part of wxSpinCtrl sends WM_COMMAND
5108 // notifications to its parent which we want to reflect back to
5110 wxSpinCtrl
*spin
= wxSpinCtrl::GetSpinForTextCtrl(control
);
5111 if ( spin
&& spin
->ProcessTextCommand(cmd
, id
) )
5113 #endif // wxUSE_SPINCTRL
5115 #if wxUSE_CHOICE && defined(__SMARTPHONE__)
5116 // the listbox ctrl which is logically part of wxChoice sends WM_COMMAND
5117 // notifications to its parent which we want to reflect back to
5119 wxChoice
*choice
= wxChoice::GetChoiceForListBox(control
);
5120 if ( choice
&& choice
->MSWCommand(cmd
, id
) )
5128 // ---------------------------------------------------------------------------
5130 // ---------------------------------------------------------------------------
5132 void wxWindowMSW::InitMouseEvent(wxMouseEvent
& event
,
5136 // our client coords are not quite the same as Windows ones
5137 wxPoint pt
= GetClientAreaOrigin();
5138 event
.m_x
= x
- pt
.x
;
5139 event
.m_y
= y
- pt
.y
;
5141 event
.m_shiftDown
= (flags
& MK_SHIFT
) != 0;
5142 event
.m_controlDown
= (flags
& MK_CONTROL
) != 0;
5143 event
.m_leftDown
= (flags
& MK_LBUTTON
) != 0;
5144 event
.m_middleDown
= (flags
& MK_MBUTTON
) != 0;
5145 event
.m_rightDown
= (flags
& MK_RBUTTON
) != 0;
5146 #ifdef wxHAS_XBUTTON
5147 event
.m_aux1Down
= (flags
& MK_XBUTTON1
) != 0;
5148 event
.m_aux2Down
= (flags
& MK_XBUTTON2
) != 0;
5149 #endif // wxHAS_XBUTTON
5150 event
.m_altDown
= ::wxIsAltDown();
5153 event
.SetTimestamp(::GetMessageTime());
5156 event
.SetEventObject(this);
5157 event
.SetId(GetId());
5159 #if wxUSE_MOUSEEVENT_HACK
5160 gs_lastMouseEvent
.pos
= ClientToScreen(wxPoint(x
, y
));
5161 gs_lastMouseEvent
.type
= event
.GetEventType();
5162 #endif // wxUSE_MOUSEEVENT_HACK
5166 // Windows doesn't send the mouse events to the static controls (which are
5167 // transparent in the sense that their WM_NCHITTEST handler returns
5168 // HTTRANSPARENT) at all but we want all controls to receive the mouse events
5169 // and so we manually check if we don't have a child window under mouse and if
5170 // we do, send the event to it instead of the window Windows had sent WM_XXX
5173 // Notice that this is not done for the mouse move events because this could
5174 // (would?) be too slow, but only for clicks which means that the static texts
5175 // still don't get move, enter nor leave events.
5176 static wxWindowMSW
*FindWindowForMouseEvent(wxWindowMSW
*win
, int *x
, int *y
)
5178 wxCHECK_MSG( x
&& y
, win
, _T("NULL pointer in FindWindowForMouseEvent") );
5180 // first try to find a non transparent child: this allows us to send events
5181 // to a static text which is inside a static box, for example
5182 POINT pt
= { *x
, *y
};
5183 HWND hwnd
= GetHwndOf(win
),
5187 hwndUnderMouse
= ::ChildWindowFromPoint
5193 hwndUnderMouse
= ::ChildWindowFromPointEx
5203 if ( !hwndUnderMouse
|| hwndUnderMouse
== hwnd
)
5205 // now try any child window at all
5206 hwndUnderMouse
= ::ChildWindowFromPoint(hwnd
, pt
);
5209 // check that we have a child window which is susceptible to receive mouse
5210 // events: for this it must be shown and enabled
5211 if ( hwndUnderMouse
&&
5212 hwndUnderMouse
!= hwnd
&&
5213 ::IsWindowVisible(hwndUnderMouse
) &&
5214 ::IsWindowEnabled(hwndUnderMouse
) )
5216 wxWindow
*winUnderMouse
= wxFindWinFromHandle(hwndUnderMouse
);
5217 if ( winUnderMouse
)
5219 // translate the mouse coords to the other window coords
5220 win
->ClientToScreen(x
, y
);
5221 winUnderMouse
->ScreenToClient(x
, y
);
5223 win
= winUnderMouse
;
5229 #endif // __WXWINCE__
5231 bool wxWindowMSW::HandleMouseEvent(WXUINT msg
, int x
, int y
, WXUINT flags
)
5233 // the mouse events take consecutive IDs from WM_MOUSEFIRST to
5234 // WM_MOUSELAST, so it's enough to subtract WM_MOUSEMOVE == WM_MOUSEFIRST
5235 // from the message id and take the value in the table to get wxWin event
5237 static const wxEventType eventsMouse
[] =
5248 wxEVT_MIDDLE_DCLICK
,
5249 0, // this one is for wxEVT_MOTION which is not used here
5258 #ifdef wxHAS_XBUTTON
5259 // the same messages are used for both auxillary mouse buttons so we need
5260 // to adjust the index manually
5263 case WM_XBUTTONDOWN
:
5265 case WM_XBUTTONDBLCLK
:
5266 if ( flags
& MK_XBUTTON2
)
5267 msg
+= wxEVT_AUX2_DOWN
- wxEVT_AUX1_DOWN
;
5269 #endif // wxHAS_XBUTTON
5271 wxMouseEvent
event(eventsMouse
[msg
- WM_MOUSEMOVE
]);
5272 InitMouseEvent(event
, x
, y
, flags
);
5274 return HandleWindowEvent(event
);
5277 bool wxWindowMSW::HandleMouseMove(int x
, int y
, WXUINT flags
)
5279 if ( !m_mouseInWindow
)
5281 // it would be wrong to assume that just because we get a mouse move
5282 // event that the mouse is inside the window: although this is usually
5283 // true, it is not if we had captured the mouse, so we need to check
5284 // the mouse coordinates here
5285 if ( !HasCapture() || IsMouseInWindow() )
5287 // Generate an ENTER event
5288 m_mouseInWindow
= true;
5290 #ifdef HAVE_TRACKMOUSEEVENT
5291 typedef BOOL (WINAPI
*_TrackMouseEvent_t
)(LPTRACKMOUSEEVENT
);
5293 static const _TrackMouseEvent_t
5294 s_pfn_TrackMouseEvent
= _TrackMouseEvent
;
5295 #else // !__WXWINCE__
5296 static _TrackMouseEvent_t s_pfn_TrackMouseEvent
;
5297 static bool s_initDone
= false;
5300 // see comment in wxApp::GetComCtl32Version() explaining the
5301 // use of wxLoadedDLL
5302 wxLoadedDLL
dllComCtl32(_T("comctl32.dll"));
5303 if ( dllComCtl32
.IsLoaded() )
5305 s_pfn_TrackMouseEvent
= (_TrackMouseEvent_t
)
5306 dllComCtl32
.RawGetSymbol(_T("_TrackMouseEvent"));
5312 if ( s_pfn_TrackMouseEvent
)
5313 #endif // __WXWINCE__/!__WXWINCE__
5315 WinStruct
<TRACKMOUSEEVENT
> trackinfo
;
5317 trackinfo
.dwFlags
= TME_LEAVE
;
5318 trackinfo
.hwndTrack
= GetHwnd();
5320 (*s_pfn_TrackMouseEvent
)(&trackinfo
);
5322 #endif // HAVE_TRACKMOUSEEVENT
5324 wxMouseEvent
event(wxEVT_ENTER_WINDOW
);
5325 InitMouseEvent(event
, x
, y
, flags
);
5327 (void)HandleWindowEvent(event
);
5330 #ifdef HAVE_TRACKMOUSEEVENT
5331 else // mouse not in window
5333 // Check if we need to send a LEAVE event
5334 // Windows doesn't send WM_MOUSELEAVE if the mouse has been captured so
5335 // send it here if we are using native mouse leave tracking
5336 if ( HasCapture() && !IsMouseInWindow() )
5338 GenerateMouseLeave();
5341 #endif // HAVE_TRACKMOUSEEVENT
5343 #if wxUSE_MOUSEEVENT_HACK
5344 // Windows often generates mouse events even if mouse position hasn't
5345 // changed (http://article.gmane.org/gmane.comp.lib.wxwidgets.devel/66576)
5347 // Filter this out as it can result in unexpected behaviour compared to
5349 if ( gs_lastMouseEvent
.type
== wxEVT_RIGHT_DOWN
||
5350 gs_lastMouseEvent
.type
== wxEVT_LEFT_DOWN
||
5351 gs_lastMouseEvent
.type
== wxEVT_MIDDLE_DOWN
||
5352 gs_lastMouseEvent
.type
== wxEVT_MOTION
)
5354 if ( ClientToScreen(wxPoint(x
, y
)) == gs_lastMouseEvent
.pos
)
5356 gs_lastMouseEvent
.type
= wxEVT_MOTION
;
5361 #endif // wxUSE_MOUSEEVENT_HACK
5363 return HandleMouseEvent(WM_MOUSEMOVE
, x
, y
, flags
);
5367 bool wxWindowMSW::HandleMouseWheel(WXWPARAM wParam
, WXLPARAM lParam
)
5369 #if wxUSE_MOUSEWHEEL
5370 // notice that WM_MOUSEWHEEL position is in screen coords (as it's
5371 // forwarded up to the parent by DefWindowProc()) and not in the client
5372 // ones as all the other messages, translate them to the client coords for
5375 pt
= ScreenToClient(wxPoint(GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
)));
5376 wxMouseEvent
event(wxEVT_MOUSEWHEEL
);
5377 InitMouseEvent(event
, pt
.x
, pt
.y
, LOWORD(wParam
));
5378 event
.m_wheelRotation
= (short)HIWORD(wParam
);
5379 event
.m_wheelDelta
= WHEEL_DELTA
;
5381 static int s_linesPerRotation
= -1;
5382 if ( s_linesPerRotation
== -1 )
5384 if ( !::SystemParametersInfo(SPI_GETWHEELSCROLLLINES
, 0,
5385 &s_linesPerRotation
, 0))
5387 // this is not supposed to happen
5388 wxLogLastError(_T("SystemParametersInfo(GETWHEELSCROLLLINES)"));
5390 // the default is 3, so use it if SystemParametersInfo() failed
5391 s_linesPerRotation
= 3;
5395 event
.m_linesPerAction
= s_linesPerRotation
;
5396 return HandleWindowEvent(event
);
5398 #else // !wxUSE_MOUSEWHEEL
5399 wxUnusedVar(wParam
);
5400 wxUnusedVar(lParam
);
5403 #endif // wxUSE_MOUSEWHEEL/!wxUSE_MOUSEWHEEL
5406 void wxWindowMSW::GenerateMouseLeave()
5408 m_mouseInWindow
= false;
5411 if ( wxIsShiftDown() )
5413 if ( wxIsCtrlDown() )
5414 state
|= MK_CONTROL
;
5416 // Only the high-order bit should be tested
5417 if ( GetKeyState( VK_LBUTTON
) & (1<<15) )
5418 state
|= MK_LBUTTON
;
5419 if ( GetKeyState( VK_MBUTTON
) & (1<<15) )
5420 state
|= MK_MBUTTON
;
5421 if ( GetKeyState( VK_RBUTTON
) & (1<<15) )
5422 state
|= MK_RBUTTON
;
5426 if ( !::GetCursorPosWinCE(&pt
) )
5428 if ( !::GetCursorPos(&pt
) )
5431 wxLogLastError(_T("GetCursorPos"));
5434 // we need to have client coordinates here for symmetry with
5435 // wxEVT_ENTER_WINDOW
5436 RECT rect
= wxGetWindowRect(GetHwnd());
5440 wxMouseEvent
event(wxEVT_LEAVE_WINDOW
);
5441 InitMouseEvent(event
, pt
.x
, pt
.y
, state
);
5443 (void)HandleWindowEvent(event
);
5446 // ---------------------------------------------------------------------------
5447 // keyboard handling
5448 // ---------------------------------------------------------------------------
5450 // create the key event of the given type for the given key - used by
5451 // HandleChar and HandleKeyDown/Up
5452 wxKeyEvent
wxWindowMSW::CreateKeyEvent(wxEventType evType
,
5455 WXWPARAM wParam
) const
5457 wxKeyEvent
event(evType
);
5458 event
.SetId(GetId());
5459 event
.m_shiftDown
= wxIsShiftDown();
5460 event
.m_controlDown
= wxIsCtrlDown();
5461 event
.m_altDown
= (HIWORD(lParam
) & KF_ALTDOWN
) == KF_ALTDOWN
;
5463 event
.SetEventObject((wxWindow
*)this); // const_cast
5464 event
.m_keyCode
= id
;
5466 event
.m_uniChar
= (wxChar
) wParam
;
5468 event
.m_rawCode
= (wxUint32
) wParam
;
5469 event
.m_rawFlags
= (wxUint32
) lParam
;
5471 event
.SetTimestamp(::GetMessageTime());
5474 // translate the position to client coords
5477 GetCursorPosWinCE(&pt
);
5482 GetWindowRect(GetHwnd(),&rect
);
5492 // isASCII is true only when we're called from WM_CHAR handler and not from
5494 bool wxWindowMSW::HandleChar(WXWPARAM wParam
, WXLPARAM lParam
, bool isASCII
)
5501 else // we're called from WM_KEYDOWN
5503 // don't pass lParam to wxCharCodeMSWToWX() here because we don't want
5504 // to get numpad key codes: CHAR events should use the logical keys
5505 // such as WXK_HOME instead of WXK_NUMPAD_HOME which is for KEY events
5506 id
= wxCharCodeMSWToWX(wParam
);
5509 // it's ASCII and will be processed here only when called from
5510 // WM_CHAR (i.e. when isASCII = true), don't process it now
5515 wxKeyEvent
event(CreateKeyEvent(wxEVT_CHAR
, id
, lParam
, wParam
));
5517 // the alphanumeric keys produced by pressing AltGr+something on European
5518 // keyboards have both Ctrl and Alt modifiers which may confuse the user
5519 // code as, normally, keys with Ctrl and/or Alt don't result in anything
5520 // alphanumeric, so pretend that there are no modifiers at all (the
5521 // KEY_DOWN event would still have the correct modifiers if they're really
5523 if ( event
.m_controlDown
&& event
.m_altDown
&&
5524 (id
>= 32 && id
< 256) )
5526 event
.m_controlDown
=
5527 event
.m_altDown
= false;
5530 return HandleWindowEvent(event
);
5533 bool wxWindowMSW::HandleKeyDown(WXWPARAM wParam
, WXLPARAM lParam
)
5535 int id
= wxCharCodeMSWToWX(wParam
, lParam
);
5539 // normal ASCII char
5543 wxKeyEvent
event(CreateKeyEvent(wxEVT_KEY_DOWN
, id
, lParam
, wParam
));
5544 return HandleWindowEvent(event
);
5547 bool wxWindowMSW::HandleKeyUp(WXWPARAM wParam
, WXLPARAM lParam
)
5549 int id
= wxCharCodeMSWToWX(wParam
, lParam
);
5553 // normal ASCII char
5557 wxKeyEvent
event(CreateKeyEvent(wxEVT_KEY_UP
, id
, lParam
, wParam
));
5558 return HandleWindowEvent(event
);
5562 int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel
),
5563 WXLPARAM
WXUNUSED_IN_WINCE(lParam
))
5565 // FIXME: implement GetMenuItemCount for WinCE, possibly
5566 // in terms of GetMenuItemInfo
5568 const HMENU hmenu
= (HMENU
)lParam
;
5572 mii
.cbSize
= sizeof(MENUITEMINFO
);
5574 // we could use MIIM_FTYPE here as we only need to know if the item is
5575 // ownerdrawn or not and not dwTypeData which MIIM_TYPE also returns, but
5576 // MIIM_FTYPE is not supported under Win95
5577 mii
.fMask
= MIIM_TYPE
| MIIM_DATA
;
5579 // find if we have this letter in any owner drawn item
5580 const int count
= ::GetMenuItemCount(hmenu
);
5581 for ( int i
= 0; i
< count
; i
++ )
5583 // previous loop iteration could modify it, reset it back before
5584 // calling GetMenuItemInfo() to prevent it from overflowing dwTypeData
5587 if ( ::GetMenuItemInfo(hmenu
, i
, TRUE
, &mii
) )
5589 if ( mii
.fType
== MFT_OWNERDRAW
)
5591 // dwItemData member of the MENUITEMINFO is a
5592 // pointer to the associated wxMenuItem -- see the
5593 // menu creation code
5594 wxMenuItem
*item
= (wxMenuItem
*)mii
.dwItemData
;
5596 const wxChar
*p
= wxStrchr(item
->GetItemLabel().wx_str(), _T('&'));
5599 if ( *p
== _T('&') )
5601 // this is not the accel char, find the real one
5602 p
= wxStrchr(p
+ 1, _T('&'));
5604 else // got the accel char
5606 // FIXME-UNICODE: this comparison doesn't risk to work
5607 // for non ASCII accelerator characters I'm afraid, but
5609 if ( (wchar_t)wxToupper(*p
) == (wchar_t)chAccel
)
5615 // this one doesn't match
5622 else // failed to get the menu text?
5624 // it's not fatal, so don't show error, but still log it
5625 wxLogLastError(_T("GetMenuItemInfo"));
5632 #endif // wxUSE_MENUS
5634 bool wxWindowMSW::HandleClipboardEvent(WXUINT nMsg
)
5636 const wxEventType type
= nMsg
== WM_CUT
? wxEVT_COMMAND_TEXT_CUT
5637 : nMsg
== WM_COPY
? wxEVT_COMMAND_TEXT_COPY
5638 : /* nMsg == WM_PASTE */ wxEVT_COMMAND_TEXT_PASTE
;
5639 wxClipboardTextEvent
evt(type
, GetId());
5641 evt
.SetEventObject(this);
5643 return HandleWindowEvent(evt
);
5646 // ---------------------------------------------------------------------------
5648 // ---------------------------------------------------------------------------
5650 bool wxWindowMSW::HandleJoystickEvent(WXUINT msg
, int x
, int y
, WXUINT flags
)
5654 if ( flags
& JOY_BUTTON1CHG
)
5655 change
= wxJOY_BUTTON1
;
5656 if ( flags
& JOY_BUTTON2CHG
)
5657 change
= wxJOY_BUTTON2
;
5658 if ( flags
& JOY_BUTTON3CHG
)
5659 change
= wxJOY_BUTTON3
;
5660 if ( flags
& JOY_BUTTON4CHG
)
5661 change
= wxJOY_BUTTON4
;
5664 if ( flags
& JOY_BUTTON1
)
5665 buttons
|= wxJOY_BUTTON1
;
5666 if ( flags
& JOY_BUTTON2
)
5667 buttons
|= wxJOY_BUTTON2
;
5668 if ( flags
& JOY_BUTTON3
)
5669 buttons
|= wxJOY_BUTTON3
;
5670 if ( flags
& JOY_BUTTON4
)
5671 buttons
|= wxJOY_BUTTON4
;
5673 // the event ids aren't consecutive so we can't use table based lookup
5675 wxEventType eventType
;
5680 eventType
= wxEVT_JOY_MOVE
;
5685 eventType
= wxEVT_JOY_MOVE
;
5690 eventType
= wxEVT_JOY_ZMOVE
;
5695 eventType
= wxEVT_JOY_ZMOVE
;
5698 case MM_JOY1BUTTONDOWN
:
5700 eventType
= wxEVT_JOY_BUTTON_DOWN
;
5703 case MM_JOY2BUTTONDOWN
:
5705 eventType
= wxEVT_JOY_BUTTON_DOWN
;
5708 case MM_JOY1BUTTONUP
:
5710 eventType
= wxEVT_JOY_BUTTON_UP
;
5713 case MM_JOY2BUTTONUP
:
5715 eventType
= wxEVT_JOY_BUTTON_UP
;
5719 wxFAIL_MSG(wxT("no such joystick event"));
5724 wxJoystickEvent
event(eventType
, buttons
, joystick
, change
);
5725 event
.SetPosition(wxPoint(x
, y
));
5726 event
.SetEventObject(this);
5728 return HandleWindowEvent(event
);
5738 // ---------------------------------------------------------------------------
5740 // ---------------------------------------------------------------------------
5742 bool wxWindowMSW::MSWOnScroll(int orientation
, WXWORD wParam
,
5743 WXWORD pos
, WXHWND control
)
5745 if ( control
&& control
!= m_hWnd
) // Prevent infinite recursion
5747 wxWindow
*child
= wxFindWinFromHandle(control
);
5749 return child
->MSWOnScroll(orientation
, wParam
, pos
, control
);
5752 wxScrollWinEvent event
;
5753 event
.SetPosition(pos
);
5754 event
.SetOrientation(orientation
);
5755 event
.SetEventObject(this);
5760 event
.SetEventType(wxEVT_SCROLLWIN_TOP
);
5764 event
.SetEventType(wxEVT_SCROLLWIN_BOTTOM
);
5768 event
.SetEventType(wxEVT_SCROLLWIN_LINEUP
);
5772 event
.SetEventType(wxEVT_SCROLLWIN_LINEDOWN
);
5776 event
.SetEventType(wxEVT_SCROLLWIN_PAGEUP
);
5780 event
.SetEventType(wxEVT_SCROLLWIN_PAGEDOWN
);
5783 case SB_THUMBPOSITION
:
5785 // under Win32, the scrollbar range and position are 32 bit integers,
5786 // but WM_[HV]SCROLL only carry the low 16 bits of them, so we must
5787 // explicitly query the scrollbar for the correct position (this must
5788 // be done only for these two SB_ events as they are the only one
5789 // carrying the scrollbar position)
5791 WinStruct
<SCROLLINFO
> scrollInfo
;
5792 scrollInfo
.fMask
= SIF_TRACKPOS
;
5794 if ( !::GetScrollInfo(GetHwnd(),
5795 WXOrientToSB(orientation
),
5798 // Not necessarily an error, if there are no scrollbars yet.
5799 // wxLogLastError(_T("GetScrollInfo"));
5802 event
.SetPosition(scrollInfo
.nTrackPos
);
5805 event
.SetEventType( wParam
== SB_THUMBPOSITION
5806 ? wxEVT_SCROLLWIN_THUMBRELEASE
5807 : wxEVT_SCROLLWIN_THUMBTRACK
);
5814 return HandleWindowEvent(event
);
5817 // ----------------------------------------------------------------------------
5818 // custom message handlers
5819 // ----------------------------------------------------------------------------
5822 wxWindowMSW::MSWRegisterMessageHandler(int msg
, MSWMessageHandler handler
)
5824 wxCHECK_MSG( gs_messageHandlers
.find(msg
) == gs_messageHandlers
.end(),
5825 false, _T("registering handler for the same message twice") );
5827 gs_messageHandlers
[msg
] = handler
;
5832 wxWindowMSW::MSWUnregisterMessageHandler(int msg
, MSWMessageHandler handler
)
5834 const MSWMessageHandlers::iterator i
= gs_messageHandlers
.find(msg
);
5835 wxCHECK_RET( i
!= gs_messageHandlers
.end() && i
->second
== handler
,
5836 _T("unregistering non-registered handler?") );
5838 gs_messageHandlers
.erase(i
);
5841 // ===========================================================================
5843 // ===========================================================================
5845 void wxGetCharSize(WXHWND wnd
, int *x
, int *y
, const wxFont
& the_font
)
5848 HDC dc
= ::GetDC((HWND
) wnd
);
5851 // the_font.UseResource();
5852 // the_font.RealizeResource();
5853 HFONT fnt
= (HFONT
)the_font
.GetResourceHandle(); // const_cast
5855 was
= (HFONT
) SelectObject(dc
,fnt
);
5857 GetTextMetrics(dc
, &tm
);
5860 SelectObject(dc
,was
);
5862 ReleaseDC((HWND
)wnd
, dc
);
5865 *x
= tm
.tmAveCharWidth
;
5867 *y
= tm
.tmHeight
+ tm
.tmExternalLeading
;
5869 // the_font.ReleaseResource();
5872 // use the "extended" bit (24) of lParam to distinguish extended keys
5873 // from normal keys as the same key is sent
5875 int ChooseNormalOrExtended(int lParam
, int keyNormal
, int keyExtended
)
5877 // except that if lParam is 0, it means we don't have real lParam from
5878 // WM_KEYDOWN but are just translating just a VK constant (e.g. done from
5879 // msw/treectrl.cpp when processing TVN_KEYDOWN) -- then assume this is a
5880 // non-numpad (hence extended) key as this is a more common case
5881 return !lParam
|| (lParam
& (1 << 24)) ? keyExtended
: keyNormal
;
5884 // this array contains the Windows virtual key codes which map one to one to
5885 // WXK_xxx constants and is used in wxCharCodeMSWToWX/WXToMSW() below
5887 // note that keys having a normal and numpad version (e.g. WXK_HOME and
5888 // WXK_NUMPAD_HOME) are not included in this table as the mapping is not 1-to-1
5889 static const struct wxKeyMapping
5893 } gs_specialKeys
[] =
5895 { VK_CANCEL
, WXK_CANCEL
},
5896 { VK_BACK
, WXK_BACK
},
5897 { VK_TAB
, WXK_TAB
},
5898 { VK_CLEAR
, WXK_CLEAR
},
5899 { VK_SHIFT
, WXK_SHIFT
},
5900 { VK_CONTROL
, WXK_CONTROL
},
5901 { VK_MENU
, WXK_ALT
},
5902 { VK_PAUSE
, WXK_PAUSE
},
5903 { VK_CAPITAL
, WXK_CAPITAL
},
5904 { VK_SPACE
, WXK_SPACE
},
5905 { VK_ESCAPE
, WXK_ESCAPE
},
5906 { VK_SELECT
, WXK_SELECT
},
5907 { VK_PRINT
, WXK_PRINT
},
5908 { VK_EXECUTE
, WXK_EXECUTE
},
5909 { VK_SNAPSHOT
, WXK_SNAPSHOT
},
5910 { VK_HELP
, WXK_HELP
},
5912 { VK_NUMPAD0
, WXK_NUMPAD0
},
5913 { VK_NUMPAD1
, WXK_NUMPAD1
},
5914 { VK_NUMPAD2
, WXK_NUMPAD2
},
5915 { VK_NUMPAD3
, WXK_NUMPAD3
},
5916 { VK_NUMPAD4
, WXK_NUMPAD4
},
5917 { VK_NUMPAD5
, WXK_NUMPAD5
},
5918 { VK_NUMPAD6
, WXK_NUMPAD6
},
5919 { VK_NUMPAD7
, WXK_NUMPAD7
},
5920 { VK_NUMPAD8
, WXK_NUMPAD8
},
5921 { VK_NUMPAD9
, WXK_NUMPAD9
},
5922 { VK_MULTIPLY
, WXK_NUMPAD_MULTIPLY
},
5923 { VK_ADD
, WXK_NUMPAD_ADD
},
5924 { VK_SUBTRACT
, WXK_NUMPAD_SUBTRACT
},
5925 { VK_DECIMAL
, WXK_NUMPAD_DECIMAL
},
5926 { VK_DIVIDE
, WXK_NUMPAD_DIVIDE
},
5937 { VK_F10
, WXK_F10
},
5938 { VK_F11
, WXK_F11
},
5939 { VK_F12
, WXK_F12
},
5940 { VK_F13
, WXK_F13
},
5941 { VK_F14
, WXK_F14
},
5942 { VK_F15
, WXK_F15
},
5943 { VK_F16
, WXK_F16
},
5944 { VK_F17
, WXK_F17
},
5945 { VK_F18
, WXK_F18
},
5946 { VK_F19
, WXK_F19
},
5947 { VK_F20
, WXK_F20
},
5948 { VK_F21
, WXK_F21
},
5949 { VK_F22
, WXK_F22
},
5950 { VK_F23
, WXK_F23
},
5951 { VK_F24
, WXK_F24
},
5953 { VK_NUMLOCK
, WXK_NUMLOCK
},
5954 { VK_SCROLL
, WXK_SCROLL
},
5957 { VK_LWIN
, WXK_WINDOWS_LEFT
},
5958 { VK_RWIN
, WXK_WINDOWS_RIGHT
},
5959 { VK_APPS
, WXK_WINDOWS_MENU
},
5960 #endif // VK_APPS defined
5963 // Returns 0 if was a normal ASCII value, not a special key. This indicates that
5964 // the key should be ignored by WM_KEYDOWN and processed by WM_CHAR instead.
5965 int wxCharCodeMSWToWX(int vk
, WXLPARAM lParam
)
5967 // check the table first
5968 for ( size_t n
= 0; n
< WXSIZEOF(gs_specialKeys
); n
++ )
5970 if ( gs_specialKeys
[n
].vk
== vk
)
5971 return gs_specialKeys
[n
].wxk
;
5974 // keys requiring special handling
5978 // the mapping for these keys may be incorrect on non-US keyboards so
5979 // maybe we shouldn't map them to ASCII values at all
5980 case VK_OEM_1
: wxk
= ';'; break;
5981 case VK_OEM_PLUS
: wxk
= '+'; break;
5982 case VK_OEM_COMMA
: wxk
= ','; break;
5983 case VK_OEM_MINUS
: wxk
= '-'; break;
5984 case VK_OEM_PERIOD
: wxk
= '.'; break;
5985 case VK_OEM_2
: wxk
= '/'; break;
5986 case VK_OEM_3
: wxk
= '~'; break;
5987 case VK_OEM_4
: wxk
= '['; break;
5988 case VK_OEM_5
: wxk
= '\\'; break;
5989 case VK_OEM_6
: wxk
= ']'; break;
5990 case VK_OEM_7
: wxk
= '\''; break;
5992 // handle extended keys
5994 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_PAGEUP
, WXK_PAGEUP
);
5998 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_PAGEDOWN
, WXK_PAGEDOWN
);
6002 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_END
, WXK_END
);
6006 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_HOME
, WXK_HOME
);
6010 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_LEFT
, WXK_LEFT
);
6014 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_UP
, WXK_UP
);
6018 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_RIGHT
, WXK_RIGHT
);
6022 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_DOWN
, WXK_DOWN
);
6026 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_INSERT
, WXK_INSERT
);
6030 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_DELETE
, WXK_DELETE
);
6034 // don't use ChooseNormalOrExtended() here as the keys are reversed
6035 // here: numpad enter is the extended one
6036 wxk
= lParam
&& (lParam
& (1 << 24)) ? WXK_NUMPAD_ENTER
: WXK_RETURN
;
6046 WXWORD
wxCharCodeWXToMSW(int wxk
, bool *isVirtual
)
6051 // check the table first
6052 for ( size_t n
= 0; n
< WXSIZEOF(gs_specialKeys
); n
++ )
6054 if ( gs_specialKeys
[n
].wxk
== wxk
)
6055 return gs_specialKeys
[n
].vk
;
6058 // and then check for special keys not included in the table
6063 case WXK_NUMPAD_PAGEUP
:
6068 case WXK_NUMPAD_PAGEDOWN
:
6073 case WXK_NUMPAD_END
:
6078 case WXK_NUMPAD_HOME
:
6083 case WXK_NUMPAD_LEFT
:
6093 case WXK_NUMPAD_RIGHT
:
6098 case WXK_NUMPAD_DOWN
:
6103 case WXK_NUMPAD_INSERT
:
6108 case WXK_NUMPAD_DELETE
:
6113 // no VkKeyScan() under CE unfortunately, we need to test how does
6114 // it handle OEM keys
6116 // check to see if its one of the OEM key codes.
6117 BYTE vks
= LOBYTE(VkKeyScan(wxk
));
6123 #endif // !__WXWINCE__
6134 // small helper for wxGetKeyState() and wxGetMouseState()
6135 static inline bool wxIsKeyDown(WXWORD vk
)
6137 // SM_SWAPBUTTON is not available under CE, so don't swap buttons there
6138 #ifdef SM_SWAPBUTTON
6139 if ( vk
== VK_LBUTTON
|| vk
== VK_RBUTTON
)
6141 if ( ::GetSystemMetrics(SM_SWAPBUTTON
) )
6143 if ( vk
== VK_LBUTTON
)
6145 else // vk == VK_RBUTTON
6149 #endif // SM_SWAPBUTTON
6151 // the low order bit indicates whether the key was pressed since the last
6152 // call and the high order one indicates whether it is down right now and
6153 // we only want that one
6154 return (GetAsyncKeyState(vk
) & (1<<15)) != 0;
6157 bool wxGetKeyState(wxKeyCode key
)
6159 // although this does work under Windows, it is not supported under other
6160 // platforms so don't allow it, you must use wxGetMouseState() instead
6161 wxASSERT_MSG( key
!= VK_LBUTTON
&&
6162 key
!= VK_RBUTTON
&&
6164 wxT("can't use wxGetKeyState() for mouse buttons") );
6166 const WXWORD vk
= wxCharCodeWXToMSW(key
);
6168 // if the requested key is a LED key, return true if the led is pressed
6169 if ( key
== WXK_NUMLOCK
|| key
== WXK_CAPITAL
|| key
== WXK_SCROLL
)
6171 // low order bit means LED is highlighted and high order one means the
6172 // key is down; for compatibility with the other ports return true if
6173 // either one is set
6174 return GetKeyState(vk
) != 0;
6179 return wxIsKeyDown(vk
);
6184 wxMouseState
wxGetMouseState()
6188 GetCursorPos( &pt
);
6192 ms
.SetLeftDown(wxIsKeyDown(VK_LBUTTON
));
6193 ms
.SetMiddleDown(wxIsKeyDown(VK_MBUTTON
));
6194 ms
.SetRightDown(wxIsKeyDown(VK_RBUTTON
));
6195 #ifdef wxHAS_XBUTTON
6196 ms
.SetAux1Down(wxIsKeyDown(VK_XBUTTON1
));
6197 ms
.SetAux2Down(wxIsKeyDown(VK_XBUTTON2
));
6198 #endif // wxHAS_XBUTTON
6200 ms
.SetControlDown(wxIsCtrlDown ());
6201 ms
.SetShiftDown (wxIsShiftDown());
6202 ms
.SetAltDown (wxIsAltDown ());
6203 // ms.SetMetaDown();
6209 wxWindow
*wxGetActiveWindow()
6211 HWND hWnd
= GetActiveWindow();
6214 return wxFindWinFromHandle(hWnd
);
6219 extern wxWindow
*wxGetWindowFromHWND(WXHWND hWnd
)
6221 HWND hwnd
= (HWND
)hWnd
;
6223 // For a radiobutton, we get the radiobox from GWL_USERDATA (which is set
6224 // by code in msw/radiobox.cpp), for all the others we just search up the
6226 wxWindow
*win
= NULL
;
6229 win
= wxFindWinFromHandle(hwnd
);
6233 // native radiobuttons return DLGC_RADIOBUTTON here and for any
6234 // wxWindow class which overrides WM_GETDLGCODE processing to
6235 // do it as well, win would be already non NULL
6236 if ( ::SendMessage(hwnd
, WM_GETDLGCODE
, 0, 0) & DLGC_RADIOBUTTON
)
6238 win
= (wxWindow
*)wxGetWindowUserData(hwnd
);
6240 //else: it's a wxRadioButton, not a radiobutton from wxRadioBox
6241 #endif // wxUSE_RADIOBOX
6243 // spin control text buddy window should be mapped to spin ctrl
6244 // itself so try it too
6245 #if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__)
6248 win
= wxSpinCtrl::GetSpinForTextCtrl((WXHWND
)hwnd
);
6250 #endif // wxUSE_SPINCTRL
6254 while ( hwnd
&& !win
)
6256 // this is a really ugly hack needed to avoid mistakenly returning the
6257 // parent frame wxWindow for the find/replace modeless dialog HWND -
6258 // this, in turn, is needed to call IsDialogMessage() from
6259 // wxApp::ProcessMessage() as for this we must return NULL from here
6261 // FIXME: this is clearly not the best way to do it but I think we'll
6262 // need to change HWND <-> wxWindow code more heavily than I can
6263 // do it now to fix it
6264 #ifndef __WXMICROWIN__
6265 if ( ::GetWindow(hwnd
, GW_OWNER
) )
6267 // it's a dialog box, don't go upwards
6272 hwnd
= ::GetParent(hwnd
);
6273 win
= wxFindWinFromHandle(hwnd
);
6279 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
6281 // Windows keyboard hook. Allows interception of e.g. F1, ESCAPE
6282 // in active frames and dialogs, regardless of where the focus is.
6283 static HHOOK wxTheKeyboardHook
= 0;
6284 static FARPROC wxTheKeyboardHookProc
= 0;
6285 int APIENTRY _EXPORT
6286 wxKeyboardHook(int nCode
, WORD wParam
, DWORD lParam
);
6288 void wxSetKeyboardHook(bool doIt
)
6292 wxTheKeyboardHookProc
= MakeProcInstance((FARPROC
) wxKeyboardHook
, wxGetInstance());
6293 wxTheKeyboardHook
= SetWindowsHookEx(WH_KEYBOARD
, (HOOKPROC
) wxTheKeyboardHookProc
, wxGetInstance(),
6295 GetCurrentThreadId()
6296 // (DWORD)GetCurrentProcess()); // This is another possibility. Which is right?
6301 UnhookWindowsHookEx(wxTheKeyboardHook
);
6305 int APIENTRY _EXPORT
6306 wxKeyboardHook(int nCode
, WORD wParam
, DWORD lParam
)
6308 DWORD hiWord
= HIWORD(lParam
);
6309 if ( nCode
!= HC_NOREMOVE
&& ((hiWord
& KF_UP
) == 0) )
6311 int id
= wxCharCodeMSWToWX(wParam
, lParam
);
6314 wxKeyEvent
event(wxEVT_CHAR_HOOK
);
6315 if ( (HIWORD(lParam
) & KF_ALTDOWN
) == KF_ALTDOWN
)
6316 event
.m_altDown
= true;
6318 event
.SetEventObject(NULL
);
6319 event
.m_keyCode
= id
;
6320 event
.m_shiftDown
= wxIsShiftDown();
6321 event
.m_controlDown
= wxIsCtrlDown();
6323 event
.SetTimestamp(::GetMessageTime());
6325 wxWindow
*win
= wxGetActiveWindow();
6326 wxEvtHandler
*handler
;
6329 handler
= win
->GetEventHandler();
6330 event
.SetId(win
->GetId());
6335 event
.SetId(wxID_ANY
);
6338 if ( handler
&& handler
->ProcessEvent(event
) )
6346 return (int)CallNextHookEx(wxTheKeyboardHook
, nCode
, wParam
, lParam
);
6349 #endif // !__WXMICROWIN__
6352 const wxChar
*wxGetMessageName(int message
)
6356 case 0x0000: return wxT("WM_NULL");
6357 case 0x0001: return wxT("WM_CREATE");
6358 case 0x0002: return wxT("WM_DESTROY");
6359 case 0x0003: return wxT("WM_MOVE");
6360 case 0x0005: return wxT("WM_SIZE");
6361 case 0x0006: return wxT("WM_ACTIVATE");
6362 case 0x0007: return wxT("WM_SETFOCUS");
6363 case 0x0008: return wxT("WM_KILLFOCUS");
6364 case 0x000A: return wxT("WM_ENABLE");
6365 case 0x000B: return wxT("WM_SETREDRAW");
6366 case 0x000C: return wxT("WM_SETTEXT");
6367 case 0x000D: return wxT("WM_GETTEXT");
6368 case 0x000E: return wxT("WM_GETTEXTLENGTH");
6369 case 0x000F: return wxT("WM_PAINT");
6370 case 0x0010: return wxT("WM_CLOSE");
6371 case 0x0011: return wxT("WM_QUERYENDSESSION");
6372 case 0x0012: return wxT("WM_QUIT");
6373 case 0x0013: return wxT("WM_QUERYOPEN");
6374 case 0x0014: return wxT("WM_ERASEBKGND");
6375 case 0x0015: return wxT("WM_SYSCOLORCHANGE");
6376 case 0x0016: return wxT("WM_ENDSESSION");
6377 case 0x0017: return wxT("WM_SYSTEMERROR");
6378 case 0x0018: return wxT("WM_SHOWWINDOW");
6379 case 0x0019: return wxT("WM_CTLCOLOR");
6380 case 0x001A: return wxT("WM_WININICHANGE");
6381 case 0x001B: return wxT("WM_DEVMODECHANGE");
6382 case 0x001C: return wxT("WM_ACTIVATEAPP");
6383 case 0x001D: return wxT("WM_FONTCHANGE");
6384 case 0x001E: return wxT("WM_TIMECHANGE");
6385 case 0x001F: return wxT("WM_CANCELMODE");
6386 case 0x0020: return wxT("WM_SETCURSOR");
6387 case 0x0021: return wxT("WM_MOUSEACTIVATE");
6388 case 0x0022: return wxT("WM_CHILDACTIVATE");
6389 case 0x0023: return wxT("WM_QUEUESYNC");
6390 case 0x0024: return wxT("WM_GETMINMAXINFO");
6391 case 0x0026: return wxT("WM_PAINTICON");
6392 case 0x0027: return wxT("WM_ICONERASEBKGND");
6393 case 0x0028: return wxT("WM_NEXTDLGCTL");
6394 case 0x002A: return wxT("WM_SPOOLERSTATUS");
6395 case 0x002B: return wxT("WM_DRAWITEM");
6396 case 0x002C: return wxT("WM_MEASUREITEM");
6397 case 0x002D: return wxT("WM_DELETEITEM");
6398 case 0x002E: return wxT("WM_VKEYTOITEM");
6399 case 0x002F: return wxT("WM_CHARTOITEM");
6400 case 0x0030: return wxT("WM_SETFONT");
6401 case 0x0031: return wxT("WM_GETFONT");
6402 case 0x0037: return wxT("WM_QUERYDRAGICON");
6403 case 0x0039: return wxT("WM_COMPAREITEM");
6404 case 0x0041: return wxT("WM_COMPACTING");
6405 case 0x0044: return wxT("WM_COMMNOTIFY");
6406 case 0x0046: return wxT("WM_WINDOWPOSCHANGING");
6407 case 0x0047: return wxT("WM_WINDOWPOSCHANGED");
6408 case 0x0048: return wxT("WM_POWER");
6410 case 0x004A: return wxT("WM_COPYDATA");
6411 case 0x004B: return wxT("WM_CANCELJOURNAL");
6412 case 0x004E: return wxT("WM_NOTIFY");
6413 case 0x0050: return wxT("WM_INPUTLANGCHANGEREQUEST");
6414 case 0x0051: return wxT("WM_INPUTLANGCHANGE");
6415 case 0x0052: return wxT("WM_TCARD");
6416 case 0x0053: return wxT("WM_HELP");
6417 case 0x0054: return wxT("WM_USERCHANGED");
6418 case 0x0055: return wxT("WM_NOTIFYFORMAT");
6419 case 0x007B: return wxT("WM_CONTEXTMENU");
6420 case 0x007C: return wxT("WM_STYLECHANGING");
6421 case 0x007D: return wxT("WM_STYLECHANGED");
6422 case 0x007E: return wxT("WM_DISPLAYCHANGE");
6423 case 0x007F: return wxT("WM_GETICON");
6424 case 0x0080: return wxT("WM_SETICON");
6426 case 0x0081: return wxT("WM_NCCREATE");
6427 case 0x0082: return wxT("WM_NCDESTROY");
6428 case 0x0083: return wxT("WM_NCCALCSIZE");
6429 case 0x0084: return wxT("WM_NCHITTEST");
6430 case 0x0085: return wxT("WM_NCPAINT");
6431 case 0x0086: return wxT("WM_NCACTIVATE");
6432 case 0x0087: return wxT("WM_GETDLGCODE");
6433 case 0x00A0: return wxT("WM_NCMOUSEMOVE");
6434 case 0x00A1: return wxT("WM_NCLBUTTONDOWN");
6435 case 0x00A2: return wxT("WM_NCLBUTTONUP");
6436 case 0x00A3: return wxT("WM_NCLBUTTONDBLCLK");
6437 case 0x00A4: return wxT("WM_NCRBUTTONDOWN");
6438 case 0x00A5: return wxT("WM_NCRBUTTONUP");
6439 case 0x00A6: return wxT("WM_NCRBUTTONDBLCLK");
6440 case 0x00A7: return wxT("WM_NCMBUTTONDOWN");
6441 case 0x00A8: return wxT("WM_NCMBUTTONUP");
6442 case 0x00A9: return wxT("WM_NCMBUTTONDBLCLK");
6444 case 0x00B0: return wxT("EM_GETSEL");
6445 case 0x00B1: return wxT("EM_SETSEL");
6446 case 0x00B2: return wxT("EM_GETRECT");
6447 case 0x00B3: return wxT("EM_SETRECT");
6448 case 0x00B4: return wxT("EM_SETRECTNP");
6449 case 0x00B5: return wxT("EM_SCROLL");
6450 case 0x00B6: return wxT("EM_LINESCROLL");
6451 case 0x00B7: return wxT("EM_SCROLLCARET");
6452 case 0x00B8: return wxT("EM_GETMODIFY");
6453 case 0x00B9: return wxT("EM_SETMODIFY");
6454 case 0x00BA: return wxT("EM_GETLINECOUNT");
6455 case 0x00BB: return wxT("EM_LINEINDEX");
6456 case 0x00BC: return wxT("EM_SETHANDLE");
6457 case 0x00BD: return wxT("EM_GETHANDLE");
6458 case 0x00BE: return wxT("EM_GETTHUMB");
6459 case 0x00C1: return wxT("EM_LINELENGTH");
6460 case 0x00C2: return wxT("EM_REPLACESEL");
6461 case 0x00C4: return wxT("EM_GETLINE");
6462 case 0x00C5: return wxT("EM_LIMITTEXT/EM_SETLIMITTEXT"); /* ;win40 Name change */
6463 case 0x00C6: return wxT("EM_CANUNDO");
6464 case 0x00C7: return wxT("EM_UNDO");
6465 case 0x00C8: return wxT("EM_FMTLINES");
6466 case 0x00C9: return wxT("EM_LINEFROMCHAR");
6467 case 0x00CB: return wxT("EM_SETTABSTOPS");
6468 case 0x00CC: return wxT("EM_SETPASSWORDCHAR");
6469 case 0x00CD: return wxT("EM_EMPTYUNDOBUFFER");
6470 case 0x00CE: return wxT("EM_GETFIRSTVISIBLELINE");
6471 case 0x00CF: return wxT("EM_SETREADONLY");
6472 case 0x00D0: return wxT("EM_SETWORDBREAKPROC");
6473 case 0x00D1: return wxT("EM_GETWORDBREAKPROC");
6474 case 0x00D2: return wxT("EM_GETPASSWORDCHAR");
6475 case 0x00D3: return wxT("EM_SETMARGINS");
6476 case 0x00D4: return wxT("EM_GETMARGINS");
6477 case 0x00D5: return wxT("EM_GETLIMITTEXT");
6478 case 0x00D6: return wxT("EM_POSFROMCHAR");
6479 case 0x00D7: return wxT("EM_CHARFROMPOS");
6480 case 0x00D8: return wxT("EM_SETIMESTATUS");
6481 case 0x00D9: return wxT("EM_GETIMESTATUS");
6483 case 0x0100: return wxT("WM_KEYDOWN");
6484 case 0x0101: return wxT("WM_KEYUP");
6485 case 0x0102: return wxT("WM_CHAR");
6486 case 0x0103: return wxT("WM_DEADCHAR");
6487 case 0x0104: return wxT("WM_SYSKEYDOWN");
6488 case 0x0105: return wxT("WM_SYSKEYUP");
6489 case 0x0106: return wxT("WM_SYSCHAR");
6490 case 0x0107: return wxT("WM_SYSDEADCHAR");
6491 case 0x0108: return wxT("WM_KEYLAST");
6493 case 0x010D: return wxT("WM_IME_STARTCOMPOSITION");
6494 case 0x010E: return wxT("WM_IME_ENDCOMPOSITION");
6495 case 0x010F: return wxT("WM_IME_COMPOSITION");
6497 case 0x0110: return wxT("WM_INITDIALOG");
6498 case 0x0111: return wxT("WM_COMMAND");
6499 case 0x0112: return wxT("WM_SYSCOMMAND");
6500 case 0x0113: return wxT("WM_TIMER");
6501 case 0x0114: return wxT("WM_HSCROLL");
6502 case 0x0115: return wxT("WM_VSCROLL");
6503 case 0x0116: return wxT("WM_INITMENU");
6504 case 0x0117: return wxT("WM_INITMENUPOPUP");
6505 case 0x011F: return wxT("WM_MENUSELECT");
6506 case 0x0120: return wxT("WM_MENUCHAR");
6507 case 0x0121: return wxT("WM_ENTERIDLE");
6509 case 0x0132: return wxT("WM_CTLCOLORMSGBOX");
6510 case 0x0133: return wxT("WM_CTLCOLOREDIT");
6511 case 0x0134: return wxT("WM_CTLCOLORLISTBOX");
6512 case 0x0135: return wxT("WM_CTLCOLORBTN");
6513 case 0x0136: return wxT("WM_CTLCOLORDLG");
6514 case 0x0137: return wxT("WM_CTLCOLORSCROLLBAR");
6515 case 0x0138: return wxT("WM_CTLCOLORSTATIC");
6516 case 0x01E1: return wxT("MN_GETHMENU");
6518 case 0x0200: return wxT("WM_MOUSEMOVE");
6519 case 0x0201: return wxT("WM_LBUTTONDOWN");
6520 case 0x0202: return wxT("WM_LBUTTONUP");
6521 case 0x0203: return wxT("WM_LBUTTONDBLCLK");
6522 case 0x0204: return wxT("WM_RBUTTONDOWN");
6523 case 0x0205: return wxT("WM_RBUTTONUP");
6524 case 0x0206: return wxT("WM_RBUTTONDBLCLK");
6525 case 0x0207: return wxT("WM_MBUTTONDOWN");
6526 case 0x0208: return wxT("WM_MBUTTONUP");
6527 case 0x0209: return wxT("WM_MBUTTONDBLCLK");
6528 case 0x020A: return wxT("WM_MOUSEWHEEL");
6529 case 0x020B: return wxT("WM_XBUTTONDOWN");
6530 case 0x020C: return wxT("WM_XBUTTONUP");
6531 case 0x020D: return wxT("WM_XBUTTONDBLCLK");
6532 case 0x0210: return wxT("WM_PARENTNOTIFY");
6533 case 0x0211: return wxT("WM_ENTERMENULOOP");
6534 case 0x0212: return wxT("WM_EXITMENULOOP");
6536 case 0x0213: return wxT("WM_NEXTMENU");
6537 case 0x0214: return wxT("WM_SIZING");
6538 case 0x0215: return wxT("WM_CAPTURECHANGED");
6539 case 0x0216: return wxT("WM_MOVING");
6540 case 0x0218: return wxT("WM_POWERBROADCAST");
6541 case 0x0219: return wxT("WM_DEVICECHANGE");
6543 case 0x0220: return wxT("WM_MDICREATE");
6544 case 0x0221: return wxT("WM_MDIDESTROY");
6545 case 0x0222: return wxT("WM_MDIACTIVATE");
6546 case 0x0223: return wxT("WM_MDIRESTORE");
6547 case 0x0224: return wxT("WM_MDINEXT");
6548 case 0x0225: return wxT("WM_MDIMAXIMIZE");
6549 case 0x0226: return wxT("WM_MDITILE");
6550 case 0x0227: return wxT("WM_MDICASCADE");
6551 case 0x0228: return wxT("WM_MDIICONARRANGE");
6552 case 0x0229: return wxT("WM_MDIGETACTIVE");
6553 case 0x0230: return wxT("WM_MDISETMENU");
6554 case 0x0233: return wxT("WM_DROPFILES");
6556 case 0x0281: return wxT("WM_IME_SETCONTEXT");
6557 case 0x0282: return wxT("WM_IME_NOTIFY");
6558 case 0x0283: return wxT("WM_IME_CONTROL");
6559 case 0x0284: return wxT("WM_IME_COMPOSITIONFULL");
6560 case 0x0285: return wxT("WM_IME_SELECT");
6561 case 0x0286: return wxT("WM_IME_CHAR");
6562 case 0x0290: return wxT("WM_IME_KEYDOWN");
6563 case 0x0291: return wxT("WM_IME_KEYUP");
6565 case 0x02A0: return wxT("WM_NCMOUSEHOVER");
6566 case 0x02A1: return wxT("WM_MOUSEHOVER");
6567 case 0x02A2: return wxT("WM_NCMOUSELEAVE");
6568 case 0x02A3: return wxT("WM_MOUSELEAVE");
6570 case 0x0300: return wxT("WM_CUT");
6571 case 0x0301: return wxT("WM_COPY");
6572 case 0x0302: return wxT("WM_PASTE");
6573 case 0x0303: return wxT("WM_CLEAR");
6574 case 0x0304: return wxT("WM_UNDO");
6575 case 0x0305: return wxT("WM_RENDERFORMAT");
6576 case 0x0306: return wxT("WM_RENDERALLFORMATS");
6577 case 0x0307: return wxT("WM_DESTROYCLIPBOARD");
6578 case 0x0308: return wxT("WM_DRAWCLIPBOARD");
6579 case 0x0309: return wxT("WM_PAINTCLIPBOARD");
6580 case 0x030A: return wxT("WM_VSCROLLCLIPBOARD");
6581 case 0x030B: return wxT("WM_SIZECLIPBOARD");
6582 case 0x030C: return wxT("WM_ASKCBFORMATNAME");
6583 case 0x030D: return wxT("WM_CHANGECBCHAIN");
6584 case 0x030E: return wxT("WM_HSCROLLCLIPBOARD");
6585 case 0x030F: return wxT("WM_QUERYNEWPALETTE");
6586 case 0x0310: return wxT("WM_PALETTEISCHANGING");
6587 case 0x0311: return wxT("WM_PALETTECHANGED");
6588 case 0x0312: return wxT("WM_HOTKEY");
6590 case 0x0317: return wxT("WM_PRINT");
6591 case 0x0318: return wxT("WM_PRINTCLIENT");
6593 // common controls messages - although they're not strictly speaking
6594 // standard, it's nice to decode them nevertheless
6597 case 0x1000 + 0: return wxT("LVM_GETBKCOLOR");
6598 case 0x1000 + 1: return wxT("LVM_SETBKCOLOR");
6599 case 0x1000 + 2: return wxT("LVM_GETIMAGELIST");
6600 case 0x1000 + 3: return wxT("LVM_SETIMAGELIST");
6601 case 0x1000 + 4: return wxT("LVM_GETITEMCOUNT");
6602 case 0x1000 + 5: return wxT("LVM_GETITEMA");
6603 case 0x1000 + 75: return wxT("LVM_GETITEMW");
6604 case 0x1000 + 6: return wxT("LVM_SETITEMA");
6605 case 0x1000 + 76: return wxT("LVM_SETITEMW");
6606 case 0x1000 + 7: return wxT("LVM_INSERTITEMA");
6607 case 0x1000 + 77: return wxT("LVM_INSERTITEMW");
6608 case 0x1000 + 8: return wxT("LVM_DELETEITEM");
6609 case 0x1000 + 9: return wxT("LVM_DELETEALLITEMS");
6610 case 0x1000 + 10: return wxT("LVM_GETCALLBACKMASK");
6611 case 0x1000 + 11: return wxT("LVM_SETCALLBACKMASK");
6612 case 0x1000 + 12: return wxT("LVM_GETNEXTITEM");
6613 case 0x1000 + 13: return wxT("LVM_FINDITEMA");
6614 case 0x1000 + 83: return wxT("LVM_FINDITEMW");
6615 case 0x1000 + 14: return wxT("LVM_GETITEMRECT");
6616 case 0x1000 + 15: return wxT("LVM_SETITEMPOSITION");
6617 case 0x1000 + 16: return wxT("LVM_GETITEMPOSITION");
6618 case 0x1000 + 17: return wxT("LVM_GETSTRINGWIDTHA");
6619 case 0x1000 + 87: return wxT("LVM_GETSTRINGWIDTHW");
6620 case 0x1000 + 18: return wxT("LVM_HITTEST");
6621 case 0x1000 + 19: return wxT("LVM_ENSUREVISIBLE");
6622 case 0x1000 + 20: return wxT("LVM_SCROLL");
6623 case 0x1000 + 21: return wxT("LVM_REDRAWITEMS");
6624 case 0x1000 + 22: return wxT("LVM_ARRANGE");
6625 case 0x1000 + 23: return wxT("LVM_EDITLABELA");
6626 case 0x1000 + 118: return wxT("LVM_EDITLABELW");
6627 case 0x1000 + 24: return wxT("LVM_GETEDITCONTROL");
6628 case 0x1000 + 25: return wxT("LVM_GETCOLUMNA");
6629 case 0x1000 + 95: return wxT("LVM_GETCOLUMNW");
6630 case 0x1000 + 26: return wxT("LVM_SETCOLUMNA");
6631 case 0x1000 + 96: return wxT("LVM_SETCOLUMNW");
6632 case 0x1000 + 27: return wxT("LVM_INSERTCOLUMNA");
6633 case 0x1000 + 97: return wxT("LVM_INSERTCOLUMNW");
6634 case 0x1000 + 28: return wxT("LVM_DELETECOLUMN");
6635 case 0x1000 + 29: return wxT("LVM_GETCOLUMNWIDTH");
6636 case 0x1000 + 30: return wxT("LVM_SETCOLUMNWIDTH");
6637 case 0x1000 + 31: return wxT("LVM_GETHEADER");
6638 case 0x1000 + 33: return wxT("LVM_CREATEDRAGIMAGE");
6639 case 0x1000 + 34: return wxT("LVM_GETVIEWRECT");
6640 case 0x1000 + 35: return wxT("LVM_GETTEXTCOLOR");
6641 case 0x1000 + 36: return wxT("LVM_SETTEXTCOLOR");
6642 case 0x1000 + 37: return wxT("LVM_GETTEXTBKCOLOR");
6643 case 0x1000 + 38: return wxT("LVM_SETTEXTBKCOLOR");
6644 case 0x1000 + 39: return wxT("LVM_GETTOPINDEX");
6645 case 0x1000 + 40: return wxT("LVM_GETCOUNTPERPAGE");
6646 case 0x1000 + 41: return wxT("LVM_GETORIGIN");
6647 case 0x1000 + 42: return wxT("LVM_UPDATE");
6648 case 0x1000 + 43: return wxT("LVM_SETITEMSTATE");
6649 case 0x1000 + 44: return wxT("LVM_GETITEMSTATE");
6650 case 0x1000 + 45: return wxT("LVM_GETITEMTEXTA");
6651 case 0x1000 + 115: return wxT("LVM_GETITEMTEXTW");
6652 case 0x1000 + 46: return wxT("LVM_SETITEMTEXTA");
6653 case 0x1000 + 116: return wxT("LVM_SETITEMTEXTW");
6654 case 0x1000 + 47: return wxT("LVM_SETITEMCOUNT");
6655 case 0x1000 + 48: return wxT("LVM_SORTITEMS");
6656 case 0x1000 + 49: return wxT("LVM_SETITEMPOSITION32");
6657 case 0x1000 + 50: return wxT("LVM_GETSELECTEDCOUNT");
6658 case 0x1000 + 51: return wxT("LVM_GETITEMSPACING");
6659 case 0x1000 + 52: return wxT("LVM_GETISEARCHSTRINGA");
6660 case 0x1000 + 117: return wxT("LVM_GETISEARCHSTRINGW");
6661 case 0x1000 + 53: return wxT("LVM_SETICONSPACING");
6662 case 0x1000 + 54: return wxT("LVM_SETEXTENDEDLISTVIEWSTYLE");
6663 case 0x1000 + 55: return wxT("LVM_GETEXTENDEDLISTVIEWSTYLE");
6664 case 0x1000 + 56: return wxT("LVM_GETSUBITEMRECT");
6665 case 0x1000 + 57: return wxT("LVM_SUBITEMHITTEST");
6666 case 0x1000 + 58: return wxT("LVM_SETCOLUMNORDERARRAY");
6667 case 0x1000 + 59: return wxT("LVM_GETCOLUMNORDERARRAY");
6668 case 0x1000 + 60: return wxT("LVM_SETHOTITEM");
6669 case 0x1000 + 61: return wxT("LVM_GETHOTITEM");
6670 case 0x1000 + 62: return wxT("LVM_SETHOTCURSOR");
6671 case 0x1000 + 63: return wxT("LVM_GETHOTCURSOR");
6672 case 0x1000 + 64: return wxT("LVM_APPROXIMATEVIEWRECT");
6673 case 0x1000 + 65: return wxT("LVM_SETWORKAREA");
6676 case 0x1100 + 0: return wxT("TVM_INSERTITEMA");
6677 case 0x1100 + 50: return wxT("TVM_INSERTITEMW");
6678 case 0x1100 + 1: return wxT("TVM_DELETEITEM");
6679 case 0x1100 + 2: return wxT("TVM_EXPAND");
6680 case 0x1100 + 4: return wxT("TVM_GETITEMRECT");
6681 case 0x1100 + 5: return wxT("TVM_GETCOUNT");
6682 case 0x1100 + 6: return wxT("TVM_GETINDENT");
6683 case 0x1100 + 7: return wxT("TVM_SETINDENT");
6684 case 0x1100 + 8: return wxT("TVM_GETIMAGELIST");
6685 case 0x1100 + 9: return wxT("TVM_SETIMAGELIST");
6686 case 0x1100 + 10: return wxT("TVM_GETNEXTITEM");
6687 case 0x1100 + 11: return wxT("TVM_SELECTITEM");
6688 case 0x1100 + 12: return wxT("TVM_GETITEMA");
6689 case 0x1100 + 62: return wxT("TVM_GETITEMW");
6690 case 0x1100 + 13: return wxT("TVM_SETITEMA");
6691 case 0x1100 + 63: return wxT("TVM_SETITEMW");
6692 case 0x1100 + 14: return wxT("TVM_EDITLABELA");
6693 case 0x1100 + 65: return wxT("TVM_EDITLABELW");
6694 case 0x1100 + 15: return wxT("TVM_GETEDITCONTROL");
6695 case 0x1100 + 16: return wxT("TVM_GETVISIBLECOUNT");
6696 case 0x1100 + 17: return wxT("TVM_HITTEST");
6697 case 0x1100 + 18: return wxT("TVM_CREATEDRAGIMAGE");
6698 case 0x1100 + 19: return wxT("TVM_SORTCHILDREN");
6699 case 0x1100 + 20: return wxT("TVM_ENSUREVISIBLE");
6700 case 0x1100 + 21: return wxT("TVM_SORTCHILDRENCB");
6701 case 0x1100 + 22: return wxT("TVM_ENDEDITLABELNOW");
6702 case 0x1100 + 23: return wxT("TVM_GETISEARCHSTRINGA");
6703 case 0x1100 + 64: return wxT("TVM_GETISEARCHSTRINGW");
6704 case 0x1100 + 24: return wxT("TVM_SETTOOLTIPS");
6705 case 0x1100 + 25: return wxT("TVM_GETTOOLTIPS");
6708 case 0x1200 + 0: return wxT("HDM_GETITEMCOUNT");
6709 case 0x1200 + 1: return wxT("HDM_INSERTITEMA");
6710 case 0x1200 + 10: return wxT("HDM_INSERTITEMW");
6711 case 0x1200 + 2: return wxT("HDM_DELETEITEM");
6712 case 0x1200 + 3: return wxT("HDM_GETITEMA");
6713 case 0x1200 + 11: return wxT("HDM_GETITEMW");
6714 case 0x1200 + 4: return wxT("HDM_SETITEMA");
6715 case 0x1200 + 12: return wxT("HDM_SETITEMW");
6716 case 0x1200 + 5: return wxT("HDM_LAYOUT");
6717 case 0x1200 + 6: return wxT("HDM_HITTEST");
6718 case 0x1200 + 7: return wxT("HDM_GETITEMRECT");
6719 case 0x1200 + 8: return wxT("HDM_SETIMAGELIST");
6720 case 0x1200 + 9: return wxT("HDM_GETIMAGELIST");
6721 case 0x1200 + 15: return wxT("HDM_ORDERTOINDEX");
6722 case 0x1200 + 16: return wxT("HDM_CREATEDRAGIMAGE");
6723 case 0x1200 + 17: return wxT("HDM_GETORDERARRAY");
6724 case 0x1200 + 18: return wxT("HDM_SETORDERARRAY");
6725 case 0x1200 + 19: return wxT("HDM_SETHOTDIVIDER");
6728 case 0x1300 + 2: return wxT("TCM_GETIMAGELIST");
6729 case 0x1300 + 3: return wxT("TCM_SETIMAGELIST");
6730 case 0x1300 + 4: return wxT("TCM_GETITEMCOUNT");
6731 case 0x1300 + 5: return wxT("TCM_GETITEMA");
6732 case 0x1300 + 60: return wxT("TCM_GETITEMW");
6733 case 0x1300 + 6: return wxT("TCM_SETITEMA");
6734 case 0x1300 + 61: return wxT("TCM_SETITEMW");
6735 case 0x1300 + 7: return wxT("TCM_INSERTITEMA");
6736 case 0x1300 + 62: return wxT("TCM_INSERTITEMW");
6737 case 0x1300 + 8: return wxT("TCM_DELETEITEM");
6738 case 0x1300 + 9: return wxT("TCM_DELETEALLITEMS");
6739 case 0x1300 + 10: return wxT("TCM_GETITEMRECT");
6740 case 0x1300 + 11: return wxT("TCM_GETCURSEL");
6741 case 0x1300 + 12: return wxT("TCM_SETCURSEL");
6742 case 0x1300 + 13: return wxT("TCM_HITTEST");
6743 case 0x1300 + 14: return wxT("TCM_SETITEMEXTRA");
6744 case 0x1300 + 40: return wxT("TCM_ADJUSTRECT");
6745 case 0x1300 + 41: return wxT("TCM_SETITEMSIZE");
6746 case 0x1300 + 42: return wxT("TCM_REMOVEIMAGE");
6747 case 0x1300 + 43: return wxT("TCM_SETPADDING");
6748 case 0x1300 + 44: return wxT("TCM_GETROWCOUNT");
6749 case 0x1300 + 45: return wxT("TCM_GETTOOLTIPS");
6750 case 0x1300 + 46: return wxT("TCM_SETTOOLTIPS");
6751 case 0x1300 + 47: return wxT("TCM_GETCURFOCUS");
6752 case 0x1300 + 48: return wxT("TCM_SETCURFOCUS");
6753 case 0x1300 + 49: return wxT("TCM_SETMINTABWIDTH");
6754 case 0x1300 + 50: return wxT("TCM_DESELECTALL");
6757 case WM_USER
+1: return wxT("TB_ENABLEBUTTON");
6758 case WM_USER
+2: return wxT("TB_CHECKBUTTON");
6759 case WM_USER
+3: return wxT("TB_PRESSBUTTON");
6760 case WM_USER
+4: return wxT("TB_HIDEBUTTON");
6761 case WM_USER
+5: return wxT("TB_INDETERMINATE");
6762 case WM_USER
+9: return wxT("TB_ISBUTTONENABLED");
6763 case WM_USER
+10: return wxT("TB_ISBUTTONCHECKED");
6764 case WM_USER
+11: return wxT("TB_ISBUTTONPRESSED");
6765 case WM_USER
+12: return wxT("TB_ISBUTTONHIDDEN");
6766 case WM_USER
+13: return wxT("TB_ISBUTTONINDETERMINATE");
6767 case WM_USER
+17: return wxT("TB_SETSTATE");
6768 case WM_USER
+18: return wxT("TB_GETSTATE");
6769 case WM_USER
+19: return wxT("TB_ADDBITMAP");
6770 case WM_USER
+20: return wxT("TB_ADDBUTTONS");
6771 case WM_USER
+21: return wxT("TB_INSERTBUTTON");
6772 case WM_USER
+22: return wxT("TB_DELETEBUTTON");
6773 case WM_USER
+23: return wxT("TB_GETBUTTON");
6774 case WM_USER
+24: return wxT("TB_BUTTONCOUNT");
6775 case WM_USER
+25: return wxT("TB_COMMANDTOINDEX");
6776 case WM_USER
+26: return wxT("TB_SAVERESTOREA");
6777 case WM_USER
+76: return wxT("TB_SAVERESTOREW");
6778 case WM_USER
+27: return wxT("TB_CUSTOMIZE");
6779 case WM_USER
+28: return wxT("TB_ADDSTRINGA");
6780 case WM_USER
+77: return wxT("TB_ADDSTRINGW");
6781 case WM_USER
+29: return wxT("TB_GETITEMRECT");
6782 case WM_USER
+30: return wxT("TB_BUTTONSTRUCTSIZE");
6783 case WM_USER
+31: return wxT("TB_SETBUTTONSIZE");
6784 case WM_USER
+32: return wxT("TB_SETBITMAPSIZE");
6785 case WM_USER
+33: return wxT("TB_AUTOSIZE");
6786 case WM_USER
+35: return wxT("TB_GETTOOLTIPS");
6787 case WM_USER
+36: return wxT("TB_SETTOOLTIPS");
6788 case WM_USER
+37: return wxT("TB_SETPARENT");
6789 case WM_USER
+39: return wxT("TB_SETROWS");
6790 case WM_USER
+40: return wxT("TB_GETROWS");
6791 case WM_USER
+42: return wxT("TB_SETCMDID");
6792 case WM_USER
+43: return wxT("TB_CHANGEBITMAP");
6793 case WM_USER
+44: return wxT("TB_GETBITMAP");
6794 case WM_USER
+45: return wxT("TB_GETBUTTONTEXTA");
6795 case WM_USER
+75: return wxT("TB_GETBUTTONTEXTW");
6796 case WM_USER
+46: return wxT("TB_REPLACEBITMAP");
6797 case WM_USER
+47: return wxT("TB_SETINDENT");
6798 case WM_USER
+48: return wxT("TB_SETIMAGELIST");
6799 case WM_USER
+49: return wxT("TB_GETIMAGELIST");
6800 case WM_USER
+50: return wxT("TB_LOADIMAGES");
6801 case WM_USER
+51: return wxT("TB_GETRECT");
6802 case WM_USER
+52: return wxT("TB_SETHOTIMAGELIST");
6803 case WM_USER
+53: return wxT("TB_GETHOTIMAGELIST");
6804 case WM_USER
+54: return wxT("TB_SETDISABLEDIMAGELIST");
6805 case WM_USER
+55: return wxT("TB_GETDISABLEDIMAGELIST");
6806 case WM_USER
+56: return wxT("TB_SETSTYLE");
6807 case WM_USER
+57: return wxT("TB_GETSTYLE");
6808 case WM_USER
+58: return wxT("TB_GETBUTTONSIZE");
6809 case WM_USER
+59: return wxT("TB_SETBUTTONWIDTH");
6810 case WM_USER
+60: return wxT("TB_SETMAXTEXTROWS");
6811 case WM_USER
+61: return wxT("TB_GETTEXTROWS");
6812 case WM_USER
+41: return wxT("TB_GETBITMAPFLAGS");
6815 static wxString s_szBuf
;
6816 s_szBuf
.Printf(wxT("<unknown message = %d>"), message
);
6817 return s_szBuf
.c_str();
6820 #endif //__WXDEBUG__
6822 static TEXTMETRIC
wxGetTextMetrics(const wxWindowMSW
*win
)
6826 HWND hwnd
= GetHwndOf(win
);
6827 HDC hdc
= ::GetDC(hwnd
);
6829 #if !wxDIALOG_UNIT_COMPATIBILITY
6830 // and select the current font into it
6831 HFONT hfont
= GetHfontOf(win
->GetFont());
6834 hfont
= (HFONT
)::SelectObject(hdc
, hfont
);
6838 // finally retrieve the text metrics from it
6839 GetTextMetrics(hdc
, &tm
);
6841 #if !wxDIALOG_UNIT_COMPATIBILITY
6845 (void)::SelectObject(hdc
, hfont
);
6849 ::ReleaseDC(hwnd
, hdc
);
6854 // Find the wxWindow at the current mouse position, returning the mouse
6856 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
6858 pt
= wxGetMousePosition();
6859 return wxFindWindowAtPoint(pt
);
6862 wxWindow
* wxFindWindowAtPoint(const wxPoint
& pt
)
6868 HWND hWnd
= ::WindowFromPoint(pt2
);
6870 return wxGetWindowFromHWND((WXHWND
)hWnd
);
6873 // Get the current mouse position.
6874 wxPoint
wxGetMousePosition()
6878 GetCursorPosWinCE(&pt
);
6880 GetCursorPos( & pt
);
6883 return wxPoint(pt
.x
, pt
.y
);
6888 #if defined(__SMARTPHONE__) || defined(__POCKETPC__)
6889 static void WinCEUnregisterHotKey(int modifiers
, int id
)
6891 // Register hotkeys for the hardware buttons
6893 typedef BOOL (WINAPI
*UnregisterFunc1Proc
)(UINT
, UINT
);
6895 UnregisterFunc1Proc procUnregisterFunc
;
6896 hCoreDll
= LoadLibrary(_T("coredll.dll"));
6899 procUnregisterFunc
= (UnregisterFunc1Proc
)GetProcAddress(hCoreDll
, _T("UnregisterFunc1"));
6900 if (procUnregisterFunc
)
6901 procUnregisterFunc(modifiers
, id
);
6902 FreeLibrary(hCoreDll
);
6907 bool wxWindowMSW::RegisterHotKey(int hotkeyId
, int modifiers
, int keycode
)
6909 UINT win_modifiers
=0;
6910 if ( modifiers
& wxMOD_ALT
)
6911 win_modifiers
|= MOD_ALT
;
6912 if ( modifiers
& wxMOD_SHIFT
)
6913 win_modifiers
|= MOD_SHIFT
;
6914 if ( modifiers
& wxMOD_CONTROL
)
6915 win_modifiers
|= MOD_CONTROL
;
6916 if ( modifiers
& wxMOD_WIN
)
6917 win_modifiers
|= MOD_WIN
;
6919 #if defined(__SMARTPHONE__) || defined(__POCKETPC__)
6920 // Required for PPC and Smartphone hardware buttons
6921 if (keycode
>= WXK_SPECIAL1
&& keycode
<= WXK_SPECIAL20
)
6922 WinCEUnregisterHotKey(win_modifiers
, hotkeyId
);
6925 if ( !::RegisterHotKey(GetHwnd(), hotkeyId
, win_modifiers
, keycode
) )
6927 wxLogLastError(_T("RegisterHotKey"));
6935 bool wxWindowMSW::UnregisterHotKey(int hotkeyId
)
6937 #if defined(__SMARTPHONE__) || defined(__POCKETPC__)
6938 WinCEUnregisterHotKey(MOD_WIN
, hotkeyId
);
6941 if ( !::UnregisterHotKey(GetHwnd(), hotkeyId
) )
6943 wxLogLastError(_T("UnregisterHotKey"));
6953 bool wxWindowMSW::HandleHotKey(WXWPARAM wParam
, WXLPARAM lParam
)
6955 int hotkeyId
= wParam
;
6956 int virtualKey
= HIWORD(lParam
);
6957 int win_modifiers
= LOWORD(lParam
);
6959 wxKeyEvent
event(CreateKeyEvent(wxEVT_HOTKEY
, virtualKey
, wParam
, lParam
));
6960 event
.SetId(hotkeyId
);
6961 event
.m_shiftDown
= (win_modifiers
& MOD_SHIFT
) != 0;
6962 event
.m_controlDown
= (win_modifiers
& MOD_CONTROL
) != 0;
6963 event
.m_altDown
= (win_modifiers
& MOD_ALT
) != 0;
6964 event
.m_metaDown
= (win_modifiers
& MOD_WIN
) != 0;
6966 return HandleWindowEvent(event
);
6969 #endif // wxUSE_ACCEL
6971 #endif // wxUSE_HOTKEY
6973 // Not tested under WinCE
6976 // this class installs a message hook which really wakes up our idle processing
6977 // each time a WM_NULL is received (wxWakeUpIdle does this), even if we're
6978 // sitting inside a local modal loop (e.g. a menu is opened or scrollbar is
6979 // being dragged or even inside ::MessageBox()) and so don't control message
6980 // dispatching otherwise
6981 class wxIdleWakeUpModule
: public wxModule
6984 virtual bool OnInit()
6986 ms_hMsgHookProc
= ::SetWindowsHookEx
6989 &wxIdleWakeUpModule::MsgHookProc
,
6991 GetCurrentThreadId()
6994 if ( !ms_hMsgHookProc
)
6996 wxLogLastError(_T("SetWindowsHookEx(WH_GETMESSAGE)"));
7004 virtual void OnExit()
7006 ::UnhookWindowsHookEx(wxIdleWakeUpModule::ms_hMsgHookProc
);
7009 static LRESULT CALLBACK
MsgHookProc(int nCode
, WPARAM wParam
, LPARAM lParam
)
7011 MSG
*msg
= (MSG
*)lParam
;
7013 // only process the message if it is actually going to be removed from
7014 // the message queue, this prevents that the same event from being
7015 // processed multiple times if now someone just called PeekMessage()
7016 if ( msg
->message
== WM_NULL
&& wParam
== PM_REMOVE
)
7018 wxTheApp
->ProcessPendingEvents();
7021 return CallNextHookEx(ms_hMsgHookProc
, nCode
, wParam
, lParam
);
7025 static HHOOK ms_hMsgHookProc
;
7027 DECLARE_DYNAMIC_CLASS(wxIdleWakeUpModule
)
7030 HHOOK
wxIdleWakeUpModule::ms_hMsgHookProc
= 0;
7032 IMPLEMENT_DYNAMIC_CLASS(wxIdleWakeUpModule
, wxModule
)
7034 #endif // __WXWINCE__
7039 static void wxAdjustZOrder(wxWindow
* parent
)
7041 if (parent
->IsKindOf(CLASSINFO(wxStaticBox
)))
7043 // Set the z-order correctly
7044 SetWindowPos((HWND
) parent
->GetHWND(), HWND_BOTTOM
, 0, 0, 0, 0, SWP_NOMOVE
|SWP_NOSIZE
);
7047 wxWindowList::compatibility_iterator current
= parent
->GetChildren().GetFirst();
7050 wxWindow
*childWin
= current
->GetData();
7051 wxAdjustZOrder(childWin
);
7052 current
= current
->GetNext();
7057 // We need to adjust the z-order of static boxes in WinCE, to
7058 // make 'contained' controls visible
7059 void wxWindowMSW::OnInitDialog( wxInitDialogEvent
& event
)
7062 wxAdjustZOrder(this);