]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/window.cpp
Commited updated list of files to compile.
[wxWidgets.git] / src / msw / window.cpp
index 163a72e05531deda0fbde9059eea7e78469ed38c..f58179b4c3f260467ee1a7e9aa2c6fcc774fcd50 100644 (file)
@@ -50,7 +50,7 @@
     #include <stdio.h>
 #endif
 
-#if     wxUSE_OWNER_DRAWN
+#if wxUSE_OWNER_DRAWN
     #include "wx/ownerdrw.h"
 #endif
 
     #include "wx/caret.h"
 #endif // wxUSE_CARET
 
+#if wxUSE_SPINCTRL
+    #include "wx/spinctrl.h"
+#endif // wxUSE_SPINCTRL
+
 #include "wx/intl.h"
 #include "wx/log.h"
 
     #endif
 #endif
 
+// This didn't appear in mingw until 2.95.2
+#ifndef SIF_TRACKPOS
+#define SIF_TRACKPOS 16
+#endif
+
 // ---------------------------------------------------------------------------
 // global variables
 // ---------------------------------------------------------------------------
@@ -129,9 +138,8 @@ wxWindow *wxFindWinFromHandle(WXHWND hWnd);
 // mouse clicks
 static void TranslateKbdEventToMouse(wxWindow *win, int *x, int *y, WPARAM *flags);
 
-// get the current state of SHIFT/CTRL keys
-static inline bool IsShiftDown() { return (GetKeyState(VK_SHIFT) & 0x100) != 0; }
-static inline bool IsCtrlDown() { return (GetKeyState(VK_CONTROL) & 0x100) != 0; }
+// get the text metrics for the current font
+static TEXTMETRIC wxGetTextMetrics(const wxWindow *win);
 
 // ---------------------------------------------------------------------------
 // event tables
@@ -274,10 +282,11 @@ wxWindow::~wxWindow()
 
     if ( m_hWnd )
     {
-        if (::IsWindow(GetHwnd()))
+        // VZ: test temp removed to understand what really happens here
+        //if (::IsWindow(GetHwnd()))
         {
             if ( !::DestroyWindow(GetHwnd()) )
-                wxLogLastError("DestroyWindow");
+                wxLogLastError(wxT("DestroyWindow"));
         }
 
         // remove hWnd <-> wxWindow association
@@ -302,12 +311,17 @@ bool wxWindow::Create(wxWindow *parent, wxWindowID id,
     DWORD msflags = 0;
     if ( style & wxBORDER )
         msflags |= WS_BORDER;
+/* Not appropriate for non-frame/dialog windows, and
+   may clash with other window styles.
     if ( style & wxTHICK_FRAME )
         msflags |= WS_THICKFRAME;
-
+*/
+    //msflags |= WS_CHILD /* | WS_CLIPSIBLINGS */  | WS_VISIBLE;
     msflags |= WS_CHILD | WS_VISIBLE;
     if ( style & wxCLIP_CHILDREN )
         msflags |= WS_CLIPCHILDREN;
+    if ( style & wxCLIP_SIBLINGS )
+        msflags |= WS_CLIPSIBLINGS;
 
     bool want3D;
     WXDWORD exStyle = Determine3DEffects(WS_EX_CLIENTEDGE, &want3D);
@@ -368,6 +382,10 @@ bool wxWindow::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 eb reenabled too when you reenable the dialog!
+#if 0
     wxWindowList::Node *node = GetChildren().GetFirst();
     while ( node )
     {
@@ -376,6 +394,7 @@ bool wxWindow::Enable(bool enable)
 
         node = node->GetNext();
     }
+#endif // 0
 
     return TRUE;
 }
@@ -467,20 +486,20 @@ bool wxWindow::SetCursor(const wxCursor& cursor)
         return FALSE;
     }
 
-    wxASSERT_MSG( m_cursor.Ok(),
-                  wxT("cursor must be valid after call to the base version"));
-
-    HWND hWnd = GetHwnd();
+    if ( m_cursor.Ok() )
+    {
+        HWND hWnd = GetHwnd();
 
-    // Change the cursor NOW if we're within the correct window
-    POINT point;
-    ::GetCursorPos(&point);
+        // Change the cursor NOW if we're within the correct window
+        POINT point;
+        ::GetCursorPos(&point);
 
-    RECT rect;
-    ::GetWindowRect(hWnd, &rect);
+        RECT rect;
+        ::GetWindowRect(hWnd, &rect);
 
-    if ( ::PtInRect(&rect, point) && !wxIsBusy() )
-        ::SetCursor((HCURSOR)m_cursor.GetHCURSOR());
+        if ( ::PtInRect(&rect, point) && !wxIsBusy() )
+            ::SetCursor(GetHcursorOf(m_cursor));
+    }
 
     return TRUE;
 }
