]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/window.cpp
Removing OS/2 specific positioning methods, no longer needed
[wxWidgets.git] / src / msw / window.cpp
index 3ada51d84709c3c69dd31fb0487b4adf9a3fef11..0613d376591f66c1a6f8d5299d906f8d361a095c 100644 (file)
@@ -37,6 +37,7 @@
     #include "wx/menu.h"
     #include "wx/dc.h"
     #include "wx/dcclient.h"
+    #include "wx/dcmemory.h"
     #include "wx/utils.h"
     #include "wx/app.h"
     #include "wx/layout.h"
     #endif
 #endif
 
-
 // ---------------------------------------------------------------------------
 // global variables
 // ---------------------------------------------------------------------------
 
-// the last Windows message we got (MT-UNSAFE)
+// the last Windows message we got (FIXME-MT)
 extern MSG s_currentMsg;
 
 #if wxUSE_MENUS_NATIVE
@@ -132,6 +132,10 @@ wxMenu *wxCurrentPopupMenu = NULL;
 
 extern const wxChar *wxCanvasClassName;
 
+// true if we had already created the std colour map, used by
+// wxGetStdColourMap() and wxWindow::OnSysColourChanged()           (FIXME-MT)
+static bool gs_hasStdCmap = FALSE;
+
 // ---------------------------------------------------------------------------
 // private functions
 // ---------------------------------------------------------------------------
@@ -299,9 +303,6 @@ void wxWindowMSW::Init()
 
     m_hWnd = 0;
 
-    // pass WM_GETDLGCODE to DefWindowProc()
-    m_lDlgCode = 0;
-
     m_xThumbSize = 0;
     m_yThumbSize = 0;
     m_backgroundTransparent = FALSE;
