]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/window.cpp
Fix broken and missing DataView interface items for Phoenix
[wxWidgets.git] / src / msw / window.cpp
index 8a34b50fa98a60d4127b676ab0a9957155690218..1289c4fcb845651b37b493dc0251667a06276c64 100644 (file)
@@ -81,6 +81,7 @@
 #include "wx/msw/private.h"
 #include "wx/msw/private/keyboard.h"
 #include "wx/msw/dcclient.h"
+#include "wx/private/textmeasure.h"
 
 #if wxUSE_TOOLTIPS
     #include "wx/tooltip.h"
     #include <windowsx.h>
 #endif
 
-#if !defined __WXWINCE__ && !defined NEED_PBT_H
-    #include <pbt.h>
-#endif
-
 #if defined(__WXWINCE__)
     #include "wx/msw/wince/missing.h"
 #ifdef __POCKETPC__
@@ -186,7 +183,7 @@ extern wxMenu *wxCurrentPopupMenu;
 // This is a hack used by the owner-drawn wxButton implementation to ensure
 // that the brush used for erasing its background is correctly aligned with the
 // control.
-extern wxWindowMSW *wxWindowBeingErased = NULL;
+wxWindowMSW *wxWindowBeingErased = NULL;
 #endif // wxUSE_UXTHEME
 
 namespace
@@ -321,20 +318,23 @@ static void EnsureParentHasControlParentStyle(wxWindow *parent)
 
 #endif // !__WXWINCE__
 
-#ifdef __WXWINCE__
-// On Windows CE, GetCursorPos can return an error, so use this function
-// instead
-bool GetCursorPosWinCE(POINT* pt)
+// GetCursorPos can return an error, so use this function
+// instead.
+// Error originally observed with WinCE, but later using Remote Desktop
+// to connect to XP.
+void wxGetCursorPosMSW(POINT* pt)
 {
     if (!GetCursorPos(pt))
     {
+#ifdef __WXWINCE__
+        wxLogLastError(wxT("GetCursorPos"));
+#endif
         DWORD pos = GetMessagePos();
-        pt->x = LOWORD(pos);
-        pt->y = HIWORD(pos);
+        // the coordinates may be negative in multi-monitor systems
+        pt->x = GET_X_LPARAM(pos);
+        pt->y = GET_Y_LPARAM(pos);
     }
-    return true;
 }
-#endif
 
 // ---------------------------------------------------------------------------
 // event tables
@@ -410,7 +410,7 @@ wxWindow *wxWindowMSW::FindItemByHWND(WXHWND hWnd, bool controlOnly) const
 
         if ( !controlOnly
 #if wxUSE_CONTROLS
-                || parent->IsKindOf(CLASSINFO(wxControl))
+                || wxDynamicCast(parent, wxControl)
 #endif // wxUSE_CONTROLS
            )
         {
@@ -671,6 +671,7 @@ wxWindowMSW::MSWShowWithEffect(bool show,
                                wxShowEffect effect,
                                unsigned timeout)
 {
+#if wxUSE_DYNLIB_CLASS
     if ( effect == wxSHOW_EFFECT_NONE )
         return Show(show);
 
@@ -767,6 +768,9 @@ wxWindowMSW::MSWShowWithEffect(bool show,
     }
 
     return true;
+#else    // wxUSE_DYNLIB_CLASS
+    return Show(show);
+#endif
 }
 
 // Raise the window to the top of the Z order
@@ -829,6 +833,7 @@ bool wxWindowMSW::SetFont(const wxFont& font)
 
     return true;
 }
+
 bool wxWindowMSW::SetCursor(const wxCursor& cursor)
 {
     if ( !wxWindowBase::SetCursor(cursor) )
@@ -838,7 +843,10 @@ bool wxWindowMSW::SetCursor(const wxCursor& cursor)
     }
 
     // don't "overwrite" busy cursor
-    if ( m_cursor.IsOk() && !wxIsBusy() )
+    if ( wxIsBusy() )
+        return true;
+
+    if ( m_cursor.IsOk() )
     {
         // normally we should change the cursor only if it's over this window
         // but we should do it always if we capture the mouse currently
@@ -848,11 +856,7 @@ bool wxWindowMSW::SetCursor(const wxCursor& cursor)
             HWND hWnd = GetHwnd();
 
             POINT point;
-#ifdef __WXWINCE__
-            ::GetCursorPosWinCE(&point);
-#else
-            ::GetCursorPos(&point);
-#endif
+            ::wxGetCursorPosMSW(&point);
 
             RECT rect = wxGetWindowRect(hWnd);
 
@@ -865,6 +869,22 @@ bool wxWindowMSW::SetCursor(const wxCursor& cursor)
         }
         //else: will be set later when the mouse enters this window
     }
