X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/473d0f930e0a6e0dd11f2965ef46444e1589ecdb..dd44c130144ad153bf67121a94b23a615db409f5:/src/msw/window.cpp diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 31c9f5e62e..a08d1fa2ab 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -4,7 +4,6 @@ // Author: Julian Smart // Modified by: VZ on 13.05.99: no more Default(), MSWOnXXX() reorganisation // Created: 04/01/98 -// RCS-ID: $Id$ // Copyright: (c) Julian Smart // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -60,6 +59,7 @@ #include "wx/hashmap.h" #include "wx/evtloop.h" #include "wx/power.h" +#include "wx/scopeguard.h" #include "wx/sysopt.h" #if wxUSE_DRAG_AND_DROP @@ -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 @@ -244,6 +241,9 @@ EraseBgHooks gs_eraseBgHooks; // needed. int gs_modalEntryWindowCount = 0; +// Indicates whether we are currently processing WM_CAPTURECHANGED message. +bool gs_insideCaptureChanged = false; + } // anonymous namespace // --------------------------------------------------------------------------- @@ -321,20 +321,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 +413,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 +674,7 @@ wxWindowMSW::MSWShowWithEffect(bool show, wxShowEffect effect, unsigned timeout) { +#if wxUSE_DYNLIB_CLASS if ( effect == wxSHOW_EFFECT_NONE ) return Show(show); @@ -767,6 +771,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 @@ -801,6 +808,13 @@ void wxWindowMSW::DoReleaseMouse() /* static */ wxWindow *wxWindowBase::GetCapture() { + // When we receive WM_CAPTURECHANGED message, ::GetCapture() still returns + // the HWND that is losing the mouse capture. But as we must not release + // the capture for it (it's going to happen anyhow), pretend that there is + // no capture any more. + if ( gs_insideCaptureChanged ) + return NULL; + HWND hwnd = ::GetCapture(); return hwnd ? wxFindWinFromHandle(hwnd) : NULL; } @@ -829,6 +843,7 @@ bool wxWindowMSW::SetFont(const wxFont& font) return true; } + bool wxWindowMSW::SetCursor(const wxCursor& cursor) { if ( !wxWindowBase::SetCursor(cursor) ) @@ -838,7 +853,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 +866,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 +879,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; } @@ -1170,6 +1200,11 @@ void wxWindowMSW::SubclassWin(WXHWND hWnd) if ( !wxCheckWindowWndProc(hWnd, (WXFARPROC)wxWndProc) ) { wxSetWindowProc(hwnd, wxWndProc); + + // If the window didn't use our window proc during its creation, the + // code in HandleCreate() hasn't been executed, so do it here. + if ( wxHasWindowExStyle(this, WS_EX_CONTROLPARENT) ) + EnsureParentHasControlParentStyle(GetParent()); } else { @@ -1410,7 +1445,7 @@ WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const // it doesn't seem useful to use WS_CLIPSIBLINGS here as we officially // don't support overlapping windows and it only makes sense for them and, // presumably, gives the system some extra work (to manage more clipping - // regions), so avoid it alltogether + // regions), so avoid it altogether if ( flags & wxVSCROLL ) @@ -1493,11 +1528,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 @@ -2149,31 +2180,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()); + font = *fontToUse; - WindowHDC hdc(GetHwnd()); - SelectInHDC selectFont(hdc, hfontToUse); - - 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); } // --------------------------------------------------------------------------- @@ -2285,7 +2303,12 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) { // wxUniversal implements tab traversal itself #ifndef __WXUNIVERSAL__ - if ( m_hWnd != 0 && (GetWindowStyleFlag() & wxTAB_TRAVERSAL) ) + // Notice that we check for WS_EX_CONTROLPARENT and not wxTAB_TRAVERSAL + // here. While usually they are both set or both unset, doing it like this + // also works if there is ever a bug that results in wxTAB_TRAVERSAL being + // set but not WS_EX_CONTROLPARENT as we must not call IsDialogMessage() in + // this case, it would simply hang (see #15458). + if ( m_hWnd != 0 && (wxGetWindowExStyle(this) & WS_EX_CONTROLPARENT) ) { // intercept dialog navigation keys MSG *msg = (MSG *)pMsg; @@ -2379,8 +2402,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? { @@ -2440,6 +2461,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__ @@ -2699,7 +2727,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; @@ -2878,9 +2910,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: @@ -3003,8 +3039,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__ @@ -3129,6 +3165,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: @@ -3416,26 +3453,31 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l #if !defined(__WXWINCE__) case WM_CONTEXTMENU: { - // we don't convert from screen to client coordinates as - // the event may be handled by a parent window - wxPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); - - wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt); - - // we could have got an event from our child, reflect it back - // to it if this is the case - wxWindowMSW *win = NULL; + // Ignore the events that are propagated from a child window by + // DefWindowProc(): as wxContextMenuEvent is already propagated + // upwards the window hierarchy by us, not doing this would + // result in duplicate events being sent. WXHWND hWnd = (WXHWND)wParam; if ( hWnd != m_hWnd ) { - win = FindItemByHWND(hWnd); + wxWindowMSW *win = FindItemByHWND(hWnd); + if ( win && IsDescendant(win) ) + { + // We had already generated wxContextMenuEvent when we + // got WM_CONTEXTMENU for that window. + processed = true; + break; + } } - if ( !win ) - win = this; + // we don't convert from screen to client coordinates as + // the event may be handled by a parent window + wxPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); - evtCtx.SetEventObject(win); - processed = win->HandleWindowEvent(evtCtx); + wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt); + evtCtx.SetEventObject(this); + + processed = HandleWindowEvent(evtCtx); } break; #endif @@ -3579,15 +3621,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; } // ---------------------------------------------------------------------------- @@ -3725,8 +3778,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(), @@ -3846,7 +3899,7 @@ bool wxWindowMSW::HandleTooltipNotify(WXUINT code, ( CP_ACP, 0, // no flags - ttip.wx_str(), + ttip.t_str(), tipLength, buf, WXSIZEOF(buf) - 1 @@ -4160,14 +4213,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; @@ -4519,6 +4565,12 @@ bool wxWindowMSW::HandlePaletteChanged(WXHWND hWndPalChange) bool wxWindowMSW::HandleCaptureChanged(WXHWND hWndGainedCapture) { + // Ensure that wxWindow::GetCapture() returns NULL if called from the event + // handlers invoked below. This is necessary to avoid wrongly calling + // ReleaseMouse() when we're already losing the mouse capture anyhow. + gs_insideCaptureChanged = true; + wxON_BLOCK_EXIT_SET(gs_insideCaptureChanged, false); + // notify windows on the capture stack about lost capture // (see http://sourceforge.net/tracker/index.php?func=detail&aid=1153662&group_id=9863&atid=109863): wxWindowBase::NotifyCaptureLost(); @@ -4795,6 +4847,8 @@ bool wxWindowMSW::HandlePaint() // be called from inside the event handlers called above) m_updateRegion.Clear(); + wxPaintDCImpl::EndPaint((wxWindow *)this); + return processed; } @@ -4814,6 +4868,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: @@ -4926,7 +4990,11 @@ wxWindowMSW::MSWGetBgBrushForChild(WXHDC hDC, wxWindowMSW *child) ::MapWindowPoints(NULL, GetHwnd(), (POINT *)&rc, 1); - if ( !::SetBrushOrgEx((HDC)hDC, -rc.left, -rc.top, NULL) ) + int x = rc.left, + y = rc.top; + MSWAdjustBrushOrg(&x, &y); + + if ( !::SetBrushOrgEx((HDC)hDC, -x, -y, NULL) ) { wxLogLastError(wxT("SetBrushOrgEx(bg brush)")); } @@ -5066,11 +5134,9 @@ bool wxWindowMSW::HandleExitSizeMove() return HandleWindowEvent(event); } -bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam) +bool wxWindowMSW::BeginRepositioningChildren() { #if wxUSE_DEFERRED_SIZING - // when we resize this window, its children are probably going to be - // repositioned as well, prepare to use DeferWindowPos() for them int numChildren = 0; for ( HWND child = ::GetWindow(GetHwndOf(this), GW_CHILD); child; @@ -5079,23 +5145,60 @@ bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam) numChildren ++; } + // Nothing is gained by deferring the repositioning of a single child. + if ( numChildren < 2 ) + return false; + // Protect against valid m_hDWP being overwritten - bool useDefer = false; + if ( m_hDWP ) + return false; - if ( numChildren > 1 ) + m_hDWP = (WXHANDLE)::BeginDeferWindowPos(numChildren); + if ( !m_hDWP ) { - if (!m_hDWP) - { - m_hDWP = (WXHANDLE)::BeginDeferWindowPos(numChildren); - if ( !m_hDWP ) - { - wxLogLastError(wxT("BeginDeferWindowPos")); - } - if (m_hDWP) - useDefer = true; - } + wxLogLastError(wxT("BeginDeferWindowPos")); + return false; } + + // Return true to indicate that EndDeferWindowPos() should be called. + return true; #endif // wxUSE_DEFERRED_SIZING +} + +void wxWindowMSW::EndRepositioningChildren() +{ +#if wxUSE_DEFERRED_SIZING + wxASSERT_MSG( m_hDWP, wxS("Shouldn't be called") ); + + // reset m_hDWP to NULL so that child windows don't try to use our + // m_hDWP after we call EndDeferWindowPos() on it (this shouldn't + // happen anyhow normally but who knows what weird flow of control we + // may have depending on what the users EVT_SIZE handler does...) + HDWP hDWP = (HDWP)m_hDWP; + m_hDWP = NULL; + + // do put all child controls in place at once + if ( !::EndDeferWindowPos(hDWP) ) + { + wxLogLastError(wxT("EndDeferWindowPos")); + } + + // Reset our children's pending pos/size values. + for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + wxWindowMSW * const child = node->GetData(); + child->MSWEndDeferWindowPos(); + } +#endif // wxUSE_DEFERRED_SIZING +} + +bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam) +{ + // when we resize this window, its children are probably going to be + // repositioned as well, prepare to use DeferWindowPos() for them + ChildrenRepositioningGuard repositionGuard(this); // update this window size bool processed = false; @@ -5128,34 +5231,6 @@ bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam) processed = HandleWindowEvent(event); } -#if wxUSE_DEFERRED_SIZING - // and finally change the positions of all child windows at once - if ( useDefer && m_hDWP ) - { - // reset m_hDWP to NULL so that child windows don't try to use our - // m_hDWP after we call EndDeferWindowPos() on it (this shouldn't - // happen anyhow normally but who knows what weird flow of control we - // may have depending on what the users EVT_SIZE handler does...) - HDWP hDWP = (HDWP)m_hDWP; - m_hDWP = NULL; - - // do put all child controls in place at once - if ( !::EndDeferWindowPos(hDWP) ) - { - wxLogLastError(wxT("EndDeferWindowPos")); - } - - // Reset our children's pending pos/size values. - for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); - node; - node = node->GetNext() ) - { - wxWindowMSW * const child = node->GetData(); - child->MSWEndDeferWindowPos(); - } - } -#endif // wxUSE_DEFERRED_SIZING - return processed; } @@ -5254,10 +5329,10 @@ bool wxWindowMSW::HandleCommand(WXWORD id_, WXWORD cmd, WXHWND control) // the messages sent from the in-place edit control used by the treectrl // for label editing have id == 0, but they should _not_ be treated as menu // messages (they are EN_XXX ones, in fact) so don't translate anything - // coming from a control to wxEVT_COMMAND_MENU_SELECTED + // coming from a control to wxEVT_MENU if ( !control ) { - wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, id); + wxCommandEvent event(wxEVT_MENU, id); event.SetEventObject(this); event.SetInt(id); @@ -5418,7 +5493,7 @@ bool wxWindowMSW::HandleMouseEvent(WXUINT msg, int x, int y, WXUINT flags) }; #ifdef wxHAS_XBUTTON - // the same messages are used for both auxillary mouse buttons so we need + // the same messages are used for both auxiliary mouse buttons so we need // to adjust the index manually switch ( msg ) { @@ -5526,7 +5601,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 @@ -5539,6 +5616,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 ) @@ -5554,7 +5632,20 @@ bool wxWindowMSW::HandleMouseWheel(WXWPARAM wParam, WXLPARAM lParam) } } + static int s_columnsPerRotation = -1; + if ( s_columnsPerRotation == -1 ) + { + if ( !::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, + &s_columnsPerRotation, 0)) + { + // this setting is not supported on Windows 2000/XP, so use the value of 1 + // http://msdn.microsoft.com/en-us/library/ms997498.aspx + s_columnsPerRotation = 1; + } + } + event.m_linesPerAction = s_linesPerRotation; + event.m_columnsPerAction = s_columnsPerRotation; return HandleWindowEvent(event); #else // !wxUSE_MOUSEWHEEL @@ -5584,14 +5675,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 @@ -5643,21 +5727,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 @@ -5776,9 +5845,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 @@ -5803,7 +5870,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('&') ) @@ -5843,9 +5910,9 @@ int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel), bool wxWindowMSW::HandleClipboardEvent(WXUINT nMsg) { - const wxEventType type = nMsg == WM_CUT ? wxEVT_COMMAND_TEXT_CUT - : nMsg == WM_COPY ? wxEVT_COMMAND_TEXT_COPY - : /* nMsg == WM_PASTE */ wxEVT_COMMAND_TEXT_PASTE; + const wxEventType type = nMsg == WM_CUT ? wxEVT_TEXT_CUT + : nMsg == WM_COPY ? wxEVT_TEXT_COPY + : /* nMsg == WM_PASTE */ wxEVT_TEXT_PASTE; wxClipboardTextEvent evt(type, GetId()); evt.SetEventObject(this); @@ -5932,7 +5999,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); @@ -6217,6 +6287,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); @@ -6289,12 +6360,18 @@ int VKToWX(WXWORD vk, WXLPARAM lParam, wchar_t *uc) case VK_DELETE: wxk = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DELETE, WXK_DELETE); + + if ( uc ) + *uc = WXK_DELETE; break; case VK_RETURN: // 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: @@ -6477,7 +6554,7 @@ wxMouseState wxGetMouseState() { wxMouseState ms; POINT pt; - GetCursorPos( &pt ); + wxGetCursorPosMSW(&pt); ms.SetX(pt.x); ms.SetY(pt.y); @@ -6580,7 +6657,7 @@ wxKeyboardHook(int nCode, WORD wParam, DWORD lParam) DWORD hiWord = HIWORD(lParam); if ( nCode != HC_NOREMOVE && ((hiWord & KF_UP) == 0) ) { - wchar_t uc; + wchar_t uc = 0; int id = wxMSWKeyboard::VKToWX(wParam, lParam, &uc); // Don't intercept keyboard entry (notably Escape) if a modal window @@ -6600,7 +6677,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); @@ -6615,8 +6699,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; + } } } } @@ -7172,6 +7259,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); } @@ -7180,11 +7287,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); } @@ -7254,8 +7357,6 @@ bool wxWindowMSW::UnregisterHotKey(int hotkeyId) return true; } -#if wxUSE_ACCEL - bool wxWindowMSW::HandleHotKey(WXWPARAM wParam, WXLPARAM lParam) { int win_modifiers = LOWORD(lParam); @@ -7270,8 +7371,6 @@ bool wxWindowMSW::HandleHotKey(WXWPARAM wParam, WXLPARAM lParam) return HandleWindowEvent(event); } -#endif // wxUSE_ACCEL - #endif // wxUSE_HOTKEY // Not tested under WinCE @@ -7342,7 +7441,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);