@@ -321,8 +322,6 @@ wxWindowMSW::~wxWindowMSW()
 {
     m_isBeingDeleted = TRUE;
 
-    MSWDetachWindowMenu();
-
 #ifndef __WXUNIVERSAL__
     // VS: make sure there's no wxFrame with last focus set to us:
     for ( wxWindow *win = GetParent(); win; win = win->GetParent() )
@@ -378,7 +377,7 @@ bool wxWindowMSW::Create(wxWindow *parent,
     //
     // the correct solution is to create the controls as siblings of the
     // static box
-    wxASSERT_MSG( !wxDynamicCastThis(wxStaticBox),
+    wxASSERT_MSG( !wxDynamicCast(parent, wxStaticBox),
                   _T("wxStaticBox can't be used as a window parent!") );
 #endif // wxUSE_STATBOX
 
@@ -413,14 +412,6 @@ bool wxWindowMSW::Create(wxWindow *parent,
     {
         msflags |= WS_BORDER;
     }
-
-    // calculate the value to return from WM_GETDLGCODE handler
-    if ( GetWindowStyleFlag() & wxWANTS_CHARS )
-    {
-        // want everything: i.e. all keys and WM_CHAR message
-        m_lDlgCode = DLGC_WANTARROWS | DLGC_WANTCHARS |
-                     DLGC_WANTTAB | DLGC_WANTMESSAGE;
-    }
 #endif // wxUniversal/!wxUniversal
 
     if ( style & wxPOPUP_WINDOW )
@@ -451,23 +442,18 @@ void wxWindowMSW::SetFocus()
 
     if ( !::SetFocus(hWnd) )
     {
+#if defined(__WXDEBUG__) && !defined(__WXMICROWIN__)
         // was there really an error?
-#ifndef __WXMICROWIN__
         DWORD dwRes = ::GetLastError();
-#else
-
-        DWORD dwRes = 0;
-#endif
         if ( dwRes )
         {
-            wxLogApiError(_T("SetFocus"), dwRes);
+            HWND hwndFocus = ::GetFocus();
+            if ( hwndFocus != hWnd )
+            {
+                wxLogApiError(_T("SetFocus"), dwRes);
+            }
         }
-
-        // VZ: just why does this happen sometimes?? any idea?
-#if 0
-        HWND hwndFocus = ::GetFocus();
-        wxASSERT_MSG( hwndFocus == hWnd, _T("SetFocus() didn't work?") );
-#endif // 0
+#endif // Debug
     }
 }
 
@@ -549,7 +535,7 @@ wxString wxWindowMSW::GetTitle() const
     return wxGetWindowText(GetHWND());
 }
 
-void wxWindowMSW::CaptureMouse()
+void wxWindowMSW::DoCaptureMouse()
 {
     HWND hWnd = GetHwnd();
     if ( hWnd )
@@ -558,7 +544,7 @@ void wxWindowMSW::CaptureMouse()
     }
 }
 
-void wxWindowMSW::ReleaseMouse()
+void wxWindowMSW::DoReleaseMouse()
 {
     if ( !::ReleaseCapture() )
     {
@@ -826,36 +812,23 @@ int wxWindowMSW::GetScrollThumb(int orient) const
 
 void wxWindowMSW::SetScrollPos(int orient, int pos, bool refresh)
 {
-#if defined(__WIN95__)
-    SCROLLINFO info;
-    int dir;
+    HWND hWnd = GetHwnd();
+    wxCHECK_RET( hWnd, _T("SetScrollPos: no HWND") );
 
-    if ( orient == wxHORIZONTAL ) {
-        dir = SB_HORZ;
-    } else {
-        dir = SB_VERT;
-    }
+    int dir = orient == wxHORIZONTAL ? SB_HORZ : SB_VERT;
 
+#if defined(__WIN95__)
+    SCROLLINFO info;
     info.cbSize = sizeof(SCROLLINFO);
     info.nPage = 0;
     info.nMin = 0;
     info.nPos = pos;
     info.fMask = SIF_POS;
 
-    HWND hWnd = GetHwnd();
-    if ( hWnd )
-        ::SetScrollInfo(hWnd, dir, &info, refresh);
-#else
-    int wOrient;
-    if ( orient == wxHORIZONTAL )
-        wOrient = SB_HORZ;
-    else
-        wOrient = SB_VERT;
-
-    HWND hWnd = GetHwnd();
-    if ( hWnd )
-        ::SetScrollPos(hWnd, wOrient, pos, refresh);
-#endif
+    ::SetScrollInfo(hWnd, dir, &info, refresh);
+#else // !__WIN95__
+    ::SetScrollPos(hWnd, dir, pos, refresh);
+#endif // __WIN95__/!__WIN95__
 }
 
 // New function that will replace some of the above.
@@ -918,15 +891,21 @@ void wxWindowMSW::SetScrollbar(int orient, int pos, int thumbVisible,
 void wxWindowMSW::ScrollWindow(int dx, int dy, const wxRect *prect)
 {
     RECT rect;
+    RECT *pr;
     if ( prect )
     {
         rect.left = prect->x;
         rect.top = prect->y;
         rect.right = prect->x + prect->width;
         rect.bottom = prect->y + prect->height;
+        pr = ▭
+    }
+    else
+    {
+        pr = NULL;
     }
 
-    ::ScrollWindow(GetHwnd(), dx, dy, prect ? &rect : NULL, NULL);
+    ::ScrollWindow(GetHwnd(), dx, dy, pr, pr);
 }
 
 static bool ScrollVertically(HWND hwnd, int kind, int count)
@@ -982,11 +961,11 @@ void wxWindowMSW::SubclassWin(WXHWND hWnd)
 
     wxAssociateWinWithHandle(hwnd, this);
 
-    m_oldWndProc = (WXFARPROC)::GetWindowLong(hwnd, GWL_WNDPROC);
-
+    m_oldWndProc = (WXFARPROC)::GetWindowLong((HWND)hWnd, GWL_WNDPROC);
+    
     // we don't need to subclass the window of our own class (in the Windows
     // sense of the word)
-    if ( (WXFARPROC) m_oldWndProc != (WXFARPROC) wxWndProc )
+    if ( !wxCheckWindowWndProc(hWnd, (WXFARPROC)wxWndProc) )
     {
         ::SetWindowLong(hwnd, GWL_WNDPROC, (LONG) wxWndProc);
     }
@@ -1011,8 +990,7 @@ void wxWindowMSW::UnsubclassWin()
 
         if ( m_oldWndProc )
         {
-            FARPROC wndProc = (FARPROC)::GetWindowLong(hwnd, GWL_WNDPROC);
-            if ( wndProc != (FARPROC) m_oldWndProc )
+            if ( !wxCheckWindowWndProc((WXHWND)hwnd, m_oldWndProc) )
             {
                 ::SetWindowLong(hwnd, GWL_WNDPROC, (LONG) m_oldWndProc);
             }
@@ -1022,6 +1000,35 @@ void wxWindowMSW::UnsubclassWin()
     }
 }
 
+bool wxCheckWindowWndProc(WXHWND hWnd, WXFARPROC wndProc)
+{
+#if wxUSE_UNICODE_MSLU
+    // VS: We can't use GetWindowLong(hwnd, GWL_WNDPROC) together with unicows.dll
+    //     because it doesn't return pointer to the real wnd proc but rather a handle
+    //     of a fake proc that does Unicode<->ANSI translation.
+    //
+    //     The hack bellow works, because WNDCLASS contains original window handler
+    //     rather that the unicows fake one. This may not be on purpose, though; if
+    //     it stops working with future versions of unicows.dll, we can override
+    //     unicows hooks by setting Unicows_{Set,Get}WindowLong and
+    //     Unicows_RegisterClass to our own versions that keep track of
+    //     fake<->real wnd proc mapping.
+    //
+    //     FIXME: Doesn't handle wnd procs set by SetWindowLong, only these set
+    //            with RegisterClass!!
+
+    static wxChar buffer[512];
+    WNDCLASS cls;
+
+    ::GetClassName((HWND)hWnd, buffer, 512);
+    ::GetClassInfo(wxGetInstance(), buffer, &cls);
+    return wndProc == (WXFARPROC)cls.lpfnWndProc;
+#else
+    return wndProc == (WXFARPROC)::GetWindowLong((HWND)hWnd, GWL_WNDPROC);
+#endif
+}
+
+
 // Make a Windows extended style from the given wxWindows window style
 WXDWORD wxWindowMSW::MakeExtendedStyle(long style, bool eliminateBorders)
 {
@@ -1168,7 +1175,7 @@ void wxWindowMSW::OnIdle(wxIdleEvent& WXUNUSED(event))
     // Check if we need to send a LEAVE event
     if ( m_mouseInWindow )
     {
-        if ( !IsMouseInWindow() )
+        if ( !IsMouseInWindow() && !HasCapture())
         {
             // Generate a LEAVE event
             m_mouseInWindow = FALSE;
@@ -1234,7 +1241,9 @@ void wxWindowMSW::Clear()
 
 static inline void SendSetRedraw(HWND hwnd, bool on)
 {
+#ifndef __WXMICROWIN__
     ::SendMessage(hwnd, WM_SETREDRAW, (WPARAM)on, 0);
+#endif
 }
 
 void wxWindowMSW::Freeze()
@@ -1430,6 +1439,12 @@ void wxWindowMSW::DoClientToScreen(int *x, int *y) const
 
 void wxWindowMSW::DoMoveWindow(int x, int y, int width, int height)
 {
+    // TODO: is this consistent with other platforms?
+    // Still, negative width or height shouldn't be allowed
+    if (width < 0)
+        width = 0;
+    if (height < 0)
+        height = 0;
     if ( !::MoveWindow(GetHwnd(), x, y, width, height, TRUE) )
     {
         wxLogLastError(wxT("MoveWindow"));
@@ -1505,40 +1520,68 @@ void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags)
 
 void wxWindowMSW::DoSetClientSize(int width, int height)
 {
-    wxWindow *parent = GetParent();
-    HWND hWnd = GetHwnd();
-    HWND hParentWnd = (HWND) 0;
-    if ( parent )
-        hParentWnd = (HWND) parent->GetHWND();
+    // setting the client size is less obvious than it it could have been
+    // because in the result of changing the total size the window scrollbar
+    // may [dis]appear and/or its menubar may [un]wrap and so the client size
+    // will not be correct as the difference between the total and client size
+    // changes - so we keep changing it until we get it right
+    //
+    // normally this loop shouldn't take more than 3 iterations (usually 1 but
+    // if scrollbars [dis]appear as the result of the first call, then 2 and it
+    // may become 3 if the window had 0 size originally and so we didn't
+    // calculate the scrollbar correction correctly during the first iteration)
+    // but just to be on the safe side we check for it instead of making it an
+    // "infinite" loop (i.e. leaving break inside as the only way to get out)
+    for ( int i = 0; i < 4; i++ )
+    {
+        RECT rectClient;
+        ::GetClientRect(GetHwnd(), &rectClient);
 
-    RECT rect;
-    ::GetClientRect(hWnd, &rect);
+        // if the size is already ok, stop here (rectClient.left = top = 0)
+        if ( (rectClient.right == width || width == -1) &&
+             (rectClient.bottom == height || height == -1) )
+        {
+            break;
+        }
 
-    RECT rect2;
-    GetWindowRect(hWnd, &rect2);
+        if ( i == 3 )
+        {
+            // how did it happen? maybe OnSize() handler does something really
+            // strange in this class?
+            wxFAIL_MSG( _T("logic error in DoSetClientSize") );
 
-    // Find the difference between the entire window (title bar and all)
-    // and the client area; add this to the new client size to move the
-    // window
-    int actual_width = rect2.right - rect2.left - rect.right + width;
-    int actual_height = rect2.bottom - rect2.top - rect.bottom + height;
+            break;
+        }
 
-    // If there's a parent, must subtract the parent's top left corner
-    // since MoveWindow moves relative to the parent
+        int widthClient = width,
+            heightClient = height;
 
-    POINT point;
-    point.x = rect2.left;
-    point.y = rect2.top;
-    if ( parent )
-    {
-        ::ScreenToClient(hParentWnd, &point);
-    }
+        // Find the difference between the entire window (title bar and all)
+        // and the client area; add this to the new client size to move the
+        // window
+        RECT rectWin;
+        ::GetWindowRect(GetHwnd(), &rectWin);
 
-    DoMoveWindow(point.x, point.y, actual_width, actual_height);
+        widthClient += rectWin.right - rectWin.left - rectClient.right;
+        heightClient += rectWin.bottom - rectWin.top - rectClient.bottom;
 
-    wxSizeEvent event(wxSize(width, height), m_windowId);
-    event.SetEventObject(this);
-    GetEventHandler()->ProcessEvent(event);
+        POINT point;
+        point.x = rectWin.left;
+        point.y = rectWin.top;
+
+        // MoveWindow positions the child windows relative to the parent, so
+        // adjust if necessary
+        if ( !IsTopLevel() )
+        {
+            wxWindow *parent = GetParent();
+            if ( parent )
+            {
+                ::ScreenToClient(GetHwndOf(parent), &point);
+            }
+        }
+
+        DoMoveWindow(point.x, point.y, widthClient, heightClient);
+    }
 }
 
 // For implementation purposes - sometimes decorations make the client area
@@ -1908,11 +1951,12 @@ bool wxWindowMSW::MSWTranslateMessage(WXMSG* pMsg)
 #if wxUSE_ACCEL && !defined(__WXUNIVERSAL__)
     return m_acceleratorTable.Translate(this, pMsg);
 #else
+    (void) pMsg;
     return FALSE;
 #endif // wxUSE_ACCEL
 }
 
-bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* pMsg)
+bool wxWindowMSW::MSWShouldPreProcessMessage(WXMSG* WXUNUSED(pMsg))
 {
     // preprocess all messages by default
     return TRUE;
@@ -2315,9 +2359,11 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam
 #endif // defined(WM_DRAWITEM)
 
         case WM_GETDLGCODE:
-            if ( m_lDlgCode )
+            if ( GetWindowStyleFlag() & wxWANTS_CHARS )
             {
-                rc.result = m_lDlgCode;
+                // want everything: i.e. all keys and WM_CHAR message
+                rc.result = DLGC_WANTARROWS | DLGC_WANTCHARS |
+                            DLGC_WANTTAB | DLGC_WANTMESSAGE;
                 processed = TRUE;
             }
             //else: get the dlg code from the DefWindowProc()
@@ -2451,11 +2497,15 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam
             break;
 #endif // !__WXMICROWIN__
 
-            // the return value for this message is ignored
         case WM_SYSCOLORCHANGE:
+            // the return value for this message is ignored
             processed = HandleSysColorChange();
             break;
 
+        case WM_DISPLAYCHANGE:
+            processed = HandleDisplayChange();
+            break;
+
         case WM_PALETTECHANGED:
             processed = HandlePaletteChanged((WXHWND) (HWND) wParam);
             break;
@@ -2562,7 +2612,10 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam
             break;
 #endif // __WIN32__
 
-#ifdef __WXUNIVERSAL__
+            // unfortunately this doesn't really work as then window which
+            // doesn't accept focus doesn't get any mouse events neither which
+            // means it can't get any input at all
+#if 0 //def __WXUNIVERSAL__
         case WM_NCHITTEST:
             // we shouldn't allow the windows which don't want to get focus to
             // get it
@@ -2591,14 +2644,11 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam
 // wxWindow <-> HWND map
 // ----------------------------------------------------------------------------
 
-wxList *wxWinHandleList = NULL;
+wxWinHashTable *wxWinHandleHash = NULL;
 
 wxWindow *wxFindWinFromHandle(WXHWND hWnd)
 {
-    wxNode *node = wxWinHandleList->Find((long)hWnd);
-    if ( !node )
-        return NULL;
-    return (wxWindow *)node->Data();
+    return wxWinHandleHash->Get((long)hWnd);
 }
 
 void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win)
@@ -2619,13 +2669,13 @@ void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win)
 #endif // __WXDEBUG__
     if (!oldWin)
     {
-        wxWinHandleList->Append((long)hWnd, win);
+        wxWinHandleHash->Put((long)hWnd, (wxWindow *)win);
     }
 }
 
 void wxRemoveHandleAssociation(wxWindowMSW *win)
 {
-    wxWinHandleList->DeleteObject(win);
+    wxWinHandleHash->Delete((long)win->GetHWND());
 }
 
 // ----------------------------------------------------------------------------
@@ -2638,38 +2688,6 @@ void wxWindowMSW::MSWDestroyWindow()
 {
 }
 
-void wxWindowMSW::MSWDetachWindowMenu()
-{
-#ifndef __WXUNIVERSAL__
-    if ( m_hMenu )
-    {
-        wxChar buf[1024];
-        HMENU hMenu = (HMENU)m_hMenu;
-
-        int N = ::GetMenuItemCount(hMenu);
-        for ( int i = 0; i < N; i++ )
-        {
-            if ( !::GetMenuString(hMenu, i, buf, WXSIZEOF(buf), MF_BYPOSITION) )
-            {
-                wxLogLastError(wxT("GetMenuString"));
-
-                continue;
-            }
-
-            if ( wxStrcmp(buf, _("&Window")) == 0 )
-            {
-                if ( !::RemoveMenu(hMenu, i, MF_BYPOSITION) )
-                {
-                    wxLogLastError(wxT("RemoveMenu"));
-                }
-
-                break;
-            }
-        }
-    }
-#endif // __WXUNIVERSAL__
-}
-
 bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
                                            const wxSize& size,
                                            int& x, int& y,
@@ -2692,29 +2710,32 @@ bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
         nonDefault = TRUE;
     }
 
-    if ( size.x == -1 || size.y == -1 )
+    /*
+      NB: there used to be some code here which set the initial size of the
+          window to the client size of the parent if no explicit size was
+          specified. This was wrong because wxWindows programs often assume
+          that they get a WM_SIZE (EVT_SIZE) upon creation, however this broke
+          it. To see why, you should understand that Windows sends WM_SIZE from
+          inside ::CreateWindow() anyhow. However, ::CreateWindow() is called
+          from some base class ctor and so this WM_SIZE is not processed in the
+          real class' OnSize() (because it's not fully constructed yet and the
+          event goes to some base class OnSize() instead). So the WM_SIZE we
+          rely on is the one sent when the parent frame resizes its children
+          but here is the problem: if the child already has just the right
+          size, nothing will happen as both wxWindows and Windows check for
+          this and ignore any attempts to change the window size to the size it
+          already has - so no WM_SIZE would be sent.
+     */
+    if ( size.x == -1 )
     {
-        // Find parent's size, if it exists, to set up a possible default panel
-        // size the size of the parent window
-        wxWindow *parent = GetParent();
-        if ( parent )
-        {
-            RECT rectParent;
-            ::GetClientRect(GetHwndOf(parent), &rectParent);
-
-            w = size.x == -1 ? rectParent.right - rectParent.left : size.x;
-            h = size.y == -1 ? rectParent.bottom - rectParent.top : size.y;
-        }
-        else
-        {
-            w =
-            h = CW_USEDEFAULT;
-        }
+        // as abobe, h is not used at all in this case anyhow
+        w =
+        h = CW_USEDEFAULT;
     }
     else
     {
         w = size.x;
-        h = size.y;
+        h = size.y == -1 ? CW_USEDEFAULT : size.y;
 
         nonDefault = TRUE;
     }
@@ -2815,7 +2836,7 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass,
 
     SubclassWin(m_hWnd);
 
-    SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT));
+    SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
 
     return TRUE;
 }