+    else // Invalid cursor: this means reset to the default one.
+    {
+        // To revert to the correct cursor we need to find the window currently
+        // under the cursor and ask it to set its cursor itself as only it
+        // knows what it is.
+        POINT pt;
+        wxGetCursorPosMSW(&pt);
+
+        const wxWindowMSW* win = wxFindWindowAtPoint(wxPoint(pt.x, pt.y));
+        if ( !win )
+            win = this;
+
+        ::SendMessage(GetHwndOf(win), WM_SETCURSOR,
+                      (WPARAM)GetHwndOf(win),
+                      MAKELPARAM(HTCLIENT, WM_MOUSEMOVE));
+    }
 
     return true;
 }
@@ -1493,11 +1513,7 @@ bool wxWindowMSW::IsMouseInWindow() const
 {
     // get the mouse position
     POINT pt;
-#ifdef __WXWINCE__
-    ::GetCursorPosWinCE(&pt);
-#else
-    ::GetCursorPos(&pt);
-#endif
+    wxGetCursorPosMSW(&pt);
 
     // find the window which currently has the cursor and go up the window
     // chain until we find this window - or exhaust it
@@ -1787,6 +1803,15 @@ void wxWindowMSW::DoGetClientSize(int *x, int *y) const
         if ( y )
             *y = rect.bottom;
     }
+
+    // The size of the client window can't be negative but ::GetClientRect()
+    // can return negative size for an extremely small (1x1) window with
+    // borders so ensure that we correct it here as having negative sizes is
+    // completely unexpected.
+    if ( x && *x < 0 )
+        *x = 0;
+    if ( y && *y < 0 )
+        *y = 0;
 }
 
 void wxWindowMSW::DoGetPosition(int *x, int *y) const
@@ -2140,31 +2165,18 @@ void wxWindowMSW::DoGetTextExtent(const wxString& string,
                                   int *externalLeading,
                                   const wxFont *fontToUse) const
 {
-    wxASSERT_MSG( !fontToUse || fontToUse->IsOk(),
-                    wxT("invalid font in GetTextExtent()") );
-
-    HFONT hfontToUse;
-    if ( fontToUse )
-        hfontToUse = GetHfontOf(*fontToUse);
+    // ensure we work with a valid font
+    wxFont font;
+    if ( !fontToUse || !fontToUse->IsOk() )
+        font = GetFont();
     else
-        hfontToUse = GetHfontOf(GetFont());
-
-    WindowHDC hdc(GetHwnd());
-    SelectInHDC selectFont(hdc, hfontToUse);
+        font = *fontToUse;
 
-    SIZE sizeRect;
-    TEXTMETRIC tm;
-    ::GetTextExtentPoint32(hdc, string.wx_str(), string.length(), &sizeRect);
-    GetTextMetrics(hdc, &tm);
+    wxCHECK_RET( font.IsOk(), wxT("invalid font in GetTextExtent()") );
 
-    if ( x )
-        *x = sizeRect.cx;
-    if ( y )
-        *y = sizeRect.cy;
-    if ( descent )
-        *descent = tm.tmDescent;
-    if ( externalLeading )
-        *externalLeading = tm.tmExternalLeading;
+    const wxWindow* win = static_cast<const wxWindow*>(this);
+    wxTextMeasure txm(win, &font);
+    txm.GetTextExtent(string, x, y, descent, externalLeading);
 }
 
 // ---------------------------------------------------------------------------
@@ -2204,18 +2216,16 @@ bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y)
 {
     menu->UpdateUI();
 
+    wxPoint pt;
     if ( x == wxDefaultCoord && y == wxDefaultCoord )
     {
-        wxPoint mouse = ScreenToClient(wxGetMousePosition());
-        x = mouse.x; y = mouse.y;
+        pt = wxGetMousePosition();
+    }
+    else
+    {
+        pt = ClientToScreen(wxPoint(x, y));
     }
 
-    HWND hWnd = GetHwnd();
-    HMENU hMenu = GetHmenuOf(menu);
-    POINT point;
-    point.x = x;
-    point.y = y;
-    ::ClientToScreen(hWnd, &point);
 #if defined(__WXWINCE__)
     static const UINT flags = 0;
 #else // !__WXWINCE__
@@ -2233,7 +2243,7 @@ bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y)
     }
 #endif // __WXWINCE__/!__WXWINCE__
 
