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