1
/////////////////////////////////////////////////////////////////////////////
2
// Name: src/msw/windows.cpp
4
// Author: Julian Smart
5
// Modified by: VZ on 13.05.99: no more Default(), MSWOnXXX() reorganisation
7
// RCS-ID: $Id: window.cpp,v 1.638.2.18 2006/04/07 21:32:41 JS Exp $
8
// Copyright: (c) Julian Smart
9
// Licence: wxWindows licence
10
/////////////////////////////////////////////////////////////////////////////
12
// ===========================================================================
14
// ===========================================================================
16
// ---------------------------------------------------------------------------
18
// ---------------------------------------------------------------------------
20
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21
#pragma implementation "window.h"
24
// For compilers that support precompilation, includes "wx.h".
25
#include "wx/wxprec.h"
32
#include "wx/msw/wrapwin.h"
33
#include "wx/window.h"
38
#include "wx/dcclient.h"
39
#include "wx/dcmemory.h"
42
#include "wx/layout.h"
43
#include "wx/dialog.h"
45
#include "wx/listbox.h"
46
#include "wx/button.h"
47
#include "wx/msgdlg.h"
48
#include "wx/settings.h"
49
#include "wx/statbox.h"
53
#if wxUSE_OWNER_DRAWN && !defined(__WXUNIVERSAL__)
54
#include "wx/ownerdrw.h"
57
#include "wx/evtloop.h"
58
#include "wx/module.h"
59
#include "wx/sysopt.h"
61
#if wxUSE_DRAG_AND_DROP
65
#if wxUSE_ACCESSIBILITY
66
#include "wx/access.h"
70
#define WM_GETOBJECT 0x003D
73
#define OBJID_CLIENT 0xFFFFFFFC
77
#include "wx/menuitem.h"
80
#include "wx/msw/private.h"
83
#include "wx/tooltip.h"
91
#include "wx/spinctrl.h"
92
#endif // wxUSE_SPINCTRL
97
#include "wx/textctrl.h"
98
#include "wx/notebook.h"
99
#include "wx/listctrl.h"
103
#if (!defined(__GNUWIN32_OLD__) && !defined(__WXMICROWIN__) /* && !defined(__WXWINCE__) */ ) || defined(__CYGWIN10__)
104
#include <shellapi.h>
105
#include <mmsystem.h>
109
#include <windowsx.h>
112
#include <commctrl.h>
114
#include "wx/msw/missing.h"
116
#if defined(__WXWINCE__)
119
#include <shellapi.h>
121
#include <aygshell.h>
123
#include "wx/msw/wince/missing.h"
126
#if defined(TME_LEAVE) && defined(WM_MOUSELEAVE)
127
#define HAVE_TRACKMOUSEEVENT
128
#endif // everything needed for TrackMouseEvent()
130
// if this is set to 1, we use deferred window sizing to reduce flicker when
131
// resizing complicated window hierarchies, but this can in theory result in
132
// different behaviour than the old code so we keep the possibility to use it
133
// by setting this to 0 (in the future this should be removed completely)
135
#define USE_DEFERRED_SIZING 0
137
#define USE_DEFERRED_SIZING 1
140
// ---------------------------------------------------------------------------
142
// ---------------------------------------------------------------------------
144
#if wxUSE_MENUS_NATIVE
145
wxMenu *wxCurrentPopupMenu = NULL;
146
#endif // wxUSE_MENUS_NATIVE
149
extern wxChar *wxCanvasClassName;
151
extern const wxChar *wxCanvasClassName;
154
// true if we had already created the std colour map, used by
155
// wxGetStdColourMap() and wxWindow::OnSysColourChanged() (FIXME-MT)
156
static bool gs_hasStdCmap = false;
158
// ---------------------------------------------------------------------------
160
// ---------------------------------------------------------------------------
162
// the window proc for all our windows
163
LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message,
164
WPARAM wParam, LPARAM lParam);
168
const wxChar *wxGetMessageName(int message);
171
void wxRemoveHandleAssociation(wxWindowMSW *win);
172
extern void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win);
173
wxWindow *wxFindWinFromHandle(WXHWND hWnd);
175
// get the text metrics for the current font
176
static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win);
179
// find the window for the mouse event at the specified position
180
static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y);
181
#endif // __WXWINCE__
183
// wrapper around BringWindowToTop() API
184
static inline void wxBringWindowToTop(HWND hwnd)
186
#ifdef __WXMICROWIN__
187
// It seems that MicroWindows brings the _parent_ of the window to the top,
188
// which can be the wrong one.
190
// activate (set focus to) specified window
194
// raise top level parent to top of z order
195
if (!::SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE))
197
wxLogLastError(_T("SetWindowPos"));
203
// ensure that all our parent windows have WS_EX_CONTROLPARENT style
204
static void EnsureParentHasControlParentStyle(wxWindow *parent)
207
If we have WS_EX_CONTROLPARENT flag we absolutely *must* set it for our
208
parent as well as otherwise several Win32 functions using
209
GetNextDlgTabItem() to iterate over all controls such as
210
IsDialogMessage() or DefDlgProc() would enter an infinite loop: indeed,
211
all of them iterate over all the controls starting from the currently
212
focused one and stop iterating when they get back to the focus but
213
unless all parents have WS_EX_CONTROLPARENT bit set, they would never
214
get back to the initial (focused) window: as we do have this style,
215
GetNextDlgTabItem() will leave this window and continue in its parent,
216
but if the parent doesn't have it, it wouldn't recurse inside it later
217
on and so wouldn't have a chance of getting back to this window neither.
219
while ( parent && !parent->IsTopLevel() )
221
LONG exStyle = ::GetWindowLong(GetHwndOf(parent), GWL_EXSTYLE);
222
if ( !(exStyle & WS_EX_CONTROLPARENT) )
224
// force the parent to have this style
225
::SetWindowLong(GetHwndOf(parent), GWL_EXSTYLE,
226
exStyle | WS_EX_CONTROLPARENT);
229
parent = parent->GetParent();
233
#endif // !__WXWINCE__
236
// On Windows CE, GetCursorPos can return an error, so use this function
238
bool GetCursorPosWinCE(POINT* pt)
240
if (!GetCursorPos(pt))
242
DWORD pos = GetMessagePos();
250
// ---------------------------------------------------------------------------
252
// ---------------------------------------------------------------------------
254
// in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
256
#ifdef __WXUNIVERSAL__
257
IMPLEMENT_ABSTRACT_CLASS(wxWindowMSW, wxWindowBase)
259
#if wxUSE_EXTENDED_RTTI
261
// windows that are created from a parent window during its Create method, eg. spin controls in a calendar controls
262
// must never been streamed out separately otherwise chaos occurs. Right now easiest is to test for negative ids, as
263
// windows with negative ids never can be recreated anyway
265
bool wxWindowStreamingCallback( const wxObject *object, wxWriter * , wxPersister * , wxxVariantArray & )
267
const wxWindow * win = dynamic_cast<const wxWindow*>(object) ;
268
if ( win && win->GetId() < 0 )
273
IMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxWindow, wxWindowBase,"wx/window.h", wxWindowStreamingCallback)
275
// make wxWindowList known before the property is used
277
wxCOLLECTION_TYPE_INFO( wxWindow* , wxWindowList ) ;
279
template<> void wxCollectionToVariantArray( wxWindowList const &theList, wxxVariantArray &value)
281
wxListCollectionToVariantArray<wxWindowList::compatibility_iterator>( theList , value ) ;
284
WX_DEFINE_FLAGS( wxWindowStyle )
286
wxBEGIN_FLAGS( wxWindowStyle )
287
// new style border flags, we put them first to
288
// use them for streaming out
290
wxFLAGS_MEMBER(wxBORDER_SIMPLE)
291
wxFLAGS_MEMBER(wxBORDER_SUNKEN)
292
wxFLAGS_MEMBER(wxBORDER_DOUBLE)
293
wxFLAGS_MEMBER(wxBORDER_RAISED)
294
wxFLAGS_MEMBER(wxBORDER_STATIC)
295
wxFLAGS_MEMBER(wxBORDER_NONE)
297
// old style border flags
298
wxFLAGS_MEMBER(wxSIMPLE_BORDER)
299
wxFLAGS_MEMBER(wxSUNKEN_BORDER)
300
wxFLAGS_MEMBER(wxDOUBLE_BORDER)
301
wxFLAGS_MEMBER(wxRAISED_BORDER)
302
wxFLAGS_MEMBER(wxSTATIC_BORDER)
303
wxFLAGS_MEMBER(wxBORDER)
305
// standard window styles
306
wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
307
wxFLAGS_MEMBER(wxCLIP_CHILDREN)
308
wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
309
wxFLAGS_MEMBER(wxWANTS_CHARS)
310
wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
311
wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
312
wxFLAGS_MEMBER(wxVSCROLL)
313
wxFLAGS_MEMBER(wxHSCROLL)
315
wxEND_FLAGS( wxWindowStyle )
317
wxBEGIN_PROPERTIES_TABLE(wxWindow)
318
wxEVENT_PROPERTY( Close , wxEVT_CLOSE_WINDOW , wxCloseEvent)
319
wxEVENT_PROPERTY( Create , wxEVT_CREATE , wxWindowCreateEvent )
320
wxEVENT_PROPERTY( Destroy , wxEVT_DESTROY , wxWindowDestroyEvent )
321
// Always constructor Properties first
323
wxREADONLY_PROPERTY( Parent,wxWindow*, GetParent, EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
324
wxPROPERTY( Id,wxWindowID, SetId, GetId, -1 /*wxID_ANY*/ , 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
325
wxPROPERTY( Position,wxPoint, SetPosition , GetPosition, wxDefaultPosition , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // pos
326
wxPROPERTY( Size,wxSize, SetSize, GetSize, wxDefaultSize , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // size
327
wxPROPERTY( WindowStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
329
// Then all relations of the object graph
331
wxREADONLY_PROPERTY_COLLECTION( Children , wxWindowList , wxWindowBase* , GetWindowChildren , wxPROP_OBJECT_GRAPH /*flags*/ , wxT("Helpstring") , wxT("group"))
333
// and finally all other properties
335
wxPROPERTY( ExtraStyle , long , SetExtraStyle , GetExtraStyle , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // extstyle
336
wxPROPERTY( BackgroundColour , wxColour , SetBackgroundColour , GetBackgroundColour , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // bg
337
wxPROPERTY( ForegroundColour , wxColour , SetForegroundColour , GetForegroundColour , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // fg
338
wxPROPERTY( Enabled , bool , Enable , IsEnabled , wxxVariant((bool)true) , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
339
wxPROPERTY( Shown , bool , Show , IsShown , wxxVariant((bool)true) , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
341
// possible property candidates (not in xrc) or not valid in all subclasses
342
wxPROPERTY( Title,wxString, SetTitle, GetTitle, wxEmptyString )
343
wxPROPERTY( Font , wxFont , SetFont , GetWindowFont , )
344
wxPROPERTY( Label,wxString, SetLabel, GetLabel, wxEmptyString )
345
// MaxHeight, Width , MinHeight , Width
346
// TODO switch label to control and title to toplevels
348
wxPROPERTY( ThemeEnabled , bool , SetThemeEnabled , GetThemeEnabled , )
349
//wxPROPERTY( Cursor , wxCursor , SetCursor , GetCursor , )
350
// wxPROPERTY( ToolTip , wxString , SetToolTip , GetToolTipText , )
351
wxPROPERTY( AutoLayout , bool , SetAutoLayout , GetAutoLayout , )
356
wxEND_PROPERTIES_TABLE()
358
wxBEGIN_HANDLERS_TABLE(wxWindow)
359
wxEND_HANDLERS_TABLE()
361
wxCONSTRUCTOR_DUMMY(wxWindow)
364
IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
366
#endif // __WXUNIVERSAL__/__WXMSW__
368
BEGIN_EVENT_TABLE(wxWindowMSW, wxWindowBase)
369
EVT_SYS_COLOUR_CHANGED(wxWindowMSW::OnSysColourChanged)
370
EVT_ERASE_BACKGROUND(wxWindowMSW::OnEraseBackground)
372
EVT_INIT_DIALOG(wxWindowMSW::OnInitDialog)
376
// ===========================================================================
378
// ===========================================================================
380
// ---------------------------------------------------------------------------
381
// wxWindow utility functions
382
// ---------------------------------------------------------------------------
384
// Find an item given the MS Windows id
385
wxWindow *wxWindowMSW::FindItem(long id) const
388
wxControl *item = wxDynamicCastThis(wxControl);
391
// is it we or one of our "internal" children?
392
if ( item->GetId() == id
393
#ifndef __WXUNIVERSAL__
394
|| (item->GetSubcontrols().Index(id) != wxNOT_FOUND)
395
#endif // __WXUNIVERSAL__
401
#endif // wxUSE_CONTROLS
403
wxWindowList::compatibility_iterator current = GetChildren().GetFirst();
406
wxWindow *childWin = current->GetData();
408
wxWindow *wnd = childWin->FindItem(id);
412
current = current->GetNext();
418
// Find an item given the MS Windows handle
419
wxWindow *wxWindowMSW::FindItemByHWND(WXHWND hWnd, bool controlOnly) const
421
wxWindowList::compatibility_iterator current = GetChildren().GetFirst();
424
wxWindow *parent = current->GetData();
426
// Do a recursive search.
427
wxWindow *wnd = parent->FindItemByHWND(hWnd);
433
|| parent->IsKindOf(CLASSINFO(wxControl))
434
#endif // wxUSE_CONTROLS
437
wxWindow *item = current->GetData();
438
if ( item->GetHWND() == hWnd )
442
if ( item->ContainsHWND(hWnd) )
447
current = current->GetNext();
452
// Default command handler
453
bool wxWindowMSW::MSWCommand(WXUINT WXUNUSED(param), WXWORD WXUNUSED(id))
458
// ----------------------------------------------------------------------------
459
// constructors and such
460
// ----------------------------------------------------------------------------
462
void wxWindowMSW::Init()
465
m_isBeingDeleted = false;
467
m_mouseInWindow = false;
468
m_lastKeydownProcessed = false;
470
m_childrenDisabled = NULL;
479
#if wxUSE_MOUSEEVENT_HACK
482
m_lastMouseEvent = -1;
483
#endif // wxUSE_MOUSEEVENT_HACK
485
m_pendingPosition = wxDefaultPosition;
486
m_pendingSize = wxDefaultSize;
489
m_contextMenuEnabled = false;
494
wxWindowMSW::~wxWindowMSW()
496
m_isBeingDeleted = true;
498
#ifndef __WXUNIVERSAL__
499
// VS: make sure there's no wxFrame with last focus set to us:
500
for ( wxWindow *win = GetParent(); win; win = win->GetParent() )
502
wxTopLevelWindow *frame = wxDynamicCast(win, wxTopLevelWindow);
505
if ( frame->GetLastFocus() == this )
507
frame->SetLastFocus(NULL);
510
// apparently sometimes we can end up with our grand parent
511
// pointing to us as well: this is surely a bug in focus handling
512
// code but it's not clear where it happens so for now just try to
513
// fix it here by not breaking out of the loop
517
#endif // __WXUNIVERSAL__
519
// VS: destroy children first and _then_ detach *this from its parent.
520
// If we'd do it the other way around, children wouldn't be able
521
// find their parent frame (see above).
526
// VZ: test temp removed to understand what really happens here
527
//if (::IsWindow(GetHwnd()))
529
if ( !::DestroyWindow(GetHwnd()) )
530
wxLogLastError(wxT("DestroyWindow"));
533
// remove hWnd <-> wxWindow association
534
wxRemoveHandleAssociation(this);
537
delete m_childrenDisabled;
541
// real construction (Init() must have been called before!)
542
bool wxWindowMSW::Create(wxWindow *parent,
547
const wxString& name)
549
wxCHECK_MSG( parent, false, wxT("can't create wxWindow without parent") );
551
if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) )
554
parent->AddChild(this);
557
DWORD msflags = MSWGetCreateWindowFlags(&exstyle);
559
#ifdef __WXUNIVERSAL__
560
// no borders, we draw them ourselves
561
exstyle &= ~(WS_EX_DLGMODALFRAME |
565
msflags &= ~WS_BORDER;
566
#endif // wxUniversal
570
msflags |= WS_VISIBLE;
573
if ( !MSWCreate(wxCanvasClassName, NULL, pos, size, msflags, exstyle) )
581
// ---------------------------------------------------------------------------
583
// ---------------------------------------------------------------------------
585
void wxWindowMSW::SetFocus()
587
HWND hWnd = GetHwnd();
588
wxCHECK_RET( hWnd, _T("can't set focus to invalid window") );
590
#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
594
if ( !::SetFocus(hWnd) )
596
#if defined(__WXDEBUG__) && !defined(__WXMICROWIN__)
597
// was there really an error?
598
DWORD dwRes = ::GetLastError();
601
HWND hwndFocus = ::GetFocus();
602
if ( hwndFocus != hWnd )
604
wxLogApiError(_T("SetFocus"), dwRes);
611
void wxWindowMSW::SetFocusFromKbd()
613
// when the focus is given to the control with DLGC_HASSETSEL style from
614
// keyboard its contents should be entirely selected: this is what
615
// ::IsDialogMessage() does and so we should do it as well to provide the
616
// same LNF as the native programs
617
if ( ::SendMessage(GetHwnd(), WM_GETDLGCODE, 0, 0) & DLGC_HASSETSEL )
619
::SendMessage(GetHwnd(), EM_SETSEL, 0, -1);
622
// do this after (maybe) setting the selection as like this when
623
// wxEVT_SET_FOCUS handler is called, the selection would have been already
624
// set correctly -- this may be important
625
wxWindowBase::SetFocusFromKbd();
628
// Get the window with the focus
629
wxWindow *wxWindowBase::DoFindFocus()
631
HWND hWnd = ::GetFocus();
634
return wxGetWindowFromHWND((WXHWND)hWnd);
640
bool wxWindowMSW::Enable(bool enable)
642
if ( !wxWindowBase::Enable(enable) )
645
HWND hWnd = GetHwnd();
647
::EnableWindow(hWnd, (BOOL)enable);
649
// the logic below doesn't apply to the top level windows -- otherwise
650
// showing a modal dialog would result in total greying out (and ungreying
651
// out later) of everything which would be really ugly
655
// when the parent is disabled, all of its children should be disabled as
656
// well but when it is enabled back, only those of the children which
657
// hadn't been already disabled in the beginning should be enabled again,
658
// so we have to keep the list of those children
659
for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
661
node = node->GetNext() )
663
wxWindow *child = node->GetData();
664
if ( child->IsTopLevel() )
666
// the logic below doesn't apply to top level children
672
// enable the child back unless it had been disabled before us
673
if ( !m_childrenDisabled || !m_childrenDisabled->Find(child) )
676
else // we're being disabled
678
if ( child->IsEnabled() )
680
// disable it as children shouldn't stay enabled while the
684
else // child already disabled, remember it
686
// have we created the list of disabled children already?
687
if ( !m_childrenDisabled )
688
m_childrenDisabled = new wxWindowList;
690
m_childrenDisabled->Append(child);
695
if ( enable && m_childrenDisabled )
697
// we don't need this list any more, don't keep unused memory
698
delete m_childrenDisabled;
699
m_childrenDisabled = NULL;
705
bool wxWindowMSW::Show(bool show)
707
if ( !wxWindowBase::Show(show) )
710
HWND hWnd = GetHwnd();
711
int cshow = show ? SW_SHOW : SW_HIDE;
712
::ShowWindow(hWnd, cshow);
714
if ( show && IsTopLevel() )
716
wxBringWindowToTop(hWnd);
722
// Raise the window to the top of the Z order
723
void wxWindowMSW::Raise()
725
wxBringWindowToTop(GetHwnd());
728
// Lower the window to the bottom of the Z order
729
void wxWindowMSW::Lower()
731
::SetWindowPos(GetHwnd(), HWND_BOTTOM, 0, 0, 0, 0,
732
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
735
void wxWindowMSW::SetTitle( const wxString& title)
737
SetWindowText(GetHwnd(), title.c_str());
740
wxString wxWindowMSW::GetTitle() const
742
return wxGetWindowText(GetHWND());
745
void wxWindowMSW::DoCaptureMouse()
747
HWND hWnd = GetHwnd();
754
void wxWindowMSW::DoReleaseMouse()
756
if ( !::ReleaseCapture() )
758
wxLogLastError(_T("ReleaseCapture"));
762
/* static */ wxWindow *wxWindowBase::GetCapture()
764
HWND hwnd = ::GetCapture();
765
return hwnd ? wxFindWinFromHandle((WXHWND)hwnd) : (wxWindow *)NULL;
768
bool wxWindowMSW::SetFont(const wxFont& font)
770
if ( !wxWindowBase::SetFont(font) )
776
HWND hWnd = GetHwnd();
779
WXHANDLE hFont = m_font.GetResourceHandle();
781
wxASSERT_MSG( hFont, wxT("should have valid font") );
783
::SendMessage(hWnd, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
788
bool wxWindowMSW::SetCursor(const wxCursor& cursor)
790
if ( !wxWindowBase::SetCursor(cursor) )
798
HWND hWnd = GetHwnd();
800
// Change the cursor NOW if we're within the correct window
803
::GetCursorPosWinCE(&point);
805
::GetCursorPos(&point);
808
RECT rect = wxGetWindowRect(hWnd);
810
if ( ::PtInRect(&rect, point) && !wxIsBusy() )
811
::SetCursor(GetHcursorOf(m_cursor));
817
void wxWindowMSW::WarpPointer(int x, int y)
819
ClientToScreen(&x, &y);
821
if ( !::SetCursorPos(x, y) )
823
wxLogLastError(_T("SetCursorPos"));
827
void wxWindowMSW::MSWUpdateUIState()
829
// WM_CHANGEUISTATE only appeared in Windows 2000 so it can do us no good
830
// to use it on older systems -- and could possibly do some harm
831
static int s_needToUpdate = -1;
832
if ( s_needToUpdate == -1 )
835
s_needToUpdate = wxGetOsVersion(&verMaj, &verMin) == wxWINDOWS_NT &&
839
if ( s_needToUpdate )
841
// we send WM_CHANGEUISTATE so if nothing needs changing then the system
842
// won't send WM_UPDATEUISTATE
843
::SendMessage(GetHwnd(), WM_CHANGEUISTATE,
844
MAKEWPARAM(UIS_CLEAR, UISF_HIDEFOCUS), 0);
848
// ---------------------------------------------------------------------------
850
// ---------------------------------------------------------------------------
852
inline int GetScrollPosition(HWND hWnd, int wOrient)
854
#ifdef __WXMICROWIN__
855
return ::GetScrollPosWX(hWnd, wOrient);
857
WinStruct<SCROLLINFO> scrollInfo;
858
scrollInfo.cbSize = sizeof(SCROLLINFO);
859
scrollInfo.fMask = SIF_POS;
860
::GetScrollInfo(hWnd, wOrient, &scrollInfo);
862
return scrollInfo.nPos;
866
int wxWindowMSW::GetScrollPos(int orient) const
868
HWND hWnd = GetHwnd();
869
wxCHECK_MSG( hWnd, 0, _T("no HWND in GetScrollPos") );
871
return GetScrollPosition(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT);
874
// This now returns the whole range, not just the number
875
// of positions that we can scroll.
876
int wxWindowMSW::GetScrollRange(int orient) const
879
HWND hWnd = GetHwnd();
883
::GetScrollRange(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
886
WinStruct<SCROLLINFO> scrollInfo;
887
scrollInfo.fMask = SIF_RANGE;
888
if ( !::GetScrollInfo(hWnd,
889
orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
892
// Most of the time this is not really an error, since the return
893
// value can also be zero when there is no scrollbar yet.
894
// wxLogLastError(_T("GetScrollInfo"));
896
maxPos = scrollInfo.nMax;
898
// undo "range - 1" done in SetScrollbar()
902
int wxWindowMSW::GetScrollThumb(int orient) const
904
return orient == wxHORIZONTAL ? m_xThumbSize : m_yThumbSize;
907
void wxWindowMSW::SetScrollPos(int orient, int pos, bool refresh)
909
HWND hWnd = GetHwnd();
910
wxCHECK_RET( hWnd, _T("SetScrollPos: no HWND") );
912
WinStruct<SCROLLINFO> info;
916
info.fMask = SIF_POS;
917
if ( HasFlag(wxALWAYS_SHOW_SB) )
919
// disable scrollbar instead of removing it then
920
info.fMask |= SIF_DISABLENOSCROLL;
923
::SetScrollInfo(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
927
// New function that will replace some of the above.
928
void wxWindowMSW::SetScrollbar(int orient,
934
WinStruct<SCROLLINFO> info;
935
info.nPage = pageSize;
936
info.nMin = 0; // range is nMax - nMin + 1
937
info.nMax = range - 1; // as both nMax and nMax are inclusive
939
info.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
940
if ( HasFlag(wxALWAYS_SHOW_SB) )
942
// disable scrollbar instead of removing it then
943
info.fMask |= SIF_DISABLENOSCROLL;
946
HWND hWnd = GetHwnd();
949
// We have to set the variables here to make them valid in events
950
// triggered by ::SetScrollInfo()
951
*(orient == wxHORIZONTAL ? &m_xThumbSize : &m_yThumbSize) = pageSize;
953
::SetScrollInfo(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
958
void wxWindowMSW::ScrollWindow(int dx, int dy, const wxRect *prect)
964
rect.left = prect->x;
966
rect.right = prect->x + prect->width;
967
rect.bottom = prect->y + prect->height;
977
// FIXME: is this the exact equivalent of the line below?
978
::ScrollWindowEx(GetHwnd(), dx, dy, pr, pr, 0, 0, SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
980
::ScrollWindow(GetHwnd(), dx, dy, pr, pr);
984
static bool ScrollVertically(HWND hwnd, int kind, int count)
986
int posStart = GetScrollPosition(hwnd, SB_VERT);
989
for ( int n = 0; n < count; n++ )
991
::SendMessage(hwnd, WM_VSCROLL, kind, 0);
993
int posNew = GetScrollPosition(hwnd, SB_VERT);
996
// don't bother to continue, we're already at top/bottom
1003
return pos != posStart;
1006
bool wxWindowMSW::ScrollLines(int lines)
1008
bool down = lines > 0;
1010
return ScrollVertically(GetHwnd(),
1011
down ? SB_LINEDOWN : SB_LINEUP,
1012
down ? lines : -lines);
1015
bool wxWindowMSW::ScrollPages(int pages)
1017
bool down = pages > 0;
1019
return ScrollVertically(GetHwnd(),
1020
down ? SB_PAGEDOWN : SB_PAGEUP,
1021
down ? pages : -pages);
1024
// ---------------------------------------------------------------------------
1026
// ---------------------------------------------------------------------------
1028
void wxWindowMSW::SubclassWin(WXHWND hWnd)
1030
wxASSERT_MSG( !m_oldWndProc, wxT("subclassing window twice?") );
1032
HWND hwnd = (HWND)hWnd;
1033
wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in SubclassWin") );
1035
wxAssociateWinWithHandle(hwnd, this);
1037
m_oldWndProc = (WXFARPROC)wxGetWindowProc((HWND)hWnd);
1039
// we don't need to subclass the window of our own class (in the Windows
1040
// sense of the word)
1041
if ( !wxCheckWindowWndProc(hWnd, (WXFARPROC)wxWndProc) )
1043
wxSetWindowProc(hwnd, wxWndProc);
1047
// don't bother restoring it neither: this also makes it easy to
1048
// implement IsOfStandardClass() method which returns true for the
1049
// standard controls and false for the wxWidgets own windows as it can
1050
// simply check m_oldWndProc
1051
m_oldWndProc = NULL;
1055
void wxWindowMSW::UnsubclassWin()
1057
wxRemoveHandleAssociation(this);
1059
// Restore old Window proc
1060
HWND hwnd = GetHwnd();
1065
wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in UnsubclassWin") );
1069
if ( !wxCheckWindowWndProc((WXHWND)hwnd, m_oldWndProc) )
1071
wxSetWindowProc(hwnd, (WNDPROC)m_oldWndProc);
1074
m_oldWndProc = NULL;
1079
void wxWindowMSW::AssociateHandle(WXWidget handle)
1083
if ( !::DestroyWindow(GetHwnd()) )
1084
wxLogLastError(wxT("DestroyWindow"));
1087
WXHWND wxhwnd = (WXHWND)handle;
1090
SubclassWin(wxhwnd);
1093
void wxWindowMSW::DissociateHandle()
1095
// this also calls SetHWND(0) for us
1100
bool wxCheckWindowWndProc(WXHWND hWnd,
1101
WXFARPROC WXUNUSED(wndProc))
1103
// TODO: This list of window class names should be factored out so they can be
1104
// managed in one place and then accessed from here and other places, such as
1105
// wxApp::RegisterWindowClasses() and wxApp::UnregisterWindowClasses()
1108
extern wxChar *wxCanvasClassName;
1109
extern wxChar *wxCanvasClassNameNR;
1111
extern const wxChar *wxCanvasClassName;
1112
extern const wxChar *wxCanvasClassNameNR;
1114
extern const wxChar *wxMDIFrameClassName;
1115
extern const wxChar *wxMDIFrameClassNameNoRedraw;
1116
extern const wxChar *wxMDIChildFrameClassName;
1117
extern const wxChar *wxMDIChildFrameClassNameNoRedraw;
1118
wxString str(wxGetWindowClass(hWnd));
1119
if (str == wxCanvasClassName ||
1120
str == wxCanvasClassNameNR ||
1122
str == _T("wxGLCanvasClass") ||
1123
str == _T("wxGLCanvasClassNR") ||
1124
#endif // wxUSE_GLCANVAS
1125
str == wxMDIFrameClassName ||
1126
str == wxMDIFrameClassNameNoRedraw ||
1127
str == wxMDIChildFrameClassName ||
1128
str == wxMDIChildFrameClassNameNoRedraw ||
1129
str == _T("wxTLWHiddenParent"))
1130
return true; // Effectively means don't subclass
1135
// ----------------------------------------------------------------------------
1137
// ----------------------------------------------------------------------------
1139
void wxWindowMSW::SetWindowStyleFlag(long flags)
1141
long flagsOld = GetWindowStyleFlag();
1142
if ( flags == flagsOld )
1145
// update the internal variable
1146
wxWindowBase::SetWindowStyleFlag(flags);
1148
// now update the Windows style as well if needed - and if the window had
1149
// been already created
1153
WXDWORD exstyle, exstyleOld;
1154
long style = MSWGetStyle(flags, &exstyle),
1155
styleOld = MSWGetStyle(flagsOld, &exstyleOld);
1157
if ( style != styleOld )
1159
// some flags (e.g. WS_VISIBLE or WS_DISABLED) should not be changed by
1160
// this function so instead of simply setting the style to the new
1161
// value we clear the bits which were set in styleOld but are set in
1162
// the new one and set the ones which were not set before
1163
long styleReal = ::GetWindowLong(GetHwnd(), GWL_STYLE);
1164
styleReal &= ~styleOld;
1167
::SetWindowLong(GetHwnd(), GWL_STYLE, styleReal);
1170
// and the extended style
1171
if ( exstyle != exstyleOld )
1173
long exstyleReal = ::GetWindowLong(GetHwnd(), GWL_EXSTYLE);
1174
exstyleReal &= ~exstyleOld;
1175
exstyleReal |= exstyle;
1177
::SetWindowLong(GetHwnd(), GWL_EXSTYLE, exstyleReal);
1179
// we must call SetWindowPos() to flush the cached extended style and
1180
// also to make the change to wxSTAY_ON_TOP style take effect: just
1181
// setting the style simply doesn't work
1182
if ( !::SetWindowPos(GetHwnd(),
1183
exstyleReal & WS_EX_TOPMOST ? HWND_TOPMOST
1186
SWP_NOMOVE | SWP_NOSIZE) )
1188
wxLogLastError(_T("SetWindowPos"));
1193
WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const
1195
// translate common wxWidgets styles to Windows ones
1197
// most of windows are child ones, those which are not (such as
1198
// wxTopLevelWindow) should remove WS_CHILD in their MSWGetStyle()
1199
WXDWORD style = WS_CHILD;
1201
// using this flag results in very significant reduction in flicker,
1202
// especially with controls inside the static boxes (as the interior of the
1203
// box is not redrawn twice).but sometimes results in redraw problems, so
1204
// optionally allow the old code to continue to use it provided a special
1205
// system option is turned on
1206
if ( !wxSystemOptions::GetOptionInt(wxT("msw.window.no-clip-children"))
1207
|| (flags & wxCLIP_CHILDREN) )
1208
style |= WS_CLIPCHILDREN;
1210
// it doesn't seem useful to use WS_CLIPSIBLINGS here as we officially
1211
// don't support overlapping windows and it only makes sense for them and,
1212
// presumably, gives the system some extra work (to manage more clipping
1213
// regions), so avoid it alltogether
1216
if ( flags & wxVSCROLL )
1217
style |= WS_VSCROLL;
1219
if ( flags & wxHSCROLL )
1220
style |= WS_HSCROLL;
1222
const wxBorder border = GetBorder(flags);
1224
// WS_BORDER is only required for wxBORDER_SIMPLE
1225
if ( border == wxBORDER_SIMPLE )
1228
// now deal with ext style if the caller wants it
1234
if ( flags & wxTRANSPARENT_WINDOW )
1235
*exstyle |= WS_EX_TRANSPARENT;
1241
case wxBORDER_DEFAULT:
1242
wxFAIL_MSG( _T("unknown border style") );
1246
case wxBORDER_SIMPLE:
1249
case wxBORDER_STATIC:
1250
*exstyle |= WS_EX_STATICEDGE;
1253
case wxBORDER_RAISED:
1254
*exstyle |= WS_EX_DLGMODALFRAME;
1257
case wxBORDER_SUNKEN:
1258
*exstyle |= WS_EX_CLIENTEDGE;
1259
style &= ~WS_BORDER;
1262
case wxBORDER_DOUBLE:
1263
*exstyle |= WS_EX_DLGMODALFRAME;
1267
// wxUniv doesn't use Windows dialog navigation functions at all
1268
#if !defined(__WXUNIVERSAL__) && !defined(__WXWINCE__)
1269
// to make the dialog navigation work with the nested panels we must
1270
// use this style (top level windows such as dialogs don't need it)
1271
if ( (flags & wxTAB_TRAVERSAL) && !IsTopLevel() )
1273
*exstyle |= WS_EX_CONTROLPARENT;
1275
#endif // __WXUNIVERSAL__
1281
// Setup background and foreground colours correctly
1282
void wxWindowMSW::SetupColours()
1285
SetBackgroundColour(GetParent()->GetBackgroundColour());
1288
bool wxWindowMSW::IsMouseInWindow() const
1290
// get the mouse position
1293
::GetCursorPosWinCE(&pt);
1295
::GetCursorPos(&pt);
1298
// find the window which currently has the cursor and go up the window
1299
// chain until we find this window - or exhaust it
1300
HWND hwnd = ::WindowFromPoint(pt);
1301
while ( hwnd && (hwnd != GetHwnd()) )
1302
hwnd = ::GetParent(hwnd);
1304
return hwnd != NULL;
1307
void wxWindowMSW::OnInternalIdle()
1309
#ifndef HAVE_TRACKMOUSEEVENT
1310
// Check if we need to send a LEAVE event
1311
if ( m_mouseInWindow )
1313
// note that we should generate the leave event whether the window has
1314
// or doesn't have mouse capture
1315
if ( !IsMouseInWindow() )
1317
GenerateMouseLeave();
1320
#endif // !HAVE_TRACKMOUSEEVENT
1322
if (wxUpdateUIEvent::CanUpdate(this))
1323
UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
1326
// Set this window to be the child of 'parent'.
1327
bool wxWindowMSW::Reparent(wxWindowBase *parent)
1329
if ( !wxWindowBase::Reparent(parent) )
1332
HWND hWndChild = GetHwnd();
1333
HWND hWndParent = GetParent() ? GetWinHwnd(GetParent()) : (HWND)0;
1335
::SetParent(hWndChild, hWndParent);
1338
if ( ::GetWindowLong(hWndChild, GWL_EXSTYLE) & WS_EX_CONTROLPARENT )
1340
EnsureParentHasControlParentStyle(GetParent());
1342
#endif // !__WXWINCE__
1347
static inline void SendSetRedraw(HWND hwnd, bool on)
1349
#ifndef __WXMICROWIN__
1350
::SendMessage(hwnd, WM_SETREDRAW, (WPARAM)on, 0);
1354
void wxWindowMSW::Freeze()
1356
if ( !m_frozenness++ )
1359
SendSetRedraw(GetHwnd(), false);
1363
void wxWindowMSW::Thaw()
1365
wxASSERT_MSG( m_frozenness > 0, _T("Thaw() without matching Freeze()") );
1367
if ( !--m_frozenness )
1371
SendSetRedraw(GetHwnd(), true);
1373
// we need to refresh everything or otherwise the invalidated area
1374
// is not going to be repainted
1380
void wxWindowMSW::Refresh(bool eraseBack, const wxRect *rect)
1382
HWND hWnd = GetHwnd();
1389
mswRect.left = rect->x;
1390
mswRect.top = rect->y;
1391
mswRect.right = rect->x + rect->width;
1392
mswRect.bottom = rect->y + rect->height;
1401
// RedrawWindow not available on SmartPhone or eVC++ 3
1402
#if !defined(__SMARTPHONE__) && !(defined(_WIN32_WCE) && _WIN32_WCE < 400)
1403
UINT flags = RDW_INVALIDATE | RDW_ALLCHILDREN;
1407
::RedrawWindow(hWnd, pRect, NULL, flags);
1409
::InvalidateRect(hWnd, pRect, eraseBack);
1414
void wxWindowMSW::Update()
1416
if ( !::UpdateWindow(GetHwnd()) )
1418
wxLogLastError(_T("UpdateWindow"));
1421
#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
1422
// just calling UpdateWindow() is not enough, what we did in our WM_PAINT
1423
// handler needs to be really drawn right now
1428
// ---------------------------------------------------------------------------
1430
// ---------------------------------------------------------------------------
1433
#if wxUSE_DRAG_AND_DROP
1434
void wxWindowMSW::SetDropTarget(wxDropTarget *pDropTarget)
1436
if ( m_dropTarget != 0 ) {
1437
m_dropTarget->Revoke(m_hWnd);
1438
delete m_dropTarget;
1441
m_dropTarget = pDropTarget;
1442
if ( m_dropTarget != 0 )
1443
m_dropTarget->Register(m_hWnd);
1445
#endif // wxUSE_DRAG_AND_DROP
1447
// old style file-manager drag&drop support: we retain the old-style
1448
// DragAcceptFiles in parallel with SetDropTarget.
1449
void wxWindowMSW::DragAcceptFiles(bool WXUNUSED_IN_WINCE(accept))
1452
HWND hWnd = GetHwnd();
1454
::DragAcceptFiles(hWnd, (BOOL)accept);
1458
// ----------------------------------------------------------------------------
1460
// ----------------------------------------------------------------------------
1464
void wxWindowMSW::DoSetToolTip(wxToolTip *tooltip)
1466
wxWindowBase::DoSetToolTip(tooltip);
1469
m_tooltip->SetWindow((wxWindow *)this);
1472
#endif // wxUSE_TOOLTIPS
1474
// ---------------------------------------------------------------------------
1475
// moving and resizing
1476
// ---------------------------------------------------------------------------
1478
bool wxWindowMSW::IsSizeDeferred() const
1480
#if USE_DEFERRED_SIZING
1481
if ( m_pendingPosition != wxDefaultPosition ||
1482
m_pendingSize != wxDefaultSize )
1484
#endif // USE_DEFERRED_SIZING
1490
void wxWindowMSW::DoGetSize(int *x, int *y) const
1492
// if SetSize() had been called at wx level but not realized at Windows
1493
// level yet (i.e. EndDeferWindowPos() not called), we still should return
1494
// the new and not the old position to the other wx code
1495
if ( m_pendingSize != wxDefaultSize )
1498
*x = m_pendingSize.x;
1500
*y = m_pendingSize.y;
1502
else // use current size
1504
RECT rect = wxGetWindowRect(GetHwnd());
1507
*x = rect.right - rect.left;
1509
*y = rect.bottom - rect.top;
1513
// Get size *available for subwindows* i.e. excluding menu bar etc.
1514
void wxWindowMSW::DoGetClientSize(int *x, int *y) const
1516
#if USE_DEFERRED_SIZING
1517
if ( IsTopLevel() || m_pendingSize == wxDefaultSize )
1520
// top level windows resizing is never deferred, so we can safely use
1521
// the current size here
1522
RECT rect = wxGetClientRect(GetHwnd());
1529
#if USE_DEFERRED_SIZING
1530
else // non top level and using deferred sizing
1532
// we need to calculate the *pending* client size here
1534
rect.left = m_pendingPosition.x;
1535
rect.top = m_pendingPosition.y;
1536
rect.right = rect.left + m_pendingSize.x;
1537
rect.bottom = rect.top + m_pendingSize.y;
1539
::SendMessage(GetHwnd(), WM_NCCALCSIZE, FALSE, (LPARAM)&rect);
1542
*x = rect.right - rect.left;
1544
*y = rect.bottom - rect.top;
1549
void wxWindowMSW::DoGetPosition(int *x, int *y) const
1551
wxWindow * const parent = GetParent();
1554
if ( m_pendingPosition != wxDefaultPosition )
1556
pos = m_pendingPosition;
1558
else // use current position
1560
RECT rect = wxGetWindowRect(GetHwnd());
1563
point.x = rect.left;
1566
// we do the adjustments with respect to the parent only for the "real"
1567
// children, not for the dialogs/frames
1568
if ( !IsTopLevel() )
1570
// Since we now have the absolute screen coords, if there's a
1571
// parent we must subtract its top left corner
1574
::ScreenToClient(GetHwndOf(parent), &point);
1582
// we also must adjust by the client area offset: a control which is just
1583
// under a toolbar could be at (0, 30) in Windows but at (0, 0) in wx
1584
if ( parent && !IsTopLevel() )
1586
const wxPoint pt(parent->GetClientAreaOrigin());
1597
void wxWindowMSW::DoScreenToClient(int *x, int *y) const
1605
::ScreenToClient(GetHwnd(), &pt);
1613
void wxWindowMSW::DoClientToScreen(int *x, int *y) const
1621
::ClientToScreen(GetHwnd(), &pt);
1630
wxWindowMSW::DoMoveSibling(WXHWND hwnd, int x, int y, int width, int height)
1632
#if USE_DEFERRED_SIZING
1633
// if our parent had prepared a defer window handle for us, use it (unless
1634
// we are a top level window)
1635
wxWindowMSW * const parent = IsTopLevel() ? NULL : GetParent();
1637
HDWP hdwp = parent ? (HDWP)parent->m_hDWP : NULL;
1640
hdwp = ::DeferWindowPos(hdwp, (HWND)hwnd, NULL, x, y, width, height,
1641
SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE);
1644
wxLogLastError(_T("DeferWindowPos"));
1650
// hdwp must be updated as it may have been changed
1651
parent->m_hDWP = (WXHANDLE)hdwp;
1656
// did deferred move, remember new coordinates of the window as they're
1657
// different from what Windows would return for it
1661
// otherwise (or if deferring failed) move the window in place immediately
1662
#endif // USE_DEFERRED_SIZING
1663
if ( !::MoveWindow((HWND)hwnd, x, y, width, height, IsShown()) )
1665
wxLogLastError(wxT("MoveWindow"));
1668
// if USE_DEFERRED_SIZING, indicates that we didn't use deferred move,
1669
// ignored otherwise
1673
void wxWindowMSW::DoMoveWindow(int x, int y, int width, int height)
1675
// TODO: is this consistent with other platforms?
1676
// Still, negative width or height shouldn't be allowed
1682
if ( DoMoveSibling(m_hWnd, x, y, width, height) )
1684
#if USE_DEFERRED_SIZING
1685
m_pendingPosition = wxPoint(x, y);
1686
m_pendingSize = wxSize(width, height);
1687
#endif // USE_DEFERRED_SIZING
1691
// set the size of the window: if the dimensions are positive, just use them,
1692
// but if any of them is equal to -1, it means that we must find the value for
1693
// it ourselves (unless sizeFlags contains wxSIZE_ALLOW_MINUS_ONE flag, in
1694
// which case -1 is a valid value for x and y)
1696
// If sizeFlags contains wxSIZE_AUTO_WIDTH/HEIGHT flags (default), we calculate
1697
// the width/height to best suit our contents, otherwise we reuse the current
1699
void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags)
1701
// get the current size and position...
1702
int currentX, currentY;
1703
int currentW, currentH;
1705
GetPosition(¤tX, ¤tY);
1706
GetSize(¤tW, ¤tH);
1708
// ... and don't do anything (avoiding flicker) if it's already ok unless
1709
// we're forced to resize the window
1710
if ( x == currentX && y == currentY &&
1711
width == currentW && height == currentH &&
1712
!(sizeFlags & wxSIZE_FORCE) )
1717
if ( x == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
1719
if ( y == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
1722
AdjustForParentClientOrigin(x, y, sizeFlags);
1724
wxSize size = wxDefaultSize;
1725
if ( width == wxDefaultCoord )
1727
if ( sizeFlags & wxSIZE_AUTO_WIDTH )
1729
size = DoGetBestSize();
1734
// just take the current one
1739
if ( height == wxDefaultCoord )
1741
if ( sizeFlags & wxSIZE_AUTO_HEIGHT )
1743
if ( size.x == wxDefaultCoord )
1745
size = DoGetBestSize();
1747
//else: already called DoGetBestSize() above
1753
// just take the current one
1758
DoMoveWindow(x, y, width, height);
1761
void wxWindowMSW::DoSetClientSize(int width, int height)
1763
// setting the client size is less obvious than it it could have been
1764
// because in the result of changing the total size the window scrollbar
1765
// may [dis]appear and/or its menubar may [un]wrap and so the client size
1766
// will not be correct as the difference between the total and client size
1767
// changes - so we keep changing it until we get it right
1769
// normally this loop shouldn't take more than 3 iterations (usually 1 but
1770
// if scrollbars [dis]appear as the result of the first call, then 2 and it
1771
// may become 3 if the window had 0 size originally and so we didn't
1772
// calculate the scrollbar correction correctly during the first iteration)
1773
// but just to be on the safe side we check for it instead of making it an
1774
// "infinite" loop (i.e. leaving break inside as the only way to get out)
1775
for ( int i = 0; i < 4; i++ )
1778
::GetClientRect(GetHwnd(), &rectClient);
1780
// if the size is already ok, stop here (NB: rectClient.left = top = 0)
1781
if ( (rectClient.right == width || width == wxDefaultCoord) &&
1782
(rectClient.bottom == height || height == wxDefaultCoord) )
1787
// Find the difference between the entire window (title bar and all)
1788
// and the client area; add this to the new client size to move the
1791
::GetWindowRect(GetHwnd(), &rectWin);
1793
const int widthWin = rectWin.right - rectWin.left,
1794
heightWin = rectWin.bottom - rectWin.top;
1796
// MoveWindow positions the child windows relative to the parent, so
1797
// adjust if necessary
1798
if ( !IsTopLevel() )
1800
wxWindow *parent = GetParent();
1803
::ScreenToClient(GetHwndOf(parent), (POINT *)&rectWin);
1807
// don't call DoMoveWindow() because we want to move window immediately
1808
// and not defer it here
1809
if ( !::MoveWindow(GetHwnd(),
1812
width + widthWin - rectClient.right,
1813
height + heightWin - rectClient.bottom,
1816
wxLogLastError(_T("MoveWindow"));
1821
// ---------------------------------------------------------------------------
1823
// ---------------------------------------------------------------------------
1825
int wxWindowMSW::GetCharHeight() const
1827
return wxGetTextMetrics(this).tmHeight;
1830
int wxWindowMSW::GetCharWidth() const
1832
// +1 is needed because Windows apparently adds it when calculating the
1833
// dialog units size in pixels
1834
#if wxDIALOG_UNIT_COMPATIBILITY
1835
return wxGetTextMetrics(this).tmAveCharWidth;
1837
return wxGetTextMetrics(this).tmAveCharWidth + 1;
1841
void wxWindowMSW::GetTextExtent(const wxString& string,
1843
int *descent, int *externalLeading,
1844
const wxFont *theFont) const
1846
wxASSERT_MSG( !theFont || theFont->Ok(),
1847
_T("invalid font in GetTextExtent()") );
1851
fontToUse = *theFont;
1853
fontToUse = GetFont();
1855
WindowHDC hdc(GetHwnd());
1856
SelectInHDC selectFont(hdc, GetHfontOf(fontToUse));
1860
::GetTextExtentPoint32(hdc, string, string.length(), &sizeRect);
1861
GetTextMetrics(hdc, &tm);
1868
*descent = tm.tmDescent;
1869
if ( externalLeading )
1870
*externalLeading = tm.tmExternalLeading;
1873
// ---------------------------------------------------------------------------
1875
// ---------------------------------------------------------------------------
1877
#if wxUSE_MENUS_NATIVE
1879
// yield for WM_COMMAND events only, i.e. process all WM_COMMANDs in the queue
1880
// immediately, without waiting for the next event loop iteration
1882
// NB: this function should probably be made public later as it can almost
1883
// surely replace wxYield() elsewhere as well
1884
static void wxYieldForCommandsOnly()
1886
// peek all WM_COMMANDs (it will always return WM_QUIT too but we don't
1887
// want to process it here)
1889
while ( ::PeekMessage(&msg, (HWND)0, WM_COMMAND, WM_COMMAND, PM_REMOVE) )
1891
if ( msg.message == WM_QUIT )
1893
// if we retrieved a WM_QUIT, insert back into the message queue.
1894
::PostQuitMessage(0);
1898
// luckily (as we don't have access to wxEventLoopImpl method from here
1899
// anyhow...) we don't need to pre process WM_COMMANDs so dispatch it
1901
::TranslateMessage(&msg);
1902
::DispatchMessage(&msg);
1906
bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y)
1908
menu->SetInvokingWindow(this);
1911
if ( x == wxDefaultCoord && y == wxDefaultCoord )
1913
wxPoint mouse = ScreenToClient(wxGetMousePosition());
1914
x = mouse.x; y = mouse.y;
1917
HWND hWnd = GetHwnd();
1918
HMENU hMenu = GetHmenuOf(menu);
1922
::ClientToScreen(hWnd, &point);
1923
wxCurrentPopupMenu = menu;
1924
#if defined(__WXWINCE__)
1927
UINT flags = TPM_RIGHTBUTTON;
1929
::TrackPopupMenu(hMenu, flags, point.x, point.y, 0, hWnd, NULL);
1931
// we need to do it righ now as otherwise the events are never going to be
1932
// sent to wxCurrentPopupMenu from HandleCommand()
1934
// note that even eliminating (ugly) wxCurrentPopupMenu global wouldn't
1935
// help and we'd still need wxYieldForCommandsOnly() as the menu may be
1936
// destroyed as soon as we return (it can be a local variable in the caller
1937
// for example) and so we do need to process the event immediately
1938
wxYieldForCommandsOnly();
1940
wxCurrentPopupMenu = NULL;
1942
menu->SetInvokingWindow(NULL);
1947
#endif // wxUSE_MENUS_NATIVE
1949
// ===========================================================================
1950
// pre/post message processing
1951
// ===========================================================================
1953
WXLRESULT wxWindowMSW::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
1956
return ::CallWindowProc(CASTWNDPROC m_oldWndProc, GetHwnd(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam);
1958
return ::DefWindowProc(GetHwnd(), nMsg, wParam, lParam);
1961
bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
1963
// wxUniversal implements tab traversal itself
1964
#ifndef __WXUNIVERSAL__
1965
if ( m_hWnd != 0 && (GetWindowStyleFlag() & wxTAB_TRAVERSAL) )
1967
// intercept dialog navigation keys
1968
MSG *msg = (MSG *)pMsg;
1970
// here we try to do all the job which ::IsDialogMessage() usually does
1972
if ( msg->message == WM_KEYDOWN )
1974
bool bCtrlDown = wxIsCtrlDown();
1975
bool bShiftDown = wxIsShiftDown();
1977
// WM_GETDLGCODE: ask the control if it wants the key for itself,
1978
// don't process it if it's the case (except for Ctrl-Tab/Enter
1979
// combinations which are always processed)
1983
lDlgCode = ::SendMessage(msg->hwnd, WM_GETDLGCODE, 0, 0);
1985
// surprizingly, DLGC_WANTALLKEYS bit mask doesn't contain the
1986
// DLGC_WANTTAB nor DLGC_WANTARROWS bits although, logically,
1987
// it, of course, implies them
1988
if ( lDlgCode & DLGC_WANTALLKEYS )
1990
lDlgCode |= DLGC_WANTTAB | DLGC_WANTARROWS;
1994
bool bForward = true,
1995
bWindowChange = false,
1998
// should we process this message specially?
1999
bool bProcess = true;
2000
switch ( msg->wParam )
2003
if ( lDlgCode & DLGC_WANTTAB ) {
2007
// Ctrl-Tab cycles thru notebook pages
2008
bWindowChange = bCtrlDown;
2009
bForward = !bShiftDown;
2016
if ( (lDlgCode & DLGC_WANTARROWS) || bCtrlDown )
2024
if ( (lDlgCode & DLGC_WANTARROWS) || bCtrlDown )
2030
if ( (lDlgCode & DLGC_WANTMESSAGE) && !bCtrlDown )
2032
// control wants to process Enter itself, don't
2033
// call IsDialogMessage() which would interpret
2038
// currently active button should get enter press even
2039
// if there is a default button elsewhere
2040
if ( lDlgCode & DLGC_DEFPUSHBUTTON )
2042
// let IsDialogMessage() handle this for all
2043
// buttons except the owner-drawn ones which it
2044
// just seems to ignore
2045
long style = ::GetWindowLong(msg->hwnd, GWL_STYLE);
2046
if ( (style & BS_OWNERDRAW) == BS_OWNERDRAW )
2048
// emulate the button click
2050
btn = wxFindWinFromHandle((WXHWND)msg->hwnd);
2052
btn->MSWCommand(BN_CLICKED, 0 /* unused */);
2057
else // not a button itself
2060
wxButton *btn = wxDynamicCast(GetDefaultItem(),
2062
if ( btn && btn->IsEnabled() )
2064
// if we do have a default button, do press it
2065
btn->MSWCommand(BN_CLICKED, 0 /* unused */);
2069
else // no default button
2070
#endif // wxUSE_BUTTON
2072
// this is a quick and dirty test for a text
2074
if ( !(lDlgCode & DLGC_HASSETSEL) )
2076
// don't process Enter, the control might
2077
// need it for itself and don't let
2078
// ::IsDialogMessage() have it as it can
2079
// eat the Enter events sometimes
2082
else if (!IsTopLevel())
2084
// if not a top level window, let parent
2088
//else: treat Enter as TAB: pass to the next
2089
// control as this is the best thing to do
2090
// if the text doesn't handle Enter itself
2102
wxNavigationKeyEvent event;
2103
event.SetDirection(bForward);
2104
event.SetWindowChange(bWindowChange);
2105
event.SetFromTab(bFromTab);
2106
event.SetEventObject(this);
2108
if ( GetEventHandler()->ProcessEvent(event) )
2110
// as we don't call IsDialogMessage(), which would take of
2111
// this by default, we need to manually send this message
2112
// so that controls could change their appearance
2121
// don't let IsDialogMessage() get VK_ESCAPE as it _always_ eats the
2122
// message even when there is no cancel button and when the message is
2123
// needed by the control itself: in particular, it prevents the tree in
2124
// place edit control from being closed with Escape in a dialog
2125
if ( msg->message != WM_KEYDOWN || msg->wParam != VK_ESCAPE )
2127
// ::IsDialogMessage() is broken and may sometimes hang the
2128
// application by going into an infinite loop, so we try to detect
2129
// [some of] the situatations when this may happen and not call it
2132
// assume we can call it by default
2133
bool canSafelyCallIsDlgMsg = true;
2135
HWND hwndFocus = ::GetFocus();
2137
// if the currently focused window itself has WS_EX_CONTROLPARENT style, ::IsDialogMessage() will also enter
2138
// an infinite loop, because it will recursively check the child
2139
// windows but not the window itself and so if none of the children
2140
// accepts focus it loops forever (as it only stops when it gets
2141
// back to the window it started from)
2143
// while it is very unusual that a window with WS_EX_CONTROLPARENT
2144
// style has the focus, it can happen. One such possibility is if
2145
// all windows are either toplevel, wxDialog, wxPanel or static
2146
// controls and no window can actually accept keyboard input.
2147
#if !defined(__WXWINCE__)
2148
if ( ::GetWindowLong(hwndFocus, GWL_EXSTYLE) & WS_EX_CONTROLPARENT )
2150
// passimistic by default
2151
canSafelyCallIsDlgMsg = false;
2152
for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
2154
node = node->GetNext() )
2156
wxWindow * const win = node->GetData();
2157
if ( win->AcceptsFocus() &&
2158
!(::GetWindowLong(GetHwndOf(win), GWL_EXSTYLE) &
2159
WS_EX_CONTROLPARENT) )
2161
// it shouldn't hang...
2162
canSafelyCallIsDlgMsg = true;
2168
#endif // !__WXWINCE__
2170
if ( canSafelyCallIsDlgMsg )
2172
// ::IsDialogMessage() can enter in an infinite loop when the
2173
// currently focused window is disabled or hidden and its
2174
// parent has WS_EX_CONTROLPARENT style, so don't call it in
2178
if ( !::IsWindowEnabled(hwndFocus) ||
2179
!::IsWindowVisible(hwndFocus) )
2181
// it would enter an infinite loop if we do this!
2182
canSafelyCallIsDlgMsg = false;
2187
if ( !(::GetWindowLong(hwndFocus, GWL_STYLE) & WS_CHILD) )
2189
// it's a top level window, don't go further -- e.g. even
2190
// if the parent of a dialog is disabled, this doesn't
2191
// break navigation inside the dialog
2195
hwndFocus = ::GetParent(hwndFocus);
2199
// let IsDialogMessage() have the message if it's safe to call it
2200
if ( canSafelyCallIsDlgMsg && ::IsDialogMessage(GetHwnd(), msg) )
2202
// IsDialogMessage() did something...
2207
#endif // __WXUNIVERSAL__
2212
// relay mouse move events to the tooltip control
2213
MSG *msg = (MSG *)pMsg;
2214
if ( msg->message == WM_MOUSEMOVE )
2215
m_tooltip->RelayEvent(pMsg);
2217
#endif // wxUSE_TOOLTIPS
2222
bool wxWindowMSW::MSWTranslateMessage(WXMSG* pMsg)
2224
#if wxUSE_ACCEL && !defined(__WXUNIVERSAL__)
2225
return m_acceleratorTable.Translate(this, pMsg);
2229
#endif // wxUSE_ACCEL
2232
bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* WXUNUSED(pMsg))
2234
// preprocess all messages by default
2238
// ---------------------------------------------------------------------------
2239
// message params unpackers
2240
// ---------------------------------------------------------------------------
2242
void wxWindowMSW::UnpackCommand(WXWPARAM wParam, WXLPARAM lParam,
2243
WORD *id, WXHWND *hwnd, WORD *cmd)
2245
*id = LOWORD(wParam);
2246
*hwnd = (WXHWND)lParam;
2247
*cmd = HIWORD(wParam);
2250
void wxWindowMSW::UnpackActivate(WXWPARAM wParam, WXLPARAM lParam,
2251
WXWORD *state, WXWORD *minimized, WXHWND *hwnd)
2253
*state = LOWORD(wParam);
2254
*minimized = HIWORD(wParam);
2255
*hwnd = (WXHWND)lParam;
2258
void wxWindowMSW::UnpackScroll(WXWPARAM wParam, WXLPARAM lParam,
2259
WXWORD *code, WXWORD *pos, WXHWND *hwnd)
2261
*code = LOWORD(wParam);
2262
*pos = HIWORD(wParam);
2263
*hwnd = (WXHWND)lParam;
2266
void wxWindowMSW::UnpackCtlColor(WXWPARAM wParam, WXLPARAM lParam,
2267
WXHDC *hdc, WXHWND *hwnd)
2269
*hwnd = (WXHWND)lParam;
2270
*hdc = (WXHDC)wParam;
2273
void wxWindowMSW::UnpackMenuSelect(WXWPARAM wParam, WXLPARAM lParam,
2274
WXWORD *item, WXWORD *flags, WXHMENU *hmenu)
2276
*item = (WXWORD)wParam;
2277
*flags = HIWORD(wParam);
2278
*hmenu = (WXHMENU)lParam;
2281
// ---------------------------------------------------------------------------
2282
// Main wxWidgets window proc and the window proc for wxWindow
2283
// ---------------------------------------------------------------------------
2285
// Hook for new window just as it's being created, when the window isn't yet
2286
// associated with the handle
2287
static wxWindowMSW *gs_winBeingCreated = NULL;
2289
// implementation of wxWindowCreationHook class: it just sets gs_winBeingCreated to the
2290
// window being created and insures that it's always unset back later
2291
wxWindowCreationHook::wxWindowCreationHook(wxWindowMSW *winBeingCreated)
2293
gs_winBeingCreated = winBeingCreated;
2296
wxWindowCreationHook::~wxWindowCreationHook()
2298
gs_winBeingCreated = NULL;
2302
LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
2304
// trace all messages - useful for the debugging
2306
wxLogTrace(wxTraceMessages,
2307
wxT("Processing %s(hWnd=%08lx, wParam=%8lx, lParam=%8lx)"),
2308
wxGetMessageName(message), (long)hWnd, (long)wParam, lParam);
2309
#endif // __WXDEBUG__
2311
wxWindowMSW *wnd = wxFindWinFromHandle((WXHWND) hWnd);
2313
// when we get the first message for the HWND we just created, we associate
2314
// it with wxWindow stored in gs_winBeingCreated
2315
if ( !wnd && gs_winBeingCreated )
2317
wxAssociateWinWithHandle(hWnd, gs_winBeingCreated);
2318
wnd = gs_winBeingCreated;
2319
gs_winBeingCreated = NULL;
2320
wnd->SetHWND((WXHWND)hWnd);
2325
if ( wnd && wxEventLoop::AllowProcessing(wnd) )
2326
rc = wnd->MSWWindowProc(message, wParam, lParam);
2328
rc = ::DefWindowProc(hWnd, message, wParam, lParam);
2333
WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
2335
// did we process the message?
2336
bool processed = false;
2346
// for most messages we should return 0 when we do process the message
2354
processed = HandleCreate((WXLPCREATESTRUCT)lParam, &mayCreate);
2357
// return 0 to allow window creation
2358
rc.result = mayCreate ? 0 : -1;
2364
// never set processed to true and *always* pass WM_DESTROY to
2365
// DefWindowProc() as Windows may do some internal cleanup when
2366
// processing it and failing to pass the message along may cause
2367
// memory and resource leaks!
2368
(void)HandleDestroy();
2372
processed = HandleSize(LOWORD(lParam), HIWORD(lParam), wParam);
2376
processed = HandleMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
2379
#if !defined(__WXWINCE__)
2382
LPRECT pRect = (LPRECT)lParam;
2384
rc.SetLeft(pRect->left);
2385
rc.SetTop(pRect->top);
2386
rc.SetRight(pRect->right);
2387
rc.SetBottom(pRect->bottom);
2388
processed = HandleMoving(rc);
2390
pRect->left = rc.GetLeft();
2391
pRect->top = rc.GetTop();
2392
pRect->right = rc.GetRight();
2393
pRect->bottom = rc.GetBottom();
2400
LPRECT pRect = (LPRECT)lParam;
2402
rc.SetLeft(pRect->left);
2403
rc.SetTop(pRect->top);
2404
rc.SetRight(pRect->right);
2405
rc.SetBottom(pRect->bottom);
2406
processed = HandleSizing(rc);
2408
pRect->left = rc.GetLeft();
2409
pRect->top = rc.GetTop();
2410
pRect->right = rc.GetRight();
2411
pRect->bottom = rc.GetBottom();
2415
#endif // !__WXWINCE__
2417
#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
2418
case WM_ACTIVATEAPP:
2419
// This implicitly sends a wxEVT_ACTIVATE_APP event
2420
wxTheApp->SetActive(wParam != 0, FindFocus());
2426
WXWORD state, minimized;
2428
UnpackActivate(wParam, lParam, &state, &minimized, &hwnd);
2430
processed = HandleActivate(state, minimized != 0, (WXHWND)hwnd);
2435
processed = HandleSetFocus((WXHWND)(HWND)wParam);
2439
processed = HandleKillFocus((WXHWND)(HWND)wParam);
2442
case WM_PRINTCLIENT:
2443
processed = HandlePrintClient((WXHDC)wParam);
2449
wxPaintDCEx dc((wxWindow *)this, (WXHDC)wParam);
2451
processed = HandlePaint();
2455
processed = HandlePaint();
2460
#ifdef __WXUNIVERSAL__
2461
// Universal uses its own wxFrame/wxDialog, so we don't receive
2462
// close events unless we have this.
2464
#endif // __WXUNIVERSAL__
2466
// don't let the DefWindowProc() destroy our window - we'll do it
2467
// ourselves in ~wxWindow
2473
processed = HandleShow(wParam != 0, (int)lParam);
2477
processed = HandleMouseMove(GET_X_LPARAM(lParam),
2478
GET_Y_LPARAM(lParam),
2482
#ifdef HAVE_TRACKMOUSEEVENT
2484
// filter out excess WM_MOUSELEAVE events sent after PopupMenu() (on XP at least)
2485
if ( m_mouseInWindow )
2487
GenerateMouseLeave();
2490
// always pass processed back as false, this allows the window
2491
// manager to process the message too. This is needed to
2492
// ensure windows XP themes work properly as the mouse moves
2493
// over widgets like buttons. So don't set processed to true here.
2495
#endif // HAVE_TRACKMOUSEEVENT
2497
#if wxUSE_MOUSEWHEEL
2499
processed = HandleMouseWheel(wParam, lParam);
2503
case WM_LBUTTONDOWN:
2505
case WM_LBUTTONDBLCLK:
2506
case WM_RBUTTONDOWN:
2508
case WM_RBUTTONDBLCLK:
2509
case WM_MBUTTONDOWN:
2511
case WM_MBUTTONDBLCLK:
2513
#ifdef __WXMICROWIN__
2514
// MicroWindows seems to ignore the fact that a window is
2515
// disabled. So catch mouse events and throw them away if
2517
wxWindowMSW* win = this;
2520
if (!win->IsEnabled())
2526
win = win->GetParent();
2527
if ( !win || win->IsTopLevel() )
2534
#endif // __WXMICROWIN__
2535
int x = GET_X_LPARAM(lParam),
2536
y = GET_Y_LPARAM(lParam);
2539
// redirect the event to a static control if necessary by
2540
// finding one under mouse because under CE the static controls
2541
// don't generate mouse events (even with SS_NOTIFY)
2543
if ( GetCapture() == this )
2545
// but don't do it if the mouse is captured by this window
2546
// because then it should really get this event itself
2551
win = FindWindowForMouseEvent(this, &x, &y);
2553
// this should never happen
2554
wxCHECK_MSG( win, 0,
2555
_T("FindWindowForMouseEvent() returned NULL") );
2559
if (IsContextMenuEnabled() && message == WM_LBUTTONDOWN)
2561
SHRGINFO shrgi = {0};
2563
shrgi.cbSize = sizeof(SHRGINFO);
2564
shrgi.hwndClient = (HWND) GetHWND();
2568
shrgi.dwFlags = SHRG_RETURNCMD;
2569
// shrgi.dwFlags = SHRG_NOTIFYPARENT;
2571
if (GN_CONTEXTMENU == ::SHRecognizeGesture(&shrgi))
2574
pt = ClientToScreen(pt);
2576
wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt);
2578
evtCtx.SetEventObject(this);
2579
if (GetEventHandler()->ProcessEvent(evtCtx))
2588
#else // !__WXWINCE__
2589
wxWindowMSW *win = this;
2590
#endif // __WXWINCE__/!__WXWINCE__
2592
processed = win->HandleMouseEvent(message, x, y, wParam);
2594
// if the app didn't eat the event, handle it in the default
2595
// way, that is by giving this window the focus
2598
// for the standard classes their WndProc sets the focus to
2599
// them anyhow and doing it from here results in some weird
2600
// problems, so don't do it for them (unnecessary anyhow)
2601
if ( !win->IsOfStandardClass() )
2603
if ( message == WM_LBUTTONDOWN && win->AcceptsFocus() )
2615
case MM_JOY1BUTTONDOWN:
2616
case MM_JOY2BUTTONDOWN:
2617
case MM_JOY1BUTTONUP:
2618
case MM_JOY2BUTTONUP:
2619
processed = HandleJoystickEvent(message,
2620
GET_X_LPARAM(lParam),
2621
GET_Y_LPARAM(lParam),
2624
#endif // __WXMICROWIN__
2630
UnpackCommand(wParam, lParam, &id, &hwnd, &cmd);
2632
processed = HandleCommand(id, cmd, hwnd);
2637
processed = HandleNotify((int)wParam, lParam, &rc.result);
2640
// we only need to reply to WM_NOTIFYFORMAT manually when using MSLU,
2641
// otherwise DefWindowProc() does it perfectly fine for us, but MSLU
2642
// apparently doesn't always behave properly and needs some help
2643
#if wxUSE_UNICODE_MSLU && defined(NF_QUERY)
2644
case WM_NOTIFYFORMAT:
2645
if ( lParam == NF_QUERY )
2648
rc.result = NFR_UNICODE;
2651
#endif // wxUSE_UNICODE_MSLU
2653
// for these messages we must return true if process the message
2656
case WM_MEASUREITEM:
2658
int idCtrl = (UINT)wParam;
2659
if ( message == WM_DRAWITEM )
2661
processed = MSWOnDrawItem(idCtrl,
2662
(WXDRAWITEMSTRUCT *)lParam);
2666
processed = MSWOnMeasureItem(idCtrl,
2667
(WXMEASUREITEMSTRUCT *)lParam);
2674
#endif // defined(WM_DRAWITEM)
2677
if ( !IsOfStandardClass() )
2679
// we always want to get the char events
2680
rc.result = DLGC_WANTCHARS;
2682
if ( GetWindowStyleFlag() & wxWANTS_CHARS )
2684
// in fact, we want everything
2685
rc.result |= DLGC_WANTARROWS |
2692
//else: get the dlg code from the DefWindowProc()
2697
// If this has been processed by an event handler, return 0 now
2698
// (we've handled it).
2699
m_lastKeydownProcessed = HandleKeyDown((WORD) wParam, lParam);
2700
if ( m_lastKeydownProcessed )
2709
// we consider these message "not interesting" to OnChar, so
2710
// just don't do anything more with them
2720
// avoid duplicate messages to OnChar for these ASCII keys:
2721
// they will be translated by TranslateMessage() and received
2743
// but set processed to false, not true to still pass them
2744
// to the control's default window proc - otherwise
2745
// built-in keyboard handling won't work
2750
// special case of VK_APPS: treat it the same as right mouse
2751
// click because both usually pop up a context menu
2753
processed = HandleMouseEvent(WM_RBUTTONDOWN, -1, -1, 0);
2758
// do generate a CHAR event
2759
processed = HandleChar((WORD)wParam, lParam);
2762
if (message == WM_SYSKEYDOWN) // Let Windows still handle the SYSKEYs
2769
// special case of VK_APPS: treat it the same as right mouse button
2770
if ( wParam == VK_APPS )
2772
processed = HandleMouseEvent(WM_RBUTTONUP, -1, -1, 0);
2777
processed = HandleKeyUp((WORD) wParam, lParam);
2782
case WM_CHAR: // Always an ASCII character
2783
if ( m_lastKeydownProcessed )
2785
// The key was handled in the EVT_KEY_DOWN and handling
2786
// a key in an EVT_KEY_DOWN handler is meant, by
2787
// design, to prevent EVT_CHARs from happening
2788
m_lastKeydownProcessed = false;
2793
processed = HandleChar((WORD)wParam, lParam, true);
2799
processed = HandleHotKey((WORD)wParam, lParam);
2801
#endif // wxUSE_HOTKEY
2808
UnpackScroll(wParam, lParam, &code, &pos, &hwnd);
2810
processed = MSWOnScroll(message == WM_HSCROLL ? wxHORIZONTAL
2816
// CTLCOLOR messages are sent by children to query the parent for their
2818
#ifndef __WXMICROWIN__
2819
case WM_CTLCOLORMSGBOX:
2820
case WM_CTLCOLOREDIT:
2821
case WM_CTLCOLORLISTBOX:
2822
case WM_CTLCOLORBTN:
2823
case WM_CTLCOLORDLG:
2824
case WM_CTLCOLORSCROLLBAR:
2825
case WM_CTLCOLORSTATIC:
2829
UnpackCtlColor(wParam, lParam, &hdc, &hwnd);
2831
processed = HandleCtlColor(&rc.hBrush, (WXHDC)hdc, (WXHWND)hwnd);
2834
#endif // !__WXMICROWIN__
2836
case WM_SYSCOLORCHANGE:
2837
// the return value for this message is ignored
2838
processed = HandleSysColorChange();
2841
#if !defined(__WXWINCE__)
2842
case WM_DISPLAYCHANGE:
2843
processed = HandleDisplayChange();
2847
case WM_PALETTECHANGED:
2848
processed = HandlePaletteChanged((WXHWND) (HWND) wParam);
2851
case WM_CAPTURECHANGED:
2852
processed = HandleCaptureChanged((WXHWND) (HWND) lParam);
2855
case WM_QUERYNEWPALETTE:
2856
processed = HandleQueryNewPalette();
2860
processed = HandleEraseBkgnd((WXHDC)(HDC)wParam);
2863
// we processed the message, i.e. erased the background
2868
#if !defined(__WXWINCE__)
2870
processed = HandleDropFiles(wParam);
2875
processed = HandleInitDialog((WXHWND)(HWND)wParam);
2879
// we never set focus from here
2884
#if !defined(__WXWINCE__)
2885
case WM_QUERYENDSESSION:
2886
processed = HandleQueryEndSession(lParam, &rc.allow);
2890
processed = HandleEndSession(wParam != 0, lParam);
2893
case WM_GETMINMAXINFO:
2894
processed = HandleGetMinMaxInfo((MINMAXINFO*)lParam);
2899
processed = HandleSetCursor((WXHWND)(HWND)wParam,
2900
LOWORD(lParam), // hit test
2901
HIWORD(lParam)); // mouse msg
2905
// returning TRUE stops the DefWindowProc() from further
2906
// processing this message - exactly what we need because we've
2907
// just set the cursor.
2912
#if wxUSE_ACCESSIBILITY
2915
//WPARAM dwFlags = (WPARAM) (DWORD) wParam;
2916
LPARAM dwObjId = (LPARAM) (DWORD) lParam;
2918
if (dwObjId == (LPARAM)OBJID_CLIENT && GetOrCreateAccessible())
2920
return LresultFromObject(IID_IAccessible, wParam, (IUnknown*) GetAccessible()->GetIAccessible());
2926
#if defined(WM_HELP)
2929
// HELPINFO doesn't seem to be supported on WinCE.
2931
HELPINFO* info = (HELPINFO*) lParam;
2932
// Don't yet process menu help events, just windows
2933
if (info->iContextType == HELPINFO_WINDOW)
2936
wxWindowMSW* subjectOfHelp = this;
2937
bool eventProcessed = false;
2938
while (subjectOfHelp && !eventProcessed)
2940
wxHelpEvent helpEvent(wxEVT_HELP,
2941
subjectOfHelp->GetId(),
2945
wxPoint(info->MousePos.x, info->MousePos.y)
2949
helpEvent.SetEventObject(this);
2951
GetEventHandler()->ProcessEvent(helpEvent);
2953
// Go up the window hierarchy until the event is
2955
subjectOfHelp = subjectOfHelp->GetParent();
2958
processed = eventProcessed;
2961
else if (info->iContextType == HELPINFO_MENUITEM)
2963
wxHelpEvent helpEvent(wxEVT_HELP, info->iCtrlId);
2964
helpEvent.SetEventObject(this);
2965
processed = GetEventHandler()->ProcessEvent(helpEvent);
2968
//else: processed is already false
2974
#if !defined(__WXWINCE__)
2975
case WM_CONTEXTMENU:
2977
// we don't convert from screen to client coordinates as
2978
// the event may be handled by a parent window
2979
wxPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
2981
wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt);
2983
// we could have got an event from our child, reflect it back
2984
// to it if this is the case
2985
wxWindowMSW *win = NULL;
2986
if ( (WXHWND)wParam != m_hWnd )
2988
win = FindItemByHWND((WXHWND)wParam);
2994
evtCtx.SetEventObject(win);
2995
processed = win->GetEventHandler()->ProcessEvent(evtCtx);
3001
// we're only interested in our own menus, not MF_SYSMENU
3002
if ( HIWORD(wParam) == MF_POPUP )
3004
// handle menu chars for ownerdrawn menu items
3005
int i = HandleMenuChar(toupper(LOWORD(wParam)), lParam);
3006
if ( i != wxNOT_FOUND )
3008
rc.result = MAKELRESULT(i, MNC_EXECUTE);
3018
wxLogTrace(wxTraceMessages, wxT("Forwarding %s to DefWindowProc."),
3019
wxGetMessageName(message));
3020
#endif // __WXDEBUG__
3021
rc.result = MSWDefWindowProc(message, wParam, lParam);
3027
// ----------------------------------------------------------------------------
3028
// wxWindow <-> HWND map
3029
// ----------------------------------------------------------------------------
3031
wxWinHashTable *wxWinHandleHash = NULL;
3033
wxWindow *wxFindWinFromHandle(WXHWND hWnd)
3035
return (wxWindow*)wxWinHandleHash->Get((long)hWnd);
3038
void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win)
3040
// adding NULL hWnd is (first) surely a result of an error and
3041
// (secondly) breaks menu command processing
3042
wxCHECK_RET( hWnd != (HWND)NULL,
3043
wxT("attempt to add a NULL hWnd to window list ignored") );
3045
wxWindow *oldWin = wxFindWinFromHandle((WXHWND) hWnd);
3047
if ( oldWin && (oldWin != win) )
3049
wxLogDebug(wxT("HWND %X already associated with another window (%s)"),
3050
(int) hWnd, win->GetClassInfo()->GetClassName());
3053
#endif // __WXDEBUG__
3056
wxWinHandleHash->Put((long)hWnd, (wxWindow *)win);
3060
void wxRemoveHandleAssociation(wxWindowMSW *win)
3062
wxWinHandleHash->Delete((long)win->GetHWND());
3065
// ----------------------------------------------------------------------------
3066
// various MSW speciic class dependent functions
3067
// ----------------------------------------------------------------------------
3069
// Default destroyer - override if you destroy it in some other way
3070
// (e.g. with MDI child windows)
3071
void wxWindowMSW::MSWDestroyWindow()
3075
bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
3078
int& w, int& h) const
3080
// yes, those are just some arbitrary hardcoded numbers
3081
static const int DEFAULT_Y = 200;
3083
bool nonDefault = false;
3085
if ( pos.x == wxDefaultCoord )
3087
// if x is set to CW_USEDEFAULT, y parameter is ignored anyhow so we
3088
// can just as well set it to CW_USEDEFAULT as well
3094
// OTOH, if x is not set to CW_USEDEFAULT, y shouldn't be set to it
3095
// neither because it is not handled as a special value by Windows then
3096
// and so we have to choose some default value for it
3098
y = pos.y == wxDefaultCoord ? DEFAULT_Y : pos.y;
3104
NB: there used to be some code here which set the initial size of the
3105
window to the client size of the parent if no explicit size was
3106
specified. This was wrong because wxWidgets programs often assume
3107
that they get a WM_SIZE (EVT_SIZE) upon creation, however this broke
3108
it. To see why, you should understand that Windows sends WM_SIZE from
3109
inside ::CreateWindow() anyhow. However, ::CreateWindow() is called
3110
from some base class ctor and so this WM_SIZE is not processed in the
3111
real class' OnSize() (because it's not fully constructed yet and the
3112
event goes to some base class OnSize() instead). So the WM_SIZE we
3113
rely on is the one sent when the parent frame resizes its children
3114
but here is the problem: if the child already has just the right
3115
size, nothing will happen as both wxWidgets and Windows check for
3116
this and ignore any attempts to change the window size to the size it
3117
already has - so no WM_SIZE would be sent.
3121
// we don't use CW_USEDEFAULT here for several reasons:
3123
// 1. it results in huge frames on modern screens (1000*800 is not
3124
// uncommon on my 1280*1024 screen) which is way too big for a half
3125
// empty frame of most of wxWidgets samples for example)
3127
// 2. it is buggy for frames with wxFRAME_TOOL_WINDOW style for which
3128
// the default is for whatever reason 8*8 which breaks client <->
3129
// window size calculations (it would be nice if it didn't, but it
3130
// does and the simplest way to fix it seemed to change the broken
3131
// default size anyhow)
3133
// 3. there is just no advantage in doing it: with x and y it is
3134
// possible that [future versions of] Windows position the new top
3135
// level window in some smart way which we can't do, but we can
3136
// guess a reasonably good size for a new window just as well
3139
// However, on PocketPC devices, we must use the default
3140
// size if possible.
3142
if (size.x == wxDefaultCoord)
3146
if (size.y == wxDefaultCoord)
3151
if ( size.x == wxDefaultCoord || size.y == wxDefaultCoord)
3155
w = WidthDefault(size.x);
3156
h = HeightDefault(size.y);
3159
AdjustForParentClientOrigin(x, y);
3164
WXHWND wxWindowMSW::MSWGetParent() const
3166
return m_parent ? m_parent->GetHWND() : WXHWND(NULL);
3169
bool wxWindowMSW::MSWCreate(const wxChar *wclass,
3170
const wxChar *title,
3174
WXDWORD extendedStyle)
3176
// choose the position/size for the new window
3178
(void)MSWGetCreateWindowCoords(pos, size, x, y, w, h);
3180
// controlId is menu handle for the top level windows, so set it to 0
3181
// unless we're creating a child window
3182
int controlId = style & WS_CHILD ? GetId() : 0;
3184
// for each class "Foo" we have we also have "FooNR" ("no repaint") class
3185
// which is the same but without CS_[HV]REDRAW class styles so using it
3186
// ensures that the window is not fully repainted on each resize
3187
wxString className(wclass);
3188
if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) )
3190
className += wxT("NR");
3193
// do create the window
3194
wxWindowCreationHook hook(this);
3196
m_hWnd = (WXHWND)::CreateWindowEx
3200
title ? title : m_windowName.c_str(),
3203
(HWND)MSWGetParent(),
3206
NULL // no extra data
3211
wxLogSysError(_("Can't create window of class %s"), className.c_str());
3216
SubclassWin(m_hWnd);
3221
// ===========================================================================
3222
// MSW message handlers
3223
// ===========================================================================
3225
// ---------------------------------------------------------------------------
3227
// ---------------------------------------------------------------------------
3231
bool wxWindowMSW::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
3233
#ifndef __WXMICROWIN__
3234
LPNMHDR hdr = (LPNMHDR)lParam;
3235
HWND hWnd = hdr->hwndFrom;
3236
wxWindow *win = wxFindWinFromHandle((WXHWND)hWnd);
3238
// if the control is one of our windows, let it handle the message itself
3241
return win->MSWOnNotify(idCtrl, lParam, result);
3244
// VZ: why did we do it? normally this is unnecessary and, besides, it
3245
// breaks the message processing for the toolbars because the tooltip
3246
// notifications were being forwarded to the toolbar child controls
3247
// (if it had any) before being passed to the toolbar itself, so in my
3248
// example the tooltip for the combobox was always shown instead of the
3249
// correct button tooltips
3251
// try all our children
3252
wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
3255
wxWindow *child = node->GetData();
3256
if ( child->MSWOnNotify(idCtrl, lParam, result) )
3261
node = node->GetNext();
3265
// by default, handle it ourselves
3266
return MSWOnNotify(idCtrl, lParam, result);
3267
#else // __WXMICROWIN__
3274
bool wxWindowMSW::HandleTooltipNotify(WXUINT code,
3276
const wxString& ttip)
3278
// I don't know why it happens, but the versions of comctl32.dll starting
3279
// from 4.70 sometimes send TTN_NEEDTEXTW even to ANSI programs (normally,
3280
// this message is supposed to be sent to Unicode programs only) -- hence
3281
// we need to handle it as well, otherwise no tooltips will be shown in
3284
if ( !(code == (WXUINT) TTN_NEEDTEXTA || code == (WXUINT) TTN_NEEDTEXTW)
3287
// not a tooltip message or no tooltip to show anyhow
3292
LPTOOLTIPTEXT ttText = (LPTOOLTIPTEXT)lParam;
3294
// We don't want to use the szText buffer because it has a limit of 80
3295
// bytes and this is not enough, especially for Unicode build where it
3296
// limits the tooltip string length to only 40 characters
3298
// The best would be, of course, to not impose any length limitations at
3299
// all but then the buffer would have to be dynamic and someone would have
3300
// to free it and we don't have the tooltip owner object here any more, so
3301
// for now use our own static buffer with a higher fixed max length.
3303
// Note that using a static buffer should not be a problem as only a single
3304
// tooltip can be shown at the same time anyhow.
3306
if ( code == (WXUINT) TTN_NEEDTEXTW )
3308
// We need to convert tooltip from multi byte to Unicode on the fly.
3309
static wchar_t buf[513];
3311
// Truncate tooltip length if needed as otherwise we might not have
3312
// enough space for it in the buffer and MultiByteToWideChar() would
3314
size_t tipLength = wxMin(ttip.Len(), WXSIZEOF(buf) - 1);
3316
// Convert to WideChar without adding the NULL character. The NULL
3317
// character is added afterwards (this is more efficient).
3318
int len = ::MultiByteToWideChar
3330
wxLogLastError(_T("MultiByteToWideChar()"));
3334
ttText->lpszText = (LPSTR) buf;
3336
else // TTN_NEEDTEXTA
3337
#endif // !wxUSE_UNICODE
3339
// we get here if we got TTN_NEEDTEXTA (only happens in ANSI build) or
3340
// if we got TTN_NEEDTEXTW in Unicode build: in this case we just have
3341
// to copy the string we have into the buffer
3342
static wxChar buf[513];
3343
wxStrncpy(buf, ttip.c_str(), WXSIZEOF(buf) - 1);
3344
buf[WXSIZEOF(buf) - 1] = _T('\0');
3345
ttText->lpszText = buf;
3351
#endif // wxUSE_TOOLTIPS
3353
bool wxWindowMSW::MSWOnNotify(int WXUNUSED(idCtrl),
3355
WXLPARAM* WXUNUSED(result))
3360
NMHDR* hdr = (NMHDR *)lParam;
3361
if ( HandleTooltipNotify(hdr->code, lParam, m_tooltip->GetTip()))
3368
wxUnusedVar(lParam);
3369
#endif // wxUSE_TOOLTIPS
3376
// ---------------------------------------------------------------------------
3377
// end session messages
3378
// ---------------------------------------------------------------------------
3380
bool wxWindowMSW::HandleQueryEndSession(long logOff, bool *mayEnd)
3382
#ifdef ENDSESSION_LOGOFF
3383
wxCloseEvent event(wxEVT_QUERY_END_SESSION, wxID_ANY);
3384
event.SetEventObject(wxTheApp);
3385
event.SetCanVeto(true);
3386
event.SetLoggingOff(logOff == (long)ENDSESSION_LOGOFF);
3388
bool rc = wxTheApp->ProcessEvent(event);
3392
// we may end only if the app didn't veto session closing (double
3394
*mayEnd = !event.GetVeto();
3399
wxUnusedVar(logOff);
3400
wxUnusedVar(mayEnd);
3405
bool wxWindowMSW::HandleEndSession(bool endSession, long logOff)
3407
#ifdef ENDSESSION_LOGOFF
3408
// do nothing if the session isn't ending
3413
if ( (this != wxTheApp->GetTopWindow()) )
3416
wxCloseEvent event(wxEVT_END_SESSION, wxID_ANY);
3417
event.SetEventObject(wxTheApp);
3418
event.SetCanVeto(false);
3419
event.SetLoggingOff( (logOff == (long)ENDSESSION_LOGOFF) );
3421
return wxTheApp->ProcessEvent(event);
3423
wxUnusedVar(endSession);
3424
wxUnusedVar(logOff);
3429
// ---------------------------------------------------------------------------
3430
// window creation/destruction
3431
// ---------------------------------------------------------------------------
3433
bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT WXUNUSED_IN_WINCE(cs),
3436
// VZ: why is this commented out for WinCE? If it doesn't support
3437
// WS_EX_CONTROLPARENT at all it should be somehow handled globally,
3438
// not with multiple #ifdef's!
3440
if ( ((CREATESTRUCT *)cs)->dwExStyle & WS_EX_CONTROLPARENT )
3441
EnsureParentHasControlParentStyle(GetParent());
3442
#endif // !__WXWINCE__
3444
// TODO: should generate this event from WM_NCCREATE
3445
wxWindowCreateEvent event((wxWindow *)this);
3446
(void)GetEventHandler()->ProcessEvent(event);
3453
bool wxWindowMSW::HandleDestroy()
3457
// delete our drop target if we've got one
3458
#if wxUSE_DRAG_AND_DROP
3459
if ( m_dropTarget != NULL )
3461
m_dropTarget->Revoke(m_hWnd);
3463
delete m_dropTarget;
3464
m_dropTarget = NULL;
3466
#endif // wxUSE_DRAG_AND_DROP
3468
// WM_DESTROY handled
3472
// ---------------------------------------------------------------------------
3474
// ---------------------------------------------------------------------------
3476
bool wxWindowMSW::HandleActivate(int state,
3477
bool WXUNUSED(minimized),
3478
WXHWND WXUNUSED(activate))
3480
wxActivateEvent event(wxEVT_ACTIVATE,
3481
(state == WA_ACTIVE) || (state == WA_CLICKACTIVE),
3483
event.SetEventObject(this);
3485
return GetEventHandler()->ProcessEvent(event);
3488
bool wxWindowMSW::HandleSetFocus(WXHWND hwnd)
3490
// Strangly enough, some controls get set focus events when they are being
3491
// deleted, even if they already had focus before.
3492
if ( m_isBeingDeleted )
3497
// notify the parent keeping track of focus for the kbd navigation
3498
// purposes that we got it
3499
wxChildFocusEvent eventFocus((wxWindow *)this);
3500
(void)GetEventHandler()->ProcessEvent(eventFocus);
3506
m_caret->OnSetFocus();
3508
#endif // wxUSE_CARET
3511
// If it's a wxTextCtrl don't send the event as it will be done
3512
// after the control gets to process it from EN_FOCUS handler
3513
if ( wxDynamicCastThis(wxTextCtrl) )
3517
#endif // wxUSE_TEXTCTRL
3519
wxFocusEvent event(wxEVT_SET_FOCUS, m_windowId);
3520
event.SetEventObject(this);
3522
// wxFindWinFromHandle() may return NULL, it is ok
3523
event.SetWindow(wxFindWinFromHandle(hwnd));
3525
return GetEventHandler()->ProcessEvent(event);
3528
bool wxWindowMSW::HandleKillFocus(WXHWND hwnd)
3534
m_caret->OnKillFocus();
3536
#endif // wxUSE_CARET
3539
// If it's a wxTextCtrl don't send the event as it will be done
3540
// after the control gets to process it.
3541
wxTextCtrl *ctrl = wxDynamicCastThis(wxTextCtrl);
3548
// Don't send the event when in the process of being deleted. This can
3549
// only cause problems if the event handler tries to access the object.
3550
if ( m_isBeingDeleted )
3555
wxFocusEvent event(wxEVT_KILL_FOCUS, m_windowId);
3556
event.SetEventObject(this);
3558
// wxFindWinFromHandle() may return NULL, it is ok
3559
event.SetWindow(wxFindWinFromHandle(hwnd));
3561
return GetEventHandler()->ProcessEvent(event);
3564
// ---------------------------------------------------------------------------
3566
// ---------------------------------------------------------------------------
3568
bool wxWindowMSW::HandleShow(bool show, int WXUNUSED(status))
3570
wxShowEvent event(GetId(), show);
3571
event.SetEventObject(this);
3573
return GetEventHandler()->ProcessEvent(event);
3576
bool wxWindowMSW::HandleInitDialog(WXHWND WXUNUSED(hWndFocus))
3578
wxInitDialogEvent event(GetId());
3579
event.SetEventObject(this);
3581
return GetEventHandler()->ProcessEvent(event);
3584
bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam)
3586
#if defined (__WXMICROWIN__) || defined(__WXWINCE__)
3587
wxUnusedVar(wParam);
3589
#else // __WXMICROWIN__
3590
HDROP hFilesInfo = (HDROP) wParam;
3592
// Get the total number of files dropped
3593
UINT gwFilesDropped = ::DragQueryFile
3601
wxString *files = new wxString[gwFilesDropped];
3602
for ( UINT wIndex = 0; wIndex < gwFilesDropped; wIndex++ )
3604
// first get the needed buffer length (+1 for terminating NUL)
3605
size_t len = ::DragQueryFile(hFilesInfo, wIndex, NULL, 0) + 1;
3607
// and now get the file name
3608
::DragQueryFile(hFilesInfo, wIndex,
3609
wxStringBuffer(files[wIndex], len), len);
3611
DragFinish (hFilesInfo);
3613
wxDropFilesEvent event(wxEVT_DROP_FILES, gwFilesDropped, files);
3614
event.SetEventObject(this);
3617
DragQueryPoint(hFilesInfo, (LPPOINT) &dropPoint);
3618
event.m_pos.x = dropPoint.x;
3619
event.m_pos.y = dropPoint.y;
3621
return GetEventHandler()->ProcessEvent(event);
3626
bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd),
3628
int WXUNUSED(mouseMsg))
3630
#ifndef __WXMICROWIN__
3631
// the logic is as follows:
3632
// -1. don't set cursor for non client area, including but not limited to
3633
// the title bar, scrollbars, &c
3634
// 0. allow the user to override default behaviour by using EVT_SET_CURSOR
3635
// 1. if we have the cursor set it unless wxIsBusy()
3636
// 2. if we're a top level window, set some cursor anyhow
3637
// 3. if wxIsBusy(), set the busy cursor, otherwise the global one
3639
if ( nHitTest != HTCLIENT )
3644
HCURSOR hcursor = 0;
3646
// first ask the user code - it may wish to set the cursor in some very
3647
// specific way (for example, depending on the current position)
3650
if ( !::GetCursorPosWinCE(&pt))
3652
if ( !::GetCursorPos(&pt) )
3655
wxLogLastError(wxT("GetCursorPos"));
3660
ScreenToClient(&x, &y);
3661
wxSetCursorEvent event(x, y);
3663
bool processedEvtSetCursor = GetEventHandler()->ProcessEvent(event);
3664
if ( processedEvtSetCursor && event.HasCursor() )
3666
hcursor = GetHcursorOf(event.GetCursor());
3671
bool isBusy = wxIsBusy();
3673
// the test for processedEvtSetCursor is here to prevent using m_cursor
3674
// if the user code caught EVT_SET_CURSOR() and returned nothing from
3675
// it - this is a way to say that our cursor shouldn't be used for this
3677
if ( !processedEvtSetCursor && m_cursor.Ok() )
3679
hcursor = GetHcursorOf(m_cursor);
3686
hcursor = wxGetCurrentBusyCursor();
3688
else if ( !hcursor )
3690
const wxCursor *cursor = wxGetGlobalCursor();
3691
if ( cursor && cursor->Ok() )
3693
hcursor = GetHcursorOf(*cursor);
3701
// wxLogDebug("HandleSetCursor: Setting cursor %ld", (long) hcursor);
3703
::SetCursor(hcursor);
3705
// cursor set, stop here
3708
#endif // __WXMICROWIN__
3710
// pass up the window chain
3714
// ---------------------------------------------------------------------------
3715
// owner drawn stuff
3716
// ---------------------------------------------------------------------------
3718
#if (wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE) || \
3719
(wxUSE_CONTROLS && !defined(__WXUNIVERSAL__))
3720
#define WXUNUSED_UNLESS_ODRAWN(param) param
3722
#define WXUNUSED_UNLESS_ODRAWN(param)
3726
wxWindowMSW::MSWOnDrawItem(int WXUNUSED_UNLESS_ODRAWN(id),
3727
WXDRAWITEMSTRUCT * WXUNUSED_UNLESS_ODRAWN(itemStruct))
3729
#if wxUSE_OWNER_DRAWN
3731
#if wxUSE_MENUS_NATIVE
3732
// is it a menu item?
3733
DRAWITEMSTRUCT *pDrawStruct = (DRAWITEMSTRUCT *)itemStruct;
3734
if ( id == 0 && pDrawStruct->CtlType == ODT_MENU )
3736
wxMenuItem *pMenuItem = (wxMenuItem *)(pDrawStruct->itemData);
3738
// see comment before the same test in MSWOnMeasureItem() below
3742
wxCHECK_MSG( wxDynamicCast(pMenuItem, wxMenuItem),
3743
false, _T("MSWOnDrawItem: bad wxMenuItem pointer") );
3745
// prepare to call OnDrawItem(): notice using of wxDCTemp to prevent
3746
// the DC from being released
3747
wxDCTemp dc((WXHDC)pDrawStruct->hDC);
3748
wxRect rect(pDrawStruct->rcItem.left, pDrawStruct->rcItem.top,
3749
pDrawStruct->rcItem.right - pDrawStruct->rcItem.left,
3750
pDrawStruct->rcItem.bottom - pDrawStruct->rcItem.top);
3752
return pMenuItem->OnDrawItem
3756
(wxOwnerDrawn::wxODAction)pDrawStruct->itemAction,
3757
(wxOwnerDrawn::wxODStatus)pDrawStruct->itemState
3760
#endif // wxUSE_MENUS_NATIVE
3762
#endif // USE_OWNER_DRAWN
3764
#if wxUSE_CONTROLS && !defined(__WXUNIVERSAL__)
3766
#if wxUSE_OWNER_DRAWN
3767
wxControl *item = wxDynamicCast(FindItem(id), wxControl);
3768
#else // !wxUSE_OWNER_DRAWN
3769
// we may still have owner-drawn buttons internally because we have to make
3770
// them owner-drawn to support colour change
3773
wxDynamicCast(FindItem(id), wxButton)
3778
#endif // USE_OWNER_DRAWN
3782
return item->MSWOnDraw(itemStruct);
3785
#endif // wxUSE_CONTROLS
3791
wxWindowMSW::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct)
3793
#if wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE
3794
// is it a menu item?
3795
MEASUREITEMSTRUCT *pMeasureStruct = (MEASUREITEMSTRUCT *)itemStruct;
3796
if ( id == 0 && pMeasureStruct->CtlType == ODT_MENU )
3798
wxMenuItem *pMenuItem = (wxMenuItem *)(pMeasureStruct->itemData);
3800
// according to Carsten Fuchs the pointer may be NULL under XP if an
3801
// MDI child frame is initially maximized, see this for more info:
3802
// http://article.gmane.org/gmane.comp.lib.wxwidgets.general/27745
3804
// so silently ignore it instead of asserting
3808
wxCHECK_MSG( wxDynamicCast(pMenuItem, wxMenuItem),
3809
false, _T("MSWOnMeasureItem: bad wxMenuItem pointer") );
3812
bool rc = pMenuItem->OnMeasureItem(&w, &h);
3814
pMeasureStruct->itemWidth = w;
3815
pMeasureStruct->itemHeight = h;
3820
wxControl *item = wxDynamicCast(FindItem(id), wxControl);
3823
return item->MSWOnMeasure(itemStruct);
3827
wxUnusedVar(itemStruct);
3828
#endif // wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE
3833
// ---------------------------------------------------------------------------
3834
// colours and palettes
3835
// ---------------------------------------------------------------------------
3837
bool wxWindowMSW::HandleSysColorChange()
3839
wxSysColourChangedEvent event;
3840
event.SetEventObject(this);
3842
(void)GetEventHandler()->ProcessEvent(event);
3844
// always let the system carry on the default processing to allow the
3845
// native controls to react to the colours update
3849
bool wxWindowMSW::HandleDisplayChange()
3851
wxDisplayChangedEvent event;
3852
event.SetEventObject(this);
3854
return GetEventHandler()->ProcessEvent(event);
3857
#ifndef __WXMICROWIN__
3859
bool wxWindowMSW::HandleCtlColor(WXHBRUSH *brush, WXHDC hDC, WXHWND hWnd)
3861
#if !wxUSE_CONTROLS || defined(__WXUNIVERSAL__)
3865
wxControl *item = wxDynamicCast(FindItemByHWND(hWnd, true), wxControl);
3868
*brush = item->MSWControlColor(hDC, hWnd);
3870
#endif // wxUSE_CONTROLS
3873
return *brush != NULL;
3876
#endif // __WXMICROWIN__
3878
bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange)
3881
// same as below except we don't respond to our own messages
3882
if ( hWndPalChange != GetHWND() )
3884
// check to see if we our our parents have a custom palette
3885
wxWindowMSW *win = this;
3886
while ( win && !win->HasCustomPalette() )
3888
win = win->GetParent();
3891
if ( win && win->HasCustomPalette() )
3893
// realize the palette to see whether redrawing is needed
3894
HDC hdc = ::GetDC((HWND) hWndPalChange);
3895
win->m_palette.SetHPALETTE((WXHPALETTE)
3896
::SelectPalette(hdc, GetHpaletteOf(win->m_palette), FALSE));
3898
int result = ::RealizePalette(hdc);
3900
// restore the palette (before releasing the DC)
3901
win->m_palette.SetHPALETTE((WXHPALETTE)
3902
::SelectPalette(hdc, GetHpaletteOf(win->m_palette), FALSE));
3903
::RealizePalette(hdc);
3904
::ReleaseDC((HWND) hWndPalChange, hdc);
3906
// now check for the need to redraw
3908
::InvalidateRect((HWND) hWndPalChange, NULL, TRUE);
3912
#endif // wxUSE_PALETTE
3914
wxPaletteChangedEvent event(GetId());
3915
event.SetEventObject(this);
3916
event.SetChangedWindow(wxFindWinFromHandle(hWndPalChange));
3918
return GetEventHandler()->ProcessEvent(event);
3921
bool wxWindowMSW::HandleCaptureChanged(WXHWND hWndGainedCapture)
3923
wxMouseCaptureChangedEvent event(GetId(), wxFindWinFromHandle(hWndGainedCapture));
3924
event.SetEventObject(this);
3926
return GetEventHandler()->ProcessEvent(event);
3929
bool wxWindowMSW::HandleQueryNewPalette()
3933
// check to see if we our our parents have a custom palette
3934
wxWindowMSW *win = this;
3935
while (!win->HasCustomPalette() && win->GetParent()) win = win->GetParent();
3936
if (win->HasCustomPalette()) {
3937
/* realize the palette to see whether redrawing is needed */
3938
HDC hdc = ::GetDC((HWND) GetHWND());
3939
win->m_palette.SetHPALETTE( (WXHPALETTE)
3940
::SelectPalette(hdc, (HPALETTE) win->m_palette.GetHPALETTE(), FALSE) );
3942
int result = ::RealizePalette(hdc);
3943
/* restore the palette (before releasing the DC) */
3944
win->m_palette.SetHPALETTE( (WXHPALETTE)
3945
::SelectPalette(hdc, (HPALETTE) win->m_palette.GetHPALETTE(), TRUE) );
3946
::RealizePalette(hdc);
3947
::ReleaseDC((HWND) GetHWND(), hdc);
3948
/* now check for the need to redraw */
3950
::InvalidateRect((HWND) GetHWND(), NULL, TRUE);
3952
#endif // wxUSE_PALETTE
3954
wxQueryNewPaletteEvent event(GetId());
3955
event.SetEventObject(this);
3957
return GetEventHandler()->ProcessEvent(event) && event.GetPaletteRealized();
3960
// Responds to colour changes: passes event on to children.
3961
void wxWindowMSW::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event))
3963
// the top level window also reset the standard colour map as it might have
3964
// changed (there is no need to do it for the non top level windows as we
3965
// only have to do it once)
3969
gs_hasStdCmap = false;
3971
wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
3974
// Only propagate to non-top-level windows because Windows already
3975
// sends this event to all top-level ones
3976
wxWindow *win = node->GetData();
3977
if ( !win->IsTopLevel() )
3979
// we need to send the real WM_SYSCOLORCHANGE and not just trigger
3980
// EVT_SYS_COLOUR_CHANGED call because the latter wouldn't work for
3981
// the standard controls
3982
::SendMessage(GetHwndOf(win), WM_SYSCOLORCHANGE, 0, 0);
3985
node = node->GetNext();
3989
extern wxCOLORMAP *wxGetStdColourMap()
3991
static COLORREF s_stdColours[wxSTD_COL_MAX];
3992
static wxCOLORMAP s_cmap[wxSTD_COL_MAX];
3994
if ( !gs_hasStdCmap )
3996
static bool s_coloursInit = false;
3998
if ( !s_coloursInit )
4000
// When a bitmap is loaded, the RGB values can change (apparently
4001
// because Windows adjusts them to care for the old programs always
4002
// using 0xc0c0c0 while the transparent colour for the new Windows
4003
// versions is different). But we do this adjustment ourselves so
4004
// we want to avoid Windows' "help" and for this we need to have a
4005
// reference bitmap which can tell us what the RGB values change
4007
wxLogNull logNo; // suppress error if we couldn't load the bitmap
4008
wxBitmap stdColourBitmap(_T("wxBITMAP_STD_COLOURS"));
4009
if ( stdColourBitmap.Ok() )
4011
// the pixels in the bitmap must correspond to wxSTD_COL_XXX!
4012
wxASSERT_MSG( stdColourBitmap.GetWidth() == wxSTD_COL_MAX,
4013
_T("forgot to update wxBITMAP_STD_COLOURS!") );
4016
memDC.SelectObject(stdColourBitmap);
4019
for ( size_t i = 0; i < WXSIZEOF(s_stdColours); i++ )
4021
memDC.GetPixel(i, 0, &colour);
4022
s_stdColours[i] = wxColourToRGB(colour);
4025
else // wxBITMAP_STD_COLOURS couldn't be loaded
4027
s_stdColours[0] = RGB(000,000,000); // black
4028
s_stdColours[1] = RGB(128,128,128); // dark grey
4029
s_stdColours[2] = RGB(192,192,192); // light grey
4030
s_stdColours[3] = RGB(255,255,255); // white
4031
//s_stdColours[4] = RGB(000,000,255); // blue
4032
//s_stdColours[5] = RGB(255,000,255); // magenta
4035
s_coloursInit = true;
4038
gs_hasStdCmap = true;
4040
// create the colour map
4041
#define INIT_CMAP_ENTRY(col) \
4042
s_cmap[wxSTD_COL_##col].from = s_stdColours[wxSTD_COL_##col]; \
4043
s_cmap[wxSTD_COL_##col].to = ::GetSysColor(COLOR_##col)
4045
INIT_CMAP_ENTRY(BTNTEXT);
4046
INIT_CMAP_ENTRY(BTNSHADOW);
4047
INIT_CMAP_ENTRY(BTNFACE);
4048
INIT_CMAP_ENTRY(BTNHIGHLIGHT);
4050
#undef INIT_CMAP_ENTRY
4056
// ---------------------------------------------------------------------------
4058
// ---------------------------------------------------------------------------
4060
bool wxWindowMSW::HandlePaint()
4062
HRGN hRegion = ::CreateRectRgn(0, 0, 0, 0); // Dummy call to get a handle
4064
wxLogLastError(wxT("CreateRectRgn"));
4065
if ( ::GetUpdateRgn(GetHwnd(), hRegion, FALSE) == ERROR )
4066
wxLogLastError(wxT("GetUpdateRgn"));
4068
m_updateRegion = wxRegion((WXHRGN) hRegion);
4070
wxPaintEvent event(m_windowId);
4071
event.SetEventObject(this);
4073
bool processed = GetEventHandler()->ProcessEvent(event);
4075
// note that we must generate NC event after the normal one as otherwise
4076
// BeginPaint() will happily overwrite our decorations with the background
4078
wxNcPaintEvent eventNc(m_windowId);
4079
eventNc.SetEventObject(this);
4080
GetEventHandler()->ProcessEvent(eventNc);
4085
// Can be called from an application's OnPaint handler
4086
void wxWindowMSW::OnPaint(wxPaintEvent& event)
4088
#ifdef __WXUNIVERSAL__
4091
HDC hDC = (HDC) wxPaintDC::FindDCInCache((wxWindow*) event.GetEventObject());
4094
MSWDefWindowProc(WM_PAINT, (WPARAM) hDC, 0);
4099
bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc)
4104
dc.SetWindow((wxWindow *)this);
4107
wxEraseEvent event(m_windowId, &dc);
4108
event.SetEventObject(this);
4109
bool rc = GetEventHandler()->ProcessEvent(event);
4113
// must be called manually as ~wxDC doesn't do anything for wxDCTemp
4114
dc.SelectOldObjects(hdc);
4119
void wxWindowMSW::OnEraseBackground(wxEraseEvent& event)
4121
// standard non top level controls (i.e. except the dialogs) always erase
4122
// their background themselves in HandleCtlColor() or have some control-
4123
// specific ways to set the colours (common controls)
4124
if ( IsOfStandardClass() && !IsTopLevel() )
4130
if ( GetBackgroundStyle() == wxBG_STYLE_CUSTOM )
4132
// don't skip the event here, custom background means that the app
4133
// is drawing it itself in its OnPaint(), so don't draw it at all
4134
// now to avoid flicker
4139
// do default background painting
4140
if ( !DoEraseBackground(GetHdcOf(*event.GetDC())) )
4142
// let the system paint the background
4147
bool wxWindowMSW::DoEraseBackground(WXHDC hDC)
4149
HBRUSH hbr = (HBRUSH)MSWGetBgBrush(hDC);
4153
wxFillRect(GetHwnd(), (HDC)hDC, hbr);
4159
wxWindowMSW::MSWGetBgBrushForChild(WXHDC WXUNUSED(hDC), WXHWND hWnd)
4163
// our background colour applies to:
4164
// 1. this window itself, always
4165
// 2. all children unless the colour is "not inheritable"
4166
// 3. even if it is not inheritable, our immediate transparent
4167
// children should still inherit it -- but not any transparent
4168
// children because it would look wrong if a child of non
4169
// transparent child would show our bg colour when the child itself
4171
wxWindow *win = wxFindWinFromHandle(hWnd);
4174
(win && win->HasTransparentBackground() &&
4175
win->GetParent() == this) )
4177
// draw children with the same colour as the parent
4179
brush = wxTheBrushList->FindOrCreateBrush(GetBackgroundColour());
4181
return (WXHBRUSH)GetHbrushOf(*brush);
4188
WXHBRUSH wxWindowMSW::MSWGetBgBrush(WXHDC hDC, WXHWND hWndToPaint)
4191
hWndToPaint = GetHWND();
4193
for ( wxWindowMSW *win = this; win; win = win->GetParent() )
4195
WXHBRUSH hBrush = win->MSWGetBgBrushForChild(hDC, hWndToPaint);
4199
// background is not inherited beyond top level windows
4200
if ( win->IsTopLevel() )
4207
bool wxWindowMSW::HandlePrintClient(WXHDC hDC)
4209
// we receive this message when DrawThemeParentBackground() is
4210
// called from def window proc of several controls under XP and we
4211
// must draw properly themed background here
4213
// note that naively I'd expect filling the client rect with the
4214
// brush returned by MSWGetBgBrush() work -- but for some reason it
4215
// doesn't and we have to call parents MSWPrintChild() which is
4216
// supposed to call DrawThemeBackground() with appropriate params
4218
// also note that in this case lParam == PRF_CLIENT but we're
4219
// clearly expected to paint the background and nothing else!
4221
if ( IsTopLevel() || InheritsBackgroundColour() )
4224
// sometimes we don't want the parent to handle it at all, instead
4225
// return whatever value this window wants
4226
if ( !MSWShouldPropagatePrintChild() )
4227
return MSWPrintChild(hDC, (wxWindow *)this);
4229
for ( wxWindow *win = GetParent(); win; win = win->GetParent() )
4231
if ( win->MSWPrintChild(hDC, (wxWindow *)this) )
4234
if ( win->IsTopLevel() || win->InheritsBackgroundColour() )
4241
// ---------------------------------------------------------------------------
4242
// moving and resizing
4243
// ---------------------------------------------------------------------------
4245
bool wxWindowMSW::HandleMinimize()
4247
wxIconizeEvent event(m_windowId);
4248
event.SetEventObject(this);
4250
return GetEventHandler()->ProcessEvent(event);
4253
bool wxWindowMSW::HandleMaximize()
4255
wxMaximizeEvent event(m_windowId);
4256
event.SetEventObject(this);
4258
return GetEventHandler()->ProcessEvent(event);
4261
bool wxWindowMSW::HandleMove(int x, int y)
4264
wxMoveEvent event(point, m_windowId);
4265
event.SetEventObject(this);
4267
return GetEventHandler()->ProcessEvent(event);
4270
bool wxWindowMSW::HandleMoving(wxRect& rect)
4272
wxMoveEvent event(rect, m_windowId);
4273
event.SetEventObject(this);
4275
bool rc = GetEventHandler()->ProcessEvent(event);
4277
rect = event.GetRect();
4281
bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam)
4283
#if USE_DEFERRED_SIZING
4284
// when we resize this window, its children are probably going to be
4285
// repositioned as well, prepare to use DeferWindowPos() for them
4286
int numChildren = 0;
4287
for ( HWND child = ::GetWindow(GetHwndOf(this), GW_CHILD);
4289
child = ::GetWindow(child, GW_HWNDNEXT) )
4294
// Protect against valid m_hDWP being overwritten
4295
bool useDefer = false;
4297
if ( numChildren > 1 )
4301
m_hDWP = (WXHANDLE)::BeginDeferWindowPos(numChildren);
4304
wxLogLastError(_T("BeginDeferWindowPos"));
4310
#endif // USE_DEFERRED_SIZING
4312
// update this window size
4313
bool processed = false;
4317
wxFAIL_MSG( _T("unexpected WM_SIZE parameter") );
4318
// fall through nevertheless
4322
// we're not interested in these messages at all
4325
case SIZE_MINIMIZED:
4326
processed = HandleMinimize();
4329
case SIZE_MAXIMIZED:
4330
/* processed = */ HandleMaximize();
4331
// fall through to send a normal size event as well
4334
// don't use w and h parameters as they specify the client size
4335
// while according to the docs EVT_SIZE handler is supposed to
4336
// receive the total size
4337
wxSizeEvent event(GetSize(), m_windowId);
4338
event.SetEventObject(this);
4340
processed = GetEventHandler()->ProcessEvent(event);
4343
#if USE_DEFERRED_SIZING
4344
// and finally change the positions of all child windows at once
4345
if ( useDefer && m_hDWP )
4347
// reset m_hDWP to NULL so that child windows don't try to use our
4348
// m_hDWP after we call EndDeferWindowPos() on it (this shouldn't
4349
// happen anyhow normally but who knows what weird flow of control we
4350
// may have depending on what the users EVT_SIZE handler does...)
4351
HDWP hDWP = (HDWP)m_hDWP;
4354
// do put all child controls in place at once
4355
if ( !::EndDeferWindowPos(hDWP) )
4357
wxLogLastError(_T("EndDeferWindowPos"));
4360
// Reset our children's pending pos/size values.
4361
for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
4363
node = node->GetNext() )
4365
wxWindowMSW *child = node->GetData();
4366
child->m_pendingPosition = wxDefaultPosition;
4367
child->m_pendingSize = wxDefaultSize;
4370
#endif // USE_DEFERRED_SIZING
4375
bool wxWindowMSW::HandleSizing(wxRect& rect)
4377
wxSizeEvent event(rect, m_windowId);
4378
event.SetEventObject(this);
4380
bool rc = GetEventHandler()->ProcessEvent(event);
4382
rect = event.GetRect();
4386
bool wxWindowMSW::HandleGetMinMaxInfo(void *WXUNUSED_IN_WINCE(mmInfo))
4391
MINMAXINFO *info = (MINMAXINFO *)mmInfo;
4395
int minWidth = GetMinWidth(),
4396
minHeight = GetMinHeight(),
4397
maxWidth = GetMaxWidth(),
4398
maxHeight = GetMaxHeight();
4400
if ( minWidth != wxDefaultCoord )
4402
info->ptMinTrackSize.x = minWidth;
4406
if ( minHeight != wxDefaultCoord )
4408
info->ptMinTrackSize.y = minHeight;
4412
if ( maxWidth != wxDefaultCoord )
4414
info->ptMaxTrackSize.x = maxWidth;
4418
if ( maxHeight != wxDefaultCoord )
4420
info->ptMaxTrackSize.y = maxHeight;
4428
// ---------------------------------------------------------------------------
4430
// ---------------------------------------------------------------------------
4432
bool wxWindowMSW::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control)
4434
#if wxUSE_MENUS_NATIVE
4435
if ( !cmd && wxCurrentPopupMenu )
4437
wxMenu *popupMenu = wxCurrentPopupMenu;
4438
wxCurrentPopupMenu = NULL;
4440
return popupMenu->MSWCommand(cmd, id);
4442
#endif // wxUSE_MENUS_NATIVE
4444
wxWindow *win = NULL;
4446
// first try to find it from HWND - this works even with the broken
4447
// programs using the same ids for different controls
4450
win = wxFindWinFromHandle(control);
4456
// must cast to a signed type before comparing with other ids!
4457
win = FindItem((signed short)id);
4462
return win->MSWCommand(cmd, id);
4465
// the messages sent from the in-place edit control used by the treectrl
4466
// for label editing have id == 0, but they should _not_ be treated as menu
4467
// messages (they are EN_XXX ones, in fact) so don't translate anything
4468
// coming from a control to wxEVT_COMMAND_MENU_SELECTED
4471
// If no child window, it may be an accelerator, e.g. for a popup menu
4474
wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED);
4475
event.SetEventObject(this);
4479
return GetEventHandler()->ProcessEvent(event);
4483
#if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__)
4484
// the text ctrl which is logically part of wxSpinCtrl sends WM_COMMAND
4485
// notifications to its parent which we want to reflect back to
4487
wxSpinCtrl *spin = wxSpinCtrl::GetSpinForTextCtrl(control);
4488
if ( spin && spin->ProcessTextCommand(cmd, id) )
4490
#endif // wxUSE_SPINCTRL
4492
#if wxUSE_CHOICE && defined(__SMARTPHONE__)
4493
// the listbox ctrl which is logically part of wxChoice sends WM_COMMAND
4494
// notifications to its parent which we want to reflect back to
4496
wxChoice *choice = wxChoice::GetChoiceForListBox(control);
4497
if ( choice && choice->MSWCommand(cmd, id) )
4505
// ---------------------------------------------------------------------------
4507
// ---------------------------------------------------------------------------
4509
void wxWindowMSW::InitMouseEvent(wxMouseEvent& event,
4513
// our client coords are not quite the same as Windows ones
4514
wxPoint pt = GetClientAreaOrigin();
4515
event.m_x = x - pt.x;
4516
event.m_y = y - pt.y;
4518
event.m_shiftDown = (flags & MK_SHIFT) != 0;
4519
event.m_controlDown = (flags & MK_CONTROL) != 0;
4520
event.m_leftDown = (flags & MK_LBUTTON) != 0;
4521
event.m_middleDown = (flags & MK_MBUTTON) != 0;
4522
event.m_rightDown = (flags & MK_RBUTTON) != 0;
4523
event.m_altDown = ::GetKeyState(VK_MENU) < 0;
4526
event.SetTimestamp(::GetMessageTime());
4529
event.SetEventObject(this);
4530
event.SetId(GetId());
4532
#if wxUSE_MOUSEEVENT_HACK
4535
m_lastMouseEvent = event.GetEventType();
4536
#endif // wxUSE_MOUSEEVENT_HACK
4540
// Windows doesn't send the mouse events to the static controls (which are
4541
// transparent in the sense that their WM_NCHITTEST handler returns
4542
// HTTRANSPARENT) at all but we want all controls to receive the mouse events
4543
// and so we manually check if we don't have a child window under mouse and if
4544
// we do, send the event to it instead of the window Windows had sent WM_XXX
4547
// Notice that this is not done for the mouse move events because this could
4548
// (would?) be too slow, but only for clicks which means that the static texts
4549
// still don't get move, enter nor leave events.
4550
static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y)
4552
wxCHECK_MSG( x && y, win, _T("NULL pointer in FindWindowForMouseEvent") );
4554
// first try to find a non transparent child: this allows us to send events
4555
// to a static text which is inside a static box, for example
4556
POINT pt = { *x, *y };
4557
HWND hwnd = GetHwndOf(win),
4561
hwndUnderMouse = ::ChildWindowFromPoint
4567
hwndUnderMouse = ::ChildWindowFromPointEx
4577
if ( !hwndUnderMouse || hwndUnderMouse == hwnd )
4579
// now try any child window at all
4580
hwndUnderMouse = ::ChildWindowFromPoint(hwnd, pt);
4583
// check that we have a child window which is susceptible to receive mouse
4584
// events: for this it must be shown and enabled
4585
if ( hwndUnderMouse &&
4586
hwndUnderMouse != hwnd &&
4587
::IsWindowVisible(hwndUnderMouse) &&
4588
::IsWindowEnabled(hwndUnderMouse) )
4590
wxWindow *winUnderMouse = wxFindWinFromHandle((WXHWND)hwndUnderMouse);
4591
if ( winUnderMouse )
4593
// translate the mouse coords to the other window coords
4594
win->ClientToScreen(x, y);
4595
winUnderMouse->ScreenToClient(x, y);
4597
win = winUnderMouse;
4603
#endif // __WXWINCE__
4605
bool wxWindowMSW::HandleMouseEvent(WXUINT msg, int x, int y, WXUINT flags)
4607
// the mouse events take consecutive IDs from WM_MOUSEFIRST to
4608
// WM_MOUSELAST, so it's enough to subtract WM_MOUSEMOVE == WM_MOUSEFIRST
4609
// from the message id and take the value in the table to get wxWin event
4611
static const wxEventType eventsMouse[] =
4625
wxMouseEvent event(eventsMouse[msg - WM_MOUSEMOVE]);
4626
InitMouseEvent(event, x, y, flags);
4628
return GetEventHandler()->ProcessEvent(event);
4631
bool wxWindowMSW::HandleMouseMove(int x, int y, WXUINT flags)
4633
if ( !m_mouseInWindow )
4635
// it would be wrong to assume that just because we get a mouse move
4636
// event that the mouse is inside the window: although this is usually
4637
// true, it is not if we had captured the mouse, so we need to check
4638
// the mouse coordinates here
4639
if ( !HasCapture() || IsMouseInWindow() )
4641
// Generate an ENTER event
4642
m_mouseInWindow = true;
4644
#ifdef HAVE_TRACKMOUSEEVENT
4645
WinStruct<TRACKMOUSEEVENT> trackinfo;
4647
trackinfo.dwFlags = TME_LEAVE;
4648
trackinfo.hwndTrack = GetHwnd();
4650
// Use the commctrl.h _TrackMouseEvent(), which will call the real
4651
// TrackMouseEvent() if available or emulate it
4652
_TrackMouseEvent(&trackinfo);
4653
#endif // HAVE_TRACKMOUSEEVENT
4655
wxMouseEvent event(wxEVT_ENTER_WINDOW);
4656
InitMouseEvent(event, x, y, flags);
4658
(void)GetEventHandler()->ProcessEvent(event);
4661
#ifdef HAVE_TRACKMOUSEEVENT
4664
// Check if we need to send a LEAVE event
4665
// Windows doesn't send WM_MOUSELEAVE if the mouse has been captured so
4666
// send it here if we are using native mouse leave tracking
4667
if ( HasCapture() && !IsMouseInWindow() )
4669
GenerateMouseLeave();
4672
#endif // HAVE_TRACKMOUSEEVENT
4674
#if wxUSE_MOUSEEVENT_HACK
4675
// Window gets a click down message followed by a mouse move message even
4676
// if position isn't changed! We want to discard the trailing move event
4677
// if x and y are the same.
4678
if ( (m_lastMouseEvent == wxEVT_RIGHT_DOWN ||
4679
m_lastMouseEvent == wxEVT_LEFT_DOWN ||
4680
m_lastMouseEvent == wxEVT_MIDDLE_DOWN) &&
4681
(m_lastMouseX == x && m_lastMouseY == y) )
4683
m_lastMouseEvent = wxEVT_MOTION;
4687
#endif // wxUSE_MOUSEEVENT_HACK
4689
return HandleMouseEvent(WM_MOUSEMOVE, x, y, flags);
4693
bool wxWindowMSW::HandleMouseWheel(WXWPARAM wParam, WXLPARAM lParam)
4695
#if wxUSE_MOUSEWHEEL
4696
// notice that WM_MOUSEWHEEL position is in screen coords (as it's
4697
// forwarded up to the parent by DefWindowProc()) and not in the client
4698
// ones as all the other messages, translate them to the client coords for
4701
pt = ScreenToClient(wxPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
4702
wxMouseEvent event(wxEVT_MOUSEWHEEL);
4703
InitMouseEvent(event, pt.x, pt.y, LOWORD(wParam));
4704
event.m_wheelRotation = (short)HIWORD(wParam);
4705
event.m_wheelDelta = WHEEL_DELTA;
4707
static int s_linesPerRotation = -1;
4708
if ( s_linesPerRotation == -1 )
4710
if ( !::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
4711
&s_linesPerRotation, 0))
4713
// this is not supposed to happen
4714
wxLogLastError(_T("SystemParametersInfo(GETWHEELSCROLLLINES)"));
4716
// the default is 3, so use it if SystemParametersInfo() failed
4717
s_linesPerRotation = 3;
4721
event.m_linesPerAction = s_linesPerRotation;
4722
return GetEventHandler()->ProcessEvent(event);
4724
#else // !wxUSE_MOUSEWHEEL
4725
wxUnusedVar(wParam);
4726
wxUnusedVar(lParam);
4729
#endif // wxUSE_MOUSEWHEEL/!wxUSE_MOUSEWHEEL
4732
void wxWindowMSW::GenerateMouseLeave()
4734
m_mouseInWindow = false;
4737
if ( wxIsShiftDown() )
4739
if ( wxIsCtrlDown() )
4740
state |= MK_CONTROL;
4742
// Only the high-order bit should be tested
4743
if ( GetKeyState( VK_LBUTTON ) & (1<<15) )
4744
state |= MK_LBUTTON;
4745
if ( GetKeyState( VK_MBUTTON ) & (1<<15) )
4746
state |= MK_MBUTTON;
4747
if ( GetKeyState( VK_RBUTTON ) & (1<<15) )
4748
state |= MK_RBUTTON;
4752
if ( !::GetCursorPosWinCE(&pt) )
4754
if ( !::GetCursorPos(&pt) )
4757
wxLogLastError(_T("GetCursorPos"));
4760
// we need to have client coordinates here for symmetry with
4761
// wxEVT_ENTER_WINDOW
4762
RECT rect = wxGetWindowRect(GetHwnd());
4766
wxMouseEvent event(wxEVT_LEAVE_WINDOW);
4767
InitMouseEvent(event, pt.x, pt.y, state);
4769
(void)GetEventHandler()->ProcessEvent(event);
4772
// ---------------------------------------------------------------------------
4773
// keyboard handling
4774
// ---------------------------------------------------------------------------
4776
// create the key event of the given type for the given key - used by
4777
// HandleChar and HandleKeyDown/Up
4778
wxKeyEvent wxWindowMSW::CreateKeyEvent(wxEventType evType,
4781
WXWPARAM wParam) const
4783
wxKeyEvent event(evType);
4784
event.SetId(GetId());
4785
event.m_shiftDown = wxIsShiftDown();
4786
event.m_controlDown = wxIsCtrlDown();
4787
event.m_altDown = (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN;
4789
event.SetEventObject((wxWindow *)this); // const_cast
4790
event.m_keyCode = id;
4792
event.m_uniChar = (wxChar) wParam;
4794
event.m_rawCode = (wxUint32) wParam;
4795
event.m_rawFlags = (wxUint32) lParam;
4797
event.SetTimestamp(::GetMessageTime());
4800
// translate the position to client coords
4803
GetCursorPosWinCE(&pt);
4808
GetWindowRect(GetHwnd(),&rect);
4818
// isASCII is true only when we're called from WM_CHAR handler and not from
4820
bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam, bool isASCII)
4825
// If 1 -> 26, translate to either special keycode or just set
4826
// ctrlDown. IOW, Ctrl-C should result in keycode == 3 and
4827
// ControlDown() == true.
4829
if ( (id > 0) && (id < 27) )
4851
else // we're called from WM_KEYDOWN
4853
id = wxCharCodeMSWToWX(wParam, lParam);
4856
// it's ASCII and will be processed here only when called from
4857
// WM_CHAR (i.e. when isASCII = true), don't process it now
4862
wxKeyEvent event(CreateKeyEvent(wxEVT_CHAR, id, lParam, wParam));
4864
// the alphanumeric keys produced by pressing AltGr+something on European
4865
// keyboards have both Ctrl and Alt modifiers which may confuse the user
4866
// code as, normally, keys with Ctrl and/or Alt don't result in anything
4867
// alphanumeric, so pretend that there are no modifiers at all (the
4868
// KEY_DOWN event would still have the correct modifiers if they're really
4870
if ( event.m_controlDown && event.m_altDown &&
4871
(id >= 32 && id < 256) )
4873
event.m_controlDown =
4874
event.m_altDown = false;
4877
return GetEventHandler()->ProcessEvent(event);
4880
bool wxWindowMSW::HandleKeyDown(WXWPARAM wParam, WXLPARAM lParam)
4882
int id = wxCharCodeMSWToWX(wParam, lParam);
4886
// normal ASCII char
4890
if ( id != -1 ) // VZ: does this ever happen (FIXME)?
4892
wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_DOWN, id, lParam, wParam));
4893
if ( GetEventHandler()->ProcessEvent(event) )
4902
bool wxWindowMSW::HandleKeyUp(WXWPARAM wParam, WXLPARAM lParam)
4904
int id = wxCharCodeMSWToWX(wParam, lParam);
4908
// normal ASCII char
4912
if ( id != -1 ) // VZ: does this ever happen (FIXME)?
4914
wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_UP, id, lParam, wParam));
4915
if ( GetEventHandler()->ProcessEvent(event) )
4922
int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel),
4923
WXLPARAM WXUNUSED_IN_WINCE(lParam))
4925
// FIXME: implement GetMenuItemCount for WinCE, possibly
4926
// in terms of GetMenuItemInfo
4928
const HMENU hmenu = (HMENU)lParam;
4932
mii.cbSize = sizeof(MENUITEMINFO);
4934
// we could use MIIM_FTYPE here as we only need to know if the item is
4935
// ownerdrawn or not and not dwTypeData which MIIM_TYPE also returns, but
4936
// MIIM_FTYPE is not supported under Win95
4937
mii.fMask = MIIM_TYPE | MIIM_DATA;
4939
// find if we have this letter in any owner drawn item
4940
const int count = ::GetMenuItemCount(hmenu);
4941
for ( int i = 0; i < count; i++ )
4943
// previous loop iteration could modify it, reset it back before
4944
// calling GetMenuItemInfo() to prevent it from overflowing dwTypeData
4947
if ( ::GetMenuItemInfo(hmenu, i, TRUE, &mii) )
4949
if ( mii.fType == MFT_OWNERDRAW )
4951
// dwItemData member of the MENUITEMINFO is a
4952
// pointer to the associated wxMenuItem -- see the
4953
// menu creation code
4954
wxMenuItem *item = (wxMenuItem*)mii.dwItemData;
4956
const wxChar *p = wxStrchr(item->GetText(), _T('&'));
4959
if ( *p == _T('&') )
4961
// this is not the accel char, find the real one
4962
p = wxStrchr(p + 1, _T('&'));
4964
else // got the accel char
4966
// FIXME-UNICODE: this comparison doesn't risk to work
4967
// for non ASCII accelerator characters I'm afraid, but
4969
if ( (wchar_t)wxToupper(*p) == (wchar_t)chAccel )
4975
// this one doesn't match
4982
else // failed to get the menu text?
4984
// it's not fatal, so don't show error, but still log it
4985
wxLogLastError(_T("GetMenuItemInfo"));
4992
// ---------------------------------------------------------------------------
4994
// ---------------------------------------------------------------------------
4996
bool wxWindowMSW::HandleJoystickEvent(WXUINT msg, int x, int y, WXUINT flags)
5000
if ( flags & JOY_BUTTON1CHG )
5001
change = wxJOY_BUTTON1;
5002
if ( flags & JOY_BUTTON2CHG )
5003
change = wxJOY_BUTTON2;
5004
if ( flags & JOY_BUTTON3CHG )
5005
change = wxJOY_BUTTON3;
5006
if ( flags & JOY_BUTTON4CHG )
5007
change = wxJOY_BUTTON4;
5010
if ( flags & JOY_BUTTON1 )
5011
buttons |= wxJOY_BUTTON1;
5012
if ( flags & JOY_BUTTON2 )
5013
buttons |= wxJOY_BUTTON2;
5014
if ( flags & JOY_BUTTON3 )
5015
buttons |= wxJOY_BUTTON3;
5016
if ( flags & JOY_BUTTON4 )
5017
buttons |= wxJOY_BUTTON4;
5019
// the event ids aren't consecutive so we can't use table based lookup
5021
wxEventType eventType;
5026
eventType = wxEVT_JOY_MOVE;
5031
eventType = wxEVT_JOY_MOVE;
5036
eventType = wxEVT_JOY_ZMOVE;
5041
eventType = wxEVT_JOY_ZMOVE;
5044
case MM_JOY1BUTTONDOWN:
5046
eventType = wxEVT_JOY_BUTTON_DOWN;
5049
case MM_JOY2BUTTONDOWN:
5051
eventType = wxEVT_JOY_BUTTON_DOWN;
5054
case MM_JOY1BUTTONUP:
5056
eventType = wxEVT_JOY_BUTTON_UP;
5059
case MM_JOY2BUTTONUP:
5061
eventType = wxEVT_JOY_BUTTON_UP;
5065
wxFAIL_MSG(wxT("no such joystick event"));
5070
wxJoystickEvent event(eventType, buttons, joystick, change);
5071
event.SetPosition(wxPoint(x, y));
5072
event.SetEventObject(this);
5074
return GetEventHandler()->ProcessEvent(event);
5084
// ---------------------------------------------------------------------------
5086
// ---------------------------------------------------------------------------
5088
bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam,
5089
WXWORD pos, WXHWND control)
5091
if ( control && control != m_hWnd ) // Prevent infinite recursion
5093
wxWindow *child = wxFindWinFromHandle(control);
5095
return child->MSWOnScroll(orientation, wParam, pos, control);
5098
wxScrollWinEvent event;
5099
event.SetPosition(pos);
5100
event.SetOrientation(orientation);
5101
event.SetEventObject(this);
5106
event.SetEventType(wxEVT_SCROLLWIN_TOP);
5110
event.SetEventType(wxEVT_SCROLLWIN_BOTTOM);
5114
event.SetEventType(wxEVT_SCROLLWIN_LINEUP);
5118
event.SetEventType(wxEVT_SCROLLWIN_LINEDOWN);
5122
event.SetEventType(wxEVT_SCROLLWIN_PAGEUP);
5126
event.SetEventType(wxEVT_SCROLLWIN_PAGEDOWN);
5129
case SB_THUMBPOSITION:
5131
// under Win32, the scrollbar range and position are 32 bit integers,
5132
// but WM_[HV]SCROLL only carry the low 16 bits of them, so we must
5133
// explicitly query the scrollbar for the correct position (this must
5134
// be done only for these two SB_ events as they are the only one
5135
// carrying the scrollbar position)
5137
WinStruct<SCROLLINFO> scrollInfo;
5138
scrollInfo.fMask = SIF_TRACKPOS;
5140
if ( !::GetScrollInfo(GetHwnd(),
5141
orientation == wxHORIZONTAL ? SB_HORZ
5145
// Not necessarily an error, if there are no scrollbars yet.
5146
// wxLogLastError(_T("GetScrollInfo"));
5149
event.SetPosition(scrollInfo.nTrackPos);
5152
event.SetEventType( wParam == SB_THUMBPOSITION
5153
? wxEVT_SCROLLWIN_THUMBRELEASE
5154
: wxEVT_SCROLLWIN_THUMBTRACK );
5161
return GetEventHandler()->ProcessEvent(event);
5164
// ===========================================================================
5166
// ===========================================================================
5168
void wxGetCharSize(WXHWND wnd, int *x, int *y, const wxFont& the_font)
5171
HDC dc = ::GetDC((HWND) wnd);
5174
// the_font.UseResource();
5175
// the_font.RealizeResource();
5176
HFONT fnt = (HFONT)the_font.GetResourceHandle(); // const_cast
5178
was = (HFONT) SelectObject(dc,fnt);
5180
GetTextMetrics(dc, &tm);
5183
SelectObject(dc,was);
5185
ReleaseDC((HWND)wnd, dc);
5188
*x = tm.tmAveCharWidth;
5190
*y = tm.tmHeight + tm.tmExternalLeading;
5192
// the_font.ReleaseResource();
5195
// use the "extended" bit (24) of lParam to distinguish extended keys
5196
// from normal keys as the same key is sent
5197
static inline int ChooseNormalOrExtended(int lParam, int keyNormal, int keyExtended)
5199
// except that if lParam is 0, it means we don't have real lParam from
5200
// WM_KEYDOWN but are just translating just a VK constant (e.g. done from
5201
// msw/treectrl.cpp when processing TVN_KEYDOWN) -- then assume this is a
5202
// non-numpad (hence extended) key as this is a more common case
5203
return !lParam || (lParam & (1 << 24)) ? keyExtended : keyNormal;
5206
// Returns 0 if was a normal ASCII value, not a special key. This indicates that
5207
// the key should be ignored by WM_KEYDOWN and processed by WM_CHAR instead.
5208
int wxCharCodeMSWToWX(int keySym, WXLPARAM lParam)
5213
case VK_CANCEL: id = WXK_CANCEL; break;
5214
case VK_BACK: id = WXK_BACK; break;
5215
case VK_TAB: id = WXK_TAB; break;
5216
case VK_CLEAR: id = WXK_CLEAR; break;
5217
case VK_SHIFT: id = WXK_SHIFT; break;
5218
case VK_CONTROL: id = WXK_CONTROL; break;
5219
case VK_MENU : id = WXK_ALT; break;
5220
case VK_PAUSE: id = WXK_PAUSE; break;
5221
case VK_CAPITAL: id = WXK_CAPITAL; break;
5222
case VK_SPACE: id = WXK_SPACE; break;
5223
case VK_ESCAPE: id = WXK_ESCAPE; break;
5224
case VK_SELECT: id = WXK_SELECT; break;
5225
case VK_PRINT: id = WXK_PRINT; break;
5226
case VK_EXECUTE: id = WXK_EXECUTE; break;
5227
case VK_HELP : id = WXK_HELP; break;
5228
case VK_NUMPAD0: id = WXK_NUMPAD0; break;
5229
case VK_NUMPAD1: id = WXK_NUMPAD1; break;
5230
case VK_NUMPAD2: id = WXK_NUMPAD2; break;
5231
case VK_NUMPAD3: id = WXK_NUMPAD3; break;
5232
case VK_NUMPAD4: id = WXK_NUMPAD4; break;
5233
case VK_NUMPAD5: id = WXK_NUMPAD5; break;
5234
case VK_NUMPAD6: id = WXK_NUMPAD6; break;
5235
case VK_NUMPAD7: id = WXK_NUMPAD7; break;
5236
case VK_NUMPAD8: id = WXK_NUMPAD8; break;
5237
case VK_NUMPAD9: id = WXK_NUMPAD9; break;
5238
case VK_MULTIPLY: id = WXK_NUMPAD_MULTIPLY; break;
5239
case VK_ADD: id = WXK_NUMPAD_ADD; break;
5240
case VK_SUBTRACT: id = WXK_NUMPAD_SUBTRACT; break;
5241
case VK_DECIMAL: id = WXK_NUMPAD_DECIMAL; break;
5242
case VK_DIVIDE: id = WXK_NUMPAD_DIVIDE; break;
5243
case VK_F1: id = WXK_F1; break;
5244
case VK_F2: id = WXK_F2; break;
5245
case VK_F3: id = WXK_F3; break;
5246
case VK_F4: id = WXK_F4; break;
5247
case VK_F5: id = WXK_F5; break;
5248
case VK_F6: id = WXK_F6; break;
5249
case VK_F7: id = WXK_F7; break;
5250
case VK_F8: id = WXK_F8; break;
5251
case VK_F9: id = WXK_F9; break;
5252
case VK_F10: id = WXK_F10; break;
5253
case VK_F11: id = WXK_F11; break;
5254
case VK_F12: id = WXK_F12; break;
5255
case VK_F13: id = WXK_F13; break;
5256
case VK_F14: id = WXK_F14; break;
5257
case VK_F15: id = WXK_F15; break;
5258
case VK_F16: id = WXK_F16; break;
5259
case VK_F17: id = WXK_F17; break;
5260
case VK_F18: id = WXK_F18; break;
5261
case VK_F19: id = WXK_F19; break;
5262
case VK_F20: id = WXK_F20; break;
5263
case VK_F21: id = WXK_F21; break;
5264
case VK_F22: id = WXK_F22; break;
5265
case VK_F23: id = WXK_F23; break;
5266
case VK_F24: id = WXK_F24; break;
5267
case VK_NUMLOCK: id = WXK_NUMLOCK; break;
5268
case VK_SCROLL: id = WXK_SCROLL; break;
5270
// the mapping for these keys may be incorrect on non-US keyboards so
5271
// maybe we shouldn't map them to ASCII values at all
5272
case VK_OEM_1: id = ';'; break;
5273
case VK_OEM_PLUS: id = '+'; break;
5274
case VK_OEM_COMMA: id = ','; break;
5275
case VK_OEM_MINUS: id = '-'; break;
5276
case VK_OEM_PERIOD: id = '.'; break;
5277
case VK_OEM_2: id = '/'; break;
5278
case VK_OEM_3: id = '~'; break;
5279
case VK_OEM_4: id = '['; break;
5280
case VK_OEM_5: id = '\\'; break;
5281
case VK_OEM_6: id = ']'; break;
5282
case VK_OEM_7: id = '\''; break;
5285
case VK_LWIN: id = WXK_WINDOWS_LEFT; break;
5286
case VK_RWIN: id = WXK_WINDOWS_RIGHT; break;
5287
case VK_APPS: id = WXK_WINDOWS_MENU; break;
5288
#endif // VK_APPS defined
5290
// handle extended keys
5292
id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_PRIOR, WXK_PRIOR);
5295
id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_NEXT, WXK_NEXT);
5298
id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_END, WXK_END);
5301
id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_HOME, WXK_HOME);
5304
id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_LEFT, WXK_LEFT);
5307
id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_UP, WXK_UP);
5310
id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_RIGHT, WXK_RIGHT);
5313
id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DOWN, WXK_DOWN);
5316
id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_INSERT, WXK_INSERT);
5319
id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DELETE, WXK_DELETE);
5322
// don't use ChooseNormalOrExtended() here as the keys are reversed
5323
// here: numpad enter is the extended one
5324
id = lParam && (lParam & (1 << 24)) ? WXK_NUMPAD_ENTER : WXK_RETURN;
5333
WXWORD wxCharCodeWXToMSW(int id, bool *isVirtual)
5339
case WXK_CANCEL: keySym = VK_CANCEL; break;
5340
case WXK_CLEAR: keySym = VK_CLEAR; break;
5341
case WXK_SHIFT: keySym = VK_SHIFT; break;
5342
case WXK_CONTROL: keySym = VK_CONTROL; break;
5343
case WXK_ALT: keySym = VK_MENU; break;
5344
case WXK_PAUSE: keySym = VK_PAUSE; break;
5345
case WXK_CAPITAL: keySym = VK_CAPITAL; break;
5346
case WXK_PRIOR: keySym = VK_PRIOR; break;
5347
case WXK_NEXT : keySym = VK_NEXT; break;
5348
case WXK_END: keySym = VK_END; break;
5349
case WXK_HOME : keySym = VK_HOME; break;
5350
case WXK_LEFT : keySym = VK_LEFT; break;
5351
case WXK_UP: keySym = VK_UP; break;
5352
case WXK_RIGHT: keySym = VK_RIGHT; break;
5353
case WXK_DOWN : keySym = VK_DOWN; break;
5354
case WXK_SELECT: keySym = VK_SELECT; break;
5355
case WXK_PRINT: keySym = VK_PRINT; break;
5356
case WXK_EXECUTE: keySym = VK_EXECUTE; break;
5357
case WXK_INSERT: keySym = VK_INSERT; break;
5358
case WXK_DELETE: keySym = VK_DELETE; break;
5359
case WXK_HELP : keySym = VK_HELP; break;
5360
case WXK_NUMPAD0: keySym = VK_NUMPAD0; break;
5361
case WXK_NUMPAD1: keySym = VK_NUMPAD1; break;
5362
case WXK_NUMPAD2: keySym = VK_NUMPAD2; break;
5363
case WXK_NUMPAD3: keySym = VK_NUMPAD3; break;
5364
case WXK_NUMPAD4: keySym = VK_NUMPAD4; break;
5365
case WXK_NUMPAD5: keySym = VK_NUMPAD5; break;
5366
case WXK_NUMPAD6: keySym = VK_NUMPAD6; break;
5367
case WXK_NUMPAD7: keySym = VK_NUMPAD7; break;
5368
case WXK_NUMPAD8: keySym = VK_NUMPAD8; break;
5369
case WXK_NUMPAD9: keySym = VK_NUMPAD9; break;
5370
case WXK_NUMPAD_MULTIPLY: keySym = VK_MULTIPLY; break;
5371
case WXK_NUMPAD_ADD: keySym = VK_ADD; break;
5372
case WXK_NUMPAD_SUBTRACT: keySym = VK_SUBTRACT; break;
5373
case WXK_NUMPAD_DECIMAL: keySym = VK_DECIMAL; break;
5374
case WXK_NUMPAD_DIVIDE: keySym = VK_DIVIDE; break;
5375
case WXK_F1: keySym = VK_F1; break;
5376
case WXK_F2: keySym = VK_F2; break;
5377
case WXK_F3: keySym = VK_F3; break;
5378
case WXK_F4: keySym = VK_F4; break;
5379
case WXK_F5: keySym = VK_F5; break;
5380
case WXK_F6: keySym = VK_F6; break;
5381
case WXK_F7: keySym = VK_F7; break;
5382
case WXK_F8: keySym = VK_F8; break;
5383
case WXK_F9: keySym = VK_F9; break;
5384
case WXK_F10: keySym = VK_F10; break;
5385
case WXK_F11: keySym = VK_F11; break;
5386
case WXK_F12: keySym = VK_F12; break;
5387
case WXK_F13: keySym = VK_F13; break;
5388
case WXK_F14: keySym = VK_F14; break;
5389
case WXK_F15: keySym = VK_F15; break;
5390
case WXK_F16: keySym = VK_F16; break;
5391
case WXK_F17: keySym = VK_F17; break;
5392
case WXK_F18: keySym = VK_F18; break;
5393
case WXK_F19: keySym = VK_F19; break;
5394
case WXK_F20: keySym = VK_F20; break;
5395
case WXK_F21: keySym = VK_F21; break;
5396
case WXK_F22: keySym = VK_F22; break;
5397
case WXK_F23: keySym = VK_F23; break;
5398
case WXK_F24: keySym = VK_F24; break;
5399
case WXK_NUMLOCK: keySym = VK_NUMLOCK; break;
5400
case WXK_SCROLL: keySym = VK_SCROLL; break;
5411
bool wxGetKeyState(wxKeyCode key)
5415
wxASSERT_MSG(key != WXK_LBUTTON && key != WXK_RBUTTON && key !=
5416
WXK_MBUTTON, wxT("can't use wxGetKeyState() for mouse buttons"));
5418
//High order with GetAsyncKeyState only available on WIN32
5420
//If the requested key is a LED key, return
5421
//true if the led is pressed
5422
if (key == WXK_NUMLOCK ||
5423
key == WXK_CAPITAL ||
5427
//low order bit means LED is highlighted,
5428
//high order means key is down
5429
//Here, for compat with other ports we want both
5430
return GetKeyState( wxCharCodeWXToMSW(key, &bVirtual) ) != 0;
5437
//low order bit means key pressed since last call
5438
//high order means key is down
5439
//We want only the high order bit - the key may not be down if only low order
5440
return ( GetAsyncKeyState( wxCharCodeWXToMSW(key, &bVirtual) ) & (1<<15) ) != 0;
5446
wxMouseState wxGetMouseState()
5450
GetCursorPos( &pt );
5454
ms.SetLeftDown( (GetAsyncKeyState(VK_LBUTTON) & (1<<15)) != 0 );
5455
ms.SetMiddleDown( (GetAsyncKeyState(VK_MBUTTON) & (1<<15)) != 0 );
5456
ms.SetRightDown( (GetAsyncKeyState(VK_RBUTTON) & (1<<15)) != 0 );
5458
ms.SetControlDown( (GetAsyncKeyState(VK_CONTROL) & (1<<15)) != 0 );
5459
ms.SetShiftDown( (GetAsyncKeyState(VK_SHIFT) & (1<<15)) != 0 );
5460
ms.SetAltDown( (GetAsyncKeyState(VK_MENU) & (1<<15)) != 0 );
5461
// ms.SetMetaDown();
5467
wxWindow *wxGetActiveWindow()
5469
HWND hWnd = GetActiveWindow();
5472
return wxFindWinFromHandle((WXHWND) hWnd);
5477
extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd)
5479
HWND hwnd = (HWND)hWnd;
5481
// For a radiobutton, we get the radiobox from GWL_USERDATA (which is set
5482
// by code in msw/radiobox.cpp), for all the others we just search up the
5484
wxWindow *win = (wxWindow *)NULL;
5487
win = wxFindWinFromHandle((WXHWND)hwnd);
5491
// native radiobuttons return DLGC_RADIOBUTTON here and for any
5492
// wxWindow class which overrides WM_GETDLGCODE processing to
5493
// do it as well, win would be already non NULL
5494
if ( ::SendMessage(hwnd, WM_GETDLGCODE, 0, 0) & DLGC_RADIOBUTTON )
5496
win = (wxWindow *)wxGetWindowUserData(hwnd);
5498
//else: it's a wxRadioButton, not a radiobutton from wxRadioBox
5499
#endif // wxUSE_RADIOBOX
5501
// spin control text buddy window should be mapped to spin ctrl
5502
// itself so try it too
5503
#if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__)
5506
win = wxSpinCtrl::GetSpinForTextCtrl((WXHWND)hwnd);
5508
#endif // wxUSE_SPINCTRL
5512
while ( hwnd && !win )
5514
// this is a really ugly hack needed to avoid mistakenly returning the
5515
// parent frame wxWindow for the find/replace modeless dialog HWND -
5516
// this, in turn, is needed to call IsDialogMessage() from
5517
// wxApp::ProcessMessage() as for this we must return NULL from here
5519
// FIXME: this is clearly not the best way to do it but I think we'll
5520
// need to change HWND <-> wxWindow code more heavily than I can
5521
// do it now to fix it
5522
#ifndef __WXMICROWIN__
5523
if ( ::GetWindow(hwnd, GW_OWNER) )
5525
// it's a dialog box, don't go upwards
5530
hwnd = ::GetParent(hwnd);
5531
win = wxFindWinFromHandle((WXHWND)hwnd);
5537
#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
5539
// Windows keyboard hook. Allows interception of e.g. F1, ESCAPE
5540
// in active frames and dialogs, regardless of where the focus is.
5541
static HHOOK wxTheKeyboardHook = 0;
5542
static FARPROC wxTheKeyboardHookProc = 0;
5543
int APIENTRY _EXPORT
5544
wxKeyboardHook(int nCode, WORD wParam, DWORD lParam);
5546
void wxSetKeyboardHook(bool doIt)
5550
wxTheKeyboardHookProc = MakeProcInstance((FARPROC) wxKeyboardHook, wxGetInstance());
5551
wxTheKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC) wxTheKeyboardHookProc, wxGetInstance(),
5553
GetCurrentThreadId()
5554
// (DWORD)GetCurrentProcess()); // This is another possibility. Which is right?
5559
UnhookWindowsHookEx(wxTheKeyboardHook);
5563
int APIENTRY _EXPORT
5564
wxKeyboardHook(int nCode, WORD wParam, DWORD lParam)
5566
DWORD hiWord = HIWORD(lParam);
5567
if ( nCode != HC_NOREMOVE && ((hiWord & KF_UP) == 0) )
5569
int id = wxCharCodeMSWToWX(wParam, lParam);
5572
wxKeyEvent event(wxEVT_CHAR_HOOK);
5573
if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN )
5574
event.m_altDown = true;
5576
event.SetEventObject(NULL);
5577
event.m_keyCode = id;
5578
event.m_shiftDown = wxIsShiftDown();
5579
event.m_controlDown = wxIsCtrlDown();
5581
event.SetTimestamp(::GetMessageTime());
5583
wxWindow *win = wxGetActiveWindow();
5584
wxEvtHandler *handler;
5587
handler = win->GetEventHandler();
5588
event.SetId(win->GetId());
5593
event.SetId(wxID_ANY);
5596
if ( handler && handler->ProcessEvent(event) )
5604
return (int)CallNextHookEx(wxTheKeyboardHook, nCode, wParam, lParam);
5607
#endif // !__WXMICROWIN__
5610
const wxChar *wxGetMessageName(int message)
5614
case 0x0000: return wxT("WM_NULL");
5615
case 0x0001: return wxT("WM_CREATE");
5616
case 0x0002: return wxT("WM_DESTROY");
5617
case 0x0003: return wxT("WM_MOVE");
5618
case 0x0005: return wxT("WM_SIZE");
5619
case 0x0006: return wxT("WM_ACTIVATE");
5620
case 0x0007: return wxT("WM_SETFOCUS");
5621
case 0x0008: return wxT("WM_KILLFOCUS");
5622
case 0x000A: return wxT("WM_ENABLE");
5623
case 0x000B: return wxT("WM_SETREDRAW");
5624
case 0x000C: return wxT("WM_SETTEXT");
5625
case 0x000D: return wxT("WM_GETTEXT");
5626
case 0x000E: return wxT("WM_GETTEXTLENGTH");
5627
case 0x000F: return wxT("WM_PAINT");
5628
case 0x0010: return wxT("WM_CLOSE");
5629
case 0x0011: return wxT("WM_QUERYENDSESSION");
5630
case 0x0012: return wxT("WM_QUIT");
5631
case 0x0013: return wxT("WM_QUERYOPEN");
5632
case 0x0014: return wxT("WM_ERASEBKGND");
5633
case 0x0015: return wxT("WM_SYSCOLORCHANGE");
5634
case 0x0016: return wxT("WM_ENDSESSION");
5635
case 0x0017: return wxT("WM_SYSTEMERROR");
5636
case 0x0018: return wxT("WM_SHOWWINDOW");
5637
case 0x0019: return wxT("WM_CTLCOLOR");
5638
case 0x001A: return wxT("WM_WININICHANGE");
5639
case 0x001B: return wxT("WM_DEVMODECHANGE");
5640
case 0x001C: return wxT("WM_ACTIVATEAPP");
5641
case 0x001D: return wxT("WM_FONTCHANGE");
5642
case 0x001E: return wxT("WM_TIMECHANGE");
5643
case 0x001F: return wxT("WM_CANCELMODE");
5644
case 0x0020: return wxT("WM_SETCURSOR");
5645
case 0x0021: return wxT("WM_MOUSEACTIVATE");
5646
case 0x0022: return wxT("WM_CHILDACTIVATE");
5647
case 0x0023: return wxT("WM_QUEUESYNC");
5648
case 0x0024: return wxT("WM_GETMINMAXINFO");
5649
case 0x0026: return wxT("WM_PAINTICON");
5650
case 0x0027: return wxT("WM_ICONERASEBKGND");
5651
case 0x0028: return wxT("WM_NEXTDLGCTL");
5652
case 0x002A: return wxT("WM_SPOOLERSTATUS");
5653
case 0x002B: return wxT("WM_DRAWITEM");
5654
case 0x002C: return wxT("WM_MEASUREITEM");
5655
case 0x002D: return wxT("WM_DELETEITEM");
5656
case 0x002E: return wxT("WM_VKEYTOITEM");
5657
case 0x002F: return wxT("WM_CHARTOITEM");
5658
case 0x0030: return wxT("WM_SETFONT");
5659
case 0x0031: return wxT("WM_GETFONT");
5660
case 0x0037: return wxT("WM_QUERYDRAGICON");
5661
case 0x0039: return wxT("WM_COMPAREITEM");
5662
case 0x0041: return wxT("WM_COMPACTING");
5663
case 0x0044: return wxT("WM_COMMNOTIFY");
5664
case 0x0046: return wxT("WM_WINDOWPOSCHANGING");
5665
case 0x0047: return wxT("WM_WINDOWPOSCHANGED");
5666
case 0x0048: return wxT("WM_POWER");
5668
case 0x004A: return wxT("WM_COPYDATA");
5669
case 0x004B: return wxT("WM_CANCELJOURNAL");
5670
case 0x004E: return wxT("WM_NOTIFY");
5671
case 0x0050: return wxT("WM_INPUTLANGCHANGEREQUEST");
5672
case 0x0051: return wxT("WM_INPUTLANGCHANGE");
5673
case 0x0052: return wxT("WM_TCARD");
5674
case 0x0053: return wxT("WM_HELP");
5675
case 0x0054: return wxT("WM_USERCHANGED");
5676
case 0x0055: return wxT("WM_NOTIFYFORMAT");
5677
case 0x007B: return wxT("WM_CONTEXTMENU");
5678
case 0x007C: return wxT("WM_STYLECHANGING");
5679
case 0x007D: return wxT("WM_STYLECHANGED");
5680
case 0x007E: return wxT("WM_DISPLAYCHANGE");
5681
case 0x007F: return wxT("WM_GETICON");
5682
case 0x0080: return wxT("WM_SETICON");
5684
case 0x0081: return wxT("WM_NCCREATE");
5685
case 0x0082: return wxT("WM_NCDESTROY");
5686
case 0x0083: return wxT("WM_NCCALCSIZE");
5687
case 0x0084: return wxT("WM_NCHITTEST");
5688
case 0x0085: return wxT("WM_NCPAINT");
5689
case 0x0086: return wxT("WM_NCACTIVATE");
5690
case 0x0087: return wxT("WM_GETDLGCODE");
5691
case 0x00A0: return wxT("WM_NCMOUSEMOVE");
5692
case 0x00A1: return wxT("WM_NCLBUTTONDOWN");
5693
case 0x00A2: return wxT("WM_NCLBUTTONUP");
5694
case 0x00A3: return wxT("WM_NCLBUTTONDBLCLK");
5695
case 0x00A4: return wxT("WM_NCRBUTTONDOWN");
5696
case 0x00A5: return wxT("WM_NCRBUTTONUP");
5697
case 0x00A6: return wxT("WM_NCRBUTTONDBLCLK");
5698
case 0x00A7: return wxT("WM_NCMBUTTONDOWN");
5699
case 0x00A8: return wxT("WM_NCMBUTTONUP");
5700
case 0x00A9: return wxT("WM_NCMBUTTONDBLCLK");
5701
case 0x0100: return wxT("WM_KEYDOWN");
5702
case 0x0101: return wxT("WM_KEYUP");
5703
case 0x0102: return wxT("WM_CHAR");
5704
case 0x0103: return wxT("WM_DEADCHAR");
5705
case 0x0104: return wxT("WM_SYSKEYDOWN");
5706
case 0x0105: return wxT("WM_SYSKEYUP");
5707
case 0x0106: return wxT("WM_SYSCHAR");
5708
case 0x0107: return wxT("WM_SYSDEADCHAR");
5709
case 0x0108: return wxT("WM_KEYLAST");
5711
case 0x010D: return wxT("WM_IME_STARTCOMPOSITION");
5712
case 0x010E: return wxT("WM_IME_ENDCOMPOSITION");
5713
case 0x010F: return wxT("WM_IME_COMPOSITION");
5715
case 0x0110: return wxT("WM_INITDIALOG");
5716
case 0x0111: return wxT("WM_COMMAND");
5717
case 0x0112: return wxT("WM_SYSCOMMAND");
5718
case 0x0113: return wxT("WM_TIMER");
5719
case 0x0114: return wxT("WM_HSCROLL");
5720
case 0x0115: return wxT("WM_VSCROLL");
5721
case 0x0116: return wxT("WM_INITMENU");
5722
case 0x0117: return wxT("WM_INITMENUPOPUP");
5723
case 0x011F: return wxT("WM_MENUSELECT");
5724
case 0x0120: return wxT("WM_MENUCHAR");
5725
case 0x0121: return wxT("WM_ENTERIDLE");
5726
case 0x0200: return wxT("WM_MOUSEMOVE");
5727
case 0x0201: return wxT("WM_LBUTTONDOWN");
5728
case 0x0202: return wxT("WM_LBUTTONUP");
5729
case 0x0203: return wxT("WM_LBUTTONDBLCLK");
5730
case 0x0204: return wxT("WM_RBUTTONDOWN");
5731
case 0x0205: return wxT("WM_RBUTTONUP");
5732
case 0x0206: return wxT("WM_RBUTTONDBLCLK");
5733
case 0x0207: return wxT("WM_MBUTTONDOWN");
5734
case 0x0208: return wxT("WM_MBUTTONUP");
5735
case 0x0209: return wxT("WM_MBUTTONDBLCLK");
5736
case 0x020A: return wxT("WM_MOUSEWHEEL");
5737
case 0x0210: return wxT("WM_PARENTNOTIFY");
5738
case 0x0211: return wxT("WM_ENTERMENULOOP");
5739
case 0x0212: return wxT("WM_EXITMENULOOP");
5741
case 0x0213: return wxT("WM_NEXTMENU");
5742
case 0x0214: return wxT("WM_SIZING");
5743
case 0x0215: return wxT("WM_CAPTURECHANGED");
5744
case 0x0216: return wxT("WM_MOVING");
5745
case 0x0218: return wxT("WM_POWERBROADCAST");
5746
case 0x0219: return wxT("WM_DEVICECHANGE");
5748
case 0x0220: return wxT("WM_MDICREATE");
5749
case 0x0221: return wxT("WM_MDIDESTROY");
5750
case 0x0222: return wxT("WM_MDIACTIVATE");
5751
case 0x0223: return wxT("WM_MDIRESTORE");
5752
case 0x0224: return wxT("WM_MDINEXT");
5753
case 0x0225: return wxT("WM_MDIMAXIMIZE");
5754
case 0x0226: return wxT("WM_MDITILE");
5755
case 0x0227: return wxT("WM_MDICASCADE");
5756
case 0x0228: return wxT("WM_MDIICONARRANGE");
5757
case 0x0229: return wxT("WM_MDIGETACTIVE");
5758
case 0x0230: return wxT("WM_MDISETMENU");
5759
case 0x0233: return wxT("WM_DROPFILES");
5761
case 0x0281: return wxT("WM_IME_SETCONTEXT");
5762
case 0x0282: return wxT("WM_IME_NOTIFY");
5763
case 0x0283: return wxT("WM_IME_CONTROL");
5764
case 0x0284: return wxT("WM_IME_COMPOSITIONFULL");
5765
case 0x0285: return wxT("WM_IME_SELECT");
5766
case 0x0286: return wxT("WM_IME_CHAR");
5767
case 0x0290: return wxT("WM_IME_KEYDOWN");
5768
case 0x0291: return wxT("WM_IME_KEYUP");
5770
case 0x0300: return wxT("WM_CUT");
5771
case 0x0301: return wxT("WM_COPY");
5772
case 0x0302: return wxT("WM_PASTE");
5773
case 0x0303: return wxT("WM_CLEAR");
5774
case 0x0304: return wxT("WM_UNDO");
5775
case 0x0305: return wxT("WM_RENDERFORMAT");
5776
case 0x0306: return wxT("WM_RENDERALLFORMATS");
5777
case 0x0307: return wxT("WM_DESTROYCLIPBOARD");
5778
case 0x0308: return wxT("WM_DRAWCLIPBOARD");
5779
case 0x0309: return wxT("WM_PAINTCLIPBOARD");
5780
case 0x030A: return wxT("WM_VSCROLLCLIPBOARD");
5781
case 0x030B: return wxT("WM_SIZECLIPBOARD");
5782
case 0x030C: return wxT("WM_ASKCBFORMATNAME");
5783
case 0x030D: return wxT("WM_CHANGECBCHAIN");
5784
case 0x030E: return wxT("WM_HSCROLLCLIPBOARD");
5785
case 0x030F: return wxT("WM_QUERYNEWPALETTE");
5786
case 0x0310: return wxT("WM_PALETTEISCHANGING");
5787
case 0x0311: return wxT("WM_PALETTECHANGED");
5789
case 0x0312: return wxT("WM_HOTKEY");
5792
// common controls messages - although they're not strictly speaking
5793
// standard, it's nice to decode them nevertheless
5796
case 0x1000 + 0: return wxT("LVM_GETBKCOLOR");
5797
case 0x1000 + 1: return wxT("LVM_SETBKCOLOR");
5798
case 0x1000 + 2: return wxT("LVM_GETIMAGELIST");
5799
case 0x1000 + 3: return wxT("LVM_SETIMAGELIST");
5800
case 0x1000 + 4: return wxT("LVM_GETITEMCOUNT");
5801
case 0x1000 + 5: return wxT("LVM_GETITEMA");
5802
case 0x1000 + 75: return wxT("LVM_GETITEMW");
5803
case 0x1000 + 6: return wxT("LVM_SETITEMA");
5804
case 0x1000 + 76: return wxT("LVM_SETITEMW");
5805
case 0x1000 + 7: return wxT("LVM_INSERTITEMA");
5806
case 0x1000 + 77: return wxT("LVM_INSERTITEMW");
5807
case 0x1000 + 8: return wxT("LVM_DELETEITEM");
5808
case 0x1000 + 9: return wxT("LVM_DELETEALLITEMS");
5809
case 0x1000 + 10: return wxT("LVM_GETCALLBACKMASK");
5810
case 0x1000 + 11: return wxT("LVM_SETCALLBACKMASK");
5811
case 0x1000 + 12: return wxT("LVM_GETNEXTITEM");
5812
case 0x1000 + 13: return wxT("LVM_FINDITEMA");
5813
case 0x1000 + 83: return wxT("LVM_FINDITEMW");
5814
case 0x1000 + 14: return wxT("LVM_GETITEMRECT");
5815
case 0x1000 + 15: return wxT("LVM_SETITEMPOSITION");
5816
case 0x1000 + 16: return wxT("LVM_GETITEMPOSITION");
5817
case 0x1000 + 17: return wxT("LVM_GETSTRINGWIDTHA");
5818
case 0x1000 + 87: return wxT("LVM_GETSTRINGWIDTHW");
5819
case 0x1000 + 18: return wxT("LVM_HITTEST");
5820
case 0x1000 + 19: return wxT("LVM_ENSUREVISIBLE");
5821
case 0x1000 + 20: return wxT("LVM_SCROLL");
5822
case 0x1000 + 21: return wxT("LVM_REDRAWITEMS");
5823
case 0x1000 + 22: return wxT("LVM_ARRANGE");
5824
case 0x1000 + 23: return wxT("LVM_EDITLABELA");
5825
case 0x1000 + 118: return wxT("LVM_EDITLABELW");
5826
case 0x1000 + 24: return wxT("LVM_GETEDITCONTROL");
5827
case 0x1000 + 25: return wxT("LVM_GETCOLUMNA");
5828
case 0x1000 + 95: return wxT("LVM_GETCOLUMNW");
5829
case 0x1000 + 26: return wxT("LVM_SETCOLUMNA");
5830
case 0x1000 + 96: return wxT("LVM_SETCOLUMNW");
5831
case 0x1000 + 27: return wxT("LVM_INSERTCOLUMNA");
5832
case 0x1000 + 97: return wxT("LVM_INSERTCOLUMNW");
5833
case 0x1000 + 28: return wxT("LVM_DELETECOLUMN");
5834
case 0x1000 + 29: return wxT("LVM_GETCOLUMNWIDTH");
5835
case 0x1000 + 30: return wxT("LVM_SETCOLUMNWIDTH");
5836
case 0x1000 + 31: return wxT("LVM_GETHEADER");
5837
case 0x1000 + 33: return wxT("LVM_CREATEDRAGIMAGE");
5838
case 0x1000 + 34: return wxT("LVM_GETVIEWRECT");
5839
case 0x1000 + 35: return wxT("LVM_GETTEXTCOLOR");
5840
case 0x1000 + 36: return wxT("LVM_SETTEXTCOLOR");
5841
case 0x1000 + 37: return wxT("LVM_GETTEXTBKCOLOR");
5842
case 0x1000 + 38: return wxT("LVM_SETTEXTBKCOLOR");
5843
case 0x1000 + 39: return wxT("LVM_GETTOPINDEX");
5844
case 0x1000 + 40: return wxT("LVM_GETCOUNTPERPAGE");
5845
case 0x1000 + 41: return wxT("LVM_GETORIGIN");
5846
case 0x1000 + 42: return wxT("LVM_UPDATE");
5847
case 0x1000 + 43: return wxT("LVM_SETITEMSTATE");
5848
case 0x1000 + 44: return wxT("LVM_GETITEMSTATE");
5849
case 0x1000 + 45: return wxT("LVM_GETITEMTEXTA");
5850
case 0x1000 + 115: return wxT("LVM_GETITEMTEXTW");
5851
case 0x1000 + 46: return wxT("LVM_SETITEMTEXTA");
5852
case 0x1000 + 116: return wxT("LVM_SETITEMTEXTW");
5853
case 0x1000 + 47: return wxT("LVM_SETITEMCOUNT");
5854
case 0x1000 + 48: return wxT("LVM_SORTITEMS");
5855
case 0x1000 + 49: return wxT("LVM_SETITEMPOSITION32");
5856
case 0x1000 + 50: return wxT("LVM_GETSELECTEDCOUNT");
5857
case 0x1000 + 51: return wxT("LVM_GETITEMSPACING");
5858
case 0x1000 + 52: return wxT("LVM_GETISEARCHSTRINGA");
5859
case 0x1000 + 117: return wxT("LVM_GETISEARCHSTRINGW");
5860
case 0x1000 + 53: return wxT("LVM_SETICONSPACING");
5861
case 0x1000 + 54: return wxT("LVM_SETEXTENDEDLISTVIEWSTYLE");
5862
case 0x1000 + 55: return wxT("LVM_GETEXTENDEDLISTVIEWSTYLE");
5863
case 0x1000 + 56: return wxT("LVM_GETSUBITEMRECT");
5864
case 0x1000 + 57: return wxT("LVM_SUBITEMHITTEST");
5865
case 0x1000 + 58: return wxT("LVM_SETCOLUMNORDERARRAY");
5866
case 0x1000 + 59: return wxT("LVM_GETCOLUMNORDERARRAY");
5867
case 0x1000 + 60: return wxT("LVM_SETHOTITEM");
5868
case 0x1000 + 61: return wxT("LVM_GETHOTITEM");
5869
case 0x1000 + 62: return wxT("LVM_SETHOTCURSOR");
5870
case 0x1000 + 63: return wxT("LVM_GETHOTCURSOR");
5871
case 0x1000 + 64: return wxT("LVM_APPROXIMATEVIEWRECT");
5872
case 0x1000 + 65: return wxT("LVM_SETWORKAREA");
5875
case 0x1100 + 0: return wxT("TVM_INSERTITEMA");
5876
case 0x1100 + 50: return wxT("TVM_INSERTITEMW");
5877
case 0x1100 + 1: return wxT("TVM_DELETEITEM");
5878
case 0x1100 + 2: return wxT("TVM_EXPAND");
5879
case 0x1100 + 4: return wxT("TVM_GETITEMRECT");
5880
case 0x1100 + 5: return wxT("TVM_GETCOUNT");
5881
case 0x1100 + 6: return wxT("TVM_GETINDENT");
5882
case 0x1100 + 7: return wxT("TVM_SETINDENT");
5883
case 0x1100 + 8: return wxT("TVM_GETIMAGELIST");
5884
case 0x1100 + 9: return wxT("TVM_SETIMAGELIST");
5885
case 0x1100 + 10: return wxT("TVM_GETNEXTITEM");
5886
case 0x1100 + 11: return wxT("TVM_SELECTITEM");
5887
case 0x1100 + 12: return wxT("TVM_GETITEMA");
5888
case 0x1100 + 62: return wxT("TVM_GETITEMW");
5889
case 0x1100 + 13: return wxT("TVM_SETITEMA");
5890
case 0x1100 + 63: return wxT("TVM_SETITEMW");
5891
case 0x1100 + 14: return wxT("TVM_EDITLABELA");
5892
case 0x1100 + 65: return wxT("TVM_EDITLABELW");
5893
case 0x1100 + 15: return wxT("TVM_GETEDITCONTROL");
5894
case 0x1100 + 16: return wxT("TVM_GETVISIBLECOUNT");
5895
case 0x1100 + 17: return wxT("TVM_HITTEST");
5896
case 0x1100 + 18: return wxT("TVM_CREATEDRAGIMAGE");
5897
case 0x1100 + 19: return wxT("TVM_SORTCHILDREN");
5898
case 0x1100 + 20: return wxT("TVM_ENSUREVISIBLE");
5899
case 0x1100 + 21: return wxT("TVM_SORTCHILDRENCB");
5900
case 0x1100 + 22: return wxT("TVM_ENDEDITLABELNOW");
5901
case 0x1100 + 23: return wxT("TVM_GETISEARCHSTRINGA");
5902
case 0x1100 + 64: return wxT("TVM_GETISEARCHSTRINGW");
5903
case 0x1100 + 24: return wxT("TVM_SETTOOLTIPS");
5904
case 0x1100 + 25: return wxT("TVM_GETTOOLTIPS");
5907
case 0x1200 + 0: return wxT("HDM_GETITEMCOUNT");
5908
case 0x1200 + 1: return wxT("HDM_INSERTITEMA");
5909
case 0x1200 + 10: return wxT("HDM_INSERTITEMW");
5910
case 0x1200 + 2: return wxT("HDM_DELETEITEM");
5911
case 0x1200 + 3: return wxT("HDM_GETITEMA");
5912
case 0x1200 + 11: return wxT("HDM_GETITEMW");
5913
case 0x1200 + 4: return wxT("HDM_SETITEMA");
5914
case 0x1200 + 12: return wxT("HDM_SETITEMW");
5915
case 0x1200 + 5: return wxT("HDM_LAYOUT");
5916
case 0x1200 + 6: return wxT("HDM_HITTEST");
5917
case 0x1200 + 7: return wxT("HDM_GETITEMRECT");
5918
case 0x1200 + 8: return wxT("HDM_SETIMAGELIST");
5919
case 0x1200 + 9: return wxT("HDM_GETIMAGELIST");
5920
case 0x1200 + 15: return wxT("HDM_ORDERTOINDEX");
5921
case 0x1200 + 16: return wxT("HDM_CREATEDRAGIMAGE");
5922
case 0x1200 + 17: return wxT("HDM_GETORDERARRAY");
5923
case 0x1200 + 18: return wxT("HDM_SETORDERARRAY");
5924
case 0x1200 + 19: return wxT("HDM_SETHOTDIVIDER");
5927
case 0x1300 + 2: return wxT("TCM_GETIMAGELIST");
5928
case 0x1300 + 3: return wxT("TCM_SETIMAGELIST");
5929
case 0x1300 + 4: return wxT("TCM_GETITEMCOUNT");
5930
case 0x1300 + 5: return wxT("TCM_GETITEMA");
5931
case 0x1300 + 60: return wxT("TCM_GETITEMW");
5932
case 0x1300 + 6: return wxT("TCM_SETITEMA");
5933
case 0x1300 + 61: return wxT("TCM_SETITEMW");
5934
case 0x1300 + 7: return wxT("TCM_INSERTITEMA");
5935
case 0x1300 + 62: return wxT("TCM_INSERTITEMW");
5936
case 0x1300 + 8: return wxT("TCM_DELETEITEM");
5937
case 0x1300 + 9: return wxT("TCM_DELETEALLITEMS");
5938
case 0x1300 + 10: return wxT("TCM_GETITEMRECT");
5939
case 0x1300 + 11: return wxT("TCM_GETCURSEL");
5940
case 0x1300 + 12: return wxT("TCM_SETCURSEL");
5941
case 0x1300 + 13: return wxT("TCM_HITTEST");
5942
case 0x1300 + 14: return wxT("TCM_SETITEMEXTRA");
5943
case 0x1300 + 40: return wxT("TCM_ADJUSTRECT");
5944
case 0x1300 + 41: return wxT("TCM_SETITEMSIZE");
5945
case 0x1300 + 42: return wxT("TCM_REMOVEIMAGE");
5946
case 0x1300 + 43: return wxT("TCM_SETPADDING");
5947
case 0x1300 + 44: return wxT("TCM_GETROWCOUNT");
5948
case 0x1300 + 45: return wxT("TCM_GETTOOLTIPS");
5949
case 0x1300 + 46: return wxT("TCM_SETTOOLTIPS");
5950
case 0x1300 + 47: return wxT("TCM_GETCURFOCUS");
5951
case 0x1300 + 48: return wxT("TCM_SETCURFOCUS");
5952
case 0x1300 + 49: return wxT("TCM_SETMINTABWIDTH");
5953
case 0x1300 + 50: return wxT("TCM_DESELECTALL");
5956
case WM_USER+1: return wxT("TB_ENABLEBUTTON");
5957
case WM_USER+2: return wxT("TB_CHECKBUTTON");
5958
case WM_USER+3: return wxT("TB_PRESSBUTTON");
5959
case WM_USER+4: return wxT("TB_HIDEBUTTON");
5960
case WM_USER+5: return wxT("TB_INDETERMINATE");
5961
case WM_USER+9: return wxT("TB_ISBUTTONENABLED");
5962
case WM_USER+10: return wxT("TB_ISBUTTONCHECKED");
5963
case WM_USER+11: return wxT("TB_ISBUTTONPRESSED");
5964
case WM_USER+12: return wxT("TB_ISBUTTONHIDDEN");
5965
case WM_USER+13: return wxT("TB_ISBUTTONINDETERMINATE");
5966
case WM_USER+17: return wxT("TB_SETSTATE");
5967
case WM_USER+18: return wxT("TB_GETSTATE");
5968
case WM_USER+19: return wxT("TB_ADDBITMAP");
5969
case WM_USER+20: return wxT("TB_ADDBUTTONS");
5970
case WM_USER+21: return wxT("TB_INSERTBUTTON");
5971
case WM_USER+22: return wxT("TB_DELETEBUTTON");
5972
case WM_USER+23: return wxT("TB_GETBUTTON");
5973
case WM_USER+24: return wxT("TB_BUTTONCOUNT");
5974
case WM_USER+25: return wxT("TB_COMMANDTOINDEX");
5975
case WM_USER+26: return wxT("TB_SAVERESTOREA");
5976
case WM_USER+76: return wxT("TB_SAVERESTOREW");
5977
case WM_USER+27: return wxT("TB_CUSTOMIZE");
5978
case WM_USER+28: return wxT("TB_ADDSTRINGA");
5979
case WM_USER+77: return wxT("TB_ADDSTRINGW");
5980
case WM_USER+29: return wxT("TB_GETITEMRECT");
5981
case WM_USER+30: return wxT("TB_BUTTONSTRUCTSIZE");
5982
case WM_USER+31: return wxT("TB_SETBUTTONSIZE");
5983
case WM_USER+32: return wxT("TB_SETBITMAPSIZE");
5984
case WM_USER+33: return wxT("TB_AUTOSIZE");
5985
case WM_USER+35: return wxT("TB_GETTOOLTIPS");
5986
case WM_USER+36: return wxT("TB_SETTOOLTIPS");
5987
case WM_USER+37: return wxT("TB_SETPARENT");
5988
case WM_USER+39: return wxT("TB_SETROWS");
5989
case WM_USER+40: return wxT("TB_GETROWS");
5990
case WM_USER+42: return wxT("TB_SETCMDID");
5991
case WM_USER+43: return wxT("TB_CHANGEBITMAP");
5992
case WM_USER+44: return wxT("TB_GETBITMAP");
5993
case WM_USER+45: return wxT("TB_GETBUTTONTEXTA");
5994
case WM_USER+75: return wxT("TB_GETBUTTONTEXTW");
5995
case WM_USER+46: return wxT("TB_REPLACEBITMAP");
5996
case WM_USER+47: return wxT("TB_SETINDENT");
5997
case WM_USER+48: return wxT("TB_SETIMAGELIST");
5998
case WM_USER+49: return wxT("TB_GETIMAGELIST");
5999
case WM_USER+50: return wxT("TB_LOADIMAGES");
6000
case WM_USER+51: return wxT("TB_GETRECT");
6001
case WM_USER+52: return wxT("TB_SETHOTIMAGELIST");
6002
case WM_USER+53: return wxT("TB_GETHOTIMAGELIST");
6003
case WM_USER+54: return wxT("TB_SETDISABLEDIMAGELIST");
6004
case WM_USER+55: return wxT("TB_GETDISABLEDIMAGELIST");
6005
case WM_USER+56: return wxT("TB_SETSTYLE");
6006
case WM_USER+57: return wxT("TB_GETSTYLE");
6007
case WM_USER+58: return wxT("TB_GETBUTTONSIZE");
6008
case WM_USER+59: return wxT("TB_SETBUTTONWIDTH");
6009
case WM_USER+60: return wxT("TB_SETMAXTEXTROWS");
6010
case WM_USER+61: return wxT("TB_GETTEXTROWS");
6011
case WM_USER+41: return wxT("TB_GETBITMAPFLAGS");
6014
static wxString s_szBuf;
6015
s_szBuf.Printf(wxT("<unknown message = %d>"), message);
6016
return s_szBuf.c_str();
6019
#endif //__WXDEBUG__
6021
static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win)
6025
HWND hwnd = GetHwndOf(win);
6026
HDC hdc = ::GetDC(hwnd);
6028
#if !wxDIALOG_UNIT_COMPATIBILITY
6029
// and select the current font into it
6030
HFONT hfont = GetHfontOf(win->GetFont());
6033
hfont = (HFONT)::SelectObject(hdc, hfont);
6037
// finally retrieve the text metrics from it
6038
GetTextMetrics(hdc, &tm);
6040
#if !wxDIALOG_UNIT_COMPATIBILITY
6044
(void)::SelectObject(hdc, hfont);
6048
::ReleaseDC(hwnd, hdc);
6053
// Find the wxWindow at the current mouse position, returning the mouse
6055
wxWindow* wxFindWindowAtPointer(wxPoint& pt)
6057
pt = wxGetMousePosition();
6058
return wxFindWindowAtPoint(pt);
6061
wxWindow* wxFindWindowAtPoint(const wxPoint& pt)
6066
HWND hWndHit = ::WindowFromPoint(pt2);
6068
wxWindow* win = wxFindWinFromHandle((WXHWND) hWndHit) ;
6069
HWND hWnd = hWndHit;
6071
// Try to find a window with a wxWindow associated with it
6072
while (!win && (hWnd != 0))
6074
hWnd = ::GetParent(hWnd);
6075
win = wxFindWinFromHandle((WXHWND) hWnd) ;
6080
// Get the current mouse position.
6081
wxPoint wxGetMousePosition()
6085
GetCursorPosWinCE(&pt);
6087
GetCursorPos( & pt );
6090
return wxPoint(pt.x, pt.y);
6095
#if defined(__SMARTPHONE__) || defined(__POCKETPC__)
6096
static void WinCEUnregisterHotKey(int modifiers, int id)
6098
// Register hotkeys for the hardware buttons
6100
typedef BOOL (WINAPI *UnregisterFunc1Proc)(UINT, UINT);
6102
UnregisterFunc1Proc procUnregisterFunc;
6103
hCoreDll = LoadLibrary(_T("coredll.dll"));
6106
procUnregisterFunc = (UnregisterFunc1Proc)GetProcAddress(hCoreDll, _T("UnregisterFunc1"));
6107
if (procUnregisterFunc)
6108
procUnregisterFunc(modifiers, id);
6109
FreeLibrary(hCoreDll);
6114
bool wxWindowMSW::RegisterHotKey(int hotkeyId, int modifiers, int keycode)
6116
UINT win_modifiers=0;
6117
if ( modifiers & wxMOD_ALT )
6118
win_modifiers |= MOD_ALT;
6119
if ( modifiers & wxMOD_SHIFT )
6120
win_modifiers |= MOD_SHIFT;
6121
if ( modifiers & wxMOD_CONTROL )
6122
win_modifiers |= MOD_CONTROL;
6123
if ( modifiers & wxMOD_WIN )
6124
win_modifiers |= MOD_WIN;
6126
#if defined(__SMARTPHONE__) || defined(__POCKETPC__)
6127
// Required for PPC and Smartphone hardware buttons
6128
if (keycode >= WXK_SPECIAL1 && keycode <= WXK_SPECIAL20)
6129
WinCEUnregisterHotKey(win_modifiers, hotkeyId);
6132
if ( !::RegisterHotKey(GetHwnd(), hotkeyId, win_modifiers, keycode) )
6134
wxLogLastError(_T("RegisterHotKey"));
6142
bool wxWindowMSW::UnregisterHotKey(int hotkeyId)
6144
#if defined(__SMARTPHONE__) || defined(__POCKETPC__)
6145
WinCEUnregisterHotKey(MOD_WIN, hotkeyId);
6148
if ( !::UnregisterHotKey(GetHwnd(), hotkeyId) )
6150
wxLogLastError(_T("UnregisterHotKey"));
6160
bool wxWindowMSW::HandleHotKey(WXWPARAM wParam, WXLPARAM lParam)
6162
int hotkeyId = wParam;
6163
int virtualKey = HIWORD(lParam);
6164
int win_modifiers = LOWORD(lParam);
6166
wxKeyEvent event(CreateKeyEvent(wxEVT_HOTKEY, virtualKey, wParam, lParam));
6167
event.SetId(hotkeyId);
6168
event.m_shiftDown = (win_modifiers & MOD_SHIFT) != 0;
6169
event.m_controlDown = (win_modifiers & MOD_CONTROL) != 0;
6170
event.m_altDown = (win_modifiers & MOD_ALT) != 0;
6171
event.m_metaDown = (win_modifiers & MOD_WIN) != 0;
6173
return GetEventHandler()->ProcessEvent(event);
6176
#endif // wxUSE_ACCEL
6178
#endif // wxUSE_HOTKEY
6180
// Not tested under WinCE
6183
// this class installs a message hook which really wakes up our idle processing
6184
// each time a WM_NULL is received (wxWakeUpIdle does this), even if we're
6185
// sitting inside a local modal loop (e.g. a menu is opened or scrollbar is
6186
// being dragged or even inside ::MessageBox()) and so don't control message
6187
// dispatching otherwise
6188
class wxIdleWakeUpModule : public wxModule
6191
virtual bool OnInit()
6193
ms_hMsgHookProc = ::SetWindowsHookEx
6196
&wxIdleWakeUpModule::MsgHookProc,
6198
GetCurrentThreadId()
6201
if ( !ms_hMsgHookProc )
6203
wxLogLastError(_T("SetWindowsHookEx(WH_GETMESSAGE)"));
6211
virtual void OnExit()
6213
::UnhookWindowsHookEx(wxIdleWakeUpModule::ms_hMsgHookProc);
6216
static LRESULT CALLBACK MsgHookProc(int nCode, WPARAM wParam, LPARAM lParam)
6218
MSG *msg = (MSG*)lParam;
6220
// only process the message if it is actually going to be removed from
6221
// the message queue, this prevents that the same event from being
6222
// processed multiple times if now someone just called PeekMessage()
6223
if ( msg->message == WM_NULL && wParam == PM_REMOVE )
6225
wxTheApp->ProcessPendingEvents();
6228
return CallNextHookEx(ms_hMsgHookProc, nCode, wParam, lParam);
6232
static HHOOK ms_hMsgHookProc;
6234
DECLARE_DYNAMIC_CLASS(wxIdleWakeUpModule)
6237
HHOOK wxIdleWakeUpModule::ms_hMsgHookProc = 0;
6239
IMPLEMENT_DYNAMIC_CLASS(wxIdleWakeUpModule, wxModule)
6241
#endif // __WXWINCE__
6246
static void wxAdjustZOrder(wxWindow* parent)
6248
if (parent->IsKindOf(CLASSINFO(wxStaticBox)))
6250
// Set the z-order correctly
6251
SetWindowPos((HWND) parent->GetHWND(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
6254
wxWindowList::compatibility_iterator current = parent->GetChildren().GetFirst();
6257
wxWindow *childWin = current->GetData();
6258
wxAdjustZOrder(childWin);
6259
current = current->GetNext();
6264
// We need to adjust the z-order of static boxes in WinCE, to
6265
// make 'contained' controls visible
6266
void wxWindowMSW::OnInitDialog( wxInitDialogEvent& event )
6269
wxAdjustZOrder(this);