]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/window.cpp
Fix warnings for the OSX WebKit backend.
[wxWidgets.git] / src / msw / window.cpp
index 8934f9ac74f3a0241c744503b59e418138036f08..7535e4efeb10d7b3710682d038be5878ea8ba1cb 100644 (file)
@@ -28,6 +28,8 @@
 
 #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/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
 
+#include "wx/hashmap.h"
 #include "wx/evtloop.h"
-#include "wx/module.h"
 #include "wx/power.h"
 #include "wx/sysopt.h"
 
@@ -73,9 +78,9 @@
     #endif
 #endif
 
-#include "wx/menuitem.h"
-
 #include "wx/msw/private.h"
+#include "wx/msw/private/keyboard.h"
+#include "wx/msw/dcclient.h"
 
 #if wxUSE_TOOLTIPS
     #include "wx/tooltip.h"
     #include "wx/caret.h"
 #endif // wxUSE_CARET
 
+#if wxUSE_RADIOBOX
+    #include "wx/radiobox.h"
+#endif // wxUSE_RADIOBOX
+
 #if wxUSE_SPINCTRL
     #include "wx/spinctrl.h"
 #endif // wxUSE_SPINCTRL
 
-#include "wx/textctrl.h"
 #include "wx/notebook.h"
 #include "wx/listctrl.h"
+#include "wx/dynlib.h"
 
 #include <string.h>
 
     #include <windowsx.h>
 #endif
 
-// include <commctrl.h> "properly"
-#include "wx/msw/wrapcctl.h"
-
-#ifndef __WXWINCE__
+#if !defined __WXWINCE__ && !defined NEED_PBT_H
     #include <pbt.h>
 #endif
 
-#include "wx/msw/missing.h"
-
 #if defined(__WXWINCE__)
     #include "wx/msw/wince/missing.h"
 #ifdef __POCKETPC__
 #endif
 #endif
 
-#if defined(TME_LEAVE) && defined(WM_MOUSELEAVE)
-    #define HAVE_TRACKMOUSEEVENT
-#endif // everything needed for TrackMouseEvent()
+#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 this is set to 1, we use deferred window sizing to reduce flicker when
-// resizing complicated window hierarchies, but this can in theory result in
-// different behaviour than the old code so we keep the possibility to use it
-// by setting this to 0 (in the future this should be removed completely)
-#ifdef __WXWINCE__
-#define USE_DEFERRED_SIZING 0
-#else
-#define USE_DEFERRED_SIZING 1
+// define the constants used by AnimateWindow() if our SDK doesn't have them
+#ifndef AW_CENTER
+    #define AW_HOR_POSITIVE 0x00000001
+    #define AW_HOR_NEGATIVE 0x00000002
+    #define AW_VER_POSITIVE 0x00000004
+    #define AW_VER_NEGATIVE 0x00000008
+    #define AW_CENTER       0x00000010
+    #define AW_HIDE         0x00010000
+    #define AW_ACTIVATE     0x00020000
+    #define AW_SLIDE        0x00040000
+    #define AW_BLEND        0x00080000
 #endif
 
+#if defined(TME_LEAVE) && defined(WM_MOUSELEAVE) && wxUSE_DYNLIB_CLASS
+    #define HAVE_TRACKMOUSEEVENT
+#endif // everything needed for TrackMouseEvent()
+
 // set this to 1 to filter out duplicate mouse events, e.g. mouse move events
 // when mouse position didnd't change
 #ifdef __WXWINCE__
     #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
+
+#ifndef MAPVK_VK_TO_CHAR
+    #define MAPVK_VK_TO_CHAR 2
+#endif
+
 // ---------------------------------------------------------------------------
 // global variables
 // ---------------------------------------------------------------------------
 
 #if wxUSE_MENUS_NATIVE
-wxMenu *wxCurrentPopupMenu = NULL;
-#endif // wxUSE_MENUS_NATIVE
-
-#ifdef __WXWINCE__
-extern       wxChar *wxCanvasClassName;
-#else
-extern const wxChar *wxCanvasClassName;
+extern wxMenu *wxCurrentPopupMenu;
 #endif
 
+#if wxUSE_UXTHEME
+// This is a hack used by the owner-drawn wxButton implementation to ensure
+// that the brush used for erasing its background is correctly aligned with the
+// control.
+wxWindowMSW *wxWindowBeingErased = NULL;
+#endif // wxUSE_UXTHEME
+
+namespace
+{
+
 // true if we had already created the std colour map, used by
 // wxGetStdColourMap() and wxWindow::OnSysColourChanged()           (FIXME-MT)
-static bool gs_hasStdCmap = false;
+bool gs_hasStdCmap = false;
 
 // last mouse event information we need to filter out the duplicates
 #if wxUSE_MOUSEEVENT_HACK
-static struct MouseEventInfoDummy
+struct MouseEventInfoDummy
 {
     // mouse position (in screen coordinates)
     wxPoint pos;
@@ -175,6 +208,44 @@ static struct MouseEventInfoDummy
 } 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);
+
+MSWMessageHandlers gs_messageHandlers;
+
+// hash containing all our windows, it uses HWND keys and wxWindow* values
+WX_DECLARE_HASH_MAP(HWND, wxWindow *,
+                    wxPointerHash, wxPointerEqual,
+                    WindowHandles);
+
+WindowHandles gs_windowHandles;
+
+#ifdef wxHAS_MSW_BACKGROUND_ERASE_HOOK
+
+// temporary override for WM_ERASEBKGND processing: we don't store this in
+// wxWindow itself as we don't need it during most of the time so don't
+// increase the size of all window objects unnecessarily
+WX_DECLARE_HASH_MAP(wxWindow *, wxWindow *,
+                    wxPointerHash, wxPointerEqual,
+                    EraseBgHooks);
+
+EraseBgHooks gs_eraseBgHooks;
+
+#endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK
+
+// If this variable is strictly positive, EVT_CHAR_HOOK is not generated for
+// Escape key presses as it can't be intercepted because it's needed by some
+// currently shown window, e.g. IME entry.
+//
+// This is currently global as we allow using UI from the main thread only
+// anyhow but could be replaced with a thread-specific value in the future if
+// needed.
+int gs_modalEntryWindowCount = 0;
+
+} // anonymous namespace
+
 // ---------------------------------------------------------------------------
 // private functions
 // ---------------------------------------------------------------------------
@@ -184,13 +255,12 @@ LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message,
                                    WPARAM wParam, LPARAM lParam);
 
 
-#ifdef  __WXDEBUG__
+#if wxDEBUG_LEVEL >= 2
     const wxChar *wxGetMessageName(int message);
-#endif  //__WXDEBUG__
+#endif  // wxDEBUG_LEVEL >= 2
 
 void wxRemoveHandleAssociation(wxWindowMSW *win);
 extern void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win);
-wxWindow *wxFindWinFromHandle(WXHWND hWnd);
 
 // get the text metrics for the current font
 static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win);
@@ -214,7 +284,7 @@ static inline void wxBringWindowToTop(HWND hwnd)
     // raise top level parent to top of z order
     if (!::SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE))
     {
-        wxLogLastError(_T("SetWindowPos"));
+        wxLogLastError(wxT("SetWindowPos"));
     }
 }
 
