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