@@ -3061,11 +3082,9 @@ bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam)
 {
 #ifndef __WXMICROWIN__
     HDROP hFilesInfo = (HDROP) wParam;
-    POINT dropPoint;
-    DragQueryPoint(hFilesInfo, (LPPOINT) &dropPoint);
 
     // Get the total number of files dropped
-    WORD gwFilesDropped = (WORD)::DragQueryFile
+    UINT gwFilesDropped = ::DragQueryFile
                             (
                                 (HDROP)hFilesInfo,
                                 (UINT)-1,
@@ -3074,24 +3093,28 @@ bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam)
                             );
 
     wxString *files = new wxString[gwFilesDropped];
-    int wIndex;
-    for (wIndex=0; wIndex < (int)gwFilesDropped; wIndex++)
+    for ( UINT wIndex = 0; wIndex < gwFilesDropped; wIndex++ )
     {
-        DragQueryFile (hFilesInfo, wIndex, (LPTSTR) wxBuffer, 1000);
-        files[wIndex] = wxBuffer;
+        // first get the needed buffer length (+1 for terminating NUL)
+        size_t len = ::DragQueryFile(hFilesInfo, wIndex, NULL, 0) + 1;
+
+        // and now get the file name
+        ::DragQueryFile(hFilesInfo, wIndex,
+                        files[wIndex].GetWriteBuf(len), len);
+
+        files[wIndex].UngetWriteBuf();
     }
     DragFinish (hFilesInfo);
 
     wxDropFilesEvent event(wxEVT_DROP_FILES, gwFilesDropped, files);
     event.m_eventObject = this;
