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