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