+
+    POINT dropPoint;
+    DragQueryPoint(hFilesInfo, (LPPOINT) &dropPoint);
     event.m_pos.x = dropPoint.x;
     event.m_pos.y = dropPoint.y;
 
-    bool rc = GetEventHandler()->ProcessEvent(event);
-
-    delete[] files;
-
-    return rc;
+    return GetEventHandler()->ProcessEvent(event);
 #else // __WXMICROWIN__
     return FALSE;
 #endif
@@ -3264,6 +3287,18 @@ bool wxWindowMSW::HandleSysColorChange()
     wxSysColourChangedEvent event;
     event.SetEventObject(this);
 
+    (void)GetEventHandler()->ProcessEvent(event);
+
+    // always let the system carry on the default processing to allow the
+    // native controls to react to the colours update
+    return FALSE;
+}
+
+bool wxWindowMSW::HandleDisplayChange()
+{
+    wxDisplayChangedEvent event;
+    event.SetEventObject(this);
+
     return GetEventHandler()->ProcessEvent(event);
 }
 
@@ -3313,6 +3348,40 @@ WXHBRUSH wxWindowMSW::OnCtlColor(WXHDC WXUNUSED(hDC),
 
 bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange)
 {
+#if wxUSE_PALETTE
+    // same as below except we don't respond to our own messages
+    if ( hWndPalChange != GetHWND() )
+    {
+        // check to see if we our our parents have a custom palette
+        wxWindow *win = this;
+        while ( win && !win->HasCustomPalette() )
+        {
+            win = win->GetParent();
+        }
+
+        if ( win && win->HasCustomPalette() )
+        {
+            // realize the palette to see whether redrawing is needed
+            HDC hdc = ::GetDC((HWND) hWndPalChange);
+            win->m_palette.SetHPALETTE((WXHPALETTE)
+                    ::SelectPalette(hdc, GetHpaletteOf(win->m_palette), FALSE));
+
+            int result = ::RealizePalette(hdc);
+
+            // restore the palette (before releasing the DC)
+            win->m_palette.SetHPALETTE((WXHPALETTE)
+                    ::SelectPalette(hdc, GetHpaletteOf(win->m_palette), FALSE));
+            ::RealizePalette(hdc);
+            ::ReleaseDC((HWND) hWndPalChange, hdc);
+
+            // now check for the need to redraw
+            if (result > 0)
+                InvalidateRect((HWND) hWndPalChange, NULL, TRUE);
+        }
+
+    }
+#endif // wxUSE_PALETTE
+
     wxPaletteChangedEvent event(GetId());
     event.SetEventObject(this);
     event.SetChangedWindow(wxFindWinFromHandle(hWndPalChange));
@@ -3322,6 +3391,29 @@ bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange)
 
 bool wxWindowMSW::HandleQueryNewPalette()
 {
+
+#if wxUSE_PALETTE
+    // check to see if we our our parents have a custom palette
+    wxWindow *win = this;
+    while (!win->HasCustomPalette() && win->GetParent()) win = win->GetParent();
+    if (win->HasCustomPalette()) {
+        /* realize the palette to see whether redrawing is needed */
+        HDC hdc = GetDC((HWND) GetHWND());
+        win->m_palette.SetHPALETTE( (WXHPALETTE)
+             ::SelectPalette(hdc, (HPALETTE) win->m_palette.GetHPALETTE(), FALSE) );
+
+        int result = ::RealizePalette(hdc);
+        /* restore the palette (before releasing the DC) */
+        win->m_palette.SetHPALETTE( (WXHPALETTE)
+             ::SelectPalette(hdc, (HPALETTE) win->m_palette.GetHPALETTE(), TRUE) );
+        ::RealizePalette(hdc);
+        ::ReleaseDC((HWND) GetHWND(), hdc);
+        /* now check for the need to redraw */
+        if (result > 0)
+            ::InvalidateRect((HWND) GetHWND(), NULL, TRUE);
+        }
+#endif // wxUSE_PALETTE
+
     wxQueryNewPaletteEvent event(GetId());
     event.SetEventObject(this);
 
@@ -3329,24 +3421,114 @@ bool wxWindowMSW::HandleQueryNewPalette()
 }
 
 // Responds to colour changes: passes event on to children.