@@ -852,7 +871,8 @@ WXDWORD wxWindow::MakeExtendedStyle(long style, bool eliminateBorders)
             exStyle |= WS_EX_DLGMODALFRAME;
 #if defined(__WIN95__)
         if ( style & wxRAISED_BORDER )
-            exStyle |= WS_EX_WINDOWEDGE;
+            // It seems that WS_EX_WINDOWEDGE doesn't work, but WS_EX_DLGMODALFRAME does
+            exStyle |= WS_EX_DLGMODALFRAME; /* WS_EX_WINDOWEDGE */;
         if ( style & wxSTATIC_BORDER )
             exStyle |= WS_EX_STATICEDGE;
 #endif
@@ -973,11 +993,17 @@ void wxWindow::OnIdle(wxIdleEvent& event)
             // by the time the OnIdle function is called, so 'state' may be
             // meaningless.
             int state = 0;
-            if ( ::GetKeyState(VK_SHIFT) != 0 )
+            if ( wxIsShiftDown() )
                 state |= MK_SHIFT;
-            if ( ::GetKeyState(VK_CONTROL) != 0 )
+            if ( wxIsCtrlDown() )
                 state |= MK_CONTROL;
-
+            if ( GetKeyState( VK_LBUTTON ) )
+                state |= MK_LBUTTON;
+            if ( GetKeyState( VK_MBUTTON ) )
+                state |= MK_MBUTTON;
+            if ( GetKeyState( VK_RBUTTON ) )
+                state |= MK_RBUTTON;
+  
             wxMouseEvent event(wxEVT_LEAVE_WINDOW);
             InitMouseEvent(event, pt.x, pt.y, state);
 
@@ -1084,8 +1110,14 @@ void wxWindow::DoGetSize(int *x, int *y) const
 {
     HWND hWnd = GetHwnd();
     RECT rect;
-    GetWindowRect(hWnd, &rect);
-
+#ifdef __WIN16__
+    ::GetWindowRect(hWnd, &rect);
+#else
+    if ( !::GetWindowRect(hWnd, &rect) )
+    {
+        wxLogLastError(_T("GetWindowRect"));
+    }
+#endif
     if ( x )
         *x = rect.right - rect.left;
     if ( y )
@@ -1119,11 +1151,14 @@ void wxWindow::DoGetPosition(int *x, int *y) const
             ::ScreenToClient(hParentWnd, &point);
         }
 
-        // We may be faking the client origin. So a window that's really at (0,
-        // 30) may appear (to wxWin apps) to be at (0, 0).
-        wxPoint pt(parent->GetClientAreaOrigin());
-        point.x -= pt.x;
-        point.y -= pt.y;
+        if ( parent )
+        {
+            // We may be faking the client origin. So a window that's really at (0,
+            // 30) may appear (to wxWin apps) to be at (0, 0).
+            wxPoint pt(parent->GetClientAreaOrigin());
+            point.x -= pt.x;
+            point.y -= pt.y;
+        }
     }
 
     if ( x )
@@ -1182,7 +1217,7 @@ void wxWindow::DoMoveWindow(int x, int y, int width, int height)
 {
     if ( !::MoveWindow(GetHwnd(), x, y, width, height, TRUE) )
     {
-        wxLogLastError("MoveWindow");
+        wxLogLastError(wxT("MoveWindow"));
     }
 }
 
@@ -1321,26 +1356,18 @@ void wxWindow::AdjustForParentClientOrigin(int& x, int& y, int sizeFlags)
 
 int wxWindow::GetCharHeight() const
 {
-    TEXTMETRIC lpTextMetric;
-    HWND hWnd = GetHwnd();
-    HDC dc = ::GetDC(hWnd);
-
-    GetTextMetrics(dc, &lpTextMetric);
-    ::ReleaseDC(hWnd, dc);
-
-    return lpTextMetric.tmHeight;
+    return wxGetTextMetrics(this).tmHeight;
 }
 
 int wxWindow::GetCharWidth() const
 {
-    TEXTMETRIC lpTextMetric;
-    HWND hWnd = GetHwnd();
-    HDC dc = ::GetDC(hWnd);
-
-    GetTextMetrics(dc, &lpTextMetric);
-    ::ReleaseDC(hWnd, dc);
-
-    return lpTextMetric.tmAveCharWidth;
+    // +1 is needed because Windows apparently adds it when calculating the
+    // dialog units size in pixels
+#if wxDIALOG_UNIT_COMPATIBILITY
+    return wxGetTextMetrics(this).tmAveCharWidth ;
+#else
+    return wxGetTextMetrics(this).tmAveCharWidth + 1;
+#endif
 }
 
 void wxWindow::GetTextExtent(const wxString& string,
@@ -1443,7 +1470,7 @@ bool wxWindow::DoPopupMenu(wxMenu *menu, int x, int y)
     ::ClientToScreen(hWnd, &point);
     wxCurrentPopupMenu = menu;
     ::TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, point.x, point.y, 0, hWnd, NULL);
