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