]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/window.cpp
Removed a deprecated wxBitmap constructor, and some
[wxWidgets.git] / src / msw / window.cpp
index d219c90534b21916a22dfd939c4f290e05dda834..d097ef44ccf20877142163342eb2829b8c88fdb6 100644 (file)
@@ -5,8 +5,8 @@
 // Modified by: VZ on 13.05.99: no more Default(), MSWOnXXX() reorganisation
 // Created:     04/01/98
 // RCS-ID:      $Id$
-// Copyright:   (c) Julian Smart and Markus Holzem
-// Licence:     wxWindows license
+// Copyright:   (c) Julian Smart
+// Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
 // ===========================================================================
     #include "wx/dnd.h"
 #endif
 
+#if wxUSE_ACCESSIBILITY
+    #include "wx/access.h"
+    #include <oleacc.h>
+    #ifndef WM_GETOBJECT
+        #define WM_GETOBJECT 0x003D
+    #endif
+    #ifndef OBJID_CLIENT
+        #define OBJID_CLIENT 0xFFFFFFFC
+    #endif
+#endif
+
 #include "wx/menuitem.h"
 #include "wx/log.h"
 
@@ -312,14 +323,14 @@ void wxWindowMSW::Init()
     InitBase();
 
     // MSW specific
-    m_doubleClickAllowed = 0;
-
     m_isBeingDeleted = FALSE;
-    m_oldWndProc = 0;
+    m_oldWndProc = NULL;
     m_useCtl3D = FALSE;
     m_mouseInWindow = FALSE;
     m_lastKeydownProcessed = FALSE;
 
+    m_childrenDisabled = NULL;
+
     // wxWnd
     m_hMenu = 0;
 
@@ -348,12 +359,12 @@ wxWindowMSW::~wxWindowMSW()
     // VS: make sure there's no wxFrame with last focus set to us:
     for ( wxWindow *win = GetParent(); win; win = win->GetParent() )
     {
-        wxFrame *frame = wxDynamicCast(win, wxFrame);
+        wxTopLevelWindow *frame = wxDynamicCast(win, wxTopLevelWindow);
         if ( frame )
         {
             if ( frame->GetLastFocus() == this )
             {
-                frame->SetLastFocus((wxWindow*)NULL);
+                frame->SetLastFocus(NULL);
             }
             break;
         }
@@ -380,6 +391,8 @@ wxWindowMSW::~wxWindowMSW()
         // remove hWnd <-> wxWindow association
         wxRemoveHandleAssociation(this);
     }
+
+    delete m_childrenDisabled;
 }
 
 // real construction (Init() must have been called before!)
@@ -392,17 +405,6 @@ bool wxWindowMSW::Create(wxWindow *parent,
 {
     wxCHECK_MSG( parent, FALSE, wxT("can't create wxWindow without parent") );
 
-#if wxUSE_STATBOX
-    // wxGTK doesn't allow to create controls with static box as the parent so
-    // this will result in a crash when the program is ported to wxGTK - warn
-    // about it
-    //
-    // the correct solution is to create the controls as siblings of the
-    // static box
-    wxASSERT_MSG( !wxDynamicCast(parent, wxStaticBox),
-                  _T("wxStaticBox can't be used as a window parent!") );
-#endif // wxUSE_STATBOX
-
     if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) )
         return FALSE;
 
@@ -500,19 +502,58 @@ bool wxWindowMSW::Enable(bool enable)
     if ( hWnd )
         ::EnableWindow(hWnd, (BOOL)enable);
 
-    // VZ: no, this is a bad idea: imagine that you have a dialog with some
-    //     disabled controls and disable it - you really wouldn't like the
-    //     disabled controls be reenabled too when you reenable the dialog!
-#if 0
-    wxWindowList::Node *node = GetChildren().GetFirst();
-    while ( node )
+    // 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::Node *node = GetChildren().GetFirst();
+          node;
+          node = node->GetNext() )
     {
         wxWindow *child = node->GetData();
-        child->Enable(enable);
+        if ( child->IsTopLevel() )
+        {
+            // the logic below doesn't apply to top level children
+            continue;
+        }
 
-        node = node->GetNext();
+        if ( enable )
+        {
+            // enable the child back unless it had been disabled before us
+            if ( !m_childrenDisabled || !m_childrenDisabled->Find(child) )
+                child->Enable();
+        }
+        else // we're being disabled
+        {
+            if ( child->IsEnabled() )
+            {
+                // disable it as children shouldn't stay enabled while the
+                // parent is not
+                child->Disable();
+            }
+            else // child already disabled, remember it
+            {
+                // have we created the list of disabled children already?
+                if ( !m_childrenDisabled )
+                    m_childrenDisabled = new wxWindowList;
+
+                m_childrenDisabled->Append(child);
+            }
+        }
+    }
+
+    if ( enable && m_childrenDisabled )
+    {
+        // we don't need this list any more, don't keep unused memory
+        delete m_childrenDisabled;
+        m_childrenDisabled = NULL;
     }
