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