@@ -238,12 +308,11 @@ static void EnsureParentHasControlParentStyle(wxWindow *parent)
      */
     while ( parent && !parent->IsTopLevel() )
     {
-        LONG exStyle = ::GetWindowLong(GetHwndOf(parent), GWL_EXSTYLE);
+        LONG exStyle = wxGetWindowExStyle(parent);
         if ( !(exStyle & WS_EX_CONTROLPARENT) )
         {
             // force the parent to have this style
-            ::SetWindowLong(GetHwndOf(parent), GWL_EXSTYLE,
-                            exStyle | WS_EX_CONTROLPARENT);
+            wxSetWindowExStyle(parent, exStyle | WS_EX_CONTROLPARENT);
         }
 
         parent = parent->GetParent();
@@ -275,119 +344,10 @@ bool GetCursorPosWinCE(POINT* pt)
 // method
 #ifdef __WXUNIVERSAL__
     IMPLEMENT_ABSTRACT_CLASS(wxWindowMSW, wxWindowBase)
-#else // __WXMSW__
-#if wxUSE_EXTENDED_RTTI
-
-// windows that are created from a parent window during its Create method, eg. spin controls in a calendar controls
-// must never been streamed out separately otherwise chaos occurs. Right now easiest is to test for negative ids, as
-// windows with negative ids never can be recreated anyway
-
-bool wxWindowStreamingCallback( const wxObject *object, wxWriter * , wxPersister * , wxxVariantArray & )
-{
-    const wxWindow * win = dynamic_cast<const wxWindow*>(object) ;
-    if ( win && win->GetId() < 0 )
-        return false ;
-    return true ;
-}
-
-IMPLEMENT_DYNAMIC_CLASS_XTI_CALLBACK(wxWindow, wxWindowBase,"wx/window.h", wxWindowStreamingCallback)
-
-// make wxWindowList known before the property is used
-
-wxCOLLECTION_TYPE_INFO( wxWindow* , wxWindowList ) ;
-
-template<> void wxCollectionToVariantArray( wxWindowList const &theList, wxxVariantArray &value)
-{
-    wxListCollectionToVariantArray<wxWindowList::compatibility_iterator>( theList , value ) ;
-}
-
-WX_DEFINE_FLAGS( wxWindowStyle )
-
-wxBEGIN_FLAGS( wxWindowStyle )
-    // new style border flags, we put them first to
-    // use them for streaming out
-
-    wxFLAGS_MEMBER(wxBORDER_SIMPLE)
-    wxFLAGS_MEMBER(wxBORDER_SUNKEN)
-    wxFLAGS_MEMBER(wxBORDER_DOUBLE)
-    wxFLAGS_MEMBER(wxBORDER_RAISED)
-    wxFLAGS_MEMBER(wxBORDER_STATIC)
-    wxFLAGS_MEMBER(wxBORDER_NONE)
-
-    // old style border flags
-    wxFLAGS_MEMBER(wxSIMPLE_BORDER)
-    wxFLAGS_MEMBER(wxSUNKEN_BORDER)
-    wxFLAGS_MEMBER(wxDOUBLE_BORDER)
-    wxFLAGS_MEMBER(wxRAISED_BORDER)
-    wxFLAGS_MEMBER(wxSTATIC_BORDER)
-    wxFLAGS_MEMBER(wxBORDER)
-
-    // standard window styles
-    wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
-    wxFLAGS_MEMBER(wxCLIP_CHILDREN)
-    wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
-    wxFLAGS_MEMBER(wxWANTS_CHARS)
-    wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
-    wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
-    wxFLAGS_MEMBER(wxVSCROLL)
-    wxFLAGS_MEMBER(wxHSCROLL)
-
-wxEND_FLAGS( wxWindowStyle )
-
-wxBEGIN_PROPERTIES_TABLE(wxWindow)
-    wxEVENT_PROPERTY( Close , wxEVT_CLOSE_WINDOW , wxCloseEvent)
-    wxEVENT_PROPERTY( Create , wxEVT_CREATE , wxWindowCreateEvent )
-    wxEVENT_PROPERTY( Destroy , wxEVT_DESTROY , wxWindowDestroyEvent )
-    // Always constructor Properties first
-
-    wxREADONLY_PROPERTY( Parent,wxWindow*, GetParent, EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
-    wxPROPERTY( Id,wxWindowID, SetId, GetId, -1 /*wxID_ANY*/ , 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
-    wxPROPERTY( Position,wxPoint, SetPosition , GetPosition, wxDefaultPosition , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // pos
-    wxPROPERTY( Size,wxSize, SetSize, GetSize, wxDefaultSize , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // size
-    wxPROPERTY( WindowStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
-
-    // Then all relations of the object graph
-
-    wxREADONLY_PROPERTY_COLLECTION( Children , wxWindowList , wxWindowBase* , GetWindowChildren , wxPROP_OBJECT_GRAPH /*flags*/ , wxT("Helpstring") , wxT("group"))
-
-   // and finally all other properties
-
-    wxPROPERTY( ExtraStyle , long , SetExtraStyle , GetExtraStyle , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // extstyle
-    wxPROPERTY( BackgroundColour , wxColour , SetBackgroundColour , GetBackgroundColour , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // bg
-    wxPROPERTY( ForegroundColour , wxColour , SetForegroundColour , GetForegroundColour , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // fg
-    wxPROPERTY( Enabled , bool , Enable , IsEnabled , wxxVariant((bool)true) , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
-    wxPROPERTY( Shown , bool , Show , IsShown , wxxVariant((bool)true) , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
-#if 0
-    // possible property candidates (not in xrc) or not valid in all subclasses
-    wxPROPERTY( Title,wxString, SetTitle, GetTitle, wxEmptyString )
-    wxPROPERTY( Font , wxFont , SetFont , GetWindowFont  , )
-    wxPROPERTY( Label,wxString, SetLabel, GetLabel, wxEmptyString )
-    // MaxHeight, Width , MinHeight , Width
-    // TODO switch label to control and title to toplevels
-
-    wxPROPERTY( ThemeEnabled , bool , SetThemeEnabled , GetThemeEnabled , )
-    //wxPROPERTY( Cursor , wxCursor , SetCursor , GetCursor , )
-    // wxPROPERTY( ToolTip , wxString , SetToolTip , GetToolTipText , )
-    wxPROPERTY( AutoLayout , bool , SetAutoLayout , GetAutoLayout , )
-
-
-
-#endif
-wxEND_PROPERTIES_TABLE()
-
-wxBEGIN_HANDLERS_TABLE(wxWindow)
-wxEND_HANDLERS_TABLE()
-
-wxCONSTRUCTOR_DUMMY(wxWindow)
-
-#else
-    IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
-#endif
-#endif // __WXUNIVERSAL__/__WXMSW__
+#endif // __WXUNIVERSAL__
 
 BEGIN_EVENT_TABLE(wxWindowMSW, wxWindowBase)
     EVT_SYS_COLOUR_CHANGED(wxWindowMSW::OnSysColourChanged)
-    EVT_ERASE_BACKGROUND(wxWindowMSW::OnEraseBackground)
 #ifdef __WXWINCE__
     EVT_INIT_DIALOG(wxWindowMSW::OnInitDialog)
 #endif
@@ -482,22 +442,20 @@ bool wxWindowMSW::MSWCommand(WXUINT WXUNUSED(param), WXWORD WXUNUSED(id))
 void wxWindowMSW::Init()
 {
     // MSW specific
-    m_isBeingDeleted = false;
     m_oldWndProc = NULL;
     m_mouseInWindow = false;
     m_lastKeydownProcessed = false;
 
-    m_childrenDisabled = NULL;
-    m_frozenness = 0;
-
     m_hWnd = 0;
-    m_hDWP = 0;
 
     m_xThumbSize = 0;
     m_yThumbSize = 0;
 
+#if wxUSE_DEFERRED_SIZING
+    m_hDWP = 0;
     m_pendingPosition = wxDefaultPosition;
     m_pendingSize = wxDefaultSize;
+#endif // wxUSE_DEFERRED_SIZING
 
 #ifdef __POCKETPC__
     m_contextMenuEnabled = false;
@@ -507,7 +465,7 @@ void wxWindowMSW::Init()
 // Destructor
 wxWindowMSW::~wxWindowMSW()
 {
-    m_isBeingDeleted = true;
+    SendDestroyEvent();
 
 #ifndef __WXUNIVERSAL__
     // VS: make sure there's no wxFrame with last focus set to us:
@@ -541,15 +499,21 @@ wxWindowMSW::~wxWindowMSW()
         //if (::IsWindow(GetHwnd()))
         {
             if ( !::DestroyWindow(GetHwnd()) )
+            {
                 wxLogLastError(wxT("DestroyWindow"));
+            }
         }
 
         // remove hWnd <-> wxWindow association
         wxRemoveHandleAssociation(this);
     }
 
-    delete m_childrenDisabled;
+}
 
+/* static */
+const wxChar *wxWindowMSW::MSWGetRegisteredClassName()
+{
+    return wxApp::GetRegisteredClassName(wxT("wxWindow"), COLOR_BTNFACE);
 }
 
 // real construction (Init() must have been called before!)
@@ -584,7 +548,8 @@ bool wxWindowMSW::Create(wxWindow *parent,
         msflags |= WS_VISIBLE;
     }
 
-    if ( !MSWCreate(wxCanvasClassName, NULL, pos, size, msflags, exstyle) )
+    if ( !MSWCreate(MSWGetRegisteredClassName(),
+                    NULL, pos, size, msflags, exstyle) )
         return false;
 
     InheritAttributes();
@@ -599,15 +564,14 @@ bool wxWindowMSW::Create(wxWindow *parent,
 void wxWindowMSW::SetFocus()
 {
     HWND hWnd = GetHwnd();
-    wxCHECK_RET( hWnd, _T("can't set focus to invalid window") );
+    wxCHECK_RET( hWnd, wxT("can't set focus to invalid window") );
 
-#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
+#if !defined(__WXWINCE__)
     ::SetLastError(0);
 #endif
 
     if ( !::SetFocus(hWnd) )
     {
-#if defined(__WXDEBUG__) && !defined(__WXMICROWIN__)
         // was there really an error?
         DWORD dwRes = ::GetLastError();
         if ( dwRes )
@@ -615,10 +579,9 @@ void wxWindowMSW::SetFocus()
             HWND hwndFocus = ::GetFocus();
             if ( hwndFocus != hWnd )
             {
-                wxLogApiError(_T("SetFocus"), dwRes);
+                wxLogApiError(wxT("SetFocus"), dwRes);
             }
         }
-#endif // Debug
     }
 }
 
@@ -651,69 +614,23 @@ wxWindow *wxWindowBase::DoFindFocus()
     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);
-
-    // 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;
-        }
+    MSWEnableHWND(GetHwnd(), enable);
+}
 
-        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;
+bool wxWindowMSW::MSWEnableHWND(WXHWND hWnd, bool enable)
+{
+    if ( !hWnd )
+        return false;
 
-                m_childrenDisabled->Append(child);
-            }
-        }
-    }
+    // If disabling focused control, we move focus to the next one, as if the
+    // user pressed Tab. That's because we can't keep focus on a disabled
+    // control, Tab-navigation would stop working then.
+    if ( !enable && ::GetFocus() == hWnd )
+        Navigate();
 
-    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;
+    return ::EnableWindow(hWnd, (BOOL)enable) != 0;
 }
 
 bool wxWindowMSW::Show(bool show)
@@ -736,6 +653,119 @@ bool wxWindowMSW::Show(bool show)
         ::ShowWindow(hWnd, show ? SW_SHOW : SW_HIDE);
     }
 
+    if ( IsFrozen() )
+    {
+        // DoFreeze/DoThaw don't do anything if the window is not shown, so
+        // we have to call them from here now
+        if ( show )
+            DoFreeze();
+        else
+            DoThaw();
+    }
+
+    return true;
+}
+
+bool
+wxWindowMSW::MSWShowWithEffect(bool show,
+                               wxShowEffect effect,
+                               unsigned timeout)
+{
+    if ( effect == wxSHOW_EFFECT_NONE )
+        return Show(show);
+
+    if ( !wxWindowBase::Show(show) )
+        return false;
+
+    typedef BOOL (WINAPI *AnimateWindow_t)(HWND, DWORD, DWORD);
+
+    static AnimateWindow_t s_pfnAnimateWindow = NULL;
+    static bool s_initDone = false;
+    if ( !s_initDone )
+    {
+        wxDynamicLibrary dllUser32(wxT("user32.dll"), wxDL_VERBATIM | wxDL_QUIET);
+        wxDL_INIT_FUNC(s_pfn, AnimateWindow, dllUser32);
+
+        s_initDone = true;
+
+        // notice that it's ok to unload user32.dll here as it won't be really
+        // unloaded, being still in use because we link to it statically too
+    }
+
+    if ( !s_pfnAnimateWindow )
+        return Show(show);
+
+    // Show() has a side effect of sending a WM_SIZE to the window, which helps
+    // ensuring that it's laid out correctly, but AnimateWindow() doesn't do
+    // this so send the event ourselves
+    SendSizeEvent();
+
+    // prepare to use AnimateWindow()
+
+    if ( !timeout )
+        timeout = 200; // this is the default animation timeout, per MSDN
+
+    DWORD dwFlags = show ? 0 : AW_HIDE;
+
+    switch ( effect )
+    {
+        case wxSHOW_EFFECT_ROLL_TO_LEFT:
+            dwFlags |= AW_HOR_NEGATIVE;
+            break;
+
+        case wxSHOW_EFFECT_ROLL_TO_RIGHT:
+            dwFlags |= AW_HOR_POSITIVE;
+            break;
+
+        case wxSHOW_EFFECT_ROLL_TO_TOP:
+            dwFlags |= AW_VER_NEGATIVE;
+            break;
+
+        case wxSHOW_EFFECT_ROLL_TO_BOTTOM:
+            dwFlags |= AW_VER_POSITIVE;
+            break;
+
+        case wxSHOW_EFFECT_SLIDE_TO_LEFT:
+            dwFlags |= AW_SLIDE | AW_HOR_NEGATIVE;
+            break;
+
+        case wxSHOW_EFFECT_SLIDE_TO_RIGHT:
+            dwFlags |= AW_SLIDE | AW_HOR_POSITIVE;
+            break;
+
+        case wxSHOW_EFFECT_SLIDE_TO_TOP:
+            dwFlags |= AW_SLIDE | AW_VER_NEGATIVE;
+            break;
+
+        case wxSHOW_EFFECT_SLIDE_TO_BOTTOM:
+            dwFlags |= AW_SLIDE | AW_VER_POSITIVE;
+            break;
+
+        case wxSHOW_EFFECT_BLEND:
+            dwFlags |= AW_BLEND;
+            break;
+
+        case wxSHOW_EFFECT_EXPAND:
+            dwFlags |= AW_CENTER;
+            break;
+
+
+        case wxSHOW_EFFECT_MAX:
+            wxFAIL_MSG( wxT("invalid window show effect") );
+            return false;
+
+        default:
+            wxFAIL_MSG( wxT("unknown window show effect") );
+            return false;
+    }
+
+    if ( !(*s_pfnAnimateWindow)(GetHwnd(), timeout, dwFlags) )
+    {
+        wxLogLastError(wxT("AnimateWindow"));
+
+        return false;
+    }
+
     return true;
 }
 
@@ -765,14 +795,14 @@ void wxWindowMSW::DoReleaseMouse()
 {
     if ( !::ReleaseCapture() )
     {
-        wxLogLastError(_T("ReleaseCapture"));
+        wxLogLastError(wxT("ReleaseCapture"));
     }
 }
 
 /* static */ wxWindow *wxWindowBase::GetCapture()
 {
     HWND hwnd = ::GetCapture();
-    return hwnd ? wxFindWinFromHandle((WXHWND)hwnd) : (wxWindow *)NULL;
+    return hwnd ? wxFindWinFromHandle(hwnd) : NULL;
 }
 
 bool wxWindowMSW::SetFont(const wxFont& font)
@@ -786,7 +816,11 @@ bool wxWindowMSW::SetFont(const wxFont& font)
     HWND hWnd = GetHwnd();
     if ( hWnd != 0 )
     {
-        WXHANDLE hFont = m_font.GetResourceHandle();
+        // note the use of GetFont() instead of m_font: our own font could have
+        // just been reset and in this case we need to change the font used by
+        // the native window to the default for this class, i.e. exactly what
+        // GetFont() returns
+        WXHANDLE hFont = GetFont().GetResourceHandle();
 
         wxASSERT_MSG( hFont, wxT("should have valid font") );
 
@@ -795,6 +829,7 @@ bool wxWindowMSW::SetFont(const wxFont& font)
 
     return true;
 }
+
 bool wxWindowMSW::SetCursor(const wxCursor& cursor)
 {
     if ( !wxWindowBase::SetCursor(cursor) )
@@ -804,9 +839,55 @@ bool wxWindowMSW::SetCursor(const wxCursor& cursor)
     }
 
     // don't "overwrite" busy cursor
-    if ( m_cursor.Ok() && !wxIsBusy() )
+    if ( wxIsBusy() )
+        return true;
+
+    if ( m_cursor.IsOk() )
     {
-        ::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
+    }
+    else // Invalid cursor: this means reset to the default one.
+    {
+        // To revert to the correct cursor we need to find the window currently
+        // under the cursor and ask it to set its cursor itself as only it
+        // knows what it is.
+        POINT pt;
+        if ( !::GetCursorPos(&pt) )
+        {
+            wxLogLastError(wxT("GetCursorPos"));
+            return false;
+        }
+
+        const wxWindow* win = wxFindWindowAtPoint(wxPoint(pt.x, pt.y));
+        if ( !win )
+            win = this;
+
+        ::SendMessage(GetHwndOf(win), WM_SETCURSOR,
+                      (WPARAM)GetHwndOf(win),
+                      MAKELPARAM(HTCLIENT, WM_MOUSEMOVE));
     }
 
     return true;
@@ -818,7 +899,7 @@ void wxWindowMSW::WarpPointer(int x, int y)
 
     if ( !::SetCursorPos(x, y) )
     {
-        wxLogLastError(_T("SetCursorPos"));
+        wxLogLastError(wxT("SetCursorPos"));
     }
 }
 
@@ -830,7 +911,7 @@ void wxWindowMSW::MSWUpdateUIState(int action, int state)
     if ( s_needToUpdate == -1 )
     {
         int verMaj, verMin;
-        s_needToUpdate = wxGetOsVersion(&verMaj, &verMin) == wxWINDOWS_NT &&
+        s_needToUpdate = wxGetOsVersion(&verMaj, &verMin) == wxOS_WINDOWS_NT &&
                             verMaj >= 5;
     }
 
@@ -846,6 +927,9 @@ void wxWindowMSW::MSWUpdateUIState(int action, int state)
 // scrolling stuff
 // ---------------------------------------------------------------------------
 
+namespace
+{
+
 inline int GetScrollPosition(HWND hWnd, int wOrient)
 {
 #ifdef __WXMICROWIN__
@@ -861,12 +945,19 @@ inline int GetScrollPosition(HWND hWnd, int wOrient)
 #endif
 }
 
+inline UINT WXOrientToSB(int orient)
+{
+    return orient == wxHORIZONTAL ? SB_HORZ : SB_VERT;
+}
+
+} // anonymous namespace
+
 int wxWindowMSW::GetScrollPos(int orient) const
 {
     HWND hWnd = GetHwnd();
-    wxCHECK_MSG( hWnd, 0, _T("no HWND in GetScrollPos") );
+    wxCHECK_MSG( hWnd, 0, wxT("no HWND in GetScrollPos") );
 
-    return GetScrollPosition(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT);
+    return GetScrollPosition(hWnd, WXOrientToSB(orient));
 }
 
 // This now returns the whole range, not just the number
@@ -877,19 +968,13 @@ int wxWindowMSW::GetScrollRange(int orient) const
     HWND hWnd = GetHwnd();
     if ( !hWnd )
         return 0;
-#if 0
-    ::GetScrollRange(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
-                     &minPos, &maxPos);
-#endif
     WinStruct<SCROLLINFO> scrollInfo;
     scrollInfo.fMask = SIF_RANGE;
-    if ( !::GetScrollInfo(hWnd,
-                          orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
-                          &scrollInfo) )
+    if ( !::GetScrollInfo(hWnd, WXOrientToSB(orient), &scrollInfo) )
     {
         // Most of the time this is not really an error, since the return
         // value can also be zero when there is no scrollbar yet.
-        // wxLogLastError(_T("GetScrollInfo"));
+        // wxLogLastError(wxT("GetScrollInfo"));
     }
     maxPos = scrollInfo.nMax;
 
@@ -905,7 +990,7 @@ int wxWindowMSW::GetScrollThumb(int orient) const
 void wxWindowMSW::SetScrollPos(int orient, int pos, bool refresh)
 {
     HWND hWnd = GetHwnd();
-    wxCHECK_RET( hWnd, _T("SetScrollPos: no HWND") );
+    wxCHECK_RET( hWnd, wxT("SetScrollPos: no HWND") );
 
     WinStruct<SCROLLINFO> info;
     info.nPage = 0;
@@ -918,8 +1003,7 @@ void wxWindowMSW::SetScrollPos(int orient, int pos, bool refresh)
         info.fMask |= SIF_DISABLENOSCROLL;
     }
 
-    ::SetScrollInfo(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
-                    &info, refresh);
+    ::SetScrollInfo(hWnd, WXOrientToSB(orient), &info, refresh);
 }
 
 // New function that will replace some of the above.
@@ -929,28 +1013,41 @@ void wxWindowMSW::SetScrollbar(int orient,
                                int range,
                                bool refresh)
 {
+    // We have to set the variables here to make them valid in events
+    // triggered by ::SetScrollInfo()
+    *(orient == wxHORIZONTAL ? &m_xThumbSize : &m_yThumbSize) = pageSize;
+
+    HWND hwnd = GetHwnd();
+    if ( !hwnd )
+        return;
+
     WinStruct<SCROLLINFO> info;
-    info.nPage = pageSize;
-    info.nMin = 0;              // range is nMax - nMin + 1
-    info.nMax = range - 1;      //  as both nMax and nMax are inclusive
-    info.nPos = pos;
+    if ( range != -1 )
+    {
+        info.nPage = pageSize;
+        info.nMin = 0;              // range is nMax - nMin + 1
+        info.nMax = range - 1;      //  as both nMax and nMax are inclusive
+        info.nPos = pos;
+
+        // We normally also reenable scrollbar in case it had been previously
+        // disabled by specifying SIF_DISABLENOSCROLL below but we should only
+        // do this if it has valid range, otherwise it would be enabled but not
+        // do anything.
+        if ( range >= pageSize )
+        {
+            ::EnableScrollBar(hwnd, WXOrientToSB(orient), ESB_ENABLE_BOTH);
+        }
+    }
+    //else: leave all the fields to be 0
+
     info.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
-    if ( HasFlag(wxALWAYS_SHOW_SB) )
+    if ( HasFlag(wxALWAYS_SHOW_SB) || range == -1 )
     {
         // disable scrollbar instead of removing it then
         info.fMask |= SIF_DISABLENOSCROLL;
     }
 
-    HWND hWnd = GetHwnd();
-    if ( hWnd )
-    {
-        // We have to set the variables here to make them valid in events
-        // triggered by ::SetScrollInfo()
-        *(orient == wxHORIZONTAL ? &m_xThumbSize : &m_yThumbSize) = pageSize;
-
-        ::SetScrollInfo(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT,
-                        &info, refresh);
-    }
+    ::SetScrollInfo(hwnd, WXOrientToSB(orient), &info, refresh);
 }
 
 void wxWindowMSW::ScrollWindow(int dx, int dy, const wxRect *prect)
@@ -959,10 +1056,7 @@ void wxWindowMSW::ScrollWindow(int dx, int dy, const wxRect *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
@@ -1019,6 +1113,65 @@ bool wxWindowMSW::ScrollPages(int pages)
                             down ? pages : -pages);
 }
 
+// ----------------------------------------------------------------------------
+// RTL support
+// ----------------------------------------------------------------------------
+
+void wxWindowMSW::SetLayoutDirection(wxLayoutDirection dir)
+{
+#ifdef __WXWINCE__
+    wxUnusedVar(dir);
+#else
+    wxCHECK_RET( GetHwnd(),
+                 wxT("layout direction must be set after window creation") );
+
+    LONG styleOld = wxGetWindowExStyle(this);
+
+    LONG styleNew = styleOld;
+    switch ( dir )
+    {
+        case wxLayout_LeftToRight:
+            styleNew &= ~WS_EX_LAYOUTRTL;
+            break;
+
+        case wxLayout_RightToLeft:
+            styleNew |= WS_EX_LAYOUTRTL;
+            break;
+
+        default:
+            wxFAIL_MSG(wxT("unsupported layout direction"));
+            break;
+    }
+
+    if ( styleNew != styleOld )
+    {
+        wxSetWindowExStyle(this, styleNew);
+    }
+#endif
+}
+
+wxLayoutDirection wxWindowMSW::GetLayoutDirection() const
+{
+#ifdef __WXWINCE__
+    return wxLayout_Default;
+#else
+    wxCHECK_MSG( GetHwnd(), wxLayout_Default, wxT("invalid window") );
+
+    return wxHasWindowExStyle(this, 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
 // ---------------------------------------------------------------------------
@@ -1030,6 +1183,8 @@ void wxWindowMSW::SubclassWin(WXHWND hWnd)
     HWND hwnd = (HWND)hWnd;
     wxCHECK_RET( ::IsWindow(hwnd), wxT("invalid HWND in SubclassWin") );
 
+    SetHWND(hWnd);
+
     wxAssociateWinWithHandle(hwnd, this);
 
     m_oldWndProc = (WXFARPROC)wxGetWindowProc((HWND)hWnd);
@@ -1051,7 +1206,7 @@ void wxWindowMSW::SubclassWin(WXHWND hWnd)
 
     // we're officially created now, send the event
     wxWindowCreateEvent event((wxWindow *)this);
-    (void)GetEventHandler()->ProcessEvent(event);
+    (void)HandleWindowEvent(event);
 }
 
 void wxWindowMSW::UnsubclassWin()
@@ -1083,12 +1238,14 @@ void wxWindowMSW::AssociateHandle(WXWidget handle)
     if ( m_hWnd )
     {
       if ( !::DestroyWindow(GetHwnd()) )
+      {
         wxLogLastError(wxT("DestroyWindow"));
+      }
     }
 
     WXHWND wxhwnd = (WXHWND)handle;
 
-    SetHWND(wxhwnd);
+    // this also calls SetHWND(wxhwnd)
     SubclassWin(wxhwnd);
 }
 
@@ -1102,36 +1259,12 @@ void wxWindowMSW::DissociateHandle()
 bool wxCheckWindowWndProc(WXHWND hWnd,
                           WXFARPROC WXUNUSED(wndProc))
 {
-// TODO: This list of window class names should be factored out so they can be
-// managed in one place and then accessed from here and other places, such as
-// wxApp::RegisterWindowClasses() and wxApp::UnregisterWindowClasses()
+    const wxString str(wxGetWindowClass(hWnd));
 
-#ifdef __WXWINCE__
-    extern       wxChar *wxCanvasClassName;
-    extern       wxChar *wxCanvasClassNameNR;
-#else
-    extern const wxChar *wxCanvasClassName;
-    extern const wxChar *wxCanvasClassNameNR;
-#endif
-    extern const wxChar *wxMDIFrameClassName;
-    extern const wxChar *wxMDIFrameClassNameNoRedraw;
-    extern const wxChar *wxMDIChildFrameClassName;
-    extern const wxChar *wxMDIChildFrameClassNameNoRedraw;
-    wxString str(wxGetWindowClass(hWnd));
-    if (str == wxCanvasClassName ||
-        str == wxCanvasClassNameNR ||
-#if wxUSE_GLCANVAS
-        str == _T("wxGLCanvasClass") ||
-        str == _T("wxGLCanvasClassNR") ||
-#endif // wxUSE_GLCANVAS
-        str == wxMDIFrameClassName ||
-        str == wxMDIFrameClassNameNoRedraw ||
-        str == wxMDIChildFrameClassName ||
-        str == wxMDIChildFrameClassNameNoRedraw ||
-        str == _T("wxTLWHiddenParent"))
-        return true; // Effectively means don't subclass
-    else
-        return false;
+    // TODO: get rid of wxTLWHiddenParent special case (currently it's not
+    //       registered by wxApp but using ad hoc code in msw/toplevel.cpp);
+    //       there is also a hidden window class used by sockets &c
+    return wxApp::IsRegisteredClassName(str) || str == wxT("wxTLWHiddenParent");
 }
 
 // ----------------------------------------------------------------------------
@@ -1147,6 +1280,25 @@ void wxWindowMSW::SetWindowStyleFlag(long 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() )
@@ -1155,9 +1307,21 @@ void wxWindowMSW::SetWindowStyleFlag(long flags)
     // 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 )
     {
@@ -1171,14 +1335,8 @@ void wxWindowMSW::SetWindowStyleFlag(long flags)
 
         ::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 |
@@ -1189,14 +1347,14 @@ void wxWindowMSW::SetWindowStyleFlag(long flags)
     }
 
     // and the extended style
-    long exstyleReal = ::GetWindowLong(GetHwnd(), GWL_EXSTYLE);
+    long exstyleReal = wxGetWindowExStyle(this);
 
     if ( exstyle != exstyleOld )
     {
         exstyleReal &= ~exstyleOld;
         exstyleReal |= exstyle;
 
-        ::SetWindowLong(GetHwnd(), GWL_EXSTYLE, exstyleReal);
+        wxSetWindowExStyle(this, exstyleReal);
 
         // ex style changes don't take effect without calling SetWindowPos
         callSWP = true;
@@ -1211,13 +1369,51 @@ void wxWindowMSW::SetWindowStyleFlag(long flags)
                              exstyleReal & WS_EX_TOPMOST ? HWND_TOPMOST
                                                          : HWND_NOTOPMOST,
                              0, 0, 0, 0,
-                             SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED) )
+                             SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE |
+                             SWP_FRAMECHANGED) )
         {
-            wxLogLastError(_T("SetWindowPos"));
+            wxLogLastError(wxT("SetWindowPos"));
         }
     }
 }
 
