]> git.saurik.com Git - wxWidgets.git/blame - src/msw/window.cpp
Renamed m_clientData member variable to avoid clash with variable with same
[wxWidgets.git] / src / msw / window.cpp
CommitLineData
2bda0e17 1/////////////////////////////////////////////////////////////////////////////
faa49bfd
WS
2// Name: src/msw/window.cpp
3// Purpose: wxWindowMSW
2bda0e17 4// Author: Julian Smart
a23fd0e1 5// Modified by: VZ on 13.05.99: no more Default(), MSWOnXXX() reorganisation
2bda0e17
KB
6// Created: 04/01/98
7// RCS-ID: $Id$
6c9a19aa 8// Copyright: (c) Julian Smart
65571936 9// Licence: wxWindows licence
2bda0e17
KB
10/////////////////////////////////////////////////////////////////////////////
11
a23fd0e1
VZ
12// ===========================================================================
13// declarations
14// ===========================================================================
15
16// ---------------------------------------------------------------------------
17// headers
18// ---------------------------------------------------------------------------
19
2bda0e17
KB
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
09914df7 24 #pragma hdrstop
2bda0e17
KB
25#endif
26
e4db172a
WS
27#include "wx/window.h"
28
2bda0e17 29#ifndef WX_PRECOMP
9ed0d735 30 #include "wx/msw/wrapwin.h"
57bd4c60
WS
31 #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
32 #include "wx/msw/missing.h"
0c589ad0 33 #include "wx/accel.h"
3a19e16d
VZ
34 #include "wx/menu.h"
35 #include "wx/dc.h"
36 #include "wx/dcclient.h"
8e92ccef 37 #include "wx/dcmemory.h"
3a19e16d
VZ
38 #include "wx/utils.h"
39 #include "wx/app.h"
3a19e16d
VZ
40 #include "wx/layout.h"
41 #include "wx/dialog.h"
42 #include "wx/frame.h"
43 #include "wx/listbox.h"
44 #include "wx/button.h"
3a19e16d 45 #include "wx/msgdlg.h"
1f3943e0 46 #include "wx/settings.h"
8d753488 47 #include "wx/statbox.h"
1e2aa2f8 48 #include "wx/sizer.h"
88a7a4e1 49 #include "wx/intl.h"
e4db172a 50 #include "wx/log.h"
fec9cc08 51 #include "wx/textctrl.h"
25466131 52 #include "wx/menuitem.h"
02761f6c 53 #include "wx/module.h"
2bda0e17
KB
54#endif
55
61fef19b 56#if wxUSE_OWNER_DRAWN && !defined(__WXUNIVERSAL__)
09914df7 57 #include "wx/ownerdrw.h"
2bda0e17
KB
58#endif
59
a3dc1da9 60#include "wx/evtloop.h"
355debca 61#include "wx/power.h"
c6430ed0 62#include "wx/sysopt.h"
d79df32c 63
9e2896e5
VZ
64#if wxUSE_DRAG_AND_DROP
65 #include "wx/dnd.h"
2bda0e17
KB
66#endif
67
ed5317e5
JS
68#if wxUSE_ACCESSIBILITY
69 #include "wx/access.h"
bef8d481 70 #include <ole2.h>
ed5317e5
JS
71 #include <oleacc.h>
72 #ifndef WM_GETOBJECT
73 #define WM_GETOBJECT 0x003D
74 #endif
75 #ifndef OBJID_CLIENT
76 #define OBJID_CLIENT 0xFFFFFFFC
77 #endif
78#endif
79
0c589ad0
BM
80#include "wx/msw/private.h"
81
750b78ba 82#if wxUSE_TOOLTIPS
42e69d6b 83 #include "wx/tooltip.h"
750b78ba
JS
84#endif
85
789295bf
VZ
86#if wxUSE_CARET
87 #include "wx/caret.h"
88#endif // wxUSE_CARET
89
6fe19057
VZ
90#if wxUSE_SPINCTRL
91 #include "wx/spinctrl.h"
92#endif // wxUSE_SPINCTRL
93
d9317fd4 94#include "wx/notebook.h"
5c6c3176 95#include "wx/listctrl.h"
aafb9978 96#include "wx/dynlib.h"
2a47d3c1 97
2bda0e17
KB
98#include <string.h>
99
d61c1a6f 100#if (!defined(__GNUWIN32_OLD__) && !defined(__WXMICROWIN__) /* && !defined(__WXWINCE__) */ ) || defined(__CYGWIN10__)
3a19e16d
VZ
101 #include <shellapi.h>
102 #include <mmsystem.h>
2bda0e17
KB
103#endif
104
105#ifdef __WIN32__
3a19e16d 106 #include <windowsx.h>
2bda0e17
KB
107#endif
108
dcfd4ac4 109#if !defined __WXWINCE__ && !defined NEED_PBT_H
dbc74bcc
WS
110 #include <pbt.h>
111#endif
2bda0e17 112
7f0586ef 113#if defined(__WXWINCE__)
4e5c6c33 114 #include "wx/msw/wince/missing.h"
7d4f65e3
JS
115#ifdef __POCKETPC__
116 #include <windows.h>
117 #include <shellapi.h>
118 #include <ole2.h>
119 #include <aygshell.h>
120#endif
7f0586ef
JS
121#endif
122
aafb9978 123#if defined(TME_LEAVE) && defined(WM_MOUSELEAVE) && wxUSE_DYNLIB_CLASS
4e5c6c33
VZ
124 #define HAVE_TRACKMOUSEEVENT
125#endif // everything needed for TrackMouseEvent()
126
7d86a2d4
VZ
127// if this is set to 1, we use deferred window sizing to reduce flicker when
128// resizing complicated window hierarchies, but this can in theory result in
129// different behaviour than the old code so we keep the possibility to use it
130// by setting this to 0 (in the future this should be removed completely)
f2197644
JS
131#ifdef __WXWINCE__
132#define USE_DEFERRED_SIZING 0
133#else
8e44f3ca 134#define USE_DEFERRED_SIZING 1
f2197644 135#endif
8e44f3ca 136
c358ea41
VZ
137// set this to 1 to filter out duplicate mouse events, e.g. mouse move events
138// when mouse position didnd't change
139#ifdef __WXWINCE__
140 #define wxUSE_MOUSEEVENT_HACK 0
141#else
142 #define wxUSE_MOUSEEVENT_HACK 1
143#endif
144
a23fd0e1 145// ---------------------------------------------------------------------------
42e69d6b 146// global variables
a23fd0e1 147// ---------------------------------------------------------------------------
47cbd6da 148
1e6feb95 149#if wxUSE_MENUS_NATIVE
2bda0e17 150wxMenu *wxCurrentPopupMenu = NULL;
1e6feb95
VZ
151#endif // wxUSE_MENUS_NATIVE
152
46fa338b
RR
153#ifdef __WXWINCE__
154extern wxChar *wxCanvasClassName;
155#else
2ffa221c 156extern const wxChar *wxCanvasClassName;
46fa338b 157#endif
42e69d6b 158
90c1530a
VZ
159// true if we had already created the std colour map, used by
160// wxGetStdColourMap() and wxWindow::OnSysColourChanged() (FIXME-MT)
08158721 161static bool gs_hasStdCmap = false;
90c1530a 162
c358ea41
VZ
163// last mouse event information we need to filter out the duplicates
164#if wxUSE_MOUSEEVENT_HACK
2b053ae9 165static struct MouseEventInfoDummy
c358ea41
VZ
166{
167 // mouse position (in screen coordinates)
168 wxPoint pos;
169
170 // last mouse event type
171 wxEventType type;
172} gs_lastMouseEvent;
173#endif // wxUSE_MOUSEEVENT_HACK
174
42e69d6b
VZ
175// ---------------------------------------------------------------------------
176// private functions
177// ---------------------------------------------------------------------------
178
179// the window proc for all our windows
3135f4a7 180LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message,
42e69d6b 181 WPARAM wParam, LPARAM lParam);
577baeef 182
42e69d6b
VZ
183
184#ifdef __WXDEBUG__
4a712ba3 185 const wxChar *wxGetMessageName(int message);
42e69d6b 186#endif //__WXDEBUG__
2bda0e17 187
1e6feb95 188void wxRemoveHandleAssociation(wxWindowMSW *win);
cc972ac6 189extern void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win);
2bda0e17
KB
190wxWindow *wxFindWinFromHandle(WXHWND hWnd);
191
f6bcfd97 192// get the text metrics for the current font
1e6feb95
VZ
193static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win);
194
42b1fb63 195#ifdef __WXWINCE__
dfafa702 196// find the window for the mouse event at the specified position
42b1fb63
VZ
197static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y);
198#endif // __WXWINCE__
dfafa702 199
c48926e1 200// wrapper around BringWindowToTop() API
44d5b352 201static inline void wxBringWindowToTop(HWND hwnd)
c48926e1
VZ
202{
203#ifdef __WXMICROWIN__
204 // It seems that MicroWindows brings the _parent_ of the window to the top,
205 // which can be the wrong one.
206
207 // activate (set focus to) specified window
208 ::SetFocus(hwnd);
313901f3 209#endif
c48926e1
VZ
210
211 // raise top level parent to top of z order
313901f3 212 if (!::SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE))
c48926e1 213 {
313901f3 214 wxLogLastError(_T("SetWindowPos"));
c48926e1 215 }
c48926e1 216}
f6bcfd97 217
e0c5c96f
VZ
218#ifndef __WXWINCE__
219
ee471817
VZ
220// ensure that all our parent windows have WS_EX_CONTROLPARENT style
221static void EnsureParentHasControlParentStyle(wxWindow *parent)
222{
223 /*
224 If we have WS_EX_CONTROLPARENT flag we absolutely *must* set it for our
225 parent as well as otherwise several Win32 functions using
226 GetNextDlgTabItem() to iterate over all controls such as
227 IsDialogMessage() or DefDlgProc() would enter an infinite loop: indeed,
228 all of them iterate over all the controls starting from the currently
229 focused one and stop iterating when they get back to the focus but
230 unless all parents have WS_EX_CONTROLPARENT bit set, they would never
231 get back to the initial (focused) window: as we do have this style,
232 GetNextDlgTabItem() will leave this window and continue in its parent,
233 but if the parent doesn't have it, it wouldn't recurse inside it later
90e572f1 234 on and so wouldn't have a chance of getting back to this window either.
ee471817 235 */
ee471817
VZ
236 while ( parent && !parent->IsTopLevel() )
237 {
238 LONG exStyle = ::GetWindowLong(GetHwndOf(parent), GWL_EXSTYLE);
239 if ( !(exStyle & WS_EX_CONTROLPARENT) )
240 {
241 // force the parent to have this style
242 ::SetWindowLong(GetHwndOf(parent), GWL_EXSTYLE,
243 exStyle | WS_EX_CONTROLPARENT);
244 }
245
246 parent = parent->GetParent();
247 }
ee471817
VZ
248}
249
e0c5c96f
VZ
250#endif // !__WXWINCE__
251
f2325516
JS
252#ifdef __WXWINCE__
253// On Windows CE, GetCursorPos can return an error, so use this function
254// instead
255bool GetCursorPosWinCE(POINT* pt)
256{
7d30268c
JS
257 if (!GetCursorPos(pt))
258 {
259 DWORD pos = GetMessagePos();
260 pt->x = LOWORD(pos);
261 pt->y = HIWORD(pos);
262 }
f2325516
JS
263 return true;
264}
265#endif
266
a23fd0e1
VZ
267// ---------------------------------------------------------------------------
268// event tables
269// ---------------------------------------------------------------------------
270
1e6feb95
VZ
271// in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
272// method
273#ifdef __WXUNIVERSAL__
274 IMPLEMENT_ABSTRACT_CLASS(wxWindowMSW, wxWindowBase)
275#else // __WXMSW__
51596bcb 276#if wxUSE_EXTENDED_RTTI
6a89f9ee 277
f3291a82
SC
278// windows that are created from a parent window during its Create method, eg. spin controls in a calendar controls
279// must never been streamed out separately otherwise chaos occurs. Right now easiest is to test for negative ids, as
280// windows with negative ids never can be recreated anyway
281
282bool wxWindowStreamingCallback( const wxObject *object, wxWriter * , wxPersister * , wxxVariantArray & )
283{
284 const wxWindow * win = dynamic_cast<const wxWindow*>(object) ;
285 if ( win && win->GetId() < 0 )
286 return false ;
287 return true ;
288}
289
290IMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxWindow, wxWindowBase,"wx/window.h", wxWindowStreamingCallback)
51596bcb 291
6a89f9ee
SC
292// make wxWindowList known before the property is used
293
321239b6 294wxCOLLECTION_TYPE_INFO( wxWindow* , wxWindowList ) ;
6a89f9ee
SC
295
296template<> void wxCollectionToVariantArray( wxWindowList const &theList, wxxVariantArray &value)
297{
0c6b0084 298 wxListCollectionToVariantArray<wxWindowList::compatibility_iterator>( theList , value ) ;
6a89f9ee
SC
299}
300
bc9fb572
JS
301WX_DEFINE_FLAGS( wxWindowStyle )
302
321239b6 303wxBEGIN_FLAGS( wxWindowStyle )
bc9fb572
JS
304 // new style border flags, we put them first to
305 // use them for streaming out
5c6c3176 306
321239b6
SC
307 wxFLAGS_MEMBER(wxBORDER_SIMPLE)
308 wxFLAGS_MEMBER(wxBORDER_SUNKEN)
309 wxFLAGS_MEMBER(wxBORDER_DOUBLE)
310 wxFLAGS_MEMBER(wxBORDER_RAISED)
311 wxFLAGS_MEMBER(wxBORDER_STATIC)
312 wxFLAGS_MEMBER(wxBORDER_NONE)
35bbb0c6 313
bc9fb572 314 // old style border flags
321239b6
SC
315 wxFLAGS_MEMBER(wxSIMPLE_BORDER)
316 wxFLAGS_MEMBER(wxSUNKEN_BORDER)
317 wxFLAGS_MEMBER(wxDOUBLE_BORDER)
318 wxFLAGS_MEMBER(wxRAISED_BORDER)
319 wxFLAGS_MEMBER(wxSTATIC_BORDER)
cb0afb26 320 wxFLAGS_MEMBER(wxBORDER)
bc9fb572
JS
321
322 // standard window styles
321239b6
SC
323 wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
324 wxFLAGS_MEMBER(wxCLIP_CHILDREN)
325 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
326 wxFLAGS_MEMBER(wxWANTS_CHARS)
cb0afb26 327 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
321239b6
SC
328 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
329 wxFLAGS_MEMBER(wxVSCROLL)
330 wxFLAGS_MEMBER(wxHSCROLL)
331
332wxEND_FLAGS( wxWindowStyle )
333
334wxBEGIN_PROPERTIES_TABLE(wxWindow)
3a3c8603
DS
335 wxEVENT_PROPERTY( Close , wxEVT_CLOSE_WINDOW , wxCloseEvent)
336 wxEVENT_PROPERTY( Create , wxEVT_CREATE , wxWindowCreateEvent )
337 wxEVENT_PROPERTY( Destroy , wxEVT_DESTROY , wxWindowDestroyEvent )
51741307
SC
338 // Always constructor Properties first
339
af498247 340 wxREADONLY_PROPERTY( Parent,wxWindow*, GetParent, EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
fb7e28db 341 wxPROPERTY( Id,wxWindowID, SetId, GetId, -1 /*wxID_ANY*/ , 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
abb74e0f
WS
342 wxPROPERTY( Position,wxPoint, SetPosition , GetPosition, wxDefaultPosition , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // pos
343 wxPROPERTY( Size,wxSize, SetSize, GetSize, wxDefaultSize , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // size
af498247 344 wxPROPERTY( WindowStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
51741307
SC
345
346 // Then all relations of the object graph
347
321239b6 348 wxREADONLY_PROPERTY_COLLECTION( Children , wxWindowList , wxWindowBase* , GetWindowChildren , wxPROP_OBJECT_GRAPH /*flags*/ , wxT("Helpstring") , wxT("group"))
51741307
SC
349
350 // and finally all other properties
351
3a3c8603
DS
352 wxPROPERTY( ExtraStyle , long , SetExtraStyle , GetExtraStyle , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // extstyle
353 wxPROPERTY( BackgroundColour , wxColour , SetBackgroundColour , GetBackgroundColour , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // bg
354 wxPROPERTY( ForegroundColour , wxColour , SetForegroundColour , GetForegroundColour , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // fg
355 wxPROPERTY( Enabled , bool , Enable , IsEnabled , wxxVariant((bool)true) , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
356 wxPROPERTY( Shown , bool , Show , IsShown , wxxVariant((bool)true) , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
51741307
SC
357#if 0
358 // possible property candidates (not in xrc) or not valid in all subclasses
8b5d5223 359 wxPROPERTY( Title,wxString, SetTitle, GetTitle, wxEmptyString )
3a3c8603 360 wxPROPERTY( Font , wxFont , SetFont , GetWindowFont , )
8b5d5223 361 wxPROPERTY( Label,wxString, SetLabel, GetLabel, wxEmptyString )
3a3c8603
DS
362 // MaxHeight, Width , MinHeight , Width
363 // TODO switch label to control and title to toplevels
6a89f9ee 364
3a3c8603
DS
365 wxPROPERTY( ThemeEnabled , bool , SetThemeEnabled , GetThemeEnabled , )
366 //wxPROPERTY( Cursor , wxCursor , SetCursor , GetCursor , )
367 // wxPROPERTY( ToolTip , wxString , SetToolTip , GetToolTipText , )
368 wxPROPERTY( AutoLayout , bool , SetAutoLayout , GetAutoLayout , )
6a89f9ee
SC
369
370
371
51741307 372#endif
321239b6 373wxEND_PROPERTIES_TABLE()
51596bcb 374
321239b6
SC
375wxBEGIN_HANDLERS_TABLE(wxWindow)
376wxEND_HANDLERS_TABLE()
51596bcb 377
321239b6 378wxCONSTRUCTOR_DUMMY(wxWindow)
6a89f9ee 379
51596bcb 380#else
1e6feb95 381 IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
51596bcb 382#endif
1e6feb95
VZ
383#endif // __WXUNIVERSAL__/__WXMSW__
384
385BEGIN_EVENT_TABLE(wxWindowMSW, wxWindowBase)
1e6feb95 386 EVT_SYS_COLOUR_CHANGED(wxWindowMSW::OnSysColourChanged)
8681b094 387 EVT_ERASE_BACKGROUND(wxWindowMSW::OnEraseBackground)
79099b80 388#ifdef __WXWINCE__
1e6feb95 389 EVT_INIT_DIALOG(wxWindowMSW::OnInitDialog)
79099b80 390#endif
2bda0e17
KB
391END_EVENT_TABLE()
392
a23fd0e1
VZ
393// ===========================================================================
394// implementation
395// ===========================================================================
396
42e69d6b
VZ
397// ---------------------------------------------------------------------------
398// wxWindow utility functions
399// ---------------------------------------------------------------------------
400
2bda0e17 401// Find an item given the MS Windows id
1e6feb95 402wxWindow *wxWindowMSW::FindItem(long id) const
2bda0e17 403{
1e6feb95 404#if wxUSE_CONTROLS
f7637829 405 wxControl *item = wxDynamicCastThis(wxControl);
f048e32f
VZ
406 if ( item )
407 {
90e572f1 408 // is it us or one of our "internal" children?
1e6feb95
VZ
409 if ( item->GetId() == id
410#ifndef __WXUNIVERSAL__
411 || (item->GetSubcontrols().Index(id) != wxNOT_FOUND)
412#endif // __WXUNIVERSAL__
413 )
f048e32f
VZ
414 {
415 return item;
416 }
417 }
1e6feb95 418#endif // wxUSE_CONTROLS
f048e32f 419
222ed1d6 420 wxWindowList::compatibility_iterator current = GetChildren().GetFirst();
2d0a075d
JS
421 while (current)
422 {
42e69d6b 423 wxWindow *childWin = current->GetData();
2bda0e17 424
42e69d6b 425 wxWindow *wnd = childWin->FindItem(id);
cc2b7472 426 if ( wnd )
42e69d6b 427 return wnd;
2bda0e17 428
42e69d6b 429 current = current->GetNext();
2bda0e17 430 }
42e69d6b 431
2d0a075d 432 return NULL;
2bda0e17
KB
433}
434
435// Find an item given the MS Windows handle
1e6feb95 436wxWindow *wxWindowMSW::FindItemByHWND(WXHWND hWnd, bool controlOnly) const
2bda0e17 437{
222ed1d6 438 wxWindowList::compatibility_iterator current = GetChildren().GetFirst();
2d0a075d 439 while (current)
2bda0e17 440 {
42e69d6b
VZ
441 wxWindow *parent = current->GetData();
442
2d0a075d 443 // Do a recursive search.
42e69d6b 444 wxWindow *wnd = parent->FindItemByHWND(hWnd);
cc2b7472 445 if ( wnd )
42e69d6b 446 return wnd;
2d0a075d 447
1e6feb95
VZ
448 if ( !controlOnly
449#if wxUSE_CONTROLS
450 || parent->IsKindOf(CLASSINFO(wxControl))
451#endif // wxUSE_CONTROLS
452 )
2d0a075d 453 {
42e69d6b
VZ
454 wxWindow *item = current->GetData();
455 if ( item->GetHWND() == hWnd )
2d0a075d
JS
456 return item;
457 else
458 {
459 if ( item->ContainsHWND(hWnd) )
460 return item;
461 }
462 }
42e69d6b
VZ
463
464 current = current->GetNext();
2bda0e17 465 }
2d0a075d 466 return NULL;
2bda0e17
KB
467}
468
469// Default command handler
1e6feb95 470bool wxWindowMSW::MSWCommand(WXUINT WXUNUSED(param), WXWORD WXUNUSED(id))
2bda0e17 471{
08158721 472 return false;
2bda0e17
KB
473}
474
fd3f686c
VZ
475// ----------------------------------------------------------------------------
476// constructors and such
477// ----------------------------------------------------------------------------
478
1e6feb95 479void wxWindowMSW::Init()
2bda0e17 480{
cc2b7472 481 // MSW specific
08158721 482 m_isBeingDeleted = false;
5a403e3f 483 m_oldWndProc = NULL;
08158721
DS
484 m_mouseInWindow = false;
485 m_lastKeydownProcessed = false;
2bda0e17 486
d7cbabe0 487 m_childrenDisabled = NULL;
a1037371 488 m_frozenness = 0;
d7cbabe0 489
319fefa9 490 m_hWnd = 0;
220f77b0 491 m_hDWP = 0;
319fefa9 492
2d0a075d
JS
493 m_xThumbSize = 0;
494 m_yThumbSize = 0;
2bda0e17 495
67644c1d
RD
496 m_pendingPosition = wxDefaultPosition;
497 m_pendingSize = wxDefaultSize;
7d4f65e3
JS
498
499#ifdef __POCKETPC__
500 m_contextMenuEnabled = false;
501#endif
fd3f686c
VZ
502}
503
2bda0e17 504// Destructor
1e6feb95 505wxWindowMSW::~wxWindowMSW()
2bda0e17 506{
08158721 507 m_isBeingDeleted = true;
2bda0e17 508
2e9f62da 509#ifndef __WXUNIVERSAL__
4a41c655 510 // VS: make sure there's no wxFrame with last focus set to us:
2e9f62da 511 for ( wxWindow *win = GetParent(); win; win = win->GetParent() )
4a41c655 512 {
085ad686 513 wxTopLevelWindow *frame = wxDynamicCast(win, wxTopLevelWindow);
4a41c655
VS
514 if ( frame )
515 {
c5053639 516 if ( frame->GetLastFocus() == this )
2e9f62da 517 {
085ad686 518 frame->SetLastFocus(NULL);
2e9f62da 519 }
4552892f
VZ
520
521 // apparently sometimes we can end up with our grand parent
522 // pointing to us as well: this is surely a bug in focus handling
523 // code but it's not clear where it happens so for now just try to
524 // fix it here by not breaking out of the loop
525 //break;
4a41c655
VS
526 }
527 }
2e9f62da 528#endif // __WXUNIVERSAL__
2bda0e17 529
cc0c7cd8 530 // VS: destroy children first and _then_ detach *this from its parent.
90e572f1 531 // If we did it the other way around, children wouldn't be able
cc0c7cd8
VS
532 // find their parent frame (see above).
533 DestroyChildren();
534
cc2b7472 535 if ( m_hWnd )
42e69d6b 536 {
98440bc3
VZ
537 // VZ: test temp removed to understand what really happens here
538 //if (::IsWindow(GetHwnd()))
df61c009
JS
539 {
540 if ( !::DestroyWindow(GetHwnd()) )
f6bcfd97 541 wxLogLastError(wxT("DestroyWindow"));
df61c009 542 }
2bda0e17 543
c50f1fb9
VZ
544 // remove hWnd <-> wxWindow association
545 wxRemoveHandleAssociation(this);
546 }
d7cbabe0
VZ
547
548 delete m_childrenDisabled;
da78f3b1 549
2bda0e17
KB
550}
551
fd3f686c 552// real construction (Init() must have been called before!)
1e6feb95
VZ
553bool wxWindowMSW::Create(wxWindow *parent,
554 wxWindowID id,
555 const wxPoint& pos,
556 const wxSize& size,
557 long style,
558 const wxString& name)
2d0a075d 559{
08158721 560 wxCHECK_MSG( parent, false, wxT("can't create wxWindow without parent") );
2bda0e17 561
8d99be5f 562 if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) )
08158721 563 return false;
42e69d6b 564
fd3f686c 565 parent->AddChild(this);
2bda0e17 566
b2d5a7ee 567 WXDWORD exstyle;
e49d97e6 568 DWORD msflags = MSWGetCreateWindowFlags(&exstyle);
1e6feb95
VZ
569
570#ifdef __WXUNIVERSAL__
d1fe917b 571 // no borders, we draw them ourselves
76c79ff4
VZ
572 exstyle &= ~(WS_EX_DLGMODALFRAME |
573 WS_EX_STATICEDGE |
574 WS_EX_CLIENTEDGE |
575 WS_EX_WINDOWEDGE);
d1fe917b 576 msflags &= ~WS_BORDER;
b2d5a7ee 577#endif // wxUniversal
1e6feb95 578
ff792344 579 if ( IsShown() )
e49d97e6
VZ
580 {
581 msflags |= WS_VISIBLE;
582 }
1e6feb95 583
45956e37
VZ
584 if ( !MSWCreate(wxCanvasClassName, NULL, pos, size, msflags, exstyle) )
585 return false;
586
587 InheritAttributes();
588
589 return true;
2bda0e17
KB
590}
591
42e69d6b
VZ
592// ---------------------------------------------------------------------------
593// basic operations
594// ---------------------------------------------------------------------------
595
1e6feb95 596void wxWindowMSW::SetFocus()
2bda0e17 597{
a23fd0e1 598 HWND hWnd = GetHwnd();
1e6feb95
VZ
599 wxCHECK_RET( hWnd, _T("can't set focus to invalid window") );
600
7f0586ef 601#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
1e6feb95 602 ::SetLastError(0);
8cb172b4 603#endif
d0a3d109 604
1e6feb95
VZ
605 if ( !::SetFocus(hWnd) )
606 {
5262eb0a 607#if defined(__WXDEBUG__) && !defined(__WXMICROWIN__)
1e6feb95
VZ
608 // was there really an error?
609 DWORD dwRes = ::GetLastError();
610 if ( dwRes )
611 {
5262eb0a
VZ
612 HWND hwndFocus = ::GetFocus();
613 if ( hwndFocus != hWnd )
614 {
615 wxLogApiError(_T("SetFocus"), dwRes);
616 }
1e6feb95 617 }
5262eb0a 618#endif // Debug
1e6feb95 619 }
2bda0e17
KB
620}
621
ddf9d04f
VZ
622void wxWindowMSW::SetFocusFromKbd()
623{
ddf9d04f
VZ
624 // when the focus is given to the control with DLGC_HASSETSEL style from
625 // keyboard its contents should be entirely selected: this is what
626 // ::IsDialogMessage() does and so we should do it as well to provide the
627 // same LNF as the native programs
628 if ( ::SendMessage(GetHwnd(), WM_GETDLGCODE, 0, 0) & DLGC_HASSETSEL )
629 {
630 ::SendMessage(GetHwnd(), EM_SETSEL, 0, -1);
631 }
1b1ca07a
VZ
632
633 // do this after (maybe) setting the selection as like this when
634 // wxEVT_SET_FOCUS handler is called, the selection would have been already
635 // set correctly -- this may be important
636 wxWindowBase::SetFocusFromKbd();
ddf9d04f
VZ
637}
638
42e69d6b 639// Get the window with the focus
0fe02759 640wxWindow *wxWindowBase::DoFindFocus()
42e69d6b
VZ
641{
642 HWND hWnd = ::GetFocus();
643 if ( hWnd )
644 {
a2242341 645 return wxGetWindowFromHWND((WXHWND)hWnd);
42e69d6b
VZ
646 }
647
648 return NULL;
649}
650
1e6feb95 651bool wxWindowMSW::Enable(bool enable)
2bda0e17 652{
cc2b7472 653 if ( !wxWindowBase::Enable(enable) )
08158721 654 return false;
cc2b7472 655
a23fd0e1 656 HWND hWnd = GetHwnd();
cc2b7472 657 if ( hWnd )
2d0a075d 658 ::EnableWindow(hWnd, (BOOL)enable);
cc2b7472 659
83a16cfa
VZ
660 // the logic below doesn't apply to the top level windows -- otherwise
661 // showing a modal dialog would result in total greying out (and ungreying
662 // out later) of everything which would be really ugly
663 if ( IsTopLevel() )
08158721 664 return true;
83a16cfa 665
d7cbabe0
VZ
666 // when the parent is disabled, all of its children should be disabled as
667 // well but when it is enabled back, only those of the children which
668 // hadn't been already disabled in the beginning should be enabled again,
669 // so we have to keep the list of those children
222ed1d6 670 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
fa3d9b4e
VZ
671 node;
672 node = node->GetNext() )
87a1e308
VZ
673 {
674 wxWindow *child = node->GetData();
fa3d9b4e
VZ
675 if ( child->IsTopLevel() )
676 {
677 // the logic below doesn't apply to top level children
678 continue;
679 }
d7cbabe0
VZ
680
681 if ( enable )
682 {
90e572f1 683 // re-enable the child unless it had been disabled before us
d7cbabe0
VZ
684 if ( !m_childrenDisabled || !m_childrenDisabled->Find(child) )
685 child->Enable();
686 }
687 else // we're being disabled
688 {
689 if ( child->IsEnabled() )
690 {
691 // disable it as children shouldn't stay enabled while the
692 // parent is not
693 child->Disable();
694 }
695 else // child already disabled, remember it
696 {
697 // have we created the list of disabled children already?
698 if ( !m_childrenDisabled )
699 m_childrenDisabled = new wxWindowList;
700
701 m_childrenDisabled->Append(child);
702 }
703 }
87a1e308 704 }
d7cbabe0
VZ
705
706 if ( enable && m_childrenDisabled )
707 {
708 // we don't need this list any more, don't keep unused memory
709 delete m_childrenDisabled;
710 m_childrenDisabled = NULL;
711 }
87a1e308 712
08158721 713 return true;
2bda0e17
KB
714}
715
1e6feb95 716bool wxWindowMSW::Show(bool show)
42e69d6b
VZ
717{
718 if ( !wxWindowBase::Show(show) )
08158721 719 return false;
42e69d6b
VZ
720
721 HWND hWnd = GetHwnd();
42e69d6b 722
a068160f
VZ
723 // we could be called before the underlying window is created (this is
724 // actually useful to prevent it from being initially shown), e.g.
725 //
726 // wxFoo *foo = new wxFoo;
727 // foo->Hide();
728 // foo->Create(parent, ...);
729 //
730 // should work without errors
731 if ( hWnd )
42e69d6b 732 {
a068160f 733 ::ShowWindow(hWnd, show ? SW_SHOW : SW_HIDE);
42e69d6b
VZ
734 }
735
08158721 736 return true;
42e69d6b
VZ
737}
738
739// Raise the window to the top of the Z order
1e6feb95 740void wxWindowMSW::Raise()
42e69d6b 741{
c48926e1 742 wxBringWindowToTop(GetHwnd());
42e69d6b
VZ
743}
744
745// Lower the window to the bottom of the Z order
1e6feb95 746void wxWindowMSW::Lower()
42e69d6b
VZ
747{
748 ::SetWindowPos(GetHwnd(), HWND_BOTTOM, 0, 0, 0, 0,
749 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
750}
751
94633ad9 752void wxWindowMSW::DoCaptureMouse()
2bda0e17 753{
a23fd0e1 754 HWND hWnd = GetHwnd();
1e6feb95 755 if ( hWnd )
2d0a075d 756 {
1e6feb95 757 ::SetCapture(hWnd);
2d0a075d 758 }
2bda0e17
KB
759}
760
94633ad9 761void wxWindowMSW::DoReleaseMouse()
2bda0e17 762{
1e6feb95 763 if ( !::ReleaseCapture() )
2d0a075d 764 {
1e6feb95 765 wxLogLastError(_T("ReleaseCapture"));
2d0a075d 766 }
2bda0e17
KB
767}
768
1e6feb95
VZ
769/* static */ wxWindow *wxWindowBase::GetCapture()
770{
771 HWND hwnd = ::GetCapture();
772 return hwnd ? wxFindWinFromHandle((WXHWND)hwnd) : (wxWindow *)NULL;
773}
774
775bool wxWindowMSW::SetFont(const wxFont& font)
2bda0e17 776{
42e69d6b
VZ
777 if ( !wxWindowBase::SetFont(font) )
778 {
779 // nothing to do
08158721 780 return false;
2d0a075d 781 }
195896c7 782
42e69d6b
VZ
783 HWND hWnd = GetHwnd();
784 if ( hWnd != 0 )
785 {
786 WXHANDLE hFont = m_font.GetResourceHandle();
2bda0e17 787
223d09f6 788 wxASSERT_MSG( hFont, wxT("should have valid font") );
3a19e16d 789
c50f1fb9 790 ::SendMessage(hWnd, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
42e69d6b 791 }
2bda0e17 792
08158721 793 return true;
42e69d6b 794}
1e6feb95 795bool wxWindowMSW::SetCursor(const wxCursor& cursor)
2bda0e17 796{
42e69d6b
VZ
797 if ( !wxWindowBase::SetCursor(cursor) )
798 {
799 // no change
08158721 800 return false;
42e69d6b
VZ
801 }
802
8e75dca8
VZ
803 // don't "overwrite" busy cursor
804 if ( m_cursor.Ok() && !wxIsBusy() )
8a9c2246 805 {
8e75dca8 806 ::SetCursor(GetHcursorOf(m_cursor));
8a9c2246 807 }
3a19e16d 808
08158721 809 return true;
3a19e16d
VZ
810}
811
d7e0024b 812void wxWindowMSW::WarpPointer(int x, int y)
2bda0e17 813{
1e6feb95 814 ClientToScreen(&x, &y);
42e69d6b 815
1e6feb95
VZ
816 if ( !::SetCursorPos(x, y) )
817 {
818 wxLogLastError(_T("SetCursorPos"));
819 }
2bda0e17
KB
820}
821
1ca78aa1 822void wxWindowMSW::MSWUpdateUIState(int action, int state)
d7e0024b 823{
1ca78aa1 824 // WM_CHANGEUISTATE only appeared in Windows 2000 so it can do us no good
d7e0024b
VZ
825 // to use it on older systems -- and could possibly do some harm
826 static int s_needToUpdate = -1;
827 if ( s_needToUpdate == -1 )
828 {
829 int verMaj, verMin;
406d283a 830 s_needToUpdate = wxGetOsVersion(&verMaj, &verMin) == wxOS_WINDOWS_NT &&
d7e0024b
VZ
831 verMaj >= 5;
832 }
833
834 if ( s_needToUpdate )
835 {
1ca78aa1
JS
836 // we send WM_CHANGEUISTATE so if nothing needs changing then the system
837 // won't send WM_UPDATEUISTATE
838 ::SendMessage(GetHwnd(), WM_CHANGEUISTATE, MAKEWPARAM(action, state), 0);
d7e0024b
VZ
839 }
840}
841
42e69d6b
VZ
842// ---------------------------------------------------------------------------
843// scrolling stuff
844// ---------------------------------------------------------------------------
2d0a075d 845
9cd6d737
VZ
846inline int GetScrollPosition(HWND hWnd, int wOrient)
847{
848#ifdef __WXMICROWIN__
849 return ::GetScrollPosWX(hWnd, wOrient);
850#else
f676b387 851 WinStruct<SCROLLINFO> scrollInfo;
4676948b 852 scrollInfo.cbSize = sizeof(SCROLLINFO);
7f0586ef 853 scrollInfo.fMask = SIF_POS;
e795e8b5 854 ::GetScrollInfo(hWnd, wOrient, &scrollInfo );
a71d815b 855
7f0586ef 856 return scrollInfo.nPos;
e795e8b5 857
9cd6d737
VZ
858#endif
859}
860
1e6feb95 861int wxWindowMSW::GetScrollPos(int orient) const
2bda0e17 862{
42e69d6b 863 HWND hWnd = GetHwnd();
9cd6d737
VZ
864 wxCHECK_MSG( hWnd, 0, _T("no HWND in GetScrollPos") );
865
0cf5de11 866 return GetScrollPosition(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT);
42e69d6b 867}
2bda0e17 868
42e69d6b
VZ
869// This now returns the whole range, not just the number
870// of positions that we can scroll.
1e6feb95 871int wxWindowMSW::GetScrollRange(int orient) const
42e69d6b 872{
7f0586ef 873 int maxPos;
a23fd0e1 874 HWND hWnd = GetHwnd();
0cf5de11 875 if ( !hWnd )
42e69d6b 876 return 0;
7f0586ef 877#if 0
0cf5de11
VZ
878 ::GetScrollRange(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
879 &minPos, &maxPos);
7f0586ef 880#endif
f676b387 881 WinStruct<SCROLLINFO> scrollInfo;
7f0586ef
JS
882 scrollInfo.fMask = SIF_RANGE;
883 if ( !::GetScrollInfo(hWnd,
f676b387
RD
884 orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
885 &scrollInfo) )
7f0586ef 886 {
f676b387
RD
887 // Most of the time this is not really an error, since the return
888 // value can also be zero when there is no scrollbar yet.
889 // wxLogLastError(_T("GetScrollInfo"));
7f0586ef
JS
890 }
891 maxPos = scrollInfo.nMax;
0cf5de11
VZ
892
893 // undo "range - 1" done in SetScrollbar()
894 return maxPos + 1;
cc2b7472 895}
2bda0e17 896
1e6feb95 897int wxWindowMSW::GetScrollThumb(int orient) const
2bda0e17 898{
0cf5de11 899 return orient == wxHORIZONTAL ? m_xThumbSize : m_yThumbSize;
2bda0e17
KB
900}
901
1e6feb95 902void wxWindowMSW::SetScrollPos(int orient, int pos, bool refresh)
2bda0e17 903{
5f3286d1
VZ
904 HWND hWnd = GetHwnd();
905 wxCHECK_RET( hWnd, _T("SetScrollPos: no HWND") );
72fd19a1 906
0cf5de11 907 WinStruct<SCROLLINFO> info;
42e69d6b
VZ
908 info.nPage = 0;
909 info.nMin = 0;
910 info.nPos = pos;
911 info.fMask = SIF_POS;
a647d42a
VZ
912 if ( HasFlag(wxALWAYS_SHOW_SB) )
913 {
914 // disable scrollbar instead of removing it then
915 info.fMask |= SIF_DISABLENOSCROLL;
916 }
2d0a075d 917
0cf5de11
VZ
918 ::SetScrollInfo(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
919 &info, refresh);
2bda0e17
KB
920}
921
42e69d6b 922// New function that will replace some of the above.
0cf5de11
VZ
923void wxWindowMSW::SetScrollbar(int orient,
924 int pos,
925 int pageSize,
926 int range,
927 bool refresh)
928{
929 WinStruct<SCROLLINFO> info;
930 info.nPage = pageSize;
931 info.nMin = 0; // range is nMax - nMin + 1
932 info.nMax = range - 1; // as both nMax and nMax are inclusive
42e69d6b
VZ
933 info.nPos = pos;
934 info.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
a647d42a
VZ
935 if ( HasFlag(wxALWAYS_SHOW_SB) )
936 {
937 // disable scrollbar instead of removing it then
938 info.fMask |= SIF_DISABLENOSCROLL;
939 }
2bda0e17 940
42e69d6b
VZ
941 HWND hWnd = GetHwnd();
942 if ( hWnd )
81d66cf3 943 {
55a667b6
JS
944 // We have to set the variables here to make them valid in events
945 // triggered by ::SetScrollInfo()
946 *(orient == wxHORIZONTAL ? &m_xThumbSize : &m_yThumbSize) = pageSize;
521bf4ff 947
0cf5de11
VZ
948 ::SetScrollInfo(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
949 &info, refresh);
81d66cf3
JS
950 }
951}
952
1e6feb95 953void wxWindowMSW::ScrollWindow(int dx, int dy, const wxRect *prect)
2bda0e17 954{
574c939e
KB
955 RECT rect;
956 RECT *pr;
1e6feb95 957 if ( prect )
2d0a075d 958 {
1e6feb95
VZ
959 rect.left = prect->x;
960 rect.top = prect->y;
961 rect.right = prect->x + prect->width;
962 rect.bottom = prect->y + prect->height;
f797e53d
VZ
963 pr = &rect;
964 }
965 else
966 {
967 pr = NULL;
304b8bc1 968
2d0a075d 969 }
2bda0e17 970
7f0586ef
JS
971#ifdef __WXWINCE__
972 // FIXME: is this the exact equivalent of the line below?
304b8bc1 973 ::ScrollWindowEx(GetHwnd(), dx, dy, pr, pr, 0, 0, SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
7f0586ef 974#else
f797e53d 975 ::ScrollWindow(GetHwnd(), dx, dy, pr, pr);
7f0586ef 976#endif
2bda0e17
KB
977}
978
9cd6d737 979static bool ScrollVertically(HWND hwnd, int kind, int count)
b9b3393e 980{
9cd6d737
VZ
981 int posStart = GetScrollPosition(hwnd, SB_VERT);
982
983 int pos = posStart;
c0cdd6cc
VZ
984 for ( int n = 0; n < count; n++ )
985 {
986 ::SendMessage(hwnd, WM_VSCROLL, kind, 0);
9cd6d737
VZ
987
988 int posNew = GetScrollPosition(hwnd, SB_VERT);
989 if ( posNew == pos )
990 {
991 // don't bother to continue, we're already at top/bottom
992 break;
993 }
994
995 pos = posNew;
c0cdd6cc 996 }
9cd6d737
VZ
997
998 return pos != posStart;
b9b3393e
VZ
999}
1000
9cd6d737 1001bool wxWindowMSW::ScrollLines(int lines)
b9b3393e
VZ
1002{
1003 bool down = lines > 0;
1004
9cd6d737
VZ
1005 return ScrollVertically(GetHwnd(),
1006 down ? SB_LINEDOWN : SB_LINEUP,
1007 down ? lines : -lines);
b9b3393e
VZ
1008}
1009
9cd6d737 1010bool wxWindowMSW::ScrollPages(int pages)
b9b3393e
VZ
1011{
1012 bool down = pages > 0;
1013
9cd6d737
VZ
1014 return ScrollVertically(GetHwnd(),
1015 down ? SB_PAGEDOWN : SB_PAGEUP,
1016 down ? pages : -pages);
b9b3393e
VZ
1017}
1018
978af864
VZ
1019// ----------------------------------------------------------------------------
1020// RTL support
1021// ----------------------------------------------------------------------------
1022
1023void wxWindowMSW::SetLayoutDirection(wxLayoutDirection dir)
1024{
08a58133
WS
1025#ifdef __WXWINCE__
1026 wxUnusedVar(dir);
1027#else
978af864
VZ
1028 const HWND hwnd = GetHwnd();
1029 wxCHECK_RET( hwnd, _T("layout direction must be set after window creation") );
1030
1031 LONG styleOld = ::GetWindowLong(hwnd, GWL_EXSTYLE);
1032
1033 LONG styleNew = styleOld;
1034 switch ( dir )
1035 {
1036 case wxLayout_LeftToRight:
1037 styleNew &= ~WS_EX_LAYOUTRTL;
1038 break;
1039
1040 case wxLayout_RightToLeft:
1041 styleNew |= WS_EX_LAYOUTRTL;
1042 break;
1043
1044 default:
1045 wxFAIL_MSG(_T("unsupported layout direction"));
1046 break;
1047 }
1048
1049 if ( styleNew != styleOld )
1050 {
1051 ::SetWindowLong(hwnd, GWL_EXSTYLE, styleNew);
1052 }
08a58133 1053#endif
978af864
VZ
1054}
1055
1056wxLayoutDirection wxWindowMSW::GetLayoutDirection() const
1057{
08a58133
WS
1058#ifdef __WXWINCE__
1059 return wxLayout_Default;
1060#else
978af864
VZ
1061 const HWND hwnd = GetHwnd();
1062 wxCHECK_MSG( hwnd, wxLayout_Default, _T("invalid window") );
1063
1064 return ::GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL
1065 ? wxLayout_RightToLeft
1066 : wxLayout_LeftToRight;
08a58133 1067#endif
978af864
VZ
1068}
1069
1070wxCoord
1071wxWindowMSW::AdjustForLayoutDirection(wxCoord x,
1072 wxCoord WXUNUSED(width),
1073 wxCoord WXUNUSED(widthTotal)) const
1074{
1075 // Win32 mirrors the coordinates of RTL windows automatically, so don't
1076 // redo it ourselves
1077 return x;
1078}
1079
42e69d6b
VZ
1080// ---------------------------------------------------------------------------
1081// subclassing
1082// ---------------------------------------------------------------------------
1083
1e6feb95 1084void wxWindowMSW::SubclassWin(WXHWND hWnd)
2bda0e17 1085{
223d09f6 1086 wxASSERT_MSG( !m_oldWndProc, wxT("subclassing window twice?") );
2bda0e17 1087
c50f1fb9 1088 HWND hwnd = (HWND)hWnd;
223d09f6 1089 wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in SubclassWin") );
c50f1fb9
VZ
1090
1091 wxAssociateWinWithHandle(hwnd, this);
2bda0e17 1092
975b6bcf 1093 m_oldWndProc = (WXFARPROC)wxGetWindowProc((HWND)hWnd);
b2d5a7ee 1094
b225f659
VZ
1095 // we don't need to subclass the window of our own class (in the Windows
1096 // sense of the word)
3a3c8603 1097 if ( !wxCheckWindowWndProc(hWnd, (WXFARPROC)wxWndProc) )
b225f659 1098 {
975b6bcf 1099 wxSetWindowProc(hwnd, wxWndProc);
b225f659
VZ
1100 }
1101 else
1102 {
90e572f1 1103 // don't bother restoring it either: this also makes it easy to
08158721 1104 // implement IsOfStandardClass() method which returns true for the
77ffb593 1105 // standard controls and false for the wxWidgets own windows as it can
5a403e3f 1106 // simply check m_oldWndProc
b225f659
VZ
1107 m_oldWndProc = NULL;
1108 }
e7c652bc
VZ
1109
1110 // we're officially created now, send the event
1111 wxWindowCreateEvent event((wxWindow *)this);
1112 (void)GetEventHandler()->ProcessEvent(event);
2bda0e17
KB
1113}
1114
1e6feb95 1115void wxWindowMSW::UnsubclassWin()
2bda0e17 1116{
42e69d6b 1117 wxRemoveHandleAssociation(this);
2bda0e17 1118
42e69d6b 1119 // Restore old Window proc
c50f1fb9
VZ
1120 HWND hwnd = GetHwnd();
1121 if ( hwnd )
42e69d6b 1122 {
ed4780ea 1123 SetHWND(0);
c50f1fb9 1124
223d09f6 1125 wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in UnsubclassWin") );
c50f1fb9 1126
b225f659 1127 if ( m_oldWndProc )
42e69d6b 1128 {
eb5e4d9a 1129 if ( !wxCheckWindowWndProc((WXHWND)hwnd, m_oldWndProc) )
b225f659 1130 {
975b6bcf 1131 wxSetWindowProc(hwnd, (WNDPROC)m_oldWndProc);
b225f659
VZ
1132 }
1133
1134 m_oldWndProc = NULL;
42e69d6b 1135 }
42e69d6b 1136 }
2bda0e17
KB
1137}
1138
a4d1972d 1139void wxWindowMSW::AssociateHandle(WXWidget handle)
ed4780ea
VZ
1140{
1141 if ( m_hWnd )
1142 {
1143 if ( !::DestroyWindow(GetHwnd()) )
1144 wxLogLastError(wxT("DestroyWindow"));
1145 }
a4d1972d 1146
ed4780ea
VZ
1147 WXHWND wxhwnd = (WXHWND)handle;
1148
1149 SetHWND(wxhwnd);
1150 SubclassWin(wxhwnd);
1151}
1152
1153void wxWindowMSW::DissociateHandle()
a4d1972d 1154{
ed4780ea 1155 // this also calls SetHWND(0) for us
a4d1972d 1156 UnsubclassWin();
ed4780ea
VZ
1157}
1158
1159
0c0d1521 1160bool wxCheckWindowWndProc(WXHWND hWnd,
11f104e5 1161 WXFARPROC WXUNUSED(wndProc))
eb5e4d9a 1162{
f57f984c
RD
1163// TODO: This list of window class names should be factored out so they can be
1164// managed in one place and then accessed from here and other places, such as
1165// wxApp::RegisterWindowClasses() and wxApp::UnregisterWindowClasses()
521bf4ff
WS
1166
1167#ifdef __WXWINCE__
3a3c8603
DS
1168 extern wxChar *wxCanvasClassName;
1169 extern wxChar *wxCanvasClassNameNR;
f57f984c
RD
1170#else
1171 extern const wxChar *wxCanvasClassName;
1172 extern const wxChar *wxCanvasClassNameNR;
1173#endif
3a3c8603
DS
1174 extern const wxChar *wxMDIFrameClassName;
1175 extern const wxChar *wxMDIFrameClassNameNoRedraw;
1176 extern const wxChar *wxMDIChildFrameClassName;
1177 extern const wxChar *wxMDIChildFrameClassNameNoRedraw;
1178 wxString str(wxGetWindowClass(hWnd));
1179 if (str == wxCanvasClassName ||
1180 str == wxCanvasClassNameNR ||
26c2a266
JG
1181#if wxUSE_GLCANVAS
1182 str == _T("wxGLCanvasClass") ||
1183 str == _T("wxGLCanvasClassNR") ||
1184#endif // wxUSE_GLCANVAS
3a3c8603
DS
1185 str == wxMDIFrameClassName ||
1186 str == wxMDIFrameClassNameNoRedraw ||
1187 str == wxMDIChildFrameClassName ||
1188 str == wxMDIChildFrameClassNameNoRedraw ||
1189 str == _T("wxTLWHiddenParent"))
1190 return true; // Effectively means don't subclass
f57f984c 1191 else
08158721 1192 return false;
eb5e4d9a
VS
1193}
1194
b2d5a7ee
VZ
1195// ----------------------------------------------------------------------------
1196// Style handling
1197// ----------------------------------------------------------------------------
1198
1199void wxWindowMSW::SetWindowStyleFlag(long flags)
1200{
1201 long flagsOld = GetWindowStyleFlag();
1202 if ( flags == flagsOld )
1203 return;
1204
1205 // update the internal variable
1206 wxWindowBase::SetWindowStyleFlag(flags);
1207
7bd6bf45
VZ
1208 // and the real window flags
1209 MSWUpdateStyle(flagsOld, GetExtraStyle());
1210}
1211
1212void wxWindowMSW::SetExtraStyle(long exflags)
1213{
1214 long exflagsOld = GetExtraStyle();
1215 if ( exflags == exflagsOld )
1216 return;
1217
1218 // update the internal variable
1219 wxWindowBase::SetExtraStyle(exflags);
1220
1221 // and the real window flags
1222 MSWUpdateStyle(GetWindowStyleFlag(), exflagsOld);
1223}
1224
1225void wxWindowMSW::MSWUpdateStyle(long flagsOld, long exflagsOld)
1226{
5b2f31eb
VZ
1227 // now update the Windows style as well if needed - and if the window had
1228 // been already created
1229 if ( !GetHwnd() )
1230 return;
1231
9ce75461
VZ
1232 // we may need to call SetWindowPos() when we change some styles
1233 bool callSWP = false;
1234
7bd6bf45
VZ
1235 WXDWORD exstyle;
1236 long style = MSWGetStyle(GetWindowStyleFlag(), &exstyle);
1237
1238 // this is quite a horrible hack but we need it because MSWGetStyle()
1239 // doesn't take exflags as parameter but uses GetExtraStyle() internally
1240 // and so we have to modify the window exflags temporarily to get the
1241 // correct exstyleOld
1242 long exflagsNew = GetExtraStyle();
1243 wxWindowBase::SetExtraStyle(exflagsOld);
1244
1245 WXDWORD exstyleOld;
1246 long styleOld = MSWGetStyle(flagsOld, &exstyleOld);
1247
1248 wxWindowBase::SetExtraStyle(exflagsNew);
1249
b2d5a7ee
VZ
1250
1251 if ( style != styleOld )
1252 {
1253 // some flags (e.g. WS_VISIBLE or WS_DISABLED) should not be changed by
1254 // this function so instead of simply setting the style to the new
1255 // value we clear the bits which were set in styleOld but are set in
1256 // the new one and set the ones which were not set before
1257 long styleReal = ::GetWindowLong(GetHwnd(), GWL_STYLE);
1258 styleReal &= ~styleOld;
1259 styleReal |= style;
1260
1261 ::SetWindowLong(GetHwnd(), GWL_STYLE, styleReal);
9ce75461 1262
7bd6bf45
VZ
1263 // we need to call SetWindowPos() if any of the styles affecting the
1264 // frame appearance have changed
9ce75461
VZ
1265 callSWP = ((styleOld ^ style ) & (WS_BORDER |
1266 WS_THICKFRAME |
1267 WS_CAPTION |
1268 WS_DLGFRAME |
1269 WS_MAXIMIZEBOX |
1270 WS_MINIMIZEBOX |
1271 WS_SYSMENU) ) != 0;
b2d5a7ee
VZ
1272 }
1273
1274 // and the extended style
9ce75461
VZ
1275 long exstyleReal = ::GetWindowLong(GetHwnd(), GWL_EXSTYLE);
1276
b2d5a7ee
VZ
1277 if ( exstyle != exstyleOld )
1278 {
b2d5a7ee
VZ
1279 exstyleReal &= ~exstyleOld;
1280 exstyleReal |= exstyle;
1281
1282 ::SetWindowLong(GetHwnd(), GWL_EXSTYLE, exstyleReal);
1283
9ce75461
VZ
1284 // ex style changes don't take effect without calling SetWindowPos
1285 callSWP = true;
1286 }
1287
1288 if ( callSWP )
1289 {
85d8df29 1290 // we must call SetWindowPos() to flush the cached extended style and
b2d5a7ee
VZ
1291 // also to make the change to wxSTAY_ON_TOP style take effect: just
1292 // setting the style simply doesn't work
1293 if ( !::SetWindowPos(GetHwnd(),
1294 exstyleReal & WS_EX_TOPMOST ? HWND_TOPMOST
1295 : HWND_NOTOPMOST,
1296 0, 0, 0, 0,
9ce75461 1297 SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED) )
b2d5a7ee
VZ
1298 {
1299 wxLogLastError(_T("SetWindowPos"));
1300 }
1301 }
1302}
1303
1304WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const
1305{
77ffb593 1306 // translate common wxWidgets styles to Windows ones
af495479
VZ
1307
1308 // most of windows are child ones, those which are not (such as
1309 // wxTopLevelWindow) should remove WS_CHILD in their MSWGetStyle()
1310 WXDWORD style = WS_CHILD;
b2d5a7ee 1311
9b6ae450
VZ
1312 // using this flag results in very significant reduction in flicker,
1313 // especially with controls inside the static boxes (as the interior of the
90e572f1 1314 // box is not redrawn twice), but sometimes results in redraw problems, so
c7e1d004
VZ
1315 // optionally allow the old code to continue to use it provided a special
1316 // system option is turned on
1317 if ( !wxSystemOptions::GetOptionInt(wxT("msw.window.no-clip-children"))
1318 || (flags & wxCLIP_CHILDREN) )
c6430ed0 1319 style |= WS_CLIPCHILDREN;
9b6ae450
VZ
1320
1321 // it doesn't seem useful to use WS_CLIPSIBLINGS here as we officially
1322 // don't support overlapping windows and it only makes sense for them and,
1323 // presumably, gives the system some extra work (to manage more clipping
1324 // regions), so avoid it alltogether
b2d5a7ee 1325
b2d5a7ee 1326
f9007c32
JS
1327 if ( flags & wxVSCROLL )
1328 style |= WS_VSCROLL;
1329
1330 if ( flags & wxHSCROLL )
1331 style |= WS_HSCROLL;
1332
65bc172c 1333 const wxBorder border = GetBorder(flags);
577baeef 1334
65bc172c
VZ
1335 // WS_BORDER is only required for wxBORDER_SIMPLE
1336 if ( border == wxBORDER_SIMPLE )
b2d5a7ee 1337 style |= WS_BORDER;
577baeef 1338
b2d5a7ee
VZ
1339 // now deal with ext style if the caller wants it
1340 if ( exstyle )
1341 {
1342 *exstyle = 0;
1343
7f0586ef 1344#ifndef __WXWINCE__
b2d5a7ee
VZ
1345 if ( flags & wxTRANSPARENT_WINDOW )
1346 *exstyle |= WS_EX_TRANSPARENT;
7f0586ef 1347#endif
b2d5a7ee 1348
fe3d9123 1349 switch ( border )
b2d5a7ee
VZ
1350 {
1351 default:
65bc172c 1352 case wxBORDER_DEFAULT:
b2d5a7ee
VZ
1353 wxFAIL_MSG( _T("unknown border style") );
1354 // fall through
1355
1356 case wxBORDER_NONE:
1357 case wxBORDER_SIMPLE:
1358 break;
1359
1360 case wxBORDER_STATIC:
1361 *exstyle |= WS_EX_STATICEDGE;
1362 break;
1363
1364 case wxBORDER_RAISED:
7699361c 1365 *exstyle |= WS_EX_DLGMODALFRAME;
b2d5a7ee
VZ
1366 break;
1367
b2d5a7ee
VZ
1368 case wxBORDER_SUNKEN:
1369 *exstyle |= WS_EX_CLIENTEDGE;
fe3d9123 1370 style &= ~WS_BORDER;
b2d5a7ee
VZ
1371 break;
1372
1373 case wxBORDER_DOUBLE:
1374 *exstyle |= WS_EX_DLGMODALFRAME;
1375 break;
1376 }
d515c32d 1377
09168de7 1378 // wxUniv doesn't use Windows dialog navigation functions at all
7f0586ef 1379#if !defined(__WXUNIVERSAL__) && !defined(__WXWINCE__)
5b9c12e1 1380 // to make the dialog navigation work with the nested panels we must
09168de7
VZ
1381 // use this style (top level windows such as dialogs don't need it)
1382 if ( (flags & wxTAB_TRAVERSAL) && !IsTopLevel() )
d515c32d
VZ
1383 {
1384 *exstyle |= WS_EX_CONTROLPARENT;
1385 }
09168de7 1386#endif // __WXUNIVERSAL__
b2d5a7ee
VZ
1387 }
1388
1389 return style;
1390}
eb5e4d9a 1391
42e69d6b 1392// Setup background and foreground colours correctly
1e6feb95 1393void wxWindowMSW::SetupColours()
42e69d6b
VZ
1394{
1395 if ( GetParent() )
1396 SetBackgroundColour(GetParent()->GetBackgroundColour());
1397}
a23fd0e1 1398
1e6feb95
VZ
1399bool wxWindowMSW::IsMouseInWindow() const
1400{
1401 // get the mouse position
1402 POINT pt;
f2325516
JS
1403#ifdef __WXWINCE__
1404 ::GetCursorPosWinCE(&pt);
1405#else
1e6feb95 1406 ::GetCursorPos(&pt);
f2325516 1407#endif
1e6feb95
VZ
1408
1409 // find the window which currently has the cursor and go up the window
1410 // chain until we find this window - or exhaust it
1411 HWND hwnd = ::WindowFromPoint(pt);
1412 while ( hwnd && (hwnd != GetHwnd()) )
1413 hwnd = ::GetParent(hwnd);
1414
1415 return hwnd != NULL;
1416}
1417
e39af974 1418void wxWindowMSW::OnInternalIdle()
42e69d6b 1419{
4e5c6c33 1420#ifndef HAVE_TRACKMOUSEEVENT
42e69d6b
VZ
1421 // Check if we need to send a LEAVE event
1422 if ( m_mouseInWindow )
2d0a075d 1423 {
ee74faf9
VZ
1424 // note that we should generate the leave event whether the window has
1425 // or doesn't have mouse capture
1426 if ( !IsMouseInWindow() )
42e69d6b 1427 {
51e4e266 1428 GenerateMouseLeave();
42e69d6b
VZ
1429 }
1430 }
4e5c6c33 1431#endif // !HAVE_TRACKMOUSEEVENT
c085e333 1432
e39af974
JS
1433 if (wxUpdateUIEvent::CanUpdate(this))
1434 UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
42e69d6b 1435}
568cb543 1436
42e69d6b 1437// Set this window to be the child of 'parent'.
1e6feb95 1438bool wxWindowMSW::Reparent(wxWindowBase *parent)
42e69d6b
VZ
1439{
1440 if ( !wxWindowBase::Reparent(parent) )
08158721 1441 return false;
c085e333 1442
42e69d6b
VZ
1443 HWND hWndChild = GetHwnd();
1444 HWND hWndParent = GetParent() ? GetWinHwnd(GetParent()) : (HWND)0;
a23fd0e1 1445
42e69d6b 1446 ::SetParent(hWndChild, hWndParent);
a23fd0e1 1447
ee471817
VZ
1448#ifndef __WXWINCE__
1449 if ( ::GetWindowLong(hWndChild, GWL_EXSTYLE) & WS_EX_CONTROLPARENT )
1450 {
1451 EnsureParentHasControlParentStyle(GetParent());
1452 }
1453#endif // !__WXWINCE__
1454
08158721 1455 return true;
42e69d6b 1456}
a23fd0e1 1457
a0e449ff
VZ
1458static inline void SendSetRedraw(HWND hwnd, bool on)
1459{
c67d6888 1460#ifndef __WXMICROWIN__
a0e449ff 1461 ::SendMessage(hwnd, WM_SETREDRAW, (WPARAM)on, 0);
c67d6888 1462#endif
a0e449ff
VZ
1463}
1464
1465void wxWindowMSW::Freeze()
1466{
a1037371
VZ
1467 if ( !m_frozenness++ )
1468 {
dc993cbf
VZ
1469 if ( IsShown() )
1470 SendSetRedraw(GetHwnd(), false);
a1037371 1471 }
a0e449ff
VZ
1472}
1473
1474void wxWindowMSW::Thaw()
1475{
a1037371 1476 wxASSERT_MSG( m_frozenness > 0, _T("Thaw() without matching Freeze()") );
c0cdd6cc 1477
8d7eaf91 1478 if ( --m_frozenness == 0 )
a1037371 1479 {
dc993cbf
VZ
1480 if ( IsShown() )
1481 {
1482 SendSetRedraw(GetHwnd(), true);
a1037371 1483
dc993cbf
VZ
1484 // we need to refresh everything or otherwise the invalidated area
1485 // is not going to be repainted
1486 Refresh();
1487 }
a1037371 1488 }
a0e449ff
VZ
1489}
1490
1e6feb95 1491void wxWindowMSW::Refresh(bool eraseBack, const wxRect *rect)
42e69d6b
VZ
1492{
1493 HWND hWnd = GetHwnd();
1494 if ( hWnd )
1495 {
d181e053
VZ
1496 RECT mswRect;
1497 const RECT *pRect;
42e69d6b
VZ
1498 if ( rect )
1499 {
42e69d6b
VZ
1500 mswRect.left = rect->x;
1501 mswRect.top = rect->y;
1502 mswRect.right = rect->x + rect->width;
1503 mswRect.bottom = rect->y + rect->height;
a23fd0e1 1504
d181e053 1505 pRect = &mswRect;
42e69d6b
VZ
1506 }
1507 else
d181e053
VZ
1508 {
1509 pRect = NULL;
1510 }
1511
82e3664e 1512 // RedrawWindow not available on SmartPhone or eVC++ 3
41527143 1513#if !defined(__SMARTPHONE__) && !(defined(_WIN32_WCE) && _WIN32_WCE < 400)
d181e053
VZ
1514 UINT flags = RDW_INVALIDATE | RDW_ALLCHILDREN;
1515 if ( eraseBack )
1516 flags |= RDW_ERASE;
1517
1518 ::RedrawWindow(hWnd, pRect, NULL, flags);
480e9098 1519#else
16d652a5 1520 ::InvalidateRect(hWnd, pRect, eraseBack);
480e9098 1521#endif
42e69d6b
VZ
1522 }
1523}
a23fd0e1 1524
1e6feb95
VZ
1525void wxWindowMSW::Update()
1526{
1527 if ( !::UpdateWindow(GetHwnd()) )
1528 {
1529 wxLogLastError(_T("UpdateWindow"));
1530 }
2b5f62a0 1531
7f0586ef 1532#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
1e6feb95
VZ
1533 // just calling UpdateWindow() is not enough, what we did in our WM_PAINT
1534 // handler needs to be really drawn right now
1535 (void)::GdiFlush();
1536#endif // __WIN32__
1537}
1538
42e69d6b
VZ
1539// ---------------------------------------------------------------------------
1540// drag and drop
1541// ---------------------------------------------------------------------------
a23fd0e1 1542
3febc967
VZ
1543#if wxUSE_DRAG_AND_DROP || !defined(__WXWINCE__)
1544
1545#if wxUSE_STATBOX
1546
006b8dff
JG
1547// we need to lower the sibling static boxes so controls contained within can be
1548// a drop target
3febc967 1549static void AdjustStaticBoxZOrder(wxWindow *parent)
006b8dff 1550{
deb0d191
JG
1551 // no sibling static boxes if we have no parent (ie TLW)
1552 if ( !parent )
1553 return;
1554
006b8dff
JG
1555 for ( wxWindowList::compatibility_iterator node = parent->GetChildren().GetFirst();
1556 node;
1557 node = node->GetNext() )
1558 {
1559 wxStaticBox *statbox = wxDynamicCast(node->GetData(), wxStaticBox);
1560 if ( statbox )
1561 {
1562 ::SetWindowPos(GetHwndOf(statbox), HWND_BOTTOM, 0, 0, 0, 0,
1563 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
1564 }
1565 }
1566}
a23fd0e1 1567
3febc967
VZ
1568#else // !wxUSE_STATBOX
1569
1570static inline void AdjustStaticBoxZOrder(wxWindow * WXUNUSED(parent))
1571{
1572}
1573
1574#endif // wxUSE_STATBOX/!wxUSE_STATBOX
1575
1576#endif // drag and drop is used
1577
4ce1efe1 1578#if wxUSE_DRAG_AND_DROP
1e6feb95 1579void wxWindowMSW::SetDropTarget(wxDropTarget *pDropTarget)
42e69d6b
VZ
1580{
1581 if ( m_dropTarget != 0 ) {
1582 m_dropTarget->Revoke(m_hWnd);
1583 delete m_dropTarget;
1584 }
a23fd0e1 1585
42e69d6b
VZ
1586 m_dropTarget = pDropTarget;
1587 if ( m_dropTarget != 0 )
006b8dff
JG
1588 {
1589 AdjustStaticBoxZOrder(GetParent());
42e69d6b 1590 m_dropTarget->Register(m_hWnd);
006b8dff 1591 }
42e69d6b 1592}
42e69d6b 1593#endif // wxUSE_DRAG_AND_DROP
2a47d3c1 1594
90e572f1 1595// old-style file manager drag&drop support: we retain the old-style
42e69d6b 1596// DragAcceptFiles in parallel with SetDropTarget.
0c0d1521 1597void wxWindowMSW::DragAcceptFiles(bool WXUNUSED_IN_WINCE(accept))
42e69d6b 1598{
0c0d1521 1599#ifndef __WXWINCE__
42e69d6b
VZ
1600 HWND hWnd = GetHwnd();
1601 if ( hWnd )
006b8dff
JG
1602 {
1603 AdjustStaticBoxZOrder(GetParent());
42e69d6b 1604 ::DragAcceptFiles(hWnd, (BOOL)accept);
006b8dff 1605 }
7f0586ef 1606#endif
42e69d6b 1607}
a23fd0e1 1608
42e69d6b
VZ
1609// ----------------------------------------------------------------------------
1610// tooltips
1611// ----------------------------------------------------------------------------
dbda9e86 1612
42e69d6b 1613#if wxUSE_TOOLTIPS
2d0a075d 1614
1e6feb95 1615void wxWindowMSW::DoSetToolTip(wxToolTip *tooltip)
42e69d6b
VZ
1616{
1617 wxWindowBase::DoSetToolTip(tooltip);
839b865d 1618
42e69d6b 1619 if ( m_tooltip )
d4e5272b 1620 m_tooltip->SetWindow((wxWindow *)this);
42e69d6b 1621}
9a05fd8d 1622
42e69d6b 1623#endif // wxUSE_TOOLTIPS
9a05fd8d 1624
42e69d6b
VZ
1625// ---------------------------------------------------------------------------
1626// moving and resizing
1627// ---------------------------------------------------------------------------
839b865d 1628
f7040b5f
VZ
1629bool wxWindowMSW::IsSizeDeferred() const
1630{
1631#if USE_DEFERRED_SIZING
1632 if ( m_pendingPosition != wxDefaultPosition ||
1633 m_pendingSize != wxDefaultSize )
1634 return true;
1635#endif // USE_DEFERRED_SIZING
1636
1637 return false;
1638}
1639
42e69d6b 1640// Get total size
1e6feb95 1641void wxWindowMSW::DoGetSize(int *x, int *y) const
42e69d6b 1642{
0d6fdb3c 1643#if USE_DEFERRED_SIZING
11cfa8ef
VZ
1644 // if SetSize() had been called at wx level but not realized at Windows
1645 // level yet (i.e. EndDeferWindowPos() not called), we still should return
1646 // the new and not the old position to the other wx code
1647 if ( m_pendingSize != wxDefaultSize )
1648 {
1649 if ( x )
1650 *x = m_pendingSize.x;
1651 if ( y )
1652 *y = m_pendingSize.y;
1653 }
1654 else // use current size
0d6fdb3c 1655#endif // USE_DEFERRED_SIZING
11cfa8ef
VZ
1656 {
1657 RECT rect = wxGetWindowRect(GetHwnd());
82c9f85c 1658
11cfa8ef
VZ
1659 if ( x )
1660 *x = rect.right - rect.left;
1661 if ( y )
1662 *y = rect.bottom - rect.top;
1663 }
42e69d6b
VZ
1664}
1665
82c9f85c
VZ
1666// Get size *available for subwindows* i.e. excluding menu bar etc.
1667void wxWindowMSW::DoGetClientSize(int *x, int *y) const
42e69d6b 1668{
f2197644 1669#if USE_DEFERRED_SIZING
0d6fdb3c 1670 if ( m_pendingSize != wxDefaultSize )
0d7f75df 1671 {
0d6fdb3c 1672 // we need to calculate the client size corresponding to pending size
dc497201
JG
1673 RECT rect;
1674 rect.left = m_pendingPosition.x;
1675 rect.top = m_pendingPosition.y;
1676 rect.right = rect.left + m_pendingSize.x;
1677 rect.bottom = rect.top + m_pendingSize.y;
1678
1679 ::SendMessage(GetHwnd(), WM_NCCALCSIZE, FALSE, (LPARAM)&rect);
1680
1681 if ( x )
1682 *x = rect.right - rect.left;
1683 if ( y )
1684 *y = rect.bottom - rect.top;
0d7f75df 1685 }
0d6fdb3c
VZ
1686 else
1687#endif // USE_DEFERRED_SIZING
1688 {
1689 RECT rect = wxGetClientRect(GetHwnd());
1690
1691 if ( x )
1692 *x = rect.right;
1693 if ( y )
1694 *y = rect.bottom;
1695 }
82c9f85c
VZ
1696}
1697
1698void wxWindowMSW::DoGetPosition(int *x, int *y) const
1699{
a7e0e432
VZ
1700 wxWindow * const parent = GetParent();
1701
1702 wxPoint pos;
11cfa8ef
VZ
1703 if ( m_pendingPosition != wxDefaultPosition )
1704 {
a7e0e432 1705 pos = m_pendingPosition;
11cfa8ef
VZ
1706 }
1707 else // use current position
1708 {
1709 RECT rect = wxGetWindowRect(GetHwnd());
42e69d6b 1710
11cfa8ef
VZ
1711 POINT point;
1712 point.x = rect.left;
1713 point.y = rect.top;
42e69d6b 1714
11cfa8ef
VZ
1715 // we do the adjustments with respect to the parent only for the "real"
1716 // children, not for the dialogs/frames
1717 if ( !IsTopLevel() )
92049cd4 1718 {
e5b5af91
VZ
1719 if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft )
1720 {
967acfb5 1721 // In RTL mode, we want the logical left x-coordinate,
e5b5af91
VZ
1722 // which would be the physical right x-coordinate.
1723 point.x = rect.right;
1724 }
1725
11cfa8ef
VZ
1726 // Since we now have the absolute screen coords, if there's a
1727 // parent we must subtract its top left corner
11cfa8ef
VZ
1728 if ( parent )
1729 {
a7e0e432 1730 ::ScreenToClient(GetHwndOf(parent), &point);
11cfa8ef 1731 }
89e3037c 1732 }
42e69d6b 1733
a7e0e432
VZ
1734 pos.x = point.x;
1735 pos.y = point.y;
1736 }
1737
1738 // we also must adjust by the client area offset: a control which is just
1739 // under a toolbar could be at (0, 30) in Windows but at (0, 0) in wx
1740 if ( parent && !IsTopLevel() )
1741 {
1742 const wxPoint pt(parent->GetClientAreaOrigin());
1743 pos.x -= pt.x;
1744 pos.y -= pt.y;
11cfa8ef 1745 }
a7e0e432
VZ
1746
1747 if ( x )
1748 *x = pos.x;
1749 if ( y )
1750 *y = pos.y;
42e69d6b 1751}
54bdd8b0 1752
1e6feb95 1753void wxWindowMSW::DoScreenToClient(int *x, int *y) const
42e69d6b
VZ
1754{
1755 POINT pt;
1756 if ( x )
1757 pt.x = *x;
1758 if ( y )
1759 pt.y = *y;
54bdd8b0 1760
82c9f85c 1761 ::ScreenToClient(GetHwnd(), &pt);
a23fd0e1 1762
42e69d6b
VZ
1763 if ( x )
1764 *x = pt.x;
1765 if ( y )
1766 *y = pt.y;
1767}
a23fd0e1 1768
1e6feb95 1769void wxWindowMSW::DoClientToScreen(int *x, int *y) const
42e69d6b
VZ
1770{
1771 POINT pt;
1772 if ( x )
1773 pt.x = *x;
1774 if ( y )
1775 pt.y = *y;
54bdd8b0 1776
82c9f85c 1777 ::ClientToScreen(GetHwnd(), &pt);
a23fd0e1 1778
42e69d6b
VZ
1779 if ( x )
1780 *x = pt.x;
1781 if ( y )
1782 *y = pt.y;
1783}
a23fd0e1 1784
86e30911 1785bool
7d86a2d4
VZ
1786wxWindowMSW::DoMoveSibling(WXHWND hwnd, int x, int y, int width, int height)
1787{
1788#if USE_DEFERRED_SIZING
1789 // if our parent had prepared a defer window handle for us, use it (unless
1790 // we are a top level window)
1791 wxWindowMSW * const parent = IsTopLevel() ? NULL : GetParent();
1792
1793 HDWP hdwp = parent ? (HDWP)parent->m_hDWP : NULL;
1794 if ( hdwp )
1795 {
1796 hdwp = ::DeferWindowPos(hdwp, (HWND)hwnd, NULL, x, y, width, height,
dd28827a 1797 SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE);
7d86a2d4
VZ
1798 if ( !hdwp )
1799 {
1800 wxLogLastError(_T("DeferWindowPos"));
1801 }
1802 }
1803
1804 if ( parent )
1805 {
1806 // hdwp must be updated as it may have been changed
1807 parent->m_hDWP = (WXHANDLE)hdwp;
1808 }
1809
86e30911
VZ
1810 if ( hdwp )
1811 {
1812 // did deferred move, remember new coordinates of the window as they're
1813 // different from what Windows would return for it
1814 return true;
1815 }
1816
7d86a2d4 1817 // otherwise (or if deferring failed) move the window in place immediately
7d86a2d4 1818#endif // USE_DEFERRED_SIZING
86e30911 1819 if ( !::MoveWindow((HWND)hwnd, x, y, width, height, IsShown()) )
7d86a2d4 1820 {
86e30911 1821 wxLogLastError(wxT("MoveWindow"));
7d86a2d4 1822 }
86e30911
VZ
1823
1824 // if USE_DEFERRED_SIZING, indicates that we didn't use deferred move,
1825 // ignored otherwise
1826 return false;
7d86a2d4
VZ
1827}
1828
1e6feb95 1829void wxWindowMSW::DoMoveWindow(int x, int y, int width, int height)
b782f2e0 1830{
62e1ba75
JS
1831 // TODO: is this consistent with other platforms?
1832 // Still, negative width or height shouldn't be allowed
1833 if (width < 0)
1834 width = 0;
1835 if (height < 0)
1836 height = 0;
9b6ae450 1837
86e30911
VZ
1838 if ( DoMoveSibling(m_hWnd, x, y, width, height) )
1839 {
1840#if USE_DEFERRED_SIZING
1841 m_pendingPosition = wxPoint(x, y);
1842 m_pendingSize = wxSize(width, height);
1843#endif // USE_DEFERRED_SIZING
1844 }
b782f2e0
VZ
1845}
1846
4438caf4
VZ
1847// set the size of the window: if the dimensions are positive, just use them,
1848// but if any of them is equal to -1, it means that we must find the value for
1849// it ourselves (unless sizeFlags contains wxSIZE_ALLOW_MINUS_ONE flag, in
1850// which case -1 is a valid value for x and y)
1851//
1852// If sizeFlags contains wxSIZE_AUTO_WIDTH/HEIGHT flags (default), we calculate
1853// the width/height to best suit our contents, otherwise we reuse the current
1854// width/height
1e6feb95 1855void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags)
42e69d6b 1856{
4438caf4 1857 // get the current size and position...
42e69d6b 1858 int currentX, currentY;
da78f3b1
RD
1859 int currentW, currentH;
1860
42e69d6b 1861 GetPosition(&currentX, &currentY);
42e69d6b 1862 GetSize(&currentW, &currentH);
a23fd0e1 1863
952f2aaa
VZ
1864 // ... and don't do anything (avoiding flicker) if it's already ok unless
1865 // we're forced to resize the window
4438caf4 1866 if ( x == currentX && y == currentY &&
952f2aaa
VZ
1867 width == currentW && height == currentH &&
1868 !(sizeFlags & wxSIZE_FORCE) )
4438caf4 1869 {
42e69d6b 1870 return;
4438caf4 1871 }
a23fd0e1 1872
422d0ff0 1873 if ( x == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
4438caf4 1874 x = currentX;
422d0ff0 1875 if ( y == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
4438caf4 1876 y = currentY;
a23fd0e1 1877
4438caf4 1878 AdjustForParentClientOrigin(x, y, sizeFlags);
a23fd0e1 1879
abb74e0f 1880 wxSize size = wxDefaultSize;
422d0ff0 1881 if ( width == wxDefaultCoord )
4438caf4 1882 {
9e2896e5 1883 if ( sizeFlags & wxSIZE_AUTO_WIDTH )
4438caf4
VZ
1884 {
1885 size = DoGetBestSize();
1886 width = size.x;
1887 }
1888 else
1889 {
1890 // just take the current one
1891 width = currentW;
1892 }
1893 }
1894
422d0ff0 1895 if ( height == wxDefaultCoord )
4438caf4 1896 {
9e2896e5 1897 if ( sizeFlags & wxSIZE_AUTO_HEIGHT )
4438caf4 1898 {
422d0ff0 1899 if ( size.x == wxDefaultCoord )
4438caf4 1900 {
b782f2e0 1901 size = DoGetBestSize();
4438caf4
VZ
1902 }
1903 //else: already called DoGetBestSize() above
a23fd0e1 1904
4438caf4
VZ
1905 height = size.y;
1906 }
1907 else
1908 {
1909 // just take the current one
1910 height = currentH;
1911 }
1912 }
1913
b782f2e0 1914 DoMoveWindow(x, y, width, height);
4438caf4
VZ
1915}
1916
1e6feb95 1917void wxWindowMSW::DoSetClientSize(int width, int height)
42e69d6b 1918{
90e572f1 1919 // setting the client size is less obvious than it could have been
d4597e13 1920 // because in the result of changing the total size the window scrollbar
c72b1ad7
VZ
1921 // may [dis]appear and/or its menubar may [un]wrap (and AdjustWindowRect()
1922 // doesn't take neither into account) and so the client size will not be
1923 // correct as the difference between the total and client size changes --
1924 // so we keep changing it until we get it right
d4597e13 1925 //
d6a97306
VZ
1926 // normally this loop shouldn't take more than 3 iterations (usually 1 but
1927 // if scrollbars [dis]appear as the result of the first call, then 2 and it
1928 // may become 3 if the window had 0 size originally and so we didn't
1929 // calculate the scrollbar correction correctly during the first iteration)
1930 // but just to be on the safe side we check for it instead of making it an
d4597e13 1931 // "infinite" loop (i.e. leaving break inside as the only way to get out)
d6a97306 1932 for ( int i = 0; i < 4; i++ )
d4597e13
VZ
1933 {
1934 RECT rectClient;
1935 ::GetClientRect(GetHwnd(), &rectClient);
2bda0e17 1936
b0268daf 1937 // if the size is already ok, stop here (NB: rectClient.left = top = 0)
422d0ff0
WS
1938 if ( (rectClient.right == width || width == wxDefaultCoord) &&
1939 (rectClient.bottom == height || height == wxDefaultCoord) )
d4597e13
VZ
1940 {
1941 break;
1942 }
a23fd0e1 1943
d4597e13
VZ
1944 // Find the difference between the entire window (title bar and all)
1945 // and the client area; add this to the new client size to move the
1946 // window
1947 RECT rectWin;
1948 ::GetWindowRect(GetHwnd(), &rectWin);
1949
b0268daf
VZ
1950 const int widthWin = rectWin.right - rectWin.left,
1951 heightWin = rectWin.bottom - rectWin.top;
387a3b02 1952
d4597e13
VZ
1953 // MoveWindow positions the child windows relative to the parent, so
1954 // adjust if necessary
1955 if ( !IsTopLevel() )
1956 {
1957 wxWindow *parent = GetParent();
1958 if ( parent )
1959 {
b0268daf 1960 ::ScreenToClient(GetHwndOf(parent), (POINT *)&rectWin);
d4597e13
VZ
1961 }
1962 }
a23fd0e1 1963
b0268daf 1964 // don't call DoMoveWindow() because we want to move window immediately
c72b1ad7
VZ
1965 // and not defer it here as otherwise the value returned by
1966 // GetClient/WindowRect() wouldn't change as the window wouldn't be
1967 // really resized
b0268daf
VZ
1968 if ( !::MoveWindow(GetHwnd(),
1969 rectWin.left,
1970 rectWin.top,
1971 width + widthWin - rectClient.right,
1972 height + heightWin - rectClient.bottom,
1973 TRUE) )
1974 {
1975 wxLogLastError(_T("MoveWindow"));
1976 }
d4597e13 1977 }
42e69d6b 1978}
a23fd0e1 1979
42e69d6b
VZ
1980// ---------------------------------------------------------------------------
1981// text metrics
1982// ---------------------------------------------------------------------------
a23fd0e1 1983
1e6feb95 1984int wxWindowMSW::GetCharHeight() const
42e69d6b 1985{
f6bcfd97 1986 return wxGetTextMetrics(this).tmHeight;
42e69d6b 1987}
3eddf563 1988
1e6feb95 1989int wxWindowMSW::GetCharWidth() const
42e69d6b 1990{
f6bcfd97
BP
1991 // +1 is needed because Windows apparently adds it when calculating the
1992 // dialog units size in pixels
1993#if wxDIALOG_UNIT_COMPATIBILITY
1e6feb95 1994 return wxGetTextMetrics(this).tmAveCharWidth;
f6bcfd97
BP
1995#else
1996 return wxGetTextMetrics(this).tmAveCharWidth + 1;
1997#endif
42e69d6b 1998}
f4621a09 1999
1e6feb95 2000void wxWindowMSW::GetTextExtent(const wxString& string,
34636400 2001 int *x, int *y,
42e69d6b
VZ
2002 int *descent, int *externalLeading,
2003 const wxFont *theFont) const
2004{
64869ab7
VZ
2005 wxASSERT_MSG( !theFont || theFont->Ok(),
2006 _T("invalid font in GetTextExtent()") );
634903fd 2007
2d17baae
VS
2008 wxFont fontToUse;
2009 if (theFont)
2010 fontToUse = *theFont;
2011 else
2012 fontToUse = GetFont();
634903fd 2013
64869ab7
VZ
2014 WindowHDC hdc(GetHwnd());
2015 SelectInHDC selectFont(hdc, GetHfontOf(fontToUse));
341c92a8 2016
42e69d6b
VZ
2017 SIZE sizeRect;
2018 TEXTMETRIC tm;
767b35a5 2019 ::GetTextExtentPoint32(hdc, string, string.length(), &sizeRect);
64869ab7 2020 GetTextMetrics(hdc, &tm);
42e69d6b 2021
0655ad29
VZ
2022 if ( x )
2023 *x = sizeRect.cx;
2024 if ( y )
2025 *y = sizeRect.cy;
2026 if ( descent )
2027 *descent = tm.tmDescent;
2028 if ( externalLeading )
2029 *externalLeading = tm.tmExternalLeading;
2bda0e17
KB
2030}
2031
c50f1fb9
VZ
2032// ---------------------------------------------------------------------------
2033// popup menu
2034// ---------------------------------------------------------------------------
2035
2e9f62da
VZ
2036#if wxUSE_MENUS_NATIVE
2037
ed45e263
VZ
2038// yield for WM_COMMAND events only, i.e. process all WM_COMMANDs in the queue
2039// immediately, without waiting for the next event loop iteration
2040//
2041// NB: this function should probably be made public later as it can almost
2042// surely replace wxYield() elsewhere as well
2043static void wxYieldForCommandsOnly()
2044{
2045 // peek all WM_COMMANDs (it will always return WM_QUIT too but we don't
2046 // want to process it here)
2047 MSG msg;
1bf77ee5 2048 while ( ::PeekMessage(&msg, (HWND)0, WM_COMMAND, WM_COMMAND, PM_REMOVE) )
ed45e263 2049 {
dd7ebf8b 2050 if ( msg.message == WM_QUIT )
1bf77ee5
VZ
2051 {
2052 // if we retrieved a WM_QUIT, insert back into the message queue.
2053 ::PostQuitMessage(0);
2054 break;
2055 }
7de59551 2056
1bf77ee5
VZ
2057 // luckily (as we don't have access to wxEventLoopImpl method from here
2058 // anyhow...) we don't need to pre process WM_COMMANDs so dispatch it
2059 // immediately
2060 ::TranslateMessage(&msg);
2061 ::DispatchMessage(&msg);
2062 }
ed45e263
VZ
2063}
2064
1e6feb95 2065bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y)
c50f1fb9
VZ
2066{
2067 menu->SetInvokingWindow(this);
2068 menu->UpdateUI();
2069
27d2dbbc 2070 if ( x == wxDefaultCoord && y == wxDefaultCoord )
971562cb
VS
2071 {
2072 wxPoint mouse = ScreenToClient(wxGetMousePosition());
2073 x = mouse.x; y = mouse.y;
2074 }
2075
c50f1fb9
VZ
2076 HWND hWnd = GetHwnd();
2077 HMENU hMenu = GetHmenuOf(menu);
2078 POINT point;
2079 point.x = x;
2080 point.y = y;
2081 ::ClientToScreen(hWnd, &point);
2082 wxCurrentPopupMenu = menu;
5cb598ae 2083#if defined(__WXWINCE__)
7f0586ef 2084 UINT flags = 0;
5cb598ae 2085#else
114c220f 2086 UINT flags = TPM_RIGHTBUTTON | TPM_RECURSE;
7f0586ef
JS
2087#endif
2088 ::TrackPopupMenu(hMenu, flags, point.x, point.y, 0, hWnd, NULL);
ed45e263 2089
90e572f1 2090 // we need to do it right now as otherwise the events are never going to be
ed45e263
VZ
2091 // sent to wxCurrentPopupMenu from HandleCommand()
2092 //
2093 // note that even eliminating (ugly) wxCurrentPopupMenu global wouldn't
2094 // help and we'd still need wxYieldForCommandsOnly() as the menu may be
2095 // destroyed as soon as we return (it can be a local variable in the caller
2096 // for example) and so we do need to process the event immediately
2097 wxYieldForCommandsOnly();
2098
c50f1fb9
VZ
2099 wxCurrentPopupMenu = NULL;
2100
2101 menu->SetInvokingWindow(NULL);
2102
08158721 2103 return true;
c50f1fb9
VZ
2104}
2105
1e6feb95
VZ
2106#endif // wxUSE_MENUS_NATIVE
2107
42e69d6b
VZ
2108// ===========================================================================
2109// pre/post message processing
2110// ===========================================================================
2bda0e17 2111
c140b7e7 2112WXLRESULT wxWindowMSW::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
42e69d6b
VZ
2113{
2114 if ( m_oldWndProc )
2115 return ::CallWindowProc(CASTWNDPROC m_oldWndProc, GetHwnd(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam);
2116 else
2117 return ::DefWindowProc(GetHwnd(), nMsg, wParam, lParam);
2118}
2bda0e17 2119
1e6feb95 2120bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
42e69d6b 2121{
1e6feb95
VZ
2122 // wxUniversal implements tab traversal itself
2123#ifndef __WXUNIVERSAL__
42e69d6b 2124 if ( m_hWnd != 0 && (GetWindowStyleFlag() & wxTAB_TRAVERSAL) )
2d0a075d 2125 {
42e69d6b
VZ
2126 // intercept dialog navigation keys
2127 MSG *msg = (MSG *)pMsg;
d9317fd4
VZ
2128
2129 // here we try to do all the job which ::IsDialogMessage() usually does
2130 // internally
573a1586 2131 if ( msg->message == WM_KEYDOWN )
42e69d6b 2132 {
3f7bc32b
VZ
2133 bool bCtrlDown = wxIsCtrlDown();
2134 bool bShiftDown = wxIsShiftDown();
a23fd0e1 2135
42e69d6b
VZ
2136 // WM_GETDLGCODE: ask the control if it wants the key for itself,
2137 // don't process it if it's the case (except for Ctrl-Tab/Enter
2138 // combinations which are always processed)
977f50f3
VZ
2139 LONG lDlgCode = ::SendMessage(msg->hwnd, WM_GETDLGCODE, 0, 0);
2140
2141 // surprizingly, DLGC_WANTALLKEYS bit mask doesn't contain the
2142 // DLGC_WANTTAB nor DLGC_WANTARROWS bits although, logically,
2143 // it, of course, implies them
2144 if ( lDlgCode & DLGC_WANTALLKEYS )
42e69d6b 2145 {
977f50f3 2146 lDlgCode |= DLGC_WANTTAB | DLGC_WANTARROWS;
42e69d6b 2147 }
a23fd0e1 2148
08158721 2149 bool bForward = true,
298ca00c
VZ
2150 bWindowChange = false,
2151 bFromTab = false;
a23fd0e1 2152
573a1586 2153 // should we process this message specially?
08158721 2154 bool bProcess = true;
9145664b 2155 switch ( msg->wParam )
42e69d6b
VZ
2156 {
2157 case VK_TAB:
6afa47d6 2158 if ( lDlgCode & DLGC_WANTTAB ) {
08158721 2159 bProcess = false;
42e69d6b
VZ
2160 }
2161 else {
2162 // Ctrl-Tab cycles thru notebook pages
2163 bWindowChange = bCtrlDown;
319fefa9 2164 bForward = !bShiftDown;
298ca00c 2165 bFromTab = true;
42e69d6b
VZ
2166 }
2167 break;
a23fd0e1 2168
42e69d6b
VZ
2169 case VK_UP:
2170 case VK_LEFT:
2171 if ( (lDlgCode & DLGC_WANTARROWS) || bCtrlDown )
08158721 2172 bProcess = false;
42e69d6b 2173 else
08158721 2174 bForward = false;
42e69d6b 2175 break;
a02eb1d2 2176
42e69d6b
VZ
2177 case VK_DOWN:
2178 case VK_RIGHT:
2179 if ( (lDlgCode & DLGC_WANTARROWS) || bCtrlDown )
08158721 2180 bProcess = false;
42e69d6b 2181 break;
2bda0e17 2182
efe5e221
VZ
2183 case VK_PRIOR:
2184 bForward = false;
2185 // fall through
2186
2187 case VK_NEXT:
2188 // we treat PageUp/Dn as arrows because chances are that
2189 // a control which needs arrows also needs them for
2190 // navigation (e.g. wxTextCtrl, wxListCtrl, ...)
2191 if ( (lDlgCode & DLGC_WANTARROWS) || !bCtrlDown )
2192 bProcess = false;
2193 else
2194 bWindowChange = true;
2195 break;
2196
42e69d6b
VZ
2197 case VK_RETURN:
2198 {
edccf428 2199 if ( (lDlgCode & DLGC_WANTMESSAGE) && !bCtrlDown )
42e69d6b
VZ
2200 {
2201 // control wants to process Enter itself, don't
90c6edd7 2202 // call IsDialogMessage() which would consume it
08158721 2203 return false;
42e69d6b 2204 }
3147bb58 2205
90c6edd7 2206#if wxUSE_BUTTON
3147bb58 2207 // currently active button should get enter press even
90c6edd7
VZ
2208 // if there is a default button elsewhere so check if
2209 // this window is a button first
2210 wxWindow *btn = NULL;
3147bb58 2211 if ( lDlgCode & DLGC_DEFPUSHBUTTON )
319fefa9 2212 {
3e79ed96
VZ
2213 // let IsDialogMessage() handle this for all
2214 // buttons except the owner-drawn ones which it
2215 // just seems to ignore
2216 long style = ::GetWindowLong(msg->hwnd, GWL_STYLE);
2217 if ( (style & BS_OWNERDRAW) == BS_OWNERDRAW )
2218 {
2219 // emulate the button click
90c6edd7 2220 btn = wxFindWinFromHandle((WXHWND)msg->hwnd);
3e79ed96
VZ
2221 }
2222
08158721 2223 bProcess = false;
319fefa9 2224 }
90c6edd7 2225 else // not a button itself, do we have default button?
c50f1fb9 2226 {
90c6edd7
VZ
2227 wxTopLevelWindow *
2228 tlw = wxDynamicCast(wxGetTopLevelParent(this),
2229 wxTopLevelWindow);
6c20e8f8 2230 if ( tlw )
c50f1fb9 2231 {
90c6edd7
VZ
2232 btn = wxDynamicCast(tlw->GetDefaultItem(),
2233 wxButton);
c50f1fb9 2234 }
90c6edd7
VZ
2235 }
2236
2237 if ( btn && btn->IsEnabled() )
2238 {
2239 btn->MSWCommand(BN_CLICKED, 0 /* unused */);
2240 return true;
2241 }
2242
1e6feb95 2243#endif // wxUSE_BUTTON
90c6edd7 2244
7b504551 2245#ifdef __WXWINCE__
90c6edd7
VZ
2246 // map Enter presses into button presses on PDAs
2247 wxJoystickEvent event(wxEVT_JOY_BUTTON_DOWN);
2248 event.SetEventObject(this);
2249 if ( GetEventHandler()->ProcessEvent(event) )
2250 return true;
2251#endif // __WXWINCE__
42e69d6b
VZ
2252 }
2253 break;
2bda0e17 2254
42e69d6b 2255 default:
08158721 2256 bProcess = false;
42e69d6b 2257 }
2bda0e17 2258
42e69d6b
VZ
2259 if ( bProcess )
2260 {
2261 wxNavigationKeyEvent event;
2262 event.SetDirection(bForward);
2263 event.SetWindowChange(bWindowChange);
298ca00c 2264 event.SetFromTab(bFromTab);
42e69d6b 2265 event.SetEventObject(this);
3572173c 2266
42e69d6b 2267 if ( GetEventHandler()->ProcessEvent(event) )
57c0af52 2268 {
d7e0024b
VZ
2269 // as we don't call IsDialogMessage(), which would take of
2270 // this by default, we need to manually send this message
1ca78aa1
JS
2271 // so that controls can change their UI state if needed
2272 MSWUpdateUIState(UIS_CLEAR, UISF_HIDEFOCUS);
d7e0024b 2273
08158721 2274 return true;
57c0af52 2275 }
42e69d6b
VZ
2276 }
2277 }
a23fd0e1 2278
98ebf919 2279 if ( ::IsDialogMessage(GetHwnd(), msg) )
f6bcfd97 2280 {
98ebf919
VZ
2281 // IsDialogMessage() did something...
2282 return true;
f6bcfd97 2283 }
42e69d6b 2284 }
1e6feb95 2285#endif // __WXUNIVERSAL__
a23fd0e1 2286
42e69d6b
VZ
2287#if wxUSE_TOOLTIPS
2288 if ( m_tooltip )
387a3b02 2289 {
42e69d6b
VZ
2290 // relay mouse move events to the tooltip control
2291 MSG *msg = (MSG *)pMsg;
2292 if ( msg->message == WM_MOUSEMOVE )
259a4264 2293 wxToolTip::RelayEvent(pMsg);
387a3b02 2294 }
42e69d6b 2295#endif // wxUSE_TOOLTIPS
a23fd0e1 2296
08158721 2297 return false;
387a3b02
JS
2298}
2299
1e6feb95 2300bool wxWindowMSW::MSWTranslateMessage(WXMSG* pMsg)
387a3b02 2301{
1e6feb95 2302#if wxUSE_ACCEL && !defined(__WXUNIVERSAL__)
c50f1fb9 2303 return m_acceleratorTable.Translate(this, pMsg);
1e6feb95 2304#else
574c939e 2305 (void) pMsg;
08158721 2306 return false;
1e6feb95 2307#endif // wxUSE_ACCEL
387a3b02
JS
2308}
2309
98ebf919 2310bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* msg)
a37d422a 2311{
98ebf919
VZ
2312 // all tests below have to deal with various bugs/misfeatures of
2313 // IsDialogMessage(): we have to prevent it from being called from our
2314 // MSWProcessMessage() in some situations
2315
2316 // don't let IsDialogMessage() get VK_ESCAPE as it _always_ eats the
2317 // message even when there is no cancel button and when the message is
2318 // needed by the control itself: in particular, it prevents the tree in
2319 // place edit control from being closed with Escape in a dialog
2320 if ( msg->message == WM_KEYDOWN && msg->wParam == VK_ESCAPE )
2321 {
2322 return false;
2323 }
2324
2325 // ::IsDialogMessage() is broken and may sometimes hang the application by
2326 // going into an infinite loop when it tries to find the control to give
2327 // focus to when Alt-<key> is pressed, so we try to detect [some of] the
2328 // situations when this may happen and not call it then
2329 if ( msg->message != WM_SYSCHAR )
2330 return true;
2331
2332 // assume we can call it by default
2333 bool canSafelyCallIsDlgMsg = true;
2334
2335 HWND hwndFocus = ::GetFocus();
2336
2337 // if the currently focused window itself has WS_EX_CONTROLPARENT style,
2338 // ::IsDialogMessage() will also enter an infinite loop, because it will
2339 // recursively check the child windows but not the window itself and so if
2340 // none of the children accepts focus it loops forever (as it only stops
2341 // when it gets back to the window it started from)
2342 //
2343 // while it is very unusual that a window with WS_EX_CONTROLPARENT
2344 // style has the focus, it can happen. One such possibility is if
2345 // all windows are either toplevel, wxDialog, wxPanel or static
2346 // controls and no window can actually accept keyboard input.
2347#if !defined(__WXWINCE__)
2348 if ( ::GetWindowLong(hwndFocus, GWL_EXSTYLE) & WS_EX_CONTROLPARENT )
2349 {
2350 // pessimistic by default
2351 canSafelyCallIsDlgMsg = false;
2352 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
2353 node;
2354 node = node->GetNext() )
2355 {
2356 wxWindow * const win = node->GetData();
2357 if ( win->AcceptsFocus() &&
2358 !(::GetWindowLong(GetHwndOf(win), GWL_EXSTYLE) &
2359 WS_EX_CONTROLPARENT) )
2360 {
2361 // it shouldn't hang...
2362 canSafelyCallIsDlgMsg = true;
2363
2364 break;
2365 }
2366 }
2367 }
2368#endif // !__WXWINCE__
2369
2370 if ( canSafelyCallIsDlgMsg )
2371 {
2372 // ::IsDialogMessage() can enter in an infinite loop when the
2373 // currently focused window is disabled or hidden and its
2374 // parent has WS_EX_CONTROLPARENT style, so don't call it in
2375 // this case
2376 while ( hwndFocus )
2377 {
2378 if ( !::IsWindowEnabled(hwndFocus) ||
2379 !::IsWindowVisible(hwndFocus) )
2380 {
2381 // it would enter an infinite loop if we do this!
2382 canSafelyCallIsDlgMsg = false;
2383
2384 break;
2385 }
2386
2387 if ( !(::GetWindowLong(hwndFocus, GWL_STYLE) & WS_CHILD) )
2388 {
2389 // it's a top level window, don't go further -- e.g. even
2390 // if the parent of a dialog is disabled, this doesn't
2391 // break navigation inside the dialog
2392 break;
2393 }
2394
2395 hwndFocus = ::GetParent(hwndFocus);
2396 }
2397 }
2398
2399 return canSafelyCallIsDlgMsg;
a37d422a
VZ
2400}
2401
42e69d6b 2402// ---------------------------------------------------------------------------
e39af974 2403// message params unpackers
42e69d6b 2404// ---------------------------------------------------------------------------
2bda0e17 2405
1e6feb95 2406void wxWindowMSW::UnpackCommand(WXWPARAM wParam, WXLPARAM lParam,
42e69d6b
VZ
2407 WORD *id, WXHWND *hwnd, WORD *cmd)
2408{
2409 *id = LOWORD(wParam);
2410 *hwnd = (WXHWND)lParam;
2411 *cmd = HIWORD(wParam);
2bda0e17
KB
2412}
2413
1e6feb95 2414void wxWindowMSW::UnpackActivate(WXWPARAM wParam, WXLPARAM lParam,
42e69d6b 2415 WXWORD *state, WXWORD *minimized, WXHWND *hwnd)
2bda0e17 2416{
42e69d6b
VZ
2417 *state = LOWORD(wParam);
2418 *minimized = HIWORD(wParam);
2419 *hwnd = (WXHWND)lParam;
2bda0e17
KB
2420}
2421
1e6feb95 2422void wxWindowMSW::UnpackScroll(WXWPARAM wParam, WXLPARAM lParam,
42e69d6b 2423 WXWORD *code, WXWORD *pos, WXHWND *hwnd)
2bda0e17 2424{
42e69d6b
VZ
2425 *code = LOWORD(wParam);
2426 *pos = HIWORD(wParam);
2427 *hwnd = (WXHWND)lParam;
2428}
a23fd0e1 2429
1e6feb95 2430void wxWindowMSW::UnpackCtlColor(WXWPARAM wParam, WXLPARAM lParam,
01c500af 2431 WXHDC *hdc, WXHWND *hwnd)
42e69d6b 2432{
42e69d6b
VZ
2433 *hwnd = (WXHWND)lParam;
2434 *hdc = (WXHDC)wParam;
2bda0e17
KB
2435}
2436
1e6feb95 2437void wxWindowMSW::UnpackMenuSelect(WXWPARAM wParam, WXLPARAM lParam,
42e69d6b 2438 WXWORD *item, WXWORD *flags, WXHMENU *hmenu)
2bda0e17 2439{
42e69d6b
VZ
2440 *item = (WXWORD)wParam;
2441 *flags = HIWORD(wParam);
2442 *hmenu = (WXHMENU)lParam;
2443}
c085e333 2444
42e69d6b 2445// ---------------------------------------------------------------------------
77ffb593 2446// Main wxWidgets window proc and the window proc for wxWindow
42e69d6b 2447// ---------------------------------------------------------------------------
2bda0e17 2448
42e69d6b
VZ
2449// Hook for new window just as it's being created, when the window isn't yet
2450// associated with the handle
b225f659
VZ
2451static wxWindowMSW *gs_winBeingCreated = NULL;
2452
2453// implementation of wxWindowCreationHook class: it just sets gs_winBeingCreated to the
2454// window being created and insures that it's always unset back later
2455wxWindowCreationHook::wxWindowCreationHook(wxWindowMSW *winBeingCreated)
2456{
2457 gs_winBeingCreated = winBeingCreated;
2458}
2459
2460wxWindowCreationHook::~wxWindowCreationHook()
2461{
2462 gs_winBeingCreated = NULL;
2463}
42e69d6b
VZ
2464
2465// Main window proc
3135f4a7 2466LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
2bda0e17 2467{
42e69d6b
VZ
2468 // trace all messages - useful for the debugging
2469#ifdef __WXDEBUG__
13e4c4d9
VZ
2470 wxLogTrace(wxTraceMessages,
2471 wxT("Processing %s(hWnd=%08lx, wParam=%8lx, lParam=%8lx)"),
2472 wxGetMessageName(message), (long)hWnd, (long)wParam, lParam);
42e69d6b 2473#endif // __WXDEBUG__
2bda0e17 2474
1e6feb95 2475 wxWindowMSW *wnd = wxFindWinFromHandle((WXHWND) hWnd);
c085e333 2476
42e69d6b 2477 // when we get the first message for the HWND we just created, we associate
b225f659
VZ
2478 // it with wxWindow stored in gs_winBeingCreated
2479 if ( !wnd && gs_winBeingCreated )
2d0a075d 2480 {
b225f659
VZ
2481 wxAssociateWinWithHandle(hWnd, gs_winBeingCreated);
2482 wnd = gs_winBeingCreated;
2483 gs_winBeingCreated = NULL;
42e69d6b 2484 wnd->SetHWND((WXHWND)hWnd);
2d0a075d 2485 }
2bda0e17 2486
42e69d6b 2487 LRESULT rc;
a23fd0e1 2488
a3dc1da9 2489 if ( wnd && wxEventLoop::AllowProcessing(wnd) )
b225f659 2490 rc = wnd->MSWWindowProc(message, wParam, lParam);
a23fd0e1 2491 else
b225f659 2492 rc = ::DefWindowProc(hWnd, message, wParam, lParam);
2bda0e17 2493
42e69d6b 2494 return rc;
f7bd2698
JS
2495}
2496
c140b7e7 2497WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
f7bd2698 2498{
42e69d6b 2499 // did we process the message?
08158721 2500 bool processed = false;
f7bd2698 2501
42e69d6b
VZ
2502 // the return value
2503 union
2bda0e17 2504 {
42e69d6b 2505 bool allow;
c140b7e7 2506 WXLRESULT result;
42e69d6b
VZ
2507 WXHBRUSH hBrush;
2508 } rc;
2bda0e17 2509
42e69d6b
VZ
2510 // for most messages we should return 0 when we do process the message
2511 rc.result = 0;
2bda0e17 2512
42e69d6b 2513 switch ( message )
39136494 2514 {
42e69d6b
VZ
2515 case WM_CREATE:
2516 {
2517 bool mayCreate;
2518 processed = HandleCreate((WXLPCREATESTRUCT)lParam, &mayCreate);
2519 if ( processed )
2520 {
2521 // return 0 to allow window creation
2522 rc.result = mayCreate ? 0 : -1;
2523 }
2524 }
2525 break;
47cbd6da 2526
42e69d6b 2527 case WM_DESTROY:
08158721 2528 // never set processed to true and *always* pass WM_DESTROY to
ad4297f3
VZ
2529 // DefWindowProc() as Windows may do some internal cleanup when
2530 // processing it and failing to pass the message along may cause
2531 // memory and resource leaks!
2532 (void)HandleDestroy();
42e69d6b
VZ
2533 break;
2534
9b6ae450
VZ
2535 case WM_SIZE:
2536 processed = HandleSize(LOWORD(lParam), HIWORD(lParam), wParam);
9b6ae450
VZ
2537 break;
2538
42e69d6b 2539 case WM_MOVE:
132cb640 2540 processed = HandleMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
42e69d6b 2541 break;
47cbd6da 2542
7f0586ef 2543#if !defined(__WXWINCE__)
5706de1c 2544 case WM_MOVING:
540b6b09
VZ
2545 {
2546 LPRECT pRect = (LPRECT)lParam;
2547 wxRect rc;
2548 rc.SetLeft(pRect->left);
2549 rc.SetTop(pRect->top);
2550 rc.SetRight(pRect->right);
2551 rc.SetBottom(pRect->bottom);
2552 processed = HandleMoving(rc);
2553 if (processed) {
2554 pRect->left = rc.GetLeft();
2555 pRect->top = rc.GetTop();
2556 pRect->right = rc.GetRight();
2557 pRect->bottom = rc.GetBottom();
2558 }
2559 }
5706de1c
JS
2560 break;
2561
5706de1c
JS
2562 case WM_SIZING:
2563 {
2564 LPRECT pRect = (LPRECT)lParam;
2565 wxRect rc;
2566 rc.SetLeft(pRect->left);
2567 rc.SetTop(pRect->top);
2568 rc.SetRight(pRect->right);
2569 rc.SetBottom(pRect->bottom);
2570 processed = HandleSizing(rc);
2571 if (processed) {
2572 pRect->left = rc.GetLeft();
2573 pRect->top = rc.GetTop();
2574 pRect->right = rc.GetRight();
2575 pRect->bottom = rc.GetBottom();
2576 }
2577 }
2578 break;
9b6ae450 2579#endif // !__WXWINCE__
5706de1c 2580
7f0586ef 2581#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
1e6feb95 2582 case WM_ACTIVATEAPP:
afafd942 2583 // This implicitly sends a wxEVT_ACTIVATE_APP event
1e6feb95 2584 wxTheApp->SetActive(wParam != 0, FindFocus());
42e69d6b 2585 break;
8a46f9b1 2586#endif
47cbd6da 2587
42e69d6b 2588 case WM_ACTIVATE:
341c92a8 2589 {
42e69d6b
VZ
2590 WXWORD state, minimized;
2591 WXHWND hwnd;
2592 UnpackActivate(wParam, lParam, &state, &minimized, &hwnd);
2593
2594 processed = HandleActivate(state, minimized != 0, (WXHWND)hwnd);
341c92a8 2595 }
42e69d6b 2596 break;
341c92a8 2597
42e69d6b
VZ
2598 case WM_SETFOCUS:
2599 processed = HandleSetFocus((WXHWND)(HWND)wParam);
2600 break;
47cbd6da 2601
42e69d6b
VZ
2602 case WM_KILLFOCUS:
2603 processed = HandleKillFocus((WXHWND)(HWND)wParam);
2604 break;
47cbd6da 2605
c3732409 2606 case WM_PRINTCLIENT:
1a784dfc 2607 processed = HandlePrintClient((WXHDC)wParam);
07c19327
VZ
2608 break;
2609
c3732409
VZ
2610 case WM_PAINT:
2611 if ( wParam )
5c6c3176 2612 {
5c6c3176 2613 wxPaintDCEx dc((wxWindow *)this, (WXHDC)wParam);
07c19327 2614
5c6c3176
RD
2615 processed = HandlePaint();
2616 }
c3732409
VZ
2617 else // no DC given
2618 {
2619 processed = HandlePaint();
2620 }
5c6c3176
RD
2621 break;
2622
42e69d6b 2623 case WM_CLOSE:
9fd9e47a
JS
2624#ifdef __WXUNIVERSAL__
2625 // Universal uses its own wxFrame/wxDialog, so we don't receive
2626 // close events unless we have this.
2627 Close();
c3732409
VZ
2628#endif // __WXUNIVERSAL__
2629
42e69d6b
VZ
2630 // don't let the DefWindowProc() destroy our window - we'll do it
2631 // ourselves in ~wxWindow
08158721 2632 processed = true;
42e69d6b
VZ
2633 rc.result = TRUE;
2634 break;
47cbd6da 2635
42e69d6b
VZ
2636 case WM_SHOWWINDOW:
2637 processed = HandleShow(wParam != 0, (int)lParam);
2638 break;
3a19e16d 2639
42e69d6b 2640 case WM_MOUSEMOVE:
132cb640
VZ
2641 processed = HandleMouseMove(GET_X_LPARAM(lParam),
2642 GET_Y_LPARAM(lParam),
2643 wParam);
2644 break;
0d0512bd 2645
4e5c6c33 2646#ifdef HAVE_TRACKMOUSEEVENT
e5297b7f 2647 case WM_MOUSELEAVE:
aafb9978
VZ
2648 // filter out excess WM_MOUSELEAVE events sent after PopupMenu()
2649 // (on XP at least)
4e5c6c33 2650 if ( m_mouseInWindow )
e5297b7f 2651 {
4e5c6c33 2652 GenerateMouseLeave();
e5297b7f 2653 }
4e5c6c33
VZ
2654
2655 // always pass processed back as false, this allows the window
2656 // manager to process the message too. This is needed to
2657 // ensure windows XP themes work properly as the mouse moves
2658 // over widgets like buttons. So don't set processed to true here.
51e4e266 2659 break;
4e5c6c33 2660#endif // HAVE_TRACKMOUSEEVENT
35bbb0c6 2661
d2c52078
RD
2662#if wxUSE_MOUSEWHEEL
2663 case WM_MOUSEWHEEL:
2664 processed = HandleMouseWheel(wParam, lParam);
2665 break;
2666#endif
2667
42e69d6b
VZ
2668 case WM_LBUTTONDOWN:
2669 case WM_LBUTTONUP:
2670 case WM_LBUTTONDBLCLK:
2671 case WM_RBUTTONDOWN:
2672 case WM_RBUTTONUP:
2673 case WM_RBUTTONDBLCLK:
2674 case WM_MBUTTONDOWN:
2675 case WM_MBUTTONUP:
2676 case WM_MBUTTONDBLCLK:
dfafa702 2677 {
98363307 2678#ifdef __WXMICROWIN__
cd4453e5
VZ
2679 // MicroWindows seems to ignore the fact that a window is
2680 // disabled. So catch mouse events and throw them away if
2681 // necessary.
d0a3d109 2682 wxWindowMSW* win = this;
dfafa702 2683 for ( ;; )
d0a3d109
VZ
2684 {
2685 if (!win->IsEnabled())
2686 {
08158721 2687 processed = true;
d0a3d109
VZ
2688 break;
2689 }
dfafa702 2690
d0a3d109 2691 win = win->GetParent();
dfafa702 2692 if ( !win || win->IsTopLevel() )
d0a3d109
VZ
2693 break;
2694 }
dfafa702 2695
03e0b2b1
VZ
2696 if ( processed )
2697 break;
2698
dfafa702 2699#endif // __WXMICROWIN__
03e0b2b1
VZ
2700 int x = GET_X_LPARAM(lParam),
2701 y = GET_Y_LPARAM(lParam);
dfafa702 2702
42b1fb63 2703#ifdef __WXWINCE__
03e0b2b1 2704 // redirect the event to a static control if necessary by
42b1fb63
VZ
2705 // finding one under mouse because under CE the static controls
2706 // don't generate mouse events (even with SS_NOTIFY)
03e0b2b1
VZ
2707 wxWindowMSW *win;
2708 if ( GetCapture() == this )
2709 {
2710 // but don't do it if the mouse is captured by this window
2711 // because then it should really get this event itself
2712 win = this;
d0a3d109 2713 }
03e0b2b1
VZ
2714 else
2715 {
2716 win = FindWindowForMouseEvent(this, &x, &y);
2b5f62a0
VZ
2717
2718 // this should never happen
2719 wxCHECK_MSG( win, 0,
2720 _T("FindWindowForMouseEvent() returned NULL") );
9f011847 2721 }
7d4f65e3
JS
2722#ifdef __POCKETPC__
2723 if (IsContextMenuEnabled() && message == WM_LBUTTONDOWN)
2724 {
2725 SHRGINFO shrgi = {0};
faa94f3e 2726
7d4f65e3
JS
2727 shrgi.cbSize = sizeof(SHRGINFO);
2728 shrgi.hwndClient = (HWND) GetHWND();
2729 shrgi.ptDown.x = x;
2730 shrgi.ptDown.y = y;
faa94f3e 2731
7d4f65e3
JS
2732 shrgi.dwFlags = SHRG_RETURNCMD;
2733 // shrgi.dwFlags = SHRG_NOTIFYPARENT;
faa94f3e 2734
7d4f65e3
JS
2735 if (GN_CONTEXTMENU == ::SHRecognizeGesture(&shrgi))
2736 {
2737 wxPoint pt(x, y);
2738 pt = ClientToScreen(pt);
faa94f3e 2739
7d4f65e3 2740 wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt);
faa94f3e 2741
7d4f65e3
JS
2742 evtCtx.SetEventObject(this);
2743 if (GetEventHandler()->ProcessEvent(evtCtx))
f350d4b2 2744 {
7d4f65e3 2745 processed = true;
f350d4b2
JS
2746 return true;
2747 }
7d4f65e3
JS
2748 }
2749 }
2750#endif
2751
42b1fb63
VZ
2752#else // !__WXWINCE__
2753 wxWindowMSW *win = this;
2754#endif // __WXWINCE__/!__WXWINCE__
9f011847
VZ
2755
2756 processed = win->HandleMouseEvent(message, x, y, wParam);
2b5f62a0 2757
9f011847
VZ
2758 // if the app didn't eat the event, handle it in the default
2759 // way, that is by giving this window the focus
2760 if ( !processed )
2761 {
2b5f62a0
VZ
2762 // for the standard classes their WndProc sets the focus to
2763 // them anyhow and doing it from here results in some weird
9f011847 2764 // problems, so don't do it for them (unnecessary anyhow)
2b5f62a0
VZ
2765 if ( !win->IsOfStandardClass() )
2766 {
2767 if ( message == WM_LBUTTONDOWN && win->AcceptsFocus() )
2768 win->SetFocus();
2769 }
03e0b2b1 2770 }
98363307 2771 }
dfafa702 2772 break;
d0a3d109 2773
cd4453e5 2774#ifdef MM_JOY1MOVE
42e69d6b
VZ
2775 case MM_JOY1MOVE:
2776 case MM_JOY2MOVE:
2777 case MM_JOY1ZMOVE:
2778 case MM_JOY2ZMOVE:
2779 case MM_JOY1BUTTONDOWN:
2780 case MM_JOY2BUTTONDOWN:
2781 case MM_JOY1BUTTONUP:
2782 case MM_JOY2BUTTONUP:
132cb640
VZ
2783 processed = HandleJoystickEvent(message,
2784 GET_X_LPARAM(lParam),
2785 GET_Y_LPARAM(lParam),
2786 wParam);
42e69d6b 2787 break;
cd4453e5 2788#endif // __WXMICROWIN__
47cbd6da 2789
42e69d6b
VZ
2790 case WM_COMMAND:
2791 {
2792 WORD id, cmd;
2793 WXHWND hwnd;
2794 UnpackCommand(wParam, lParam, &id, &hwnd, &cmd);
47cbd6da 2795
42e69d6b
VZ
2796 processed = HandleCommand(id, cmd, hwnd);
2797 }
2798 break;
7d532b0c 2799
42e69d6b
VZ
2800 case WM_NOTIFY:
2801 processed = HandleNotify((int)wParam, lParam, &rc.result);
2802 break;
2bda0e17 2803
27005f3a
VZ
2804 // we only need to reply to WM_NOTIFYFORMAT manually when using MSLU,
2805 // otherwise DefWindowProc() does it perfectly fine for us, but MSLU
2806 // apparently doesn't always behave properly and needs some help
2807#if wxUSE_UNICODE_MSLU && defined(NF_QUERY)
2808 case WM_NOTIFYFORMAT:
2809 if ( lParam == NF_QUERY )
2810 {
2811 processed = true;
2812 rc.result = NFR_UNICODE;
2813 }
2814 break;
2815#endif // wxUSE_UNICODE_MSLU
2816
08158721 2817 // for these messages we must return true if process the message
cd4453e5 2818#ifdef WM_DRAWITEM
42e69d6b
VZ
2819 case WM_DRAWITEM:
2820 case WM_MEASUREITEM:
2821 {
2822 int idCtrl = (UINT)wParam;
2823 if ( message == WM_DRAWITEM )
2824 {
2825 processed = MSWOnDrawItem(idCtrl,
2826 (WXDRAWITEMSTRUCT *)lParam);
2827 }
2828 else
2829 {
2830 processed = MSWOnMeasureItem(idCtrl,
2831 (WXMEASUREITEMSTRUCT *)lParam);
2832 }
57a7b7c1 2833
42e69d6b
VZ
2834 if ( processed )
2835 rc.result = TRUE;
2836 }
2837 break;
cd4453e5
VZ
2838#endif // defined(WM_DRAWITEM)
2839
9bf84618 2840 case WM_GETDLGCODE:
5a403e3f 2841 if ( !IsOfStandardClass() )
9bf84618 2842 {
5a403e3f
VZ
2843 // we always want to get the char events
2844 rc.result = DLGC_WANTCHARS;
2845
2846 if ( GetWindowStyleFlag() & wxWANTS_CHARS )
2847 {
2848 // in fact, we want everything
2849 rc.result |= DLGC_WANTARROWS |
2850 DLGC_WANTTAB |
2851 DLGC_WANTALLKEYS;
2852 }
2853
08158721 2854 processed = true;
9bf84618 2855 }
101f488c 2856 //else: get the dlg code from the DefWindowProc()
9bf84618
VZ
2857 break;
2858
4004f41e 2859 case WM_SYSKEYDOWN:
42e69d6b 2860 case WM_KEYDOWN:
9c7df356
VZ
2861 // If this has been processed by an event handler, return 0 now
2862 // (we've handled it).
2863 m_lastKeydownProcessed = HandleKeyDown((WORD) wParam, lParam);
2864 if ( m_lastKeydownProcessed )
2d0a075d 2865 {
08158721 2866 processed = true;
2d0a075d 2867 }
81d66cf3 2868
2b5f62a0 2869 if ( !processed )
42e69d6b 2870 {
2b5f62a0
VZ
2871 switch ( wParam )
2872 {
90e572f1 2873 // we consider these messages "not interesting" to OnChar, so
2b5f62a0
VZ
2874 // just don't do anything more with them
2875 case VK_SHIFT:
2876 case VK_CONTROL:
2877 case VK_MENU:
2878 case VK_CAPITAL:
2879 case VK_NUMLOCK:
2880 case VK_SCROLL:
08158721 2881 processed = true;
2b5f62a0 2882 break;
2bda0e17 2883
2b5f62a0
VZ
2884 // avoid duplicate messages to OnChar for these ASCII keys:
2885 // they will be translated by TranslateMessage() and received
2886 // in WM_CHAR
2887 case VK_ESCAPE:
2888 case VK_SPACE:
2889 case VK_RETURN:
2890 case VK_BACK:
2891 case VK_TAB:
2892 case VK_ADD:
2893 case VK_SUBTRACT:
2894 case VK_MULTIPLY:
2895 case VK_DIVIDE:
3f2174bb
VZ
2896 case VK_NUMPAD0:
2897 case VK_NUMPAD1:
2898 case VK_NUMPAD2:
2899 case VK_NUMPAD3:
2900 case VK_NUMPAD4:
2901 case VK_NUMPAD5:
2902 case VK_NUMPAD6:
2903 case VK_NUMPAD7:
2904 case VK_NUMPAD8:
2905 case VK_NUMPAD9:
2b5f62a0
VZ
2906 case VK_OEM_1:
2907 case VK_OEM_2:
2908 case VK_OEM_3:
2909 case VK_OEM_4:
2910 case VK_OEM_5:
2911 case VK_OEM_6:
2912 case VK_OEM_7:
2913 case VK_OEM_PLUS:
2914 case VK_OEM_COMMA:
2915 case VK_OEM_MINUS:
2916 case VK_OEM_PERIOD:
08158721 2917 // but set processed to false, not true to still pass them
2b5f62a0
VZ
2918 // to the control's default window proc - otherwise
2919 // built-in keyboard handling won't work
08158721 2920 processed = false;
2b5f62a0 2921 break;
2bda0e17 2922
42e69d6b 2923#ifdef VK_APPS
2b5f62a0
VZ
2924 // special case of VK_APPS: treat it the same as right mouse
2925 // click because both usually pop up a context menu
2926 case VK_APPS:
ae177b45 2927 processed = HandleMouseEvent(WM_RBUTTONDOWN, -1, -1, 0);
2b5f62a0 2928 break;
42e69d6b 2929#endif // VK_APPS
2bda0e17 2930
2b5f62a0
VZ
2931 default:
2932 // do generate a CHAR event
2933 processed = HandleChar((WORD)wParam, lParam);
2934 }
42e69d6b 2935 }
2b5f62a0 2936 if (message == WM_SYSKEYDOWN) // Let Windows still handle the SYSKEYs
08158721 2937 processed = false;
42e69d6b 2938 break;
2bda0e17 2939
4004f41e 2940 case WM_SYSKEYUP:
42e69d6b 2941 case WM_KEYUP:
4aff28fc
VZ
2942#ifdef VK_APPS
2943 // special case of VK_APPS: treat it the same as right mouse button
2944 if ( wParam == VK_APPS )
2945 {
ae177b45 2946 processed = HandleMouseEvent(WM_RBUTTONUP, -1, -1, 0);
4aff28fc
VZ
2947 }
2948 else
2949#endif // VK_APPS
2950 {
2951 processed = HandleKeyUp((WORD) wParam, lParam);
2952 }
42e69d6b 2953 break;
debe6624 2954
170cbe33 2955 case WM_SYSCHAR:
42e69d6b 2956 case WM_CHAR: // Always an ASCII character
d9f14e16
RD
2957 if ( m_lastKeydownProcessed )
2958 {
2959 // The key was handled in the EVT_KEY_DOWN and handling
2960 // a key in an EVT_KEY_DOWN handler is meant, by
2961 // design, to prevent EVT_CHARs from happening
08158721
DS
2962 m_lastKeydownProcessed = false;
2963 processed = true;
d9f14e16
RD
2964 }
2965 else
7de5bdf4 2966 {
08158721 2967 processed = HandleChar((WORD)wParam, lParam, true);
7de5bdf4 2968 }
42e69d6b 2969 break;
2bda0e17 2970
5048c832
JS
2971#if wxUSE_HOTKEY
2972 case WM_HOTKEY:
2973 processed = HandleHotKey((WORD)wParam, lParam);
2974 break;
540b6b09 2975#endif // wxUSE_HOTKEY
5048c832 2976
42e69d6b
VZ
2977 case WM_HSCROLL:
2978 case WM_VSCROLL:
a23fd0e1 2979 {
42e69d6b
VZ
2980 WXWORD code, pos;
2981 WXHWND hwnd;
2982 UnpackScroll(wParam, lParam, &code, &pos, &hwnd);
2bda0e17 2983
42e69d6b
VZ
2984 processed = MSWOnScroll(message == WM_HSCROLL ? wxHORIZONTAL
2985 : wxVERTICAL,
2986 code, pos, hwnd);
a23fd0e1 2987 }
42e69d6b 2988 break;
a23fd0e1 2989
42e69d6b 2990 // CTLCOLOR messages are sent by children to query the parent for their
01c500af 2991 // colors
04ef50df 2992#ifndef __WXMICROWIN__
42e69d6b
VZ
2993 case WM_CTLCOLORMSGBOX:
2994 case WM_CTLCOLOREDIT:
2995 case WM_CTLCOLORLISTBOX:
2996 case WM_CTLCOLORBTN:
2997 case WM_CTLCOLORDLG:
2998 case WM_CTLCOLORSCROLLBAR:
2999 case WM_CTLCOLORSTATIC:
a23fd0e1 3000 {
42e69d6b
VZ
3001 WXHDC hdc;
3002 WXHWND hwnd;
01c500af 3003 UnpackCtlColor(wParam, lParam, &hdc, &hwnd);
42e69d6b 3004
48fa6bd3 3005 processed = HandleCtlColor(&rc.hBrush, (WXHDC)hdc, (WXHWND)hwnd);
a23fd0e1 3006 }
42e69d6b 3007 break;
cd4453e5 3008#endif // !__WXMICROWIN__
debe6624 3009
42e69d6b 3010 case WM_SYSCOLORCHANGE:
90c1530a 3011 // the return value for this message is ignored
42e69d6b
VZ
3012 processed = HandleSysColorChange();
3013 break;
2bda0e17 3014
7f0586ef 3015#if !defined(__WXWINCE__)
574c939e
KB
3016 case WM_DISPLAYCHANGE:
3017 processed = HandleDisplayChange();
3018 break;
7f0586ef 3019#endif
574c939e 3020
42e69d6b
VZ
3021 case WM_PALETTECHANGED:
3022 processed = HandlePaletteChanged((WXHWND) (HWND) wParam);
3023 break;
2bda0e17 3024
a5e84126
JS
3025 case WM_CAPTURECHANGED:
3026 processed = HandleCaptureChanged((WXHWND) (HWND) lParam);
3027 break;
3028
3c96418b
JG
3029 case WM_SETTINGCHANGE:
3030 processed = HandleSettingChange(wParam, lParam);
3031 break;
3032
42e69d6b
VZ
3033 case WM_QUERYNEWPALETTE:
3034 processed = HandleQueryNewPalette();
3035 break;
2bda0e17 3036
42e69d6b
VZ
3037 case WM_ERASEBKGND:
3038 processed = HandleEraseBkgnd((WXHDC)(HDC)wParam);
3039 if ( processed )
3040 {
3041 // we processed the message, i.e. erased the background
3042 rc.result = TRUE;
3043 }
3044 break;
debe6624 3045
7f0586ef 3046#if !defined(__WXWINCE__)
42e69d6b
VZ
3047 case WM_DROPFILES:
3048 processed = HandleDropFiles(wParam);
3049 break;
7f0586ef 3050#endif
2bda0e17 3051
42e69d6b
VZ
3052 case WM_INITDIALOG:
3053 processed = HandleInitDialog((WXHWND)(HWND)wParam);
a23fd0e1 3054
42e69d6b
VZ
3055 if ( processed )
3056 {
3057 // we never set focus from here
3058 rc.result = FALSE;
3059 }
3060 break;
a23fd0e1 3061
7f0586ef 3062#if !defined(__WXWINCE__)
42e69d6b
VZ
3063 case WM_QUERYENDSESSION:
3064 processed = HandleQueryEndSession(lParam, &rc.allow);
3065 break;
2bda0e17 3066
42e69d6b
VZ
3067 case WM_ENDSESSION:
3068 processed = HandleEndSession(wParam != 0, lParam);
3069 break;
2bda0e17 3070
42e69d6b 3071 case WM_GETMINMAXINFO:
25889d3c 3072 processed = HandleGetMinMaxInfo((MINMAXINFO*)lParam);
42e69d6b 3073 break;
7f0586ef 3074#endif
debe6624 3075
42e69d6b
VZ
3076 case WM_SETCURSOR:
3077 processed = HandleSetCursor((WXHWND)(HWND)wParam,
3078 LOWORD(lParam), // hit test
3079 HIWORD(lParam)); // mouse msg
3080
3081 if ( processed )
3082 {
3083 // returning TRUE stops the DefWindowProc() from further
3084 // processing this message - exactly what we need because we've
3085 // just set the cursor.
3086 rc.result = TRUE;
3087 }
3088 break;
4cdc2c13 3089
ed5317e5
JS
3090#if wxUSE_ACCESSIBILITY
3091 case WM_GETOBJECT:
3092 {
3093 //WPARAM dwFlags = (WPARAM) (DWORD) wParam;
3094 LPARAM dwObjId = (LPARAM) (DWORD) lParam;
3095
66b9ec3d 3096 if (dwObjId == (LPARAM)OBJID_CLIENT && GetOrCreateAccessible())
ed5317e5
JS
3097 {
3098 return LresultFromObject(IID_IAccessible, wParam, (IUnknown*) GetAccessible()->GetIAccessible());
3099 }
3100 break;
3101 }
3102#endif
3103
e39af974 3104#if defined(WM_HELP)
b96340e6 3105 case WM_HELP:
b96340e6 3106 {
a9c11b71
VZ
3107 // by default, WM_HELP is propagated by DefWindowProc() upwards
3108 // to the window parent but as we do it ourselves already
3109 // (wxHelpEvent is derived from wxCommandEvent), we don't want
3110 // to get the other events if we process this message at all
3111 processed = true;
3112
3113 // WM_HELP doesn't use lParam under CE
7f0586ef 3114#ifndef __WXWINCE__
4cdc2c13 3115 HELPINFO* info = (HELPINFO*) lParam;
a9c11b71 3116 if ( info->iContextType == HELPINFO_WINDOW )
b96340e6 3117 {
a9c11b71
VZ
3118#endif // !__WXWINCE__
3119 wxHelpEvent helpEvent
3120 (
3121 wxEVT_HELP,
3122 GetId(),
7f0586ef 3123#ifdef __WXWINCE__
2d4ec362 3124 wxGetMousePosition() // what else?
7f0586ef 3125#else
a9c11b71 3126 wxPoint(info->MousePos.x, info->MousePos.y)
7f0586ef 3127#endif
a9c11b71 3128 );
b96340e6 3129
a9c11b71
VZ
3130 helpEvent.SetEventObject(this);
3131 GetEventHandler()->ProcessEvent(helpEvent);
7f0586ef 3132#ifndef __WXWINCE__
b96340e6 3133 }
a9c11b71 3134 else if ( info->iContextType == HELPINFO_MENUITEM )
4cdc2c13
VZ
3135 {
3136 wxHelpEvent helpEvent(wxEVT_HELP, info->iCtrlId);
3137 helpEvent.SetEventObject(this);
a9c11b71 3138 GetEventHandler()->ProcessEvent(helpEvent);
69231000 3139
4cdc2c13 3140 }
a9c11b71
VZ
3141 else // unknown help event?
3142 {
3143 processed = false;
3144 }
3145#endif // !__WXWINCE__
b96340e6 3146 }
b96340e6 3147 break;
a9c11b71 3148#endif // WM_HELP
4cdc2c13 3149
7f0586ef 3150#if !defined(__WXWINCE__)
69231000 3151 case WM_CONTEXTMENU:
4cdc2c13
VZ
3152 {
3153 // we don't convert from screen to client coordinates as
3154 // the event may be handled by a parent window
3155 wxPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
3156
3157 wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt);
2d1715aa
VZ
3158
3159 // we could have got an event from our child, reflect it back
3160 // to it if this is the case
d85c53a5 3161 wxWindowMSW *win = NULL;
c140b7e7 3162 if ( (WXHWND)wParam != m_hWnd )
2d1715aa
VZ
3163 {
3164 win = FindItemByHWND((WXHWND)wParam);
3165 }
3166
3167 if ( !win )
3168 win = this;
3169
3170 evtCtx.SetEventObject(win);
3171 processed = win->GetEventHandler()->ProcessEvent(evtCtx);
4cdc2c13 3172 }
69231000 3173 break;
7f0586ef 3174#endif
b74cce40
VZ
3175
3176 case WM_MENUCHAR:
3177 // we're only interested in our own menus, not MF_SYSMENU
3178 if ( HIWORD(wParam) == MF_POPUP )
3179 {
3180 // handle menu chars for ownerdrawn menu items
3181 int i = HandleMenuChar(toupper(LOWORD(wParam)), lParam);
3182 if ( i != wxNOT_FOUND )
3183 {
3184 rc.result = MAKELRESULT(i, MNC_EXECUTE);
08158721 3185 processed = true;
b74cce40
VZ
3186 }
3187 }
3188 break;
355debca 3189
dbc74bcc 3190#ifndef __WXWINCE__
355debca
VZ
3191 case WM_POWERBROADCAST:
3192 {
3193 bool vetoed;
3194 processed = HandlePower(wParam, lParam, &vetoed);
3195 rc.result = processed && vetoed ? BROADCAST_QUERY_DENY : TRUE;
3196 }
3197 break;
dbc74bcc 3198#endif // __WXWINCE__
a23fd0e1 3199 }
2d0a075d 3200
42e69d6b 3201 if ( !processed )
2d0a075d 3202 {
42e69d6b 3203#ifdef __WXDEBUG__
223d09f6 3204 wxLogTrace(wxTraceMessages, wxT("Forwarding %s to DefWindowProc."),
42e69d6b
VZ
3205 wxGetMessageName(message));
3206#endif // __WXDEBUG__
3207 rc.result = MSWDefWindowProc(message, wParam, lParam);
a23fd0e1 3208 }
2bda0e17 3209
42e69d6b 3210 return rc.result;
2bda0e17
KB
3211}
3212
b225f659
VZ
3213// ----------------------------------------------------------------------------
3214// wxWindow <-> HWND map
3215// ----------------------------------------------------------------------------
2bda0e17 3216
1bffa913 3217wxWinHashTable *wxWinHandleHash = NULL;
b225f659 3218
42e69d6b 3219wxWindow *wxFindWinFromHandle(WXHWND hWnd)
4ce81a75 3220{
40ad3426 3221 return (wxWindow*)wxWinHandleHash->Get((long)hWnd);
42e69d6b 3222}
4ce81a75 3223
1e6feb95 3224void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win)
42e69d6b
VZ
3225{
3226 // adding NULL hWnd is (first) surely a result of an error and
3227 // (secondly) breaks menu command processing
3228 wxCHECK_RET( hWnd != (HWND)NULL,
223d09f6 3229 wxT("attempt to add a NULL hWnd to window list ignored") );
4ce81a75 3230
c7527e3f 3231 wxWindow *oldWin = wxFindWinFromHandle((WXHWND) hWnd);
b225f659 3232#ifdef __WXDEBUG__
c7527e3f
JS
3233 if ( oldWin && (oldWin != win) )
3234 {
b225f659 3235 wxLogDebug(wxT("HWND %X already associated with another window (%s)"),
9b601c24 3236 (int) hWnd, win->GetClassInfo()->GetClassName());
c7527e3f 3237 }
b225f659
VZ
3238 else
3239#endif // __WXDEBUG__
3240 if (!oldWin)
c7527e3f 3241 {
d2d14464 3242 wxWinHandleHash->Put((long)hWnd, (wxWindow *)win);
c7527e3f 3243 }
42e69d6b 3244}
4ce81a75 3245
1e6feb95 3246void wxRemoveHandleAssociation(wxWindowMSW *win)
42e69d6b 3247{
1bffa913 3248 wxWinHandleHash->Delete((long)win->GetHWND());
4ce81a75
JS
3249}
3250
b225f659
VZ
3251// ----------------------------------------------------------------------------
3252// various MSW speciic class dependent functions
3253// ----------------------------------------------------------------------------
3254
42e69d6b
VZ
3255// Default destroyer - override if you destroy it in some other way
3256// (e.g. with MDI child windows)
1e6feb95 3257void wxWindowMSW::MSWDestroyWindow()
4ce81a75 3258{
42e69d6b 3259}
4ce81a75 3260
b225f659
VZ
3261bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
3262 const wxSize& size,
3263 int& x, int& y,
3264 int& w, int& h) const
2bda0e17 3265{
9cb57df4 3266 // yes, those are just some arbitrary hardcoded numbers
2a77c8c4 3267 static const int DEFAULT_Y = 200;
2a77c8c4 3268
08158721 3269 bool nonDefault = false;
c085e333 3270
422d0ff0 3271 if ( pos.x == wxDefaultCoord )
b225f659 3272 {
9cb57df4
VZ
3273 // if x is set to CW_USEDEFAULT, y parameter is ignored anyhow so we
3274 // can just as well set it to CW_USEDEFAULT as well
b225f659
VZ
3275 x =
3276 y = CW_USEDEFAULT;
3277 }
3278 else
a23fd0e1 3279 {
2a77c8c4
VZ
3280 // OTOH, if x is not set to CW_USEDEFAULT, y shouldn't be set to it
3281 // neither because it is not handled as a special value by Windows then
3282 // and so we have to choose some default value for it
b225f659 3283 x = pos.x;
422d0ff0 3284 y = pos.y == wxDefaultCoord ? DEFAULT_Y : pos.y;
c085e333 3285
08158721 3286 nonDefault = true;
42e69d6b 3287 }
2bda0e17 3288
b889a3a2
VZ
3289 /*
3290 NB: there used to be some code here which set the initial size of the
3291 window to the client size of the parent if no explicit size was
77ffb593 3292 specified. This was wrong because wxWidgets programs often assume
b889a3a2
VZ
3293 that they get a WM_SIZE (EVT_SIZE) upon creation, however this broke
3294 it. To see why, you should understand that Windows sends WM_SIZE from
3295 inside ::CreateWindow() anyhow. However, ::CreateWindow() is called
3296 from some base class ctor and so this WM_SIZE is not processed in the
3297 real class' OnSize() (because it's not fully constructed yet and the
3298 event goes to some base class OnSize() instead). So the WM_SIZE we
3299 rely on is the one sent when the parent frame resizes its children
3300 but here is the problem: if the child already has just the right
77ffb593 3301 size, nothing will happen as both wxWidgets and Windows check for
b889a3a2
VZ
3302 this and ignore any attempts to change the window size to the size it
3303 already has - so no WM_SIZE would be sent.
3304 */
b225f659 3305
35bbb0c6 3306
426936d1
RD
3307 // we don't use CW_USEDEFAULT here for several reasons:
3308 //
3309 // 1. it results in huge frames on modern screens (1000*800 is not
3310 // uncommon on my 1280*1024 screen) which is way too big for a half
77ffb593 3311 // empty frame of most of wxWidgets samples for example)
426936d1
RD
3312 //
3313 // 2. it is buggy for frames with wxFRAME_TOOL_WINDOW style for which
3314 // the default is for whatever reason 8*8 which breaks client <->
3315 // window size calculations (it would be nice if it didn't, but it
3316 // does and the simplest way to fix it seemed to change the broken
3317 // default size anyhow)
3318 //
3319 // 3. there is just no advantage in doing it: with x and y it is
3320 // possible that [future versions of] Windows position the new top
3321 // level window in some smart way which we can't do, but we can
3322 // guess a reasonably good size for a new window just as well
3323 // ourselves
960b193e 3324
3a3c8603
DS
3325 // However, on PocketPC devices, we must use the default
3326 // size if possible.
960b193e 3327#ifdef _WIN32_WCE
422d0ff0 3328 if (size.x == wxDefaultCoord)
3a3c8603
DS
3329 w = CW_USEDEFAULT;
3330 else
3331 w = size.x;
422d0ff0 3332 if (size.y == wxDefaultCoord)
3a3c8603
DS
3333 h = CW_USEDEFAULT;
3334 else
3335 h = size.y;
960b193e 3336#else
422d0ff0 3337 if ( size.x == wxDefaultCoord || size.y == wxDefaultCoord)
426936d1 3338 {
08158721 3339 nonDefault = true;
8614c467 3340 }
426936d1
RD
3341 w = WidthDefault(size.x);
3342 h = HeightDefault(size.y);
960b193e 3343#endif
8614c467 3344
4e9d23cd
VZ
3345 AdjustForParentClientOrigin(x, y);
3346
b225f659
VZ
3347 return nonDefault;
3348}
3349
9dfef5ac
VZ
3350WXHWND wxWindowMSW::MSWGetParent() const
3351{
d285d708 3352 return m_parent ? m_parent->GetHWND() : WXHWND(NULL);
9dfef5ac
VZ
3353}
3354
b225f659
VZ
3355bool wxWindowMSW::MSWCreate(const wxChar *wclass,
3356 const wxChar *title,
3357 const wxPoint& pos,
3358 const wxSize& size,
3359 WXDWORD style,
3360 WXDWORD extendedStyle)
3361{
3362 // choose the position/size for the new window
3363 int x, y, w, h;
3364 (void)MSWGetCreateWindowCoords(pos, size, x, y, w, h);
3365
b225f659
VZ
3366 // controlId is menu handle for the top level windows, so set it to 0
3367 // unless we're creating a child window
f586fde3 3368 int controlId = style & WS_CHILD ? GetId() : 0;
2bda0e17 3369
b225f659
VZ
3370 // for each class "Foo" we have we also have "FooNR" ("no repaint") class
3371 // which is the same but without CS_[HV]REDRAW class styles so using it
3372 // ensures that the window is not fully repainted on each resize
3373 wxString className(wclass);
e441e1f4 3374 if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) )
b225f659
VZ
3375 {
3376 className += wxT("NR");
a23fd0e1 3377 }
c085e333 3378
b225f659
VZ
3379 // do create the window
3380 wxWindowCreationHook hook(this);
b3daa5a3 3381
5e67eb97
VZ
3382 m_hWnd = (WXHWND)::CreateWindowEx
3383 (
3384 extendedStyle,
3385 className,
3386 title ? title : m_windowName.c_str(),
3387 style,
3388 x, y, w, h,
3389 (HWND)MSWGetParent(),
3390 (HMENU)controlId,
3391 wxGetInstance(),
3392 NULL // no extra data
3393 );
b225f659
VZ
3394
3395 if ( !m_hWnd )
c7527e3f 3396 {
5e67eb97 3397 wxLogSysError(_("Can't create window of class %s"), className.c_str());
b225f659 3398
08158721 3399 return false;
c7527e3f 3400 }
b3daa5a3 3401
b225f659 3402 SubclassWin(m_hWnd);
c085e333 3403
08158721 3404 return true;
2bda0e17
KB
3405}
3406
42e69d6b
VZ
3407// ===========================================================================
3408// MSW message handlers
3409// ===========================================================================
3410
3411// ---------------------------------------------------------------------------
3412// WM_NOTIFY
3413// ---------------------------------------------------------------------------
3414
1e6feb95 3415bool wxWindowMSW::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
2bda0e17 3416{
04ef50df 3417#ifndef __WXMICROWIN__
42e69d6b
VZ
3418 LPNMHDR hdr = (LPNMHDR)lParam;
3419 HWND hWnd = hdr->hwndFrom;
3420 wxWindow *win = wxFindWinFromHandle((WXHWND)hWnd);
3421
2b15b970 3422 // if the control is one of our windows, let it handle the message itself
42e69d6b 3423 if ( win )
564b2609 3424 {
42e69d6b 3425 return win->MSWOnNotify(idCtrl, lParam, result);
564b2609 3426 }
2bda0e17 3427
2b15b970
VZ
3428 // VZ: why did we do it? normally this is unnecessary and, besides, it
3429 // breaks the message processing for the toolbars because the tooltip
3430 // notifications were being forwarded to the toolbar child controls
3431 // (if it had any) before being passed to the toolbar itself, so in my
3432 // example the tooltip for the combobox was always shown instead of the
3433 // correct button tooltips
3434#if 0
42e69d6b 3435 // try all our children
222ed1d6 3436 wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
42e69d6b 3437 while ( node )
564b2609 3438 {
42e69d6b
VZ
3439 wxWindow *child = node->GetData();
3440 if ( child->MSWOnNotify(idCtrl, lParam, result) )
3441 {
08158721 3442 return true;
42e69d6b 3443 }
2d0a075d 3444
42e69d6b
VZ
3445 node = node->GetNext();
3446 }
2b15b970 3447#endif // 0
2d0a075d 3448
2b15b970 3449 // by default, handle it ourselves
42e69d6b 3450 return MSWOnNotify(idCtrl, lParam, result);
cd4453e5 3451#else // __WXMICROWIN__
08158721 3452 return false;
04ef50df 3453#endif
42e69d6b 3454}
2d0a075d 3455
bd9cd534
VZ
3456#if wxUSE_TOOLTIPS
3457
3458bool wxWindowMSW::HandleTooltipNotify(WXUINT code,
3459 WXLPARAM lParam,
3460 const wxString& ttip)
3461{
3462 // I don't know why it happens, but the versions of comctl32.dll starting
3463 // from 4.70 sometimes send TTN_NEEDTEXTW even to ANSI programs (normally,
3464 // this message is supposed to be sent to Unicode programs only) -- hence
3465 // we need to handle it as well, otherwise no tooltips will be shown in
3466 // this case
7f0586ef 3467#ifndef __WXWINCE__
118208ac
VZ
3468 if ( !(code == (WXUINT) TTN_NEEDTEXTA || code == (WXUINT) TTN_NEEDTEXTW)
3469 || ttip.empty() )
bd9cd534
VZ
3470 {
3471 // not a tooltip message or no tooltip to show anyhow
08158721 3472 return false;
bd9cd534 3473 }
7f0586ef 3474#endif
bd9cd534
VZ
3475
3476 LPTOOLTIPTEXT ttText = (LPTOOLTIPTEXT)lParam;
3477
118208ac
VZ
3478 // We don't want to use the szText buffer because it has a limit of 80
3479 // bytes and this is not enough, especially for Unicode build where it
3480 // limits the tooltip string length to only 40 characters
3481 //
3482 // The best would be, of course, to not impose any length limitations at
3483 // all but then the buffer would have to be dynamic and someone would have
3484 // to free it and we don't have the tooltip owner object here any more, so
3485 // for now use our own static buffer with a higher fixed max length.
3486 //
3487 // Note that using a static buffer should not be a problem as only a single
3488 // tooltip can be shown at the same time anyhow.
2b5f62a0 3489#if !wxUSE_UNICODE
118208ac 3490 if ( code == (WXUINT) TTN_NEEDTEXTW )
bd9cd534 3491 {
118208ac
VZ
3492 // We need to convert tooltip from multi byte to Unicode on the fly.
3493 static wchar_t buf[513];
25c46fda 3494
118208ac
VZ
3495 // Truncate tooltip length if needed as otherwise we might not have
3496 // enough space for it in the buffer and MultiByteToWideChar() would
3497 // return an error
fec9cc08 3498 size_t tipLength = wxMin(ttip.length(), WXSIZEOF(buf) - 1);
7afebc8c
JS
3499
3500 // Convert to WideChar without adding the NULL character. The NULL
25c46fda 3501 // character is added afterwards (this is more efficient).
118208ac
VZ
3502 int len = ::MultiByteToWideChar
3503 (
3504 CP_ACP,
3505 0, // no flags
3506 ttip,
3507 tipLength,
3508 buf,
3509 WXSIZEOF(buf) - 1
3510 );
3511
3512 if ( !len )
3513 {
3514 wxLogLastError(_T("MultiByteToWideChar()"));
3515 }
7afebc8c 3516
118208ac
VZ
3517 buf[len] = L'\0';
3518 ttText->lpszText = (LPSTR) buf;
3519 }
3520 else // TTN_NEEDTEXTA
3521#endif // !wxUSE_UNICODE
3522 {
3523 // we get here if we got TTN_NEEDTEXTA (only happens in ANSI build) or
3524 // if we got TTN_NEEDTEXTW in Unicode build: in this case we just have
3525 // to copy the string we have into the buffer
3526 static wxChar buf[513];
3527 wxStrncpy(buf, ttip.c_str(), WXSIZEOF(buf) - 1);
3528 buf[WXSIZEOF(buf) - 1] = _T('\0');
3529 ttText->lpszText = buf;
bd9cd534
VZ
3530 }
3531
08158721 3532 return true;
bd9cd534
VZ
3533}
3534
3535#endif // wxUSE_TOOLTIPS
3536
1e6feb95 3537bool wxWindowMSW::MSWOnNotify(int WXUNUSED(idCtrl),
bd9cd534
VZ
3538 WXLPARAM lParam,
3539 WXLPARAM* WXUNUSED(result))
42e69d6b
VZ
3540{
3541#if wxUSE_TOOLTIPS
bd9cd534 3542 if ( m_tooltip )
42e69d6b 3543 {
bd9cd534
VZ
3544 NMHDR* hdr = (NMHDR *)lParam;
3545 if ( HandleTooltipNotify(hdr->code, lParam, m_tooltip->GetTip()))
3546 {
3547 // processed
08158721 3548 return true;
bd9cd534 3549 }
42e69d6b 3550 }
f5dd1cf1
WS
3551#else
3552 wxUnusedVar(lParam);
42e69d6b
VZ
3553#endif // wxUSE_TOOLTIPS
3554
08158721 3555 return false;
42e69d6b 3556}
2b15b970 3557
42e69d6b
VZ
3558// ---------------------------------------------------------------------------
3559// end session messages
3560// ---------------------------------------------------------------------------
2d0a075d 3561
1e6feb95 3562bool wxWindowMSW::HandleQueryEndSession(long logOff, bool *mayEnd)
42e69d6b 3563{
040e5f77 3564#ifdef ENDSESSION_LOGOFF
abb74e0f 3565 wxCloseEvent event(wxEVT_QUERY_END_SESSION, wxID_ANY);
42e69d6b 3566 event.SetEventObject(wxTheApp);
08158721 3567 event.SetCanVeto(true);
a17e237f 3568 event.SetLoggingOff(logOff == (long)ENDSESSION_LOGOFF);
2d0a075d 3569
42e69d6b
VZ
3570 bool rc = wxTheApp->ProcessEvent(event);
3571
3572 if ( rc )
3573 {
3574 // we may end only if the app didn't veto session closing (double
3575 // negation...)
3576 *mayEnd = !event.GetVeto();
2d0a075d
JS
3577 }
3578
42e69d6b 3579 return rc;
7f0586ef 3580#else
040e5f77
VZ
3581 wxUnusedVar(logOff);
3582 wxUnusedVar(mayEnd);
08158721 3583 return false;
7f0586ef 3584#endif
2bda0e17
KB
3585}
3586
1e6feb95 3587bool wxWindowMSW::HandleEndSession(bool endSession, long logOff)
2bda0e17 3588{
040e5f77 3589#ifdef ENDSESSION_LOGOFF
42e69d6b
VZ
3590 // do nothing if the session isn't ending
3591 if ( !endSession )
08158721 3592 return false;
a23fd0e1 3593
519dc37f
VZ
3594 // only send once
3595 if ( (this != wxTheApp->GetTopWindow()) )
08158721 3596 return false;
519dc37f 3597
abb74e0f 3598 wxCloseEvent event(wxEVT_END_SESSION, wxID_ANY);
42e69d6b 3599 event.SetEventObject(wxTheApp);
08158721 3600 event.SetCanVeto(false);
a17e237f 3601 event.SetLoggingOff( (logOff == (long)ENDSESSION_LOGOFF) );
519dc37f
VZ
3602
3603 return wxTheApp->ProcessEvent(event);
7f0586ef 3604#else
040e5f77
VZ
3605 wxUnusedVar(endSession);
3606 wxUnusedVar(logOff);
08158721 3607 return false;
7f0586ef 3608#endif
2bda0e17
KB
3609}
3610
42e69d6b
VZ
3611// ---------------------------------------------------------------------------
3612// window creation/destruction
3613// ---------------------------------------------------------------------------
3614
0c0d1521
WS
3615bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT WXUNUSED_IN_WINCE(cs),
3616 bool *mayCreate)
61179e28 3617{
ee471817
VZ
3618 // VZ: why is this commented out for WinCE? If it doesn't support
3619 // WS_EX_CONTROLPARENT at all it should be somehow handled globally,
3620 // not with multiple #ifdef's!
7f0586ef 3621#ifndef __WXWINCE__
61179e28 3622 if ( ((CREATESTRUCT *)cs)->dwExStyle & WS_EX_CONTROLPARENT )
ee471817
VZ
3623 EnsureParentHasControlParentStyle(GetParent());
3624#endif // !__WXWINCE__
61179e28 3625
08158721 3626 *mayCreate = true;
42e69d6b 3627
08158721 3628 return true;
2bda0e17
KB
3629}
3630
1e6feb95 3631bool wxWindowMSW::HandleDestroy()
2bda0e17 3632{
7de59551 3633 SendDestroyEvent();
42e69d6b
VZ
3634
3635 // delete our drop target if we've got one
3636#if wxUSE_DRAG_AND_DROP
3637 if ( m_dropTarget != NULL )
2d0a075d 3638 {
42e69d6b
VZ
3639 m_dropTarget->Revoke(m_hWnd);
3640
3641 delete m_dropTarget;
3642 m_dropTarget = NULL;
2d0a075d 3643 }
42e69d6b 3644#endif // wxUSE_DRAG_AND_DROP
2bda0e17 3645
42e69d6b 3646 // WM_DESTROY handled
08158721 3647 return true;
2bda0e17
KB
3648}
3649
42e69d6b
VZ
3650// ---------------------------------------------------------------------------
3651// activation/focus
3652// ---------------------------------------------------------------------------
3653
1e6feb95 3654bool wxWindowMSW::HandleActivate(int state,
42e69d6b
VZ
3655 bool WXUNUSED(minimized),
3656 WXHWND WXUNUSED(activate))
2bda0e17 3657{
42e69d6b
VZ
3658 wxActivateEvent event(wxEVT_ACTIVATE,
3659 (state == WA_ACTIVE) || (state == WA_CLICKACTIVE),
3660 m_windowId);
3661 event.SetEventObject(this);
3662
3663 return GetEventHandler()->ProcessEvent(event);
3664}
3665
1e6feb95 3666bool wxWindowMSW::HandleSetFocus(WXHWND hwnd)
42e69d6b 3667{
c7aee865
RD
3668 // Strangly enough, some controls get set focus events when they are being
3669 // deleted, even if they already had focus before.
3670 if ( m_isBeingDeleted )
3671 {
3672 return false;
3673 }
35bbb0c6 3674
456bc6d9
VZ
3675 // notify the parent keeping track of focus for the kbd navigation
3676 // purposes that we got it
e72aa7f5 3677 wxChildFocusEvent eventFocus((wxWindow *)this);
456bc6d9
VZ
3678 (void)GetEventHandler()->ProcessEvent(eventFocus);
3679
789295bf 3680#if wxUSE_CARET
42e69d6b 3681 // Deal with caret
789295bf 3682 if ( m_caret )
2d0a075d 3683 {
789295bf 3684 m_caret->OnSetFocus();
2bda0e17 3685 }
789295bf 3686#endif // wxUSE_CARET
42e69d6b 3687
ab93a576
RD
3688#if wxUSE_TEXTCTRL
3689 // If it's a wxTextCtrl don't send the event as it will be done
456bc6d9
VZ
3690 // after the control gets to process it from EN_FOCUS handler
3691 if ( wxDynamicCastThis(wxTextCtrl) )
ab93a576 3692 {
08158721 3693 return false;
ab93a576 3694 }
456bc6d9 3695#endif // wxUSE_TEXTCTRL
ab93a576 3696
42e69d6b
VZ
3697 wxFocusEvent event(wxEVT_SET_FOCUS, m_windowId);
3698 event.SetEventObject(this);
3699
1e6feb95
VZ
3700 // wxFindWinFromHandle() may return NULL, it is ok
3701 event.SetWindow(wxFindWinFromHandle(hwnd));
3702
42e69d6b 3703 return GetEventHandler()->ProcessEvent(event);
2bda0e17
KB
3704}
3705
1e6feb95 3706bool wxWindowMSW::HandleKillFocus(WXHWND hwnd)
2bda0e17 3707{
789295bf 3708#if wxUSE_CARET
42e69d6b 3709 // Deal with caret
789295bf 3710 if ( m_caret )
2d0a075d 3711 {
789295bf 3712 m_caret->OnKillFocus();
2bda0e17 3713 }
789295bf 3714#endif // wxUSE_CARET
42e69d6b 3715
ab93a576
RD
3716#if wxUSE_TEXTCTRL
3717 // If it's a wxTextCtrl don't send the event as it will be done
3718 // after the control gets to process it.
3719 wxTextCtrl *ctrl = wxDynamicCastThis(wxTextCtrl);
3720 if ( ctrl )
3721 {
08158721 3722 return false;
ab93a576
RD
3723 }
3724#endif
3725
2913e597
RD
3726 // Don't send the event when in the process of being deleted. This can
3727 // only cause problems if the event handler tries to access the object.
3728 if ( m_isBeingDeleted )
3729 {
08158721 3730 return false;
2913e597
RD
3731 }
3732
42e69d6b
VZ
3733 wxFocusEvent event(wxEVT_KILL_FOCUS, m_windowId);
3734 event.SetEventObject(this);
3735
1e6feb95
VZ
3736 // wxFindWinFromHandle() may return NULL, it is ok
3737 event.SetWindow(wxFindWinFromHandle(hwnd));
3738
42e69d6b 3739 return GetEventHandler()->ProcessEvent(event);
2bda0e17
KB
3740}
3741
faa49bfd
WS
3742// ---------------------------------------------------------------------------
3743// labels
3744// ---------------------------------------------------------------------------
3745
3746void wxWindowMSW::SetLabel( const wxString& label)
3747{
3748 SetWindowText(GetHwnd(), label.c_str());
3749}
3750
3751wxString wxWindowMSW::GetLabel() const
3752{
3753 return wxGetWindowText(GetHWND());
3754}
3755
42e69d6b
VZ
3756// ---------------------------------------------------------------------------
3757// miscellaneous
3758// ---------------------------------------------------------------------------
3759
1e6feb95 3760bool wxWindowMSW::HandleShow(bool show, int WXUNUSED(status))
2bda0e17 3761{
42e69d6b 3762 wxShowEvent event(GetId(), show);
687706f5 3763 event.SetEventObject(this);
42e69d6b
VZ
3764
3765 return GetEventHandler()->ProcessEvent(event);
2bda0e17
KB
3766}
3767
1e6feb95 3768bool wxWindowMSW::HandleInitDialog(WXHWND WXUNUSED(hWndFocus))
2bda0e17 3769{
42e69d6b 3770 wxInitDialogEvent event(GetId());
687706f5 3771 event.SetEventObject(this);
42e69d6b
VZ
3772
3773 return GetEventHandler()->ProcessEvent(event);
2bda0e17
KB
3774}
3775
1e6feb95 3776bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam)
2bda0e17 3777{
7f0586ef 3778#if defined (__WXMICROWIN__) || defined(__WXWINCE__)
35bbb0c6 3779 wxUnusedVar(wParam);
08158721 3780 return false;
4ce1efe1 3781#else // __WXMICROWIN__
42e69d6b 3782 HDROP hFilesInfo = (HDROP) wParam;
42e69d6b
VZ
3783
3784 // Get the total number of files dropped
c3c39620 3785 UINT gwFilesDropped = ::DragQueryFile
f6bcfd97
BP
3786 (
3787 (HDROP)hFilesInfo,
3788 (UINT)-1,
3789 (LPTSTR)0,
3790 (UINT)0
3791 );
42e69d6b
VZ
3792
3793 wxString *files = new wxString[gwFilesDropped];
c3c39620 3794 for ( UINT wIndex = 0; wIndex < gwFilesDropped; wIndex++ )
2d0a075d 3795 {
c3c39620
VZ
3796 // first get the needed buffer length (+1 for terminating NUL)
3797 size_t len = ::DragQueryFile(hFilesInfo, wIndex, NULL, 0) + 1;
3798
3799 // and now get the file name
3800 ::DragQueryFile(hFilesInfo, wIndex,
de564874 3801 wxStringBuffer(files[wIndex], len), len);
2d0a075d 3802 }
42e69d6b 3803 DragFinish (hFilesInfo);
2bda0e17 3804
42e69d6b 3805 wxDropFilesEvent event(wxEVT_DROP_FILES, gwFilesDropped, files);
687706f5 3806 event.SetEventObject(this);
c3c39620
VZ
3807
3808 POINT dropPoint;
3809 DragQueryPoint(hFilesInfo, (LPPOINT) &dropPoint);
b3dc8a3e
VZ
3810 event.m_pos.x = dropPoint.x;
3811 event.m_pos.y = dropPoint.y;
42e69d6b 3812
c3c39620 3813 return GetEventHandler()->ProcessEvent(event);
04ef50df 3814#endif
2bda0e17
KB
3815}
3816
cc972ac6 3817
1e6feb95
VZ
3818bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd),
3819 short nHitTest,
3820 int WXUNUSED(mouseMsg))
2bda0e17 3821{
04ef50df 3822#ifndef __WXMICROWIN__
bfbd6dc1 3823 // the logic is as follows:
43b5058d
VZ
3824 // -1. don't set cursor for non client area, including but not limited to
3825 // the title bar, scrollbars, &c
3826 // 0. allow the user to override default behaviour by using EVT_SET_CURSOR
bfbd6dc1
VZ
3827 // 1. if we have the cursor set it unless wxIsBusy()
3828 // 2. if we're a top level window, set some cursor anyhow
3829 // 3. if wxIsBusy(), set the busy cursor, otherwise the global one
42e69d6b 3830
43b5058d
VZ
3831 if ( nHitTest != HTCLIENT )
3832 {
08158721 3833 return false;
43b5058d
VZ
3834 }
3835
bfbd6dc1 3836 HCURSOR hcursor = 0;
43b5058d
VZ
3837
3838 // first ask the user code - it may wish to set the cursor in some very
3839 // specific way (for example, depending on the current position)
3840 POINT pt;
f2325516 3841#ifdef __WXWINCE__
7d30268c 3842 if ( !::GetCursorPosWinCE(&pt))
f2325516 3843#else
43b5058d 3844 if ( !::GetCursorPos(&pt) )
3fca879c 3845#endif
43b5058d 3846 {
f6bcfd97 3847 wxLogLastError(wxT("GetCursorPos"));
43b5058d
VZ
3848 }
3849
3850 int x = pt.x,
3851 y = pt.y;
3852 ScreenToClient(&x, &y);
3853 wxSetCursorEvent event(x, y);
3854
3855 bool processedEvtSetCursor = GetEventHandler()->ProcessEvent(event);
3856 if ( processedEvtSetCursor && event.HasCursor() )
bfbd6dc1 3857 {
43b5058d 3858 hcursor = GetHcursorOf(event.GetCursor());
bfbd6dc1 3859 }
42e69d6b 3860
43b5058d 3861 if ( !hcursor )
bfbd6dc1 3862 {
43b5058d
VZ
3863 bool isBusy = wxIsBusy();
3864
3865 // the test for processedEvtSetCursor is here to prevent using m_cursor
3866 // if the user code caught EVT_SET_CURSOR() and returned nothing from
3867 // it - this is a way to say that our cursor shouldn't be used for this
3868 // point
3869 if ( !processedEvtSetCursor && m_cursor.Ok() )
bfbd6dc1 3870 {
43b5058d 3871 hcursor = GetHcursorOf(m_cursor);
bfbd6dc1 3872 }
43b5058d
VZ
3873
3874 if ( !GetParent() )
bfbd6dc1 3875 {
43b5058d 3876 if ( isBusy )
42e69d6b 3877 {
43b5058d
VZ
3878 hcursor = wxGetCurrentBusyCursor();
3879 }
3880 else if ( !hcursor )
3881 {
3882 const wxCursor *cursor = wxGetGlobalCursor();
3883 if ( cursor && cursor->Ok() )
3884 {
3885 hcursor = GetHcursorOf(*cursor);
3886 }
42e69d6b
VZ
3887 }
3888 }
3889 }
3890
bfbd6dc1
VZ
3891 if ( hcursor )
3892 {
2b5f62a0
VZ
3893// wxLogDebug("HandleSetCursor: Setting cursor %ld", (long) hcursor);
3894
bfbd6dc1
VZ
3895 ::SetCursor(hcursor);
3896
3897 // cursor set, stop here
08158721 3898 return true;
bfbd6dc1 3899 }
cd4453e5
VZ
3900#endif // __WXMICROWIN__
3901
3ca6a5f0 3902 // pass up the window chain
08158721 3903 return false;
2bda0e17
KB
3904}
3905
dbc74bcc 3906bool wxWindowMSW::HandlePower(WXWPARAM WXUNUSED_IN_WINCE(wParam),
355debca 3907 WXLPARAM WXUNUSED(lParam),
dbc74bcc 3908 bool *WXUNUSED_IN_WINCE(vetoed))
355debca 3909{
dbc74bcc
WS
3910#ifdef __WXWINCE__
3911 // FIXME
3912 return false;
3913#else
355debca
VZ
3914 wxEventType evtType;
3915 switch ( wParam )
3916 {
3917 case PBT_APMQUERYSUSPEND:
3918 evtType = wxEVT_POWER_SUSPENDING;
3919 break;
3920
3921 case PBT_APMQUERYSUSPENDFAILED:
3922 evtType = wxEVT_POWER_SUSPEND_CANCEL;
3923 break;
3924
3925 case PBT_APMSUSPEND:
3926 evtType = wxEVT_POWER_SUSPENDED;
3927 break;
3928
3929 case PBT_APMRESUMESUSPEND:
d4cd85a0
VZ
3930#ifdef PBT_APMRESUMEAUTOMATIC
3931 case PBT_APMRESUMEAUTOMATIC:
3932#endif
355debca
VZ
3933 evtType = wxEVT_POWER_RESUME;
3934 break;
3935
3936 default:
3937 wxLogDebug(_T("Unknown WM_POWERBROADCAST(%d) event"), wParam);
3938 // fall through
3939
3940 // these messages are currently not mapped to wx events
3941 case PBT_APMQUERYSTANDBY:
3942 case PBT_APMQUERYSTANDBYFAILED:
3943 case PBT_APMSTANDBY:
3944 case PBT_APMRESUMESTANDBY:
3945 case PBT_APMBATTERYLOW:
3946 case PBT_APMPOWERSTATUSCHANGE:
3947 case PBT_APMOEMEVENT:
355debca
VZ
3948 case PBT_APMRESUMECRITICAL:
3949 evtType = wxEVT_NULL;
3950 break;
3951 }
3952
3953 // don't handle unknown messages
3954 if ( evtType == wxEVT_NULL )
3955 return false;
3956
3957 // TODO: notify about PBTF_APMRESUMEFROMFAILURE in case of resume events?
3958
3959 wxPowerEvent event(evtType);
3960 if ( !GetEventHandler()->ProcessEvent(event) )
3961 return false;
3962
3963 *vetoed = event.IsVetoed();
3964
3965 return true;
dbc74bcc 3966#endif
355debca
VZ
3967}
3968
2e992e06
VZ
3969bool wxWindowMSW::IsDoubleBuffered() const
3970{
967acfb5 3971 for ( const wxWindowMSW *wnd = this;
c719013f
VZ
3972 wnd && !wnd->IsTopLevel(); wnd =
3973 wnd->GetParent() )
2e992e06 3974 {
c719013f 3975 if ( ::GetWindowLong(GetHwndOf(wnd), GWL_EXSTYLE) & WS_EX_COMPOSITED )
2e992e06 3976 return true;
2e992e06
VZ
3977 }
3978
3979 return false;
3980}
3981
42e69d6b
VZ
3982// ---------------------------------------------------------------------------
3983// owner drawn stuff
3984// ---------------------------------------------------------------------------
3985
61fef19b
VZ
3986#if (wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE) || \
3987 (wxUSE_CONTROLS && !defined(__WXUNIVERSAL__))
3988 #define WXUNUSED_UNLESS_ODRAWN(param) param
3989#else
3990 #define WXUNUSED_UNLESS_ODRAWN(param)
3991#endif
3992
3993bool
3994wxWindowMSW::MSWOnDrawItem(int WXUNUSED_UNLESS_ODRAWN(id),
3995 WXDRAWITEMSTRUCT * WXUNUSED_UNLESS_ODRAWN(itemStruct))
2bda0e17 3996{
4286a5b5 3997#if wxUSE_OWNER_DRAWN
1e6feb95
VZ
3998
3999#if wxUSE_MENUS_NATIVE
42e69d6b 4000 // is it a menu item?
6f806543
VZ
4001 DRAWITEMSTRUCT *pDrawStruct = (DRAWITEMSTRUCT *)itemStruct;
4002 if ( id == 0 && pDrawStruct->CtlType == ODT_MENU )
42e69d6b 4003 {
42e69d6b 4004 wxMenuItem *pMenuItem = (wxMenuItem *)(pDrawStruct->itemData);
03cef643 4005
2d29bf54
JS
4006 // see comment before the same test in MSWOnMeasureItem() below
4007 if ( !pMenuItem )
4008 return false;
4009
4010 wxCHECK_MSG( wxDynamicCast(pMenuItem, wxMenuItem),
42f25dcf 4011 false, _T("MSWOnDrawItem: bad wxMenuItem pointer") );
42e69d6b 4012
7561aacd
VZ
4013 // prepare to call OnDrawItem(): notice using of wxDCTemp to prevent
4014 // the DC from being released
4015 wxDCTemp dc((WXHDC)pDrawStruct->hDC);
42e69d6b
VZ
4016 wxRect rect(pDrawStruct->rcItem.left, pDrawStruct->rcItem.top,
4017 pDrawStruct->rcItem.right - pDrawStruct->rcItem.left,
4018 pDrawStruct->rcItem.bottom - pDrawStruct->rcItem.top);
4019
4020 return pMenuItem->OnDrawItem
7561aacd
VZ
4021 (
4022 dc,
4023 rect,
4024 (wxOwnerDrawn::wxODAction)pDrawStruct->itemAction,
4025 (wxOwnerDrawn::wxODStatus)pDrawStruct->itemState
4026 );
42e69d6b 4027 }
1e6feb95 4028#endif // wxUSE_MENUS_NATIVE
42e69d6b 4029
c8e4fa8b
JS
4030#endif // USE_OWNER_DRAWN
4031
6a89f9ee 4032#if wxUSE_CONTROLS && !defined(__WXUNIVERSAL__)
c8e4fa8b 4033
c8e4fa8b 4034#if wxUSE_OWNER_DRAWN
1384636d 4035 wxControl *item = wxDynamicCast(FindItem(id), wxControl);
567be187 4036#else // !wxUSE_OWNER_DRAWN
1384636d
VS
4037 // we may still have owner-drawn buttons internally because we have to make
4038 // them owner-drawn to support colour change
35bbb0c6 4039 wxControl *item =
095b80e2
WS
4040# if wxUSE_BUTTON
4041 wxDynamicCast(FindItem(id), wxButton)
4042# else
4043 NULL
4044# endif
4045 ;
cd0b1709 4046#endif // USE_OWNER_DRAWN
567be187
VZ
4047
4048 if ( item )
4049 {
4050 return item->MSWOnDraw(itemStruct);
4051 }
4286a5b5 4052
c8e4fa8b
JS
4053#endif // wxUSE_CONTROLS
4054
08158721 4055 return false;
2bda0e17
KB
4056}
4057
61fef19b 4058bool
d1d276f2 4059wxWindowMSW::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct)
2bda0e17 4060{
61fef19b 4061#if wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE
42e69d6b 4062 // is it a menu item?
6f806543
VZ
4063 MEASUREITEMSTRUCT *pMeasureStruct = (MEASUREITEMSTRUCT *)itemStruct;
4064 if ( id == 0 && pMeasureStruct->CtlType == ODT_MENU )
2d0a075d 4065 {
42e69d6b
VZ
4066 wxMenuItem *pMenuItem = (wxMenuItem *)(pMeasureStruct->itemData);
4067
b6afa1a3
VZ
4068 // according to Carsten Fuchs the pointer may be NULL under XP if an
4069 // MDI child frame is initially maximized, see this for more info:
4070 // http://article.gmane.org/gmane.comp.lib.wxwidgets.general/27745
4071 //
4072 // so silently ignore it instead of asserting
4073 if ( !pMenuItem )
4074 return false;
4075
4076 wxCHECK_MSG( wxDynamicCast(pMenuItem, wxMenuItem),
42f25dcf 4077 false, _T("MSWOnMeasureItem: bad wxMenuItem pointer") );
42e69d6b 4078
975b6bcf
VZ
4079 size_t w, h;
4080 bool rc = pMenuItem->OnMeasureItem(&w, &h);
4081
4082 pMeasureStruct->itemWidth = w;
4083 pMeasureStruct->itemHeight = h;
4084
4085 return rc;
2d0a075d 4086 }
42e69d6b 4087
567be187
VZ
4088 wxControl *item = wxDynamicCast(FindItem(id), wxControl);
4089 if ( item )
42e69d6b 4090 {
567be187 4091 return item->MSWOnMeasure(itemStruct);
42e69d6b 4092 }
d1d276f2
WS
4093#else
4094 wxUnusedVar(id);
4095 wxUnusedVar(itemStruct);
4096#endif // wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE
567be187 4097
08158721 4098 return false;
2bda0e17
KB
4099}
4100
42e69d6b
VZ
4101// ---------------------------------------------------------------------------
4102// colours and palettes
4103// ---------------------------------------------------------------------------
2bda0e17 4104
1e6feb95 4105bool wxWindowMSW::HandleSysColorChange()
2bda0e17 4106{
42e69d6b
VZ
4107 wxSysColourChangedEvent event;
4108 event.SetEventObject(this);
4109
23895080
VZ
4110 (void)GetEventHandler()->ProcessEvent(event);
4111
4112 // always let the system carry on the default processing to allow the
4113 // native controls to react to the colours update
08158721 4114 return false;
42e69d6b
VZ
4115}
4116
574c939e
KB
4117bool wxWindowMSW::HandleDisplayChange()
4118{
4119 wxDisplayChangedEvent event;
4120 event.SetEventObject(this);
4121
4122 return GetEventHandler()->ProcessEvent(event);
4123}
4124
04ef50df 4125#ifndef __WXMICROWIN__
42e69d6b 4126
1a784dfc 4127bool wxWindowMSW::HandleCtlColor(WXHBRUSH *brush, WXHDC hDC, WXHWND hWnd)
01c500af 4128{
3d74a760 4129#if !wxUSE_CONTROLS || defined(__WXUNIVERSAL__)
43bfb798 4130 wxUnusedVar(hDC);
3d74a760
WS
4131 wxUnusedVar(hWnd);
4132#else
2bae4332 4133 wxControl *item = wxDynamicCast(FindItemByHWND(hWnd, true), wxControl);
c3732409 4134
01c500af 4135 if ( item )
1a784dfc 4136 *brush = item->MSWControlColor(hDC, hWnd);
2d0a075d 4137 else
1e6feb95 4138#endif // wxUSE_CONTROLS
01c500af 4139 *brush = NULL;
42e69d6b 4140
01c500af 4141 return *brush != NULL;
2bda0e17
KB
4142}
4143
01c500af
VZ
4144#endif // __WXMICROWIN__
4145
1e6feb95 4146bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange)
42e69d6b 4147{
574c939e 4148#if wxUSE_PALETTE
b95edd47
VZ
4149 // same as below except we don't respond to our own messages
4150 if ( hWndPalChange != GetHWND() )
4151 {
574c939e 4152 // check to see if we our our parents have a custom palette
fa21d338 4153 wxWindowMSW *win = this;
b95edd47
VZ
4154 while ( win && !win->HasCustomPalette() )
4155 {
4156 win = win->GetParent();
4157 }
4158
4159 if ( win && win->HasCustomPalette() )
4160 {
4161 // realize the palette to see whether redrawing is needed
4162 HDC hdc = ::GetDC((HWND) hWndPalChange);
4163 win->m_palette.SetHPALETTE((WXHPALETTE)
4164 ::SelectPalette(hdc, GetHpaletteOf(win->m_palette), FALSE));
574c939e
KB
4165
4166 int result = ::RealizePalette(hdc);
b95edd47
VZ
4167
4168 // restore the palette (before releasing the DC)
4169 win->m_palette.SetHPALETTE((WXHPALETTE)
4170 ::SelectPalette(hdc, GetHpaletteOf(win->m_palette), FALSE));
4171 ::RealizePalette(hdc);
4172 ::ReleaseDC((HWND) hWndPalChange, hdc);
4173
4174 // now check for the need to redraw
574c939e 4175 if (result > 0)
08158721 4176 ::InvalidateRect((HWND) hWndPalChange, NULL, TRUE);
574c939e 4177 }
b95edd47
VZ
4178
4179 }
4180#endif // wxUSE_PALETTE
574c939e 4181
42e69d6b
VZ
4182 wxPaletteChangedEvent event(GetId());
4183 event.SetEventObject(this);
4184 event.SetChangedWindow(wxFindWinFromHandle(hWndPalChange));
2d0a075d 4185
42e69d6b
VZ
4186 return GetEventHandler()->ProcessEvent(event);
4187}
4188
a5e84126
JS
4189bool wxWindowMSW::HandleCaptureChanged(WXHWND hWndGainedCapture)
4190{
63e819f2
VS
4191 // notify windows on the capture stack about lost capture
4192 // (see http://sourceforge.net/tracker/index.php?func=detail&aid=1153662&group_id=9863&atid=109863):
72f8c792 4193 wxWindowBase::NotifyCaptureLost();
a5e84126 4194
72f8c792 4195 wxWindow *win = wxFindWinFromHandle(hWndGainedCapture);
63e819f2
VS
4196 wxMouseCaptureChangedEvent event(GetId(), win);
4197 event.SetEventObject(this);
a5e84126
JS
4198 return GetEventHandler()->ProcessEvent(event);
4199}
4200
3c96418b
JG
4201bool wxWindowMSW::HandleSettingChange(WXWPARAM wParam, WXLPARAM lParam)
4202{
4203 // despite MSDN saying "(This message cannot be sent directly to a window.)"
4204 // we need to send this to child windows (it is only sent to top-level
4205 // windows) so {list,tree}ctrls can adjust their font size if necessary
4206 // this is exactly how explorer does it to enable the font size changes
4207
4208 wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
4209 while ( node )
4210 {
4211 // top-level windows already get this message from the system
4212 wxWindow *win = node->GetData();
4213 if ( !win->IsTopLevel() )
4214 {
4215 ::SendMessage(GetHwndOf(win), WM_SETTINGCHANGE, wParam, lParam);
4216 }
4217
4218 node = node->GetNext();
4219 }
4220
3c96418b
JG
4221 // let the system handle it
4222 return false;
4223}
4224
1e6feb95 4225bool wxWindowMSW::HandleQueryNewPalette()
42e69d6b 4226{
574c939e
KB
4227
4228#if wxUSE_PALETTE
4229 // check to see if we our our parents have a custom palette
fa21d338 4230 wxWindowMSW *win = this;
574c939e
KB
4231 while (!win->HasCustomPalette() && win->GetParent()) win = win->GetParent();
4232 if (win->HasCustomPalette()) {
4233 /* realize the palette to see whether redrawing is needed */
3a3c8603 4234 HDC hdc = ::GetDC((HWND) GetHWND());
574c939e 4235 win->m_palette.SetHPALETTE( (WXHPALETTE)
b95edd47 4236 ::SelectPalette(hdc, (HPALETTE) win->m_palette.GetHPALETTE(), FALSE) );
574c939e
KB
4237
4238 int result = ::RealizePalette(hdc);
4239 /* restore the palette (before releasing the DC) */
4240 win->m_palette.SetHPALETTE( (WXHPALETTE)
b95edd47 4241 ::SelectPalette(hdc, (HPALETTE) win->m_palette.GetHPALETTE(), TRUE) );
574c939e
KB
4242 ::RealizePalette(hdc);
4243 ::ReleaseDC((HWND) GetHWND(), hdc);
4244 /* now check for the need to redraw */
4245 if (result > 0)
4246 ::InvalidateRect((HWND) GetHWND(), NULL, TRUE);
4247 }
b95edd47 4248#endif // wxUSE_PALETTE
574c939e 4249
42e69d6b
VZ
4250 wxQueryNewPaletteEvent event(GetId());
4251 event.SetEventObject(this);
4252
4253 return GetEventHandler()->ProcessEvent(event) && event.GetPaletteRealized();
4254}
4255
4256// Responds to colour changes: passes event on to children.
574c939e 4257void wxWindowMSW::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event))
42e69d6b 4258{
90c1530a
VZ
4259 // the top level window also reset the standard colour map as it might have
4260 // changed (there is no need to do it for the non top level windows as we
4261 // only have to do it once)
4262 if ( IsTopLevel() )
4263 {
4264 // FIXME-MT
08158721 4265 gs_hasStdCmap = false;
90c1530a 4266 }
222ed1d6 4267 wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
42e69d6b
VZ
4268 while ( node )
4269 {
23895080
VZ
4270 // Only propagate to non-top-level windows because Windows already
4271 // sends this event to all top-level ones
4272 wxWindow *win = node->GetData();
4273 if ( !win->IsTopLevel() )
42e69d6b 4274 {
23895080
VZ
4275 // we need to send the real WM_SYSCOLORCHANGE and not just trigger
4276 // EVT_SYS_COLOUR_CHANGED call because the latter wouldn't work for
4277 // the standard controls
4278 ::SendMessage(GetHwndOf(win), WM_SYSCOLORCHANGE, 0, 0);
564b2609 4279 }
42e69d6b 4280
23895080
VZ
4281 node = node->GetNext();
4282 }
2bda0e17
KB
4283}
4284
90c1530a
VZ
4285extern wxCOLORMAP *wxGetStdColourMap()
4286{
4287 static COLORREF s_stdColours[wxSTD_COL_MAX];
4288 static wxCOLORMAP s_cmap[wxSTD_COL_MAX];
4289
4290 if ( !gs_hasStdCmap )
4291 {
08158721 4292 static bool s_coloursInit = false;
90c1530a
VZ
4293
4294 if ( !s_coloursInit )
4295 {
4296 // When a bitmap is loaded, the RGB values can change (apparently
4297 // because Windows adjusts them to care for the old programs always
4298 // using 0xc0c0c0 while the transparent colour for the new Windows
4299 // versions is different). But we do this adjustment ourselves so
4300 // we want to avoid Windows' "help" and for this we need to have a
4301 // reference bitmap which can tell us what the RGB values change
4302 // to.
e5dbcb50 4303 wxLogNull logNo; // suppress error if we couldn't load the bitmap
90c1530a
VZ
4304 wxBitmap stdColourBitmap(_T("wxBITMAP_STD_COLOURS"));
4305 if ( stdColourBitmap.Ok() )
4306 {
4307 // the pixels in the bitmap must correspond to wxSTD_COL_XXX!
4308 wxASSERT_MSG( stdColourBitmap.GetWidth() == wxSTD_COL_MAX,
4309 _T("forgot to update wxBITMAP_STD_COLOURS!") );
4310
4311 wxMemoryDC memDC;
4312 memDC.SelectObject(stdColourBitmap);
4313
4314 wxColour colour;
4315 for ( size_t i = 0; i < WXSIZEOF(s_stdColours); i++ )
4316 {
4317 memDC.GetPixel(i, 0, &colour);
4318 s_stdColours[i] = wxColourToRGB(colour);
4319 }
4320 }
4321 else // wxBITMAP_STD_COLOURS couldn't be loaded
4322 {
4323 s_stdColours[0] = RGB(000,000,000); // black
4324 s_stdColours[1] = RGB(128,128,128); // dark grey
4325 s_stdColours[2] = RGB(192,192,192); // light grey
4326 s_stdColours[3] = RGB(255,255,255); // white
4327 //s_stdColours[4] = RGB(000,000,255); // blue
4328 //s_stdColours[5] = RGB(255,000,255); // magenta
4329 }
4330
08158721 4331 s_coloursInit = true;
90c1530a
VZ
4332 }
4333
08158721 4334 gs_hasStdCmap = true;
90c1530a
VZ
4335
4336 // create the colour map
4337#define INIT_CMAP_ENTRY(col) \
4338 s_cmap[wxSTD_COL_##col].from = s_stdColours[wxSTD_COL_##col]; \
4339 s_cmap[wxSTD_COL_##col].to = ::GetSysColor(COLOR_##col)
4340
4341 INIT_CMAP_ENTRY(BTNTEXT);
4342 INIT_CMAP_ENTRY(BTNSHADOW);
4343 INIT_CMAP_ENTRY(BTNFACE);
4344 INIT_CMAP_ENTRY(BTNHIGHLIGHT);
4345
4346#undef INIT_CMAP_ENTRY
4347 }
4348
4349 return s_cmap;
4350}
4351
42e69d6b
VZ
4352// ---------------------------------------------------------------------------
4353// painting
4354// ---------------------------------------------------------------------------
4355
1e6feb95 4356bool wxWindowMSW::HandlePaint()
2bda0e17 4357{
42e69d6b
VZ
4358 HRGN hRegion = ::CreateRectRgn(0, 0, 0, 0); // Dummy call to get a handle
4359 if ( !hRegion )
f6bcfd97 4360 wxLogLastError(wxT("CreateRectRgn"));
42e69d6b 4361 if ( ::GetUpdateRgn(GetHwnd(), hRegion, FALSE) == ERROR )
f6bcfd97 4362 wxLogLastError(wxT("GetUpdateRgn"));
c085e333 4363
42e69d6b 4364 m_updateRegion = wxRegion((WXHRGN) hRegion);
c085e333 4365
42e69d6b
VZ
4366 wxPaintEvent event(m_windowId);
4367 event.SetEventObject(this);
2bda0e17 4368
1e6feb95
VZ
4369 bool processed = GetEventHandler()->ProcessEvent(event);
4370
4371 // note that we must generate NC event after the normal one as otherwise
4372 // BeginPaint() will happily overwrite our decorations with the background
4373 // colour
4374 wxNcPaintEvent eventNc(m_windowId);
4375 eventNc.SetEventObject(this);
4376 GetEventHandler()->ProcessEvent(eventNc);
4377
4378 return processed;
2bda0e17
KB
4379}
4380
63da7df7 4381// Can be called from an application's OnPaint handler
1e6feb95 4382void wxWindowMSW::OnPaint(wxPaintEvent& event)
63da7df7 4383{
1e6feb95
VZ
4384#ifdef __WXUNIVERSAL__
4385 event.Skip();
4386#else
63da7df7
JS
4387 HDC hDC = (HDC) wxPaintDC::FindDCInCache((wxWindow*) event.GetEventObject());
4388 if (hDC != 0)
4389 {
4390 MSWDefWindowProc(WM_PAINT, (WPARAM) hDC, 0);
4391 }
1e6feb95 4392#endif
63da7df7
JS
4393}
4394
1e6feb95 4395bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc)
a23fd0e1 4396{
e0e6ac8a 4397 wxDCTemp dc(hdc, GetClientSize());
c085e333 4398
1e6feb95
VZ
4399 dc.SetHDC(hdc);
4400 dc.SetWindow((wxWindow *)this);
c085e333 4401
2bda0e17 4402 wxEraseEvent event(m_windowId, &dc);
42e69d6b 4403 event.SetEventObject(this);
a23fd0e1 4404 bool rc = GetEventHandler()->ProcessEvent(event);
c085e333 4405
7561aacd 4406 // must be called manually as ~wxDC doesn't do anything for wxDCTemp
a23fd0e1 4407 dc.SelectOldObjects(hdc);
a23fd0e1
VZ
4408
4409 return rc;
2bda0e17
KB
4410}
4411
8681b094
VZ
4412void wxWindowMSW::OnEraseBackground(wxEraseEvent& event)
4413{
52c3e064
VZ
4414 // standard non top level controls (i.e. except the dialogs) always erase
4415 // their background themselves in HandleCtlColor() or have some control-
4416 // specific ways to set the colours (common controls)
4417 if ( IsOfStandardClass() && !IsTopLevel() )
b8335252 4418 {
c5bd3c62
VZ
4419 event.Skip();
4420 return;
4421 }
b8335252 4422
c5bd3c62
VZ
4423 if ( GetBackgroundStyle() == wxBG_STYLE_CUSTOM )
4424 {
4425 // don't skip the event here, custom background means that the app
4426 // is drawing it itself in its OnPaint(), so don't draw it at all
4427 // now to avoid flicker
4428 return;
4429 }
8681b094 4430
8681b094 4431
c5bd3c62 4432 // do default background painting
c3732409 4433 if ( !DoEraseBackground(GetHdcOf(*event.GetDC())) )
c5bd3c62
VZ
4434 {
4435 // let the system paint the background
4436 event.Skip();
4437 }
4438}
4439
c3732409 4440bool wxWindowMSW::DoEraseBackground(WXHDC hDC)
c581abbc 4441{
c3732409
VZ
4442 HBRUSH hbr = (HBRUSH)MSWGetBgBrush(hDC);
4443 if ( !hbr )
c581abbc
VZ
4444 return false;
4445
c3732409 4446 wxFillRect(GetHwnd(), (HDC)hDC, hbr);
c581abbc
VZ
4447
4448 return true;
4449}
4450
c3732409 4451WXHBRUSH
2bae4332 4452wxWindowMSW::MSWGetBgBrushForChild(WXHDC WXUNUSED(hDC), WXHWND hWnd)
c5bd3c62 4453{
accbb1e7
VZ
4454 if ( m_hasBgCol )
4455 {
8d075f8d
VZ
4456 // our background colour applies to:
4457 // 1. this window itself, always
4458 // 2. all children unless the colour is "not inheritable"
c3732409
VZ
4459 // 3. even if it is not inheritable, our immediate transparent
4460 // children should still inherit it -- but not any transparent
4461 // children because it would look wrong if a child of non
4462 // transparent child would show our bg colour when the child itself
4463 // does not
2bae4332
VZ
4464 wxWindow *win = wxFindWinFromHandle(hWnd);
4465 if ( win == this ||
c3732409 4466 m_inheritBgCol ||
2bae4332
VZ
4467 (win && win->HasTransparentBackground() &&
4468 win->GetParent() == this) )
accbb1e7 4469 {
c3732409
VZ
4470 // draw children with the same colour as the parent
4471 wxBrush *
4472 brush = wxTheBrushList->FindOrCreateBrush(GetBackgroundColour());
4473
4474 return (WXHBRUSH)GetHbrushOf(*brush);
accbb1e7
VZ
4475 }
4476 }
4477
c3732409 4478 return 0;
c5bd3c62 4479}
8681b094 4480
2bae4332 4481WXHBRUSH wxWindowMSW::MSWGetBgBrush(WXHDC hDC, WXHWND hWndToPaint)
bdd1a35d 4482{
2bae4332
VZ
4483 if ( !hWndToPaint )
4484 hWndToPaint = GetHWND();
bdd1a35d 4485
c3732409 4486 for ( wxWindowMSW *win = this; win; win = win->GetParent() )
c5bd3c62 4487 {
2bae4332 4488 WXHBRUSH hBrush = win->MSWGetBgBrushForChild(hDC, hWndToPaint);
c5bd3c62
VZ
4489 if ( hBrush )
4490 return hBrush;
24cb4019 4491
c3732409
VZ
4492 // background is not inherited beyond top level windows
4493 if ( win->IsTopLevel() )
24cb4019 4494 break;
01c500af 4495 }
c5bd3c62
VZ
4496
4497 return 0;
8681b094
VZ
4498}
4499
b728a212 4500bool wxWindowMSW::HandlePrintClient(WXHDC hDC)
1a784dfc 4501{
b728a212
JG
4502 // we receive this message when DrawThemeParentBackground() is
4503 // called from def window proc of several controls under XP and we
4504 // must draw properly themed background here
4505 //
4506 // note that naively I'd expect filling the client rect with the
4507 // brush returned by MSWGetBgBrush() work -- but for some reason it
4508 // doesn't and we have to call parents MSWPrintChild() which is
4509 // supposed to call DrawThemeBackground() with appropriate params
4510 //
4511 // also note that in this case lParam == PRF_CLIENT but we're
4512 // clearly expected to paint the background and nothing else!
4513
4514 if ( IsTopLevel() || InheritsBackgroundColour() )
4515 return false;
4516
4517 // sometimes we don't want the parent to handle it at all, instead
4518 // return whatever value this window wants
4519 if ( !MSWShouldPropagatePrintChild() )
4520 return MSWPrintChild(hDC, (wxWindow *)this);
4521
4522 for ( wxWindow *win = GetParent(); win; win = win->GetParent() )
4523 {
4524 if ( win->MSWPrintChild(hDC, (wxWindow *)this) )
4525 return true;
4526
4527 if ( win->IsTopLevel() || win->InheritsBackgroundColour() )
4528 break;
4529 }
4530
1a784dfc
VZ
4531 return false;
4532}
4533
42e69d6b
VZ
4534// ---------------------------------------------------------------------------
4535// moving and resizing
4536// ---------------------------------------------------------------------------
4537
1e6feb95 4538bool wxWindowMSW::HandleMinimize()
42e69d6b
VZ
4539{
4540 wxIconizeEvent event(m_windowId);
4541 event.SetEventObject(this);
2d0a075d 4542
42e69d6b 4543 return GetEventHandler()->ProcessEvent(event);
2bda0e17
KB
4544}
4545
1e6feb95 4546bool wxWindowMSW::HandleMaximize()
2bda0e17 4547{
42e69d6b
VZ
4548 wxMaximizeEvent event(m_windowId);
4549 event.SetEventObject(this);
c085e333 4550
42e69d6b
VZ
4551 return GetEventHandler()->ProcessEvent(event);
4552}
2bda0e17 4553
1e6feb95 4554bool wxWindowMSW::HandleMove(int x, int y)
42e69d6b 4555{
907173e5
WS
4556 wxPoint point(x,y);
4557 wxMoveEvent event(point, m_windowId);
42e69d6b
VZ
4558 event.SetEventObject(this);
4559
4560 return GetEventHandler()->ProcessEvent(event);
4561}
4562
5706de1c
JS
4563bool wxWindowMSW::HandleMoving(wxRect& rect)
4564{
4565 wxMoveEvent event(rect, m_windowId);
4566 event.SetEventObject(this);
577baeef 4567
5706de1c
JS
4568 bool rc = GetEventHandler()->ProcessEvent(event);
4569 if (rc)
4570 rect = event.GetRect();
4571 return rc;
4572}
4573
4bc0f25e 4574bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam)
42e69d6b 4575{
c3723477
JS
4576#if USE_DEFERRED_SIZING
4577 // when we resize this window, its children are probably going to be
4578 // repositioned as well, prepare to use DeferWindowPos() for them
4579 int numChildren = 0;
4580 for ( HWND child = ::GetWindow(GetHwndOf(this), GW_CHILD);
4581 child;
4582 child = ::GetWindow(child, GW_HWNDNEXT) )
4583 {
4584 numChildren ++;
4585 }
4586
3fca879c 4587 // Protect against valid m_hDWP being overwritten
c3723477
JS
4588 bool useDefer = false;
4589
3f48c8e2
VZ
4590 if ( numChildren > 1 )
4591 {
c3723477 4592 if (!m_hDWP)
3fca879c 4593 {
c3723477
JS
4594 m_hDWP = (WXHANDLE)::BeginDeferWindowPos(numChildren);
4595 if ( !m_hDWP )
4596 {
4597 wxLogLastError(_T("BeginDeferWindowPos"));
4598 }
4599 if (m_hDWP)
4600 useDefer = true;
3f48c8e2
VZ
4601 }
4602 }
f7040b5f 4603#endif // USE_DEFERRED_SIZING
42e69d6b 4604
3f48c8e2
VZ
4605 // update this window size
4606 bool processed = false;
4bc0f25e
VZ
4607 switch ( wParam )
4608 {
4609 default:
4610 wxFAIL_MSG( _T("unexpected WM_SIZE parameter") );
4611 // fall through nevertheless
4612
4613 case SIZE_MAXHIDE:
4614 case SIZE_MAXSHOW:
4615 // we're not interested in these messages at all
4616 break;
4617
4618 case SIZE_MINIMIZED:
4619 processed = HandleMinimize();
4620 break;
4621
4622 case SIZE_MAXIMIZED:
a4d1972d 4623 /* processed = */ HandleMaximize();
4bc0f25e
VZ
4624 // fall through to send a normal size event as well
4625
4626 case SIZE_RESTORED:
4627 // don't use w and h parameters as they specify the client size
4628 // while according to the docs EVT_SIZE handler is supposed to
4629 // receive the total size
4630 wxSizeEvent event(GetSize(), m_windowId);
4631 event.SetEventObject(this);
4632
4633 processed = GetEventHandler()->ProcessEvent(event);
4634 }
4635
c3723477 4636#if USE_DEFERRED_SIZING
3f48c8e2 4637 // and finally change the positions of all child windows at once
c3723477 4638 if ( useDefer && m_hDWP )
3f48c8e2
VZ
4639 {
4640 // reset m_hDWP to NULL so that child windows don't try to use our
4641 // m_hDWP after we call EndDeferWindowPos() on it (this shouldn't
4642 // happen anyhow normally but who knows what weird flow of control we
4643 // may have depending on what the users EVT_SIZE handler does...)
4644 HDWP hDWP = (HDWP)m_hDWP;
4645 m_hDWP = NULL;
3fca879c 4646
3f48c8e2
VZ
4647 // do put all child controls in place at once
4648 if ( !::EndDeferWindowPos(hDWP) )
4649 {
4650 wxLogLastError(_T("EndDeferWindowPos"));
4651 }
c3723477 4652
da78f3b1 4653 // Reset our children's pending pos/size values.
c3723477
JS
4654 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
4655 node;
4656 node = node->GetNext() )
4657 {
82e3664e 4658 wxWindowMSW *child = node->GetData();
67644c1d
RD
4659 child->m_pendingPosition = wxDefaultPosition;
4660 child->m_pendingSize = wxDefaultSize;
c3723477 4661 }
3f48c8e2 4662 }
7d86a2d4 4663#endif // USE_DEFERRED_SIZING
3f48c8e2 4664
4bc0f25e 4665 return processed;
42e69d6b
VZ
4666}
4667
5706de1c
JS
4668bool wxWindowMSW::HandleSizing(wxRect& rect)
4669{
4670 wxSizeEvent event(rect, m_windowId);
4671 event.SetEventObject(this);
577baeef 4672
5706de1c
JS
4673 bool rc = GetEventHandler()->ProcessEvent(event);
4674 if (rc)
4675 rect = event.GetRect();
4676 return rc;
4677}
4678
0c0d1521 4679bool wxWindowMSW::HandleGetMinMaxInfo(void *WXUNUSED_IN_WINCE(mmInfo))
42e69d6b 4680{
7f0586ef 4681#ifdef __WXWINCE__
08158721 4682 return false;
7f0586ef 4683#else
42e69d6b
VZ
4684 MINMAXINFO *info = (MINMAXINFO *)mmInfo;
4685
08158721 4686 bool rc = false;
b2d5a7ee 4687
e7dda1ff
VS
4688 int minWidth = GetMinWidth(),
4689 minHeight = GetMinHeight(),
4690 maxWidth = GetMaxWidth(),
4691 maxHeight = GetMaxHeight();
42e69d6b 4692
422d0ff0 4693 if ( minWidth != wxDefaultCoord )
2d0a075d 4694 {
e7dda1ff 4695 info->ptMinTrackSize.x = minWidth;
08158721 4696 rc = true;
2d0a075d 4697 }
2bda0e17 4698
422d0ff0 4699 if ( minHeight != wxDefaultCoord )
42e69d6b 4700 {
e7dda1ff 4701 info->ptMinTrackSize.y = minHeight;
08158721 4702 rc = true;
42e69d6b 4703 }
2bda0e17 4704
422d0ff0 4705 if ( maxWidth != wxDefaultCoord )
42e69d6b 4706 {
e7dda1ff 4707 info->ptMaxTrackSize.x = maxWidth;
08158721 4708 rc = true;
2d0a075d 4709 }
2bda0e17 4710
422d0ff0 4711 if ( maxHeight != wxDefaultCoord )
42e69d6b 4712 {
e7dda1ff 4713 info->ptMaxTrackSize.y = maxHeight;
08158721 4714 rc = true;
42e69d6b 4715 }
2bda0e17 4716
42e69d6b 4717 return rc;
7f0586ef 4718#endif
42e69d6b 4719}
2d0a075d 4720
42e69d6b
VZ
4721// ---------------------------------------------------------------------------
4722// command messages
4723// ---------------------------------------------------------------------------
4724
1e6feb95 4725bool wxWindowMSW::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control)
42e69d6b 4726{
1e6feb95 4727#if wxUSE_MENUS_NATIVE
8c290175 4728 if ( !cmd && wxCurrentPopupMenu )
42e69d6b
VZ
4729 {
4730 wxMenu *popupMenu = wxCurrentPopupMenu;
4731 wxCurrentPopupMenu = NULL;
4732
4733 return popupMenu->MSWCommand(cmd, id);
4734 }
1e6feb95 4735#endif // wxUSE_MENUS_NATIVE
42e69d6b 4736
8c290175 4737 wxWindow *win = NULL;
71292fab
VZ
4738
4739 // first try to find it from HWND - this works even with the broken
4740 // programs using the same ids for different controls
4741 if ( control )
42e69d6b 4742 {
71292fab 4743 win = wxFindWinFromHandle(control);
b853f898 4744 }
2f4ef631 4745
71292fab
VZ
4746 // try the id
4747 if ( !win )
b853f898 4748 {
71292fab
VZ
4749 // must cast to a signed type before comparing with other ids!
4750 win = FindItem((signed short)id);
42e69d6b
VZ
4751 }
4752
4753 if ( win )
b94ae1ea 4754 {
42e69d6b 4755 return win->MSWCommand(cmd, id);
b94ae1ea
VZ
4756 }
4757
4758 // the messages sent from the in-place edit control used by the treectrl
4759 // for label editing have id == 0, but they should _not_ be treated as menu
4760 // messages (they are EN_XXX ones, in fact) so don't translate anything
4761 // coming from a control to wxEVT_COMMAND_MENU_SELECTED
4762 if ( !control )
a84fc80b 4763 {
b94ae1ea
VZ
4764 // If no child window, it may be an accelerator, e.g. for a popup menu
4765 // command
a84fc80b
JS
4766
4767 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED);
4768 event.SetEventObject(this);
4769 event.SetId(id);
4770 event.SetInt(id);
b94ae1ea
VZ
4771
4772 return GetEventHandler()->ProcessEvent(event);
a84fc80b 4773 }
6fe19057
VZ
4774 else
4775 {
01d2bf4d 4776#if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__)
6fe19057
VZ
4777 // the text ctrl which is logically part of wxSpinCtrl sends WM_COMMAND
4778 // notifications to its parent which we want to reflect back to
4779 // wxSpinCtrl
4780 wxSpinCtrl *spin = wxSpinCtrl::GetSpinForTextCtrl(control);
4781 if ( spin && spin->ProcessTextCommand(cmd, id) )
08158721 4782 return true;
6fe19057 4783#endif // wxUSE_SPINCTRL
42e69d6b 4784
01d2bf4d
WS
4785#if wxUSE_CHOICE && defined(__SMARTPHONE__)
4786 // the listbox ctrl which is logically part of wxChoice sends WM_COMMAND
4787 // notifications to its parent which we want to reflect back to
4788 // wxChoice
4789 wxChoice *choice = wxChoice::GetChoiceForListBox(control);
4790 if ( choice && choice->MSWCommand(cmd, id) )
4791 return true;
4792#endif
4793 }
4794
08158721 4795 return false;
2bda0e17
KB
4796}
4797
42e69d6b
VZ
4798// ---------------------------------------------------------------------------
4799// mouse events
4800// ---------------------------------------------------------------------------
4801
1e6feb95
VZ
4802void wxWindowMSW::InitMouseEvent(wxMouseEvent& event,
4803 int x, int y,
4804 WXUINT flags)
42e69d6b 4805{
1e6feb95
VZ
4806 // our client coords are not quite the same as Windows ones
4807 wxPoint pt = GetClientAreaOrigin();
4808 event.m_x = x - pt.x;
4809 event.m_y = y - pt.y;
4810
4811 event.m_shiftDown = (flags & MK_SHIFT) != 0;
4812 event.m_controlDown = (flags & MK_CONTROL) != 0;
4813 event.m_leftDown = (flags & MK_LBUTTON) != 0;
4814 event.m_middleDown = (flags & MK_MBUTTON) != 0;
4815 event.m_rightDown = (flags & MK_RBUTTON) != 0;
1fdf858b 4816 event.m_altDown = ::GetKeyState(VK_MENU) < 0;
1e6feb95 4817
f0b1ccde 4818#ifndef __WXWINCE__
1bf77ee5 4819 event.SetTimestamp(::GetMessageTime());
f0b1ccde
JS
4820#endif
4821
687706f5 4822 event.SetEventObject(this);
fb35f0c7 4823 event.SetId(GetId());
42e69d6b
VZ
4824
4825#if wxUSE_MOUSEEVENT_HACK
c358ea41
VZ
4826 gs_lastMouseEvent.pos = ClientToScreen(wxPoint(x, y));
4827 gs_lastMouseEvent.type = event.GetEventType();
42e69d6b 4828#endif // wxUSE_MOUSEEVENT_HACK
2bda0e17
KB
4829}
4830
42b1fb63 4831#ifdef __WXWINCE__
dfafa702
VZ
4832// Windows doesn't send the mouse events to the static controls (which are
4833// transparent in the sense that their WM_NCHITTEST handler returns
4834// HTTRANSPARENT) at all but we want all controls to receive the mouse events
4835// and so we manually check if we don't have a child window under mouse and if
4836// we do, send the event to it instead of the window Windows had sent WM_XXX
4837// to.
4838//
4839// Notice that this is not done for the mouse move events because this could
4840// (would?) be too slow, but only for clicks which means that the static texts
4841// still don't get move, enter nor leave events.
42b1fb63 4842static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y)
dfafa702
VZ
4843{
4844 wxCHECK_MSG( x && y, win, _T("NULL pointer in FindWindowForMouseEvent") );
4845
4846 // first try to find a non transparent child: this allows us to send events
4847 // to a static text which is inside a static box, for example
4848 POINT pt = { *x, *y };
4849 HWND hwnd = GetHwndOf(win),
4850 hwndUnderMouse;
4851
7f0586ef
JS
4852#ifdef __WXWINCE__
4853 hwndUnderMouse = ::ChildWindowFromPoint
4854 (
4855 hwnd,
4856 pt
4857 );
4858#else
dfafa702
VZ
4859 hwndUnderMouse = ::ChildWindowFromPointEx
4860 (
4861 hwnd,
4862 pt,
4863 CWP_SKIPINVISIBLE |
4864 CWP_SKIPDISABLED |
4865 CWP_SKIPTRANSPARENT
4866 );
7f0586ef 4867#endif
dfafa702
VZ
4868
4869 if ( !hwndUnderMouse || hwndUnderMouse == hwnd )
dfafa702
VZ
4870 {
4871 // now try any child window at all
4872 hwndUnderMouse = ::ChildWindowFromPoint(hwnd, pt);
4873 }
4874
4875 // check that we have a child window which is susceptible to receive mouse
4876 // events: for this it must be shown and enabled
4877 if ( hwndUnderMouse &&
4878 hwndUnderMouse != hwnd &&
4879 ::IsWindowVisible(hwndUnderMouse) &&
4880 ::IsWindowEnabled(hwndUnderMouse) )
4881 {
4882 wxWindow *winUnderMouse = wxFindWinFromHandle((WXHWND)hwndUnderMouse);
4883 if ( winUnderMouse )
4884 {
4885 // translate the mouse coords to the other window coords
4886 win->ClientToScreen(x, y);
4887 winUnderMouse->ScreenToClient(x, y);
4888
4889 win = winUnderMouse;
4890 }
4891 }
4892
4893 return win;
4894}
42b1fb63 4895#endif // __WXWINCE__
dfafa702 4896
1e6feb95 4897bool wxWindowMSW::HandleMouseEvent(WXUINT msg, int x, int y, WXUINT flags)
2bda0e17 4898{
42e69d6b 4899 // the mouse events take consecutive IDs from WM_MOUSEFIRST to
34621cc5 4900 // WM_MOUSELAST, so it's enough to subtract WM_MOUSEMOVE == WM_MOUSEFIRST
42e69d6b
VZ
4901 // from the message id and take the value in the table to get wxWin event
4902 // id
4903 static const wxEventType eventsMouse[] =
4904 {
4905 wxEVT_MOTION,
4906 wxEVT_LEFT_DOWN,
4907 wxEVT_LEFT_UP,
4908 wxEVT_LEFT_DCLICK,
4909 wxEVT_RIGHT_DOWN,
4910 wxEVT_RIGHT_UP,
4911 wxEVT_RIGHT_DCLICK,
4912 wxEVT_MIDDLE_DOWN,
4913 wxEVT_MIDDLE_UP,
4914 wxEVT_MIDDLE_DCLICK
4915 };
2bda0e17 4916
42e69d6b
VZ
4917 wxMouseEvent event(eventsMouse[msg - WM_MOUSEMOVE]);
4918 InitMouseEvent(event, x, y, flags);
4919
4920 return GetEventHandler()->ProcessEvent(event);
4921}
4922
1e6feb95 4923bool wxWindowMSW::HandleMouseMove(int x, int y, WXUINT flags)
42e69d6b
VZ
4924{
4925 if ( !m_mouseInWindow )
2bda0e17 4926 {
1e6feb95
VZ
4927 // it would be wrong to assume that just because we get a mouse move
4928 // event that the mouse is inside the window: although this is usually
4929 // true, it is not if we had captured the mouse, so we need to check
4930 // the mouse coordinates here
4931 if ( !HasCapture() || IsMouseInWindow() )
4932 {
4933 // Generate an ENTER event
08158721 4934 m_mouseInWindow = true;
e5297b7f 4935
4e5c6c33 4936#ifdef HAVE_TRACKMOUSEEVENT
aafb9978
VZ
4937 typedef BOOL (WINAPI *_TrackMouseEvent_t)(LPTRACKMOUSEEVENT);
4938#ifdef __WXWINCE__
4939 static const _TrackMouseEvent_t
4940 s_pfn_TrackMouseEvent = _TrackMouseEvent;
4941#else // !__WXWINCE__
4942 static _TrackMouseEvent_t s_pfn_TrackMouseEvent;
4943 static bool s_initDone = false;
4944 if ( !s_initDone )
4945 {
4946 wxLogNull noLog;
4947
4948 wxDynamicLibrary dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM);
4949 if ( dllComCtl32.IsLoaded() )
4950 {
4951 s_pfn_TrackMouseEvent = (_TrackMouseEvent_t)
4952 dllComCtl32.GetSymbol(_T("_TrackMouseEvent"));
4953 }
4954
4955 s_initDone = true;
4e5c6c33 4956
aafb9978
VZ
4957 // notice that it's ok to unload comctl32.dll here as it won't
4958 // be really unloaded, being still in use because we link to it
4959 // statically too
4960 }
4961
4962 if ( s_pfn_TrackMouseEvent )
4963#endif // __WXWINCE__/!__WXWINCE__
4964 {
4965 WinStruct<TRACKMOUSEEVENT> trackinfo;
4e5c6c33 4966
aafb9978
VZ
4967 trackinfo.dwFlags = TME_LEAVE;
4968 trackinfo.hwndTrack = GetHwnd();
4969
4970 (*s_pfn_TrackMouseEvent)(&trackinfo);
4971 }
4e5c6c33
VZ
4972#endif // HAVE_TRACKMOUSEEVENT
4973
1e6feb95
VZ
4974 wxMouseEvent event(wxEVT_ENTER_WINDOW);
4975 InitMouseEvent(event, x, y, flags);
42e69d6b 4976
1e6feb95
VZ
4977 (void)GetEventHandler()->ProcessEvent(event);
4978 }
42e69d6b 4979 }
cff58b52 4980#ifdef HAVE_TRACKMOUSEEVENT
aafb9978 4981 else // mouse not in window
cff58b52
KH
4982 {
4983 // Check if we need to send a LEAVE event
4984 // Windows doesn't send WM_MOUSELEAVE if the mouse has been captured so
4985 // send it here if we are using native mouse leave tracking
4986 if ( HasCapture() && !IsMouseInWindow() )
4987 {
4988 GenerateMouseLeave();
4989 }
4990 }
1ca78aa1 4991#endif // HAVE_TRACKMOUSEEVENT
42e69d6b
VZ
4992
4993#if wxUSE_MOUSEEVENT_HACK
c358ea41
VZ
4994 // Windows often generates mouse events even if mouse position hasn't
4995 // changed (http://article.gmane.org/gmane.comp.lib.wxwidgets.devel/66576)
4996 //
4997 // Filter this out as it can result in unexpected behaviour compared to
4998 // other platforms
4999 if ( gs_lastMouseEvent.type == wxEVT_RIGHT_DOWN ||
5000 gs_lastMouseEvent.type == wxEVT_LEFT_DOWN ||
5001 gs_lastMouseEvent.type == wxEVT_MIDDLE_DOWN ||
5002 gs_lastMouseEvent.type == wxEVT_MOTION )
5003 {
5004 if ( ClientToScreen(wxPoint(x, y)) == gs_lastMouseEvent.pos )
5005 {
5006 gs_lastMouseEvent.type = wxEVT_MOTION;
42e69d6b 5007
c358ea41
VZ
5008 return false;
5009 }
42e69d6b
VZ
5010 }
5011#endif // wxUSE_MOUSEEVENT_HACK
5012
5013 return HandleMouseEvent(WM_MOUSEMOVE, x, y, flags);
5014}
5015
d2c52078 5016
24ce4c18 5017bool wxWindowMSW::HandleMouseWheel(WXWPARAM wParam, WXLPARAM lParam)
d2c52078
RD
5018{
5019#if wxUSE_MOUSEWHEEL
3c297348
VZ
5020 // notice that WM_MOUSEWHEEL position is in screen coords (as it's
5021 // forwarded up to the parent by DefWindowProc()) and not in the client
5022 // ones as all the other messages, translate them to the client coords for
5023 // consistency
5024 const wxPoint
5025 pt = ScreenToClient(wxPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
d2c52078 5026 wxMouseEvent event(wxEVT_MOUSEWHEEL);
3c297348 5027 InitMouseEvent(event, pt.x, pt.y, LOWORD(wParam));
d2c52078
RD
5028 event.m_wheelRotation = (short)HIWORD(wParam);
5029 event.m_wheelDelta = WHEEL_DELTA;
5030
0f7a546d
RD
5031 static int s_linesPerRotation = -1;
5032 if ( s_linesPerRotation == -1 )
5033 {
5034 if ( !::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
5035 &s_linesPerRotation, 0))
5036 {
5037 // this is not supposed to happen
5038 wxLogLastError(_T("SystemParametersInfo(GETWHEELSCROLLLINES)"));
5039
5040 // the default is 3, so use it if SystemParametersInfo() failed
5041 s_linesPerRotation = 3;
5042 }
5043 }
d2c52078 5044
0f7a546d 5045 event.m_linesPerAction = s_linesPerRotation;
d2c52078 5046 return GetEventHandler()->ProcessEvent(event);
0f7a546d 5047
51e4e266
VZ
5048#else // !wxUSE_MOUSEWHEEL
5049 wxUnusedVar(wParam);
5050 wxUnusedVar(lParam);
38caaa61 5051
08158721 5052 return false;
51e4e266 5053#endif // wxUSE_MOUSEWHEEL/!wxUSE_MOUSEWHEEL
d2c52078
RD
5054}
5055
51e4e266
VZ
5056void wxWindowMSW::GenerateMouseLeave()
5057{
5058 m_mouseInWindow = false;
5059
5060 int state = 0;
5061 if ( wxIsShiftDown() )
5062 state |= MK_SHIFT;
5063 if ( wxIsCtrlDown() )
5064 state |= MK_CONTROL;
5065
5066 // Only the high-order bit should be tested
5067 if ( GetKeyState( VK_LBUTTON ) & (1<<15) )
5068 state |= MK_LBUTTON;
5069 if ( GetKeyState( VK_MBUTTON ) & (1<<15) )
5070 state |= MK_MBUTTON;
5071 if ( GetKeyState( VK_RBUTTON ) & (1<<15) )
5072 state |= MK_RBUTTON;
5073
5074 POINT pt;
f2325516
JS
5075#ifdef __WXWINCE__
5076 if ( !::GetCursorPosWinCE(&pt) )
5077#else
51e4e266 5078 if ( !::GetCursorPos(&pt) )
f2325516 5079#endif
51e4e266
VZ
5080 {
5081 wxLogLastError(_T("GetCursorPos"));
5082 }
5083
5084 // we need to have client coordinates here for symmetry with
5085 // wxEVT_ENTER_WINDOW
5086 RECT rect = wxGetWindowRect(GetHwnd());
5087 pt.x -= rect.left;
5088 pt.y -= rect.top;
5089
5090 wxMouseEvent event(wxEVT_LEAVE_WINDOW);
5091 InitMouseEvent(event, pt.x, pt.y, state);
5092
5093 (void)GetEventHandler()->ProcessEvent(event);
5094}
d2c52078 5095
42e69d6b
VZ
5096// ---------------------------------------------------------------------------
5097// keyboard handling
5098// ---------------------------------------------------------------------------
5099
c42404a5
VZ
5100// create the key event of the given type for the given key - used by
5101// HandleChar and HandleKeyDown/Up
1e6feb95 5102wxKeyEvent wxWindowMSW::CreateKeyEvent(wxEventType evType,
b09bda68 5103 int id,
9c7df356
VZ
5104 WXLPARAM lParam,
5105 WXWPARAM wParam) const
c42404a5
VZ
5106{
5107 wxKeyEvent event(evType);
5108 event.SetId(GetId());
3f7bc32b
VZ
5109 event.m_shiftDown = wxIsShiftDown();
5110 event.m_controlDown = wxIsCtrlDown();
c42404a5
VZ
5111 event.m_altDown = (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN;
5112
687706f5 5113 event.SetEventObject((wxWindow *)this); // const_cast
c42404a5 5114 event.m_keyCode = id;
0d9b2c16 5115#if wxUSE_UNICODE
32b13913 5116 event.m_uniChar = (wxChar) wParam;
0d9b2c16 5117#endif
9c7df356
VZ
5118 event.m_rawCode = (wxUint32) wParam;
5119 event.m_rawFlags = (wxUint32) lParam;
f0b1ccde 5120#ifndef __WXWINCE__
1bf77ee5 5121 event.SetTimestamp(::GetMessageTime());
f0b1ccde 5122#endif
c42404a5
VZ
5123
5124 // translate the position to client coords
5125 POINT pt;
f2325516
JS
5126#ifdef __WXWINCE__
5127 GetCursorPosWinCE(&pt);
5128#else
c42404a5 5129 GetCursorPos(&pt);
f2325516 5130#endif
c42404a5
VZ
5131 RECT rect;
5132 GetWindowRect(GetHwnd(),&rect);
5133 pt.x -= rect.left;
5134 pt.y -= rect.top;
5135
5136 event.m_x = pt.x;
5137 event.m_y = pt.y;
5138
5139 return event;
5140}
5141
08158721 5142// isASCII is true only when we're called from WM_CHAR handler and not from
42e69d6b 5143// WM_KEYDOWN one
1e6feb95 5144bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam, bool isASCII)
42e69d6b
VZ
5145{
5146 int id;
42e69d6b
VZ
5147 if ( isASCII )
5148 {
42e69d6b 5149 id = wParam;
2d0a075d 5150 }
9c7df356 5151 else // we're called from WM_KEYDOWN
c42404a5 5152 {
6121a198
VZ
5153 // don't pass lParam to wxCharCodeMSWToWX() here because we don't want
5154 // to get numpad key codes: CHAR events should use the logical keys
5155 // such as WXK_HOME instead of WXK_NUMPAD_HOME which is for KEY events
5156 id = wxCharCodeMSWToWX(wParam);
9c7df356 5157 if ( id == 0 )
c42404a5 5158 {
9c7df356 5159 // it's ASCII and will be processed here only when called from
08158721
DS
5160 // WM_CHAR (i.e. when isASCII = true), don't process it now
5161 return false;
c42404a5 5162 }
9c7df356 5163 }
42e69d6b 5164
9c7df356 5165 wxKeyEvent event(CreateKeyEvent(wxEVT_CHAR, id, lParam, wParam));
2b5f62a0
VZ
5166
5167 // the alphanumeric keys produced by pressing AltGr+something on European
5168 // keyboards have both Ctrl and Alt modifiers which may confuse the user
5169 // code as, normally, keys with Ctrl and/or Alt don't result in anything
5170 // alphanumeric, so pretend that there are no modifiers at all (the
5171 // KEY_DOWN event would still have the correct modifiers if they're really
5172 // needed)
5173 if ( event.m_controlDown && event.m_altDown &&
5174 (id >= 32 && id < 256) )
9c7df356 5175 {
2b5f62a0 5176 event.m_controlDown =
08158721 5177 event.m_altDown = false;
2d0a075d 5178 }
c42404a5 5179
9c7df356 5180 return GetEventHandler()->ProcessEvent(event);
2bda0e17
KB
5181}
5182
1e6feb95 5183bool wxWindowMSW::HandleKeyDown(WXWPARAM wParam, WXLPARAM lParam)
2bda0e17 5184{
ff792344 5185 int id = wxCharCodeMSWToWX(wParam, lParam);
2bda0e17 5186
c42404a5
VZ
5187 if ( !id )
5188 {
5189 // normal ASCII char
42e69d6b
VZ
5190 id = wParam;
5191 }
5192
b60978b2
VZ
5193 wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_DOWN, id, lParam, wParam));
5194 return GetEventHandler()->ProcessEvent(event);
2bda0e17
KB
5195}
5196
1e6feb95 5197bool wxWindowMSW::HandleKeyUp(WXWPARAM wParam, WXLPARAM lParam)
2bda0e17 5198{
ff792344 5199 int id = wxCharCodeMSWToWX(wParam, lParam);
2bda0e17 5200
c42404a5
VZ
5201 if ( !id )
5202 {
5203 // normal ASCII char
42e69d6b 5204 id = wParam;
2d0a075d 5205 }
2bda0e17 5206
b60978b2
VZ
5207 wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_UP, id, lParam, wParam));
5208 return GetEventHandler()->ProcessEvent(event);
2bda0e17
KB
5209}
5210
0c0d1521
WS
5211int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel),
5212 WXLPARAM WXUNUSED_IN_WINCE(lParam))
b74cce40 5213{
7f0586ef
JS
5214 // FIXME: implement GetMenuItemCount for WinCE, possibly
5215 // in terms of GetMenuItemInfo
5216#ifndef __WXWINCE__
b74cce40
VZ
5217 const HMENU hmenu = (HMENU)lParam;
5218
5219 MENUITEMINFO mii;
5220 wxZeroMemory(mii);
5221 mii.cbSize = sizeof(MENUITEMINFO);
c70ffbdb
VZ
5222
5223 // we could use MIIM_FTYPE here as we only need to know if the item is
5224 // ownerdrawn or not and not dwTypeData which MIIM_TYPE also returns, but
5225 // MIIM_FTYPE is not supported under Win95
b74cce40
VZ
5226 mii.fMask = MIIM_TYPE | MIIM_DATA;
5227
5228 // find if we have this letter in any owner drawn item
5229 const int count = ::GetMenuItemCount(hmenu);
5230 for ( int i = 0; i < count; i++ )
5231 {
c70ffbdb
VZ
5232 // previous loop iteration could modify it, reset it back before
5233 // calling GetMenuItemInfo() to prevent it from overflowing dwTypeData
5234 mii.cch = 0;
5235
b74cce40
VZ
5236 if ( ::GetMenuItemInfo(hmenu, i, TRUE, &mii) )
5237 {
5238 if ( mii.fType == MFT_OWNERDRAW )
5239 {
5240 // dwItemData member of the MENUITEMINFO is a
5241 // pointer to the associated wxMenuItem -- see the
5242 // menu creation code
5243 wxMenuItem *item = (wxMenuItem*)mii.dwItemData;
5244
5245 const wxChar *p = wxStrchr(item->GetText(), _T('&'));
5246 while ( p++ )
5247 {
5248 if ( *p == _T('&') )
5249 {
5250 // this is not the accel char, find the real one
5251 p = wxStrchr(p + 1, _T('&'));
5252 }
5253 else // got the accel char
5254 {
5255 // FIXME-UNICODE: this comparison doesn't risk to work
5256 // for non ASCII accelerator characters I'm afraid, but
5257 // what can we do?
907173e5 5258 if ( (wchar_t)wxToupper(*p) == (wchar_t)chAccel )
b74cce40
VZ
5259 {
5260 return i;
5261 }
5262 else
5263 {
5264 // this one doesn't match
5265 break;
5266 }
5267 }
5268 }
5269 }
5270 }
e39af974 5271 else // failed to get the menu text?
b74cce40 5272 {
c70ffbdb 5273 // it's not fatal, so don't show error, but still log it
b74cce40
VZ
5274 wxLogLastError(_T("GetMenuItemInfo"));
5275 }
5276 }
7f0586ef 5277#endif
b74cce40
VZ
5278 return wxNOT_FOUND;
5279}
5280
78c91815
VZ
5281bool wxWindowMSW::HandleClipboardEvent( WXUINT nMsg )
5282{
5283 const wxEventType type = ( nMsg == WM_CUT ) ? wxEVT_COMMAND_TEXT_CUT :
5284 ( nMsg == WM_COPY ) ? wxEVT_COMMAND_TEXT_COPY :
5285 /*( nMsg == WM_PASTE ) ? */ wxEVT_COMMAND_TEXT_PASTE;
5286 wxClipboardTextEvent evt(type, GetId());
5287
5288 evt.SetEventObject(this);
5289
5290 return GetEventHandler()->ProcessEvent(evt);
5291}
5292
42e69d6b
VZ
5293// ---------------------------------------------------------------------------
5294// joystick
5295// ---------------------------------------------------------------------------
5296
1e6feb95 5297bool wxWindowMSW::HandleJoystickEvent(WXUINT msg, int x, int y, WXUINT flags)
2bda0e17 5298{
8cb172b4 5299#ifdef JOY_BUTTON1
42e69d6b
VZ
5300 int change = 0;
5301 if ( flags & JOY_BUTTON1CHG )
5302 change = wxJOY_BUTTON1;
5303 if ( flags & JOY_BUTTON2CHG )
5304 change = wxJOY_BUTTON2;
5305 if ( flags & JOY_BUTTON3CHG )
5306 change = wxJOY_BUTTON3;
5307 if ( flags & JOY_BUTTON4CHG )
5308 change = wxJOY_BUTTON4;
2bda0e17 5309
42e69d6b
VZ
5310 int buttons = 0;
5311 if ( flags & JOY_BUTTON1 )
5312 buttons |= wxJOY_BUTTON1;
5313 if ( flags & JOY_BUTTON2 )
5314 buttons |= wxJOY_BUTTON2;
5315 if ( flags & JOY_BUTTON3 )
5316 buttons |= wxJOY_BUTTON3;
5317 if ( flags & JOY_BUTTON4 )
5318 buttons |= wxJOY_BUTTON4;
c085e333 5319
42e69d6b
VZ
5320 // the event ids aren't consecutive so we can't use table based lookup
5321 int joystick;
5322 wxEventType eventType;
5323 switch ( msg )
5324 {
5325 case MM_JOY1MOVE:
5326 joystick = 1;
5327 eventType = wxEVT_JOY_MOVE;
5328 break;
2bda0e17 5329
42e69d6b
VZ
5330 case MM_JOY2MOVE:
5331 joystick = 2;
5332 eventType = wxEVT_JOY_MOVE;
5333 break;
2bda0e17 5334
42e69d6b
VZ
5335 case MM_JOY1ZMOVE:
5336 joystick = 1;
5337 eventType = wxEVT_JOY_ZMOVE;
5338 break;
2bda0e17 5339
42e69d6b
VZ
5340 case MM_JOY2ZMOVE:
5341 joystick = 2;
5342 eventType = wxEVT_JOY_ZMOVE;
5343 break;
2bda0e17 5344
42e69d6b
VZ
5345 case MM_JOY1BUTTONDOWN:
5346 joystick = 1;
5347 eventType = wxEVT_JOY_BUTTON_DOWN;
5348 break;
2bda0e17 5349
42e69d6b
VZ
5350 case MM_JOY2BUTTONDOWN:
5351 joystick = 2;
5352 eventType = wxEVT_JOY_BUTTON_DOWN;
5353 break;
2bda0e17 5354
42e69d6b
VZ
5355 case MM_JOY1BUTTONUP:
5356 joystick = 1;
5357 eventType = wxEVT_JOY_BUTTON_UP;
5358 break;
5359
5360 case MM_JOY2BUTTONUP:
5361 joystick = 2;
5362 eventType = wxEVT_JOY_BUTTON_UP;
5363 break;
5364
5365 default:
223d09f6 5366 wxFAIL_MSG(wxT("no such joystick event"));
2d0a075d 5367
08158721 5368 return false;
2d0a075d 5369 }
2bda0e17 5370
42e69d6b
VZ
5371 wxJoystickEvent event(eventType, buttons, joystick, change);
5372 event.SetPosition(wxPoint(x, y));
5373 event.SetEventObject(this);
c085e333 5374
42e69d6b 5375 return GetEventHandler()->ProcessEvent(event);
8cb172b4 5376#else
991420e6
WS
5377 wxUnusedVar(msg);
5378 wxUnusedVar(x);
5379 wxUnusedVar(y);
5380 wxUnusedVar(flags);
08158721 5381 return false;
8cb172b4 5382#endif
2bda0e17
KB
5383}
5384
42e69d6b
VZ
5385// ---------------------------------------------------------------------------
5386// scrolling
5387// ---------------------------------------------------------------------------
5388
1e6feb95 5389bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam,
f4f734c1 5390 WXWORD pos, WXHWND control)
35bbb0c6 5391{
a0d924c6 5392 if ( control && control != m_hWnd ) // Prevent infinite recursion
cc2b7472 5393 {
42e69d6b
VZ
5394 wxWindow *child = wxFindWinFromHandle(control);
5395 if ( child )
5396 return child->MSWOnScroll(orientation, wParam, pos, control);
cc2b7472 5397 }
2bda0e17 5398
9145664b 5399 wxScrollWinEvent event;
42e69d6b
VZ
5400 event.SetPosition(pos);
5401 event.SetOrientation(orientation);
687706f5 5402 event.SetEventObject(this);
cc2b7472 5403
42e69d6b
VZ
5404 switch ( wParam )
5405 {
5406 case SB_TOP:
687706f5 5407 event.SetEventType(wxEVT_SCROLLWIN_TOP);
42e69d6b 5408 break;
cc2b7472 5409
42e69d6b 5410 case SB_BOTTOM:
687706f5 5411 event.SetEventType(wxEVT_SCROLLWIN_BOTTOM);
42e69d6b 5412 break;
cc2b7472 5413
42e69d6b 5414 case SB_LINEUP:
687706f5 5415 event.SetEventType(wxEVT_SCROLLWIN_LINEUP);
42e69d6b 5416 break;
2bda0e17 5417
42e69d6b 5418 case SB_LINEDOWN:
687706f5 5419 event.SetEventType(wxEVT_SCROLLWIN_LINEDOWN);
42e69d6b 5420 break;
a02eb1d2 5421
42e69d6b 5422 case SB_PAGEUP:
687706f5 5423 event.SetEventType(wxEVT_SCROLLWIN_PAGEUP);
42e69d6b 5424 break;
2bda0e17 5425
42e69d6b 5426 case SB_PAGEDOWN:
687706f5 5427 event.SetEventType(wxEVT_SCROLLWIN_PAGEDOWN);
42e69d6b 5428 break;
2bda0e17 5429
42e69d6b 5430 case SB_THUMBPOSITION:
feda3011 5431 case SB_THUMBTRACK:
f6bcfd97
BP
5432 // under Win32, the scrollbar range and position are 32 bit integers,
5433 // but WM_[HV]SCROLL only carry the low 16 bits of them, so we must
5434 // explicitly query the scrollbar for the correct position (this must
5435 // be done only for these two SB_ events as they are the only one
5436 // carrying the scrollbar position)
5437 {
0cf5de11 5438 WinStruct<SCROLLINFO> scrollInfo;
f6bcfd97
BP
5439 scrollInfo.fMask = SIF_TRACKPOS;
5440
5441 if ( !::GetScrollInfo(GetHwnd(),
5442 orientation == wxHORIZONTAL ? SB_HORZ
5443 : SB_VERT,
5444 &scrollInfo) )
5445 {
3103e8a9 5446 // Not necessarily an error, if there are no scrollbars yet.
f676b387 5447 // wxLogLastError(_T("GetScrollInfo"));
f6bcfd97
BP
5448 }
5449
5450 event.SetPosition(scrollInfo.nTrackPos);
5451 }
f6bcfd97 5452
687706f5 5453 event.SetEventType( wParam == SB_THUMBPOSITION
f6bcfd97 5454 ? wxEVT_SCROLLWIN_THUMBRELEASE
687706f5 5455 : wxEVT_SCROLLWIN_THUMBTRACK );
42e69d6b 5456 break;
c085e333 5457
42e69d6b 5458 default:
08158721 5459 return false;
564b2609 5460 }
2bda0e17 5461
42e69d6b 5462 return GetEventHandler()->ProcessEvent(event);
2bda0e17
KB
5463}
5464
42e69d6b
VZ
5465// ===========================================================================
5466// global functions
5467// ===========================================================================
5468
7a5e53ab 5469void wxGetCharSize(WXHWND wnd, int *x, int *y, const wxFont& the_font)
2bda0e17 5470{
42e69d6b
VZ
5471 TEXTMETRIC tm;
5472 HDC dc = ::GetDC((HWND) wnd);
42e69d6b 5473 HFONT was = 0;
35bbb0c6 5474
7a5e53ab
VS
5475 // the_font.UseResource();
5476 // the_font.RealizeResource();
c57c2993 5477 HFONT fnt = (HFONT)the_font.GetResourceHandle(); // const_cast
7a5e53ab
VS
5478 if ( fnt )
5479 was = (HFONT) SelectObject(dc,fnt);
35bbb0c6 5480
42e69d6b 5481 GetTextMetrics(dc, &tm);
7a5e53ab 5482 if ( fnt && was )
2d0a075d 5483 {
42e69d6b 5484 SelectObject(dc,was);
2d0a075d 5485 }
42e69d6b 5486 ReleaseDC((HWND)wnd, dc);
0655ad29
VZ
5487
5488 if ( x )
5489 *x = tm.tmAveCharWidth;
5490 if ( y )
5491 *y = tm.tmHeight + tm.tmExternalLeading;
2bda0e17 5492
7a5e53ab 5493 // the_font.ReleaseResource();
42e69d6b 5494}
c085e333 5495
5004c3ad
JG
5496// use the "extended" bit (24) of lParam to distinguish extended keys
5497// from normal keys as the same key is sent
ed5bc8f1
VZ
5498static inline
5499int ChooseNormalOrExtended(int lParam, int keyNormal, int keyExtended)
5004c3ad 5500{
ed5bc8f1
VZ
5501 // except that if lParam is 0, it means we don't have real lParam from
5502 // WM_KEYDOWN but are just translating just a VK constant (e.g. done from
5503 // msw/treectrl.cpp when processing TVN_KEYDOWN) -- then assume this is a
5504 // non-numpad (hence extended) key as this is a more common case
5505 return !lParam || (lParam & (1 << 24)) ? keyExtended : keyNormal;
5004c3ad
JG
5506}
5507
d5c21b02
VZ
5508// this array contains the Windows virtual key codes which map one to one to
5509// WXK_xxx constants and is used in wxCharCodeMSWToWX/WXToMSW() below
5510//
5511// note that keys having a normal and numpad version (e.g. WXK_HOME and
5512// WXK_NUMPAD_HOME) are not included in this table as the mapping is not 1-to-1
5513static const struct wxKeyMapping
5514{
5515 int vk;
5516 wxKeyCode wxk;
5517} gs_specialKeys[] =
5518{
5519 { VK_CANCEL, WXK_CANCEL },
5520 { VK_BACK, WXK_BACK },
5521 { VK_TAB, WXK_TAB },
5522 { VK_CLEAR, WXK_CLEAR },
5523 { VK_SHIFT, WXK_SHIFT },
5524 { VK_CONTROL, WXK_CONTROL },
5525 { VK_MENU , WXK_ALT },
5526 { VK_PAUSE, WXK_PAUSE },
5527 { VK_CAPITAL, WXK_CAPITAL },
5528 { VK_SPACE, WXK_SPACE },
5529 { VK_ESCAPE, WXK_ESCAPE },
5530 { VK_SELECT, WXK_SELECT },
5531 { VK_PRINT, WXK_PRINT },
5532 { VK_EXECUTE, WXK_EXECUTE },
e59c2b2d
VZ
5533 { VK_SNAPSHOT, WXK_SNAPSHOT },
5534 { VK_HELP, WXK_HELP },
d5c21b02
VZ
5535
5536 { VK_NUMPAD0, WXK_NUMPAD0 },
5537 { VK_NUMPAD1, WXK_NUMPAD1 },
5538 { VK_NUMPAD2, WXK_NUMPAD2 },
5539 { VK_NUMPAD3, WXK_NUMPAD3 },
5540 { VK_NUMPAD4, WXK_NUMPAD4 },
5541 { VK_NUMPAD5, WXK_NUMPAD5 },
5542 { VK_NUMPAD6, WXK_NUMPAD6 },
5543 { VK_NUMPAD7, WXK_NUMPAD7 },
5544 { VK_NUMPAD8, WXK_NUMPAD8 },
5545 { VK_NUMPAD9, WXK_NUMPAD9 },
5546 { VK_MULTIPLY, WXK_NUMPAD_MULTIPLY },
5547 { VK_ADD, WXK_NUMPAD_ADD },
5548 { VK_SUBTRACT, WXK_NUMPAD_SUBTRACT },
5549 { VK_DECIMAL, WXK_NUMPAD_DECIMAL },
5550 { VK_DIVIDE, WXK_NUMPAD_DIVIDE },
5551
5552 { VK_F1, WXK_F1 },
5553 { VK_F2, WXK_F2 },
5554 { VK_F3, WXK_F3 },
5555 { VK_F4, WXK_F4 },
5556 { VK_F5, WXK_F5 },
5557 { VK_F6, WXK_F6 },
5558 { VK_F7, WXK_F7 },
5559 { VK_F8, WXK_F8 },
5560 { VK_F9, WXK_F9 },
5561 { VK_F10, WXK_F10 },
5562 { VK_F11, WXK_F11 },
5563 { VK_F12, WXK_F12 },
5564 { VK_F13, WXK_F13 },
5565 { VK_F14, WXK_F14 },
5566 { VK_F15, WXK_F15 },
5567 { VK_F16, WXK_F16 },
5568 { VK_F17, WXK_F17 },
5569 { VK_F18, WXK_F18 },
5570 { VK_F19, WXK_F19 },
5571 { VK_F20, WXK_F20 },
5572 { VK_F21, WXK_F21 },
5573 { VK_F22, WXK_F22 },
5574 { VK_F23, WXK_F23 },
5575 { VK_F24, WXK_F24 },
5576
5577 { VK_NUMLOCK, WXK_NUMLOCK },
5578 { VK_SCROLL, WXK_SCROLL },
5579
5580#ifdef VK_APPS
5581 { VK_LWIN, WXK_WINDOWS_LEFT },
5582 { VK_RWIN, WXK_WINDOWS_RIGHT },
5583 { VK_APPS, WXK_WINDOWS_MENU },
5584#endif // VK_APPS defined
5585};
5586
42e69d6b
VZ
5587// Returns 0 if was a normal ASCII value, not a special key. This indicates that
5588// the key should be ignored by WM_KEYDOWN and processed by WM_CHAR instead.
d5c21b02 5589int wxCharCodeMSWToWX(int vk, WXLPARAM lParam)
42e69d6b 5590{
d5c21b02
VZ
5591 // check the table first
5592 for ( size_t n = 0; n < WXSIZEOF(gs_specialKeys); n++ )
5593 {
5594 if ( gs_specialKeys[n].vk == vk )
5595 return gs_specialKeys[n].wxk;
5596 }
9c7df356 5597
d5c21b02
VZ
5598 // keys requiring special handling
5599 int wxk;
5600 switch ( vk )
5601 {
e77c5d96
VZ
5602 // the mapping for these keys may be incorrect on non-US keyboards so
5603 // maybe we shouldn't map them to ASCII values at all
d5c21b02
VZ
5604 case VK_OEM_1: wxk = ';'; break;
5605 case VK_OEM_PLUS: wxk = '+'; break;
5606 case VK_OEM_COMMA: wxk = ','; break;
5607 case VK_OEM_MINUS: wxk = '-'; break;
5608 case VK_OEM_PERIOD: wxk = '.'; break;
5609 case VK_OEM_2: wxk = '/'; break;
5610 case VK_OEM_3: wxk = '~'; break;
5611 case VK_OEM_4: wxk = '['; break;
5612 case VK_OEM_5: wxk = '\\'; break;
5613 case VK_OEM_6: wxk = ']'; break;
5614 case VK_OEM_7: wxk = '\''; break;
702c4208 5615
5004c3ad 5616 // handle extended keys
413553cc 5617 case VK_PRIOR:
d5c21b02 5618 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_PAGEUP, WXK_PAGEUP);
413553cc 5619 break;
d5c21b02 5620
413553cc 5621 case VK_NEXT:
d5c21b02 5622 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_PAGEDOWN, WXK_PAGEDOWN);
413553cc 5623 break;
d5c21b02 5624
413553cc 5625 case VK_END:
d5c21b02 5626 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_END, WXK_END);
413553cc 5627 break;
d5c21b02 5628
413553cc 5629 case VK_HOME:
d5c21b02 5630 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_HOME, WXK_HOME);
413553cc 5631 break;
d5c21b02 5632
413553cc 5633 case VK_LEFT:
d5c21b02 5634 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_LEFT, WXK_LEFT);
413553cc 5635 break;
d5c21b02 5636
413553cc 5637 case VK_UP:
d5c21b02 5638 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_UP, WXK_UP);
413553cc 5639 break;
d5c21b02 5640
413553cc 5641 case VK_RIGHT:
d5c21b02 5642 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_RIGHT, WXK_RIGHT);
413553cc 5643 break;
d5c21b02 5644
413553cc 5645 case VK_DOWN:
d5c21b02 5646 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DOWN, WXK_DOWN);
413553cc 5647 break;
d5c21b02 5648
413553cc 5649 case VK_INSERT:
d5c21b02 5650 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_INSERT, WXK_INSERT);
413553cc 5651 break;
d5c21b02 5652
413553cc 5653 case VK_DELETE:
d5c21b02 5654 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DELETE, WXK_DELETE);
413553cc 5655 break;
d5c21b02 5656
ff792344 5657 case VK_RETURN:
ed5bc8f1
VZ
5658 // don't use ChooseNormalOrExtended() here as the keys are reversed
5659 // here: numpad enter is the extended one
d5c21b02 5660 wxk = lParam && (lParam & (1 << 24)) ? WXK_NUMPAD_ENTER : WXK_RETURN;
ff792344
VZ
5661 break;
5662
f6bcfd97 5663 default:
d5c21b02
VZ
5664 wxk = 0;
5665 }
5666
5667 return wxk;
5668}
5669
5670WXWORD wxCharCodeWXToMSW(int wxk, bool *isVirtual)
5671{
5672 if ( isVirtual )
5673 *isVirtual = true;
5674
5675 // check the table first
5676 for ( size_t n = 0; n < WXSIZEOF(gs_specialKeys); n++ )
5677 {
5678 if ( gs_specialKeys[n].wxk == wxk )
5679 return gs_specialKeys[n].vk;
5680 }
5681
5682 // and then check for special keys not included in the table
5683 WXWORD vk;
5684 switch ( wxk )
5685 {
71403278
VZ
5686 case WXK_PAGEUP:
5687 case WXK_NUMPAD_PAGEUP:
5688 vk = VK_PRIOR;
5689 break;
5690
5691 case WXK_PAGEDOWN:
5692 case WXK_NUMPAD_PAGEDOWN:
5693 vk = VK_NEXT;
5694 break;
5695
5696 case WXK_END:
5697 case WXK_NUMPAD_END:
5698 vk = VK_END;
5699 break;
5700
5701 case WXK_HOME:
5702 case WXK_NUMPAD_HOME:
5703 vk = VK_HOME;
5704 break;
5705
5706 case WXK_LEFT:
5707 case WXK_NUMPAD_LEFT:
5708 vk = VK_LEFT;
5709 break;
5710
5711 case WXK_UP:
5712 case WXK_NUMPAD_UP:
5713 vk = VK_UP;
5714 break;
5715
5716 case WXK_RIGHT:
5717 case WXK_NUMPAD_RIGHT:
5718 vk = VK_RIGHT;
5719 break;
5720
5721 case WXK_DOWN:
5722 case WXK_NUMPAD_DOWN:
5723 vk = VK_DOWN;
5724 break;
5725
5726 case WXK_INSERT:
5727 case WXK_NUMPAD_INSERT:
5728 vk = VK_INSERT;
5729 break;
5730
5731 case WXK_DELETE:
5732 case WXK_NUMPAD_DELETE:
5733 vk = VK_DELETE;
5734 break;
d5c21b02
VZ
5735
5736 default:
5737 if ( isVirtual )
5738 *isVirtual = false;
5739 vk = (WXWORD)wxk;
42e69d6b 5740 break;
2bda0e17 5741 }
d5c21b02
VZ
5742
5743 return vk;
5744}
5745
5746// small helper for wxGetKeyState() and wxGetMouseState()
5747static inline bool wxIsKeyDown(WXWORD vk)
5748{
5749 // the low order bit indicates whether the key was pressed since the last
5750 // call and the high order one indicates whether it is down right now and
5751 // we only want that one
5752 return (::GetAsyncKeyState(vk) & (1<<15)) != 0;
2bda0e17
KB
5753}
5754
1751226c 5755bool wxGetKeyState(wxKeyCode key)
6ed892f3 5756{
d5c21b02
VZ
5757 // although this does work under Windows, it is not supported under other
5758 // platforms so don't allow it, you must use wxGetMouseState() instead
5759 wxASSERT_MSG( key != VK_LBUTTON &&
5760 key != VK_RBUTTON &&
5761 key != VK_MBUTTON,
5762 wxT("can't use wxGetKeyState() for mouse buttons") );
6ed892f3 5763
d5c21b02 5764 const WXWORD vk = wxCharCodeWXToMSW(key);
44353523 5765
d5c21b02
VZ
5766 // if the requested key is a LED key, return true if the led is pressed
5767 if ( key == WXK_NUMLOCK || key == WXK_CAPITAL || key == WXK_SCROLL )
fdec2c05 5768 {
d5c21b02
VZ
5769 // low order bit means LED is highlighted and high order one means the
5770 // key is down; for compatibility with the other ports return true if
5771 // either one is set
5772 return ::GetKeyState(vk) != 0;
35bbb0c6 5773
fdec2c05 5774 }
d5c21b02 5775 else // normal key
84c51ddf 5776 {
d5c21b02 5777 return wxIsKeyDown(vk);
84c51ddf 5778 }
6ed892f3
RN
5779}
5780
7dd40b6f
RD
5781
5782wxMouseState wxGetMouseState()
5783{
5784 wxMouseState ms;
5785 POINT pt;
5786 GetCursorPos( &pt );
5787
5788 ms.SetX(pt.x);
5789 ms.SetY(pt.y);
d5c21b02
VZ
5790 ms.SetLeftDown(wxIsKeyDown(VK_LBUTTON));
5791 ms.SetMiddleDown(wxIsKeyDown(VK_MBUTTON));
5792 ms.SetRightDown(wxIsKeyDown(VK_RBUTTON));
dd28827a 5793
d5c21b02
VZ
5794 ms.SetControlDown(wxIsKeyDown(VK_CONTROL));
5795 ms.SetShiftDown(wxIsKeyDown(VK_SHIFT));
5796 ms.SetAltDown(wxIsKeyDown(VK_MENU));
7dd40b6f 5797// ms.SetMetaDown();
dd28827a 5798
7dd40b6f
RD
5799 return ms;
5800}
5801
5802
42e69d6b 5803wxWindow *wxGetActiveWindow()
2bda0e17 5804{
42e69d6b
VZ
5805 HWND hWnd = GetActiveWindow();
5806 if ( hWnd != 0 )
2d0a075d 5807 {
42e69d6b 5808 return wxFindWinFromHandle((WXHWND) hWnd);
2d0a075d 5809 }
42e69d6b 5810 return NULL;
2bda0e17
KB
5811}
5812
8614c467
VZ
5813extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd)
5814{
5815 HWND hwnd = (HWND)hWnd;
5816
5817 // For a radiobutton, we get the radiobox from GWL_USERDATA (which is set
5818 // by code in msw/radiobox.cpp), for all the others we just search up the
5819 // window hierarchy
5820 wxWindow *win = (wxWindow *)NULL;
5821 if ( hwnd )
5822 {
5823 win = wxFindWinFromHandle((WXHWND)hwnd);
5824 if ( !win )
5825 {
a2242341 5826#if wxUSE_RADIOBOX
8614c467
VZ
5827 // native radiobuttons return DLGC_RADIOBUTTON here and for any
5828 // wxWindow class which overrides WM_GETDLGCODE processing to
5829 // do it as well, win would be already non NULL
a2242341 5830 if ( ::SendMessage(hwnd, WM_GETDLGCODE, 0, 0) & DLGC_RADIOBUTTON )
8614c467 5831 {
975b6bcf 5832 win = (wxWindow *)wxGetWindowUserData(hwnd);
8614c467 5833 }
a2242341
VZ
5834 //else: it's a wxRadioButton, not a radiobutton from wxRadioBox
5835#endif // wxUSE_RADIOBOX
5836
5837 // spin control text buddy window should be mapped to spin ctrl
5838 // itself so try it too
24ce4c18 5839#if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__)
a2242341
VZ
5840 if ( !win )
5841 {
5842 win = wxSpinCtrl::GetSpinForTextCtrl((WXHWND)hwnd);
5843 }
5844#endif // wxUSE_SPINCTRL
8614c467 5845 }
8614c467
VZ
5846 }
5847
5848 while ( hwnd && !win )
5849 {
761989ff
VZ
5850 // this is a really ugly hack needed to avoid mistakenly returning the
5851 // parent frame wxWindow for the find/replace modeless dialog HWND -
5852 // this, in turn, is needed to call IsDialogMessage() from
5853 // wxApp::ProcessMessage() as for this we must return NULL from here
5854 //
5855 // FIXME: this is clearly not the best way to do it but I think we'll
5856 // need to change HWND <-> wxWindow code more heavily than I can
5857 // do it now to fix it
c67d6888 5858#ifndef __WXMICROWIN__
761989ff
VZ
5859 if ( ::GetWindow(hwnd, GW_OWNER) )
5860 {
5861 // it's a dialog box, don't go upwards
5862 break;
5863 }
c67d6888 5864#endif
761989ff 5865
8614c467 5866 hwnd = ::GetParent(hwnd);
761989ff 5867 win = wxFindWinFromHandle((WXHWND)hwnd);
8614c467
VZ
5868 }
5869
5870 return win;
5871}
5872
7f0586ef 5873#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
04ef50df 5874
42e69d6b
VZ
5875// Windows keyboard hook. Allows interception of e.g. F1, ESCAPE
5876// in active frames and dialogs, regardless of where the focus is.
5877static HHOOK wxTheKeyboardHook = 0;
5878static FARPROC wxTheKeyboardHookProc = 0;
5879int APIENTRY _EXPORT
5880wxKeyboardHook(int nCode, WORD wParam, DWORD lParam);
2bda0e17 5881
42e69d6b 5882void wxSetKeyboardHook(bool doIt)
2bda0e17 5883{
42e69d6b 5884 if ( doIt )
2d0a075d 5885 {
42e69d6b
VZ
5886 wxTheKeyboardHookProc = MakeProcInstance((FARPROC) wxKeyboardHook, wxGetInstance());
5887 wxTheKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC) wxTheKeyboardHookProc, wxGetInstance(),
c7527e3f 5888
8614c467 5889 GetCurrentThreadId()
42e69d6b 5890 // (DWORD)GetCurrentProcess()); // This is another possibility. Which is right?
8614c467 5891 );
2d0a075d 5892 }
2d0a075d 5893 else
2d0a075d 5894 {
42e69d6b 5895 UnhookWindowsHookEx(wxTheKeyboardHook);
2d0a075d 5896 }
2bda0e17
KB
5897}
5898
42e69d6b
VZ
5899int APIENTRY _EXPORT
5900wxKeyboardHook(int nCode, WORD wParam, DWORD lParam)
2bda0e17 5901{
42e69d6b
VZ
5902 DWORD hiWord = HIWORD(lParam);
5903 if ( nCode != HC_NOREMOVE && ((hiWord & KF_UP) == 0) )
43d811ea 5904 {
ff792344 5905 int id = wxCharCodeMSWToWX(wParam, lParam);
32de7d24 5906 if ( id != 0 )
43d811ea 5907 {
42e69d6b
VZ
5908 wxKeyEvent event(wxEVT_CHAR_HOOK);
5909 if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN )
08158721 5910 event.m_altDown = true;
c085e333 5911
687706f5 5912 event.SetEventObject(NULL);
42e69d6b 5913 event.m_keyCode = id;
3f7bc32b
VZ
5914 event.m_shiftDown = wxIsShiftDown();
5915 event.m_controlDown = wxIsCtrlDown();
f0b1ccde 5916#ifndef __WXWINCE__
1bf77ee5 5917 event.SetTimestamp(::GetMessageTime());
f0b1ccde 5918#endif
42e69d6b 5919 wxWindow *win = wxGetActiveWindow();
32de7d24 5920 wxEvtHandler *handler;
42e69d6b
VZ
5921 if ( win )
5922 {
32de7d24
VZ
5923 handler = win->GetEventHandler();
5924 event.SetId(win->GetId());
42e69d6b
VZ
5925 }
5926 else
5927 {
32de7d24 5928 handler = wxTheApp;
abb74e0f 5929 event.SetId(wxID_ANY);
32de7d24
VZ
5930 }
5931
5932 if ( handler && handler->ProcessEvent(event) )
5933 {
5934 // processed
5935 return 1;
42e69d6b 5936 }
43d811ea
JS
5937 }
5938 }
32de7d24 5939
42e69d6b 5940 return (int)CallNextHookEx(wxTheKeyboardHook, nCode, wParam, lParam);
4fabb575 5941}
cd4453e5
VZ
5942
5943#endif // !__WXMICROWIN__
4fabb575 5944
b2aef89b 5945#ifdef __WXDEBUG__
4a712ba3 5946const wxChar *wxGetMessageName(int message)
47cbd6da 5947{
42e69d6b
VZ
5948 switch ( message )
5949 {
4a712ba3
VZ
5950 case 0x0000: return wxT("WM_NULL");
5951 case 0x0001: return wxT("WM_CREATE");
5952 case 0x0002: return wxT("WM_DESTROY");
5953 case 0x0003: return wxT("WM_MOVE");
5954 case 0x0005: return wxT("WM_SIZE");
5955 case 0x0006: return wxT("WM_ACTIVATE");
5956 case 0x0007: return wxT("WM_SETFOCUS");
5957 case 0x0008: return wxT("WM_KILLFOCUS");
5958 case 0x000A: return wxT("WM_ENABLE");
5959 case 0x000B: return wxT("WM_SETREDRAW");
5960 case 0x000C: return wxT("WM_SETTEXT");
5961 case 0x000D: return wxT("WM_GETTEXT");
5962 case 0x000E: return wxT("WM_GETTEXTLENGTH");
5963 case 0x000F: return wxT("WM_PAINT");
5964 case 0x0010: return wxT("WM_CLOSE");
5965 case 0x0011: return wxT("WM_QUERYENDSESSION");
5966 case 0x0012: return wxT("WM_QUIT");
5967 case 0x0013: return wxT("WM_QUERYOPEN");
5968 case 0x0014: return wxT("WM_ERASEBKGND");
5969 case 0x0015: return wxT("WM_SYSCOLORCHANGE");
5970 case 0x0016: return wxT("WM_ENDSESSION");
5971 case 0x0017: return wxT("WM_SYSTEMERROR");
5972 case 0x0018: return wxT("WM_SHOWWINDOW");
5973 case 0x0019: return wxT("WM_CTLCOLOR");
5974 case 0x001A: return wxT("WM_WININICHANGE");
5975 case 0x001B: return wxT("WM_DEVMODECHANGE");
5976 case 0x001C: return wxT("WM_ACTIVATEAPP");
5977 case 0x001D: return wxT("WM_FONTCHANGE");
5978 case 0x001E: return wxT("WM_TIMECHANGE");
5979 case 0x001F: return wxT("WM_CANCELMODE");
5980 case 0x0020: return wxT("WM_SETCURSOR");
5981 case 0x0021: return wxT("WM_MOUSEACTIVATE");
5982 case 0x0022: return wxT("WM_CHILDACTIVATE");
5983 case 0x0023: return wxT("WM_QUEUESYNC");
5984 case 0x0024: return wxT("WM_GETMINMAXINFO");
5985 case 0x0026: return wxT("WM_PAINTICON");
5986 case 0x0027: return wxT("WM_ICONERASEBKGND");
5987 case 0x0028: return wxT("WM_NEXTDLGCTL");
5988 case 0x002A: return wxT("WM_SPOOLERSTATUS");
5989 case 0x002B: return wxT("WM_DRAWITEM");
5990 case 0x002C: return wxT("WM_MEASUREITEM");
5991 case 0x002D: return wxT("WM_DELETEITEM");
5992 case 0x002E: return wxT("WM_VKEYTOITEM");
5993 case 0x002F: return wxT("WM_CHARTOITEM");
5994 case 0x0030: return wxT("WM_SETFONT");
5995 case 0x0031: return wxT("WM_GETFONT");
5996 case 0x0037: return wxT("WM_QUERYDRAGICON");
5997 case 0x0039: return wxT("WM_COMPAREITEM");
5998 case 0x0041: return wxT("WM_COMPACTING");
5999 case 0x0044: return wxT("WM_COMMNOTIFY");
6000 case 0x0046: return wxT("WM_WINDOWPOSCHANGING");
6001 case 0x0047: return wxT("WM_WINDOWPOSCHANGED");
6002 case 0x0048: return wxT("WM_POWER");
6003
6004 case 0x004A: return wxT("WM_COPYDATA");
6005 case 0x004B: return wxT("WM_CANCELJOURNAL");
6006 case 0x004E: return wxT("WM_NOTIFY");
6007 case 0x0050: return wxT("WM_INPUTLANGCHANGEREQUEST");
6008 case 0x0051: return wxT("WM_INPUTLANGCHANGE");
6009 case 0x0052: return wxT("WM_TCARD");
6010 case 0x0053: return wxT("WM_HELP");
6011 case 0x0054: return wxT("WM_USERCHANGED");
6012 case 0x0055: return wxT("WM_NOTIFYFORMAT");
6013 case 0x007B: return wxT("WM_CONTEXTMENU");
6014 case 0x007C: return wxT("WM_STYLECHANGING");
6015 case 0x007D: return wxT("WM_STYLECHANGED");
6016 case 0x007E: return wxT("WM_DISPLAYCHANGE");
6017 case 0x007F: return wxT("WM_GETICON");
6018 case 0x0080: return wxT("WM_SETICON");
6019
6020 case 0x0081: return wxT("WM_NCCREATE");
6021 case 0x0082: return wxT("WM_NCDESTROY");
6022 case 0x0083: return wxT("WM_NCCALCSIZE");
6023 case 0x0084: return wxT("WM_NCHITTEST");
6024 case 0x0085: return wxT("WM_NCPAINT");
6025 case 0x0086: return wxT("WM_NCACTIVATE");
6026 case 0x0087: return wxT("WM_GETDLGCODE");
6027 case 0x00A0: return wxT("WM_NCMOUSEMOVE");
6028 case 0x00A1: return wxT("WM_NCLBUTTONDOWN");
6029 case 0x00A2: return wxT("WM_NCLBUTTONUP");
6030 case 0x00A3: return wxT("WM_NCLBUTTONDBLCLK");
6031 case 0x00A4: return wxT("WM_NCRBUTTONDOWN");
6032 case 0x00A5: return wxT("WM_NCRBUTTONUP");
6033 case 0x00A6: return wxT("WM_NCRBUTTONDBLCLK");
6034 case 0x00A7: return wxT("WM_NCMBUTTONDOWN");
6035 case 0x00A8: return wxT("WM_NCMBUTTONUP");
6036 case 0x00A9: return wxT("WM_NCMBUTTONDBLCLK");
6037 case 0x0100: return wxT("WM_KEYDOWN");
6038 case 0x0101: return wxT("WM_KEYUP");
6039 case 0x0102: return wxT("WM_CHAR");
6040 case 0x0103: return wxT("WM_DEADCHAR");
6041 case 0x0104: return wxT("WM_SYSKEYDOWN");
6042 case 0x0105: return wxT("WM_SYSKEYUP");
6043 case 0x0106: return wxT("WM_SYSCHAR");
6044 case 0x0107: return wxT("WM_SYSDEADCHAR");
6045 case 0x0108: return wxT("WM_KEYLAST");
6046
6047 case 0x010D: return wxT("WM_IME_STARTCOMPOSITION");
6048 case 0x010E: return wxT("WM_IME_ENDCOMPOSITION");
6049 case 0x010F: return wxT("WM_IME_COMPOSITION");
6050
6051 case 0x0110: return wxT("WM_INITDIALOG");
6052 case 0x0111: return wxT("WM_COMMAND");
6053 case 0x0112: return wxT("WM_SYSCOMMAND");
6054 case 0x0113: return wxT("WM_TIMER");
6055 case 0x0114: return wxT("WM_HSCROLL");
6056 case 0x0115: return wxT("WM_VSCROLL");
6057 case 0x0116: return wxT("WM_INITMENU");
6058 case 0x0117: return wxT("WM_INITMENUPOPUP");
6059 case 0x011F: return wxT("WM_MENUSELECT");
6060 case 0x0120: return wxT("WM_MENUCHAR");
6061 case 0x0121: return wxT("WM_ENTERIDLE");
6062 case 0x0200: return wxT("WM_MOUSEMOVE");
6063 case 0x0201: return wxT("WM_LBUTTONDOWN");
6064 case 0x0202: return wxT("WM_LBUTTONUP");
6065 case 0x0203: return wxT("WM_LBUTTONDBLCLK");
6066 case 0x0204: return wxT("WM_RBUTTONDOWN");
6067 case 0x0205: return wxT("WM_RBUTTONUP");
6068 case 0x0206: return wxT("WM_RBUTTONDBLCLK");
6069 case 0x0207: return wxT("WM_MBUTTONDOWN");
6070 case 0x0208: return wxT("WM_MBUTTONUP");
6071 case 0x0209: return wxT("WM_MBUTTONDBLCLK");
6072 case 0x020A: return wxT("WM_MOUSEWHEEL");
6073 case 0x0210: return wxT("WM_PARENTNOTIFY");
6074 case 0x0211: return wxT("WM_ENTERMENULOOP");
6075 case 0x0212: return wxT("WM_EXITMENULOOP");
6076
6077 case 0x0213: return wxT("WM_NEXTMENU");
6078 case 0x0214: return wxT("WM_SIZING");
6079 case 0x0215: return wxT("WM_CAPTURECHANGED");
6080 case 0x0216: return wxT("WM_MOVING");
6081 case 0x0218: return wxT("WM_POWERBROADCAST");
6082 case 0x0219: return wxT("WM_DEVICECHANGE");
6083
6084 case 0x0220: return wxT("WM_MDICREATE");
6085 case 0x0221: return wxT("WM_MDIDESTROY");
6086 case 0x0222: return wxT("WM_MDIACTIVATE");
6087 case 0x0223: return wxT("WM_MDIRESTORE");
6088 case 0x0224: return wxT("WM_MDINEXT");
6089 case 0x0225: return wxT("WM_MDIMAXIMIZE");
6090 case 0x0226: return wxT("WM_MDITILE");
6091 case 0x0227: return wxT("WM_MDICASCADE");
6092 case 0x0228: return wxT("WM_MDIICONARRANGE");
6093 case 0x0229: return wxT("WM_MDIGETACTIVE");
6094 case 0x0230: return wxT("WM_MDISETMENU");
6095 case 0x0233: return wxT("WM_DROPFILES");
6096
6097 case 0x0281: return wxT("WM_IME_SETCONTEXT");
6098 case 0x0282: return wxT("WM_IME_NOTIFY");
6099 case 0x0283: return wxT("WM_IME_CONTROL");
6100 case 0x0284: return wxT("WM_IME_COMPOSITIONFULL");
6101 case 0x0285: return wxT("WM_IME_SELECT");
6102 case 0x0286: return wxT("WM_IME_CHAR");
6103 case 0x0290: return wxT("WM_IME_KEYDOWN");
6104 case 0x0291: return wxT("WM_IME_KEYUP");
6105
6106 case 0x0300: return wxT("WM_CUT");
6107 case 0x0301: return wxT("WM_COPY");
6108 case 0x0302: return wxT("WM_PASTE");
6109 case 0x0303: return wxT("WM_CLEAR");
6110 case 0x0304: return wxT("WM_UNDO");
6111 case 0x0305: return wxT("WM_RENDERFORMAT");
6112 case 0x0306: return wxT("WM_RENDERALLFORMATS");
6113 case 0x0307: return wxT("WM_DESTROYCLIPBOARD");
6114 case 0x0308: return wxT("WM_DRAWCLIPBOARD");
6115 case 0x0309: return wxT("WM_PAINTCLIPBOARD");
6116 case 0x030A: return wxT("WM_VSCROLLCLIPBOARD");
6117 case 0x030B: return wxT("WM_SIZECLIPBOARD");
6118 case 0x030C: return wxT("WM_ASKCBFORMATNAME");
6119 case 0x030D: return wxT("WM_CHANGECBCHAIN");
6120 case 0x030E: return wxT("WM_HSCROLLCLIPBOARD");
6121 case 0x030F: return wxT("WM_QUERYNEWPALETTE");
6122 case 0x0310: return wxT("WM_PALETTEISCHANGING");
6123 case 0x0311: return wxT("WM_PALETTECHANGED");
5048c832 6124#if wxUSE_HOTKEY
4a712ba3 6125 case 0x0312: return wxT("WM_HOTKEY");
5048c832 6126#endif
c085e333 6127
2d0a075d
JS
6128 // common controls messages - although they're not strictly speaking
6129 // standard, it's nice to decode them nevertheless
a02eb1d2 6130
2d0a075d 6131 // listview
4a712ba3
VZ
6132 case 0x1000 + 0: return wxT("LVM_GETBKCOLOR");
6133 case 0x1000 + 1: return wxT("LVM_SETBKCOLOR");
6134 case 0x1000 + 2: return wxT("LVM_GETIMAGELIST");
6135 case 0x1000 + 3: return wxT("LVM_SETIMAGELIST");
6136 case 0x1000 + 4: return wxT("LVM_GETITEMCOUNT");
6137 case 0x1000 + 5: return wxT("LVM_GETITEMA");
6138 case 0x1000 + 75: return wxT("LVM_GETITEMW");
6139 case 0x1000 + 6: return wxT("LVM_SETITEMA");
6140 case 0x1000 + 76: return wxT("LVM_SETITEMW");
6141 case 0x1000 + 7: return wxT("LVM_INSERTITEMA");
6142 case 0x1000 + 77: return wxT("LVM_INSERTITEMW");
6143 case 0x1000 + 8: return wxT("LVM_DELETEITEM");
6144 case 0x1000 + 9: return wxT("LVM_DELETEALLITEMS");
6145 case 0x1000 + 10: return wxT("LVM_GETCALLBACKMASK");
6146 case 0x1000 + 11: return wxT("LVM_SETCALLBACKMASK");
6147 case 0x1000 + 12: return wxT("LVM_GETNEXTITEM");
6148 case 0x1000 + 13: return wxT("LVM_FINDITEMA");
6149 case 0x1000 + 83: return wxT("LVM_FINDITEMW");
6150 case 0x1000 + 14: return wxT("LVM_GETITEMRECT");
6151 case 0x1000 + 15: return wxT("LVM_SETITEMPOSITION");
6152 case 0x1000 + 16: return wxT("LVM_GETITEMPOSITION");
6153 case 0x1000 + 17: return wxT("LVM_GETSTRINGWIDTHA");
6154 case 0x1000 + 87: return wxT("LVM_GETSTRINGWIDTHW");
6155 case 0x1000 + 18: return wxT("LVM_HITTEST");
6156 case 0x1000 + 19: return wxT("LVM_ENSUREVISIBLE");
6157 case 0x1000 + 20: return wxT("LVM_SCROLL");
6158 case 0x1000 + 21: return wxT("LVM_REDRAWITEMS");
6159 case 0x1000 + 22: return wxT("LVM_ARRANGE");
6160 case 0x1000 + 23: return wxT("LVM_EDITLABELA");
6161 case 0x1000 + 118: return wxT("LVM_EDITLABELW");
6162 case 0x1000 + 24: return wxT("LVM_GETEDITCONTROL");
6163 case 0x1000 + 25: return wxT("LVM_GETCOLUMNA");
6164 case 0x1000 + 95: return wxT("LVM_GETCOLUMNW");
6165 case 0x1000 + 26: return wxT("LVM_SETCOLUMNA");
6166 case 0x1000 + 96: return wxT("LVM_SETCOLUMNW");
6167 case 0x1000 + 27: return wxT("LVM_INSERTCOLUMNA");
6168 case 0x1000 + 97: return wxT("LVM_INSERTCOLUMNW");
6169 case 0x1000 + 28: return wxT("LVM_DELETECOLUMN");
6170 case 0x1000 + 29: return wxT("LVM_GETCOLUMNWIDTH");
6171 case 0x1000 + 30: return wxT("LVM_SETCOLUMNWIDTH");
6172 case 0x1000 + 31: return wxT("LVM_GETHEADER");
6173 case 0x1000 + 33: return wxT("LVM_CREATEDRAGIMAGE");
6174 case 0x1000 + 34: return wxT("LVM_GETVIEWRECT");
6175 case 0x1000 + 35: return wxT("LVM_GETTEXTCOLOR");
6176 case 0x1000 + 36: return wxT("LVM_SETTEXTCOLOR");
6177 case 0x1000 + 37: return wxT("LVM_GETTEXTBKCOLOR");
6178 case 0x1000 + 38: return wxT("LVM_SETTEXTBKCOLOR");
6179 case 0x1000 + 39: return wxT("LVM_GETTOPINDEX");
6180 case 0x1000 + 40: return wxT("LVM_GETCOUNTPERPAGE");
6181 case 0x1000 + 41: return wxT("LVM_GETORIGIN");
6182 case 0x1000 + 42: return wxT("LVM_UPDATE");
6183 case 0x1000 + 43: return wxT("LVM_SETITEMSTATE");
6184 case 0x1000 + 44: return wxT("LVM_GETITEMSTATE");
6185 case 0x1000 + 45: return wxT("LVM_GETITEMTEXTA");
6186 case 0x1000 + 115: return wxT("LVM_GETITEMTEXTW");
6187 case 0x1000 + 46: return wxT("LVM_SETITEMTEXTA");
6188 case 0x1000 + 116: return wxT("LVM_SETITEMTEXTW");
6189 case 0x1000 + 47: return wxT("LVM_SETITEMCOUNT");
6190 case 0x1000 + 48: return wxT("LVM_SORTITEMS");
6191 case 0x1000 + 49: return wxT("LVM_SETITEMPOSITION32");
6192 case 0x1000 + 50: return wxT("LVM_GETSELECTEDCOUNT");
6193 case 0x1000 + 51: return wxT("LVM_GETITEMSPACING");
6194 case 0x1000 + 52: return wxT("LVM_GETISEARCHSTRINGA");
6195 case 0x1000 + 117: return wxT("LVM_GETISEARCHSTRINGW");
6196 case 0x1000 + 53: return wxT("LVM_SETICONSPACING");
6197 case 0x1000 + 54: return wxT("LVM_SETEXTENDEDLISTVIEWSTYLE");
6198 case 0x1000 + 55: return wxT("LVM_GETEXTENDEDLISTVIEWSTYLE");
6199 case 0x1000 + 56: return wxT("LVM_GETSUBITEMRECT");
6200 case 0x1000 + 57: return wxT("LVM_SUBITEMHITTEST");
6201 case 0x1000 + 58: return wxT("LVM_SETCOLUMNORDERARRAY");
6202 case 0x1000 + 59: return wxT("LVM_GETCOLUMNORDERARRAY");
6203 case 0x1000 + 60: return wxT("LVM_SETHOTITEM");
6204 case 0x1000 + 61: return wxT("LVM_GETHOTITEM");
6205 case 0x1000 + 62: return wxT("LVM_SETHOTCURSOR");
6206 case 0x1000 + 63: return wxT("LVM_GETHOTCURSOR");
6207 case 0x1000 + 64: return wxT("LVM_APPROXIMATEVIEWRECT");
6208 case 0x1000 + 65: return wxT("LVM_SETWORKAREA");
c085e333 6209
2d0a075d 6210 // tree view
4a712ba3
VZ
6211 case 0x1100 + 0: return wxT("TVM_INSERTITEMA");
6212 case 0x1100 + 50: return wxT("TVM_INSERTITEMW");
6213 case 0x1100 + 1: return wxT("TVM_DELETEITEM");
6214 case 0x1100 + 2: return wxT("TVM_EXPAND");
6215 case 0x1100 + 4: return wxT("TVM_GETITEMRECT");
6216 case 0x1100 + 5: return wxT("TVM_GETCOUNT");
6217 case 0x1100 + 6: return wxT("TVM_GETINDENT");
6218 case 0x1100 + 7: return wxT("TVM_SETINDENT");
6219 case 0x1100 + 8: return wxT("TVM_GETIMAGELIST");
6220 case 0x1100 + 9: return wxT("TVM_SETIMAGELIST");
6221 case 0x1100 + 10: return wxT("TVM_GETNEXTITEM");
6222 case 0x1100 + 11: return wxT("TVM_SELECTITEM");
6223 case 0x1100 + 12: return wxT("TVM_GETITEMA");
6224 case 0x1100 + 62: return wxT("TVM_GETITEMW");
6225 case 0x1100 + 13: return wxT("TVM_SETITEMA");
6226 case 0x1100 + 63: return wxT("TVM_SETITEMW");
6227 case 0x1100 + 14: return wxT("TVM_EDITLABELA");
6228 case 0x1100 + 65: return wxT("TVM_EDITLABELW");
6229 case 0x1100 + 15: return wxT("TVM_GETEDITCONTROL");
6230 case 0x1100 + 16: return wxT("TVM_GETVISIBLECOUNT");
6231 case 0x1100 + 17: return wxT("TVM_HITTEST");
6232 case 0x1100 + 18: return wxT("TVM_CREATEDRAGIMAGE");
6233 case 0x1100 + 19: return wxT("TVM_SORTCHILDREN");
6234 case 0x1100 + 20: return wxT("TVM_ENSUREVISIBLE");
6235 case 0x1100 + 21: return wxT("TVM_SORTCHILDRENCB");
6236 case 0x1100 + 22: return wxT("TVM_ENDEDITLABELNOW");
6237 case 0x1100 + 23: return wxT("TVM_GETISEARCHSTRINGA");
6238 case 0x1100 + 64: return wxT("TVM_GETISEARCHSTRINGW");
6239 case 0x1100 + 24: return wxT("TVM_SETTOOLTIPS");
6240 case 0x1100 + 25: return wxT("TVM_GETTOOLTIPS");
c085e333 6241
2d0a075d 6242 // header
4a712ba3
VZ
6243 case 0x1200 + 0: return wxT("HDM_GETITEMCOUNT");
6244 case 0x1200 + 1: return wxT("HDM_INSERTITEMA");
6245 case 0x1200 + 10: return wxT("HDM_INSERTITEMW");
6246 case 0x1200 + 2: return wxT("HDM_DELETEITEM");
6247 case 0x1200 + 3: return wxT("HDM_GETITEMA");
6248 case 0x1200 + 11: return wxT("HDM_GETITEMW");
6249 case 0x1200 + 4: return wxT("HDM_SETITEMA");
6250 case 0x1200 + 12: return wxT("HDM_SETITEMW");
6251 case 0x1200 + 5: return wxT("HDM_LAYOUT");
6252 case 0x1200 + 6: return wxT("HDM_HITTEST");
6253 case 0x1200 + 7: return wxT("HDM_GETITEMRECT");
6254 case 0x1200 + 8: return wxT("HDM_SETIMAGELIST");
6255 case 0x1200 + 9: return wxT("HDM_GETIMAGELIST");
6256 case 0x1200 + 15: return wxT("HDM_ORDERTOINDEX");
6257 case 0x1200 + 16: return wxT("HDM_CREATEDRAGIMAGE");
6258 case 0x1200 + 17: return wxT("HDM_GETORDERARRAY");
6259 case 0x1200 + 18: return wxT("HDM_SETORDERARRAY");
6260 case 0x1200 + 19: return wxT("HDM_SETHOTDIVIDER");
c085e333 6261
2d0a075d 6262 // tab control
4a712ba3
VZ
6263 case 0x1300 + 2: return wxT("TCM_GETIMAGELIST");
6264 case 0x1300 + 3: return wxT("TCM_SETIMAGELIST");
6265 case 0x1300 + 4: return wxT("TCM_GETITEMCOUNT");
6266 case 0x1300 + 5: return wxT("TCM_GETITEMA");
6267 case 0x1300 + 60: return wxT("TCM_GETITEMW");
6268 case 0x1300 + 6: return wxT("TCM_SETITEMA");
6269 case 0x1300 + 61: return wxT("TCM_SETITEMW");
6270 case 0x1300 + 7: return wxT("TCM_INSERTITEMA");
6271 case 0x1300 + 62: return wxT("TCM_INSERTITEMW");
6272 case 0x1300 + 8: return wxT("TCM_DELETEITEM");
6273 case 0x1300 + 9: return wxT("TCM_DELETEALLITEMS");
6274 case 0x1300 + 10: return wxT("TCM_GETITEMRECT");
6275 case 0x1300 + 11: return wxT("TCM_GETCURSEL");
6276 case 0x1300 + 12: return wxT("TCM_SETCURSEL");
6277 case 0x1300 + 13: return wxT("TCM_HITTEST");
6278 case 0x1300 + 14: return wxT("TCM_SETITEMEXTRA");
6279 case 0x1300 + 40: return wxT("TCM_ADJUSTRECT");
6280 case 0x1300 + 41: return wxT("TCM_SETITEMSIZE");
6281 case 0x1300 + 42: return wxT("TCM_REMOVEIMAGE");
6282 case 0x1300 + 43: return wxT("TCM_SETPADDING");
6283 case 0x1300 + 44: return wxT("TCM_GETROWCOUNT");
6284 case 0x1300 + 45: return wxT("TCM_GETTOOLTIPS");
6285 case 0x1300 + 46: return wxT("TCM_SETTOOLTIPS");
6286 case 0x1300 + 47: return wxT("TCM_GETCURFOCUS");
6287 case 0x1300 + 48: return wxT("TCM_SETCURFOCUS");
6288 case 0x1300 + 49: return wxT("TCM_SETMINTABWIDTH");
6289 case 0x1300 + 50: return wxT("TCM_DESELECTALL");
c085e333 6290
2d0a075d 6291 // toolbar
4a712ba3
VZ
6292 case WM_USER+1: return wxT("TB_ENABLEBUTTON");
6293 case WM_USER+2: return wxT("TB_CHECKBUTTON");
6294 case WM_USER+3: return wxT("TB_PRESSBUTTON");
6295 case WM_USER+4: return wxT("TB_HIDEBUTTON");
6296 case WM_USER+5: return wxT("TB_INDETERMINATE");
6297 case WM_USER+9: return wxT("TB_ISBUTTONENABLED");
6298 case WM_USER+10: return wxT("TB_ISBUTTONCHECKED");
6299 case WM_USER+11: return wxT("TB_ISBUTTONPRESSED");
6300 case WM_USER+12: return wxT("TB_ISBUTTONHIDDEN");
6301 case WM_USER+13: return wxT("TB_ISBUTTONINDETERMINATE");
6302 case WM_USER+17: return wxT("TB_SETSTATE");
6303 case WM_USER+18: return wxT("TB_GETSTATE");
6304 case WM_USER+19: return wxT("TB_ADDBITMAP");
6305 case WM_USER+20: return wxT("TB_ADDBUTTONS");
6306 case WM_USER+21: return wxT("TB_INSERTBUTTON");
6307 case WM_USER+22: return wxT("TB_DELETEBUTTON");
6308 case WM_USER+23: return wxT("TB_GETBUTTON");
6309 case WM_USER+24: return wxT("TB_BUTTONCOUNT");
6310 case WM_USER+25: return wxT("TB_COMMANDTOINDEX");
6311 case WM_USER+26: return wxT("TB_SAVERESTOREA");
6312 case WM_USER+76: return wxT("TB_SAVERESTOREW");
6313 case WM_USER+27: return wxT("TB_CUSTOMIZE");
6314 case WM_USER+28: return wxT("TB_ADDSTRINGA");
6315 case WM_USER+77: return wxT("TB_ADDSTRINGW");
6316 case WM_USER+29: return wxT("TB_GETITEMRECT");
6317 case WM_USER+30: return wxT("TB_BUTTONSTRUCTSIZE");
6318 case WM_USER+31: return wxT("TB_SETBUTTONSIZE");
6319 case WM_USER+32: return wxT("TB_SETBITMAPSIZE");
6320 case WM_USER+33: return wxT("TB_AUTOSIZE");
6321 case WM_USER+35: return wxT("TB_GETTOOLTIPS");
6322 case WM_USER+36: return wxT("TB_SETTOOLTIPS");
6323 case WM_USER+37: return wxT("TB_SETPARENT");
6324 case WM_USER+39: return wxT("TB_SETROWS");
6325 case WM_USER+40: return wxT("TB_GETROWS");
6326 case WM_USER+42: return wxT("TB_SETCMDID");
6327 case WM_USER+43: return wxT("TB_CHANGEBITMAP");
6328 case WM_USER+44: return wxT("TB_GETBITMAP");
6329 case WM_USER+45: return wxT("TB_GETBUTTONTEXTA");
6330 case WM_USER+75: return wxT("TB_GETBUTTONTEXTW");
6331 case WM_USER+46: return wxT("TB_REPLACEBITMAP");
6332 case WM_USER+47: return wxT("TB_SETINDENT");
6333 case WM_USER+48: return wxT("TB_SETIMAGELIST");
6334 case WM_USER+49: return wxT("TB_GETIMAGELIST");
6335 case WM_USER+50: return wxT("TB_LOADIMAGES");
6336 case WM_USER+51: return wxT("TB_GETRECT");
6337 case WM_USER+52: return wxT("TB_SETHOTIMAGELIST");
6338 case WM_USER+53: return wxT("TB_GETHOTIMAGELIST");
6339 case WM_USER+54: return wxT("TB_SETDISABLEDIMAGELIST");
6340 case WM_USER+55: return wxT("TB_GETDISABLEDIMAGELIST");
6341 case WM_USER+56: return wxT("TB_SETSTYLE");
6342 case WM_USER+57: return wxT("TB_GETSTYLE");
6343 case WM_USER+58: return wxT("TB_GETBUTTONSIZE");
6344 case WM_USER+59: return wxT("TB_SETBUTTONWIDTH");
6345 case WM_USER+60: return wxT("TB_SETMAXTEXTROWS");
6346 case WM_USER+61: return wxT("TB_GETTEXTROWS");
6347 case WM_USER+41: return wxT("TB_GETBITMAPFLAGS");
c085e333 6348
42e69d6b 6349 default:
4a712ba3
VZ
6350 static wxString s_szBuf;
6351 s_szBuf.Printf(wxT("<unknown message = %d>"), message);
6352 return s_szBuf.c_str();
42e69d6b 6353 }
47cbd6da 6354}
ea57084d 6355#endif //__WXDEBUG__
4aff28fc 6356
1e6feb95 6357static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win)
f6bcfd97
BP
6358{
6359 // prepare the DC
6360 TEXTMETRIC tm;
6361 HWND hwnd = GetHwndOf(win);
6362 HDC hdc = ::GetDC(hwnd);
6363
6364#if !wxDIALOG_UNIT_COMPATIBILITY
6365 // and select the current font into it
6366 HFONT hfont = GetHfontOf(win->GetFont());
6367 if ( hfont )
6368 {
6369 hfont = (HFONT)::SelectObject(hdc, hfont);
6370 }
6371#endif
6372
6373 // finally retrieve the text metrics from it
6374 GetTextMetrics(hdc, &tm);
6375
6376#if !wxDIALOG_UNIT_COMPATIBILITY
6377 // and clean up
6378 if ( hfont )
6379 {
6380 (void)::SelectObject(hdc, hfont);
6381 }
6382#endif
6383
6384 ::ReleaseDC(hwnd, hdc);
6385
6386 return tm;
6387}
3723b7b1
JS
6388
6389// Find the wxWindow at the current mouse position, returning the mouse
6390// position.
2b5f62a0 6391wxWindow* wxFindWindowAtPointer(wxPoint& pt)
3723b7b1 6392{
2b5f62a0
VZ
6393 pt = wxGetMousePosition();
6394 return wxFindWindowAtPoint(pt);
57591e0e
JS
6395}
6396
6397wxWindow* wxFindWindowAtPoint(const wxPoint& pt)
6398{
6399 POINT pt2;
6400 pt2.x = pt.x;
6401 pt2.y = pt.y;
3723b7b1 6402
ab3eae34 6403 HWND hWnd = ::WindowFromPoint(pt2);
3723b7b1 6404
ab3eae34 6405 return wxGetWindowFromHWND((WXHWND)hWnd);
3723b7b1
JS
6406}
6407
6408// Get the current mouse position.
6409wxPoint wxGetMousePosition()
6410{
1772ead0 6411 POINT pt;
f2325516
JS
6412#ifdef __WXWINCE__
6413 GetCursorPosWinCE(&pt);
6414#else
1772ead0 6415 GetCursorPos( & pt );
f2325516 6416#endif
5cd16c0c 6417
1772ead0 6418 return wxPoint(pt.x, pt.y);
3723b7b1
JS
6419}
6420
5048c832 6421#if wxUSE_HOTKEY
540b6b09 6422
afafd942
JS
6423#if defined(__SMARTPHONE__) || defined(__POCKETPC__)
6424static void WinCEUnregisterHotKey(int modifiers, int id)
6425{
6426 // Register hotkeys for the hardware buttons
6427 HINSTANCE hCoreDll;
6428 typedef BOOL (WINAPI *UnregisterFunc1Proc)(UINT, UINT);
6429
6430 UnregisterFunc1Proc procUnregisterFunc;
6431 hCoreDll = LoadLibrary(_T("coredll.dll"));
6432 if (hCoreDll)
6433 {
6434 procUnregisterFunc = (UnregisterFunc1Proc)GetProcAddress(hCoreDll, _T("UnregisterFunc1"));
6435 if (procUnregisterFunc)
6436 procUnregisterFunc(modifiers, id);
6437 FreeLibrary(hCoreDll);
6438 }
6439}
6440#endif
6441
540b6b09 6442bool wxWindowMSW::RegisterHotKey(int hotkeyId, int modifiers, int keycode)
5048c832
JS
6443{
6444 UINT win_modifiers=0;
540b6b09
VZ
6445 if ( modifiers & wxMOD_ALT )
6446 win_modifiers |= MOD_ALT;
6447 if ( modifiers & wxMOD_SHIFT )
6448 win_modifiers |= MOD_SHIFT;
6449 if ( modifiers & wxMOD_CONTROL )
6450 win_modifiers |= MOD_CONTROL;
6451 if ( modifiers & wxMOD_WIN )
6452 win_modifiers |= MOD_WIN;
6453
afafd942
JS
6454#if defined(__SMARTPHONE__) || defined(__POCKETPC__)
6455 // Required for PPC and Smartphone hardware buttons
6456 if (keycode >= WXK_SPECIAL1 && keycode <= WXK_SPECIAL20)
6457 WinCEUnregisterHotKey(win_modifiers, hotkeyId);
6458#endif
6459
540b6b09
VZ
6460 if ( !::RegisterHotKey(GetHwnd(), hotkeyId, win_modifiers, keycode) )
6461 {
6462 wxLogLastError(_T("RegisterHotKey"));
5048c832 6463
08158721 6464 return false;
540b6b09
VZ
6465 }
6466
08158721 6467 return true;
5048c832
JS
6468}
6469
6470bool wxWindowMSW::UnregisterHotKey(int hotkeyId)
6471{
afafd942
JS
6472#if defined(__SMARTPHONE__) || defined(__POCKETPC__)
6473 WinCEUnregisterHotKey(MOD_WIN, hotkeyId);
6474#endif
6475
540b6b09
VZ
6476 if ( !::UnregisterHotKey(GetHwnd(), hotkeyId) )
6477 {
6478 wxLogLastError(_T("UnregisterHotKey"));
6479
08158721 6480 return false;
540b6b09
VZ
6481 }
6482
08158721 6483 return true;
5048c832
JS
6484}
6485
0b4f47a3
DS
6486#if wxUSE_ACCEL
6487
5048c832
JS
6488bool wxWindowMSW::HandleHotKey(WXWPARAM wParam, WXLPARAM lParam)
6489{
540b6b09
VZ
6490 int hotkeyId = wParam;
6491 int virtualKey = HIWORD(lParam);
6492 int win_modifiers = LOWORD(lParam);
6493
5048c832
JS
6494 wxKeyEvent event(CreateKeyEvent(wxEVT_HOTKEY, virtualKey, wParam, lParam));
6495 event.SetId(hotkeyId);
6496 event.m_shiftDown = (win_modifiers & MOD_SHIFT) != 0;
6497 event.m_controlDown = (win_modifiers & MOD_CONTROL) != 0;
6498 event.m_altDown = (win_modifiers & MOD_ALT) != 0;
6499 event.m_metaDown = (win_modifiers & MOD_WIN) != 0;
540b6b09
VZ
6500
6501 return GetEventHandler()->ProcessEvent(event);
5048c832 6502}
540b6b09 6503
0b4f47a3
DS
6504#endif // wxUSE_ACCEL
6505
540b6b09 6506#endif // wxUSE_HOTKEY
5048c832 6507
550049c2 6508// Not tested under WinCE
d79df32c 6509#ifndef __WXWINCE__
d79df32c 6510
550049c2
VZ
6511// this class installs a message hook which really wakes up our idle processing
6512// each time a WM_NULL is received (wxWakeUpIdle does this), even if we're
6513// sitting inside a local modal loop (e.g. a menu is opened or scrollbar is
6514// being dragged or even inside ::MessageBox()) and so don't control message
6515// dispatching otherwise
6516class wxIdleWakeUpModule : public wxModule
6517{
d79df32c 6518public:
3a3c8603 6519 virtual bool OnInit()
550049c2 6520 {
3a3c8603 6521 ms_hMsgHookProc = ::SetWindowsHookEx
550049c2
VZ
6522 (
6523 WH_GETMESSAGE,
6524 &wxIdleWakeUpModule::MsgHookProc,
6525 NULL,
6526 GetCurrentThreadId()
6527 );
d79df32c 6528
550049c2
VZ
6529 if ( !ms_hMsgHookProc )
6530 {
6531 wxLogLastError(_T("SetWindowsHookEx(WH_GETMESSAGE)"));
6532
6533 return false;
6534 }
6535
6536 return true;
3a3c8603 6537 }
550049c2 6538
3a3c8603 6539 virtual void OnExit()
550049c2 6540 {
3a3c8603
DS
6541 ::UnhookWindowsHookEx(wxIdleWakeUpModule::ms_hMsgHookProc);
6542 }
550049c2 6543
3a3c8603 6544 static LRESULT CALLBACK MsgHookProc(int nCode, WPARAM wParam, LPARAM lParam)
550049c2 6545 {
3a3c8603 6546 MSG *msg = (MSG*)lParam;
34ea3c74
VZ
6547
6548 // only process the message if it is actually going to be removed from
6549 // the message queue, this prevents that the same event from being
6550 // processed multiple times if now someone just called PeekMessage()
6551 if ( msg->message == WM_NULL && wParam == PM_REMOVE )
3a3c8603 6552 {
550049c2 6553 wxTheApp->ProcessPendingEvents();
3a3c8603 6554 }
550049c2 6555
3a3c8603
DS
6556 return CallNextHookEx(ms_hMsgHookProc, nCode, wParam, lParam);
6557 };
550049c2 6558
d79df32c 6559private:
3a3c8603 6560 static HHOOK ms_hMsgHookProc;
550049c2
VZ
6561
6562 DECLARE_DYNAMIC_CLASS(wxIdleWakeUpModule)
d79df32c 6563};
d79df32c 6564
550049c2
VZ
6565HHOOK wxIdleWakeUpModule::ms_hMsgHookProc = 0;
6566
6567IMPLEMENT_DYNAMIC_CLASS(wxIdleWakeUpModule, wxModule)
6568
6569#endif // __WXWINCE__
3a3c8603 6570
d26e1ab2
JS
6571#ifdef __WXWINCE__
6572
6573#if wxUSE_STATBOX
6574static void wxAdjustZOrder(wxWindow* parent)
6575{
6576 if (parent->IsKindOf(CLASSINFO(wxStaticBox)))
6577 {
6578 // Set the z-order correctly
6579 SetWindowPos((HWND) parent->GetHWND(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
6580 }
35bbb0c6 6581
d26e1ab2
JS
6582 wxWindowList::compatibility_iterator current = parent->GetChildren().GetFirst();
6583 while (current)
6584 {
6585 wxWindow *childWin = current->GetData();
6586 wxAdjustZOrder(childWin);
6587 current = current->GetNext();
6588 }
6589}
6590#endif
6591
6592// We need to adjust the z-order of static boxes in WinCE, to
6593// make 'contained' controls visible
6594void wxWindowMSW::OnInitDialog( wxInitDialogEvent& event )
6595{
6596#if wxUSE_STATBOX
6597 wxAdjustZOrder(this);
6598#endif
35bbb0c6 6599
d26e1ab2
JS
6600 event.Skip();
6601}
6602#endif