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