+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;
+        }
+        return wxBORDER_SUNKEN;
+    }
+#endif
+    return border;
+#endif
+}
+
+
 WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const
 {
     // translate common wxWidgets styles to Windows ones
@@ -1247,7 +1443,10 @@ WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const
     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 )
@@ -1267,11 +1466,12 @@ WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const
         {
             default:
             case wxBORDER_DEFAULT:
-                wxFAIL_MSG( _T("unknown border style") );
+                wxFAIL_MSG( wxT("unknown border style") );
                 // fall through
 
             case wxBORDER_NONE:
             case wxBORDER_SIMPLE:
+            case wxBORDER_THEME:
                 break;
 
             case wxBORDER_STATIC:
@@ -1287,9 +1487,9 @@ WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const
                 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
@@ -1347,8 +1547,7 @@ void wxWindowMSW::OnInternalIdle()
     }
 #endif // !HAVE_TRACKMOUSEEVENT
 
-    if (wxUpdateUIEvent::CanUpdate(this))
-        UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
+    wxWindowBase::OnInternalIdle();
 }
 
 // Set this window to be the child of 'parent'.
@@ -1363,7 +1562,7 @@ bool wxWindowMSW::Reparent(wxWindowBase *parent)
     ::SetParent(hWndChild, hWndParent);
 
 #ifndef __WXWINCE__
-    if ( ::GetWindowLong(hWndChild, GWL_EXSTYLE) & WS_EX_CONTROLPARENT )
+    if ( wxHasWindowExStyle(this, WS_EX_CONTROLPARENT) )
     {
         EnsureParentHasControlParentStyle(GetParent());
     }
@@ -1379,30 +1578,24 @@ static inline void SendSetRedraw(HWND hwnd, bool on)
 #endif
 }
 
-void wxWindowMSW::Freeze()
+void wxWindowMSW::DoFreeze()
 {
-    if ( !m_frozenness++ )
-    {
-        if ( IsShown() )
-            SendSetRedraw(GetHwnd(), false);
-    }
+    if ( !IsShown() )
+        return; // no point in freezing hidden window
+
+    SendSetRedraw(GetHwnd(), false);
 }
 
-void wxWindowMSW::Thaw()
+void wxWindowMSW::DoThaw()
 {
-    wxASSERT_MSG( m_frozenness > 0, _T("Thaw() without matching Freeze()") );
+    if ( !IsShown() )
+        return; // hidden windows aren't frozen by DoFreeze
 
-    if ( --m_frozenness == 0 )
-    {
-        if ( IsShown() )
-        {
-            SendSetRedraw(GetHwnd(), true);
+    SendSetRedraw(GetHwnd(), true);
 
-            // we need to refresh everything or otherwise the invalidated area
-            // is not going to be repainted
-            Refresh();
-        }
-    }
+    // we need to refresh everything or otherwise the invalidated area
+    // is not going to be repainted
+    Refresh();
 }
 
 void wxWindowMSW::Refresh(bool eraseBack, const wxRect *rect)
@@ -1414,11 +1607,7 @@ void wxWindowMSW::Refresh(bool eraseBack, const wxRect *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
@@ -1443,7 +1632,7 @@ void wxWindowMSW::Update()
 {
     if ( !::UpdateWindow(GetHwnd()) )
     {
-        wxLogLastError(_T("UpdateWindow"));
+        wxLogLastError(wxT("UpdateWindow"));
     }
 
 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
@@ -1457,9 +1646,13 @@ void wxWindowMSW::Update()
 // drag and drop
 // ---------------------------------------------------------------------------
 
+#if wxUSE_DRAG_AND_DROP || !defined(__WXWINCE__)
+
+#if wxUSE_STATBOX
+
 // we need to lower the sibling static boxes so controls contained within can be
 // a drop target
-static inline void AdjustStaticBoxZOrder(wxWindow *parent)
+static void AdjustStaticBoxZOrder(wxWindow *parent)
 {
     // no sibling static boxes if we have no parent (ie TLW)
     if ( !parent )
@@ -1478,6 +1671,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)
 {
@@ -1531,11 +1734,11 @@ void wxWindowMSW::DoSetToolTip(wxToolTip *tooltip)
 
 bool wxWindowMSW::IsSizeDeferred() const
 {
-#if USE_DEFERRED_SIZING
+#if wxUSE_DEFERRED_SIZING
     if ( m_pendingPosition != wxDefaultPosition ||
          m_pendingSize     != wxDefaultSize )
         return true;
-#endif // USE_DEFERRED_SIZING
+#endif // wxUSE_DEFERRED_SIZING
 
     return false;
 }
@@ -1543,6 +1746,7 @@ bool wxWindowMSW::IsSizeDeferred() const
 // Get total size
 void wxWindowMSW::DoGetSize(int *x, int *y) const
 {
+#if wxUSE_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
@@ -1554,6 +1758,7 @@ void wxWindowMSW::DoGetSize(int *x, int *y) const
             *y = m_pendingSize.y;
     }
     else // use current size
+#endif // wxUSE_DEFERRED_SIZING
     {
         RECT rect = wxGetWindowRect(GetHwnd());
 
@@ -1567,22 +1772,22 @@ void wxWindowMSW::DoGetSize(int *x, int *y) const
 // Get size *available for subwindows* i.e. excluding menu bar etc.
 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 wxUSE_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
+        //
+        // FIXME: Unfortunately this doesn't work correctly for the maximized
+        //        top level windows, the returned values are too small (e.g.
+        //        under Windows 7 on a 1600*1200 screen with task bar on the
+        //        right the pending size for a maximized window is 1538*1200
+        //        and WM_NCCALCSIZE returns 1528*1172 even though the correct
+        //        client size of such window is 1538*1182). No idea how to fix
+        //        it though, setting WS_MAXIMIZE in GWL_STYLE before calling
+        //        WM_NCCALCSIZE doesn't help and AdjustWindowRectEx() doesn't
+        //        work in this direction neither. So we just have to live with
+        //        the slightly wrong results and relayout the window when it
+        //        gets finally shown in its maximized state (see #11762).
         RECT rect;
         rect.left = m_pendingPosition.x;
         rect.top = m_pendingPosition.y;
@@ -1596,7 +1801,25 @@ void wxWindowMSW::DoGetClientSize(int *x, int *y) const
         if ( y )
             *y = rect.bottom - rect.top;
     }
-#endif
+    else
+#endif // wxUSE_DEFERRED_SIZING
+    {
+        RECT rect = wxGetClientRect(GetHwnd());
+
+        if ( x )
+            *x = rect.right;
+        if ( y )
+            *y = rect.bottom;
+    }
+
+    // The size of the client window can't be negative but ::GetClientRect()
+    // can return negative size for an extremely small (1x1) window with
+    // borders so ensure that we correct it here as having negative sizes is
+    // completely unexpected.
+    if ( x && *x < 0 )
+        *x = 0;
+    if ( y && *y < 0 )
+        *y = 0;
 }
 
 void wxWindowMSW::DoGetPosition(int *x, int *y) const
@@ -1604,11 +1827,13 @@ void wxWindowMSW::DoGetPosition(int *x, int *y) const
     wxWindow * const parent = GetParent();
 
     wxPoint pos;
+#if wxUSE_DEFERRED_SIZING
     if ( m_pendingPosition != wxDefaultPosition )
     {
         pos = m_pendingPosition;
     }
     else // use current position
+#endif // wxUSE_DEFERRED_SIZING
     {
         RECT rect = wxGetWindowRect(GetHwnd());
 
@@ -1620,6 +1845,13 @@ void wxWindowMSW::DoGetPosition(int *x, int *y) const
         // 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 )
@@ -1682,7 +1914,7 @@ void wxWindowMSW::DoClientToScreen(int *x, int *y) const
 bool
 wxWindowMSW::DoMoveSibling(WXHWND hwnd, int x, int y, int width, int height)
 {
-#if USE_DEFERRED_SIZING
+#if wxUSE_DEFERRED_SIZING
     // if our parent had prepared a defer window handle for us, use it (unless
     // we are a top level window)
     wxWindowMSW * const parent = IsTopLevel() ? NULL : GetParent();
@@ -1694,7 +1926,7 @@ wxWindowMSW::DoMoveSibling(WXHWND hwnd, int x, int y, int width, int height)
                                 SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE);
         if ( !hdwp )
         {
-            wxLogLastError(_T("DeferWindowPos"));
+            wxLogLastError(wxT("DeferWindowPos"));
         }
     }
 
@@ -1712,13 +1944,13 @@ wxWindowMSW::DoMoveSibling(WXHWND hwnd, int x, int y, int width, int height)
     }
 
     // otherwise (or if deferring failed) move the window in place immediately
-#endif // USE_DEFERRED_SIZING
+#endif // wxUSE_DEFERRED_SIZING
     if ( !::MoveWindow((HWND)hwnd, x, y, width, height, IsShown()) )
     {
         wxLogLastError(wxT("MoveWindow"));
     }
 
-    // if USE_DEFERRED_SIZING, indicates that we didn't use deferred move,
+    // if wxUSE_DEFERRED_SIZING, indicates that we didn't use deferred move,
     // ignored otherwise
     return false;
 }
@@ -1734,10 +1966,15 @@ void wxWindowMSW::DoMoveWindow(int x, int y, int width, int height)
 
     if ( DoMoveSibling(m_hWnd, x, y, width, height) )
     {
-#if USE_DEFERRED_SIZING
+#if wxUSE_DEFERRED_SIZING
         m_pendingPosition = wxPoint(x, y);
         m_pendingSize = wxSize(width, height);
-#endif // USE_DEFERRED_SIZING
+    }
+    else // window was moved immediately, without deferring it
+    {
+        m_pendingPosition = wxDefaultPosition;
+        m_pendingSize = wxDefaultSize;
+#endif // wxUSE_DEFERRED_SIZING
     }
 }
 
@@ -1764,6 +2001,12 @@ void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags)
          width == currentW && height == currentH &&
             !(sizeFlags & wxSIZE_FORCE) )
     {
+        if (sizeFlags & wxSIZE_FORCE_EVENT)
+        {
+            wxSizeEvent event( wxSize(width,height), GetId() );
+            event.SetEventObject( this );
+            HandleWindowEvent( event );
+        }
         return;
     }
 
@@ -1779,7 +2022,7 @@ void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags)
     {
         if ( sizeFlags & wxSIZE_AUTO_WIDTH )
         {
-            size = DoGetBestSize();
+            size = GetBestSize();
             width = size.x;
         }
         else
@@ -1795,9 +2038,9 @@ void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags)
         {
             if ( size.x == wxDefaultCoord )
             {
-                size = DoGetBestSize();
+                size = GetBestSize();
             }
-            //else: already called DoGetBestSize() above
+            //else: already called GetBestSize() above
 
             height = size.y;
         }
@@ -1869,11 +2112,41 @@ void wxWindowMSW::DoSetClientSize(int width, int height)
                            height + heightWin - rectClient.bottom,
                            TRUE) )
         {
-            wxLogLastError(_T("MoveWindow"));
+            wxLogLastError(wxT("MoveWindow"));
         }
     }
 }
 
+wxSize wxWindowMSW::DoGetBorderSize() const
+{
+    wxCoord border;
+    switch ( GetBorder() )
+    {
+        case wxBORDER_STATIC:
+        case wxBORDER_SIMPLE:
+            border = 1;
+            break;
+
+        case wxBORDER_SUNKEN:
+            border = 2;
+            break;
+
+        case wxBORDER_RAISED:
+        case wxBORDER_DOUBLE:
+            border = 3;
+            break;
+
+        default:
+            wxFAIL_MSG( wxT("unknown border style") );
+            // fall through
+
+        case wxBORDER_NONE:
+            border = 0;
+    }
+
+    return 2*wxSize(border, border);
+}
+
 // ---------------------------------------------------------------------------
 // text metrics
 // ---------------------------------------------------------------------------
@@ -1894,26 +2167,27 @@ int wxWindowMSW::GetCharWidth() const
 #endif
 }
 
-void wxWindowMSW::GetTextExtent(const wxString& string,
-                             int *x, int *y,
-                             int *descent, int *externalLeading,
-                             const wxFont *theFont) const
+void wxWindowMSW::DoGetTextExtent(const wxString& string,
+                                  int *x, int *y,
+                                  int *descent,
+                                  int *externalLeading,
+                                  const wxFont *fontToUse) const
 {
-    wxASSERT_MSG( !theFont || theFont->Ok(),
-                    _T("invalid font in GetTextExtent()") );
+    wxASSERT_MSG( !fontToUse || fontToUse->IsOk(),
+                    wxT("invalid font in GetTextExtent()") );
 
-    wxFont fontToUse;
-    if (theFont)
-        fontToUse = *theFont;
+    HFONT hfontToUse;
+    if ( fontToUse )
+        hfontToUse = GetHfontOf(*fontToUse);
     else
-        fontToUse = GetFont();
+        hfontToUse = GetHfontOf(GetFont());
 
     WindowHDC hdc(GetHwnd());
-    SelectInHDC selectFont(hdc, GetHfontOf(fontToUse));
+    SelectInHDC selectFont(hdc, hfontToUse);
 
     SIZE sizeRect;
     TEXTMETRIC tm;
-    ::GetTextExtentPoint32(hdc, string, string.length(), &sizeRect);
+    ::GetTextExtentPoint32(hdc, string.wx_str(), string.length(), &sizeRect);
     GetTextMetrics(hdc, &tm);
 
     if ( x )
@@ -1961,28 +2235,36 @@ static void wxYieldForCommandsOnly()
 
 bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y)
 {
-    menu->SetInvokingWindow(this);
     menu->UpdateUI();
 
+    wxPoint pt;
     if ( x == wxDefaultCoord && y == wxDefaultCoord )
     {
-        wxPoint mouse = ScreenToClient(wxGetMousePosition());
-        x = mouse.x; y = mouse.y;
+        pt = wxGetMousePosition();
+    }
+    else
+    {
+        pt = ClientToScreen(wxPoint(x, y));
     }
 
-    HWND hWnd = GetHwnd();
-    HMENU hMenu = GetHmenuOf(menu);
-    POINT point;
-    point.x = x;
-    point.y = y;
-    ::ClientToScreen(hWnd, &point);
-    wxCurrentPopupMenu = menu;
 #if defined(__WXWINCE__)
-    UINT flags = 0;
-#else
-    UINT flags = TPM_RIGHTBUTTON | TPM_RECURSE;
-#endif
-    ::TrackPopupMenu(hMenu, flags, point.x, point.y, 0, hWnd, NULL);
+    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(GetHmenuOf(menu), flags, pt.x, pt.y, 0, GetHwnd(), NULL);
 
     // we need to do it right now as otherwise the events are never going to be
     // sent to wxCurrentPopupMenu from HandleCommand()
@@ -1993,10 +2275,6 @@ bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y)
     // for example) and so we do need to process the event immediately
     wxYieldForCommandsOnly();
 
-    wxCurrentPopupMenu = NULL;
-
-    menu->SetInvokingWindow(NULL);
-
     return true;
 }
 
