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