-    wxYield();
+    wxYieldIfNeeded();
     wxCurrentPopupMenu = NULL;
 
     menu->SetInvokingWindow(NULL);
@@ -1482,8 +1509,8 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg)
 
         if ( bProcess )
         {
-            bool bCtrlDown = IsCtrlDown();
-            bool bShiftDown = IsShiftDown();
+            bool bCtrlDown = wxIsCtrlDown();
+            bool bShiftDown = wxIsShiftDown();
 
             // WM_GETDLGCODE: ask the control if it wants the key for itself,
             // don't process it if it's the case (except for Ctrl-Tab/Enter
@@ -1538,7 +1565,18 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg)
                         }
                         else if ( lDlgCode & DLGC_BUTTON )
                         {
-                            // buttons want process Enter themselevs
+                            // let IsDialogMessage() handle this for all
+                            // buttons except the owner-drawn ones which it
+                            // just seems to ignore
+                            long style = ::GetWindowLong(msg->hwnd, GWL_STYLE);
+                            if ( (style & BS_OWNERDRAW) == BS_OWNERDRAW )
+                            {
+                                // emulate the button click
+                                wxWindow *btn = wxFindWinFromHandle((WXHWND)msg->hwnd);
+                                if ( btn )
+                                    btn->MSWCommand(BN_CLICKED, 0 /* unused */);
+                            }
+
                             bProcess = FALSE;
                         }
                         else
@@ -1598,7 +1636,7 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg)
             // don't process system keys here
             if ( !(HIWORD(msg->lParam) & KF_ALTDOWN) )
             {
-                if ( (msg->wParam == VK_TAB) && IsCtrlDown() )
+                if ( (msg->wParam == VK_TAB) && wxIsCtrlDown() )
                 {
                     // find the first notebook parent and change its page
                     wxWindow *win = this;
@@ -1611,7 +1649,7 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg)
 
                     if ( nbook )
                     {
-                        bool forward = !IsShiftDown();
+                        bool forward = !wxIsShiftDown();
 
                         nbook->AdvanceSelection(forward);
                     }
@@ -1621,7 +1659,10 @@ bool wxWindow::MSWProcessMessage(WXMSG* pMsg)
 #endif // 0
 
         if ( ::IsDialogMessage(GetHwnd(), msg) )
+        {
+            // IsDialogMessage() did something...
             return TRUE;
+        }
     }
 
 #if wxUSE_TOOLTIPS
@@ -1824,7 +1865,7 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
             break;
 
         case WM_MOVE:
-            processed = HandleMove(LOWORD(lParam), HIWORD(lParam));
+            processed = HandleMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
             break;
 
         case WM_SIZE:
@@ -1865,17 +1906,15 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
             break;
 
         case WM_MOUSEMOVE:
-           {
-                short x = LOWORD(lParam);
-                short y = HIWORD(lParam);
-
-                processed = HandleMouseMove(x, y, wParam);
-           }
-           break;
+            processed = HandleMouseMove(GET_X_LPARAM(lParam),
+                                        GET_Y_LPARAM(lParam),
+                                        wParam);
+            break;
 
         case WM_LBUTTONDOWN:
            // set focus to this window
-           SetFocus();
+           if (AcceptsFocus())
+                SetFocus();
 
            // fall through
 
@@ -1887,12 +1926,10 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
         case WM_MBUTTONDOWN:
         case WM_MBUTTONUP:
         case WM_MBUTTONDBLCLK:
-            {
-                short x = LOWORD(lParam);
-                short y = HIWORD(lParam);
-
-                processed = HandleMouseEvent(message, x, y, wParam);
-            }
+            processed = HandleMouseEvent(message,
+                                         GET_X_LPARAM(lParam),
+                                         GET_Y_LPARAM(lParam),
+                                         wParam);
             break;
 
         case MM_JOY1MOVE:
@@ -1903,12 +1940,10 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
         case MM_JOY2BUTTONDOWN:
         case MM_JOY1BUTTONUP:
         case MM_JOY2BUTTONUP:
-            {
-                int x = LOWORD(lParam);
-                int y = HIWORD(lParam);
-
-                processed = HandleJoystickEvent(message, x, y, wParam);
-            }
+            processed = HandleJoystickEvent(message,
+                                            GET_X_LPARAM(lParam),
+                                            GET_Y_LPARAM(lParam),
+                                            wParam);
             break;
 
         case WM_SYSCOMMAND:
@@ -2148,6 +2183,36 @@ long wxWindow::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
                 rc.result = TRUE;
             }
             break;
