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