-#endif // 0
 
     return TRUE;
 }
@@ -993,7 +1034,10 @@ void wxWindowMSW::SubclassWin(WXHWND hWnd)
     }
     else
     {
-        // don't bother restoring it neither
+        // don't bother restoring it neither: this also makes it easy to
+        // implement IsOfStandardClass() method which returns TRUE for the
+        // standard controls and FALSE for the wxWindows own windows as it can
+        // simply check m_oldWndProc
         m_oldWndProc = NULL;
     }
 }
@@ -1024,35 +1068,21 @@ 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!!
-
-    if ( wxUsingUnicowsDll() )
+    // Unicows note: the code below works, but only 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.
+    WNDCLASS cls;
+    if ( !::GetClassInfo(wxGetInstance(), wxGetWindowClass(hWnd), &cls) )
     {
-        static wxChar buffer[512];
-        WNDCLASS cls;
+        wxLogLastError(_T("GetClassInfo"));
 
-        ::GetClassName((HWND)hWnd, buffer, 512);
-        ::GetClassInfo(wxGetInstance(), buffer, &cls);
-        return wndProc == (WXFARPROC)cls.lpfnWndProc;
-    }
-    else
-#endif
-    {
-        return wndProc == (WXFARPROC)::GetWindowLong((HWND)hWnd, GWL_WNDPROC);
+        return FALSE;
     }
+
+    return wndProc == (WXFARPROC)cls.lpfnWndProc;
 }
 
 // ----------------------------------------------------------------------------
@@ -1163,6 +1193,16 @@ WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const
                 *exstyle |= WS_EX_DLGMODALFRAME;
                 break;
         }
+
+        // wxUniv doesn't use Windows dialog navigation functions at all
+#ifndef __WXUNIVERSAL__
+        // to make the dialog navigation work with the nested panels we must
+        // use this style (top level windows such as dialogs don't need it)
+        if ( (flags & wxTAB_TRAVERSAL) && !IsTopLevel() )
+        {
+            *exstyle |= WS_EX_CONTROLPARENT;
+        }
+#endif // __WXUNIVERSAL__
     }
 
     return style;
@@ -1475,7 +1515,7 @@ void wxWindowMSW::DoSetToolTip(wxToolTip *tooltip)
     wxWindowBase::DoSetToolTip(tooltip);
 
     if ( m_tooltip )
-        m_tooltip->SetWindow(this);
+        m_tooltip->SetWindow((wxWindow *)this);
 }
 
 #endif // wxUSE_TOOLTIPS
@@ -1847,6 +1887,10 @@ static void wxYieldForCommandsOnly()
     {
         wxTheApp->DoMessage((WXMSG *)&msg);
     }
+
+    // If we retrieved a WM_QUIT, insert back into the message queue.
+    if (msg.message == WM_QUIT)
+        ::PostQuitMessage(0);
 }
 
 bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y)
@@ -1905,14 +1949,7 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
         // here we try to do all the job which ::IsDialogMessage() usually does
         // internally
 #if 1
