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