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