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