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