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