-void wxWindowMSW::OnSysColourChanged(wxSysColourChangedEvent& event)
+void wxWindowMSW::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event))
 {
-    wxNode *node = GetChildren().First();
+    // the top level window also reset the standard colour map as it might have
+    // changed (there is no need to do it for the non top level windows as we
+    // only have to do it once)
+    if ( IsTopLevel() )
+    {
+        // FIXME-MT
+        gs_hasStdCmap = FALSE;
+    }
+    wxWindowList::Node *node = GetChildren().GetFirst();
     while ( node )
     {
-        // Only propagate to non-top-level windows
-        wxWindow *win = (wxWindow *)node->Data();
-        if ( win->GetParent() )
+        // Only propagate to non-top-level windows because Windows already
+        // sends this event to all top-level ones
+        wxWindow *win = node->GetData();
+        if ( !win->IsTopLevel() )
         {
-            wxSysColourChangedEvent event2;
-            event.m_eventObject = win;
-            win->GetEventHandler()->ProcessEvent(event2);
+            // we need to send the real WM_SYSCOLORCHANGE and not just trigger
+            // EVT_SYS_COLOUR_CHANGED call because the latter wouldn't work for
+            // the standard controls
+            ::SendMessage(GetHwndOf(win), WM_SYSCOLORCHANGE, 0, 0);
         }
 
-        node = node->Next();
+        node = node->GetNext();
+    }
+
+    // update the colours we use if they were not set explicitly by the user:
+    // this must be done or OnCtlColor() would continue to use the old colours
+    if ( !m_hasFgCol )
+    {
+        m_foregroundColour = wxSystemSettings::
+                                GetSystemColour(wxSYS_COLOUR_WINDOWTEXT);
+    }
+
+    if ( !m_hasBgCol )
+    {
+        m_backgroundColour = wxSystemSettings::
+                                GetSystemColour(wxSYS_COLOUR_BTNFACE);
     }
 }
 
