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