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