]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/window.cpp
added wxWindow::GetPrev/NextSibling()
[wxWidgets.git] / src / msw / window.cpp
index 7e6640eb42e9aecd8e47b3733bec9e814d25354c..d8be1a890be8f0ba2332ef232eaccf256994497b 100644 (file)
@@ -28,6 +28,8 @@
 
 #ifndef WX_PRECOMP
     #include "wx/msw/wrapwin.h"
 
 #ifndef WX_PRECOMP
     #include "wx/msw/wrapwin.h"
+    #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
+    #include "wx/msw/missing.h"
     #include "wx/accel.h"
     #include "wx/menu.h"
     #include "wx/dc.h"
     #include "wx/accel.h"
     #include "wx/menu.h"
     #include "wx/dc.h"
     #include "wx/sizer.h"
     #include "wx/intl.h"
     #include "wx/log.h"
     #include "wx/sizer.h"
     #include "wx/intl.h"
     #include "wx/log.h"
+    #include "wx/textctrl.h"
+    #include "wx/menuitem.h"
+    #include "wx/module.h"
 #endif
 
 #if wxUSE_OWNER_DRAWN && !defined(__WXUNIVERSAL__)
     #include "wx/ownerdrw.h"
 #endif
 
 #endif
 
 #if wxUSE_OWNER_DRAWN && !defined(__WXUNIVERSAL__)
     #include "wx/ownerdrw.h"
 #endif
 
+#include "wx/hashmap.h"
 #include "wx/evtloop.h"
 #include "wx/evtloop.h"
-#include "wx/module.h"
+#include "wx/power.h"
 #include "wx/sysopt.h"
 
 #if wxUSE_DRAG_AND_DROP
 #include "wx/sysopt.h"
 
 #if wxUSE_DRAG_AND_DROP
@@ -72,8 +78,6 @@
     #endif
 #endif
 
     #endif
 #endif
 
-#include "wx/menuitem.h"
-
 #include "wx/msw/private.h"
 
 #if wxUSE_TOOLTIPS
 #include "wx/msw/private.h"
 
 #if wxUSE_TOOLTIPS
@@ -88,9 +92,9 @@
     #include "wx/spinctrl.h"
 #endif // wxUSE_SPINCTRL
 
     #include "wx/spinctrl.h"
 #endif // wxUSE_SPINCTRL
 
-#include "wx/textctrl.h"
 #include "wx/notebook.h"
 #include "wx/listctrl.h"
 #include "wx/notebook.h"
 #include "wx/listctrl.h"
+#include "wx/dynlib.h"
 
 #include <string.h>
 
 
 #include <string.h>
 
     #include <windowsx.h>
 #endif
 
     #include <windowsx.h>
 #endif
 
-#include <commctrl.h>
-
-#include "wx/msw/missing.h"
+#if !defined __WXWINCE__ && !defined NEED_PBT_H
+    #include <pbt.h>
+#endif
 
 #if defined(__WXWINCE__)
     #include "wx/msw/wince/missing.h"
 
 #if defined(__WXWINCE__)
     #include "wx/msw/wince/missing.h"
 #endif
 #endif
 
 #endif
 #endif
 
-#if defined(TME_LEAVE) && defined(WM_MOUSELEAVE)
+#if wxUSE_UXTHEME
+    #include "wx/msw/uxtheme.h"
+    #define EP_EDITTEXT         1
+    #define ETS_NORMAL          1
+    #define ETS_HOT             2
+    #define ETS_SELECTED        3
+    #define ETS_DISABLED        4
+    #define ETS_FOCUSED         5
+    #define ETS_READONLY        6
+    #define ETS_ASSIST          7
+#endif
+
+#if defined(TME_LEAVE) && defined(WM_MOUSELEAVE) && wxUSE_DYNLIB_CLASS
     #define HAVE_TRACKMOUSEEVENT
 #endif // everything needed for TrackMouseEvent()
 
     #define HAVE_TRACKMOUSEEVENT
 #endif // everything needed for TrackMouseEvent()
 
     #define wxUSE_MOUSEEVENT_HACK 1
 #endif
 
     #define wxUSE_MOUSEEVENT_HACK 1
 #endif
 
+// not all compilers/platforms have X button related declarations (notably
+// Windows CE doesn't, and probably some old SDKs don't neither)
+#ifdef WM_XBUTTONDOWN
+    #define wxHAS_XBUTTON
+#endif
+
 // ---------------------------------------------------------------------------
 // global variables
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 // global variables
 // ---------------------------------------------------------------------------
@@ -169,6 +191,13 @@ static struct MouseEventInfoDummy
 } gs_lastMouseEvent;
 #endif // wxUSE_MOUSEEVENT_HACK
 
 } gs_lastMouseEvent;
 #endif // wxUSE_MOUSEEVENT_HACK
 
+// hash containing the registered handlers for the custom messages
+WX_DECLARE_HASH_MAP(int, wxWindow::MSWMessageHandler,
+                    wxIntegerHash, wxIntegerEqual,
+                    MSWMessageHandlers);
+
+static MSWMessageHandlers gs_messageHandlers;
+
 // ---------------------------------------------------------------------------
 // private functions
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 // private functions
 // ---------------------------------------------------------------------------
@@ -481,7 +510,6 @@ void wxWindowMSW::Init()
     m_mouseInWindow = false;
     m_lastKeydownProcessed = false;
 
     m_mouseInWindow = false;
     m_lastKeydownProcessed = false;
 
-    m_childrenDisabled = NULL;
     m_frozenness = 0;
 
     m_hWnd = 0;
     m_frozenness = 0;
 
     m_hWnd = 0;
@@ -542,8 +570,6 @@ wxWindowMSW::~wxWindowMSW()
         wxRemoveHandleAssociation(this);
     }
 
         wxRemoveHandleAssociation(this);
     }
 
-    delete m_childrenDisabled;
-
 }
 
 // real construction (Init() must have been called before!)
 }
 
 // real construction (Init() must have been called before!)
@@ -645,69 +671,11 @@ wxWindow *wxWindowBase::DoFindFocus()
     return NULL;
 }
 
     return NULL;
 }
 
-bool wxWindowMSW::Enable(bool enable)
+void wxWindowMSW::DoEnable( bool enable )
 {
 {
-    if ( !wxWindowBase::Enable(enable) )
-        return false;
-
     HWND hWnd = GetHwnd();
     if ( hWnd )
         ::EnableWindow(hWnd, (BOOL)enable);
     HWND hWnd = GetHwnd();
     if ( hWnd )
         ::EnableWindow(hWnd, (BOOL)enable);
-
-    // the logic below doesn't apply to the top level windows -- otherwise
-    // showing a modal dialog would result in total greying out (and ungreying
-    // out later) of everything which would be really ugly
-    if ( IsTopLevel() )
-        return true;
-
-    // when the parent is disabled, all of its children should be disabled as
-    // well but when it is enabled back, only those of the children which
-    // hadn't been already disabled in the beginning should be enabled again,
-    // so we have to keep the list of those children
-    for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
-          node;
-          node = node->GetNext() )
-    {
-        wxWindow *child = node->GetData();
-        if ( child->IsTopLevel() )
-        {
-            // the logic below doesn't apply to top level children
-            continue;
-        }
-
-        if ( enable )
-        {
-            // re-enable the child unless it had been disabled before us
-            if ( !m_childrenDisabled || !m_childrenDisabled->Find(child) )
-                child->Enable();
-        }
-        else // we're being disabled
-        {
-            if ( child->IsEnabled() )
-            {
-                // disable it as children shouldn't stay enabled while the
-                // parent is not
-                child->Disable();
-            }
-            else // child already disabled, remember it
-            {
-                // have we created the list of disabled children already?
-                if ( !m_childrenDisabled )
-                    m_childrenDisabled = new wxWindowList;
-
-                m_childrenDisabled->Append(child);
-            }
-        }
-    }
-
-    if ( enable && m_childrenDisabled )
-    {
-        // we don't need this list any more, don't keep unused memory
-        delete m_childrenDisabled;
-        m_childrenDisabled = NULL;
-    }
-
-    return true;
 }
 
 bool wxWindowMSW::Show(bool show)
 }
 
 bool wxWindowMSW::Show(bool show)
@@ -800,7 +768,30 @@ bool wxWindowMSW::SetCursor(const wxCursor& cursor)
     // don't "overwrite" busy cursor
     if ( m_cursor.Ok() && !wxIsBusy() )
     {
     // don't "overwrite" busy cursor
     if ( m_cursor.Ok() && !wxIsBusy() )
     {
-        ::SetCursor(GetHcursorOf(m_cursor));
+        // normally we should change the cursor only if it's over this window
+        // but we should do it always if we capture the mouse currently
+        bool set = HasCapture();
+        if ( !set )
+        {
+            HWND hWnd = GetHwnd();
+
+            POINT point;
+#ifdef __WXWINCE__
+            ::GetCursorPosWinCE(&point);
+#else
+            ::GetCursorPos(&point);
+#endif
+
+            RECT rect = wxGetWindowRect(hWnd);
+
+            set = ::PtInRect(&rect, point) != 0;
+        }
+
+        if ( set )
+        {
+            ::SetCursor(GetHcursorOf(m_cursor));
+        }
+        //else: will be set later when the mouse enters this window
     }
 
     return true;
     }
 
     return true;
@@ -824,7 +815,7 @@ void wxWindowMSW::MSWUpdateUIState(int action, int state)
     if ( s_needToUpdate == -1 )
     {
         int verMaj, verMin;
     if ( s_needToUpdate == -1 )
     {
         int verMaj, verMin;
-        s_needToUpdate = wxGetOsVersion(&verMaj, &verMin) == wxWINDOWS_NT &&
+        s_needToUpdate = wxGetOsVersion(&verMaj, &verMin) == wxOS_WINDOWS_NT &&
                             verMaj >= 5;
     }
 
                             verMaj >= 5;
     }
 
@@ -953,10 +944,7 @@ void wxWindowMSW::ScrollWindow(int dx, int dy, const wxRect *prect)
     RECT *pr;
     if ( prect )
     {
     RECT *pr;
     if ( prect )
     {
-        rect.left = prect->x;
-        rect.top = prect->y;
-        rect.right = prect->x + prect->width;
-        rect.bottom = prect->y + prect->height;
+        wxCopyRectToRECT(*prect, rect);
         pr = &rect;
     }
     else
         pr = &rect;
     }
     else
@@ -1013,6 +1001,67 @@ bool wxWindowMSW::ScrollPages(int pages)
                             down ? pages : -pages);
 }
 
                             down ? pages : -pages);
 }
 
+// ----------------------------------------------------------------------------
+// RTL support
+// ----------------------------------------------------------------------------
+
+void wxWindowMSW::SetLayoutDirection(wxLayoutDirection dir)
+{
+#ifdef __WXWINCE__
+    wxUnusedVar(dir);
+#else
+    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
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 // subclassing
 // ---------------------------------------------------------------------------
@@ -1141,6 +1190,25 @@ void wxWindowMSW::SetWindowStyleFlag(long flags)
     // update the internal variable
     wxWindowBase::SetWindowStyleFlag(flags);
 
     // 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() )
     // now update the Windows style as well if needed - and if the window had
     // been already created
     if ( !GetHwnd() )
@@ -1149,9 +1217,21 @@ void wxWindowMSW::SetWindowStyleFlag(long flags)
     // we may need to call SetWindowPos() when we change some styles
     bool callSWP = false;
 
     // we may need to call SetWindowPos() when we change some styles
     bool callSWP = false;
 
-    WXDWORD exstyle, exstyleOld;
-    long style = MSWGetStyle(flags, &exstyle),
-         styleOld = MSWGetStyle(flagsOld, &exstyleOld);
+    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 )
     {
 
     if ( style != styleOld )
     {
@@ -1165,14 +1245,8 @@ void wxWindowMSW::SetWindowStyleFlag(long flags)
 
         ::SetWindowLong(GetHwnd(), GWL_STYLE, styleReal);
 
 
         ::SetWindowLong(GetHwnd(), GWL_STYLE, styleReal);
 
-        // If any of the style changes changed any of the frame styles:
-        // MSDN: SetWindowLong:
-        //       Certain window data is cached, so changes you make using
-        //       SetWindowLong will not take effect until you call the
-        //       SetWindowPos function. Specifically, if you change any of
-        //       the frame styles, you must call SetWindowPos with the
-        //       SWP_FRAMECHANGED flag for the cache to be updated properly.
-
+        // 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 |
         callSWP = ((styleOld ^ style ) & (WS_BORDER |
                                       WS_THICKFRAME |
                                       WS_CAPTION |
@@ -1212,6 +1286,42 @@ void wxWindowMSW::SetWindowStyleFlag(long flags)
     }
 }
 
     }
 }
 