-    ::TrackPopupMenu(hMenu, flags, point.x, point.y, 0, hWnd, NULL);
+    ::TrackPopupMenu(GetHmenuOf(menu), flags, pt.x, pt.y, 0, GetHwnd(), NULL);
 
     // we need to do it right now as otherwise the events are never going to be
     // sent to wxCurrentPopupMenu from HandleCommand()
@@ -2372,8 +2382,6 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
                                 // emulate the button click
                                 btn = wxFindWinFromHandle(msg->hwnd);
                             }
-
-                            bProcess = false;
                         }
                         else // not a button itself, do we have default button?
                         {
@@ -2433,6 +2441,13 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg)
                             return true;
                         }
 
+                        // This "Return" key press won't be actually used for
+                        // navigation so don't generate wxNavigationKeyEvent
+                        // for it but still pass it to IsDialogMessage() as it
+                        // may handle it in some other way (e.g. by playing the
+                        // default error sound).
+                        bProcess = false;
+
 #endif // wxUSE_BUTTON
 
 #ifdef __WXWINCE__
@@ -2692,7 +2707,11 @@ LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM w
     return rc;
 }
 
-WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
+bool
+wxWindowMSW::MSWHandleMessage(WXLRESULT *result,
+                              WXUINT message,
+                              WXWPARAM wParam,
+                              WXLPARAM lParam)
 {
     // did we process the message?
     bool processed = false;
@@ -2871,9 +2890,13 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
 
 #if wxUSE_MOUSEWHEEL
         case WM_MOUSEWHEEL:
-            processed = HandleMouseWheel(wParam, lParam);
+            processed = HandleMouseWheel(wxMOUSE_WHEEL_VERTICAL, wParam, lParam);
             break;
-#endif
+
+        case WM_MOUSEHWHEEL:
+            processed = HandleMouseWheel(wxMOUSE_WHEEL_HORIZONTAL, wParam, lParam);
+            break;
+#endif // wxUSE_MOUSEWHEEL
 
         case WM_LBUTTONDOWN:
         case WM_LBUTTONUP:
@@ -2996,8 +3019,8 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
         case MM_JOY1BUTTONUP:
         case MM_JOY2BUTTONUP:
             processed = HandleJoystickEvent(message,
-                                            GET_X_LPARAM(lParam),
-                                            GET_Y_LPARAM(lParam),
+                                            LOWORD(lParam),
+                                            HIWORD(lParam),
                                             wParam);
             break;
 #endif // __WXMICROWIN__
@@ -3122,6 +3145,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
                     case VK_OEM_5:
                     case VK_OEM_6:
                     case VK_OEM_7:
+                    case VK_OEM_102:
                     case VK_OEM_PLUS:
                     case VK_OEM_COMMA:
                     case VK_OEM_MINUS:
@@ -3572,15 +3596,26 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l
     }
 
     if ( !processed )
+        return false;
+
+    *result = rc.result;
+
+    return true;
+}
+
+WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM lParam)
+{
+    WXLRESULT result;
+    if ( !MSWHandleMessage(&result, message, wParam, lParam) )
     {
 #if wxDEBUG_LEVEL >= 2
         wxLogTrace("winmsg", wxT("Forwarding %s to DefWindowProc."),
                    wxGetMessageName(message));
 #endif // wxDEBUG_LEVEL >= 2
-        rc.result = MSWDefWindowProc(message, wParam, lParam);
+        result = MSWDefWindowProc(message, wParam, lParam);
     }
 
-    return rc.result;
+    return result;
 }
 
 // ----------------------------------------------------------------------------
