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