+wxBorder wxWindowMSW::GetDefaultBorderForControl() const
+{
+    return wxBORDER_THEME;
+}
+
+wxBorder wxWindowMSW::GetDefaultBorder() const
+{
+    return wxWindowBase::GetDefaultBorder();
+}
+
+// Translate wxBORDER_THEME (and other border styles if necessary to the value
+// that makes most sense for this Windows environment
+wxBorder wxWindowMSW::TranslateBorder(wxBorder border) const
+{
+#if defined(__POCKETPC__) || defined(__SMARTPHONE__)
+    if (border == wxBORDER_THEME || border == wxBORDER_SUNKEN || border == wxBORDER_SIMPLE)
+        return wxBORDER_SIMPLE;
+    else
+        return wxBORDER_NONE;
+#else
+#if wxUSE_UXTHEME
+    if (border == wxBORDER_THEME)
+    {
+        if (CanApplyThemeBorder())
+        {
+            wxUxThemeEngine* theme = wxUxThemeEngine::GetIfActive();
+            if (theme)
+                return wxBORDER_THEME;
+        }
+    }
+#endif
+    return border;
+#endif
+}
+
+
 WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const
 {
     // translate common wxWidgets styles to Windows ones
 WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const
 {
     // translate common wxWidgets styles to Windows ones
@@ -1241,7 +1351,10 @@ WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const
     if ( flags & wxHSCROLL )
         style |= WS_HSCROLL;
 
     if ( flags & wxHSCROLL )
         style |= WS_HSCROLL;
 
-    const wxBorder border = GetBorder(flags);
+    const wxBorder border = TranslateBorder(GetBorder(flags));
+
+    // After translation, border is now optimized for the specific version of Windows
+    // and theme engine presence.
 
     // WS_BORDER is only required for wxBORDER_SIMPLE
     if ( border == wxBORDER_SIMPLE )
 
     // WS_BORDER is only required for wxBORDER_SIMPLE
     if ( border == wxBORDER_SIMPLE )
@@ -1266,6 +1379,7 @@ WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const
 
             case wxBORDER_NONE:
             case wxBORDER_SIMPLE:
 
             case wxBORDER_NONE:
             case wxBORDER_SIMPLE:
+            case wxBORDER_THEME:
                 break;
 
             case wxBORDER_STATIC:
                 break;
 
             case wxBORDER_STATIC:
@@ -1281,9 +1395,9 @@ WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const
                 style &= ~WS_BORDER;
                 break;
 
                 style &= ~WS_BORDER;
                 break;
 
-            case wxBORDER_DOUBLE:
-                *exstyle |= WS_EX_DLGMODALFRAME;
-                break;
+//            case wxBORDER_DOUBLE:
+//                *exstyle |= WS_EX_DLGMODALFRAME;
+//                break;
         }
 
         // wxUniv doesn't use Windows dialog navigation functions at all
         }
 
         // wxUniv doesn't use Windows dialog navigation functions at all
@@ -1341,7 +1455,7 @@ void wxWindowMSW::OnInternalIdle()
     }
 #endif // !HAVE_TRACKMOUSEEVENT
 
     }
 #endif // !HAVE_TRACKMOUSEEVENT
 
-    if (wxUpdateUIEvent::CanUpdate(this))
+    if (wxUpdateUIEvent::CanUpdate(this) && IsShown())
         UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
 }
 
         UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
 }
 
@@ -1408,11 +1522,7 @@ void wxWindowMSW::Refresh(bool eraseBack, const wxRect *rect)
         const RECT *pRect;
         if ( rect )
         {
         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;
-
+            wxCopyRectToRECT(*rect, mswRect);
             pRect = &mswRect;
         }
         else
             pRect = &mswRect;
         }
         else
@@ -1451,9 +1561,13 @@ void wxWindowMSW::Update()
 // drag and drop
 // ---------------------------------------------------------------------------
 
 // 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
 // we need to lower the sibling static boxes so controls contained within can be
 // a drop target
-static inline void AdjustStaticBoxZOrder(wxWindow *parent)
+static void AdjustStaticBoxZOrder(wxWindow *parent)
 {
     // no sibling static boxes if we have no parent (ie TLW)
     if ( !parent )
 {
     // no sibling static boxes if we have no parent (ie TLW)
     if ( !parent )
@@ -1472,6 +1586,16 @@ static inline void AdjustStaticBoxZOrder(wxWindow *parent)
     }
 }
 
     }
 }
 
+#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 wxUSE_DRAG_AND_DROP
 void wxWindowMSW::SetDropTarget(wxDropTarget *pDropTarget)
 {
@@ -1537,6 +1661,7 @@ bool wxWindowMSW::IsSizeDeferred() const
 // Get total size
 void wxWindowMSW::DoGetSize(int *x, int *y) const
 {
 // 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 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
@@ -1548,6 +1673,7 @@ void wxWindowMSW::DoGetSize(int *x, int *y) const
             *y = m_pendingSize.y;
     }
     else // use current size
             *y = m_pendingSize.y;
     }
     else // use current size
+#endif // USE_DEFERRED_SIZING
     {
         RECT rect = wxGetWindowRect(GetHwnd());
 
     {
         RECT rect = wxGetWindowRect(GetHwnd());
 
@@ -1562,21 +1688,9 @@ void wxWindowMSW::DoGetSize(int *x, int *y) const
 void wxWindowMSW::DoGetClientSize(int *x, int *y) const
 {
 #if USE_DEFERRED_SIZING
 void wxWindowMSW::DoGetClientSize(int *x, int *y) const
 {
 #if USE_DEFERRED_SIZING
-    if ( IsTopLevel() || m_pendingSize == wxDefaultSize )
-#endif
-    {        // top level windows resizing is never deferred, so we can safely use
-        // the current size here
-        RECT rect = wxGetClientRect(GetHwnd());
-
-        if ( x )
-            *x = rect.right;
-        if ( y )
-            *y = rect.bottom;
-    }
-#if USE_DEFERRED_SIZING
-    else // non top level and using deferred sizing
+    if ( m_pendingSize != wxDefaultSize )
     {
     {
-        // we need to calculate the *pending* client size here
+        // we need to calculate the client size corresponding to pending size
         RECT rect;
         rect.left = m_pendingPosition.x;
         rect.top = m_pendingPosition.y;
         RECT rect;
         rect.left = m_pendingPosition.x;
         rect.top = m_pendingPosition.y;
@@ -1590,7 +1704,16 @@ void wxWindowMSW::DoGetClientSize(int *x, int *y) const
         if ( y )
             *y = rect.bottom - rect.top;
     }
         if ( y )
             *y = rect.bottom - rect.top;
     }
-#endif
+    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
 }
 
 void wxWindowMSW::DoGetPosition(int *x, int *y) const
@@ -1614,6 +1737,13 @@ void wxWindowMSW::DoGetPosition(int *x, int *y) const
         // children, not for the dialogs/frames
         if ( !IsTopLevel() )
         {
         // 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 )
             // Since we now have the absolute screen coords, if there's a
             // parent we must subtract its top left corner
             if ( parent )
@@ -1907,7 +2037,7 @@ void wxWindowMSW::GetTextExtent(const wxString& string,
 
     SIZE sizeRect;
     TEXTMETRIC tm;
 
     SIZE sizeRect;
     TEXTMETRIC tm;
-    ::GetTextExtentPoint32(hdc, string, string.length(), &sizeRect);
+    ::GetTextExtentPoint32(hdc, string.wx_str(), string.length(), &sizeRect);
     GetTextMetrics(hdc, &tm);
 
     if ( x )
     GetTextMetrics(hdc, &tm);
 
     if ( x )
@@ -1972,10 +2102,22 @@ bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y)
     ::ClientToScreen(hWnd, &point);
     wxCurrentPopupMenu = menu;
 #if defined(__WXWINCE__)
     ::ClientToScreen(hWnd, &point);
     wxCurrentPopupMenu = menu;
 #if defined(__WXWINCE__)
-    UINT flags = 0;
-#else
-    UINT flags = TPM_RIGHTBUTTON | TPM_RECURSE;
-#endif
+    static const UINT flags = 0;
+#else // !__WXWINCE__
+    UINT flags = TPM_RIGHTBUTTON;
+    // NT4 doesn't support TPM_RECURSE and simply doesn't show the menu at all
+    // when it's use, I'm not sure about Win95/98 but prefer to err on the safe
+    // side and not to use it there neither -- modify the test if it does work
+    // on these systems
+    if ( wxGetWinVersion() >= wxWinVersion_5 )
+    {
+        // using TPM_RECURSE allows us to show a popup menu while another menu
+        // is opened which can be useful and is supported by the other
+        // platforms, so allow it under Windows too
+        flags |= TPM_RECURSE;
+    }
+#endif // __WXWINCE__/!__WXWINCE__
+
     ::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
     ::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
@@ -2027,18 +2169,14 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
             // 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)
             // 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 = 0;
-            if ( !bCtrlDown )
-            {
-                lDlgCode = ::SendMessage(msg->hwnd, WM_GETDLGCODE, 0, 0);
+            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;
-                }
+            // 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,
             }
 
             bool bForward = true,
@@ -2050,10 +2188,13 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
             switch ( msg->wParam )
             {
                 case VK_TAB:
             switch ( msg->wParam )
             {
                 case VK_TAB:
-                    if ( lDlgCode & DLGC_WANTTAB ) {
+                    if ( (lDlgCode & DLGC_WANTTAB) && !bCtrlDown )
+                    {
+                        // let the control have the TAB
                         bProcess = false;
                     }
                         bProcess = false;
                     }
-                    else {
+                    else // use it for navigation
+                    {
                         // Ctrl-Tab cycles thru notebook pages
                         bWindowChange = bCtrlDown;
                         bForward = !bShiftDown;
                         // Ctrl-Tab cycles thru notebook pages
                         bWindowChange = bCtrlDown;
                         bForward = !bShiftDown;
@@ -2075,18 +2216,27 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
                         bProcess = false;
                     break;
 
                         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 // OTOH Ctrl-PageUp/Dn works as [Shift-]Ctrl-Tab
+                        bWindowChange = true;
+                    break;
+
                 case VK_RETURN:
                     {
                 case VK_RETURN:
                     {
-                        if ( (lDlgCode & DLGC_WANTMESSAGE) && !bCtrlDown )
-                        {
-                            // control wants to process Enter itself, don't
-                            // call IsDialogMessage() which would interpret
-                            // it
-                            return false;
-                        }
-
+#if wxUSE_BUTTON
                         // currently active button should get enter press even
                         // currently active button should get enter press even
-                        // if there is a default button elsewhere
+                        // 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
                         if ( lDlgCode & DLGC_DEFPUSHBUTTON )
                         {
                             // let IsDialogMessage() handle this for all
@@ -2096,56 +2246,78 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
                             if ( (style & BS_OWNERDRAW) == BS_OWNERDRAW )
                             {
                                 // emulate the button click
                             if ( (style & BS_OWNERDRAW) == BS_OWNERDRAW )
                             {
                                 // emulate the button click
-                                wxWindow *
-                                    btn = wxFindWinFromHandle((WXHWND)msg->hwnd);
-                                if ( btn )
-                                    btn->MSWCommand(BN_CLICKED, 0 /* unused */);
+                                btn = wxFindWinFromHandle((WXHWND)msg->hwnd);
                             }
 
                             bProcess = false;
                         }
                             }
 
                             bProcess = false;
                         }
-                        else // not a button itself
+                        else // not a button itself, do we have default button?
                         {
                         {
-#if wxUSE_BUTTON
-                            wxButton *btn = wxDynamicCast(GetDefaultItem(),
-                                                          wxButton);
-                            if ( btn && btn->IsEnabled() )
+                            // check if this window or any of its ancestors
+                            // wants the message for itself (we always reserve
+                            // Ctrl-Enter for dialog navigation though)
+                            wxWindow *win = this;
+                            if ( !bCtrlDown )
                             {
                             {
-                                // if we do have a default button, do press it
-                                btn->MSWCommand(BN_CLICKED, 0 /* unused */);
+                                // this will contain the dialog code of this
+                                // window and all of its parent windows in turn
+                                LONG lDlgCode2 = lDlgCode;
 
 
-                                return true;
-                            }
-                            else // no default button
-#endif // wxUSE_BUTTON
-                            {
-#ifdef __WXWINCE__
-                                wxJoystickEvent event(wxEVT_JOY_BUTTON_DOWN);
-                                event.SetEventObject(this);
-                                if(GetEventHandler()->ProcessEvent(event))
-                                    return true;
-#endif
-                                // this is a quick and dirty test for a text
-                                // control
-                                if ( !(lDlgCode & DLGC_HASSETSEL) )
+                                while ( win )
                                 {
                                 {
-                                    // don't process Enter, the control might
-                                    // need it for itself and don't let
-                                    // ::IsDialogMessage() have it as it can
-                                    // eat the Enter events sometimes
-                                    return false;
+                                    if ( lDlgCode2 & DLGC_WANTMESSAGE )
+                                    {
+                                        // as it wants to process Enter itself,
+                                        // don't call IsDialogMessage() which
+                                        // would consume it
+                                        return false;
+                                    }
+
+                                    // don't propagate keyboard messages beyond
+                                    // the first top level window parent
+                                    if ( win->IsTopLevel() )
+                                        break;
+
+                                    win = win->GetParent();
+
+                                    lDlgCode2 = ::SendMessage
+                                                  (
+                                                    GetHwndOf(win),
+                                                    WM_GETDLGCODE,
+                                                    0,
+                                                    0
+                                                  );
                                 }
                                 }
-                                else if (!IsTopLevel())
-                                {
-                                    // if not a top level window, let parent
-                                    // handle it
-                                    return false;
-                                }
-                                //else: treat Enter as TAB: pass to the next
-                                //      control as this is the best thing to do
-                                //      if the text doesn't handle Enter itself
                             }
                             }
+                            else // bCtrlDown
+                            {
+                                win = wxGetTopLevelParent(win);
+                            }
+
+                            wxTopLevelWindow * const
+                                tlw = wxDynamicCast(win, 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;
 
                     }
                     break;
 
@@ -2173,90 +2345,10 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
             }
         }
 
             }
         }
 
-        // 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 )
+        if ( ::IsDialogMessage(GetHwnd(), msg) )
         {
         {
-            // ::IsDialogMessage() is broken and may sometimes hang the
-            // application by going into an infinite loop, so we try to detect
-            // [some of] the situations when this may happen and not call it
-            // then
-
-            // 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);
-                }
-            }
-
-            // let IsDialogMessage() have the message if it's safe to call it
-            if ( canSafelyCallIsDlgMsg && ::IsDialogMessage(GetHwnd(), msg) )
-            {
-                // IsDialogMessage() did something...
-                return true;
-            }
+            // IsDialogMessage() did something...
+            return true;
         }
     }
 #endif // __WXUNIVERSAL__
         }
     }
 #endif // __WXUNIVERSAL__
@@ -2284,10 +2376,96 @@ bool wxWindowMSW::MSWTranslateMessage(WXMSG* pMsg)
 #endif // wxUSE_ACCEL
 }
 
 #endif // wxUSE_ACCEL
 }
 
-bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* WXUNUSED(pMsg))
+bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* msg)
 {
 {
-    // preprocess all messages by default
-    return true;
+    // 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->CanAcceptFocus() &&
+                    !(::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;
 }
 
 // ---------------------------------------------------------------------------
 }
 
 // ---------------------------------------------------------------------------
@@ -2377,7 +2555,7 @@ LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM w
 
     LRESULT rc;
 
 
     LRESULT rc;
 
-    if ( wnd && wxEventLoop::AllowProcessing(wnd) )
+    if ( wnd && wxGUIEventLoop::AllowProcessing(wnd) )
         rc = wnd->MSWWindowProc(message, wParam, lParam);
     else
         rc = ::DefWindowProc(hWnd, message, wParam, lParam);
         rc = wnd->MSWWindowProc(message, wParam, lParam);
     else
         rc = ::DefWindowProc(hWnd, message, wParam, lParam);
@@ -2449,7 +2627,19 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
                 }
             }
             break;
                 }
             }
             break;
+#if 0
+        case WM_ENTERSIZEMOVE:
+            {
+                processed = HandleEnterSizeMove();
+            }
+            break;
 
 
+        case WM_EXITSIZEMOVE:
+            {
+                processed = HandleExitSizeMove();
+            }
+            break;
+#endif
         case WM_SIZING:
             {
                 LPRECT pRect = (LPRECT)lParam;
         case WM_SIZING:
             {
                 LPRECT pRect = (LPRECT)lParam;
@@ -2536,7 +2726,8 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
 
 #ifdef HAVE_TRACKMOUSEEVENT
         case WM_MOUSELEAVE:
 
 #ifdef HAVE_TRACKMOUSEEVENT
         case WM_MOUSELEAVE:
-            // filter out excess WM_MOUSELEAVE events sent after PopupMenu() (on XP at least)
+            // filter out excess WM_MOUSELEAVE events sent after PopupMenu()
+            // (on XP at least)
             if ( m_mouseInWindow )
             {
                 GenerateMouseLeave();
             if ( m_mouseInWindow )
             {
                 GenerateMouseLeave();
@@ -2564,6 +2755,11 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
         case WM_MBUTTONDOWN:
         case WM_MBUTTONUP:
         case WM_MBUTTONDBLCLK:
         case WM_MBUTTONDOWN:
         case WM_MBUTTONUP:
         case WM_MBUTTONDBLCLK:
+#ifdef wxHAS_XBUTTON
+        case WM_XBUTTONDOWN:
+        case WM_XBUTTONUP:
+        case WM_XBUTTONDBLCLK:
+#endif // wxHAS_XBUTTON
             {
 #ifdef __WXMICROWIN__
                 // MicroWindows seems to ignore the fact that a window is
             {
 #ifdef __WXMICROWIN__
                 // MicroWindows seems to ignore the fact that a window is
@@ -2654,7 +2850,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
                     // problems, so don't do it for them (unnecessary anyhow)
                     if ( !win->IsOfStandardClass() )
                     {
                     // problems, so don't do it for them (unnecessary anyhow)
                     if ( !win->IsOfStandardClass() )
                     {
-                        if ( message == WM_LBUTTONDOWN && win->AcceptsFocus() )
+                        if ( message == WM_LBUTTONDOWN && win->IsFocusable() )
                             win->SetFocus();
                     }
                 }
                             win->SetFocus();
                     }
                 }
@@ -2728,12 +2924,12 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
 #endif // defined(WM_DRAWITEM)
 
         case WM_GETDLGCODE:
 #endif // defined(WM_DRAWITEM)
 
         case WM_GETDLGCODE:
-            if ( !IsOfStandardClass() )
+            if ( !IsOfStandardClass() || HasFlag(wxWANTS_CHARS) )
             {
                 // we always want to get the char events
                 rc.result = DLGC_WANTCHARS;
 
             {
                 // we always want to get the char events
                 rc.result = DLGC_WANTCHARS;
 
-                if ( GetWindowStyleFlag() & wxWANTS_CHARS )
+                if ( HasFlag(wxWANTS_CHARS) )
                 {
                     // in fact, we want everything
                     rc.result |= DLGC_WANTARROWS |
                 {
                     // in fact, we want everything
                     rc.result |= DLGC_WANTARROWS |
@@ -2994,50 +3190,48 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
 #if defined(WM_HELP)
         case WM_HELP:
             {
 #if defined(WM_HELP)
         case WM_HELP:
             {
-                // HELPINFO doesn't seem to be supported on WinCE.
+                // by default, WM_HELP is propagated by DefWindowProc() upwards
+                // to the window parent but as we do it ourselves already
+                // (wxHelpEvent is derived from wxCommandEvent), we don't want
+                // to get the other events if we process this message at all
+                processed = true;
+
+                // WM_HELP doesn't use lParam under CE
 #ifndef __WXWINCE__
                 HELPINFO* info = (HELPINFO*) lParam;
 #ifndef __WXWINCE__
                 HELPINFO* info = (HELPINFO*) lParam;
-                // Don't yet process menu help events, just windows
-                if (info->iContextType == HELPINFO_WINDOW)
+                if ( info->iContextType == HELPINFO_WINDOW )
                 {
                 {
-#endif
-                    wxWindowMSW* subjectOfHelp = this;
-                    bool eventProcessed = false;
-                    while (subjectOfHelp && !eventProcessed)
-                    {
-                        wxHelpEvent helpEvent(wxEVT_HELP,
-                                              subjectOfHelp->GetId(),
+#endif // !__WXWINCE__
+                    wxHelpEvent helpEvent
+                                (
+                                    wxEVT_HELP,
+                                    GetId(),
 #ifdef __WXWINCE__
 #ifdef __WXWINCE__
-                                              wxPoint(0,0)
+                                    wxGetMousePosition() // what else?
 #else
 #else
-                                              wxPoint(info->MousePos.x, info->MousePos.y)
+                                    wxPoint(info->MousePos.x, info->MousePos.y)
 #endif
 #endif
-                                              );
-
-                        helpEvent.SetEventObject(this);
-                        eventProcessed =
-                            GetEventHandler()->ProcessEvent(helpEvent);
-
-                        // Go up the window hierarchy until the event is
-                        // handled (or not)
-                        subjectOfHelp = subjectOfHelp->GetParent();
-                    }
+                                );
 
 
-                    processed = eventProcessed;
+                    helpEvent.SetEventObject(this);
+                    GetEventHandler()->ProcessEvent(helpEvent);
 #ifndef __WXWINCE__
                 }
 #ifndef __WXWINCE__
                 }
-                else if (info->iContextType == HELPINFO_MENUITEM)
+                else if ( info->iContextType == HELPINFO_MENUITEM )
                 {
                     wxHelpEvent helpEvent(wxEVT_HELP, info->iCtrlId);
                     helpEvent.SetEventObject(this);
                 {
                     wxHelpEvent helpEvent(wxEVT_HELP, info->iCtrlId);
                     helpEvent.SetEventObject(this);
-                    processed = GetEventHandler()->ProcessEvent(helpEvent);
+                    GetEventHandler()->ProcessEvent(helpEvent);
 
                 }
 
                 }
-                //else: processed is already false
-#endif
+                else // unknown help event?
+                {
+                    processed = false;
+                }
+#endif // !__WXWINCE__
             }
             break;
             }
             break;
-#endif
+#endif // WM_HELP
 
 #if !defined(__WXWINCE__)
         case WM_CONTEXTMENU:
 
 #if !defined(__WXWINCE__)
         case WM_CONTEXTMENU:
@@ -3065,6 +3259,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
             break;
 #endif
 
             break;
 #endif
 
+#if wxUSE_MENUS
         case WM_MENUCHAR:
             // we're only interested in our own menus, not MF_SYSMENU
             if ( HIWORD(wParam) == MF_POPUP )
         case WM_MENUCHAR:
             // we're only interested in our own menus, not MF_SYSMENU
             if ( HIWORD(wParam) == MF_POPUP )
@@ -3078,6 +3273,116 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
                 }
             }
             break;
                 }
             }
             break;
+#endif // wxUSE_MENUS
+
+#ifndef __WXWINCE__
+        case WM_POWERBROADCAST:
+            {
+                bool vetoed;
+                processed = HandlePower(wParam, lParam, &vetoed);
+                rc.result = processed && vetoed ? BROADCAST_QUERY_DENY : TRUE;
+            }
+            break;
+#endif // __WXWINCE__
+
+#if wxUSE_UXTHEME
+        // If we want the default themed border then we need to draw it ourselves
+        case WM_NCCALCSIZE:
+            {
+                wxUxThemeEngine* theme = wxUxThemeEngine::GetIfActive();
+                const wxBorder border = TranslateBorder(GetBorder());
+                if (theme && border == wxBORDER_THEME)
+                {
+                    // first ask the widget to calculate the border size
+                    rc.result = MSWDefWindowProc(message, wParam, lParam);
+                    processed = true;
+
+                    // now alter the client size making room for drawing a themed border
+                    NCCALCSIZE_PARAMS *csparam = NULL;
+                    RECT rect;
+                    if (wParam)
+                    {
+                        csparam = (NCCALCSIZE_PARAMS*)lParam;
+                        rect = csparam->rgrc[0];
+                    }
+                    else
+                    {
+                        rect = *((RECT*)lParam);
+                    }
+                    wxUxThemeHandle hTheme((wxWindow *)this, L"EDIT");
+                    RECT rcClient = { 0, 0, 0, 0 };
+                    wxClientDC dc((wxWindow *)this);
+
+                    if (theme->GetThemeBackgroundContentRect(
+                            hTheme, GetHdcOf(dc), EP_EDITTEXT, ETS_NORMAL,
+                            &rect, &rcClient) == S_OK)
+                    {
+                        InflateRect(&rcClient, -1, -1);
+                        if (wParam)
+                            csparam->rgrc[0] = rcClient;
+                        else
+                            *((RECT*)lParam) = rcClient;
+                        rc.result = WVR_REDRAW;
+                    }
+                }
+            }
+            break;
+
+        case WM_NCPAINT:
+            {
+                wxUxThemeEngine* theme = wxUxThemeEngine::GetIfActive();
+                const wxBorder border = TranslateBorder(GetBorder());
+                if (theme && border == wxBORDER_THEME)
+                {
+                    // first ask the widget to paint its non-client area, such as scrollbars, etc.
+                    rc.result = MSWDefWindowProc(message, wParam, lParam);
+                    processed = true;
+
+                    wxUxThemeHandle hTheme((wxWindow *)this, L"EDIT");
+                    wxWindowDC dc((wxWindow *)this);
+
+                    // Clip the DC so that you only draw on the non-client area
+                    RECT rcBorder;
+                    wxCopyRectToRECT(GetSize(), rcBorder);
+
+                    RECT rcClient;
+                    theme->GetThemeBackgroundContentRect(
+                        hTheme, GetHdcOf(dc), EP_EDITTEXT, ETS_NORMAL, &rcBorder, &rcClient);
+                    InflateRect(&rcClient, -1, -1);
+
+                    ::ExcludeClipRect(GetHdcOf(dc), rcClient.left, rcClient.top,
+                                      rcClient.right, rcClient.bottom);
+
+                    // Make sure the background is in a proper state
+                    if (theme->IsThemeBackgroundPartiallyTransparent(hTheme, EP_EDITTEXT, ETS_NORMAL))
+                    {
+                        theme->DrawThemeParentBackground(GetHwnd(), GetHdcOf(dc), &rcBorder);
+                    }
+
+                    // Draw the border
+                    int nState;
+                    if ( !IsEnabled() )
+                        nState = ETS_DISABLED;
+                    // should we check this?
+                    //else if ( ::GetWindowLong(GetHwnd(), GWL_STYLE) & ES_READONLY)
+                    //    nState = ETS_READONLY;
+                    else
+                        nState = ETS_NORMAL;
+                    theme->DrawThemeBackground(hTheme, GetHdcOf(dc), EP_EDITTEXT, nState, &rcBorder, NULL);
+                }
+            }
+            break;
+
+#endif // wxUSE_UXTHEME
+
+        default:
+            // try a custom message handler
+            const MSWMessageHandlers::const_iterator
+                i = gs_messageHandlers.find(message);
+            if ( i != gs_messageHandlers.end() )
+            {
+                processed = (*i->second)(this, message, wParam, lParam);
+            }
     }
 
     if ( !processed )
     }
 
     if ( !processed )
@@ -3264,8 +3569,8 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass,
     m_hWnd = (WXHWND)::CreateWindowEx
                        (
                         extendedStyle,
     m_hWnd = (WXHWND)::CreateWindowEx
                        (
                         extendedStyle,
-                        className,
-                        title ? title : m_windowName.c_str(),
+                        className.wx_str(),
+                        title ? title : m_windowName.wx_str(),
                         style,
                         x, y, w, h,
                         (HWND)MSWGetParent(),
                         style,
                         x, y, w, h,
                         (HWND)MSWGetParent(),
@@ -3377,7 +3682,7 @@ bool wxWindowMSW::HandleTooltipNotify(WXUINT code,
         // Truncate tooltip length if needed as otherwise we might not have
         // enough space for it in the buffer and MultiByteToWideChar() would
         // return an error
         // Truncate tooltip length if needed as otherwise we might not have
         // enough space for it in the buffer and MultiByteToWideChar() would
         // return an error
-        size_t tipLength = wxMin(ttip.Len(), WXSIZEOF(buf) - 1);
+        size_t tipLength = wxMin(ttip.length(), WXSIZEOF(buf) - 1);
 
         // Convert to WideChar without adding the NULL character. The NULL
         // character is added afterwards (this is more efficient).
 
         // Convert to WideChar without adding the NULL character. The NULL
         // character is added afterwards (this is more efficient).
@@ -3385,7 +3690,7 @@ bool wxWindowMSW::HandleTooltipNotify(WXUINT code,
                     (
                         CP_ACP,
                         0,                      // no flags
                     (
                         CP_ACP,
                         0,                      // no flags
-                        ttip,
+                        ttip.wx_str(),
                         tipLength,
                         buf,
                         WXSIZEOF(buf) - 1
                         tipLength,
                         buf,
                         WXSIZEOF(buf) - 1
@@ -3703,63 +4008,56 @@ bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd),
 {
 #ifndef __WXMICROWIN__
     // the logic is as follows:
 {
 #ifndef __WXMICROWIN__
     // the logic is as follows:
-    // -1. don't set cursor for non client area, including but not limited to
-    //     the title bar, scrollbars, &c
-    //  0. allow the user to override default behaviour by using EVT_SET_CURSOR
-    //  1. if we have the cursor set it unless wxIsBusy()
-    //  2. if we're a top level window, set some cursor anyhow
-    //  3. if wxIsBusy(), set the busy cursor, otherwise the global one
+    //  0. if we're busy, set the busy cursor (even for non client elements)
+    //  1. don't set custom cursor for non client area of enabled windows
+    //  2. ask user EVT_SET_CURSOR handler for the cursor
+    //  3. if still no cursor but we're in a TLW, set the global cursor
 
 
-    if ( nHitTest != HTCLIENT )
+    HCURSOR hcursor = 0;
+    if ( wxIsBusy() )
     {
     {
-        return false;
+        hcursor = wxGetCurrentBusyCursor();
     }
     }
+    else // not busy
+    {
+        if ( nHitTest != HTCLIENT )
+            return false;
 
 
-    HCURSOR hcursor = 0;
-
-    // first ask the user code - it may wish to set the cursor in some very
-    // specific way (for example, depending on the current position)
-    POINT pt;
+        // first ask the user code - it may wish to set the cursor in some very
+        // specific way (for example, depending on the current position)
+        POINT pt;
 #ifdef __WXWINCE__
 #ifdef __WXWINCE__
-    if ( !::GetCursorPosWinCE(&pt))
+        if ( !::GetCursorPosWinCE(&pt))
 #else
 #else
-    if ( !::GetCursorPos(&pt) )
+        if ( !::GetCursorPos(&pt) )
 #endif
 #endif
-    {
-        wxLogLastError(wxT("GetCursorPos"));
-    }
-
-    int x = pt.x,
-        y = pt.y;
-    ScreenToClient(&x, &y);
-    wxSetCursorEvent event(x, y);
-
-    bool processedEvtSetCursor = GetEventHandler()->ProcessEvent(event);
-    if ( processedEvtSetCursor && event.HasCursor() )
-    {
-        hcursor = GetHcursorOf(event.GetCursor());
-    }
+        {
+            wxLogLastError(wxT("GetCursorPos"));
+        }
 
 
-    if ( !hcursor )
-    {
-        bool isBusy = wxIsBusy();
+        int x = pt.x,
+            y = pt.y;
+        ScreenToClient(&x, &y);
+        wxSetCursorEvent event(x, y);
 
 
-        // the test for processedEvtSetCursor is here to prevent using m_cursor
-        // if the user code caught EVT_SET_CURSOR() and returned nothing from
-        // it - this is a way to say that our cursor shouldn't be used for this
-        // point
-        if ( !processedEvtSetCursor && m_cursor.Ok() )
+        bool processedEvtSetCursor = GetEventHandler()->ProcessEvent(event);
+        if ( processedEvtSetCursor && event.HasCursor() )
         {
         {
-            hcursor = GetHcursorOf(m_cursor);
+            hcursor = GetHcursorOf(event.GetCursor());
         }
 
         }
 
-        if ( !GetParent() )
+        if ( !hcursor )
         {
         {
-            if ( isBusy )
+            // the test for processedEvtSetCursor is here to prevent using
+            // m_cursor if the user code caught EVT_SET_CURSOR() and returned
+            // nothing from it - this is a way to say that our cursor shouldn't
+            // be used for this point
+            if ( !processedEvtSetCursor && m_cursor.Ok() )
             {
             {
-                hcursor = wxGetCurrentBusyCursor();
+                hcursor = GetHcursorOf(m_cursor);
             }
             }
-            else if ( !hcursor )
+
+            if ( !hcursor && !GetParent() )
             {
                 const wxCursor *cursor = wxGetGlobalCursor();
                 if ( cursor && cursor->Ok() )
             {
                 const wxCursor *cursor = wxGetGlobalCursor();
                 if ( cursor && cursor->Ok() )
@@ -3770,10 +4068,9 @@ bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd),
         }
     }
 
         }
     }
 
+
     if ( hcursor )
     {
     if ( hcursor )
     {
-//        wxLogDebug("HandleSetCursor: Setting cursor %ld", (long) hcursor);
-
         ::SetCursor(hcursor);
 
         // cursor set, stop here
         ::SetCursor(hcursor);
 
         // cursor set, stop here
@@ -3785,6 +4082,82 @@ bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd),
     return false;
 }
 
     return false;
 }
 
+bool wxWindowMSW::HandlePower(WXWPARAM WXUNUSED_IN_WINCE(wParam),
+                              WXLPARAM WXUNUSED(lParam),
+                              bool *WXUNUSED_IN_WINCE(vetoed))
+{
+#ifdef __WXWINCE__
+    // FIXME
+    return false;
+#else
+    wxEventType evtType;
+    switch ( wParam )
+    {
+        case PBT_APMQUERYSUSPEND:
+            evtType = wxEVT_POWER_SUSPENDING;
+            break;
+
+        case PBT_APMQUERYSUSPENDFAILED:
+            evtType = wxEVT_POWER_SUSPEND_CANCEL;
+            break;
+
+        case PBT_APMSUSPEND:
+            evtType = wxEVT_POWER_SUSPENDED;
+            break;
+
+        case PBT_APMRESUMESUSPEND:
+#ifdef PBT_APMRESUMEAUTOMATIC
+        case PBT_APMRESUMEAUTOMATIC:
+#endif
+            evtType = wxEVT_POWER_RESUME;
+            break;
+
+        default:
+            wxLogDebug(_T("Unknown WM_POWERBROADCAST(%d) event"), wParam);
+            // fall through
+
+        // these messages are currently not mapped to wx events
+        case PBT_APMQUERYSTANDBY:
+        case PBT_APMQUERYSTANDBYFAILED:
+        case PBT_APMSTANDBY:
+        case PBT_APMRESUMESTANDBY:
+        case PBT_APMBATTERYLOW:
+        case PBT_APMPOWERSTATUSCHANGE:
+        case PBT_APMOEMEVENT:
+        case PBT_APMRESUMECRITICAL:
+            evtType = wxEVT_NULL;
+            break;
+    }
+
+    // don't handle unknown messages
+    if ( evtType == wxEVT_NULL )
+        return false;
+
+    // TODO: notify about PBTF_APMRESUMEFROMFAILURE in case of resume events?
+
+    wxPowerEvent event(evtType);
+    if ( !GetEventHandler()->ProcessEvent(event) )
+        return false;
+
+    *vetoed = event.IsVetoed();
+
+    return true;
+#endif
+}
+
+bool wxWindowMSW::IsDoubleBuffered() const
+{
+    for ( const wxWindowMSW *wnd = this;
+          wnd && !wnd->IsTopLevel(); wnd =
+          wnd->GetParent() )
+    {
+        if ( ::GetWindowLong(GetHwndOf(wnd), GWL_EXSTYLE) & WS_EX_COMPOSITED )
+            return true;
+    }
+
+    return false;
+}
+
 // ---------------------------------------------------------------------------
 // owner drawn stuff
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 // owner drawn stuff
 // ---------------------------------------------------------------------------
@@ -3994,9 +4367,13 @@ bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange)
 
 bool wxWindowMSW::HandleCaptureChanged(WXHWND hWndGainedCapture)
 {
 
 bool wxWindowMSW::HandleCaptureChanged(WXHWND hWndGainedCapture)
 {
-    wxMouseCaptureChangedEvent event(GetId(), wxFindWinFromHandle(hWndGainedCapture));
-    event.SetEventObject(this);
+    // notify windows on the capture stack about lost capture
+    // (see http://sourceforge.net/tracker/index.php?func=detail&aid=1153662&group_id=9863&atid=109863):
+    wxWindowBase::NotifyCaptureLost();
 
 
+    wxWindow *win = wxFindWinFromHandle(hWndGainedCapture);
+    wxMouseCaptureChangedEvent event(GetId(), win);
+    event.SetEventObject(this);
     return GetEventHandler()->ProcessEvent(event);
 }
 
     return GetEventHandler()->ProcessEvent(event);
 }
 
@@ -4177,6 +4554,10 @@ bool wxWindowMSW::HandlePaint()
     eventNc.SetEventObject(this);
     GetEventHandler()->ProcessEvent(eventNc);
 
     eventNc.SetEventObject(this);
     GetEventHandler()->ProcessEvent(eventNc);
 
+    // don't keep an HRGN we don't need any longer (GetUpdateRegion() can only
+    // be called from inside the event handlers called above)
+    m_updateRegion.Clear();
+
     return processed;
 }
 
     return processed;
 }
 
@@ -4196,7 +4577,7 @@ void wxWindowMSW::OnPaint(wxPaintEvent& event)
 
 bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc)
 {
 
 bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc)
 {
-    wxDCTemp dc(hdc);
+    wxDCTemp dc(hdc, GetClientSize());
 
     dc.SetHDC(hdc);
     dc.SetWindow((wxWindow *)this);
 
     dc.SetHDC(hdc);
     dc.SetWindow((wxWindow *)this);
@@ -4373,6 +4754,24 @@ bool wxWindowMSW::HandleMoving(wxRect& rect)
     return rc;
 }
 
     return rc;
 }
 
+bool wxWindowMSW::HandleEnterSizeMove()
+{
+    wxMoveEvent event(wxPoint(0,0), m_windowId);
+    event.SetEventType(wxEVT_MOVE_START);
+    event.SetEventObject(this);
+
+    return GetEventHandler()->ProcessEvent(event);
+}
+
+bool wxWindowMSW::HandleExitSizeMove()
+{
+    wxMoveEvent event(wxPoint(0,0), m_windowId);
+    event.SetEventType(wxEVT_MOVE_END);
+    event.SetEventObject(this);
+
+    return GetEventHandler()->ProcessEvent(event);
+}
+
 bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam)
 {
 #if USE_DEFERRED_SIZING
 bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam)
 {
 #if USE_DEFERRED_SIZING
@@ -4524,8 +4923,11 @@ bool wxWindowMSW::HandleGetMinMaxInfo(void *WXUNUSED_IN_WINCE(mmInfo))
 // command messages
 // ---------------------------------------------------------------------------
 
 // command messages
 // ---------------------------------------------------------------------------
 
-bool wxWindowMSW::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control)
+bool wxWindowMSW::HandleCommand(WXWORD id_, WXWORD cmd, WXHWND control)
 {
 {
+    // sign extend to int from short before comparing with the other int ids
+    int id = (signed short)id_;
+
 #if wxUSE_MENUS_NATIVE
     if ( !cmd && wxCurrentPopupMenu )
     {
 #if wxUSE_MENUS_NATIVE
     if ( !cmd && wxCurrentPopupMenu )
     {
@@ -4548,8 +4950,7 @@ bool wxWindowMSW::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control)
     // try the id
     if ( !win )
     {
     // try the id
     if ( !win )
     {
-        // must cast to a signed type before comparing with other ids!
-        win = FindItem((signed short)id);
+        win = FindItem(id);
     }
 
     if ( win )
     }
 
     if ( win )
@@ -4615,7 +5016,11 @@ void wxWindowMSW::InitMouseEvent(wxMouseEvent& event,
     event.m_leftDown = (flags & MK_LBUTTON) != 0;
     event.m_middleDown = (flags & MK_MBUTTON) != 0;
     event.m_rightDown = (flags & MK_RBUTTON) != 0;
     event.m_leftDown = (flags & MK_LBUTTON) != 0;
     event.m_middleDown = (flags & MK_MBUTTON) != 0;
     event.m_rightDown = (flags & MK_RBUTTON) != 0;
-    event.m_altDown = ::GetKeyState(VK_MENU) < 0;
+#ifdef wxHAS_XBUTTON
+    event.m_aux1Down = (flags & MK_XBUTTON1) != 0;
+    event.m_aux2Down = (flags & MK_XBUTTON2) != 0;
+#endif // wxHAS_XBUTTON
+    event.m_altDown = ::wxIsAltDown();
 
 #ifndef __WXWINCE__
     event.SetTimestamp(::GetMessageTime());
 
 #ifndef __WXWINCE__
     event.SetTimestamp(::GetMessageTime());
@@ -4713,9 +5118,29 @@ bool wxWindowMSW::HandleMouseEvent(WXUINT msg, int x, int y, WXUINT flags)
         wxEVT_RIGHT_DCLICK,
         wxEVT_MIDDLE_DOWN,
         wxEVT_MIDDLE_UP,
         wxEVT_RIGHT_DCLICK,
         wxEVT_MIDDLE_DOWN,
         wxEVT_MIDDLE_UP,
-        wxEVT_MIDDLE_DCLICK
+        wxEVT_MIDDLE_DCLICK,
+        0, // this one is for wxEVT_MOTION which is not used here
+        wxEVT_AUX1_DOWN,
+        wxEVT_AUX1_UP,
+        wxEVT_AUX1_DCLICK,
+        wxEVT_AUX2_DOWN,
+        wxEVT_AUX2_UP,
+        wxEVT_AUX2_DCLICK
     };
 
     };
 
+#ifdef wxHAS_XBUTTON
+    // the same messages are used for both auxillary mouse buttons so we need
+    // to adjust the index manually
+    switch ( msg )
+    {
+        case WM_XBUTTONDOWN:
+        case WM_XBUTTONUP:
+        case WM_XBUTTONDBLCLK:
+            if ( flags & MK_XBUTTON2 )
+                msg += wxEVT_AUX2_DOWN - wxEVT_AUX1_DOWN;
+    }
+#endif // wxHAS_XBUTTON
+
     wxMouseEvent event(eventsMouse[msg - WM_MOUSEMOVE]);
     InitMouseEvent(event, x, y, flags);
 
     wxMouseEvent event(eventsMouse[msg - WM_MOUSEMOVE]);
     InitMouseEvent(event, x, y, flags);
 
@@ -4736,14 +5161,41 @@ bool wxWindowMSW::HandleMouseMove(int x, int y, WXUINT flags)
             m_mouseInWindow = true;
 
 #ifdef HAVE_TRACKMOUSEEVENT
             m_mouseInWindow = true;
 
 #ifdef HAVE_TRACKMOUSEEVENT
-            WinStruct<TRACKMOUSEEVENT> trackinfo;
+            typedef BOOL (WINAPI *_TrackMouseEvent_t)(LPTRACKMOUSEEVENT);
+#ifdef __WXWINCE__
+            static const _TrackMouseEvent_t
+                s_pfn_TrackMouseEvent = _TrackMouseEvent;
+#else // !__WXWINCE__
+            static _TrackMouseEvent_t s_pfn_TrackMouseEvent;
+            static bool s_initDone = false;
+            if ( !s_initDone )
+            {
+                wxLogNull noLog;
+
+                wxDynamicLibrary dllComCtl32(_T("comctl32.dll"), wxDL_VERBATIM);
+                if ( dllComCtl32.IsLoaded() )
+                {
+                    s_pfn_TrackMouseEvent = (_TrackMouseEvent_t)
+                        dllComCtl32.GetSymbol(_T("_TrackMouseEvent"));
+                }
+
+                s_initDone = true;
+
+                // notice that it's ok to unload comctl32.dll here as it won't
+                // be really unloaded, being still in use because we link to it
+                // statically too
+            }
 
 
-            trackinfo.dwFlags = TME_LEAVE;
-            trackinfo.hwndTrack = GetHwnd();
+            if ( s_pfn_TrackMouseEvent )
+#endif // __WXWINCE__/!__WXWINCE__
+            {
+                WinStruct<TRACKMOUSEEVENT> trackinfo;
 
 
-            // Use the commctrl.h _TrackMouseEvent(), which will call the real
-            // TrackMouseEvent() if available or emulate it
-            _TrackMouseEvent(&trackinfo);
+                trackinfo.dwFlags = TME_LEAVE;
+                trackinfo.hwndTrack = GetHwnd();
+
+                (*s_pfn_TrackMouseEvent)(&trackinfo);
+            }
 #endif // HAVE_TRACKMOUSEEVENT
 
             wxMouseEvent event(wxEVT_ENTER_WINDOW);
 #endif // HAVE_TRACKMOUSEEVENT
 
             wxMouseEvent event(wxEVT_ENTER_WINDOW);
@@ -4753,7 +5205,7 @@ bool wxWindowMSW::HandleMouseMove(int x, int y, WXUINT flags)
         }
     }
 #ifdef HAVE_TRACKMOUSEEVENT
         }
     }
 #ifdef HAVE_TRACKMOUSEEVENT
-    else
+    else // mouse not in window
     {
         // Check if we need to send a LEAVE event
         // Windows doesn't send WM_MOUSELEAVE if the mouse has been captured so
     {
         // Check if we need to send a LEAVE event
         // Windows doesn't send WM_MOUSELEAVE if the mouse has been captured so
@@ -4983,6 +5435,7 @@ bool wxWindowMSW::HandleKeyUp(WXWPARAM wParam, WXLPARAM lParam)
     return GetEventHandler()->ProcessEvent(event);
 }
 
     return GetEventHandler()->ProcessEvent(event);
 }
 
+#if wxUSE_MENUS
 int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel),
                                 WXLPARAM WXUNUSED_IN_WINCE(lParam))
 {
 int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel),
                                 WXLPARAM WXUNUSED_IN_WINCE(lParam))
 {
@@ -5017,7 +5470,7 @@ int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel),
                 //  menu creation code
                 wxMenuItem *item = (wxMenuItem*)mii.dwItemData;
 
                 //  menu creation code
                 wxMenuItem *item = (wxMenuItem*)mii.dwItemData;
 