@@ -3718,8 +3753,8 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass,
     m_hWnd = (WXHWND)::CreateWindowEx
                        (
                         extendedStyle,
-                        className.wx_str(),
-                        title ? title : m_windowName.wx_str(),
+                        className.t_str(),
+                        title ? title : m_windowName.t_str(),
                         style,
                         x, y, w, h,
                         (HWND)MSWGetParent(),
@@ -3839,7 +3874,7 @@ bool wxWindowMSW::HandleTooltipNotify(WXUINT code,
                     (
                         CP_ACP,
                         0,                      // no flags
-                        ttip.wx_str(),
+                        ttip.t_str(),
                         tipLength,
                         buf,
                         WXSIZEOF(buf) - 1
@@ -4153,14 +4188,7 @@ bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd),
         // first ask the user code - it may wish to set the cursor in some very
         // specific way (for example, depending on the current position)
         POINT pt;
-#ifdef __WXWINCE__
-        if ( !::GetCursorPosWinCE(&pt))
-#else
-        if ( !::GetCursorPos(&pt) )
-#endif
-        {
-            wxLogLastError(wxT("GetCursorPos"));
-        }
+        wxGetCursorPosMSW(&pt);
 
         int x = pt.x,
             y = pt.y;
@@ -4788,6 +4816,8 @@ bool wxWindowMSW::HandlePaint()
     // be called from inside the event handlers called above)
     m_updateRegion.Clear();
 
+    wxPaintDCImpl::EndPaint((wxWindow *)this);
+
     return processed;
 }
 
@@ -4807,6 +4837,16 @@ void wxWindowMSW::OnPaint(wxPaintEvent& event)
 
 bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc)
 {
+    if ( IsBeingDeleted() )
+    {
+        // We can get WM_ERASEBKGND after starting the destruction of our top
+        // level parent. Handling it in this case is unnecessary and can be
+        // actually harmful as e.g. wxStaticBox::GetClientSize() doesn't work
+        // without a valid TLW parent (because it uses dialog units internally
+        // which use the dialog font), so just don't do anything then.
+        return false;
+    }
+
     switch ( GetBackgroundStyle() )
     {
         case wxBG_STYLE_ERASE:
@@ -5519,7 +5559,9 @@ bool wxWindowMSW::HandleMouseMove(int x, int y, WXUINT flags)
 }
 
 
-bool wxWindowMSW::HandleMouseWheel(WXWPARAM wParam, WXLPARAM lParam)
+bool
+wxWindowMSW::HandleMouseWheel(wxMouseWheelAxis axis,
+                              WXWPARAM wParam, WXLPARAM lParam)
 {
 #if wxUSE_MOUSEWHEEL
     // notice that WM_MOUSEWHEEL position is in screen coords (as it's
@@ -5532,6 +5574,7 @@ bool wxWindowMSW::HandleMouseWheel(WXWPARAM wParam, WXLPARAM lParam)
     InitMouseEvent(event, pt.x, pt.y, LOWORD(wParam));
     event.m_wheelRotation = (short)HIWORD(wParam);
     event.m_wheelDelta = WHEEL_DELTA;
+    event.m_wheelAxis = axis;
 
     static int s_linesPerRotation = -1;
     if ( s_linesPerRotation == -1 )
@@ -5577,14 +5620,7 @@ void wxWindowMSW::GenerateMouseLeave()
         state |= MK_RBUTTON;
 
     POINT pt;
-#ifdef __WXWINCE__
-    if ( !::GetCursorPosWinCE(&pt) )
-#else
-    if ( !::GetCursorPos(&pt) )
-#endif
-    {
-        wxLogLastError(wxT("GetCursorPos"));
-    }
+    wxGetCursorPosMSW(&pt);
 
     // we need to have client coordinates here for symmetry with
     // wxEVT_ENTER_WINDOW
@@ -5636,21 +5672,6 @@ MSWInitAnyKeyEvent(wxKeyEvent& event,
 #ifndef __WXWINCE__
     event.SetTimestamp(::GetMessageTime());
 #endif
-
-    // Event coordinates must be in window client coordinates system which
-    // doesn't make sense if there is no window.
-    //
-    // We could use screen coordinates for such events but this would make the
-    // logic of the event handlers more complicated: you'd need to test for the
-    // event object and interpret the coordinates differently according to
-    // whether it's NULL or not so unless somebody really asks for this let's
-    // just avoid the issue.
-    if ( win )
-    {
-        const wxPoint mousePos = win->ScreenToClient(wxGetMousePosition());
-        event.m_x = mousePos.x;
-        event.m_y = mousePos.y;
-    }
 }
 
 } // anonymous namespace
@@ -5769,9 +5790,7 @@ int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel),
 #ifndef __WXWINCE__
     const HMENU hmenu = (HMENU)lParam;
 
-    MENUITEMINFO mii;
-    wxZeroMemory(mii);
-    mii.cbSize = sizeof(MENUITEMINFO);
+    WinStruct<MENUITEMINFO> mii;
 
     // we could use MIIM_FTYPE here as we only need to know if the item is
     // ownerdrawn or not and not dwTypeData which MIIM_TYPE also returns, but
@@ -5796,7 +5815,7 @@ int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel),
                 wxMenuItem *item = (wxMenuItem*)mii.dwItemData;
 
                 const wxString label(item->GetItemLabel());
-                const wxChar *p = wxStrchr(label.wx_str(), wxT('&'));
+                const wxChar *p = wxStrchr(label.t_str(), wxT('&'));
                 while ( p++ )
                 {
                     if ( *p == wxT('&') )
@@ -5925,7 +5944,10 @@ bool wxWindowMSW::HandleJoystickEvent(WXUINT msg, int x, int y, WXUINT flags)
     }
 
     wxJoystickEvent event(eventType, buttons, joystick, change);
