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