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