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