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"
84 #include "wx/tooltip.h"
92 #include "wx/spinctrl.h"
93 #endif // wxUSE_SPINCTRL
95 #include "wx/notebook.h"
96 #include "wx/listctrl.h"
97 #include "wx/dynlib.h"
101 #if (!defined(__GNUWIN32_OLD__) && !defined(__WXMICROWIN__) /* && !defined(__WXWINCE__) */ ) || defined(__CYGWIN10__)
102 #include <shellapi.h>
103 #include <mmsystem.h>
107 #include <windowsx.h>
110 #if !defined __WXWINCE__ && !defined NEED_PBT_H
114 #if defined(__WXWINCE__)
115 #include "wx/msw/wince/missing.h"
118 #include <shellapi.h>
120 #include <aygshell.h>
124 #if defined(TME_LEAVE) && defined(WM_MOUSELEAVE) && wxUSE_DYNLIB_CLASS
125 #define HAVE_TRACKMOUSEEVENT
126 #endif // everything needed for TrackMouseEvent()
128 // if this is set to 1, we use deferred window sizing to reduce flicker when
129 // resizing complicated window hierarchies, but this can in theory result in
130 // different behaviour than the old code so we keep the possibility to use it
131 // by setting this to 0 (in the future this should be removed completely)
133 #define USE_DEFERRED_SIZING 0
135 #define USE_DEFERRED_SIZING 1
138 // set this to 1 to filter out duplicate mouse events, e.g. mouse move events
139 // when mouse position didnd't change
141 #define wxUSE_MOUSEEVENT_HACK 0
143 #define wxUSE_MOUSEEVENT_HACK 1
146 // not all compilers/platforms have X button related declarations (notably
147 // Windows CE doesn't, and probably some old SDKs don't neither)
148 #ifdef WM_XBUTTONDOWN
149 #define wxHAS_XBUTTON
152 // ---------------------------------------------------------------------------
154 // ---------------------------------------------------------------------------
156 #if wxUSE_MENUS_NATIVE
157 wxMenu
*wxCurrentPopupMenu
= NULL
;
158 #endif // wxUSE_MENUS_NATIVE
161 extern wxChar
*wxCanvasClassName
;
163 extern const wxChar
*wxCanvasClassName
;
166 // true if we had already created the std colour map, used by
167 // wxGetStdColourMap() and wxWindow::OnSysColourChanged() (FIXME-MT)
168 static bool gs_hasStdCmap
= false;
170 // last mouse event information we need to filter out the duplicates
171 #if wxUSE_MOUSEEVENT_HACK
172 static struct MouseEventInfoDummy
174 // mouse position (in screen coordinates)
177 // last mouse event type
180 #endif // wxUSE_MOUSEEVENT_HACK
182 // hash containing the registered handlers for the custom messages
183 WX_DECLARE_HASH_MAP(int, wxWindow::MSWMessageHandler
,
184 wxIntegerHash
, wxIntegerEqual
,
187 static MSWMessageHandlers gs_messageHandlers
;
189 // ---------------------------------------------------------------------------
191 // ---------------------------------------------------------------------------
193 // the window proc for all our windows
194 LRESULT WXDLLEXPORT APIENTRY _EXPORT
wxWndProc(HWND hWnd
, UINT message
,
195 WPARAM wParam
, LPARAM lParam
);
199 const wxChar
*wxGetMessageName(int message
);
202 void wxRemoveHandleAssociation(wxWindowMSW
*win
);
203 extern void wxAssociateWinWithHandle(HWND hWnd
, wxWindowMSW
*win
);
204 wxWindow
*wxFindWinFromHandle(WXHWND hWnd
);
206 // get the text metrics for the current font
207 static TEXTMETRIC
wxGetTextMetrics(const wxWindowMSW
*win
);
210 // find the window for the mouse event at the specified position
211 static wxWindowMSW
*FindWindowForMouseEvent(wxWindowMSW
*win
, int *x
, int *y
);
212 #endif // __WXWINCE__
214 // wrapper around BringWindowToTop() API
215 static inline void wxBringWindowToTop(HWND hwnd
)
217 #ifdef __WXMICROWIN__
218 // It seems that MicroWindows brings the _parent_ of the window to the top,
219 // which can be the wrong one.
221 // activate (set focus to) specified window
225 // raise top level parent to top of z order
226 if (!::SetWindowPos(hwnd
, HWND_TOP
, 0, 0, 0, 0, SWP_NOMOVE
| SWP_NOSIZE
))
228 wxLogLastError(_T("SetWindowPos"));
234 // ensure that all our parent windows have WS_EX_CONTROLPARENT style
235 static void EnsureParentHasControlParentStyle(wxWindow
*parent
)
238 If we have WS_EX_CONTROLPARENT flag we absolutely *must* set it for our
239 parent as well as otherwise several Win32 functions using
240 GetNextDlgTabItem() to iterate over all controls such as
241 IsDialogMessage() or DefDlgProc() would enter an infinite loop: indeed,
242 all of them iterate over all the controls starting from the currently
243 focused one and stop iterating when they get back to the focus but
244 unless all parents have WS_EX_CONTROLPARENT bit set, they would never
245 get back to the initial (focused) window: as we do have this style,
246 GetNextDlgTabItem() will leave this window and continue in its parent,
247 but if the parent doesn't have it, it wouldn't recurse inside it later
248 on and so wouldn't have a chance of getting back to this window either.
250 while ( parent
&& !parent
->IsTopLevel() )
252 LONG exStyle
= ::GetWindowLong(GetHwndOf(parent
), GWL_EXSTYLE
);
253 if ( !(exStyle
& WS_EX_CONTROLPARENT
) )
255 // force the parent to have this style
256 ::SetWindowLong(GetHwndOf(parent
), GWL_EXSTYLE
,
257 exStyle
| WS_EX_CONTROLPARENT
);
260 parent
= parent
->GetParent();
264 #endif // !__WXWINCE__
267 // On Windows CE, GetCursorPos can return an error, so use this function
269 bool GetCursorPosWinCE(POINT
* pt
)
271 if (!GetCursorPos(pt
))
273 DWORD pos
= GetMessagePos();
281 // ---------------------------------------------------------------------------
283 // ---------------------------------------------------------------------------
285 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
287 #ifdef __WXUNIVERSAL__
288 IMPLEMENT_ABSTRACT_CLASS(wxWindowMSW
, wxWindowBase
)
290 #if wxUSE_EXTENDED_RTTI
292 // windows that are created from a parent window during its Create method, eg. spin controls in a calendar controls
293 // must never been streamed out separately otherwise chaos occurs. Right now easiest is to test for negative ids, as
294 // windows with negative ids never can be recreated anyway
296 bool wxWindowStreamingCallback( const wxObject
*object
, wxWriter
* , wxPersister
* , wxxVariantArray
& )
298 const wxWindow
* win
= dynamic_cast<const wxWindow
*>(object
) ;
299 if ( win
&& win
->GetId() < 0 )
304 IMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxWindow
, wxWindowBase
,"wx/window.h", wxWindowStreamingCallback
)
306 // make wxWindowList known before the property is used
308 wxCOLLECTION_TYPE_INFO( wxWindow
* , wxWindowList
) ;
310 template<> void wxCollectionToVariantArray( wxWindowList
const &theList
, wxxVariantArray
&value
)
312 wxListCollectionToVariantArray
<wxWindowList::compatibility_iterator
>( theList
, value
) ;
315 WX_DEFINE_FLAGS( wxWindowStyle
)
317 wxBEGIN_FLAGS( wxWindowStyle
)
318 // new style border flags, we put them first to
319 // use them for streaming out
321 wxFLAGS_MEMBER(wxBORDER_SIMPLE
)
322 wxFLAGS_MEMBER(wxBORDER_SUNKEN
)
323 wxFLAGS_MEMBER(wxBORDER_DOUBLE
)
324 wxFLAGS_MEMBER(wxBORDER_RAISED
)
325 wxFLAGS_MEMBER(wxBORDER_STATIC
)
326 wxFLAGS_MEMBER(wxBORDER_NONE
)
328 // old style border flags
329 wxFLAGS_MEMBER(wxSIMPLE_BORDER
)
330 wxFLAGS_MEMBER(wxSUNKEN_BORDER
)
331 wxFLAGS_MEMBER(wxDOUBLE_BORDER
)
332 wxFLAGS_MEMBER(wxRAISED_BORDER
)
333 wxFLAGS_MEMBER(wxSTATIC_BORDER
)
334 wxFLAGS_MEMBER(wxBORDER
)
336 // standard window styles
337 wxFLAGS_MEMBER(wxTAB_TRAVERSAL
)
338 wxFLAGS_MEMBER(wxCLIP_CHILDREN
)
339 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
)
340 wxFLAGS_MEMBER(wxWANTS_CHARS
)
341 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
)
342 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB
)
343 wxFLAGS_MEMBER(wxVSCROLL
)
344 wxFLAGS_MEMBER(wxHSCROLL
)
346 wxEND_FLAGS( wxWindowStyle
)
348 wxBEGIN_PROPERTIES_TABLE(wxWindow
)
349 wxEVENT_PROPERTY( Close
, wxEVT_CLOSE_WINDOW
, wxCloseEvent
)
350 wxEVENT_PROPERTY( Create
, wxEVT_CREATE
, wxWindowCreateEvent
)
351 wxEVENT_PROPERTY( Destroy
, wxEVT_DESTROY
, wxWindowDestroyEvent
)
352 // Always constructor Properties first
354 wxREADONLY_PROPERTY( Parent
,wxWindow
*, GetParent
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
355 wxPROPERTY( Id
,wxWindowID
, SetId
, GetId
, -1 /*wxID_ANY*/ , 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
356 wxPROPERTY( Position
,wxPoint
, SetPosition
, GetPosition
, wxDefaultPosition
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // pos
357 wxPROPERTY( Size
,wxSize
, SetSize
, GetSize
, wxDefaultSize
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // size
358 wxPROPERTY( WindowStyle
, long , SetWindowStyleFlag
, GetWindowStyleFlag
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
360 // Then all relations of the object graph
362 wxREADONLY_PROPERTY_COLLECTION( Children
, wxWindowList
, wxWindowBase
* , GetWindowChildren
, wxPROP_OBJECT_GRAPH
/*flags*/ , wxT("Helpstring") , wxT("group"))
364 // and finally all other properties
366 wxPROPERTY( ExtraStyle
, long , SetExtraStyle
, GetExtraStyle
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // extstyle
367 wxPROPERTY( BackgroundColour
, wxColour
, SetBackgroundColour
, GetBackgroundColour
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // bg
368 wxPROPERTY( ForegroundColour
, wxColour
, SetForegroundColour
, GetForegroundColour
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // fg
369 wxPROPERTY( Enabled
, bool , Enable
, IsEnabled
, wxxVariant((bool)true) , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
370 wxPROPERTY( Shown
, bool , Show
, IsShown
, wxxVariant((bool)true) , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
372 // possible property candidates (not in xrc) or not valid in all subclasses
373 wxPROPERTY( Title
,wxString
, SetTitle
, GetTitle
, wxEmptyString
)
374 wxPROPERTY( Font
, wxFont
, SetFont
, GetWindowFont
, )
375 wxPROPERTY( Label
,wxString
, SetLabel
, GetLabel
, wxEmptyString
)
376 // MaxHeight, Width , MinHeight , Width
377 // TODO switch label to control and title to toplevels
379 wxPROPERTY( ThemeEnabled
, bool , SetThemeEnabled
, GetThemeEnabled
, )
380 //wxPROPERTY( Cursor , wxCursor , SetCursor , GetCursor , )
381 // wxPROPERTY( ToolTip , wxString , SetToolTip , GetToolTipText , )
382 wxPROPERTY( AutoLayout
, bool , SetAutoLayout
, GetAutoLayout
, )
387 wxEND_PROPERTIES_TABLE()
389 wxBEGIN_HANDLERS_TABLE(wxWindow
)
390 wxEND_HANDLERS_TABLE()
392 wxCONSTRUCTOR_DUMMY(wxWindow
)
395 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
397 #endif // __WXUNIVERSAL__/__WXMSW__
399 BEGIN_EVENT_TABLE(wxWindowMSW
, wxWindowBase
)
400 EVT_SYS_COLOUR_CHANGED(wxWindowMSW::OnSysColourChanged
)
401 EVT_ERASE_BACKGROUND(wxWindowMSW::OnEraseBackground
)
403 EVT_INIT_DIALOG(wxWindowMSW::OnInitDialog
)
407 // ===========================================================================
409 // ===========================================================================
411 // ---------------------------------------------------------------------------
412 // wxWindow utility functions
413 // ---------------------------------------------------------------------------
415 // Find an item given the MS Windows id
416 wxWindow
*wxWindowMSW::FindItem(long id
) const
419 wxControl
*item
= wxDynamicCastThis(wxControl
);
422 // is it us or one of our "internal" children?
423 if ( item
->GetId() == id
424 #ifndef __WXUNIVERSAL__
425 || (item
->GetSubcontrols().Index(id
) != wxNOT_FOUND
)
426 #endif // __WXUNIVERSAL__
432 #endif // wxUSE_CONTROLS
434 wxWindowList::compatibility_iterator current
= GetChildren().GetFirst();
437 wxWindow
*childWin
= current
->GetData();
439 wxWindow
*wnd
= childWin
->FindItem(id
);
443 current
= current
->GetNext();
449 // Find an item given the MS Windows handle
450 wxWindow
*wxWindowMSW::FindItemByHWND(WXHWND hWnd
, bool controlOnly
) const
452 wxWindowList::compatibility_iterator current
= GetChildren().GetFirst();
455 wxWindow
*parent
= current
->GetData();
457 // Do a recursive search.
458 wxWindow
*wnd
= parent
->FindItemByHWND(hWnd
);
464 || parent
->IsKindOf(CLASSINFO(wxControl
))
465 #endif // wxUSE_CONTROLS
468 wxWindow
*item
= current
->GetData();
469 if ( item
->GetHWND() == hWnd
)
473 if ( item
->ContainsHWND(hWnd
) )
478 current
= current
->GetNext();
483 // Default command handler
484 bool wxWindowMSW::MSWCommand(WXUINT
WXUNUSED(param
), WXWORD
WXUNUSED(id
))
489 // ----------------------------------------------------------------------------
490 // constructors and such
491 // ----------------------------------------------------------------------------
493 void wxWindowMSW::Init()
496 m_isBeingDeleted
= false;
498 m_mouseInWindow
= false;
499 m_lastKeydownProcessed
= false;
509 m_pendingPosition
= wxDefaultPosition
;
510 m_pendingSize
= wxDefaultSize
;
513 m_contextMenuEnabled
= false;
518 wxWindowMSW::~wxWindowMSW()
520 m_isBeingDeleted
= true;
522 #ifndef __WXUNIVERSAL__
523 // VS: make sure there's no wxFrame with last focus set to us:
524 for ( wxWindow
*win
= GetParent(); win
; win
= win
->GetParent() )
526 wxTopLevelWindow
*frame
= wxDynamicCast(win
, wxTopLevelWindow
);
529 if ( frame
->GetLastFocus() == this )
531 frame
->SetLastFocus(NULL
);
534 // apparently sometimes we can end up with our grand parent
535 // pointing to us as well: this is surely a bug in focus handling
536 // code but it's not clear where it happens so for now just try to
537 // fix it here by not breaking out of the loop
541 #endif // __WXUNIVERSAL__
543 // VS: destroy children first and _then_ detach *this from its parent.
544 // If we did it the other way around, children wouldn't be able
545 // find their parent frame (see above).
550 // VZ: test temp removed to understand what really happens here
551 //if (::IsWindow(GetHwnd()))
553 if ( !::DestroyWindow(GetHwnd()) )
554 wxLogLastError(wxT("DestroyWindow"));
557 // remove hWnd <-> wxWindow association
558 wxRemoveHandleAssociation(this);
563 // real construction (Init() must have been called before!)
564 bool wxWindowMSW::Create(wxWindow
*parent
,
569 const wxString
& name
)
571 wxCHECK_MSG( parent
, false, wxT("can't create wxWindow without parent") );
573 if ( !CreateBase(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
) )
576 parent
->AddChild(this);
579 DWORD msflags
= MSWGetCreateWindowFlags(&exstyle
);
581 #ifdef __WXUNIVERSAL__
582 // no borders, we draw them ourselves
583 exstyle
&= ~(WS_EX_DLGMODALFRAME
|
587 msflags
&= ~WS_BORDER
;
588 #endif // wxUniversal
592 msflags
|= WS_VISIBLE
;
595 if ( !MSWCreate(wxCanvasClassName
, NULL
, pos
, size
, msflags
, exstyle
) )
603 // ---------------------------------------------------------------------------
605 // ---------------------------------------------------------------------------
607 void wxWindowMSW::SetFocus()
609 HWND hWnd
= GetHwnd();
610 wxCHECK_RET( hWnd
, _T("can't set focus to invalid window") );
612 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
616 if ( !::SetFocus(hWnd
) )
618 #if defined(__WXDEBUG__) && !defined(__WXMICROWIN__)
619 // was there really an error?
620 DWORD dwRes
= ::GetLastError();
623 HWND hwndFocus
= ::GetFocus();
624 if ( hwndFocus
!= hWnd
)
626 wxLogApiError(_T("SetFocus"), dwRes
);
633 void wxWindowMSW::SetFocusFromKbd()
635 // when the focus is given to the control with DLGC_HASSETSEL style from
636 // keyboard its contents should be entirely selected: this is what
637 // ::IsDialogMessage() does and so we should do it as well to provide the
638 // same LNF as the native programs
639 if ( ::SendMessage(GetHwnd(), WM_GETDLGCODE
, 0, 0) & DLGC_HASSETSEL
)
641 ::SendMessage(GetHwnd(), EM_SETSEL
, 0, -1);
644 // do this after (maybe) setting the selection as like this when
645 // wxEVT_SET_FOCUS handler is called, the selection would have been already
646 // set correctly -- this may be important
647 wxWindowBase::SetFocusFromKbd();
650 // Get the window with the focus
651 wxWindow
*wxWindowBase::DoFindFocus()
653 HWND hWnd
= ::GetFocus();
656 return wxGetWindowFromHWND((WXHWND
)hWnd
);
662 void wxWindowMSW::DoEnable( bool enable
)
664 HWND hWnd
= GetHwnd();
666 ::EnableWindow(hWnd
, (BOOL
)enable
);
669 bool wxWindowMSW::Show(bool show
)
671 if ( !wxWindowBase::Show(show
) )
674 HWND hWnd
= GetHwnd();
676 // we could be called before the underlying window is created (this is
677 // actually useful to prevent it from being initially shown), e.g.
679 // wxFoo *foo = new wxFoo;
681 // foo->Create(parent, ...);
683 // should work without errors
686 ::ShowWindow(hWnd
, show
? SW_SHOW
: SW_HIDE
);
692 // Raise the window to the top of the Z order
693 void wxWindowMSW::Raise()
695 wxBringWindowToTop(GetHwnd());
698 // Lower the window to the bottom of the Z order
699 void wxWindowMSW::Lower()
701 ::SetWindowPos(GetHwnd(), HWND_BOTTOM
, 0, 0, 0, 0,
702 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
705 void wxWindowMSW::DoCaptureMouse()
707 HWND hWnd
= GetHwnd();
714 void wxWindowMSW::DoReleaseMouse()
716 if ( !::ReleaseCapture() )
718 wxLogLastError(_T("ReleaseCapture"));
722 /* static */ wxWindow
*wxWindowBase::GetCapture()
724 HWND hwnd
= ::GetCapture();
725 return hwnd
? wxFindWinFromHandle((WXHWND
)hwnd
) : (wxWindow
*)NULL
;
728 bool wxWindowMSW::SetFont(const wxFont
& font
)
730 if ( !wxWindowBase::SetFont(font
) )
736 HWND hWnd
= GetHwnd();
739 WXHANDLE hFont
= m_font
.GetResourceHandle();
741 wxASSERT_MSG( hFont
, wxT("should have valid font") );
743 ::SendMessage(hWnd
, WM_SETFONT
, (WPARAM
)hFont
, MAKELPARAM(TRUE
, 0));
748 bool wxWindowMSW::SetCursor(const wxCursor
& cursor
)
750 if ( !wxWindowBase::SetCursor(cursor
) )
756 // don't "overwrite" busy cursor
757 if ( m_cursor
.Ok() && !wxIsBusy() )
759 // normally we should change the cursor only if it's over this window
760 // but we should do it always if we capture the mouse currently
761 bool set
= HasCapture();
764 HWND hWnd
= GetHwnd();
768 ::GetCursorPosWinCE(&point
);
770 ::GetCursorPos(&point
);
773 RECT rect
= wxGetWindowRect(hWnd
);
775 set
= ::PtInRect(&rect
, point
) != 0;
780 ::SetCursor(GetHcursorOf(m_cursor
));
782 //else: will be set later when the mouse enters this window
788 void wxWindowMSW::WarpPointer(int x
, int y
)
790 ClientToScreen(&x
, &y
);
792 if ( !::SetCursorPos(x
, y
) )
794 wxLogLastError(_T("SetCursorPos"));
798 void wxWindowMSW::MSWUpdateUIState(int action
, int state
)
800 // WM_CHANGEUISTATE only appeared in Windows 2000 so it can do us no good
801 // to use it on older systems -- and could possibly do some harm
802 static int s_needToUpdate
= -1;
803 if ( s_needToUpdate
== -1 )
806 s_needToUpdate
= wxGetOsVersion(&verMaj
, &verMin
) == wxOS_WINDOWS_NT
&&
810 if ( s_needToUpdate
)
812 // we send WM_CHANGEUISTATE so if nothing needs changing then the system
813 // won't send WM_UPDATEUISTATE
814 ::SendMessage(GetHwnd(), WM_CHANGEUISTATE
, MAKEWPARAM(action
, state
), 0);
818 // ---------------------------------------------------------------------------
820 // ---------------------------------------------------------------------------
822 inline int GetScrollPosition(HWND hWnd
, int wOrient
)
824 #ifdef __WXMICROWIN__
825 return ::GetScrollPosWX(hWnd
, wOrient
);
827 WinStruct
<SCROLLINFO
> scrollInfo
;
828 scrollInfo
.cbSize
= sizeof(SCROLLINFO
);
829 scrollInfo
.fMask
= SIF_POS
;
830 ::GetScrollInfo(hWnd
, wOrient
, &scrollInfo
);
832 return scrollInfo
.nPos
;
837 int wxWindowMSW::GetScrollPos(int orient
) const
839 HWND hWnd
= GetHwnd();
840 wxCHECK_MSG( hWnd
, 0, _T("no HWND in GetScrollPos") );
842 return GetScrollPosition(hWnd
, orient
== wxHORIZONTAL
? SB_HORZ
: SB_VERT
);
845 // This now returns the whole range, not just the number
846 // of positions that we can scroll.
847 int wxWindowMSW::GetScrollRange(int orient
) const
850 HWND hWnd
= GetHwnd();
854 ::GetScrollRange(hWnd
, orient
== wxHORIZONTAL
? SB_HORZ
: SB_VERT
,
857 WinStruct
<SCROLLINFO
> scrollInfo
;
858 scrollInfo
.fMask
= SIF_RANGE
;
859 if ( !::GetScrollInfo(hWnd
,
860 orient
== wxHORIZONTAL
? SB_HORZ
: SB_VERT
,
863 // Most of the time this is not really an error, since the return
864 // value can also be zero when there is no scrollbar yet.
865 // wxLogLastError(_T("GetScrollInfo"));
867 maxPos
= scrollInfo
.nMax
;
869 // undo "range - 1" done in SetScrollbar()
873 int wxWindowMSW::GetScrollThumb(int orient
) const
875 return orient
== wxHORIZONTAL
? m_xThumbSize
: m_yThumbSize
;
878 void wxWindowMSW::SetScrollPos(int orient
, int pos
, bool refresh
)
880 HWND hWnd
= GetHwnd();
881 wxCHECK_RET( hWnd
, _T("SetScrollPos: no HWND") );
883 WinStruct
<SCROLLINFO
> info
;
887 info
.fMask
= SIF_POS
;
888 if ( HasFlag(wxALWAYS_SHOW_SB
) )
890 // disable scrollbar instead of removing it then
891 info
.fMask
|= SIF_DISABLENOSCROLL
;
894 ::SetScrollInfo(hWnd
, orient
== wxHORIZONTAL
? SB_HORZ
: SB_VERT
,
898 // New function that will replace some of the above.
899 void wxWindowMSW::SetScrollbar(int orient
,
905 WinStruct
<SCROLLINFO
> info
;
906 info
.nPage
= pageSize
;
907 info
.nMin
= 0; // range is nMax - nMin + 1
908 info
.nMax
= range
- 1; // as both nMax and nMax are inclusive
910 info
.fMask
= SIF_RANGE
| SIF_PAGE
| SIF_POS
;
911 if ( HasFlag(wxALWAYS_SHOW_SB
) )
913 // disable scrollbar instead of removing it then
914 info
.fMask
|= SIF_DISABLENOSCROLL
;
917 HWND hWnd
= GetHwnd();
920 // We have to set the variables here to make them valid in events
921 // triggered by ::SetScrollInfo()
922 *(orient
== wxHORIZONTAL
? &m_xThumbSize
: &m_yThumbSize
) = pageSize
;
924 ::SetScrollInfo(hWnd
, orient
== wxHORIZONTAL
? SB_HORZ
: SB_VERT
,
929 void wxWindowMSW::ScrollWindow(int dx
, int dy
, const wxRect
*prect
)
935 wxCopyRectToRECT(*prect
, rect
);
945 // FIXME: is this the exact equivalent of the line below?
946 ::ScrollWindowEx(GetHwnd(), dx
, dy
, pr
, pr
, 0, 0, SW_SCROLLCHILDREN
|SW_ERASE
|SW_INVALIDATE
);
948 ::ScrollWindow(GetHwnd(), dx
, dy
, pr
, pr
);
952 static bool ScrollVertically(HWND hwnd
, int kind
, int count
)
954 int posStart
= GetScrollPosition(hwnd
, SB_VERT
);
957 for ( int n
= 0; n
< count
; n
++ )
959 ::SendMessage(hwnd
, WM_VSCROLL
, kind
, 0);
961 int posNew
= GetScrollPosition(hwnd
, SB_VERT
);
964 // don't bother to continue, we're already at top/bottom
971 return pos
!= posStart
;
974 bool wxWindowMSW::ScrollLines(int lines
)
976 bool down
= lines
> 0;
978 return ScrollVertically(GetHwnd(),
979 down
? SB_LINEDOWN
: SB_LINEUP
,
980 down
? lines
: -lines
);
983 bool wxWindowMSW::ScrollPages(int pages
)
985 bool down
= pages
> 0;
987 return ScrollVertically(GetHwnd(),
988 down
? SB_PAGEDOWN
: SB_PAGEUP
,
989 down
? pages
: -pages
);
992 // ----------------------------------------------------------------------------
994 // ----------------------------------------------------------------------------
996 void wxWindowMSW::SetLayoutDirection(wxLayoutDirection dir
)
1001 const HWND hwnd
= GetHwnd();
1002 wxCHECK_RET( hwnd
, _T("layout direction must be set after window creation") );
1004 LONG styleOld
= ::GetWindowLong(hwnd
, GWL_EXSTYLE
);
1006 LONG styleNew
= styleOld
;
1009 case wxLayout_LeftToRight
:
1010 styleNew
&= ~WS_EX_LAYOUTRTL
;
1013 case wxLayout_RightToLeft
:
1014 styleNew
|= WS_EX_LAYOUTRTL
;
1018 wxFAIL_MSG(_T("unsupported layout direction"));
1022 if ( styleNew
!= styleOld
)
1024 ::SetWindowLong(hwnd
, GWL_EXSTYLE
, styleNew
);
1029 wxLayoutDirection
wxWindowMSW::GetLayoutDirection() const
1032 return wxLayout_Default
;
1034 const HWND hwnd
= GetHwnd();
1035 wxCHECK_MSG( hwnd
, wxLayout_Default
, _T("invalid window") );
1037 return ::GetWindowLong(hwnd
, GWL_EXSTYLE
) & WS_EX_LAYOUTRTL
1038 ? wxLayout_RightToLeft
1039 : wxLayout_LeftToRight
;
1044 wxWindowMSW::AdjustForLayoutDirection(wxCoord x
,
1045 wxCoord
WXUNUSED(width
),
1046 wxCoord
WXUNUSED(widthTotal
)) const
1048 // Win32 mirrors the coordinates of RTL windows automatically, so don't
1049 // redo it ourselves
1053 // ---------------------------------------------------------------------------
1055 // ---------------------------------------------------------------------------
1057 void wxWindowMSW::SubclassWin(WXHWND hWnd
)
1059 wxASSERT_MSG( !m_oldWndProc
, wxT("subclassing window twice?") );
1061 HWND hwnd
= (HWND
)hWnd
;
1062 wxCHECK_RET( ::IsWindow(hwnd
), wxT("invalid HWND in SubclassWin") );
1064 wxAssociateWinWithHandle(hwnd
, this);
1066 m_oldWndProc
= (WXFARPROC
)wxGetWindowProc((HWND
)hWnd
);
1068 // we don't need to subclass the window of our own class (in the Windows
1069 // sense of the word)
1070 if ( !wxCheckWindowWndProc(hWnd
, (WXFARPROC
)wxWndProc
) )
1072 wxSetWindowProc(hwnd
, wxWndProc
);
1076 // don't bother restoring it either: this also makes it easy to
1077 // implement IsOfStandardClass() method which returns true for the
1078 // standard controls and false for the wxWidgets own windows as it can
1079 // simply check m_oldWndProc
1080 m_oldWndProc
= NULL
;
1083 // we're officially created now, send the event
1084 wxWindowCreateEvent
event((wxWindow
*)this);
1085 (void)GetEventHandler()->ProcessEvent(event
);
1088 void wxWindowMSW::UnsubclassWin()
1090 wxRemoveHandleAssociation(this);
1092 // Restore old Window proc
1093 HWND hwnd
= GetHwnd();
1098 wxCHECK_RET( ::IsWindow(hwnd
), wxT("invalid HWND in UnsubclassWin") );
1102 if ( !wxCheckWindowWndProc((WXHWND
)hwnd
, m_oldWndProc
) )
1104 wxSetWindowProc(hwnd
, (WNDPROC
)m_oldWndProc
);
1107 m_oldWndProc
= NULL
;
1112 void wxWindowMSW::AssociateHandle(WXWidget handle
)
1116 if ( !::DestroyWindow(GetHwnd()) )
1117 wxLogLastError(wxT("DestroyWindow"));
1120 WXHWND wxhwnd
= (WXHWND
)handle
;
1123 SubclassWin(wxhwnd
);
1126 void wxWindowMSW::DissociateHandle()
1128 // this also calls SetHWND(0) for us
1133 bool wxCheckWindowWndProc(WXHWND hWnd
,
1134 WXFARPROC
WXUNUSED(wndProc
))
1136 // TODO: This list of window class names should be factored out so they can be
1137 // managed in one place and then accessed from here and other places, such as
1138 // wxApp::RegisterWindowClasses() and wxApp::UnregisterWindowClasses()
1141 extern wxChar
*wxCanvasClassName
;
1142 extern wxChar
*wxCanvasClassNameNR
;
1144 extern const wxChar
*wxCanvasClassName
;
1145 extern const wxChar
*wxCanvasClassNameNR
;
1147 extern const wxChar
*wxMDIFrameClassName
;
1148 extern const wxChar
*wxMDIFrameClassNameNoRedraw
;
1149 extern const wxChar
*wxMDIChildFrameClassName
;
1150 extern const wxChar
*wxMDIChildFrameClassNameNoRedraw
;
1151 wxString
str(wxGetWindowClass(hWnd
));
1152 if (str
== wxCanvasClassName
||
1153 str
== wxCanvasClassNameNR
||
1155 str
== _T("wxGLCanvasClass") ||
1156 str
== _T("wxGLCanvasClassNR") ||
1157 #endif // wxUSE_GLCANVAS
1158 str
== wxMDIFrameClassName
||
1159 str
== wxMDIFrameClassNameNoRedraw
||
1160 str
== wxMDIChildFrameClassName
||
1161 str
== wxMDIChildFrameClassNameNoRedraw
||
1162 str
== _T("wxTLWHiddenParent"))
1163 return true; // Effectively means don't subclass
1168 // ----------------------------------------------------------------------------
1170 // ----------------------------------------------------------------------------
1172 void wxWindowMSW::SetWindowStyleFlag(long flags
)
1174 long flagsOld
= GetWindowStyleFlag();
1175 if ( flags
== flagsOld
)
1178 // update the internal variable
1179 wxWindowBase::SetWindowStyleFlag(flags
);
1181 // and the real window flags
1182 MSWUpdateStyle(flagsOld
, GetExtraStyle());
1185 void wxWindowMSW::SetExtraStyle(long exflags
)
1187 long exflagsOld
= GetExtraStyle();
1188 if ( exflags
== exflagsOld
)
1191 // update the internal variable
1192 wxWindowBase::SetExtraStyle(exflags
);
1194 // and the real window flags
1195 MSWUpdateStyle(GetWindowStyleFlag(), exflagsOld
);
1198 void wxWindowMSW::MSWUpdateStyle(long flagsOld
, long exflagsOld
)
1200 // now update the Windows style as well if needed - and if the window had
1201 // been already created
1205 // we may need to call SetWindowPos() when we change some styles
1206 bool callSWP
= false;
1209 long style
= MSWGetStyle(GetWindowStyleFlag(), &exstyle
);
1211 // this is quite a horrible hack but we need it because MSWGetStyle()
1212 // doesn't take exflags as parameter but uses GetExtraStyle() internally
1213 // and so we have to modify the window exflags temporarily to get the
1214 // correct exstyleOld
1215 long exflagsNew
= GetExtraStyle();
1216 wxWindowBase::SetExtraStyle(exflagsOld
);
1219 long styleOld
= MSWGetStyle(flagsOld
, &exstyleOld
);
1221 wxWindowBase::SetExtraStyle(exflagsNew
);
1224 if ( style
!= styleOld
)
1226 // some flags (e.g. WS_VISIBLE or WS_DISABLED) should not be changed by
1227 // this function so instead of simply setting the style to the new
1228 // value we clear the bits which were set in styleOld but are set in
1229 // the new one and set the ones which were not set before
1230 long styleReal
= ::GetWindowLong(GetHwnd(), GWL_STYLE
);
1231 styleReal
&= ~styleOld
;
1234 ::SetWindowLong(GetHwnd(), GWL_STYLE
, styleReal
);
1236 // we need to call SetWindowPos() if any of the styles affecting the
1237 // frame appearance have changed
1238 callSWP
= ((styleOld
^ style
) & (WS_BORDER
|
1247 // and the extended style
1248 long exstyleReal
= ::GetWindowLong(GetHwnd(), GWL_EXSTYLE
);
1250 if ( exstyle
!= exstyleOld
)
1252 exstyleReal
&= ~exstyleOld
;
1253 exstyleReal
|= exstyle
;
1255 ::SetWindowLong(GetHwnd(), GWL_EXSTYLE
, exstyleReal
);
1257 // ex style changes don't take effect without calling SetWindowPos
1263 // we must call SetWindowPos() to flush the cached extended style and
1264 // also to make the change to wxSTAY_ON_TOP style take effect: just
1265 // setting the style simply doesn't work
1266 if ( !::SetWindowPos(GetHwnd(),
1267 exstyleReal
& WS_EX_TOPMOST
? HWND_TOPMOST
1270 SWP_NOMOVE
| SWP_NOSIZE
| SWP_FRAMECHANGED
) )
1272 wxLogLastError(_T("SetWindowPos"));
1277 WXDWORD
wxWindowMSW::MSWGetStyle(long flags
, WXDWORD
*exstyle
) const
1279 // translate common wxWidgets styles to Windows ones
1281 // most of windows are child ones, those which are not (such as
1282 // wxTopLevelWindow) should remove WS_CHILD in their MSWGetStyle()
1283 WXDWORD style
= WS_CHILD
;
1285 // using this flag results in very significant reduction in flicker,
1286 // especially with controls inside the static boxes (as the interior of the
1287 // box is not redrawn twice), but sometimes results in redraw problems, so
1288 // optionally allow the old code to continue to use it provided a special
1289 // system option is turned on
1290 if ( !wxSystemOptions::GetOptionInt(wxT("msw.window.no-clip-children"))
1291 || (flags
& wxCLIP_CHILDREN
) )
1292 style
|= WS_CLIPCHILDREN
;
1294 // it doesn't seem useful to use WS_CLIPSIBLINGS here as we officially
1295 // don't support overlapping windows and it only makes sense for them and,
1296 // presumably, gives the system some extra work (to manage more clipping
1297 // regions), so avoid it alltogether
1300 if ( flags
& wxVSCROLL
)
1301 style
|= WS_VSCROLL
;
1303 if ( flags
& wxHSCROLL
)
1304 style
|= WS_HSCROLL
;
1306 const wxBorder border
= GetBorder(flags
);
1308 // WS_BORDER is only required for wxBORDER_SIMPLE
1309 if ( border
== wxBORDER_SIMPLE
)
1312 // now deal with ext style if the caller wants it
1318 if ( flags
& wxTRANSPARENT_WINDOW
)
1319 *exstyle
|= WS_EX_TRANSPARENT
;
1325 case wxBORDER_DEFAULT
:
1326 wxFAIL_MSG( _T("unknown border style") );
1330 case wxBORDER_SIMPLE
:
1333 case wxBORDER_STATIC
:
1334 *exstyle
|= WS_EX_STATICEDGE
;
1337 case wxBORDER_RAISED
:
1338 *exstyle
|= WS_EX_DLGMODALFRAME
;
1341 case wxBORDER_SUNKEN
:
1342 *exstyle
|= WS_EX_CLIENTEDGE
;
1343 style
&= ~WS_BORDER
;
1346 case wxBORDER_DOUBLE
:
1347 *exstyle
|= WS_EX_DLGMODALFRAME
;
1351 // wxUniv doesn't use Windows dialog navigation functions at all
1352 #if !defined(__WXUNIVERSAL__) && !defined(__WXWINCE__)
1353 // to make the dialog navigation work with the nested panels we must
1354 // use this style (top level windows such as dialogs don't need it)
1355 if ( (flags
& wxTAB_TRAVERSAL
) && !IsTopLevel() )
1357 *exstyle
|= WS_EX_CONTROLPARENT
;
1359 #endif // __WXUNIVERSAL__
1365 // Setup background and foreground colours correctly
1366 void wxWindowMSW::SetupColours()
1369 SetBackgroundColour(GetParent()->GetBackgroundColour());
1372 bool wxWindowMSW::IsMouseInWindow() const
1374 // get the mouse position
1377 ::GetCursorPosWinCE(&pt
);
1379 ::GetCursorPos(&pt
);
1382 // find the window which currently has the cursor and go up the window
1383 // chain until we find this window - or exhaust it
1384 HWND hwnd
= ::WindowFromPoint(pt
);
1385 while ( hwnd
&& (hwnd
!= GetHwnd()) )
1386 hwnd
= ::GetParent(hwnd
);
1388 return hwnd
!= NULL
;
1391 void wxWindowMSW::OnInternalIdle()
1393 #ifndef HAVE_TRACKMOUSEEVENT
1394 // Check if we need to send a LEAVE event
1395 if ( m_mouseInWindow
)
1397 // note that we should generate the leave event whether the window has
1398 // or doesn't have mouse capture
1399 if ( !IsMouseInWindow() )
1401 GenerateMouseLeave();
1404 #endif // !HAVE_TRACKMOUSEEVENT
1406 if (wxUpdateUIEvent::CanUpdate(this))
1407 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
1410 // Set this window to be the child of 'parent'.
1411 bool wxWindowMSW::Reparent(wxWindowBase
*parent
)
1413 if ( !wxWindowBase::Reparent(parent
) )
1416 HWND hWndChild
= GetHwnd();
1417 HWND hWndParent
= GetParent() ? GetWinHwnd(GetParent()) : (HWND
)0;
1419 ::SetParent(hWndChild
, hWndParent
);
1422 if ( ::GetWindowLong(hWndChild
, GWL_EXSTYLE
) & WS_EX_CONTROLPARENT
)
1424 EnsureParentHasControlParentStyle(GetParent());
1426 #endif // !__WXWINCE__
1431 static inline void SendSetRedraw(HWND hwnd
, bool on
)
1433 #ifndef __WXMICROWIN__
1434 ::SendMessage(hwnd
, WM_SETREDRAW
, (WPARAM
)on
, 0);
1438 void wxWindowMSW::Freeze()
1440 if ( !m_frozenness
++ )
1443 SendSetRedraw(GetHwnd(), false);
1447 void wxWindowMSW::Thaw()
1449 wxASSERT_MSG( m_frozenness
> 0, _T("Thaw() without matching Freeze()") );
1451 if ( --m_frozenness
== 0 )
1455 SendSetRedraw(GetHwnd(), true);
1457 // we need to refresh everything or otherwise the invalidated area
1458 // is not going to be repainted
1464 void wxWindowMSW::Refresh(bool eraseBack
, const wxRect
*rect
)
1466 HWND hWnd
= GetHwnd();
1473 wxCopyRectToRECT(*rect
, mswRect
);
1481 // RedrawWindow not available on SmartPhone or eVC++ 3
1482 #if !defined(__SMARTPHONE__) && !(defined(_WIN32_WCE) && _WIN32_WCE < 400)
1483 UINT flags
= RDW_INVALIDATE
| RDW_ALLCHILDREN
;
1487 ::RedrawWindow(hWnd
, pRect
, NULL
, flags
);
1489 ::InvalidateRect(hWnd
, pRect
, eraseBack
);
1494 void wxWindowMSW::Update()
1496 if ( !::UpdateWindow(GetHwnd()) )
1498 wxLogLastError(_T("UpdateWindow"));
1501 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
1502 // just calling UpdateWindow() is not enough, what we did in our WM_PAINT
1503 // handler needs to be really drawn right now
1508 // ---------------------------------------------------------------------------
1510 // ---------------------------------------------------------------------------
1512 #if wxUSE_DRAG_AND_DROP || !defined(__WXWINCE__)
1516 // we need to lower the sibling static boxes so controls contained within can be
1518 static void AdjustStaticBoxZOrder(wxWindow
*parent
)
1520 // no sibling static boxes if we have no parent (ie TLW)
1524 for ( wxWindowList::compatibility_iterator node
= parent
->GetChildren().GetFirst();
1526 node
= node
->GetNext() )
1528 wxStaticBox
*statbox
= wxDynamicCast(node
->GetData(), wxStaticBox
);
1531 ::SetWindowPos(GetHwndOf(statbox
), HWND_BOTTOM
, 0, 0, 0, 0,
1532 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
1537 #else // !wxUSE_STATBOX
1539 static inline void AdjustStaticBoxZOrder(wxWindow
* WXUNUSED(parent
))
1543 #endif // wxUSE_STATBOX/!wxUSE_STATBOX
1545 #endif // drag and drop is used
1547 #if wxUSE_DRAG_AND_DROP
1548 void wxWindowMSW::SetDropTarget(wxDropTarget
*pDropTarget
)
1550 if ( m_dropTarget
!= 0 ) {
1551 m_dropTarget
->Revoke(m_hWnd
);
1552 delete m_dropTarget
;
1555 m_dropTarget
= pDropTarget
;
1556 if ( m_dropTarget
!= 0 )
1558 AdjustStaticBoxZOrder(GetParent());
1559 m_dropTarget
->Register(m_hWnd
);
1562 #endif // wxUSE_DRAG_AND_DROP
1564 // old-style file manager drag&drop support: we retain the old-style
1565 // DragAcceptFiles in parallel with SetDropTarget.
1566 void wxWindowMSW::DragAcceptFiles(bool WXUNUSED_IN_WINCE(accept
))
1569 HWND hWnd
= GetHwnd();
1572 AdjustStaticBoxZOrder(GetParent());
1573 ::DragAcceptFiles(hWnd
, (BOOL
)accept
);
1578 // ----------------------------------------------------------------------------
1580 // ----------------------------------------------------------------------------
1584 void wxWindowMSW::DoSetToolTip(wxToolTip
*tooltip
)
1586 wxWindowBase::DoSetToolTip(tooltip
);
1589 m_tooltip
->SetWindow((wxWindow
*)this);
1592 #endif // wxUSE_TOOLTIPS
1594 // ---------------------------------------------------------------------------
1595 // moving and resizing
1596 // ---------------------------------------------------------------------------
1598 bool wxWindowMSW::IsSizeDeferred() const
1600 #if USE_DEFERRED_SIZING
1601 if ( m_pendingPosition
!= wxDefaultPosition
||
1602 m_pendingSize
!= wxDefaultSize
)
1604 #endif // USE_DEFERRED_SIZING
1610 void wxWindowMSW::DoGetSize(int *x
, int *y
) const
1612 #if USE_DEFERRED_SIZING
1613 // if SetSize() had been called at wx level but not realized at Windows
1614 // level yet (i.e. EndDeferWindowPos() not called), we still should return
1615 // the new and not the old position to the other wx code
1616 if ( m_pendingSize
!= wxDefaultSize
)
1619 *x
= m_pendingSize
.x
;
1621 *y
= m_pendingSize
.y
;
1623 else // use current size
1624 #endif // USE_DEFERRED_SIZING
1626 RECT rect
= wxGetWindowRect(GetHwnd());
1629 *x
= rect
.right
- rect
.left
;
1631 *y
= rect
.bottom
- rect
.top
;
1635 // Get size *available for subwindows* i.e. excluding menu bar etc.
1636 void wxWindowMSW::DoGetClientSize(int *x
, int *y
) const
1638 #if USE_DEFERRED_SIZING
1639 if ( m_pendingSize
!= wxDefaultSize
)
1641 // we need to calculate the client size corresponding to pending size
1643 rect
.left
= m_pendingPosition
.x
;
1644 rect
.top
= m_pendingPosition
.y
;
1645 rect
.right
= rect
.left
+ m_pendingSize
.x
;
1646 rect
.bottom
= rect
.top
+ m_pendingSize
.y
;
1648 ::SendMessage(GetHwnd(), WM_NCCALCSIZE
, FALSE
, (LPARAM
)&rect
);
1651 *x
= rect
.right
- rect
.left
;
1653 *y
= rect
.bottom
- rect
.top
;
1656 #endif // USE_DEFERRED_SIZING
1658 RECT rect
= wxGetClientRect(GetHwnd());
1667 void wxWindowMSW::DoGetPosition(int *x
, int *y
) const
1669 wxWindow
* const parent
= GetParent();
1672 if ( m_pendingPosition
!= wxDefaultPosition
)
1674 pos
= m_pendingPosition
;
1676 else // use current position
1678 RECT rect
= wxGetWindowRect(GetHwnd());
1681 point
.x
= rect
.left
;
1684 // we do the adjustments with respect to the parent only for the "real"
1685 // children, not for the dialogs/frames
1686 if ( !IsTopLevel() )
1688 if ( wxTheApp
->GetLayoutDirection() == wxLayout_RightToLeft
)
1690 // In RTL mode, we want the logical left x-coordinate,
1691 // which would be the physical right x-coordinate.
1692 point
.x
= rect
.right
;
1695 // Since we now have the absolute screen coords, if there's a
1696 // parent we must subtract its top left corner
1699 ::ScreenToClient(GetHwndOf(parent
), &point
);
1707 // we also must adjust by the client area offset: a control which is just
1708 // under a toolbar could be at (0, 30) in Windows but at (0, 0) in wx
1709 if ( parent
&& !IsTopLevel() )
1711 const wxPoint
pt(parent
->GetClientAreaOrigin());
1722 void wxWindowMSW::DoScreenToClient(int *x
, int *y
) const
1730 ::ScreenToClient(GetHwnd(), &pt
);
1738 void wxWindowMSW::DoClientToScreen(int *x
, int *y
) const
1746 ::ClientToScreen(GetHwnd(), &pt
);
1755 wxWindowMSW::DoMoveSibling(WXHWND hwnd
, int x
, int y
, int width
, int height
)
1757 #if USE_DEFERRED_SIZING
1758 // if our parent had prepared a defer window handle for us, use it (unless
1759 // we are a top level window)
1760 wxWindowMSW
* const parent
= IsTopLevel() ? NULL
: GetParent();
1762 HDWP hdwp
= parent
? (HDWP
)parent
->m_hDWP
: NULL
;
1765 hdwp
= ::DeferWindowPos(hdwp
, (HWND
)hwnd
, NULL
, x
, y
, width
, height
,
1766 SWP_NOZORDER
| SWP_NOOWNERZORDER
| SWP_NOACTIVATE
);
1769 wxLogLastError(_T("DeferWindowPos"));
1775 // hdwp must be updated as it may have been changed
1776 parent
->m_hDWP
= (WXHANDLE
)hdwp
;
1781 // did deferred move, remember new coordinates of the window as they're
1782 // different from what Windows would return for it
1786 // otherwise (or if deferring failed) move the window in place immediately
1787 #endif // USE_DEFERRED_SIZING
1788 if ( !::MoveWindow((HWND
)hwnd
, x
, y
, width
, height
, IsShown()) )
1790 wxLogLastError(wxT("MoveWindow"));
1793 // if USE_DEFERRED_SIZING, indicates that we didn't use deferred move,
1794 // ignored otherwise
1798 void wxWindowMSW::DoMoveWindow(int x
, int y
, int width
, int height
)
1800 // TODO: is this consistent with other platforms?
1801 // Still, negative width or height shouldn't be allowed
1807 if ( DoMoveSibling(m_hWnd
, x
, y
, width
, height
) )
1809 #if USE_DEFERRED_SIZING
1810 m_pendingPosition
= wxPoint(x
, y
);
1811 m_pendingSize
= wxSize(width
, height
);
1812 #endif // USE_DEFERRED_SIZING
1816 // set the size of the window: if the dimensions are positive, just use them,
1817 // but if any of them is equal to -1, it means that we must find the value for
1818 // it ourselves (unless sizeFlags contains wxSIZE_ALLOW_MINUS_ONE flag, in
1819 // which case -1 is a valid value for x and y)
1821 // If sizeFlags contains wxSIZE_AUTO_WIDTH/HEIGHT flags (default), we calculate
1822 // the width/height to best suit our contents, otherwise we reuse the current
1824 void wxWindowMSW::DoSetSize(int x
, int y
, int width
, int height
, int sizeFlags
)
1826 // get the current size and position...
1827 int currentX
, currentY
;
1828 int currentW
, currentH
;
1830 GetPosition(¤tX
, ¤tY
);
1831 GetSize(¤tW
, ¤tH
);
1833 // ... and don't do anything (avoiding flicker) if it's already ok unless
1834 // we're forced to resize the window
1835 if ( x
== currentX
&& y
== currentY
&&
1836 width
== currentW
&& height
== currentH
&&
1837 !(sizeFlags
& wxSIZE_FORCE
) )
1842 if ( x
== wxDefaultCoord
&& !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) )
1844 if ( y
== wxDefaultCoord
&& !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) )
1847 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
1849 wxSize size
= wxDefaultSize
;
1850 if ( width
== wxDefaultCoord
)
1852 if ( sizeFlags
& wxSIZE_AUTO_WIDTH
)
1854 size
= DoGetBestSize();
1859 // just take the current one
1864 if ( height
== wxDefaultCoord
)
1866 if ( sizeFlags
& wxSIZE_AUTO_HEIGHT
)
1868 if ( size
.x
== wxDefaultCoord
)
1870 size
= DoGetBestSize();
1872 //else: already called DoGetBestSize() above
1878 // just take the current one
1883 DoMoveWindow(x
, y
, width
, height
);
1886 void wxWindowMSW::DoSetClientSize(int width
, int height
)
1888 // setting the client size is less obvious than it could have been
1889 // because in the result of changing the total size the window scrollbar
1890 // may [dis]appear and/or its menubar may [un]wrap (and AdjustWindowRect()
1891 // doesn't take neither into account) and so the client size will not be
1892 // correct as the difference between the total and client size changes --
1893 // so we keep changing it until we get it right
1895 // normally this loop shouldn't take more than 3 iterations (usually 1 but
1896 // if scrollbars [dis]appear as the result of the first call, then 2 and it
1897 // may become 3 if the window had 0 size originally and so we didn't
1898 // calculate the scrollbar correction correctly during the first iteration)
1899 // but just to be on the safe side we check for it instead of making it an
1900 // "infinite" loop (i.e. leaving break inside as the only way to get out)
1901 for ( int i
= 0; i
< 4; i
++ )
1904 ::GetClientRect(GetHwnd(), &rectClient
);
1906 // if the size is already ok, stop here (NB: rectClient.left = top = 0)
1907 if ( (rectClient
.right
== width
|| width
== wxDefaultCoord
) &&
1908 (rectClient
.bottom
== height
|| height
== wxDefaultCoord
) )
1913 // Find the difference between the entire window (title bar and all)
1914 // and the client area; add this to the new client size to move the
1917 ::GetWindowRect(GetHwnd(), &rectWin
);
1919 const int widthWin
= rectWin
.right
- rectWin
.left
,
1920 heightWin
= rectWin
.bottom
- rectWin
.top
;
1922 // MoveWindow positions the child windows relative to the parent, so
1923 // adjust if necessary
1924 if ( !IsTopLevel() )
1926 wxWindow
*parent
= GetParent();
1929 ::ScreenToClient(GetHwndOf(parent
), (POINT
*)&rectWin
);
1933 // don't call DoMoveWindow() because we want to move window immediately
1934 // and not defer it here as otherwise the value returned by
1935 // GetClient/WindowRect() wouldn't change as the window wouldn't be
1937 if ( !::MoveWindow(GetHwnd(),
1940 width
+ widthWin
- rectClient
.right
,
1941 height
+ heightWin
- rectClient
.bottom
,
1944 wxLogLastError(_T("MoveWindow"));
1949 // ---------------------------------------------------------------------------
1951 // ---------------------------------------------------------------------------
1953 int wxWindowMSW::GetCharHeight() const
1955 return wxGetTextMetrics(this).tmHeight
;
1958 int wxWindowMSW::GetCharWidth() const
1960 // +1 is needed because Windows apparently adds it when calculating the
1961 // dialog units size in pixels
1962 #if wxDIALOG_UNIT_COMPATIBILITY
1963 return wxGetTextMetrics(this).tmAveCharWidth
;
1965 return wxGetTextMetrics(this).tmAveCharWidth
+ 1;
1969 void wxWindowMSW::GetTextExtent(const wxString
& string
,
1971 int *descent
, int *externalLeading
,
1972 const wxFont
*theFont
) const
1974 wxASSERT_MSG( !theFont
|| theFont
->Ok(),
1975 _T("invalid font in GetTextExtent()") );
1979 fontToUse
= *theFont
;
1981 fontToUse
= GetFont();
1983 WindowHDC
hdc(GetHwnd());
1984 SelectInHDC
selectFont(hdc
, GetHfontOf(fontToUse
));
1988 ::GetTextExtentPoint32(hdc
, string
.wx_str(), string
.length(), &sizeRect
);
1989 GetTextMetrics(hdc
, &tm
);
1996 *descent
= tm
.tmDescent
;
1997 if ( externalLeading
)
1998 *externalLeading
= tm
.tmExternalLeading
;
2001 // ---------------------------------------------------------------------------
2003 // ---------------------------------------------------------------------------
2005 #if wxUSE_MENUS_NATIVE
2007 // yield for WM_COMMAND events only, i.e. process all WM_COMMANDs in the queue
2008 // immediately, without waiting for the next event loop iteration
2010 // NB: this function should probably be made public later as it can almost
2011 // surely replace wxYield() elsewhere as well
2012 static void wxYieldForCommandsOnly()
2014 // peek all WM_COMMANDs (it will always return WM_QUIT too but we don't
2015 // want to process it here)
2017 while ( ::PeekMessage(&msg
, (HWND
)0, WM_COMMAND
, WM_COMMAND
, PM_REMOVE
) )
2019 if ( msg
.message
== WM_QUIT
)
2021 // if we retrieved a WM_QUIT, insert back into the message queue.
2022 ::PostQuitMessage(0);
2026 // luckily (as we don't have access to wxEventLoopImpl method from here
2027 // anyhow...) we don't need to pre process WM_COMMANDs so dispatch it
2029 ::TranslateMessage(&msg
);
2030 ::DispatchMessage(&msg
);
2034 bool wxWindowMSW::DoPopupMenu(wxMenu
*menu
, int x
, int y
)
2036 menu
->SetInvokingWindow(this);
2039 if ( x
== wxDefaultCoord
&& y
== wxDefaultCoord
)
2041 wxPoint mouse
= ScreenToClient(wxGetMousePosition());
2042 x
= mouse
.x
; y
= mouse
.y
;
2045 HWND hWnd
= GetHwnd();
2046 HMENU hMenu
= GetHmenuOf(menu
);
2050 ::ClientToScreen(hWnd
, &point
);
2051 wxCurrentPopupMenu
= menu
;
2052 #if defined(__WXWINCE__)
2053 static const UINT flags
= 0;
2054 #else // !__WXWINCE__
2055 UINT flags
= TPM_RIGHTBUTTON
;
2056 // NT4 doesn't support TPM_RECURSE and simply doesn't show the menu at all
2057 // when it's use, I'm not sure about Win95/98 but prefer to err on the safe
2058 // side and not to use it there neither -- modify the test if it does work
2060 if ( wxGetWinVersion() >= wxWinVersion_5
)
2062 // using TPM_RECURSE allows us to show a popup menu while another menu
2063 // is opened which can be useful and is supported by the other
2064 // platforms, so allow it under Windows too
2065 flags
|= TPM_RECURSE
;
2067 #endif // __WXWINCE__/!__WXWINCE__
2069 ::TrackPopupMenu(hMenu
, flags
, point
.x
, point
.y
, 0, hWnd
, NULL
);
2071 // we need to do it right now as otherwise the events are never going to be
2072 // sent to wxCurrentPopupMenu from HandleCommand()
2074 // note that even eliminating (ugly) wxCurrentPopupMenu global wouldn't
2075 // help and we'd still need wxYieldForCommandsOnly() as the menu may be
2076 // destroyed as soon as we return (it can be a local variable in the caller
2077 // for example) and so we do need to process the event immediately
2078 wxYieldForCommandsOnly();
2080 wxCurrentPopupMenu
= NULL
;
2082 menu
->SetInvokingWindow(NULL
);
2087 #endif // wxUSE_MENUS_NATIVE
2089 // ===========================================================================
2090 // pre/post message processing
2091 // ===========================================================================
2093 WXLRESULT
wxWindowMSW::MSWDefWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
)
2096 return ::CallWindowProc(CASTWNDPROC m_oldWndProc
, GetHwnd(), (UINT
) nMsg
, (WPARAM
) wParam
, (LPARAM
) lParam
);
2098 return ::DefWindowProc(GetHwnd(), nMsg
, wParam
, lParam
);
2101 bool wxWindowMSW::MSWProcessMessage(WXMSG
* pMsg
)
2103 // wxUniversal implements tab traversal itself
2104 #ifndef __WXUNIVERSAL__
2105 if ( m_hWnd
!= 0 && (GetWindowStyleFlag() & wxTAB_TRAVERSAL
) )
2107 // intercept dialog navigation keys
2108 MSG
*msg
= (MSG
*)pMsg
;
2110 // here we try to do all the job which ::IsDialogMessage() usually does
2112 if ( msg
->message
== WM_KEYDOWN
)
2114 bool bCtrlDown
= wxIsCtrlDown();
2115 bool bShiftDown
= wxIsShiftDown();
2117 // WM_GETDLGCODE: ask the control if it wants the key for itself,
2118 // don't process it if it's the case (except for Ctrl-Tab/Enter
2119 // combinations which are always processed)
2120 LONG lDlgCode
= ::SendMessage(msg
->hwnd
, WM_GETDLGCODE
, 0, 0);
2122 // surprizingly, DLGC_WANTALLKEYS bit mask doesn't contain the
2123 // DLGC_WANTTAB nor DLGC_WANTARROWS bits although, logically,
2124 // it, of course, implies them
2125 if ( lDlgCode
& DLGC_WANTALLKEYS
)
2127 lDlgCode
|= DLGC_WANTTAB
| DLGC_WANTARROWS
;
2130 bool bForward
= true,
2131 bWindowChange
= false,
2134 // should we process this message specially?
2135 bool bProcess
= true;
2136 switch ( msg
->wParam
)
2139 if ( (lDlgCode
& DLGC_WANTTAB
) && !bCtrlDown
)
2141 // let the control have the TAB
2144 else // use it for navigation
2146 // Ctrl-Tab cycles thru notebook pages
2147 bWindowChange
= bCtrlDown
;
2148 bForward
= !bShiftDown
;
2155 if ( (lDlgCode
& DLGC_WANTARROWS
) || bCtrlDown
)
2163 if ( (lDlgCode
& DLGC_WANTARROWS
) || bCtrlDown
)
2172 // we treat PageUp/Dn as arrows because chances are that
2173 // a control which needs arrows also needs them for
2174 // navigation (e.g. wxTextCtrl, wxListCtrl, ...)
2175 if ( (lDlgCode
& DLGC_WANTARROWS
) && !bCtrlDown
)
2177 else // OTOH Ctrl-PageUp/Dn works as [Shift-]Ctrl-Tab
2178 bWindowChange
= true;
2183 if ( (lDlgCode
& DLGC_WANTMESSAGE
) && !bCtrlDown
)
2185 // control wants to process Enter itself, don't
2186 // call IsDialogMessage() which would consume it
2191 // currently active button should get enter press even
2192 // if there is a default button elsewhere so check if
2193 // this window is a button first
2194 wxWindow
*btn
= NULL
;
2195 if ( lDlgCode
& DLGC_DEFPUSHBUTTON
)
2197 // let IsDialogMessage() handle this for all
2198 // buttons except the owner-drawn ones which it
2199 // just seems to ignore
2200 long style
= ::GetWindowLong(msg
->hwnd
, GWL_STYLE
);
2201 if ( (style
& BS_OWNERDRAW
) == BS_OWNERDRAW
)
2203 // emulate the button click
2204 btn
= wxFindWinFromHandle((WXHWND
)msg
->hwnd
);
2209 else // not a button itself, do we have default button?
2212 tlw
= wxDynamicCast(wxGetTopLevelParent(this),
2216 btn
= wxDynamicCast(tlw
->GetDefaultItem(),
2221 if ( btn
&& btn
->IsEnabled() )
2223 btn
->MSWCommand(BN_CLICKED
, 0 /* unused */);
2227 #endif // wxUSE_BUTTON
2230 // map Enter presses into button presses on PDAs
2231 wxJoystickEvent
event(wxEVT_JOY_BUTTON_DOWN
);
2232 event
.SetEventObject(this);
2233 if ( GetEventHandler()->ProcessEvent(event
) )
2235 #endif // __WXWINCE__
2245 wxNavigationKeyEvent event
;
2246 event
.SetDirection(bForward
);
2247 event
.SetWindowChange(bWindowChange
);
2248 event
.SetFromTab(bFromTab
);
2249 event
.SetEventObject(this);
2251 if ( GetEventHandler()->ProcessEvent(event
) )
2253 // as we don't call IsDialogMessage(), which would take of
2254 // this by default, we need to manually send this message
2255 // so that controls can change their UI state if needed
2256 MSWUpdateUIState(UIS_CLEAR
, UISF_HIDEFOCUS
);
2263 if ( ::IsDialogMessage(GetHwnd(), msg
) )
2265 // IsDialogMessage() did something...
2269 #endif // __WXUNIVERSAL__
2274 // relay mouse move events to the tooltip control
2275 MSG
*msg
= (MSG
*)pMsg
;
2276 if ( msg
->message
== WM_MOUSEMOVE
)
2277 wxToolTip::RelayEvent(pMsg
);
2279 #endif // wxUSE_TOOLTIPS
2284 bool wxWindowMSW::MSWTranslateMessage(WXMSG
* pMsg
)
2286 #if wxUSE_ACCEL && !defined(__WXUNIVERSAL__)
2287 return m_acceleratorTable
.Translate(this, pMsg
);
2291 #endif // wxUSE_ACCEL
2294 bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG
* msg
)
2296 // all tests below have to deal with various bugs/misfeatures of
2297 // IsDialogMessage(): we have to prevent it from being called from our
2298 // MSWProcessMessage() in some situations
2300 // don't let IsDialogMessage() get VK_ESCAPE as it _always_ eats the
2301 // message even when there is no cancel button and when the message is
2302 // needed by the control itself: in particular, it prevents the tree in
2303 // place edit control from being closed with Escape in a dialog
2304 if ( msg
->message
== WM_KEYDOWN
&& msg
->wParam
== VK_ESCAPE
)
2309 // ::IsDialogMessage() is broken and may sometimes hang the application by
2310 // going into an infinite loop when it tries to find the control to give
2311 // focus to when Alt-<key> is pressed, so we try to detect [some of] the
2312 // situations when this may happen and not call it then
2313 if ( msg
->message
!= WM_SYSCHAR
)
2316 // assume we can call it by default
2317 bool canSafelyCallIsDlgMsg
= true;
2319 HWND hwndFocus
= ::GetFocus();
2321 // if the currently focused window itself has WS_EX_CONTROLPARENT style,
2322 // ::IsDialogMessage() will also enter an infinite loop, because it will
2323 // recursively check the child windows but not the window itself and so if
2324 // none of the children accepts focus it loops forever (as it only stops
2325 // when it gets back to the window it started from)
2327 // while it is very unusual that a window with WS_EX_CONTROLPARENT
2328 // style has the focus, it can happen. One such possibility is if
2329 // all windows are either toplevel, wxDialog, wxPanel or static
2330 // controls and no window can actually accept keyboard input.
2331 #if !defined(__WXWINCE__)
2332 if ( ::GetWindowLong(hwndFocus
, GWL_EXSTYLE
) & WS_EX_CONTROLPARENT
)
2334 // pessimistic by default
2335 canSafelyCallIsDlgMsg
= false;
2336 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
2338 node
= node
->GetNext() )
2340 wxWindow
* const win
= node
->GetData();
2341 if ( win
->CanAcceptFocus() &&
2342 !(::GetWindowLong(GetHwndOf(win
), GWL_EXSTYLE
) &
2343 WS_EX_CONTROLPARENT
) )
2345 // it shouldn't hang...
2346 canSafelyCallIsDlgMsg
= true;
2352 #endif // !__WXWINCE__
2354 if ( canSafelyCallIsDlgMsg
)
2356 // ::IsDialogMessage() can enter in an infinite loop when the
2357 // currently focused window is disabled or hidden and its
2358 // parent has WS_EX_CONTROLPARENT style, so don't call it in
2362 if ( !::IsWindowEnabled(hwndFocus
) ||
2363 !::IsWindowVisible(hwndFocus
) )
2365 // it would enter an infinite loop if we do this!
2366 canSafelyCallIsDlgMsg
= false;
2371 if ( !(::GetWindowLong(hwndFocus
, GWL_STYLE
) & WS_CHILD
) )
2373 // it's a top level window, don't go further -- e.g. even
2374 // if the parent of a dialog is disabled, this doesn't
2375 // break navigation inside the dialog
2379 hwndFocus
= ::GetParent(hwndFocus
);
2383 return canSafelyCallIsDlgMsg
;
2386 // ---------------------------------------------------------------------------
2387 // message params unpackers
2388 // ---------------------------------------------------------------------------
2390 void wxWindowMSW::UnpackCommand(WXWPARAM wParam
, WXLPARAM lParam
,
2391 WORD
*id
, WXHWND
*hwnd
, WORD
*cmd
)
2393 *id
= LOWORD(wParam
);
2394 *hwnd
= (WXHWND
)lParam
;
2395 *cmd
= HIWORD(wParam
);
2398 void wxWindowMSW::UnpackActivate(WXWPARAM wParam
, WXLPARAM lParam
,
2399 WXWORD
*state
, WXWORD
*minimized
, WXHWND
*hwnd
)
2401 *state
= LOWORD(wParam
);
2402 *minimized
= HIWORD(wParam
);
2403 *hwnd
= (WXHWND
)lParam
;
2406 void wxWindowMSW::UnpackScroll(WXWPARAM wParam
, WXLPARAM lParam
,
2407 WXWORD
*code
, WXWORD
*pos
, WXHWND
*hwnd
)
2409 *code
= LOWORD(wParam
);
2410 *pos
= HIWORD(wParam
);
2411 *hwnd
= (WXHWND
)lParam
;
2414 void wxWindowMSW::UnpackCtlColor(WXWPARAM wParam
, WXLPARAM lParam
,
2415 WXHDC
*hdc
, WXHWND
*hwnd
)
2417 *hwnd
= (WXHWND
)lParam
;
2418 *hdc
= (WXHDC
)wParam
;
2421 void wxWindowMSW::UnpackMenuSelect(WXWPARAM wParam
, WXLPARAM lParam
,
2422 WXWORD
*item
, WXWORD
*flags
, WXHMENU
*hmenu
)
2424 *item
= (WXWORD
)wParam
;
2425 *flags
= HIWORD(wParam
);
2426 *hmenu
= (WXHMENU
)lParam
;
2429 // ---------------------------------------------------------------------------
2430 // Main wxWidgets window proc and the window proc for wxWindow
2431 // ---------------------------------------------------------------------------
2433 // Hook for new window just as it's being created, when the window isn't yet
2434 // associated with the handle
2435 static wxWindowMSW
*gs_winBeingCreated
= NULL
;
2437 // implementation of wxWindowCreationHook class: it just sets gs_winBeingCreated to the
2438 // window being created and insures that it's always unset back later
2439 wxWindowCreationHook::wxWindowCreationHook(wxWindowMSW
*winBeingCreated
)
2441 gs_winBeingCreated
= winBeingCreated
;
2444 wxWindowCreationHook::~wxWindowCreationHook()
2446 gs_winBeingCreated
= NULL
;
2450 LRESULT WXDLLEXPORT APIENTRY _EXPORT
wxWndProc(HWND hWnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
2452 // trace all messages - useful for the debugging
2454 wxLogTrace(wxTraceMessages
,
2455 wxT("Processing %s(hWnd=%08lx, wParam=%8lx, lParam=%8lx)"),
2456 wxGetMessageName(message
), (long)hWnd
, (long)wParam
, lParam
);
2457 #endif // __WXDEBUG__
2459 wxWindowMSW
*wnd
= wxFindWinFromHandle((WXHWND
) hWnd
);
2461 // when we get the first message for the HWND we just created, we associate
2462 // it with wxWindow stored in gs_winBeingCreated
2463 if ( !wnd
&& gs_winBeingCreated
)
2465 wxAssociateWinWithHandle(hWnd
, gs_winBeingCreated
);
2466 wnd
= gs_winBeingCreated
;
2467 gs_winBeingCreated
= NULL
;
2468 wnd
->SetHWND((WXHWND
)hWnd
);
2473 if ( wnd
&& wxGUIEventLoop::AllowProcessing(wnd
) )
2474 rc
= wnd
->MSWWindowProc(message
, wParam
, lParam
);
2476 rc
= ::DefWindowProc(hWnd
, message
, wParam
, lParam
);
2481 WXLRESULT
wxWindowMSW::MSWWindowProc(WXUINT message
, WXWPARAM wParam
, WXLPARAM lParam
)
2483 // did we process the message?
2484 bool processed
= false;
2494 // for most messages we should return 0 when we do process the message
2502 processed
= HandleCreate((WXLPCREATESTRUCT
)lParam
, &mayCreate
);
2505 // return 0 to allow window creation
2506 rc
.result
= mayCreate
? 0 : -1;
2512 // never set processed to true and *always* pass WM_DESTROY to
2513 // DefWindowProc() as Windows may do some internal cleanup when
2514 // processing it and failing to pass the message along may cause
2515 // memory and resource leaks!
2516 (void)HandleDestroy();
2520 processed
= HandleSize(LOWORD(lParam
), HIWORD(lParam
), wParam
);
2524 processed
= HandleMove(GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
));
2527 #if !defined(__WXWINCE__)
2530 LPRECT pRect
= (LPRECT
)lParam
;
2532 rc
.SetLeft(pRect
->left
);
2533 rc
.SetTop(pRect
->top
);
2534 rc
.SetRight(pRect
->right
);
2535 rc
.SetBottom(pRect
->bottom
);
2536 processed
= HandleMoving(rc
);
2538 pRect
->left
= rc
.GetLeft();
2539 pRect
->top
= rc
.GetTop();
2540 pRect
->right
= rc
.GetRight();
2541 pRect
->bottom
= rc
.GetBottom();
2546 case WM_ENTERSIZEMOVE
:
2548 processed
= HandleEnterSizeMove();
2552 case WM_EXITSIZEMOVE
:
2554 processed
= HandleExitSizeMove();
2560 LPRECT pRect
= (LPRECT
)lParam
;
2562 rc
.SetLeft(pRect
->left
);
2563 rc
.SetTop(pRect
->top
);
2564 rc
.SetRight(pRect
->right
);
2565 rc
.SetBottom(pRect
->bottom
);
2566 processed
= HandleSizing(rc
);
2568 pRect
->left
= rc
.GetLeft();
2569 pRect
->top
= rc
.GetTop();
2570 pRect
->right
= rc
.GetRight();
2571 pRect
->bottom
= rc
.GetBottom();
2575 #endif // !__WXWINCE__
2577 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
2578 case WM_ACTIVATEAPP
:
2579 // This implicitly sends a wxEVT_ACTIVATE_APP event
2580 wxTheApp
->SetActive(wParam
!= 0, FindFocus());
2586 WXWORD state
, minimized
;
2588 UnpackActivate(wParam
, lParam
, &state
, &minimized
, &hwnd
);
2590 processed
= HandleActivate(state
, minimized
!= 0, (WXHWND
)hwnd
);
2595 processed
= HandleSetFocus((WXHWND
)(HWND
)wParam
);
2599 processed
= HandleKillFocus((WXHWND
)(HWND
)wParam
);
2602 case WM_PRINTCLIENT
:
2603 processed
= HandlePrintClient((WXHDC
)wParam
);
2609 wxPaintDCEx
dc((wxWindow
*)this, (WXHDC
)wParam
);
2611 processed
= HandlePaint();
2615 processed
= HandlePaint();
2620 #ifdef __WXUNIVERSAL__
2621 // Universal uses its own wxFrame/wxDialog, so we don't receive
2622 // close events unless we have this.
2624 #endif // __WXUNIVERSAL__
2626 // don't let the DefWindowProc() destroy our window - we'll do it
2627 // ourselves in ~wxWindow
2633 processed
= HandleShow(wParam
!= 0, (int)lParam
);
2637 processed
= HandleMouseMove(GET_X_LPARAM(lParam
),
2638 GET_Y_LPARAM(lParam
),
2642 #ifdef HAVE_TRACKMOUSEEVENT
2644 // filter out excess WM_MOUSELEAVE events sent after PopupMenu()
2646 if ( m_mouseInWindow
)
2648 GenerateMouseLeave();
2651 // always pass processed back as false, this allows the window
2652 // manager to process the message too. This is needed to
2653 // ensure windows XP themes work properly as the mouse moves
2654 // over widgets like buttons. So don't set processed to true here.
2656 #endif // HAVE_TRACKMOUSEEVENT
2658 #if wxUSE_MOUSEWHEEL
2660 processed
= HandleMouseWheel(wParam
, lParam
);
2664 case WM_LBUTTONDOWN
:
2666 case WM_LBUTTONDBLCLK
:
2667 case WM_RBUTTONDOWN
:
2669 case WM_RBUTTONDBLCLK
:
2670 case WM_MBUTTONDOWN
:
2672 case WM_MBUTTONDBLCLK
:
2673 #ifdef wxHAS_XBUTTON
2674 case WM_XBUTTONDOWN
:
2676 case WM_XBUTTONDBLCLK
:
2677 #endif // wxHAS_XBUTTON
2679 #ifdef __WXMICROWIN__
2680 // MicroWindows seems to ignore the fact that a window is
2681 // disabled. So catch mouse events and throw them away if
2683 wxWindowMSW
* win
= this;
2686 if (!win
->IsEnabled())
2692 win
= win
->GetParent();
2693 if ( !win
|| win
->IsTopLevel() )
2700 #endif // __WXMICROWIN__
2701 int x
= GET_X_LPARAM(lParam
),
2702 y
= GET_Y_LPARAM(lParam
);
2705 // redirect the event to a static control if necessary by
2706 // finding one under mouse because under CE the static controls
2707 // don't generate mouse events (even with SS_NOTIFY)
2709 if ( GetCapture() == this )
2711 // but don't do it if the mouse is captured by this window
2712 // because then it should really get this event itself
2717 win
= FindWindowForMouseEvent(this, &x
, &y
);
2719 // this should never happen
2720 wxCHECK_MSG( win
, 0,
2721 _T("FindWindowForMouseEvent() returned NULL") );
2724 if (IsContextMenuEnabled() && message
== WM_LBUTTONDOWN
)
2726 SHRGINFO shrgi
= {0};
2728 shrgi
.cbSize
= sizeof(SHRGINFO
);
2729 shrgi
.hwndClient
= (HWND
) GetHWND();
2733 shrgi
.dwFlags
= SHRG_RETURNCMD
;
2734 // shrgi.dwFlags = SHRG_NOTIFYPARENT;
2736 if (GN_CONTEXTMENU
== ::SHRecognizeGesture(&shrgi
))
2739 pt
= ClientToScreen(pt
);
2741 wxContextMenuEvent
evtCtx(wxEVT_CONTEXT_MENU
, GetId(), pt
);
2743 evtCtx
.SetEventObject(this);
2744 if (GetEventHandler()->ProcessEvent(evtCtx
))
2753 #else // !__WXWINCE__
2754 wxWindowMSW
*win
= this;
2755 #endif // __WXWINCE__/!__WXWINCE__
2757 processed
= win
->HandleMouseEvent(message
, x
, y
, wParam
);
2759 // if the app didn't eat the event, handle it in the default
2760 // way, that is by giving this window the focus
2763 // for the standard classes their WndProc sets the focus to
2764 // them anyhow and doing it from here results in some weird
2765 // problems, so don't do it for them (unnecessary anyhow)
2766 if ( !win
->IsOfStandardClass() )
2768 if ( message
== WM_LBUTTONDOWN
&& win
->IsFocusable() )
2780 case MM_JOY1BUTTONDOWN
:
2781 case MM_JOY2BUTTONDOWN
:
2782 case MM_JOY1BUTTONUP
:
2783 case MM_JOY2BUTTONUP
:
2784 processed
= HandleJoystickEvent(message
,
2785 GET_X_LPARAM(lParam
),
2786 GET_Y_LPARAM(lParam
),
2789 #endif // __WXMICROWIN__
2795 UnpackCommand(wParam
, lParam
, &id
, &hwnd
, &cmd
);
2797 processed
= HandleCommand(id
, cmd
, hwnd
);
2802 processed
= HandleNotify((int)wParam
, lParam
, &rc
.result
);
2805 // we only need to reply to WM_NOTIFYFORMAT manually when using MSLU,
2806 // otherwise DefWindowProc() does it perfectly fine for us, but MSLU
2807 // apparently doesn't always behave properly and needs some help
2808 #if wxUSE_UNICODE_MSLU && defined(NF_QUERY)
2809 case WM_NOTIFYFORMAT
:
2810 if ( lParam
== NF_QUERY
)
2813 rc
.result
= NFR_UNICODE
;
2816 #endif // wxUSE_UNICODE_MSLU
2818 // for these messages we must return true if process the message
2821 case WM_MEASUREITEM
:
2823 int idCtrl
= (UINT
)wParam
;
2824 if ( message
== WM_DRAWITEM
)
2826 processed
= MSWOnDrawItem(idCtrl
,
2827 (WXDRAWITEMSTRUCT
*)lParam
);
2831 processed
= MSWOnMeasureItem(idCtrl
,
2832 (WXMEASUREITEMSTRUCT
*)lParam
);
2839 #endif // defined(WM_DRAWITEM)
2842 if ( !IsOfStandardClass() || HasFlag(wxWANTS_CHARS
) )
2844 // we always want to get the char events
2845 rc
.result
= DLGC_WANTCHARS
;
2847 if ( HasFlag(wxWANTS_CHARS
) )
2849 // in fact, we want everything
2850 rc
.result
|= DLGC_WANTARROWS
|
2857 //else: get the dlg code from the DefWindowProc()
2862 // If this has been processed by an event handler, return 0 now
2863 // (we've handled it).
2864 m_lastKeydownProcessed
= HandleKeyDown((WORD
) wParam
, lParam
);
2865 if ( m_lastKeydownProcessed
)
2874 // we consider these messages "not interesting" to OnChar, so
2875 // just don't do anything more with them
2885 // avoid duplicate messages to OnChar for these ASCII keys:
2886 // they will be translated by TranslateMessage() and received
2918 // but set processed to false, not true to still pass them
2919 // to the control's default window proc - otherwise
2920 // built-in keyboard handling won't work
2925 // special case of VK_APPS: treat it the same as right mouse
2926 // click because both usually pop up a context menu
2928 processed
= HandleMouseEvent(WM_RBUTTONDOWN
, -1, -1, 0);
2933 // do generate a CHAR event
2934 processed
= HandleChar((WORD
)wParam
, lParam
);
2937 if (message
== WM_SYSKEYDOWN
) // Let Windows still handle the SYSKEYs
2944 // special case of VK_APPS: treat it the same as right mouse button
2945 if ( wParam
== VK_APPS
)
2947 processed
= HandleMouseEvent(WM_RBUTTONUP
, -1, -1, 0);
2952 processed
= HandleKeyUp((WORD
) wParam
, lParam
);
2957 case WM_CHAR
: // Always an ASCII character
2958 if ( m_lastKeydownProcessed
)
2960 // The key was handled in the EVT_KEY_DOWN and handling
2961 // a key in an EVT_KEY_DOWN handler is meant, by
2962 // design, to prevent EVT_CHARs from happening
2963 m_lastKeydownProcessed
= false;
2968 processed
= HandleChar((WORD
)wParam
, lParam
, true);
2974 processed
= HandleHotKey((WORD
)wParam
, lParam
);
2976 #endif // wxUSE_HOTKEY
2983 UnpackScroll(wParam
, lParam
, &code
, &pos
, &hwnd
);
2985 processed
= MSWOnScroll(message
== WM_HSCROLL
? wxHORIZONTAL
2991 // CTLCOLOR messages are sent by children to query the parent for their
2993 #ifndef __WXMICROWIN__
2994 case WM_CTLCOLORMSGBOX
:
2995 case WM_CTLCOLOREDIT
:
2996 case WM_CTLCOLORLISTBOX
:
2997 case WM_CTLCOLORBTN
:
2998 case WM_CTLCOLORDLG
:
2999 case WM_CTLCOLORSCROLLBAR
:
3000 case WM_CTLCOLORSTATIC
:
3004 UnpackCtlColor(wParam
, lParam
, &hdc
, &hwnd
);
3006 processed
= HandleCtlColor(&rc
.hBrush
, (WXHDC
)hdc
, (WXHWND
)hwnd
);
3009 #endif // !__WXMICROWIN__
3011 case WM_SYSCOLORCHANGE
:
3012 // the return value for this message is ignored
3013 processed
= HandleSysColorChange();
3016 #if !defined(__WXWINCE__)
3017 case WM_DISPLAYCHANGE
:
3018 processed
= HandleDisplayChange();
3022 case WM_PALETTECHANGED
:
3023 processed
= HandlePaletteChanged((WXHWND
) (HWND
) wParam
);
3026 case WM_CAPTURECHANGED
:
3027 processed
= HandleCaptureChanged((WXHWND
) (HWND
) lParam
);
3030 case WM_SETTINGCHANGE
:
3031 processed
= HandleSettingChange(wParam
, lParam
);
3034 case WM_QUERYNEWPALETTE
:
3035 processed
= HandleQueryNewPalette();
3039 processed
= HandleEraseBkgnd((WXHDC
)(HDC
)wParam
);
3042 // we processed the message, i.e. erased the background
3047 #if !defined(__WXWINCE__)
3049 processed
= HandleDropFiles(wParam
);
3054 processed
= HandleInitDialog((WXHWND
)(HWND
)wParam
);
3058 // we never set focus from here
3063 #if !defined(__WXWINCE__)
3064 case WM_QUERYENDSESSION
:
3065 processed
= HandleQueryEndSession(lParam
, &rc
.allow
);
3069 processed
= HandleEndSession(wParam
!= 0, lParam
);
3072 case WM_GETMINMAXINFO
:
3073 processed
= HandleGetMinMaxInfo((MINMAXINFO
*)lParam
);
3078 processed
= HandleSetCursor((WXHWND
)(HWND
)wParam
,
3079 LOWORD(lParam
), // hit test
3080 HIWORD(lParam
)); // mouse msg
3084 // returning TRUE stops the DefWindowProc() from further
3085 // processing this message - exactly what we need because we've
3086 // just set the cursor.
3091 #if wxUSE_ACCESSIBILITY
3094 //WPARAM dwFlags = (WPARAM) (DWORD) wParam;
3095 LPARAM dwObjId
= (LPARAM
) (DWORD
) lParam
;
3097 if (dwObjId
== (LPARAM
)OBJID_CLIENT
&& GetOrCreateAccessible())
3099 return LresultFromObject(IID_IAccessible
, wParam
, (IUnknown
*) GetAccessible()->GetIAccessible());
3105 #if defined(WM_HELP)
3108 // by default, WM_HELP is propagated by DefWindowProc() upwards
3109 // to the window parent but as we do it ourselves already
3110 // (wxHelpEvent is derived from wxCommandEvent), we don't want
3111 // to get the other events if we process this message at all
3114 // WM_HELP doesn't use lParam under CE
3116 HELPINFO
* info
= (HELPINFO
*) lParam
;
3117 if ( info
->iContextType
== HELPINFO_WINDOW
)
3119 #endif // !__WXWINCE__
3120 wxHelpEvent helpEvent
3125 wxGetMousePosition() // what else?
3127 wxPoint(info
->MousePos
.x
, info
->MousePos
.y
)
3131 helpEvent
.SetEventObject(this);
3132 GetEventHandler()->ProcessEvent(helpEvent
);
3135 else if ( info
->iContextType
== HELPINFO_MENUITEM
)
3137 wxHelpEvent
helpEvent(wxEVT_HELP
, info
->iCtrlId
);
3138 helpEvent
.SetEventObject(this);
3139 GetEventHandler()->ProcessEvent(helpEvent
);
3142 else // unknown help event?
3146 #endif // !__WXWINCE__
3151 #if !defined(__WXWINCE__)
3152 case WM_CONTEXTMENU
:
3154 // we don't convert from screen to client coordinates as
3155 // the event may be handled by a parent window
3156 wxPoint
pt(GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
));
3158 wxContextMenuEvent
evtCtx(wxEVT_CONTEXT_MENU
, GetId(), pt
);
3160 // we could have got an event from our child, reflect it back
3161 // to it if this is the case
3162 wxWindowMSW
*win
= NULL
;
3163 if ( (WXHWND
)wParam
!= m_hWnd
)
3165 win
= FindItemByHWND((WXHWND
)wParam
);
3171 evtCtx
.SetEventObject(win
);
3172 processed
= win
->GetEventHandler()->ProcessEvent(evtCtx
);
3179 // we're only interested in our own menus, not MF_SYSMENU
3180 if ( HIWORD(wParam
) == MF_POPUP
)
3182 // handle menu chars for ownerdrawn menu items
3183 int i
= HandleMenuChar(toupper(LOWORD(wParam
)), lParam
);
3184 if ( i
!= wxNOT_FOUND
)
3186 rc
.result
= MAKELRESULT(i
, MNC_EXECUTE
);
3191 #endif // wxUSE_MENUS
3194 case WM_POWERBROADCAST
:
3197 processed
= HandlePower(wParam
, lParam
, &vetoed
);
3198 rc
.result
= processed
&& vetoed
? BROADCAST_QUERY_DENY
: TRUE
;
3201 #endif // __WXWINCE__
3204 // try a custom message handler
3205 const MSWMessageHandlers::const_iterator
3206 i
= gs_messageHandlers
.find(message
);
3207 if ( i
!= gs_messageHandlers
.end() )
3209 processed
= (*i
->second
)(this, message
, wParam
, lParam
);
3216 wxLogTrace(wxTraceMessages
, wxT("Forwarding %s to DefWindowProc."),
3217 wxGetMessageName(message
));
3218 #endif // __WXDEBUG__
3219 rc
.result
= MSWDefWindowProc(message
, wParam
, lParam
);
3225 // ----------------------------------------------------------------------------
3226 // wxWindow <-> HWND map
3227 // ----------------------------------------------------------------------------
3229 wxWinHashTable
*wxWinHandleHash
= NULL
;
3231 wxWindow
*wxFindWinFromHandle(WXHWND hWnd
)
3233 return (wxWindow
*)wxWinHandleHash
->Get((long)hWnd
);
3236 void wxAssociateWinWithHandle(HWND hWnd
, wxWindowMSW
*win
)
3238 // adding NULL hWnd is (first) surely a result of an error and
3239 // (secondly) breaks menu command processing
3240 wxCHECK_RET( hWnd
!= (HWND
)NULL
,
3241 wxT("attempt to add a NULL hWnd to window list ignored") );
3243 wxWindow
*oldWin
= wxFindWinFromHandle((WXHWND
) hWnd
);
3245 if ( oldWin
&& (oldWin
!= win
) )
3247 wxLogDebug(wxT("HWND %X already associated with another window (%s)"),
3248 (int) hWnd
, win
->GetClassInfo()->GetClassName());
3251 #endif // __WXDEBUG__
3254 wxWinHandleHash
->Put((long)hWnd
, (wxWindow
*)win
);
3258 void wxRemoveHandleAssociation(wxWindowMSW
*win
)
3260 wxWinHandleHash
->Delete((long)win
->GetHWND());
3263 // ----------------------------------------------------------------------------
3264 // various MSW speciic class dependent functions
3265 // ----------------------------------------------------------------------------
3267 // Default destroyer - override if you destroy it in some other way
3268 // (e.g. with MDI child windows)
3269 void wxWindowMSW::MSWDestroyWindow()
3273 bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint
& pos
,
3276 int& w
, int& h
) const
3278 // yes, those are just some arbitrary hardcoded numbers
3279 static const int DEFAULT_Y
= 200;
3281 bool nonDefault
= false;
3283 if ( pos
.x
== wxDefaultCoord
)
3285 // if x is set to CW_USEDEFAULT, y parameter is ignored anyhow so we
3286 // can just as well set it to CW_USEDEFAULT as well
3292 // OTOH, if x is not set to CW_USEDEFAULT, y shouldn't be set to it
3293 // neither because it is not handled as a special value by Windows then
3294 // and so we have to choose some default value for it
3296 y
= pos
.y
== wxDefaultCoord
? DEFAULT_Y
: pos
.y
;
3302 NB: there used to be some code here which set the initial size of the
3303 window to the client size of the parent if no explicit size was
3304 specified. This was wrong because wxWidgets programs often assume
3305 that they get a WM_SIZE (EVT_SIZE) upon creation, however this broke
3306 it. To see why, you should understand that Windows sends WM_SIZE from
3307 inside ::CreateWindow() anyhow. However, ::CreateWindow() is called
3308 from some base class ctor and so this WM_SIZE is not processed in the
3309 real class' OnSize() (because it's not fully constructed yet and the
3310 event goes to some base class OnSize() instead). So the WM_SIZE we
3311 rely on is the one sent when the parent frame resizes its children
3312 but here is the problem: if the child already has just the right
3313 size, nothing will happen as both wxWidgets and Windows check for
3314 this and ignore any attempts to change the window size to the size it
3315 already has - so no WM_SIZE would be sent.
3319 // we don't use CW_USEDEFAULT here for several reasons:
3321 // 1. it results in huge frames on modern screens (1000*800 is not
3322 // uncommon on my 1280*1024 screen) which is way too big for a half
3323 // empty frame of most of wxWidgets samples for example)
3325 // 2. it is buggy for frames with wxFRAME_TOOL_WINDOW style for which
3326 // the default is for whatever reason 8*8 which breaks client <->
3327 // window size calculations (it would be nice if it didn't, but it
3328 // does and the simplest way to fix it seemed to change the broken
3329 // default size anyhow)
3331 // 3. there is just no advantage in doing it: with x and y it is
3332 // possible that [future versions of] Windows position the new top
3333 // level window in some smart way which we can't do, but we can
3334 // guess a reasonably good size for a new window just as well
3337 // However, on PocketPC devices, we must use the default
3338 // size if possible.
3340 if (size
.x
== wxDefaultCoord
)
3344 if (size
.y
== wxDefaultCoord
)
3349 if ( size
.x
== wxDefaultCoord
|| size
.y
== wxDefaultCoord
)
3353 w
= WidthDefault(size
.x
);
3354 h
= HeightDefault(size
.y
);
3357 AdjustForParentClientOrigin(x
, y
);
3362 WXHWND
wxWindowMSW::MSWGetParent() const
3364 return m_parent
? m_parent
->GetHWND() : WXHWND(NULL
);
3367 bool wxWindowMSW::MSWCreate(const wxChar
*wclass
,
3368 const wxChar
*title
,
3372 WXDWORD extendedStyle
)
3374 // choose the position/size for the new window
3376 (void)MSWGetCreateWindowCoords(pos
, size
, x
, y
, w
, h
);
3378 // controlId is menu handle for the top level windows, so set it to 0
3379 // unless we're creating a child window
3380 int controlId
= style
& WS_CHILD
? GetId() : 0;
3382 // for each class "Foo" we have we also have "FooNR" ("no repaint") class
3383 // which is the same but without CS_[HV]REDRAW class styles so using it
3384 // ensures that the window is not fully repainted on each resize
3385 wxString
className(wclass
);
3386 if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE
) )
3388 className
+= wxT("NR");
3391 // do create the window
3392 wxWindowCreationHook
hook(this);
3394 m_hWnd
= (WXHWND
)::CreateWindowEx
3398 title
? title
: m_windowName
.wx_str(),
3401 (HWND
)MSWGetParent(),
3404 NULL
// no extra data
3409 wxLogSysError(_("Can't create window of class %s"), className
.c_str());
3414 SubclassWin(m_hWnd
);
3419 // ===========================================================================
3420 // MSW message handlers
3421 // ===========================================================================
3423 // ---------------------------------------------------------------------------
3425 // ---------------------------------------------------------------------------
3427 bool wxWindowMSW::HandleNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM
*result
)
3429 #ifndef __WXMICROWIN__
3430 LPNMHDR hdr
= (LPNMHDR
)lParam
;
3431 HWND hWnd
= hdr
->hwndFrom
;
3432 wxWindow
*win
= wxFindWinFromHandle((WXHWND
)hWnd
);
3434 // if the control is one of our windows, let it handle the message itself
3437 return win
->MSWOnNotify(idCtrl
, lParam
, result
);
3440 // VZ: why did we do it? normally this is unnecessary and, besides, it
3441 // breaks the message processing for the toolbars because the tooltip
3442 // notifications were being forwarded to the toolbar child controls
3443 // (if it had any) before being passed to the toolbar itself, so in my
3444 // example the tooltip for the combobox was always shown instead of the
3445 // correct button tooltips
3447 // try all our children
3448 wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
3451 wxWindow
*child
= node
->GetData();
3452 if ( child
->MSWOnNotify(idCtrl
, lParam
, result
) )
3457 node
= node
->GetNext();
3461 // by default, handle it ourselves
3462 return MSWOnNotify(idCtrl
, lParam
, result
);
3463 #else // __WXMICROWIN__
3470 bool wxWindowMSW::HandleTooltipNotify(WXUINT code
,
3472 const wxString
& ttip
)
3474 // I don't know why it happens, but the versions of comctl32.dll starting
3475 // from 4.70 sometimes send TTN_NEEDTEXTW even to ANSI programs (normally,
3476 // this message is supposed to be sent to Unicode programs only) -- hence
3477 // we need to handle it as well, otherwise no tooltips will be shown in
3480 if ( !(code
== (WXUINT
) TTN_NEEDTEXTA
|| code
== (WXUINT
) TTN_NEEDTEXTW
)
3483 // not a tooltip message or no tooltip to show anyhow
3488 LPTOOLTIPTEXT ttText
= (LPTOOLTIPTEXT
)lParam
;
3490 // We don't want to use the szText buffer because it has a limit of 80
3491 // bytes and this is not enough, especially for Unicode build where it
3492 // limits the tooltip string length to only 40 characters
3494 // The best would be, of course, to not impose any length limitations at
3495 // all but then the buffer would have to be dynamic and someone would have
3496 // to free it and we don't have the tooltip owner object here any more, so
3497 // for now use our own static buffer with a higher fixed max length.
3499 // Note that using a static buffer should not be a problem as only a single
3500 // tooltip can be shown at the same time anyhow.
3502 if ( code
== (WXUINT
) TTN_NEEDTEXTW
)
3504 // We need to convert tooltip from multi byte to Unicode on the fly.
3505 static wchar_t buf
[513];
3507 // Truncate tooltip length if needed as otherwise we might not have
3508 // enough space for it in the buffer and MultiByteToWideChar() would
3510 size_t tipLength
= wxMin(ttip
.length(), WXSIZEOF(buf
) - 1);
3512 // Convert to WideChar without adding the NULL character. The NULL
3513 // character is added afterwards (this is more efficient).
3514 int len
= ::MultiByteToWideChar
3526 wxLogLastError(_T("MultiByteToWideChar()"));
3530 ttText
->lpszText
= (LPSTR
) buf
;
3532 else // TTN_NEEDTEXTA
3533 #endif // !wxUSE_UNICODE
3535 // we get here if we got TTN_NEEDTEXTA (only happens in ANSI build) or
3536 // if we got TTN_NEEDTEXTW in Unicode build: in this case we just have
3537 // to copy the string we have into the buffer
3538 static wxChar buf
[513];
3539 wxStrncpy(buf
, ttip
.c_str(), WXSIZEOF(buf
) - 1);
3540 buf
[WXSIZEOF(buf
) - 1] = _T('\0');
3541 ttText
->lpszText
= buf
;
3547 #endif // wxUSE_TOOLTIPS
3549 bool wxWindowMSW::MSWOnNotify(int WXUNUSED(idCtrl
),
3551 WXLPARAM
* WXUNUSED(result
))
3556 NMHDR
* hdr
= (NMHDR
*)lParam
;
3557 if ( HandleTooltipNotify(hdr
->code
, lParam
, m_tooltip
->GetTip()))
3564 wxUnusedVar(lParam
);
3565 #endif // wxUSE_TOOLTIPS
3570 // ---------------------------------------------------------------------------
3571 // end session messages
3572 // ---------------------------------------------------------------------------
3574 bool wxWindowMSW::HandleQueryEndSession(long logOff
, bool *mayEnd
)
3576 #ifdef ENDSESSION_LOGOFF
3577 wxCloseEvent
event(wxEVT_QUERY_END_SESSION
, wxID_ANY
);
3578 event
.SetEventObject(wxTheApp
);
3579 event
.SetCanVeto(true);
3580 event
.SetLoggingOff(logOff
== (long)ENDSESSION_LOGOFF
);
3582 bool rc
= wxTheApp
->ProcessEvent(event
);
3586 // we may end only if the app didn't veto session closing (double
3588 *mayEnd
= !event
.GetVeto();
3593 wxUnusedVar(logOff
);
3594 wxUnusedVar(mayEnd
);
3599 bool wxWindowMSW::HandleEndSession(bool endSession
, long logOff
)
3601 #ifdef ENDSESSION_LOGOFF
3602 // do nothing if the session isn't ending
3607 if ( (this != wxTheApp
->GetTopWindow()) )
3610 wxCloseEvent
event(wxEVT_END_SESSION
, wxID_ANY
);
3611 event
.SetEventObject(wxTheApp
);
3612 event
.SetCanVeto(false);
3613 event
.SetLoggingOff( (logOff
== (long)ENDSESSION_LOGOFF
) );
3615 return wxTheApp
->ProcessEvent(event
);
3617 wxUnusedVar(endSession
);
3618 wxUnusedVar(logOff
);
3623 // ---------------------------------------------------------------------------
3624 // window creation/destruction
3625 // ---------------------------------------------------------------------------
3627 bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT
WXUNUSED_IN_WINCE(cs
),
3630 // VZ: why is this commented out for WinCE? If it doesn't support
3631 // WS_EX_CONTROLPARENT at all it should be somehow handled globally,
3632 // not with multiple #ifdef's!
3634 if ( ((CREATESTRUCT
*)cs
)->dwExStyle
& WS_EX_CONTROLPARENT
)
3635 EnsureParentHasControlParentStyle(GetParent());
3636 #endif // !__WXWINCE__
3643 bool wxWindowMSW::HandleDestroy()
3647 // delete our drop target if we've got one
3648 #if wxUSE_DRAG_AND_DROP
3649 if ( m_dropTarget
!= NULL
)
3651 m_dropTarget
->Revoke(m_hWnd
);
3653 delete m_dropTarget
;
3654 m_dropTarget
= NULL
;
3656 #endif // wxUSE_DRAG_AND_DROP
3658 // WM_DESTROY handled
3662 // ---------------------------------------------------------------------------
3664 // ---------------------------------------------------------------------------
3666 bool wxWindowMSW::HandleActivate(int state
,
3667 bool WXUNUSED(minimized
),
3668 WXHWND
WXUNUSED(activate
))
3670 wxActivateEvent
event(wxEVT_ACTIVATE
,
3671 (state
== WA_ACTIVE
) || (state
== WA_CLICKACTIVE
),
3673 event
.SetEventObject(this);
3675 return GetEventHandler()->ProcessEvent(event
);
3678 bool wxWindowMSW::HandleSetFocus(WXHWND hwnd
)
3680 // Strangly enough, some controls get set focus events when they are being
3681 // deleted, even if they already had focus before.
3682 if ( m_isBeingDeleted
)
3687 // notify the parent keeping track of focus for the kbd navigation
3688 // purposes that we got it
3689 wxChildFocusEvent
eventFocus((wxWindow
*)this);
3690 (void)GetEventHandler()->ProcessEvent(eventFocus
);
3696 m_caret
->OnSetFocus();
3698 #endif // wxUSE_CARET
3701 // If it's a wxTextCtrl don't send the event as it will be done
3702 // after the control gets to process it from EN_FOCUS handler
3703 if ( wxDynamicCastThis(wxTextCtrl
) )
3707 #endif // wxUSE_TEXTCTRL
3709 wxFocusEvent
event(wxEVT_SET_FOCUS
, m_windowId
);
3710 event
.SetEventObject(this);
3712 // wxFindWinFromHandle() may return NULL, it is ok
3713 event
.SetWindow(wxFindWinFromHandle(hwnd
));
3715 return GetEventHandler()->ProcessEvent(event
);
3718 bool wxWindowMSW::HandleKillFocus(WXHWND hwnd
)
3724 m_caret
->OnKillFocus();
3726 #endif // wxUSE_CARET
3729 // If it's a wxTextCtrl don't send the event as it will be done
3730 // after the control gets to process it.
3731 wxTextCtrl
*ctrl
= wxDynamicCastThis(wxTextCtrl
);
3738 // Don't send the event when in the process of being deleted. This can
3739 // only cause problems if the event handler tries to access the object.
3740 if ( m_isBeingDeleted
)
3745 wxFocusEvent
event(wxEVT_KILL_FOCUS
, m_windowId
);
3746 event
.SetEventObject(this);
3748 // wxFindWinFromHandle() may return NULL, it is ok
3749 event
.SetWindow(wxFindWinFromHandle(hwnd
));
3751 return GetEventHandler()->ProcessEvent(event
);
3754 // ---------------------------------------------------------------------------
3756 // ---------------------------------------------------------------------------
3758 void wxWindowMSW::SetLabel( const wxString
& label
)
3760 SetWindowText(GetHwnd(), label
.c_str());
3763 wxString
wxWindowMSW::GetLabel() const
3765 return wxGetWindowText(GetHWND());
3768 // ---------------------------------------------------------------------------
3770 // ---------------------------------------------------------------------------
3772 bool wxWindowMSW::HandleShow(bool show
, int WXUNUSED(status
))
3774 wxShowEvent
event(GetId(), show
);
3775 event
.SetEventObject(this);
3777 return GetEventHandler()->ProcessEvent(event
);
3780 bool wxWindowMSW::HandleInitDialog(WXHWND
WXUNUSED(hWndFocus
))
3782 wxInitDialogEvent
event(GetId());
3783 event
.SetEventObject(this);
3785 return GetEventHandler()->ProcessEvent(event
);
3788 bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam
)
3790 #if defined (__WXMICROWIN__) || defined(__WXWINCE__)
3791 wxUnusedVar(wParam
);
3793 #else // __WXMICROWIN__
3794 HDROP hFilesInfo
= (HDROP
) wParam
;
3796 // Get the total number of files dropped
3797 UINT gwFilesDropped
= ::DragQueryFile
3805 wxString
*files
= new wxString
[gwFilesDropped
];
3806 for ( UINT wIndex
= 0; wIndex
< gwFilesDropped
; wIndex
++ )
3808 // first get the needed buffer length (+1 for terminating NUL)
3809 size_t len
= ::DragQueryFile(hFilesInfo
, wIndex
, NULL
, 0) + 1;
3811 // and now get the file name
3812 ::DragQueryFile(hFilesInfo
, wIndex
,
3813 wxStringBuffer(files
[wIndex
], len
), len
);
3815 DragFinish (hFilesInfo
);
3817 wxDropFilesEvent
event(wxEVT_DROP_FILES
, gwFilesDropped
, files
);
3818 event
.SetEventObject(this);
3821 DragQueryPoint(hFilesInfo
, (LPPOINT
) &dropPoint
);
3822 event
.m_pos
.x
= dropPoint
.x
;
3823 event
.m_pos
.y
= dropPoint
.y
;
3825 return GetEventHandler()->ProcessEvent(event
);
3830 bool wxWindowMSW::HandleSetCursor(WXHWND
WXUNUSED(hWnd
),
3832 int WXUNUSED(mouseMsg
))
3834 #ifndef __WXMICROWIN__
3835 // the logic is as follows:
3836 // 0. if we're busy, set the busy cursor (even for non client elements)
3837 // 1. don't set custom cursor for non client area of enabled windows
3838 // 2. ask user EVT_SET_CURSOR handler for the cursor
3839 // 3. if still no cursor but we're in a TLW, set the global cursor
3841 HCURSOR hcursor
= 0;
3844 hcursor
= wxGetCurrentBusyCursor();
3848 if ( nHitTest
!= HTCLIENT
)
3851 // first ask the user code - it may wish to set the cursor in some very
3852 // specific way (for example, depending on the current position)
3855 if ( !::GetCursorPosWinCE(&pt
))
3857 if ( !::GetCursorPos(&pt
) )
3860 wxLogLastError(wxT("GetCursorPos"));
3865 ScreenToClient(&x
, &y
);
3866 wxSetCursorEvent
event(x
, y
);
3868 bool processedEvtSetCursor
= GetEventHandler()->ProcessEvent(event
);
3869 if ( processedEvtSetCursor
&& event
.HasCursor() )
3871 hcursor
= GetHcursorOf(event
.GetCursor());
3876 // the test for processedEvtSetCursor is here to prevent using
3877 // m_cursor if the user code caught EVT_SET_CURSOR() and returned
3878 // nothing from it - this is a way to say that our cursor shouldn't
3879 // be used for this point
3880 if ( !processedEvtSetCursor
&& m_cursor
.Ok() )
3882 hcursor
= GetHcursorOf(m_cursor
);
3885 if ( !hcursor
&& !GetParent() )
3887 const wxCursor
*cursor
= wxGetGlobalCursor();
3888 if ( cursor
&& cursor
->Ok() )
3890 hcursor
= GetHcursorOf(*cursor
);
3899 ::SetCursor(hcursor
);
3901 // cursor set, stop here
3904 #endif // __WXMICROWIN__
3906 // pass up the window chain
3910 bool wxWindowMSW::HandlePower(WXWPARAM
WXUNUSED_IN_WINCE(wParam
),
3911 WXLPARAM
WXUNUSED(lParam
),
3912 bool *WXUNUSED_IN_WINCE(vetoed
))
3918 wxEventType evtType
;
3921 case PBT_APMQUERYSUSPEND
:
3922 evtType
= wxEVT_POWER_SUSPENDING
;
3925 case PBT_APMQUERYSUSPENDFAILED
:
3926 evtType
= wxEVT_POWER_SUSPEND_CANCEL
;
3929 case PBT_APMSUSPEND
:
3930 evtType
= wxEVT_POWER_SUSPENDED
;
3933 case PBT_APMRESUMESUSPEND
:
3934 #ifdef PBT_APMRESUMEAUTOMATIC
3935 case PBT_APMRESUMEAUTOMATIC
:
3937 evtType
= wxEVT_POWER_RESUME
;
3941 wxLogDebug(_T("Unknown WM_POWERBROADCAST(%d) event"), wParam
);
3944 // these messages are currently not mapped to wx events
3945 case PBT_APMQUERYSTANDBY
:
3946 case PBT_APMQUERYSTANDBYFAILED
:
3947 case PBT_APMSTANDBY
:
3948 case PBT_APMRESUMESTANDBY
:
3949 case PBT_APMBATTERYLOW
:
3950 case PBT_APMPOWERSTATUSCHANGE
:
3951 case PBT_APMOEMEVENT
:
3952 case PBT_APMRESUMECRITICAL
:
3953 evtType
= wxEVT_NULL
;
3957 // don't handle unknown messages
3958 if ( evtType
== wxEVT_NULL
)
3961 // TODO: notify about PBTF_APMRESUMEFROMFAILURE in case of resume events?
3963 wxPowerEvent
event(evtType
);
3964 if ( !GetEventHandler()->ProcessEvent(event
) )
3967 *vetoed
= event
.IsVetoed();
3973 bool wxWindowMSW::IsDoubleBuffered() const
3975 for ( const wxWindowMSW
*wnd
= this;
3976 wnd
&& !wnd
->IsTopLevel(); wnd
=
3979 if ( ::GetWindowLong(GetHwndOf(wnd
), GWL_EXSTYLE
) & WS_EX_COMPOSITED
)
3986 // ---------------------------------------------------------------------------
3987 // owner drawn stuff
3988 // ---------------------------------------------------------------------------
3990 #if (wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE) || \
3991 (wxUSE_CONTROLS && !defined(__WXUNIVERSAL__))
3992 #define WXUNUSED_UNLESS_ODRAWN(param) param
3994 #define WXUNUSED_UNLESS_ODRAWN(param)
3998 wxWindowMSW::MSWOnDrawItem(int WXUNUSED_UNLESS_ODRAWN(id
),
3999 WXDRAWITEMSTRUCT
* WXUNUSED_UNLESS_ODRAWN(itemStruct
))
4001 #if wxUSE_OWNER_DRAWN
4003 #if wxUSE_MENUS_NATIVE
4004 // is it a menu item?
4005 DRAWITEMSTRUCT
*pDrawStruct
= (DRAWITEMSTRUCT
*)itemStruct
;
4006 if ( id
== 0 && pDrawStruct
->CtlType
== ODT_MENU
)
4008 wxMenuItem
*pMenuItem
= (wxMenuItem
*)(pDrawStruct
->itemData
);
4010 // see comment before the same test in MSWOnMeasureItem() below
4014 wxCHECK_MSG( wxDynamicCast(pMenuItem
, wxMenuItem
),
4015 false, _T("MSWOnDrawItem: bad wxMenuItem pointer") );
4017 // prepare to call OnDrawItem(): notice using of wxDCTemp to prevent
4018 // the DC from being released
4019 wxDCTemp
dc((WXHDC
)pDrawStruct
->hDC
);
4020 wxRect
rect(pDrawStruct
->rcItem
.left
, pDrawStruct
->rcItem
.top
,
4021 pDrawStruct
->rcItem
.right
- pDrawStruct
->rcItem
.left
,
4022 pDrawStruct
->rcItem
.bottom
- pDrawStruct
->rcItem
.top
);
4024 return pMenuItem
->OnDrawItem
4028 (wxOwnerDrawn::wxODAction
)pDrawStruct
->itemAction
,
4029 (wxOwnerDrawn::wxODStatus
)pDrawStruct
->itemState
4032 #endif // wxUSE_MENUS_NATIVE
4034 #endif // USE_OWNER_DRAWN
4036 #if wxUSE_CONTROLS && !defined(__WXUNIVERSAL__)
4038 #if wxUSE_OWNER_DRAWN
4039 wxControl
*item
= wxDynamicCast(FindItem(id
), wxControl
);
4040 #else // !wxUSE_OWNER_DRAWN
4041 // we may still have owner-drawn buttons internally because we have to make
4042 // them owner-drawn to support colour change
4045 wxDynamicCast(FindItem(id
), wxButton
)
4050 #endif // USE_OWNER_DRAWN
4054 return item
->MSWOnDraw(itemStruct
);
4057 #endif // wxUSE_CONTROLS
4063 wxWindowMSW::MSWOnMeasureItem(int id
, WXMEASUREITEMSTRUCT
*itemStruct
)
4065 #if wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE
4066 // is it a menu item?
4067 MEASUREITEMSTRUCT
*pMeasureStruct
= (MEASUREITEMSTRUCT
*)itemStruct
;
4068 if ( id
== 0 && pMeasureStruct
->CtlType
== ODT_MENU
)
4070 wxMenuItem
*pMenuItem
= (wxMenuItem
*)(pMeasureStruct
->itemData
);
4072 // according to Carsten Fuchs the pointer may be NULL under XP if an
4073 // MDI child frame is initially maximized, see this for more info:
4074 // http://article.gmane.org/gmane.comp.lib.wxwidgets.general/27745
4076 // so silently ignore it instead of asserting
4080 wxCHECK_MSG( wxDynamicCast(pMenuItem
, wxMenuItem
),
4081 false, _T("MSWOnMeasureItem: bad wxMenuItem pointer") );
4084 bool rc
= pMenuItem
->OnMeasureItem(&w
, &h
);
4086 pMeasureStruct
->itemWidth
= w
;
4087 pMeasureStruct
->itemHeight
= h
;
4092 wxControl
*item
= wxDynamicCast(FindItem(id
), wxControl
);
4095 return item
->MSWOnMeasure(itemStruct
);
4099 wxUnusedVar(itemStruct
);
4100 #endif // wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE
4105 // ---------------------------------------------------------------------------
4106 // colours and palettes
4107 // ---------------------------------------------------------------------------
4109 bool wxWindowMSW::HandleSysColorChange()
4111 wxSysColourChangedEvent event
;
4112 event
.SetEventObject(this);
4114 (void)GetEventHandler()->ProcessEvent(event
);
4116 // always let the system carry on the default processing to allow the
4117 // native controls to react to the colours update
4121 bool wxWindowMSW::HandleDisplayChange()
4123 wxDisplayChangedEvent event
;
4124 event
.SetEventObject(this);
4126 return GetEventHandler()->ProcessEvent(event
);
4129 #ifndef __WXMICROWIN__
4131 bool wxWindowMSW::HandleCtlColor(WXHBRUSH
*brush
, WXHDC hDC
, WXHWND hWnd
)
4133 #if !wxUSE_CONTROLS || defined(__WXUNIVERSAL__)
4137 wxControl
*item
= wxDynamicCast(FindItemByHWND(hWnd
, true), wxControl
);
4140 *brush
= item
->MSWControlColor(hDC
, hWnd
);
4142 #endif // wxUSE_CONTROLS
4145 return *brush
!= NULL
;
4148 #endif // __WXMICROWIN__
4150 bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange
)
4153 // same as below except we don't respond to our own messages
4154 if ( hWndPalChange
!= GetHWND() )
4156 // check to see if we our our parents have a custom palette
4157 wxWindowMSW
*win
= this;
4158 while ( win
&& !win
->HasCustomPalette() )
4160 win
= win
->GetParent();
4163 if ( win
&& win
->HasCustomPalette() )
4165 // realize the palette to see whether redrawing is needed
4166 HDC hdc
= ::GetDC((HWND
) hWndPalChange
);
4167 win
->m_palette
.SetHPALETTE((WXHPALETTE
)
4168 ::SelectPalette(hdc
, GetHpaletteOf(win
->m_palette
), FALSE
));
4170 int result
= ::RealizePalette(hdc
);
4172 // restore the palette (before releasing the DC)
4173 win
->m_palette
.SetHPALETTE((WXHPALETTE
)
4174 ::SelectPalette(hdc
, GetHpaletteOf(win
->m_palette
), FALSE
));
4175 ::RealizePalette(hdc
);
4176 ::ReleaseDC((HWND
) hWndPalChange
, hdc
);
4178 // now check for the need to redraw
4180 ::InvalidateRect((HWND
) hWndPalChange
, NULL
, TRUE
);
4184 #endif // wxUSE_PALETTE
4186 wxPaletteChangedEvent
event(GetId());
4187 event
.SetEventObject(this);
4188 event
.SetChangedWindow(wxFindWinFromHandle(hWndPalChange
));
4190 return GetEventHandler()->ProcessEvent(event
);
4193 bool wxWindowMSW::HandleCaptureChanged(WXHWND hWndGainedCapture
)
4195 // notify windows on the capture stack about lost capture
4196 // (see http://sourceforge.net/tracker/index.php?func=detail&aid=1153662&group_id=9863&atid=109863):
4197 wxWindowBase::NotifyCaptureLost();
4199 wxWindow
*win
= wxFindWinFromHandle(hWndGainedCapture
);
4200 wxMouseCaptureChangedEvent
event(GetId(), win
);
4201 event
.SetEventObject(this);
4202 return GetEventHandler()->ProcessEvent(event
);
4205 bool wxWindowMSW::HandleSettingChange(WXWPARAM wParam
, WXLPARAM lParam
)
4207 // despite MSDN saying "(This message cannot be sent directly to a window.)"
4208 // we need to send this to child windows (it is only sent to top-level
4209 // windows) so {list,tree}ctrls can adjust their font size if necessary
4210 // this is exactly how explorer does it to enable the font size changes
4212 wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
4215 // top-level windows already get this message from the system
4216 wxWindow
*win
= node
->GetData();
4217 if ( !win
->IsTopLevel() )
4219 ::SendMessage(GetHwndOf(win
), WM_SETTINGCHANGE
, wParam
, lParam
);
4222 node
= node
->GetNext();
4225 // let the system handle it
4229 bool wxWindowMSW::HandleQueryNewPalette()
4233 // check to see if we our our parents have a custom palette
4234 wxWindowMSW
*win
= this;
4235 while (!win
->HasCustomPalette() && win
->GetParent()) win
= win
->GetParent();
4236 if (win
->HasCustomPalette()) {
4237 /* realize the palette to see whether redrawing is needed */
4238 HDC hdc
= ::GetDC((HWND
) GetHWND());
4239 win
->m_palette
.SetHPALETTE( (WXHPALETTE
)
4240 ::SelectPalette(hdc
, (HPALETTE
) win
->m_palette
.GetHPALETTE(), FALSE
) );
4242 int result
= ::RealizePalette(hdc
);
4243 /* restore the palette (before releasing the DC) */
4244 win
->m_palette
.SetHPALETTE( (WXHPALETTE
)
4245 ::SelectPalette(hdc
, (HPALETTE
) win
->m_palette
.GetHPALETTE(), TRUE
) );
4246 ::RealizePalette(hdc
);
4247 ::ReleaseDC((HWND
) GetHWND(), hdc
);
4248 /* now check for the need to redraw */
4250 ::InvalidateRect((HWND
) GetHWND(), NULL
, TRUE
);
4252 #endif // wxUSE_PALETTE
4254 wxQueryNewPaletteEvent
event(GetId());
4255 event
.SetEventObject(this);
4257 return GetEventHandler()->ProcessEvent(event
) && event
.GetPaletteRealized();
4260 // Responds to colour changes: passes event on to children.
4261 void wxWindowMSW::OnSysColourChanged(wxSysColourChangedEvent
& WXUNUSED(event
))
4263 // the top level window also reset the standard colour map as it might have
4264 // changed (there is no need to do it for the non top level windows as we
4265 // only have to do it once)
4269 gs_hasStdCmap
= false;
4271 wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
4274 // Only propagate to non-top-level windows because Windows already
4275 // sends this event to all top-level ones
4276 wxWindow
*win
= node
->GetData();
4277 if ( !win
->IsTopLevel() )
4279 // we need to send the real WM_SYSCOLORCHANGE and not just trigger
4280 // EVT_SYS_COLOUR_CHANGED call because the latter wouldn't work for
4281 // the standard controls
4282 ::SendMessage(GetHwndOf(win
), WM_SYSCOLORCHANGE
, 0, 0);
4285 node
= node
->GetNext();
4289 extern wxCOLORMAP
*wxGetStdColourMap()
4291 static COLORREF s_stdColours
[wxSTD_COL_MAX
];
4292 static wxCOLORMAP s_cmap
[wxSTD_COL_MAX
];
4294 if ( !gs_hasStdCmap
)
4296 static bool s_coloursInit
= false;
4298 if ( !s_coloursInit
)
4300 // When a bitmap is loaded, the RGB values can change (apparently
4301 // because Windows adjusts them to care for the old programs always
4302 // using 0xc0c0c0 while the transparent colour for the new Windows
4303 // versions is different). But we do this adjustment ourselves so
4304 // we want to avoid Windows' "help" and for this we need to have a
4305 // reference bitmap which can tell us what the RGB values change
4307 wxLogNull logNo
; // suppress error if we couldn't load the bitmap
4308 wxBitmap
stdColourBitmap(_T("wxBITMAP_STD_COLOURS"));
4309 if ( stdColourBitmap
.Ok() )
4311 // the pixels in the bitmap must correspond to wxSTD_COL_XXX!
4312 wxASSERT_MSG( stdColourBitmap
.GetWidth() == wxSTD_COL_MAX
,
4313 _T("forgot to update wxBITMAP_STD_COLOURS!") );
4316 memDC
.SelectObject(stdColourBitmap
);
4319 for ( size_t i
= 0; i
< WXSIZEOF(s_stdColours
); i
++ )
4321 memDC
.GetPixel(i
, 0, &colour
);
4322 s_stdColours
[i
] = wxColourToRGB(colour
);
4325 else // wxBITMAP_STD_COLOURS couldn't be loaded
4327 s_stdColours
[0] = RGB(000,000,000); // black
4328 s_stdColours
[1] = RGB(128,128,128); // dark grey
4329 s_stdColours
[2] = RGB(192,192,192); // light grey
4330 s_stdColours
[3] = RGB(255,255,255); // white
4331 //s_stdColours[4] = RGB(000,000,255); // blue
4332 //s_stdColours[5] = RGB(255,000,255); // magenta
4335 s_coloursInit
= true;
4338 gs_hasStdCmap
= true;
4340 // create the colour map
4341 #define INIT_CMAP_ENTRY(col) \
4342 s_cmap[wxSTD_COL_##col].from = s_stdColours[wxSTD_COL_##col]; \
4343 s_cmap[wxSTD_COL_##col].to = ::GetSysColor(COLOR_##col)
4345 INIT_CMAP_ENTRY(BTNTEXT
);
4346 INIT_CMAP_ENTRY(BTNSHADOW
);
4347 INIT_CMAP_ENTRY(BTNFACE
);
4348 INIT_CMAP_ENTRY(BTNHIGHLIGHT
);
4350 #undef INIT_CMAP_ENTRY
4356 // ---------------------------------------------------------------------------
4358 // ---------------------------------------------------------------------------
4360 bool wxWindowMSW::HandlePaint()
4362 HRGN hRegion
= ::CreateRectRgn(0, 0, 0, 0); // Dummy call to get a handle
4364 wxLogLastError(wxT("CreateRectRgn"));
4365 if ( ::GetUpdateRgn(GetHwnd(), hRegion
, FALSE
) == ERROR
)
4366 wxLogLastError(wxT("GetUpdateRgn"));
4368 m_updateRegion
= wxRegion((WXHRGN
) hRegion
);
4370 wxPaintEvent
event(m_windowId
);
4371 event
.SetEventObject(this);
4373 bool processed
= GetEventHandler()->ProcessEvent(event
);
4375 // note that we must generate NC event after the normal one as otherwise
4376 // BeginPaint() will happily overwrite our decorations with the background
4378 wxNcPaintEvent
eventNc(m_windowId
);
4379 eventNc
.SetEventObject(this);
4380 GetEventHandler()->ProcessEvent(eventNc
);
4385 // Can be called from an application's OnPaint handler
4386 void wxWindowMSW::OnPaint(wxPaintEvent
& event
)
4388 #ifdef __WXUNIVERSAL__
4391 HDC hDC
= (HDC
) wxPaintDC::FindDCInCache((wxWindow
*) event
.GetEventObject());
4394 MSWDefWindowProc(WM_PAINT
, (WPARAM
) hDC
, 0);
4399 bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc
)
4401 wxDCTemp
dc(hdc
, GetClientSize());
4404 dc
.SetWindow((wxWindow
*)this);
4406 wxEraseEvent
event(m_windowId
, &dc
);
4407 event
.SetEventObject(this);
4408 bool rc
= GetEventHandler()->ProcessEvent(event
);
4410 // must be called manually as ~wxDC doesn't do anything for wxDCTemp
4411 dc
.SelectOldObjects(hdc
);
4416 void wxWindowMSW::OnEraseBackground(wxEraseEvent
& event
)
4418 // standard non top level controls (i.e. except the dialogs) always erase
4419 // their background themselves in HandleCtlColor() or have some control-
4420 // specific ways to set the colours (common controls)
4421 if ( IsOfStandardClass() && !IsTopLevel() )
4427 if ( GetBackgroundStyle() == wxBG_STYLE_CUSTOM
)
4429 // don't skip the event here, custom background means that the app
4430 // is drawing it itself in its OnPaint(), so don't draw it at all
4431 // now to avoid flicker
4436 // do default background painting
4437 if ( !DoEraseBackground(GetHdcOf(*event
.GetDC())) )
4439 // let the system paint the background
4444 bool wxWindowMSW::DoEraseBackground(WXHDC hDC
)
4446 HBRUSH hbr
= (HBRUSH
)MSWGetBgBrush(hDC
);
4450 wxFillRect(GetHwnd(), (HDC
)hDC
, hbr
);
4456 wxWindowMSW::MSWGetBgBrushForChild(WXHDC
WXUNUSED(hDC
), WXHWND hWnd
)
4460 // our background colour applies to:
4461 // 1. this window itself, always
4462 // 2. all children unless the colour is "not inheritable"
4463 // 3. even if it is not inheritable, our immediate transparent
4464 // children should still inherit it -- but not any transparent
4465 // children because it would look wrong if a child of non
4466 // transparent child would show our bg colour when the child itself
4468 wxWindow
*win
= wxFindWinFromHandle(hWnd
);
4471 (win
&& win
->HasTransparentBackground() &&
4472 win
->GetParent() == this) )
4474 // draw children with the same colour as the parent
4476 brush
= wxTheBrushList
->FindOrCreateBrush(GetBackgroundColour());
4478 return (WXHBRUSH
)GetHbrushOf(*brush
);
4485 WXHBRUSH
wxWindowMSW::MSWGetBgBrush(WXHDC hDC
, WXHWND hWndToPaint
)
4488 hWndToPaint
= GetHWND();
4490 for ( wxWindowMSW
*win
= this; win
; win
= win
->GetParent() )
4492 WXHBRUSH hBrush
= win
->MSWGetBgBrushForChild(hDC
, hWndToPaint
);
4496 // background is not inherited beyond top level windows
4497 if ( win
->IsTopLevel() )
4504 bool wxWindowMSW::HandlePrintClient(WXHDC hDC
)
4506 // we receive this message when DrawThemeParentBackground() is
4507 // called from def window proc of several controls under XP and we
4508 // must draw properly themed background here
4510 // note that naively I'd expect filling the client rect with the
4511 // brush returned by MSWGetBgBrush() work -- but for some reason it
4512 // doesn't and we have to call parents MSWPrintChild() which is
4513 // supposed to call DrawThemeBackground() with appropriate params
4515 // also note that in this case lParam == PRF_CLIENT but we're
4516 // clearly expected to paint the background and nothing else!
4518 if ( IsTopLevel() || InheritsBackgroundColour() )
4521 // sometimes we don't want the parent to handle it at all, instead
4522 // return whatever value this window wants
4523 if ( !MSWShouldPropagatePrintChild() )
4524 return MSWPrintChild(hDC
, (wxWindow
*)this);
4526 for ( wxWindow
*win
= GetParent(); win
; win
= win
->GetParent() )
4528 if ( win
->MSWPrintChild(hDC
, (wxWindow
*)this) )
4531 if ( win
->IsTopLevel() || win
->InheritsBackgroundColour() )
4538 // ---------------------------------------------------------------------------
4539 // moving and resizing
4540 // ---------------------------------------------------------------------------
4542 bool wxWindowMSW::HandleMinimize()
4544 wxIconizeEvent
event(m_windowId
);
4545 event
.SetEventObject(this);
4547 return GetEventHandler()->ProcessEvent(event
);
4550 bool wxWindowMSW::HandleMaximize()
4552 wxMaximizeEvent
event(m_windowId
);
4553 event
.SetEventObject(this);
4555 return GetEventHandler()->ProcessEvent(event
);
4558 bool wxWindowMSW::HandleMove(int x
, int y
)
4561 wxMoveEvent
event(point
, m_windowId
);
4562 event
.SetEventObject(this);
4564 return GetEventHandler()->ProcessEvent(event
);
4567 bool wxWindowMSW::HandleMoving(wxRect
& rect
)
4569 wxMoveEvent
event(rect
, m_windowId
);
4570 event
.SetEventObject(this);
4572 bool rc
= GetEventHandler()->ProcessEvent(event
);
4574 rect
= event
.GetRect();
4578 bool wxWindowMSW::HandleEnterSizeMove()
4580 wxMoveEvent
event(wxPoint(), m_windowId
);
4581 event
.SetEventType(wxEVT_MOVE_START
);
4582 event
.SetEventObject(this);
4584 return GetEventHandler()->ProcessEvent(event
);
4587 bool wxWindowMSW::HandleExitSizeMove()
4589 wxMoveEvent
event(wxPoint(), m_windowId
);
4590 event
.SetEventType(wxEVT_MOVE_END
);
4591 event
.SetEventObject(this);
4593 return GetEventHandler()->ProcessEvent(event
);
4596 bool wxWindowMSW::HandleSize(int WXUNUSED(w
), int WXUNUSED(h
), WXUINT wParam
)
4598 #if USE_DEFERRED_SIZING
4599 // when we resize this window, its children are probably going to be
4600 // repositioned as well, prepare to use DeferWindowPos() for them
4601 int numChildren
= 0;
4602 for ( HWND child
= ::GetWindow(GetHwndOf(this), GW_CHILD
);
4604 child
= ::GetWindow(child
, GW_HWNDNEXT
) )
4609 // Protect against valid m_hDWP being overwritten
4610 bool useDefer
= false;
4612 if ( numChildren
> 1 )
4616 m_hDWP
= (WXHANDLE
)::BeginDeferWindowPos(numChildren
);
4619 wxLogLastError(_T("BeginDeferWindowPos"));
4625 #endif // USE_DEFERRED_SIZING
4627 // update this window size
4628 bool processed
= false;
4632 wxFAIL_MSG( _T("unexpected WM_SIZE parameter") );
4633 // fall through nevertheless
4637 // we're not interested in these messages at all
4640 case SIZE_MINIMIZED
:
4641 processed
= HandleMinimize();
4644 case SIZE_MAXIMIZED
:
4645 /* processed = */ HandleMaximize();
4646 // fall through to send a normal size event as well
4649 // don't use w and h parameters as they specify the client size
4650 // while according to the docs EVT_SIZE handler is supposed to
4651 // receive the total size
4652 wxSizeEvent
event(GetSize(), m_windowId
);
4653 event
.SetEventObject(this);
4655 processed
= GetEventHandler()->ProcessEvent(event
);
4658 #if USE_DEFERRED_SIZING
4659 // and finally change the positions of all child windows at once
4660 if ( useDefer
&& m_hDWP
)
4662 // reset m_hDWP to NULL so that child windows don't try to use our
4663 // m_hDWP after we call EndDeferWindowPos() on it (this shouldn't
4664 // happen anyhow normally but who knows what weird flow of control we
4665 // may have depending on what the users EVT_SIZE handler does...)
4666 HDWP hDWP
= (HDWP
)m_hDWP
;
4669 // do put all child controls in place at once
4670 if ( !::EndDeferWindowPos(hDWP
) )
4672 wxLogLastError(_T("EndDeferWindowPos"));
4675 // Reset our children's pending pos/size values.
4676 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
4678 node
= node
->GetNext() )
4680 wxWindowMSW
*child
= node
->GetData();
4681 child
->m_pendingPosition
= wxDefaultPosition
;
4682 child
->m_pendingSize
= wxDefaultSize
;
4685 #endif // USE_DEFERRED_SIZING
4690 bool wxWindowMSW::HandleSizing(wxRect
& rect
)
4692 wxSizeEvent
event(rect
, m_windowId
);
4693 event
.SetEventObject(this);
4695 bool rc
= GetEventHandler()->ProcessEvent(event
);
4697 rect
= event
.GetRect();
4701 bool wxWindowMSW::HandleGetMinMaxInfo(void *WXUNUSED_IN_WINCE(mmInfo
))
4706 MINMAXINFO
*info
= (MINMAXINFO
*)mmInfo
;
4710 int minWidth
= GetMinWidth(),
4711 minHeight
= GetMinHeight(),
4712 maxWidth
= GetMaxWidth(),
4713 maxHeight
= GetMaxHeight();
4715 if ( minWidth
!= wxDefaultCoord
)
4717 info
->ptMinTrackSize
.x
= minWidth
;
4721 if ( minHeight
!= wxDefaultCoord
)
4723 info
->ptMinTrackSize
.y
= minHeight
;
4727 if ( maxWidth
!= wxDefaultCoord
)
4729 info
->ptMaxTrackSize
.x
= maxWidth
;
4733 if ( maxHeight
!= wxDefaultCoord
)
4735 info
->ptMaxTrackSize
.y
= maxHeight
;
4743 // ---------------------------------------------------------------------------
4745 // ---------------------------------------------------------------------------
4747 bool wxWindowMSW::HandleCommand(WXWORD id
, WXWORD cmd
, WXHWND control
)
4749 #if wxUSE_MENUS_NATIVE
4750 if ( !cmd
&& wxCurrentPopupMenu
)
4752 wxMenu
*popupMenu
= wxCurrentPopupMenu
;
4753 wxCurrentPopupMenu
= NULL
;
4755 return popupMenu
->MSWCommand(cmd
, id
);
4757 #endif // wxUSE_MENUS_NATIVE
4759 wxWindow
*win
= NULL
;
4761 // first try to find it from HWND - this works even with the broken
4762 // programs using the same ids for different controls
4765 win
= wxFindWinFromHandle(control
);
4771 // must cast to a signed type before comparing with other ids!
4772 win
= FindItem((signed short)id
);
4777 return win
->MSWCommand(cmd
, id
);
4780 // the messages sent from the in-place edit control used by the treectrl
4781 // for label editing have id == 0, but they should _not_ be treated as menu
4782 // messages (they are EN_XXX ones, in fact) so don't translate anything
4783 // coming from a control to wxEVT_COMMAND_MENU_SELECTED
4786 // If no child window, it may be an accelerator, e.g. for a popup menu
4789 wxCommandEvent
event(wxEVT_COMMAND_MENU_SELECTED
);
4790 event
.SetEventObject(this);
4794 return GetEventHandler()->ProcessEvent(event
);
4798 #if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__)
4799 // the text ctrl which is logically part of wxSpinCtrl sends WM_COMMAND
4800 // notifications to its parent which we want to reflect back to
4802 wxSpinCtrl
*spin
= wxSpinCtrl::GetSpinForTextCtrl(control
);
4803 if ( spin
&& spin
->ProcessTextCommand(cmd
, id
) )
4805 #endif // wxUSE_SPINCTRL
4807 #if wxUSE_CHOICE && defined(__SMARTPHONE__)
4808 // the listbox ctrl which is logically part of wxChoice sends WM_COMMAND
4809 // notifications to its parent which we want to reflect back to
4811 wxChoice
*choice
= wxChoice::GetChoiceForListBox(control
);
4812 if ( choice
&& choice
->MSWCommand(cmd
, id
) )
4820 // ---------------------------------------------------------------------------
4822 // ---------------------------------------------------------------------------
4824 void wxWindowMSW::InitMouseEvent(wxMouseEvent
& event
,
4828 // our client coords are not quite the same as Windows ones
4829 wxPoint pt
= GetClientAreaOrigin();
4830 event
.m_x
= x
- pt
.x
;
4831 event
.m_y
= y
- pt
.y
;
4833 event
.m_shiftDown
= (flags
& MK_SHIFT
) != 0;
4834 event
.m_controlDown
= (flags
& MK_CONTROL
) != 0;
4835 event
.m_leftDown
= (flags
& MK_LBUTTON
) != 0;
4836 event
.m_middleDown
= (flags
& MK_MBUTTON
) != 0;
4837 event
.m_rightDown
= (flags
& MK_RBUTTON
) != 0;
4838 #ifdef wxHAS_XBUTTON
4839 event
.m_aux1Down
= (flags
& MK_XBUTTON1
) != 0;
4840 event
.m_aux2Down
= (flags
& MK_XBUTTON2
) != 0;
4841 #endif // wxHAS_XBUTTON
4842 event
.m_altDown
= ::GetKeyState(VK_MENU
) < 0;
4845 event
.SetTimestamp(::GetMessageTime());
4848 event
.SetEventObject(this);
4849 event
.SetId(GetId());
4851 #if wxUSE_MOUSEEVENT_HACK
4852 gs_lastMouseEvent
.pos
= ClientToScreen(wxPoint(x
, y
));
4853 gs_lastMouseEvent
.type
= event
.GetEventType();
4854 #endif // wxUSE_MOUSEEVENT_HACK
4858 // Windows doesn't send the mouse events to the static controls (which are
4859 // transparent in the sense that their WM_NCHITTEST handler returns
4860 // HTTRANSPARENT) at all but we want all controls to receive the mouse events
4861 // and so we manually check if we don't have a child window under mouse and if
4862 // we do, send the event to it instead of the window Windows had sent WM_XXX
4865 // Notice that this is not done for the mouse move events because this could
4866 // (would?) be too slow, but only for clicks which means that the static texts
4867 // still don't get move, enter nor leave events.
4868 static wxWindowMSW
*FindWindowForMouseEvent(wxWindowMSW
*win
, int *x
, int *y
)
4870 wxCHECK_MSG( x
&& y
, win
, _T("NULL pointer in FindWindowForMouseEvent") );
4872 // first try to find a non transparent child: this allows us to send events
4873 // to a static text which is inside a static box, for example
4874 POINT pt
= { *x
, *y
};
4875 HWND hwnd
= GetHwndOf(win
),
4879 hwndUnderMouse
= ::ChildWindowFromPoint
4885 hwndUnderMouse
= ::ChildWindowFromPointEx
4895 if ( !hwndUnderMouse
|| hwndUnderMouse
== hwnd
)
4897 // now try any child window at all
4898 hwndUnderMouse
= ::ChildWindowFromPoint(hwnd
, pt
);
4901 // check that we have a child window which is susceptible to receive mouse
4902 // events: for this it must be shown and enabled
4903 if ( hwndUnderMouse
&&
4904 hwndUnderMouse
!= hwnd
&&
4905 ::IsWindowVisible(hwndUnderMouse
) &&
4906 ::IsWindowEnabled(hwndUnderMouse
) )
4908 wxWindow
*winUnderMouse
= wxFindWinFromHandle((WXHWND
)hwndUnderMouse
);
4909 if ( winUnderMouse
)
4911 // translate the mouse coords to the other window coords
4912 win
->ClientToScreen(x
, y
);
4913 winUnderMouse
->ScreenToClient(x
, y
);
4915 win
= winUnderMouse
;
4921 #endif // __WXWINCE__
4923 bool wxWindowMSW::HandleMouseEvent(WXUINT msg
, int x
, int y
, WXUINT flags
)
4925 // the mouse events take consecutive IDs from WM_MOUSEFIRST to
4926 // WM_MOUSELAST, so it's enough to subtract WM_MOUSEMOVE == WM_MOUSEFIRST
4927 // from the message id and take the value in the table to get wxWin event
4929 static const wxEventType eventsMouse
[] =
4940 wxEVT_MIDDLE_DCLICK
,
4941 0, // this one is for wxEVT_MOTION which is not used here
4950 #ifdef wxHAS_XBUTTON
4951 // the same messages are used for both auxillary mouse buttons so we need
4952 // to adjust the index manually
4955 case WM_XBUTTONDOWN
:
4957 case WM_XBUTTONDBLCLK
:
4958 if ( flags
& MK_XBUTTON2
)
4959 msg
+= wxEVT_AUX2_DOWN
- wxEVT_AUX1_DOWN
;
4961 #endif // wxHAS_XBUTTON
4963 wxMouseEvent
event(eventsMouse
[msg
- WM_MOUSEMOVE
]);
4964 InitMouseEvent(event
, x
, y
, flags
);
4966 return GetEventHandler()->ProcessEvent(event
);
4969 bool wxWindowMSW::HandleMouseMove(int x
, int y
, WXUINT flags
)
4971 if ( !m_mouseInWindow
)
4973 // it would be wrong to assume that just because we get a mouse move
4974 // event that the mouse is inside the window: although this is usually
4975 // true, it is not if we had captured the mouse, so we need to check
4976 // the mouse coordinates here
4977 if ( !HasCapture() || IsMouseInWindow() )
4979 // Generate an ENTER event
4980 m_mouseInWindow
= true;
4982 #ifdef HAVE_TRACKMOUSEEVENT
4983 typedef BOOL (WINAPI
*_TrackMouseEvent_t
)(LPTRACKMOUSEEVENT
);
4985 static const _TrackMouseEvent_t
4986 s_pfn_TrackMouseEvent
= _TrackMouseEvent
;
4987 #else // !__WXWINCE__
4988 static _TrackMouseEvent_t s_pfn_TrackMouseEvent
;
4989 static bool s_initDone
= false;
4994 wxDynamicLibrary
dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM
);
4995 if ( dllComCtl32
.IsLoaded() )
4997 s_pfn_TrackMouseEvent
= (_TrackMouseEvent_t
)
4998 dllComCtl32
.GetSymbol(_T("_TrackMouseEvent"));
5003 // notice that it's ok to unload comctl32.dll here as it won't
5004 // be really unloaded, being still in use because we link to it
5008 if ( s_pfn_TrackMouseEvent
)
5009 #endif // __WXWINCE__/!__WXWINCE__
5011 WinStruct
<TRACKMOUSEEVENT
> trackinfo
;
5013 trackinfo
.dwFlags
= TME_LEAVE
;
5014 trackinfo
.hwndTrack
= GetHwnd();
5016 (*s_pfn_TrackMouseEvent
)(&trackinfo
);
5018 #endif // HAVE_TRACKMOUSEEVENT
5020 wxMouseEvent
event(wxEVT_ENTER_WINDOW
);
5021 InitMouseEvent(event
, x
, y
, flags
);
5023 (void)GetEventHandler()->ProcessEvent(event
);
5026 #ifdef HAVE_TRACKMOUSEEVENT
5027 else // mouse not in window
5029 // Check if we need to send a LEAVE event
5030 // Windows doesn't send WM_MOUSELEAVE if the mouse has been captured so
5031 // send it here if we are using native mouse leave tracking
5032 if ( HasCapture() && !IsMouseInWindow() )
5034 GenerateMouseLeave();
5037 #endif // HAVE_TRACKMOUSEEVENT
5039 #if wxUSE_MOUSEEVENT_HACK
5040 // Windows often generates mouse events even if mouse position hasn't
5041 // changed (http://article.gmane.org/gmane.comp.lib.wxwidgets.devel/66576)
5043 // Filter this out as it can result in unexpected behaviour compared to
5045 if ( gs_lastMouseEvent
.type
== wxEVT_RIGHT_DOWN
||
5046 gs_lastMouseEvent
.type
== wxEVT_LEFT_DOWN
||
5047 gs_lastMouseEvent
.type
== wxEVT_MIDDLE_DOWN
||
5048 gs_lastMouseEvent
.type
== wxEVT_MOTION
)
5050 if ( ClientToScreen(wxPoint(x
, y
)) == gs_lastMouseEvent
.pos
)
5052 gs_lastMouseEvent
.type
= wxEVT_MOTION
;
5057 #endif // wxUSE_MOUSEEVENT_HACK
5059 return HandleMouseEvent(WM_MOUSEMOVE
, x
, y
, flags
);
5063 bool wxWindowMSW::HandleMouseWheel(WXWPARAM wParam
, WXLPARAM lParam
)
5065 #if wxUSE_MOUSEWHEEL
5066 // notice that WM_MOUSEWHEEL position is in screen coords (as it's
5067 // forwarded up to the parent by DefWindowProc()) and not in the client
5068 // ones as all the other messages, translate them to the client coords for
5071 pt
= ScreenToClient(wxPoint(GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
)));
5072 wxMouseEvent
event(wxEVT_MOUSEWHEEL
);
5073 InitMouseEvent(event
, pt
.x
, pt
.y
, LOWORD(wParam
));
5074 event
.m_wheelRotation
= (short)HIWORD(wParam
);
5075 event
.m_wheelDelta
= WHEEL_DELTA
;
5077 static int s_linesPerRotation
= -1;
5078 if ( s_linesPerRotation
== -1 )
5080 if ( !::SystemParametersInfo(SPI_GETWHEELSCROLLLINES
, 0,
5081 &s_linesPerRotation
, 0))
5083 // this is not supposed to happen
5084 wxLogLastError(_T("SystemParametersInfo(GETWHEELSCROLLLINES)"));
5086 // the default is 3, so use it if SystemParametersInfo() failed
5087 s_linesPerRotation
= 3;
5091 event
.m_linesPerAction
= s_linesPerRotation
;
5092 return GetEventHandler()->ProcessEvent(event
);
5094 #else // !wxUSE_MOUSEWHEEL
5095 wxUnusedVar(wParam
);
5096 wxUnusedVar(lParam
);
5099 #endif // wxUSE_MOUSEWHEEL/!wxUSE_MOUSEWHEEL
5102 void wxWindowMSW::GenerateMouseLeave()
5104 m_mouseInWindow
= false;
5107 if ( wxIsShiftDown() )
5109 if ( wxIsCtrlDown() )
5110 state
|= MK_CONTROL
;
5112 // Only the high-order bit should be tested
5113 if ( GetKeyState( VK_LBUTTON
) & (1<<15) )
5114 state
|= MK_LBUTTON
;
5115 if ( GetKeyState( VK_MBUTTON
) & (1<<15) )
5116 state
|= MK_MBUTTON
;
5117 if ( GetKeyState( VK_RBUTTON
) & (1<<15) )
5118 state
|= MK_RBUTTON
;
5122 if ( !::GetCursorPosWinCE(&pt
) )
5124 if ( !::GetCursorPos(&pt
) )
5127 wxLogLastError(_T("GetCursorPos"));
5130 // we need to have client coordinates here for symmetry with
5131 // wxEVT_ENTER_WINDOW
5132 RECT rect
= wxGetWindowRect(GetHwnd());
5136 wxMouseEvent
event(wxEVT_LEAVE_WINDOW
);
5137 InitMouseEvent(event
, pt
.x
, pt
.y
, state
);
5139 (void)GetEventHandler()->ProcessEvent(event
);
5142 // ---------------------------------------------------------------------------
5143 // keyboard handling
5144 // ---------------------------------------------------------------------------
5146 // create the key event of the given type for the given key - used by
5147 // HandleChar and HandleKeyDown/Up
5148 wxKeyEvent
wxWindowMSW::CreateKeyEvent(wxEventType evType
,
5151 WXWPARAM wParam
) const
5153 wxKeyEvent
event(evType
);
5154 event
.SetId(GetId());
5155 event
.m_shiftDown
= wxIsShiftDown();
5156 event
.m_controlDown
= wxIsCtrlDown();
5157 event
.m_altDown
= (HIWORD(lParam
) & KF_ALTDOWN
) == KF_ALTDOWN
;
5159 event
.SetEventObject((wxWindow
*)this); // const_cast
5160 event
.m_keyCode
= id
;
5162 event
.m_uniChar
= (wxChar
) wParam
;
5164 event
.m_rawCode
= (wxUint32
) wParam
;
5165 event
.m_rawFlags
= (wxUint32
) lParam
;
5167 event
.SetTimestamp(::GetMessageTime());
5170 // translate the position to client coords
5173 GetCursorPosWinCE(&pt
);
5178 GetWindowRect(GetHwnd(),&rect
);
5188 // isASCII is true only when we're called from WM_CHAR handler and not from
5190 bool wxWindowMSW::HandleChar(WXWPARAM wParam
, WXLPARAM lParam
, bool isASCII
)
5197 else // we're called from WM_KEYDOWN
5199 // don't pass lParam to wxCharCodeMSWToWX() here because we don't want
5200 // to get numpad key codes: CHAR events should use the logical keys
5201 // such as WXK_HOME instead of WXK_NUMPAD_HOME which is for KEY events
5202 id
= wxCharCodeMSWToWX(wParam
);
5205 // it's ASCII and will be processed here only when called from
5206 // WM_CHAR (i.e. when isASCII = true), don't process it now
5211 wxKeyEvent
event(CreateKeyEvent(wxEVT_CHAR
, id
, lParam
, wParam
));
5213 // the alphanumeric keys produced by pressing AltGr+something on European
5214 // keyboards have both Ctrl and Alt modifiers which may confuse the user
5215 // code as, normally, keys with Ctrl and/or Alt don't result in anything
5216 // alphanumeric, so pretend that there are no modifiers at all (the
5217 // KEY_DOWN event would still have the correct modifiers if they're really
5219 if ( event
.m_controlDown
&& event
.m_altDown
&&
5220 (id
>= 32 && id
< 256) )
5222 event
.m_controlDown
=
5223 event
.m_altDown
= false;
5226 return GetEventHandler()->ProcessEvent(event
);
5229 bool wxWindowMSW::HandleKeyDown(WXWPARAM wParam
, WXLPARAM lParam
)
5231 int id
= wxCharCodeMSWToWX(wParam
, lParam
);
5235 // normal ASCII char
5239 wxKeyEvent
event(CreateKeyEvent(wxEVT_KEY_DOWN
, id
, lParam
, wParam
));
5240 return GetEventHandler()->ProcessEvent(event
);
5243 bool wxWindowMSW::HandleKeyUp(WXWPARAM wParam
, WXLPARAM lParam
)
5245 int id
= wxCharCodeMSWToWX(wParam
, lParam
);
5249 // normal ASCII char
5253 wxKeyEvent
event(CreateKeyEvent(wxEVT_KEY_UP
, id
, lParam
, wParam
));
5254 return GetEventHandler()->ProcessEvent(event
);
5258 int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel
),
5259 WXLPARAM
WXUNUSED_IN_WINCE(lParam
))
5261 // FIXME: implement GetMenuItemCount for WinCE, possibly
5262 // in terms of GetMenuItemInfo
5264 const HMENU hmenu
= (HMENU
)lParam
;
5268 mii
.cbSize
= sizeof(MENUITEMINFO
);
5270 // we could use MIIM_FTYPE here as we only need to know if the item is
5271 // ownerdrawn or not and not dwTypeData which MIIM_TYPE also returns, but
5272 // MIIM_FTYPE is not supported under Win95
5273 mii
.fMask
= MIIM_TYPE
| MIIM_DATA
;
5275 // find if we have this letter in any owner drawn item
5276 const int count
= ::GetMenuItemCount(hmenu
);
5277 for ( int i
= 0; i
< count
; i
++ )
5279 // previous loop iteration could modify it, reset it back before
5280 // calling GetMenuItemInfo() to prevent it from overflowing dwTypeData
5283 if ( ::GetMenuItemInfo(hmenu
, i
, TRUE
, &mii
) )
5285 if ( mii
.fType
== MFT_OWNERDRAW
)
5287 // dwItemData member of the MENUITEMINFO is a
5288 // pointer to the associated wxMenuItem -- see the
5289 // menu creation code
5290 wxMenuItem
*item
= (wxMenuItem
*)mii
.dwItemData
;
5292 const wxChar
*p
= wxStrchr(item
->GetText().wx_str(), _T('&'));
5295 if ( *p
== _T('&') )
5297 // this is not the accel char, find the real one
5298 p
= wxStrchr(p
+ 1, _T('&'));
5300 else // got the accel char
5302 // FIXME-UNICODE: this comparison doesn't risk to work
5303 // for non ASCII accelerator characters I'm afraid, but
5305 if ( (wchar_t)wxToupper(*p
) == (wchar_t)chAccel
)
5311 // this one doesn't match
5318 else // failed to get the menu text?
5320 // it's not fatal, so don't show error, but still log it
5321 wxLogLastError(_T("GetMenuItemInfo"));
5328 bool wxWindowMSW::HandleClipboardEvent( WXUINT nMsg
)
5330 const wxEventType type
= ( nMsg
== WM_CUT
) ? wxEVT_COMMAND_TEXT_CUT
:
5331 ( nMsg
== WM_COPY
) ? wxEVT_COMMAND_TEXT_COPY
:
5332 /*( nMsg == WM_PASTE ) ? */ wxEVT_COMMAND_TEXT_PASTE
;
5333 wxClipboardTextEvent
evt(type
, GetId());
5335 evt
.SetEventObject(this);
5337 return GetEventHandler()->ProcessEvent(evt
);
5339 #endif // wxUSE_MENUS
5341 // ---------------------------------------------------------------------------
5343 // ---------------------------------------------------------------------------
5345 bool wxWindowMSW::HandleJoystickEvent(WXUINT msg
, int x
, int y
, WXUINT flags
)
5349 if ( flags
& JOY_BUTTON1CHG
)
5350 change
= wxJOY_BUTTON1
;
5351 if ( flags
& JOY_BUTTON2CHG
)
5352 change
= wxJOY_BUTTON2
;
5353 if ( flags
& JOY_BUTTON3CHG
)
5354 change
= wxJOY_BUTTON3
;
5355 if ( flags
& JOY_BUTTON4CHG
)
5356 change
= wxJOY_BUTTON4
;
5359 if ( flags
& JOY_BUTTON1
)
5360 buttons
|= wxJOY_BUTTON1
;
5361 if ( flags
& JOY_BUTTON2
)
5362 buttons
|= wxJOY_BUTTON2
;
5363 if ( flags
& JOY_BUTTON3
)
5364 buttons
|= wxJOY_BUTTON3
;
5365 if ( flags
& JOY_BUTTON4
)
5366 buttons
|= wxJOY_BUTTON4
;
5368 // the event ids aren't consecutive so we can't use table based lookup
5370 wxEventType eventType
;
5375 eventType
= wxEVT_JOY_MOVE
;
5380 eventType
= wxEVT_JOY_MOVE
;
5385 eventType
= wxEVT_JOY_ZMOVE
;
5390 eventType
= wxEVT_JOY_ZMOVE
;
5393 case MM_JOY1BUTTONDOWN
:
5395 eventType
= wxEVT_JOY_BUTTON_DOWN
;
5398 case MM_JOY2BUTTONDOWN
:
5400 eventType
= wxEVT_JOY_BUTTON_DOWN
;
5403 case MM_JOY1BUTTONUP
:
5405 eventType
= wxEVT_JOY_BUTTON_UP
;
5408 case MM_JOY2BUTTONUP
:
5410 eventType
= wxEVT_JOY_BUTTON_UP
;
5414 wxFAIL_MSG(wxT("no such joystick event"));
5419 wxJoystickEvent
event(eventType
, buttons
, joystick
, change
);
5420 event
.SetPosition(wxPoint(x
, y
));
5421 event
.SetEventObject(this);
5423 return GetEventHandler()->ProcessEvent(event
);
5433 // ---------------------------------------------------------------------------
5435 // ---------------------------------------------------------------------------
5437 bool wxWindowMSW::MSWOnScroll(int orientation
, WXWORD wParam
,
5438 WXWORD pos
, WXHWND control
)
5440 if ( control
&& control
!= m_hWnd
) // Prevent infinite recursion
5442 wxWindow
*child
= wxFindWinFromHandle(control
);
5444 return child
->MSWOnScroll(orientation
, wParam
, pos
, control
);
5447 wxScrollWinEvent event
;
5448 event
.SetPosition(pos
);
5449 event
.SetOrientation(orientation
);
5450 event
.SetEventObject(this);
5455 event
.SetEventType(wxEVT_SCROLLWIN_TOP
);
5459 event
.SetEventType(wxEVT_SCROLLWIN_BOTTOM
);
5463 event
.SetEventType(wxEVT_SCROLLWIN_LINEUP
);
5467 event
.SetEventType(wxEVT_SCROLLWIN_LINEDOWN
);
5471 event
.SetEventType(wxEVT_SCROLLWIN_PAGEUP
);
5475 event
.SetEventType(wxEVT_SCROLLWIN_PAGEDOWN
);
5478 case SB_THUMBPOSITION
:
5480 // under Win32, the scrollbar range and position are 32 bit integers,
5481 // but WM_[HV]SCROLL only carry the low 16 bits of them, so we must
5482 // explicitly query the scrollbar for the correct position (this must
5483 // be done only for these two SB_ events as they are the only one
5484 // carrying the scrollbar position)
5486 WinStruct
<SCROLLINFO
> scrollInfo
;
5487 scrollInfo
.fMask
= SIF_TRACKPOS
;
5489 if ( !::GetScrollInfo(GetHwnd(),
5490 orientation
== wxHORIZONTAL
? SB_HORZ
5494 // Not necessarily an error, if there are no scrollbars yet.
5495 // wxLogLastError(_T("GetScrollInfo"));
5498 event
.SetPosition(scrollInfo
.nTrackPos
);
5501 event
.SetEventType( wParam
== SB_THUMBPOSITION
5502 ? wxEVT_SCROLLWIN_THUMBRELEASE
5503 : wxEVT_SCROLLWIN_THUMBTRACK
);
5510 return GetEventHandler()->ProcessEvent(event
);
5513 // ----------------------------------------------------------------------------
5514 // custom message handlers
5515 // ----------------------------------------------------------------------------
5518 wxWindowMSW::MSWRegisterMessageHandler(int msg
, MSWMessageHandler handler
)
5520 wxCHECK_MSG( gs_messageHandlers
.find(msg
) == gs_messageHandlers
.end(),
5521 false, _T("registering handler for the same message twice") );
5523 gs_messageHandlers
[msg
] = handler
;
5528 wxWindowMSW::MSWUnregisterMessageHandler(int msg
, MSWMessageHandler handler
)
5530 const MSWMessageHandlers::iterator i
= gs_messageHandlers
.find(msg
);
5531 wxCHECK_RET( i
!= gs_messageHandlers
.end() && i
->second
== handler
,
5532 _T("unregistering non-registered handler?") );
5534 gs_messageHandlers
.erase(i
);
5537 // ===========================================================================
5539 // ===========================================================================
5541 void wxGetCharSize(WXHWND wnd
, int *x
, int *y
, const wxFont
& the_font
)
5544 HDC dc
= ::GetDC((HWND
) wnd
);
5547 // the_font.UseResource();
5548 // the_font.RealizeResource();
5549 HFONT fnt
= (HFONT
)the_font
.GetResourceHandle(); // const_cast
5551 was
= (HFONT
) SelectObject(dc
,fnt
);
5553 GetTextMetrics(dc
, &tm
);
5556 SelectObject(dc
,was
);
5558 ReleaseDC((HWND
)wnd
, dc
);
5561 *x
= tm
.tmAveCharWidth
;
5563 *y
= tm
.tmHeight
+ tm
.tmExternalLeading
;
5565 // the_font.ReleaseResource();
5568 // use the "extended" bit (24) of lParam to distinguish extended keys
5569 // from normal keys as the same key is sent
5571 int ChooseNormalOrExtended(int lParam
, int keyNormal
, int keyExtended
)
5573 // except that if lParam is 0, it means we don't have real lParam from
5574 // WM_KEYDOWN but are just translating just a VK constant (e.g. done from
5575 // msw/treectrl.cpp when processing TVN_KEYDOWN) -- then assume this is a
5576 // non-numpad (hence extended) key as this is a more common case
5577 return !lParam
|| (lParam
& (1 << 24)) ? keyExtended
: keyNormal
;
5580 // this array contains the Windows virtual key codes which map one to one to
5581 // WXK_xxx constants and is used in wxCharCodeMSWToWX/WXToMSW() below
5583 // note that keys having a normal and numpad version (e.g. WXK_HOME and
5584 // WXK_NUMPAD_HOME) are not included in this table as the mapping is not 1-to-1
5585 static const struct wxKeyMapping
5589 } gs_specialKeys
[] =
5591 { VK_CANCEL
, WXK_CANCEL
},
5592 { VK_BACK
, WXK_BACK
},
5593 { VK_TAB
, WXK_TAB
},
5594 { VK_CLEAR
, WXK_CLEAR
},
5595 { VK_SHIFT
, WXK_SHIFT
},
5596 { VK_CONTROL
, WXK_CONTROL
},
5597 { VK_MENU
, WXK_ALT
},
5598 { VK_PAUSE
, WXK_PAUSE
},
5599 { VK_CAPITAL
, WXK_CAPITAL
},
5600 { VK_SPACE
, WXK_SPACE
},
5601 { VK_ESCAPE
, WXK_ESCAPE
},
5602 { VK_SELECT
, WXK_SELECT
},
5603 { VK_PRINT
, WXK_PRINT
},
5604 { VK_EXECUTE
, WXK_EXECUTE
},
5605 { VK_SNAPSHOT
, WXK_SNAPSHOT
},
5606 { VK_HELP
, WXK_HELP
},
5608 { VK_NUMPAD0
, WXK_NUMPAD0
},
5609 { VK_NUMPAD1
, WXK_NUMPAD1
},
5610 { VK_NUMPAD2
, WXK_NUMPAD2
},
5611 { VK_NUMPAD3
, WXK_NUMPAD3
},
5612 { VK_NUMPAD4
, WXK_NUMPAD4
},
5613 { VK_NUMPAD5
, WXK_NUMPAD5
},
5614 { VK_NUMPAD6
, WXK_NUMPAD6
},
5615 { VK_NUMPAD7
, WXK_NUMPAD7
},
5616 { VK_NUMPAD8
, WXK_NUMPAD8
},
5617 { VK_NUMPAD9
, WXK_NUMPAD9
},
5618 { VK_MULTIPLY
, WXK_NUMPAD_MULTIPLY
},
5619 { VK_ADD
, WXK_NUMPAD_ADD
},
5620 { VK_SUBTRACT
, WXK_NUMPAD_SUBTRACT
},
5621 { VK_DECIMAL
, WXK_NUMPAD_DECIMAL
},
5622 { VK_DIVIDE
, WXK_NUMPAD_DIVIDE
},
5633 { VK_F10
, WXK_F10
},
5634 { VK_F11
, WXK_F11
},
5635 { VK_F12
, WXK_F12
},
5636 { VK_F13
, WXK_F13
},
5637 { VK_F14
, WXK_F14
},
5638 { VK_F15
, WXK_F15
},
5639 { VK_F16
, WXK_F16
},
5640 { VK_F17
, WXK_F17
},
5641 { VK_F18
, WXK_F18
},
5642 { VK_F19
, WXK_F19
},
5643 { VK_F20
, WXK_F20
},
5644 { VK_F21
, WXK_F21
},
5645 { VK_F22
, WXK_F22
},
5646 { VK_F23
, WXK_F23
},
5647 { VK_F24
, WXK_F24
},
5649 { VK_NUMLOCK
, WXK_NUMLOCK
},
5650 { VK_SCROLL
, WXK_SCROLL
},
5653 { VK_LWIN
, WXK_WINDOWS_LEFT
},
5654 { VK_RWIN
, WXK_WINDOWS_RIGHT
},
5655 { VK_APPS
, WXK_WINDOWS_MENU
},
5656 #endif // VK_APPS defined
5659 // Returns 0 if was a normal ASCII value, not a special key. This indicates that
5660 // the key should be ignored by WM_KEYDOWN and processed by WM_CHAR instead.
5661 int wxCharCodeMSWToWX(int vk
, WXLPARAM lParam
)
5663 // check the table first
5664 for ( size_t n
= 0; n
< WXSIZEOF(gs_specialKeys
); n
++ )
5666 if ( gs_specialKeys
[n
].vk
== vk
)
5667 return gs_specialKeys
[n
].wxk
;
5670 // keys requiring special handling
5674 // the mapping for these keys may be incorrect on non-US keyboards so
5675 // maybe we shouldn't map them to ASCII values at all
5676 case VK_OEM_1
: wxk
= ';'; break;
5677 case VK_OEM_PLUS
: wxk
= '+'; break;
5678 case VK_OEM_COMMA
: wxk
= ','; break;
5679 case VK_OEM_MINUS
: wxk
= '-'; break;
5680 case VK_OEM_PERIOD
: wxk
= '.'; break;
5681 case VK_OEM_2
: wxk
= '/'; break;
5682 case VK_OEM_3
: wxk
= '~'; break;
5683 case VK_OEM_4
: wxk
= '['; break;
5684 case VK_OEM_5
: wxk
= '\\'; break;
5685 case VK_OEM_6
: wxk
= ']'; break;
5686 case VK_OEM_7
: wxk
= '\''; break;
5688 // handle extended keys
5690 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_PAGEUP
, WXK_PAGEUP
);
5694 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_PAGEDOWN
, WXK_PAGEDOWN
);
5698 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_END
, WXK_END
);
5702 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_HOME
, WXK_HOME
);
5706 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_LEFT
, WXK_LEFT
);
5710 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_UP
, WXK_UP
);
5714 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_RIGHT
, WXK_RIGHT
);
5718 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_DOWN
, WXK_DOWN
);
5722 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_INSERT
, WXK_INSERT
);
5726 wxk
= ChooseNormalOrExtended(lParam
, WXK_NUMPAD_DELETE
, WXK_DELETE
);
5730 // don't use ChooseNormalOrExtended() here as the keys are reversed
5731 // here: numpad enter is the extended one
5732 wxk
= lParam
&& (lParam
& (1 << 24)) ? WXK_NUMPAD_ENTER
: WXK_RETURN
;
5742 WXWORD
wxCharCodeWXToMSW(int wxk
, bool *isVirtual
)
5747 // check the table first
5748 for ( size_t n
= 0; n
< WXSIZEOF(gs_specialKeys
); n
++ )
5750 if ( gs_specialKeys
[n
].wxk
== wxk
)
5751 return gs_specialKeys
[n
].vk
;
5754 // and then check for special keys not included in the table
5759 case WXK_NUMPAD_PAGEUP
:
5764 case WXK_NUMPAD_PAGEDOWN
:
5769 case WXK_NUMPAD_END
:
5774 case WXK_NUMPAD_HOME
:
5779 case WXK_NUMPAD_LEFT
:
5789 case WXK_NUMPAD_RIGHT
:
5794 case WXK_NUMPAD_DOWN
:
5799 case WXK_NUMPAD_INSERT
:
5804 case WXK_NUMPAD_DELETE
:
5818 #ifndef SM_SWAPBUTTON
5819 #define SM_SWAPBUTTON 23
5822 // small helper for wxGetKeyState() and wxGetMouseState()
5823 static inline bool wxIsKeyDown(WXWORD vk
)
5828 if (GetSystemMetrics(SM_SWAPBUTTON
)) vk
= VK_RBUTTON
;
5831 if (GetSystemMetrics(SM_SWAPBUTTON
)) vk
= VK_LBUTTON
;
5834 // the low order bit indicates whether the key was pressed since the last
5835 // call and the high order one indicates whether it is down right now and
5836 // we only want that one
5837 return (GetAsyncKeyState(vk
) & (1<<15)) != 0;
5840 bool wxGetKeyState(wxKeyCode key
)
5842 // although this does work under Windows, it is not supported under other
5843 // platforms so don't allow it, you must use wxGetMouseState() instead
5844 wxASSERT_MSG( key
!= VK_LBUTTON
&&
5845 key
!= VK_RBUTTON
&&
5847 wxT("can't use wxGetKeyState() for mouse buttons") );
5849 const WXWORD vk
= wxCharCodeWXToMSW(key
);
5851 // if the requested key is a LED key, return true if the led is pressed
5852 if ( key
== WXK_NUMLOCK
|| key
== WXK_CAPITAL
|| key
== WXK_SCROLL
)
5854 // low order bit means LED is highlighted and high order one means the
5855 // key is down; for compatibility with the other ports return true if
5856 // either one is set
5857 return GetKeyState(vk
) != 0;
5862 return wxIsKeyDown(vk
);
5867 wxMouseState
wxGetMouseState()
5871 GetCursorPos( &pt
);
5875 ms
.SetLeftDown(wxIsKeyDown(VK_LBUTTON
));
5876 ms
.SetMiddleDown(wxIsKeyDown(VK_MBUTTON
));
5877 ms
.SetRightDown(wxIsKeyDown(VK_RBUTTON
));
5878 #ifdef wxHAS_XBUTTON
5879 ms
.SetAux1Down(wxIsKeyDown(VK_XBUTTON1
));
5880 ms
.SetAux2Down(wxIsKeyDown(VK_XBUTTON2
));
5881 #endif // wxHAS_XBUTTON
5883 ms
.SetControlDown(wxIsKeyDown(VK_CONTROL
));
5884 ms
.SetShiftDown(wxIsKeyDown(VK_SHIFT
));
5885 ms
.SetAltDown(wxIsKeyDown(VK_MENU
));
5886 // ms.SetMetaDown();
5892 wxWindow
*wxGetActiveWindow()
5894 HWND hWnd
= GetActiveWindow();
5897 return wxFindWinFromHandle((WXHWND
) hWnd
);
5902 extern wxWindow
*wxGetWindowFromHWND(WXHWND hWnd
)
5904 HWND hwnd
= (HWND
)hWnd
;
5906 // For a radiobutton, we get the radiobox from GWL_USERDATA (which is set
5907 // by code in msw/radiobox.cpp), for all the others we just search up the
5909 wxWindow
*win
= (wxWindow
*)NULL
;
5912 win
= wxFindWinFromHandle((WXHWND
)hwnd
);
5916 // native radiobuttons return DLGC_RADIOBUTTON here and for any
5917 // wxWindow class which overrides WM_GETDLGCODE processing to
5918 // do it as well, win would be already non NULL
5919 if ( ::SendMessage(hwnd
, WM_GETDLGCODE
, 0, 0) & DLGC_RADIOBUTTON
)
5921 win
= (wxWindow
*)wxGetWindowUserData(hwnd
);
5923 //else: it's a wxRadioButton, not a radiobutton from wxRadioBox
5924 #endif // wxUSE_RADIOBOX
5926 // spin control text buddy window should be mapped to spin ctrl
5927 // itself so try it too
5928 #if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__)
5931 win
= wxSpinCtrl::GetSpinForTextCtrl((WXHWND
)hwnd
);
5933 #endif // wxUSE_SPINCTRL
5937 while ( hwnd
&& !win
)
5939 // this is a really ugly hack needed to avoid mistakenly returning the
5940 // parent frame wxWindow for the find/replace modeless dialog HWND -
5941 // this, in turn, is needed to call IsDialogMessage() from
5942 // wxApp::ProcessMessage() as for this we must return NULL from here
5944 // FIXME: this is clearly not the best way to do it but I think we'll
5945 // need to change HWND <-> wxWindow code more heavily than I can
5946 // do it now to fix it
5947 #ifndef __WXMICROWIN__
5948 if ( ::GetWindow(hwnd
, GW_OWNER
) )
5950 // it's a dialog box, don't go upwards
5955 hwnd
= ::GetParent(hwnd
);
5956 win
= wxFindWinFromHandle((WXHWND
)hwnd
);
5962 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
5964 // Windows keyboard hook. Allows interception of e.g. F1, ESCAPE
5965 // in active frames and dialogs, regardless of where the focus is.
5966 static HHOOK wxTheKeyboardHook
= 0;
5967 static FARPROC wxTheKeyboardHookProc
= 0;
5968 int APIENTRY _EXPORT
5969 wxKeyboardHook(int nCode
, WORD wParam
, DWORD lParam
);
5971 void wxSetKeyboardHook(bool doIt
)
5975 wxTheKeyboardHookProc
= MakeProcInstance((FARPROC
) wxKeyboardHook
, wxGetInstance());
5976 wxTheKeyboardHook
= SetWindowsHookEx(WH_KEYBOARD
, (HOOKPROC
) wxTheKeyboardHookProc
, wxGetInstance(),
5978 GetCurrentThreadId()
5979 // (DWORD)GetCurrentProcess()); // This is another possibility. Which is right?
5984 UnhookWindowsHookEx(wxTheKeyboardHook
);
5988 int APIENTRY _EXPORT
5989 wxKeyboardHook(int nCode
, WORD wParam
, DWORD lParam
)
5991 DWORD hiWord
= HIWORD(lParam
);
5992 if ( nCode
!= HC_NOREMOVE
&& ((hiWord
& KF_UP
) == 0) )
5994 int id
= wxCharCodeMSWToWX(wParam
, lParam
);
5997 wxKeyEvent
event(wxEVT_CHAR_HOOK
);
5998 if ( (HIWORD(lParam
) & KF_ALTDOWN
) == KF_ALTDOWN
)
5999 event
.m_altDown
= true;
6001 event
.SetEventObject(NULL
);
6002 event
.m_keyCode
= id
;
6003 event
.m_shiftDown
= wxIsShiftDown();
6004 event
.m_controlDown
= wxIsCtrlDown();
6006 event
.SetTimestamp(::GetMessageTime());
6008 wxWindow
*win
= wxGetActiveWindow();
6009 wxEvtHandler
*handler
;
6012 handler
= win
->GetEventHandler();
6013 event
.SetId(win
->GetId());
6018 event
.SetId(wxID_ANY
);
6021 if ( handler
&& handler
->ProcessEvent(event
) )
6029 return (int)CallNextHookEx(wxTheKeyboardHook
, nCode
, wParam
, lParam
);
6032 #endif // !__WXMICROWIN__
6035 const wxChar
*wxGetMessageName(int message
)
6039 case 0x0000: return wxT("WM_NULL");
6040 case 0x0001: return wxT("WM_CREATE");
6041 case 0x0002: return wxT("WM_DESTROY");
6042 case 0x0003: return wxT("WM_MOVE");
6043 case 0x0005: return wxT("WM_SIZE");
6044 case 0x0006: return wxT("WM_ACTIVATE");
6045 case 0x0007: return wxT("WM_SETFOCUS");
6046 case 0x0008: return wxT("WM_KILLFOCUS");
6047 case 0x000A: return wxT("WM_ENABLE");
6048 case 0x000B: return wxT("WM_SETREDRAW");
6049 case 0x000C: return wxT("WM_SETTEXT");
6050 case 0x000D: return wxT("WM_GETTEXT");
6051 case 0x000E: return wxT("WM_GETTEXTLENGTH");
6052 case 0x000F: return wxT("WM_PAINT");
6053 case 0x0010: return wxT("WM_CLOSE");
6054 case 0x0011: return wxT("WM_QUERYENDSESSION");
6055 case 0x0012: return wxT("WM_QUIT");
6056 case 0x0013: return wxT("WM_QUERYOPEN");
6057 case 0x0014: return wxT("WM_ERASEBKGND");
6058 case 0x0015: return wxT("WM_SYSCOLORCHANGE");
6059 case 0x0016: return wxT("WM_ENDSESSION");
6060 case 0x0017: return wxT("WM_SYSTEMERROR");
6061 case 0x0018: return wxT("WM_SHOWWINDOW");
6062 case 0x0019: return wxT("WM_CTLCOLOR");
6063 case 0x001A: return wxT("WM_WININICHANGE");
6064 case 0x001B: return wxT("WM_DEVMODECHANGE");
6065 case 0x001C: return wxT("WM_ACTIVATEAPP");
6066 case 0x001D: return wxT("WM_FONTCHANGE");
6067 case 0x001E: return wxT("WM_TIMECHANGE");
6068 case 0x001F: return wxT("WM_CANCELMODE");
6069 case 0x0020: return wxT("WM_SETCURSOR");
6070 case 0x0021: return wxT("WM_MOUSEACTIVATE");
6071 case 0x0022: return wxT("WM_CHILDACTIVATE");
6072 case 0x0023: return wxT("WM_QUEUESYNC");
6073 case 0x0024: return wxT("WM_GETMINMAXINFO");
6074 case 0x0026: return wxT("WM_PAINTICON");
6075 case 0x0027: return wxT("WM_ICONERASEBKGND");
6076 case 0x0028: return wxT("WM_NEXTDLGCTL");
6077 case 0x002A: return wxT("WM_SPOOLERSTATUS");
6078 case 0x002B: return wxT("WM_DRAWITEM");
6079 case 0x002C: return wxT("WM_MEASUREITEM");
6080 case 0x002D: return wxT("WM_DELETEITEM");
6081 case 0x002E: return wxT("WM_VKEYTOITEM");
6082 case 0x002F: return wxT("WM_CHARTOITEM");
6083 case 0x0030: return wxT("WM_SETFONT");
6084 case 0x0031: return wxT("WM_GETFONT");
6085 case 0x0037: return wxT("WM_QUERYDRAGICON");
6086 case 0x0039: return wxT("WM_COMPAREITEM");
6087 case 0x0041: return wxT("WM_COMPACTING");
6088 case 0x0044: return wxT("WM_COMMNOTIFY");
6089 case 0x0046: return wxT("WM_WINDOWPOSCHANGING");
6090 case 0x0047: return wxT("WM_WINDOWPOSCHANGED");
6091 case 0x0048: return wxT("WM_POWER");
6093 case 0x004A: return wxT("WM_COPYDATA");
6094 case 0x004B: return wxT("WM_CANCELJOURNAL");
6095 case 0x004E: return wxT("WM_NOTIFY");
6096 case 0x0050: return wxT("WM_INPUTLANGCHANGEREQUEST");
6097 case 0x0051: return wxT("WM_INPUTLANGCHANGE");
6098 case 0x0052: return wxT("WM_TCARD");
6099 case 0x0053: return wxT("WM_HELP");
6100 case 0x0054: return wxT("WM_USERCHANGED");
6101 case 0x0055: return wxT("WM_NOTIFYFORMAT");
6102 case 0x007B: return wxT("WM_CONTEXTMENU");
6103 case 0x007C: return wxT("WM_STYLECHANGING");
6104 case 0x007D: return wxT("WM_STYLECHANGED");
6105 case 0x007E: return wxT("WM_DISPLAYCHANGE");
6106 case 0x007F: return wxT("WM_GETICON");
6107 case 0x0080: return wxT("WM_SETICON");
6109 case 0x0081: return wxT("WM_NCCREATE");
6110 case 0x0082: return wxT("WM_NCDESTROY");
6111 case 0x0083: return wxT("WM_NCCALCSIZE");
6112 case 0x0084: return wxT("WM_NCHITTEST");
6113 case 0x0085: return wxT("WM_NCPAINT");
6114 case 0x0086: return wxT("WM_NCACTIVATE");
6115 case 0x0087: return wxT("WM_GETDLGCODE");
6116 case 0x00A0: return wxT("WM_NCMOUSEMOVE");
6117 case 0x00A1: return wxT("WM_NCLBUTTONDOWN");
6118 case 0x00A2: return wxT("WM_NCLBUTTONUP");
6119 case 0x00A3: return wxT("WM_NCLBUTTONDBLCLK");
6120 case 0x00A4: return wxT("WM_NCRBUTTONDOWN");
6121 case 0x00A5: return wxT("WM_NCRBUTTONUP");
6122 case 0x00A6: return wxT("WM_NCRBUTTONDBLCLK");
6123 case 0x00A7: return wxT("WM_NCMBUTTONDOWN");
6124 case 0x00A8: return wxT("WM_NCMBUTTONUP");
6125 case 0x00A9: return wxT("WM_NCMBUTTONDBLCLK");
6127 case 0x00B0: return wxT("EM_GETSEL");
6128 case 0x00B1: return wxT("EM_SETSEL");
6129 case 0x00B2: return wxT("EM_GETRECT");
6130 case 0x00B3: return wxT("EM_SETRECT");
6131 case 0x00B4: return wxT("EM_SETRECTNP");
6132 case 0x00B5: return wxT("EM_SCROLL");
6133 case 0x00B6: return wxT("EM_LINESCROLL");
6134 case 0x00B7: return wxT("EM_SCROLLCARET");
6135 case 0x00B8: return wxT("EM_GETMODIFY");
6136 case 0x00B9: return wxT("EM_SETMODIFY");
6137 case 0x00BA: return wxT("EM_GETLINECOUNT");
6138 case 0x00BB: return wxT("EM_LINEINDEX");
6139 case 0x00BC: return wxT("EM_SETHANDLE");
6140 case 0x00BD: return wxT("EM_GETHANDLE");
6141 case 0x00BE: return wxT("EM_GETTHUMB");
6142 case 0x00C1: return wxT("EM_LINELENGTH");
6143 case 0x00C2: return wxT("EM_REPLACESEL");
6144 case 0x00C4: return wxT("EM_GETLINE");
6145 case 0x00C5: return wxT("EM_LIMITTEXT/EM_SETLIMITTEXT"); /* ;win40 Name change */
6146 case 0x00C6: return wxT("EM_CANUNDO");
6147 case 0x00C7: return wxT("EM_UNDO");
6148 case 0x00C8: return wxT("EM_FMTLINES");
6149 case 0x00C9: return wxT("EM_LINEFROMCHAR");
6150 case 0x00CB: return wxT("EM_SETTABSTOPS");
6151 case 0x00CC: return wxT("EM_SETPASSWORDCHAR");
6152 case 0x00CD: return wxT("EM_EMPTYUNDOBUFFER");
6153 case 0x00CE: return wxT("EM_GETFIRSTVISIBLELINE");
6154 case 0x00CF: return wxT("EM_SETREADONLY");
6155 case 0x00D0: return wxT("EM_SETWORDBREAKPROC");
6156 case 0x00D1: return wxT("EM_GETWORDBREAKPROC");
6157 case 0x00D2: return wxT("EM_GETPASSWORDCHAR");
6158 case 0x00D3: return wxT("EM_SETMARGINS");
6159 case 0x00D4: return wxT("EM_GETMARGINS");
6160 case 0x00D5: return wxT("EM_GETLIMITTEXT");
6161 case 0x00D6: return wxT("EM_POSFROMCHAR");
6162 case 0x00D7: return wxT("EM_CHARFROMPOS");
6163 case 0x00D8: return wxT("EM_SETIMESTATUS");
6164 case 0x00D9: return wxT("EM_GETIMESTATUS");
6166 case 0x0100: return wxT("WM_KEYDOWN");
6167 case 0x0101: return wxT("WM_KEYUP");
6168 case 0x0102: return wxT("WM_CHAR");
6169 case 0x0103: return wxT("WM_DEADCHAR");
6170 case 0x0104: return wxT("WM_SYSKEYDOWN");
6171 case 0x0105: return wxT("WM_SYSKEYUP");
6172 case 0x0106: return wxT("WM_SYSCHAR");
6173 case 0x0107: return wxT("WM_SYSDEADCHAR");
6174 case 0x0108: return wxT("WM_KEYLAST");
6176 case 0x010D: return wxT("WM_IME_STARTCOMPOSITION");
6177 case 0x010E: return wxT("WM_IME_ENDCOMPOSITION");
6178 case 0x010F: return wxT("WM_IME_COMPOSITION");
6180 case 0x0110: return wxT("WM_INITDIALOG");
6181 case 0x0111: return wxT("WM_COMMAND");
6182 case 0x0112: return wxT("WM_SYSCOMMAND");
6183 case 0x0113: return wxT("WM_TIMER");
6184 case 0x0114: return wxT("WM_HSCROLL");
6185 case 0x0115: return wxT("WM_VSCROLL");
6186 case 0x0116: return wxT("WM_INITMENU");
6187 case 0x0117: return wxT("WM_INITMENUPOPUP");
6188 case 0x011F: return wxT("WM_MENUSELECT");
6189 case 0x0120: return wxT("WM_MENUCHAR");
6190 case 0x0121: return wxT("WM_ENTERIDLE");
6192 case 0x0132: return wxT("WM_CTLCOLORMSGBOX");
6193 case 0x0133: return wxT("WM_CTLCOLOREDIT");
6194 case 0x0134: return wxT("WM_CTLCOLORLISTBOX");
6195 case 0x0135: return wxT("WM_CTLCOLORBTN");
6196 case 0x0136: return wxT("WM_CTLCOLORDLG");
6197 case 0x0137: return wxT("WM_CTLCOLORSCROLLBAR");
6198 case 0x0138: return wxT("WM_CTLCOLORSTATIC");
6199 case 0x01E1: return wxT("MN_GETHMENU");
6201 case 0x0200: return wxT("WM_MOUSEMOVE");
6202 case 0x0201: return wxT("WM_LBUTTONDOWN");
6203 case 0x0202: return wxT("WM_LBUTTONUP");
6204 case 0x0203: return wxT("WM_LBUTTONDBLCLK");
6205 case 0x0204: return wxT("WM_RBUTTONDOWN");
6206 case 0x0205: return wxT("WM_RBUTTONUP");
6207 case 0x0206: return wxT("WM_RBUTTONDBLCLK");
6208 case 0x0207: return wxT("WM_MBUTTONDOWN");
6209 case 0x0208: return wxT("WM_MBUTTONUP");
6210 case 0x0209: return wxT("WM_MBUTTONDBLCLK");
6211 case 0x020A: return wxT("WM_MOUSEWHEEL");
6212 case 0x020B: return wxT("WM_XBUTTONDOWN");
6213 case 0x020C: return wxT("WM_XBUTTONUP");
6214 case 0x020D: return wxT("WM_XBUTTONDBLCLK");
6215 case 0x0210: return wxT("WM_PARENTNOTIFY");
6216 case 0x0211: return wxT("WM_ENTERMENULOOP");
6217 case 0x0212: return wxT("WM_EXITMENULOOP");
6219 case 0x0213: return wxT("WM_NEXTMENU");
6220 case 0x0214: return wxT("WM_SIZING");
6221 case 0x0215: return wxT("WM_CAPTURECHANGED");
6222 case 0x0216: return wxT("WM_MOVING");
6223 case 0x0218: return wxT("WM_POWERBROADCAST");
6224 case 0x0219: return wxT("WM_DEVICECHANGE");
6226 case 0x0220: return wxT("WM_MDICREATE");
6227 case 0x0221: return wxT("WM_MDIDESTROY");
6228 case 0x0222: return wxT("WM_MDIACTIVATE");
6229 case 0x0223: return wxT("WM_MDIRESTORE");
6230 case 0x0224: return wxT("WM_MDINEXT");
6231 case 0x0225: return wxT("WM_MDIMAXIMIZE");
6232 case 0x0226: return wxT("WM_MDITILE");
6233 case 0x0227: return wxT("WM_MDICASCADE");
6234 case 0x0228: return wxT("WM_MDIICONARRANGE");
6235 case 0x0229: return wxT("WM_MDIGETACTIVE");
6236 case 0x0230: return wxT("WM_MDISETMENU");
6237 case 0x0233: return wxT("WM_DROPFILES");
6239 case 0x0281: return wxT("WM_IME_SETCONTEXT");
6240 case 0x0282: return wxT("WM_IME_NOTIFY");
6241 case 0x0283: return wxT("WM_IME_CONTROL");
6242 case 0x0284: return wxT("WM_IME_COMPOSITIONFULL");
6243 case 0x0285: return wxT("WM_IME_SELECT");
6244 case 0x0286: return wxT("WM_IME_CHAR");
6245 case 0x0290: return wxT("WM_IME_KEYDOWN");
6246 case 0x0291: return wxT("WM_IME_KEYUP");
6248 case 0x02A0: return wxT("WM_NCMOUSEHOVER");
6249 case 0x02A1: return wxT("WM_MOUSEHOVER");
6250 case 0x02A2: return wxT("WM_NCMOUSELEAVE");
6251 case 0x02A3: return wxT("WM_MOUSELEAVE");
6253 case 0x0300: return wxT("WM_CUT");
6254 case 0x0301: return wxT("WM_COPY");
6255 case 0x0302: return wxT("WM_PASTE");
6256 case 0x0303: return wxT("WM_CLEAR");
6257 case 0x0304: return wxT("WM_UNDO");
6258 case 0x0305: return wxT("WM_RENDERFORMAT");
6259 case 0x0306: return wxT("WM_RENDERALLFORMATS");
6260 case 0x0307: return wxT("WM_DESTROYCLIPBOARD");
6261 case 0x0308: return wxT("WM_DRAWCLIPBOARD");
6262 case 0x0309: return wxT("WM_PAINTCLIPBOARD");
6263 case 0x030A: return wxT("WM_VSCROLLCLIPBOARD");
6264 case 0x030B: return wxT("WM_SIZECLIPBOARD");
6265 case 0x030C: return wxT("WM_ASKCBFORMATNAME");
6266 case 0x030D: return wxT("WM_CHANGECBCHAIN");
6267 case 0x030E: return wxT("WM_HSCROLLCLIPBOARD");
6268 case 0x030F: return wxT("WM_QUERYNEWPALETTE");
6269 case 0x0310: return wxT("WM_PALETTEISCHANGING");
6270 case 0x0311: return wxT("WM_PALETTECHANGED");
6271 case 0x0312: return wxT("WM_HOTKEY");
6273 case 0x0317: return wxT("WM_PRINT");
6274 case 0x0318: return wxT("WM_PRINTCLIENT");
6276 // common controls messages - although they're not strictly speaking
6277 // standard, it's nice to decode them nevertheless
6280 case 0x1000 + 0: return wxT("LVM_GETBKCOLOR");
6281 case 0x1000 + 1: return wxT("LVM_SETBKCOLOR");
6282 case 0x1000 + 2: return wxT("LVM_GETIMAGELIST");
6283 case 0x1000 + 3: return wxT("LVM_SETIMAGELIST");
6284 case 0x1000 + 4: return wxT("LVM_GETITEMCOUNT");
6285 case 0x1000 + 5: return wxT("LVM_GETITEMA");
6286 case 0x1000 + 75: return wxT("LVM_GETITEMW");
6287 case 0x1000 + 6: return wxT("LVM_SETITEMA");
6288 case 0x1000 + 76: return wxT("LVM_SETITEMW");
6289 case 0x1000 + 7: return wxT("LVM_INSERTITEMA");
6290 case 0x1000 + 77: return wxT("LVM_INSERTITEMW");
6291 case 0x1000 + 8: return wxT("LVM_DELETEITEM");
6292 case 0x1000 + 9: return wxT("LVM_DELETEALLITEMS");
6293 case 0x1000 + 10: return wxT("LVM_GETCALLBACKMASK");
6294 case 0x1000 + 11: return wxT("LVM_SETCALLBACKMASK");
6295 case 0x1000 + 12: return wxT("LVM_GETNEXTITEM");
6296 case 0x1000 + 13: return wxT("LVM_FINDITEMA");
6297 case 0x1000 + 83: return wxT("LVM_FINDITEMW");
6298 case 0x1000 + 14: return wxT("LVM_GETITEMRECT");
6299 case 0x1000 + 15: return wxT("LVM_SETITEMPOSITION");
6300 case 0x1000 + 16: return wxT("LVM_GETITEMPOSITION");
6301 case 0x1000 + 17: return wxT("LVM_GETSTRINGWIDTHA");
6302 case 0x1000 + 87: return wxT("LVM_GETSTRINGWIDTHW");
6303 case 0x1000 + 18: return wxT("LVM_HITTEST");
6304 case 0x1000 + 19: return wxT("LVM_ENSUREVISIBLE");
6305 case 0x1000 + 20: return wxT("LVM_SCROLL");
6306 case 0x1000 + 21: return wxT("LVM_REDRAWITEMS");
6307 case 0x1000 + 22: return wxT("LVM_ARRANGE");
6308 case 0x1000 + 23: return wxT("LVM_EDITLABELA");
6309 case 0x1000 + 118: return wxT("LVM_EDITLABELW");
6310 case 0x1000 + 24: return wxT("LVM_GETEDITCONTROL");
6311 case 0x1000 + 25: return wxT("LVM_GETCOLUMNA");
6312 case 0x1000 + 95: return wxT("LVM_GETCOLUMNW");
6313 case 0x1000 + 26: return wxT("LVM_SETCOLUMNA");
6314 case 0x1000 + 96: return wxT("LVM_SETCOLUMNW");
6315 case 0x1000 + 27: return wxT("LVM_INSERTCOLUMNA");
6316 case 0x1000 + 97: return wxT("LVM_INSERTCOLUMNW");
6317 case 0x1000 + 28: return wxT("LVM_DELETECOLUMN");
6318 case 0x1000 + 29: return wxT("LVM_GETCOLUMNWIDTH");
6319 case 0x1000 + 30: return wxT("LVM_SETCOLUMNWIDTH");
6320 case 0x1000 + 31: return wxT("LVM_GETHEADER");
6321 case 0x1000 + 33: return wxT("LVM_CREATEDRAGIMAGE");
6322 case 0x1000 + 34: return wxT("LVM_GETVIEWRECT");
6323 case 0x1000 + 35: return wxT("LVM_GETTEXTCOLOR");
6324 case 0x1000 + 36: return wxT("LVM_SETTEXTCOLOR");
6325 case 0x1000 + 37: return wxT("LVM_GETTEXTBKCOLOR");
6326 case 0x1000 + 38: return wxT("LVM_SETTEXTBKCOLOR");
6327 case 0x1000 + 39: return wxT("LVM_GETTOPINDEX");
6328 case 0x1000 + 40: return wxT("LVM_GETCOUNTPERPAGE");
6329 case 0x1000 + 41: return wxT("LVM_GETORIGIN");
6330 case 0x1000 + 42: return wxT("LVM_UPDATE");
6331 case 0x1000 + 43: return wxT("LVM_SETITEMSTATE");
6332 case 0x1000 + 44: return wxT("LVM_GETITEMSTATE");
6333 case 0x1000 + 45: return wxT("LVM_GETITEMTEXTA");
6334 case 0x1000 + 115: return wxT("LVM_GETITEMTEXTW");
6335 case 0x1000 + 46: return wxT("LVM_SETITEMTEXTA");
6336 case 0x1000 + 116: return wxT("LVM_SETITEMTEXTW");
6337 case 0x1000 + 47: return wxT("LVM_SETITEMCOUNT");
6338 case 0x1000 + 48: return wxT("LVM_SORTITEMS");
6339 case 0x1000 + 49: return wxT("LVM_SETITEMPOSITION32");
6340 case 0x1000 + 50: return wxT("LVM_GETSELECTEDCOUNT");
6341 case 0x1000 + 51: return wxT("LVM_GETITEMSPACING");
6342 case 0x1000 + 52: return wxT("LVM_GETISEARCHSTRINGA");
6343 case 0x1000 + 117: return wxT("LVM_GETISEARCHSTRINGW");
6344 case 0x1000 + 53: return wxT("LVM_SETICONSPACING");
6345 case 0x1000 + 54: return wxT("LVM_SETEXTENDEDLISTVIEWSTYLE");
6346 case 0x1000 + 55: return wxT("LVM_GETEXTENDEDLISTVIEWSTYLE");
6347 case 0x1000 + 56: return wxT("LVM_GETSUBITEMRECT");
6348 case 0x1000 + 57: return wxT("LVM_SUBITEMHITTEST");
6349 case 0x1000 + 58: return wxT("LVM_SETCOLUMNORDERARRAY");
6350 case 0x1000 + 59: return wxT("LVM_GETCOLUMNORDERARRAY");
6351 case 0x1000 + 60: return wxT("LVM_SETHOTITEM");
6352 case 0x1000 + 61: return wxT("LVM_GETHOTITEM");
6353 case 0x1000 + 62: return wxT("LVM_SETHOTCURSOR");
6354 case 0x1000 + 63: return wxT("LVM_GETHOTCURSOR");
6355 case 0x1000 + 64: return wxT("LVM_APPROXIMATEVIEWRECT");
6356 case 0x1000 + 65: return wxT("LVM_SETWORKAREA");
6359 case 0x1100 + 0: return wxT("TVM_INSERTITEMA");
6360 case 0x1100 + 50: return wxT("TVM_INSERTITEMW");
6361 case 0x1100 + 1: return wxT("TVM_DELETEITEM");
6362 case 0x1100 + 2: return wxT("TVM_EXPAND");
6363 case 0x1100 + 4: return wxT("TVM_GETITEMRECT");
6364 case 0x1100 + 5: return wxT("TVM_GETCOUNT");
6365 case 0x1100 + 6: return wxT("TVM_GETINDENT");
6366 case 0x1100 + 7: return wxT("TVM_SETINDENT");
6367 case 0x1100 + 8: return wxT("TVM_GETIMAGELIST");
6368 case 0x1100 + 9: return wxT("TVM_SETIMAGELIST");
6369 case 0x1100 + 10: return wxT("TVM_GETNEXTITEM");
6370 case 0x1100 + 11: return wxT("TVM_SELECTITEM");
6371 case 0x1100 + 12: return wxT("TVM_GETITEMA");
6372 case 0x1100 + 62: return wxT("TVM_GETITEMW");
6373 case 0x1100 + 13: return wxT("TVM_SETITEMA");
6374 case 0x1100 + 63: return wxT("TVM_SETITEMW");
6375 case 0x1100 + 14: return wxT("TVM_EDITLABELA");
6376 case 0x1100 + 65: return wxT("TVM_EDITLABELW");
6377 case 0x1100 + 15: return wxT("TVM_GETEDITCONTROL");
6378 case 0x1100 + 16: return wxT("TVM_GETVISIBLECOUNT");
6379 case 0x1100 + 17: return wxT("TVM_HITTEST");
6380 case 0x1100 + 18: return wxT("TVM_CREATEDRAGIMAGE");
6381 case 0x1100 + 19: return wxT("TVM_SORTCHILDREN");
6382 case 0x1100 + 20: return wxT("TVM_ENSUREVISIBLE");
6383 case 0x1100 + 21: return wxT("TVM_SORTCHILDRENCB");
6384 case 0x1100 + 22: return wxT("TVM_ENDEDITLABELNOW");
6385 case 0x1100 + 23: return wxT("TVM_GETISEARCHSTRINGA");
6386 case 0x1100 + 64: return wxT("TVM_GETISEARCHSTRINGW");
6387 case 0x1100 + 24: return wxT("TVM_SETTOOLTIPS");
6388 case 0x1100 + 25: return wxT("TVM_GETTOOLTIPS");
6391 case 0x1200 + 0: return wxT("HDM_GETITEMCOUNT");
6392 case 0x1200 + 1: return wxT("HDM_INSERTITEMA");
6393 case 0x1200 + 10: return wxT("HDM_INSERTITEMW");
6394 case 0x1200 + 2: return wxT("HDM_DELETEITEM");
6395 case 0x1200 + 3: return wxT("HDM_GETITEMA");
6396 case 0x1200 + 11: return wxT("HDM_GETITEMW");
6397 case 0x1200 + 4: return wxT("HDM_SETITEMA");
6398 case 0x1200 + 12: return wxT("HDM_SETITEMW");
6399 case 0x1200 + 5: return wxT("HDM_LAYOUT");
6400 case 0x1200 + 6: return wxT("HDM_HITTEST");
6401 case 0x1200 + 7: return wxT("HDM_GETITEMRECT");
6402 case 0x1200 + 8: return wxT("HDM_SETIMAGELIST");
6403 case 0x1200 + 9: return wxT("HDM_GETIMAGELIST");
6404 case 0x1200 + 15: return wxT("HDM_ORDERTOINDEX");
6405 case 0x1200 + 16: return wxT("HDM_CREATEDRAGIMAGE");
6406 case 0x1200 + 17: return wxT("HDM_GETORDERARRAY");
6407 case 0x1200 + 18: return wxT("HDM_SETORDERARRAY");
6408 case 0x1200 + 19: return wxT("HDM_SETHOTDIVIDER");
6411 case 0x1300 + 2: return wxT("TCM_GETIMAGELIST");
6412 case 0x1300 + 3: return wxT("TCM_SETIMAGELIST");
6413 case 0x1300 + 4: return wxT("TCM_GETITEMCOUNT");
6414 case 0x1300 + 5: return wxT("TCM_GETITEMA");
6415 case 0x1300 + 60: return wxT("TCM_GETITEMW");
6416 case 0x1300 + 6: return wxT("TCM_SETITEMA");
6417 case 0x1300 + 61: return wxT("TCM_SETITEMW");
6418 case 0x1300 + 7: return wxT("TCM_INSERTITEMA");
6419 case 0x1300 + 62: return wxT("TCM_INSERTITEMW");
6420 case 0x1300 + 8: return wxT("TCM_DELETEITEM");
6421 case 0x1300 + 9: return wxT("TCM_DELETEALLITEMS");
6422 case 0x1300 + 10: return wxT("TCM_GETITEMRECT");
6423 case 0x1300 + 11: return wxT("TCM_GETCURSEL");
6424 case 0x1300 + 12: return wxT("TCM_SETCURSEL");
6425 case 0x1300 + 13: return wxT("TCM_HITTEST");
6426 case 0x1300 + 14: return wxT("TCM_SETITEMEXTRA");
6427 case 0x1300 + 40: return wxT("TCM_ADJUSTRECT");
6428 case 0x1300 + 41: return wxT("TCM_SETITEMSIZE");
6429 case 0x1300 + 42: return wxT("TCM_REMOVEIMAGE");
6430 case 0x1300 + 43: return wxT("TCM_SETPADDING");
6431 case 0x1300 + 44: return wxT("TCM_GETROWCOUNT");
6432 case 0x1300 + 45: return wxT("TCM_GETTOOLTIPS");
6433 case 0x1300 + 46: return wxT("TCM_SETTOOLTIPS");
6434 case 0x1300 + 47: return wxT("TCM_GETCURFOCUS");
6435 case 0x1300 + 48: return wxT("TCM_SETCURFOCUS");
6436 case 0x1300 + 49: return wxT("TCM_SETMINTABWIDTH");
6437 case 0x1300 + 50: return wxT("TCM_DESELECTALL");
6440 case WM_USER
+1: return wxT("TB_ENABLEBUTTON");
6441 case WM_USER
+2: return wxT("TB_CHECKBUTTON");
6442 case WM_USER
+3: return wxT("TB_PRESSBUTTON");
6443 case WM_USER
+4: return wxT("TB_HIDEBUTTON");
6444 case WM_USER
+5: return wxT("TB_INDETERMINATE");
6445 case WM_USER
+9: return wxT("TB_ISBUTTONENABLED");
6446 case WM_USER
+10: return wxT("TB_ISBUTTONCHECKED");
6447 case WM_USER
+11: return wxT("TB_ISBUTTONPRESSED");
6448 case WM_USER
+12: return wxT("TB_ISBUTTONHIDDEN");
6449 case WM_USER
+13: return wxT("TB_ISBUTTONINDETERMINATE");
6450 case WM_USER
+17: return wxT("TB_SETSTATE");
6451 case WM_USER
+18: return wxT("TB_GETSTATE");
6452 case WM_USER
+19: return wxT("TB_ADDBITMAP");
6453 case WM_USER
+20: return wxT("TB_ADDBUTTONS");
6454 case WM_USER
+21: return wxT("TB_INSERTBUTTON");
6455 case WM_USER
+22: return wxT("TB_DELETEBUTTON");
6456 case WM_USER
+23: return wxT("TB_GETBUTTON");
6457 case WM_USER
+24: return wxT("TB_BUTTONCOUNT");
6458 case WM_USER
+25: return wxT("TB_COMMANDTOINDEX");
6459 case WM_USER
+26: return wxT("TB_SAVERESTOREA");
6460 case WM_USER
+76: return wxT("TB_SAVERESTOREW");
6461 case WM_USER
+27: return wxT("TB_CUSTOMIZE");
6462 case WM_USER
+28: return wxT("TB_ADDSTRINGA");
6463 case WM_USER
+77: return wxT("TB_ADDSTRINGW");
6464 case WM_USER
+29: return wxT("TB_GETITEMRECT");
6465 case WM_USER
+30: return wxT("TB_BUTTONSTRUCTSIZE");
6466 case WM_USER
+31: return wxT("TB_SETBUTTONSIZE");
6467 case WM_USER
+32: return wxT("TB_SETBITMAPSIZE");
6468 case WM_USER
+33: return wxT("TB_AUTOSIZE");
6469 case WM_USER
+35: return wxT("TB_GETTOOLTIPS");
6470 case WM_USER
+36: return wxT("TB_SETTOOLTIPS");
6471 case WM_USER
+37: return wxT("TB_SETPARENT");
6472 case WM_USER
+39: return wxT("TB_SETROWS");
6473 case WM_USER
+40: return wxT("TB_GETROWS");
6474 case WM_USER
+42: return wxT("TB_SETCMDID");
6475 case WM_USER
+43: return wxT("TB_CHANGEBITMAP");
6476 case WM_USER
+44: return wxT("TB_GETBITMAP");
6477 case WM_USER
+45: return wxT("TB_GETBUTTONTEXTA");
6478 case WM_USER
+75: return wxT("TB_GETBUTTONTEXTW");
6479 case WM_USER
+46: return wxT("TB_REPLACEBITMAP");
6480 case WM_USER
+47: return wxT("TB_SETINDENT");
6481 case WM_USER
+48: return wxT("TB_SETIMAGELIST");
6482 case WM_USER
+49: return wxT("TB_GETIMAGELIST");
6483 case WM_USER
+50: return wxT("TB_LOADIMAGES");
6484 case WM_USER
+51: return wxT("TB_GETRECT");
6485 case WM_USER
+52: return wxT("TB_SETHOTIMAGELIST");
6486 case WM_USER
+53: return wxT("TB_GETHOTIMAGELIST");
6487 case WM_USER
+54: return wxT("TB_SETDISABLEDIMAGELIST");
6488 case WM_USER
+55: return wxT("TB_GETDISABLEDIMAGELIST");
6489 case WM_USER
+56: return wxT("TB_SETSTYLE");
6490 case WM_USER
+57: return wxT("TB_GETSTYLE");
6491 case WM_USER
+58: return wxT("TB_GETBUTTONSIZE");
6492 case WM_USER
+59: return wxT("TB_SETBUTTONWIDTH");
6493 case WM_USER
+60: return wxT("TB_SETMAXTEXTROWS");
6494 case WM_USER
+61: return wxT("TB_GETTEXTROWS");
6495 case WM_USER
+41: return wxT("TB_GETBITMAPFLAGS");
6498 static wxString s_szBuf
;
6499 s_szBuf
.Printf(wxT("<unknown message = %d>"), message
);
6500 return s_szBuf
.c_str();
6503 #endif //__WXDEBUG__
6505 static TEXTMETRIC
wxGetTextMetrics(const wxWindowMSW
*win
)
6509 HWND hwnd
= GetHwndOf(win
);
6510 HDC hdc
= ::GetDC(hwnd
);
6512 #if !wxDIALOG_UNIT_COMPATIBILITY
6513 // and select the current font into it
6514 HFONT hfont
= GetHfontOf(win
->GetFont());
6517 hfont
= (HFONT
)::SelectObject(hdc
, hfont
);
6521 // finally retrieve the text metrics from it
6522 GetTextMetrics(hdc
, &tm
);
6524 #if !wxDIALOG_UNIT_COMPATIBILITY
6528 (void)::SelectObject(hdc
, hfont
);
6532 ::ReleaseDC(hwnd
, hdc
);
6537 // Find the wxWindow at the current mouse position, returning the mouse
6539 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
6541 pt
= wxGetMousePosition();
6542 return wxFindWindowAtPoint(pt
);
6545 wxWindow
* wxFindWindowAtPoint(const wxPoint
& pt
)
6551 HWND hWnd
= ::WindowFromPoint(pt2
);
6553 return wxGetWindowFromHWND((WXHWND
)hWnd
);
6556 // Get the current mouse position.
6557 wxPoint
wxGetMousePosition()
6561 GetCursorPosWinCE(&pt
);
6563 GetCursorPos( & pt
);
6566 return wxPoint(pt
.x
, pt
.y
);
6571 #if defined(__SMARTPHONE__) || defined(__POCKETPC__)
6572 static void WinCEUnregisterHotKey(int modifiers
, int id
)
6574 // Register hotkeys for the hardware buttons
6576 typedef BOOL (WINAPI
*UnregisterFunc1Proc
)(UINT
, UINT
);
6578 UnregisterFunc1Proc procUnregisterFunc
;
6579 hCoreDll
= LoadLibrary(_T("coredll.dll"));
6582 procUnregisterFunc
= (UnregisterFunc1Proc
)GetProcAddress(hCoreDll
, _T("UnregisterFunc1"));
6583 if (procUnregisterFunc
)
6584 procUnregisterFunc(modifiers
, id
);
6585 FreeLibrary(hCoreDll
);
6590 bool wxWindowMSW::RegisterHotKey(int hotkeyId
, int modifiers
, int keycode
)
6592 UINT win_modifiers
=0;
6593 if ( modifiers
& wxMOD_ALT
)
6594 win_modifiers
|= MOD_ALT
;
6595 if ( modifiers
& wxMOD_SHIFT
)
6596 win_modifiers
|= MOD_SHIFT
;
6597 if ( modifiers
& wxMOD_CONTROL
)
6598 win_modifiers
|= MOD_CONTROL
;
6599 if ( modifiers
& wxMOD_WIN
)
6600 win_modifiers
|= MOD_WIN
;
6602 #if defined(__SMARTPHONE__) || defined(__POCKETPC__)
6603 // Required for PPC and Smartphone hardware buttons
6604 if (keycode
>= WXK_SPECIAL1
&& keycode
<= WXK_SPECIAL20
)
6605 WinCEUnregisterHotKey(win_modifiers
, hotkeyId
);
6608 if ( !::RegisterHotKey(GetHwnd(), hotkeyId
, win_modifiers
, keycode
) )
6610 wxLogLastError(_T("RegisterHotKey"));
6618 bool wxWindowMSW::UnregisterHotKey(int hotkeyId
)
6620 #if defined(__SMARTPHONE__) || defined(__POCKETPC__)
6621 WinCEUnregisterHotKey(MOD_WIN
, hotkeyId
);
6624 if ( !::UnregisterHotKey(GetHwnd(), hotkeyId
) )
6626 wxLogLastError(_T("UnregisterHotKey"));
6636 bool wxWindowMSW::HandleHotKey(WXWPARAM wParam
, WXLPARAM lParam
)
6638 int hotkeyId
= wParam
;
6639 int virtualKey
= HIWORD(lParam
);
6640 int win_modifiers
= LOWORD(lParam
);
6642 wxKeyEvent
event(CreateKeyEvent(wxEVT_HOTKEY
, virtualKey
, wParam
, lParam
));
6643 event
.SetId(hotkeyId
);
6644 event
.m_shiftDown
= (win_modifiers
& MOD_SHIFT
) != 0;
6645 event
.m_controlDown
= (win_modifiers
& MOD_CONTROL
) != 0;
6646 event
.m_altDown
= (win_modifiers
& MOD_ALT
) != 0;
6647 event
.m_metaDown
= (win_modifiers
& MOD_WIN
) != 0;
6649 return GetEventHandler()->ProcessEvent(event
);
6652 #endif // wxUSE_ACCEL
6654 #endif // wxUSE_HOTKEY
6656 // Not tested under WinCE
6659 // this class installs a message hook which really wakes up our idle processing
6660 // each time a WM_NULL is received (wxWakeUpIdle does this), even if we're
6661 // sitting inside a local modal loop (e.g. a menu is opened or scrollbar is
6662 // being dragged or even inside ::MessageBox()) and so don't control message
6663 // dispatching otherwise
6664 class wxIdleWakeUpModule
: public wxModule
6667 virtual bool OnInit()
6669 ms_hMsgHookProc
= ::SetWindowsHookEx
6672 &wxIdleWakeUpModule::MsgHookProc
,
6674 GetCurrentThreadId()
6677 if ( !ms_hMsgHookProc
)
6679 wxLogLastError(_T("SetWindowsHookEx(WH_GETMESSAGE)"));
6687 virtual void OnExit()
6689 ::UnhookWindowsHookEx(wxIdleWakeUpModule::ms_hMsgHookProc
);
6692 static LRESULT CALLBACK
MsgHookProc(int nCode
, WPARAM wParam
, LPARAM lParam
)
6694 MSG
*msg
= (MSG
*)lParam
;
6696 // only process the message if it is actually going to be removed from
6697 // the message queue, this prevents that the same event from being
6698 // processed multiple times if now someone just called PeekMessage()
6699 if ( msg
->message
== WM_NULL
&& wParam
== PM_REMOVE
)
6701 wxTheApp
->ProcessPendingEvents();
6704 return CallNextHookEx(ms_hMsgHookProc
, nCode
, wParam
, lParam
);
6708 static HHOOK ms_hMsgHookProc
;
6710 DECLARE_DYNAMIC_CLASS(wxIdleWakeUpModule
)
6713 HHOOK
wxIdleWakeUpModule::ms_hMsgHookProc
= 0;
6715 IMPLEMENT_DYNAMIC_CLASS(wxIdleWakeUpModule
, wxModule
)
6717 #endif // __WXWINCE__
6722 static void wxAdjustZOrder(wxWindow
* parent
)
6724 if (parent
->IsKindOf(CLASSINFO(wxStaticBox
)))
6726 // Set the z-order correctly
6727 SetWindowPos((HWND
) parent
->GetHWND(), HWND_BOTTOM
, 0, 0, 0, 0, SWP_NOMOVE
|SWP_NOSIZE
);
6730 wxWindowList::compatibility_iterator current
= parent
->GetChildren().GetFirst();
6733 wxWindow
*childWin
= current
->GetData();
6734 wxAdjustZOrder(childWin
);
6735 current
= current
->GetNext();
6740 // We need to adjust the z-order of static boxes in WinCE, to
6741 // make 'contained' controls visible
6742 void wxWindowMSW::OnInitDialog( wxInitDialogEvent
& event
)
6745 wxAdjustZOrder(this);