-                const wxChar *p = wxStrchr(item->GetText(), _T('&'));
+                const wxChar *p = wxStrchr(item->GetItemLabel().wx_str(), _T('&'));
                 while ( p++ )
                 {
                     if ( *p == _T('&') )
                 while ( p++ )
                 {
                     if ( *p == _T('&') )
@@ -5053,6 +5506,19 @@ int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel),
     return wxNOT_FOUND;
 }
 
     return wxNOT_FOUND;
 }
 
+bool wxWindowMSW::HandleClipboardEvent( WXUINT nMsg )
+{
+    const wxEventType type = ( nMsg == WM_CUT ) ? wxEVT_COMMAND_TEXT_CUT :
+                             ( nMsg == WM_COPY ) ? wxEVT_COMMAND_TEXT_COPY :
+                           /*( nMsg == WM_PASTE ) ? */ wxEVT_COMMAND_TEXT_PASTE;
+    wxClipboardTextEvent evt(type, GetId());
+
+    evt.SetEventObject(this);
+
+    return GetEventHandler()->ProcessEvent(evt);
+}
+#endif // wxUSE_MENUS
+
 // ---------------------------------------------------------------------------
 // joystick
 // ---------------------------------------------------------------------------
 // ---------------------------------------------------------------------------
 // joystick
 // ---------------------------------------------------------------------------