-        bool bProcess = TRUE;
-        if ( msg->message != WM_KEYDOWN )
-            bProcess = FALSE;
-
-        if ( bProcess && (HIWORD(msg->lParam) & KF_ALTDOWN) == KF_ALTDOWN )
-            bProcess = FALSE;
-
-        if ( bProcess )
+        if ( msg->message == WM_KEYDOWN )
         {
             bool bCtrlDown = wxIsCtrlDown();
             bool bShiftDown = wxIsShiftDown();
@@ -1924,11 +1961,21 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
             if ( !bCtrlDown )
             {
                 lDlgCode = ::SendMessage(msg->hwnd, WM_GETDLGCODE, 0, 0);
+
+                // surprizingly, DLGC_WANTALLKEYS bit mask doesn't contain the
+                // DLGC_WANTTAB nor DLGC_WANTARROWS bits although, logically,
+                // it, of course, implies them
+                if ( lDlgCode & DLGC_WANTALLKEYS )
+                {
+                    lDlgCode |= DLGC_WANTTAB | DLGC_WANTARROWS;
+                }
             }
 
             bool bForward = TRUE,
                  bWindowChange = FALSE;
 
+            // should we process this message specially?
+            bool bProcess = TRUE;
             switch ( msg->wParam )
             {
                 case VK_TAB:
@@ -2011,6 +2058,12 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
                                     // eat the Enter events sometimes
                                     return FALSE;
                                 }
+                                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
@@ -2073,7 +2126,35 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
         // 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() 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
+            bool canSafelyCallIsDlgMsg = TRUE;
+
+            HWND hwndFocus = ::GetFocus();
+            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);
+            }
+
+            if ( canSafelyCallIsDlgMsg && ::IsDialogMessage(GetHwnd(), msg) )
             {
                 // IsDialogMessage() did something...
                 return TRUE;
@@ -2228,8 +2309,10 @@ LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM w
 {
     // trace all messages - useful for the debugging
 #ifdef __WXDEBUG__
+#if wxUSE_LOG
     wxLogTrace(wxTraceMessages, wxT("Processing %s(wParam=%8lx, lParam=%8lx)"),
-               wxGetMessageName(message), wParam, lParam);
+               wxGetMessageName(message), (long) wParam, lParam);
+#endif // wxUSE_LOG
 #endif // __WXDEBUG__
 
     wxWindowMSW *wnd = wxFindWinFromHandle((WXHWND) hWnd);
@@ -2412,28 +2495,42 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam
                         break;
                 }
 
-                if (!processed)
+                if ( processed )
+                    break;
+
 #endif // __WXMICROWIN__
+                int x = GET_X_LPARAM(lParam),
+                    y = GET_Y_LPARAM(lParam);
+
+                // redirect the event to a static control if necessary by
+                // finding one under mouse
+                wxWindowMSW *win;
+                if ( GetCapture() == this )
                 {
-                    // VZ: why do we need it here? DefWindowProc() is supposed
-                    //     to do this for us anyhow
-                    if ( message == WM_LBUTTONDOWN && AcceptsFocus() )
-                        SetFocus();
+                    // but don't do it if the mouse is captured by this window
+                    // because then it should really get this event itself
+                    win = this;
+                }
+                else
+                {
+                    win = FindWindowForMouseEvent(this, &x, &y);
 
-                    int x = GET_X_LPARAM(lParam),
-                        y = GET_Y_LPARAM(lParam);
+                    // this should never happen
+                    wxCHECK_MSG( win, 0,
+                                 _T("FindWindowForMouseEvent() returned NULL") );
 
-                    // redirect the event to a static control if necessary
-                    if (this == GetCapture())
-                    {
-                        processed = HandleMouseEvent(message, x, y, wParam);
-                    }
-                    else
+                    // for the standard classes their WndProc sets the focus to
+                    // them anyhow and doing it from here results in some weird
+                    // problems, but for our windows we want them to acquire
+                    // focus when clicked
+                    if ( !win->IsOfStandardClass() )
                     {
-                        wxWindowMSW *win = FindWindowForMouseEvent(this, &x, &y); //TW:REQ:Univ
-                        processed = win->HandleMouseEvent(message, x, y, wParam);
+                        if ( message == WM_LBUTTONDOWN && win->AcceptsFocus() )
+                            win->SetFocus();
                     }
                 }
+
+                processed = win->HandleMouseEvent(message, x, y, wParam);
             }
             break;
 
@@ -2497,11 +2594,19 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam
 #endif // defined(WM_DRAWITEM)
 
         case WM_GETDLGCODE:
