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