@@ -2008,10 +2286,23 @@ bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y)
 
 WXLRESULT wxWindowMSW::MSWDefWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
 {
+    WXLRESULT rc;
     if ( m_oldWndProc )
-        return ::CallWindowProc(CASTWNDPROC m_oldWndProc, GetHwnd(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam);
+        rc = ::CallWindowProc(CASTWNDPROC m_oldWndProc, GetHwnd(), (UINT) nMsg, (WPARAM) wParam, (LPARAM) lParam);
     else
-        return ::DefWindowProc(GetHwnd(), nMsg, wParam, lParam);
+        rc = ::DefWindowProc(GetHwnd(), nMsg, wParam, lParam);
+
+    // Special hack used by wxTextEntry auto-completion only: this event is
+    // sent after the normal keyboard processing so that its handler could use
+    // the updated contents of the text control, after taking the key that was
+    // pressed into account.
+    if ( nMsg == WM_CHAR )
+    {
+        wxKeyEvent event(CreateCharEvent(wxEVT_AFTER_CHAR, wParam, lParam));
+        HandleWindowEvent(event);
+    }
+
+    return rc;
 }
 
 bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
@@ -2033,18 +2324,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)
-            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;
-                }
+            // surprisingly, 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,
@@ -2056,10 +2343,13 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
             switch ( msg->wParam )
             {
                 case VK_TAB:
-                    if ( lDlgCode & DLGC_WANTTAB ) {
+                    if ( (lDlgCode & DLGC_WANTTAB) && !bCtrlDown )
+                    {
+                        // let the control have the TAB
                         bProcess = false;
                     }
-                    else {
+                    else // use it for navigation
+                    {
                         // Ctrl-Tab cycles thru notebook pages
                         bWindowChange = bCtrlDown;
                         bForward = !bShiftDown;
@@ -2081,18 +2371,27 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
                         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:
                     {
-                        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
-                        // 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
@@ -2102,56 +2401,83 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
                             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(msg->hwnd);
                             }
-
-                            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;
                         }
+
+                        // This "Return" key press won't be actually used for
+                        // navigation so don't generate wxNavigationKeyEvent
+                        // for it but still pass it to IsDialogMessage() as it
+                        // may handle it in some other way (e.g. by playing the
+                        // default error sound).
+                        bProcess = false;
+
+#endif // wxUSE_BUTTON
+
+#ifdef __WXWINCE__
+                        // map Enter presses into button presses on PDAs
+                        wxJoystickEvent event(wxEVT_JOY_BUTTON_DOWN);
+                        event.SetEventObject(this);
+                        if ( HandleWindowEvent(event) )
+                            return true;
+#endif // __WXWINCE__
                     }
                     break;
 
@@ -2167,7 +2493,7 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
                 event.SetFromTab(bFromTab);
                 event.SetEventObject(this);
 
-                if ( GetEventHandler()->ProcessEvent(event) )
+                if ( HandleWindowEvent(event) )
                 {
                     // as we don't call IsDialogMessage(), which would take of
                     // this by default, we need to manually send this message
@@ -2179,90 +2505,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__
@@ -2290,10 +2536,95 @@ bool wxWindowMSW::MSWTranslateMessage(WXMSG* pMsg)
 #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() &&
+                    !wxHasWindowExStyle(win, 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;
 }
 
 // ---------------------------------------------------------------------------
@@ -2362,14 +2693,20 @@ wxWindowCreationHook::~wxWindowCreationHook()
 // Main window proc
 LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
-    // trace all messages - useful for the debugging
-#ifdef __WXDEBUG__
-    wxLogTrace(wxTraceMessages,
-               wxT("Processing %s(hWnd=%08lx, wParam=%8lx, lParam=%8lx)"),
-               wxGetMessageName(message), (long)hWnd, (long)wParam, lParam);
-#endif // __WXDEBUG__
+    // trace all messages: useful for the debugging but noticeably slows down
+    // the code so don't do it by default
+#if wxDEBUG_LEVEL >= 2
+    // notice that we cast wParam and lParam to long to avoid mismatch with
+    // format specifiers in 64 bit builds where they are both int64 quantities
+    //
+    // casting like this loses information, of course, but it shouldn't matter
+    // much for this diagnostic code and it keeps the code simple
+    wxLogTrace("winmsg",
+               wxT("Processing %s(hWnd=%p, wParam=%08lx, lParam=%08lx)"),
+               wxGetMessageName(message), hWnd, (long)wParam, (long)lParam);
+#endif // wxDEBUG_LEVEL >= 2
 
-    wxWindowMSW *wnd = wxFindWinFromHandle((WXHWND) hWnd);
+    wxWindowMSW *wnd = wxFindWinFromHandle(hWnd);
 
     // when we get the first message for the HWND we just created, we associate
     // it with wxWindow stored in gs_winBeingCreated
@@ -2383,7 +2720,7 @@ LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM w
 
     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);
@@ -2391,7 +2728,11 @@ LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM w
     return rc;
 }
 
-WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
+bool
+wxWindowMSW::MSWHandleMessage(WXLRESULT *result,
+                              WXUINT message,
+                              WXWPARAM wParam,
+                              WXLPARAM lParam)
 {
     // did we process the message?
     bool processed = false;
@@ -2456,6 +2797,18 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
             }
             break;
 
+        case WM_ENTERSIZEMOVE:
+            {
+                processed = HandleEnterSizeMove();
+            }
+            break;
+
+        case WM_EXITSIZEMOVE:
+            {
+                processed = HandleExitSizeMove();
+            }
+            break;
+
         case WM_SIZING:
             {
                 LPRECT pRect = (LPRECT)lParam;
@@ -2493,11 +2846,11 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
             break;
 
         case WM_SETFOCUS:
-            processed = HandleSetFocus((WXHWND)(HWND)wParam);
+            processed = HandleSetFocus((WXHWND)wParam);
             break;
 
         case WM_KILLFOCUS:
-            processed = HandleKillFocus((WXHWND)(HWND)wParam);
+            processed = HandleKillFocus((WXHWND)wParam);
             break;
 
         case WM_PRINTCLIENT:
@@ -2542,7 +2895,8 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
 
 #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();
@@ -2570,6 +2924,11 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
         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
@@ -2613,7 +2972,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
 
                     // this should never happen
                     wxCHECK_MSG( win, 0,
-                                 _T("FindWindowForMouseEvent() returned NULL") );
+                                 wxT("FindWindowForMouseEvent() returned NULL") );
                 }
 #ifdef __POCKETPC__
                 if (IsContextMenuEnabled() && message == WM_LBUTTONDOWN)
@@ -2636,7 +2995,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
                         wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt);
 
                         evtCtx.SetEventObject(this);
-                        if (GetEventHandler()->ProcessEvent(evtCtx))
+                        if (HandleWindowEvent(evtCtx))
                         {
                             processed = true;
                             return true;
@@ -2660,7 +3019,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
                     // 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();
                     }
                 }
@@ -2711,35 +3070,27 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
 #endif // wxUSE_UNICODE_MSLU
 
             // for these messages we must return true if process the message
-#ifdef WM_DRAWITEM
-        case WM_DRAWITEM:
-        case WM_MEASUREITEM:
-            {
-                int idCtrl = (UINT)wParam;
-                if ( message == WM_DRAWITEM )
-                {
-                    processed = MSWOnDrawItem(idCtrl,
-                                              (WXDRAWITEMSTRUCT *)lParam);
-                }
-                else
-                {
-                    processed = MSWOnMeasureItem(idCtrl,
-                                                 (WXMEASUREITEMSTRUCT *)lParam);
-                }
+#ifdef WM_DRAWITEM
+        case WM_DRAWITEM:
+            processed = MSWOnDrawItem(wParam, (WXDRAWITEMSTRUCT *)lParam);
+            if ( processed )
+                rc.result = TRUE;
+            break;
 
-                if ( processed )
-                    rc.result = TRUE;
-            }
+        case WM_MEASUREITEM:
+            processed = MSWOnMeasureItem(wParam, (WXMEASUREITEMSTRUCT *)lParam);
+            if ( processed )
+                rc.result = TRUE;
             break;
 #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;
 
-                if ( GetWindowStyleFlag() & wxWANTS_CHARS )
+                if ( HasFlag(wxWANTS_CHARS) )
                 {
                     // in fact, we want everything
                     rc.result |= DLGC_WANTARROWS |
@@ -2754,32 +3105,36 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
 
         case WM_SYSKEYDOWN:
         case WM_KEYDOWN:
-            // If this has been processed by an event handler, return 0 now
-            // (we've handled it).
+            // Generate the key down event in any case.
             m_lastKeydownProcessed = HandleKeyDown((WORD) wParam, lParam);
             if ( m_lastKeydownProcessed )
             {
+                // If it was processed by an event handler, we stop here,
+                // notably we intentionally don't generate char event then.
                 processed = true;
             }
-
-            if ( !processed )
+            else // key down event not handled
             {
+                // Examine the event to decide whether we need to generate a
+                // char event for it ourselves or let Windows do it. Window
+                // mostly only does it for the keys which produce printable
+                // characters (although there are exceptions, e.g. VK_ESCAPE or
+                // VK_BACK (but not VK_DELETE)) while we do it for all keys
+                // except the modifier ones (the wisdom of this is debatable
+                // but by now this decision is enshrined forever due to
+                // backwards compatibility).
                 switch ( wParam )
                 {
-                    // we consider these messages "not interesting" to OnChar, so
-                    // just don't do anything more with them
+                    // No wxEVT_CHAR events are generated for these keys at all.
                     case VK_SHIFT:
                     case VK_CONTROL:
                     case VK_MENU:
                     case VK_CAPITAL:
                     case VK_NUMLOCK:
                     case VK_SCROLL:
-                        processed = true;
-                        break;
 
-                    // avoid duplicate messages to OnChar for these ASCII keys:
-                    // they will be translated by TranslateMessage() and received
-                    // in WM_CHAR
+                    // Windows will send us WM_CHAR for these ones so we'll
+                    // generate wxEVT_CHAR for them later when we get it.
                     case VK_ESCAPE:
                     case VK_SPACE:
                     case VK_RETURN:
@@ -2789,6 +3144,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
                     case VK_SUBTRACT:
                     case VK_MULTIPLY:
                     case VK_DIVIDE:
+                    case VK_DECIMAL:
                     case VK_NUMPAD0:
                     case VK_NUMPAD1:
                     case VK_NUMPAD2:
@@ -2810,10 +3166,6 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
                     case VK_OEM_COMMA:
                     case VK_OEM_MINUS:
                     case VK_OEM_PERIOD:
-                        // but set processed to false, not true to still pass them
-                        // to the control's default window proc - otherwise
-                        // built-in keyboard handling won't work
-                        processed = false;
                         break;
 
 #ifdef VK_APPS
@@ -2825,8 +3177,32 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
 #endif // VK_APPS
 
                     default:
-                        // do generate a CHAR event
-                        processed = HandleChar((WORD)wParam, lParam);
+                        if ( (wParam >= '0' && wParam <= '9') ||
+                                (wParam >= 'A' && wParam <= 'Z') )
+                        {
+                            // We'll get WM_CHAR for those later too.
+                            break;
+                        }
+
+                        // But for the rest we won't get WM_CHAR later so we do
+                        // need to generate the event right now.
+                        wxKeyEvent event(wxEVT_CHAR);
+                        InitAnyKeyEvent(event, wParam, lParam);
+
+                        // Set the "extended" bit in lParam because we want to
+                        // generate CHAR events with WXK_HOME and not
+                        // WXK_NUMPAD_HOME even if the "Home" key on numpad was
+                        // pressed.
+                        event.m_keyCode = wxMSWKeyboard::VKToWX
+                                          (
+                                            wParam,
+                                            lParam | (KF_EXTENDED << 16)
+                                          );
+
+                        // Don't produce events without any valid character
+                        // code (even if this shouldn't normally happen...).
+                        if ( event.m_keyCode != WXK_NONE )
+                            processed = HandleWindowEvent(event);
                 }
             }
             if (message == WM_SYSKEYDOWN)  // Let Windows still handle the SYSKEYs
@@ -2860,16 +3236,33 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
             }
             else
             {
-                processed = HandleChar((WORD)wParam, lParam, true);
+                processed = HandleChar((WORD)wParam, lParam);
             }
             break;
 
+        case WM_IME_STARTCOMPOSITION:
+            // IME popup needs Escape as it should undo the changes in its
+            // entry window instead of e.g. closing the dialog for which the
+            // IME is used (and losing all the changes in the IME window).
+            gs_modalEntryWindowCount++;
+            break;
+
+        case WM_IME_ENDCOMPOSITION:
+            gs_modalEntryWindowCount--;
+            break;
+
 #if wxUSE_HOTKEY
         case WM_HOTKEY:
             processed = HandleHotKey((WORD)wParam, lParam);
             break;
 #endif // wxUSE_HOTKEY
 
+        case WM_CUT:
+        case WM_COPY:
+        case WM_PASTE:
+            processed = HandleClipboardEvent(message);
+            break;
+
         case WM_HSCROLL:
         case WM_VSCROLL:
             {
@@ -2915,11 +3308,11 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
 #endif
 
         case WM_PALETTECHANGED:
-            processed = HandlePaletteChanged((WXHWND) (HWND) wParam);
+            processed = HandlePaletteChanged((WXHWND)wParam);
             break;
 
         case WM_CAPTURECHANGED:
-            processed = HandleCaptureChanged((WXHWND) (HWND) lParam);
+            processed = HandleCaptureChanged((WXHWND)lParam);
             break;
 
         case WM_SETTINGCHANGE:
@@ -2931,7 +3324,17 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
             break;
 
         case WM_ERASEBKGND:
-            processed = HandleEraseBkgnd((WXHDC)(HDC)wParam);
+            {
+#ifdef wxHAS_MSW_BACKGROUND_ERASE_HOOK
+                // check if an override was configured for this window
+                EraseBgHooks::const_iterator it = gs_eraseBgHooks.find(this);
+                if ( it != gs_eraseBgHooks.end() )
+                    processed = it->second->MSWEraseBgHook((WXHDC)wParam);
+                else
+#endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK
+                    processed = HandleEraseBkgnd((WXHDC)wParam);
+            }
+
             if ( processed )
             {
                 // we processed the message, i.e. erased the background
@@ -2946,7 +3349,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
 #endif
 
         case WM_INITDIALOG:
-            processed = HandleInitDialog((WXHWND)(HWND)wParam);
+            processed = HandleInitDialog((WXHWND)wParam);
 
             if ( processed )
             {
@@ -2970,7 +3373,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
 #endif
 
         case WM_SETCURSOR:
-            processed = HandleSetCursor((WXHWND)(HWND)wParam,
+            processed = HandleSetCursor((WXHWND)wParam,
                                         LOWORD(lParam),     // hit test
                                         HIWORD(lParam));    // mouse msg
 
@@ -3000,50 +3403,48 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
 #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;
-                // 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__
-                                              wxPoint(0,0)
+                                    wxGetMousePosition() // what else?
 #else
-                                              wxPoint(info->MousePos.x, info->MousePos.y)
+                                    wxPoint(info->MousePos.x, info->MousePos.y)
 #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);
+                    HandleWindowEvent(helpEvent);
 #ifndef __WXWINCE__
                 }
-                else if (info->iContextType == HELPINFO_MENUITEM)
+                else if ( info->iContextType == HELPINFO_MENUITEM )
                 {
                     wxHelpEvent helpEvent(wxEVT_HELP, info->iCtrlId);
                     helpEvent.SetEventObject(this);
-                    processed = GetEventHandler()->ProcessEvent(helpEvent);
+                    HandleWindowEvent(helpEvent);
 
                 }
-                //else: processed is already false
-#endif
+                else // unknown help event?
+                {
+                    processed = false;
+                }
+#endif // !__WXWINCE__
             }
             break;
-#endif
+#endif // WM_HELP
 
 #if !defined(__WXWINCE__)
         case WM_CONTEXTMENU:
@@ -3057,20 +3458,22 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
                 // we could have got an event from our child, reflect it back
                 // to it if this is the case
                 wxWindowMSW *win = NULL;
-                if ( (WXHWND)wParam != m_hWnd )
+                WXHWND hWnd = (WXHWND)wParam;
+                if ( hWnd != m_hWnd )
                 {
-                    win = FindItemByHWND((WXHWND)wParam);
+                    win = FindItemByHWND(hWnd);
                 }
 
                 if ( !win )
                     win = this;
 
                 evtCtx.SetEventObject(win);
-                processed = win->GetEventHandler()->ProcessEvent(evtCtx);
+                processed = win->HandleWindowEvent(evtCtx);
             }
             break;
 #endif
 
+#if wxUSE_MENUS
         case WM_MENUCHAR:
             // we're only interested in our own menus, not MF_SYSMENU
             if ( HIWORD(wParam) == MF_POPUP )
@@ -3084,6 +3487,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
                 }
             }
             break;
+#endif // wxUSE_MENUS
 
 #ifndef __WXWINCE__
         case WM_POWERBROADCAST:
@@ -3094,56 +3498,184 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
             }
             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
+                    RECT *rect;
+                    NCCALCSIZE_PARAMS *csparam = NULL;
+                    if ( wParam )
+                    {
+                        csparam = (NCCALCSIZE_PARAMS *)lParam;
+                        rect = &csparam->rgrc[0];
+                    }
+                    else
+                    {
+                        rect = (RECT *)lParam;
+                    }
+
+                    wxUxThemeHandle hTheme((const wxWindow *)this, L"EDIT");
+                    RECT rcClient = { 0, 0, 0, 0 };
+                    wxClientDC dc((wxWindow *)this);
+                    wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl();
+
+                    if ( theme->GetThemeBackgroundContentRect
+                                (
+                                 hTheme,
+                                 GetHdcOf(*impl),
+                                 EP_EDITTEXT,
+                                 ETS_NORMAL,
+                                 rect,
+                                 &rcClient) == S_OK )
+                    {
+                        InflateRect(&rcClient, -1, -1);
+                        if (wParam)
+                            csparam->rgrc[0] = rcClient;
+                        else
+                            *((RECT*)lParam) = rcClient;
+
+                        // WVR_REDRAW triggers a bug whereby child windows are moved up and left,
+                        // so don't use.
+                        // 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((const wxWindow *)this, L"EDIT");
+                    wxWindowDC dc((wxWindow *)this);
+                    wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl();
+
+                    // Clip the DC so that you only draw on the non-client area
+                    RECT rcBorder;
+                    wxCopyRectToRECT(GetSize(), rcBorder);
+
+                    RECT rcClient;
+                    theme->GetThemeBackgroundContentRect(
+                        hTheme, GetHdcOf(*impl), EP_EDITTEXT, ETS_NORMAL, &rcBorder, &rcClient);
+                    InflateRect(&rcClient, -1, -1);
+
+                    ::ExcludeClipRect(GetHdcOf(*impl), 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(*impl), &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(*impl), 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 )
+        return false;
+
+    *result = rc.result;
+
+    return true;
+}
+
+WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
+{
+    WXLRESULT result;
+    if ( !MSWHandleMessage(&result, message, wParam, lParam) )
     {
-#ifdef __WXDEBUG__
-        wxLogTrace(wxTraceMessages, wxT("Forwarding %s to DefWindowProc."),
+#if wxDEBUG_LEVEL >= 2
+        wxLogTrace("winmsg", wxT("Forwarding %s to DefWindowProc."),
                    wxGetMessageName(message));
-#endif // __WXDEBUG__
-        rc.result = MSWDefWindowProc(message, wParam, lParam);
+#endif // wxDEBUG_LEVEL >= 2
+        result = MSWDefWindowProc(message, wParam, lParam);
     }
 
-    return rc.result;
+    return result;
 }
 
 // ----------------------------------------------------------------------------
 // wxWindow <-> HWND map
 // ----------------------------------------------------------------------------
 
-wxWinHashTable *wxWinHandleHash = NULL;
-
-wxWindow *wxFindWinFromHandle(WXHWND hWnd)
+wxWindow *wxFindWinFromHandle(HWND hwnd)
 {
-    return (wxWindow*)wxWinHandleHash->Get((long)hWnd);
+    WindowHandles::const_iterator i = gs_windowHandles.find(hwnd);
+    return i == gs_windowHandles.end() ? NULL : i->second;
 }
 
-void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win)
+void wxAssociateWinWithHandle(HWND hwnd, wxWindowMSW *win)
 {
-    // adding NULL hWnd is (first) surely a result of an error and
+    // adding NULL hwnd is (first) surely a result of an error and
     // (secondly) breaks menu command processing
-    wxCHECK_RET( hWnd != (HWND)NULL,
-                 wxT("attempt to add a NULL hWnd to window list ignored") );
+    wxCHECK_RET( hwnd != (HWND)NULL,
+                 wxT("attempt to add a NULL hwnd to window list ignored") );
 
-    wxWindow *oldWin = wxFindWinFromHandle((WXHWND) hWnd);
-#ifdef __WXDEBUG__
-    if ( oldWin && (oldWin != win) )
-    {
-        wxLogDebug(wxT("HWND %X already associated with another window (%s)"),
-                   (int) hWnd, win->GetClassInfo()->GetClassName());
-    }
-    else
-#endif // __WXDEBUG__
-    if (!oldWin)
+#if wxDEBUG_LEVEL
+    WindowHandles::const_iterator i = gs_windowHandles.find(hwnd);
+    if ( i != gs_windowHandles.end() )
     {
-        wxWinHandleHash->Put((long)hWnd, (wxWindow *)win);
+        if ( i->second != win )
+        {
+            wxFAIL_MSG(
+                wxString::Format(
+                    wxT("HWND %p already associated with another window (%s)"),
+                    hwnd, win->GetClassInfo()->GetClassName()
+                )
+            );
+        }
+        //else: this actually happens currently because we associate the window
+        //      with its HWND during creation (if we create it) and also when
+        //      SubclassWin() is called later, this is ok
     }
+#endif // wxDEBUG_LEVEL
+
+    gs_windowHandles[hwnd] = (wxWindow *)win;
 }
 
 void wxRemoveHandleAssociation(wxWindowMSW *win)
 {
-    wxWinHandleHash->Delete((long)win->GetHWND());
+    gs_windowHandles.erase(GetHwndOf(win));
 }
 
 // ----------------------------------------------------------------------------