@@ -5225,6 +5691,30 @@ bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam,
     return GetEventHandler()->ProcessEvent(event);
 }
 
     return GetEventHandler()->ProcessEvent(event);
 }
 
+// ----------------------------------------------------------------------------
+// custom message handlers
+// ----------------------------------------------------------------------------
+
+/* static */ bool
+wxWindowMSW::MSWRegisterMessageHandler(int msg, MSWMessageHandler handler)
+{
+    wxCHECK_MSG( gs_messageHandlers.find(msg) == gs_messageHandlers.end(),
+                 false, _T("registering handler for the same message twice") );
+
+    gs_messageHandlers[msg] = handler;
+    return true;
+}
+
+/* static */ void
+wxWindowMSW::MSWUnregisterMessageHandler(int msg, MSWMessageHandler handler)
+{
+    const MSWMessageHandlers::iterator i = gs_messageHandlers.find(msg);
+    wxCHECK_RET( i != gs_messageHandlers.end() && i->second == handler,
+                 _T("unregistering non-registered handler?") );
+
+    gs_messageHandlers.erase(i);
+}
+
 // ===========================================================================
 // global functions
 // ===========================================================================
 // ===========================================================================
 // global functions
 // ===========================================================================
@@ -5268,244 +5758,290 @@ int ChooseNormalOrExtended(int lParam, int keyNormal, int keyExtended)
     return !lParam || (lParam & (1 << 24)) ? keyExtended : keyNormal;
 }
 
     return !lParam || (lParam & (1 << 24)) ? keyExtended : keyNormal;
 }
 
