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