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