@@ -3156,33 +3688,22 @@ void wxWindowMSW::MSWDestroyWindow()
 {
 }
 
-bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
+void wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
                                            const wxSize& size,
                                            int& x, int& y,
                                            int& w, int& h) const
 {
-    // yes, those are just some arbitrary hardcoded numbers
-    static const int DEFAULT_Y = 200;
+    // CW_USEDEFAULT can't be used for child windows so just position them at
+    // the origin by default
+    x = pos.x == wxDefaultCoord ? 0 : pos.x;
+    y = pos.y == wxDefaultCoord ? 0 : pos.y;
 
-    bool nonDefault = false;
-
-    if ( pos.x == wxDefaultCoord )
-    {
-        // if x is set to CW_USEDEFAULT, y parameter is ignored anyhow so we
-        // can just as well set it to CW_USEDEFAULT as well
-        x =
-        y = CW_USEDEFAULT;
-    }
-    else
-    {
-        // OTOH, if x is not set to CW_USEDEFAULT, y shouldn't be set to it
-        // neither because it is not handled as a special value by Windows then
-        // and so we have to choose some default value for it
-        x = pos.x;
-        y = pos.y == wxDefaultCoord ? DEFAULT_Y : pos.y;
+    AdjustForParentClientOrigin(x, y);
 
-        nonDefault = true;
-    }
+    // We don't have any clearly good choice for the size by default neither
+    // but we must use something non-zero.
+    w = WidthDefault(size.x);
+    h = HeightDefault(size.y);
 
     /*
       NB: there used to be some code here which set the initial size of the
@@ -3200,49 +3721,6 @@ bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
           this and ignore any attempts to change the window size to the size it
           already has - so no WM_SIZE would be sent.
      */
-
-
-    // we don't use CW_USEDEFAULT here for several reasons:
-    //
-    //  1. it results in huge frames on modern screens (1000*800 is not
-    //     uncommon on my 1280*1024 screen) which is way too big for a half
-    //     empty frame of most of wxWidgets samples for example)
-    //
-    //  2. it is buggy for frames with wxFRAME_TOOL_WINDOW style for which
-    //     the default is for whatever reason 8*8 which breaks client <->
-    //     window size calculations (it would be nice if it didn't, but it
-    //     does and the simplest way to fix it seemed to change the broken
-    //     default size anyhow)
-    //
-    //  3. there is just no advantage in doing it: with x and y it is
-    //     possible that [future versions of] Windows position the new top
-    //     level window in some smart way which we can't do, but we can
-    //     guess a reasonably good size for a new window just as well
-    //     ourselves
-
-    // However, on PocketPC devices, we must use the default
-    // size if possible.
-#ifdef _WIN32_WCE
-    if (size.x == wxDefaultCoord)
-        w = CW_USEDEFAULT;
-    else
-        w = size.x;
-    if (size.y == wxDefaultCoord)
-        h = CW_USEDEFAULT;
-    else
-        h = size.y;
-#else
-    if ( size.x == wxDefaultCoord || size.y == wxDefaultCoord)
-    {
-        nonDefault = true;
-    }
-    w = WidthDefault(size.x);
-    h = HeightDefault(size.y);
-#endif
-
-    AdjustForParentClientOrigin(x, y);
-
-    return nonDefault;
 }
 
 WXHWND wxWindowMSW::MSWGetParent() const
@@ -3257,6 +3735,17 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass,
                             WXDWORD style,
                             WXDWORD extendedStyle)
 {
+    // check a common bug in the user code: if the window is created with a
+    // non-default ctor and Create() is called too, we'd create 2 HWND for a
+    // single wxWindow object and this results in all sorts of trouble,
+    // especially for wxTLWs
+    wxCHECK_MSG( !m_hWnd, true, "window can't be recreated" );
+
+    // this can happen if this function is called using the return value of
+    // wxApp::GetRegisteredClassName() which failed
+    wxCHECK_MSG( wclass, false, "failed to register window class?" );
+
+
     // choose the position/size for the new window
     int x, y, w, h;
     (void)MSWGetCreateWindowCoords(pos, size, x, y, w, h);
@@ -3271,7 +3760,7 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass,
     wxString className(wclass);
     if ( !HasFlag(wxFULL_REPAINT_ON_RESIZE) )
     {
-        className += wxT("NR");
+        className += wxApp::GetNoRedrawClassSuffix();
     }
 
     // do create the window
@@ -3280,12 +3769,12 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass,
     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(),
-                        (HMENU)controlId,
+                        (HMENU)wxUIntToPtr(controlId),
                         wxGetInstance(),
                         NULL                        // no extra data
                        );
@@ -3315,7 +3804,7 @@ bool wxWindowMSW::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
 #ifndef __WXMICROWIN__
     LPNMHDR hdr = (LPNMHDR)lParam;
     HWND hWnd = hdr->hwndFrom;
-    wxWindow *win = wxFindWinFromHandle((WXHWND)hWnd);
+    wxWindow *win = wxFindWinFromHandle(hWnd);
 
     // if the control is one of our windows, let it handle the message itself
     if ( win )
@@ -3393,7 +3882,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
-        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).
@@ -3401,7 +3890,7 @@ bool wxWindowMSW::HandleTooltipNotify(WXUINT code,
                     (
                         CP_ACP,
                         0,                      // no flags
-                        ttip,
+                        ttip.wx_str(),
                         tipLength,
                         buf,
                         WXSIZEOF(buf) - 1
@@ -3409,7 +3898,7 @@ bool wxWindowMSW::HandleTooltipNotify(WXUINT code,
 
         if ( !len )
         {
-            wxLogLastError(_T("MultiByteToWideChar()"));
+            wxLogLastError(wxT("MultiByteToWideChar()"));
         }
 
         buf[len] = L'\0';
@@ -3422,8 +3911,7 @@ bool wxWindowMSW::HandleTooltipNotify(WXUINT code,
         // if we got TTN_NEEDTEXTW in Unicode build: in this case we just have
         // to copy the string we have into the buffer
         static wxChar buf[513];
-        wxStrncpy(buf, ttip.c_str(), WXSIZEOF(buf) - 1);
-        buf[WXSIZEOF(buf) - 1] = _T('\0');
+        wxStrlcpy(buf, ttip.c_str(), WXSIZEOF(buf));
         ttText->lpszText = buf;
     }
 
@@ -3496,7 +3984,7 @@ bool wxWindowMSW::HandleEndSession(bool endSession, long logOff)
     wxCloseEvent event(wxEVT_END_SESSION, wxID_ANY);
     event.SetEventObject(wxTheApp);
     event.SetCanVeto(false);
-    event.SetLoggingOff( (logOff == (long)ENDSESSION_LOGOFF) );
+    event.SetLoggingOff((logOff & ENDSESSION_LOGOFF) != 0);
 
     return wxTheApp->ProcessEvent(event);
 #else
@@ -3528,16 +4016,13 @@ bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT WXUNUSED_IN_WINCE(cs),
 
 bool wxWindowMSW::HandleDestroy()
 {
-    SendDestroyEvent();
-
     // delete our drop target if we've got one
 #if wxUSE_DRAG_AND_DROP
     if ( m_dropTarget != NULL )
     {
         m_dropTarget->Revoke(m_hWnd);
 
-        delete m_dropTarget;
-        m_dropTarget = NULL;
+        wxDELETE(m_dropTarget);
     }
 #endif // wxUSE_DRAG_AND_DROP
 
@@ -3558,7 +4043,7 @@ bool wxWindowMSW::HandleActivate(int state,
                           m_windowId);
     event.SetEventObject(this);
 
-    return GetEventHandler()->ProcessEvent(event);
+    return HandleWindowEvent(event);
 }
 
 bool wxWindowMSW::HandleSetFocus(WXHWND hwnd)
@@ -3573,7 +4058,7 @@ bool wxWindowMSW::HandleSetFocus(WXHWND hwnd)
     // notify the parent keeping track of focus for the kbd navigation
     // purposes that we got it
     wxChildFocusEvent eventFocus((wxWindow *)this);
-    (void)GetEventHandler()->ProcessEvent(eventFocus);
+    (void)HandleWindowEvent(eventFocus);
 
 #if wxUSE_CARET
     // Deal with caret
@@ -3583,22 +4068,13 @@ bool wxWindowMSW::HandleSetFocus(WXHWND hwnd)
     }
 #endif // wxUSE_CARET
 
-#if wxUSE_TEXTCTRL
-    // If it's a wxTextCtrl don't send the event as it will be done
-    // after the control gets to process it from EN_FOCUS handler
-    if ( wxDynamicCastThis(wxTextCtrl) )
-    {
-        return false;
-    }
-#endif // wxUSE_TEXTCTRL
-
     wxFocusEvent event(wxEVT_SET_FOCUS, m_windowId);
     event.SetEventObject(this);
 
     // wxFindWinFromHandle() may return NULL, it is ok
     event.SetWindow(wxFindWinFromHandle(hwnd));
 
-    return GetEventHandler()->ProcessEvent(event);
+    return HandleWindowEvent(event);
 }
 
 bool wxWindowMSW::HandleKillFocus(WXHWND hwnd)
@@ -3611,16 +4087,6 @@ bool wxWindowMSW::HandleKillFocus(WXHWND hwnd)
     }
 #endif // wxUSE_CARET
 
-#if wxUSE_TEXTCTRL
-    // If it's a wxTextCtrl don't send the event as it will be done
-    // after the control gets to process it.
-    wxTextCtrl *ctrl = wxDynamicCastThis(wxTextCtrl);
-    if ( ctrl )
-    {
-        return false;
-    }
-#endif
-
     // Don't send the event when in the process of being deleted.  This can
     // only cause problems if the event handler tries to access the object.
     if ( m_isBeingDeleted )
@@ -3634,7 +4100,7 @@ bool wxWindowMSW::HandleKillFocus(WXHWND hwnd)
     // wxFindWinFromHandle() may return NULL, it is ok
     event.SetWindow(wxFindWinFromHandle(hwnd));
 
-    return GetEventHandler()->ProcessEvent(event);
+    return HandleWindowEvent(event);
 }
 
 // ---------------------------------------------------------------------------
@@ -3660,7 +4126,7 @@ bool wxWindowMSW::HandleShow(bool show, int WXUNUSED(status))
     wxShowEvent event(GetId(), show);
     event.SetEventObject(this);
 
-    return GetEventHandler()->ProcessEvent(event);
+    return HandleWindowEvent(event);
 }
 
 bool wxWindowMSW::HandleInitDialog(WXHWND WXUNUSED(hWndFocus))
@@ -3668,7 +4134,7 @@ bool wxWindowMSW::HandleInitDialog(WXHWND WXUNUSED(hWndFocus))
     wxInitDialogEvent event(GetId());
     event.SetEventObject(this);
 
-    return GetEventHandler()->ProcessEvent(event);
+    return HandleWindowEvent(event);
 }
 
 bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam)
@@ -3698,7 +4164,6 @@ bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam)
         ::DragQueryFile(hFilesInfo, wIndex,
                         wxStringBuffer(files[wIndex], len), len);
     }
-    DragFinish (hFilesInfo);
 
     wxDropFilesEvent event(wxEVT_DROP_FILES, gwFilesDropped, files);
     event.SetEventObject(this);
@@ -3708,7 +4173,9 @@ bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam)
     event.m_pos.x = dropPoint.x;
     event.m_pos.y = dropPoint.y;
 
-    return GetEventHandler()->ProcessEvent(event);
+    DragFinish(hFilesInfo);
+
+    return HandleWindowEvent(event);
 #endif
 }
 
@@ -3719,66 +4186,61 @@ bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd),
 {
 #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__
-    if ( !::GetCursorPosWinCE(&pt))
+        if ( !::GetCursorPosWinCE(&pt))
 #else
-    if ( !::GetCursorPos(&pt) )
+        if ( !::GetCursorPos(&pt) )
 #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);
+        event.SetId(GetId());
+        event.SetEventObject(this);
 
-        // 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 = HandleWindowEvent(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.IsOk() )
             {
-                hcursor = wxGetCurrentBusyCursor();
+                hcursor = GetHcursorOf(m_cursor);
             }
-            else if ( !hcursor )
+
+            if ( !hcursor && !GetParent() )
             {
                 const wxCursor *cursor = wxGetGlobalCursor();
-                if ( cursor && cursor->Ok() )
+                if ( cursor && cursor->IsOk() )
                 {
                     hcursor = GetHcursorOf(*cursor);
                 }
@@ -3786,10 +4248,9 @@ bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd),
         }
     }
 
+
     if ( hcursor )
     {
-//        wxLogDebug("HandleSetCursor: Setting cursor %ld", (long) hcursor);
-
         ::SetCursor(hcursor);
 
         // cursor set, stop here
@@ -3829,7 +4290,7 @@ bool wxWindowMSW::HandlePower(WXWPARAM WXUNUSED_IN_WINCE(wParam),
             break;
 
         default:
-            wxLogDebug(_T("Unknown WM_POWERBROADCAST(%d) event"), wParam);
+            wxLogDebug(wxT("Unknown WM_POWERBROADCAST(%d) event"), wParam);
             // fall through
 
         // these messages are currently not mapped to wx events
@@ -3840,10 +4301,10 @@ bool wxWindowMSW::HandlePower(WXWPARAM WXUNUSED_IN_WINCE(wParam),
         case PBT_APMBATTERYLOW:
         case PBT_APMPOWERSTATUSCHANGE:
         case PBT_APMOEMEVENT:
+        case PBT_APMRESUMECRITICAL:
 #ifdef PBT_APMRESUMEAUTOMATIC
         case PBT_APMRESUMEAUTOMATIC:
 #endif
-        case PBT_APMRESUMECRITICAL:
             evtType = wxEVT_NULL;
             break;
     }
@@ -3855,7 +4316,7 @@ bool wxWindowMSW::HandlePower(WXWPARAM WXUNUSED_IN_WINCE(wParam),
     // TODO: notify about PBTF_APMRESUMEFROMFAILURE in case of resume events?
 
     wxPowerEvent event(evtType);
-    if ( !GetEventHandler()->ProcessEvent(event) )
+    if ( !HandleWindowEvent(event) )
         return false;
 
     *vetoed = event.IsVetoed();
@@ -3864,6 +4325,35 @@ bool wxWindowMSW::HandlePower(WXWPARAM WXUNUSED_IN_WINCE(wParam),
 #endif
 }
 
+bool wxWindowMSW::IsDoubleBuffered() const
+{
+    for ( const wxWindowMSW *win = this; win; win = win->GetParent() )
+    {
+        if ( wxHasWindowExStyle(win, WS_EX_COMPOSITED) )
+            return true;
+
+        if ( win->IsTopLevel() )
+            break;
+    }
+
+    return false;
+}
+
+void wxWindowMSW::SetDoubleBuffered(bool on)
+{
+    // Get the current extended style bits
+    long exstyle = wxGetWindowExStyle(this);
+
+    // Twiddle the bit as needed
+    if ( on )
+        exstyle |= WS_EX_COMPOSITED;
+    else
+        exstyle &= ~WS_EX_COMPOSITED;
+
+    // put it back
+    wxSetWindowExStyle(this, exstyle);
+}
+
 // ---------------------------------------------------------------------------
 // owner drawn stuff
 // ---------------------------------------------------------------------------
@@ -3893,7 +4383,7 @@ wxWindowMSW::MSWOnDrawItem(int WXUNUSED_UNLESS_ODRAWN(id),
             return false;
 
         wxCHECK_MSG( wxDynamicCast(pMenuItem, wxMenuItem),
-                         false, _T("MSWOnDrawItem: bad wxMenuItem pointer") );
+                         false, wxT("MSWOnDrawItem: bad wxMenuItem pointer") );
 
         // prepare to call OnDrawItem(): notice using of wxDCTemp to prevent
         // the DC from being released
@@ -3959,7 +4449,7 @@ wxWindowMSW::MSWOnMeasureItem(int id, WXMEASUREITEMSTRUCT *itemStruct)
             return false;
 
         wxCHECK_MSG( wxDynamicCast(pMenuItem, wxMenuItem),
-                        false, _T("MSWOnMeasureItem: bad wxMenuItem pointer") );
+                        false, wxT("MSWOnMeasureItem: bad wxMenuItem pointer") );
 
         size_t w, h;
         bool rc = pMenuItem->OnMeasureItem(&w, &h);
@@ -3992,7 +4482,7 @@ bool wxWindowMSW::HandleSysColorChange()
     wxSysColourChangedEvent event;
     event.SetEventObject(this);
 
-    (void)GetEventHandler()->ProcessEvent(event);
+    (void)HandleWindowEvent(event);
 
     // always let the system carry on the default processing to allow the
     // native controls to react to the colours update
@@ -4004,7 +4494,7 @@ bool wxWindowMSW::HandleDisplayChange()
     wxDisplayChangedEvent event;
     event.SetEventObject(this);
 
-    return GetEventHandler()->ProcessEvent(event);
+    return HandleWindowEvent(event);
 }
 
 #ifndef __WXMICROWIN__
@@ -4068,15 +4558,19 @@ bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange)
     event.SetEventObject(this);
     event.SetChangedWindow(wxFindWinFromHandle(hWndPalChange));
 
-    return GetEventHandler()->ProcessEvent(event);
+    return HandleWindowEvent(event);
 }
 
 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();
 
-    return GetEventHandler()->ProcessEvent(event);
+    wxWindow *win = wxFindWinFromHandle(hWndGainedCapture);
+    wxMouseCaptureChangedEvent event(GetId(), win);
+    event.SetEventObject(this);
+    return HandleWindowEvent(event);
 }
 
 bool wxWindowMSW::HandleSettingChange(WXWPARAM wParam, WXLPARAM lParam)
@@ -4131,7 +4625,7 @@ bool wxWindowMSW::HandleQueryNewPalette()
     wxQueryNewPaletteEvent event(GetId());
     event.SetEventObject(this);
 
-    return GetEventHandler()->ProcessEvent(event) && event.GetPaletteRealized();
+    return HandleWindowEvent(event) && event.GetPaletteRealized();
 }
 
 // Responds to colour changes: passes event on to children.
