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