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