/[pcsx2_0.9.7]/branch/r3113_0.9.7_beta/3rdparty/wxWidgets/src/msw/window.cpp
ViewVC logotype

Contents of /branch/r3113_0.9.7_beta/3rdparty/wxWidgets/src/msw/window.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 32 - (show annotations) (download)
Tue Sep 7 03:29:01 2010 UTC (9 years, 11 months ago) by william
File size: 218601 byte(s)
branching from upstream revision (http://pcsx2.googlecode.com/svn/trunk
): r3113 to
https://svn.netsolutions.dnsalias.com/websvn/ps2/pcsx2/pcsx2_0.9.7/branch/r3113_0.9.7_beta
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/window.cpp
3 // Purpose: wxWindowMSW
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: window.cpp 58750 2009-02-08 10:01:03Z VZ $
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ===========================================================================
13 // declarations
14 // ===========================================================================
15
16 // ---------------------------------------------------------------------------
17 // headers
18 // ---------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #include "wx/window.h"
28
29 #ifndef WX_PRECOMP
30 #include "wx/msw/wrapwin.h"
31 #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
32 #include "wx/msw/missing.h"
33 #include "wx/accel.h"
34 #include "wx/menu.h"
35 #include "wx/dc.h"
36 #include "wx/dcclient.h"
37 #include "wx/dcmemory.h"
38 #include "wx/utils.h"
39 #include "wx/app.h"
40 #include "wx/layout.h"
41 #include "wx/dialog.h"
42 #include "wx/frame.h"
43 #include "wx/listbox.h"
44 #include "wx/button.h"
45 #include "wx/msgdlg.h"
46 #include "wx/settings.h"
47 #include "wx/statbox.h"
48 #include "wx/sizer.h"
49 #include "wx/intl.h"
50 #include "wx/log.h"
51 #include "wx/textctrl.h"
52 #include "wx/menuitem.h"
53 #include "wx/module.h"
54 #endif
55
56 #if wxUSE_OWNER_DRAWN && !defined(__WXUNIVERSAL__)
57 #include "wx/ownerdrw.h"
58 #endif
59
60 #include "wx/evtloop.h"
61 #include "wx/power.h"
62 #include "wx/sysopt.h"
63
64 #if wxUSE_DRAG_AND_DROP
65 #include "wx/dnd.h"
66 #endif
67
68 #if wxUSE_ACCESSIBILITY
69 #include "wx/access.h"
70 #include <ole2.h>
71 #include <oleacc.h>
72 #ifndef WM_GETOBJECT
73 #define WM_GETOBJECT 0x003D
74 #endif
75 #ifndef OBJID_CLIENT
76 #define OBJID_CLIENT 0xFFFFFFFC
77 #endif
78 #endif
79
80 #include "wx/msw/private.h"
81
82 #if wxUSE_TOOLTIPS
83 #include "wx/tooltip.h"
84 #endif
85
86 #if wxUSE_CARET
87 #include "wx/caret.h"
88 #endif // wxUSE_CARET
89
90 #if wxUSE_SPINCTRL
91 #include "wx/spinctrl.h"
92 #endif // wxUSE_SPINCTRL
93
94 #include "wx/notebook.h"
95 #include "wx/listctrl.h"
96 #include "wx/dynlib.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 __WXWINCE__ && !defined NEED_PBT_H
110 #include <pbt.h>
111 #endif
112
113 #if defined(__WXWINCE__)
114 #include "wx/msw/wince/missing.h"
115 #ifdef __POCKETPC__
116 #include <windows.h>
117 #include <shellapi.h>
118 #include <ole2.h>
119 #include <aygshell.h>
120 #endif
121 #endif
122
123 #if wxUSE_UXTHEME
124 #include "wx/msw/uxtheme.h"
125 #define EP_EDITTEXT 1
126 #define ETS_NORMAL 1
127 #define ETS_HOT 2
128 #define ETS_SELECTED 3
129 #define ETS_DISABLED 4
130 #define ETS_FOCUSED 5
131 #define ETS_READONLY 6
132 #define ETS_ASSIST 7
133 #endif
134
135 #if defined(TME_LEAVE) && defined(WM_MOUSELEAVE) && wxUSE_DYNLIB_CLASS
136 #define HAVE_TRACKMOUSEEVENT
137 #endif // everything needed for TrackMouseEvent()
138
139 // if this is set to 1, we use deferred window sizing to reduce flicker when
140 // resizing complicated window hierarchies, but this can in theory result in
141 // different behaviour than the old code so we keep the possibility to use it
142 // by setting this to 0 (in the future this should be removed completely)
143 #ifdef __WXWINCE__
144 #define USE_DEFERRED_SIZING 0
145 #else
146 #define USE_DEFERRED_SIZING 1
147 #endif
148
149 // set this to 1 to filter out duplicate mouse events, e.g. mouse move events
150 // when mouse position didnd't change
151 #ifdef __WXWINCE__
152 #define wxUSE_MOUSEEVENT_HACK 0
153 #else
154 #define wxUSE_MOUSEEVENT_HACK 1
155 #endif
156
157 // ---------------------------------------------------------------------------
158 // global variables
159 // ---------------------------------------------------------------------------
160
161 #if wxUSE_MENUS_NATIVE
162 wxMenu *wxCurrentPopupMenu = NULL;
163 #endif // wxUSE_MENUS_NATIVE
164
165 #ifdef __WXWINCE__
166 extern wxChar *wxCanvasClassName;
167 #else
168 extern const wxChar *wxCanvasClassName;
169 #endif
170
171 // true if we had already created the std colour map, used by
172 // wxGetStdColourMap() and wxWindow::OnSysColourChanged() (FIXME-MT)
173 static bool gs_hasStdCmap = false;
174
175 // last mouse event information we need to filter out the duplicates
176 #if wxUSE_MOUSEEVENT_HACK
177 static struct MouseEventInfoDummy
178 {
179 // mouse position (in screen coordinates)
180 wxPoint pos;
181
182 // last mouse event type
183 wxEventType type;
184 } gs_lastMouseEvent;
185 #endif // wxUSE_MOUSEEVENT_HACK
186
187 // ---------------------------------------------------------------------------
188 // private functions
189 // ---------------------------------------------------------------------------
190
191 // the window proc for all our windows
192 LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message,
193 WPARAM wParam, LPARAM lParam);
194
195
196 #ifdef __WXDEBUG__
197 const wxChar *wxGetMessageName(int message);
198 #endif //__WXDEBUG__
199
200 void wxRemoveHandleAssociation(wxWindowMSW *win);
201 extern void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win);
202 wxWindow *wxFindWinFromHandle(WXHWND hWnd);
203
204 // get the text metrics for the current font
205 static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win);
206
207 #ifdef __WXWINCE__
208 // find the window for the mouse event at the specified position
209 static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y);
210 #endif // __WXWINCE__
211
212 // wrapper around BringWindowToTop() API
213 static inline void wxBringWindowToTop(HWND hwnd)
214 {
215 #ifdef __WXMICROWIN__
216 // It seems that MicroWindows brings the _parent_ of the window to the top,
217 // which can be the wrong one.
218
219 // activate (set focus to) specified window
220 ::SetFocus(hwnd);
221 #endif
222
223 // raise top level parent to top of z order
224 if (!::SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE))
225 {
226 wxLogLastError(_T("SetWindowPos"));
227 }
228 }
229
230 #ifndef __WXWINCE__
231
232 // ensure that all our parent windows have WS_EX_CONTROLPARENT style
233 static void EnsureParentHasControlParentStyle(wxWindow *parent)
234 {
235 /*
236 If we have WS_EX_CONTROLPARENT flag we absolutely *must* set it for our
237 parent as well as otherwise several Win32 functions using
238 GetNextDlgTabItem() to iterate over all controls such as
239 IsDialogMessage() or DefDlgProc() would enter an infinite loop: indeed,
240 all of them iterate over all the controls starting from the currently
241 focused one and stop iterating when they get back to the focus but
242 unless all parents have WS_EX_CONTROLPARENT bit set, they would never
243 get back to the initial (focused) window: as we do have this style,
244 GetNextDlgTabItem() will leave this window and continue in its parent,
245 but if the parent doesn't have it, it wouldn't recurse inside it later
246 on and so wouldn't have a chance of getting back to this window either.
247 */
248 while ( parent && !parent->IsTopLevel() )
249 {
250 LONG exStyle = ::GetWindowLong(GetHwndOf(parent), GWL_EXSTYLE);
251 if ( !(exStyle & WS_EX_CONTROLPARENT) )
252 {
253 // force the parent to have this style
254 ::SetWindowLong(GetHwndOf(parent), GWL_EXSTYLE,
255 exStyle | WS_EX_CONTROLPARENT);
256 }
257
258 parent = parent->GetParent();
259 }
260 }
261
262 #endif // !__WXWINCE__
263
264 #ifdef __WXWINCE__
265 // On Windows CE, GetCursorPos can return an error, so use this function
266 // instead
267 bool GetCursorPosWinCE(POINT* pt)
268 {
269 if (!GetCursorPos(pt))
270 {
271 DWORD pos = GetMessagePos();
272 pt->x = LOWORD(pos);
273 pt->y = HIWORD(pos);
274 }
275 return true;
276 }
277 #endif
278
279 static wxBorder TranslateBorder(wxBorder border)
280 {
281 if ( border == wxBORDER_THEME )
282 {
283 #if defined(__POCKETPC__) || defined(__SMARTPHONE__)
284 return wxBORDER_SIMPLE;
285 #elif wxUSE_UXTHEME
286 if (wxUxThemeEngine::GetIfActive())
287 return wxBORDER_THEME;
288 #endif
289 return wxBORDER_SUNKEN;
290 }
291
292 return border;
293 }
294
295 // ---------------------------------------------------------------------------
296 // event tables
297 // ---------------------------------------------------------------------------
298
299 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
300 // method
301 #ifdef __WXUNIVERSAL__
302 IMPLEMENT_ABSTRACT_CLASS(wxWindowMSW, wxWindowBase)
303 #else // __WXMSW__
304 #if wxUSE_EXTENDED_RTTI
305
306 // windows that are created from a parent window during its Create method, eg. spin controls in a calendar controls
307 // must never been streamed out separately otherwise chaos occurs. Right now easiest is to test for negative ids, as
308 // windows with negative ids never can be recreated anyway
309
310 bool wxWindowStreamingCallback( const wxObject *object, wxWriter * , wxPersister * , wxxVariantArray & )
311 {
312 const wxWindow * win = dynamic_cast<const wxWindow*>(object) ;
313 if ( win && win->GetId() < 0 )
314 return false ;
315 return true ;
316 }
317
318 IMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxWindow, wxWindowBase,"wx/window.h", wxWindowStreamingCallback)
319
320 // make wxWindowList known before the property is used
321
322 wxCOLLECTION_TYPE_INFO( wxWindow* , wxWindowList ) ;
323
324 template<> void wxCollectionToVariantArray( wxWindowList const &theList, wxxVariantArray &value)
325 {
326 wxListCollectionToVariantArray<wxWindowList::compatibility_iterator>( theList , value ) ;
327 }
328
329 WX_DEFINE_FLAGS( wxWindowStyle )
330
331 wxBEGIN_FLAGS( wxWindowStyle )
332 // new style border flags, we put them first to
333 // use them for streaming out
334
335 wxFLAGS_MEMBER(wxBORDER_SIMPLE)
336 wxFLAGS_MEMBER(wxBORDER_SUNKEN)
337 wxFLAGS_MEMBER(wxBORDER_DOUBLE)
338 wxFLAGS_MEMBER(wxBORDER_RAISED)
339 wxFLAGS_MEMBER(wxBORDER_STATIC)
340 wxFLAGS_MEMBER(wxBORDER_NONE)
341
342 // old style border flags
343 wxFLAGS_MEMBER(wxSIMPLE_BORDER)
344 wxFLAGS_MEMBER(wxSUNKEN_BORDER)
345 wxFLAGS_MEMBER(wxDOUBLE_BORDER)
346 wxFLAGS_MEMBER(wxRAISED_BORDER)
347 wxFLAGS_MEMBER(wxSTATIC_BORDER)
348 wxFLAGS_MEMBER(wxBORDER)
349
350 // standard window styles
351 wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
352 wxFLAGS_MEMBER(wxCLIP_CHILDREN)
353 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
354 wxFLAGS_MEMBER(wxWANTS_CHARS)
355 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
356 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
357 wxFLAGS_MEMBER(wxVSCROLL)
358 wxFLAGS_MEMBER(wxHSCROLL)
359
360 wxEND_FLAGS( wxWindowStyle )
361
362 wxBEGIN_PROPERTIES_TABLE(wxWindow)
363 wxEVENT_PROPERTY( Close , wxEVT_CLOSE_WINDOW , wxCloseEvent)
364 wxEVENT_PROPERTY( Create , wxEVT_CREATE , wxWindowCreateEvent )
365 wxEVENT_PROPERTY( Destroy , wxEVT_DESTROY , wxWindowDestroyEvent )
366 // Always constructor Properties first
367
368 wxREADONLY_PROPERTY( Parent,wxWindow*, GetParent, EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
369 wxPROPERTY( Id,wxWindowID, SetId, GetId, -1 /*wxID_ANY*/ , 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
370 wxPROPERTY( Position,wxPoint, SetPosition , GetPosition, wxDefaultPosition , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // pos
371 wxPROPERTY( Size,wxSize, SetSize, GetSize, wxDefaultSize , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // size
372 wxPROPERTY( WindowStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
373
374 // Then all relations of the object graph
375
376 wxREADONLY_PROPERTY_COLLECTION( Children , wxWindowList , wxWindowBase* , GetWindowChildren , wxPROP_OBJECT_GRAPH /*flags*/ , wxT("Helpstring") , wxT("group"))
377
378 // and finally all other properties
379
380 wxPROPERTY( ExtraStyle , long , SetExtraStyle , GetExtraStyle , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // extstyle
381 wxPROPERTY( BackgroundColour , wxColour , SetBackgroundColour , GetBackgroundColour , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // bg
382 wxPROPERTY( ForegroundColour , wxColour , SetForegroundColour , GetForegroundColour , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // fg
383 wxPROPERTY( Enabled , bool , Enable , IsEnabled , wxxVariant((bool)true) , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
384 wxPROPERTY( Shown , bool , Show , IsShown , wxxVariant((bool)true) , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
385 #if 0
386 // possible property candidates (not in xrc) or not valid in all subclasses
387 wxPROPERTY( Title,wxString, SetTitle, GetTitle, wxEmptyString )
388 wxPROPERTY( Font , wxFont , SetFont , GetWindowFont , )
389 wxPROPERTY( Label,wxString, SetLabel, GetLabel, wxEmptyString )
390 // MaxHeight, Width , MinHeight , Width
391 // TODO switch label to control and title to toplevels
392
393 wxPROPERTY( ThemeEnabled , bool , SetThemeEnabled , GetThemeEnabled , )
394 //wxPROPERTY( Cursor , wxCursor , SetCursor , GetCursor , )
395 // wxPROPERTY( ToolTip , wxString , SetToolTip , GetToolTipText , )
396 wxPROPERTY( AutoLayout , bool , SetAutoLayout , GetAutoLayout , )
397
398
399
400 #endif
401 wxEND_PROPERTIES_TABLE()
402
403 wxBEGIN_HANDLERS_TABLE(wxWindow)
404 wxEND_HANDLERS_TABLE()
405
406 wxCONSTRUCTOR_DUMMY(wxWindow)
407
408 #else
409 IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
410 #endif
411 #endif // __WXUNIVERSAL__/__WXMSW__
412
413 BEGIN_EVENT_TABLE(wxWindowMSW, wxWindowBase)
414 EVT_SYS_COLOUR_CHANGED(wxWindowMSW::OnSysColourChanged)
415 EVT_ERASE_BACKGROUND(wxWindowMSW::OnEraseBackground)
416 #ifdef __WXWINCE__
417 EVT_INIT_DIALOG(wxWindowMSW::OnInitDialog)
418 #endif
419 END_EVENT_TABLE()
420
421 // ===========================================================================
422 // implementation
423 // ===========================================================================
424
425 // ---------------------------------------------------------------------------
426 // wxWindow utility functions
427 // ---------------------------------------------------------------------------
428
429 // Find an item given the MS Windows id
430 wxWindow *wxWindowMSW::FindItem(long id) const
431 {
432 #if wxUSE_CONTROLS
433 wxControl *item = wxDynamicCastThis(wxControl);
434 if ( item )
435 {
436 // is it us or one of our "internal" children?
437 if ( item->GetId() == id
438 #ifndef __WXUNIVERSAL__
439 || (item->GetSubcontrols().Index(id) != wxNOT_FOUND)
440 #endif // __WXUNIVERSAL__
441 )
442 {
443 return item;
444 }
445 }
446 #endif // wxUSE_CONTROLS
447
448 wxWindowList::compatibility_iterator current = GetChildren().GetFirst();
449 while (current)
450 {
451 wxWindow *childWin = current->GetData();
452
453 wxWindow *wnd = childWin->FindItem(id);
454 if ( wnd )
455 return wnd;
456
457 current = current->GetNext();
458 }
459
460 return NULL;
461 }
462
463 // Find an item given the MS Windows handle
464 wxWindow *wxWindowMSW::FindItemByHWND(WXHWND hWnd, bool controlOnly) const
465 {
466 wxWindowList::compatibility_iterator current = GetChildren().GetFirst();
467 while (current)
468 {
469 wxWindow *parent = current->GetData();
470
471 // Do a recursive search.
472 wxWindow *wnd = parent->FindItemByHWND(hWnd);
473 if ( wnd )
474 return wnd;
475
476 if ( !controlOnly
477 #if wxUSE_CONTROLS
478 || parent->IsKindOf(CLASSINFO(wxControl))
479 #endif // wxUSE_CONTROLS
480 )
481 {
482 wxWindow *item = current->GetData();
483 if ( item->GetHWND() == hWnd )
484 return item;
485 else
486 {
487 if ( item->ContainsHWND(hWnd) )
488 return item;
489 }
490 }
491
492 current = current->GetNext();
493 }
494 return NULL;
495 }
496
497 // Default command handler
498 bool wxWindowMSW::MSWCommand(WXUINT WXUNUSED(param), WXWORD WXUNUSED(id))
499 {
500 return false;
501 }
502
503 // ----------------------------------------------------------------------------
504 // constructors and such
505 // ----------------------------------------------------------------------------
506
507 void wxWindowMSW::Init()
508 {
509 // MSW specific
510 m_isBeingDeleted = false;
511 m_oldWndProc = NULL;
512 m_mouseInWindow = false;
513 m_lastKeydownProcessed = false;
514
515 m_childrenDisabled = NULL;
516 m_frozenness = 0;
517
518 m_hWnd = 0;
519 m_hDWP = 0;
520
521 m_xThumbSize = 0;
522 m_yThumbSize = 0;
523
524 m_pendingPosition = wxDefaultPosition;
525 m_pendingSize = wxDefaultSize;
526
527 #ifdef __POCKETPC__
528 m_contextMenuEnabled = false;
529 #endif
530 }
531
532 // Destructor
533 wxWindowMSW::~wxWindowMSW()
534 {
535 m_isBeingDeleted = true;
536
537 #ifndef __WXUNIVERSAL__
538 // VS: make sure there's no wxFrame with last focus set to us:
539 for ( wxWindow *win = GetParent(); win; win = win->GetParent() )
540 {
541 wxTopLevelWindow *frame = wxDynamicCast(win, wxTopLevelWindow);
542 if ( frame )
543 {
544 if ( frame->GetLastFocus() == this )
545 {
546 frame->SetLastFocus(NULL);
547 }
548
549 // apparently sometimes we can end up with our grand parent
550 // pointing to us as well: this is surely a bug in focus handling
551 // code but it's not clear where it happens so for now just try to
552 // fix it here by not breaking out of the loop
553 //break;
554 }
555 }
556 #endif // __WXUNIVERSAL__
557
558 // VS: destroy children first and _then_ detach *this from its parent.
559 // If we did it the other way around, children wouldn't be able
560 // find their parent frame (see above).
561 DestroyChildren();
562
563 if ( m_hWnd )
564 {
565 // VZ: test temp removed to understand what really happens here
566 //if (::IsWindow(GetHwnd()))
567 {
568 if ( !::DestroyWindow(GetHwnd()) )
569 wxLogLastError(wxT("DestroyWindow"));
570 }
571
572 // remove hWnd <-> wxWindow association
573 wxRemoveHandleAssociation(this);
574 }
575
576 delete m_childrenDisabled;
577
578 }
579
580 // real construction (Init() must have been called before!)
581 bool wxWindowMSW::Create(wxWindow *parent,
582 wxWindowID id,
583 const wxPoint& pos,
584 const wxSize& size,
585 long style,
586 const wxString& name)
587 {
588 wxCHECK_MSG( parent, false, wxT("can't create wxWindow without parent") );
589
590 if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) )
591 return false;
592
593 parent->AddChild(this);
594
595 WXDWORD exstyle;
596 DWORD msflags = MSWGetCreateWindowFlags(&exstyle);
597
598 #ifdef __WXUNIVERSAL__
599 // no borders, we draw them ourselves
600 exstyle &= ~(WS_EX_DLGMODALFRAME |
601 WS_EX_STATICEDGE |
602 WS_EX_CLIENTEDGE |
603 WS_EX_WINDOWEDGE);
604 msflags &= ~WS_BORDER;
605 #endif // wxUniversal
606
607 if ( IsShown() )
608 {
609 msflags |= WS_VISIBLE;
610 }
611
612 if ( !MSWCreate(wxCanvasClassName, NULL, pos, size, msflags, exstyle) )
613 return false;
614
615 InheritAttributes();
616
617 return true;
618 }
619
620 // ---------------------------------------------------------------------------
621 // basic operations
622 // ---------------------------------------------------------------------------
623
624 void wxWindowMSW::SetFocus()
625 {
626 HWND hWnd = GetHwnd();
627 wxCHECK_RET( hWnd, _T("can't set focus to invalid window") );
628
629 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
630 ::SetLastError(0);
631 #endif
632
633 if ( !::SetFocus(hWnd) )
634 {
635 #if defined(__WXDEBUG__) && !defined(__WXMICROWIN__)
636 // was there really an error?
637 DWORD dwRes = ::GetLastError();
638 if ( dwRes )
639 {
640 HWND hwndFocus = ::GetFocus();
641 if ( hwndFocus != hWnd )
642 {
643 wxLogApiError(_T("SetFocus"), dwRes);
644 }
645 }
646 #endif // Debug
647 }
648 }
649
650 void wxWindowMSW::SetFocusFromKbd()
651 {
652 // when the focus is given to the control with DLGC_HASSETSEL style from
653 // keyboard its contents should be entirely selected: this is what
654 // ::IsDialogMessage() does and so we should do it as well to provide the
655 // same LNF as the native programs
656 if ( ::SendMessage(GetHwnd(), WM_GETDLGCODE, 0, 0) & DLGC_HASSETSEL )
657 {
658 ::SendMessage(GetHwnd(), EM_SETSEL, 0, -1);
659 }
660
661 // do this after (maybe) setting the selection as like this when
662 // wxEVT_SET_FOCUS handler is called, the selection would have been already
663 // set correctly -- this may be important
664 wxWindowBase::SetFocusFromKbd();
665 }
666
667 // Get the window with the focus
668 wxWindow *wxWindowBase::DoFindFocus()
669 {
670 HWND hWnd = ::GetFocus();
671 if ( hWnd )
672 {
673 return wxGetWindowFromHWND((WXHWND)hWnd);
674 }
675
676 return NULL;
677 }
678
679 bool wxWindowMSW::Enable(bool enable)
680 {
681 if ( !wxWindowBase::Enable(enable) )
682 return false;
683
684 HWND hWnd = GetHwnd();
685 if ( hWnd )
686 ::EnableWindow(hWnd, (BOOL)enable);
687
688 // the logic below doesn't apply to the top level windows -- otherwise
689 // showing a modal dialog would result in total greying out (and ungreying
690 // out later) of everything which would be really ugly
691 if ( IsTopLevel() )
692 return true;
693
694 // when the parent is disabled, all of its children should be disabled as
695 // well but when it is enabled back, only those of the children which
696 // hadn't been already disabled in the beginning should be enabled again,
697 // so we have to keep the list of those children
698 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
699 node;
700 node = node->GetNext() )
701 {
702 wxWindow *child = node->GetData();
703 if ( child->IsTopLevel() )
704 {
705 // the logic below doesn't apply to top level children
706 continue;
707 }
708
709 if ( enable )
710 {
711 // re-enable the child unless it had been disabled before us
712 if ( !m_childrenDisabled || !m_childrenDisabled->Find(child) )
713 child->Enable();
714 }
715 else // we're being disabled
716 {
717 if ( child->IsEnabled() )
718 {
719 // disable it as children shouldn't stay enabled while the
720 // parent is not
721 child->Disable();
722 }
723 else // child already disabled, remember it
724 {
725 // have we created the list of disabled children already?
726 if ( !m_childrenDisabled )
727 m_childrenDisabled = new wxWindowList;
728
729 m_childrenDisabled->Append(child);
730 }
731 }
732 }
733
734 if ( enable && m_childrenDisabled )
735 {
736 // we don't need this list any more, don't keep unused memory
737 delete m_childrenDisabled;
738 m_childrenDisabled = NULL;
739 }
740
741 return true;
742 }
743
744 bool wxWindowMSW::Show(bool show)
745 {
746 if ( !wxWindowBase::Show(show) )
747 return false;
748
749 HWND hWnd = GetHwnd();
750
751 // we could be called before the underlying window is created (this is
752 // actually useful to prevent it from being initially shown), e.g.
753 //
754 // wxFoo *foo = new wxFoo;
755 // foo->Hide();
756 // foo->Create(parent, ...);
757 //
758 // should work without errors
759 if ( hWnd )
760 {
761 ::ShowWindow(hWnd, show ? SW_SHOW : SW_HIDE);
762 }
763
764 return true;
765 }
766
767 // Raise the window to the top of the Z order
768 void wxWindowMSW::Raise()
769 {
770 wxBringWindowToTop(GetHwnd());
771 }
772
773 // Lower the window to the bottom of the Z order
774 void wxWindowMSW::Lower()
775 {
776 ::SetWindowPos(GetHwnd(), HWND_BOTTOM, 0, 0, 0, 0,
777 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
778 }
779
780 void wxWindowMSW::DoCaptureMouse()
781 {
782 HWND hWnd = GetHwnd();
783 if ( hWnd )
784 {
785 ::SetCapture(hWnd);
786 }
787 }
788
789 void wxWindowMSW::DoReleaseMouse()
790 {
791 if ( !::ReleaseCapture() )
792 {
793 wxLogLastError(_T("ReleaseCapture"));
794 }
795 }
796
797 /* static */ wxWindow *wxWindowBase::GetCapture()
798 {
799 HWND hwnd = ::GetCapture();
800 return hwnd ? wxFindWinFromHandle((WXHWND)hwnd) : (wxWindow *)NULL;
801 }
802
803 bool wxWindowMSW::SetFont(const wxFont& font)
804 {
805 if ( !wxWindowBase::SetFont(font) )
806 {
807 // nothing to do
808 return false;
809 }
810
811 HWND hWnd = GetHwnd();
812 if ( hWnd != 0 )
813 {
814 // note the use of GetFont() instead of m_font: our own font could have
815 // just been reset and in this case we need to change the font used by
816 // the native window to the default for this class, i.e. exactly what
817 // GetFont() returns
818 WXHANDLE hFont = GetFont().GetResourceHandle();
819
820 wxASSERT_MSG( hFont, wxT("should have valid font") );
821
822 ::SendMessage(hWnd, WM_SETFONT, (WPARAM)hFont, MAKELPARAM(TRUE, 0));
823 }
824
825 return true;
826 }
827 bool wxWindowMSW::SetCursor(const wxCursor& cursor)
828 {
829 if ( !wxWindowBase::SetCursor(cursor) )
830 {
831 // no change
832 return false;
833 }
834
835 // don't "overwrite" busy cursor
836 if ( m_cursor.Ok() && !wxIsBusy() )
837 {
838 // normally we should change the cursor only if it's over this window
839 // but we should do it always if we capture the mouse currently
840 bool set = HasCapture();
841 if ( !set )
842 {
843 HWND hWnd = GetHwnd();
844
845 POINT point;
846 #ifdef __WXWINCE__
847 ::GetCursorPosWinCE(&point);
848 #else
849 ::GetCursorPos(&point);
850 #endif
851
852 RECT rect = wxGetWindowRect(hWnd);
853
854 set = ::PtInRect(&rect, point) != 0;
855 }
856
857 if ( set )
858 {
859 ::SetCursor(GetHcursorOf(m_cursor));
860 }
861 //else: will be set later when the mouse enters this window
862 }
863
864 return true;
865 }
866
867 void wxWindowMSW::WarpPointer(int x, int y)
868 {
869 ClientToScreen(&x, &y);
870
871 if ( !::SetCursorPos(x, y) )
872 {
873 wxLogLastError(_T("SetCursorPos"));
874 }
875 }
876
877 void wxWindowMSW::MSWUpdateUIState(int action, int state)
878 {
879 // WM_CHANGEUISTATE only appeared in Windows 2000 so it can do us no good
880 // to use it on older systems -- and could possibly do some harm
881 static int s_needToUpdate = -1;
882 if ( s_needToUpdate == -1 )
883 {
884 int verMaj, verMin;
885 s_needToUpdate = wxGetOsVersion(&verMaj, &verMin) == wxOS_WINDOWS_NT &&
886 verMaj >= 5;
887 }
888
889 if ( s_needToUpdate )
890 {
891 // we send WM_CHANGEUISTATE so if nothing needs changing then the system
892 // won't send WM_UPDATEUISTATE
893 ::SendMessage(GetHwnd(), WM_CHANGEUISTATE, MAKEWPARAM(action, state), 0);
894 }
895 }
896
897 // ---------------------------------------------------------------------------
898 // scrolling stuff
899 // ---------------------------------------------------------------------------
900
901 inline int GetScrollPosition(HWND hWnd, int wOrient)
902 {
903 #ifdef __WXMICROWIN__
904 return ::GetScrollPosWX(hWnd, wOrient);
905 #else
906 WinStruct<SCROLLINFO> scrollInfo;
907 scrollInfo.cbSize = sizeof(SCROLLINFO);
908 scrollInfo.fMask = SIF_POS;
909 ::GetScrollInfo(hWnd, wOrient, &scrollInfo );
910
911 return scrollInfo.nPos;
912
913 #endif
914 }
915
916 int wxWindowMSW::GetScrollPos(int orient) const
917 {
918 HWND hWnd = GetHwnd();
919 wxCHECK_MSG( hWnd, 0, _T("no HWND in GetScrollPos") );
920
921 return GetScrollPosition(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT);
922 }
923
924 // This now returns the whole range, not just the number
925 // of positions that we can scroll.
926 int wxWindowMSW::GetScrollRange(int orient) const
927 {
928 int maxPos;
929 HWND hWnd = GetHwnd();
930 if ( !hWnd )
931 return 0;
932 #if 0
933 ::GetScrollRange(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
934 &minPos, &maxPos);
935 #endif
936 WinStruct<SCROLLINFO> scrollInfo;
937 scrollInfo.fMask = SIF_RANGE;
938 if ( !::GetScrollInfo(hWnd,
939 orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
940 &scrollInfo) )
941 {
942 // Most of the time this is not really an error, since the return
943 // value can also be zero when there is no scrollbar yet.
944 // wxLogLastError(_T("GetScrollInfo"));
945 }
946 maxPos = scrollInfo.nMax;
947
948 // undo "range - 1" done in SetScrollbar()
949 return maxPos + 1;
950 }
951
952 int wxWindowMSW::GetScrollThumb(int orient) const
953 {
954 return orient == wxHORIZONTAL ? m_xThumbSize : m_yThumbSize;
955 }
956
957 void wxWindowMSW::SetScrollPos(int orient, int pos, bool refresh)
958 {
959 HWND hWnd = GetHwnd();
960 wxCHECK_RET( hWnd, _T("SetScrollPos: no HWND") );
961
962 WinStruct<SCROLLINFO> info;
963 info.nPage = 0;
964 info.nMin = 0;
965 info.nPos = pos;
966 info.fMask = SIF_POS;
967 if ( HasFlag(wxALWAYS_SHOW_SB) )
968 {
969 // disable scrollbar instead of removing it then
970 info.fMask |= SIF_DISABLENOSCROLL;
971 }
972
973 ::SetScrollInfo(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
974 &info, refresh);
975 }
976
977 // New function that will replace some of the above.
978 void wxWindowMSW::SetScrollbar(int orient,
979 int pos,
980 int pageSize,
981 int range,
982 bool refresh)
983 {
984 WinStruct<SCROLLINFO> info;
985 info.nPage = pageSize;
986 info.nMin = 0; // range is nMax - nMin + 1
987 info.nMax = range - 1; // as both nMax and nMax are inclusive
988 info.nPos = pos;
989 info.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
990 if ( HasFlag(wxALWAYS_SHOW_SB) )
991 {
992 // disable scrollbar instead of removing it then
993 info.fMask |= SIF_DISABLENOSCROLL;
994 }
995
996 HWND hWnd = GetHwnd();
997 if ( hWnd )
998 {
999 // We have to set the variables here to make them valid in events
1000 // triggered by ::SetScrollInfo()
1001 *(orient == wxHORIZONTAL ? &m_xThumbSize : &m_yThumbSize) = pageSize;
1002
1003 ::SetScrollInfo(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
1004 &info, refresh);
1005 }
1006 }
1007
1008 void wxWindowMSW::ScrollWindow(int dx, int dy, const wxRect *prect)
1009 {
1010 RECT rect;
1011 RECT *pr;
1012 if ( prect )
1013 {
1014 rect.left = prect->x;
1015 rect.top = prect->y;
1016 rect.right = prect->x + prect->width;
1017 rect.bottom = prect->y + prect->height;
1018 pr = &rect;
1019 }
1020 else
1021 {
1022 pr = NULL;
1023
1024 }
1025
1026 #ifdef __WXWINCE__
1027 // FIXME: is this the exact equivalent of the line below?
1028 ::ScrollWindowEx(GetHwnd(), dx, dy, pr, pr, 0, 0, SW_SCROLLCHILDREN|SW_ERASE|SW_INVALIDATE);
1029 #else
1030 ::ScrollWindow(GetHwnd(), dx, dy, pr, pr);
1031 #endif
1032 }
1033
1034 static bool ScrollVertically(HWND hwnd, int kind, int count)
1035 {
1036 int posStart = GetScrollPosition(hwnd, SB_VERT);
1037
1038 int pos = posStart;
1039 for ( int n = 0; n < count; n++ )
1040 {
1041 ::SendMessage(hwnd, WM_VSCROLL, kind, 0);
1042
1043 int posNew = GetScrollPosition(hwnd, SB_VERT);
1044 if ( posNew == pos )
1045 {
1046 // don't bother to continue, we're already at top/bottom
1047 break;
1048 }
1049
1050 pos = posNew;
1051 }
1052
1053 return pos != posStart;
1054 }
1055
1056 bool wxWindowMSW::ScrollLines(int lines)
1057 {
1058 bool down = lines > 0;
1059
1060 return ScrollVertically(GetHwnd(),
1061 down ? SB_LINEDOWN : SB_LINEUP,
1062 down ? lines : -lines);
1063 }
1064
1065 bool wxWindowMSW::ScrollPages(int pages)
1066 {
1067 bool down = pages > 0;
1068
1069 return ScrollVertically(GetHwnd(),
1070 down ? SB_PAGEDOWN : SB_PAGEUP,
1071 down ? pages : -pages);
1072 }
1073
1074 // ----------------------------------------------------------------------------
1075 // RTL support
1076 // ----------------------------------------------------------------------------
1077
1078 void wxWindowMSW::SetLayoutDirection(wxLayoutDirection dir)
1079 {
1080 #ifdef __WXWINCE__
1081 wxUnusedVar(dir);
1082 #else
1083 const HWND hwnd = GetHwnd();
1084 wxCHECK_RET( hwnd, _T("layout direction must be set after window creation") );
1085
1086 LONG styleOld = ::GetWindowLong(hwnd, GWL_EXSTYLE);
1087
1088 LONG styleNew = styleOld;
1089 switch ( dir )
1090 {
1091 case wxLayout_LeftToRight:
1092 styleNew &= ~WS_EX_LAYOUTRTL;
1093 break;
1094
1095 case wxLayout_RightToLeft:
1096 styleNew |= WS_EX_LAYOUTRTL;
1097 break;
1098
1099 default:
1100 wxFAIL_MSG(_T("unsupported layout direction"));
1101 break;
1102 }
1103
1104 if ( styleNew != styleOld )
1105 {
1106 ::SetWindowLong(hwnd, GWL_EXSTYLE, styleNew);
1107 }
1108 #endif
1109 }
1110
1111 wxLayoutDirection wxWindowMSW::GetLayoutDirection() const
1112 {
1113 #ifdef __WXWINCE__
1114 return wxLayout_Default;
1115 #else
1116 const HWND hwnd = GetHwnd();
1117 wxCHECK_MSG( hwnd, wxLayout_Default, _T("invalid window") );
1118
1119 return ::GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL
1120 ? wxLayout_RightToLeft
1121 : wxLayout_LeftToRight;
1122 #endif
1123 }
1124
1125 wxCoord
1126 wxWindowMSW::AdjustForLayoutDirection(wxCoord x,
1127 wxCoord WXUNUSED(width),
1128 wxCoord WXUNUSED(widthTotal)) const
1129 {
1130 // Win32 mirrors the coordinates of RTL windows automatically, so don't
1131 // redo it ourselves
1132 return x;
1133 }
1134
1135 // ---------------------------------------------------------------------------
1136 // subclassing
1137 // ---------------------------------------------------------------------------
1138
1139 void wxWindowMSW::SubclassWin(WXHWND hWnd)
1140 {
1141 wxASSERT_MSG( !m_oldWndProc, wxT("subclassing window twice?") );
1142
1143 HWND hwnd = (HWND)hWnd;
1144 wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in SubclassWin") );
1145
1146 wxAssociateWinWithHandle(hwnd, this);
1147
1148 m_oldWndProc = (WXFARPROC)wxGetWindowProc((HWND)hWnd);
1149
1150 // we don't need to subclass the window of our own class (in the Windows
1151 // sense of the word)
1152 if ( !wxCheckWindowWndProc(hWnd, (WXFARPROC)wxWndProc) )
1153 {
1154 wxSetWindowProc(hwnd, wxWndProc);
1155 }
1156 else
1157 {
1158 // don't bother restoring it either: this also makes it easy to
1159 // implement IsOfStandardClass() method which returns true for the
1160 // standard controls and false for the wxWidgets own windows as it can
1161 // simply check m_oldWndProc
1162 m_oldWndProc = NULL;
1163 }
1164
1165 // we're officially created now, send the event
1166 wxWindowCreateEvent event((wxWindow *)this);
1167 (void)GetEventHandler()->ProcessEvent(event);
1168 }
1169
1170 void wxWindowMSW::UnsubclassWin()
1171 {
1172 wxRemoveHandleAssociation(this);
1173
1174 // Restore old Window proc
1175 HWND hwnd = GetHwnd();
1176 if ( hwnd )
1177 {
1178 SetHWND(0);
1179
1180 wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in UnsubclassWin") );
1181
1182 if ( m_oldWndProc )
1183 {
1184 if ( !wxCheckWindowWndProc((WXHWND)hwnd, m_oldWndProc) )
1185 {
1186 wxSetWindowProc(hwnd, (WNDPROC)m_oldWndProc);
1187 }
1188
1189 m_oldWndProc = NULL;
1190 }
1191 }
1192 }
1193
1194 void wxWindowMSW::AssociateHandle(WXWidget handle)
1195 {
1196 if ( m_hWnd )
1197 {
1198 if ( !::DestroyWindow(GetHwnd()) )
1199 wxLogLastError(wxT("DestroyWindow"));
1200 }
1201
1202 WXHWND wxhwnd = (WXHWND)handle;
1203
1204 SetHWND(wxhwnd);
1205 SubclassWin(wxhwnd);
1206 }
1207
1208 void wxWindowMSW::DissociateHandle()
1209 {
1210 // this also calls SetHWND(0) for us
1211 UnsubclassWin();
1212 }
1213
1214
1215 bool wxCheckWindowWndProc(WXHWND hWnd,
1216 WXFARPROC WXUNUSED(wndProc))
1217 {
1218 // TODO: This list of window class names should be factored out so they can be
1219 // managed in one place and then accessed from here and other places, such as
1220 // wxApp::RegisterWindowClasses() and wxApp::UnregisterWindowClasses()
1221
1222 #ifdef __WXWINCE__
1223 extern wxChar *wxCanvasClassName;
1224 extern wxChar *wxCanvasClassNameNR;
1225 #else
1226 extern const wxChar *wxCanvasClassName;
1227 extern const wxChar *wxCanvasClassNameNR;
1228 #endif
1229 extern const wxChar *wxMDIFrameClassName;
1230 extern const wxChar *wxMDIFrameClassNameNoRedraw;
1231 extern const wxChar *wxMDIChildFrameClassName;
1232 extern const wxChar *wxMDIChildFrameClassNameNoRedraw;
1233 wxString str(wxGetWindowClass(hWnd));
1234 if (str == wxCanvasClassName ||
1235 str == wxCanvasClassNameNR ||
1236 #if wxUSE_GLCANVAS
1237 str == _T("wxGLCanvasClass") ||
1238 str == _T("wxGLCanvasClassNR") ||
1239 #endif // wxUSE_GLCANVAS
1240 str == wxMDIFrameClassName ||
1241 str == wxMDIFrameClassNameNoRedraw ||
1242 str == wxMDIChildFrameClassName ||
1243 str == wxMDIChildFrameClassNameNoRedraw ||
1244 str == _T("wxTLWHiddenParent"))
1245 return true; // Effectively means don't subclass
1246 else
1247 return false;
1248 }
1249
1250 // ----------------------------------------------------------------------------
1251 // Style handling
1252 // ----------------------------------------------------------------------------
1253
1254 void wxWindowMSW::SetWindowStyleFlag(long flags)
1255 {
1256 long flagsOld = GetWindowStyleFlag();
1257 if ( flags == flagsOld )
1258 return;
1259
1260 // update the internal variable
1261 wxWindowBase::SetWindowStyleFlag(flags);
1262
1263 // and the real window flags
1264 MSWUpdateStyle(flagsOld, GetExtraStyle());
1265 }
1266
1267 void wxWindowMSW::SetExtraStyle(long exflags)
1268 {
1269 long exflagsOld = GetExtraStyle();
1270 if ( exflags == exflagsOld )
1271 return;
1272
1273 // update the internal variable
1274 wxWindowBase::SetExtraStyle(exflags);
1275
1276 // and the real window flags
1277 MSWUpdateStyle(GetWindowStyleFlag(), exflagsOld);
1278 }
1279
1280 void wxWindowMSW::MSWUpdateStyle(long flagsOld, long exflagsOld)
1281 {
1282 // now update the Windows style as well if needed - and if the window had
1283 // been already created
1284 if ( !GetHwnd() )
1285 return;
1286
1287 // we may need to call SetWindowPos() when we change some styles
1288 bool callSWP = false;
1289
1290 WXDWORD exstyle;
1291 long style = MSWGetStyle(GetWindowStyleFlag(), &exstyle);
1292
1293 // this is quite a horrible hack but we need it because MSWGetStyle()
1294 // doesn't take exflags as parameter but uses GetExtraStyle() internally
1295 // and so we have to modify the window exflags temporarily to get the
1296 // correct exstyleOld
1297 long exflagsNew = GetExtraStyle();
1298 wxWindowBase::SetExtraStyle(exflagsOld);
1299
1300 WXDWORD exstyleOld;
1301 long styleOld = MSWGetStyle(flagsOld, &exstyleOld);
1302
1303 wxWindowBase::SetExtraStyle(exflagsNew);
1304
1305
1306 if ( style != styleOld )
1307 {
1308 // some flags (e.g. WS_VISIBLE or WS_DISABLED) should not be changed by
1309 // this function so instead of simply setting the style to the new
1310 // value we clear the bits which were set in styleOld but are set in
1311 // the new one and set the ones which were not set before
1312 long styleReal = ::GetWindowLong(GetHwnd(), GWL_STYLE);
1313 styleReal &= ~styleOld;
1314 styleReal |= style;
1315
1316 ::SetWindowLong(GetHwnd(), GWL_STYLE, styleReal);
1317
1318 // we need to call SetWindowPos() if any of the styles affecting the
1319 // frame appearance have changed
1320 callSWP = ((styleOld ^ style ) & (WS_BORDER |
1321 WS_THICKFRAME |
1322 WS_CAPTION |
1323 WS_DLGFRAME |
1324 WS_MAXIMIZEBOX |
1325 WS_MINIMIZEBOX |
1326 WS_SYSMENU) ) != 0;
1327 }
1328
1329 // and the extended style
1330 long exstyleReal = ::GetWindowLong(GetHwnd(), GWL_EXSTYLE);
1331
1332 if ( exstyle != exstyleOld )
1333 {
1334 exstyleReal &= ~exstyleOld;
1335 exstyleReal |= exstyle;
1336
1337 ::SetWindowLong(GetHwnd(), GWL_EXSTYLE, exstyleReal);
1338
1339 // ex style changes don't take effect without calling SetWindowPos
1340 callSWP = true;
1341 }
1342
1343 if ( callSWP )
1344 {
1345 // we must call SetWindowPos() to flush the cached extended style and
1346 // also to make the change to wxSTAY_ON_TOP style take effect: just
1347 // setting the style simply doesn't work
1348 if ( !::SetWindowPos(GetHwnd(),
1349 exstyleReal & WS_EX_TOPMOST ? HWND_TOPMOST
1350 : HWND_NOTOPMOST,
1351 0, 0, 0, 0,
1352 SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED) )
1353 {
1354 wxLogLastError(_T("SetWindowPos"));
1355 }
1356 }
1357 }
1358
1359 WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const
1360 {
1361 // translate common wxWidgets styles to Windows ones
1362
1363 // most of windows are child ones, those which are not (such as
1364 // wxTopLevelWindow) should remove WS_CHILD in their MSWGetStyle()
1365 WXDWORD style = WS_CHILD;
1366
1367 // using this flag results in very significant reduction in flicker,
1368 // especially with controls inside the static boxes (as the interior of the
1369 // box is not redrawn twice), but sometimes results in redraw problems, so
1370 // optionally allow the old code to continue to use it provided a special
1371 // system option is turned on
1372 if ( !wxSystemOptions::GetOptionInt(wxT("msw.window.no-clip-children"))
1373 || (flags & wxCLIP_CHILDREN) )
1374 style |= WS_CLIPCHILDREN;
1375
1376 // it doesn't seem useful to use WS_CLIPSIBLINGS here as we officially
1377 // don't support overlapping windows and it only makes sense for them and,
1378 // presumably, gives the system some extra work (to manage more clipping
1379 // regions), so avoid it alltogether
1380
1381
1382 if ( flags & wxVSCROLL )
1383 style |= WS_VSCROLL;
1384
1385 if ( flags & wxHSCROLL )
1386 style |= WS_HSCROLL;
1387
1388 const wxBorder border = TranslateBorder(GetBorder(flags));
1389
1390 // WS_BORDER is only required for wxBORDER_SIMPLE
1391 if ( border == wxBORDER_SIMPLE )
1392 style |= WS_BORDER;
1393
1394 // now deal with ext style if the caller wants it
1395 if ( exstyle )
1396 {
1397 *exstyle = 0;
1398
1399 #ifndef __WXWINCE__
1400 if ( flags & wxTRANSPARENT_WINDOW )
1401 *exstyle |= WS_EX_TRANSPARENT;
1402 #endif
1403
1404 switch ( border )
1405 {
1406 default:
1407 case wxBORDER_DEFAULT:
1408 wxFAIL_MSG( _T("unknown border style") );
1409 // fall through
1410
1411 case wxBORDER_NONE:
1412 case wxBORDER_SIMPLE:
1413 case wxBORDER_THEME:
1414 break;
1415
1416 case wxBORDER_STATIC:
1417 *exstyle |= WS_EX_STATICEDGE;
1418 break;
1419
1420 case wxBORDER_RAISED:
1421 *exstyle |= WS_EX_DLGMODALFRAME;
1422 break;
1423
1424 case wxBORDER_SUNKEN:
1425 *exstyle |= WS_EX_CLIENTEDGE;
1426 style &= ~WS_BORDER;
1427 break;
1428
1429 // case wxBORDER_DOUBLE:
1430 // *exstyle |= WS_EX_DLGMODALFRAME;
1431 // break;
1432 }
1433
1434 // wxUniv doesn't use Windows dialog navigation functions at all
1435 #if !defined(__WXUNIVERSAL__) && !defined(__WXWINCE__)
1436 // to make the dialog navigation work with the nested panels we must
1437 // use this style (top level windows such as dialogs don't need it)
1438 if ( (flags & wxTAB_TRAVERSAL) && !IsTopLevel() )
1439 {
1440 *exstyle |= WS_EX_CONTROLPARENT;
1441 }
1442 #endif // __WXUNIVERSAL__
1443 }
1444
1445 return style;
1446 }
1447
1448 // Helper for getting an appropriate theme style for the application. Unnecessary in
1449 // 2.9 and above.
1450 wxBorder wxWindowMSW::GetThemedBorderStyle() const
1451 {
1452 return TranslateBorder(wxBORDER_THEME);
1453 }
1454
1455 // Setup background and foreground colours correctly
1456 void wxWindowMSW::SetupColours()
1457 {
1458 if ( GetParent() )
1459 SetBackgroundColour(GetParent()->GetBackgroundColour());
1460 }
1461
1462 bool wxWindowMSW::IsMouseInWindow() const
1463 {
1464 // get the mouse position
1465 POINT pt;
1466 #ifdef __WXWINCE__
1467 ::GetCursorPosWinCE(&pt);
1468 #else
1469 ::GetCursorPos(&pt);
1470 #endif
1471
1472 // find the window which currently has the cursor and go up the window
1473 // chain until we find this window - or exhaust it
1474 HWND hwnd = ::WindowFromPoint(pt);
1475 while ( hwnd && (hwnd != GetHwnd()) )
1476 hwnd = ::GetParent(hwnd);
1477
1478 return hwnd != NULL;
1479 }
1480
1481 void wxWindowMSW::OnInternalIdle()
1482 {
1483 #ifndef HAVE_TRACKMOUSEEVENT
1484 // Check if we need to send a LEAVE event
1485 if ( m_mouseInWindow )
1486 {
1487 // note that we should generate the leave event whether the window has
1488 // or doesn't have mouse capture
1489 if ( !IsMouseInWindow() )
1490 {
1491 GenerateMouseLeave();
1492 }
1493 }
1494 #endif // !HAVE_TRACKMOUSEEVENT
1495
1496 if (wxUpdateUIEvent::CanUpdate(this) && IsShownOnScreen())
1497 UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
1498 }
1499
1500 // Set this window to be the child of 'parent'.
1501 bool wxWindowMSW::Reparent(wxWindowBase *parent)
1502 {
1503 if ( !wxWindowBase::Reparent(parent) )
1504 return false;
1505
1506 HWND hWndChild = GetHwnd();
1507 HWND hWndParent = GetParent() ? GetWinHwnd(GetParent()) : (HWND)0;
1508
1509 ::SetParent(hWndChild, hWndParent);
1510
1511 #ifndef __WXWINCE__
1512 if ( ::GetWindowLong(hWndChild, GWL_EXSTYLE) & WS_EX_CONTROLPARENT )
1513 {
1514 EnsureParentHasControlParentStyle(GetParent());
1515 }
1516 #endif // !__WXWINCE__
1517
1518 return true;
1519 }
1520
1521 static inline void SendSetRedraw(HWND hwnd, bool on)
1522 {
1523 #ifndef __WXMICROWIN__
1524 ::SendMessage(hwnd, WM_SETREDRAW, (WPARAM)on, 0);
1525 #endif
1526 }
1527
1528 void wxWindowMSW::Freeze()
1529 {
1530 if ( !m_frozenness++ )
1531 {
1532 if ( IsShown() )
1533 {
1534 if ( IsTopLevel() )
1535 {
1536 // If this is a TLW, then freeze it's non-TLW children
1537 // instead. This is needed because on Windows a frozen TLW
1538 // lets window paint and mouse events pass through to other
1539 // Windows below this one in z-order.
1540 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
1541 node;
1542 node = node->GetNext() )
1543 {
1544 wxWindow *child = node->GetData();
1545 if ( child->IsTopLevel() )
1546 continue;
1547 else
1548 child->Freeze();
1549 }
1550 }
1551 else // This is not a TLW, so just freeze it.
1552 {
1553 SendSetRedraw(GetHwnd(), false);
1554 }
1555 }
1556 }
1557 }
1558
1559 void wxWindowMSW::Thaw()
1560 {
1561 wxASSERT_MSG( m_frozenness > 0, _T("Thaw() without matching Freeze()") );
1562
1563 if ( --m_frozenness == 0 )
1564 {
1565 if ( IsShown() )
1566 {
1567 if ( IsTopLevel() )
1568 {
1569 // If this is a TLW, then Thaw it's non-TLW children
1570 // instead. See Freeze.
1571 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
1572 node;
1573 node = node->GetNext() )
1574 {
1575 wxWindow *child = node->GetData();
1576 if ( child->IsTopLevel() )
1577 continue;
1578 else
1579 {
1580 // in case the child was added while the TLW was
1581 // frozen, it won't be frozen now so avoid the Thaw.
1582 if ( child->IsFrozen() )
1583 child->Thaw();
1584 }
1585 }
1586 }
1587 else // This is not a TLW, so just thaw it.
1588 {
1589 SendSetRedraw(GetHwnd(), true);
1590 }
1591
1592 // we need to refresh everything or otherwise the invalidated area
1593 // is not going to be repainted
1594 Refresh();
1595 }
1596 }
1597 }
1598
1599 void wxWindowMSW::Refresh(bool eraseBack, const wxRect *rect)
1600 {
1601 HWND hWnd = GetHwnd();
1602 if ( hWnd )
1603 {
1604 RECT mswRect;
1605 const RECT *pRect;
1606 if ( rect )
1607 {
1608 mswRect.left = rect->x;
1609 mswRect.top = rect->y;
1610 mswRect.right = rect->x + rect->width;
1611 mswRect.bottom = rect->y + rect->height;
1612
1613 pRect = &mswRect;
1614 }
1615 else
1616 {
1617 pRect = NULL;
1618 }
1619
1620 // RedrawWindow not available on SmartPhone or eVC++ 3
1621 #if !defined(__SMARTPHONE__) && !(defined(_WIN32_WCE) && _WIN32_WCE < 400)
1622 UINT flags = RDW_INVALIDATE | RDW_ALLCHILDREN;
1623 if ( eraseBack )
1624 flags |= RDW_ERASE;
1625
1626 ::RedrawWindow(hWnd, pRect, NULL, flags);
1627 #else
1628 ::InvalidateRect(hWnd, pRect, eraseBack);
1629 #endif
1630 }
1631 }
1632
1633 void wxWindowMSW::Update()
1634 {
1635 if ( !::UpdateWindow(GetHwnd()) )
1636 {
1637 wxLogLastError(_T("UpdateWindow"));
1638 }
1639
1640 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
1641 // just calling UpdateWindow() is not enough, what we did in our WM_PAINT
1642 // handler needs to be really drawn right now
1643 (void)::GdiFlush();
1644 #endif // __WIN32__
1645 }
1646
1647 // ---------------------------------------------------------------------------
1648 // drag and drop
1649 // ---------------------------------------------------------------------------
1650
1651 #if wxUSE_DRAG_AND_DROP || !defined(__WXWINCE__)
1652
1653 #if wxUSE_STATBOX
1654
1655 // we need to lower the sibling static boxes so controls contained within can be
1656 // a drop target
1657 static void AdjustStaticBoxZOrder(wxWindow *parent)
1658 {
1659 // no sibling static boxes if we have no parent (ie TLW)
1660 if ( !parent )
1661 return;
1662
1663 for ( wxWindowList::compatibility_iterator node = parent->GetChildren().GetFirst();
1664 node;
1665 node = node->GetNext() )
1666 {
1667 wxStaticBox *statbox = wxDynamicCast(node->GetData(), wxStaticBox);
1668 if ( statbox )
1669 {
1670 ::SetWindowPos(GetHwndOf(statbox), HWND_BOTTOM, 0, 0, 0, 0,
1671 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
1672 }
1673 }
1674 }
1675
1676 #else // !wxUSE_STATBOX
1677
1678 static inline void AdjustStaticBoxZOrder(wxWindow * WXUNUSED(parent))
1679 {
1680 }
1681
1682 #endif // wxUSE_STATBOX/!wxUSE_STATBOX
1683
1684 #endif // drag and drop is used
1685
1686 #if wxUSE_DRAG_AND_DROP
1687 void wxWindowMSW::SetDropTarget(wxDropTarget *pDropTarget)
1688 {
1689 if ( m_dropTarget != 0 ) {
1690 m_dropTarget->Revoke(m_hWnd);
1691 delete m_dropTarget;
1692 }
1693
1694 m_dropTarget = pDropTarget;
1695 if ( m_dropTarget != 0 )
1696 {
1697 AdjustStaticBoxZOrder(GetParent());
1698 m_dropTarget->Register(m_hWnd);
1699 }
1700 }
1701 #endif // wxUSE_DRAG_AND_DROP
1702
1703 // old-style file manager drag&drop support: we retain the old-style
1704 // DragAcceptFiles in parallel with SetDropTarget.
1705 void wxWindowMSW::DragAcceptFiles(bool WXUNUSED_IN_WINCE(accept))
1706 {
1707 #ifndef __WXWINCE__
1708 HWND hWnd = GetHwnd();
1709 if ( hWnd )
1710 {
1711 AdjustStaticBoxZOrder(GetParent());
1712 ::DragAcceptFiles(hWnd, (BOOL)accept);
1713 }
1714 #endif
1715 }
1716
1717 // ----------------------------------------------------------------------------
1718 // tooltips
1719 // ----------------------------------------------------------------------------
1720
1721 #if wxUSE_TOOLTIPS
1722
1723 void wxWindowMSW::DoSetToolTip(wxToolTip *tooltip)
1724 {
1725 wxWindowBase::DoSetToolTip(tooltip);
1726
1727 if ( m_tooltip )
1728 m_tooltip->SetWindow((wxWindow *)this);
1729 }
1730
1731 #endif // wxUSE_TOOLTIPS
1732
1733 // ---------------------------------------------------------------------------
1734 // moving and resizing
1735 // ---------------------------------------------------------------------------
1736
1737 bool wxWindowMSW::IsSizeDeferred() const
1738 {
1739 #if USE_DEFERRED_SIZING
1740 if ( m_pendingPosition != wxDefaultPosition ||
1741 m_pendingSize != wxDefaultSize )
1742 return true;
1743 #endif // USE_DEFERRED_SIZING
1744
1745 return false;
1746 }
1747
1748 // Get total size
1749 void wxWindowMSW::DoGetSize(int *x, int *y) const
1750 {
1751 #if USE_DEFERRED_SIZING
1752 // if SetSize() had been called at wx level but not realized at Windows
1753 // level yet (i.e. EndDeferWindowPos() not called), we still should return
1754 // the new and not the old position to the other wx code
1755 if ( m_pendingSize != wxDefaultSize )
1756 {
1757 if ( x )
1758 *x = m_pendingSize.x;
1759 if ( y )
1760 *y = m_pendingSize.y;
1761 }
1762 else // use current size
1763 #endif // USE_DEFERRED_SIZING
1764 {
1765 RECT rect = wxGetWindowRect(GetHwnd());
1766
1767 if ( x )
1768 *x = rect.right - rect.left;
1769 if ( y )
1770 *y = rect.bottom - rect.top;
1771 }
1772 }
1773
1774 // Get size *available for subwindows* i.e. excluding menu bar etc.
1775 void wxWindowMSW::DoGetClientSize(int *x, int *y) const
1776 {
1777 #if USE_DEFERRED_SIZING
1778 if ( m_pendingSize != wxDefaultSize )
1779 {
1780 // we need to calculate the client size corresponding to pending size
1781 RECT rect;
1782 rect.left = m_pendingPosition.x;
1783 rect.top = m_pendingPosition.y;
1784 rect.right = rect.left + m_pendingSize.x;
1785 rect.bottom = rect.top + m_pendingSize.y;
1786
1787 ::SendMessage(GetHwnd(), WM_NCCALCSIZE, FALSE, (LPARAM)&rect);
1788
1789 if ( x )
1790 *x = rect.right - rect.left;
1791 if ( y )
1792 *y = rect.bottom - rect.top;
1793 }
1794 else
1795 #endif // USE_DEFERRED_SIZING
1796 {
1797 RECT rect = wxGetClientRect(GetHwnd());
1798
1799 if ( x )
1800 *x = rect.right;
1801 if ( y )
1802 *y = rect.bottom;
1803 }
1804 }
1805
1806 void wxWindowMSW::DoGetPosition(int *x, int *y) const
1807 {
1808 wxWindow * const parent = GetParent();
1809
1810 wxPoint pos;
1811 if ( m_pendingPosition != wxDefaultPosition )
1812 {
1813 pos = m_pendingPosition;
1814 }
1815 else // use current position
1816 {
1817 RECT rect = wxGetWindowRect(GetHwnd());
1818
1819 POINT point;
1820 point.x = rect.left;
1821 point.y = rect.top;
1822
1823 // we do the adjustments with respect to the parent only for the "real"
1824 // children, not for the dialogs/frames
1825 if ( !IsTopLevel() )
1826 {
1827 if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft )
1828 {
1829 // In RTL mode, we want the logical left x-coordinate,
1830 // which would be the physical right x-coordinate.
1831 point.x = rect.right;
1832 }
1833
1834 // Since we now have the absolute screen coords, if there's a
1835 // parent we must subtract its top left corner
1836 if ( parent )
1837 {
1838 ::ScreenToClient(GetHwndOf(parent), &point);
1839 }
1840 }
1841
1842 pos.x = point.x;
1843 pos.y = point.y;
1844 }
1845
1846 // we also must adjust by the client area offset: a control which is just
1847 // under a toolbar could be at (0, 30) in Windows but at (0, 0) in wx
1848 if ( parent && !IsTopLevel() )
1849 {
1850 const wxPoint pt(parent->GetClientAreaOrigin());
1851 pos.x -= pt.x;
1852 pos.y -= pt.y;
1853 }
1854
1855 if ( x )
1856 *x = pos.x;
1857 if ( y )
1858 *y = pos.y;
1859 }
1860
1861 void wxWindowMSW::DoScreenToClient(int *x, int *y) const
1862 {
1863 POINT pt;
1864 if ( x )
1865 pt.x = *x;
1866 if ( y )
1867 pt.y = *y;
1868
1869 ::ScreenToClient(GetHwnd(), &pt);
1870
1871 if ( x )
1872 *x = pt.x;
1873 if ( y )
1874 *y = pt.y;
1875 }
1876
1877 void wxWindowMSW::DoClientToScreen(int *x, int *y) const
1878 {
1879 POINT pt;
1880 if ( x )
1881 pt.x = *x;
1882 if ( y )
1883 pt.y = *y;
1884
1885 ::ClientToScreen(GetHwnd(), &pt);
1886
1887 if ( x )
1888 *x = pt.x;
1889 if ( y )
1890 *y = pt.y;
1891 }
1892
1893 bool
1894 wxWindowMSW::DoMoveSibling(WXHWND hwnd, int x, int y, int width, int height)
1895 {
1896 #if USE_DEFERRED_SIZING
1897 // if our parent had prepared a defer window handle for us, use it (unless
1898 // we are a top level window)
1899 wxWindowMSW * const parent = IsTopLevel() ? NULL : GetParent();
1900
1901 HDWP hdwp = parent ? (HDWP)parent->m_hDWP : NULL;
1902 if ( hdwp )
1903 {
1904 hdwp = ::DeferWindowPos(hdwp, (HWND)hwnd, NULL, x, y, width, height,
1905 SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE);
1906 if ( !hdwp )
1907 {
1908 wxLogLastError(_T("DeferWindowPos"));
1909 }
1910 }
1911
1912 if ( parent )
1913 {
1914 // hdwp must be updated as it may have been changed
1915 parent->m_hDWP = (WXHANDLE)hdwp;
1916 }
1917
1918 if ( hdwp )
1919 {
1920 // did deferred move, remember new coordinates of the window as they're
1921 // different from what Windows would return for it
1922 return true;
1923 }
1924
1925 // otherwise (or if deferring failed) move the window in place immediately
1926 #endif // USE_DEFERRED_SIZING
1927 if ( !::MoveWindow((HWND)hwnd, x, y, width, height, IsShown()) )
1928 {
1929 wxLogLastError(wxT("MoveWindow"));
1930 }
1931
1932 // if USE_DEFERRED_SIZING, indicates that we didn't use deferred move,
1933 // ignored otherwise
1934 return false;
1935 }
1936
1937 void wxWindowMSW::DoMoveWindow(int x, int y, int width, int height)
1938 {
1939 // TODO: is this consistent with other platforms?
1940 // Still, negative width or height shouldn't be allowed
1941 if (width < 0)
1942 width = 0;
1943 if (height < 0)
1944 height = 0;
1945
1946 if ( DoMoveSibling(m_hWnd, x, y, width, height) )
1947 {
1948 #if USE_DEFERRED_SIZING
1949 m_pendingPosition = wxPoint(x, y);
1950 m_pendingSize = wxSize(width, height);
1951 }
1952 else // window was moved immediately, without deferring it
1953 {
1954 m_pendingPosition = wxDefaultPosition;
1955 m_pendingSize = wxDefaultSize;
1956 #endif // USE_DEFERRED_SIZING
1957 }
1958 }
1959
1960 // set the size of the window: if the dimensions are positive, just use them,
1961 // but if any of them is equal to -1, it means that we must find the value for
1962 // it ourselves (unless sizeFlags contains wxSIZE_ALLOW_MINUS_ONE flag, in
1963 // which case -1 is a valid value for x and y)
1964 //
1965 // If sizeFlags contains wxSIZE_AUTO_WIDTH/HEIGHT flags (default), we calculate
1966 // the width/height to best suit our contents, otherwise we reuse the current
1967 // width/height
1968 void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags)
1969 {
1970 // get the current size and position...
1971 int currentX, currentY;
1972 int currentW, currentH;
1973
1974 GetPosition(&currentX, &currentY);
1975 GetSize(&currentW, &currentH);
1976
1977 // ... and don't do anything (avoiding flicker) if it's already ok unless
1978 // we're forced to resize the window
1979 if ( x == currentX && y == currentY &&
1980 width == currentW && height == currentH &&
1981 !(sizeFlags & wxSIZE_FORCE) )
1982 {
1983 return;
1984 }
1985
1986 if ( x == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
1987 x = currentX;
1988 if ( y == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
1989 y = currentY;
1990
1991 AdjustForParentClientOrigin(x, y, sizeFlags);
1992
1993 wxSize size = wxDefaultSize;
1994 if ( width == wxDefaultCoord )
1995 {
1996 if ( sizeFlags & wxSIZE_AUTO_WIDTH )
1997 {
1998 size = DoGetBestSize();
1999 width = size.x;
2000 }
2001 else
2002 {
2003 // just take the current one
2004 width = currentW;
2005 }
2006 }
2007
2008 if ( height == wxDefaultCoord )
2009 {
2010 if ( sizeFlags & wxSIZE_AUTO_HEIGHT )
2011 {
2012 if ( size.x == wxDefaultCoord )
2013 {
2014 size = DoGetBestSize();
2015 }
2016 //else: already called DoGetBestSize() above
2017
2018 height = size.y;
2019 }
2020 else
2021 {
2022 // just take the current one
2023 height = currentH;
2024 }
2025 }
2026
2027 DoMoveWindow(x, y, width, height);
2028 }
2029
2030 void wxWindowMSW::DoSetClientSize(int width, int height)
2031 {
2032 // setting the client size is less obvious than it could have been
2033 // because in the result of changing the total size the window scrollbar
2034 // may [dis]appear and/or its menubar may [un]wrap (and AdjustWindowRect()
2035 // doesn't take neither into account) and so the client size will not be
2036 // correct as the difference between the total and client size changes --
2037 // so we keep changing it until we get it right
2038 //
2039 // normally this loop shouldn't take more than 3 iterations (usually 1 but
2040 // if scrollbars [dis]appear as the result of the first call, then 2 and it
2041 // may become 3 if the window had 0 size originally and so we didn't
2042 // calculate the scrollbar correction correctly during the first iteration)
2043 // but just to be on the safe side we check for it instead of making it an
2044 // "infinite" loop (i.e. leaving break inside as the only way to get out)
2045 for ( int i = 0; i < 4; i++ )
2046 {
2047 RECT rectClient;
2048 ::GetClientRect(GetHwnd(), &rectClient);
2049
2050 // if the size is already ok, stop here (NB: rectClient.left = top = 0)
2051 if ( (rectClient.right == width || width == wxDefaultCoord) &&
2052 (rectClient.bottom == height || height == wxDefaultCoord) )
2053 {
2054 break;
2055 }
2056
2057 // Find the difference between the entire window (title bar and all)
2058 // and the client area; add this to the new client size to move the
2059 // window
2060 RECT rectWin;
2061 ::GetWindowRect(GetHwnd(), &rectWin);
2062
2063 const int widthWin = rectWin.right - rectWin.left,
2064 heightWin = rectWin.bottom - rectWin.top;
2065
2066 // MoveWindow positions the child windows relative to the parent, so
2067 // adjust if necessary
2068 if ( !IsTopLevel() )
2069 {
2070 wxWindow *parent = GetParent();
2071 if ( parent )
2072 {
2073 ::ScreenToClient(GetHwndOf(parent), (POINT *)&rectWin);
2074 }
2075 }
2076
2077 // don't call DoMoveWindow() because we want to move window immediately
2078 // and not defer it here as otherwise the value returned by
2079 // GetClient/WindowRect() wouldn't change as the window wouldn't be
2080 // really resized
2081 if ( !::MoveWindow(GetHwnd(),
2082 rectWin.left,
2083 rectWin.top,
2084 width + widthWin - rectClient.right,
2085 height + heightWin - rectClient.bottom,
2086 TRUE) )
2087 {
2088 wxLogLastError(_T("MoveWindow"));
2089 }
2090 }
2091 }
2092
2093 // ---------------------------------------------------------------------------
2094 // text metrics
2095 // ---------------------------------------------------------------------------
2096
2097 int wxWindowMSW::GetCharHeight() const
2098 {
2099 return wxGetTextMetrics(this).tmHeight;
2100 }
2101
2102 int wxWindowMSW::GetCharWidth() const
2103 {
2104 // +1 is needed because Windows apparently adds it when calculating the
2105 // dialog units size in pixels
2106 #if wxDIALOG_UNIT_COMPATIBILITY
2107 return wxGetTextMetrics(this).tmAveCharWidth;
2108 #else
2109 return wxGetTextMetrics(this).tmAveCharWidth + 1;
2110 #endif
2111 }
2112
2113 void wxWindowMSW::GetTextExtent(const wxString& string,
2114 int *x, int *y,
2115 int *descent, int *externalLeading,
2116 const wxFont *theFont) const
2117 {
2118 wxASSERT_MSG( !theFont || theFont->Ok(),
2119 _T("invalid font in GetTextExtent()") );
2120
2121 wxFont fontToUse;
2122 if (theFont)
2123 fontToUse = *theFont;
2124 else
2125 fontToUse = GetFont();
2126
2127 WindowHDC hdc(GetHwnd());
2128 SelectInHDC selectFont(hdc, GetHfontOf(fontToUse));
2129
2130 SIZE sizeRect;
2131 TEXTMETRIC tm;
2132 ::GetTextExtentPoint32(hdc, string, string.length(), &sizeRect);
2133 GetTextMetrics(hdc, &tm);
2134
2135 if ( x )
2136 *x = sizeRect.cx;
2137 if ( y )
2138 *y = sizeRect.cy;
2139 if ( descent )
2140 *descent = tm.tmDescent;
2141 if ( externalLeading )
2142 *externalLeading = tm.tmExternalLeading;
2143 }
2144
2145 // ---------------------------------------------------------------------------
2146 // popup menu
2147 // ---------------------------------------------------------------------------
2148
2149 #if wxUSE_MENUS_NATIVE
2150
2151 // yield for WM_COMMAND events only, i.e. process all WM_COMMANDs in the queue
2152 // immediately, without waiting for the next event loop iteration
2153 //
2154 // NB: this function should probably be made public later as it can almost
2155 // surely replace wxYield() elsewhere as well
2156 static void wxYieldForCommandsOnly()
2157 {
2158 // peek all WM_COMMANDs (it will always return WM_QUIT too but we don't
2159 // want to process it here)
2160 MSG msg;
2161 while ( ::PeekMessage(&msg, (HWND)0, WM_COMMAND, WM_COMMAND, PM_REMOVE) )
2162 {
2163 if ( msg.message == WM_QUIT )
2164 {
2165 // if we retrieved a WM_QUIT, insert back into the message queue.
2166 ::PostQuitMessage(0);
2167 break;
2168 }
2169
2170 // luckily (as we don't have access to wxEventLoopImpl method from here
2171 // anyhow...) we don't need to pre process WM_COMMANDs so dispatch it
2172 // immediately
2173 ::TranslateMessage(&msg);
2174 ::DispatchMessage(&msg);
2175 }
2176 }
2177
2178 bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y)
2179 {
2180 menu->SetInvokingWindow(this);
2181 menu->UpdateUI();
2182
2183 if ( x == wxDefaultCoord && y == wxDefaultCoord )
2184 {
2185 wxPoint mouse = ScreenToClient(wxGetMousePosition());
2186 x = mouse.x; y = mouse.y;
2187 }
2188
2189 HWND hWnd = GetHwnd();
2190 HMENU hMenu = GetHmenuOf(menu);
2191 POINT point;
2192 point.x = x;
2193 point.y = y;
2194 ::ClientToScreen(hWnd, &point);
2195 wxCurrentPopupMenu = menu;
2196 #if defined(__WXWINCE__)
2197 static const UINT flags = 0;
2198 #else // !__WXWINCE__
2199 UINT flags = TPM_RIGHTBUTTON;
2200 // NT4 doesn't support TPM_RECURSE and simply doesn't show the menu at all
2201 // when it's use, I'm not sure about Win95/98 but prefer to err on the safe
2202 // side and not to use it there neither -- modify the test if it does work
2203 // on these systems
2204 if ( wxGetWinVersion() >= wxWinVersion_5 )
2205 {
2206 // using TPM_RECURSE allows us to show a popup menu while another menu
2207 // is opened which can be useful and is supported by the other
2208 // platforms, so allow it under Windows too
2209 flags |= TPM_RECURSE;
2210 }
2211 #endif // __WXWINCE__/!__WXWINCE__
2212
2213 ::TrackPopupMenu(hMenu, flags, point.x, point.y, 0, hWnd, NULL);
2214
2215 // we need to do it right now as otherwise the events are never going to be
2216 // sent to wxCurrentPopupMenu from HandleCommand()
2217 //
2218 // note that even eliminating (ugly) wxCurrentPopupMenu global wouldn't
2219 // help and we'd still need wxYieldForCommandsOnly() as the menu may be
2220 // destroyed as soon as we return (it can be a local variable in the caller
2221 // for example) and so we do need to process the event immediately
2222 wxYieldForCommandsOnly();
2223
2224 wxCurrentPopupMenu = NULL;
2225
2226 menu->SetInvokingWindow(NULL);
2227
2228 return true;
2229 }
2230
2231 #endif // wxUSE_MENUS_NATIVE
2232
2233 // ===========================================================================
2234 // pre/post message processing
2235 // ===========================================================================
2236
2237 WXLRESULT wxWindowMSW::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
2238 {
2239 if ( m_oldWndProc )
2240 return ::CallWindowProc(CASTWNDPROC m_oldWndProc, GetHwnd(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam);
2241 else
2242 return ::DefWindowProc(GetHwnd(), nMsg, wParam, lParam);
2243 }
2244
2245 bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
2246 {
2247 // wxUniversal implements tab traversal itself
2248 #ifndef __WXUNIVERSAL__
2249 if ( m_hWnd != 0 && (GetWindowStyleFlag() & wxTAB_TRAVERSAL) )
2250 {
2251 // intercept dialog navigation keys
2252 MSG *msg = (MSG *)pMsg;
2253
2254 // here we try to do all the job which ::IsDialogMessage() usually does
2255 // internally
2256 if ( msg->message == WM_KEYDOWN )
2257 {
2258 bool bCtrlDown = wxIsCtrlDown();
2259 bool bShiftDown = wxIsShiftDown();
2260
2261 // WM_GETDLGCODE: ask the control if it wants the key for itself,
2262 // don't process it if it's the case (except for Ctrl-Tab/Enter
2263 // combinations which are always processed)
2264 LONG lDlgCode = ::SendMessage(msg->hwnd, WM_GETDLGCODE, 0, 0);
2265
2266 // surprizingly, DLGC_WANTALLKEYS bit mask doesn't contain the
2267 // DLGC_WANTTAB nor DLGC_WANTARROWS bits although, logically,
2268 // it, of course, implies them
2269 if ( lDlgCode & DLGC_WANTALLKEYS )
2270 {
2271 lDlgCode |= DLGC_WANTTAB | DLGC_WANTARROWS;
2272 }
2273
2274 bool bForward = true,
2275 bWindowChange = false,
2276 bFromTab = false;
2277
2278 // should we process this message specially?
2279 bool bProcess = true;
2280 switch ( msg->wParam )
2281 {
2282 case VK_TAB:
2283 if ( (lDlgCode & DLGC_WANTTAB) && !bCtrlDown )
2284 {
2285 // let the control have the TAB
2286 bProcess = false;
2287 }
2288 else // use it for navigation
2289 {
2290 // Ctrl-Tab cycles thru notebook pages
2291 bWindowChange = bCtrlDown;
2292 bForward = !bShiftDown;
2293 bFromTab = true;
2294 }
2295 break;
2296
2297 case VK_UP:
2298 case VK_LEFT:
2299 if ( (lDlgCode & DLGC_WANTARROWS) || bCtrlDown )
2300 bProcess = false;
2301 else
2302 bForward = false;
2303 break;
2304
2305 case VK_DOWN:
2306 case VK_RIGHT:
2307 if ( (lDlgCode & DLGC_WANTARROWS) || bCtrlDown )
2308 bProcess = false;
2309 break;
2310
2311 case VK_PRIOR:
2312 bForward = false;
2313 // fall through
2314
2315 case VK_NEXT:
2316 // we treat PageUp/Dn as arrows because chances are that
2317 // a control which needs arrows also needs them for
2318 // navigation (e.g. wxTextCtrl, wxListCtrl, ...)
2319 if ( (lDlgCode & DLGC_WANTARROWS) && !bCtrlDown )
2320 bProcess = false;
2321 else // OTOH Ctrl-PageUp/Dn works as [Shift-]Ctrl-Tab
2322 bWindowChange = true;
2323 break;
2324
2325 case VK_RETURN:
2326 {
2327 if ( (lDlgCode & DLGC_WANTMESSAGE) && !bCtrlDown )
2328 {
2329 // control wants to process Enter itself, don't
2330 // call IsDialogMessage() which would consume it
2331 return false;
2332 }
2333
2334 #if wxUSE_BUTTON
2335 // currently active button should get enter press even
2336 // if there is a default button elsewhere so check if
2337 // this window is a button first
2338 wxWindow *btn = NULL;
2339 if ( lDlgCode & DLGC_DEFPUSHBUTTON )
2340 {
2341 // let IsDialogMessage() handle this for all
2342 // buttons except the owner-drawn ones which it
2343 // just seems to ignore
2344 long style = ::GetWindowLong(msg->hwnd, GWL_STYLE);
2345 if ( (style & BS_OWNERDRAW) == BS_OWNERDRAW )
2346 {
2347 // emulate the button click
2348 btn = wxFindWinFromHandle((WXHWND)msg->hwnd);
2349 }
2350
2351 bProcess = false;
2352 }
2353 else // not a button itself, do we have default button?
2354 {
2355 wxTopLevelWindow *
2356 tlw = wxDynamicCast(wxGetTopLevelParent(this),
2357 wxTopLevelWindow);
2358 if ( tlw )
2359 {
2360 btn = wxDynamicCast(tlw->GetDefaultItem(),
2361 wxButton);
2362 }
2363 }
2364
2365 if ( btn && btn->IsEnabled() )
2366 {
2367 btn->MSWCommand(BN_CLICKED, 0 /* unused */);
2368 return true;
2369 }
2370
2371 #endif // wxUSE_BUTTON
2372
2373 #ifdef __WXWINCE__
2374 // map Enter presses into button presses on PDAs
2375 wxJoystickEvent event(wxEVT_JOY_BUTTON_DOWN);
2376 event.SetEventObject(this);
2377 if ( GetEventHandler()->ProcessEvent(event) )
2378 return true;
2379 #endif // __WXWINCE__
2380 }
2381 break;
2382
2383 default:
2384 bProcess = false;
2385 }
2386
2387 if ( bProcess )
2388 {
2389 wxNavigationKeyEvent event;
2390 event.SetDirection(bForward);
2391 event.SetWindowChange(bWindowChange);
2392 event.SetFromTab(bFromTab);
2393 event.SetEventObject(this);
2394
2395 if ( GetEventHandler()->ProcessEvent(event) )
2396 {
2397 // as we don't call IsDialogMessage(), which would take of
2398 // this by default, we need to manually send this message
2399 // so that controls can change their UI state if needed
2400 MSWUpdateUIState(UIS_CLEAR, UISF_HIDEFOCUS);
2401
2402 return true;
2403 }
2404 }
2405 }
2406
2407 if ( ::IsDialogMessage(GetHwnd(), msg) )
2408 {
2409 // IsDialogMessage() did something...
2410 return true;
2411 }
2412 }
2413 #endif // __WXUNIVERSAL__
2414
2415 #if wxUSE_TOOLTIPS
2416 if ( m_tooltip )
2417 {
2418 // relay mouse move events to the tooltip control
2419 MSG *msg = (MSG *)pMsg;
2420 if ( msg->message == WM_MOUSEMOVE )
2421 wxToolTip::RelayEvent(pMsg);
2422 }
2423 #endif // wxUSE_TOOLTIPS
2424
2425 return false;
2426 }
2427
2428 bool wxWindowMSW::MSWTranslateMessage(WXMSG* pMsg)
2429 {
2430 #if wxUSE_ACCEL && !defined(__WXUNIVERSAL__)
2431 return m_acceleratorTable.Translate(this, pMsg);
2432 #else
2433 (void) pMsg;
2434 return false;
2435 #endif // wxUSE_ACCEL
2436 }
2437
2438 bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* msg)
2439 {
2440 // all tests below have to deal with various bugs/misfeatures of
2441 // IsDialogMessage(): we have to prevent it from being called from our
2442 // MSWProcessMessage() in some situations
2443
2444 // don't let IsDialogMessage() get VK_ESCAPE as it _always_ eats the
2445 // message even when there is no cancel button and when the message is
2446 // needed by the control itself: in particular, it prevents the tree in
2447 // place edit control from being closed with Escape in a dialog
2448 if ( msg->message == WM_KEYDOWN && msg->wParam == VK_ESCAPE )
2449 {
2450 return false;
2451 }
2452
2453 // ::IsDialogMessage() is broken and may sometimes hang the application by
2454 // going into an infinite loop when it tries to find the control to give
2455 // focus to when Alt-<key> is pressed, so we try to detect [some of] the
2456 // situations when this may happen and not call it then
2457 if ( msg->message != WM_SYSCHAR )
2458 return true;
2459
2460 // assume we can call it by default
2461 bool canSafelyCallIsDlgMsg = true;
2462
2463 HWND hwndFocus = ::GetFocus();
2464
2465 // if the currently focused window itself has WS_EX_CONTROLPARENT style,
2466 // ::IsDialogMessage() will also enter an infinite loop, because it will
2467 // recursively check the child windows but not the window itself and so if
2468 // none of the children accepts focus it loops forever (as it only stops
2469 // when it gets back to the window it started from)
2470 //
2471 // while it is very unusual that a window with WS_EX_CONTROLPARENT
2472 // style has the focus, it can happen. One such possibility is if
2473 // all windows are either toplevel, wxDialog, wxPanel or static
2474 // controls and no window can actually accept keyboard input.
2475 #if !defined(__WXWINCE__)
2476 if ( ::GetWindowLong(hwndFocus, GWL_EXSTYLE) & WS_EX_CONTROLPARENT )
2477 {
2478 // pessimistic by default
2479 canSafelyCallIsDlgMsg = false;
2480 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
2481 node;
2482 node = node->GetNext() )
2483 {
2484 wxWindow * const win = node->GetData();
2485 if ( win->AcceptsFocus() &&
2486 !(::GetWindowLong(GetHwndOf(win), GWL_EXSTYLE) &
2487 WS_EX_CONTROLPARENT) )
2488 {
2489 // it shouldn't hang...
2490 canSafelyCallIsDlgMsg = true;
2491
2492 break;
2493 }
2494 }
2495 }
2496 #endif // !__WXWINCE__
2497
2498 if ( canSafelyCallIsDlgMsg )
2499 {
2500 // ::IsDialogMessage() can enter in an infinite loop when the
2501 // currently focused window is disabled or hidden and its
2502 // parent has WS_EX_CONTROLPARENT style, so don't call it in
2503 // this case
2504 while ( hwndFocus )
2505 {
2506 if ( !::IsWindowEnabled(hwndFocus) ||
2507 !::IsWindowVisible(hwndFocus) )
2508 {
2509 // it would enter an infinite loop if we do this!
2510 canSafelyCallIsDlgMsg = false;
2511
2512 break;
2513 }
2514
2515 if ( !(::GetWindowLong(hwndFocus, GWL_STYLE) & WS_CHILD) )
2516 {
2517 // it's a top level window, don't go further -- e.g. even
2518 // if the parent of a dialog is disabled, this doesn't
2519 // break navigation inside the dialog
2520 break;
2521 }
2522
2523 hwndFocus = ::GetParent(hwndFocus);
2524 }
2525 }
2526
2527 return canSafelyCallIsDlgMsg;
2528 }
2529
2530 // ---------------------------------------------------------------------------
2531 // message params unpackers
2532 // ---------------------------------------------------------------------------
2533
2534 void wxWindowMSW::UnpackCommand(WXWPARAM wParam, WXLPARAM lParam,
2535 WORD *id, WXHWND *hwnd, WORD *cmd)
2536 {
2537 *id = LOWORD(wParam);
2538 *hwnd = (WXHWND)lParam;
2539 *cmd = HIWORD(wParam);
2540 }
2541
2542 void wxWindowMSW::UnpackActivate(WXWPARAM wParam, WXLPARAM lParam,
2543 WXWORD *state, WXWORD *minimized, WXHWND *hwnd)
2544 {
2545 *state = LOWORD(wParam);
2546 *minimized = HIWORD(wParam);
2547 *hwnd = (WXHWND)lParam;
2548 }
2549
2550 void wxWindowMSW::UnpackScroll(WXWPARAM wParam, WXLPARAM lParam,
2551 WXWORD *code, WXWORD *pos, WXHWND *hwnd)
2552 {
2553 *code = LOWORD(wParam);
2554 *pos = HIWORD(wParam);
2555 *hwnd = (WXHWND)lParam;
2556 }
2557
2558 void wxWindowMSW::UnpackCtlColor(WXWPARAM wParam, WXLPARAM lParam,
2559 WXHDC *hdc, WXHWND *hwnd)
2560 {
2561 *hwnd = (WXHWND)lParam;
2562 *hdc = (WXHDC)wParam;
2563 }
2564
2565 void wxWindowMSW::UnpackMenuSelect(WXWPARAM wParam, WXLPARAM lParam,
2566 WXWORD *item, WXWORD *flags, WXHMENU *hmenu)
2567 {
2568 *item = (WXWORD)wParam;
2569 *flags = HIWORD(wParam);
2570 *hmenu = (WXHMENU)lParam;
2571 }
2572
2573 // ---------------------------------------------------------------------------
2574 // Main wxWidgets window proc and the window proc for wxWindow
2575 // ---------------------------------------------------------------------------
2576
2577 // Hook for new window just as it's being created, when the window isn't yet
2578 // associated with the handle
2579 static wxWindowMSW *gs_winBeingCreated = NULL;
2580
2581 // implementation of wxWindowCreationHook class: it just sets gs_winBeingCreated to the
2582 // window being created and insures that it's always unset back later
2583 wxWindowCreationHook::wxWindowCreationHook(wxWindowMSW *winBeingCreated)
2584 {
2585 gs_winBeingCreated = winBeingCreated;
2586 }
2587
2588 wxWindowCreationHook::~wxWindowCreationHook()
2589 {
2590 gs_winBeingCreated = NULL;
2591 }
2592
2593 // Main window proc
2594 LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
2595 {
2596 // trace all messages - useful for the debugging
2597 // PCSX2: Not really! Trace logging is shit slow, and is only really useful to devs of
2598 // wxWidgets itself so I disabled it. -- air
2599
2600 #if 0 //def __WXDEBUG__
2601 wxLogTrace(wxTraceMessages,
2602 wxT("Processing %s(hWnd=%08lx, wParam=%8lx, lParam=%8lx)"),
2603 wxGetMessageName(message), (long)hWnd, (long)wParam, lParam);
2604 #endif // __WXDEBUG__
2605
2606 wxWindowMSW *wnd = wxFindWinFromHandle((WXHWND) hWnd);
2607
2608 // when we get the first message for the HWND we just created, we associate
2609 // it with wxWindow stored in gs_winBeingCreated
2610 if ( !wnd && gs_winBeingCreated )
2611 {
2612 wxAssociateWinWithHandle(hWnd, gs_winBeingCreated);
2613 wnd = gs_winBeingCreated;
2614 gs_winBeingCreated = NULL;
2615 wnd->SetHWND((WXHWND)hWnd);
2616 }
2617
2618 LRESULT rc;
2619
2620 if ( wnd && wxEventLoop::AllowProcessing(wnd) )
2621 rc = wnd->MSWWindowProc(message, wParam, lParam);
2622 else
2623 rc = ::DefWindowProc(hWnd, message, wParam, lParam);
2624
2625 return rc;
2626 }
2627
2628 WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
2629 {
2630 // did we process the message?
2631 bool processed = false;
2632
2633 // the return value
2634 union
2635 {
2636 bool allow;
2637 WXLRESULT result;
2638 WXHBRUSH hBrush;
2639 } rc;
2640
2641 // for most messages we should return 0 when we do process the message
2642 rc.result = 0;
2643
2644 switch ( message )
2645 {
2646 case WM_CREATE:
2647 {
2648 bool mayCreate;
2649 processed = HandleCreate((WXLPCREATESTRUCT)lParam, &mayCreate);
2650 if ( processed )
2651 {
2652 // return 0 to allow window creation
2653 rc.result = mayCreate ? 0 : -1;
2654 }
2655 }
2656 break;
2657
2658 case WM_DESTROY:
2659 // never set processed to true and *always* pass WM_DESTROY to
2660 // DefWindowProc() as Windows may do some internal cleanup when
2661 // processing it and failing to pass the message along may cause
2662 // memory and resource leaks!
2663 (void)HandleDestroy();
2664 break;
2665
2666 case WM_SIZE:
2667 processed = HandleSize(LOWORD(lParam), HIWORD(lParam), wParam);
2668 break;
2669
2670 case WM_MOVE:
2671 processed = HandleMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
2672 break;
2673
2674 #if !defined(__WXWINCE__)
2675 case WM_MOVING:
2676 {
2677 LPRECT pRect = (LPRECT)lParam;
2678 wxRect rc;
2679 rc.SetLeft(pRect->left);
2680 rc.SetTop(pRect->top);
2681 rc.SetRight(pRect->right);
2682 rc.SetBottom(pRect->bottom);
2683 processed = HandleMoving(rc);
2684 if (processed) {
2685 pRect->left = rc.GetLeft();
2686 pRect->top = rc.GetTop();
2687 pRect->right = rc.GetRight();
2688 pRect->bottom = rc.GetBottom();
2689 }
2690 }
2691 break;
2692
2693 case WM_SIZING:
2694 {
2695 LPRECT pRect = (LPRECT)lParam;
2696 wxRect rc;
2697 rc.SetLeft(pRect->left);
2698 rc.SetTop(pRect->top);
2699 rc.SetRight(pRect->right);
2700 rc.SetBottom(pRect->bottom);
2701 processed = HandleSizing(rc);
2702 if (processed) {
2703 pRect->left = rc.GetLeft();
2704 pRect->top = rc.GetTop();
2705 pRect->right = rc.GetRight();
2706 pRect->bottom = rc.GetBottom();
2707 }
2708 }
2709 break;
2710 #endif // !__WXWINCE__
2711
2712 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
2713 case WM_ACTIVATEAPP:
2714 // This implicitly sends a wxEVT_ACTIVATE_APP event
2715 wxTheApp->SetActive(wParam != 0, FindFocus());
2716 break;
2717 #endif
2718
2719 case WM_ACTIVATE:
2720 {
2721 WXWORD state, minimized;
2722 WXHWND hwnd;
2723 UnpackActivate(wParam, lParam, &state, &minimized, &hwnd);
2724
2725 processed = HandleActivate(state, minimized != 0, (WXHWND)hwnd);
2726 }
2727 break;
2728
2729 case WM_SETFOCUS:
2730 processed = HandleSetFocus((WXHWND)(HWND)wParam);
2731 break;
2732
2733 case WM_KILLFOCUS:
2734 processed = HandleKillFocus((WXHWND)(HWND)wParam);
2735 break;
2736
2737 case WM_PRINTCLIENT:
2738 processed = HandlePrintClient((WXHDC)wParam);
2739 break;
2740
2741 case WM_PAINT:
2742 if ( wParam )
2743 {
2744 wxPaintDCEx dc((wxWindow *)this, (WXHDC)wParam);
2745
2746 processed = HandlePaint();
2747 }
2748 else // no DC given
2749 {
2750 processed = HandlePaint();
2751 }
2752 break;
2753
2754 case WM_CLOSE:
2755 #ifdef __WXUNIVERSAL__
2756 // Universal uses its own wxFrame/wxDialog, so we don't receive
2757 // close events unless we have this.
2758 Close();
2759 #endif // __WXUNIVERSAL__
2760
2761 // don't let the DefWindowProc() destroy our window - we'll do it
2762 // ourselves in ~wxWindow
2763 processed = true;
2764 rc.result = TRUE;
2765 break;
2766
2767 case WM_SHOWWINDOW:
2768 processed = HandleShow(wParam != 0, (int)lParam);
2769 break;
2770
2771 case WM_MOUSEMOVE:
2772 processed = HandleMouseMove(GET_X_LPARAM(lParam),
2773 GET_Y_LPARAM(lParam),
2774 wParam);
2775 break;
2776
2777 #ifdef HAVE_TRACKMOUSEEVENT
2778 case WM_MOUSELEAVE:
2779 // filter out excess WM_MOUSELEAVE events sent after PopupMenu()
2780 // (on XP at least)
2781 if ( m_mouseInWindow )
2782 {
2783 GenerateMouseLeave();
2784 }
2785
2786 // always pass processed back as false, this allows the window
2787 // manager to process the message too. This is needed to
2788 // ensure windows XP themes work properly as the mouse moves
2789 // over widgets like buttons. So don't set processed to true here.
2790 break;
2791 #endif // HAVE_TRACKMOUSEEVENT
2792
2793 #if wxUSE_MOUSEWHEEL
2794 case WM_MOUSEWHEEL:
2795 processed = HandleMouseWheel(wParam, lParam);
2796 break;
2797 #endif
2798
2799 case WM_LBUTTONDOWN:
2800 case WM_LBUTTONUP:
2801 case WM_LBUTTONDBLCLK:
2802 case WM_RBUTTONDOWN:
2803 case WM_RBUTTONUP:
2804 case WM_RBUTTONDBLCLK:
2805 case WM_MBUTTONDOWN:
2806 case WM_MBUTTONUP:
2807 case WM_MBUTTONDBLCLK:
2808 {
2809 #ifdef __WXMICROWIN__
2810 // MicroWindows seems to ignore the fact that a window is
2811 // disabled. So catch mouse events and throw them away if
2812 // necessary.
2813 wxWindowMSW* win = this;
2814 for ( ;; )
2815 {
2816 if (!win->IsEnabled())
2817 {
2818 processed = true;
2819 break;
2820 }
2821
2822 win = win->GetParent();
2823 if ( !win || win->IsTopLevel() )
2824 break;
2825 }
2826
2827 if ( processed )
2828 break;
2829
2830 #endif // __WXMICROWIN__
2831 int x = GET_X_LPARAM(lParam),
2832 y = GET_Y_LPARAM(lParam);
2833
2834 #ifdef __WXWINCE__
2835 // redirect the event to a static control if necessary by
2836 // finding one under mouse because under CE the static controls
2837 // don't generate mouse events (even with SS_NOTIFY)
2838 wxWindowMSW *win;
2839 if ( GetCapture() == this )
2840 {
2841 // but don't do it if the mouse is captured by this window
2842 // because then it should really get this event itself
2843 win = this;
2844 }
2845 else
2846 {
2847 win = FindWindowForMouseEvent(this, &x, &y);
2848
2849 // this should never happen
2850 wxCHECK_MSG( win, 0,
2851 _T("FindWindowForMouseEvent() returned NULL") );
2852 }
2853 #ifdef __POCKETPC__
2854 if (IsContextMenuEnabled() && message == WM_LBUTTONDOWN)
2855 {
2856 SHRGINFO shrgi = {0};
2857
2858 shrgi.cbSize = sizeof(SHRGINFO);
2859 shrgi.hwndClient = (HWND) GetHWND();
2860 shrgi.ptDown.x = x;
2861 shrgi.ptDown.y = y;
2862
2863 shrgi.dwFlags = SHRG_RETURNCMD;
2864 // shrgi.dwFlags = SHRG_NOTIFYPARENT;
2865
2866 if (GN_CONTEXTMENU == ::SHRecognizeGesture(&shrgi))
2867 {
2868 wxPoint pt(x, y);
2869 pt = ClientToScreen(pt);
2870
2871 wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt);
2872
2873 evtCtx.SetEventObject(this);
2874 if (GetEventHandler()->ProcessEvent(evtCtx))
2875 {
2876 processed = true;
2877 return true;
2878 }
2879 }
2880 }
2881 #endif
2882
2883 #else // !__WXWINCE__
2884 wxWindowMSW *win = this;
2885 #endif // __WXWINCE__/!__WXWINCE__
2886
2887 processed = win->HandleMouseEvent(message, x, y, wParam);
2888
2889 // if the app didn't eat the event, handle it in the default
2890 // way, that is by giving this window the focus
2891 if ( !processed )
2892 {
2893 // for the standard classes their WndProc sets the focus to
2894 // them anyhow and doing it from here results in some weird
2895 // problems, so don't do it for them (unnecessary anyhow)
2896 if ( !win->IsOfStandardClass() )
2897 {
2898 if ( message == WM_LBUTTONDOWN && win->AcceptsFocus() )
2899 win->SetFocus();
2900 }
2901 }
2902 }
2903 break;
2904
2905 #ifdef MM_JOY1MOVE
2906 case MM_JOY1MOVE:
2907 case MM_JOY2MOVE:
2908 case MM_JOY1ZMOVE:
2909 case MM_JOY2ZMOVE:
2910 case MM_JOY1BUTTONDOWN:
2911 case MM_JOY2BUTTONDOWN:
2912 case MM_JOY1BUTTONUP:
2913 case MM_JOY2BUTTONUP:
2914 processed = HandleJoystickEvent(message,
2915 GET_X_LPARAM(lParam),
2916 GET_Y_LPARAM(lParam),
2917 wParam);
2918 break;
2919 #endif // __WXMICROWIN__
2920
2921 case WM_COMMAND:
2922 {
2923 WORD id, cmd;
2924 WXHWND hwnd;
2925 UnpackCommand(wParam, lParam, &id, &hwnd, &cmd);
2926
2927 processed = HandleCommand(id, cmd, hwnd);
2928 }
2929 break;
2930
2931 case WM_NOTIFY:
2932 processed = HandleNotify((int)wParam, lParam, &rc.result);
2933 break;
2934
2935 // we only need to reply to WM_NOTIFYFORMAT manually when using MSLU,
2936 // otherwise DefWindowProc() does it perfectly fine for us, but MSLU
2937 // apparently doesn't always behave properly and needs some help
2938 #if wxUSE_UNICODE_MSLU && defined(NF_QUERY)
2939 case WM_NOTIFYFORMAT:
2940 if ( lParam == NF_QUERY )
2941 {
2942 processed = true;
2943 rc.result = NFR_UNICODE;
2944 }
2945 break;
2946 #endif // wxUSE_UNICODE_MSLU
2947
2948 // for these messages we must return true if process the message
2949 #ifdef WM_DRAWITEM
2950 case WM_DRAWITEM:
2951 case WM_MEASUREITEM:
2952 {
2953 int idCtrl = (UINT)wParam;
2954 if ( message == WM_DRAWITEM )
2955 {
2956 processed = MSWOnDrawItem(idCtrl,
2957 (WXDRAWITEMSTRUCT *)lParam);
2958 }
2959 else
2960 {
2961 processed = MSWOnMeasureItem(idCtrl,
2962 (WXMEASUREITEMSTRUCT *)lParam);
2963 }
2964
2965 if ( processed )
2966 rc.result = TRUE;
2967 }
2968 break;
2969 #endif // defined(WM_DRAWITEM)
2970
2971 case WM_GETDLGCODE:
2972 if ( !IsOfStandardClass() || HasFlag(wxWANTS_CHARS) )
2973 {
2974 // we always want to get the char events
2975 rc.result = DLGC_WANTCHARS;
2976
2977 if ( HasFlag(wxWANTS_CHARS) )
2978 {
2979 // in fact, we want everything
2980 rc.result |= DLGC_WANTARROWS |
2981 DLGC_WANTTAB |
2982 DLGC_WANTALLKEYS;
2983 }
2984
2985 processed = true;
2986 }
2987 //else: get the dlg code from the DefWindowProc()
2988 break;
2989
2990 case WM_SYSKEYDOWN:
2991 case WM_KEYDOWN:
2992 // If this has been processed by an event handler, return 0 now
2993 // (we've handled it).
2994 m_lastKeydownProcessed = HandleKeyDown((WORD) wParam, lParam);
2995 if ( m_lastKeydownProcessed )
2996 {
2997 processed = true;
2998 }
2999
3000 if ( !processed )
3001 {
3002 switch ( wParam )
3003 {
3004 // we consider these messages "not interesting" to OnChar, so
3005 // just don't do anything more with them
3006 case VK_SHIFT:
3007 case VK_CONTROL:
3008 case VK_MENU:
3009 case VK_CAPITAL:
3010 case VK_NUMLOCK:
3011 case VK_SCROLL:
3012 processed = true;
3013 break;
3014
3015 // avoid duplicate messages to OnChar for these ASCII keys:
3016 // they will be translated by TranslateMessage() and received
3017 // in WM_CHAR
3018 case VK_ESCAPE:
3019 case VK_SPACE:
3020 case VK_RETURN:
3021 case VK_BACK:
3022 case VK_TAB:
3023 case VK_ADD:
3024 case VK_SUBTRACT:
3025 case VK_MULTIPLY:
3026 case VK_DIVIDE:
3027 case VK_NUMPAD0:
3028 case VK_NUMPAD1:
3029 case VK_NUMPAD2:
3030 case VK_NUMPAD3:
3031 case VK_NUMPAD4:
3032 case VK_NUMPAD5:
3033 case VK_NUMPAD6:
3034 case VK_NUMPAD7:
3035 case VK_NUMPAD8:
3036 case VK_NUMPAD9:
3037 case VK_OEM_1:
3038 case VK_OEM_2:
3039 case VK_OEM_3:
3040 case VK_OEM_4:
3041 case VK_OEM_5:
3042 case VK_OEM_6:
3043 case VK_OEM_7:
3044 case VK_OEM_PLUS:
3045 case VK_OEM_COMMA:
3046 case VK_OEM_MINUS:
3047 case VK_OEM_PERIOD:
3048 // but set processed to false, not true to still pass them
3049 // to the control's default window proc - otherwise
3050 // built-in keyboard handling won't work
3051 processed = false;
3052 break;
3053
3054 #ifdef VK_APPS
3055 // special case of VK_APPS: treat it the same as right mouse
3056 // click because both usually pop up a context menu
3057 case VK_APPS:
3058 processed = HandleMouseEvent(WM_RBUTTONDOWN, -1, -1, 0);
3059 break;
3060 #endif // VK_APPS
3061
3062 default:
3063 // do generate a CHAR event
3064 processed = HandleChar((WORD)wParam, lParam);
3065 }
3066 }
3067 if (message == WM_SYSKEYDOWN) // Let Windows still handle the SYSKEYs
3068 processed = false;
3069 break;
3070
3071 case WM_SYSKEYUP:
3072 case WM_KEYUP:
3073 #ifdef VK_APPS
3074 // special case of VK_APPS: treat it the same as right mouse button
3075 if ( wParam == VK_APPS )
3076 {
3077 processed = HandleMouseEvent(WM_RBUTTONUP, -1, -1, 0);
3078 }
3079 else
3080 #endif // VK_APPS
3081 {
3082 processed = HandleKeyUp((WORD) wParam, lParam);
3083 }
3084 break;
3085
3086 case WM_SYSCHAR:
3087 case WM_CHAR: // Always an ASCII character
3088 if ( m_lastKeydownProcessed )
3089 {
3090 // The key was handled in the EVT_KEY_DOWN and handling
3091 // a key in an EVT_KEY_DOWN handler is meant, by
3092 // design, to prevent EVT_CHARs from happening
3093 m_lastKeydownProcessed = false;
3094 processed = true;
3095 }
3096 else
3097 {
3098 processed = HandleChar((WORD)wParam, lParam, true);
3099 }
3100 break;
3101
3102 #if wxUSE_HOTKEY
3103 case WM_HOTKEY:
3104 processed = HandleHotKey((WORD)wParam, lParam);
3105 break;
3106 #endif // wxUSE_HOTKEY
3107
3108 case WM_HSCROLL:
3109 case WM_VSCROLL:
3110 {
3111 WXWORD code, pos;
3112 WXHWND hwnd;
3113 UnpackScroll(wParam, lParam, &code, &pos, &hwnd);
3114
3115 processed = MSWOnScroll(message == WM_HSCROLL ? wxHORIZONTAL
3116 : wxVERTICAL,
3117 code, pos, hwnd);
3118 }
3119 break;
3120
3121 // CTLCOLOR messages are sent by children to query the parent for their
3122 // colors
3123 #ifndef __WXMICROWIN__
3124 case WM_CTLCOLORMSGBOX:
3125 case WM_CTLCOLOREDIT:
3126 case WM_CTLCOLORLISTBOX:
3127 case WM_CTLCOLORBTN:
3128 case WM_CTLCOLORDLG:
3129 case WM_CTLCOLORSCROLLBAR:
3130 case WM_CTLCOLORSTATIC:
3131 {
3132 WXHDC hdc;
3133 WXHWND hwnd;
3134 UnpackCtlColor(wParam, lParam, &hdc, &hwnd);
3135
3136 processed = HandleCtlColor(&rc.hBrush, (WXHDC)hdc, (WXHWND)hwnd);
3137 }
3138 break;
3139 #endif // !__WXMICROWIN__
3140
3141 case WM_SYSCOLORCHANGE:
3142 // the return value for this message is ignored
3143 processed = HandleSysColorChange();
3144 break;
3145
3146 #if !defined(__WXWINCE__)
3147 case WM_DISPLAYCHANGE:
3148 processed = HandleDisplayChange();
3149 break;
3150 #endif
3151
3152 case WM_PALETTECHANGED:
3153 processed = HandlePaletteChanged((WXHWND) (HWND) wParam);
3154 break;
3155
3156 case WM_CAPTURECHANGED:
3157 processed = HandleCaptureChanged((WXHWND) (HWND) lParam);
3158 break;
3159
3160 case WM_SETTINGCHANGE:
3161 processed = HandleSettingChange(wParam, lParam);
3162 break;
3163
3164 case WM_QUERYNEWPALETTE:
3165 processed = HandleQueryNewPalette();
3166 break;
3167
3168 case WM_ERASEBKGND:
3169 processed = HandleEraseBkgnd((WXHDC)(HDC)wParam);
3170 if ( processed )
3171 {
3172 // we processed the message, i.e. erased the background
3173 rc.result = TRUE;
3174 }
3175 break;
3176
3177 #if !defined(__WXWINCE__)
3178 case WM_DROPFILES:
3179 processed = HandleDropFiles(wParam);
3180 break;
3181 #endif
3182
3183 case WM_INITDIALOG:
3184 processed = HandleInitDialog((WXHWND)(HWND)wParam);
3185
3186 if ( processed )
3187 {
3188 // we never set focus from here
3189 rc.result = FALSE;
3190 }
3191 break;
3192
3193 #if !defined(__WXWINCE__)
3194 case WM_QUERYENDSESSION:
3195 processed = HandleQueryEndSession(lParam, &rc.allow);
3196 break;
3197
3198 case WM_ENDSESSION:
3199 processed = HandleEndSession(wParam != 0, lParam);
3200 break;
3201
3202 case WM_GETMINMAXINFO:
3203 processed = HandleGetMinMaxInfo((MINMAXINFO*)lParam);
3204 break;
3205 #endif
3206
3207 case WM_SETCURSOR:
3208 processed = HandleSetCursor((WXHWND)(HWND)wParam,
3209 LOWORD(lParam), // hit test
3210 HIWORD(lParam)); // mouse msg
3211
3212 if ( processed )
3213 {
3214 // returning TRUE stops the DefWindowProc() from further
3215 // processing this message - exactly what we need because we've
3216 // just set the cursor.
3217 rc.result = TRUE;
3218 }
3219 break;
3220
3221 #if wxUSE_ACCESSIBILITY
3222 case WM_GETOBJECT:
3223 {
3224 //WPARAM dwFlags = (WPARAM) (DWORD) wParam;
3225 LPARAM dwObjId = (LPARAM) (DWORD) lParam;
3226
3227 if (dwObjId == (LPARAM)OBJID_CLIENT && GetOrCreateAccessible())
3228 {
3229 return LresultFromObject(IID_IAccessible, wParam, (IUnknown*) GetAccessible()->GetIAccessible());
3230 }
3231 break;
3232 }
3233 #endif
3234
3235 #if defined(WM_HELP)
3236 case WM_HELP:
3237 {
3238 // by default, WM_HELP is propagated by DefWindowProc() upwards
3239 // to the window parent but as we do it ourselves already
3240 // (wxHelpEvent is derived from wxCommandEvent), we don't want
3241 // to get the other events if we process this message at all
3242 processed = true;
3243
3244 // WM_HELP doesn't use lParam under CE
3245 #ifndef __WXWINCE__
3246 HELPINFO* info = (HELPINFO*) lParam;
3247 if ( info->iContextType == HELPINFO_WINDOW )
3248 {
3249 #endif // !__WXWINCE__
3250 wxHelpEvent helpEvent
3251 (
3252 wxEVT_HELP,
3253 GetId(),
3254 #ifdef __WXWINCE__
3255 wxGetMousePosition() // what else?
3256 #else
3257 wxPoint(info->MousePos.x, info->MousePos.y)
3258 #endif
3259 );
3260
3261 helpEvent.SetEventObject(this);
3262 GetEventHandler()->ProcessEvent(helpEvent);
3263 #ifndef __WXWINCE__
3264 }
3265 else if ( info->iContextType == HELPINFO_MENUITEM )
3266 {
3267 wxHelpEvent helpEvent(wxEVT_HELP, info->iCtrlId);
3268 helpEvent.SetEventObject(this);
3269 GetEventHandler()->ProcessEvent(helpEvent);
3270
3271 }
3272 else // unknown help event?
3273 {
3274 processed = false;
3275 }
3276 #endif // !__WXWINCE__
3277 }
3278 break;
3279 #endif // WM_HELP
3280
3281 #if !defined(__WXWINCE__)
3282 case WM_CONTEXTMENU:
3283 {
3284 // we don't convert from screen to client coordinates as
3285 // the event may be handled by a parent window
3286 wxPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
3287
3288 wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt);
3289
3290 // we could have got an event from our child, reflect it back
3291 // to it if this is the case
3292 wxWindowMSW *win = NULL;
3293 if ( (WXHWND)wParam != m_hWnd )
3294 {
3295 win = FindItemByHWND((WXHWND)wParam);
3296 }
3297
3298 if ( !win )
3299 win = this;
3300
3301 evtCtx.SetEventObject(win);
3302 processed = win->GetEventHandler()->ProcessEvent(evtCtx);
3303 }
3304 break;
3305 #endif
3306
3307 case WM_MENUCHAR:
3308 // we're only interested in our own menus, not MF_SYSMENU
3309 if ( HIWORD(wParam) == MF_POPUP )
3310 {
3311 // handle menu chars for ownerdrawn menu items
3312 int i = HandleMenuChar(toupper(LOWORD(wParam)), lParam);
3313 if ( i != wxNOT_FOUND )
3314 {
3315 rc.result = MAKELRESULT(i, MNC_EXECUTE);
3316 processed = true;
3317 }
3318 }
3319 break;
3320
3321 #ifndef __WXWINCE__
3322 case WM_POWERBROADCAST:
3323 {
3324 bool vetoed;
3325 processed = HandlePower(wParam, lParam, &vetoed);
3326 rc.result = processed && vetoed ? BROADCAST_QUERY_DENY : TRUE;
3327 }
3328 break;
3329 #endif // __WXWINCE__
3330
3331 #if wxUSE_UXTHEME
3332 // If we want the default themed border then we need to draw it ourselves
3333 case WM_NCCALCSIZE:
3334 {
3335 wxUxThemeEngine* theme = wxUxThemeEngine::GetIfActive();
3336 if (theme && TranslateBorder(GetBorder()) == wxBORDER_THEME)
3337 {
3338 // first ask the widget to calculate the border size
3339 rc.result = MSWDefWindowProc(message, wParam, lParam);
3340 processed = true;
3341
3342 // now alter the client size making room for drawing a themed border
3343 NCCALCSIZE_PARAMS *csparam = NULL;
3344 RECT rect;
3345 if (wParam)
3346 {
3347 csparam = (NCCALCSIZE_PARAMS*)lParam;
3348 rect = csparam->rgrc[0];
3349 }
3350 else
3351 {
3352 rect = *((RECT*)lParam);
3353 }
3354 wxUxThemeHandle hTheme((const wxWindow*) this, L"EDIT");
3355 RECT rcClient = { 0, 0, 0, 0 };
3356 wxClientDC dc((wxWindow*) this);
3357
3358 if (theme->GetThemeBackgroundContentRect(
3359 hTheme, GetHdcOf(dc), EP_EDITTEXT, ETS_NORMAL,
3360 &rect, &rcClient) == S_OK)
3361 {
3362 InflateRect(&rcClient, -1, -1);
3363 if (wParam)
3364 csparam->rgrc[0] = rcClient;
3365 else
3366 *((RECT*)lParam) = rcClient;
3367 rc.result = WVR_REDRAW;
3368 }
3369 }
3370 }
3371 break;
3372
3373 case WM_NCPAINT:
3374 {
3375 wxUxThemeEngine* theme = wxUxThemeEngine::GetIfActive();
3376 if (theme && TranslateBorder(GetBorder()) == wxBORDER_THEME)
3377 {
3378 // first ask the widget to paint its non-client area, such as scrollbars, etc.
3379 rc.result = MSWDefWindowProc(message, wParam, lParam);
3380 processed = true;
3381
3382 wxUxThemeHandle hTheme((const wxWindow*) this, L"EDIT");
3383 wxWindowDC dc((wxWindow*) this);
3384
3385 // Clip the DC so that you only draw on the non-client area
3386 RECT rcBorder;
3387 wxCopyRectToRECT(GetSize(), rcBorder);
3388
3389 RECT rcClient;
3390 theme->GetThemeBackgroundContentRect(
3391 hTheme, GetHdcOf(dc), EP_EDITTEXT, ETS_NORMAL, &rcBorder, &rcClient);
3392 InflateRect(&rcClient, -1, -1);
3393
3394 ::ExcludeClipRect(GetHdcOf(dc), rcClient.left, rcClient.top,
3395 rcClient.right, rcClient.bottom);
3396
3397 // Make sure the background is in a proper state
3398 if (theme->IsThemeBackgroundPartiallyTransparent(hTheme, EP_EDITTEXT, ETS_NORMAL))
3399 {
3400 theme->DrawThemeParentBackground(GetHwnd(), GetHdcOf(dc), &rcBorder);
3401 }
3402
3403 // Draw the border
3404 int nState;
3405 if ( !IsEnabled() )
3406 nState = ETS_DISABLED;
3407 // should we check this?
3408 //else if ( ::GetWindowLong(GetHwnd(), GWL_STYLE) & ES_READONLY)
3409 // nState = ETS_READONLY;
3410 else
3411 nState = ETS_NORMAL;
3412 theme->DrawThemeBackground(hTheme, GetHdcOf(dc), EP_EDITTEXT, nState, &rcBorder, NULL);
3413 }
3414 }
3415 break;
3416
3417 #endif // wxUSE_UXTHEME
3418
3419 }
3420
3421 if ( !processed )
3422 {
3423 // PCSX2: Trace logging is shit slow, and is only really useful to devs of wxWidgets itself
3424 // so I disabled it. -- air
3425 #if 0 //def __WXDEBUG__
3426 wxLogTrace(wxTraceMessages, wxT("Forwarding %s to DefWindowProc."),
3427 wxGetMessageName(message));
3428 #endif // __WXDEBUG__
3429 rc.result = MSWDefWindowProc(message, wParam, lParam);
3430 }
3431
3432 return rc.result;
3433 }
3434
3435 // ----------------------------------------------------------------------------
3436 // wxWindow <-> HWND map
3437 // ----------------------------------------------------------------------------
3438
3439 wxWinHashTable *wxWinHandleHash = NULL;
3440
3441 wxWindow *wxFindWinFromHandle(WXHWND hWnd)
3442 {
3443 return (wxWindow*)wxWinHandleHash->Get((long)hWnd);
3444 }
3445
3446 void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win)
3447 {
3448 // adding NULL hWnd is (first) surely a result of an error and
3449 // (secondly) breaks menu command processing
3450 wxCHECK_RET( hWnd != (HWND)NULL,
3451 wxT("attempt to add a NULL hWnd to window list ignored") );
3452
3453 wxWindow *oldWin = wxFindWinFromHandle((WXHWND) hWnd);
3454 #ifdef __WXDEBUG__
3455 if ( oldWin && (oldWin != win) )
3456 {
3457 wxLogDebug(wxT("HWND %X already associated with another window (%s)"),
3458 (int) hWnd, win->GetClassInfo()->GetClassName());
3459 }
3460 else
3461 #endif // __WXDEBUG__
3462 if (!oldWin)
3463 {
3464 wxWinHandleHash->Put((long)hWnd, (wxWindow *)win);
3465 }
3466 }
3467
3468 void wxRemoveHandleAssociation(wxWindowMSW *win)
3469 {
3470 wxWinHandleHash->Delete((long)win->GetHWND());
3471 }
3472
3473 // ----------------------------------------------------------------------------
3474 // various MSW speciic class dependent functions
3475 // ----------------------------------------------------------------------------
3476
3477 // Default destroyer - override if you destroy it in some other way
3478 // (e.g. with MDI child windows)
3479 void wxWindowMSW::MSWDestroyWindow()
3480 {
3481 }
3482
3483 bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
3484 const wxSize& size,
3485 int& x, int& y,
3486 int& w, int& h) const
3487 {
3488 // yes, those are just some arbitrary hardcoded numbers
3489 static const int DEFAULT_Y = 200;
3490
3491 bool nonDefault = false;
3492
3493 if ( pos.x == wxDefaultCoord )
3494 {
3495 // if x is set to CW_USEDEFAULT, y parameter is ignored anyhow so we
3496 // can just as well set it to CW_USEDEFAULT as well
3497 x =
3498 y = CW_USEDEFAULT;
3499 }
3500 else
3501 {
3502 // OTOH, if x is not set to CW_USEDEFAULT, y shouldn't be set to it
3503 // neither because it is not handled as a special value by Windows then
3504 // and so we have to choose some default value for it
3505 x = pos.x;
3506 y = pos.y == wxDefaultCoord ? DEFAULT_Y : pos.y;
3507
3508 nonDefault = true;
3509 }
3510
3511 /*
3512 NB: there used to be some code here which set the initial size of the
3513 window to the client size of the parent if no explicit size was
3514 specified. This was wrong because wxWidgets programs often assume
3515 that they get a WM_SIZE (EVT_SIZE) upon creation, however this broke
3516 it. To see why, you should understand that Windows sends WM_SIZE from
3517 inside ::CreateWindow() anyhow. However, ::CreateWindow() is called
3518 from some base class ctor and so this WM_SIZE is not processed in the
3519 real class' OnSize() (because it's not fully constructed yet and the
3520 event goes to some base class OnSize() instead). So the WM_SIZE we
3521 rely on is the one sent when the parent frame resizes its children
3522 but here is the problem: if the child already has just the right
3523 size, nothing will happen as both wxWidgets and Windows check for
3524 this and ignore any attempts to change the window size to the size it
3525 already has - so no WM_SIZE would be sent.
3526 */
3527
3528
3529 // we don't use CW_USEDEFAULT here for several reasons:
3530 //
3531 // 1. it results in huge frames on modern screens (1000*800 is not
3532 // uncommon on my 1280*1024 screen) which is way too big for a half
3533 // empty frame of most of wxWidgets samples for example)
3534 //
3535 // 2. it is buggy for frames with wxFRAME_TOOL_WINDOW style for which
3536 // the default is for whatever reason 8*8 which breaks client <->
3537 // window size calculations (it would be nice if it didn't, but it
3538 // does and the simplest way to fix it seemed to change the broken
3539 // default size anyhow)
3540 //
3541 // 3. there is just no advantage in doing it: with x and y it is
3542 // possible that [future versions of] Windows position the new top
3543 // level window in some smart way which we can't do, but we can
3544 // guess a reasonably good size for a new window just as well
3545 // ourselves
3546
3547 // However, on PocketPC devices, we must use the default
3548 // size if possible.
3549 #ifdef _WIN32_WCE
3550 if (size.x == wxDefaultCoord)
3551 w = CW_USEDEFAULT;
3552 else
3553 w = size.x;
3554 if (size.y == wxDefaultCoord)
3555 h = CW_USEDEFAULT;
3556 else
3557 h = size.y;
3558 #else
3559 if ( size.x == wxDefaultCoord || size.y == wxDefaultCoord)
3560 {
3561 nonDefault = true;
3562 }
3563 w = WidthDefault(size.x);
3564 h = HeightDefault(size.y);
3565 #endif
3566
3567 AdjustForParentClientOrigin(x, y);
3568
3569 return nonDefault;
3570 }
3571
3572 WXHWND wxWindowMSW::MSWGetParent() const
3573 {
3574 return m_parent ? m_parent->GetHWND() : WXHWND(NULL);
3575 }
3576
3577 bool wxWindowMSW::MSWCreate(const wxChar *wclass,
3578 const wxChar *title,
3579 const wxPoint& pos,
3580 const wxSize& size,
3581 WXDWORD style,
3582 WXDWORD extendedStyle)
3583 {
3584 // choose the position/size for the new window
3585 int x, y, w, h;
3586 (void)MSWGetCreateWindowCoords(pos, size, x, y, w, h);
3587
3588 // controlId is menu handle for the top level windows, so set it to 0
3589 // unless we're creating a child window
3590 int controlId = style & WS_CHILD ? GetId() : 0;
3591
3592 // for each class "Foo" we have we also have "FooNR" ("no repaint") class
3593 // which is the same but without CS_[HV]REDRAW class styles so using it
3594 // ensures that the window is not fully repainted on each resize
3595 wxString className(wclass);
3596 if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) )
3597 {
3598 className += wxT("NR");
3599 }
3600
3601 // do create the window
3602 wxWindowCreationHook hook(this);
3603
3604 m_hWnd = (WXHWND)::CreateWindowEx
3605 (
3606 extendedStyle,
3607 className,
3608 title ? title : m_windowName.c_str(),
3609 style,
3610 x, y, w, h,
3611 (HWND)MSWGetParent(),
3612 (HMENU)controlId,
3613 wxGetInstance(),
3614 NULL // no extra data
3615 );
3616
3617 if ( !m_hWnd )
3618 {
3619 wxLogSysError(_("Can't create window of class %s"), className.c_str());
3620
3621 return false;
3622 }
3623
3624 SubclassWin(m_hWnd);
3625
3626 return true;
3627 }
3628
3629 // ===========================================================================
3630 // MSW message handlers
3631 // ===========================================================================
3632
3633 // ---------------------------------------------------------------------------
3634 // WM_NOTIFY
3635 // ---------------------------------------------------------------------------
3636
3637 bool wxWindowMSW::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
3638 {
3639 #ifndef __WXMICROWIN__
3640 LPNMHDR hdr = (LPNMHDR)lParam;
3641 HWND hWnd = hdr->hwndFrom;
3642 wxWindow *win = wxFindWinFromHandle((WXHWND)hWnd);
3643
3644 // if the control is one of our windows, let it handle the message itself
3645 if ( win )
3646 {
3647 return win->MSWOnNotify(idCtrl, lParam, result);
3648 }
3649
3650 // VZ: why did we do it? normally this is unnecessary and, besides, it
3651 // breaks the message processing for the toolbars because the tooltip
3652 // notifications were being forwarded to the toolbar child controls
3653 // (if it had any) before being passed to the toolbar itself, so in my
3654 // example the tooltip for the combobox was always shown instead of the
3655 // correct button tooltips
3656 #if 0
3657 // try all our children
3658 wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
3659 while ( node )
3660 {
3661 wxWindow *child = node->GetData();
3662 if ( child->MSWOnNotify(idCtrl, lParam, result) )
3663 {
3664 return true;
3665 }
3666
3667 node = node->GetNext();
3668 }
3669 #endif // 0
3670
3671 // by default, handle it ourselves
3672 return MSWOnNotify(idCtrl, lParam, result);
3673 #else // __WXMICROWIN__
3674 return false;
3675 #endif
3676 }
3677
3678 #if wxUSE_TOOLTIPS
3679
3680 bool wxWindowMSW::HandleTooltipNotify(WXUINT code,
3681 WXLPARAM lParam,
3682 const wxString& ttip)
3683 {
3684 // I don't know why it happens, but the versions of comctl32.dll starting
3685 // from 4.70 sometimes send TTN_NEEDTEXTW even to ANSI programs (normally,
3686 // this message is supposed to be sent to Unicode programs only) -- hence
3687 // we need to handle it as well, otherwise no tooltips will be shown in
3688 // this case
3689 #ifndef __WXWINCE__
3690 if ( !(code == (WXUINT) TTN_NEEDTEXTA || code == (WXUINT) TTN_NEEDTEXTW)
3691 || ttip.empty() )
3692 {
3693 // not a tooltip message or no tooltip to show anyhow
3694 return false;
3695 }
3696 #endif
3697
3698 LPTOOLTIPTEXT ttText = (LPTOOLTIPTEXT)lParam;
3699
3700 // We don't want to use the szText buffer because it has a limit of 80
3701 // bytes and this is not enough, especially for Unicode build where it
3702 // limits the tooltip string length to only 40 characters
3703 //
3704 // The best would be, of course, to not impose any length limitations at
3705 // all but then the buffer would have to be dynamic and someone would have
3706 // to free it and we don't have the tooltip owner object here any more, so
3707 // for now use our own static buffer with a higher fixed max length.
3708 //
3709 // Note that using a static buffer should not be a problem as only a single
3710 // tooltip can be shown at the same time anyhow.
3711 #if !wxUSE_UNICODE
3712 if ( code == (WXUINT) TTN_NEEDTEXTW )
3713 {
3714 // We need to convert tooltip from multi byte to Unicode on the fly.
3715 static wchar_t buf[513];
3716
3717 // Truncate tooltip length if needed as otherwise we might not have
3718 // enough space for it in the buffer and MultiByteToWideChar() would
3719 // return an error
3720 size_t tipLength = wxMin(ttip.length(), WXSIZEOF(buf) - 1);
3721
3722 // Convert to WideChar without adding the NULL character. The NULL
3723 // character is added afterwards (this is more efficient).
3724 int len = ::MultiByteToWideChar
3725 (
3726 CP_ACP,
3727 0, // no flags
3728 ttip,
3729 tipLength,
3730 buf,
3731 WXSIZEOF(buf) - 1
3732 );
3733
3734 if ( !len )
3735 {
3736 wxLogLastError(_T("MultiByteToWideChar()"));
3737 }
3738
3739 buf[len] = L'\0';
3740 ttText->lpszText = (LPSTR) buf;
3741 }
3742 else // TTN_NEEDTEXTA
3743 #endif // !wxUSE_UNICODE
3744 {
3745 // we get here if we got TTN_NEEDTEXTA (only happens in ANSI build) or
3746 // if we got TTN_NEEDTEXTW in Unicode build: in this case we just have
3747 // to copy the string we have into the buffer
3748 static wxChar buf[513];
3749 wxStrncpy(buf, ttip.c_str(), WXSIZEOF(buf) - 1);
3750 buf[WXSIZEOF(buf) - 1] = _T('\0');
3751 ttText->lpszText = buf;
3752 }
3753
3754 return true;
3755 }
3756
3757 #endif // wxUSE_TOOLTIPS
3758
3759 bool wxWindowMSW::MSWOnNotify(int WXUNUSED(idCtrl),
3760 WXLPARAM lParam,
3761 WXLPARAM* WXUNUSED(result))
3762 {
3763 #if wxUSE_TOOLTIPS
3764 if ( m_tooltip )
3765 {
3766 NMHDR* hdr = (NMHDR *)lParam;
3767 if ( HandleTooltipNotify(hdr->code, lParam, m_tooltip->GetTip()))
3768 {
3769 // processed
3770 return true;
3771 }
3772 }
3773 #else
3774 wxUnusedVar(lParam);
3775 #endif // wxUSE_TOOLTIPS
3776
3777 return false;
3778 }
3779
3780 // ---------------------------------------------------------------------------
3781 // end session messages
3782 // ---------------------------------------------------------------------------
3783
3784 bool wxWindowMSW::HandleQueryEndSession(long logOff, bool *mayEnd)
3785 {
3786 #ifdef ENDSESSION_LOGOFF
3787 wxCloseEvent event(wxEVT_QUERY_END_SESSION, wxID_ANY);
3788 event.SetEventObject(wxTheApp);
3789 event.SetCanVeto(true);
3790 event.SetLoggingOff(logOff == (long)ENDSESSION_LOGOFF);
3791
3792 bool rc = wxTheApp->ProcessEvent(event);
3793