-            if ( GetWindowStyleFlag() & wxWANTS_CHARS )
+            if ( !IsOfStandardClass() )
             {
-                // want everything: i.e. all keys and WM_CHAR message
-                rc.result = DLGC_WANTARROWS | DLGC_WANTCHARS |
-                            DLGC_WANTTAB | DLGC_WANTMESSAGE;
+                // we always want to get the char events
+                rc.result = DLGC_WANTCHARS;
+
+                if ( GetWindowStyleFlag() & wxWANTS_CHARS )
+                {
+                    // in fact, we want everything
+                    rc.result |= DLGC_WANTARROWS |
+                                 DLGC_WANTTAB |
+                                 DLGC_WANTALLKEYS;
+                }
+
                 processed = TRUE;
             }
             //else: get the dlg code from the DefWindowProc()
@@ -2515,71 +2620,73 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam
             if ( m_lastKeydownProcessed )
             {
                 processed = TRUE;
-                break;
             }
 
-            switch ( wParam )
+            if ( !processed )
             {
-                // we consider these message "not interesting" to OnChar, so
-                // just don't do anything more with them
-                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
-                case VK_ESCAPE:
-                case VK_SPACE:
-                case VK_RETURN:
-                case VK_BACK:
-                case VK_TAB:
-                case VK_ADD:
-                case VK_SUBTRACT:
-                case VK_MULTIPLY:
-                case VK_DIVIDE:
-                case VK_OEM_1:
-                case VK_OEM_2:
-                case VK_OEM_3:
-                case VK_OEM_4:
-                case VK_OEM_5:
-                case VK_OEM_6:
-                case VK_OEM_7:
-                case VK_OEM_PLUS:
-                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;
+                switch ( wParam )
+                {
+                    // we consider these message "not interesting" to OnChar, so
+                    // just don't do anything more with them
+                    case VK_SHIFT:
+                    case VK_CONTROL:
+                    case VK_MENU:
+                    case VK_CAPITAL:
+                    case VK_NUMLOCK:
+                    case VK_SCROLL:
+                        processed = TRUE;
+                        break;
 
-                    break;
+                    // avoid duplicate messages to OnChar for these ASCII keys:
+                    // they will be translated by TranslateMessage() and received
+                    // in WM_CHAR
+                    case VK_ESCAPE:
+                    case VK_SPACE:
+                    case VK_RETURN:
+                    case VK_BACK:
+                    case VK_TAB:
+                    case VK_ADD:
+                    case VK_SUBTRACT:
+                    case VK_MULTIPLY:
+                    case VK_DIVIDE:
+                    case VK_OEM_1:
+                    case VK_OEM_2:
+                    case VK_OEM_3:
+                    case VK_OEM_4:
+                    case VK_OEM_5:
+                    case VK_OEM_6:
+                    case VK_OEM_7:
+                    case VK_OEM_PLUS:
+                    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
-                // special case of VK_APPS: treat it the same as right mouse
-                // click because both usually pop up a context menu
-                case VK_APPS:
-                    {
-                        WPARAM flags;
-                        int x, y;
+                    // special case of VK_APPS: treat it the same as right mouse
+                    // click because both usually pop up a context menu
+                    case VK_APPS:
+                        {
+                            WPARAM flags;
+                            int x, y;
 
-                        TranslateKbdEventToMouse(this, &x, &y, &flags);
-                        processed = HandleMouseEvent(WM_RBUTTONDOWN, x, y, flags);
-                    }
-                    break;
+                            TranslateKbdEventToMouse(this, &x, &y, &flags);
+                            processed = HandleMouseEvent(WM_RBUTTONDOWN, x, y, flags);
+                        }
+                        break;
 #endif // VK_APPS
 
-                default:
-                    // do generate a CHAR event
-                    processed = HandleChar((WORD)wParam, lParam);
-
+                    default:
+                        // do generate a CHAR event
+                        processed = HandleChar((WORD)wParam, lParam);
+                }
             }
+            if (message == WM_SYSKEYDOWN)  // Let Windows still handle the SYSKEYs
+                processed = FALSE;
             break;
 
         case WM_SYSKEYUP:
@@ -2731,6 +2838,20 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam
             }
             break;
 
+#if wxUSE_ACCESSIBILITY
+        case WM_GETOBJECT:
+            {
+                //WPARAM dwFlags = (WPARAM) (DWORD) wParam;
+                LPARAM dwObjId = (LPARAM) (DWORD) lParam;
+
+                if (dwObjId == OBJID_CLIENT && GetOrCreateAccessible())
+                {
+                    return LresultFromObject(IID_IAccessible, wParam, (IUnknown*) GetAccessible()->GetIAccessible());
+                }
+                break;
+            }
+#endif
+
 #if defined(__WIN32__) && defined(WM_HELP)
         case WM_HELP:
             {
@@ -2778,14 +2899,30 @@ long wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam
                 processed = GetEventHandler()->ProcessEvent(evtCtx);
             }
             break;
