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