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