+
+        case WM_MENUCHAR:
+            // we're only interested in our own menus, not MF_SYSMENU
+            if ( HIWORD(wParam) == MF_POPUP )
+            {
+                // handle menu chars for ownerdrawn menu items
+                int i = HandleMenuChar(toupper(LOWORD(wParam)), lParam);
+                if ( i != wxNOT_FOUND )
+                {
+                    rc.result = MAKELRESULT(i, MNC_EXECUTE);
+                    processed = TRUE;
+                }
+            }
+            break;
 #endif // __WIN32__
     }
 
     if ( !processed )
     {
 #ifdef __WXDEBUG__
+#if wxUSE_LOG
         wxLogTrace(wxTraceMessages, wxT("Forwarding %s to DefWindowProc."),
                    wxGetMessageName(message));
+#endif // wxUSE_LOG
 #endif // __WXDEBUG__
         rc.result = MSWDefWindowProc(message, wParam, lParam);
     }
@@ -2816,7 +2953,7 @@ void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win)
     if ( oldWin && (oldWin != win) )
     {
         wxLogDebug(wxT("HWND %X already associated with another window (%s)"),
-                   hWnd, win->GetClassInfo()->GetClassName());
+                   (int) hWnd, win->GetClassInfo()->GetClassName());
     }
     else
 #endif // __WXDEBUG__
@@ -2905,7 +3042,7 @@ bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
 
 WXHWND wxWindowMSW::MSWGetParent() const
 {
-    return m_parent ? m_parent->GetHWND() : NULL;
+    return m_parent ? m_parent->GetHWND() : WXHWND(NULL);
 }
 
 bool wxWindowMSW::MSWCreate(const wxChar *wclass,
@@ -2921,20 +3058,7 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass,
 
     // controlId is menu handle for the top level windows, so set it to 0
     // unless we're creating a child window
-    int controlId;
-    if ( style & WS_CHILD )
-    {
-        controlId = GetId();
-
-        if ( GetWindowStyleFlag() & wxCLIP_SIBLINGS )
-        {
-            style |= WS_CLIPSIBLINGS;
-        }
-    }
-    else // !child
-    {
-        controlId = 0;
-    }
+    int controlId = style & WS_CHILD ? GetId() : 0;
 
     // for each class "Foo" we have we also have "FooNR" ("no repaint") class
     // which is the same but without CS_[HV]REDRAW class styles so using it
@@ -2984,7 +3108,7 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass,
 // ---------------------------------------------------------------------------
 
 #ifdef __WIN95__
-// FIXME: VZ: I'm not sure at all that the order of processing is correct
+
 bool wxWindowMSW::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
 {
 #ifndef __WXMICROWIN__
@@ -2992,12 +3116,19 @@ bool wxWindowMSW::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
     HWND hWnd = hdr->hwndFrom;
     wxWindow *win = wxFindWinFromHandle((WXHWND)hWnd);
 
-    // is this one of our windows?
+    // if the control is one of our windows, let it handle the message itself
     if ( win )
     {
         return win->MSWOnNotify(idCtrl, lParam, result);
     }
 
+    // VZ: why did we do it? normally this is unnecessary and, besides, it
+    //     breaks the message processing for the toolbars because the tooltip
+    //     notifications were being forwarded to the toolbar child controls
+    //     (if it had any) before being passed to the toolbar itself, so in my
+    //     example the tooltip for the combobox was always shown instead of the
+    //     correct button tooltips
+#if 0
     // try all our children
     wxWindowList::Node *node = GetChildren().GetFirst();
     while ( node )
@@ -3010,32 +3141,105 @@ bool wxWindowMSW::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
 
         node = node->GetNext();
     }
+#endif // 0
 
-    // finally try this window too (catches toolbar case)
+    // by default, handle it ourselves
     return MSWOnNotify(idCtrl, lParam, result);
 #else // __WXMICROWIN__
     return FALSE;
 #endif
 }
 