@@ -4182,12 +4676,12 @@ extern wxCOLORMAP *wxGetStdColourMap()
             // reference bitmap which can tell us what the RGB values change
             // to.
             wxLogNull logNo; // suppress error if we couldn't load the bitmap
-            wxBitmap stdColourBitmap(_T("wxBITMAP_STD_COLOURS"));
-            if ( stdColourBitmap.Ok() )
+            wxBitmap stdColourBitmap(wxT("wxBITMAP_STD_COLOURS"));
+            if ( stdColourBitmap.IsOk() )
             {
                 // the pixels in the bitmap must correspond to wxSTD_COL_XXX!
                 wxASSERT_MSG( stdColourBitmap.GetWidth() == wxSTD_COL_MAX,
-                              _T("forgot to update wxBITMAP_STD_COLOURS!") );
+                              wxT("forgot to update wxBITMAP_STD_COLOURS!") );
 
                 wxMemoryDC memDC;
                 memDC.SelectObject(stdColourBitmap);
@@ -4230,31 +4724,120 @@ extern wxCOLORMAP *wxGetStdColourMap()
     return s_cmap;
 }
 
+#if wxUSE_UXTHEME && !defined(TMT_FILLCOLOR)
+    #define TMT_FILLCOLOR       3802
+    #define TMT_TEXTCOLOR       3803
+    #define TMT_BORDERCOLOR     3801
+#endif
+
+wxColour wxWindowMSW::MSWGetThemeColour(const wchar_t *themeName,
+                                        int themePart,
+                                        int themeState,
+                                        MSWThemeColour themeColour,
+                                        wxSystemColour fallback) const
+{
+#if wxUSE_UXTHEME
+    const wxUxThemeEngine* theme = wxUxThemeEngine::GetIfActive();
+    if ( theme )
+    {
+        int themeProperty = 0;
+
+        // TODO: Convert this into a table? Sure would be faster.
+        switch ( themeColour )
+        {
+            case ThemeColourBackground:
+                themeProperty = TMT_FILLCOLOR;
+                break;
+            case ThemeColourText:
+                themeProperty = TMT_TEXTCOLOR;
+                break;
+            case ThemeColourBorder:
+                themeProperty = TMT_BORDERCOLOR;
+                break;
+            default:
+                wxFAIL_MSG(wxT("unsupported theme colour"));
+        };
+
+        wxUxThemeHandle hTheme((const wxWindow *)this, themeName);
+        COLORREF col;
+        HRESULT hr = theme->GetThemeColor
+                            (
+                                hTheme,
+                                themePart,
+                                themeState,
+                                themeProperty,
+                                &col
+                            );
+
+        if ( SUCCEEDED(hr) )
+            return wxRGBToColour(col);
+
+        wxLogApiError(
+            wxString::Format(
+                "GetThemeColor(%s, %i, %i, %i)",
+                themeName, themePart, themeState, themeProperty),
+            hr);
+    }
+#else
+    wxUnusedVar(themeName);
+    wxUnusedVar(themePart);
+    wxUnusedVar(themeState);
+    wxUnusedVar(themeColour);
+#endif
+    return wxSystemSettings::GetColour(fallback);
+}
+
 // ---------------------------------------------------------------------------
 // painting
 // ---------------------------------------------------------------------------
 
+// this variable is used to check that a paint event handler which processed
+// the event did create a wxPaintDC inside its code and called BeginPaint() to
+// validate the invalidated window area as otherwise we'd keep getting an
+// endless stream of WM_PAINT messages for this window resulting in a lot of
+// difficult to debug problems (e.g. impossibility to repaint other windows,
+// lack of timer and idle events and so on)
+extern bool wxDidCreatePaintDC;
+bool wxDidCreatePaintDC = false;
+
 bool wxWindowMSW::HandlePaint()
 {
     HRGN hRegion = ::CreateRectRgn(0, 0, 0, 0); // Dummy call to get a handle
     if ( !hRegion )
+    {
         wxLogLastError(wxT("CreateRectRgn"));
+    }
     if ( ::GetUpdateRgn(GetHwnd(), hRegion, FALSE) == ERROR )
+    {
         wxLogLastError(wxT("GetUpdateRgn"));
+    }
 
     m_updateRegion = wxRegion((WXHRGN) hRegion);
 
+    wxDidCreatePaintDC = false;
+
     wxPaintEvent event(m_windowId);
     event.SetEventObject(this);
 
-    bool processed = GetEventHandler()->ProcessEvent(event);
+    bool processed = HandleWindowEvent(event);
+
+    if ( processed && !wxDidCreatePaintDC )
+    {
+        // do call MSWDefWindowProc() to validate the update region to avoid
+        // the problems mentioned above
+        processed = false;
+    }
 
     // note that we must generate NC event after the normal one as otherwise
     // BeginPaint() will happily overwrite our decorations with the background
     // colour
     wxNcPaintEvent eventNc(m_windowId);
     eventNc.SetEventObject(this);
-    GetEventHandler()->ProcessEvent(eventNc);
+    HandleWindowEvent(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;
 }
@@ -4265,7 +4848,7 @@ void wxWindowMSW::OnPaint(wxPaintEvent& event)
 #ifdef __WXUNIVERSAL__
     event.Skip();
 #else
-    HDC hDC = (HDC) wxPaintDC::FindDCInCache((wxWindow*) event.GetEventObject());
+    HDC hDC = (HDC) wxPaintDCImpl::FindDCInCache((wxWindow*) event.GetEventObject());
     if (hDC != 0)
     {
         MSWDefWindowProc(WM_PAINT, (WPARAM) hDC, 0);
@@ -4275,101 +4858,158 @@ void wxWindowMSW::OnPaint(wxPaintEvent& event)
 
 bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc)
 {
-    wxDCTemp dc(hdc);
+    switch ( GetBackgroundStyle() )
+    {
+        case wxBG_STYLE_ERASE:
+        case wxBG_STYLE_COLOUR:
+            // we need to generate an erase background event
+            {
+                wxDCTemp dc(hdc, GetClientSize());
+                wxDCTempImpl *impl = (wxDCTempImpl*) dc.GetImpl();
 
-    dc.SetHDC(hdc);
-    dc.SetWindow((wxWindow *)this);
+                impl->SetHDC(hdc);
+                impl->SetWindow((wxWindow *)this);
 
-    wxEraseEvent event(m_windowId, &dc);
-    event.SetEventObject(this);
-    bool rc = GetEventHandler()->ProcessEvent(event);
+                wxEraseEvent event(m_windowId, &dc);
+                event.SetEventObject(this);
+                bool rc = HandleWindowEvent(event);
 
-    // must be called manually as ~wxDC doesn't do anything for wxDCTemp
-    dc.SelectOldObjects(hdc);
+                // must be called manually as ~wxDC doesn't do anything for
+                // wxDCTemp
+                impl->SelectOldObjects(hdc);
 
-    return rc;
+                if ( rc )
+                {
+                    // background erased by the user-defined handler
+                    return true;
+                }
+            }
+            // fall through
+
+        case wxBG_STYLE_SYSTEM:
+            if ( !DoEraseBackground(hdc) )
+            {
+                // let the default processing to take place if we didn't erase
+                // the background ourselves
+                return false;
+            }
+            break;
+
+        case wxBG_STYLE_PAINT:
+        case wxBG_STYLE_TRANSPARENT:
+            // no need to do anything here at all, background will be entirely
+            // redrawn in WM_PAINT handler
+            break;
+
+        default:
+            wxFAIL_MSG( "unknown background style" );
+    }
+
+    return true;
 }
 
-void wxWindowMSW::OnEraseBackground(wxEraseEvent& event)
+#ifdef wxHAS_MSW_BACKGROUND_ERASE_HOOK
+
+bool wxWindowMSW::MSWHasEraseBgHook() const
 {
-    // standard non top level controls (i.e. except the dialogs) always erase
-    // their background themselves in HandleCtlColor() or have some control-
-    // specific ways to set the colours (common controls)
-    if ( IsOfStandardClass() && !IsTopLevel() )
-    {
-        event.Skip();
-        return;
-    }
+    return gs_eraseBgHooks.find(const_cast<wxWindowMSW *>(this))
+                != gs_eraseBgHooks.end();
+}
 
-    if ( GetBackgroundStyle() == wxBG_STYLE_CUSTOM )
+void wxWindowMSW::MSWSetEraseBgHook(wxWindow *child)
+{
+    if ( child )
     {
-        // don't skip the event here, custom background means that the app
-        // is drawing it itself in its OnPaint(), so don't draw it at all
-        // now to avoid flicker
-        return;
+        if ( !gs_eraseBgHooks.insert(
+                EraseBgHooks::value_type(this, child)).second )
+        {
+            wxFAIL_MSG( wxT("Setting erase background hook twice?") );
+        }
     }
-
-
-    // do default background painting
-    if ( !DoEraseBackground(GetHdcOf(*event.GetDC())) )
+    else // reset the hook
     {
-        // let the system paint the background
-        event.Skip();
+        if ( gs_eraseBgHooks.erase(this) != 1 )
+        {
+            wxFAIL_MSG( wxT("Resetting erase background which was not set?") );
+        }
     }
 }
 
+#endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK
+
 bool wxWindowMSW::DoEraseBackground(WXHDC hDC)
 {
     HBRUSH hbr = (HBRUSH)MSWGetBgBrush(hDC);
     if ( !hbr )
         return false;
 
-    wxFillRect(GetHwnd(), (HDC)hDC, hbr);
+    // erase just the client area of the window, this is important for the
+    // frames to avoid drawing over the toolbar part of the window (you might
+    // think using WS_CLIPCHILDREN would prevent this from happening, but it
+    // clearly doesn't)
+    RECT rc;
+    wxCopyRectToRECT(GetClientRect(), rc);
+    ::FillRect((HDC)hDC, &rc, hbr);
 
     return true;
 }
 
 WXHBRUSH
-wxWindowMSW::MSWGetBgBrushForChild(WXHDC WXUNUSED(hDC), WXHWND hWnd)
+wxWindowMSW::MSWGetBgBrushForChild(WXHDC hDC, wxWindowMSW *child)
 {
-    if ( m_hasBgCol )
+    // Test for the custom background brush first.
+    WXHBRUSH hbrush = MSWGetCustomBgBrush();
+    if ( hbrush )
     {
-        // our background colour applies to:
-        //  1. this window itself, always
-        //  2. all children unless the colour is "not inheritable"
-        //  3. even if it is not inheritable, our immediate transparent
-        //     children should still inherit it -- but not any transparent
-        //     children because it would look wrong if a child of non
-        //     transparent child would show our bg colour when the child itself
-        //     does not
-        wxWindow *win = wxFindWinFromHandle(hWnd);
-        if ( win == this ||
-                m_inheritBgCol ||
-                    (win && win->HasTransparentBackground() &&
-                        win->GetParent() == this) )
-        {
-            // draw children with the same colour as the parent
-            wxBrush *
-                brush = wxTheBrushList->FindOrCreateBrush(GetBackgroundColour());
+        // We assume that this is either a stipple or hatched brush and not a
+        // solid one as otherwise it would have been enough to set the
+        // background colour and such brushes need to be positioned correctly
+        // in order to align when different windows are painted, so do it here.
+        RECT rc;
+        ::GetWindowRect(GetHwndOf(child), &rc);
+
+        ::MapWindowPoints(NULL, GetHwnd(), (POINT *)&rc, 1);
 
-            return (WXHBRUSH)GetHbrushOf(*brush);
+        if ( !::SetBrushOrgEx((HDC)hDC, -rc.left, -rc.top, NULL) )
+        {
+            wxLogLastError(wxT("SetBrushOrgEx(bg brush)"));
         }
+
+        return hbrush;
+    }
+
+    // Otherwise see if we have a custom background colour.
+    if ( m_hasBgCol )
+    {
+        wxBrush *
+            brush = wxTheBrushList->FindOrCreateBrush(GetBackgroundColour());
+
+        return (WXHBRUSH)GetHbrushOf(*brush);
     }
 
     return 0;
 }
 
-WXHBRUSH wxWindowMSW::MSWGetBgBrush(WXHDC hDC, WXHWND hWndToPaint)
+WXHBRUSH wxWindowMSW::MSWGetBgBrush(WXHDC hDC)
 {
-    if ( !hWndToPaint )
-        hWndToPaint = GetHWND();
+    // Use the special wxWindowBeingErased variable if it is set as the child
+    // being erased.
+    wxWindowMSW * const child =
+#if wxUSE_UXTHEME
+                                wxWindowBeingErased ? wxWindowBeingErased :
+#endif
+                                this;
 
     for ( wxWindowMSW *win = this; win; win = win->GetParent() )
     {
-        WXHBRUSH hBrush = win->MSWGetBgBrushForChild(hDC, hWndToPaint);
+        WXHBRUSH hBrush = win->MSWGetBgBrushForChild(hDC, child);
         if ( hBrush )
             return hBrush;
 
+        // don't use the parent background if we're not transparent
+        if ( !win->HasTransparentBackground() )
+            break;
+
         // background is not inherited beyond top level windows
         if ( win->IsTopLevel() )
             break;
@@ -4421,7 +5061,7 @@ bool wxWindowMSW::HandleMinimize()
     wxIconizeEvent event(m_windowId);
     event.SetEventObject(this);
 
-    return GetEventHandler()->ProcessEvent(event);
+    return HandleWindowEvent(event);
 }
 
 bool wxWindowMSW::HandleMaximize()
@@ -4429,7 +5069,7 @@ bool wxWindowMSW::HandleMaximize()
     wxMaximizeEvent event(m_windowId);
     event.SetEventObject(this);
 
-    return GetEventHandler()->ProcessEvent(event);
+    return HandleWindowEvent(event);
 }
 
 bool wxWindowMSW::HandleMove(int x, int y)
@@ -4438,7 +5078,7 @@ bool wxWindowMSW::HandleMove(int x, int y)
     wxMoveEvent event(point, m_windowId);
     event.SetEventObject(this);
 
-    return GetEventHandler()->ProcessEvent(event);
+    return HandleWindowEvent(event);
 }
 
 bool wxWindowMSW::HandleMoving(wxRect& rect)
@@ -4446,15 +5086,33 @@ bool wxWindowMSW::HandleMoving(wxRect& rect)
     wxMoveEvent event(rect, m_windowId);
     event.SetEventObject(this);
 
-    bool rc = GetEventHandler()->ProcessEvent(event);
+    bool rc = HandleWindowEvent(event);
     if (rc)
         rect = event.GetRect();
     return rc;
 }
 
+bool wxWindowMSW::HandleEnterSizeMove()
+{
+    wxMoveEvent event(wxPoint(0,0), m_windowId);
+    event.SetEventType(wxEVT_MOVE_START);
+    event.SetEventObject(this);
+
+    return HandleWindowEvent(event);
+}
+
+bool wxWindowMSW::HandleExitSizeMove()
+{
+    wxMoveEvent event(wxPoint(0,0), m_windowId);
+    event.SetEventType(wxEVT_MOVE_END);
+    event.SetEventObject(this);
+
+    return HandleWindowEvent(event);
+}
+
 bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam)
 {
-#if USE_DEFERRED_SIZING
+#if wxUSE_DEFERRED_SIZING
     // when we resize this window, its children are probably going to be
     // repositioned as well, prepare to use DeferWindowPos() for them
     int numChildren = 0;
@@ -4475,20 +5133,20 @@ bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam)
             m_hDWP = (WXHANDLE)::BeginDeferWindowPos(numChildren);
             if ( !m_hDWP )
             {
-                wxLogLastError(_T("BeginDeferWindowPos"));
+                wxLogLastError(wxT("BeginDeferWindowPos"));
             }
             if (m_hDWP)
                 useDefer = true;
         }
     }
-#endif // USE_DEFERRED_SIZING
+#endif // wxUSE_DEFERRED_SIZING
 
     // update this window size
     bool processed = false;
     switch ( wParam )
     {
         default:
-            wxFAIL_MSG( _T("unexpected WM_SIZE parameter") );
+            wxFAIL_MSG( wxT("unexpected WM_SIZE parameter") );
             // fall through nevertheless
 
         case SIZE_MAXHIDE:
@@ -4511,10 +5169,10 @@ bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam)
             wxSizeEvent event(GetSize(), m_windowId);
             event.SetEventObject(this);
 
-            processed = GetEventHandler()->ProcessEvent(event);
+            processed = HandleWindowEvent(event);
     }
 
-#if USE_DEFERRED_SIZING
+#if wxUSE_DEFERRED_SIZING
     // and finally change the positions of all child windows at once
     if ( useDefer && m_hDWP )
     {
@@ -4528,7 +5186,7 @@ bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam)
         // do put all child controls in place at once
         if ( !::EndDeferWindowPos(hDWP) )
         {
-            wxLogLastError(_T("EndDeferWindowPos"));
+            wxLogLastError(wxT("EndDeferWindowPos"));
         }
 
         // Reset our children's pending pos/size values.
@@ -4536,12 +5194,11 @@ bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam)
               node;
               node = node->GetNext() )
         {
-            wxWindowMSW *child = node->GetData();
-            child->m_pendingPosition = wxDefaultPosition;
-            child->m_pendingSize = wxDefaultSize;
+            wxWindowMSW * const child = node->GetData();
+            child->MSWEndDeferWindowPos();
         }
     }
-#endif // USE_DEFERRED_SIZING
+#endif // wxUSE_DEFERRED_SIZING
 
     return processed;
 }
@@ -4551,7 +5208,7 @@ bool wxWindowMSW::HandleSizing(wxRect& rect)
     wxSizeEvent event(rect, m_windowId);
     event.SetEventObject(this);
 
-    bool rc = GetEventHandler()->ProcessEvent(event);
+    bool rc = HandleWindowEvent(event);
     if (rc)
         rect = event.GetRect();
     return rc;
@@ -4603,8 +5260,11 @@ bool wxWindowMSW::HandleGetMinMaxInfo(void *WXUNUSED_IN_WINCE(mmInfo))
 // 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 )
     {
@@ -4627,8 +5287,7 @@ bool wxWindowMSW::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control)
     // 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 )
@@ -4642,15 +5301,11 @@ bool wxWindowMSW::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control)
     // coming from a control to wxEVT_COMMAND_MENU_SELECTED
     if ( !control )
     {
-        // If no child window, it may be an accelerator, e.g. for a popup menu
-        // command
-
-        wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED);
+        wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, id);
         event.SetEventObject(this);
-        event.SetId(id);
         event.SetInt(id);
 
