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