+// this array contains the Windows virtual key codes which map one to one to
+// WXK_xxx constants and is used in wxCharCodeMSWToWX/WXToMSW() below
+//
+// note that keys having a normal and numpad version (e.g. WXK_HOME and
+// WXK_NUMPAD_HOME) are not included in this table as the mapping is not 1-to-1
+static const struct wxKeyMapping
+{
+    int vk;
+    wxKeyCode wxk;
+} gs_specialKeys[] =
+{
+    { VK_CANCEL,        WXK_CANCEL },
+    { VK_BACK,          WXK_BACK },
+    { VK_TAB,           WXK_TAB },
+    { VK_CLEAR,         WXK_CLEAR },
+    { VK_SHIFT,         WXK_SHIFT },
+    { VK_CONTROL,       WXK_CONTROL },
+    { VK_MENU ,         WXK_ALT },
+    { VK_PAUSE,         WXK_PAUSE },
+    { VK_CAPITAL,       WXK_CAPITAL },
+    { VK_SPACE,         WXK_SPACE },
+    { VK_ESCAPE,        WXK_ESCAPE },
+    { VK_SELECT,        WXK_SELECT },
+    { VK_PRINT,         WXK_PRINT },
+    { VK_EXECUTE,       WXK_EXECUTE },
+    { VK_SNAPSHOT,      WXK_SNAPSHOT },
+    { VK_HELP,          WXK_HELP },
+
+    { VK_NUMPAD0,       WXK_NUMPAD0 },
+    { VK_NUMPAD1,       WXK_NUMPAD1 },
+    { VK_NUMPAD2,       WXK_NUMPAD2 },
+    { VK_NUMPAD3,       WXK_NUMPAD3 },
+    { VK_NUMPAD4,       WXK_NUMPAD4 },
+    { VK_NUMPAD5,       WXK_NUMPAD5 },
+    { VK_NUMPAD6,       WXK_NUMPAD6 },
+    { VK_NUMPAD7,       WXK_NUMPAD7 },
+    { VK_NUMPAD8,       WXK_NUMPAD8 },
+    { VK_NUMPAD9,       WXK_NUMPAD9 },
+    { VK_MULTIPLY,      WXK_NUMPAD_MULTIPLY },
+    { VK_ADD,           WXK_NUMPAD_ADD },
+    { VK_SUBTRACT,      WXK_NUMPAD_SUBTRACT },
+    { VK_DECIMAL,       WXK_NUMPAD_DECIMAL },
+    { VK_DIVIDE,        WXK_NUMPAD_DIVIDE },
+
+    { VK_F1,            WXK_F1 },
+    { VK_F2,            WXK_F2 },
+    { VK_F3,            WXK_F3 },
+    { VK_F4,            WXK_F4 },
+    { VK_F5,            WXK_F5 },
+    { VK_F6,            WXK_F6 },
+    { VK_F7,            WXK_F7 },
+    { VK_F8,            WXK_F8 },
+    { VK_F9,            WXK_F9 },
+    { VK_F10,           WXK_F10 },
+    { VK_F11,           WXK_F11 },
+    { VK_F12,           WXK_F12 },
+    { VK_F13,           WXK_F13 },
+    { VK_F14,           WXK_F14 },
+    { VK_F15,           WXK_F15 },
+    { VK_F16,           WXK_F16 },
+    { VK_F17,           WXK_F17 },
+    { VK_F18,           WXK_F18 },
+    { VK_F19,           WXK_F19 },
+    { VK_F20,           WXK_F20 },
+    { VK_F21,           WXK_F21 },
+    { VK_F22,           WXK_F22 },
+    { VK_F23,           WXK_F23 },
+    { VK_F24,           WXK_F24 },
+
+    { VK_NUMLOCK,       WXK_NUMLOCK },
+    { VK_SCROLL,        WXK_SCROLL },
+
+#ifdef VK_APPS
+    { VK_LWIN,          WXK_WINDOWS_LEFT },
+    { VK_RWIN,          WXK_WINDOWS_RIGHT },
+    { VK_APPS,          WXK_WINDOWS_MENU },
+#endif // VK_APPS defined
+};
+
 // Returns 0 if was a normal ASCII value, not a special key. This indicates that
 // the key should be ignored by WM_KEYDOWN and processed by WM_CHAR instead.
 // Returns 0 if was a normal ASCII value, not a special key. This indicates that
 // the key should be ignored by WM_KEYDOWN and processed by WM_CHAR instead.
-int wxCharCodeMSWToWX(int keySym, WXLPARAM lParam)
+int wxCharCodeMSWToWX(int vk, WXLPARAM lParam)
 {
 {
-    int id;
-    switch (keySym)
-    {
-        case VK_CANCEL:     id = WXK_CANCEL; break;
-        case VK_BACK:       id = WXK_BACK; break;
-        case VK_TAB:        id = WXK_TAB; break;
-        case VK_CLEAR:      id = WXK_CLEAR; break;
-        case VK_SHIFT:      id = WXK_SHIFT; break;
-        case VK_CONTROL:    id = WXK_CONTROL; break;
-        case VK_MENU :      id = WXK_ALT; break;
-        case VK_PAUSE:      id = WXK_PAUSE; break;
-        case VK_CAPITAL:    id = WXK_CAPITAL; break;
-        case VK_SPACE:      id = WXK_SPACE; break;
-        case VK_ESCAPE:     id = WXK_ESCAPE; break;
-        case VK_SELECT:     id = WXK_SELECT; break;
-        case VK_PRINT:      id = WXK_PRINT; break;
-        case VK_EXECUTE:    id = WXK_EXECUTE; break;
-        case VK_HELP :      id = WXK_HELP; break;
-        case VK_NUMPAD0:    id = WXK_NUMPAD0; break;
-        case VK_NUMPAD1:    id = WXK_NUMPAD1; break;
-        case VK_NUMPAD2:    id = WXK_NUMPAD2; break;
-        case VK_NUMPAD3:    id = WXK_NUMPAD3; break;
-        case VK_NUMPAD4:    id = WXK_NUMPAD4; break;
-        case VK_NUMPAD5:    id = WXK_NUMPAD5; break;
-        case VK_NUMPAD6:    id = WXK_NUMPAD6; break;
-        case VK_NUMPAD7:    id = WXK_NUMPAD7; break;
-        case VK_NUMPAD8:    id = WXK_NUMPAD8; break;
-        case VK_NUMPAD9:    id = WXK_NUMPAD9; break;
-        case VK_MULTIPLY:   id = WXK_NUMPAD_MULTIPLY; break;
-        case VK_ADD:        id = WXK_NUMPAD_ADD; break;
-        case VK_SUBTRACT:   id = WXK_NUMPAD_SUBTRACT; break;
-        case VK_DECIMAL:    id = WXK_NUMPAD_DECIMAL; break;
-        case VK_DIVIDE:     id = WXK_NUMPAD_DIVIDE; break;
-        case VK_F1:         id = WXK_F1; break;
-        case VK_F2:         id = WXK_F2; break;
-        case VK_F3:         id = WXK_F3; break;
-        case VK_F4:         id = WXK_F4; break;
-        case VK_F5:         id = WXK_F5; break;
-        case VK_F6:         id = WXK_F6; break;
-        case VK_F7:         id = WXK_F7; break;
-        case VK_F8:         id = WXK_F8; break;
-        case VK_F9:         id = WXK_F9; break;
-        case VK_F10:        id = WXK_F10; break;
-        case VK_F11:        id = WXK_F11; break;
-        case VK_F12:        id = WXK_F12; break;
-        case VK_F13:        id = WXK_F13; break;
-        case VK_F14:        id = WXK_F14; break;
-        case VK_F15:        id = WXK_F15; break;
-        case VK_F16:        id = WXK_F16; break;
-        case VK_F17:        id = WXK_F17; break;
-        case VK_F18:        id = WXK_F18; break;
-        case VK_F19:        id = WXK_F19; break;
-        case VK_F20:        id = WXK_F20; break;
-        case VK_F21:        id = WXK_F21; break;
-        case VK_F22:        id = WXK_F22; break;
-        case VK_F23:        id = WXK_F23; break;
-        case VK_F24:        id = WXK_F24; break;
-        case VK_NUMLOCK:    id = WXK_NUMLOCK; break;
-        case VK_SCROLL:     id = WXK_SCROLL; break;
+    // check the table first
+    for ( size_t n = 0; n < WXSIZEOF(gs_specialKeys); n++ )
+    {
+        if ( gs_specialKeys[n].vk == vk )
+            return gs_specialKeys[n].wxk;
+    }
 
 
+    // keys requiring special handling
+    int wxk;
+    switch ( vk )
+    {
         // the mapping for these keys may be incorrect on non-US keyboards so
         // maybe we shouldn't map them to ASCII values at all
         // the mapping for these keys may be incorrect on non-US keyboards so
         // maybe we shouldn't map them to ASCII values at all
-        case VK_OEM_1:      id = ';'; break;
-        case VK_OEM_PLUS:   id = '+'; break;
-        case VK_OEM_COMMA:  id = ','; break;
-        case VK_OEM_MINUS:  id = '-'; break;
-        case VK_OEM_PERIOD: id = '.'; break;
-        case VK_OEM_2:      id = '/'; break;
-        case VK_OEM_3:      id = '~'; break;
-        case VK_OEM_4:      id = '['; break;
-        case VK_OEM_5:      id = '\\'; break;
-        case VK_OEM_6:      id = ']'; break;
-        case VK_OEM_7:      id = '\''; break;
-
-#ifdef VK_APPS
-        case VK_LWIN:       id = WXK_WINDOWS_LEFT; break;
-        case VK_RWIN:       id = WXK_WINDOWS_RIGHT; break;
-        case VK_APPS:       id = WXK_WINDOWS_MENU; break;
-#endif // VK_APPS defined
+        case VK_OEM_1:      wxk = ';'; break;
+        case VK_OEM_PLUS:   wxk = '+'; break;
+        case VK_OEM_COMMA:  wxk = ','; break;
+        case VK_OEM_MINUS:  wxk = '-'; break;
+        case VK_OEM_PERIOD: wxk = '.'; break;
+        case VK_OEM_2:      wxk = '/'; break;
+        case VK_OEM_3:      wxk = '~'; break;
+        case VK_OEM_4:      wxk = '['; break;
+        case VK_OEM_5:      wxk = '\\'; break;
+        case VK_OEM_6:      wxk = ']'; break;
+        case VK_OEM_7:      wxk = '\''; break;
 
         // handle extended keys
         case VK_PRIOR:
 
         // handle extended keys
         case VK_PRIOR:
-            id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_PAGEUP, WXK_PAGEUP);
+            wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_PAGEUP, WXK_PAGEUP);
             break;
             break;
+
         case VK_NEXT:
         case VK_NEXT:
-            id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_PAGEDOWN, WXK_PAGEDOWN);
+            wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_PAGEDOWN, WXK_PAGEDOWN);
             break;
             break;