+#ifdef __WIN32__
+        case WM_HELP:
+        {
+            HELPINFO* info = (HELPINFO*) lParam;
+            // Don't yet process menu help events, just windows
+            if (info->iContextType == HELPINFO_WINDOW)
+            {
+                wxWindow* subjectOfHelp = this;
+                bool eventProcessed = FALSE;
+                while (subjectOfHelp && !eventProcessed)
+                {
+                    wxHelpEvent helpEvent(wxEVT_HELP, subjectOfHelp->GetId(), wxPoint(info->MousePos.x, info->MousePos.y) ) ; // info->iCtrlId);
+                    helpEvent.SetEventObject(this);
+                    eventProcessed = GetEventHandler()->ProcessEvent(helpEvent);
+
+                    // Go up the window hierarchy until the event is handled (or not)
+                    subjectOfHelp = subjectOfHelp->GetParent();
+                }
+                processed = eventProcessed;
+            }
+            else if (info->iContextType == HELPINFO_MENUITEM)
+            {
+                wxHelpEvent helpEvent(wxEVT_HELP, info->iCtrlId) ;
+                helpEvent.SetEventObject(this);
+                processed = GetEventHandler()->ProcessEvent(helpEvent);
+            }
+            else processed = FALSE;
+            break;
+        }
+#endif
     }
 
     if ( !processed )