-        return GetEventHandler()->ProcessEvent(event);
+        return HandleWindowEvent(event);
     }
     else
     {
@@ -4694,7 +5349,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_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());
@@ -4722,7 +5381,7 @@ void wxWindowMSW::InitMouseEvent(wxMouseEvent& event,
 // still don't get move, enter nor leave events.
 static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y)
 {
-    wxCHECK_MSG( x && y, win, _T("NULL pointer in FindWindowForMouseEvent") );
+    wxCHECK_MSG( x && y, win, wxT("NULL pointer in FindWindowForMouseEvent") );
 
     // first try to find a non transparent child: this allows us to send events
     // to a static text which is inside a static box, for example
@@ -4760,7 +5419,7 @@ static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y)
                 ::IsWindowVisible(hwndUnderMouse) &&
                     ::IsWindowEnabled(hwndUnderMouse) )
     {
-        wxWindow *winUnderMouse = wxFindWinFromHandle((WXHWND)hwndUnderMouse);
+        wxWindow *winUnderMouse = wxFindWinFromHandle(hwndUnderMouse);
         if ( winUnderMouse )
         {
             // translate the mouse coords to the other window coords
@@ -4792,13 +5451,33 @@ bool wxWindowMSW::HandleMouseEvent(WXUINT msg, int x, int y, WXUINT flags)
         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);
 
-    return GetEventHandler()->ProcessEvent(event);
+    return HandleWindowEvent(event);
 }
 
 bool wxWindowMSW::HandleMouseMove(int x, int y, WXUINT flags)
@@ -4815,24 +5494,47 @@ bool wxWindowMSW::HandleMouseMove(int x, int y, WXUINT flags)
             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 )
+            {
+                // see comment in wxApp::GetComCtl32Version() explaining the
+                // use of wxLoadedDLL
+                wxLoadedDLL dllComCtl32(wxT("comctl32.dll"));
+                if ( dllComCtl32.IsLoaded() )
+                {
+                    s_pfn_TrackMouseEvent = (_TrackMouseEvent_t)
+                        dllComCtl32.RawGetSymbol(wxT("_TrackMouseEvent"));
+                }
+
+                s_initDone = true;
+            }
+
+            if ( s_pfn_TrackMouseEvent )
+#endif // __WXWINCE__/!__WXWINCE__
+            {
+                WinStruct<TRACKMOUSEEVENT> trackinfo;
 
-            trackinfo.dwFlags = TME_LEAVE;
-            trackinfo.hwndTrack = GetHwnd();
+                trackinfo.dwFlags = TME_LEAVE;
+                trackinfo.hwndTrack = GetHwnd();
 
-            // Use the commctrl.h _TrackMouseEvent(), which will call the real
-            // TrackMouseEvent() if available or emulate it
-            _TrackMouseEvent(&trackinfo);
+                (*s_pfn_TrackMouseEvent)(&trackinfo);
+            }
 #endif // HAVE_TRACKMOUSEEVENT
 
             wxMouseEvent event(wxEVT_ENTER_WINDOW);
             InitMouseEvent(event, x, y, flags);
 
-            (void)GetEventHandler()->ProcessEvent(event);
+            (void)HandleWindowEvent(event);
         }
     }
 #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
@@ -4889,7 +5591,7 @@ bool wxWindowMSW::HandleMouseWheel(WXWPARAM wParam, WXLPARAM lParam)
                                      &s_linesPerRotation, 0))
         {
             // this is not supposed to happen
-            wxLogLastError(_T("SystemParametersInfo(GETWHEELSCROLLLINES)"));
+            wxLogLastError(wxT("SystemParametersInfo(GETWHEELSCROLLLINES)"));
 
             // the default is 3, so use it if SystemParametersInfo() failed
             s_linesPerRotation = 3;
@@ -4897,7 +5599,7 @@ bool wxWindowMSW::HandleMouseWheel(WXWPARAM wParam, WXLPARAM lParam)
     }
 
     event.m_linesPerAction = s_linesPerRotation;
-    return GetEventHandler()->ProcessEvent(event);
+    return HandleWindowEvent(event);
 
 #else // !wxUSE_MOUSEWHEEL
     wxUnusedVar(wParam);
@@ -4932,7 +5634,7 @@ void wxWindowMSW::GenerateMouseLeave()
     if ( !::GetCursorPos(&pt) )
 #endif
     {
-        wxLogLastError(_T("GetCursorPos"));
+        wxLogLastError(wxT("GetCursorPos"));
     }
 
     // we need to have client coordinates here for symmetry with
@@ -4944,80 +5646,135 @@ void wxWindowMSW::GenerateMouseLeave()
     wxMouseEvent event(wxEVT_LEAVE_WINDOW);
     InitMouseEvent(event, pt.x, pt.y, state);
 
-    (void)GetEventHandler()->ProcessEvent(event);
+    (void)HandleWindowEvent(event);
 }
 
 // ---------------------------------------------------------------------------
 // keyboard handling
 // ---------------------------------------------------------------------------
 
-// create the key event of the given type for the given key - used by
-// HandleChar and HandleKeyDown/Up
-wxKeyEvent wxWindowMSW::CreateKeyEvent(wxEventType evType,
-                                       int id,
-                                       WXLPARAM lParam,
-                                       WXWPARAM wParam) const
+namespace
 {
-    wxKeyEvent event(evType);
-    event.SetId(GetId());
+
+// Implementation of InitAnyKeyEvent() which can also be used when there is no
+// associated window: this can happen for the wxEVT_CHAR_HOOK events created by
+// the global keyboard hook (e.g. the event might have happened in a non-wx
+// window).
+void
+MSWInitAnyKeyEvent(wxKeyEvent& event,
+                   WXWPARAM wParam,
+                   WXLPARAM lParam,
+                   const wxWindowBase *win /* may be NULL */)
+{
+    if ( win )
+    {
+        event.SetId(win->GetId());
+        event.SetEventObject(const_cast<wxWindowBase *>(win));
+    }
+    else // No associated window.
+    {
+        // Use wxID_ANY for compatibility with the old code even if wxID_NONE
+        // would arguably make more sense.
+        event.SetId(wxID_ANY);
+    }
+
     event.m_shiftDown = wxIsShiftDown();
     event.m_controlDown = wxIsCtrlDown();
     event.m_altDown = (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN;
 
-    event.SetEventObject((wxWindow *)this); // const_cast
-    event.m_keyCode = id;
-#if wxUSE_UNICODE
-    event.m_uniChar = (wxChar) wParam;
-#endif
     event.m_rawCode = (wxUint32) wParam;
     event.m_rawFlags = (wxUint32) lParam;
 #ifndef __WXWINCE__
     event.SetTimestamp(::GetMessageTime());
 #endif
 
-    // translate the position to client coords
-    POINT pt;
-#ifdef __WXWINCE__
-    GetCursorPosWinCE(&pt);
-#else
-    GetCursorPos(&pt);
-#endif
-    RECT rect;
-    GetWindowRect(GetHwnd(),&rect);
-    pt.x -= rect.left;
-    pt.y -= rect.top;
+    // Event coordinates must be in window client coordinates system which
+    // doesn't make sense if there is no window.
+    //
+    // We could use screen coordinates for such events but this would make the
+    // logic of the event handlers more complicated: you'd need to test for the
+    // event object and interpret the coordinates differently according to
+    // whether it's NULL or not so unless somebody really asks for this let's
+    // just avoid the issue.
+    if ( win )
+    {
+        const wxPoint mousePos = win->ScreenToClient(wxGetMousePosition());
+        event.m_x = mousePos.x;
+        event.m_y = mousePos.y;
+    }
+}
+
+} // anonymous namespace
+
+void
+wxWindowMSW::InitAnyKeyEvent(wxKeyEvent& event,
+                             WXWPARAM wParam,
+                             WXLPARAM lParam) const
+{
+    MSWInitAnyKeyEvent(event, wParam, lParam, this);
+}
+
+wxKeyEvent
+wxWindowMSW::CreateKeyEvent(wxEventType evType,
+                            WXWPARAM wParam,
+                            WXLPARAM lParam) const
+{
+    // Catch any attempts to use this with WM_CHAR, it wouldn't work because
+    // wParam is supposed to be a virtual key and not a character here.
+    wxASSERT_MSG( evType != wxEVT_CHAR && evType != wxEVT_CHAR_HOOK,
+                    "CreateKeyEvent() can't be used for char events" );
+
+    wxKeyEvent event(evType);
+    InitAnyKeyEvent(event, wParam, lParam);
 
-    event.m_x = pt.x;
-    event.m_y = pt.y;
+    event.m_keyCode = wxMSWKeyboard::VKToWX
+                                     (
+                                        wParam,
+                                        lParam
+#if wxUSE_UNICODE
+                                        , &event.m_uniChar
+#endif // wxUSE_UNICODE
+                                     );
 
     return event;
 }
 
-// isASCII is true only when we're called from WM_CHAR handler and not from
-// WM_KEYDOWN one
-bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam, bool isASCII)
+wxKeyEvent
+wxWindowMSW::CreateCharEvent(wxEventType evType,
+                             WXWPARAM wParam,
+                             WXLPARAM lParam) const
 {
-    int id;
-    if ( isASCII )
+    wxKeyEvent event(evType);
+    InitAnyKeyEvent(event, wParam, lParam);
+
+#if wxUSE_UNICODE
+    // TODO: wParam uses UTF-16 so this is incorrect for characters outside of
+    //       the BMP, we should use WM_UNICHAR to handle them.
+    event.m_uniChar = wParam;
+#endif // wxUSE_UNICODE
+
+    // Set non-Unicode key code too for compatibility if possible.
+    if ( wParam < 0x80 )
     {
-        id = wParam;
+        // It's an ASCII character, no need to translate it.
+        event.m_keyCode = wParam;
     }
-    else // we're called from WM_KEYDOWN
+    else
     {
-        // don't pass lParam to wxCharCodeMSWToWX() here because we don't want
-        // to get numpad key codes: CHAR events should use the logical keys
-        // such as WXK_HOME instead of WXK_NUMPAD_HOME which is for KEY events
-        id = wxCharCodeMSWToWX(wParam);
-        if ( id == 0 )
+        // Check if this key can be represented (as a single character) in the
+        // current locale.
+        const wchar_t wc = wParam;
+        char ch;
+        if ( wxConvLibc.FromWChar(&ch, 1, &wc, 1) != wxCONV_FAILED )
         {
-            // it's ASCII and will be processed here only when called from
-            // WM_CHAR (i.e. when isASCII = true), don't process it now
-            return false;
+            // For compatibility continue to provide the key code in this field
+            // even though using GetUnicodeKey() is recommended now.
+            event.m_keyCode = static_cast<unsigned char>(ch);
         }
+        //else: Key can't be represented in the current locale, leave m_keyCode
+        //      as WXK_NONE and use GetUnicodeKey() to access the character.
     }
 
-    wxKeyEvent event(CreateKeyEvent(wxEVT_CHAR, id, lParam, wParam));
-
     // the alphanumeric keys produced by pressing AltGr+something on European
     // keyboards have both Ctrl and Alt modifiers which may confuse the user
     // code as, normally, keys with Ctrl and/or Alt don't result in anything
@@ -5025,43 +5782,36 @@ bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam, bool isASCII)
     // KEY_DOWN event would still have the correct modifiers if they're really
     // needed)
     if ( event.m_controlDown && event.m_altDown &&
-            (id >= 32 && id < 256) )
+            (event.m_keyCode >= 32 && event.m_keyCode < 256) )
     {
         event.m_controlDown =
         event.m_altDown = false;
     }
 
-    return GetEventHandler()->ProcessEvent(event);
+    return event;
 }
 
-bool wxWindowMSW::HandleKeyDown(WXWPARAM wParam, WXLPARAM lParam)
+// isASCII is true only when we're called from WM_CHAR handler and not from
+// WM_KEYDOWN one
+bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam)
 {
-    int id = wxCharCodeMSWToWX(wParam, lParam);
-
-    if ( !id )
-    {
-        // normal ASCII char
-        id = wParam;
-    }
+    wxKeyEvent event(CreateCharEvent(wxEVT_CHAR, wParam, lParam));
+    return HandleWindowEvent(event);
+}
 
-    wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_DOWN, id, lParam, wParam));
-    return GetEventHandler()->ProcessEvent(event);
+bool wxWindowMSW::HandleKeyDown(WXWPARAM wParam, WXLPARAM lParam)
+{
+    wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_DOWN, wParam, lParam));
+    return HandleWindowEvent(event);
 }
 
 bool wxWindowMSW::HandleKeyUp(WXWPARAM wParam, WXLPARAM lParam)
 {
-    int id = wxCharCodeMSWToWX(wParam, lParam);
-
-    if ( !id )
-    {
-        // normal ASCII char
-        id = wParam;
-    }
-
-    wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_UP, id, lParam, wParam));
-    return GetEventHandler()->ProcessEvent(event);
+    wxKeyEvent event(CreateKeyEvent(wxEVT_KEY_UP, wParam, lParam));
+    return HandleWindowEvent(event);
 }
 
+#if wxUSE_MENUS
 int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel),
                                 WXLPARAM WXUNUSED_IN_WINCE(lParam))
 {
@@ -5096,13 +5846,14 @@ int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel),
                 //  menu creation code
                 wxMenuItem *item = (wxMenuItem*)mii.dwItemData;
 
-                const wxChar *p = wxStrchr(item->GetText(), _T('&'));
+                const wxString label(item->GetItemLabel());
+                const wxChar *p = wxStrchr(label.wx_str(), wxT('&'));
                 while ( p++ )
                 {
-                    if ( *p == _T('&') )
+                    if ( *p == wxT('&') )
                     {
                         // this is not the accel char, find the real one
-                        p = wxStrchr(p + 1, _T('&'));
+                        p = wxStrchr(p + 1, wxT('&'));
                     }
                     else // got the accel char
                     {
@@ -5125,23 +5876,25 @@ int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel),
         else // failed to get the menu text?
         {
             // it's not fatal, so don't show error, but still log it
-            wxLogLastError(_T("GetMenuItemInfo"));
+            wxLogLastError(wxT("GetMenuItemInfo"));
         }
     }
 #endif
     return wxNOT_FOUND;
 }
 
-bool wxWindowMSW::HandleClipboardEvent( WXUINT nMsg )
+#endif // wxUSE_MENUS
+
+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;
+    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);
+    return HandleWindowEvent(evt);
 }
 
 // ---------------------------------------------------------------------------
@@ -5226,7 +5979,7 @@ bool wxWindowMSW::HandleJoystickEvent(WXUINT msg, int x, int y, WXUINT flags)
     event.SetPosition(wxPoint(x, y));
     event.SetEventObject(this);
 
-    return GetEventHandler()->ProcessEvent(event);
+    return HandleWindowEvent(event);
 #else
     wxUnusedVar(msg);
     wxUnusedVar(x);
@@ -5293,12 +6046,11 @@ bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam,
             scrollInfo.fMask = SIF_TRACKPOS;
 
             if ( !::GetScrollInfo(GetHwnd(),
-                                  orientation == wxHORIZONTAL ? SB_HORZ
-                                                              : SB_VERT,
+                                  WXOrientToSB(orientation),
                                   &scrollInfo) )
             {
                 // Not necessarily an error, if there are no scrollbars yet.
-                // wxLogLastError(_T("GetScrollInfo"));
+                // wxLogLastError(wxT("GetScrollInfo"));
             }
 
             event.SetPosition(scrollInfo.nTrackPos);
@@ -5313,7 +6065,31 @@ bool wxWindowMSW::MSWOnScroll(int orientation, WXWORD wParam,
         return false;
     }
 
-    return GetEventHandler()->ProcessEvent(event);
+    return HandleWindowEvent(event);
+}
+
+// ----------------------------------------------------------------------------
+// custom message handlers
+// ----------------------------------------------------------------------------
+
+/* static */ bool
+wxWindowMSW::MSWRegisterMessageHandler(int msg, MSWMessageHandler handler)
+{
+    wxCHECK_MSG( gs_messageHandlers.find(msg) == gs_messageHandlers.end(),
+                 false, wxT("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,
+                 wxT("unregistering non-registered handler?") );
+
+    gs_messageHandlers.erase(i);
 }
 
 // ===========================================================================
@@ -5347,256 +6123,397 @@ void wxGetCharSize(WXHWND wnd, int *x, int *y, const wxFont& the_font)
     //   the_font.ReleaseResource();
 }
 
-// use the "extended" bit (24) of lParam to distinguish extended keys
-// from normal keys as the same key is sent
-static inline
+// ----------------------------------------------------------------------------
+// keyboard codes
+// ----------------------------------------------------------------------------
+
+namespace wxMSWKeyboard
+{
+
+namespace
+{
+
+// use the "extended" bit of lParam to distinguish extended keys from normal
+// keys as the same virtual key code is sent for both by Windows
+inline
 int ChooseNormalOrExtended(int lParam, int keyNormal, int keyExtended)
 {
     // except that if lParam is 0, it means we don't have real lParam from
     // WM_KEYDOWN but are just translating just a VK constant (e.g. done from
     // msw/treectrl.cpp when processing TVN_KEYDOWN) -- then assume this is a
     // non-numpad (hence extended) key as this is a more common case
-    return !lParam || (lParam & (1 << 24)) ? keyExtended : keyNormal;
-}
-
-// 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 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;
-
-        // 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;
+    return !lParam || (HIWORD(lParam) & KF_EXTENDED) ? keyExtended : keyNormal;
+}
+
+// this array contains the Windows virtual key codes which map one to one to
+// WXK_xxx constants and is used in wxMSWKeyboard::VKToWX/WXToVK() 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
+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
-        case VK_LWIN:       id = WXK_WINDOWS_LEFT; break;
-        case VK_RWIN:       id = WXK_WINDOWS_RIGHT; break;
-        case VK_APPS:       id = WXK_WINDOWS_MENU; break;
+    { VK_LWIN,          WXK_WINDOWS_LEFT },
+    { VK_RWIN,          WXK_WINDOWS_RIGHT },
+    { VK_APPS,          WXK_WINDOWS_MENU },
 #endif // VK_APPS defined
+};
+
+} // anonymous namespace
+
+int VKToWX(WXWORD vk, WXLPARAM lParam, wchar_t *uc)
+{
+    int wxk;
+
+    // check the table first
+    for ( size_t n = 0; n < WXSIZEOF(gs_specialKeys); n++ )
+    {
+        if ( gs_specialKeys[n].vk == vk )
+        {
+            wxk = gs_specialKeys[n].wxk;
+            if ( wxk < WXK_START )
+            {
+                // Unicode code for this key is the same as its ASCII code.
+                if ( uc )
+                    *uc = wxk;
+            }
+
+            return wxk;
+        }
+    }
+
+    // keys requiring special handling
+    switch ( vk )
+    {
+        case VK_OEM_1:
+        case VK_OEM_PLUS:
+        case VK_OEM_COMMA:
+        case VK_OEM_MINUS:
+        case VK_OEM_PERIOD:
+        case VK_OEM_2:
+        case VK_OEM_3:
+        case VK_OEM_4:
+        case VK_OEM_5:
+        case VK_OEM_6:
+        case VK_OEM_7:
+            // MapVirtualKey() returns 0 if it fails to convert the virtual
+            // key which nicely corresponds to our WXK_NONE.
+            wxk = ::MapVirtualKey(vk, MAPVK_VK_TO_CHAR);
+
+            if ( HIWORD(wxk) & 0x8000 )
+            {
+                // It's a dead key and we don't return anything at all for them
+                // as we simply don't have any way to indicate the difference
+                // between e.g. a normal "'" and "'" as a dead key -- and
+                // generating the same events for them just doesn't seem like a
+                // good idea.
+                wxk = WXK_NONE;
+            }
+
+            // In any case return this as a Unicode character value.
+            if ( uc )
+                *uc = wxk;
+
+            // For compatibility with the old non-Unicode code we continue
+            // returning key codes for Latin-1 characters directly
+            // (normally it would really only make sense to do it for the
+            // ASCII characters, not Latin-1 ones).
+            if ( wxk > 255 )
+            {
+                // But for anything beyond this we can only return the key
+                // value as a real Unicode character, not a wxKeyCode
+                // because this enum values clash with Unicode characters
+                // (e.g. WXK_LBUTTON also happens to be U+012C a.k.a.
+                // "LATIN CAPITAL LETTER I WITH BREVE").
+                wxk = WXK_NONE;
+            }
+            break;
 
         // handle extended keys
         case VK_PRIOR:
-            id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_PAGEUP, WXK_PAGEUP);
+            wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_PAGEUP, WXK_PAGEUP);
             break;