+
         case VK_END:
         case VK_END:
-            id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_END, WXK_END);
+            wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_END, WXK_END);
             break;
             break;
+
         case VK_HOME:
         case VK_HOME:
-            id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_HOME, WXK_HOME);
+            wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_HOME, WXK_HOME);
             break;
             break;
+
         case VK_LEFT:
         case VK_LEFT:
-            id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_LEFT, WXK_LEFT);
+            wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_LEFT, WXK_LEFT);
             break;
             break;
+
         case VK_UP:
         case VK_UP:
-            id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_UP, WXK_UP);
+            wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_UP, WXK_UP);
             break;
             break;
+
         case VK_RIGHT:
         case VK_RIGHT:
-            id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_RIGHT, WXK_RIGHT);
+            wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_RIGHT, WXK_RIGHT);
             break;
             break;
+
         case VK_DOWN:
         case VK_DOWN:
-            id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DOWN, WXK_DOWN);
+            wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DOWN, WXK_DOWN);
             break;
             break;
+
         case VK_INSERT:
         case VK_INSERT:
-            id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_INSERT, WXK_INSERT);
+            wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_INSERT, WXK_INSERT);
             break;
             break;
+
         case VK_DELETE:
         case VK_DELETE:
-            id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DELETE, WXK_DELETE);
+            wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DELETE, WXK_DELETE);
             break;
             break;
+
         case VK_RETURN:
             // don't use ChooseNormalOrExtended() here as the keys are reversed
             // here: numpad enter is the extended one
         case VK_RETURN:
             // don't use ChooseNormalOrExtended() here as the keys are reversed
             // here: numpad enter is the extended one
-            id = lParam && (lParam & (1 << 24)) ? WXK_NUMPAD_ENTER : WXK_RETURN;
+            wxk = lParam && (lParam & (1 << 24)) ? WXK_NUMPAD_ENTER : WXK_RETURN;
             break;
 
         default:
             break;
 
         default:
-            id = 0;
-    }
-
-    return id;
-}
-
-WXWORD wxCharCodeWXToMSW(int id, bool *isVirtual)
-{
-    *isVirtual = true;
-    WXWORD keySym;
-    switch (id)
-    {
-    case WXK_CANCEL:    keySym = VK_CANCEL; break;
-    case WXK_CLEAR:     keySym = VK_CLEAR; break;
-    case WXK_SHIFT:     keySym = VK_SHIFT; break;
-    case WXK_CONTROL:   keySym = VK_CONTROL; break;
-    case WXK_ALT:       keySym = VK_MENU; break;
-    case WXK_PAUSE:     keySym = VK_PAUSE; break;
-    case WXK_CAPITAL:   keySym = VK_CAPITAL; break;
-    case WXK_PAGEUP:    keySym = VK_PRIOR; break;
-    case WXK_PAGEDOWN:  keySym = VK_NEXT; break;
-    case WXK_END:       keySym = VK_END; break;
-    case WXK_HOME :     keySym = VK_HOME; break;
-    case WXK_LEFT :     keySym = VK_LEFT; break;
-    case WXK_UP:        keySym = VK_UP; break;
-    case WXK_RIGHT:     keySym = VK_RIGHT; break;
-    case WXK_DOWN :     keySym = VK_DOWN; break;
-    case WXK_SELECT:    keySym = VK_SELECT; break;
-    case WXK_PRINT:     keySym = VK_PRINT; break;
-    case WXK_EXECUTE:   keySym = VK_EXECUTE; break;
-    case WXK_INSERT:    keySym = VK_INSERT; break;
-    case WXK_DELETE:    keySym = VK_DELETE; break;
-    case WXK_HELP :     keySym = VK_HELP; break;
-    case WXK_NUMPAD0:   keySym = VK_NUMPAD0; break;
-    case WXK_NUMPAD1:   keySym = VK_NUMPAD1; break;
-    case WXK_NUMPAD2:   keySym = VK_NUMPAD2; break;
-    case WXK_NUMPAD3:   keySym = VK_NUMPAD3; break;
-    case WXK_NUMPAD4:   keySym = VK_NUMPAD4; break;
-    case WXK_NUMPAD5:   keySym = VK_NUMPAD5; break;
-    case WXK_NUMPAD6:   keySym = VK_NUMPAD6; break;
-    case WXK_NUMPAD7:   keySym = VK_NUMPAD7; break;
-    case WXK_NUMPAD8:   keySym = VK_NUMPAD8; break;
-    case WXK_NUMPAD9:   keySym = VK_NUMPAD9; break;
-    case WXK_NUMPAD_MULTIPLY:  keySym = VK_MULTIPLY; break;
-    case WXK_NUMPAD_ADD:       keySym = VK_ADD; break;
-    case WXK_NUMPAD_SUBTRACT:  keySym = VK_SUBTRACT; break;
-    case WXK_NUMPAD_DECIMAL:   keySym = VK_DECIMAL; break;
-    case WXK_NUMPAD_DIVIDE:    keySym = VK_DIVIDE; break;
-    case WXK_F1:        keySym = VK_F1; break;
-    case WXK_F2:        keySym = VK_F2; break;
-    case WXK_F3:        keySym = VK_F3; break;
-    case WXK_F4:        keySym = VK_F4; break;
-    case WXK_F5:        keySym = VK_F5; break;
-    case WXK_F6:        keySym = VK_F6; break;
-    case WXK_F7:        keySym = VK_F7; break;
-    case WXK_F8:        keySym = VK_F8; break;
-    case WXK_F9:        keySym = VK_F9; break;
-    case WXK_F10:       keySym = VK_F10; break;
-    case WXK_F11:       keySym = VK_F11; break;
-    case WXK_F12:       keySym = VK_F12; break;
-    case WXK_F13:       keySym = VK_F13; break;
-    case WXK_F14:       keySym = VK_F14; break;
-    case WXK_F15:       keySym = VK_F15; break;
-    case WXK_F16:       keySym = VK_F16; break;
-    case WXK_F17:       keySym = VK_F17; break;
-    case WXK_F18:       keySym = VK_F18; break;
-    case WXK_F19:       keySym = VK_F19; break;
-    case WXK_F20:       keySym = VK_F20; break;
-    case WXK_F21:       keySym = VK_F21; break;
-    case WXK_F22:       keySym = VK_F22; break;
-    case WXK_F23:       keySym = VK_F23; break;
-    case WXK_F24:       keySym = VK_F24; break;
-    case WXK_NUMLOCK:   keySym = VK_NUMLOCK; break;
-    case WXK_SCROLL:    keySym = VK_SCROLL; break;
-    default:
-        {
-            *isVirtual = false;
-            keySym = (WORD)id;
+            wxk = 0;
+    }
+
+    return wxk;
+}
+
+WXWORD wxCharCodeWXToMSW(int wxk, bool *isVirtual)
+{
+    if ( isVirtual )
+        *isVirtual = true;
+
+    // check the table first
+    for ( size_t n = 0; n < WXSIZEOF(gs_specialKeys); n++ )
+    {
+        if ( gs_specialKeys[n].wxk == wxk )
+            return gs_specialKeys[n].vk;
+    }
+
+    // and then check for special keys not included in the table
+    WXWORD vk;
+    switch ( wxk )
+    {
+        case WXK_PAGEUP:
+        case WXK_NUMPAD_PAGEUP:
+            vk = VK_PRIOR;
+            break;
+
+        case WXK_PAGEDOWN:
+        case WXK_NUMPAD_PAGEDOWN:
+            vk = VK_NEXT;
+            break;
+
+        case WXK_END:
+        case WXK_NUMPAD_END:
+            vk = VK_END;
+            break;
+
+        case WXK_HOME:
+        case WXK_NUMPAD_HOME:
+            vk = VK_HOME;
+            break;
+
+        case WXK_LEFT:
+        case WXK_NUMPAD_LEFT:
+            vk = VK_LEFT;
+            break;
+
+        case WXK_UP:
+        case WXK_NUMPAD_UP:
+            vk = VK_UP;
+            break;
+
+        case WXK_RIGHT:
+        case WXK_NUMPAD_RIGHT:
+            vk = VK_RIGHT;
+            break;
+
+        case WXK_DOWN:
+        case WXK_NUMPAD_DOWN:
+            vk = VK_DOWN;
+            break;
+
+        case WXK_INSERT:
+        case WXK_NUMPAD_INSERT:
+            vk = VK_INSERT;
+            break;
+
+        case WXK_DELETE:
+        case WXK_NUMPAD_DELETE:
+            vk = VK_DELETE;
+            break;
+
+        default:
+            if ( isVirtual )
+                *isVirtual = false;
+            vk = (WXWORD)wxk;
+            break;
+    }
+
+    return vk;
+}
+
+#ifndef SM_SWAPBUTTON
+    #define SM_SWAPBUTTON 23
+#endif
+
+// small helper for wxGetKeyState() and wxGetMouseState()
+static inline bool wxIsKeyDown(WXWORD vk)
+{
+    switch (vk)
+    {
+        case VK_LBUTTON:
+            if (GetSystemMetrics(SM_SWAPBUTTON)) vk = VK_RBUTTON;
+            break;
+        case VK_RBUTTON:
+            if (GetSystemMetrics(SM_SWAPBUTTON)) vk = VK_LBUTTON;
             break;
             break;
-        }
     }
     }
-    return keySym;
+    // the low order bit indicates whether the key was pressed since the last
+    // call and the high order one indicates whether it is down right now and
+    // we only want that one
+    return (GetAsyncKeyState(vk) & (1<<15)) != 0;
 }
 
 bool wxGetKeyState(wxKeyCode key)
 {
 }
 
 bool wxGetKeyState(wxKeyCode key)
 {
-    bool bVirtual;
+    // although this does work under Windows, it is not supported under other
+    // platforms so don't allow it, you must use wxGetMouseState() instead
+    wxASSERT_MSG( key != VK_LBUTTON &&
+                    key != VK_RBUTTON &&
+                        key != VK_MBUTTON,
+                    wxT("can't use wxGetKeyState() for mouse buttons") );
 
 
-    wxASSERT_MSG(key != WXK_LBUTTON && key != WXK_RBUTTON && key !=
-        WXK_MBUTTON, wxT("can't use wxGetKeyState() for mouse buttons"));
+    const WXWORD vk = wxCharCodeWXToMSW(key);
 
 
-//High order with GetAsyncKeyState only available on WIN32
-#ifdef __WIN32__
-    //If the requested key is a LED key, return
-    //true if the led is pressed
-    if (key == WXK_NUMLOCK ||
-        key == WXK_CAPITAL ||
-        key == WXK_SCROLL)
+    // if the requested key is a LED key, return true if the led is pressed
+    if ( key == WXK_NUMLOCK || key == WXK_CAPITAL || key == WXK_SCROLL )
     {
     {
-#endif
-        //low order bit means LED is highlighted,
-        //high order means key is down
-        //Here, for compat with other ports we want both
-        return GetKeyState( wxCharCodeWXToMSW(key, &bVirtual) ) != 0;
+        // low order bit means LED is highlighted and high order one means the
+        // key is down; for compatibility with the other ports return true if
+        // either one is set
+        return GetKeyState(vk) != 0;
 
 
-#ifdef __WIN32__
     }
     }
-    else
+    else // normal key
     {
     {
-        //normal key
-        //low order bit means key pressed since last call
-        //high order means key is down
-        //We want only the high order bit - the key may not be down if only low order
-        return ( GetAsyncKeyState( wxCharCodeWXToMSW(key, &bVirtual) ) & (1<<15) ) != 0;
+        return wxIsKeyDown(vk);
     }
     }
-#endif
 }
 
 
 }
 
 
