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