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