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