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