+ const HWND hwnd = GetHwnd();
+ wxCHECK_RET( hwnd, _T("layout direction must be set after window creation") );
+
+ LONG styleOld = ::GetWindowLong(hwnd, GWL_EXSTYLE);
+
+ LONG styleNew = styleOld;
+ switch ( dir )
+ {
+ case wxLayout_LeftToRight:
+ styleNew &= ~WS_EX_LAYOUTRTL;
+ break;
+
+ case wxLayout_RightToLeft:
+ styleNew |= WS_EX_LAYOUTRTL;
+ break;
+
+ default:
+ wxFAIL_MSG(_T("unsupported layout direction"));
+ break;
+ }
+
+ if ( styleNew != styleOld )
+ {
+ ::SetWindowLong(hwnd, GWL_EXSTYLE, styleNew);
+ }
+#endif
+}
+
+wxLayoutDirection wxWindowMSW::GetLayoutDirection() const
+{
+#ifdef __WXWINCE__
+ return wxLayout_Default;
+#else
+ const HWND hwnd = GetHwnd();
+ wxCHECK_MSG( hwnd, wxLayout_Default, _T("invalid window") );
+
+ return ::GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_LAYOUTRTL
+ ? wxLayout_RightToLeft
+ : wxLayout_LeftToRight;
+#endif
+}
+
+wxCoord
+wxWindowMSW::AdjustForLayoutDirection(wxCoord x,
+ wxCoord WXUNUSED(width),
+ wxCoord WXUNUSED(widthTotal)) const
+{
+ // Win32 mirrors the coordinates of RTL windows automatically, so don't
+ // redo it ourselves
+ return x;
+}
+
+// ---------------------------------------------------------------------------
+// subclassing
+// ---------------------------------------------------------------------------
+
+void wxWindowMSW::SubclassWin(WXHWND hWnd)
+{
+ wxASSERT_MSG( !m_oldWndProc, wxT("subclassing window twice?") );
+
+ HWND hwnd = (HWND)hWnd;
+ wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in SubclassWin") );
+
+ wxAssociateWinWithHandle(hwnd, this);
+
+ m_oldWndProc = (WXFARPROC)wxGetWindowProc((HWND)hWnd);
+
+ // we don't need to subclass the window of our own class (in the Windows
+ // sense of the word)
+ if ( !wxCheckWindowWndProc(hWnd, (WXFARPROC)wxWndProc) )
+ {
+ wxSetWindowProc(hwnd, wxWndProc);
+ }
+ else
+ {
+ // don't bother restoring it either: this also makes it easy to
+ // implement IsOfStandardClass() method which returns true for the
+ // standard controls and false for the wxWidgets own windows as it can
+ // simply check m_oldWndProc
+ m_oldWndProc = NULL;
+ }
+
+ // we're officially created now, send the event
+ wxWindowCreateEvent event((wxWindow *)this);
+ (void)GetEventHandler()->ProcessEvent(event);
+}
+
+void wxWindowMSW::UnsubclassWin()
+{
+ wxRemoveHandleAssociation(this);
+
+ // Restore old Window proc
+ HWND hwnd = GetHwnd();
+ if ( hwnd )
+ {
+ SetHWND(0);
+
+ wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in UnsubclassWin") );
+
+ if ( m_oldWndProc )
+ {
+ if ( !wxCheckWindowWndProc((WXHWND)hwnd, m_oldWndProc) )
+ {
+ wxSetWindowProc(hwnd, (WNDPROC)m_oldWndProc);
+ }
+
+ m_oldWndProc = NULL;
+ }
+ }
+}
+
+void wxWindowMSW::AssociateHandle(WXWidget handle)
+{
+ if ( m_hWnd )
+ {
+ if ( !::DestroyWindow(GetHwnd()) )
+ wxLogLastError(wxT("DestroyWindow"));
+ }
+
+ WXHWND wxhwnd = (WXHWND)handle;
+
+ SetHWND(wxhwnd);
+ SubclassWin(wxhwnd);
+}
+
+void wxWindowMSW::DissociateHandle()
+{
+ // this also calls SetHWND(0) for us
+ UnsubclassWin();
+}
+
+
+bool wxCheckWindowWndProc(WXHWND hWnd,
+ WXFARPROC WXUNUSED(wndProc))
+{
+// TODO: This list of window class names should be factored out so they can be
+// managed in one place and then accessed from here and other places, such as
+// wxApp::RegisterWindowClasses() and wxApp::UnregisterWindowClasses()
+
+#ifdef __WXWINCE__
+ extern wxChar *wxCanvasClassName;
+ extern wxChar *wxCanvasClassNameNR;
+#else
+ extern const wxChar *wxCanvasClassName;
+ extern const wxChar *wxCanvasClassNameNR;
+#endif
+ extern const wxChar *wxMDIFrameClassName;
+ extern const wxChar *wxMDIFrameClassNameNoRedraw;
+ extern const wxChar *wxMDIChildFrameClassName;
+ extern const wxChar *wxMDIChildFrameClassNameNoRedraw;
+ wxString str(wxGetWindowClass(hWnd));
+ if (str == wxCanvasClassName ||
+ str == wxCanvasClassNameNR ||
+#if wxUSE_GLCANVAS
+ str == _T("wxGLCanvasClass") ||
+ str == _T("wxGLCanvasClassNR") ||
+#endif // wxUSE_GLCANVAS
+ str == wxMDIFrameClassName ||
+ str == wxMDIFrameClassNameNoRedraw ||
+ str == wxMDIChildFrameClassName ||
+ str == wxMDIChildFrameClassNameNoRedraw ||
+ str == _T("wxTLWHiddenParent"))
+ return true; // Effectively means don't subclass
+ else
+ return false;
+}
+
+// ----------------------------------------------------------------------------
+// Style handling
+// ----------------------------------------------------------------------------
+
+void wxWindowMSW::SetWindowStyleFlag(long flags)
+{
+ long flagsOld = GetWindowStyleFlag();
+ if ( flags == flagsOld )
+ return;
+
+ // update the internal variable
+ wxWindowBase::SetWindowStyleFlag(flags);
+
+ // and the real window flags
+ MSWUpdateStyle(flagsOld, GetExtraStyle());
+}
+
+void wxWindowMSW::SetExtraStyle(long exflags)
+{
+ long exflagsOld = GetExtraStyle();
+ if ( exflags == exflagsOld )
+ return;
+
+ // update the internal variable
+ wxWindowBase::SetExtraStyle(exflags);
+
+ // and the real window flags
+ MSWUpdateStyle(GetWindowStyleFlag(), exflagsOld);
+}
+
+void wxWindowMSW::MSWUpdateStyle(long flagsOld, long exflagsOld)
+{
+ // now update the Windows style as well if needed - and if the window had
+ // been already created
+ if ( !GetHwnd() )
+ return;
+
+ // we may need to call SetWindowPos() when we change some styles
+ bool callSWP = false;
+
+ WXDWORD exstyle;
+ long style = MSWGetStyle(GetWindowStyleFlag(), &exstyle);
+
+ // this is quite a horrible hack but we need it because MSWGetStyle()
+ // doesn't take exflags as parameter but uses GetExtraStyle() internally
+ // and so we have to modify the window exflags temporarily to get the
+ // correct exstyleOld
+ long exflagsNew = GetExtraStyle();
+ wxWindowBase::SetExtraStyle(exflagsOld);
+
+ WXDWORD exstyleOld;
+ long styleOld = MSWGetStyle(flagsOld, &exstyleOld);
+
+ wxWindowBase::SetExtraStyle(exflagsNew);
+
+
+ if ( style != styleOld )
+ {
+ // some flags (e.g. WS_VISIBLE or WS_DISABLED) should not be changed by
+ // this function so instead of simply setting the style to the new
+ // value we clear the bits which were set in styleOld but are set in
+ // the new one and set the ones which were not set before
+ long styleReal = ::GetWindowLong(GetHwnd(), GWL_STYLE);
+ styleReal &= ~styleOld;
+ styleReal |= style;
+
+ ::SetWindowLong(GetHwnd(), GWL_STYLE, styleReal);
+
+ // we need to call SetWindowPos() if any of the styles affecting the
+ // frame appearance have changed
+ callSWP = ((styleOld ^ style ) & (WS_BORDER |
+ WS_THICKFRAME |
+ WS_CAPTION |
+ WS_DLGFRAME |
+ WS_MAXIMIZEBOX |
+ WS_MINIMIZEBOX |
+ WS_SYSMENU) ) != 0;
+ }
+
+ // and the extended style
+ long exstyleReal = ::GetWindowLong(GetHwnd(), GWL_EXSTYLE);
+
+ if ( exstyle != exstyleOld )
+ {
+ exstyleReal &= ~exstyleOld;
+ exstyleReal |= exstyle;
+
+ ::SetWindowLong(GetHwnd(), GWL_EXSTYLE, exstyleReal);
+
+ // ex style changes don't take effect without calling SetWindowPos
+ callSWP = true;
+ }
+
+ if ( callSWP )
+ {
+ // we must call SetWindowPos() to flush the cached extended style and
+ // also to make the change to wxSTAY_ON_TOP style take effect: just
+ // setting the style simply doesn't work
+ if ( !::SetWindowPos(GetHwnd(),
+ exstyleReal & WS_EX_TOPMOST ? HWND_TOPMOST
+ : HWND_NOTOPMOST,
+ 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED) )
+ {
+ wxLogLastError(_T("SetWindowPos"));
+ }
+ }
+}
+
+WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const
+{
+ // translate common wxWidgets styles to Windows ones
+
+ // most of windows are child ones, those which are not (such as
+ // wxTopLevelWindow) should remove WS_CHILD in their MSWGetStyle()
+ WXDWORD style = WS_CHILD;
+
+ // using this flag results in very significant reduction in flicker,
+ // especially with controls inside the static boxes (as the interior of the
+ // box is not redrawn twice), but sometimes results in redraw problems, so
+ // optionally allow the old code to continue to use it provided a special
+ // system option is turned on
+ if ( !wxSystemOptions::GetOptionInt(wxT("msw.window.no-clip-children"))
+ || (flags & wxCLIP_CHILDREN) )
+ style |= WS_CLIPCHILDREN;
+
+ // it doesn't seem useful to use WS_CLIPSIBLINGS here as we officially
+ // don't support overlapping windows and it only makes sense for them and,
+ // presumably, gives the system some extra work (to manage more clipping
+ // regions), so avoid it alltogether
+
+
+ if ( flags & wxVSCROLL )
+ style |= WS_VSCROLL;
+
+ if ( flags & wxHSCROLL )
+ style |= WS_HSCROLL;
+
+ const wxBorder border = GetBorder(flags);
+
+ // WS_BORDER is only required for wxBORDER_SIMPLE
+ if ( border == wxBORDER_SIMPLE )
+ style |= WS_BORDER;
+
+ // now deal with ext style if the caller wants it
+ if ( exstyle )
+ {
+ *exstyle = 0;
+
+#ifndef __WXWINCE__
+ if ( flags & wxTRANSPARENT_WINDOW )
+ *exstyle |= WS_EX_TRANSPARENT;
+#endif
+
+ switch ( border )
+ {
+ default:
+ case wxBORDER_DEFAULT:
+ wxFAIL_MSG( _T("unknown border style") );
+ // fall through
+
+ case wxBORDER_NONE:
+ case wxBORDER_SIMPLE:
+ break;
+
+ case wxBORDER_STATIC:
+ *exstyle |= WS_EX_STATICEDGE;
+ break;
+
+ case wxBORDER_RAISED:
+ *exstyle |= WS_EX_DLGMODALFRAME;
+ break;
+
+ case wxBORDER_SUNKEN:
+ *exstyle |= WS_EX_CLIENTEDGE;
+ style &= ~WS_BORDER;
+ break;
+
+ case wxBORDER_DOUBLE:
+ *exstyle |= WS_EX_DLGMODALFRAME;
+ break;
+ }
+
+ // wxUniv doesn't use Windows dialog navigation functions at all
+#if !defined(__WXUNIVERSAL__) && !defined(__WXWINCE__)
+ // to make the dialog navigation work with the nested panels we must
+ // use this style (top level windows such as dialogs don't need it)
+ if ( (flags & wxTAB_TRAVERSAL) && !IsTopLevel() )
+ {
+ *exstyle |= WS_EX_CONTROLPARENT;
+ }
+#endif // __WXUNIVERSAL__
+ }
+
+ return style;
+}
+
+// Setup background and foreground colours correctly
+void wxWindowMSW::SetupColours()
+{
+ if ( GetParent() )
+ SetBackgroundColour(GetParent()->GetBackgroundColour());
+}
+
+bool wxWindowMSW::IsMouseInWindow() const
+{
+ // get the mouse position
+ POINT pt;
+#ifdef __WXWINCE__
+ ::GetCursorPosWinCE(&pt);
+#else
+ ::GetCursorPos(&pt);
+#endif
+
+ // find the window which currently has the cursor and go up the window
+ // chain until we find this window - or exhaust it
+ HWND hwnd = ::WindowFromPoint(pt);
+ while ( hwnd && (hwnd != GetHwnd()) )
+ hwnd = ::GetParent(hwnd);
+
+ return hwnd != NULL;
+}
+
+void wxWindowMSW::OnInternalIdle()
+{
+#ifndef HAVE_TRACKMOUSEEVENT
+ // Check if we need to send a LEAVE event
+ if ( m_mouseInWindow )
+ {
+ // note that we should generate the leave event whether the window has
+ // or doesn't have mouse capture
+ if ( !IsMouseInWindow() )
+ {
+ GenerateMouseLeave();
+ }
+ }
+#endif // !HAVE_TRACKMOUSEEVENT
+
+ if (wxUpdateUIEvent::CanUpdate(this))
+ UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
+}
+
+// Set this window to be the child of 'parent'.
+bool wxWindowMSW::Reparent(wxWindowBase *parent)
+{
+ if ( !wxWindowBase::Reparent(parent) )
+ return false;
+
+ HWND hWndChild = GetHwnd();
+ HWND hWndParent = GetParent() ? GetWinHwnd(GetParent()) : (HWND)0;
+
+ ::SetParent(hWndChild, hWndParent);
+
+#ifndef __WXWINCE__
+ if ( ::GetWindowLong(hWndChild, GWL_EXSTYLE) & WS_EX_CONTROLPARENT )
+ {
+ EnsureParentHasControlParentStyle(GetParent());
+ }
+#endif // !__WXWINCE__
+
+ return true;
+}
+
+static inline void SendSetRedraw(HWND hwnd, bool on)
+{
+#ifndef __WXMICROWIN__
+ ::SendMessage(hwnd, WM_SETREDRAW, (WPARAM)on, 0);
+#endif
+}
+
+void wxWindowMSW::Freeze()
+{
+ if ( !m_frozenness++ )
+ {
+ if ( IsShown() )
+ SendSetRedraw(GetHwnd(), false);
+ }
+}
+
+void wxWindowMSW::Thaw()
+{
+ wxASSERT_MSG( m_frozenness > 0, _T("Thaw() without matching Freeze()") );
+
+ if ( --m_frozenness == 0 )
+ {
+ if ( IsShown() )
+ {
+ SendSetRedraw(GetHwnd(), true);
+
+ // we need to refresh everything or otherwise the invalidated area
+ // is not going to be repainted
+ Refresh();
+ }
+ }
+}
+
+void wxWindowMSW::Refresh(bool eraseBack, const wxRect *rect)
+{
+ HWND hWnd = GetHwnd();
+ if ( hWnd )
+ {
+ RECT mswRect;
+ const RECT *pRect;
+ if ( rect )
+ {
+ mswRect.left = rect->x;
+ mswRect.top = rect->y;
+ mswRect.right = rect->x + rect->width;
+ mswRect.bottom = rect->y + rect->height;
+
+ pRect = &mswRect;
+ }
+ else
+ {
+ pRect = NULL;
+ }
+
+ // RedrawWindow not available on SmartPhone or eVC++ 3
+#if !defined(__SMARTPHONE__) && !(defined(_WIN32_WCE) && _WIN32_WCE < 400)
+ UINT flags = RDW_INVALIDATE | RDW_ALLCHILDREN;
+ if ( eraseBack )
+ flags |= RDW_ERASE;
+
+ ::RedrawWindow(hWnd, pRect, NULL, flags);
+#else
+ ::InvalidateRect(hWnd, pRect, eraseBack);
+#endif
+ }
+}
+
+void wxWindowMSW::Update()
+{
+ if ( !::UpdateWindow(GetHwnd()) )
+ {
+ wxLogLastError(_T("UpdateWindow"));
+ }
+
+#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
+ // just calling UpdateWindow() is not enough, what we did in our WM_PAINT
+ // handler needs to be really drawn right now
+ (void)::GdiFlush();
+#endif // __WIN32__
+}
+
+// ---------------------------------------------------------------------------
+// drag and drop
+// ---------------------------------------------------------------------------
+
+#if wxUSE_DRAG_AND_DROP || !defined(__WXWINCE__)
+
+#if wxUSE_STATBOX
+
+// we need to lower the sibling static boxes so controls contained within can be
+// a drop target
+static void AdjustStaticBoxZOrder(wxWindow *parent)
+{
+ // no sibling static boxes if we have no parent (ie TLW)
+ if ( !parent )
+ return;
+
+ for ( wxWindowList::compatibility_iterator node = parent->GetChildren().GetFirst();
+ node;
+ node = node->GetNext() )
+ {
+ wxStaticBox *statbox = wxDynamicCast(node->GetData(), wxStaticBox);
+ if ( statbox )
+ {
+ ::SetWindowPos(GetHwndOf(statbox), HWND_BOTTOM, 0, 0, 0, 0,
+ SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
+ }
+ }
+}
+
+#else // !wxUSE_STATBOX
+
+static inline void AdjustStaticBoxZOrder(wxWindow * WXUNUSED(parent))
+{
+}
+
+#endif // wxUSE_STATBOX/!wxUSE_STATBOX
+
+#endif // drag and drop is used
+
+#if wxUSE_DRAG_AND_DROP
+void wxWindowMSW::SetDropTarget(wxDropTarget *pDropTarget)
+{
+ if ( m_dropTarget != 0 ) {
+ m_dropTarget->Revoke(m_hWnd);
+ delete m_dropTarget;
+ }
+
+ m_dropTarget = pDropTarget;
+ if ( m_dropTarget != 0 )
+ {
+ AdjustStaticBoxZOrder(GetParent());
+ m_dropTarget->Register(m_hWnd);
+ }
+}
+#endif // wxUSE_DRAG_AND_DROP
+
+// old-style file manager drag&drop support: we retain the old-style
+// DragAcceptFiles in parallel with SetDropTarget.
+void wxWindowMSW::DragAcceptFiles(bool WXUNUSED_IN_WINCE(accept))
+{
+#ifndef __WXWINCE__
+ HWND hWnd = GetHwnd();
+ if ( hWnd )
+ {
+ AdjustStaticBoxZOrder(GetParent());
+ ::DragAcceptFiles(hWnd, (BOOL)accept);
+ }
+#endif
+}
+
+// ----------------------------------------------------------------------------
+// tooltips
+// ----------------------------------------------------------------------------
+
+#if wxUSE_TOOLTIPS
+
+void wxWindowMSW::DoSetToolTip(wxToolTip *tooltip)
+{
+ wxWindowBase::DoSetToolTip(tooltip);
+
+ if ( m_tooltip )
+ m_tooltip->SetWindow((wxWindow *)this);
+}
+
+#endif // wxUSE_TOOLTIPS
+
+// ---------------------------------------------------------------------------
+// moving and resizing
+// ---------------------------------------------------------------------------
+
+bool wxWindowMSW::IsSizeDeferred() const
+{
+#if USE_DEFERRED_SIZING
+ if ( m_pendingPosition != wxDefaultPosition ||
+ m_pendingSize != wxDefaultSize )
+ return true;
+#endif // USE_DEFERRED_SIZING
+
+ return false;
+}
+
+// Get total size
+void wxWindowMSW::DoGetSize(int *x, int *y) const
+{
+#if USE_DEFERRED_SIZING
+ // if SetSize() had been called at wx level but not realized at Windows
+ // level yet (i.e. EndDeferWindowPos() not called), we still should return
+ // the new and not the old position to the other wx code
+ if ( m_pendingSize != wxDefaultSize )
+ {
+ if ( x )
+ *x = m_pendingSize.x;
+ if ( y )
+ *y = m_pendingSize.y;
+ }
+ else // use current size
+#endif // USE_DEFERRED_SIZING
+ {
+ RECT rect = wxGetWindowRect(GetHwnd());
+
+ if ( x )
+ *x = rect.right - rect.left;
+ if ( y )
+ *y = rect.bottom - rect.top;
+ }
+}
+
+// Get size *available for subwindows* i.e. excluding menu bar etc.
+void wxWindowMSW::DoGetClientSize(int *x, int *y) const
+{
+#if USE_DEFERRED_SIZING
+ if ( m_pendingSize != wxDefaultSize )
+ {
+ // we need to calculate the client size corresponding to pending size
+ RECT rect;
+ rect.left = m_pendingPosition.x;
+ rect.top = m_pendingPosition.y;
+ rect.right = rect.left + m_pendingSize.x;
+ rect.bottom = rect.top + m_pendingSize.y;
+
+ ::SendMessage(GetHwnd(), WM_NCCALCSIZE, FALSE, (LPARAM)&rect);
+
+ if ( x )
+ *x = rect.right - rect.left;
+ if ( y )
+ *y = rect.bottom - rect.top;
+ }
+ else
+#endif // USE_DEFERRED_SIZING
+ {
+ RECT rect = wxGetClientRect(GetHwnd());
+
+ if ( x )
+ *x = rect.right;
+ if ( y )
+ *y = rect.bottom;
+ }
+}
+
+void wxWindowMSW::DoGetPosition(int *x, int *y) const
+{
+ wxWindow * const parent = GetParent();
+
+ wxPoint pos;
+ if ( m_pendingPosition != wxDefaultPosition )
+ {
+ pos = m_pendingPosition;
+ }
+ else // use current position
+ {
+ RECT rect = wxGetWindowRect(GetHwnd());
+
+ POINT point;
+ point.x = rect.left;
+ point.y = rect.top;
+
+ // we do the adjustments with respect to the parent only for the "real"
+ // children, not for the dialogs/frames
+ if ( !IsTopLevel() )
+ {
+ if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft )
+ {
+ // In RTL mode, we want the logical left x-coordinate,
+ // which would be the physical right x-coordinate.
+ point.x = rect.right;
+ }
+
+ // Since we now have the absolute screen coords, if there's a
+ // parent we must subtract its top left corner
+ if ( parent )
+ {
+ ::ScreenToClient(GetHwndOf(parent), &point);
+ }
+ }
+
+ pos.x = point.x;
+ pos.y = point.y;
+ }
+
+ // we also must adjust by the client area offset: a control which is just
+ // under a toolbar could be at (0, 30) in Windows but at (0, 0) in wx
+ if ( parent && !IsTopLevel() )
+ {
+ const wxPoint pt(parent->GetClientAreaOrigin());
+ pos.x -= pt.x;
+ pos.y -= pt.y;
+ }
+
+ if ( x )
+ *x = pos.x;
+ if ( y )
+ *y = pos.y;
+}
+
+void wxWindowMSW::DoScreenToClient(int *x, int *y) const
+{
+ POINT pt;
+ if ( x )
+ pt.x = *x;
+ if ( y )
+ pt.y = *y;
+
+ ::ScreenToClient(GetHwnd(), &pt);
+
+ if ( x )
+ *x = pt.x;
+ if ( y )
+ *y = pt.y;
+}
+
+void wxWindowMSW::DoClientToScreen(int *x, int *y) const
+{
+ POINT pt;
+ if ( x )
+ pt.x = *x;
+ if ( y )
+ pt.y = *y;
+
+ ::ClientToScreen(GetHwnd(), &pt);
+
+ if ( x )
+ *x = pt.x;
+ if ( y )
+ *y = pt.y;
+}
+
+bool
+wxWindowMSW::DoMoveSibling(WXHWND hwnd, int x, int y, int width, int height)
+{
+#if USE_DEFERRED_SIZING
+ // if our parent had prepared a defer window handle for us, use it (unless
+ // we are a top level window)
+ wxWindowMSW * const parent = IsTopLevel() ? NULL : GetParent();
+
+ HDWP hdwp = parent ? (HDWP)parent->m_hDWP : NULL;
+ if ( hdwp )
+ {
+ hdwp = ::DeferWindowPos(hdwp, (HWND)hwnd, NULL, x, y, width, height,
+ SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE);
+ if ( !hdwp )
+ {
+ wxLogLastError(_T("DeferWindowPos"));
+ }
+ }
+
+ if ( parent )
+ {
+ // hdwp must be updated as it may have been changed
+ parent->m_hDWP = (WXHANDLE)hdwp;
+ }
+
+ if ( hdwp )
+ {
+ // did deferred move, remember new coordinates of the window as they're
+ // different from what Windows would return for it
+ return true;
+ }
+
+ // otherwise (or if deferring failed) move the window in place immediately
+#endif // USE_DEFERRED_SIZING
+ if ( !::MoveWindow((HWND)hwnd, x, y, width, height, IsShown()) )
+ {
+ wxLogLastError(wxT("MoveWindow"));
+ }
+
+ // if USE_DEFERRED_SIZING, indicates that we didn't use deferred move,
+ // ignored otherwise
+ return false;
+}
+
+void wxWindowMSW::DoMoveWindow(int x, int y, int width, int height)
+{
+ // TODO: is this consistent with other platforms?
+ // Still, negative width or height shouldn't be allowed
+ if (width < 0)
+ width = 0;
+ if (height < 0)
+ height = 0;
+
+ if ( DoMoveSibling(m_hWnd, x, y, width, height) )
+ {
+#if USE_DEFERRED_SIZING
+ m_pendingPosition = wxPoint(x, y);
+ m_pendingSize = wxSize(width, height);
+#endif // USE_DEFERRED_SIZING
+ }
+}
+
+// set the size of the window: if the dimensions are positive, just use them,
+// but if any of them is equal to -1, it means that we must find the value for
+// it ourselves (unless sizeFlags contains wxSIZE_ALLOW_MINUS_ONE flag, in
+// which case -1 is a valid value for x and y)
+//
+// If sizeFlags contains wxSIZE_AUTO_WIDTH/HEIGHT flags (default), we calculate
+// the width/height to best suit our contents, otherwise we reuse the current
+// width/height
+void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags)
+{
+ // get the current size and position...
+ int currentX, currentY;
+ int currentW, currentH;
+
+ GetPosition(¤tX, ¤tY);
+ GetSize(¤tW, ¤tH);
+
+ // ... and don't do anything (avoiding flicker) if it's already ok unless
+ // we're forced to resize the window
+ if ( x == currentX && y == currentY &&
+ width == currentW && height == currentH &&
+ !(sizeFlags & wxSIZE_FORCE) )
+ {
+ return;
+ }
+
+ if ( x == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
+ x = currentX;
+ if ( y == wxDefaultCoord && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
+ y = currentY;
+
+ AdjustForParentClientOrigin(x, y, sizeFlags);
+
+ wxSize size = wxDefaultSize;
+ if ( width == wxDefaultCoord )
+ {
+ if ( sizeFlags & wxSIZE_AUTO_WIDTH )
+ {
+ size = DoGetBestSize();
+ width = size.x;
+ }
+ else
+ {
+ // just take the current one
+ width = currentW;
+ }
+ }
+
+ if ( height == wxDefaultCoord )
+ {
+ if ( sizeFlags & wxSIZE_AUTO_HEIGHT )
+ {
+ if ( size.x == wxDefaultCoord )
+ {
+ size = DoGetBestSize();
+ }
+ //else: already called DoGetBestSize() above
+
+ height = size.y;
+ }
+ else
+ {
+ // just take the current one
+ height = currentH;
+ }
+ }
+
+ DoMoveWindow(x, y, width, height);
+}
+
+void wxWindowMSW::DoSetClientSize(int width, int height)
+{
+ // setting the client size is less obvious than it could have been
+ // because in the result of changing the total size the window scrollbar
+ // may [dis]appear and/or its menubar may [un]wrap (and AdjustWindowRect()
+ // doesn't take neither into account) and so the client size will not be
+ // correct as the difference between the total and client size changes --
+ // so we keep changing it until we get it right
+ //
+ // normally this loop shouldn't take more than 3 iterations (usually 1 but
+ // if scrollbars [dis]appear as the result of the first call, then 2 and it
+ // may become 3 if the window had 0 size originally and so we didn't
+ // calculate the scrollbar correction correctly during the first iteration)
+ // but just to be on the safe side we check for it instead of making it an
+ // "infinite" loop (i.e. leaving break inside as the only way to get out)
+ for ( int i = 0; i < 4; i++ )
+ {
+ RECT rectClient;
+ ::GetClientRect(GetHwnd(), &rectClient);
+
+ // if the size is already ok, stop here (NB: rectClient.left = top = 0)
+ if ( (rectClient.right == width || width == wxDefaultCoord) &&
+ (rectClient.bottom == height || height == wxDefaultCoord) )
+ {
+ break;
+ }
+
+ // Find the difference between the entire window (title bar and all)
+ // and the client area; add this to the new client size to move the
+ // window
+ RECT rectWin;
+ ::GetWindowRect(GetHwnd(), &rectWin);
+
+ const int widthWin = rectWin.right - rectWin.left,
+ heightWin = rectWin.bottom - rectWin.top;
+
+ // MoveWindow positions the child windows relative to the parent, so
+ // adjust if necessary
+ if ( !IsTopLevel() )
+ {
+ wxWindow *parent = GetParent();
+ if ( parent )
+ {
+ ::ScreenToClient(GetHwndOf(parent), (POINT *)&rectWin);
+ }
+ }
+
+ // don't call DoMoveWindow() because we want to move window immediately
+ // and not defer it here as otherwise the value returned by
+ // GetClient/WindowRect() wouldn't change as the window wouldn't be
+ // really resized
+ if ( !::MoveWindow(GetHwnd(),
+ rectWin.left,
+ rectWin.top,
+ width + widthWin - rectClient.right,
+ height + heightWin - rectClient.bottom,
+ TRUE) )
+ {
+ wxLogLastError(_T("MoveWindow"));
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+// text metrics
+// ---------------------------------------------------------------------------
+
+int wxWindowMSW::GetCharHeight() const
+{
+ return wxGetTextMetrics(this).tmHeight;
+}
+
+int wxWindowMSW::GetCharWidth() const
+{
+ // +1 is needed because Windows apparently adds it when calculating the
+ // dialog units size in pixels
+#if wxDIALOG_UNIT_COMPATIBILITY
+ return wxGetTextMetrics(this).tmAveCharWidth;
+#else
+ return wxGetTextMetrics(this).tmAveCharWidth + 1;
+#endif
+}
+
+void wxWindowMSW::GetTextExtent(const wxString& string,
+ int *x, int *y,
+ int *descent, int *externalLeading,
+ const wxFont *theFont) const
+{
+ wxASSERT_MSG( !theFont || theFont->Ok(),
+ _T("invalid font in GetTextExtent()") );
+
+ wxFont fontToUse;
+ if (theFont)
+ fontToUse = *theFont;
+ else
+ fontToUse = GetFont();
+
+ WindowHDC hdc(GetHwnd());
+ SelectInHDC selectFont(hdc, GetHfontOf(fontToUse));
+
+ SIZE sizeRect;
+ TEXTMETRIC tm;
+ ::GetTextExtentPoint32(hdc, string, string.length(), &sizeRect);
+ GetTextMetrics(hdc, &tm);
+
+ if ( x )
+ *x = sizeRect.cx;
+ if ( y )
+ *y = sizeRect.cy;
+ if ( descent )
+ *descent = tm.tmDescent;
+ if ( externalLeading )
+ *externalLeading = tm.tmExternalLeading;
+}
+
+// ---------------------------------------------------------------------------
+// popup menu
+// ---------------------------------------------------------------------------
+
+#if wxUSE_MENUS_NATIVE
+
+// yield for WM_COMMAND events only, i.e. process all WM_COMMANDs in the queue
+// immediately, without waiting for the next event loop iteration
+//
+// NB: this function should probably be made public later as it can almost
+// surely replace wxYield() elsewhere as well
+static void wxYieldForCommandsOnly()
+{
+ // peek all WM_COMMANDs (it will always return WM_QUIT too but we don't
+ // want to process it here)
+ MSG msg;
+ while ( ::PeekMessage(&msg, (HWND)0, WM_COMMAND, WM_COMMAND, PM_REMOVE) )
+ {
+ if ( msg.message == WM_QUIT )
+ {
+ // if we retrieved a WM_QUIT, insert back into the message queue.
+ ::PostQuitMessage(0);
+ break;
+ }
+
+ // luckily (as we don't have access to wxEventLoopImpl method from here
+ // anyhow...) we don't need to pre process WM_COMMANDs so dispatch it
+ // immediately
+ ::TranslateMessage(&msg);
+ ::DispatchMessage(&msg);
+ }
+}
+
+bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y)
+{
+ menu->SetInvokingWindow(this);
+ menu->UpdateUI();
+
+ if ( x == wxDefaultCoord && y == wxDefaultCoord )
+ {
+ wxPoint mouse = ScreenToClient(wxGetMousePosition());
+ x = mouse.x; y = mouse.y;
+ }
+
+ HWND hWnd = GetHwnd();
+ HMENU hMenu = GetHmenuOf(menu);
+ POINT point;
+ point.x = x;
+ point.y = y;
+ ::ClientToScreen(hWnd, &point);
+ wxCurrentPopupMenu = menu;
+#if defined(__WXWINCE__)
+ UINT flags = 0;
+#else
+ UINT flags = TPM_RIGHTBUTTON | TPM_RECURSE;
+#endif
+ ::TrackPopupMenu(hMenu, flags, point.x, point.y, 0, hWnd, NULL);
+
+ // we need to do it right now as otherwise the events are never going to be
+ // sent to wxCurrentPopupMenu from HandleCommand()
+ //
+ // note that even eliminating (ugly) wxCurrentPopupMenu global wouldn't
+ // help and we'd still need wxYieldForCommandsOnly() as the menu may be
+ // destroyed as soon as we return (it can be a local variable in the caller
+ // for example) and so we do need to process the event immediately
+ wxYieldForCommandsOnly();
+
+ wxCurrentPopupMenu = NULL;
+
+ menu->SetInvokingWindow(NULL);
+
+ return true;
+}
+
+#endif // wxUSE_MENUS_NATIVE
+
+// ===========================================================================
+// pre/post message processing
+// ===========================================================================
+
+WXLRESULT wxWindowMSW::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
+{
+ if ( m_oldWndProc )
+ return ::CallWindowProc(CASTWNDPROC m_oldWndProc, GetHwnd(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam);
+ else
+ return ::DefWindowProc(GetHwnd(), nMsg, wParam, lParam);
+}
+
+bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
+{
+ // wxUniversal implements tab traversal itself
+#ifndef __WXUNIVERSAL__
+ if ( m_hWnd != 0 && (GetWindowStyleFlag() & wxTAB_TRAVERSAL) )
+ {
+ // intercept dialog navigation keys
+ MSG *msg = (MSG *)pMsg;
+
+ // here we try to do all the job which ::IsDialogMessage() usually does
+ // internally
+ if ( msg->message == WM_KEYDOWN )
+ {
+ bool bCtrlDown = wxIsCtrlDown();
+ bool bShiftDown = wxIsShiftDown();
+
+ // WM_GETDLGCODE: ask the control if it wants the key for itself,
+ // don't process it if it's the case (except for Ctrl-Tab/Enter
+ // combinations which are always processed)
+ LONG lDlgCode = ::SendMessage(msg->hwnd, WM_GETDLGCODE, 0, 0);
+
+ // surprizingly, DLGC_WANTALLKEYS bit mask doesn't contain the
+ // DLGC_WANTTAB nor DLGC_WANTARROWS bits although, logically,
+ // it, of course, implies them
+ if ( lDlgCode & DLGC_WANTALLKEYS )
+ {
+ lDlgCode |= DLGC_WANTTAB | DLGC_WANTARROWS;
+ }
+
+ bool bForward = true,
+ bWindowChange = false,
+ bFromTab = false;
+
+ // should we process this message specially?
+ bool bProcess = true;
+ switch ( msg->wParam )
+ {
+ case VK_TAB:
+ if ( lDlgCode & DLGC_WANTTAB ) {
+ bProcess = false;
+ }
+ else {
+ // Ctrl-Tab cycles thru notebook pages
+ bWindowChange = bCtrlDown;
+ bForward = !bShiftDown;
+ bFromTab = true;
+ }
+ break;
+
+ case VK_UP:
+ case VK_LEFT:
+ if ( (lDlgCode & DLGC_WANTARROWS) || bCtrlDown )
+ bProcess = false;
+ else
+ bForward = false;
+ break;
+
+ case VK_DOWN:
+ case VK_RIGHT:
+ if ( (lDlgCode & DLGC_WANTARROWS) || bCtrlDown )
+ bProcess = false;
+ break;
+
+ case VK_PRIOR:
+ bForward = false;
+ // fall through
+
+ case VK_NEXT:
+ // we treat PageUp/Dn as arrows because chances are that
+ // a control which needs arrows also needs them for
+ // navigation (e.g. wxTextCtrl, wxListCtrl, ...)
+ if ( (lDlgCode & DLGC_WANTARROWS) || !bCtrlDown )
+ bProcess = false;
+ else
+ bWindowChange = true;
+ break;
+
+ case VK_RETURN:
+ {
+ if ( (lDlgCode & DLGC_WANTMESSAGE) && !bCtrlDown )
+ {
+ // control wants to process Enter itself, don't
+ // call IsDialogMessage() which would consume it
+ return false;
+ }
+
+#if wxUSE_BUTTON
+ // currently active button should get enter press even
+ // if there is a default button elsewhere so check if
+ // this window is a button first
+ wxWindow *btn = NULL;
+ if ( lDlgCode & DLGC_DEFPUSHBUTTON )
+ {
+ // let IsDialogMessage() handle this for all
+ // buttons except the owner-drawn ones which it
+ // just seems to ignore
+ long style = ::GetWindowLong(msg->hwnd, GWL_STYLE);
+ if ( (style & BS_OWNERDRAW) == BS_OWNERDRAW )
+ {
+ // emulate the button click
+ btn = wxFindWinFromHandle((WXHWND)msg->hwnd);
+ }
+
+ bProcess = false;
+ }
+ else // not a button itself, do we have default button?
+ {
+ wxTopLevelWindow *
+ tlw = wxDynamicCast(wxGetTopLevelParent(this),
+ wxTopLevelWindow);
+ if ( tlw )
+ {
+ btn = wxDynamicCast(tlw->GetDefaultItem(),
+ wxButton);
+ }
+ }
+
+ if ( btn && btn->IsEnabled() )
+ {
+ btn->MSWCommand(BN_CLICKED, 0 /* unused */);
+ return true;
+ }
+
+#endif // wxUSE_BUTTON
+
+#ifdef __WXWINCE__
+ // map Enter presses into button presses on PDAs
+ wxJoystickEvent event(wxEVT_JOY_BUTTON_DOWN);
+ event.SetEventObject(this);
+ if ( GetEventHandler()->ProcessEvent(event) )
+ return true;
+#endif // __WXWINCE__
+ }
+ break;
+
+ default:
+ bProcess = false;
+ }
+
+ if ( bProcess )
+ {
+ wxNavigationKeyEvent event;
+ event.SetDirection(bForward);
+ event.SetWindowChange(bWindowChange);
+ event.SetFromTab(bFromTab);
+ event.SetEventObject(this);
+
+ if ( GetEventHandler()->ProcessEvent(event) )
+ {
+ // as we don't call IsDialogMessage(), which would take of
+ // this by default, we need to manually send this message
+ // so that controls can change their UI state if needed
+ MSWUpdateUIState(UIS_CLEAR, UISF_HIDEFOCUS);
+
+ return true;
+ }
+ }
+ }
+
+ if ( ::IsDialogMessage(GetHwnd(), msg) )
+ {
+ // IsDialogMessage() did something...
+ return true;
+ }
+ }
+#endif // __WXUNIVERSAL__
+
+#if wxUSE_TOOLTIPS
+ if ( m_tooltip )
+ {
+ // relay mouse move events to the tooltip control
+ MSG *msg = (MSG *)pMsg;
+ if ( msg->message == WM_MOUSEMOVE )
+ wxToolTip::RelayEvent(pMsg);
+ }
+#endif // wxUSE_TOOLTIPS
+
+ return false;
+}
+
+bool wxWindowMSW::MSWTranslateMessage(WXMSG* pMsg)
+{
+#if wxUSE_ACCEL && !defined(__WXUNIVERSAL__)
+ return m_acceleratorTable.Translate(this, pMsg);
+#else
+ (void) pMsg;
+ return false;
+#endif // wxUSE_ACCEL
+}
+
+bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* msg)
+{
+ // all tests below have to deal with various bugs/misfeatures of
+ // IsDialogMessage(): we have to prevent it from being called from our
+ // MSWProcessMessage() in some situations
+
+ // don't let IsDialogMessage() get VK_ESCAPE as it _always_ eats the
+ // message even when there is no cancel button and when the message is
+ // needed by the control itself: in particular, it prevents the tree in
+ // place edit control from being closed with Escape in a dialog
+ if ( msg->message == WM_KEYDOWN && msg->wParam == VK_ESCAPE )
+ {
+ return false;
+ }
+
+ // ::IsDialogMessage() is broken and may sometimes hang the application by
+ // going into an infinite loop when it tries to find the control to give
+ // focus to when Alt-<key> is pressed, so we try to detect [some of] the
+ // situations when this may happen and not call it then
+ if ( msg->message != WM_SYSCHAR )
+ return true;
+
+ // assume we can call it by default
+ bool canSafelyCallIsDlgMsg = true;
+
+ HWND hwndFocus = ::GetFocus();
+
+ // if the currently focused window itself has WS_EX_CONTROLPARENT style,
+ // ::IsDialogMessage() will also enter an infinite loop, because it will
+ // recursively check the child windows but not the window itself and so if
+ // none of the children accepts focus it loops forever (as it only stops
+ // when it gets back to the window it started from)
+ //
+ // while it is very unusual that a window with WS_EX_CONTROLPARENT
+ // style has the focus, it can happen. One such possibility is if
+ // all windows are either toplevel, wxDialog, wxPanel or static
+ // controls and no window can actually accept keyboard input.
+#if !defined(__WXWINCE__)
+ if ( ::GetWindowLong(hwndFocus, GWL_EXSTYLE) & WS_EX_CONTROLPARENT )
+ {
+ // pessimistic by default
+ canSafelyCallIsDlgMsg = false;
+ for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
+ node;
+ node = node->GetNext() )
+ {
+ wxWindow * const win = node->GetData();
+ if ( win->AcceptsFocus() &&
+ !(::GetWindowLong(GetHwndOf(win), GWL_EXSTYLE) &
+ WS_EX_CONTROLPARENT) )
+ {
+ // it shouldn't hang...
+ canSafelyCallIsDlgMsg = true;
+
+ break;
+ }
+ }
+ }
+#endif // !__WXWINCE__
+
+ if ( canSafelyCallIsDlgMsg )
+ {
+ // ::IsDialogMessage() can enter in an infinite loop when the
+ // currently focused window is disabled or hidden and its
+ // parent has WS_EX_CONTROLPARENT style, so don't call it in
+ // this case
+ while ( hwndFocus )
+ {
+ if ( !::IsWindowEnabled(hwndFocus) ||
+ !::IsWindowVisible(hwndFocus) )
+ {
+ // it would enter an infinite loop if we do this!
+ canSafelyCallIsDlgMsg = false;
+
+ break;
+ }
+
+ if ( !(::GetWindowLong(hwndFocus, GWL_STYLE) & WS_CHILD) )
+ {
+ // it's a top level window, don't go further -- e.g. even
+ // if the parent of a dialog is disabled, this doesn't
+ // break navigation inside the dialog
+ break;
+ }
+
+ hwndFocus = ::GetParent(hwndFocus);
+ }
+ }
+
+ return canSafelyCallIsDlgMsg;
+}
+
+// ---------------------------------------------------------------------------
+// message params unpackers
+// ---------------------------------------------------------------------------
+
+void wxWindowMSW::UnpackCommand(WXWPARAM wParam, WXLPARAM lParam,
+ WORD *id, WXHWND *hwnd, WORD *cmd)
+{
+ *id = LOWORD(wParam);
+ *hwnd = (WXHWND)lParam;
+ *cmd = HIWORD(wParam);
+}
+
+void wxWindowMSW::UnpackActivate(WXWPARAM wParam, WXLPARAM lParam,
+ WXWORD *state, WXWORD *minimized, WXHWND *hwnd)
+{
+ *state = LOWORD(wParam);
+ *minimized = HIWORD(wParam);
+ *hwnd = (WXHWND)lParam;
+}
+
+void wxWindowMSW::UnpackScroll(WXWPARAM wParam, WXLPARAM lParam,
+ WXWORD *code, WXWORD *pos, WXHWND *hwnd)
+{
+ *code = LOWORD(wParam);
+ *pos = HIWORD(wParam);
+ *hwnd = (WXHWND)lParam;
+}
+
+void wxWindowMSW::UnpackCtlColor(WXWPARAM wParam, WXLPARAM lParam,
+ WXHDC *hdc, WXHWND *hwnd)
+{
+ *hwnd = (WXHWND)lParam;
+ *hdc = (WXHDC)wParam;
+}
+
+void wxWindowMSW::UnpackMenuSelect(WXWPARAM wParam, WXLPARAM lParam,
+ WXWORD *item, WXWORD *flags, WXHMENU *hmenu)
+{
+ *item = (WXWORD)wParam;
+ *flags = HIWORD(wParam);
+ *hmenu = (WXHMENU)lParam;
+}
+
+// ---------------------------------------------------------------------------
+// Main wxWidgets window proc and the window proc for wxWindow
+// ---------------------------------------------------------------------------
+
+// Hook for new window just as it's being created, when the window isn't yet
+// associated with the handle
+static wxWindowMSW *gs_winBeingCreated = NULL;
+
+// implementation of wxWindowCreationHook class: it just sets gs_winBeingCreated to the
+// window being created and insures that it's always unset back later
+wxWindowCreationHook::wxWindowCreationHook(wxWindowMSW *winBeingCreated)
+{
+ gs_winBeingCreated = winBeingCreated;
+}
+
+wxWindowCreationHook::~wxWindowCreationHook()
+{
+ gs_winBeingCreated = NULL;
+}
+
+// Main window proc
+LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ // trace all messages - useful for the debugging
+#ifdef __WXDEBUG__
+ wxLogTrace(wxTraceMessages,
+ wxT("Processing %s(hWnd=%08lx, wParam=%8lx, lParam=%8lx)"),
+ wxGetMessageName(message), (long)hWnd, (long)wParam, lParam);
+#endif // __WXDEBUG__
+
+ wxWindowMSW *wnd = wxFindWinFromHandle((WXHWND) hWnd);
+
+ // when we get the first message for the HWND we just created, we associate
+ // it with wxWindow stored in gs_winBeingCreated
+ if ( !wnd && gs_winBeingCreated )
+ {
+ wxAssociateWinWithHandle(hWnd, gs_winBeingCreated);
+ wnd = gs_winBeingCreated;
+ gs_winBeingCreated = NULL;
+ wnd->SetHWND((WXHWND)hWnd);
+ }
+
+ LRESULT rc;
+
+ if ( wnd && wxEventLoop::AllowProcessing(wnd) )
+ rc = wnd->MSWWindowProc(message, wParam, lParam);
+ else
+ rc = ::DefWindowProc(hWnd, message, wParam, lParam);
+
+ return rc;
+}
+
+WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
+{
+ // did we process the message?
+ bool processed = false;
+
+ // the return value
+ union
+ {
+ bool allow;
+ WXLRESULT result;
+ WXHBRUSH hBrush;
+ } rc;
+
+ // for most messages we should return 0 when we do process the message
+ rc.result = 0;
+
+ switch ( message )
+ {
+ case WM_CREATE:
+ {
+ bool mayCreate;
+ processed = HandleCreate((WXLPCREATESTRUCT)lParam, &mayCreate);
+ if ( processed )
+ {
+ // return 0 to allow window creation
+ rc.result = mayCreate ? 0 : -1;
+ }
+ }
+ break;
+
+ case WM_DESTROY:
+ // never set processed to true and *always* pass WM_DESTROY to
+ // DefWindowProc() as Windows may do some internal cleanup when
+ // processing it and failing to pass the message along may cause
+ // memory and resource leaks!
+ (void)HandleDestroy();
+ break;
+
+ case WM_SIZE:
+ processed = HandleSize(LOWORD(lParam), HIWORD(lParam), wParam);
+ break;
+
+ case WM_MOVE:
+ processed = HandleMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
+ break;
+
+#if !defined(__WXWINCE__)
+ case WM_MOVING:
+ {
+ LPRECT pRect = (LPRECT)lParam;
+ wxRect rc;
+ rc.SetLeft(pRect->left);
+ rc.SetTop(pRect->top);
+ rc.SetRight(pRect->right);
+ rc.SetBottom(pRect->bottom);
+ processed = HandleMoving(rc);
+ if (processed) {
+ pRect->left = rc.GetLeft();
+ pRect->top = rc.GetTop();
+ pRect->right = rc.GetRight();
+ pRect->bottom = rc.GetBottom();
+ }
+ }
+ break;
+
+ case WM_SIZING:
+ {
+ LPRECT pRect = (LPRECT)lParam;
+ wxRect rc;
+ rc.SetLeft(pRect->left);
+ rc.SetTop(pRect->top);
+ rc.SetRight(pRect->right);
+ rc.SetBottom(pRect->bottom);
+ processed = HandleSizing(rc);
+ if (processed) {
+ pRect->left = rc.GetLeft();
+ pRect->top = rc.GetTop();
+ pRect->right = rc.GetRight();
+ pRect->bottom = rc.GetBottom();
+ }
+ }
+ break;
+#endif // !__WXWINCE__
+
+#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
+ case WM_ACTIVATEAPP:
+ // This implicitly sends a wxEVT_ACTIVATE_APP event
+ wxTheApp->SetActive(wParam != 0, FindFocus());
+ break;
+#endif