-    event.SetPosition(wxPoint(x, y));
+    if ( eventType == wxEVT_JOY_ZMOVE )
+        event.SetZPosition(x);
+    else
+        event.SetPosition(wxPoint(x, y));
     event.SetEventObject(this);
 
     return HandleWindowEvent(event);
@@ -6210,6 +6232,7 @@ int VKToWX(WXWORD vk, WXLPARAM lParam, wchar_t *uc)
         case VK_OEM_5:
         case VK_OEM_6:
         case VK_OEM_7:
+        case VK_OEM_102:
             // MapVirtualKey() returns 0 if it fails to convert the virtual
             // key which nicely corresponds to our WXK_NONE.
             wxk = ::MapVirtualKey(vk, MAPVK_VK_TO_CHAR);
@@ -6288,6 +6311,9 @@ int VKToWX(WXWORD vk, WXLPARAM lParam, wchar_t *uc)
             // don't use ChooseNormalOrExtended() here as the keys are reversed
             // here: numpad enter is the extended one
             wxk = HIWORD(lParam) & KF_EXTENDED ? WXK_NUMPAD_ENTER : WXK_RETURN;
+
+            if ( uc )
+                *uc = WXK_RETURN;
             break;
 
         default:
@@ -6470,7 +6496,7 @@ wxMouseState wxGetMouseState()
 {
     wxMouseState ms;
     POINT pt;
-    GetCursorPos( &pt );
+    wxGetCursorPosMSW(&pt);
 
     ms.SetX(pt.x);
     ms.SetY(pt.y);
@@ -6593,7 +6619,14 @@ wxKeyboardHook(int nCode, WORD wParam, DWORD lParam)
 #endif // wxUSE_UNICODE
                     )
             {
-                const wxWindow * const win = wxGetActiveWindow();
+                wxWindow const* win = wxWindow::DoFindFocus();
+                if ( !win )
+                {
+                    // Even if the focus got lost somehow, still send the event
+                    // to the top level parent to allow a wxDialog to always
+                    // close on Escape.
+                    win = wxGetActiveWindow();
+                }
 
                 wxKeyEvent event(wxEVT_CHAR_HOOK);
                 MSWInitAnyKeyEvent(event, wParam, lParam, win);
@@ -6608,8 +6641,11 @@ wxKeyboardHook(int nCode, WORD wParam, DWORD lParam)
 
                 if ( handler && handler->ProcessEvent(event) )
                 {
-                    // processed
-                    return 1;
+                    if ( !event.IsNextEventAllowed() )
+                    {
+                        // Stop processing of this event.
+                        return 1;
+                    }
                 }
             }
         }
@@ -7165,6 +7201,26 @@ wxWindow* wxFindWindowAtPoint(const wxPoint& pt)
     pt2.y = pt.y;
 
     HWND hWnd = ::WindowFromPoint(pt2);
+    if ( hWnd )
+    {
+        // WindowFromPoint() ignores the disabled children but we're supposed
+        // to take them into account, so check if we have a child at this
+        // coordinate using ChildWindowFromPointEx().
+        for ( ;; )
+        {
+            pt2.x = pt.x;
+            pt2.y = pt.y;
+            ::ScreenToClient(hWnd, &pt2);
+            HWND child = ::ChildWindowFromPointEx(hWnd, pt2, CWP_SKIPINVISIBLE);
+            if ( child == hWnd || !child )
+                break;
+
+            // ChildWindowFromPointEx() only examines the immediate children
+            // but we want to get the deepest (top in Z-order) one, so continue
+            // iterating for as long as it finds anything.
+            hWnd = child;
+        }
+    }
 
     return wxGetWindowFromHWND((WXHWND)hWnd);
 }
@@ -7173,11 +7229,7 @@ wxWindow* wxFindWindowAtPoint(const wxPoint& pt)
 wxPoint wxGetMousePosition()
 {
     POINT pt;
-#ifdef __WXWINCE__
-    GetCursorPosWinCE(&pt);
-#else
-    GetCursorPos( & pt );
-#endif
+    wxGetCursorPosMSW(&pt);
 
     return wxPoint(pt.x, pt.y);
 }
@@ -7335,7 +7387,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxIdleWakeUpModule, wxModule)
 #if wxUSE_STATBOX
 static void wxAdjustZOrder(wxWindow* parent)
 {
-    if (parent->IsKindOf(CLASSINFO(wxStaticBox)))
+    if (wxDynamicCast(parent, wxStaticBox))
     {
         // Set the z-order correctly
         SetWindowPos((HWND) parent->GetHWND(), HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);