]> git.saurik.com Git - wxWidgets.git/blob - src/msw/window.cpp
dumb fix for wxDC::Clear() crash
[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 #ifdef __WXUNIVERSAL__
2342 // Universal uses its own wxFrame/wxDialog, so we don't receive
2343 // close events unless we have this.
2344 Close();
2345 processed = TRUE;
2346 rc.result = TRUE;
2347 #else
2348 // don't let the DefWindowProc() destroy our window - we'll do it
2349 // ourselves in ~wxWindow
2350 processed = TRUE;
2351 rc.result = TRUE;
2352 #endif
2353 break;
2354
2355 case WM_SHOWWINDOW:
2356 processed = HandleShow(wParam != 0, (int)lParam);
2357 break;
2358
2359 case WM_MOUSEMOVE:
2360 processed = HandleMouseMove(GET_X_LPARAM(lParam),
2361 GET_Y_LPARAM(lParam),
2362 wParam);
2363 break;
2364
2365 #if wxUSE_MOUSEWHEEL
2366 case WM_MOUSEWHEEL:
2367 processed = HandleMouseWheel(wParam, lParam);
2368 break;
2369 #endif
2370
2371 case WM_LBUTTONDOWN:
2372 case WM_LBUTTONUP:
2373 case WM_LBUTTONDBLCLK:
2374 case WM_RBUTTONDOWN:
2375 case WM_RBUTTONUP:
2376 case WM_RBUTTONDBLCLK:
2377 case WM_MBUTTONDOWN:
2378 case WM_MBUTTONUP:
2379 case WM_MBUTTONDBLCLK:
2380 {
2381 processed = FALSE;
2382 #ifdef __WXMICROWIN__
2383 // MicroWindows seems to ignore the fact that a window is
2384 // disabled. So catch mouse events and throw them away if
2385 // necessary.
2386 wxWindowMSW* win = this;
2387 while (win)
2388 {
2389 if (!win->IsEnabled())
2390 {
2391 processed = TRUE;
2392 break;
2393 }
2394 win = win->GetParent();
2395 if (win && win->IsTopLevel())
2396 break;
2397 }
2398 #endif // __WXMICROWIN__
2399 if (!processed)
2400 {
2401 if (message == WM_LBUTTONDOWN && AcceptsFocus())
2402 SetFocus();
2403 processed = HandleMouseEvent(message,
2404 GET_X_LPARAM(lParam),
2405 GET_Y_LPARAM(lParam),
2406 wParam);
2407 }
2408 break;
2409 }
2410
2411 #ifdef __WXMICROWIN__
2412 case WM_NCLBUTTONDOWN:
2413 case WM_NCLBUTTONUP:
2414 case WM_NCLBUTTONDBLCLK:
2415 case WM_NCRBUTTONDOWN:
2416 case WM_NCRBUTTONUP:
2417 case WM_NCRBUTTONDBLCLK:
2418 #if 0
2419 case WM_NCMBUTTONDOWN:
2420 case WM_NCMBUTTONUP:
2421 case WM_NCMBUTTONDBLCLK:
2422 #endif
2423 {
2424 // MicroWindows seems to ignore the fact that a window
2425 // is disabled. So catch mouse events and throw them away if necessary.
2426 processed = FALSE;
2427 wxWindowMSW* win = this;
2428 while (win)
2429 {
2430 if (!win->IsEnabled())
2431 {
2432 processed = TRUE;
2433 break;
2434 }
2435 win = win->GetParent();
2436 if (win && win->IsTopLevel())
2437 break;
2438 }
2439 break;
2440 }
2441 #endif // __WXMICROWIN__
2442
2443 #ifdef MM_JOY1MOVE
2444 case MM_JOY1MOVE:
2445 case MM_JOY2MOVE:
2446 case MM_JOY1ZMOVE:
2447 case MM_JOY2ZMOVE:
2448 case MM_JOY1BUTTONDOWN:
2449 case MM_JOY2BUTTONDOWN:
2450 case MM_JOY1BUTTONUP:
2451 case MM_JOY2BUTTONUP:
2452 processed = HandleJoystickEvent(message,
2453 GET_X_LPARAM(lParam),
2454 GET_Y_LPARAM(lParam),
2455 wParam);
2456 break;
2457 #endif // __WXMICROWIN__
2458
2459 case WM_SYSCOMMAND:
2460 processed = HandleSysCommand(wParam, lParam);
2461 break;
2462
2463 case WM_COMMAND:
2464 {
2465 WORD id, cmd;
2466 WXHWND hwnd;
2467 UnpackCommand(wParam, lParam, &id, &hwnd, &cmd);
2468
2469 processed = HandleCommand(id, cmd, hwnd);
2470 }
2471 break;
2472
2473 #ifdef __WIN95__
2474 case WM_NOTIFY:
2475 processed = HandleNotify((int)wParam, lParam, &rc.result);
2476 break;
2477 #endif // Win95
2478
2479 // for these messages we must return TRUE if process the message
2480 #ifdef WM_DRAWITEM
2481 case WM_DRAWITEM:
2482 case WM_MEASUREITEM:
2483 {
2484 int idCtrl = (UINT)wParam;
2485 if ( message == WM_DRAWITEM )
2486 {
2487 processed = MSWOnDrawItem(idCtrl,
2488 (WXDRAWITEMSTRUCT *)lParam);
2489 }
2490 else
2491 {
2492 processed = MSWOnMeasureItem(idCtrl,
2493 (WXMEASUREITEMSTRUCT *)lParam);
2494 }
2495
2496 if ( processed )
2497 rc.result = TRUE;
2498 }
2499 break;
2500 #endif // defined(WM_DRAWITEM)
2501
2502 case WM_GETDLGCODE:
2503 if ( GetWindowStyleFlag() & wxWANTS_CHARS )
2504 {
2505 // want everything: i.e. all keys and WM_CHAR message
2506 rc.result = DLGC_WANTARROWS | DLGC_WANTCHARS |
2507 DLGC_WANTTAB | DLGC_WANTMESSAGE;
2508 processed = TRUE;
2509 }
2510 //else: get the dlg code from the DefWindowProc()
2511 break;
2512
2513 case WM_SYSKEYDOWN:
2514 case WM_KEYDOWN:
2515 // If this has been processed by an event handler, return 0 now
2516 // (we've handled it).
2517 m_lastKeydownProcessed = HandleKeyDown((WORD) wParam, lParam);
2518 if ( m_lastKeydownProcessed )
2519 {
2520 processed = TRUE;
2521 break;
2522 }
2523
2524 switch ( wParam )
2525 {
2526 // we consider these message "not interesting" to OnChar, so
2527 // just don't do anything more with them
2528 case VK_SHIFT:
2529 case VK_CONTROL:
2530 case VK_MENU:
2531 case VK_CAPITAL:
2532 case VK_NUMLOCK:
2533 case VK_SCROLL:
2534 processed = TRUE;
2535 break;
2536
2537 // avoid duplicate messages to OnChar for these ASCII keys:
2538 // they will be translated by TranslateMessage() and received
2539 // in WM_CHAR
2540 case VK_ESCAPE:
2541 case VK_SPACE:
2542 case VK_RETURN:
2543 case VK_BACK:
2544 case VK_TAB:
2545 case VK_ADD:
2546 case VK_SUBTRACT:
2547 case VK_MULTIPLY:
2548 case VK_DIVIDE:
2549 case VK_OEM_1:
2550 case VK_OEM_2:
2551 case VK_OEM_3:
2552 case VK_OEM_4:
2553 case VK_OEM_5:
2554 case VK_OEM_6:
2555 case VK_OEM_7:
2556 case VK_OEM_PLUS:
2557 case VK_OEM_COMMA:
2558 case VK_OEM_MINUS:
2559 case VK_OEM_PERIOD:
2560 // but set processed to FALSE, not TRUE to still pass them
2561 // to the control's default window proc - otherwise
2562 // built-in keyboard handling won't work
2563 processed = FALSE;
2564
2565 break;
2566
2567 #ifdef VK_APPS
2568 // special case of VK_APPS: treat it the same as right mouse
2569 // click because both usually pop up a context menu
2570 case VK_APPS:
2571 {
2572 WPARAM flags;
2573 int x, y;
2574
2575 TranslateKbdEventToMouse(this, &x, &y, &flags);
2576 processed = HandleMouseEvent(WM_RBUTTONDOWN, x, y, flags);
2577 }
2578 break;
2579 #endif // VK_APPS
2580
2581 default:
2582 // do generate a CHAR event
2583 processed = HandleChar((WORD)wParam, lParam);
2584
2585 }
2586 break;
2587
2588 case WM_SYSKEYUP:
2589 case WM_KEYUP:
2590 #ifdef VK_APPS
2591 // special case of VK_APPS: treat it the same as right mouse button
2592 if ( wParam == VK_APPS )
2593 {
2594 WPARAM flags;
2595 int x, y;
2596
2597 TranslateKbdEventToMouse(this, &x, &y, &flags);
2598 processed = HandleMouseEvent(WM_RBUTTONUP, x, y, flags);
2599 }
2600 else
2601 #endif // VK_APPS
2602 {
2603 processed = HandleKeyUp((WORD) wParam, lParam);
2604 }
2605 break;
2606
2607 case WM_SYSCHAR:
2608 case WM_CHAR: // Always an ASCII character
2609 if ( m_lastKeydownProcessed )
2610 {
2611 // The key was handled in the EVT_KEY_DOWN and handling
2612 // a key in an EVT_KEY_DOWN handler is meant, by
2613 // design, to prevent EVT_CHARs from happening
2614 m_lastKeydownProcessed = FALSE;
2615 processed = TRUE;
2616 }
2617 else
2618 {
2619 processed = HandleChar((WORD)wParam, lParam, TRUE);
2620 }
2621 break;
2622
2623 case WM_HSCROLL:
2624 case WM_VSCROLL:
2625 {
2626 WXWORD code, pos;
2627 WXHWND hwnd;
2628 UnpackScroll(wParam, lParam, &code, &pos, &hwnd);
2629
2630 processed = MSWOnScroll(message == WM_HSCROLL ? wxHORIZONTAL
2631 : wxVERTICAL,
2632 code, pos, hwnd);
2633 }
2634 break;
2635
2636 // CTLCOLOR messages are sent by children to query the parent for their
2637 // colors#ifndef __WXMICROWIN__
2638 #ifndef __WXMICROWIN__
2639 #ifdef __WIN32__
2640 case WM_CTLCOLORMSGBOX:
2641 case WM_CTLCOLOREDIT:
2642 case WM_CTLCOLORLISTBOX:
2643 case WM_CTLCOLORBTN:
2644 case WM_CTLCOLORDLG:
2645 case WM_CTLCOLORSCROLLBAR:
2646 case WM_CTLCOLORSTATIC:
2647 #else // Win16
2648 case WM_CTLCOLOR:
2649 #endif // Win32/16
2650 {
2651 WXWORD nCtlColor;
2652 WXHDC hdc;
2653 WXHWND hwnd;
2654 UnpackCtlColor(wParam, lParam, &nCtlColor, &hdc, &hwnd);
2655
2656 processed = HandleCtlColor(&rc.hBrush,
2657 (WXHDC)hdc,
2658 (WXHWND)hwnd,
2659 nCtlColor,
2660 message,
2661 wParam,
2662 lParam);
2663 }
2664 break;
2665 #endif // !__WXMICROWIN__
2666
2667 case WM_SYSCOLORCHANGE:
2668 // the return value for this message is ignored
2669 processed = HandleSysColorChange();
2670 break;
2671
2672 case WM_DISPLAYCHANGE:
2673 processed = HandleDisplayChange();
2674 break;
2675
2676 case WM_PALETTECHANGED:
2677 processed = HandlePaletteChanged((WXHWND) (HWND) wParam);
2678 break;
2679
2680 case WM_CAPTURECHANGED:
2681 processed = HandleCaptureChanged((WXHWND) (HWND) lParam);
2682 break;
2683
2684 case WM_QUERYNEWPALETTE:
2685 processed = HandleQueryNewPalette();
2686 break;
2687
2688 case WM_ERASEBKGND:
2689 processed = HandleEraseBkgnd((WXHDC)(HDC)wParam);
2690 if ( processed )
2691 {
2692 // we processed the message, i.e. erased the background
2693 rc.result = TRUE;
2694 }
2695 break;
2696
2697 case WM_DROPFILES:
2698 processed = HandleDropFiles(wParam);
2699 break;
2700
2701 case WM_INITDIALOG:
2702 processed = HandleInitDialog((WXHWND)(HWND)wParam);
2703
2704 if ( processed )
2705 {
2706 // we never set focus from here
2707 rc.result = FALSE;
2708 }
2709 break;
2710
2711 case WM_QUERYENDSESSION:
2712 processed = HandleQueryEndSession(lParam, &rc.allow);
2713 break;
2714
2715 case WM_ENDSESSION:
2716 processed = HandleEndSession(wParam != 0, lParam);
2717 break;
2718
2719 case WM_GETMINMAXINFO:
2720 processed = HandleGetMinMaxInfo((MINMAXINFO*)lParam);
2721 break;
2722
2723 case WM_SETCURSOR:
2724 processed = HandleSetCursor((WXHWND)(HWND)wParam,
2725 LOWORD(lParam), // hit test
2726 HIWORD(lParam)); // mouse msg
2727
2728 if ( processed )
2729 {
2730 // returning TRUE stops the DefWindowProc() from further
2731 // processing this message - exactly what we need because we've
2732 // just set the cursor.
2733 rc.result = TRUE;
2734 }
2735 break;
2736
2737 #if defined(__WIN32__) && defined(WM_HELP)
2738 case WM_HELP:
2739 {
2740 HELPINFO* info = (HELPINFO*) lParam;
2741 // Don't yet process menu help events, just windows
2742 if (info->iContextType == HELPINFO_WINDOW)
2743 {
2744 wxWindowMSW* subjectOfHelp = this;
2745 bool eventProcessed = FALSE;
2746 while (subjectOfHelp && !eventProcessed)
2747 {
2748 wxHelpEvent helpEvent(wxEVT_HELP,
2749 subjectOfHelp->GetId(),
2750 wxPoint(info->MousePos.x,
2751 info->MousePos.y) );
2752 helpEvent.SetEventObject(this);
2753 eventProcessed =
2754 GetEventHandler()->ProcessEvent(helpEvent);
2755
2756 // Go up the window hierarchy until the event is
2757 // handled (or not)
2758 subjectOfHelp = subjectOfHelp->GetParent();
2759 }
2760
2761 processed = eventProcessed;
2762 }
2763 else if (info->iContextType == HELPINFO_MENUITEM)
2764 {
2765 wxHelpEvent helpEvent(wxEVT_HELP, info->iCtrlId);
2766 helpEvent.SetEventObject(this);
2767 processed = GetEventHandler()->ProcessEvent(helpEvent);
2768
2769 }
2770 //else: processed is already FALSE
2771 }
2772 break;
2773
2774 case WM_CONTEXTMENU:
2775 {
2776 // we don't convert from screen to client coordinates as
2777 // the event may be handled by a parent window
2778 wxPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
2779
2780 wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt);
2781 processed = GetEventHandler()->ProcessEvent(evtCtx);
2782 }
2783 break;
2784 #endif // __WIN32__
2785 }
2786
2787 if ( !processed )
2788 {
2789 #ifdef __WXDEBUG__
2790 wxLogTrace(wxTraceMessages, wxT("Forwarding %s to DefWindowProc."),
2791 wxGetMessageName(message));
2792 #endif // __WXDEBUG__
2793 rc.result = MSWDefWindowProc(message, wParam, lParam);
2794 }
2795
2796 return rc.result;
2797 }
2798
2799 // ----------------------------------------------------------------------------
2800 // wxWindow <-> HWND map
2801 // ----------------------------------------------------------------------------
2802
2803 wxWinHashTable *wxWinHandleHash = NULL;
2804
2805 wxWindow *wxFindWinFromHandle(WXHWND hWnd)
2806 {
2807 return wxWinHandleHash->Get((long)hWnd);
2808 }
2809
2810 void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win)
2811 {
2812 // adding NULL hWnd is (first) surely a result of an error and
2813 // (secondly) breaks menu command processing
2814 wxCHECK_RET( hWnd != (HWND)NULL,
2815 wxT("attempt to add a NULL hWnd to window list ignored") );
2816
2817 wxWindow *oldWin = wxFindWinFromHandle((WXHWND) hWnd);
2818 #ifdef __WXDEBUG__
2819 if ( oldWin && (oldWin != win) )
2820 {
2821 wxLogDebug(wxT("HWND %X already associated with another window (%s)"),
2822 hWnd, win->GetClassInfo()->GetClassName());
2823 }
2824 else
2825 #endif // __WXDEBUG__
2826 if (!oldWin)
2827 {
2828 wxWinHandleHash->Put((long)hWnd, (wxWindow *)win);
2829 }
2830 }
2831
2832 void wxRemoveHandleAssociation(wxWindowMSW *win)
2833 {
2834 wxWinHandleHash->Delete((long)win->GetHWND());
2835 }
2836
2837 // ----------------------------------------------------------------------------
2838 // various MSW speciic class dependent functions
2839 // ----------------------------------------------------------------------------
2840
2841 // Default destroyer - override if you destroy it in some other way
2842 // (e.g. with MDI child windows)
2843 void wxWindowMSW::MSWDestroyWindow()
2844 {
2845 }
2846
2847 bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
2848 const wxSize& size,
2849 int& x, int& y,
2850 int& w, int& h) const
2851 {
2852 bool nonDefault = FALSE;
2853
2854 if ( pos.x == -1 )
2855 {
2856 // if set x to CW_USEDEFAULT, y parameter is ignored anyhow so we can
2857 // just as well set it to CW_USEDEFAULT as well
2858 x =
2859 y = CW_USEDEFAULT;
2860 }
2861 else
2862 {
2863 x = pos.x;
2864 y = pos.y == -1 ? CW_USEDEFAULT : pos.y;
2865
2866 nonDefault = TRUE;
2867 }
2868
2869 /*
2870 NB: there used to be some code here which set the initial size of the
2871 window to the client size of the parent if no explicit size was
2872 specified. This was wrong because wxWindows programs often assume
2873 that they get a WM_SIZE (EVT_SIZE) upon creation, however this broke
2874 it. To see why, you should understand that Windows sends WM_SIZE from
2875 inside ::CreateWindow() anyhow. However, ::CreateWindow() is called
2876 from some base class ctor and so this WM_SIZE is not processed in the
2877 real class' OnSize() (because it's not fully constructed yet and the
2878 event goes to some base class OnSize() instead). So the WM_SIZE we
2879 rely on is the one sent when the parent frame resizes its children
2880 but here is the problem: if the child already has just the right
2881 size, nothing will happen as both wxWindows and Windows check for
2882 this and ignore any attempts to change the window size to the size it
2883 already has - so no WM_SIZE would be sent.
2884 */
2885 if ( size.x == -1 )
2886 {
2887 // as abobe, h is not used at all in this case anyhow
2888 w =
2889 h = CW_USEDEFAULT;
2890 }
2891 else
2892 {
2893 w = size.x;
2894 h = size.y == -1 ? CW_USEDEFAULT : size.y;
2895
2896 nonDefault = TRUE;
2897 }
2898
2899 return nonDefault;
2900 }
2901
2902 bool wxWindowMSW::MSWCreate(const wxChar *wclass,
2903 const wxChar *title,
2904 const wxPoint& pos,
2905 const wxSize& size,
2906 WXDWORD style,
2907 WXDWORD extendedStyle)
2908 {
2909 // choose the position/size for the new window
2910 int x, y, w, h;
2911 (void)MSWGetCreateWindowCoords(pos, size, x, y, w, h);
2912
2913 // find the correct parent HWND
2914 wxWindow *parent = GetParent();
2915 bool isChild = (style & WS_CHILD) != 0;
2916 HWND hParent;
2917 if ( GetWindowStyleFlag() & wxPOPUP_WINDOW )
2918 {
2919 // popup windows should have desktop as parent because they shouldn't
2920 // be limited to the parents client area as child windows usually are
2921 hParent = ::GetDesktopWindow();
2922 }
2923 else // !popup
2924 {
2925 if ( (isChild || HasFlag(wxFRAME_TOOL_WINDOW)) && parent )
2926 {
2927 // this is either a normal child window or a top level window with
2928 // wxFRAME_TOOL_WINDOW style (see below)
2929 hParent = GetHwndOf(parent);
2930 }
2931 else
2932 {
2933 // this is either a window for which no parent was specified (not
2934 // much we can do then) or a frame without wxFRAME_TOOL_WINDOW
2935 // style: we should use NULL parent HWND for it or it would be
2936 // always on top of its parent which is not what we usually want
2937 // (in fact, we only want it for frames with the special
2938 // wxFRAME_TOOL_WINDOW as above)
2939 hParent = NULL;
2940 }
2941
2942 }
2943
2944 // controlId is menu handle for the top level windows, so set it to 0
2945 // unless we're creating a child window
2946 int controlId;
2947 if ( isChild )
2948 {
2949 controlId = GetId();
2950
2951 if ( GetWindowStyleFlag() & wxCLIP_SIBLINGS )
2952 {
2953 style |= WS_CLIPSIBLINGS;
2954 }
2955 }
2956 else // !child
2957 {
2958 controlId = 0;
2959 }
2960
2961 // for each class "Foo" we have we also have "FooNR" ("no repaint") class
2962 // which is the same but without CS_[HV]REDRAW class styles so using it
2963 // ensures that the window is not fully repainted on each resize
2964 wxString className(wclass);
2965 if ( GetWindowStyleFlag() & wxNO_FULL_REPAINT_ON_RESIZE )
2966 {
2967 className += wxT("NR");
2968 }
2969
2970 // do create the window
2971 wxWindowCreationHook hook(this);
2972
2973 m_hWnd = (WXHWND)::CreateWindowEx
2974 (
2975 extendedStyle,
2976 className,
2977 title ? title : wxT(""),
2978 style,
2979 x, y, w, h,
2980 hParent,
2981 (HMENU)controlId,
2982 wxGetInstance(),
2983 NULL // no extra data
2984 );
2985
2986 if ( !m_hWnd )
2987 {
2988 wxLogSysError(_("Can't create window of class %s"), wclass);
2989
2990 return FALSE;
2991 }
2992
2993 SubclassWin(m_hWnd);
2994
2995 SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
2996
2997 return TRUE;
2998 }
2999
3000 // ===========================================================================
3001 // MSW message handlers
3002 // ===========================================================================
3003
3004 // ---------------------------------------------------------------------------
3005 // WM_NOTIFY
3006 // ---------------------------------------------------------------------------
3007
3008 #ifdef __WIN95__
3009 // FIXME: VZ: I'm not sure at all that the order of processing is correct
3010 bool wxWindowMSW::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
3011 {
3012 #ifndef __WXMICROWIN__
3013 LPNMHDR hdr = (LPNMHDR)lParam;
3014 HWND hWnd = hdr->hwndFrom;
3015 wxWindow *win = wxFindWinFromHandle((WXHWND)hWnd);
3016
3017 // is this one of our windows?
3018 if ( win )
3019 {
3020 return win->MSWOnNotify(idCtrl, lParam, result);
3021 }
3022
3023 // try all our children
3024 wxWindowList::Node *node = GetChildren().GetFirst();
3025 while ( node )
3026 {
3027 wxWindow *child = node->GetData();
3028 if ( child->MSWOnNotify(idCtrl, lParam, result) )
3029 {
3030 return TRUE;
3031 }
3032
3033 node = node->GetNext();
3034 }
3035
3036 // finally try this window too (catches toolbar case)
3037 return MSWOnNotify(idCtrl, lParam, result);
3038 #else // __WXMICROWIN__
3039 return FALSE;
3040 #endif
3041 }
3042
3043 bool wxWindowMSW::MSWOnNotify(int WXUNUSED(idCtrl),
3044 WXLPARAM lParam,
3045 WXLPARAM* WXUNUSED(result))
3046 {
3047 #if wxUSE_TOOLTIPS
3048 NMHDR* hdr = (NMHDR *)lParam;
3049 if ( (int)hdr->code == TTN_NEEDTEXT && m_tooltip )
3050 {
3051 TOOLTIPTEXT *ttt = (TOOLTIPTEXT *)lParam;
3052 ttt->lpszText = (wxChar *)m_tooltip->GetTip().c_str();
3053
3054 // processed
3055 return TRUE;
3056 }
3057 #endif // wxUSE_TOOLTIPS
3058
3059 return FALSE;
3060 }
3061 #endif // __WIN95__
3062
3063 // ---------------------------------------------------------------------------
3064 // end session messages
3065 // ---------------------------------------------------------------------------
3066
3067 bool wxWindowMSW::HandleQueryEndSession(long logOff, bool *mayEnd)
3068 {
3069 wxCloseEvent event(wxEVT_QUERY_END_SESSION, -1);
3070 event.SetEventObject(wxTheApp);
3071 event.SetCanVeto(TRUE);
3072 event.SetLoggingOff(logOff == (long)ENDSESSION_LOGOFF);
3073
3074 bool rc = wxTheApp->ProcessEvent(event);
3075
3076 if ( rc )
3077 {
3078 // we may end only if the app didn't veto session closing (double
3079 // negation...)
3080 *mayEnd = !event.GetVeto();
3081 }
3082
3083 return rc;
3084 }
3085
3086 bool wxWindowMSW::HandleEndSession(bool endSession, long logOff)
3087 {
3088 // do nothing if the session isn't ending
3089 if ( !endSession )
3090 return FALSE;
3091
3092 // only send once
3093 if ( (this != wxTheApp->GetTopWindow()) )
3094 return FALSE;
3095
3096 wxCloseEvent event(wxEVT_END_SESSION, -1);
3097 event.SetEventObject(wxTheApp);
3098 event.SetCanVeto(FALSE);
3099 event.SetLoggingOff( (logOff == (long)ENDSESSION_LOGOFF) );
3100
3101 return wxTheApp->ProcessEvent(event);
3102 }
3103
3104 // ---------------------------------------------------------------------------
3105 // window creation/destruction
3106 // ---------------------------------------------------------------------------
3107
3108 bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT WXUNUSED(cs), bool *mayCreate)
3109 {
3110 // TODO: should generate this event from WM_NCCREATE
3111 wxWindowCreateEvent event((wxWindow *)this);
3112 (void)GetEventHandler()->ProcessEvent(event);
3113
3114 *mayCreate = TRUE;
3115
3116 return TRUE;
3117 }
3118
3119 bool wxWindowMSW::HandleDestroy()
3120 {
3121 wxWindowDestroyEvent event((wxWindow *)this);
3122 (void)GetEventHandler()->ProcessEvent(event);
3123
3124 // delete our drop target if we've got one
3125 #if wxUSE_DRAG_AND_DROP
3126 if ( m_dropTarget != NULL )
3127 {
3128 m_dropTarget->Revoke(m_hWnd);
3129
3130 delete m_dropTarget;
3131 m_dropTarget = NULL;
3132 }
3133 #endif // wxUSE_DRAG_AND_DROP
3134
3135 // WM_DESTROY handled
3136 return TRUE;
3137 }
3138
3139 // ---------------------------------------------------------------------------
3140 // activation/focus
3141 // ---------------------------------------------------------------------------
3142
3143 bool wxWindowMSW::HandleActivate(int state,
3144 bool WXUNUSED(minimized),
3145 WXHWND WXUNUSED(activate))
3146 {
3147 wxActivateEvent event(wxEVT_ACTIVATE,
3148 (state == WA_ACTIVE) || (state == WA_CLICKACTIVE),
3149 m_windowId);
3150 event.SetEventObject(this);
3151
3152 return GetEventHandler()->ProcessEvent(event);
3153 }
3154
3155 bool wxWindowMSW::HandleSetFocus(WXHWND hwnd)
3156 {
3157 // notify the parent keeping track of focus for the kbd navigation
3158 // purposes that we got it
3159 wxChildFocusEvent eventFocus((wxWindow *)this);
3160 (void)GetEventHandler()->ProcessEvent(eventFocus);
3161
3162 #if wxUSE_CARET
3163 // Deal with caret
3164 if ( m_caret )
3165 {
3166 m_caret->OnSetFocus();
3167 }
3168 #endif // wxUSE_CARET
3169
3170 #if wxUSE_TEXTCTRL
3171 // If it's a wxTextCtrl don't send the event as it will be done
3172 // after the control gets to process it from EN_FOCUS handler
3173 if ( wxDynamicCastThis(wxTextCtrl) )
3174 {
3175 return FALSE;
3176 }
3177 #endif // wxUSE_TEXTCTRL
3178
3179 wxFocusEvent event(wxEVT_SET_FOCUS, m_windowId);
3180 event.SetEventObject(this);
3181
3182 // wxFindWinFromHandle() may return NULL, it is ok
3183 event.SetWindow(wxFindWinFromHandle(hwnd));
3184
3185 return GetEventHandler()->ProcessEvent(event);
3186 }
3187
3188 bool wxWindowMSW::HandleKillFocus(WXHWND hwnd)
3189 {
3190 #if wxUSE_CARET
3191 // Deal with caret
3192 if ( m_caret )
3193 {
3194 m_caret->OnKillFocus();
3195 }
3196 #endif // wxUSE_CARET
3197
3198 #if wxUSE_TEXTCTRL
3199 // If it's a wxTextCtrl don't send the event as it will be done
3200 // after the control gets to process it.
3201 wxTextCtrl *ctrl = wxDynamicCastThis(wxTextCtrl);
3202 if ( ctrl )
3203 {
3204 return FALSE;
3205 }
3206 #endif
3207
3208 wxFocusEvent event(wxEVT_KILL_FOCUS, m_windowId);
3209 event.SetEventObject(this);
3210
3211 // wxFindWinFromHandle() may return NULL, it is ok
3212 event.SetWindow(wxFindWinFromHandle(hwnd));
3213
3214 return GetEventHandler()->ProcessEvent(event);
3215 }
3216
3217 // ---------------------------------------------------------------------------
3218 // miscellaneous
3219 // ---------------------------------------------------------------------------
3220
3221 bool wxWindowMSW::HandleShow(bool show, int WXUNUSED(status))
3222 {
3223 wxShowEvent event(GetId(), show);
3224 event.m_eventObject = this;
3225
3226 return GetEventHandler()->ProcessEvent(event);
3227 }
3228
3229 bool wxWindowMSW::HandleInitDialog(WXHWND WXUNUSED(hWndFocus))
3230 {
3231 wxInitDialogEvent event(GetId());
3232 event.m_eventObject = this;
3233
3234 return GetEventHandler()->ProcessEvent(event);
3235 }
3236
3237 bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam)
3238 {
3239 #ifndef __WXMICROWIN__
3240 HDROP hFilesInfo = (HDROP) wParam;
3241
3242 // Get the total number of files dropped
3243 UINT gwFilesDropped = ::DragQueryFile
3244 (
3245 (HDROP)hFilesInfo,
3246 (UINT)-1,
3247 (LPTSTR)0,
3248 (UINT)0
3249 );
3250
3251 wxString *files = new wxString[gwFilesDropped];
3252 for ( UINT wIndex = 0; wIndex < gwFilesDropped; wIndex++ )
3253 {
3254 // first get the needed buffer length (+1 for terminating NUL)
3255 size_t len = ::DragQueryFile(hFilesInfo, wIndex, NULL, 0) + 1;
3256
3257 // and now get the file name
3258 ::DragQueryFile(hFilesInfo, wIndex,
3259 files[wIndex].GetWriteBuf(len), len);
3260
3261 files[wIndex].UngetWriteBuf();
3262 }
3263 DragFinish (hFilesInfo);
3264
3265 wxDropFilesEvent event(wxEVT_DROP_FILES, gwFilesDropped, files);
3266 event.m_eventObject = this;
3267
3268 POINT dropPoint;
3269 DragQueryPoint(hFilesInfo, (LPPOINT) &dropPoint);
3270 event.m_pos.x = dropPoint.x;
3271 event.m_pos.y = dropPoint.y;
3272
3273 return GetEventHandler()->ProcessEvent(event);
3274 #else // __WXMICROWIN__
3275 return FALSE;
3276 #endif
3277 }
3278
3279 bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd),
3280 short nHitTest,
3281 int WXUNUSED(mouseMsg))
3282 {
3283 #ifndef __WXMICROWIN__
3284 // the logic is as follows:
3285 // -1. don't set cursor for non client area, including but not limited to
3286 // the title bar, scrollbars, &c
3287 // 0. allow the user to override default behaviour by using EVT_SET_CURSOR
3288 // 1. if we have the cursor set it unless wxIsBusy()
3289 // 2. if we're a top level window, set some cursor anyhow
3290 // 3. if wxIsBusy(), set the busy cursor, otherwise the global one
3291
3292 if ( nHitTest != HTCLIENT )
3293 {
3294 return FALSE;
3295 }
3296
3297 HCURSOR hcursor = 0;
3298
3299 // first ask the user code - it may wish to set the cursor in some very
3300 // specific way (for example, depending on the current position)
3301 POINT pt;
3302 #ifdef __WIN32__
3303 if ( !::GetCursorPos(&pt) )
3304 {
3305 wxLogLastError(wxT("GetCursorPos"));
3306 }
3307 #else
3308 // In WIN16 it doesn't return a value.
3309 ::GetCursorPos(&pt);
3310 #endif
3311
3312 int x = pt.x,
3313 y = pt.y;
3314 ScreenToClient(&x, &y);
3315 wxSetCursorEvent event(x, y);
3316
3317 bool processedEvtSetCursor = GetEventHandler()->ProcessEvent(event);
3318 if ( processedEvtSetCursor && event.HasCursor() )
3319 {
3320 hcursor = GetHcursorOf(event.GetCursor());
3321 }
3322
3323 if ( !hcursor )
3324 {
3325 bool isBusy = wxIsBusy();
3326
3327 // the test for processedEvtSetCursor is here to prevent using m_cursor
3328 // if the user code caught EVT_SET_CURSOR() and returned nothing from
3329 // it - this is a way to say that our cursor shouldn't be used for this
3330 // point
3331 if ( !processedEvtSetCursor && m_cursor.Ok() )
3332 {
3333 hcursor = GetHcursorOf(m_cursor);
3334 }
3335
3336 if ( !GetParent() )
3337 {
3338 if ( isBusy )
3339 {
3340 hcursor = wxGetCurrentBusyCursor();
3341 }
3342 else if ( !hcursor )
3343 {
3344 const wxCursor *cursor = wxGetGlobalCursor();
3345 if ( cursor && cursor->Ok() )
3346 {
3347 hcursor = GetHcursorOf(*cursor);
3348 }
3349 }
3350 }
3351 }
3352
3353 if ( hcursor )
3354 {
3355 ::SetCursor(hcursor);
3356
3357 // cursor set, stop here
3358 return TRUE;
3359 }
3360 #endif // __WXMICROWIN__
3361
3362 // pass up the window chain
3363 return FALSE;
3364 }
3365
3366 // ---------------------------------------------------------------------------
3367 // owner drawn stuff
3368 // ---------------------------------------------------------------------------
3369
3370 bool wxWindowMSW::MSWOnDrawItem(int id, WXDRAWITEMSTRUCT *itemStruct)
3371 {
3372 #if wxUSE_OWNER_DRAWN
3373
3374 #if wxUSE_MENUS_NATIVE
3375 // is it a menu item?
3376 DRAWITEMSTRUCT *pDrawStruct = (DRAWITEMSTRUCT *)itemStruct;
3377 if ( id == 0 && pDrawStruct->CtlType == ODT_MENU )
3378 {
3379 wxMenuItem *pMenuItem = (wxMenuItem *)(pDrawStruct->itemData);
3380
3381 wxCHECK( pMenuItem->IsKindOf(CLASSINFO(wxMenuItem)), FALSE );
3382
3383 // prepare to call OnDrawItem(): notice using of wxDCTemp to prevent
3384 // the DC from being released
3385 wxDCTemp dc((WXHDC)pDrawStruct->hDC);
3386 wxRect rect(pDrawStruct->rcItem.left, pDrawStruct->rcItem.top,
3387 pDrawStruct->rcItem.right - pDrawStruct->rcItem.left,
3388 pDrawStruct->rcItem.bottom - pDrawStruct->rcItem.top);
3389
3390 return pMenuItem->OnDrawItem
3391 (
3392 dc,
3393 rect,
3394 (wxOwnerDrawn::wxODAction)pDrawStruct->itemAction,
3395 (wxOwnerDrawn::wxODStatus)pDrawStruct->itemState
3396 );
3397 }
3398 #endif // wxUSE_MENUS_NATIVE
3399
3400 #if wxUSE_CONTROLS
3401 wxWindow *item = FindItem(id);
3402 if ( item && item->IsKindOf(CLASSINFO(wxControl)) )
3403 {
3404 return ((wxControl *)item)->MSWOnDraw(itemStruct);
3405 }
3406 #endif // wxUSE_CONTROLS
3407
3408 #endif // USE_OWNER_DRAWN
3409
3410 return FALSE;
3411 }
3412
3413 bool wxWindowMSW::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct)
3414 {
3415 #if wxUSE_OWNER_DRAWN
3416 // is it a menu item?
3417 MEASUREITEMSTRUCT *pMeasureStruct = (MEASUREITEMSTRUCT *)itemStruct;
3418 if ( id == 0 && pMeasureStruct->CtlType == ODT_MENU )
3419 {
3420 wxMenuItem *pMenuItem = (wxMenuItem *)(pMeasureStruct->itemData);
3421
3422 wxCHECK( pMenuItem->IsKindOf(CLASSINFO(wxMenuItem)), FALSE );
3423
3424 return pMenuItem->OnMeasureItem(&pMeasureStruct->itemWidth,
3425 &pMeasureStruct->itemHeight);
3426 }
3427
3428 wxWindow *item = FindItem(id);
3429 if ( item && item->IsKindOf(CLASSINFO(wxControl)) )
3430 {
3431 return ((wxControl *)item)->MSWOnMeasure(itemStruct);
3432 }
3433 #endif // owner-drawn menus
3434 return FALSE;
3435 }
3436
3437 // ---------------------------------------------------------------------------
3438 // colours and palettes
3439 // ---------------------------------------------------------------------------
3440
3441 bool wxWindowMSW::HandleSysColorChange()
3442 {
3443 wxSysColourChangedEvent event;
3444 event.SetEventObject(this);
3445
3446 (void)GetEventHandler()->ProcessEvent(event);
3447
3448 // always let the system carry on the default processing to allow the
3449 // native controls to react to the colours update
3450 return FALSE;
3451 }
3452
3453 bool wxWindowMSW::HandleDisplayChange()
3454 {
3455 wxDisplayChangedEvent event;
3456 event.SetEventObject(this);
3457
3458 return GetEventHandler()->ProcessEvent(event);
3459 }
3460
3461 bool wxWindowMSW::HandleCtlColor(WXHBRUSH *brush,
3462 WXHDC pDC,
3463 WXHWND pWnd,
3464 WXUINT nCtlColor,
3465 WXUINT message,
3466 WXWPARAM wParam,
3467 WXLPARAM lParam)
3468 {
3469 #ifndef __WXMICROWIN__
3470 WXHBRUSH hBrush = 0;
3471
3472 if ( nCtlColor == CTLCOLOR_DLG )
3473 {
3474 hBrush = OnCtlColor(pDC, pWnd, nCtlColor, message, wParam, lParam);
3475 }
3476 #if wxUSE_CONTROLS
3477 else
3478 {
3479 wxControl *item = (wxControl *)FindItemByHWND(pWnd, TRUE);
3480 if ( item )
3481 hBrush = item->OnCtlColor(pDC, pWnd, nCtlColor, message, wParam, lParam);
3482 }
3483 #endif // wxUSE_CONTROLS
3484
3485 if ( hBrush )
3486 *brush = hBrush;
3487
3488 return hBrush != 0;
3489 #else // __WXMICROWIN__
3490 return FALSE;
3491 #endif
3492 }
3493
3494 // Define for each class of dialog and control
3495 WXHBRUSH wxWindowMSW::OnCtlColor(WXHDC WXUNUSED(hDC),
3496 WXHWND WXUNUSED(hWnd),
3497 WXUINT WXUNUSED(nCtlColor),
3498 WXUINT WXUNUSED(message),
3499 WXWPARAM WXUNUSED(wParam),
3500 WXLPARAM WXUNUSED(lParam))
3501 {
3502 return (WXHBRUSH)0;
3503 }
3504
3505 bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange)
3506 {
3507 #if wxUSE_PALETTE
3508 // same as below except we don't respond to our own messages
3509 if ( hWndPalChange != GetHWND() )
3510 {
3511 // check to see if we our our parents have a custom palette
3512 wxWindow *win = this;
3513 while ( win && !win->HasCustomPalette() )
3514 {
3515 win = win->GetParent();
3516 }
3517
3518 if ( win && win->HasCustomPalette() )
3519 {
3520 // realize the palette to see whether redrawing is needed
3521 HDC hdc = ::GetDC((HWND) hWndPalChange);
3522 win->m_palette.SetHPALETTE((WXHPALETTE)
3523 ::SelectPalette(hdc, GetHpaletteOf(win->m_palette), FALSE));
3524
3525 int result = ::RealizePalette(hdc);
3526
3527 // restore the palette (before releasing the DC)
3528 win->m_palette.SetHPALETTE((WXHPALETTE)
3529 ::SelectPalette(hdc, GetHpaletteOf(win->m_palette), FALSE));
3530 ::RealizePalette(hdc);
3531 ::ReleaseDC((HWND) hWndPalChange, hdc);
3532
3533 // now check for the need to redraw
3534 if (result > 0)
3535 InvalidateRect((HWND) hWndPalChange, NULL, TRUE);
3536 }
3537
3538 }
3539 #endif // wxUSE_PALETTE
3540
3541 wxPaletteChangedEvent event(GetId());
3542 event.SetEventObject(this);
3543 event.SetChangedWindow(wxFindWinFromHandle(hWndPalChange));
3544
3545 return GetEventHandler()->ProcessEvent(event);
3546 }
3547
3548 bool wxWindowMSW::HandleCaptureChanged(WXHWND hWndGainedCapture)
3549 {
3550 wxMouseCaptureChangedEvent event(GetId(), wxFindWinFromHandle(hWndGainedCapture));
3551 event.SetEventObject(this);
3552
3553 return GetEventHandler()->ProcessEvent(event);
3554 }
3555
3556 bool wxWindowMSW::HandleQueryNewPalette()
3557 {
3558
3559 #if wxUSE_PALETTE
3560 // check to see if we our our parents have a custom palette
3561 wxWindow *win = this;
3562 while (!win->HasCustomPalette() && win->GetParent()) win = win->GetParent();
3563 if (win->HasCustomPalette()) {
3564 /* realize the palette to see whether redrawing is needed */
3565 HDC hdc = GetDC((HWND) GetHWND());
3566 win->m_palette.SetHPALETTE( (WXHPALETTE)
3567 ::SelectPalette(hdc, (HPALETTE) win->m_palette.GetHPALETTE(), FALSE) );
3568
3569 int result = ::RealizePalette(hdc);
3570 /* restore the palette (before releasing the DC) */
3571 win->m_palette.SetHPALETTE( (WXHPALETTE)
3572 ::SelectPalette(hdc, (HPALETTE) win->m_palette.GetHPALETTE(), TRUE) );
3573 ::RealizePalette(hdc);
3574 ::ReleaseDC((HWND) GetHWND(), hdc);
3575 /* now check for the need to redraw */
3576 if (result > 0)
3577 ::InvalidateRect((HWND) GetHWND(), NULL, TRUE);
3578 }
3579 #endif // wxUSE_PALETTE
3580
3581 wxQueryNewPaletteEvent event(GetId());
3582 event.SetEventObject(this);
3583
3584 return GetEventHandler()->ProcessEvent(event) && event.GetPaletteRealized();
3585 }
3586
3587 // Responds to colour changes: passes event on to children.
3588 void wxWindowMSW::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event))
3589 {
3590 // the top level window also reset the standard colour map as it might have
3591 // changed (there is no need to do it for the non top level windows as we
3592 // only have to do it once)
3593 if ( IsTopLevel() )
3594 {
3595 // FIXME-MT
3596 gs_hasStdCmap = FALSE;
3597 }
3598 wxWindowList::Node *node = GetChildren().GetFirst();
3599 while ( node )
3600 {
3601 // Only propagate to non-top-level windows because Windows already
3602 // sends this event to all top-level ones
3603 wxWindow *win = node->GetData();
3604 if ( !win->IsTopLevel() )
3605 {
3606 // we need to send the real WM_SYSCOLORCHANGE and not just trigger
3607 // EVT_SYS_COLOUR_CHANGED call because the latter wouldn't work for
3608 // the standard controls
3609 ::SendMessage(GetHwndOf(win), WM_SYSCOLORCHANGE, 0, 0);
3610 }
3611
3612 node = node->GetNext();
3613 }
3614
3615 // update the colours we use if they were not set explicitly by the user:
3616 // this must be done or OnCtlColor() would continue to use the old colours
3617 if ( !m_hasFgCol )
3618 {
3619 m_foregroundColour = wxSystemSettings::
3620 GetSystemColour(wxSYS_COLOUR_WINDOWTEXT);
3621 }
3622
3623 if ( !m_hasBgCol )
3624 {
3625 m_backgroundColour = wxSystemSettings::
3626 GetSystemColour(wxSYS_COLOUR_BTNFACE);
3627 }
3628 }
3629
3630 extern wxCOLORMAP *wxGetStdColourMap()
3631 {
3632 static COLORREF s_stdColours[wxSTD_COL_MAX];
3633 static wxCOLORMAP s_cmap[wxSTD_COL_MAX];
3634
3635 if ( !gs_hasStdCmap )
3636 {
3637 static bool s_coloursInit = FALSE;
3638
3639 if ( !s_coloursInit )
3640 {
3641 // When a bitmap is loaded, the RGB values can change (apparently
3642 // because Windows adjusts them to care for the old programs always
3643 // using 0xc0c0c0 while the transparent colour for the new Windows
3644 // versions is different). But we do this adjustment ourselves so
3645 // we want to avoid Windows' "help" and for this we need to have a
3646 // reference bitmap which can tell us what the RGB values change
3647 // to.
3648 wxBitmap stdColourBitmap(_T("wxBITMAP_STD_COLOURS"));
3649 if ( stdColourBitmap.Ok() )
3650 {
3651 // the pixels in the bitmap must correspond to wxSTD_COL_XXX!
3652 wxASSERT_MSG( stdColourBitmap.GetWidth() == wxSTD_COL_MAX,
3653 _T("forgot to update wxBITMAP_STD_COLOURS!") );
3654
3655 wxMemoryDC memDC;
3656 memDC.SelectObject(stdColourBitmap);
3657
3658 wxColour colour;
3659 for ( size_t i = 0; i < WXSIZEOF(s_stdColours); i++ )
3660 {
3661 memDC.GetPixel(i, 0, &colour);
3662 s_stdColours[i] = wxColourToRGB(colour);
3663 }
3664 }
3665 else // wxBITMAP_STD_COLOURS couldn't be loaded
3666 {
3667 s_stdColours[0] = RGB(000,000,000); // black
3668 s_stdColours[1] = RGB(128,128,128); // dark grey
3669 s_stdColours[2] = RGB(192,192,192); // light grey
3670 s_stdColours[3] = RGB(255,255,255); // white
3671 //s_stdColours[4] = RGB(000,000,255); // blue
3672 //s_stdColours[5] = RGB(255,000,255); // magenta
3673 }
3674
3675 s_coloursInit = TRUE;
3676 }
3677
3678 gs_hasStdCmap = TRUE;
3679
3680 // create the colour map
3681 #define INIT_CMAP_ENTRY(col) \
3682 s_cmap[wxSTD_COL_##col].from = s_stdColours[wxSTD_COL_##col]; \
3683 s_cmap[wxSTD_COL_##col].to = ::GetSysColor(COLOR_##col)
3684
3685 INIT_CMAP_ENTRY(BTNTEXT);
3686 INIT_CMAP_ENTRY(BTNSHADOW);
3687 INIT_CMAP_ENTRY(BTNFACE);
3688 INIT_CMAP_ENTRY(BTNHIGHLIGHT);
3689
3690 #undef INIT_CMAP_ENTRY
3691 }
3692
3693 return s_cmap;
3694 }
3695
3696 // ---------------------------------------------------------------------------
3697 // painting
3698 // ---------------------------------------------------------------------------
3699
3700 bool wxWindowMSW::HandlePaint()
3701 {
3702 #ifdef __WIN32__
3703 HRGN hRegion = ::CreateRectRgn(0, 0, 0, 0); // Dummy call to get a handle
3704 if ( !hRegion )
3705 wxLogLastError(wxT("CreateRectRgn"));
3706 if ( ::GetUpdateRgn(GetHwnd(), hRegion, FALSE) == ERROR )
3707 wxLogLastError(wxT("GetUpdateRgn"));
3708
3709 m_updateRegion = wxRegion((WXHRGN) hRegion);
3710 #else // Win16
3711 RECT updateRect;
3712 ::GetUpdateRect(GetHwnd(), &updateRect, FALSE);
3713
3714 m_updateRegion = wxRegion(updateRect.left, updateRect.top,
3715 updateRect.right - updateRect.left,
3716 updateRect.bottom - updateRect.top);
3717 #endif // Win32/16
3718
3719 wxPaintEvent event(m_windowId);
3720 event.SetEventObject(this);
3721
3722 bool processed = GetEventHandler()->ProcessEvent(event);
3723
3724 // note that we must generate NC event after the normal one as otherwise
3725 // BeginPaint() will happily overwrite our decorations with the background
3726 // colour
3727 wxNcPaintEvent eventNc(m_windowId);
3728 eventNc.SetEventObject(this);
3729 GetEventHandler()->ProcessEvent(eventNc);
3730
3731 return processed;
3732 }
3733
3734 // Can be called from an application's OnPaint handler
3735 void wxWindowMSW::OnPaint(wxPaintEvent& event)
3736 {
3737 #ifdef __WXUNIVERSAL__
3738 event.Skip();
3739 #else
3740 HDC hDC = (HDC) wxPaintDC::FindDCInCache((wxWindow*) event.GetEventObject());
3741 if (hDC != 0)
3742 {
3743 MSWDefWindowProc(WM_PAINT, (WPARAM) hDC, 0);
3744 }
3745 #endif
3746 }
3747
3748 bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc)
3749 {
3750 // Prevents flicker when dragging
3751 if ( ::IsIconic(GetHwnd()) )
3752 return TRUE;
3753
3754 wxDCTemp dc(hdc);
3755
3756 dc.SetHDC(hdc);
3757 dc.SetWindow((wxWindow *)this);
3758 dc.BeginDrawing();
3759
3760 wxEraseEvent event(m_windowId, &dc);
3761 event.SetEventObject(this);
3762 bool rc = GetEventHandler()->ProcessEvent(event);
3763
3764 dc.EndDrawing();
3765
3766 // must be called manually as ~wxDC doesn't do anything for wxDCTemp
3767 dc.SelectOldObjects(hdc);
3768
3769 return rc;
3770 }
3771
3772 void wxWindowMSW::OnEraseBackground(wxEraseEvent& event)
3773 {
3774 RECT rect;
3775 ::GetClientRect(GetHwnd(), &rect);
3776
3777 COLORREF ref = PALETTERGB(m_backgroundColour.Red(),
3778 m_backgroundColour.Green(),
3779 m_backgroundColour.Blue());
3780 HBRUSH hBrush = ::CreateSolidBrush(ref);
3781 if ( !hBrush )
3782 wxLogLastError(wxT("CreateSolidBrush"));
3783
3784 HDC hdc = (HDC)event.GetDC()->GetHDC();
3785
3786 int mode = ::SetMapMode(hdc, MM_TEXT);
3787
3788 ::FillRect(hdc, &rect, hBrush);
3789 ::DeleteObject(hBrush);
3790 ::SetMapMode(hdc, mode);
3791 }
3792
3793 // ---------------------------------------------------------------------------
3794 // moving and resizing
3795 // ---------------------------------------------------------------------------
3796
3797 bool wxWindowMSW::HandleMinimize()
3798 {
3799 wxIconizeEvent event(m_windowId);
3800 event.SetEventObject(this);
3801
3802 return GetEventHandler()->ProcessEvent(event);
3803 }
3804
3805 bool wxWindowMSW::HandleMaximize()
3806 {
3807 wxMaximizeEvent event(m_windowId);
3808 event.SetEventObject(this);
3809
3810 return GetEventHandler()->ProcessEvent(event);
3811 }
3812
3813 bool wxWindowMSW::HandleMove(int x, int y)
3814 {
3815 wxMoveEvent event(wxPoint(x, y), m_windowId);
3816 event.SetEventObject(this);
3817
3818 return GetEventHandler()->ProcessEvent(event);
3819 }
3820
3821 bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h),
3822 WXUINT WXUNUSED(flag))
3823 {
3824 // don't use w and h parameters as they specify the client size while
3825 // according to the docs EVT_SIZE handler is supposed to receive the total
3826 // size
3827 wxSizeEvent event(GetSize(), m_windowId);
3828 event.SetEventObject(this);
3829
3830 return GetEventHandler()->ProcessEvent(event);
3831 }
3832
3833 bool wxWindowMSW::HandleGetMinMaxInfo(void *mmInfo)
3834 {
3835 MINMAXINFO *info = (MINMAXINFO *)mmInfo;
3836
3837 bool rc = FALSE;
3838
3839 int minWidth = GetMinWidth(),
3840 minHeight = GetMinHeight(),
3841 maxWidth = GetMaxWidth(),
3842 maxHeight = GetMaxHeight();
3843
3844 if ( minWidth != -1 )
3845 {
3846 info->ptMinTrackSize.x = minWidth;
3847 rc = TRUE;
3848 }
3849
3850 if ( minHeight != -1 )
3851 {
3852 info->ptMinTrackSize.y = minHeight;
3853 rc = TRUE;
3854 }
3855
3856 if ( maxWidth != -1 )
3857 {
3858 info->ptMaxTrackSize.x = maxWidth;
3859 rc = TRUE;
3860 }
3861
3862 if ( maxHeight != -1 )
3863 {
3864 info->ptMaxTrackSize.y = maxHeight;
3865 rc = TRUE;
3866 }
3867
3868 return rc;
3869 }
3870
3871 // ---------------------------------------------------------------------------
3872 // command messages
3873 // ---------------------------------------------------------------------------
3874
3875 bool wxWindowMSW::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control)
3876 {
3877 #if wxUSE_MENUS_NATIVE
3878 if ( !cmd && wxCurrentPopupMenu )
3879 {
3880 wxMenu *popupMenu = wxCurrentPopupMenu;
3881 wxCurrentPopupMenu = NULL;
3882
3883 return popupMenu->MSWCommand(cmd, id);
3884 }
3885 #endif // wxUSE_MENUS_NATIVE
3886
3887 wxWindow *win = NULL;
3888
3889 // first try to find it from HWND - this works even with the broken
3890 // programs using the same ids for different controls
3891 if ( control )
3892 {
3893 win = wxFindWinFromHandle(control);
3894 }
3895
3896 // try the id
3897 if ( !win )
3898 {
3899 // must cast to a signed type before comparing with other ids!
3900 win = FindItem((signed short)id);
3901 }
3902
3903 if ( win )
3904 {
3905 return win->MSWCommand(cmd, id);
3906 }
3907
3908 // the messages sent from the in-place edit control used by the treectrl
3909 // for label editing have id == 0, but they should _not_ be treated as menu
3910 // messages (they are EN_XXX ones, in fact) so don't translate anything
3911 // coming from a control to wxEVT_COMMAND_MENU_SELECTED
3912 if ( !control )
3913 {
3914 // If no child window, it may be an accelerator, e.g. for a popup menu
3915 // command
3916
3917 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED);
3918 event.SetEventObject(this);
3919 event.SetId(id);
3920 event.SetInt(id);
3921
3922 return GetEventHandler()->ProcessEvent(event);
3923 }
3924 #if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__)
3925 else
3926 {
3927 // the text ctrl which is logically part of wxSpinCtrl sends WM_COMMAND
3928 // notifications to its parent which we want to reflect back to
3929 // wxSpinCtrl
3930 wxSpinCtrl *spin = wxSpinCtrl::GetSpinForTextCtrl(control);
3931 if ( spin && spin->ProcessTextCommand(cmd, id) )
3932 return TRUE;
3933 }
3934 #endif // wxUSE_SPINCTRL
3935
3936 return FALSE;
3937 }
3938
3939 bool wxWindowMSW::HandleSysCommand(WXWPARAM wParam, WXLPARAM WXUNUSED(lParam))
3940 {
3941 // 4 bits are reserved
3942 switch ( wParam & 0xFFFFFFF0 )
3943 {
3944 case SC_MAXIMIZE:
3945 return HandleMaximize();
3946
3947 case SC_MINIMIZE:
3948 return HandleMinimize();
3949 }
3950
3951 return FALSE;
3952 }
3953
3954 // ---------------------------------------------------------------------------
3955 // mouse events
3956 // ---------------------------------------------------------------------------
3957
3958 void wxWindowMSW::InitMouseEvent(wxMouseEvent& event,
3959 int x, int y,
3960 WXUINT flags)
3961 {
3962 // our client coords are not quite the same as Windows ones
3963 wxPoint pt = GetClientAreaOrigin();
3964 event.m_x = x - pt.x;
3965 event.m_y = y - pt.y;
3966
3967 event.m_shiftDown = (flags & MK_SHIFT) != 0;
3968 event.m_controlDown = (flags & MK_CONTROL) != 0;
3969 event.m_leftDown = (flags & MK_LBUTTON) != 0;
3970 event.m_middleDown = (flags & MK_MBUTTON) != 0;
3971 event.m_rightDown = (flags & MK_RBUTTON) != 0;
3972 event.m_altDown = (::GetKeyState(VK_MENU) & 0x80000000) != 0;
3973
3974 event.SetTimestamp(s_currentMsg.time);
3975 event.m_eventObject = this;
3976
3977 #if wxUSE_MOUSEEVENT_HACK
3978 m_lastMouseX = x;
3979 m_lastMouseY = y;
3980 m_lastMouseEvent = event.GetEventType();
3981 #endif // wxUSE_MOUSEEVENT_HACK
3982 }
3983
3984 bool wxWindowMSW::HandleMouseEvent(WXUINT msg, int x, int y, WXUINT flags)
3985 {
3986 // the mouse events take consecutive IDs from WM_MOUSEFIRST to
3987 // WM_MOUSELAST, so it's enough to substract WM_MOUSEMOVE == WM_MOUSEFIRST
3988 // from the message id and take the value in the table to get wxWin event
3989 // id
3990 static const wxEventType eventsMouse[] =
3991 {
3992 wxEVT_MOTION,
3993 wxEVT_LEFT_DOWN,
3994 wxEVT_LEFT_UP,
3995 wxEVT_LEFT_DCLICK,
3996 wxEVT_RIGHT_DOWN,
3997 wxEVT_RIGHT_UP,
3998 wxEVT_RIGHT_DCLICK,
3999 wxEVT_MIDDLE_DOWN,
4000 wxEVT_MIDDLE_UP,
4001 wxEVT_MIDDLE_DCLICK
4002 };
4003
4004 wxMouseEvent event(eventsMouse[msg - WM_MOUSEMOVE]);
4005 InitMouseEvent(event, x, y, flags);
4006
4007 return GetEventHandler()->ProcessEvent(event);
4008 }
4009
4010 bool wxWindowMSW::HandleMouseMove(int x, int y, WXUINT flags)
4011 {
4012 if ( !m_mouseInWindow )
4013 {
4014 // it would be wrong to assume that just because we get a mouse move
4015 // event that the mouse is inside the window: although this is usually
4016 // true, it is not if we had captured the mouse, so we need to check
4017 // the mouse coordinates here
4018 if ( !HasCapture() || IsMouseInWindow() )
4019 {
4020 // Generate an ENTER event
4021 m_mouseInWindow = TRUE;
4022
4023 wxMouseEvent event(wxEVT_ENTER_WINDOW);
4024 InitMouseEvent(event, x, y, flags);
4025
4026 (void)GetEventHandler()->ProcessEvent(event);
4027 }
4028 }
4029
4030 #if wxUSE_MOUSEEVENT_HACK
4031 // Window gets a click down message followed by a mouse move message even
4032 // if position isn't changed! We want to discard the trailing move event
4033 // if x and y are the same.
4034 if ( (m_lastMouseEvent == wxEVT_RIGHT_DOWN ||
4035 m_lastMouseEvent == wxEVT_LEFT_DOWN ||
4036 m_lastMouseEvent == wxEVT_MIDDLE_DOWN) &&
4037 (m_lastMouseX == x && m_lastMouseY == y) )
4038 {
4039 m_lastMouseEvent = wxEVT_MOTION;
4040
4041 return FALSE;
4042 }
4043 #endif // wxUSE_MOUSEEVENT_HACK
4044
4045 return HandleMouseEvent(WM_MOUSEMOVE, x, y, flags);
4046 }
4047
4048
4049 bool wxWindowMSW::HandleMouseWheel(WXWPARAM wParam, WXLPARAM lParam)
4050 {
4051 #if wxUSE_MOUSEWHEEL
4052 wxMouseEvent event(wxEVT_MOUSEWHEEL);
4053 InitMouseEvent(event,
4054 GET_X_LPARAM(lParam),
4055 GET_Y_LPARAM(lParam),
4056 LOWORD(wParam));
4057 event.m_wheelRotation = (short)HIWORD(wParam);
4058 event.m_wheelDelta = WHEEL_DELTA;
4059
4060 #ifdef __WIN32__
4061 static int s_linesPerRotation = -1;
4062 if ( s_linesPerRotation == -1 )
4063 {
4064 if ( !::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
4065 &s_linesPerRotation, 0))
4066 {
4067 // this is not supposed to happen
4068 wxLogLastError(_T("SystemParametersInfo(GETWHEELSCROLLLINES)"));
4069
4070 // the default is 3, so use it if SystemParametersInfo() failed
4071 s_linesPerRotation = 3;
4072 }
4073 }
4074 #else // Win16
4075 // no SystemParametersInfo() under Win16
4076 static const int s_linesPerRotation = 3;
4077 #endif
4078
4079 event.m_linesPerAction = s_linesPerRotation;
4080 return GetEventHandler()->ProcessEvent(event);
4081
4082 #else
4083 (void) wParam;
4084 (void) lParam;
4085
4086 return FALSE;
4087 #endif
4088 }
4089
4090
4091 // ---------------------------------------------------------------------------
4092 // keyboard handling
4093 // ---------------------------------------------------------------------------
4094
4095 // create the key event of the given type for the given key - used by
4096 // HandleChar and HandleKeyDown/Up
4097 wxKeyEvent wxWindowMSW::CreateKeyEvent(wxEventType evType,
4098 int id,
4099 WXLPARAM lParam,
4100 WXWPARAM wParam) const
4101 {
4102 wxKeyEvent event(evType);
4103 event.SetId(GetId());
4104 event.m_shiftDown = wxIsShiftDown();
4105 event.m_controlDown = wxIsCtrlDown();
4106 event.m_altDown = (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN;
4107
4108 event.m_eventObject = (wxWindow *)this; // const_cast
4109 event.m_keyCode = id;
4110 event.m_rawCode = (wxUint32) wParam;
4111 event.m_rawFlags = (wxUint32) lParam;
4112 event.SetTimestamp(s_currentMsg.time);
4113
4114 // translate the position to client coords
4115 POINT pt;
4116 GetCursorPos(&pt);
4117 RECT rect;
4118 GetWindowRect(GetHwnd(),&rect);
4119 pt.x -= rect.left;
4120 pt.y -= rect.top;
4121
4122 event.m_x = pt.x;
4123 event.m_y = pt.y;
4124
4125 return event;
4126 }
4127
4128 // isASCII is TRUE only when we're called from WM_CHAR handler and not from
4129 // WM_KEYDOWN one
4130 bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam, bool isASCII)
4131 {
4132 bool ctrlDown = FALSE;
4133
4134 int id;
4135 if ( isASCII )
4136 {
4137 // If 1 -> 26, translate to CTRL plus a letter.
4138 id = wParam;
4139 if ( (id > 0) && (id < 27) )
4140 {
4141 switch (id)
4142 {
4143 case 13:
4144 id = WXK_RETURN;
4145 break;
4146
4147 case 8:
4148 id = WXK_BACK;
4149 break;
4150
4151 case 9:
4152 id = WXK_TAB;
4153 break;
4154
4155 default:
4156 ctrlDown = TRUE;
4157 id = id + 'a' - 1;
4158 }
4159 }
4160 }
4161 else // we're called from WM_KEYDOWN
4162 {
4163 id = wxCharCodeMSWToWX(wParam);
4164 if ( id == 0 )
4165 {
4166 // it's ASCII and will be processed here only when called from
4167 // WM_CHAR (i.e. when isASCII = TRUE), don't process it now
4168 return FALSE;
4169 }
4170 }
4171
4172 wxKeyEvent event(CreateKeyEvent(wxEVT_CHAR, id, lParam, wParam));
4173 if ( ctrlDown )
4174 {
4175 event.m_controlDown = TRUE;
4176 }
4177
4178 return GetEventHandler()->ProcessEvent(event);
4179 }
4180
4181 bool wxWindowMSW::HandleKeyDown(WXWPARAM wParam, WXLPARAM lParam)
4182 {
4183 int id = wxCharCodeMSWToWX(wParam);
4184
4185 if ( !id )
4186 {
4187 // normal ASCII char
4188 id = wParam;
4189 }
4190
4191 if ( id != -1 ) // VZ: does this ever happen (FIXME)?
4192 {
4193 wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_DOWN, id, lParam, wParam));
4194 if ( GetEventHandler()->ProcessEvent(event) )
4195 {
4196 return TRUE;
4197 }
4198 }
4199
4200 return FALSE;
4201 }
4202
4203 bool wxWindowMSW::HandleKeyUp(WXWPARAM wParam, WXLPARAM lParam)
4204 {
4205 int id = wxCharCodeMSWToWX(wParam);
4206
4207 if ( !id )
4208 {
4209 // normal ASCII char
4210 id = wParam;
4211 }
4212
4213 if ( id != -1 ) // VZ: does this ever happen (FIXME)?
4214 {
4215 wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_UP, id, lParam, wParam));
4216 if ( GetEventHandler()->ProcessEvent(event) )
4217 return TRUE;
4218 }
4219
4220 return FALSE;
4221 }
4222
4223 // ---------------------------------------------------------------------------
4224 // joystick
4225 // ---------------------------------------------------------------------------
4226
4227 bool wxWindowMSW::HandleJoystickEvent(WXUINT msg, int x, int y, WXUINT flags)
4228 {
4229 #ifdef JOY_BUTTON1
4230 int change = 0;
4231 if ( flags & JOY_BUTTON1CHG )
4232 change = wxJOY_BUTTON1;
4233 if ( flags & JOY_BUTTON2CHG )
4234 change = wxJOY_BUTTON2;
4235 if ( flags & JOY_BUTTON3CHG )
4236 change = wxJOY_BUTTON3;
4237 if ( flags & JOY_BUTTON4CHG )
4238 change = wxJOY_BUTTON4;
4239
4240 int buttons = 0;
4241 if ( flags & JOY_BUTTON1 )
4242 buttons |= wxJOY_BUTTON1;
4243 if ( flags & JOY_BUTTON2 )
4244 buttons |= wxJOY_BUTTON2;
4245 if ( flags & JOY_BUTTON3 )
4246 buttons |= wxJOY_BUTTON3;
4247 if ( flags & JOY_BUTTON4 )
4248 buttons |= wxJOY_BUTTON4;
4249
4250 // the event ids aren't consecutive so we can't use table based lookup
4251 int joystick;
4252 wxEventType eventType;
4253 switch ( msg )
4254 {
4255 case MM_JOY1MOVE:
4256 joystick = 1;
4257 eventType = wxEVT_JOY_MOVE;
4258 break;
4259
4260 case MM_JOY2MOVE:
4261 joystick = 2;
4262 eventType = wxEVT_JOY_MOVE;
4263 break;
4264
4265 case MM_JOY1ZMOVE:
4266 joystick = 1;
4267 eventType = wxEVT_JOY_ZMOVE;
4268 break;
4269
4270 case MM_JOY2ZMOVE:
4271 joystick = 2;
4272 eventType = wxEVT_JOY_ZMOVE;
4273 break;
4274
4275 case MM_JOY1BUTTONDOWN:
4276 joystick = 1;
4277 eventType = wxEVT_JOY_BUTTON_DOWN;
4278 break;
4279
4280 case MM_JOY2BUTTONDOWN:
4281 joystick = 2;
4282 eventType = wxEVT_JOY_BUTTON_DOWN;
4283 break;
4284
4285 case MM_JOY1BUTTONUP:
4286 joystick = 1;
4287 eventType = wxEVT_JOY_BUTTON_UP;
4288 break;
4289
4290 case MM_JOY2BUTTONUP:
4291 joystick = 2;
4292 eventType = wxEVT_JOY_BUTTON_UP;
4293 break;
4294
4295 default:
4296 wxFAIL_MSG(wxT("no such joystick event"));
4297
4298 return FALSE;
4299 }
4300
4301 wxJoystickEvent event(eventType, buttons, joystick, change);
4302 event.SetPosition(wxPoint(x, y));
4303 event.SetEventObject(this);
4304
4305 return GetEventHandler()->ProcessEvent(event);
4306 #else
4307 return FALSE;
4308 #endif
4309 }
4310
4311 // ---------------------------------------------------------------------------
4312 // scrolling
4313 // ---------------------------------------------------------------------------
4314
4315 bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam,
4316 WXWORD pos, WXHWND control)
4317 {
4318 if ( control )
4319 {
4320 wxWindow *child = wxFindWinFromHandle(control);
4321 if ( child )
4322 return child->MSWOnScroll(orientation, wParam, pos, control);
4323 }
4324
4325 wxScrollWinEvent event;
4326 event.SetPosition(pos);
4327 event.SetOrientation(orientation);
4328 event.m_eventObject = this;
4329
4330 switch ( wParam )
4331 {
4332 case SB_TOP:
4333 event.m_eventType = wxEVT_SCROLLWIN_TOP;
4334 break;
4335
4336 case SB_BOTTOM:
4337 event.m_eventType = wxEVT_SCROLLWIN_BOTTOM;
4338 break;
4339
4340 case SB_LINEUP:
4341 event.m_eventType = wxEVT_SCROLLWIN_LINEUP;
4342 break;
4343
4344 case SB_LINEDOWN:
4345 event.m_eventType = wxEVT_SCROLLWIN_LINEDOWN;
4346 break;
4347
4348 case SB_PAGEUP:
4349 event.m_eventType = wxEVT_SCROLLWIN_PAGEUP;
4350 break;
4351
4352 case SB_PAGEDOWN:
4353 event.m_eventType = wxEVT_SCROLLWIN_PAGEDOWN;
4354 break;
4355
4356 case SB_THUMBPOSITION:
4357 case SB_THUMBTRACK:
4358 #ifdef __WIN32__
4359 // under Win32, the scrollbar range and position are 32 bit integers,
4360 // but WM_[HV]SCROLL only carry the low 16 bits of them, so we must
4361 // explicitly query the scrollbar for the correct position (this must
4362 // be done only for these two SB_ events as they are the only one
4363 // carrying the scrollbar position)
4364 {
4365 SCROLLINFO scrollInfo;
4366 wxZeroMemory(scrollInfo);
4367 scrollInfo.cbSize = sizeof(SCROLLINFO);
4368 scrollInfo.fMask = SIF_TRACKPOS;
4369
4370 if ( !::GetScrollInfo(GetHwnd(),
4371 orientation == wxHORIZONTAL ? SB_HORZ
4372 : SB_VERT,
4373 &scrollInfo) )
4374 {
4375 wxLogLastError(_T("GetScrollInfo"));
4376 }
4377
4378 event.SetPosition(scrollInfo.nTrackPos);
4379 }
4380 #endif // Win32
4381
4382 event.m_eventType = wParam == SB_THUMBPOSITION
4383 ? wxEVT_SCROLLWIN_THUMBRELEASE
4384 : wxEVT_SCROLLWIN_THUMBTRACK;
4385 break;
4386
4387 default:
4388 return FALSE;
4389 }
4390
4391 return GetEventHandler()->ProcessEvent(event);
4392 }
4393
4394 // ===========================================================================
4395 // global functions
4396 // ===========================================================================
4397
4398 void wxGetCharSize(WXHWND wnd, int *x, int *y, const wxFont *the_font)
4399 {
4400 TEXTMETRIC tm;
4401 HDC dc = ::GetDC((HWND) wnd);
4402 HFONT fnt =0;
4403 HFONT was = 0;
4404 if ( the_font )
4405 {
4406 // the_font->UseResource();
4407 // the_font->RealizeResource();
4408 fnt = (HFONT)((wxFont *)the_font)->GetResourceHandle(); // const_cast
4409 if ( fnt )
4410 was = (HFONT) SelectObject(dc,fnt);
4411 }
4412 GetTextMetrics(dc, &tm);
4413 if ( the_font && fnt && was )
4414 {
4415 SelectObject(dc,was);
4416 }
4417 ReleaseDC((HWND)wnd, dc);
4418
4419 if ( x )
4420 *x = tm.tmAveCharWidth;
4421 if ( y )
4422 *y = tm.tmHeight + tm.tmExternalLeading;
4423
4424 // if ( the_font )
4425 // the_font->ReleaseResource();
4426 }
4427
4428 // Returns 0 if was a normal ASCII value, not a special key. This indicates that
4429 // the key should be ignored by WM_KEYDOWN and processed by WM_CHAR instead.
4430 int wxCharCodeMSWToWX(int keySym)
4431 {
4432 int id;
4433 switch (keySym)
4434 {
4435 case VK_CANCEL: id = WXK_CANCEL; break;
4436 case VK_BACK: id = WXK_BACK; break;
4437 case VK_TAB: id = WXK_TAB; break;
4438 case VK_CLEAR: id = WXK_CLEAR; break;
4439 case VK_RETURN: id = WXK_RETURN; break;
4440 case VK_SHIFT: id = WXK_SHIFT; break;
4441 case VK_CONTROL: id = WXK_CONTROL; break;
4442 case VK_MENU : id = WXK_MENU; break;
4443 case VK_PAUSE: id = WXK_PAUSE; break;
4444 case VK_CAPITAL: id = WXK_CAPITAL; break;
4445 case VK_SPACE: id = WXK_SPACE; break;
4446 case VK_ESCAPE: id = WXK_ESCAPE; break;
4447 case VK_PRIOR: id = WXK_PRIOR; break;
4448 case VK_NEXT : id = WXK_NEXT; break;
4449 case VK_END: id = WXK_END; break;
4450 case VK_HOME : id = WXK_HOME; break;
4451 case VK_LEFT : id = WXK_LEFT; break;
4452 case VK_UP: id = WXK_UP; break;
4453 case VK_RIGHT: id = WXK_RIGHT; break;
4454 case VK_DOWN : id = WXK_DOWN; break;
4455 case VK_SELECT: id = WXK_SELECT; break;
4456 case VK_PRINT: id = WXK_PRINT; break;
4457 case VK_EXECUTE: id = WXK_EXECUTE; break;
4458 case VK_INSERT: id = WXK_INSERT; break;
4459 case VK_DELETE: id = WXK_DELETE; break;
4460 case VK_HELP : id = WXK_HELP; break;
4461 case VK_NUMPAD0: id = WXK_NUMPAD0; break;
4462 case VK_NUMPAD1: id = WXK_NUMPAD1; break;
4463 case VK_NUMPAD2: id = WXK_NUMPAD2; break;
4464 case VK_NUMPAD3: id = WXK_NUMPAD3; break;
4465 case VK_NUMPAD4: id = WXK_NUMPAD4; break;
4466 case VK_NUMPAD5: id = WXK_NUMPAD5; break;
4467 case VK_NUMPAD6: id = WXK_NUMPAD6; break;
4468 case VK_NUMPAD7: id = WXK_NUMPAD7; break;
4469 case VK_NUMPAD8: id = WXK_NUMPAD8; break;
4470 case VK_NUMPAD9: id = WXK_NUMPAD9; break;
4471 case VK_MULTIPLY: id = WXK_NUMPAD_MULTIPLY; break;
4472 case VK_ADD: id = WXK_NUMPAD_ADD; break;
4473 case VK_SUBTRACT: id = WXK_NUMPAD_SUBTRACT; break;
4474 case VK_DECIMAL: id = WXK_NUMPAD_DECIMAL; break;
4475 case VK_DIVIDE: id = WXK_NUMPAD_DIVIDE; break;
4476 case VK_F1: id = WXK_F1; break;
4477 case VK_F2: id = WXK_F2; break;
4478 case VK_F3: id = WXK_F3; break;
4479 case VK_F4: id = WXK_F4; break;
4480 case VK_F5: id = WXK_F5; break;
4481 case VK_F6: id = WXK_F6; break;
4482 case VK_F7: id = WXK_F7; break;
4483 case VK_F8: id = WXK_F8; break;
4484 case VK_F9: id = WXK_F9; break;
4485 case VK_F10: id = WXK_F10; break;
4486 case VK_F11: id = WXK_F11; break;
4487 case VK_F12: id = WXK_F12; break;
4488 case VK_F13: id = WXK_F13; break;
4489 case VK_F14: id = WXK_F14; break;
4490 case VK_F15: id = WXK_F15; break;
4491 case VK_F16: id = WXK_F16; break;
4492 case VK_F17: id = WXK_F17; break;
4493 case VK_F18: id = WXK_F18; break;
4494 case VK_F19: id = WXK_F19; break;
4495 case VK_F20: id = WXK_F20; break;
4496 case VK_F21: id = WXK_F21; break;
4497 case VK_F22: id = WXK_F22; break;
4498 case VK_F23: id = WXK_F23; break;
4499 case VK_F24: id = WXK_F24; break;
4500 case VK_NUMLOCK: id = WXK_NUMLOCK; break;
4501 case VK_SCROLL: id = WXK_SCROLL; break;
4502
4503 case VK_OEM_1: id = ';'; break;
4504 case VK_OEM_PLUS: id = '+'; break;
4505 case VK_OEM_COMMA: id = ','; break;
4506 case VK_OEM_MINUS: id = '-'; break;
4507 case VK_OEM_PERIOD: id = '.'; break;
4508 case VK_OEM_2: id = '/'; break;
4509 case VK_OEM_3: id = '~'; break;
4510 case VK_OEM_4: id = '['; break;
4511 case VK_OEM_5: id = '\\'; break;
4512 case VK_OEM_6: id = ']'; break;
4513 case VK_OEM_7: id = '\''; break;
4514
4515 default:
4516 id = 0;
4517 }
4518
4519 return id;
4520 }
4521
4522 int wxCharCodeWXToMSW(int id, bool *isVirtual)
4523 {
4524 *isVirtual = TRUE;
4525 int keySym = 0;
4526 switch (id)
4527 {
4528 case WXK_CANCEL: keySym = VK_CANCEL; break;
4529 case WXK_CLEAR: keySym = VK_CLEAR; break;
4530 case WXK_SHIFT: keySym = VK_SHIFT; break;
4531 case WXK_CONTROL: keySym = VK_CONTROL; break;
4532 case WXK_MENU : keySym = VK_MENU; break;
4533 case WXK_PAUSE: keySym = VK_PAUSE; break;
4534 case WXK_PRIOR: keySym = VK_PRIOR; break;
4535 case WXK_NEXT : keySym = VK_NEXT; break;
4536 case WXK_END: keySym = VK_END; break;
4537 case WXK_HOME : keySym = VK_HOME; break;
4538 case WXK_LEFT : keySym = VK_LEFT; break;
4539 case WXK_UP: keySym = VK_UP; break;
4540 case WXK_RIGHT: keySym = VK_RIGHT; break;
4541 case WXK_DOWN : keySym = VK_DOWN; break;
4542 case WXK_SELECT: keySym = VK_SELECT; break;
4543 case WXK_PRINT: keySym = VK_PRINT; break;
4544 case WXK_EXECUTE: keySym = VK_EXECUTE; break;
4545 case WXK_INSERT: keySym = VK_INSERT; break;
4546 case WXK_DELETE: keySym = VK_DELETE; break;
4547 case WXK_HELP : keySym = VK_HELP; break;
4548 case WXK_NUMPAD0: keySym = VK_NUMPAD0; break;
4549 case WXK_NUMPAD1: keySym = VK_NUMPAD1; break;
4550 case WXK_NUMPAD2: keySym = VK_NUMPAD2; break;
4551 case WXK_NUMPAD3: keySym = VK_NUMPAD3; break;
4552 case WXK_NUMPAD4: keySym = VK_NUMPAD4; break;
4553 case WXK_NUMPAD5: keySym = VK_NUMPAD5; break;
4554 case WXK_NUMPAD6: keySym = VK_NUMPAD6; break;
4555 case WXK_NUMPAD7: keySym = VK_NUMPAD7; break;
4556 case WXK_NUMPAD8: keySym = VK_NUMPAD8; break;
4557 case WXK_NUMPAD9: keySym = VK_NUMPAD9; break;
4558 case WXK_NUMPAD_MULTIPLY: keySym = VK_MULTIPLY; break;
4559 case WXK_NUMPAD_ADD: keySym = VK_ADD; break;
4560 case WXK_NUMPAD_SUBTRACT: keySym = VK_SUBTRACT; break;
4561 case WXK_NUMPAD_DECIMAL: keySym = VK_DECIMAL; break;
4562 case WXK_NUMPAD_DIVIDE: keySym = VK_DIVIDE; break;
4563 case WXK_F1: keySym = VK_F1; break;
4564 case WXK_F2: keySym = VK_F2; break;
4565 case WXK_F3: keySym = VK_F3; break;
4566 case WXK_F4: keySym = VK_F4; break;
4567 case WXK_F5: keySym = VK_F5; break;
4568 case WXK_F6: keySym = VK_F6; break;
4569 case WXK_F7: keySym = VK_F7; break;
4570 case WXK_F8: keySym = VK_F8; break;
4571 case WXK_F9: keySym = VK_F9; break;
4572 case WXK_F10: keySym = VK_F10; break;
4573 case WXK_F11: keySym = VK_F11; break;
4574 case WXK_F12: keySym = VK_F12; break;
4575 case WXK_F13: keySym = VK_F13; break;
4576 case WXK_F14: keySym = VK_F14; break;
4577 case WXK_F15: keySym = VK_F15; break;
4578 case WXK_F16: keySym = VK_F16; break;
4579 case WXK_F17: keySym = VK_F17; break;
4580 case WXK_F18: keySym = VK_F18; break;
4581 case WXK_F19: keySym = VK_F19; break;
4582 case WXK_F20: keySym = VK_F20; break;
4583 case WXK_F21: keySym = VK_F21; break;
4584 case WXK_F22: keySym = VK_F22; break;
4585 case WXK_F23: keySym = VK_F23; break;
4586 case WXK_F24: keySym = VK_F24; break;
4587 case WXK_NUMLOCK: keySym = VK_NUMLOCK; break;
4588 case WXK_SCROLL: keySym = VK_SCROLL; break;
4589 default:
4590 {
4591 *isVirtual = FALSE;
4592 keySym = id;
4593 break;
4594 }
4595 }
4596 return keySym;
4597 }
4598
4599 wxWindow *wxGetActiveWindow()
4600 {
4601 HWND hWnd = GetActiveWindow();
4602 if ( hWnd != 0 )
4603 {
4604 return wxFindWinFromHandle((WXHWND) hWnd);
4605 }
4606 return NULL;
4607 }
4608
4609 extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd)
4610 {
4611 HWND hwnd = (HWND)hWnd;
4612
4613 // For a radiobutton, we get the radiobox from GWL_USERDATA (which is set
4614 // by code in msw/radiobox.cpp), for all the others we just search up the
4615 // window hierarchy
4616 wxWindow *win = (wxWindow *)NULL;
4617 if ( hwnd )
4618 {
4619 win = wxFindWinFromHandle((WXHWND)hwnd);
4620 if ( !win )
4621 {
4622 // all these hacks only work under Win32 anyhow
4623 #ifdef __WIN32__
4624
4625 #if wxUSE_RADIOBOX
4626 // native radiobuttons return DLGC_RADIOBUTTON here and for any
4627 // wxWindow class which overrides WM_GETDLGCODE processing to
4628 // do it as well, win would be already non NULL
4629 if ( ::SendMessage(hwnd, WM_GETDLGCODE, 0, 0) & DLGC_RADIOBUTTON )
4630 {
4631 win = (wxWindow *)::GetWindowLong(hwnd, GWL_USERDATA);
4632 }
4633 //else: it's a wxRadioButton, not a radiobutton from wxRadioBox
4634 #endif // wxUSE_RADIOBOX
4635
4636 // spin control text buddy window should be mapped to spin ctrl
4637 // itself so try it too
4638 #if wxUSE_SPINCTRL && !defined(__WXUNIVERSAL__)
4639 if ( !win )
4640 {
4641 win = wxSpinCtrl::GetSpinForTextCtrl((WXHWND)hwnd);
4642 }
4643 #endif // wxUSE_SPINCTRL
4644
4645 #endif // Win32
4646 }
4647 }
4648
4649 while ( hwnd && !win )
4650 {
4651 // this is a really ugly hack needed to avoid mistakenly returning the
4652 // parent frame wxWindow for the find/replace modeless dialog HWND -
4653 // this, in turn, is needed to call IsDialogMessage() from
4654 // wxApp::ProcessMessage() as for this we must return NULL from here
4655 //
4656 // FIXME: this is clearly not the best way to do it but I think we'll
4657 // need to change HWND <-> wxWindow code more heavily than I can
4658 // do it now to fix it
4659 #ifndef __WXMICROWIN__
4660 if ( ::GetWindow(hwnd, GW_OWNER) )
4661 {
4662 // it's a dialog box, don't go upwards
4663 break;
4664 }
4665 #endif
4666
4667 hwnd = ::GetParent(hwnd);
4668 win = wxFindWinFromHandle((WXHWND)hwnd);
4669 }
4670
4671 return win;
4672 }
4673
4674 #ifndef __WXMICROWIN__
4675
4676 // Windows keyboard hook. Allows interception of e.g. F1, ESCAPE
4677 // in active frames and dialogs, regardless of where the focus is.
4678 static HHOOK wxTheKeyboardHook = 0;
4679 static FARPROC wxTheKeyboardHookProc = 0;
4680 int APIENTRY _EXPORT
4681 wxKeyboardHook(int nCode, WORD wParam, DWORD lParam);
4682
4683 void wxSetKeyboardHook(bool doIt)
4684 {
4685 if ( doIt )
4686 {
4687 wxTheKeyboardHookProc = MakeProcInstance((FARPROC) wxKeyboardHook, wxGetInstance());
4688 wxTheKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC) wxTheKeyboardHookProc, wxGetInstance(),
4689
4690 #if defined(__WIN32__) && !defined(__TWIN32__)
4691 GetCurrentThreadId()
4692 // (DWORD)GetCurrentProcess()); // This is another possibility. Which is right?
4693 #else
4694 GetCurrentTask()
4695 #endif
4696 );
4697 }
4698 else
4699 {
4700 UnhookWindowsHookEx(wxTheKeyboardHook);
4701
4702 // avoids warning about statement with no effect (FreeProcInstance
4703 // doesn't do anything under Win32)
4704 #if !defined(WIN32) && !defined(_WIN32) && !defined(__WIN32__) && !defined(__NT__) && !defined(__GNUWIN32__)
4705 FreeProcInstance(wxTheKeyboardHookProc);
4706 #endif
4707 }
4708 }
4709
4710 int APIENTRY _EXPORT
4711 wxKeyboardHook(int nCode, WORD wParam, DWORD lParam)
4712 {
4713 DWORD hiWord = HIWORD(lParam);
4714 if ( nCode != HC_NOREMOVE && ((hiWord & KF_UP) == 0) )
4715 {
4716 int id = wxCharCodeMSWToWX(wParam);
4717 if ( id != 0 )
4718 {
4719 wxKeyEvent event(wxEVT_CHAR_HOOK);
4720 if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN )
4721 event.m_altDown = TRUE;
4722
4723 event.m_eventObject = NULL;
4724 event.m_keyCode = id;
4725 event.m_shiftDown = wxIsShiftDown();
4726 event.m_controlDown = wxIsCtrlDown();
4727 event.SetTimestamp(s_currentMsg.time);
4728
4729 wxWindow *win = wxGetActiveWindow();
4730 wxEvtHandler *handler;
4731 if ( win )
4732 {
4733 handler = win->GetEventHandler();
4734 event.SetId(win->GetId());
4735 }
4736 else
4737 {
4738 handler = wxTheApp;
4739 event.SetId(-1);
4740 }
4741
4742 if ( handler && handler->ProcessEvent(event) )
4743 {
4744 // processed
4745 return 1;
4746 }
4747 }
4748 }
4749
4750 return (int)CallNextHookEx(wxTheKeyboardHook, nCode, wParam, lParam);
4751 }
4752
4753 #endif // !__WXMICROWIN__
4754
4755 #ifdef __WXDEBUG__
4756 const char *wxGetMessageName(int message)
4757 {
4758 switch ( message )
4759 {
4760 case 0x0000: return "WM_NULL";
4761 case 0x0001: return "WM_CREATE";
4762 case 0x0002: return "WM_DESTROY";
4763 case 0x0003: return "WM_MOVE";
4764 case 0x0005: return "WM_SIZE";
4765 case 0x0006: return "WM_ACTIVATE";
4766 case 0x0007: return "WM_SETFOCUS";
4767 case 0x0008: return "WM_KILLFOCUS";
4768 case 0x000A: return "WM_ENABLE";
4769 case 0x000B: return "WM_SETREDRAW";
4770 case 0x000C: return "WM_SETTEXT";
4771 case 0x000D: return "WM_GETTEXT";
4772 case 0x000E: return "WM_GETTEXTLENGTH";
4773 case 0x000F: return "WM_PAINT";
4774 case 0x0010: return "WM_CLOSE";
4775 case 0x0011: return "WM_QUERYENDSESSION";
4776 case 0x0012: return "WM_QUIT";
4777 case 0x0013: return "WM_QUERYOPEN";
4778 case 0x0014: return "WM_ERASEBKGND";
4779 case 0x0015: return "WM_SYSCOLORCHANGE";
4780 case 0x0016: return "WM_ENDSESSION";
4781 case 0x0017: return "WM_SYSTEMERROR";
4782 case 0x0018: return "WM_SHOWWINDOW";
4783 case 0x0019: return "WM_CTLCOLOR";
4784 case 0x001A: return "WM_WININICHANGE";
4785 case 0x001B: return "WM_DEVMODECHANGE";
4786 case 0x001C: return "WM_ACTIVATEAPP";
4787 case 0x001D: return "WM_FONTCHANGE";
4788 case 0x001E: return "WM_TIMECHANGE";
4789 case 0x001F: return "WM_CANCELMODE";
4790 case 0x0020: return "WM_SETCURSOR";
4791 case 0x0021: return "WM_MOUSEACTIVATE";
4792 case 0x0022: return "WM_CHILDACTIVATE";
4793 case 0x0023: return "WM_QUEUESYNC";
4794 case 0x0024: return "WM_GETMINMAXINFO";
4795 case 0x0026: return "WM_PAINTICON";
4796 case 0x0027: return "WM_ICONERASEBKGND";
4797 case 0x0028: return "WM_NEXTDLGCTL";
4798 case 0x002A: return "WM_SPOOLERSTATUS";
4799 case 0x002B: return "WM_DRAWITEM";
4800 case 0x002C: return "WM_MEASUREITEM";
4801 case 0x002D: return "WM_DELETEITEM";
4802 case 0x002E: return "WM_VKEYTOITEM";
4803 case 0x002F: return "WM_CHARTOITEM";
4804 case 0x0030: return "WM_SETFONT";
4805 case 0x0031: return "WM_GETFONT";
4806 case 0x0037: return "WM_QUERYDRAGICON";
4807 case 0x0039: return "WM_COMPAREITEM";
4808 case 0x0041: return "WM_COMPACTING";
4809 case 0x0044: return "WM_COMMNOTIFY";
4810 case 0x0046: return "WM_WINDOWPOSCHANGING";
4811 case 0x0047: return "WM_WINDOWPOSCHANGED";
4812 case 0x0048: return "WM_POWER";
4813
4814 #ifdef __WIN32__
4815 case 0x004A: return "WM_COPYDATA";
4816 case 0x004B: return "WM_CANCELJOURNAL";
4817 case 0x004E: return "WM_NOTIFY";
4818 case 0x0050: return "WM_INPUTLANGCHANGEREQUEST";
4819 case 0x0051: return "WM_INPUTLANGCHANGE";
4820 case 0x0052: return "WM_TCARD";
4821 case 0x0053: return "WM_HELP";
4822 case 0x0054: return "WM_USERCHANGED";
4823 case 0x0055: return "WM_NOTIFYFORMAT";
4824 case 0x007B: return "WM_CONTEXTMENU";
4825 case 0x007C: return "WM_STYLECHANGING";
4826 case 0x007D: return "WM_STYLECHANGED";
4827 case 0x007E: return "WM_DISPLAYCHANGE";
4828 case 0x007F: return "WM_GETICON";
4829 case 0x0080: return "WM_SETICON";
4830 #endif //WIN32
4831
4832 case 0x0081: return "WM_NCCREATE";
4833 case 0x0082: return "WM_NCDESTROY";
4834 case 0x0083: return "WM_NCCALCSIZE";
4835 case 0x0084: return "WM_NCHITTEST";
4836 case 0x0085: return "WM_NCPAINT";
4837 case 0x0086: return "WM_NCACTIVATE";
4838 case 0x0087: return "WM_GETDLGCODE";
4839 case 0x00A0: return "WM_NCMOUSEMOVE";
4840 case 0x00A1: return "WM_NCLBUTTONDOWN";
4841 case 0x00A2: return "WM_NCLBUTTONUP";
4842 case 0x00A3: return "WM_NCLBUTTONDBLCLK";
4843 case 0x00A4: return "WM_NCRBUTTONDOWN";
4844 case 0x00A5: return "WM_NCRBUTTONUP";
4845 case 0x00A6: return "WM_NCRBUTTONDBLCLK";
4846 case 0x00A7: return "WM_NCMBUTTONDOWN";
4847 case 0x00A8: return "WM_NCMBUTTONUP";
4848 case 0x00A9: return "WM_NCMBUTTONDBLCLK";
4849 case 0x0100: return "WM_KEYDOWN";
4850 case 0x0101: return "WM_KEYUP";
4851 case 0x0102: return "WM_CHAR";
4852 case 0x0103: return "WM_DEADCHAR";
4853 case 0x0104: return "WM_SYSKEYDOWN";
4854 case 0x0105: return "WM_SYSKEYUP";
4855 case 0x0106: return "WM_SYSCHAR";
4856 case 0x0107: return "WM_SYSDEADCHAR";
4857 case 0x0108: return "WM_KEYLAST";
4858
4859 #ifdef __WIN32__
4860 case 0x010D: return "WM_IME_STARTCOMPOSITION";
4861 case 0x010E: return "WM_IME_ENDCOMPOSITION";
4862 case 0x010F: return "WM_IME_COMPOSITION";
4863 #endif //WIN32
4864
4865 case 0x0110: return "WM_INITDIALOG";
4866 case 0x0111: return "WM_COMMAND";
4867 case 0x0112: return "WM_SYSCOMMAND";
4868 case 0x0113: return "WM_TIMER";
4869 case 0x0114: return "WM_HSCROLL";
4870 case 0x0115: return "WM_VSCROLL";
4871 case 0x0116: return "WM_INITMENU";
4872 case 0x0117: return "WM_INITMENUPOPUP";
4873 case 0x011F: return "WM_MENUSELECT";
4874 case 0x0120: return "WM_MENUCHAR";
4875 case 0x0121: return "WM_ENTERIDLE";
4876 case 0x0200: return "WM_MOUSEMOVE";
4877 case 0x0201: return "WM_LBUTTONDOWN";
4878 case 0x0202: return "WM_LBUTTONUP";
4879 case 0x0203: return "WM_LBUTTONDBLCLK";
4880 case 0x0204: return "WM_RBUTTONDOWN";
4881 case 0x0205: return "WM_RBUTTONUP";
4882 case 0x0206: return "WM_RBUTTONDBLCLK";
4883 case 0x0207: return "WM_MBUTTONDOWN";
4884 case 0x0208: return "WM_MBUTTONUP";
4885 case 0x0209: return "WM_MBUTTONDBLCLK";
4886 case 0x020A: return "WM_MOUSEWHEEL";
4887 case 0x0210: return "WM_PARENTNOTIFY";
4888 case 0x0211: return "WM_ENTERMENULOOP";
4889 case 0x0212: return "WM_EXITMENULOOP";
4890
4891 #ifdef __WIN32__
4892 case 0x0213: return "WM_NEXTMENU";
4893 case 0x0214: return "WM_SIZING";
4894 case 0x0215: return "WM_CAPTURECHANGED";
4895 case 0x0216: return "WM_MOVING";
4896 case 0x0218: return "WM_POWERBROADCAST";
4897 case 0x0219: return "WM_DEVICECHANGE";
4898 #endif //WIN32
4899
4900 case 0x0220: return "WM_MDICREATE";
4901 case 0x0221: return "WM_MDIDESTROY";
4902 case 0x0222: return "WM_MDIACTIVATE";
4903 case 0x0223: return "WM_MDIRESTORE";
4904 case 0x0224: return "WM_MDINEXT";
4905 case 0x0225: return "WM_MDIMAXIMIZE";
4906 case 0x0226: return "WM_MDITILE";
4907 case 0x0227: return "WM_MDICASCADE";
4908 case 0x0228: return "WM_MDIICONARRANGE";
4909 case 0x0229: return "WM_MDIGETACTIVE";
4910 case 0x0230: return "WM_MDISETMENU";
4911 case 0x0233: return "WM_DROPFILES";
4912
4913 #ifdef __WIN32__
4914 case 0x0281: return "WM_IME_SETCONTEXT";
4915 case 0x0282: return "WM_IME_NOTIFY";
4916 case 0x0283: return "WM_IME_CONTROL";
4917 case 0x0284: return "WM_IME_COMPOSITIONFULL";
4918 case 0x0285: return "WM_IME_SELECT";
4919 case 0x0286: return "WM_IME_CHAR";
4920 case 0x0290: return "WM_IME_KEYDOWN";
4921 case 0x0291: return "WM_IME_KEYUP";
4922 #endif //WIN32
4923
4924 case 0x0300: return "WM_CUT";
4925 case 0x0301: return "WM_COPY";
4926 case 0x0302: return "WM_PASTE";
4927 case 0x0303: return "WM_CLEAR";
4928 case 0x0304: return "WM_UNDO";
4929 case 0x0305: return "WM_RENDERFORMAT";
4930 case 0x0306: return "WM_RENDERALLFORMATS";
4931 case 0x0307: return "WM_DESTROYCLIPBOARD";
4932 case 0x0308: return "WM_DRAWCLIPBOARD";
4933 case 0x0309: return "WM_PAINTCLIPBOARD";
4934 case 0x030A: return "WM_VSCROLLCLIPBOARD";
4935 case 0x030B: return "WM_SIZECLIPBOARD";
4936 case 0x030C: return "WM_ASKCBFORMATNAME";
4937 case 0x030D: return "WM_CHANGECBCHAIN";
4938 case 0x030E: return "WM_HSCROLLCLIPBOARD";
4939 case 0x030F: return "WM_QUERYNEWPALETTE";
4940 case 0x0310: return "WM_PALETTEISCHANGING";
4941 case 0x0311: return "WM_PALETTECHANGED";
4942
4943 #ifdef __WIN32__
4944 // common controls messages - although they're not strictly speaking
4945 // standard, it's nice to decode them nevertheless
4946
4947 // listview
4948 case 0x1000 + 0: return "LVM_GETBKCOLOR";
4949 case 0x1000 + 1: return "LVM_SETBKCOLOR";
4950 case 0x1000 + 2: return "LVM_GETIMAGELIST";
4951 case 0x1000 + 3: return "LVM_SETIMAGELIST";
4952 case 0x1000 + 4: return "LVM_GETITEMCOUNT";
4953 case 0x1000 + 5: return "LVM_GETITEMA";
4954 case 0x1000 + 75: return "LVM_GETITEMW";
4955 case 0x1000 + 6: return "LVM_SETITEMA";
4956 case 0x1000 + 76: return "LVM_SETITEMW";
4957 case 0x1000 + 7: return "LVM_INSERTITEMA";
4958 case 0x1000 + 77: return "LVM_INSERTITEMW";
4959 case 0x1000 + 8: return "LVM_DELETEITEM";
4960 case 0x1000 + 9: return "LVM_DELETEALLITEMS";
4961 case 0x1000 + 10: return "LVM_GETCALLBACKMASK";
4962 case 0x1000 + 11: return "LVM_SETCALLBACKMASK";
4963 case 0x1000 + 12: return "LVM_GETNEXTITEM";
4964 case 0x1000 + 13: return "LVM_FINDITEMA";
4965 case 0x1000 + 83: return "LVM_FINDITEMW";
4966 case 0x1000 + 14: return "LVM_GETITEMRECT";
4967 case 0x1000 + 15: return "LVM_SETITEMPOSITION";
4968 case 0x1000 + 16: return "LVM_GETITEMPOSITION";
4969 case 0x1000 + 17: return "LVM_GETSTRINGWIDTHA";
4970 case 0x1000 + 87: return "LVM_GETSTRINGWIDTHW";
4971 case 0x1000 + 18: return "LVM_HITTEST";
4972 case 0x1000 + 19: return "LVM_ENSUREVISIBLE";
4973 case 0x1000 + 20: return "LVM_SCROLL";
4974 case 0x1000 + 21: return "LVM_REDRAWITEMS";
4975 case 0x1000 + 22: return "LVM_ARRANGE";
4976 case 0x1000 + 23: return "LVM_EDITLABELA";
4977 case 0x1000 + 118: return "LVM_EDITLABELW";
4978 case 0x1000 + 24: return "LVM_GETEDITCONTROL";
4979 case 0x1000 + 25: return "LVM_GETCOLUMNA";
4980 case 0x1000 + 95: return "LVM_GETCOLUMNW";
4981 case 0x1000 + 26: return "LVM_SETCOLUMNA";
4982 case 0x1000 + 96: return "LVM_SETCOLUMNW";
4983 case 0x1000 + 27: return "LVM_INSERTCOLUMNA";
4984 case 0x1000 + 97: return "LVM_INSERTCOLUMNW";
4985 case 0x1000 + 28: return "LVM_DELETECOLUMN";
4986 case 0x1000 + 29: return "LVM_GETCOLUMNWIDTH";
4987 case 0x1000 + 30: return "LVM_SETCOLUMNWIDTH";
4988 case 0x1000 + 31: return "LVM_GETHEADER";
4989 case 0x1000 + 33: return "LVM_CREATEDRAGIMAGE";
4990 case 0x1000 + 34: return "LVM_GETVIEWRECT";
4991 case 0x1000 + 35: return "LVM_GETTEXTCOLOR";
4992 case 0x1000 + 36: return "LVM_SETTEXTCOLOR";
4993 case 0x1000 + 37: return "LVM_GETTEXTBKCOLOR";
4994 case 0x1000 + 38: return "LVM_SETTEXTBKCOLOR";
4995 case 0x1000 + 39: return "LVM_GETTOPINDEX";
4996 case 0x1000 + 40: return "LVM_GETCOUNTPERPAGE";
4997 case 0x1000 + 41: return "LVM_GETORIGIN";
4998 case 0x1000 + 42: return "LVM_UPDATE";
4999 case 0x1000 + 43: return "LVM_SETITEMSTATE";
5000 case 0x1000 + 44: return "LVM_GETITEMSTATE";
5001 case 0x1000 + 45: return "LVM_GETITEMTEXTA";
5002 case 0x1000 + 115: return "LVM_GETITEMTEXTW";
5003 case 0x1000 + 46: return "LVM_SETITEMTEXTA";
5004 case 0x1000 + 116: return "LVM_SETITEMTEXTW";
5005 case 0x1000 + 47: return "LVM_SETITEMCOUNT";
5006 case 0x1000 + 48: return "LVM_SORTITEMS";
5007 case 0x1000 + 49: return "LVM_SETITEMPOSITION32";
5008 case 0x1000 + 50: return "LVM_GETSELECTEDCOUNT";
5009 case 0x1000 + 51: return "LVM_GETITEMSPACING";
5010 case 0x1000 + 52: return "LVM_GETISEARCHSTRINGA";
5011 case 0x1000 + 117: return "LVM_GETISEARCHSTRINGW";
5012 case 0x1000 + 53: return "LVM_SETICONSPACING";
5013 case 0x1000 + 54: return "LVM_SETEXTENDEDLISTVIEWSTYLE";
5014 case 0x1000 + 55: return "LVM_GETEXTENDEDLISTVIEWSTYLE";
5015 case 0x1000 + 56: return "LVM_GETSUBITEMRECT";
5016 case 0x1000 + 57: return "LVM_SUBITEMHITTEST";
5017 case 0x1000 + 58: return "LVM_SETCOLUMNORDERARRAY";
5018 case 0x1000 + 59: return "LVM_GETCOLUMNORDERARRAY";
5019 case 0x1000 + 60: return "LVM_SETHOTITEM";
5020 case 0x1000 + 61: return "LVM_GETHOTITEM";
5021 case 0x1000 + 62: return "LVM_SETHOTCURSOR";
5022 case 0x1000 + 63: return "LVM_GETHOTCURSOR";
5023 case 0x1000 + 64: return "LVM_APPROXIMATEVIEWRECT";
5024 case 0x1000 + 65: return "LVM_SETWORKAREA";
5025
5026 // tree view
5027 case 0x1100 + 0: return "TVM_INSERTITEMA";
5028 case 0x1100 + 50: return "TVM_INSERTITEMW";
5029 case 0x1100 + 1: return "TVM_DELETEITEM";
5030 case 0x1100 + 2: return "TVM_EXPAND";
5031 case 0x1100 + 4: return "TVM_GETITEMRECT";
5032 case 0x1100 + 5: return "TVM_GETCOUNT";
5033 case 0x1100 + 6: return "TVM_GETINDENT";
5034 case 0x1100 + 7: return "TVM_SETINDENT";
5035 case 0x1100 + 8: return "TVM_GETIMAGELIST";
5036 case 0x1100 + 9: return "TVM_SETIMAGELIST";
5037 case 0x1100 + 10: return "TVM_GETNEXTITEM";
5038 case 0x1100 + 11: return "TVM_SELECTITEM";
5039 case 0x1100 + 12: return "TVM_GETITEMA";
5040 case 0x1100 + 62: return "TVM_GETITEMW";
5041 case 0x1100 + 13: return "TVM_SETITEMA";
5042 case 0x1100 + 63: return "TVM_SETITEMW";
5043 case 0x1100 + 14: return "TVM_EDITLABELA";
5044 case 0x1100 + 65: return "TVM_EDITLABELW";
5045 case 0x1100 + 15: return "TVM_GETEDITCONTROL";
5046 case 0x1100 + 16: return "TVM_GETVISIBLECOUNT";
5047 case 0x1100 + 17: return "TVM_HITTEST";
5048 case 0x1100 + 18: return "TVM_CREATEDRAGIMAGE";
5049 case 0x1100 + 19: return "TVM_SORTCHILDREN";
5050 case 0x1100 + 20: return "TVM_ENSUREVISIBLE";
5051 case 0x1100 + 21: return "TVM_SORTCHILDRENCB";
5052 case 0x1100 + 22: return "TVM_ENDEDITLABELNOW";
5053 case 0x1100 + 23: return "TVM_GETISEARCHSTRINGA";
5054 case 0x1100 + 64: return "TVM_GETISEARCHSTRINGW";
5055 case 0x1100 + 24: return "TVM_SETTOOLTIPS";
5056 case 0x1100 + 25: return "TVM_GETTOOLTIPS";
5057
5058 // header
5059 case 0x1200 + 0: return "HDM_GETITEMCOUNT";
5060 case 0x1200 + 1: return "HDM_INSERTITEMA";
5061 case 0x1200 + 10: return "HDM_INSERTITEMW";
5062 case 0x1200 + 2: return "HDM_DELETEITEM";
5063 case 0x1200 + 3: return "HDM_GETITEMA";
5064 case 0x1200 + 11: return "HDM_GETITEMW";
5065 case 0x1200 + 4: return "HDM_SETITEMA";
5066 case 0x1200 + 12: return "HDM_SETITEMW";
5067 case 0x1200 + 5: return "HDM_LAYOUT";
5068 case 0x1200 + 6: return "HDM_HITTEST";
5069 case 0x1200 + 7: return "HDM_GETITEMRECT";
5070 case 0x1200 + 8: return "HDM_SETIMAGELIST";
5071 case 0x1200 + 9: return "HDM_GETIMAGELIST";
5072 case 0x1200 + 15: return "HDM_ORDERTOINDEX";
5073 case 0x1200 + 16: return "HDM_CREATEDRAGIMAGE";
5074 case 0x1200 + 17: return "HDM_GETORDERARRAY";
5075 case 0x1200 + 18: return "HDM_SETORDERARRAY";
5076 case 0x1200 + 19: return "HDM_SETHOTDIVIDER";
5077
5078 // tab control
5079 case 0x1300 + 2: return "TCM_GETIMAGELIST";
5080 case 0x1300 + 3: return "TCM_SETIMAGELIST";
5081 case 0x1300 + 4: return "TCM_GETITEMCOUNT";
5082 case 0x1300 + 5: return "TCM_GETITEMA";
5083 case 0x1300 + 60: return "TCM_GETITEMW";
5084 case 0x1300 + 6: return "TCM_SETITEMA";
5085 case 0x1300 + 61: return "TCM_SETITEMW";
5086 case 0x1300 + 7: return "TCM_INSERTITEMA";
5087 case 0x1300 + 62: return "TCM_INSERTITEMW";
5088 case 0x1300 + 8: return "TCM_DELETEITEM";
5089 case 0x1300 + 9: return "TCM_DELETEALLITEMS";
5090 case 0x1300 + 10: return "TCM_GETITEMRECT";
5091 case 0x1300 + 11: return "TCM_GETCURSEL";
5092 case 0x1300 + 12: return "TCM_SETCURSEL";
5093 case 0x1300 + 13: return "TCM_HITTEST";
5094 case 0x1300 + 14: return "TCM_SETITEMEXTRA";
5095 case 0x1300 + 40: return "TCM_ADJUSTRECT";
5096 case 0x1300 + 41: return "TCM_SETITEMSIZE";
5097 case 0x1300 + 42: return "TCM_REMOVEIMAGE";
5098 case 0x1300 + 43: return "TCM_SETPADDING";
5099 case 0x1300 + 44: return "TCM_GETROWCOUNT";
5100 case 0x1300 + 45: return "TCM_GETTOOLTIPS";
5101 case 0x1300 + 46: return "TCM_SETTOOLTIPS";
5102 case 0x1300 + 47: return "TCM_GETCURFOCUS";
5103 case 0x1300 + 48: return "TCM_SETCURFOCUS";
5104 case 0x1300 + 49: return "TCM_SETMINTABWIDTH";
5105 case 0x1300 + 50: return "TCM_DESELECTALL";
5106
5107 // toolbar
5108 case WM_USER+1: return "TB_ENABLEBUTTON";
5109 case WM_USER+2: return "TB_CHECKBUTTON";
5110 case WM_USER+3: return "TB_PRESSBUTTON";
5111 case WM_USER+4: return "TB_HIDEBUTTON";
5112 case WM_USER+5: return "TB_INDETERMINATE";
5113 case WM_USER+9: return "TB_ISBUTTONENABLED";
5114 case WM_USER+10: return "TB_ISBUTTONCHECKED";
5115 case WM_USER+11: return "TB_ISBUTTONPRESSED";
5116 case WM_USER+12: return "TB_ISBUTTONHIDDEN";
5117 case WM_USER+13: return "TB_ISBUTTONINDETERMINATE";
5118 case WM_USER+17: return "TB_SETSTATE";
5119 case WM_USER+18: return "TB_GETSTATE";
5120 case WM_USER+19: return "TB_ADDBITMAP";
5121 case WM_USER+20: return "TB_ADDBUTTONS";
5122 case WM_USER+21: return "TB_INSERTBUTTON";
5123 case WM_USER+22: return "TB_DELETEBUTTON";
5124 case WM_USER+23: return "TB_GETBUTTON";
5125 case WM_USER+24: return "TB_BUTTONCOUNT";
5126 case WM_USER+25: return "TB_COMMANDTOINDEX";
5127 case WM_USER+26: return "TB_SAVERESTOREA";
5128 case WM_USER+76: return "TB_SAVERESTOREW";
5129 case WM_USER+27: return "TB_CUSTOMIZE";
5130 case WM_USER+28: return "TB_ADDSTRINGA";
5131 case WM_USER+77: return "TB_ADDSTRINGW";
5132 case WM_USER+29: return "TB_GETITEMRECT";
5133 case WM_USER+30: return "TB_BUTTONSTRUCTSIZE";
5134 case WM_USER+31: return "TB_SETBUTTONSIZE";
5135 case WM_USER+32: return "TB_SETBITMAPSIZE";
5136 case WM_USER+33: return "TB_AUTOSIZE";
5137 case WM_USER+35: return "TB_GETTOOLTIPS";
5138 case WM_USER+36: return "TB_SETTOOLTIPS";
5139 case WM_USER+37: return "TB_SETPARENT";
5140 case WM_USER+39: return "TB_SETROWS";
5141 case WM_USER+40: return "TB_GETROWS";
5142 case WM_USER+42: return "TB_SETCMDID";
5143 case WM_USER+43: return "TB_CHANGEBITMAP";
5144 case WM_USER+44: return "TB_GETBITMAP";
5145 case WM_USER+45: return "TB_GETBUTTONTEXTA";
5146 case WM_USER+75: return "TB_GETBUTTONTEXTW";
5147 case WM_USER+46: return "TB_REPLACEBITMAP";
5148 case WM_USER+47: return "TB_SETINDENT";
5149 case WM_USER+48: return "TB_SETIMAGELIST";
5150 case WM_USER+49: return "TB_GETIMAGELIST";
5151 case WM_USER+50: return "TB_LOADIMAGES";
5152 case WM_USER+51: return "TB_GETRECT";
5153 case WM_USER+52: return "TB_SETHOTIMAGELIST";
5154 case WM_USER+53: return "TB_GETHOTIMAGELIST";
5155 case WM_USER+54: return "TB_SETDISABLEDIMAGELIST";
5156 case WM_USER+55: return "TB_GETDISABLEDIMAGELIST";
5157 case WM_USER+56: return "TB_SETSTYLE";
5158 case WM_USER+57: return "TB_GETSTYLE";
5159 case WM_USER+58: return "TB_GETBUTTONSIZE";
5160 case WM_USER+59: return "TB_SETBUTTONWIDTH";
5161 case WM_USER+60: return "TB_SETMAXTEXTROWS";
5162 case WM_USER+61: return "TB_GETTEXTROWS";
5163 case WM_USER+41: return "TB_GETBITMAPFLAGS";
5164
5165 #endif //WIN32
5166
5167 default:
5168 static char s_szBuf[128];
5169 sprintf(s_szBuf, "<unknown message = %d>", message);
5170 return s_szBuf;
5171 }
5172 }
5173 #endif //__WXDEBUG__
5174
5175 static void TranslateKbdEventToMouse(wxWindowMSW *win,
5176 int *x, int *y, WPARAM *flags)
5177 {
5178 // construct the key mask
5179 WPARAM& fwKeys = *flags;
5180
5181 fwKeys = MK_RBUTTON;
5182 if ( wxIsCtrlDown() )
5183 fwKeys |= MK_CONTROL;
5184 if ( wxIsShiftDown() )
5185 fwKeys |= MK_SHIFT;
5186
5187 // simulate right mouse button click
5188 DWORD dwPos = ::GetMessagePos();
5189 *x = GET_X_LPARAM(dwPos);
5190 *y = GET_Y_LPARAM(dwPos);
5191
5192 win->ScreenToClient(x, y);
5193 }
5194
5195 static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win)
5196 {
5197 // prepare the DC
5198 TEXTMETRIC tm;
5199 HWND hwnd = GetHwndOf(win);
5200 HDC hdc = ::GetDC(hwnd);
5201
5202 #if !wxDIALOG_UNIT_COMPATIBILITY
5203 // and select the current font into it
5204 HFONT hfont = GetHfontOf(win->GetFont());
5205 if ( hfont )
5206 {
5207 hfont = (HFONT)::SelectObject(hdc, hfont);
5208 }
5209 #endif
5210
5211 // finally retrieve the text metrics from it
5212 GetTextMetrics(hdc, &tm);
5213
5214 #if !wxDIALOG_UNIT_COMPATIBILITY
5215 // and clean up
5216 if ( hfont )
5217 {
5218 (void)::SelectObject(hdc, hfont);
5219 }
5220 #endif
5221
5222 ::ReleaseDC(hwnd, hdc);
5223
5224 return tm;
5225 }
5226
5227 // Find the wxWindow at the current mouse position, returning the mouse
5228 // position.
5229 wxWindow* wxFindWindowAtPointer(wxPoint& WXUNUSED(pt))
5230 {
5231 return wxFindWindowAtPoint(wxGetMousePosition());
5232 }
5233
5234 wxWindow* wxFindWindowAtPoint(const wxPoint& pt)
5235 {
5236 POINT pt2;
5237 pt2.x = pt.x;
5238 pt2.y = pt.y;
5239 HWND hWndHit = ::WindowFromPoint(pt2);
5240
5241 wxWindow* win = wxFindWinFromHandle((WXHWND) hWndHit) ;
5242 HWND hWnd = hWndHit;
5243
5244 // Try to find a window with a wxWindow associated with it
5245 while (!win && (hWnd != 0))
5246 {
5247 hWnd = ::GetParent(hWnd);
5248 win = wxFindWinFromHandle((WXHWND) hWnd) ;
5249 }
5250 return win;
5251 }
5252
5253 // Get the current mouse position.
5254 wxPoint wxGetMousePosition()
5255 {
5256 POINT pt;
5257 GetCursorPos( & pt );
5258
5259 return wxPoint(pt.x, pt.y);
5260 }
5261