@@ -2240,24 +2305,25 @@ void wxWindow::MSWDetachWindowMenu()
 {
     if ( m_hMenu )
     {
+        wxChar buf[1024];
         HMENU hMenu = (HMENU)m_hMenu;
 
         int N = ::GetMenuItemCount(hMenu);
-        int i;
-        for (i = 0; i < N; i++)
+        for ( int i = 0; i < N; i++ )
         {
-            wxChar buf[100];
-            int chars = GetMenuString(hMenu, i, buf, 100, MF_BYPOSITION);
-            if ( !chars )
+            if ( !::GetMenuString(hMenu, i, buf, WXSIZEOF(buf), MF_BYPOSITION) )
             {
                 wxLogLastError(wxT("GetMenuString"));
 
                 continue;
             }
 
-            if ( wxStrcmp(buf, wxT("&Window")) == 0 )
+            if ( wxStrcmp(buf, _("&Window")) == 0 )
             {
-                RemoveMenu(hMenu, i, MF_BYPOSITION);
+                if ( !::RemoveMenu(hMenu, i, MF_BYPOSITION) )
+                {
+                    wxLogLastError(wxT("RemoveMenu"));
+                }
 
                 break;
             }
@@ -2294,30 +2360,45 @@ bool wxWindow::MSWCreate(int id,
         height1 = parent_rect.bottom - parent_rect.top;
     }
 
-    if ( x > -1 ) x1 = x;
-    if ( y > -1 ) y1 = y;
-    if ( width > -1 ) width1 = width;
-    if ( height > -1 ) height1 = height;
-
-    // Unfortunately this won't work in WIN16. Unless perhaps
-    // we define WS_EX_CONTROLPARENT ourselves?
-#ifndef __WIN16__
+    if ( x != -1 )
+        x1 = x;
+    if ( y != -1 )
+        y1 = y;
+    if ( width != -1 )
+        width1 = width;
+    if ( height != -1 )
+        height1 = height;
+
+    // unfortunately, setting WS_EX_CONTROLPARENT only for some windows in the
+    // hierarchy with several embedded panels (and not all of them) causes the
+    // program to hang during the next call to IsDialogMessage() due to the bug
+    // in this function (at least in Windows NT 4.0, it seems to work ok in
+    // Win2K)
+#if 0
     // if we have wxTAB_TRAVERSAL style, we want WS_EX_CONTROLPARENT or
     // IsDialogMessage() won't work for us
     if ( GetWindowStyleFlag() & wxTAB_TRAVERSAL )
     {
         extendedStyle |= WS_EX_CONTROLPARENT;
     }
-#endif
+#endif // 0
 
-    HWND hParent = (HWND)NULL;
-    if ( parent )
-        hParent = (HWND) parent->GetHWND();
+    HWND hParent = parent ? GetHwndOf(parent) : NULL;
 
     wxWndHook = this;
 
     if ( dialog_template )
     {
+        // for the dialogs without wxDIALOG_NO_PARENT style, use the top level
+        // app window as parent - this avoids creating modal dialogs without
+        // parent
+        if ( !hParent && !(GetWindowStyleFlag() & wxDIALOG_NO_PARENT) )
+        {
+            wxWindow *winTop = wxTheApp->GetTopWindow();
+            if ( winTop )
+                hParent = GetHwndOf(winTop);
+        }
+
         m_hWnd = (WXHWND)::CreateDialog(wxGetInstance(),
                                         dialog_template,
                                         hParent,
@@ -2325,12 +2406,44 @@ bool wxWindow::MSWCreate(int id,
 
         if ( m_hWnd == 0 )
         {
-            wxLogError(_("Can't find dummy dialog template!\n"
-                         "Check resource include path for finding wx.rc."));
+            wxLogError(_("Can't find dialog template '%s'!\nCheck resource include path for finding wx.rc."),
+                       dialog_template);
 
             return FALSE;
         }
 
+        if ( extendedStyle != 0 )
+        {
+            ::SetWindowLong(GetHwnd(), GWL_EXSTYLE, extendedStyle);
+            ::SetWindowPos(GetHwnd(), NULL, 0, 0, 0, 0,
+                           SWP_NOSIZE |
+                           SWP_NOMOVE |
+                           SWP_NOZORDER |
+                           SWP_NOACTIVATE);
+        }
+
+#if defined(__WIN95__)
+        // For some reason, the system menu is activated when we use the
+        // WS_EX_CONTEXTHELP style, so let's set a reasonable icon
+        if (extendedStyle & WS_EX_CONTEXTHELP)
+        {
+            wxFrame *winTop = wxDynamicCast(wxTheApp->GetTopWindow(), wxFrame);
+            if ( winTop )
+            {
+                wxIcon icon = winTop->GetIcon();
+                if ( icon.Ok() )
+                {
+                    ::SendMessage(GetHwnd(), WM_SETICON,
+                                  (WPARAM)TRUE,
+                                  (LPARAM)GetHiconOf(icon));
+                }
+            }
+        }
+#endif // __WIN95__
+
+
+        // JACS: is the following still necessary? The above seems to work.
+
         // ::SetWindowLong(GWL_EXSTYLE) doesn't work for the dialogs, so try
         // to take care of (at least some) extended style flags ourselves
         if ( extendedStyle & WS_EX_TOPMOST )
@@ -2348,11 +2461,15 @@ bool wxWindow::MSWCreate(int id,
             wxLogLastError(wxT("MoveWindow"));
         }
     }
-    else
+    else // creating a normal window, not a dialog
     {
         int controlId = 0;
         if ( style & WS_CHILD )
+          {
             controlId = id;
+            // all child windows should clip their siblings
+            // style |= /* WS_CLIPSIBLINGS */ ;
+          }
 
         wxString className(wclass);
         if ( GetWindowStyleFlag() & wxNO_FULL_REPAINT_ON_RESIZE )
@@ -2372,8 +2489,7 @@ bool wxWindow::MSWCreate(int id,
 
         if ( !m_hWnd )
         {
-            wxLogError(_("Can't create window of class %s!\n"
-                         "Possible Windows 3.x compatibility problem?"),
+            wxLogError(_("Can't create window of class %s!\nPossible Windows 3.x compatibility problem?"),
                        wclass);
 
             return FALSE;
@@ -2381,6 +2497,7 @@ bool wxWindow::MSWCreate(int id,
     }
 
     wxWndHook = NULL;
+
 #ifdef __WXDEBUG__
     wxNode* node = wxWinHandleList->Member(this);
     if (node)
@@ -2391,7 +2508,8 @@ bool wxWindow::MSWCreate(int id,
             wxLogError(wxT("A second HWND association is being added for the same window!"));
         }
     }
-#endif
+#endif // Debug
+
     wxAssociateWinWithHandle((HWND) m_hWnd, this);
 
     return TRUE;
@@ -2427,8 +2545,6 @@ bool wxWindow::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
         if ( child->MSWOnNotify(idCtrl, lParam, result) )
         {
             return TRUE;
-
-            break;
         }
 
         node = node->GetNext();
@@ -2635,10 +2751,13 @@ bool wxWindow::HandleDropFiles(WXWPARAM wParam)
     DragQueryPoint(hFilesInfo, (LPPOINT) &dropPoint);
 
     // Get the total number of files dropped
-    WORD gwFilesDropped = (WORD)DragQueryFile ((HDROP)hFilesInfo,
-        (UINT)-1,
-        (LPSTR)0,
-        (UINT)0);
+    WORD gwFilesDropped = (WORD)::DragQueryFile
+                            (
+                                (HDROP)hFilesInfo,
+                                (UINT)-1,
+                                (LPTSTR)0,
+                                (UINT)0
+                            );
 
     wxString *files = new wxString[gwFilesDropped];
     int wIndex;
@@ -2664,53 +2783,84 @@ bool wxWindow::HandleSetCursor(WXHWND hWnd,
                                short nHitTest,
                                int WXUNUSED(mouseMsg))
 {
-    // don't set cursor for other windows, only for this one: this prevents
-    // children of this window from getting the same cursor as the parent has
-    // (don't forget that this message is propagated by default up the window
-    // parent-child hierarchy)
-    if ( GetHWND() == hWnd )
+    // 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
+
+    if ( nHitTest != HTCLIENT )
     {
-        // don't set cursor when the mouse is not in the client part
-        if ( nHitTest == HTCLIENT || nHitTest == HTERROR )
+        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;
+#ifdef __WIN32__
+    if ( !::GetCursorPos(&pt) )
+    {
+        wxLogLastError(wxT("GetCursorPos"));
+    }
+#else
+    // In WIN16 it doesn't return a value.
+    ::GetCursorPos(&pt);
+#endif
+
+    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());
+    }
+
+    if ( !hcursor )
+    {
+        bool isBusy = wxIsBusy();
+
+        // the test for processedEvtSetCursor is here to prevent using m_cursor
+        // if the user code caught EVT_SET_CURSOR() and returned nothing from
+        // it - this is a way to say that our cursor shouldn't be used for this
+        // point
+        if ( !processedEvtSetCursor && m_cursor.Ok() )
         {
-            HCURSOR hcursor = 0;
-            if ( wxIsBusy() )
-            {
-                // from msw\utils.cpp
-                extern HCURSOR gs_wxBusyCursor;
+            hcursor = GetHcursorOf(m_cursor);
+        }
 
-                hcursor = gs_wxBusyCursor;
+        if ( !GetParent() )
+        {
+            if ( isBusy )
+            {
+                hcursor = wxGetCurrentBusyCursor();
             }
-            else
+            else if ( !hcursor )
             {
-                wxCursor *cursor = NULL;
-
-                if ( m_cursor.Ok() )
+                const wxCursor *cursor = wxGetGlobalCursor();
+                if ( cursor && cursor->Ok() )
                 {
-                    cursor = &m_cursor;
+                    hcursor = GetHcursorOf(*cursor);
                 }
-                else
-                {
-                    // from msw\data.cpp
-                    extern wxCursor *g_globalCursor;
-
-                    if ( g_globalCursor && g_globalCursor->Ok() )
-                        cursor = g_globalCursor;
-                }
-
-                if ( cursor )
-                    hcursor = (HCURSOR)cursor->GetHCURSOR();
             }
+        }
+    }
 
-            if ( hcursor )
-            {
-                ::SetCursor(hcursor);
+    if ( hcursor )
+    {
+        ::SetCursor(hcursor);
 
-                return TRUE;
-            }
-        }
+        // cursor set, stop here
+        return TRUE;
     }
 
+    // pass up the window chain
     return FALSE;
 }
 
@@ -2873,9 +3023,9 @@ bool wxWindow::HandlePaint()
 #ifdef __WIN32__
     HRGN hRegion = ::CreateRectRgn(0, 0, 0, 0); // Dummy call to get a handle
     if ( !hRegion )
-        wxLogLastError("CreateRectRgn");
+        wxLogLastError(wxT("CreateRectRgn"));
     if ( ::GetUpdateRgn(GetHwnd(), hRegion, FALSE) == ERROR )
-        wxLogLastError("GetUpdateRgn");
+        wxLogLastError(wxT("GetUpdateRgn"));
 
     m_updateRegion = wxRegion((WXHRGN) hRegion);
 #else
@@ -2893,6 +3043,16 @@ bool wxWindow::HandlePaint()
     return GetEventHandler()->ProcessEvent(event);
 }
 
+// Can be called from an application's OnPaint handler
+void wxWindow::OnPaint(wxPaintEvent& event)
+{
+    HDC hDC = (HDC) wxPaintDC::FindDCInCache((wxWindow*) event.GetEventObject());
+    if (hDC != 0)
+    {
+        MSWDefWindowProc(WM_PAINT, (WPARAM) hDC, 0);
+    }
+}
+
 bool wxWindow::HandleEraseBkgnd(WXHDC hdc)
 {
     // Prevents flicker when dragging
@@ -2926,7 +3086,7 @@ void wxWindow::OnEraseBackground(wxEraseEvent& event)
                               m_backgroundColour.Blue());
     HBRUSH hBrush = ::CreateSolidBrush(ref);
     if ( !hBrush )
-        wxLogLastError("CreateSolidBrush");
+        wxLogLastError(wxT("CreateSolidBrush"));
 
     HDC hdc = (HDC)event.GetDC()->GetHDC();
 
@@ -3006,6 +3166,25 @@ bool wxWindow::HandleGetMinMaxInfo(void *mmInfo)
     return rc;
 }
 
+// generate an artificial resize event
+/* FUNCTION IS NOW A MEMBER OF wxFrame - gt
+void wxWindow::SendSizeEvent()
+{
+    RECT r;
+#ifdef __WIN16__
+    ::GetWindowRect(GetHwnd(), &r);
+#else
+    if ( !::GetWindowRect(GetHwnd(), &r) )
+    {
+        wxLogLastError(_T("GetWindowRect"));
+    }
+#endif
+
+    (void)::PostMessage(GetHwnd(), WM_SIZE, SIZE_RESTORED,
+                        MAKELPARAM(r.right - r.left, r.bottom - r.top));
+}
+*/
+
 // ---------------------------------------------------------------------------
 // command messages
 // ---------------------------------------------------------------------------
@@ -3055,6 +3234,17 @@ bool wxWindow::HandleCommand(WXWORD id, WXWORD cmd, WXHWND control)
 
         return GetEventHandler()->ProcessEvent(event);
     }
+#if wxUSE_SPINCTRL
+    else
+    {
+        // the text ctrl which is logically part of wxSpinCtrl sends WM_COMMAND
+        // notifications to its parent which we want to reflect back to
+        // wxSpinCtrl
+        wxSpinCtrl *spin = wxSpinCtrl::GetSpinForTextCtrl(control);
+        if ( spin && spin->ProcessTextCommand(cmd, id) )
+            return TRUE;
+    }
+#endif // wxUSE_SPINCTRL
 
     return FALSE;
 }
@@ -3087,6 +3277,7 @@ void wxWindow::InitMouseEvent(wxMouseEvent& event, int x, int y, WXUINT flags)
     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) & 0x80000000) != 0;
     event.SetTimestamp(s_currentMsg.time);
     event.m_eventObject = this;
 
@@ -3167,8 +3358,8 @@ wxKeyEvent wxWindow::CreateKeyEvent(wxEventType evType,
 {
     wxKeyEvent event(evType);
     event.SetId(GetId());
-    event.m_shiftDown = IsShiftDown();
-    event.m_controlDown = IsCtrlDown();
+    event.m_shiftDown = wxIsShiftDown();
+    event.m_controlDown = wxIsCtrlDown();
     event.m_altDown = (HIWORD(lParam) & KF_ALTDOWN) == KF_ALTDOWN;
 
     event.m_eventObject = (wxWindow *)this; // const_cast
@@ -3416,11 +3607,34 @@ bool wxWindow::MSWOnScroll(int orientation, WXWORD wParam,
         break;
 
     case SB_THUMBPOSITION:
-        event.m_eventType = wxEVT_SCROLLWIN_THUMBRELEASE;
-        break;
-
     case SB_THUMBTRACK:
-        event.m_eventType = wxEVT_SCROLLWIN_THUMBTRACK;
+#ifdef __WIN32__
+        // under Win32, the scrollbar range and position are 32 bit integers,
+        // but WM_[HV]SCROLL only carry the low 16 bits of them, so we must
+        // explicitly query the scrollbar for the correct position (this must
+        // be done only for these two SB_ events as they are the only one
+        // carrying the scrollbar position)
+        {
+            SCROLLINFO scrollInfo;
+            wxZeroMemory(scrollInfo);
+            scrollInfo.cbSize = sizeof(SCROLLINFO);
+            scrollInfo.fMask = SIF_TRACKPOS;
+
+            if ( !::GetScrollInfo(GetHwnd(),
+                                  orientation == wxHORIZONTAL ? SB_HORZ
+                                                              : SB_VERT,
+                                  &scrollInfo) )
+            {
+                wxLogLastError(_T("GetScrollInfo"));
+            }
+
+            event.SetPosition(scrollInfo.nTrackPos);
+        }
+#endif // Win32
+
+        event.m_eventType = wParam == SB_THUMBPOSITION
+                                ? wxEVT_SCROLLWIN_THUMBRELEASE
+                                : wxEVT_SCROLLWIN_THUMBTRACK;
         break;
 
     default:
@@ -3468,80 +3682,82 @@ void wxGetCharSize(WXHWND wnd, int *x, int *y, const wxFont *the_font)
 // the key should be ignored by WM_KEYDOWN and processed by WM_CHAR instead.
 int wxCharCodeMSWToWX(int keySym)
 {
-    int id = 0;
+    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_RETURN:     id = WXK_RETURN; break;
-    case VK_SHIFT:      id = WXK_SHIFT; break;
-    case VK_CONTROL:    id = WXK_CONTROL; break;
-    case VK_MENU :      id = WXK_MENU; break;
-    case VK_PAUSE:      id = WXK_PAUSE; break;
-    case VK_SPACE:      id = WXK_SPACE; break;
-    case VK_ESCAPE:     id = WXK_ESCAPE; break;
-    case VK_PRIOR:      id = WXK_PRIOR; break;
-    case VK_NEXT :      id = WXK_NEXT; break;
-    case VK_END:        id = WXK_END; break;
-    case VK_HOME :      id = WXK_HOME; break;
-    case VK_LEFT :      id = WXK_LEFT; break;
-    case VK_UP:         id = WXK_UP; break;
-    case VK_RIGHT:      id = WXK_RIGHT; break;
-    case VK_DOWN :      id = WXK_DOWN; break;
-    case VK_SELECT:     id = WXK_SELECT; break;
-    case VK_PRINT:      id = WXK_PRINT; break;
-    case VK_EXECUTE:    id = WXK_EXECUTE; break;
-    case VK_INSERT:     id = WXK_INSERT; break;
-    case VK_DELETE:     id = WXK_DELETE; 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_MULTIPLY; break;
-    case VK_ADD:        id = WXK_ADD; break;
-    case VK_SUBTRACT:   id = WXK_SUBTRACT; break;
-    case VK_DECIMAL:    id = WXK_DECIMAL; break;
-    case VK_DIVIDE:     id = WXK_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;
-    default:
-        {
-            return 0;
-        }
+        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_RETURN:     id = WXK_RETURN; break;
+        case VK_SHIFT:      id = WXK_SHIFT; break;
+        case VK_CONTROL:    id = WXK_CONTROL; break;
+        case VK_MENU :      id = WXK_MENU; break;
+        case VK_PAUSE:      id = WXK_PAUSE; break;
+        case VK_SPACE:      id = WXK_SPACE; break;
+        case VK_ESCAPE:     id = WXK_ESCAPE; break;
+        case VK_PRIOR:      id = WXK_PRIOR; break;
+        case VK_NEXT :      id = WXK_NEXT; break;
+        case VK_END:        id = WXK_END; break;
+        case VK_HOME :      id = WXK_HOME; break;
+        case VK_LEFT :      id = WXK_LEFT; break;
+        case VK_UP:         id = WXK_UP; break;
+        case VK_RIGHT:      id = WXK_RIGHT; break;
+        case VK_DOWN :      id = WXK_DOWN; break;
+        case VK_SELECT:     id = WXK_SELECT; break;
+        case VK_PRINT:      id = WXK_PRINT; break;
+        case VK_EXECUTE:    id = WXK_EXECUTE; break;
+        case VK_INSERT:     id = WXK_INSERT; break;
+        case VK_DELETE:     id = WXK_DELETE; 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_MULTIPLY; break;
+        case 0xBB: // VK_OEM_PLUS
+        case VK_ADD:        id = WXK_ADD; break;
+        case 0xBD: // VK_OEM_MINUS
+        case VK_SUBTRACT:   id = WXK_SUBTRACT; break;
+        case 0xBE: // VK_OEM_PERIOD
+        case VK_DECIMAL:    id = WXK_DECIMAL; break;
+        case VK_DIVIDE:     id = WXK_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;
+        default:
+            id = 0;
     }
+
     return id;
 }
 
@@ -3722,8 +3938,8 @@ wxKeyboardHook(int nCode, WORD wParam, DWORD lParam)
 
             event.m_eventObject = NULL;
             event.m_keyCode = id;
-            event.m_shiftDown = IsShiftDown();
-            event.m_controlDown = IsCtrlDown();
+            event.m_shiftDown = wxIsShiftDown();
+            event.m_controlDown = wxIsCtrlDown();
             event.SetTimestamp(s_currentMsg.time);
 
             wxWindow *win = wxGetActiveWindow();
@@ -4175,9 +4391,9 @@ static void TranslateKbdEventToMouse(wxWindow *win, int *x, int *y, WPARAM *flag
     WPARAM& fwKeys = *flags;
 
     fwKeys = MK_RBUTTON;
-    if ( (::GetKeyState(VK_CONTROL) & 0x100) != 0 )
+    if ( wxIsCtrlDown() )
         fwKeys |= MK_CONTROL;
-    if ( (::GetKeyState(VK_SHIFT) & 0x100) != 0 )
+    if ( wxIsShiftDown() )
         fwKeys |= MK_SHIFT;
 
     // simulate right mouse button click
@@ -4187,3 +4403,70 @@ static void TranslateKbdEventToMouse(wxWindow *win, int *x, int *y, WPARAM *flag
 
     win->ScreenToClient(x, y);
 }
+
+static TEXTMETRIC wxGetTextMetrics(const wxWindow *win)
+{
+    // prepare the DC
+    TEXTMETRIC tm;
+    HWND hwnd = GetHwndOf(win);
+    HDC hdc = ::GetDC(hwnd);
+
+#if !wxDIALOG_UNIT_COMPATIBILITY
+    // and select the current font into it
+    HFONT hfont = GetHfontOf(win->GetFont());
+    if ( hfont )
+    {
+        hfont = (HFONT)::SelectObject(hdc, hfont);
+    }
+#endif
+
+    // finally retrieve the text metrics from it
+    GetTextMetrics(hdc, &tm);
+
+#if !wxDIALOG_UNIT_COMPATIBILITY
+    // and clean up
+    if ( hfont )
+    {
+        (void)::SelectObject(hdc, hfont);
+    }
+#endif
+
+    ::ReleaseDC(hwnd, hdc);
+
+    return tm;
+}
+
+// Find the wxWindow at the current mouse position, returning the mouse
+// position.
+wxWindow* wxFindWindowAtPointer(wxPoint& pt)
+{
+    return wxFindWindowAtPoint(wxGetMousePosition());
+}
+
+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;
+
+    // Try to find a window with a wxWindow associated with it
+    while (!win && (hWnd != 0))
+    {
+        hWnd = ::GetParent(hWnd);
+        win = wxFindWinFromHandle((WXHWND) hWnd) ;
+    }
+    return win;
+}
+
+// Get the current mouse position.
+wxPoint wxGetMousePosition()
+{
+    POINT pt;
+    GetCursorPos( & pt );
+    return wxPoint(pt.x, pt.y);
+}
+