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