+extern wxCOLORMAP *wxGetStdColourMap()
+{
+    static COLORREF s_stdColours[wxSTD_COL_MAX];
+    static wxCOLORMAP s_cmap[wxSTD_COL_MAX];
+
+    if ( !gs_hasStdCmap )
+    {
+        static bool s_coloursInit = FALSE;
+
+        if ( !s_coloursInit )
+        {
+            // When a bitmap is loaded, the RGB values can change (apparently
+            // because Windows adjusts them to care for the old programs always
+            // using 0xc0c0c0 while the transparent colour for the new Windows
+            // versions is different). But we do this adjustment ourselves so
+            // we want to avoid Windows' "help" and for this we need to have a
+            // reference bitmap which can tell us what the RGB values change
+            // to.
+            wxBitmap stdColourBitmap(_T("wxBITMAP_STD_COLOURS"));
+            if ( stdColourBitmap.Ok() )
+            {
+                // 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!") );
+
+                wxMemoryDC memDC;
+                memDC.SelectObject(stdColourBitmap);
+
+                wxColour colour;
+                for ( size_t i = 0; i < WXSIZEOF(s_stdColours); i++ )
+                {
+                    memDC.GetPixel(i, 0, &colour);
+                    s_stdColours[i] = wxColourToRGB(colour);
+                }
+            }
+            else // wxBITMAP_STD_COLOURS couldn't be loaded
+            {
+                s_stdColours[0] = RGB(000,000,000);     // black
+                s_stdColours[1] = RGB(128,128,128);     // dark grey
+                s_stdColours[2] = RGB(192,192,192);     // light grey
+                s_stdColours[3] = RGB(255,255,255);     // white
+                //s_stdColours[4] = RGB(000,000,255);     // blue
+                //s_stdColours[5] = RGB(255,000,255);     // magenta
+            }
+
+            s_coloursInit = TRUE;
+        }
+
+        gs_hasStdCmap = TRUE;
+
+        // create the colour map
+#define INIT_CMAP_ENTRY(col) \
+            s_cmap[wxSTD_COL_##col].from = s_stdColours[wxSTD_COL_##col]; \
+            s_cmap[wxSTD_COL_##col].to = ::GetSysColor(COLOR_##col)
+
+        INIT_CMAP_ENTRY(BTNTEXT);
+        INIT_CMAP_ENTRY(BTNSHADOW);
+        INIT_CMAP_ENTRY(BTNFACE);
+        INIT_CMAP_ENTRY(BTNHIGHLIGHT);
+
+#undef INIT_CMAP_ENTRY
+    }
+
+    return s_cmap;
+}
+
 // ---------------------------------------------------------------------------
 // painting
 // ---------------------------------------------------------------------------
@@ -3520,7 +3702,7 @@ bool wxWindowMSW::HandleGetMinMaxInfo(void *mmInfo)
 bool wxWindowMSW::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control)
 {
 #if wxUSE_MENUS_NATIVE
-    if ( wxCurrentPopupMenu )
+    if ( !cmd && wxCurrentPopupMenu )
     {
         wxMenu *popupMenu = wxCurrentPopupMenu;
         wxCurrentPopupMenu = NULL;
@@ -3529,18 +3711,20 @@ bool wxWindowMSW::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control)
     }
 #endif // wxUSE_MENUS_NATIVE
 
-    wxWindow *win = (wxWindow*) NULL;
-    if ( cmd == 0 || cmd == 1 ) // menu or accel - use id
+    wxWindow *win = NULL;
+
+    // first try to find it from HWND - this works even with the broken
+    // programs using the same ids for different controls
+    if ( control )
     {
-        // must cast to a signed type before comparing with other ids!
-        win = FindItem((signed short)id);
+        win = wxFindWinFromHandle(control);
     }
 
-    if (!win && control)
+    // try the id
+    if ( !win )
     {
-        // find it from HWND - this works even with the broken programs using
-        // the same ids for different controls
-        win = wxFindWinFromHandle(control);
+        // must cast to a signed type before comparing with other ids!
+        win = FindItem((signed short)id);
     }
 
     if ( win )
@@ -4284,11 +4468,13 @@ extern wxWindow *wxGetWindowFromHWND(WXHWND hWnd)
         // FIXME: this is clearly not the best way to do it but I think we'll
         //        need to change HWND <-> wxWindow code more heavily than I can
         //        do it now to fix it
+#ifndef __WXMICROWIN__
         if ( ::GetWindow(hwnd, GW_OWNER) )
         {
             // it's a dialog box, don't go upwards
             break;
         }
+#endif
 
         hwnd = ::GetParent(hwnd);
         win = wxFindWinFromHandle((WXHWND)hwnd);