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