]> git.saurik.com Git - wxWidgets.git/blob - src/msw/window.cpp
Added EVT_MOVE_START, EVT_MOVE_END (wxMSW only for now)
[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_ENTERSIZEMOVE:
2547 {
2548 processed = HandleEnterSizeMove();
2549 }
2550 break;
2551
2552 case WM_EXITSIZEMOVE:
2553 {
2554 processed = HandleExitSizeMove();
2555 }
2556 break;
2557
2558 case WM_SIZING:
2559 {
2560 LPRECT pRect = (LPRECT)lParam;
2561 wxRect rc;
2562 rc.SetLeft(pRect->left);
2563 rc.SetTop(pRect->top);
2564 rc.SetRight(pRect->right);
2565 rc.SetBottom(pRect->bottom);
2566 processed = HandleSizing(rc);
2567 if (processed) {
2568 pRect->left = rc.GetLeft();
2569 pRect->top = rc.GetTop();
2570 pRect->right = rc.GetRight();
2571 pRect->bottom = rc.GetBottom();
2572 }
2573 }
2574 break;
2575 #endif // !__WXWINCE__
2576
2577 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
2578 case WM_ACTIVATEAPP:
2579 // This implicitly sends a wxEVT_ACTIVATE_APP event
2580 wxTheApp->SetActive(wParam != 0, FindFocus());
2581 break;
2582 #endif
2583
2584 case WM_ACTIVATE:
2585 {
2586 WXWORD state, minimized;
2587 WXHWND hwnd;
2588 UnpackActivate(wParam, lParam, &state, &minimized, &hwnd);
2589
2590 processed = HandleActivate(state, minimized != 0, (WXHWND)hwnd);
2591 }
2592 break;
2593
2594 case WM_SETFOCUS:
2595 processed = HandleSetFocus((WXHWND)(HWND)wParam);
2596 break;
2597
2598 case WM_KILLFOCUS:
2599 processed = HandleKillFocus((WXHWND)(HWND)wParam);
2600 break;
2601
2602 case WM_PRINTCLIENT:
2603 processed = HandlePrintClient((WXHDC)wParam);
2604 break;
2605
2606 case WM_PAINT:
2607 if ( wParam )
2608 {
2609 wxPaintDCEx dc((wxWindow *)this, (WXHDC)wParam);
2610
2611 processed = HandlePaint();
2612 }
2613 else // no DC given
2614 {
2615 processed = HandlePaint();
2616 }
2617 break;
2618
2619 case WM_CLOSE:
2620 #ifdef __WXUNIVERSAL__
2621 // Universal uses its own wxFrame/wxDialog, so we don't receive
2622 // close events unless we have this.
2623 Close();
2624 #endif // __WXUNIVERSAL__
2625
2626 // don't let the DefWindowProc() destroy our window - we'll do it
2627 // ourselves in ~wxWindow
2628 processed = true;
2629 rc.result = TRUE;
2630 break;
2631
2632 case WM_SHOWWINDOW:
2633 processed = HandleShow(wParam != 0, (int)lParam);
2634 break;
2635
2636 case WM_MOUSEMOVE:
2637 processed = HandleMouseMove(GET_X_LPARAM(lParam),
2638 GET_Y_LPARAM(lParam),
2639 wParam);
2640 break;
2641
2642 #ifdef HAVE_TRACKMOUSEEVENT
2643 case WM_MOUSELEAVE:
2644 // filter out excess WM_MOUSELEAVE events sent after PopupMenu()
2645 // (on XP at least)
2646 if ( m_mouseInWindow )
2647 {
2648 GenerateMouseLeave();
2649 }
2650
2651 // always pass processed back as false, this allows the window
2652 // manager to process the message too. This is needed to
2653 // ensure windows XP themes work properly as the mouse moves
2654 // over widgets like buttons. So don't set processed to true here.
2655 break;
2656 #endif // HAVE_TRACKMOUSEEVENT
2657
2658 #if wxUSE_MOUSEWHEEL
2659 case WM_MOUSEWHEEL:
2660 processed = HandleMouseWheel(wParam, lParam);
2661 break;
2662 #endif
2663
2664 case WM_LBUTTONDOWN:
2665 case WM_LBUTTONUP:
2666 case WM_LBUTTONDBLCLK:
2667 case WM_RBUTTONDOWN:
2668 case WM_RBUTTONUP:
2669 case WM_RBUTTONDBLCLK:
2670 case WM_MBUTTONDOWN:
2671 case WM_MBUTTONUP:
2672 case WM_MBUTTONDBLCLK:
2673 #ifdef wxHAS_XBUTTON
2674 case WM_XBUTTONDOWN:
2675 case WM_XBUTTONUP:
2676 case WM_XBUTTONDBLCLK:
2677 #endif // wxHAS_XBUTTON
2678 {
2679 #ifdef __WXMICROWIN__
2680 // MicroWindows seems to ignore the fact that a window is
2681 // disabled. So catch mouse events and throw them away if
2682 // necessary.
2683 wxWindowMSW* win = this;
2684 for ( ;; )
2685 {
2686 if (!win->IsEnabled())
2687 {
2688 processed = true;
2689 break;
2690 }
2691
2692 win = win->GetParent();
2693 if ( !win || win->IsTopLevel() )
2694 break;
2695 }
2696
2697 if ( processed )
2698 break;
2699
2700 #endif // __WXMICROWIN__
2701 int x = GET_X_LPARAM(lParam),
2702 y = GET_Y_LPARAM(lParam);
2703
2704 #ifdef __WXWINCE__
2705 // redirect the event to a static control if necessary by
2706 // finding one under mouse because under CE the static controls
2707 // don't generate mouse events (even with SS_NOTIFY)
2708 wxWindowMSW *win;
2709 if ( GetCapture() == this )
2710 {
2711 // but don't do it if the mouse is captured by this window
2712 // because then it should really get this event itself
2713 win = this;
2714 }
2715 else
2716 {
2717 win = FindWindowForMouseEvent(this, &x, &y);
2718
2719 // this should never happen
2720 wxCHECK_MSG( win, 0,
2721 _T("FindWindowForMouseEvent() returned NULL") );
2722 }
2723 #ifdef __POCKETPC__
2724 if (IsContextMenuEnabled() && message == WM_LBUTTONDOWN)
2725 {
2726 SHRGINFO shrgi = {0};
2727
2728 shrgi.cbSize = sizeof(SHRGINFO);
2729 shrgi.hwndClient = (HWND) GetHWND();
2730 shrgi.ptDown.x = x;
2731 shrgi.ptDown.y = y;
2732
2733 shrgi.dwFlags = SHRG_RETURNCMD;
2734 // shrgi.dwFlags = SHRG_NOTIFYPARENT;
2735
2736 if (GN_CONTEXTMENU == ::SHRecognizeGesture(&shrgi))
2737 {
2738 wxPoint pt(x, y);
2739 pt = ClientToScreen(pt);
2740
2741 wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt);
2742
2743 evtCtx.SetEventObject(this);
2744 if (GetEventHandler()->ProcessEvent(evtCtx))
2745 {
2746 processed = true;
2747 return true;
2748 }
2749 }
2750 }
2751 #endif
2752
2753 #else // !__WXWINCE__
2754 wxWindowMSW *win = this;
2755 #endif // __WXWINCE__/!__WXWINCE__
2756
2757 processed = win->HandleMouseEvent(message, x, y, wParam);
2758
2759 // if the app didn't eat the event, handle it in the default
2760 // way, that is by giving this window the focus
2761 if ( !processed )
2762 {
2763 // for the standard classes their WndProc sets the focus to
2764 // them anyhow and doing it from here results in some weird
2765 // problems, so don't do it for them (unnecessary anyhow)
2766 if ( !win->IsOfStandardClass() )
2767 {
2768 if ( message == WM_LBUTTONDOWN && win->IsFocusable() )
2769 win->SetFocus();
2770 }
2771 }
2772 }
2773 break;
2774
2775 #ifdef MM_JOY1MOVE
2776 case MM_JOY1MOVE:
2777 case MM_JOY2MOVE:
2778 case MM_JOY1ZMOVE:
2779 case MM_JOY2ZMOVE:
2780 case MM_JOY1BUTTONDOWN:
2781 case MM_JOY2BUTTONDOWN:
2782 case MM_JOY1BUTTONUP:
2783 case MM_JOY2BUTTONUP:
2784 processed = HandleJoystickEvent(message,
2785 GET_X_LPARAM(lParam),
2786 GET_Y_LPARAM(lParam),
2787 wParam);
2788 break;
2789 #endif // __WXMICROWIN__
2790
2791 case WM_COMMAND:
2792 {
2793 WORD id, cmd;
2794 WXHWND hwnd;
2795 UnpackCommand(wParam, lParam, &id, &hwnd, &cmd);
2796
2797 processed = HandleCommand(id, cmd, hwnd);
2798 }
2799 break;
2800
2801 case WM_NOTIFY:
2802 processed = HandleNotify((int)wParam, lParam, &rc.result);
2803 break;
2804
2805 // we only need to reply to WM_NOTIFYFORMAT manually when using MSLU,
2806 // otherwise DefWindowProc() does it perfectly fine for us, but MSLU
2807 // apparently doesn't always behave properly and needs some help
2808 #if wxUSE_UNICODE_MSLU && defined(NF_QUERY)
2809 case WM_NOTIFYFORMAT:
2810 if ( lParam == NF_QUERY )
2811 {
2812 processed = true;
2813 rc.result = NFR_UNICODE;
2814 }
2815 break;
2816 #endif // wxUSE_UNICODE_MSLU
2817
2818 // for these messages we must return true if process the message
2819 #ifdef WM_DRAWITEM
2820 case WM_DRAWITEM:
2821 case WM_MEASUREITEM:
2822 {
2823 int idCtrl = (UINT)wParam;
2824 if ( message == WM_DRAWITEM )
2825 {
2826 processed = MSWOnDrawItem(idCtrl,
2827 (WXDRAWITEMSTRUCT *)lParam);
2828 }
2829 else
2830 {
2831 processed = MSWOnMeasureItem(idCtrl,
2832 (WXMEASUREITEMSTRUCT *)lParam);
2833 }
2834
2835 if ( processed )
2836 rc.result = TRUE;
2837 }
2838 break;
2839 #endif // defined(WM_DRAWITEM)
2840
2841 case WM_GETDLGCODE:
2842 if ( !IsOfStandardClass() || HasFlag(wxWANTS_CHARS) )
2843 {
2844 // we always want to get the char events
2845 rc.result = DLGC_WANTCHARS;
2846
2847 if ( HasFlag(wxWANTS_CHARS) )
2848 {
2849 // in fact, we want everything
2850 rc.result |= DLGC_WANTARROWS |
2851 DLGC_WANTTAB |
2852 DLGC_WANTALLKEYS;
2853 }
2854
2855 processed = true;
2856 }
2857 //else: get the dlg code from the DefWindowProc()
2858 break;
2859
2860 case WM_SYSKEYDOWN:
2861 case WM_KEYDOWN:
2862 // If this has been processed by an event handler, return 0 now
2863 // (we've handled it).
2864 m_lastKeydownProcessed = HandleKeyDown((WORD) wParam, lParam);
2865 if ( m_lastKeydownProcessed )
2866 {
2867 processed = true;
2868 }
2869
2870 if ( !processed )
2871 {
2872 switch ( wParam )
2873 {
2874 // we consider these messages "not interesting" to OnChar, so
2875 // just don't do anything more with them
2876 case VK_SHIFT:
2877 case VK_CONTROL:
2878 case VK_MENU:
2879 case VK_CAPITAL:
2880 case VK_NUMLOCK:
2881 case VK_SCROLL:
2882 processed = true;
2883 break;
2884
2885 // avoid duplicate messages to OnChar for these ASCII keys:
2886 // they will be translated by TranslateMessage() and received
2887 // in WM_CHAR
2888 case VK_ESCAPE:
2889 case VK_SPACE:
2890 case VK_RETURN:
2891 case VK_BACK:
2892 case VK_TAB:
2893 case VK_ADD:
2894 case VK_SUBTRACT:
2895 case VK_MULTIPLY:
2896 case VK_DIVIDE:
2897 case VK_NUMPAD0:
2898 case VK_NUMPAD1:
2899 case VK_NUMPAD2:
2900 case VK_NUMPAD3:
2901 case VK_NUMPAD4:
2902 case VK_NUMPAD5:
2903 case VK_NUMPAD6:
2904 case VK_NUMPAD7:
2905 case VK_NUMPAD8:
2906 case VK_NUMPAD9:
2907 case VK_OEM_1:
2908 case VK_OEM_2:
2909 case VK_OEM_3:
2910 case VK_OEM_4:
2911 case VK_OEM_5:
2912 case VK_OEM_6:
2913 case VK_OEM_7:
2914 case VK_OEM_PLUS:
2915 case VK_OEM_COMMA:
2916 case VK_OEM_MINUS:
2917 case VK_OEM_PERIOD:
2918 // but set processed to false, not true to still pass them
2919 // to the control's default window proc - otherwise
2920 // built-in keyboard handling won't work
2921 processed = false;
2922 break;
2923
2924 #ifdef VK_APPS
2925 // special case of VK_APPS: treat it the same as right mouse
2926 // click because both usually pop up a context menu
2927 case VK_APPS:
2928 processed = HandleMouseEvent(WM_RBUTTONDOWN, -1, -1, 0);
2929 break;
2930 #endif // VK_APPS
2931
2932 default:
2933 // do generate a CHAR event
2934 processed = HandleChar((WORD)wParam, lParam);
2935 }
2936 }
2937 if (message == WM_SYSKEYDOWN) // Let Windows still handle the SYSKEYs
2938 processed = false;
2939 break;
2940
2941 case WM_SYSKEYUP:
2942 case WM_KEYUP:
2943 #ifdef VK_APPS
2944 // special case of VK_APPS: treat it the same as right mouse button
2945 if ( wParam == VK_APPS )
2946 {
2947 processed = HandleMouseEvent(WM_RBUTTONUP, -1, -1, 0);
2948 }
2949 else
2950 #endif // VK_APPS
2951 {
2952 processed = HandleKeyUp((WORD) wParam, lParam);
2953 }
2954 break;
2955
2956 case WM_SYSCHAR:
2957 case WM_CHAR: // Always an ASCII character
2958 if ( m_lastKeydownProcessed )
2959 {
2960 // The key was handled in the EVT_KEY_DOWN and handling
2961 // a key in an EVT_KEY_DOWN handler is meant, by
2962 // design, to prevent EVT_CHARs from happening
2963 m_lastKeydownProcessed = false;
2964 processed = true;
2965 }
2966 else
2967 {
2968 processed = HandleChar((WORD)wParam, lParam, true);
2969 }
2970 break;
2971
2972 #if wxUSE_HOTKEY
2973 case WM_HOTKEY:
2974 processed = HandleHotKey((WORD)wParam, lParam);
2975 break;
2976 #endif // wxUSE_HOTKEY
2977
2978 case WM_HSCROLL:
2979 case WM_VSCROLL:
2980 {
2981 WXWORD code, pos;
2982 WXHWND hwnd;
2983 UnpackScroll(wParam, lParam, &code, &pos, &hwnd);
2984
2985 processed = MSWOnScroll(message == WM_HSCROLL ? wxHORIZONTAL
2986 : wxVERTICAL,
2987 code, pos, hwnd);
2988 }
2989 break;
2990
2991 // CTLCOLOR messages are sent by children to query the parent for their
2992 // colors
2993 #ifndef __WXMICROWIN__
2994 case WM_CTLCOLORMSGBOX:
2995 case WM_CTLCOLOREDIT:
2996 case WM_CTLCOLORLISTBOX:
2997 case WM_CTLCOLORBTN:
2998 case WM_CTLCOLORDLG:
2999 case WM_CTLCOLORSCROLLBAR:
3000 case WM_CTLCOLORSTATIC:
3001 {
3002 WXHDC hdc;
3003 WXHWND hwnd;
3004 UnpackCtlColor(wParam, lParam, &hdc, &hwnd);
3005
3006 processed = HandleCtlColor(&rc.hBrush, (WXHDC)hdc, (WXHWND)hwnd);
3007 }
3008 break;
3009 #endif // !__WXMICROWIN__
3010
3011 case WM_SYSCOLORCHANGE:
3012 // the return value for this message is ignored
3013 processed = HandleSysColorChange();
3014 break;
3015
3016 #if !defined(__WXWINCE__)
3017 case WM_DISPLAYCHANGE:
3018 processed = HandleDisplayChange();
3019 break;
3020 #endif
3021
3022 case WM_PALETTECHANGED:
3023 processed = HandlePaletteChanged((WXHWND) (HWND) wParam);
3024 break;
3025
3026 case WM_CAPTURECHANGED:
3027 processed = HandleCaptureChanged((WXHWND) (HWND) lParam);
3028 break;
3029
3030 case WM_SETTINGCHANGE:
3031 processed = HandleSettingChange(wParam, lParam);
3032 break;
3033
3034 case WM_QUERYNEWPALETTE:
3035 processed = HandleQueryNewPalette();
3036 break;
3037
3038 case WM_ERASEBKGND:
3039 processed = HandleEraseBkgnd((WXHDC)(HDC)wParam);
3040 if ( processed )
3041 {
3042 // we processed the message, i.e. erased the background
3043 rc.result = TRUE;
3044 }
3045 break;
3046
3047 #if !defined(__WXWINCE__)
3048 case WM_DROPFILES:
3049 processed = HandleDropFiles(wParam);
3050 break;
3051 #endif
3052
3053 case WM_INITDIALOG:
3054 processed = HandleInitDialog((WXHWND)(HWND)wParam);
3055
3056 if ( processed )
3057 {
3058 // we never set focus from here
3059 rc.result = FALSE;
3060 }
3061 break;
3062
3063 #if !defined(__WXWINCE__)
3064 case WM_QUERYENDSESSION:
3065 processed = HandleQueryEndSession(lParam, &rc.allow);
3066 break;
3067
3068 case WM_ENDSESSION:
3069 processed = HandleEndSession(wParam != 0, lParam);
3070 break;
3071
3072 case WM_GETMINMAXINFO:
3073 processed = HandleGetMinMaxInfo((MINMAXINFO*)lParam);
3074 break;
3075 #endif
3076
3077 case WM_SETCURSOR:
3078 processed = HandleSetCursor((WXHWND)(HWND)wParam,
3079 LOWORD(lParam), // hit test
3080 HIWORD(lParam)); // mouse msg
3081
3082 if ( processed )
3083 {
3084 // returning TRUE stops the DefWindowProc() from further
3085 // processing this message - exactly what we need because we've
3086 // just set the cursor.
3087 rc.result = TRUE;
3088 }
3089 break;
3090
3091 #if wxUSE_ACCESSIBILITY
3092 case WM_GETOBJECT:
3093 {
3094 //WPARAM dwFlags = (WPARAM) (DWORD) wParam;
3095 LPARAM dwObjId = (LPARAM) (DWORD) lParam;
3096
3097 if (dwObjId == (LPARAM)OBJID_CLIENT && GetOrCreateAccessible())
3098 {
3099 return LresultFromObject(IID_IAccessible, wParam, (IUnknown*) GetAccessible()->GetIAccessible());
3100 }
3101 break;
3102 }
3103 #endif
3104
3105 #if defined(WM_HELP)
3106 case WM_HELP:
3107 {
3108 // by default, WM_HELP is propagated by DefWindowProc() upwards
3109 // to the window parent but as we do it ourselves already
3110 // (wxHelpEvent is derived from wxCommandEvent), we don't want
3111 // to get the other events if we process this message at all
3112 processed = true;
3113
3114 // WM_HELP doesn't use lParam under CE
3115 #ifndef __WXWINCE__
3116 HELPINFO* info = (HELPINFO*) lParam;
3117 if ( info->iContextType == HELPINFO_WINDOW )
3118 {
3119 #endif // !__WXWINCE__
3120 wxHelpEvent helpEvent
3121 (
3122 wxEVT_HELP,
3123 GetId(),
3124 #ifdef __WXWINCE__
3125 wxGetMousePosition() // what else?
3126 #else
3127 wxPoint(info->MousePos.x, info->MousePos.y)
3128 #endif
3129 );
3130
3131 helpEvent.SetEventObject(this);
3132 GetEventHandler()->ProcessEvent(helpEvent);
3133 #ifndef __WXWINCE__
3134 }
3135 else if ( info->iContextType == HELPINFO_MENUITEM )
3136 {
3137 wxHelpEvent helpEvent(wxEVT_HELP, info->iCtrlId);
3138 helpEvent.SetEventObject(this);
3139 GetEventHandler()->ProcessEvent(helpEvent);
3140
3141 }
3142 else // unknown help event?
3143 {
3144 processed = false;
3145 }
3146 #endif // !__WXWINCE__
3147 }
3148 break;
3149 #endif // WM_HELP
3150
3151 #if !defined(__WXWINCE__)
3152 case WM_CONTEXTMENU:
3153 {
3154 // we don't convert from screen to client coordinates as
3155 // the event may be handled by a parent window
3156 wxPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
3157
3158 wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt);
3159
3160 // we could have got an event from our child, reflect it back
3161 // to it if this is the case
3162 wxWindowMSW *win = NULL;
3163 if ( (WXHWND)wParam != m_hWnd )
3164 {
3165 win = FindItemByHWND((WXHWND)wParam);
3166 }
3167
3168 if ( !win )
3169 win = this;
3170
3171 evtCtx.SetEventObject(win);
3172 processed = win->GetEventHandler()->ProcessEvent(evtCtx);
3173 }
3174 break;
3175 #endif
3176
3177 #if wxUSE_MENUS
3178 case WM_MENUCHAR:
3179 // we're only interested in our own menus, not MF_SYSMENU
3180 if ( HIWORD(wParam) == MF_POPUP )
3181 {
3182 // handle menu chars for ownerdrawn menu items
3183 int i = HandleMenuChar(toupper(LOWORD(wParam)), lParam);
3184 if ( i != wxNOT_FOUND )
3185 {
3186 rc.result = MAKELRESULT(i, MNC_EXECUTE);
3187 processed = true;
3188 }
3189 }
3190 break;
3191 #endif // wxUSE_MENUS
3192
3193 #ifndef __WXWINCE__
3194 case WM_POWERBROADCAST:
3195 {
3196 bool vetoed;
3197 processed = HandlePower(wParam, lParam, &vetoed);
3198 rc.result = processed && vetoed ? BROADCAST_QUERY_DENY : TRUE;
3199 }
3200 break;
3201 #endif // __WXWINCE__
3202
3203 default:
3204 // try a custom message handler
3205 const MSWMessageHandlers::const_iterator
3206 i = gs_messageHandlers.find(message);
3207 if ( i != gs_messageHandlers.end() )
3208 {
3209 processed = (*i->second)(this, message, wParam, lParam);
3210 }
3211 }
3212
3213 if ( !processed )
3214 {
3215 #ifdef __WXDEBUG__
3216 wxLogTrace(wxTraceMessages, wxT("Forwarding %s to DefWindowProc."),
3217 wxGetMessageName(message));
3218 #endif // __WXDEBUG__
3219 rc.result = MSWDefWindowProc(message, wParam, lParam);
3220 }
3221
3222 return rc.result;
3223 }
3224
3225 // ----------------------------------------------------------------------------
3226 // wxWindow <-> HWND map
3227 // ----------------------------------------------------------------------------
3228
3229 wxWinHashTable *wxWinHandleHash = NULL;
3230
3231 wxWindow *wxFindWinFromHandle(WXHWND hWnd)
3232 {
3233 return (wxWindow*)wxWinHandleHash->Get((long)hWnd);
3234 }
3235
3236 void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win)
3237 {
3238 // adding NULL hWnd is (first) surely a result of an error and
3239 // (secondly) breaks menu command processing
3240 wxCHECK_RET( hWnd != (HWND)NULL,
3241 wxT("attempt to add a NULL hWnd to window list ignored") );
3242
3243 wxWindow *oldWin = wxFindWinFromHandle((WXHWND) hWnd);
3244 #ifdef __WXDEBUG__
3245 if ( oldWin && (oldWin != win) )
3246 {
3247 wxLogDebug(wxT("HWND %X already associated with another window (%s)"),
3248 (int) hWnd, win->GetClassInfo()->GetClassName());
3249 }
3250 else
3251 #endif // __WXDEBUG__
3252 if (!oldWin)
3253 {
3254 wxWinHandleHash->Put((long)hWnd, (wxWindow *)win);
3255 }
3256 }
3257
3258 void wxRemoveHandleAssociation(wxWindowMSW *win)
3259 {
3260 wxWinHandleHash->Delete((long)win->GetHWND());
3261 }
3262
3263 // ----------------------------------------------------------------------------
3264 // various MSW speciic class dependent functions
3265 // ----------------------------------------------------------------------------
3266
3267 // Default destroyer - override if you destroy it in some other way
3268 // (e.g. with MDI child windows)
3269 void wxWindowMSW::MSWDestroyWindow()
3270 {
3271 }
3272
3273 bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
3274 const wxSize& size,
3275 int& x, int& y,
3276 int& w, int& h) const
3277 {
3278 // yes, those are just some arbitrary hardcoded numbers
3279 static const int DEFAULT_Y = 200;
3280
3281 bool nonDefault = false;
3282
3283 if ( pos.x == wxDefaultCoord )
3284 {
3285 // if x is set to CW_USEDEFAULT, y parameter is ignored anyhow so we
3286 // can just as well set it to CW_USEDEFAULT as well
3287 x =
3288 y = CW_USEDEFAULT;
3289 }
3290 else
3291 {
3292 // OTOH, if x is not set to CW_USEDEFAULT, y shouldn't be set to it
3293 // neither because it is not handled as a special value by Windows then
3294 // and so we have to choose some default value for it
3295 x = pos.x;
3296 y = pos.y == wxDefaultCoord ? DEFAULT_Y : pos.y;
3297
3298 nonDefault = true;
3299 }
3300
3301 /*
3302 NB: there used to be some code here which set the initial size of the
3303 window to the client size of the parent if no explicit size was
3304 specified. This was wrong because wxWidgets programs often assume
3305 that they get a WM_SIZE (EVT_SIZE) upon creation, however this broke
3306 it. To see why, you should understand that Windows sends WM_SIZE from
3307 inside ::CreateWindow() anyhow. However, ::CreateWindow() is called
3308 from some base class ctor and so this WM_SIZE is not processed in the
3309 real class' OnSize() (because it's not fully constructed yet and the
3310 event goes to some base class OnSize() instead). So the WM_SIZE we
3311 rely on is the one sent when the parent frame resizes its children
3312 but here is the problem: if the child already has just the right
3313 size, nothing will happen as both wxWidgets and Windows check for
3314 this and ignore any attempts to change the window size to the size it
3315 already has - so no WM_SIZE would be sent.
3316 */
3317
3318
3319 // we don't use CW_USEDEFAULT here for several reasons:
3320 //
3321 // 1. it results in huge frames on modern screens (1000*800 is not
3322 // uncommon on my 1280*1024 screen) which is way too big for a half
3323 // empty frame of most of wxWidgets samples for example)
3324 //
3325 // 2. it is buggy for frames with wxFRAME_TOOL_WINDOW style for which
3326 // the default is for whatever reason 8*8 which breaks client <->
3327 // window size calculations (it would be nice if it didn't, but it
3328 // does and the simplest way to fix it seemed to change the broken
3329 // default size anyhow)
3330 //
3331 // 3. there is just no advantage in doing it: with x and y it is
3332 // possible that [future versions of] Windows position the new top
3333 // level window in some smart way which we can't do, but we can
3334 // guess a reasonably good size for a new window just as well
3335 // ourselves
3336
3337 // However, on PocketPC devices, we must use the default
3338 // size if possible.
3339 #ifdef _WIN32_WCE
3340 if (size.x == wxDefaultCoord)
3341 w = CW_USEDEFAULT;
3342 else
3343 w = size.x;
3344 if (size.y == wxDefaultCoord)
3345 h = CW_USEDEFAULT;
3346 else
3347 h = size.y;
3348 #else
3349 if ( size.x == wxDefaultCoord || size.y == wxDefaultCoord)
3350 {
3351 nonDefault = true;
3352 }
3353 w = WidthDefault(size.x);
3354 h = HeightDefault(size.y);
3355 #endif
3356
3357 AdjustForParentClientOrigin(x, y);
3358
3359 return nonDefault;
3360 }
3361
3362 WXHWND wxWindowMSW::MSWGetParent() const
3363 {
3364 return m_parent ? m_parent->GetHWND() : WXHWND(NULL);
3365 }
3366
3367 bool wxWindowMSW::MSWCreate(const wxChar *wclass,
3368 const wxChar *title,
3369 const wxPoint& pos,
3370 const wxSize& size,
3371 WXDWORD style,
3372 WXDWORD extendedStyle)
3373 {
3374 // choose the position/size for the new window
3375 int x, y, w, h;
3376 (void)MSWGetCreateWindowCoords(pos, size, x, y, w, h);
3377
3378 // controlId is menu handle for the top level windows, so set it to 0
3379 // unless we're creating a child window
3380 int controlId = style & WS_CHILD ? GetId() : 0;
3381
3382 // for each class "Foo" we have we also have "FooNR" ("no repaint") class
3383 // which is the same but without CS_[HV]REDRAW class styles so using it
3384 // ensures that the window is not fully repainted on each resize
3385 wxString className(wclass);
3386 if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) )
3387 {
3388 className += wxT("NR");
3389 }
3390
3391 // do create the window
3392 wxWindowCreationHook hook(this);
3393
3394 m_hWnd = (WXHWND)::CreateWindowEx
3395 (
3396 extendedStyle,
3397 className.wx_str(),
3398 title ? title : m_windowName.wx_str(),
3399 style,
3400 x, y, w, h,
3401 (HWND)MSWGetParent(),
3402 (HMENU)controlId,
3403 wxGetInstance(),
3404 NULL // no extra data
3405 );
3406
3407 if ( !m_hWnd )
3408 {
3409 wxLogSysError(_("Can't create window of class %s"), className.c_str());
3410
3411 return false;
3412 }
3413
3414 SubclassWin(m_hWnd);
3415
3416 return true;
3417 }
3418
3419 // ===========================================================================
3420 // MSW message handlers
3421 // ===========================================================================
3422
3423 // ---------------------------------------------------------------------------
3424 // WM_NOTIFY
3425 // ---------------------------------------------------------------------------
3426
3427 bool wxWindowMSW::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
3428 {
3429 #ifndef __WXMICROWIN__
3430 LPNMHDR hdr = (LPNMHDR)lParam;
3431 HWND hWnd = hdr->hwndFrom;
3432 wxWindow *win = wxFindWinFromHandle((WXHWND)hWnd);
3433
3434 // if the control is one of our windows, let it handle the message itself
3435 if ( win )
3436 {
3437 return win->MSWOnNotify(idCtrl, lParam, result);
3438 }
3439
3440 // VZ: why did we do it? normally this is unnecessary and, besides, it
3441 // breaks the message processing for the toolbars because the tooltip
3442 // notifications were being forwarded to the toolbar child controls
3443 // (if it had any) before being passed to the toolbar itself, so in my
3444 // example the tooltip for the combobox was always shown instead of the
3445 // correct button tooltips
3446 #if 0
3447 // try all our children
3448 wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
3449 while ( node )
3450 {
3451 wxWindow *child = node->GetData();
3452 if ( child->MSWOnNotify(idCtrl, lParam, result) )
3453 {
3454 return true;
3455 }
3456
3457 node = node->GetNext();
3458 }
3459 #endif // 0
3460
3461 // by default, handle it ourselves
3462 return MSWOnNotify(idCtrl, lParam, result);
3463 #else // __WXMICROWIN__
3464 return false;
3465 #endif
3466 }
3467
3468 #if wxUSE_TOOLTIPS
3469
3470 bool wxWindowMSW::HandleTooltipNotify(WXUINT code,
3471 WXLPARAM lParam,
3472 const wxString& ttip)
3473 {
3474 // I don't know why it happens, but the versions of comctl32.dll starting
3475 // from 4.70 sometimes send TTN_NEEDTEXTW even to ANSI programs (normally,
3476 // this message is supposed to be sent to Unicode programs only) -- hence
3477 // we need to handle it as well, otherwise no tooltips will be shown in
3478 // this case
3479 #ifndef __WXWINCE__
3480 if ( !(code == (WXUINT) TTN_NEEDTEXTA || code == (WXUINT) TTN_NEEDTEXTW)
3481 || ttip.empty() )
3482 {
3483 // not a tooltip message or no tooltip to show anyhow
3484 return false;
3485 }
3486 #endif
3487
3488 LPTOOLTIPTEXT ttText = (LPTOOLTIPTEXT)lParam;
3489
3490 // We don't want to use the szText buffer because it has a limit of 80
3491 // bytes and this is not enough, especially for Unicode build where it
3492 // limits the tooltip string length to only 40 characters
3493 //
3494 // The best would be, of course, to not impose any length limitations at
3495 // all but then the buffer would have to be dynamic and someone would have
3496 // to free it and we don't have the tooltip owner object here any more, so
3497 // for now use our own static buffer with a higher fixed max length.
3498 //
3499 // Note that using a static buffer should not be a problem as only a single
3500 // tooltip can be shown at the same time anyhow.
3501 #if !wxUSE_UNICODE
3502 if ( code == (WXUINT) TTN_NEEDTEXTW )
3503 {
3504 // We need to convert tooltip from multi byte to Unicode on the fly.
3505 static wchar_t buf[513];
3506
3507 // Truncate tooltip length if needed as otherwise we might not have
3508 // enough space for it in the buffer and MultiByteToWideChar() would
3509 // return an error
3510 size_t tipLength = wxMin(ttip.length(), WXSIZEOF(buf) - 1);
3511
3512 // Convert to WideChar without adding the NULL character. The NULL
3513 // character is added afterwards (this is more efficient).
3514 int len = ::MultiByteToWideChar
3515 (
3516 CP_ACP,
3517 0, // no flags
3518 ttip.wx_str(),
3519 tipLength,
3520 buf,
3521 WXSIZEOF(buf) - 1
3522 );
3523
3524 if ( !len )
3525 {
3526 wxLogLastError(_T("MultiByteToWideChar()"));
3527 }
3528
3529 buf[len] = L'\0';
3530 ttText->lpszText = (LPSTR) buf;
3531 }
3532 else // TTN_NEEDTEXTA
3533 #endif // !wxUSE_UNICODE
3534 {
3535 // we get here if we got TTN_NEEDTEXTA (only happens in ANSI build) or
3536 // if we got TTN_NEEDTEXTW in Unicode build: in this case we just have
3537 // to copy the string we have into the buffer
3538 static wxChar buf[513];
3539 wxStrncpy(buf, ttip.c_str(), WXSIZEOF(buf) - 1);
3540 buf[WXSIZEOF(buf) - 1] = _T('\0');
3541 ttText->lpszText = buf;
3542 }
3543
3544 return true;
3545 }
3546
3547 #endif // wxUSE_TOOLTIPS
3548
3549 bool wxWindowMSW::MSWOnNotify(int WXUNUSED(idCtrl),
3550 WXLPARAM lParam,
3551 WXLPARAM* WXUNUSED(result))
3552 {
3553 #if wxUSE_TOOLTIPS
3554 if ( m_tooltip )
3555 {
3556 NMHDR* hdr = (NMHDR *)lParam;
3557 if ( HandleTooltipNotify(hdr->code, lParam, m_tooltip->GetTip()))
3558 {
3559 // processed
3560 return true;
3561 }
3562 }
3563 #else
3564 wxUnusedVar(lParam);
3565 #endif // wxUSE_TOOLTIPS
3566
3567 return false;
3568 }
3569
3570 // ---------------------------------------------------------------------------
3571 // end session messages
3572 // ---------------------------------------------------------------------------
3573
3574 bool wxWindowMSW::HandleQueryEndSession(long logOff, bool *mayEnd)
3575 {
3576 #ifdef ENDSESSION_LOGOFF
3577 wxCloseEvent event(wxEVT_QUERY_END_SESSION, wxID_ANY);
3578 event.SetEventObject(wxTheApp);
3579 event.SetCanVeto(true);
3580 event.SetLoggingOff(logOff == (long)ENDSESSION_LOGOFF);
3581
3582 bool rc = wxTheApp->ProcessEvent(event);
3583
3584 if ( rc )
3585 {
3586 // we may end only if the app didn't veto session closing (double
3587 // negation...)
3588 *mayEnd = !event.GetVeto();
3589 }
3590
3591 return rc;
3592 #else
3593 wxUnusedVar(logOff);
3594 wxUnusedVar(mayEnd);
3595 return false;
3596 #endif
3597 }
3598
3599 bool wxWindowMSW::HandleEndSession(bool endSession, long logOff)
3600 {
3601 #ifdef ENDSESSION_LOGOFF
3602 // do nothing if the session isn't ending
3603 if ( !endSession )
3604 return false;
3605
3606 // only send once
3607 if ( (this != wxTheApp->GetTopWindow()) )
3608 return false;
3609
3610 wxCloseEvent event(wxEVT_END_SESSION, wxID_ANY);
3611 event.SetEventObject(wxTheApp);
3612 event.SetCanVeto(false);
3613 event.SetLoggingOff( (logOff == (long)ENDSESSION_LOGOFF) );
3614
3615 return wxTheApp->ProcessEvent(event);
3616 #else
3617 wxUnusedVar(endSession);
3618 wxUnusedVar(logOff);
3619 return false;
3620 #endif
3621 }
3622
3623 // ---------------------------------------------------------------------------
3624 // window creation/destruction
3625 // ---------------------------------------------------------------------------
3626
3627 bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT WXUNUSED_IN_WINCE(cs),
3628 bool *mayCreate)
3629 {
3630 // VZ: why is this commented out for WinCE? If it doesn't support
3631 // WS_EX_CONTROLPARENT at all it should be somehow handled globally,
3632 // not with multiple #ifdef's!
3633 #ifndef __WXWINCE__
3634 if ( ((CREATESTRUCT *)cs)->dwExStyle & WS_EX_CONTROLPARENT )
3635 EnsureParentHasControlParentStyle(GetParent());
3636 #endif // !__WXWINCE__
3637
3638 *mayCreate = true;
3639
3640 return true;
3641 }
3642
3643 bool wxWindowMSW::HandleDestroy()
3644 {
3645 SendDestroyEvent();
3646
3647 // delete our drop target if we've got one
3648 #if wxUSE_DRAG_AND_DROP
3649 if ( m_dropTarget != NULL )
3650 {
3651 m_dropTarget->Revoke(m_hWnd);
3652
3653 delete m_dropTarget;
3654 m_dropTarget = NULL;
3655 }
3656 #endif // wxUSE_DRAG_AND_DROP
3657
3658 // WM_DESTROY handled
3659 return true;
3660 }
3661
3662 // ---------------------------------------------------------------------------
3663 // activation/focus
3664 // ---------------------------------------------------------------------------
3665
3666 bool wxWindowMSW::HandleActivate(int state,
3667 bool WXUNUSED(minimized),
3668 WXHWND WXUNUSED(activate))
3669 {
3670 wxActivateEvent event(wxEVT_ACTIVATE,
3671 (state == WA_ACTIVE) || (state == WA_CLICKACTIVE),
3672 m_windowId);
3673 event.SetEventObject(this);
3674
3675 return GetEventHandler()->ProcessEvent(event);
3676 }
3677
3678 bool wxWindowMSW::HandleSetFocus(WXHWND hwnd)
3679 {
3680 // Strangly enough, some controls get set focus events when they are being
3681 // deleted, even if they already had focus before.
3682 if ( m_isBeingDeleted )
3683 {
3684 return false;
3685 }
3686
3687 // notify the parent keeping track of focus for the kbd navigation
3688 // purposes that we got it
3689 wxChildFocusEvent eventFocus((wxWindow *)this);
3690 (void)GetEventHandler()->ProcessEvent(eventFocus);
3691
3692 #if wxUSE_CARET
3693 // Deal with caret
3694 if ( m_caret )
3695 {
3696 m_caret->OnSetFocus();
3697 }
3698 #endif // wxUSE_CARET
3699
3700 #if wxUSE_TEXTCTRL
3701 // If it's a wxTextCtrl don't send the event as it will be done
3702 // after the control gets to process it from EN_FOCUS handler
3703 if ( wxDynamicCastThis(wxTextCtrl) )
3704 {
3705 return false;
3706 }
3707 #endif // wxUSE_TEXTCTRL
3708
3709 wxFocusEvent event(wxEVT_SET_FOCUS, m_windowId);
3710 event.SetEventObject(this);
3711
3712 // wxFindWinFromHandle() may return NULL, it is ok
3713 event.SetWindow(wxFindWinFromHandle(hwnd));
3714
3715 return GetEventHandler()->ProcessEvent(event);
3716 }
3717
3718 bool wxWindowMSW::HandleKillFocus(WXHWND hwnd)
3719 {
3720 #if wxUSE_CARET
3721 // Deal with caret
3722 if ( m_caret )
3723 {
3724 m_caret->OnKillFocus();
3725 }
3726 #endif // wxUSE_CARET
3727
3728 #if wxUSE_TEXTCTRL
3729 // If it's a wxTextCtrl don't send the event as it will be done
3730 // after the control gets to process it.
3731 wxTextCtrl *ctrl = wxDynamicCastThis(wxTextCtrl);
3732 if ( ctrl )
3733 {
3734 return false;
3735 }
3736 #endif
3737
3738 // Don't send the event when in the process of being deleted. This can
3739 // only cause problems if the event handler tries to access the object.
3740 if ( m_isBeingDeleted )
3741 {
3742 return false;
3743 }
3744
3745 wxFocusEvent event(wxEVT_KILL_FOCUS, m_windowId);
3746 event.SetEventObject(this);
3747
3748 // wxFindWinFromHandle() may return NULL, it is ok
3749 event.SetWindow(wxFindWinFromHandle(hwnd));
3750
3751 return GetEventHandler()->ProcessEvent(event);
3752 }
3753
3754 // ---------------------------------------------------------------------------
3755 // labels
3756 // ---------------------------------------------------------------------------
3757
3758 void wxWindowMSW::SetLabel( const wxString& label)
3759 {
3760 SetWindowText(GetHwnd(), label.c_str());
3761 }
3762
3763 wxString wxWindowMSW::GetLabel() const
3764 {
3765 return wxGetWindowText(GetHWND());
3766 }
3767
3768 // ---------------------------------------------------------------------------
3769 // miscellaneous
3770 // ---------------------------------------------------------------------------
3771
3772 bool wxWindowMSW::HandleShow(bool show, int WXUNUSED(status))
3773 {
3774 wxShowEvent event(GetId(), show);
3775 event.SetEventObject(this);
3776
3777 return GetEventHandler()->ProcessEvent(event);
3778 }
3779
3780 bool wxWindowMSW::HandleInitDialog(WXHWND WXUNUSED(hWndFocus))
3781 {
3782 wxInitDialogEvent event(GetId());
3783 event.SetEventObject(this);
3784
3785 return GetEventHandler()->ProcessEvent(event);
3786 }
3787
3788 bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam)
3789 {
3790 #if defined (__WXMICROWIN__) || defined(__WXWINCE__)
3791 wxUnusedVar(wParam);
3792 return false;
3793 #else // __WXMICROWIN__
3794 HDROP hFilesInfo = (HDROP) wParam;
3795
3796 // Get the total number of files dropped
3797 UINT gwFilesDropped = ::DragQueryFile
3798 (
3799 (HDROP)hFilesInfo,
3800 (UINT)-1,
3801 (LPTSTR)0,
3802 (UINT)0
3803 );
3804
3805 wxString *files = new wxString[gwFilesDropped];
3806 for ( UINT wIndex = 0; wIndex < gwFilesDropped; wIndex++ )
3807 {
3808 // first get the needed buffer length (+1 for terminating NUL)
3809 size_t len = ::DragQueryFile(hFilesInfo, wIndex, NULL, 0) + 1;
3810
3811 // and now get the file name
3812 ::DragQueryFile(hFilesInfo, wIndex,
3813 wxStringBuffer(files[wIndex], len), len);
3814 }
3815 DragFinish (hFilesInfo);
3816
3817 wxDropFilesEvent event(wxEVT_DROP_FILES, gwFilesDropped, files);
3818 event.SetEventObject(this);
3819
3820 POINT dropPoint;
3821 DragQueryPoint(hFilesInfo, (LPPOINT) &dropPoint);
3822 event.m_pos.x = dropPoint.x;
3823 event.m_pos.y = dropPoint.y;
3824
3825 return GetEventHandler()->ProcessEvent(event);
3826 #endif
3827 }
3828
3829
3830 bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd),
3831 short nHitTest,
3832 int WXUNUSED(mouseMsg))
3833 {
3834 #ifndef __WXMICROWIN__
3835 // the logic is as follows:
3836 // 0. if we're busy, set the busy cursor (even for non client elements)
3837 // 1. don't set custom cursor for non client area of enabled windows
3838 // 2. ask user EVT_SET_CURSOR handler for the cursor
3839 // 3. if still no cursor but we're in a TLW, set the global cursor
3840
3841 HCURSOR hcursor = 0;
3842 if ( wxIsBusy() )
3843 {
3844 hcursor = wxGetCurrentBusyCursor();
3845 }
3846 else // not busy
3847 {
3848 if ( nHitTest != HTCLIENT )
3849 return false;
3850
3851 // first ask the user code - it may wish to set the cursor in some very
3852 // specific way (for example, depending on the current position)
3853 POINT pt;
3854 #ifdef __WXWINCE__
3855 if ( !::GetCursorPosWinCE(&pt))
3856 #else
3857 if ( !::GetCursorPos(&pt) )
3858 #endif
3859 {
3860 wxLogLastError(wxT("GetCursorPos"));
3861 }
3862
3863 int x = pt.x,
3864 y = pt.y;
3865 ScreenToClient(&x, &y);
3866 wxSetCursorEvent event(x, y);
3867
3868 bool processedEvtSetCursor = GetEventHandler()->ProcessEvent(event);
3869 if ( processedEvtSetCursor && event.HasCursor() )
3870 {
3871 hcursor = GetHcursorOf(event.GetCursor());
3872 }
3873
3874 if ( !hcursor )
3875 {
3876 // the test for processedEvtSetCursor is here to prevent using
3877 // m_cursor if the user code caught EVT_SET_CURSOR() and returned
3878 // nothing from it - this is a way to say that our cursor shouldn't
3879 // be used for this point
3880 if ( !processedEvtSetCursor && m_cursor.Ok() )
3881 {
3882 hcursor = GetHcursorOf(m_cursor);
3883 }
3884
3885 if ( !hcursor && !GetParent() )
3886 {
3887 const wxCursor *cursor = wxGetGlobalCursor();
3888 if ( cursor && cursor->Ok() )
3889 {
3890 hcursor = GetHcursorOf(*cursor);
3891 }
3892 }
3893 }
3894 }
3895
3896
3897 if ( hcursor )
3898 {
3899 ::SetCursor(hcursor);
3900
3901 // cursor set, stop here
3902 return true;
3903 }
3904 #endif // __WXMICROWIN__
3905
3906 // pass up the window chain
3907 return false;
3908 }
3909
3910 bool wxWindowMSW::HandlePower(WXWPARAM WXUNUSED_IN_WINCE(wParam),
3911 WXLPARAM WXUNUSED(lParam),
3912 bool *WXUNUSED_IN_WINCE(vetoed))
3913 {
3914 #ifdef __WXWINCE__
3915 // FIXME
3916 return false;
3917 #else
3918 wxEventType evtType;
3919 switch ( wParam )
3920 {
3921 case PBT_APMQUERYSUSPEND:
3922 evtType = wxEVT_POWER_SUSPENDING;
3923 break;
3924
3925 case PBT_APMQUERYSUSPENDFAILED:
3926 evtType = wxEVT_POWER_SUSPEND_CANCEL;
3927 break;
3928
3929 case PBT_APMSUSPEND:
3930 evtType = wxEVT_POWER_SUSPENDED;
3931 break;
3932
3933 case PBT_APMRESUMESUSPEND:
3934 #ifdef PBT_APMRESUMEAUTOMATIC
3935 case PBT_APMRESUMEAUTOMATIC:
3936 #endif
3937 evtType = wxEVT_POWER_RESUME;
3938 break;
3939
3940 default:
3941 wxLogDebug(_T("Unknown WM_POWERBROADCAST(%d) event"), wParam);
3942 // fall through
3943
3944 // these messages are currently not mapped to wx events
3945 case PBT_APMQUERYSTANDBY:
3946 case PBT_APMQUERYSTANDBYFAILED:
3947 case PBT_APMSTANDBY:
3948 case PBT_APMRESUMESTANDBY:
3949 case PBT_APMBATTERYLOW:
3950 case PBT_APMPOWERSTATUSCHANGE:
3951 case PBT_APMOEMEVENT:
3952 case PBT_APMRESUMECRITICAL:
3953 evtType = wxEVT_NULL;
3954 break;
3955 }
3956
3957 // don't handle unknown messages
3958 if ( evtType == wxEVT_NULL )
3959 return false;
3960
3961 // TODO: notify about PBTF_APMRESUMEFROMFAILURE in case of resume events?
3962
3963 wxPowerEvent event(evtType);
3964 if ( !GetEventHandler()->ProcessEvent(event) )
3965 return false;
3966
3967 *vetoed = event.IsVetoed();
3968
3969 return true;
3970 #endif
3971 }
3972
3973 bool wxWindowMSW::IsDoubleBuffered() const
3974 {
3975 for ( const wxWindowMSW *wnd = this;
3976 wnd && !wnd->IsTopLevel(); wnd =
3977 wnd->GetParent() )
3978 {
3979 if ( ::GetWindowLong(GetHwndOf(wnd), GWL_EXSTYLE) & WS_EX_COMPOSITED )
3980 return true;
3981 }
3982
3983 return false;
3984 }
3985
3986 // ---------------------------------------------------------------------------
3987 // owner drawn stuff
3988 // ---------------------------------------------------------------------------
3989
3990 #if (wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE) || \
3991 (wxUSE_CONTROLS && !defined(__WXUNIVERSAL__))
3992 #define WXUNUSED_UNLESS_ODRAWN(param) param
3993 #else
3994 #define WXUNUSED_UNLESS_ODRAWN(param)
3995 #endif
3996
3997 bool
3998 wxWindowMSW::MSWOnDrawItem(int WXUNUSED_UNLESS_ODRAWN(id),
3999 WXDRAWITEMSTRUCT * WXUNUSED_UNLESS_ODRAWN(itemStruct))
4000 {
4001 #if wxUSE_OWNER_DRAWN
4002
4003 #if wxUSE_MENUS_NATIVE
4004 // is it a menu item?
4005 DRAWITEMSTRUCT *pDrawStruct = (DRAWITEMSTRUCT *)itemStruct;
4006 if ( id == 0 && pDrawStruct->CtlType == ODT_MENU )
4007 {
4008 wxMenuItem *pMenuItem = (wxMenuItem *)(pDrawStruct->itemData);
4009
4010 // see comment before the same test in MSWOnMeasureItem() below
4011 if ( !pMenuItem )
4012 return false;
4013
4014 wxCHECK_MSG( wxDynamicCast(pMenuItem, wxMenuItem),
4015 false, _T("MSWOnDrawItem: bad wxMenuItem pointer") );
4016
4017 // prepare to call OnDrawItem(): notice using of wxDCTemp to prevent
4018 // the DC from being released
4019 wxDCTemp dc((WXHDC)pDrawStruct->hDC);
4020 wxRect rect(pDrawStruct->rcItem.left, pDrawStruct->rcItem.top,
4021 pDrawStruct->rcItem.right - pDrawStruct->rcItem.left,
4022 pDrawStruct->rcItem.bottom - pDrawStruct->rcItem.top);
4023
4024 return pMenuItem->OnDrawItem
4025 (
4026 dc,
4027 rect,
4028 (wxOwnerDrawn::wxODAction)pDrawStruct->itemAction,
4029 (wxOwnerDrawn::wxODStatus)pDrawStruct->itemState
4030 );
4031 }
4032 #endif // wxUSE_MENUS_NATIVE
4033
4034 #endif // USE_OWNER_DRAWN
4035
4036 #if wxUSE_CONTROLS && !defined(__WXUNIVERSAL__)
4037
4038 #if wxUSE_OWNER_DRAWN
4039 wxControl *item = wxDynamicCast(FindItem(id), wxControl);
4040 #else // !wxUSE_OWNER_DRAWN
4041 // we may still have owner-drawn buttons internally because we have to make
4042 // them owner-drawn to support colour change
4043 wxControl *item =
4044 # if wxUSE_BUTTON
4045 wxDynamicCast(FindItem(id), wxButton)
4046 # else
4047 NULL
4048 # endif
4049 ;
4050 #endif // USE_OWNER_DRAWN
4051
4052 if ( item )
4053 {
4054 return item->MSWOnDraw(itemStruct);
4055 }
4056
4057 #endif // wxUSE_CONTROLS
4058
4059 return false;
4060 }
4061
4062 bool
4063 wxWindowMSW::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct)
4064 {
4065 #if wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE
4066 // is it a menu item?
4067 MEASUREITEMSTRUCT *pMeasureStruct = (MEASUREITEMSTRUCT *)itemStruct;
4068 if ( id == 0 && pMeasureStruct->CtlType == ODT_MENU )
4069 {
4070 wxMenuItem *pMenuItem = (wxMenuItem *)(pMeasureStruct->itemData);
4071
4072 // according to Carsten Fuchs the pointer may be NULL under XP if an
4073 // MDI child frame is initially maximized, see this for more info:
4074 // http://article.gmane.org/gmane.comp.lib.wxwidgets.general/27745
4075 //
4076 // so silently ignore it instead of asserting
4077 if ( !pMenuItem )
4078 return false;
4079
4080 wxCHECK_MSG( wxDynamicCast(pMenuItem, wxMenuItem),
4081 false, _T("MSWOnMeasureItem: bad wxMenuItem pointer") );
4082
4083 size_t w, h;
4084 bool rc = pMenuItem->OnMeasureItem(&w, &h);
4085
4086 pMeasureStruct->itemWidth = w;
4087 pMeasureStruct->itemHeight = h;
4088
4089 return rc;
4090 }
4091
4092 wxControl *item = wxDynamicCast(FindItem(id), wxControl);
4093 if ( item )
4094 {
4095 return item->MSWOnMeasure(itemStruct);
4096 }
4097 #else
4098 wxUnusedVar(id);
4099 wxUnusedVar(itemStruct);
4100 #endif // wxUSE_OWNER_DRAWN && wxUSE_MENUS_NATIVE
4101
4102 return false;
4103 }
4104
4105 // ---------------------------------------------------------------------------
4106 // colours and palettes
4107 // ---------------------------------------------------------------------------
4108
4109 bool wxWindowMSW::HandleSysColorChange()
4110 {
4111 wxSysColourChangedEvent event;
4112 event.SetEventObject(this);
4113
4114 (void)GetEventHandler()->ProcessEvent(event);
4115
4116 // always let the system carry on the default processing to allow the
4117 // native controls to react to the colours update
4118 return false;
4119 }
4120
4121 bool wxWindowMSW::HandleDisplayChange()
4122 {
4123 wxDisplayChangedEvent event;
4124 event.SetEventObject(this);
4125
4126 return GetEventHandler()->ProcessEvent(event);
4127 }
4128
4129 #ifndef __WXMICROWIN__
4130
4131 bool wxWindowMSW::HandleCtlColor(WXHBRUSH *brush, WXHDC hDC, WXHWND hWnd)
4132 {
4133 #if !wxUSE_CONTROLS || defined(__WXUNIVERSAL__)
4134 wxUnusedVar(hDC);
4135 wxUnusedVar(hWnd);
4136 #else
4137 wxControl *item = wxDynamicCast(FindItemByHWND(hWnd, true), wxControl);
4138
4139 if ( item )
4140 *brush = item->MSWControlColor(hDC, hWnd);
4141 else
4142 #endif // wxUSE_CONTROLS
4143 *brush = NULL;
4144
4145 return *brush != NULL;
4146 }
4147
4148 #endif // __WXMICROWIN__
4149
4150 bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange)
4151 {
4152 #if wxUSE_PALETTE
4153 // same as below except we don't respond to our own messages
4154 if ( hWndPalChange != GetHWND() )
4155 {
4156 // check to see if we our our parents have a custom palette
4157 wxWindowMSW *win = this;
4158 while ( win && !win->HasCustomPalette() )
4159 {
4160 win = win->GetParent();
4161 }
4162
4163 if ( win && win->HasCustomPalette() )
4164 {
4165 // realize the palette to see whether redrawing is needed
4166 HDC hdc = ::GetDC((HWND) hWndPalChange);
4167 win->m_palette.SetHPALETTE((WXHPALETTE)
4168 ::SelectPalette(hdc, GetHpaletteOf(win->m_palette), FALSE));
4169
4170 int result = ::RealizePalette(hdc);
4171
4172 // restore the palette (before releasing the DC)
4173 win->m_palette.SetHPALETTE((WXHPALETTE)
4174 ::SelectPalette(hdc, GetHpaletteOf(win->m_palette), FALSE));
4175 ::RealizePalette(hdc);
4176 ::ReleaseDC((HWND) hWndPalChange, hdc);
4177
4178 // now check for the need to redraw
4179 if (result > 0)
4180 ::InvalidateRect((HWND) hWndPalChange, NULL, TRUE);
4181 }
4182
4183 }
4184 #endif // wxUSE_PALETTE
4185
4186 wxPaletteChangedEvent event(GetId());
4187 event.SetEventObject(this);
4188 event.SetChangedWindow(wxFindWinFromHandle(hWndPalChange));
4189
4190 return GetEventHandler()->ProcessEvent(event);
4191 }
4192
4193 bool wxWindowMSW::HandleCaptureChanged(WXHWND hWndGainedCapture)
4194 {
4195 // notify windows on the capture stack about lost capture
4196 // (see http://sourceforge.net/tracker/index.php?func=detail&aid=1153662&group_id=9863&atid=109863):
4197 wxWindowBase::NotifyCaptureLost();
4198
4199 wxWindow *win = wxFindWinFromHandle(hWndGainedCapture);
4200 wxMouseCaptureChangedEvent event(GetId(), win);
4201 event.SetEventObject(this);
4202 return GetEventHandler()->ProcessEvent(event);
4203 }
4204
4205 bool wxWindowMSW::HandleSettingChange(WXWPARAM wParam, WXLPARAM lParam)
4206 {
4207 // despite MSDN saying "(This message cannot be sent directly to a window.)"
4208 // we need to send this to child windows (it is only sent to top-level
4209 // windows) so {list,tree}ctrls can adjust their font size if necessary
4210 // this is exactly how explorer does it to enable the font size changes
4211
4212 wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
4213 while ( node )
4214 {
4215 // top-level windows already get this message from the system
4216 wxWindow *win = node->GetData();
4217 if ( !win->IsTopLevel() )
4218 {
4219 ::SendMessage(GetHwndOf(win), WM_SETTINGCHANGE, wParam, lParam);
4220 }
4221
4222 node = node->GetNext();
4223 }
4224
4225 // let the system handle it
4226 return false;
4227 }
4228
4229 bool wxWindowMSW::HandleQueryNewPalette()
4230 {
4231
4232 #if wxUSE_PALETTE
4233 // check to see if we our our parents have a custom palette
4234 wxWindowMSW *win = this;
4235 while (!win->HasCustomPalette() && win->GetParent()) win = win->GetParent();
4236 if (win->HasCustomPalette()) {
4237 /* realize the palette to see whether redrawing is needed */
4238 HDC hdc = ::GetDC((HWND) GetHWND());
4239 win->m_palette.SetHPALETTE( (WXHPALETTE)
4240 ::SelectPalette(hdc, (HPALETTE) win->m_palette.GetHPALETTE(), FALSE) );
4241
4242 int result = ::RealizePalette(hdc);
4243 /* restore the palette (before releasing the DC) */
4244 win->m_palette.SetHPALETTE( (WXHPALETTE)
4245 ::SelectPalette(hdc, (HPALETTE) win->m_palette.GetHPALETTE(), TRUE) );
4246 ::RealizePalette(hdc);
4247 ::ReleaseDC((HWND) GetHWND(), hdc);
4248 /* now check for the need to redraw */
4249 if (result > 0)
4250 ::InvalidateRect((HWND) GetHWND(), NULL, TRUE);
4251 }
4252 #endif // wxUSE_PALETTE
4253
4254 wxQueryNewPaletteEvent event(GetId());
4255 event.SetEventObject(this);
4256
4257 return GetEventHandler()->ProcessEvent(event) && event.GetPaletteRealized();
4258 }
4259
4260 // Responds to colour changes: passes event on to children.
4261 void wxWindowMSW::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event))
4262 {
4263 // the top level window also reset the standard colour map as it might have
4264 // changed (there is no need to do it for the non top level windows as we
4265 // only have to do it once)
4266 if ( IsTopLevel() )
4267 {
4268 // FIXME-MT
4269 gs_hasStdCmap = false;
4270 }
4271 wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
4272 while ( node )
4273 {
4274 // Only propagate to non-top-level windows because Windows already
4275 // sends this event to all top-level ones
4276 wxWindow *win = node->GetData();
4277 if ( !win->IsTopLevel() )
4278 {
4279 // we need to send the real WM_SYSCOLORCHANGE and not just trigger
4280 // EVT_SYS_COLOUR_CHANGED call because the latter wouldn't work for
4281 // the standard controls
4282 ::SendMessage(GetHwndOf(win), WM_SYSCOLORCHANGE, 0, 0);
4283 }
4284
4285 node = node->GetNext();
4286 }
4287 }
4288
4289 extern wxCOLORMAP *wxGetStdColourMap()
4290 {
4291 static COLORREF s_stdColours[wxSTD_COL_MAX];
4292 static wxCOLORMAP s_cmap[wxSTD_COL_MAX];
4293
4294 if ( !gs_hasStdCmap )
4295 {
4296 static bool s_coloursInit = false;
4297
4298 if ( !s_coloursInit )
4299 {
4300 // When a bitmap is loaded, the RGB values can change (apparently
4301 // because Windows adjusts them to care for the old programs always
4302 // using 0xc0c0c0 while the transparent colour for the new Windows
4303 // versions is different). But we do this adjustment ourselves so
4304 // we want to avoid Windows' "help" and for this we need to have a
4305 // reference bitmap which can tell us what the RGB values change
4306 // to.
4307 wxLogNull logNo; // suppress error if we couldn't load the bitmap
4308 wxBitmap stdColourBitmap(_T("wxBITMAP_STD_COLOURS"));
4309 if ( stdColourBitmap.Ok() )
4310 {
4311 // the pixels in the bitmap must correspond to wxSTD_COL_XXX!
4312 wxASSERT_MSG( stdColourBitmap.GetWidth() == wxSTD_COL_MAX,
4313 _T("forgot to update wxBITMAP_STD_COLOURS!") );
4314
4315 wxMemoryDC memDC;
4316 memDC.SelectObject(stdColourBitmap);
4317
4318 wxColour colour;
4319 for ( size_t i = 0; i < WXSIZEOF(s_stdColours); i++ )
4320 {
4321 memDC.GetPixel(i, 0, &colour);
4322 s_stdColours[i] = wxColourToRGB(colour);
4323 }
4324 }
4325 else // wxBITMAP_STD_COLOURS couldn't be loaded
4326 {
4327 s_stdColours[0] = RGB(000,000,000); // black
4328 s_stdColours[1] = RGB(128,128,128); // dark grey
4329 s_stdColours[2] = RGB(192,192,192); // light grey
4330 s_stdColours[3] = RGB(255,255,255); // white
4331 //s_stdColours[4] = RGB(000,000,255); // blue
4332 //s_stdColours[5] = RGB(255,000,255); // magenta
4333 }
4334
4335 s_coloursInit = true;
4336 }
4337
4338 gs_hasStdCmap = true;
4339
4340 // create the colour map
4341 #define INIT_CMAP_ENTRY(col) \
4342 s_cmap[wxSTD_COL_##col].from = s_stdColours[wxSTD_COL_##col]; \
4343 s_cmap[wxSTD_COL_##col].to = ::GetSysColor(COLOR_##col)
4344
4345 INIT_CMAP_ENTRY(BTNTEXT);
4346 INIT_CMAP_ENTRY(BTNSHADOW);
4347 INIT_CMAP_ENTRY(BTNFACE);
4348 INIT_CMAP_ENTRY(BTNHIGHLIGHT);
4349
4350 #undef INIT_CMAP_ENTRY
4351 }
4352
4353 return s_cmap;
4354 }
4355
4356 // ---------------------------------------------------------------------------
4357 // painting
4358 // ---------------------------------------------------------------------------
4359
4360 bool wxWindowMSW::HandlePaint()
4361 {
4362 HRGN hRegion = ::CreateRectRgn(0, 0, 0, 0); // Dummy call to get a handle
4363 if ( !hRegion )
4364 wxLogLastError(wxT("CreateRectRgn"));
4365 if ( ::GetUpdateRgn(GetHwnd(), hRegion, FALSE) == ERROR )
4366 wxLogLastError(wxT("GetUpdateRgn"));
4367
4368 m_updateRegion = wxRegion((WXHRGN) hRegion);
4369
4370 wxPaintEvent event(m_windowId);
4371 event.SetEventObject(this);
4372
4373 bool processed = GetEventHandler()->ProcessEvent(event);
4374
4375 // note that we must generate NC event after the normal one as otherwise
4376 // BeginPaint() will happily overwrite our decorations with the background
4377 // colour
4378 wxNcPaintEvent eventNc(m_windowId);
4379 eventNc.SetEventObject(this);
4380 GetEventHandler()->ProcessEvent(eventNc);
4381
4382 return processed;
4383 }
4384
4385 // Can be called from an application's OnPaint handler
4386 void wxWindowMSW::OnPaint(wxPaintEvent& event)
4387 {
4388 #ifdef __WXUNIVERSAL__
4389 event.Skip();
4390 #else
4391 HDC hDC = (HDC) wxPaintDC::FindDCInCache((wxWindow*) event.GetEventObject());
4392 if (hDC != 0)
4393 {
4394 MSWDefWindowProc(WM_PAINT, (WPARAM) hDC, 0);
4395 }
4396 #endif
4397 }
4398
4399 bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc)
4400 {
4401 wxDCTemp dc(hdc, GetClientSize());
4402
4403 dc.SetHDC(hdc);
4404 dc.SetWindow((wxWindow *)this);
4405
4406 wxEraseEvent event(m_windowId, &dc);
4407 event.SetEventObject(this);
4408 bool rc = GetEventHandler()->ProcessEvent(event);
4409
4410 // must be called manually as ~wxDC doesn't do anything for wxDCTemp
4411 dc.SelectOldObjects(hdc);
4412
4413 return rc;
4414 }
4415
4416 void wxWindowMSW::OnEraseBackground(wxEraseEvent& event)
4417 {
4418 // standard non top level controls (i.e. except the dialogs) always erase
4419 // their background themselves in HandleCtlColor() or have some control-
4420 // specific ways to set the colours (common controls)
4421 if ( IsOfStandardClass() && !IsTopLevel() )
4422 {
4423 event.Skip();
4424 return;
4425 }
4426
4427 if ( GetBackgroundStyle() == wxBG_STYLE_CUSTOM )
4428 {
4429 // don't skip the event here, custom background means that the app
4430 // is drawing it itself in its OnPaint(), so don't draw it at all
4431 // now to avoid flicker
4432 return;
4433 }
4434
4435
4436 // do default background painting
4437 if ( !DoEraseBackground(GetHdcOf(*event.GetDC())) )
4438 {
4439 // let the system paint the background
4440 event.Skip();
4441 }
4442 }
4443
4444 bool wxWindowMSW::DoEraseBackground(WXHDC hDC)
4445 {
4446 HBRUSH hbr = (HBRUSH)MSWGetBgBrush(hDC);
4447 if ( !hbr )
4448 return false;
4449
4450 wxFillRect(GetHwnd(), (HDC)hDC, hbr);
4451
4452 return true;
4453 }
4454
4455 WXHBRUSH
4456 wxWindowMSW::MSWGetBgBrushForChild(WXHDC WXUNUSED(hDC), WXHWND hWnd)
4457 {
4458 if ( m_hasBgCol )
4459 {
4460 // our background colour applies to:
4461 // 1. this window itself, always
4462 // 2. all children unless the colour is "not inheritable"
4463 // 3. even if it is not inheritable, our immediate transparent
4464 // children should still inherit it -- but not any transparent
4465 // children because it would look wrong if a child of non
4466 // transparent child would show our bg colour when the child itself
4467 // does not
4468 wxWindow *win = wxFindWinFromHandle(hWnd);
4469 if ( win == this ||
4470 m_inheritBgCol ||
4471 (win && win->HasTransparentBackground() &&
4472 win->GetParent() == this) )
4473 {
4474 // draw children with the same colour as the parent
4475 wxBrush *
4476 brush = wxTheBrushList->FindOrCreateBrush(GetBackgroundColour());
4477
4478 return (WXHBRUSH)GetHbrushOf(*brush);
4479 }
4480 }
4481
4482 return 0;
4483 }
4484
4485 WXHBRUSH wxWindowMSW::MSWGetBgBrush(WXHDC hDC, WXHWND hWndToPaint)
4486 {
4487 if ( !hWndToPaint )
4488 hWndToPaint = GetHWND();
4489
4490 for ( wxWindowMSW *win = this; win; win = win->GetParent() )
4491 {
4492 WXHBRUSH hBrush = win->MSWGetBgBrushForChild(hDC, hWndToPaint);
4493 if ( hBrush )
4494 return hBrush;
4495
4496 // background is not inherited beyond top level windows
4497 if ( win->IsTopLevel() )
4498 break;
4499 }
4500
4501 return 0;
4502 }
4503
4504 bool wxWindowMSW::HandlePrintClient(WXHDC hDC)
4505 {
4506 // we receive this message when DrawThemeParentBackground() is
4507 // called from def window proc of several controls under XP and we
4508 // must draw properly themed background here
4509 //
4510 // note that naively I'd expect filling the client rect with the
4511 // brush returned by MSWGetBgBrush() work -- but for some reason it
4512 // doesn't and we have to call parents MSWPrintChild() which is
4513 // supposed to call DrawThemeBackground() with appropriate params
4514 //
4515 // also note that in this case lParam == PRF_CLIENT but we're
4516 // clearly expected to paint the background and nothing else!
4517
4518 if ( IsTopLevel() || InheritsBackgroundColour() )
4519 return false;
4520
4521 // sometimes we don't want the parent to handle it at all, instead
4522 // return whatever value this window wants
4523 if ( !MSWShouldPropagatePrintChild() )
4524 return MSWPrintChild(hDC, (wxWindow *)this);
4525
4526 for ( wxWindow *win = GetParent(); win; win = win->GetParent() )
4527 {
4528 if ( win->MSWPrintChild(hDC, (wxWindow *)this) )
4529 return true;
4530
4531 if ( win->IsTopLevel() || win->InheritsBackgroundColour() )
4532 break;
4533 }
4534
4535 return false;
4536 }
4537
4538 // ---------------------------------------------------------------------------
4539 // moving and resizing
4540 // ---------------------------------------------------------------------------
4541
4542 bool wxWindowMSW::HandleMinimize()
4543 {
4544 wxIconizeEvent event(m_windowId);
4545 event.SetEventObject(this);
4546
4547 return GetEventHandler()->ProcessEvent(event);
4548 }
4549
4550 bool wxWindowMSW::HandleMaximize()
4551 {
4552 wxMaximizeEvent event(m_windowId);
4553 event.SetEventObject(this);
4554
4555 return GetEventHandler()->ProcessEvent(event);
4556 }
4557
4558 bool wxWindowMSW::HandleMove(int x, int y)
4559 {
4560 wxPoint point(x,y);
4561 wxMoveEvent event(point, m_windowId);
4562 event.SetEventObject(this);
4563
4564 return GetEventHandler()->ProcessEvent(event);
4565 }
4566
4567 bool wxWindowMSW::HandleMoving(wxRect& rect)
4568 {
4569 wxMoveEvent event(rect, m_windowId);
4570 event.SetEventObject(this);
4571
4572 bool rc = GetEventHandler()->ProcessEvent(event);
4573 if (rc)
4574 rect = event.GetRect();
4575 return rc;
4576 }
4577
4578 bool wxWindowMSW::HandleEnterSizeMove()
4579 {
4580 wxMoveEvent event(wxPoint(), m_windowId);
4581 event.SetEventType(wxEVT_MOVE_START);
4582 event.SetEventObject(this);
4583
4584 return GetEventHandler()->ProcessEvent(event);
4585 }
4586
4587 bool wxWindowMSW::HandleExitSizeMove()
4588 {
4589 wxMoveEvent event(wxPoint(), m_windowId);
4590 event.SetEventType(wxEVT_MOVE_END);
4591 event.SetEventObject(this);
4592
4593 return GetEventHandler()->ProcessEvent(event);
4594 }
4595
4596 bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam)
4597 {
4598 #if USE_DEFERRED_SIZING
4599 // when we resize this window, its children are probably going to be
4600 // repositioned as well, prepare to use DeferWindowPos() for them
4601 int numChildren = 0;
4602 for ( HWND child = ::GetWindow(GetHwndOf(this), GW_CHILD);
4603 child;
4604 child = ::GetWindow(child, GW_HWNDNEXT) )
4605 {
4606 numChildren ++;
4607 }
4608
4609 // Protect against valid m_hDWP being overwritten
4610 bool useDefer = false;
4611
4612 if ( numChildren > 1 )
4613 {
4614 if (!m_hDWP)
4615 {
4616 m_hDWP = (WXHANDLE)::BeginDeferWindowPos(numChildren);
4617 if ( !m_hDWP )
4618 {
4619 wxLogLastError(_T("BeginDeferWindowPos"));
4620 }
4621 if (m_hDWP)
4622 useDefer = true;
4623 }
4624 }
4625 #endif // USE_DEFERRED_SIZING
4626
4627 // update this window size
4628 bool processed = false;
4629 switch ( wParam )
4630 {
4631 default:
4632 wxFAIL_MSG( _T("unexpected WM_SIZE parameter") );
4633 // fall through nevertheless
4634
4635 case SIZE_MAXHIDE:
4636 case SIZE_MAXSHOW:
4637 // we're not interested in these messages at all
4638 break;
4639
4640 case SIZE_MINIMIZED:
4641 processed = HandleMinimize();
4642 break;
4643
4644 case SIZE_MAXIMIZED:
4645 /* processed = */ HandleMaximize();
4646 // fall through to send a normal size event as well
4647
4648 case SIZE_RESTORED:
4649 // don't use w and h parameters as they specify the client size
4650 // while according to the docs EVT_SIZE handler is supposed to
4651 // receive the total size
4652 wxSizeEvent event(GetSize(), m_windowId);
4653 event.SetEventObject(this);
4654
4655 processed = GetEventHandler()->ProcessEvent(event);
4656 }
4657
4658 #if USE_DEFERRED_SIZING
4659 // and finally change the positions of all child windows at once
4660 if ( useDefer && m_hDWP )
4661 {
4662 // reset m_hDWP to NULL so that child windows don't try to use our
4663 // m_hDWP after we call EndDeferWindowPos() on it (this shouldn't
4664 // happen anyhow normally but who knows what weird flow of control we
4665 // may have depending on what the users EVT_SIZE handler does...)
4666 HDWP hDWP = (HDWP)m_hDWP;
4667 m_hDWP = NULL;
4668
4669 // do put all child controls in place at once
4670 if ( !::EndDeferWindowPos(hDWP) )
4671 {
4672 wxLogLastError(_T("EndDeferWindowPos"));
4673 }
4674
4675 // Reset our children's pending pos/size values.
4676 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
4677 node;
4678 node = node->GetNext() )
4679 {
4680 wxWindowMSW *child = node->GetData();
4681 child->m_pendingPosition = wxDefaultPosition;
4682 child->m_pendingSize = wxDefaultSize;
4683 }
4684 }
4685 #endif // USE_DEFERRED_SIZING
4686
4687 return processed;
4688 }
4689
4690 bool wxWindowMSW::HandleSizing(wxRect& rect)
4691 {
4692 wxSizeEvent event(rect, m_windowId);
4693 event.SetEventObject(this);
4694
4695 bool rc = GetEventHandler()->ProcessEvent(event);
4696 if (rc)
4697 rect = event.GetRect();
4698 return rc;
4699 }
4700
4701 bool wxWindowMSW::HandleGetMinMaxInfo(void *WXUNUSED_IN_WINCE(mmInfo))
4702 {
4703 #ifdef __WXWINCE__
4704 return false;
4705 #else
4706 MINMAXINFO *info = (MINMAXINFO *)mmInfo;
4707
4708 bool rc = false;
4709
4710 int minWidth = GetMinWidth(),
4711 minHeight = GetMinHeight(),
4712 maxWidth = GetMaxWidth(),
4713 maxHeight = GetMaxHeight();
4714
4715 if ( minWidth != wxDefaultCoord )
4716 {
4717 info->ptMinTrackSize.x = minWidth;
4718 rc = true;
4719 }
4720
4721 if ( minHeight != wxDefaultCoord )
4722 {
4723 info->ptMinTrackSize.y = minHeight;
4724 rc = true;
4725 }
4726
4727 if ( maxWidth != wxDefaultCoord )
4728 {
4729 info->ptMaxTrackSize.x = maxWidth;
4730 rc = true;
4731 }
4732
4733 if ( maxHeight != wxDefaultCoord )
4734 {
4735 info->ptMaxTrackSize.y = maxHeight;
4736 rc = true;
4737 }
4738
4739 return rc;
4740 #endif
4741 }
4742
4743 // ---------------------------------------------------------------------------
4744 // command messages
4745 // ---------------------------------------------------------------------------
4746
4747 bool wxWindowMSW::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control)
4748 {
4749 #if wxUSE_MENUS_NATIVE
4750 if ( !cmd && wxCurrentPopupMenu )
4751 {
4752 wxMenu *popupMenu = wxCurrentPopupMenu;
4753 wxCurrentPopupMenu = NULL;
4754
4755 return popupMenu->MSWCommand(cmd, id);
4756 }
4757 #endif // wxUSE_MENUS_NATIVE
4758
4759 wxWindow *win = NULL;
4760
4761 // first try to find it from HWND - this works even with the broken
4762 // programs using the same ids for different controls
4763 if ( control )
4764 {
4765 win = wxFindWinFromHandle(control);
4766 }
4767
4768 // try the id
4769 if ( !win )
4770 {
4771 // must cast to a signed type before comparing with other ids!
4772 win = FindItem((signed short)id);
4773 }
4774
4775 if ( win )
4776 {
4777 return win->MSWCommand(cmd, id);
4778 }
4779
4780 // the messages sent from the in-place edit control used by the treectrl
4781 // for label editing have id == 0, but they should _not_ be treated as menu
4782 // messages (they are EN_XXX ones, in fact) so don't translate anything
4783 // coming from a control to wxEVT_COMMAND_MENU_SELECTED
4784 if ( !control )
4785 {
4786 // If no child window, it may be an accelerator, e.g. for a popup menu
4787 // command
4788
4789 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED);
4790 event.SetEventObject(this);
4791 event.SetId(id);
4792 event.SetInt(id);
4793
4794 return GetEventHandler()->ProcessEvent(event);
4795 }
4796 else
4797 {
4798 #if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__)
4799 // the text ctrl which is logically part of wxSpinCtrl sends WM_COMMAND
4800 // notifications to its parent which we want to reflect back to
4801 // wxSpinCtrl
4802 wxSpinCtrl *spin = wxSpinCtrl::GetSpinForTextCtrl(control);
4803 if ( spin && spin->ProcessTextCommand(cmd, id) )
4804 return true;
4805 #endif // wxUSE_SPINCTRL
4806
4807 #if wxUSE_CHOICE && defined(__SMARTPHONE__)
4808 // the listbox ctrl which is logically part of wxChoice sends WM_COMMAND
4809 // notifications to its parent which we want to reflect back to
4810 // wxChoice
4811 wxChoice *choice = wxChoice::GetChoiceForListBox(control);
4812 if ( choice && choice->MSWCommand(cmd, id) )
4813 return true;
4814 #endif
4815 }
4816
4817 return false;
4818 }
4819
4820 // ---------------------------------------------------------------------------
4821 // mouse events
4822 // ---------------------------------------------------------------------------
4823
4824 void wxWindowMSW::InitMouseEvent(wxMouseEvent& event,
4825 int x, int y,
4826 WXUINT flags)
4827 {
4828 // our client coords are not quite the same as Windows ones
4829 wxPoint pt = GetClientAreaOrigin();
4830 event.m_x = x - pt.x;
4831 event.m_y = y - pt.y;
4832
4833 event.m_shiftDown = (flags & MK_SHIFT) != 0;
4834 event.m_controlDown = (flags & MK_CONTROL) != 0;
4835 event.m_leftDown = (flags & MK_LBUTTON) != 0;
4836 event.m_middleDown = (flags & MK_MBUTTON) != 0;
4837 event.m_rightDown = (flags & MK_RBUTTON) != 0;
4838 #ifdef wxHAS_XBUTTON
4839 event.m_aux1Down = (flags & MK_XBUTTON1) != 0;
4840 event.m_aux2Down = (flags & MK_XBUTTON2) != 0;
4841 #endif // wxHAS_XBUTTON
4842 event.m_altDown = ::GetKeyState(VK_MENU) < 0;
4843
4844 #ifndef __WXWINCE__
4845 event.SetTimestamp(::GetMessageTime());
4846 #endif
4847
4848 event.SetEventObject(this);
4849 event.SetId(GetId());
4850
4851 #if wxUSE_MOUSEEVENT_HACK
4852 gs_lastMouseEvent.pos = ClientToScreen(wxPoint(x, y));
4853 gs_lastMouseEvent.type = event.GetEventType();
4854 #endif // wxUSE_MOUSEEVENT_HACK
4855 }
4856
4857 #ifdef __WXWINCE__
4858 // Windows doesn't send the mouse events to the static controls (which are
4859 // transparent in the sense that their WM_NCHITTEST handler returns
4860 // HTTRANSPARENT) at all but we want all controls to receive the mouse events
4861 // and so we manually check if we don't have a child window under mouse and if
4862 // we do, send the event to it instead of the window Windows had sent WM_XXX
4863 // to.
4864 //
4865 // Notice that this is not done for the mouse move events because this could
4866 // (would?) be too slow, but only for clicks which means that the static texts
4867 // still don't get move, enter nor leave events.
4868 static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y)
4869 {
4870 wxCHECK_MSG( x && y, win, _T("NULL pointer in FindWindowForMouseEvent") );
4871
4872 // first try to find a non transparent child: this allows us to send events
4873 // to a static text which is inside a static box, for example
4874 POINT pt = { *x, *y };
4875 HWND hwnd = GetHwndOf(win),
4876 hwndUnderMouse;
4877
4878 #ifdef __WXWINCE__
4879 hwndUnderMouse = ::ChildWindowFromPoint
4880 (
4881 hwnd,
4882 pt
4883 );
4884 #else
4885 hwndUnderMouse = ::ChildWindowFromPointEx
4886 (
4887 hwnd,
4888 pt,
4889 CWP_SKIPINVISIBLE |
4890 CWP_SKIPDISABLED |
4891 CWP_SKIPTRANSPARENT
4892 );
4893 #endif
4894
4895 if ( !hwndUnderMouse || hwndUnderMouse == hwnd )
4896 {
4897 // now try any child window at all
4898 hwndUnderMouse = ::ChildWindowFromPoint(hwnd, pt);
4899 }
4900
4901 // check that we have a child window which is susceptible to receive mouse
4902 // events: for this it must be shown and enabled
4903 if ( hwndUnderMouse &&
4904 hwndUnderMouse != hwnd &&
4905 ::IsWindowVisible(hwndUnderMouse) &&
4906 ::IsWindowEnabled(hwndUnderMouse) )
4907 {
4908 wxWindow *winUnderMouse = wxFindWinFromHandle((WXHWND)hwndUnderMouse);
4909 if ( winUnderMouse )
4910 {
4911 // translate the mouse coords to the other window coords
4912 win->ClientToScreen(x, y);
4913 winUnderMouse->ScreenToClient(x, y);
4914
4915 win = winUnderMouse;
4916 }
4917 }
4918
4919 return win;
4920 }
4921 #endif // __WXWINCE__
4922
4923 bool wxWindowMSW::HandleMouseEvent(WXUINT msg, int x, int y, WXUINT flags)
4924 {
4925 // the mouse events take consecutive IDs from WM_MOUSEFIRST to
4926 // WM_MOUSELAST, so it's enough to subtract WM_MOUSEMOVE == WM_MOUSEFIRST
4927 // from the message id and take the value in the table to get wxWin event
4928 // id
4929 static const wxEventType eventsMouse[] =
4930 {
4931 wxEVT_MOTION,
4932 wxEVT_LEFT_DOWN,
4933 wxEVT_LEFT_UP,
4934 wxEVT_LEFT_DCLICK,
4935 wxEVT_RIGHT_DOWN,
4936 wxEVT_RIGHT_UP,
4937 wxEVT_RIGHT_DCLICK,
4938 wxEVT_MIDDLE_DOWN,
4939 wxEVT_MIDDLE_UP,
4940 wxEVT_MIDDLE_DCLICK,
4941 0, // this one is for wxEVT_MOTION which is not used here
4942 wxEVT_AUX1_DOWN,
4943 wxEVT_AUX1_UP,
4944 wxEVT_AUX1_DCLICK,
4945 wxEVT_AUX2_DOWN,
4946 wxEVT_AUX2_UP,
4947 wxEVT_AUX2_DCLICK
4948 };
4949
4950 #ifdef wxHAS_XBUTTON
4951 // the same messages are used for both auxillary mouse buttons so we need
4952 // to adjust the index manually
4953 switch ( msg )
4954 {
4955 case WM_XBUTTONDOWN:
4956 case WM_XBUTTONUP:
4957 case WM_XBUTTONDBLCLK:
4958 if ( flags & MK_XBUTTON2 )
4959 msg += wxEVT_AUX2_DOWN - wxEVT_AUX1_DOWN;
4960 }
4961 #endif // wxHAS_XBUTTON
4962
4963 wxMouseEvent event(eventsMouse[msg - WM_MOUSEMOVE]);
4964 InitMouseEvent(event, x, y, flags);
4965
4966 return GetEventHandler()->ProcessEvent(event);
4967 }
4968
4969 bool wxWindowMSW::HandleMouseMove(int x, int y, WXUINT flags)
4970 {
4971 if ( !m_mouseInWindow )
4972 {
4973 // it would be wrong to assume that just because we get a mouse move
4974 // event that the mouse is inside the window: although this is usually
4975 // true, it is not if we had captured the mouse, so we need to check
4976 // the mouse coordinates here
4977 if ( !HasCapture() || IsMouseInWindow() )
4978 {
4979 // Generate an ENTER event
4980 m_mouseInWindow = true;
4981
4982 #ifdef HAVE_TRACKMOUSEEVENT
4983 typedef BOOL (WINAPI *_TrackMouseEvent_t)(LPTRACKMOUSEEVENT);
4984 #ifdef __WXWINCE__
4985 static const _TrackMouseEvent_t
4986 s_pfn_TrackMouseEvent = _TrackMouseEvent;
4987 #else // !__WXWINCE__
4988 static _TrackMouseEvent_t s_pfn_TrackMouseEvent;
4989 static bool s_initDone = false;
4990 if ( !s_initDone )
4991 {
4992 wxLogNull noLog;
4993
4994 wxDynamicLibrary dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM);
4995 if ( dllComCtl32.IsLoaded() )
4996 {
4997 s_pfn_TrackMouseEvent = (_TrackMouseEvent_t)
4998 dllComCtl32.GetSymbol(_T("_TrackMouseEvent"));
4999 }
5000
5001 s_initDone = true;
5002
5003 // notice that it's ok to unload comctl32.dll here as it won't
5004 // be really unloaded, being still in use because we link to it
5005 // statically too
5006 }
5007
5008 if ( s_pfn_TrackMouseEvent )
5009 #endif // __WXWINCE__/!__WXWINCE__
5010 {
5011 WinStruct<TRACKMOUSEEVENT> trackinfo;
5012
5013 trackinfo.dwFlags = TME_LEAVE;
5014 trackinfo.hwndTrack = GetHwnd();
5015
5016 (*s_pfn_TrackMouseEvent)(&trackinfo);
5017 }
5018 #endif // HAVE_TRACKMOUSEEVENT
5019
5020 wxMouseEvent event(wxEVT_ENTER_WINDOW);
5021 InitMouseEvent(event, x, y, flags);
5022
5023 (void)GetEventHandler()->ProcessEvent(event);
5024 }
5025 }
5026 #ifdef HAVE_TRACKMOUSEEVENT
5027 else // mouse not in window
5028 {
5029 // Check if we need to send a LEAVE event
5030 // Windows doesn't send WM_MOUSELEAVE if the mouse has been captured so
5031 // send it here if we are using native mouse leave tracking
5032 if ( HasCapture() && !IsMouseInWindow() )
5033 {
5034 GenerateMouseLeave();
5035 }
5036 }
5037 #endif // HAVE_TRACKMOUSEEVENT
5038
5039 #if wxUSE_MOUSEEVENT_HACK
5040 // Windows often generates mouse events even if mouse position hasn't
5041 // changed (http://article.gmane.org/gmane.comp.lib.wxwidgets.devel/66576)
5042 //
5043 // Filter this out as it can result in unexpected behaviour compared to
5044 // other platforms
5045 if ( gs_lastMouseEvent.type == wxEVT_RIGHT_DOWN ||
5046 gs_lastMouseEvent.type == wxEVT_LEFT_DOWN ||
5047 gs_lastMouseEvent.type == wxEVT_MIDDLE_DOWN ||
5048 gs_lastMouseEvent.type == wxEVT_MOTION )
5049 {
5050 if ( ClientToScreen(wxPoint(x, y)) == gs_lastMouseEvent.pos )
5051 {
5052 gs_lastMouseEvent.type = wxEVT_MOTION;
5053
5054 return false;
5055 }
5056 }
5057 #endif // wxUSE_MOUSEEVENT_HACK
5058
5059 return HandleMouseEvent(WM_MOUSEMOVE, x, y, flags);
5060 }
5061
5062
5063 bool wxWindowMSW::HandleMouseWheel(WXWPARAM wParam, WXLPARAM lParam)
5064 {
5065 #if wxUSE_MOUSEWHEEL
5066 // notice that WM_MOUSEWHEEL position is in screen coords (as it's
5067 // forwarded up to the parent by DefWindowProc()) and not in the client
5068 // ones as all the other messages, translate them to the client coords for
5069 // consistency
5070 const wxPoint
5071 pt = ScreenToClient(wxPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
5072 wxMouseEvent event(wxEVT_MOUSEWHEEL);
5073 InitMouseEvent(event, pt.x, pt.y, LOWORD(wParam));
5074 event.m_wheelRotation = (short)HIWORD(wParam);
5075 event.m_wheelDelta = WHEEL_DELTA;
5076
5077 static int s_linesPerRotation = -1;
5078 if ( s_linesPerRotation == -1 )
5079 {
5080 if ( !::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
5081 &s_linesPerRotation, 0))
5082 {
5083 // this is not supposed to happen
5084 wxLogLastError(_T("SystemParametersInfo(GETWHEELSCROLLLINES)"));
5085
5086 // the default is 3, so use it if SystemParametersInfo() failed
5087 s_linesPerRotation = 3;
5088 }
5089 }
5090
5091 event.m_linesPerAction = s_linesPerRotation;
5092 return GetEventHandler()->ProcessEvent(event);
5093
5094 #else // !wxUSE_MOUSEWHEEL
5095 wxUnusedVar(wParam);
5096 wxUnusedVar(lParam);
5097
5098 return false;
5099 #endif // wxUSE_MOUSEWHEEL/!wxUSE_MOUSEWHEEL
5100 }
5101
5102 void wxWindowMSW::GenerateMouseLeave()
5103 {
5104 m_mouseInWindow = false;
5105
5106 int state = 0;
5107 if ( wxIsShiftDown() )
5108 state |= MK_SHIFT;
5109 if ( wxIsCtrlDown() )
5110 state |= MK_CONTROL;
5111
5112 // Only the high-order bit should be tested
5113 if ( GetKeyState( VK_LBUTTON ) & (1<<15) )
5114 state |= MK_LBUTTON;
5115 if ( GetKeyState( VK_MBUTTON ) & (1<<15) )
5116 state |= MK_MBUTTON;
5117 if ( GetKeyState( VK_RBUTTON ) & (1<<15) )
5118 state |= MK_RBUTTON;
5119
5120 POINT pt;
5121 #ifdef __WXWINCE__
5122 if ( !::GetCursorPosWinCE(&pt) )
5123 #else
5124 if ( !::GetCursorPos(&pt) )
5125 #endif
5126 {
5127 wxLogLastError(_T("GetCursorPos"));
5128 }
5129
5130 // we need to have client coordinates here for symmetry with
5131 // wxEVT_ENTER_WINDOW
5132 RECT rect = wxGetWindowRect(GetHwnd());
5133 pt.x -= rect.left;
5134 pt.y -= rect.top;
5135
5136 wxMouseEvent event(wxEVT_LEAVE_WINDOW);
5137 InitMouseEvent(event, pt.x, pt.y, state);
5138
5139 (void)GetEventHandler()->ProcessEvent(event);
5140 }
5141
5142 // ---------------------------------------------------------------------------
5143 // keyboard handling
5144 // ---------------------------------------------------------------------------
5145
5146 // create the key event of the given type for the given key - used by
5147 // HandleChar and HandleKeyDown/Up
5148 wxKeyEvent wxWindowMSW::CreateKeyEvent(wxEventType evType,
5149 int id,
5150 WXLPARAM lParam,
5151 WXWPARAM wParam) const
5152 {
5153 wxKeyEvent event(evType);
5154 event.SetId(GetId());
5155 event.m_shiftDown = wxIsShiftDown();
5156 event.m_controlDown = wxIsCtrlDown();
5157 event.m_altDown = (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN;
5158
5159 event.SetEventObject((wxWindow *)this); // const_cast
5160 event.m_keyCode = id;
5161 #if wxUSE_UNICODE
5162 event.m_uniChar = (wxChar) wParam;
5163 #endif
5164 event.m_rawCode = (wxUint32) wParam;
5165 event.m_rawFlags = (wxUint32) lParam;
5166 #ifndef __WXWINCE__
5167 event.SetTimestamp(::GetMessageTime());
5168 #endif
5169
5170 // translate the position to client coords
5171 POINT pt;
5172 #ifdef __WXWINCE__
5173 GetCursorPosWinCE(&pt);
5174 #else
5175 GetCursorPos(&pt);
5176 #endif
5177 RECT rect;
5178 GetWindowRect(GetHwnd(),&rect);
5179 pt.x -= rect.left;
5180 pt.y -= rect.top;
5181
5182 event.m_x = pt.x;
5183 event.m_y = pt.y;
5184
5185 return event;
5186 }
5187
5188 // isASCII is true only when we're called from WM_CHAR handler and not from
5189 // WM_KEYDOWN one
5190 bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam, bool isASCII)
5191 {
5192 int id;
5193 if ( isASCII )
5194 {
5195 id = wParam;
5196 }
5197 else // we're called from WM_KEYDOWN
5198 {
5199 // don't pass lParam to wxCharCodeMSWToWX() here because we don't want
5200 // to get numpad key codes: CHAR events should use the logical keys
5201 // such as WXK_HOME instead of WXK_NUMPAD_HOME which is for KEY events
5202 id = wxCharCodeMSWToWX(wParam);
5203 if ( id == 0 )
5204 {
5205 // it's ASCII and will be processed here only when called from
5206 // WM_CHAR (i.e. when isASCII = true), don't process it now
5207 return false;
5208 }
5209 }
5210
5211 wxKeyEvent event(CreateKeyEvent(wxEVT_CHAR, id, lParam, wParam));
5212
5213 // the alphanumeric keys produced by pressing AltGr+something on European
5214 // keyboards have both Ctrl and Alt modifiers which may confuse the user
5215 // code as, normally, keys with Ctrl and/or Alt don't result in anything
5216 // alphanumeric, so pretend that there are no modifiers at all (the
5217 // KEY_DOWN event would still have the correct modifiers if they're really
5218 // needed)
5219 if ( event.m_controlDown && event.m_altDown &&
5220 (id >= 32 && id < 256) )
5221 {
5222 event.m_controlDown =
5223 event.m_altDown = false;
5224 }
5225
5226 return GetEventHandler()->ProcessEvent(event);
5227 }
5228
5229 bool wxWindowMSW::HandleKeyDown(WXWPARAM wParam, WXLPARAM lParam)
5230 {
5231 int id = wxCharCodeMSWToWX(wParam, lParam);
5232
5233 if ( !id )
5234 {
5235 // normal ASCII char
5236 id = wParam;
5237 }
5238
5239 wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_DOWN, id, lParam, wParam));
5240 return GetEventHandler()->ProcessEvent(event);
5241 }
5242
5243 bool wxWindowMSW::HandleKeyUp(WXWPARAM wParam, WXLPARAM lParam)
5244 {
5245 int id = wxCharCodeMSWToWX(wParam, lParam);
5246
5247 if ( !id )
5248 {
5249 // normal ASCII char
5250 id = wParam;
5251 }
5252
5253 wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_UP, id, lParam, wParam));
5254 return GetEventHandler()->ProcessEvent(event);
5255 }
5256
5257 #if wxUSE_MENUS
5258 int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel),
5259 WXLPARAM WXUNUSED_IN_WINCE(lParam))
5260 {
5261 // FIXME: implement GetMenuItemCount for WinCE, possibly
5262 // in terms of GetMenuItemInfo
5263 #ifndef __WXWINCE__
5264 const HMENU hmenu = (HMENU)lParam;
5265
5266 MENUITEMINFO mii;
5267 wxZeroMemory(mii);
5268 mii.cbSize = sizeof(MENUITEMINFO);
5269
5270 // we could use MIIM_FTYPE here as we only need to know if the item is
5271 // ownerdrawn or not and not dwTypeData which MIIM_TYPE also returns, but
5272 // MIIM_FTYPE is not supported under Win95
5273 mii.fMask = MIIM_TYPE | MIIM_DATA;
5274
5275 // find if we have this letter in any owner drawn item
5276 const int count = ::GetMenuItemCount(hmenu);
5277 for ( int i = 0; i < count; i++ )
5278 {
5279 // previous loop iteration could modify it, reset it back before
5280 // calling GetMenuItemInfo() to prevent it from overflowing dwTypeData
5281 mii.cch = 0;
5282
5283 if ( ::GetMenuItemInfo(hmenu, i, TRUE, &mii) )
5284 {
5285 if ( mii.fType == MFT_OWNERDRAW )
5286 {
5287 // dwItemData member of the MENUITEMINFO is a
5288 // pointer to the associated wxMenuItem -- see the
5289 // menu creation code
5290 wxMenuItem *item = (wxMenuItem*)mii.dwItemData;
5291
5292 const wxChar *p = wxStrchr(item->GetText().wx_str(), _T('&'));
5293 while ( p++ )
5294 {
5295 if ( *p == _T('&') )
5296 {
5297 // this is not the accel char, find the real one
5298 p = wxStrchr(p + 1, _T('&'));
5299 }
5300 else // got the accel char
5301 {
5302 // FIXME-UNICODE: this comparison doesn't risk to work
5303 // for non ASCII accelerator characters I'm afraid, but
5304 // what can we do?
5305 if ( (wchar_t)wxToupper(*p) == (wchar_t)chAccel )
5306 {
5307 return i;
5308 }
5309 else
5310 {
5311 // this one doesn't match
5312 break;
5313 }
5314 }
5315 }
5316 }
5317 }
5318 else // failed to get the menu text?
5319 {
5320 // it's not fatal, so don't show error, but still log it
5321 wxLogLastError(_T("GetMenuItemInfo"));
5322 }
5323 }
5324 #endif
5325 return wxNOT_FOUND;
5326 }
5327
5328 bool wxWindowMSW::HandleClipboardEvent( WXUINT nMsg )
5329 {
5330 const wxEventType type = ( nMsg == WM_CUT ) ? wxEVT_COMMAND_TEXT_CUT :
5331 ( nMsg == WM_COPY ) ? wxEVT_COMMAND_TEXT_COPY :
5332 /*( nMsg == WM_PASTE ) ? */ wxEVT_COMMAND_TEXT_PASTE;
5333 wxClipboardTextEvent evt(type, GetId());
5334
5335 evt.SetEventObject(this);
5336
5337 return GetEventHandler()->ProcessEvent(evt);
5338 }
5339 #endif // wxUSE_MENUS
5340
5341 // ---------------------------------------------------------------------------
5342 // joystick
5343 // ---------------------------------------------------------------------------
5344
5345 bool wxWindowMSW::HandleJoystickEvent(WXUINT msg, int x, int y, WXUINT flags)
5346 {
5347 #ifdef JOY_BUTTON1
5348 int change = 0;
5349 if ( flags & JOY_BUTTON1CHG )
5350 change = wxJOY_BUTTON1;
5351 if ( flags & JOY_BUTTON2CHG )
5352 change = wxJOY_BUTTON2;
5353 if ( flags & JOY_BUTTON3CHG )
5354 change = wxJOY_BUTTON3;
5355 if ( flags & JOY_BUTTON4CHG )
5356 change = wxJOY_BUTTON4;
5357
5358 int buttons = 0;
5359 if ( flags & JOY_BUTTON1 )
5360 buttons |= wxJOY_BUTTON1;
5361 if ( flags & JOY_BUTTON2 )
5362 buttons |= wxJOY_BUTTON2;
5363 if ( flags & JOY_BUTTON3 )
5364 buttons |= wxJOY_BUTTON3;
5365 if ( flags & JOY_BUTTON4 )
5366 buttons |= wxJOY_BUTTON4;
5367
5368 // the event ids aren't consecutive so we can't use table based lookup
5369 int joystick;
5370 wxEventType eventType;
5371 switch ( msg )
5372 {
5373 case MM_JOY1MOVE:
5374 joystick = 1;
5375 eventType = wxEVT_JOY_MOVE;
5376 break;
5377
5378 case MM_JOY2MOVE:
5379 joystick = 2;
5380 eventType = wxEVT_JOY_MOVE;
5381 break;
5382
5383 case MM_JOY1ZMOVE:
5384 joystick = 1;
5385 eventType = wxEVT_JOY_ZMOVE;
5386 break;
5387
5388 case MM_JOY2ZMOVE:
5389 joystick = 2;
5390 eventType = wxEVT_JOY_ZMOVE;
5391 break;
5392
5393 case MM_JOY1BUTTONDOWN:
5394 joystick = 1;
5395 eventType = wxEVT_JOY_BUTTON_DOWN;
5396 break;
5397
5398 case MM_JOY2BUTTONDOWN:
5399 joystick = 2;
5400 eventType = wxEVT_JOY_BUTTON_DOWN;
5401 break;
5402
5403 case MM_JOY1BUTTONUP:
5404 joystick = 1;
5405 eventType = wxEVT_JOY_BUTTON_UP;
5406 break;
5407
5408 case MM_JOY2BUTTONUP:
5409 joystick = 2;
5410 eventType = wxEVT_JOY_BUTTON_UP;
5411 break;
5412
5413 default:
5414 wxFAIL_MSG(wxT("no such joystick event"));
5415
5416 return false;
5417 }
5418
5419 wxJoystickEvent event(eventType, buttons, joystick, change);
5420 event.SetPosition(wxPoint(x, y));
5421 event.SetEventObject(this);
5422
5423 return GetEventHandler()->ProcessEvent(event);
5424 #else
5425 wxUnusedVar(msg);
5426 wxUnusedVar(x);
5427 wxUnusedVar(y);
5428 wxUnusedVar(flags);
5429 return false;
5430 #endif
5431 }
5432
5433 // ---------------------------------------------------------------------------
5434 // scrolling
5435 // ---------------------------------------------------------------------------
5436
5437 bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam,
5438 WXWORD pos, WXHWND control)
5439 {
5440 if ( control && control != m_hWnd ) // Prevent infinite recursion
5441 {
5442 wxWindow *child = wxFindWinFromHandle(control);
5443 if ( child )
5444 return child->MSWOnScroll(orientation, wParam, pos, control);
5445 }
5446
5447 wxScrollWinEvent event;
5448 event.SetPosition(pos);
5449 event.SetOrientation(orientation);
5450 event.SetEventObject(this);
5451
5452 switch ( wParam )
5453 {
5454 case SB_TOP:
5455 event.SetEventType(wxEVT_SCROLLWIN_TOP);
5456 break;
5457
5458 case SB_BOTTOM:
5459 event.SetEventType(wxEVT_SCROLLWIN_BOTTOM);
5460 break;
5461
5462 case SB_LINEUP:
5463 event.SetEventType(wxEVT_SCROLLWIN_LINEUP);
5464 break;
5465
5466 case SB_LINEDOWN:
5467 event.SetEventType(wxEVT_SCROLLWIN_LINEDOWN);
5468 break;
5469
5470 case SB_PAGEUP:
5471 event.SetEventType(wxEVT_SCROLLWIN_PAGEUP);
5472 break;
5473
5474 case SB_PAGEDOWN:
5475 event.SetEventType(wxEVT_SCROLLWIN_PAGEDOWN);
5476 break;
5477
5478 case SB_THUMBPOSITION:
5479 case SB_THUMBTRACK:
5480 // under Win32, the scrollbar range and position are 32 bit integers,
5481 // but WM_[HV]SCROLL only carry the low 16 bits of them, so we must
5482 // explicitly query the scrollbar for the correct position (this must
5483 // be done only for these two SB_ events as they are the only one
5484 // carrying the scrollbar position)
5485 {
5486 WinStruct<SCROLLINFO> scrollInfo;
5487 scrollInfo.fMask = SIF_TRACKPOS;
5488
5489 if ( !::GetScrollInfo(GetHwnd(),
5490 orientation == wxHORIZONTAL ? SB_HORZ
5491 : SB_VERT,
5492 &scrollInfo) )
5493 {
5494 // Not necessarily an error, if there are no scrollbars yet.
5495 // wxLogLastError(_T("GetScrollInfo"));
5496 }
5497
5498 event.SetPosition(scrollInfo.nTrackPos);
5499 }
5500
5501 event.SetEventType( wParam == SB_THUMBPOSITION
5502 ? wxEVT_SCROLLWIN_THUMBRELEASE
5503 : wxEVT_SCROLLWIN_THUMBTRACK );
5504 break;
5505
5506 default:
5507 return false;
5508 }
5509
5510 return GetEventHandler()->ProcessEvent(event);
5511 }
5512
5513 // ----------------------------------------------------------------------------
5514 // custom message handlers
5515 // ----------------------------------------------------------------------------
5516
5517 /* static */ bool
5518 wxWindowMSW::MSWRegisterMessageHandler(int msg, MSWMessageHandler handler)
5519 {
5520 wxCHECK_MSG( gs_messageHandlers.find(msg) == gs_messageHandlers.end(),
5521 false, _T("registering handler for the same message twice") );
5522
5523 gs_messageHandlers[msg] = handler;
5524 return true;
5525 }
5526
5527 /* static */ void
5528 wxWindowMSW::MSWUnregisterMessageHandler(int msg, MSWMessageHandler handler)
5529 {
5530 const MSWMessageHandlers::iterator i = gs_messageHandlers.find(msg);
5531 wxCHECK_RET( i != gs_messageHandlers.end() && i->second == handler,
5532 _T("unregistering non-registered handler?") );
5533
5534 gs_messageHandlers.erase(i);
5535 }
5536
5537 // ===========================================================================
5538 // global functions
5539 // ===========================================================================
5540
5541 void wxGetCharSize(WXHWND wnd, int *x, int *y, const wxFont& the_font)
5542 {
5543 TEXTMETRIC tm;
5544 HDC dc = ::GetDC((HWND) wnd);
5545 HFONT was = 0;
5546
5547 // the_font.UseResource();
5548 // the_font.RealizeResource();
5549 HFONT fnt = (HFONT)the_font.GetResourceHandle(); // const_cast
5550 if ( fnt )
5551 was = (HFONT) SelectObject(dc,fnt);
5552
5553 GetTextMetrics(dc, &tm);
5554 if ( fnt && was )
5555 {
5556 SelectObject(dc,was);
5557 }
5558 ReleaseDC((HWND)wnd, dc);
5559
5560 if ( x )
5561 *x = tm.tmAveCharWidth;
5562 if ( y )
5563 *y = tm.tmHeight + tm.tmExternalLeading;
5564
5565 // the_font.ReleaseResource();
5566 }
5567
5568 // use the "extended" bit (24) of lParam to distinguish extended keys
5569 // from normal keys as the same key is sent
5570 static inline
5571 int ChooseNormalOrExtended(int lParam, int keyNormal, int keyExtended)
5572 {
5573 // except that if lParam is 0, it means we don't have real lParam from
5574 // WM_KEYDOWN but are just translating just a VK constant (e.g. done from
5575 // msw/treectrl.cpp when processing TVN_KEYDOWN) -- then assume this is a
5576 // non-numpad (hence extended) key as this is a more common case
5577 return !lParam || (lParam & (1 << 24)) ? keyExtended : keyNormal;
5578 }
5579
5580 // this array contains the Windows virtual key codes which map one to one to
5581 // WXK_xxx constants and is used in wxCharCodeMSWToWX/WXToMSW() below
5582 //
5583 // note that keys having a normal and numpad version (e.g. WXK_HOME and
5584 // WXK_NUMPAD_HOME) are not included in this table as the mapping is not 1-to-1
5585 static const struct wxKeyMapping
5586 {
5587 int vk;
5588 wxKeyCode wxk;
5589 } gs_specialKeys[] =
5590 {
5591 { VK_CANCEL, WXK_CANCEL },
5592 { VK_BACK, WXK_BACK },
5593 { VK_TAB, WXK_TAB },
5594 { VK_CLEAR, WXK_CLEAR },
5595 { VK_SHIFT, WXK_SHIFT },
5596 { VK_CONTROL, WXK_CONTROL },
5597 { VK_MENU , WXK_ALT },
5598 { VK_PAUSE, WXK_PAUSE },
5599 { VK_CAPITAL, WXK_CAPITAL },
5600 { VK_SPACE, WXK_SPACE },
5601 { VK_ESCAPE, WXK_ESCAPE },
5602 { VK_SELECT, WXK_SELECT },
5603 { VK_PRINT, WXK_PRINT },
5604 { VK_EXECUTE, WXK_EXECUTE },
5605 { VK_SNAPSHOT, WXK_SNAPSHOT },
5606 { VK_HELP, WXK_HELP },
5607
5608 { VK_NUMPAD0, WXK_NUMPAD0 },
5609 { VK_NUMPAD1, WXK_NUMPAD1 },
5610 { VK_NUMPAD2, WXK_NUMPAD2 },
5611 { VK_NUMPAD3, WXK_NUMPAD3 },
5612 { VK_NUMPAD4, WXK_NUMPAD4 },
5613 { VK_NUMPAD5, WXK_NUMPAD5 },
5614 { VK_NUMPAD6, WXK_NUMPAD6 },
5615 { VK_NUMPAD7, WXK_NUMPAD7 },
5616 { VK_NUMPAD8, WXK_NUMPAD8 },
5617 { VK_NUMPAD9, WXK_NUMPAD9 },
5618 { VK_MULTIPLY, WXK_NUMPAD_MULTIPLY },
5619 { VK_ADD, WXK_NUMPAD_ADD },
5620 { VK_SUBTRACT, WXK_NUMPAD_SUBTRACT },
5621 { VK_DECIMAL, WXK_NUMPAD_DECIMAL },
5622 { VK_DIVIDE, WXK_NUMPAD_DIVIDE },
5623
5624 { VK_F1, WXK_F1 },
5625 { VK_F2, WXK_F2 },
5626 { VK_F3, WXK_F3 },
5627 { VK_F4, WXK_F4 },
5628 { VK_F5, WXK_F5 },
5629 { VK_F6, WXK_F6 },
5630 { VK_F7, WXK_F7 },
5631 { VK_F8, WXK_F8 },
5632 { VK_F9, WXK_F9 },
5633 { VK_F10, WXK_F10 },
5634 { VK_F11, WXK_F11 },
5635 { VK_F12, WXK_F12 },
5636 { VK_F13, WXK_F13 },
5637 { VK_F14, WXK_F14 },
5638 { VK_F15, WXK_F15 },
5639 { VK_F16, WXK_F16 },
5640 { VK_F17, WXK_F17 },
5641 { VK_F18, WXK_F18 },
5642 { VK_F19, WXK_F19 },
5643 { VK_F20, WXK_F20 },
5644 { VK_F21, WXK_F21 },
5645 { VK_F22, WXK_F22 },
5646 { VK_F23, WXK_F23 },
5647 { VK_F24, WXK_F24 },
5648
5649 { VK_NUMLOCK, WXK_NUMLOCK },
5650 { VK_SCROLL, WXK_SCROLL },
5651
5652 #ifdef VK_APPS
5653 { VK_LWIN, WXK_WINDOWS_LEFT },
5654 { VK_RWIN, WXK_WINDOWS_RIGHT },
5655 { VK_APPS, WXK_WINDOWS_MENU },
5656 #endif // VK_APPS defined
5657 };
5658
5659 // Returns 0 if was a normal ASCII value, not a special key. This indicates that
5660 // the key should be ignored by WM_KEYDOWN and processed by WM_CHAR instead.
5661 int wxCharCodeMSWToWX(int vk, WXLPARAM lParam)
5662 {
5663 // check the table first
5664 for ( size_t n = 0; n < WXSIZEOF(gs_specialKeys); n++ )
5665 {
5666 if ( gs_specialKeys[n].vk == vk )
5667 return gs_specialKeys[n].wxk;
5668 }
5669
5670 // keys requiring special handling
5671 int wxk;
5672 switch ( vk )
5673 {
5674 // the mapping for these keys may be incorrect on non-US keyboards so
5675 // maybe we shouldn't map them to ASCII values at all
5676 case VK_OEM_1: wxk = ';'; break;
5677 case VK_OEM_PLUS: wxk = '+'; break;
5678 case VK_OEM_COMMA: wxk = ','; break;
5679 case VK_OEM_MINUS: wxk = '-'; break;
5680 case VK_OEM_PERIOD: wxk = '.'; break;
5681 case VK_OEM_2: wxk = '/'; break;
5682 case VK_OEM_3: wxk = '~'; break;
5683 case VK_OEM_4: wxk = '['; break;
5684 case VK_OEM_5: wxk = '\\'; break;
5685 case VK_OEM_6: wxk = ']'; break;
5686 case VK_OEM_7: wxk = '\''; break;
5687
5688 // handle extended keys
5689 case VK_PRIOR:
5690 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_PAGEUP, WXK_PAGEUP);
5691 break;
5692
5693 case VK_NEXT:
5694 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_PAGEDOWN, WXK_PAGEDOWN);
5695 break;
5696
5697 case VK_END:
5698 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_END, WXK_END);
5699 break;
5700
5701 case VK_HOME:
5702 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_HOME, WXK_HOME);
5703 break;
5704
5705 case VK_LEFT:
5706 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_LEFT, WXK_LEFT);
5707 break;
5708
5709 case VK_UP:
5710 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_UP, WXK_UP);
5711 break;
5712
5713 case VK_RIGHT:
5714 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_RIGHT, WXK_RIGHT);
5715 break;
5716
5717 case VK_DOWN:
5718 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DOWN, WXK_DOWN);
5719 break;
5720
5721 case VK_INSERT:
5722 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_INSERT, WXK_INSERT);
5723 break;
5724
5725 case VK_DELETE:
5726 wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DELETE, WXK_DELETE);
5727 break;
5728
5729 case VK_RETURN:
5730 // don't use ChooseNormalOrExtended() here as the keys are reversed
5731 // here: numpad enter is the extended one
5732 wxk = lParam && (lParam & (1 << 24)) ? WXK_NUMPAD_ENTER : WXK_RETURN;
5733 break;
5734
5735 default:
5736 wxk = 0;
5737 }
5738
5739 return wxk;
5740 }
5741
5742 WXWORD wxCharCodeWXToMSW(int wxk, bool *isVirtual)
5743 {
5744 if ( isVirtual )
5745 *isVirtual = true;
5746
5747 // check the table first
5748 for ( size_t n = 0; n < WXSIZEOF(gs_specialKeys); n++ )
5749 {
5750 if ( gs_specialKeys[n].wxk == wxk )
5751 return gs_specialKeys[n].vk;
5752 }
5753
5754 // and then check for special keys not included in the table
5755 WXWORD vk;
5756 switch ( wxk )
5757 {
5758 case WXK_PAGEUP:
5759 case WXK_NUMPAD_PAGEUP:
5760 vk = VK_PRIOR;
5761 break;
5762
5763 case WXK_PAGEDOWN:
5764 case WXK_NUMPAD_PAGEDOWN:
5765 vk = VK_NEXT;
5766 break;
5767
5768 case WXK_END:
5769 case WXK_NUMPAD_END:
5770 vk = VK_END;
5771 break;
5772
5773 case WXK_HOME:
5774 case WXK_NUMPAD_HOME:
5775 vk = VK_HOME;
5776 break;
5777
5778 case WXK_LEFT:
5779 case WXK_NUMPAD_LEFT:
5780 vk = VK_LEFT;
5781 break;
5782
5783 case WXK_UP:
5784 case WXK_NUMPAD_UP:
5785 vk = VK_UP;
5786 break;
5787
5788 case WXK_RIGHT:
5789 case WXK_NUMPAD_RIGHT:
5790 vk = VK_RIGHT;
5791 break;
5792
5793 case WXK_DOWN:
5794 case WXK_NUMPAD_DOWN:
5795 vk = VK_DOWN;
5796 break;
5797
5798 case WXK_INSERT:
5799 case WXK_NUMPAD_INSERT:
5800 vk = VK_INSERT;
5801 break;
5802
5803 case WXK_DELETE:
5804 case WXK_NUMPAD_DELETE:
5805 vk = VK_DELETE;
5806 break;
5807
5808 default:
5809 if ( isVirtual )
5810 *isVirtual = false;
5811 vk = (WXWORD)wxk;
5812 break;
5813 }
5814
5815 return vk;
5816 }
5817
5818 #ifndef SM_SWAPBUTTON
5819 #define SM_SWAPBUTTON 23
5820 #endif
5821
5822 // small helper for wxGetKeyState() and wxGetMouseState()
5823 static inline bool wxIsKeyDown(WXWORD vk)
5824 {
5825 switch (vk)
5826 {
5827 case VK_LBUTTON:
5828 if (GetSystemMetrics(SM_SWAPBUTTON)) vk = VK_RBUTTON;
5829 break;
5830 case VK_RBUTTON:
5831 if (GetSystemMetrics(SM_SWAPBUTTON)) vk = VK_LBUTTON;
5832 break;
5833 }
5834 // the low order bit indicates whether the key was pressed since the last
5835 // call and the high order one indicates whether it is down right now and
5836 // we only want that one
5837 return (GetAsyncKeyState(vk) & (1<<15)) != 0;
5838 }
5839
5840 bool wxGetKeyState(wxKeyCode key)
5841 {
5842 // although this does work under Windows, it is not supported under other
5843 // platforms so don't allow it, you must use wxGetMouseState() instead
5844 wxASSERT_MSG( key != VK_LBUTTON &&
5845 key != VK_RBUTTON &&
5846 key != VK_MBUTTON,
5847 wxT("can't use wxGetKeyState() for mouse buttons") );
5848
5849 const WXWORD vk = wxCharCodeWXToMSW(key);
5850
5851 // if the requested key is a LED key, return true if the led is pressed
5852 if ( key == WXK_NUMLOCK || key == WXK_CAPITAL || key == WXK_SCROLL )
5853 {
5854 // low order bit means LED is highlighted and high order one means the
5855 // key is down; for compatibility with the other ports return true if
5856 // either one is set
5857 return GetKeyState(vk) != 0;
5858
5859 }
5860 else // normal key
5861 {
5862 return wxIsKeyDown(vk);
5863 }
5864 }
5865
5866
5867 wxMouseState wxGetMouseState()
5868 {
5869 wxMouseState ms;
5870 POINT pt;
5871 GetCursorPos( &pt );
5872
5873 ms.SetX(pt.x);
5874 ms.SetY(pt.y);
5875 ms.SetLeftDown(wxIsKeyDown(VK_LBUTTON));
5876 ms.SetMiddleDown(wxIsKeyDown(VK_MBUTTON));
5877 ms.SetRightDown(wxIsKeyDown(VK_RBUTTON));
5878 #ifdef wxHAS_XBUTTON
5879 ms.SetAux1Down(wxIsKeyDown(VK_XBUTTON1));
5880 ms.SetAux2Down(wxIsKeyDown(VK_XBUTTON2));
5881 #endif // wxHAS_XBUTTON
5882
5883 ms.SetControlDown(wxIsKeyDown(VK_CONTROL));
5884 ms.SetShiftDown(wxIsKeyDown(VK_SHIFT));
5885 ms.SetAltDown(wxIsKeyDown(VK_MENU));
5886 // ms.SetMetaDown();
5887
5888 return ms;
5889 }
5890
5891
5892 wxWindow *wxGetActiveWindow()
5893 {
5894 HWND hWnd = GetActiveWindow();
5895 if ( hWnd != 0 )
5896 {
5897 return wxFindWinFromHandle((WXHWND) hWnd);
5898 }
5899 return NULL;
5900 }
5901
5902 extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd)
5903 {
5904 HWND hwnd = (HWND)hWnd;
5905
5906 // For a radiobutton, we get the radiobox from GWL_USERDATA (which is set
5907 // by code in msw/radiobox.cpp), for all the others we just search up the
5908 // window hierarchy
5909 wxWindow *win = (wxWindow *)NULL;
5910 if ( hwnd )
5911 {
5912 win = wxFindWinFromHandle((WXHWND)hwnd);
5913 if ( !win )
5914 {
5915 #if wxUSE_RADIOBOX
5916 // native radiobuttons return DLGC_RADIOBUTTON here and for any
5917 // wxWindow class which overrides WM_GETDLGCODE processing to
5918 // do it as well, win would be already non NULL
5919 if ( ::SendMessage(hwnd, WM_GETDLGCODE, 0, 0) & DLGC_RADIOBUTTON )
5920 {
5921 win = (wxWindow *)wxGetWindowUserData(hwnd);
5922 }
5923 //else: it's a wxRadioButton, not a radiobutton from wxRadioBox
5924 #endif // wxUSE_RADIOBOX
5925
5926 // spin control text buddy window should be mapped to spin ctrl
5927 // itself so try it too
5928 #if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__)
5929 if ( !win )
5930 {
5931 win = wxSpinCtrl::GetSpinForTextCtrl((WXHWND)hwnd);
5932 }
5933 #endif // wxUSE_SPINCTRL
5934 }
5935 }
5936
5937 while ( hwnd && !win )
5938 {
5939 // this is a really ugly hack needed to avoid mistakenly returning the
5940 // parent frame wxWindow for the find/replace modeless dialog HWND -
5941 // this, in turn, is needed to call IsDialogMessage() from
5942 // wxApp::ProcessMessage() as for this we must return NULL from here
5943 //
5944 // FIXME: this is clearly not the best way to do it but I think we'll
5945 // need to change HWND <-> wxWindow code more heavily than I can
5946 // do it now to fix it
5947 #ifndef __WXMICROWIN__
5948 if ( ::GetWindow(hwnd, GW_OWNER) )
5949 {
5950 // it's a dialog box, don't go upwards
5951 break;
5952 }
5953 #endif
5954
5955 hwnd = ::GetParent(hwnd);
5956 win = wxFindWinFromHandle((WXHWND)hwnd);
5957 }
5958
5959 return win;
5960 }
5961
5962 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
5963
5964 // Windows keyboard hook. Allows interception of e.g. F1, ESCAPE
5965 // in active frames and dialogs, regardless of where the focus is.
5966 static HHOOK wxTheKeyboardHook = 0;
5967 static FARPROC wxTheKeyboardHookProc = 0;
5968 int APIENTRY _EXPORT
5969 wxKeyboardHook(int nCode, WORD wParam, DWORD lParam);
5970
5971 void wxSetKeyboardHook(bool doIt)
5972 {
5973 if ( doIt )
5974 {
5975 wxTheKeyboardHookProc = MakeProcInstance((FARPROC) wxKeyboardHook, wxGetInstance());
5976 wxTheKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC) wxTheKeyboardHookProc, wxGetInstance(),
5977
5978 GetCurrentThreadId()
5979 // (DWORD)GetCurrentProcess()); // This is another possibility. Which is right?
5980 );
5981 }
5982 else
5983 {
5984 UnhookWindowsHookEx(wxTheKeyboardHook);
5985 }
5986 }
5987
5988 int APIENTRY _EXPORT
5989 wxKeyboardHook(int nCode, WORD wParam, DWORD lParam)
5990 {
5991 DWORD hiWord = HIWORD(lParam);
5992 if ( nCode != HC_NOREMOVE && ((hiWord & KF_UP) == 0) )
5993 {
5994 int id = wxCharCodeMSWToWX(wParam, lParam);
5995 if ( id != 0 )
5996 {
5997 wxKeyEvent event(wxEVT_CHAR_HOOK);
5998 if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN )
5999 event.m_altDown = true;
6000
6001 event.SetEventObject(NULL);
6002 event.m_keyCode = id;
6003 event.m_shiftDown = wxIsShiftDown();
6004 event.m_controlDown = wxIsCtrlDown();
6005 #ifndef __WXWINCE__
6006 event.SetTimestamp(::GetMessageTime());
6007 #endif
6008 wxWindow *win = wxGetActiveWindow();
6009 wxEvtHandler *handler;
6010 if ( win )
6011 {
6012 handler = win->GetEventHandler();
6013 event.SetId(win->GetId());
6014 }
6015 else
6016 {
6017 handler = wxTheApp;
6018 event.SetId(wxID_ANY);
6019 }
6020
6021 if ( handler && handler->ProcessEvent(event) )
6022 {
6023 // processed
6024 return 1;
6025 }
6026 }
6027 }
6028
6029 return (int)CallNextHookEx(wxTheKeyboardHook, nCode, wParam, lParam);
6030 }
6031
6032 #endif // !__WXMICROWIN__
6033
6034 #ifdef __WXDEBUG__
6035 const wxChar *wxGetMessageName(int message)
6036 {
6037 switch ( message )
6038 {
6039 case 0x0000: return wxT("WM_NULL");
6040 case 0x0001: return wxT("WM_CREATE");
6041 case 0x0002: return wxT("WM_DESTROY");
6042 case 0x0003: return wxT("WM_MOVE");
6043 case 0x0005: return wxT("WM_SIZE");
6044 case 0x0006: return wxT("WM_ACTIVATE");
6045 case 0x0007: return wxT("WM_SETFOCUS");
6046 case 0x0008: return wxT("WM_KILLFOCUS");
6047 case 0x000A: return wxT("WM_ENABLE");
6048 case 0x000B: return wxT("WM_SETREDRAW");
6049 case 0x000C: return wxT("WM_SETTEXT");
6050 case 0x000D: return wxT("WM_GETTEXT");
6051 case 0x000E: return wxT("WM_GETTEXTLENGTH");
6052 case 0x000F: return wxT("WM_PAINT");
6053 case 0x0010: return wxT("WM_CLOSE");
6054 case 0x0011: return wxT("WM_QUERYENDSESSION");
6055 case 0x0012: return wxT("WM_QUIT");
6056 case 0x0013: return wxT("WM_QUERYOPEN");
6057 case 0x0014: return wxT("WM_ERASEBKGND");
6058 case 0x0015: return wxT("WM_SYSCOLORCHANGE");
6059 case 0x0016: return wxT("WM_ENDSESSION");
6060 case 0x0017: return wxT("WM_SYSTEMERROR");
6061 case 0x0018: return wxT("WM_SHOWWINDOW");
6062 case 0x0019: return wxT("WM_CTLCOLOR");
6063 case 0x001A: return wxT("WM_WININICHANGE");
6064 case 0x001B: return wxT("WM_DEVMODECHANGE");
6065 case 0x001C: return wxT("WM_ACTIVATEAPP");
6066 case 0x001D: return wxT("WM_FONTCHANGE");
6067 case 0x001E: return wxT("WM_TIMECHANGE");
6068 case 0x001F: return wxT("WM_CANCELMODE");
6069 case 0x0020: return wxT("WM_SETCURSOR");
6070 case 0x0021: return wxT("WM_MOUSEACTIVATE");
6071 case 0x0022: return wxT("WM_CHILDACTIVATE");
6072 case 0x0023: return wxT("WM_QUEUESYNC");
6073 case 0x0024: return wxT("WM_GETMINMAXINFO");
6074 case 0x0026: return wxT("WM_PAINTICON");
6075 case 0x0027: return wxT("WM_ICONERASEBKGND");
6076 case 0x0028: return wxT("WM_NEXTDLGCTL");
6077 case 0x002A: return wxT("WM_SPOOLERSTATUS");
6078 case 0x002B: return wxT("WM_DRAWITEM");
6079 case 0x002C: return wxT("WM_MEASUREITEM");
6080 case 0x002D: return wxT("WM_DELETEITEM");
6081 case 0x002E: return wxT("WM_VKEYTOITEM");
6082 case 0x002F: return wxT("WM_CHARTOITEM");
6083 case 0x0030: return wxT("WM_SETFONT");
6084 case 0x0031: return wxT("WM_GETFONT");
6085 case 0x0037: return wxT("WM_QUERYDRAGICON");
6086 case 0x0039: return wxT("WM_COMPAREITEM");
6087 case 0x0041: return wxT("WM_COMPACTING");
6088 case 0x0044: return wxT("WM_COMMNOTIFY");
6089 case 0x0046: return wxT("WM_WINDOWPOSCHANGING");
6090 case 0x0047: return wxT("WM_WINDOWPOSCHANGED");
6091 case 0x0048: return wxT("WM_POWER");
6092
6093 case 0x004A: return wxT("WM_COPYDATA");
6094 case 0x004B: return wxT("WM_CANCELJOURNAL");
6095 case 0x004E: return wxT("WM_NOTIFY");
6096 case 0x0050: return wxT("WM_INPUTLANGCHANGEREQUEST");
6097 case 0x0051: return wxT("WM_INPUTLANGCHANGE");
6098 case 0x0052: return wxT("WM_TCARD");
6099 case 0x0053: return wxT("WM_HELP");
6100 case 0x0054: return wxT("WM_USERCHANGED");
6101 case 0x0055: return wxT("WM_NOTIFYFORMAT");
6102 case 0x007B: return wxT("WM_CONTEXTMENU");
6103 case 0x007C: return wxT("WM_STYLECHANGING");
6104 case 0x007D: return wxT("WM_STYLECHANGED");
6105 case 0x007E: return wxT("WM_DISPLAYCHANGE");
6106 case 0x007F: return wxT("WM_GETICON");
6107 case 0x0080: return wxT("WM_SETICON");
6108
6109 case 0x0081: return wxT("WM_NCCREATE");
6110 case 0x0082: return wxT("WM_NCDESTROY");
6111 case 0x0083: return wxT("WM_NCCALCSIZE");
6112 case 0x0084: return wxT("WM_NCHITTEST");
6113 case 0x0085: return wxT("WM_NCPAINT");
6114 case 0x0086: return wxT("WM_NCACTIVATE");
6115 case 0x0087: return wxT("WM_GETDLGCODE");
6116 case 0x00A0: return wxT("WM_NCMOUSEMOVE");
6117 case 0x00A1: return wxT("WM_NCLBUTTONDOWN");
6118 case 0x00A2: return wxT("WM_NCLBUTTONUP");
6119 case 0x00A3: return wxT("WM_NCLBUTTONDBLCLK");
6120 case 0x00A4: return wxT("WM_NCRBUTTONDOWN");
6121 case 0x00A5: return wxT("WM_NCRBUTTONUP");
6122 case 0x00A6: return wxT("WM_NCRBUTTONDBLCLK");
6123 case 0x00A7: return wxT("WM_NCMBUTTONDOWN");
6124 case 0x00A8: return wxT("WM_NCMBUTTONUP");
6125 case 0x00A9: return wxT("WM_NCMBUTTONDBLCLK");
6126
6127 case 0x00B0: return wxT("EM_GETSEL");
6128 case 0x00B1: return wxT("EM_SETSEL");
6129 case 0x00B2: return wxT("EM_GETRECT");
6130 case 0x00B3: return wxT("EM_SETRECT");
6131 case 0x00B4: return wxT("EM_SETRECTNP");
6132 case 0x00B5: return wxT("EM_SCROLL");
6133 case 0x00B6: return wxT("EM_LINESCROLL");
6134 case 0x00B7: return wxT("EM_SCROLLCARET");
6135 case 0x00B8: return wxT("EM_GETMODIFY");
6136 case 0x00B9: return wxT("EM_SETMODIFY");
6137 case 0x00BA: return wxT("EM_GETLINECOUNT");
6138 case 0x00BB: return wxT("EM_LINEINDEX");
6139 case 0x00BC: return wxT("EM_SETHANDLE");
6140 case 0x00BD: return wxT("EM_GETHANDLE");
6141 case 0x00BE: return wxT("EM_GETTHUMB");
6142 case 0x00C1: return wxT("EM_LINELENGTH");
6143 case 0x00C2: return wxT("EM_REPLACESEL");
6144 case 0x00C4: return wxT("EM_GETLINE");
6145 case 0x00C5: return wxT("EM_LIMITTEXT/EM_SETLIMITTEXT"); /* ;win40 Name change */
6146 case 0x00C6: return wxT("EM_CANUNDO");
6147 case 0x00C7: return wxT("EM_UNDO");
6148 case 0x00C8: return wxT("EM_FMTLINES");
6149 case 0x00C9: return wxT("EM_LINEFROMCHAR");
6150 case 0x00CB: return wxT("EM_SETTABSTOPS");
6151 case 0x00CC: return wxT("EM_SETPASSWORDCHAR");
6152 case 0x00CD: return wxT("EM_EMPTYUNDOBUFFER");
6153 case 0x00CE: return wxT("EM_GETFIRSTVISIBLELINE");
6154 case 0x00CF: return wxT("EM_SETREADONLY");
6155 case 0x00D0: return wxT("EM_SETWORDBREAKPROC");
6156 case 0x00D1: return wxT("EM_GETWORDBREAKPROC");
6157 case 0x00D2: return wxT("EM_GETPASSWORDCHAR");
6158 case 0x00D3: return wxT("EM_SETMARGINS");
6159 case 0x00D4: return wxT("EM_GETMARGINS");
6160 case 0x00D5: return wxT("EM_GETLIMITTEXT");
6161 case 0x00D6: return wxT("EM_POSFROMCHAR");
6162 case 0x00D7: return wxT("EM_CHARFROMPOS");
6163 case 0x00D8: return wxT("EM_SETIMESTATUS");
6164 case 0x00D9: return wxT("EM_GETIMESTATUS");
6165
6166 case 0x0100: return wxT("WM_KEYDOWN");
6167 case 0x0101: return wxT("WM_KEYUP");
6168 case 0x0102: return wxT("WM_CHAR");
6169 case 0x0103: return wxT("WM_DEADCHAR");
6170 case 0x0104: return wxT("WM_SYSKEYDOWN");
6171 case 0x0105: return wxT("WM_SYSKEYUP");
6172 case 0x0106: return wxT("WM_SYSCHAR");
6173 case 0x0107: return wxT("WM_SYSDEADCHAR");
6174 case 0x0108: return wxT("WM_KEYLAST");
6175
6176 case 0x010D: return wxT("WM_IME_STARTCOMPOSITION");
6177 case 0x010E: return wxT("WM_IME_ENDCOMPOSITION");
6178 case 0x010F: return wxT("WM_IME_COMPOSITION");
6179
6180 case 0x0110: return wxT("WM_INITDIALOG");
6181 case 0x0111: return wxT("WM_COMMAND");
6182 case 0x0112: return wxT("WM_SYSCOMMAND");
6183 case 0x0113: return wxT("WM_TIMER");
6184 case 0x0114: return wxT("WM_HSCROLL");
6185 case 0x0115: return wxT("WM_VSCROLL");
6186 case 0x0116: return wxT("WM_INITMENU");
6187 case 0x0117: return wxT("WM_INITMENUPOPUP");
6188 case 0x011F: return wxT("WM_MENUSELECT");
6189 case 0x0120: return wxT("WM_MENUCHAR");
6190 case 0x0121: return wxT("WM_ENTERIDLE");
6191
6192 case 0x0132: return wxT("WM_CTLCOLORMSGBOX");
6193 case 0x0133: return wxT("WM_CTLCOLOREDIT");
6194 case 0x0134: return wxT("WM_CTLCOLORLISTBOX");
6195 case 0x0135: return wxT("WM_CTLCOLORBTN");
6196 case 0x0136: return wxT("WM_CTLCOLORDLG");
6197 case 0x0137: return wxT("WM_CTLCOLORSCROLLBAR");
6198 case 0x0138: return wxT("WM_CTLCOLORSTATIC");
6199 case 0x01E1: return wxT("MN_GETHMENU");
6200
6201 case 0x0200: return wxT("WM_MOUSEMOVE");
6202 case 0x0201: return wxT("WM_LBUTTONDOWN");
6203 case 0x0202: return wxT("WM_LBUTTONUP");
6204 case 0x0203: return wxT("WM_LBUTTONDBLCLK");
6205 case 0x0204: return wxT("WM_RBUTTONDOWN");
6206 case 0x0205: return wxT("WM_RBUTTONUP");
6207 case 0x0206: return wxT("WM_RBUTTONDBLCLK");
6208 case 0x0207: return wxT("WM_MBUTTONDOWN");
6209 case 0x0208: return wxT("WM_MBUTTONUP");
6210 case 0x0209: return wxT("WM_MBUTTONDBLCLK");
6211 case 0x020A: return wxT("WM_MOUSEWHEEL");
6212 case 0x020B: return wxT("WM_XBUTTONDOWN");
6213 case 0x020C: return wxT("WM_XBUTTONUP");
6214 case 0x020D: return wxT("WM_XBUTTONDBLCLK");
6215 case 0x0210: return wxT("WM_PARENTNOTIFY");
6216 case 0x0211: return wxT("WM_ENTERMENULOOP");
6217 case 0x0212: return wxT("WM_EXITMENULOOP");
6218
6219 case 0x0213: return wxT("WM_NEXTMENU");
6220 case 0x0214: return wxT("WM_SIZING");
6221 case 0x0215: return wxT("WM_CAPTURECHANGED");
6222 case 0x0216: return wxT("WM_MOVING");
6223 case 0x0218: return wxT("WM_POWERBROADCAST");
6224 case 0x0219: return wxT("WM_DEVICECHANGE");
6225
6226 case 0x0220: return wxT("WM_MDICREATE");
6227 case 0x0221: return wxT("WM_MDIDESTROY");
6228 case 0x0222: return wxT("WM_MDIACTIVATE");
6229 case 0x0223: return wxT("WM_MDIRESTORE");
6230 case 0x0224: return wxT("WM_MDINEXT");
6231 case 0x0225: return wxT("WM_MDIMAXIMIZE");
6232 case 0x0226: return wxT("WM_MDITILE");
6233 case 0x0227: return wxT("WM_MDICASCADE");
6234 case 0x0228: return wxT("WM_MDIICONARRANGE");
6235 case 0x0229: return wxT("WM_MDIGETACTIVE");
6236 case 0x0230: return wxT("WM_MDISETMENU");
6237 case 0x0233: return wxT("WM_DROPFILES");
6238
6239 case 0x0281: return wxT("WM_IME_SETCONTEXT");
6240 case 0x0282: return wxT("WM_IME_NOTIFY");
6241 case 0x0283: return wxT("WM_IME_CONTROL");
6242 case 0x0284: return wxT("WM_IME_COMPOSITIONFULL");
6243 case 0x0285: return wxT("WM_IME_SELECT");
6244 case 0x0286: return wxT("WM_IME_CHAR");
6245 case 0x0290: return wxT("WM_IME_KEYDOWN");
6246 case 0x0291: return wxT("WM_IME_KEYUP");
6247
6248 case 0x02A0: return wxT("WM_NCMOUSEHOVER");
6249 case 0x02A1: return wxT("WM_MOUSEHOVER");
6250 case 0x02A2: return wxT("WM_NCMOUSELEAVE");
6251 case 0x02A3: return wxT("WM_MOUSELEAVE");
6252
6253 case 0x0300: return wxT("WM_CUT");
6254 case 0x0301: return wxT("WM_COPY");
6255 case 0x0302: return wxT("WM_PASTE");
6256 case 0x0303: return wxT("WM_CLEAR");
6257 case 0x0304: return wxT("WM_UNDO");
6258 case 0x0305: return wxT("WM_RENDERFORMAT");
6259 case 0x0306: return wxT("WM_RENDERALLFORMATS");
6260 case 0x0307: return wxT("WM_DESTROYCLIPBOARD");
6261 case 0x0308: return wxT("WM_DRAWCLIPBOARD");
6262 case 0x0309: return wxT("WM_PAINTCLIPBOARD");
6263 case 0x030A: return wxT("WM_VSCROLLCLIPBOARD");
6264 case 0x030B: return wxT("WM_SIZECLIPBOARD");
6265 case 0x030C: return wxT("WM_ASKCBFORMATNAME");
6266 case 0x030D: return wxT("WM_CHANGECBCHAIN");
6267 case 0x030E: return wxT("WM_HSCROLLCLIPBOARD");
6268 case 0x030F: return wxT("WM_QUERYNEWPALETTE");
6269 case 0x0310: return wxT("WM_PALETTEISCHANGING");
6270 case 0x0311: return wxT("WM_PALETTECHANGED");
6271 case 0x0312: return wxT("WM_HOTKEY");
6272
6273 case 0x0317: return wxT("WM_PRINT");
6274 case 0x0318: return wxT("WM_PRINTCLIENT");
6275
6276 // common controls messages - although they're not strictly speaking
6277 // standard, it's nice to decode them nevertheless
6278
6279 // listview
6280 case 0x1000 + 0: return wxT("LVM_GETBKCOLOR");
6281 case 0x1000 + 1: return wxT("LVM_SETBKCOLOR");
6282 case 0x1000 + 2: return wxT("LVM_GETIMAGELIST");
6283 case 0x1000 + 3: return wxT("LVM_SETIMAGELIST");
6284 case 0x1000 + 4: return wxT("LVM_GETITEMCOUNT");
6285 case 0x1000 + 5: return wxT("LVM_GETITEMA");
6286 case 0x1000 + 75: return wxT("LVM_GETITEMW");
6287 case 0x1000 + 6: return wxT("LVM_SETITEMA");
6288 case 0x1000 + 76: return wxT("LVM_SETITEMW");
6289 case 0x1000 + 7: return wxT("LVM_INSERTITEMA");
6290 case 0x1000 + 77: return wxT("LVM_INSERTITEMW");
6291 case 0x1000 + 8: return wxT("LVM_DELETEITEM");
6292 case 0x1000 + 9: return wxT("LVM_DELETEALLITEMS");
6293 case 0x1000 + 10: return wxT("LVM_GETCALLBACKMASK");
6294 case 0x1000 + 11: return wxT("LVM_SETCALLBACKMASK");
6295 case 0x1000 + 12: return wxT("LVM_GETNEXTITEM");
6296 case 0x1000 + 13: return wxT("LVM_FINDITEMA");
6297 case 0x1000 + 83: return wxT("LVM_FINDITEMW");
6298 case 0x1000 + 14: return wxT("LVM_GETITEMRECT");
6299 case 0x1000 + 15: return wxT("LVM_SETITEMPOSITION");
6300 case 0x1000 + 16: return wxT("LVM_GETITEMPOSITION");
6301 case 0x1000 + 17: return wxT("LVM_GETSTRINGWIDTHA");
6302 case 0x1000 + 87: return wxT("LVM_GETSTRINGWIDTHW");
6303 case 0x1000 + 18: return wxT("LVM_HITTEST");
6304 case 0x1000 + 19: return wxT("LVM_ENSUREVISIBLE");
6305 case 0x1000 + 20: return wxT("LVM_SCROLL");
6306 case 0x1000 + 21: return wxT("LVM_REDRAWITEMS");
6307 case 0x1000 + 22: return wxT("LVM_ARRANGE");
6308 case 0x1000 + 23: return wxT("LVM_EDITLABELA");
6309 case 0x1000 + 118: return wxT("LVM_EDITLABELW");
6310 case 0x1000 + 24: return wxT("LVM_GETEDITCONTROL");
6311 case 0x1000 + 25: return wxT("LVM_GETCOLUMNA");
6312 case 0x1000 + 95: return wxT("LVM_GETCOLUMNW");
6313 case 0x1000 + 26: return wxT("LVM_SETCOLUMNA");
6314 case 0x1000 + 96: return wxT("LVM_SETCOLUMNW");
6315 case 0x1000 + 27: return wxT("LVM_INSERTCOLUMNA");
6316 case 0x1000 + 97: return wxT("LVM_INSERTCOLUMNW");
6317 case 0x1000 + 28: return wxT("LVM_DELETECOLUMN");
6318 case 0x1000 + 29: return wxT("LVM_GETCOLUMNWIDTH");
6319 case 0x1000 + 30: return wxT("LVM_SETCOLUMNWIDTH");
6320 case 0x1000 + 31: return wxT("LVM_GETHEADER");
6321 case 0x1000 + 33: return wxT("LVM_CREATEDRAGIMAGE");
6322 case 0x1000 + 34: return wxT("LVM_GETVIEWRECT");
6323 case 0x1000 + 35: return wxT("LVM_GETTEXTCOLOR");
6324 case 0x1000 + 36: return wxT("LVM_SETTEXTCOLOR");
6325 case 0x1000 + 37: return wxT("LVM_GETTEXTBKCOLOR");
6326 case 0x1000 + 38: return wxT("LVM_SETTEXTBKCOLOR");
6327 case 0x1000 + 39: return wxT("LVM_GETTOPINDEX");
6328 case 0x1000 + 40: return wxT("LVM_GETCOUNTPERPAGE");
6329 case 0x1000 + 41: return wxT("LVM_GETORIGIN");
6330 case 0x1000 + 42: return wxT("LVM_UPDATE");
6331 case 0x1000 + 43: return wxT("LVM_SETITEMSTATE");
6332 case 0x1000 + 44: return wxT("LVM_GETITEMSTATE");
6333 case 0x1000 + 45: return wxT("LVM_GETITEMTEXTA");
6334 case 0x1000 + 115: return wxT("LVM_GETITEMTEXTW");
6335 case 0x1000 + 46: return wxT("LVM_SETITEMTEXTA");
6336 case 0x1000 + 116: return wxT("LVM_SETITEMTEXTW");
6337 case 0x1000 + 47: return wxT("LVM_SETITEMCOUNT");
6338 case 0x1000 + 48: return wxT("LVM_SORTITEMS");
6339 case 0x1000 + 49: return wxT("LVM_SETITEMPOSITION32");
6340 case 0x1000 + 50: return wxT("LVM_GETSELECTEDCOUNT");
6341 case 0x1000 + 51: return wxT("LVM_GETITEMSPACING");
6342 case 0x1000 + 52: return wxT("LVM_GETISEARCHSTRINGA");
6343 case 0x1000 + 117: return wxT("LVM_GETISEARCHSTRINGW");
6344 case 0x1000 + 53: return wxT("LVM_SETICONSPACING");
6345 case 0x1000 + 54: return wxT("LVM_SETEXTENDEDLISTVIEWSTYLE");
6346 case 0x1000 + 55: return wxT("LVM_GETEXTENDEDLISTVIEWSTYLE");
6347 case 0x1000 + 56: return wxT("LVM_GETSUBITEMRECT");
6348 case 0x1000 + 57: return wxT("LVM_SUBITEMHITTEST");
6349 case 0x1000 + 58: return wxT("LVM_SETCOLUMNORDERARRAY");
6350 case 0x1000 + 59: return wxT("LVM_GETCOLUMNORDERARRAY");
6351 case 0x1000 + 60: return wxT("LVM_SETHOTITEM");
6352 case 0x1000 + 61: return wxT("LVM_GETHOTITEM");
6353 case 0x1000 + 62: return wxT("LVM_SETHOTCURSOR");
6354 case 0x1000 + 63: return wxT("LVM_GETHOTCURSOR");
6355 case 0x1000 + 64: return wxT("LVM_APPROXIMATEVIEWRECT");
6356 case 0x1000 + 65: return wxT("LVM_SETWORKAREA");
6357
6358 // tree view
6359 case 0x1100 + 0: return wxT("TVM_INSERTITEMA");
6360 case 0x1100 + 50: return wxT("TVM_INSERTITEMW");
6361 case 0x1100 + 1: return wxT("TVM_DELETEITEM");
6362 case 0x1100 + 2: return wxT("TVM_EXPAND");
6363 case 0x1100 + 4: return wxT("TVM_GETITEMRECT");
6364 case 0x1100 + 5: return wxT("TVM_GETCOUNT");
6365 case 0x1100 + 6: return wxT("TVM_GETINDENT");
6366 case 0x1100 + 7: return wxT("TVM_SETINDENT");
6367 case 0x1100 + 8: return wxT("TVM_GETIMAGELIST");
6368 case 0x1100 + 9: return wxT("TVM_SETIMAGELIST");
6369 case 0x1100 + 10: return wxT("TVM_GETNEXTITEM");
6370 case 0x1100 + 11: return wxT("TVM_SELECTITEM");
6371 case 0x1100 + 12: return wxT("TVM_GETITEMA");
6372 case 0x1100 + 62: return wxT("TVM_GETITEMW");
6373 case 0x1100 + 13: return wxT("TVM_SETITEMA");
6374 case 0x1100 + 63: return wxT("TVM_SETITEMW");
6375 case 0x1100 + 14: return wxT("TVM_EDITLABELA");
6376 case 0x1100 + 65: return wxT("TVM_EDITLABELW");
6377 case 0x1100 + 15: return wxT("TVM_GETEDITCONTROL");
6378 case 0x1100 + 16: return wxT("TVM_GETVISIBLECOUNT");
6379 case 0x1100 + 17: return wxT("TVM_HITTEST");
6380 case 0x1100 + 18: return wxT("TVM_CREATEDRAGIMAGE");
6381 case 0x1100 + 19: return wxT("TVM_SORTCHILDREN");
6382 case 0x1100 + 20: return wxT("TVM_ENSUREVISIBLE");
6383 case 0x1100 + 21: return wxT("TVM_SORTCHILDRENCB");
6384 case 0x1100 + 22: return wxT("TVM_ENDEDITLABELNOW");
6385 case 0x1100 + 23: return wxT("TVM_GETISEARCHSTRINGA");
6386 case 0x1100 + 64: return wxT("TVM_GETISEARCHSTRINGW");
6387 case 0x1100 + 24: return wxT("TVM_SETTOOLTIPS");
6388 case 0x1100 + 25: return wxT("TVM_GETTOOLTIPS");
6389
6390 // header
6391 case 0x1200 + 0: return wxT("HDM_GETITEMCOUNT");
6392 case 0x1200 + 1: return wxT("HDM_INSERTITEMA");
6393 case 0x1200 + 10: return wxT("HDM_INSERTITEMW");
6394 case 0x1200 + 2: return wxT("HDM_DELETEITEM");
6395 case 0x1200 + 3: return wxT("HDM_GETITEMA");
6396 case 0x1200 + 11: return wxT("HDM_GETITEMW");
6397 case 0x1200 + 4: return wxT("HDM_SETITEMA");
6398 case 0x1200 + 12: return wxT("HDM_SETITEMW");
6399 case 0x1200 + 5: return wxT("HDM_LAYOUT");
6400 case 0x1200 + 6: return wxT("HDM_HITTEST");
6401 case 0x1200 + 7: return wxT("HDM_GETITEMRECT");
6402 case 0x1200 + 8: return wxT("HDM_SETIMAGELIST");
6403 case 0x1200 + 9: return wxT("HDM_GETIMAGELIST");
6404 case 0x1200 + 15: return wxT("HDM_ORDERTOINDEX");
6405 case 0x1200 + 16: return wxT("HDM_CREATEDRAGIMAGE");
6406 case 0x1200 + 17: return wxT("HDM_GETORDERARRAY");
6407 case 0x1200 + 18: return wxT("HDM_SETORDERARRAY");
6408 case 0x1200 + 19: return wxT("HDM_SETHOTDIVIDER");
6409
6410 // tab control
6411 case 0x1300 + 2: return wxT("TCM_GETIMAGELIST");
6412 case 0x1300 + 3: return wxT("TCM_SETIMAGELIST");
6413 case 0x1300 + 4: return wxT("TCM_GETITEMCOUNT");
6414 case 0x1300 + 5: return wxT("TCM_GETITEMA");
6415 case 0x1300 + 60: return wxT("TCM_GETITEMW");
6416 case 0x1300 + 6: return wxT("TCM_SETITEMA");
6417 case 0x1300 + 61: return wxT("TCM_SETITEMW");
6418 case 0x1300 + 7: return wxT("TCM_INSERTITEMA");
6419 case 0x1300 + 62: return wxT("TCM_INSERTITEMW");
6420 case 0x1300 + 8: return wxT("TCM_DELETEITEM");
6421 case 0x1300 + 9: return wxT("TCM_DELETEALLITEMS");
6422 case 0x1300 + 10: return wxT("TCM_GETITEMRECT");
6423 case 0x1300 + 11: return wxT("TCM_GETCURSEL");
6424 case 0x1300 + 12: return wxT("TCM_SETCURSEL");
6425 case 0x1300 + 13: return wxT("TCM_HITTEST");
6426 case 0x1300 + 14: return wxT("TCM_SETITEMEXTRA");
6427 case 0x1300 + 40: return wxT("TCM_ADJUSTRECT");
6428 case 0x1300 + 41: return wxT("TCM_SETITEMSIZE");
6429 case 0x1300 + 42: return wxT("TCM_REMOVEIMAGE");
6430 case 0x1300 + 43: return wxT("TCM_SETPADDING");
6431 case 0x1300 + 44: return wxT("TCM_GETROWCOUNT");
6432 case 0x1300 + 45: return wxT("TCM_GETTOOLTIPS");
6433 case 0x1300 + 46: return wxT("TCM_SETTOOLTIPS");
6434 case 0x1300 + 47: return wxT("TCM_GETCURFOCUS");
6435 case 0x1300 + 48: return wxT("TCM_SETCURFOCUS");
6436 case 0x1300 + 49: return wxT("TCM_SETMINTABWIDTH");
6437 case 0x1300 + 50: return wxT("TCM_DESELECTALL");
6438
6439 // toolbar
6440 case WM_USER+1: return wxT("TB_ENABLEBUTTON");
6441 case WM_USER+2: return wxT("TB_CHECKBUTTON");
6442 case WM_USER+3: return wxT("TB_PRESSBUTTON");
6443 case WM_USER+4: return wxT("TB_HIDEBUTTON");
6444 case WM_USER+5: return wxT("TB_INDETERMINATE");
6445 case WM_USER+9: return wxT("TB_ISBUTTONENABLED");
6446 case WM_USER+10: return wxT("TB_ISBUTTONCHECKED");
6447 case WM_USER+11: return wxT("TB_ISBUTTONPRESSED");
6448 case WM_USER+12: return wxT("TB_ISBUTTONHIDDEN");
6449 case WM_USER+13: return wxT("TB_ISBUTTONINDETERMINATE");
6450 case WM_USER+17: return wxT("TB_SETSTATE");
6451 case WM_USER+18: return wxT("TB_GETSTATE");
6452 case WM_USER+19: return wxT("TB_ADDBITMAP");
6453 case WM_USER+20: return wxT("TB_ADDBUTTONS");
6454 case WM_USER+21: return wxT("TB_INSERTBUTTON");
6455 case WM_USER+22: return wxT("TB_DELETEBUTTON");
6456 case WM_USER+23: return wxT("TB_GETBUTTON");
6457 case WM_USER+24: return wxT("TB_BUTTONCOUNT");
6458 case WM_USER+25: return wxT("TB_COMMANDTOINDEX");
6459 case WM_USER+26: return wxT("TB_SAVERESTOREA");
6460 case WM_USER+76: return wxT("TB_SAVERESTOREW");
6461 case WM_USER+27: return wxT("TB_CUSTOMIZE");
6462 case WM_USER+28: return wxT("TB_ADDSTRINGA");
6463 case WM_USER+77: return wxT("TB_ADDSTRINGW");
6464 case WM_USER+29: return wxT("TB_GETITEMRECT");
6465 case WM_USER+30: return wxT("TB_BUTTONSTRUCTSIZE");
6466 case WM_USER+31: return wxT("TB_SETBUTTONSIZE");
6467 case WM_USER+32: return wxT("TB_SETBITMAPSIZE");
6468 case WM_USER+33: return wxT("TB_AUTOSIZE");
6469 case WM_USER+35: return wxT("TB_GETTOOLTIPS");
6470 case WM_USER+36: return wxT("TB_SETTOOLTIPS");
6471 case WM_USER+37: return wxT("TB_SETPARENT");
6472 case WM_USER+39: return wxT("TB_SETROWS");
6473 case WM_USER+40: return wxT("TB_GETROWS");
6474 case WM_USER+42: return wxT("TB_SETCMDID");
6475 case WM_USER+43: return wxT("TB_CHANGEBITMAP");
6476 case WM_USER+44: return wxT("TB_GETBITMAP");
6477 case WM_USER+45: return wxT("TB_GETBUTTONTEXTA");
6478 case WM_USER+75: return wxT("TB_GETBUTTONTEXTW");
6479 case WM_USER+46: return wxT("TB_REPLACEBITMAP");
6480 case WM_USER+47: return wxT("TB_SETINDENT");
6481 case WM_USER+48: return wxT("TB_SETIMAGELIST");
6482 case WM_USER+49: return wxT("TB_GETIMAGELIST");
6483 case WM_USER+50: return wxT("TB_LOADIMAGES");
6484 case WM_USER+51: return wxT("TB_GETRECT");
6485 case WM_USER+52: return wxT("TB_SETHOTIMAGELIST");
6486 case WM_USER+53: return wxT("TB_GETHOTIMAGELIST");
6487 case WM_USER+54: return wxT("TB_SETDISABLEDIMAGELIST");
6488 case WM_USER+55: return wxT("TB_GETDISABLEDIMAGELIST");
6489 case WM_USER+56: return wxT("TB_SETSTYLE");
6490 case WM_USER+57: return wxT("TB_GETSTYLE");
6491 case WM_USER+58: return wxT("TB_GETBUTTONSIZE");
6492 case WM_USER+59: return wxT("TB_SETBUTTONWIDTH");
6493 case WM_USER+60: return wxT("TB_SETMAXTEXTROWS");
6494 case WM_USER+61: return wxT("TB_GETTEXTROWS");
6495 case WM_USER+41: return wxT("TB_GETBITMAPFLAGS");
6496
6497 default:
6498 static wxString s_szBuf;
6499 s_szBuf.Printf(wxT("<unknown message = %d>"), message);
6500 return s_szBuf.c_str();
6501 }
6502 }
6503 #endif //__WXDEBUG__
6504
6505 static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win)
6506 {
6507 // prepare the DC
6508 TEXTMETRIC tm;
6509 HWND hwnd = GetHwndOf(win);
6510 HDC hdc = ::GetDC(hwnd);
6511
6512 #if !wxDIALOG_UNIT_COMPATIBILITY
6513 // and select the current font into it
6514 HFONT hfont = GetHfontOf(win->GetFont());
6515 if ( hfont )
6516 {
6517 hfont = (HFONT)::SelectObject(hdc, hfont);
6518 }
6519 #endif
6520
6521 // finally retrieve the text metrics from it
6522 GetTextMetrics(hdc, &tm);
6523
6524 #if !wxDIALOG_UNIT_COMPATIBILITY
6525 // and clean up
6526 if ( hfont )
6527 {
6528 (void)::SelectObject(hdc, hfont);
6529 }
6530 #endif
6531
6532 ::ReleaseDC(hwnd, hdc);
6533
6534 return tm;
6535 }
6536
6537 // Find the wxWindow at the current mouse position, returning the mouse
6538 // position.
6539 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
6540 {
6541 pt = wxGetMousePosition();
6542 return wxFindWindowAtPoint(pt);
6543 }
6544
6545 wxWindow* wxFindWindowAtPoint(const wxPoint& pt)
6546 {
6547 POINT pt2;
6548 pt2.x = pt.x;
6549 pt2.y = pt.y;
6550
6551 HWND hWnd = ::WindowFromPoint(pt2);
6552
6553 return wxGetWindowFromHWND((WXHWND)hWnd);
6554 }
6555
6556 // Get the current mouse position.
6557 wxPoint wxGetMousePosition()
6558 {
6559 POINT pt;
6560 #ifdef __WXWINCE__
6561 GetCursorPosWinCE(&pt);
6562 #else
6563 GetCursorPos( & pt );
6564 #endif
6565
6566 return wxPoint(pt.x, pt.y);
6567 }
6568
6569 #if wxUSE_HOTKEY
6570
6571 #if defined(__SMARTPHONE__) || defined(__POCKETPC__)
6572 static void WinCEUnregisterHotKey(int modifiers, int id)
6573 {
6574 // Register hotkeys for the hardware buttons
6575 HINSTANCE hCoreDll;
6576 typedef BOOL (WINAPI *UnregisterFunc1Proc)(UINT, UINT);
6577
6578 UnregisterFunc1Proc procUnregisterFunc;
6579 hCoreDll = LoadLibrary(_T("coredll.dll"));
6580 if (hCoreDll)
6581 {
6582 procUnregisterFunc = (UnregisterFunc1Proc)GetProcAddress(hCoreDll, _T("UnregisterFunc1"));
6583 if (procUnregisterFunc)
6584 procUnregisterFunc(modifiers, id);
6585 FreeLibrary(hCoreDll);
6586 }
6587 }
6588 #endif
6589
6590 bool wxWindowMSW::RegisterHotKey(int hotkeyId, int modifiers, int keycode)
6591 {
6592 UINT win_modifiers=0;
6593 if ( modifiers & wxMOD_ALT )
6594 win_modifiers |= MOD_ALT;
6595 if ( modifiers & wxMOD_SHIFT )
6596 win_modifiers |= MOD_SHIFT;
6597 if ( modifiers & wxMOD_CONTROL )
6598 win_modifiers |= MOD_CONTROL;
6599 if ( modifiers & wxMOD_WIN )
6600 win_modifiers |= MOD_WIN;
6601
6602 #if defined(__SMARTPHONE__) || defined(__POCKETPC__)
6603 // Required for PPC and Smartphone hardware buttons
6604 if (keycode >= WXK_SPECIAL1 && keycode <= WXK_SPECIAL20)
6605 WinCEUnregisterHotKey(win_modifiers, hotkeyId);
6606 #endif
6607
6608 if ( !::RegisterHotKey(GetHwnd(), hotkeyId, win_modifiers, keycode) )
6609 {
6610 wxLogLastError(_T("RegisterHotKey"));
6611
6612 return false;
6613 }
6614
6615 return true;
6616 }
6617
6618 bool wxWindowMSW::UnregisterHotKey(int hotkeyId)
6619 {
6620 #if defined(__SMARTPHONE__) || defined(__POCKETPC__)
6621 WinCEUnregisterHotKey(MOD_WIN, hotkeyId);
6622 #endif
6623
6624 if ( !::UnregisterHotKey(GetHwnd(), hotkeyId) )
6625 {
6626 wxLogLastError(_T("UnregisterHotKey"));
6627
6628 return false;
6629 }
6630
6631 return true;
6632 }
6633
6634 #if wxUSE_ACCEL
6635
6636 bool wxWindowMSW::HandleHotKey(WXWPARAM wParam, WXLPARAM lParam)
6637 {
6638 int hotkeyId = wParam;
6639 int virtualKey = HIWORD(lParam);
6640 int win_modifiers = LOWORD(lParam);
6641
6642 wxKeyEvent event(CreateKeyEvent(wxEVT_HOTKEY, virtualKey, wParam, lParam));
6643 event.SetId(hotkeyId);
6644 event.m_shiftDown = (win_modifiers & MOD_SHIFT) != 0;
6645 event.m_controlDown = (win_modifiers & MOD_CONTROL) != 0;
6646 event.m_altDown = (win_modifiers & MOD_ALT) != 0;
6647 event.m_metaDown = (win_modifiers & MOD_WIN) != 0;
6648
6649 return GetEventHandler()->ProcessEvent(event);
6650 }
6651
6652 #endif // wxUSE_ACCEL
6653
6654 #endif // wxUSE_HOTKEY
6655
6656 // Not tested under WinCE
6657 #ifndef __WXWINCE__
6658
6659 // this class installs a message hook which really wakes up our idle processing
6660 // each time a WM_NULL is received (wxWakeUpIdle does this), even if we're
6661 // sitting inside a local modal loop (e.g. a menu is opened or scrollbar is
6662 // being dragged or even inside ::MessageBox()) and so don't control message
6663 // dispatching otherwise
6664 class wxIdleWakeUpModule : public wxModule
6665 {
6666 public:
6667 virtual bool OnInit()
6668 {
6669 ms_hMsgHookProc = ::SetWindowsHookEx
6670 (
6671 WH_GETMESSAGE,
6672 &wxIdleWakeUpModule::MsgHookProc,
6673 NULL,
6674 GetCurrentThreadId()
6675 );
6676
6677 if ( !ms_hMsgHookProc )
6678 {
6679 wxLogLastError(_T("SetWindowsHookEx(WH_GETMESSAGE)"));
6680
6681 return false;
6682 }
6683
6684 return true;
6685 }
6686
6687 virtual void OnExit()
6688 {
6689 ::UnhookWindowsHookEx(wxIdleWakeUpModule::ms_hMsgHookProc);
6690 }
6691
6692 static LRESULT CALLBACK MsgHookProc(int nCode, WPARAM wParam, LPARAM lParam)
6693 {
6694 MSG *msg = (MSG*)lParam;
6695
6696 // only process the message if it is actually going to be removed from
6697 // the message queue, this prevents that the same event from being
6698 // processed multiple times if now someone just called PeekMessage()
6699 if ( msg->message == WM_NULL && wParam == PM_REMOVE )
6700 {
6701 wxTheApp->ProcessPendingEvents();
6702 }
6703
6704 return CallNextHookEx(ms_hMsgHookProc, nCode, wParam, lParam);
6705 }
6706
6707 private:
6708 static HHOOK ms_hMsgHookProc;
6709
6710 DECLARE_DYNAMIC_CLASS(wxIdleWakeUpModule)
6711 };
6712
6713 HHOOK wxIdleWakeUpModule::ms_hMsgHookProc = 0;
6714
6715 IMPLEMENT_DYNAMIC_CLASS(wxIdleWakeUpModule, wxModule)
6716
6717 #endif // __WXWINCE__
6718
6719 #ifdef __WXWINCE__
6720
6721 #if wxUSE_STATBOX
6722 static void wxAdjustZOrder(wxWindow* parent)
6723 {
6724 if (parent->IsKindOf(CLASSINFO(wxStaticBox)))
6725 {
6726 // Set the z-order correctly
6727 SetWindowPos((HWND) parent->GetHWND(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
6728 }
6729
6730 wxWindowList::compatibility_iterator current = parent->GetChildren().GetFirst();
6731 while (current)
6732 {
6733 wxWindow *childWin = current->GetData();
6734 wxAdjustZOrder(childWin);
6735 current = current->GetNext();
6736 }
6737 }
6738 #endif
6739
6740 // We need to adjust the z-order of static boxes in WinCE, to
6741 // make 'contained' controls visible
6742 void wxWindowMSW::OnInitDialog( wxInitDialogEvent& event )
6743 {
6744 #if wxUSE_STATBOX
6745 wxAdjustZOrder(this);
6746 #endif
6747
6748 event.Skip();
6749 }
6750 #endif