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