+#if wxUSE_TOOLTIPS
+
+bool wxWindowMSW::HandleTooltipNotify(WXUINT code,
+                                      WXLPARAM lParam,
+                                      const wxString& ttip)
+{
+    // I don't know why it happens, but the versions of comctl32.dll starting
+    // from 4.70 sometimes send TTN_NEEDTEXTW even to ANSI programs (normally,
+    // this message is supposed to be sent to Unicode programs only) -- hence
+    // we need to handle it as well, otherwise no tooltips will be shown in
+    // this case
+
+    if ( !(code == (WXUINT) TTN_NEEDTEXTA || code == (WXUINT) TTN_NEEDTEXTW) || ttip.empty() )
+    {
+        // not a tooltip message or no tooltip to show anyhow
+        return FALSE;
+    }
+
+    LPTOOLTIPTEXT ttText = (LPTOOLTIPTEXT)lParam;
+
+#if !wxUSE_UNICODE
+    if ( code == (WXUINT) TTN_NEEDTEXTA )
+    {
+        // we pass just the pointer as we store the string internally anyhow
+        ttText->lpszText = (char *)ttip.c_str();
+    }
+    else // TTN_NEEDTEXTW
+#endif // !Unicode
+    {
+#if wxUSE_UNICODE
+        // in Unicode mode this is just what we need
+        ttText->lpszText = (wxChar *)ttip.c_str();
+#else // !Unicode
+        // in ANSI mode we have to convert the string and put it into the
+        // provided buffer: be careful not to overrun it
+        const size_t lenAnsi = ttip.length();
+
+        // some compilers (MetroWerks and Cygwin) don't like calling mbstowcs
+        // with NULL argument
+        #if defined( __MWERKS__ ) || defined( __CYGWIN__ )
+            size_t lenUnicode = 2*lenAnsi;
+        #else
+            size_t lenUnicode = mbstowcs(NULL, ttip, lenAnsi);
+        #endif
+
+        // using the pointer of right type avoids us doing all sorts of
+        // pointer arithmetics ourselves
+        wchar_t *dst = (wchar_t *)ttText->szText,
+                *pwz = new wchar_t[lenUnicode + 1];
+        mbstowcs(pwz, ttip, lenAnsi + 1);
+
+        // stay inside the buffer (-1 because it must be NUL-terminated)
+        if ( lenUnicode > WXSIZEOF(ttText->szText) - 1 )
+        {
+            lenUnicode = WXSIZEOF(ttText->szText) - 1;
+        }
+
+        memcpy(dst, pwz, lenUnicode*sizeof(wchar_t));
+
+        // put the terminating wide NUL
+        dst[lenUnicode] = L'\0';
+
+        delete [] pwz;
+#endif // Unicode/!Unicode
+    }
+
+    return TRUE;
+}
+
+#endif // wxUSE_TOOLTIPS
+
 bool wxWindowMSW::MSWOnNotify(int WXUNUSED(idCtrl),
-                           WXLPARAM lParam,
-                           WXLPARAM* WXUNUSED(result))
+                              WXLPARAM lParam,
+                              WXLPARAM* WXUNUSED(result))
 {
 #if wxUSE_TOOLTIPS
-    NMHDR* hdr = (NMHDR *)lParam;
-    if ( (int)hdr->code == TTN_NEEDTEXT && m_tooltip )
+    if ( m_tooltip )
     {
-        TOOLTIPTEXT *ttt = (TOOLTIPTEXT *)lParam;
-        ttt->lpszText = (wxChar *)m_tooltip->GetTip().c_str();
-
-        // processed
-        return TRUE;
+        NMHDR* hdr = (NMHDR *)lParam;
+        if ( HandleTooltipNotify(hdr->code, lParam, m_tooltip->GetTip()))
+        {
+            // processed
+            return TRUE;
+        }
     }
 #endif // wxUSE_TOOLTIPS
 
     return FALSE;
 }
+
 #endif // __WIN95__
 
 // ---------------------------------------------------------------------------
@@ -3083,8 +3287,33 @@ bool wxWindowMSW::HandleEndSession(bool endSession, long logOff)
 // window creation/destruction
 // ---------------------------------------------------------------------------
 
-bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT WXUNUSED(cs), bool *mayCreate)
+bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT cs, bool *mayCreate)
 {
+    // if we have WS_EX_CONTROLPARENT flag we absolutely *must* set it for our
+    // parent as well as otherwise several Win32 functions using
+    // GetNextDlgTabItem() to iterate over all controls such as
+    // IsDialogMessage() or DefDlgProc() would enter an infinite loop: indeed,
+    // all of them iterate over all the controls starting from the focus and
+    // stop iterating when they get back to the focus but unless all parents
+    // have WS_EX_CONTROLPARENT bit set, they would never get back to focus
+    if ( ((CREATESTRUCT *)cs)->dwExStyle & WS_EX_CONTROLPARENT )
+    {
+        // there is no need to do anything for the top level windows
+        const wxWindow *parent = GetParent();
+        while ( parent && !parent->IsTopLevel() )
+        {
+            LONG exStyle = ::GetWindowLong(GetHwndOf(parent), GWL_EXSTYLE);
+            if ( !(exStyle & WS_EX_CONTROLPARENT) )
+            {
+                // force the parent to have this style
+                ::SetWindowLong(GetHwndOf(parent), GWL_EXSTYLE,
+                                exStyle | WS_EX_CONTROLPARENT);
+            }
+
+            parent = parent->GetParent();
+        }
+    }
+
     // TODO: should generate this event from WM_NCCREATE
     wxWindowCreateEvent event((wxWindow *)this);
     (void)GetEventHandler()->ProcessEvent(event);
@@ -3096,8 +3325,7 @@ bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT WXUNUSED(cs), bool *mayCreate)
 
 bool wxWindowMSW::HandleDestroy()
 {
-    wxWindowDestroyEvent event((wxWindow *)this);
-    (void)GetEventHandler()->ProcessEvent(event);
+    SendDestroyEvent();
 
     // delete our drop target if we've got one
 #if wxUSE_DRAG_AND_DROP
@@ -3183,6 +3411,13 @@ bool wxWindowMSW::HandleKillFocus(WXHWND hwnd)
     }
 #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 )
+    {
+        return FALSE;
+    }
+
     wxFocusEvent event(wxEVT_KILL_FOCUS, m_windowId);
     event.SetEventObject(this);
 
@@ -3330,6 +3565,8 @@ bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd),
 
     if ( hcursor )
     {
+//        wxLogDebug("HandleSetCursor: Setting cursor %ld", (long) hcursor);
+
         ::SetCursor(hcursor);
 
         // cursor set, stop here
@@ -3487,7 +3724,7 @@ bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange)
     if ( hWndPalChange != GetHWND() )
     {
         // check to see if we our our parents have a custom palette
-        wxWindow *win = this;
+        wxWindowMSW *win = this;
         while ( win && !win->HasCustomPalette() )
         {
             win = win->GetParent();
@@ -3536,7 +3773,7 @@ bool wxWindowMSW::HandleQueryNewPalette()
 
 #if wxUSE_PALETTE
     // check to see if we our our parents have a custom palette
-    wxWindow *win = this;
+    wxWindowMSW *win = this;
     while (!win->HasCustomPalette() && win->GetParent()) win = win->GetParent();
     if (win->HasCustomPalette()) {
         /* realize the palette to see whether redrawing is needed */
@@ -3951,6 +4188,7 @@ void wxWindowMSW::InitMouseEvent(wxMouseEvent& event,
 
     event.SetTimestamp(s_currentMsg.time);
     event.m_eventObject = this;
+    event.SetId(GetId());
 
 #if wxUSE_MOUSEEVENT_HACK
     m_lastMouseX = x;
@@ -4170,7 +4408,9 @@ bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam, bool isASCII)
     int id;
     if ( isASCII )
     {
-        // If 1 -> 26, translate to CTRL plus a letter.
+        // If 1 -> 26, translate to either special keycode or just set
+        // ctrlDown.  IOW, Ctrl-C should result in keycode == 3 and
+        // ControlDown() == TRUE.
         id = wParam;
         if ( (id > 0) && (id < 27) )
         {
@@ -4190,7 +4430,7 @@ bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam, bool isASCII)
 
                 default:
                     ctrlDown = TRUE;
-                    id = id + 'a' - 1;
+                    break;
             }
         }
     }
@@ -4206,9 +4446,18 @@ bool wxWindowMSW::HandleChar(WXWPARAM wParam, WXLPARAM lParam, bool isASCII)
     }
 
     wxKeyEvent event(CreateKeyEvent(wxEVT_CHAR, id, lParam, wParam));
