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