X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/1afe4f9b47b9ee020cc21e12ed603409f60a59dc..4e15d1caa03346c126015019c1fdf093033ef40b:/src/msw/window.cpp diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 0b1f0d3a3a..1289c4fcb8 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -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" @@ -113,10 +114,6 @@ #include #endif -#if !defined __WXWINCE__ && !defined NEED_PBT_H - #include -#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.Ok() && !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->Ok(), - 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(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; @@ -4181,7 +4209,7 @@ bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd), // 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() ) + if ( !processedEvtSetCursor && m_cursor.IsOk() ) { hcursor = GetHcursorOf(m_cursor); } @@ -4189,7 +4217,7 @@ bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd), if ( !hcursor && !GetParent() ) { const wxCursor *cursor = wxGetGlobalCursor(); - if ( cursor && cursor->Ok() ) + if ( cursor && cursor->IsOk() ) { hcursor = GetHcursorOf(*cursor); } @@ -4626,7 +4654,7 @@ extern wxCOLORMAP *wxGetStdColourMap() // to. wxLogNull logNo; // suppress error if we couldn't load the bitmap wxBitmap stdColourBitmap(wxT("wxBITMAP_STD_COLOURS")); - if ( stdColourBitmap.Ok() ) + if ( stdColourBitmap.IsOk() ) { // the pixels in the bitmap must correspond to wxSTD_COL_XXX! wxASSERT_MSG( stdColourBitmap.GetWidth() == wxSTD_COL_MAX, @@ -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 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);