-    if ( ctrlDown )
+
+    // 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
+    // alphanumeric, so pretend that there are no modifiers at all (the
+    // 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_controlDown = TRUE;
+        event.m_controlDown =
+        event.m_altDown = FALSE;
     }
 
     return GetEventHandler()->ProcessEvent(event);
@@ -4256,6 +4505,69 @@ bool wxWindowMSW::HandleKeyUp(WXWPARAM wParam, WXLPARAM lParam)
     return FALSE;
 }
 
+#ifdef __WIN32__
+
+int wxWindowMSW::HandleMenuChar(int chAccel, WXLPARAM lParam)
+{
+    const HMENU hmenu = (HMENU)lParam;
+
+    MENUITEMINFO mii;
+    wxZeroMemory(mii);
+    mii.cbSize = sizeof(MENUITEMINFO);
+    mii.fMask = MIIM_TYPE | MIIM_DATA;
+
+    // find if we have this letter in any owner drawn item
+    const int count = ::GetMenuItemCount(hmenu);
+    for ( int i = 0; i < count; i++ )
+    {
+        if ( ::GetMenuItemInfo(hmenu, i, TRUE, &mii) )
+        {
+            if ( mii.fType == MFT_OWNERDRAW )
+            {
+                //  dwItemData member of the MENUITEMINFO is a
+                //  pointer to the associated wxMenuItem -- see the
+                //  menu creation code
+                wxMenuItem *item = (wxMenuItem*)mii.dwItemData;
+
+                const wxChar *p = wxStrchr(item->GetText(), _T('&'));
+                while ( p++ )
+                {
+                    if ( *p == _T('&') )
+                    {
+                        // this is not the accel char, find the real one
+                        p = wxStrchr(p + 1, _T('&'));
+                    }
+                    else // got the accel char
+                    {
+                        // FIXME-UNICODE: this comparison doesn't risk to work
+                        // for non ASCII accelerator characters I'm afraid, but
+                        // what can we do?
+                        if ( wxToupper(*p) == chAccel )
+                        {
+                            return i;
+                        }
+                        else
+                        {
+                            // this one doesn't match
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        else // failed ot get the menu text?
+        {
+            // it's not fatal, so don't show error, but still log
+            // it
+            wxLogLastError(_T("GetMenuItemInfo"));
+        }
+    }
+
+    return wxNOT_FOUND;
+}
+
+#endif // __WIN32__
+
 // ---------------------------------------------------------------------------
 // joystick
 // ---------------------------------------------------------------------------
@@ -4548,6 +4860,12 @@ int wxCharCodeMSWToWX(int keySym)
         case VK_OEM_6:      id = ']'; break;
         case VK_OEM_7:      id = '\''; break;
 
+#ifdef VK_APPS
+        case VK_LWIN:       id = WXK_WINDOWS_LEFT; break;
+        case VK_RWIN:       id = WXK_WINDOWS_RIGHT; break;
+        case VK_APPS:       id = WXK_WINDOWS_MENU; break;
+#endif // VK_APPS defined
+
         default:
             id = 0;
     }
@@ -4737,7 +5055,7 @@ void wxSetKeyboardHook(bool doIt)
 
         // avoids warning about statement with no effect (FreeProcInstance
         // doesn't do anything under Win32)
-#if !defined(WIN32) && !defined(_WIN32) && !defined(__WIN32__) && !defined(__NT__) && !defined(__GNUWIN32__)
+#if !defined(__WIN32__) && !defined(__NT__)
         FreeProcInstance(wxTheKeyboardHookProc);
 #endif
     }
@@ -5262,9 +5580,10 @@ static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win)
 
 // Find the wxWindow at the current mouse position, returning the mouse
 // position.
-wxWindow* wxFindWindowAtPointer(wxPoint& WXUNUSED(pt))
+wxWindow* wxFindWindowAtPointer(wxPoint& pt)
 {
-    return wxFindWindowAtPoint(wxGetMousePosition());
+    pt = wxGetMousePosition();
+    return wxFindWindowAtPoint(pt);
 }
 
 wxWindow* wxFindWindowAtPoint(const wxPoint& pt)