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