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