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