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