@@ -5517,13 +6053,17 @@ wxMouseState wxGetMouseState()
 
     ms.SetX(pt.x);
     ms.SetY(pt.y);
 
     ms.SetX(pt.x);
     ms.SetY(pt.y);
-    ms.SetLeftDown( (GetAsyncKeyState(VK_LBUTTON) & (1<<15)) != 0 );
-    ms.SetMiddleDown( (GetAsyncKeyState(VK_MBUTTON) & (1<<15)) != 0 );
-    ms.SetRightDown( (GetAsyncKeyState(VK_RBUTTON) & (1<<15)) != 0 );
-
-    ms.SetControlDown( (GetAsyncKeyState(VK_CONTROL) & (1<<15)) != 0 );
-    ms.SetShiftDown( (GetAsyncKeyState(VK_SHIFT) & (1<<15)) != 0 );
-    ms.SetAltDown( (GetAsyncKeyState(VK_MENU) & (1<<15)) != 0 );
+    ms.SetLeftDown(wxIsKeyDown(VK_LBUTTON));
+    ms.SetMiddleDown(wxIsKeyDown(VK_MBUTTON));
+    ms.SetRightDown(wxIsKeyDown(VK_RBUTTON));
+#ifdef wxHAS_XBUTTON
+    ms.SetAux1Down(wxIsKeyDown(VK_XBUTTON1));
+    ms.SetAux2Down(wxIsKeyDown(VK_XBUTTON2));
+#endif // wxHAS_XBUTTON
+
+    ms.SetControlDown(wxIsCtrlDown ());
+    ms.SetShiftDown  (wxIsShiftDown());
+    ms.SetAltDown    (wxIsAltDown  ());
 //    ms.SetMetaDown();
 
     return ms;
 //    ms.SetMetaDown();
 
     return ms;
@@ -5764,6 +6304,46 @@ const wxChar *wxGetMessageName(int message)
         case 0x00A7: return wxT("WM_NCMBUTTONDOWN");
         case 0x00A8: return wxT("WM_NCMBUTTONUP");
         case 0x00A9: return wxT("WM_NCMBUTTONDBLCLK");
         case 0x00A7: return wxT("WM_NCMBUTTONDOWN");
         case 0x00A8: return wxT("WM_NCMBUTTONUP");
         case 0x00A9: return wxT("WM_NCMBUTTONDBLCLK");
+
+        case 0x00B0: return wxT("EM_GETSEL");
+        case 0x00B1: return wxT("EM_SETSEL");
+        case 0x00B2: return wxT("EM_GETRECT");
+        case 0x00B3: return wxT("EM_SETRECT");
+        case 0x00B4: return wxT("EM_SETRECTNP");
+        case 0x00B5: return wxT("EM_SCROLL");
+        case 0x00B6: return wxT("EM_LINESCROLL");
+        case 0x00B7: return wxT("EM_SCROLLCARET");
+        case 0x00B8: return wxT("EM_GETMODIFY");
+        case 0x00B9: return wxT("EM_SETMODIFY");
+        case 0x00BA: return wxT("EM_GETLINECOUNT");
+        case 0x00BB: return wxT("EM_LINEINDEX");
+        case 0x00BC: return wxT("EM_SETHANDLE");
+        case 0x00BD: return wxT("EM_GETHANDLE");
+        case 0x00BE: return wxT("EM_GETTHUMB");
+        case 0x00C1: return wxT("EM_LINELENGTH");
+        case 0x00C2: return wxT("EM_REPLACESEL");
+        case 0x00C4: return wxT("EM_GETLINE");
+        case 0x00C5: return wxT("EM_LIMITTEXT/EM_SETLIMITTEXT"); /* ;win40 Name change */
+        case 0x00C6: return wxT("EM_CANUNDO");
+        case 0x00C7: return wxT("EM_UNDO");
+        case 0x00C8: return wxT("EM_FMTLINES");
+        case 0x00C9: return wxT("EM_LINEFROMCHAR");
+        case 0x00CB: return wxT("EM_SETTABSTOPS");
+        case 0x00CC: return wxT("EM_SETPASSWORDCHAR");
+        case 0x00CD: return wxT("EM_EMPTYUNDOBUFFER");
+        case 0x00CE: return wxT("EM_GETFIRSTVISIBLELINE");
+        case 0x00CF: return wxT("EM_SETREADONLY");
+        case 0x00D0: return wxT("EM_SETWORDBREAKPROC");
+        case 0x00D1: return wxT("EM_GETWORDBREAKPROC");
+        case 0x00D2: return wxT("EM_GETPASSWORDCHAR");
+        case 0x00D3: return wxT("EM_SETMARGINS");
+        case 0x00D4: return wxT("EM_GETMARGINS");
+        case 0x00D5: return wxT("EM_GETLIMITTEXT");
+        case 0x00D6: return wxT("EM_POSFROMCHAR");
+        case 0x00D7: return wxT("EM_CHARFROMPOS");
+        case 0x00D8: return wxT("EM_SETIMESTATUS");
+        case 0x00D9: return wxT("EM_GETIMESTATUS");
+
         case 0x0100: return wxT("WM_KEYDOWN");
         case 0x0101: return wxT("WM_KEYUP");
         case 0x0102: return wxT("WM_CHAR");
         case 0x0100: return wxT("WM_KEYDOWN");
         case 0x0101: return wxT("WM_KEYUP");
         case 0x0102: return wxT("WM_CHAR");
@@ -5789,6 +6369,16 @@ const wxChar *wxGetMessageName(int message)
         case 0x011F: return wxT("WM_MENUSELECT");
         case 0x0120: return wxT("WM_MENUCHAR");
         case 0x0121: return wxT("WM_ENTERIDLE");
         case 0x011F: return wxT("WM_MENUSELECT");
         case 0x0120: return wxT("WM_MENUCHAR");
         case 0x0121: return wxT("WM_ENTERIDLE");
+
+        case 0x0132: return wxT("WM_CTLCOLORMSGBOX");
+        case 0x0133: return wxT("WM_CTLCOLOREDIT");
+        case 0x0134: return wxT("WM_CTLCOLORLISTBOX");
+        case 0x0135: return wxT("WM_CTLCOLORBTN");
+        case 0x0136: return wxT("WM_CTLCOLORDLG");
+        case 0x0137: return wxT("WM_CTLCOLORSCROLLBAR");
+        case 0x0138: return wxT("WM_CTLCOLORSTATIC");
+        case 0x01E1: return wxT("MN_GETHMENU");
+
         case 0x0200: return wxT("WM_MOUSEMOVE");
         case 0x0201: return wxT("WM_LBUTTONDOWN");
         case 0x0202: return wxT("WM_LBUTTONUP");
         case 0x0200: return wxT("WM_MOUSEMOVE");
         case 0x0201: return wxT("WM_LBUTTONDOWN");
         case 0x0202: return wxT("WM_LBUTTONUP");
@@ -5800,6 +6390,9 @@ const wxChar *wxGetMessageName(int message)
         case 0x0208: return wxT("WM_MBUTTONUP");
         case 0x0209: return wxT("WM_MBUTTONDBLCLK");
         case 0x020A: return wxT("WM_MOUSEWHEEL");
         case 0x0208: return wxT("WM_MBUTTONUP");
         case 0x0209: return wxT("WM_MBUTTONDBLCLK");
         case 0x020A: return wxT("WM_MOUSEWHEEL");
+        case 0x020B: return wxT("WM_XBUTTONDOWN");
+        case 0x020C: return wxT("WM_XBUTTONUP");
+        case 0x020D: return wxT("WM_XBUTTONDBLCLK");
         case 0x0210: return wxT("WM_PARENTNOTIFY");
         case 0x0211: return wxT("WM_ENTERMENULOOP");
         case 0x0212: return wxT("WM_EXITMENULOOP");
         case 0x0210: return wxT("WM_PARENTNOTIFY");
         case 0x0211: return wxT("WM_ENTERMENULOOP");
         case 0x0212: return wxT("WM_EXITMENULOOP");
@@ -5833,6 +6426,11 @@ const wxChar *wxGetMessageName(int message)
         case 0x0290: return wxT("WM_IME_KEYDOWN");
         case 0x0291: return wxT("WM_IME_KEYUP");
 
         case 0x0290: return wxT("WM_IME_KEYDOWN");
         case 0x0291: return wxT("WM_IME_KEYUP");
 
+        case 0x02A0: return wxT("WM_NCMOUSEHOVER");
+        case 0x02A1: return wxT("WM_MOUSEHOVER");
+        case 0x02A2: return wxT("WM_NCMOUSELEAVE");
+        case 0x02A3: return wxT("WM_MOUSELEAVE");
+
         case 0x0300: return wxT("WM_CUT");
         case 0x0301: return wxT("WM_COPY");
         case 0x0302: return wxT("WM_PASTE");
         case 0x0300: return wxT("WM_CUT");
         case 0x0301: return wxT("WM_COPY");
         case 0x0302: return wxT("WM_PASTE");
@@ -5851,9 +6449,10 @@ const wxChar *wxGetMessageName(int message)
         case 0x030F: return wxT("WM_QUERYNEWPALETTE");
         case 0x0310: return wxT("WM_PALETTEISCHANGING");
         case 0x0311: return wxT("WM_PALETTECHANGED");
         case 0x030F: return wxT("WM_QUERYNEWPALETTE");
         case 0x0310: return wxT("WM_PALETTEISCHANGING");
         case 0x0311: return wxT("WM_PALETTECHANGED");
-#if wxUSE_HOTKEY
         case 0x0312: return wxT("WM_HOTKEY");
         case 0x0312: return wxT("WM_HOTKEY");
-#endif
+
+        case 0x0317: return wxT("WM_PRINT");
+        case 0x0318: return wxT("WM_PRINTCLIENT");
 
         // common controls messages - although they're not strictly speaking
         // standard, it's nice to decode them nevertheless
 
         // common controls messages - although they're not strictly speaking
         // standard, it's nice to decode them nevertheless
@@ -6129,18 +6728,10 @@ wxWindow* wxFindWindowAtPoint(const wxPoint& pt)
     POINT pt2;
     pt2.x = pt.x;
     pt2.y = pt.y;
     POINT pt2;
     pt2.x = pt.x;
     pt2.y = pt.y;
-    HWND hWndHit = ::WindowFromPoint(pt2);
 
 
-    wxWindow* win = wxFindWinFromHandle((WXHWND) hWndHit) ;
-    HWND hWnd = hWndHit;
+    HWND hWnd = ::WindowFromPoint(pt2);
 
 
-    // Try to find a window with a wxWindow associated with it
-    while (!win && (hWnd != 0))
-    {
-        hWnd = ::GetParent(hWnd);
-        win = wxFindWinFromHandle((WXHWND) hWnd) ;
-    }
-    return win;
+    return wxGetWindowFromHWND((WXHWND)hWnd);
 }
 
 // Get the current mouse position.
 }
 
 // Get the current mouse position.
@@ -6292,7 +6883,7 @@ public:
         }
 
         return CallNextHookEx(ms_hMsgHookProc, nCode, wParam, lParam);
         }
 
         return CallNextHookEx(ms_hMsgHookProc, nCode, wParam, lParam);
-    };
+    }
 
 private:
     static HHOOK ms_hMsgHookProc;
 
 private:
     static HHOOK ms_hMsgHookProc;