+
         case VK_NEXT:
-            id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_PAGEDOWN, WXK_PAGEDOWN);
+            wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_PAGEDOWN, WXK_PAGEDOWN);
             break;
+
         case VK_END:
-            id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_END, WXK_END);
+            wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_END, WXK_END);
             break;
+
         case VK_HOME:
-            id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_HOME, WXK_HOME);
+            wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_HOME, WXK_HOME);
             break;
+
         case VK_LEFT:
-            id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_LEFT, WXK_LEFT);
+            wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_LEFT, WXK_LEFT);
             break;
+
         case VK_UP:
-            id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_UP, WXK_UP);
+            wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_UP, WXK_UP);
             break;
+
         case VK_RIGHT:
-            id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_RIGHT, WXK_RIGHT);
+            wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_RIGHT, WXK_RIGHT);
             break;
+
         case VK_DOWN:
-            id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DOWN, WXK_DOWN);
+            wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DOWN, WXK_DOWN);
             break;
+
         case VK_INSERT:
-            id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_INSERT, WXK_INSERT);
+            wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_INSERT, WXK_INSERT);
             break;
+
         case VK_DELETE:
-            id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DELETE, WXK_DELETE);
+            wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DELETE, WXK_DELETE);
             break;
+
         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 = HIWORD(lParam) & KF_EXTENDED ? WXK_NUMPAD_ENTER : WXK_RETURN;
             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:
+            if ( (vk >= '0' && vk <= '9') || (vk >= 'A' && vk <= 'Z') )
+            {
+                // A simple alphanumeric key and the values of them coincide in
+                // Windows and wx for both ASCII and Unicode codes.
+                wxk = vk;
+            }
+            else // Something we simply don't know about at all.
+            {
+                wxk = WXK_NONE;
+            }
+
+            if ( uc )
+                *uc = vk;
+    }
+
+    return wxk;
+}
+
+WXWORD WXToVK(int wxk, bool *isExtended)
+{
+    // check the table first
+    for ( size_t n = 0; n < WXSIZEOF(gs_specialKeys); n++ )
+    {
+        if ( gs_specialKeys[n].wxk == wxk )
         {
-            *isVirtual = false;
-            keySym = (WORD)id;
+            // All extended keys (i.e. non-numpad versions of the keys that
+            // exist both in the numpad and outside of it) are dealt with
+            // below.
+            if ( isExtended )
+                *isExtended = false;
+
+            return gs_specialKeys[n].vk;
+        }
+    }
+
+    // and then check for special keys not included in the table
+    bool extended = false;
+    WXWORD vk;
+    switch ( wxk )
+    {
+        case WXK_PAGEUP:
+            extended = true;
+        case WXK_NUMPAD_PAGEUP:
+            vk = VK_PRIOR;
+            break;
+
+        case WXK_PAGEDOWN:
+            extended = true;
+        case WXK_NUMPAD_PAGEDOWN:
+            vk = VK_NEXT;
             break;
+
+        case WXK_END:
+            extended = true;
+        case WXK_NUMPAD_END:
+            vk = VK_END;
+            break;
+
+        case WXK_HOME:
+            extended = true;
+        case WXK_NUMPAD_HOME:
+            vk = VK_HOME;
+            break;
+
+        case WXK_LEFT:
+            extended = true;
+        case WXK_NUMPAD_LEFT:
+            vk = VK_LEFT;
+            break;
+
+        case WXK_UP:
+            extended = true;
+        case WXK_NUMPAD_UP:
+            vk = VK_UP;
+            break;
+
+        case WXK_RIGHT:
+            extended = true;
+        case WXK_NUMPAD_RIGHT:
+            vk = VK_RIGHT;
+            break;
+
+        case WXK_DOWN:
+            extended = true;
+        case WXK_NUMPAD_DOWN:
+            vk = VK_DOWN;
+            break;
+
+        case WXK_INSERT:
+            extended = true;
+        case WXK_NUMPAD_INSERT:
+            vk = VK_INSERT;
+            break;
+
+        case WXK_DELETE:
+            extended = true;
+        case WXK_NUMPAD_DELETE:
+            vk = VK_DELETE;
+            break;
+
+        default:
+            // no VkKeyScan() under CE unfortunately, we need to test how does
+            // it handle OEM keys
+#ifndef __WXWINCE__
+            // check to see if its one of the OEM key codes.
+            BYTE vks = LOBYTE(VkKeyScan(wxk));
+            if ( vks != 0xff )
+            {
+                vk = vks;
+            }
+            else
+#endif // !__WXWINCE__
+            {
+                vk = (WXWORD)wxk;
+            }
+    }
+
+    if ( isExtended )
+        *isExtended = extended;
+
+    return vk;
+}
+
+} // namespace wxMSWKeyboard
+
+// small helper for wxGetKeyState() and wxGetMouseState()
+static inline bool wxIsKeyDown(WXWORD vk)
+{
+    // SM_SWAPBUTTON is not available under CE, so don't swap buttons there
+#ifdef SM_SWAPBUTTON
+    if ( vk == VK_LBUTTON || vk == VK_RBUTTON )
+    {
+        if ( ::GetSystemMetrics(SM_SWAPBUTTON) )
+        {
+            if ( vk == VK_LBUTTON )
+                vk = VK_RBUTTON;
+            else // vk == VK_RBUTTON
+                vk = VK_LBUTTON;
         }
     }
-    return keySym;
+#endif // SM_SWAPBUTTON
+
+    // 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 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 = wxMSWKeyboard::WXToVK(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
 }
 
 
@@ -5608,13 +6525,17 @@ wxMouseState wxGetMouseState()
 
     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;
@@ -5626,7 +6547,7 @@ wxWindow *wxGetActiveWindow()
     HWND hWnd = GetActiveWindow();
     if ( hWnd != 0 )
     {
-        return wxFindWinFromHandle((WXHWND) hWnd);
+        return wxFindWinFromHandle(hWnd);
     }
     return NULL;
 }
@@ -5638,19 +6559,19 @@ extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd)
     // For a radiobutton, we get the radiobox from GWL_USERDATA (which is set
     // by code in msw/radiobox.cpp), for all the others we just search up the
     // window hierarchy
-    wxWindow *win = (wxWindow *)NULL;
+    wxWindow *win = NULL;
     if ( hwnd )
     {
-        win = wxFindWinFromHandle((WXHWND)hwnd);
+        win = wxFindWinFromHandle(hwnd);
         if ( !win )
         {
-#if wxUSE_RADIOBOX
+#if wxUSE_RADIOBOX && !defined(__WXUNIVERSAL__)
             // native radiobuttons return DLGC_RADIOBUTTON here and for any
             // wxWindow class which overrides WM_GETDLGCODE processing to
             // do it as well, win would be already non NULL
             if ( ::SendMessage(hwnd, WM_GETDLGCODE, 0, 0) & DLGC_RADIOBUTTON )
             {
-                win = (wxWindow *)wxGetWindowUserData(hwnd);
+                win = wxRadioBox::GetFromRadioButtonHWND(hwnd);
             }
             //else: it's a wxRadioButton, not a radiobutton from wxRadioBox
 #endif // wxUSE_RADIOBOX
@@ -5685,7 +6606,7 @@ extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd)
 #endif
 
         hwnd = ::GetParent(hwnd);
-        win = wxFindWinFromHandle((WXHWND)hwnd);
+        win = wxFindWinFromHandle(hwnd);
     }
 
     return win;
@@ -5696,64 +6617,51 @@ extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd)
 // Windows keyboard hook. Allows interception of e.g. F1, ESCAPE
 // in active frames and dialogs, regardless of where the focus is.
 static HHOOK wxTheKeyboardHook = 0;
-static FARPROC wxTheKeyboardHookProc = 0;
-int APIENTRY _EXPORT
-wxKeyboardHook(int nCode, WORD wParam, DWORD lParam);
-
-void wxSetKeyboardHook(bool doIt)
-{
-    if ( doIt )
-    {
-        wxTheKeyboardHookProc = MakeProcInstance((FARPROC) wxKeyboardHook, wxGetInstance());
-        wxTheKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC) wxTheKeyboardHookProc, wxGetInstance(),
 
-            GetCurrentThreadId()
-        //      (DWORD)GetCurrentProcess()); // This is another possibility. Which is right?
-            );
-    }
-    else
-    {
-        UnhookWindowsHookEx(wxTheKeyboardHook);
-    }
-}
-
-int APIENTRY _EXPORT
+int APIENTRY
 wxKeyboardHook(int nCode, WORD wParam, DWORD lParam)
 {
     DWORD hiWord = HIWORD(lParam);
     if ( nCode != HC_NOREMOVE && ((hiWord & KF_UP) == 0) )
     {
-        int id = wxCharCodeMSWToWX(wParam, lParam);
-        if ( id != 0 )
+        wchar_t uc;
+        int id = wxMSWKeyboard::VKToWX(wParam, lParam, &uc);
+
+        // Don't intercept keyboard entry (notably Escape) if a modal window
+        // (not managed by wx, e.g. IME one) is currently opened as more often
+        // than not it needs all the keys for itself.
+        //
+        // Also don't catch it if a window currently captures the mouse as
+        // Escape is normally used to release the mouse capture and if you
+        // really need to catch all the keys in the window that has mouse
+        // capture it can be easily done in its own EVT_CHAR handler as it is
+        // certain to have focus while it has the capture.
+        if ( !gs_modalEntryWindowCount && !::GetCapture() )
         {
-            wxKeyEvent event(wxEVT_CHAR_HOOK);
-            if ( (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN )
-                event.m_altDown = true;
-
-            event.SetEventObject(NULL);
-            event.m_keyCode = id;
-            event.m_shiftDown = wxIsShiftDown();
-            event.m_controlDown = wxIsCtrlDown();
-#ifndef __WXWINCE__
-            event.SetTimestamp(::GetMessageTime());
-#endif
-            wxWindow *win = wxGetActiveWindow();
-            wxEvtHandler *handler;
-            if ( win )
-            {
-                handler = win->GetEventHandler();
-                event.SetId(win->GetId());
-            }
-            else
+            if ( id != WXK_NONE
+#if wxUSE_UNICODE
+                    || static_cast<int>(uc) != WXK_NONE
+#endif // wxUSE_UNICODE
+                    )
             {
-                handler = wxTheApp;
-                event.SetId(wxID_ANY);
-            }
+                const wxWindow * const win = wxGetActiveWindow();
 
-            if ( handler && handler->ProcessEvent(event) )
-            {
-                // processed
-                return 1;
+                wxKeyEvent event(wxEVT_CHAR_HOOK);
+                MSWInitAnyKeyEvent(event, wParam, lParam, win);
+
+                event.m_keyCode = id;
+#if wxUSE_UNICODE
+                event.m_uniChar = uc;
+#endif // wxUSE_UNICODE
+
+                wxEvtHandler * const handler = win ? win->GetEventHandler()
+                                                   : wxTheApp;
+
+                if ( handler && handler->ProcessEvent(event) )
+                {
+                    // processed
+                    return 1;
+                }
             }
         }
     }
@@ -5761,9 +6669,32 @@ wxKeyboardHook(int nCode, WORD wParam, DWORD lParam)
     return (int)CallNextHookEx(wxTheKeyboardHook, nCode, wParam, lParam);
 }
 
+void wxSetKeyboardHook(bool doIt)
+{
+    if ( doIt )
+    {
+        wxTheKeyboardHook = ::SetWindowsHookEx
+                              (
+                                WH_KEYBOARD,
+                                (HOOKPROC)wxKeyboardHook,
+                                NULL,   // must be NULL for process hook
+                                ::GetCurrentThreadId()
+                              );
+        if ( !wxTheKeyboardHook )
+        {
+            wxLogLastError(wxT("SetWindowsHookEx(wxKeyboardHook)"));
+        }
+    }
+    else // uninstall
+    {
+        if ( wxTheKeyboardHook )
+            ::UnhookWindowsHookEx(wxTheKeyboardHook);
+    }
+}
+
 #endif // !__WXMICROWIN__
 
-#ifdef __WXDEBUG__
+#if wxDEBUG_LEVEL >= 2
 const wxChar *wxGetMessageName(int message)
 {
     switch ( message )
@@ -5855,6 +6786,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 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");
@@ -5880,6 +6851,20 @@ const wxChar *wxGetMessageName(int message)
         case 0x011F: return wxT("WM_MENUSELECT");
         case 0x0120: return wxT("WM_MENUCHAR");
         case 0x0121: return wxT("WM_ENTERIDLE");
+
+        case 0x0127: return wxT("WM_CHANGEUISTATE");
+        case 0x0128: return wxT("WM_UPDATEUISTATE");
+        case 0x0129: return wxT("WM_QUERYUISTATE");
+
+        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");
@@ -5891,6 +6876,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 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");
@@ -5924,6 +6912,11 @@ const wxChar *wxGetMessageName(int message)
         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");
@@ -5942,9 +6935,10 @@ const wxChar *wxGetMessageName(int message)
         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");
-#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
@@ -6173,7 +7167,7 @@ const wxChar *wxGetMessageName(int message)
             return s_szBuf.c_str();
     }
 }
-#endif //__WXDEBUG__
+#endif // wxDEBUG_LEVEL >= 2
 
 static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win)
 {
@@ -6220,18 +7214,10 @@ wxWindow* wxFindWindowAtPoint(const wxPoint& pt)
     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.
@@ -6257,10 +7243,10 @@ static void WinCEUnregisterHotKey(int modifiers, int id)
     typedef BOOL (WINAPI *UnregisterFunc1Proc)(UINT, UINT);
 
     UnregisterFunc1Proc procUnregisterFunc;
-    hCoreDll = LoadLibrary(_T("coredll.dll"));
+    hCoreDll = LoadLibrary(wxT("coredll.dll"));
     if (hCoreDll)
     {
-        procUnregisterFunc = (UnregisterFunc1Proc)GetProcAddress(hCoreDll, _T("UnregisterFunc1"));
+        procUnregisterFunc = (UnregisterFunc1Proc)GetProcAddress(hCoreDll, wxT("UnregisterFunc1"));
         if (procUnregisterFunc)
             procUnregisterFunc(modifiers, id);
         FreeLibrary(hCoreDll);
@@ -6288,7 +7274,7 @@ bool wxWindowMSW::RegisterHotKey(int hotkeyId, int modifiers, int keycode)
 
     if ( !::RegisterHotKey(GetHwnd(), hotkeyId, win_modifiers, keycode) )
     {
-        wxLogLastError(_T("RegisterHotKey"));
+        wxLogLastError(wxT("RegisterHotKey"));
 
         return false;
     }
@@ -6304,7 +7290,7 @@ bool wxWindowMSW::UnregisterHotKey(int hotkeyId)
 
     if ( !::UnregisterHotKey(GetHwnd(), hotkeyId) )
     {
-        wxLogLastError(_T("UnregisterHotKey"));
+        wxLogLastError(wxT("UnregisterHotKey"));
 
         return false;
     }
@@ -6316,18 +7302,16 @@ bool wxWindowMSW::UnregisterHotKey(int hotkeyId)
 
 bool wxWindowMSW::HandleHotKey(WXWPARAM wParam, WXLPARAM lParam)
 {
-    int hotkeyId = wParam;
-    int virtualKey = HIWORD(lParam);
     int win_modifiers = LOWORD(lParam);
 
-    wxKeyEvent event(CreateKeyEvent(wxEVT_HOTKEY, virtualKey, wParam, lParam));
-    event.SetId(hotkeyId);
+    wxKeyEvent event(CreateKeyEvent(wxEVT_HOTKEY, HIWORD(lParam)));
+    event.SetId(wParam);
     event.m_shiftDown = (win_modifiers & MOD_SHIFT) != 0;
     event.m_controlDown = (win_modifiers & MOD_CONTROL) != 0;
     event.m_altDown = (win_modifiers & MOD_ALT) != 0;
     event.m_metaDown = (win_modifiers & MOD_WIN) != 0;
 
-    return GetEventHandler()->ProcessEvent(event);
+    return HandleWindowEvent(event);
 }
 
 #endif // wxUSE_ACCEL
@@ -6357,7 +7341,7 @@ public:
 
         if ( !ms_hMsgHookProc )
         {
-            wxLogLastError(_T("SetWindowsHookEx(WH_GETMESSAGE)"));
+            wxLogLastError(wxT("SetWindowsHookEx(WH_GETMESSAGE)"));
 
             return false;
         }
@@ -6383,7 +7367,7 @@ public:
         }
 
         return CallNextHookEx(ms_hMsgHookProc, nCode, wParam, lParam);
-    };
+    }
 
 private:
     static HHOOK ms_hMsgHookProc;