X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/4a712ba3cfe27e8d39ee8fe8691ff67d1c96cb43..fe1f34f82e583289d77764525a556b0ffcc68994:/src/msw/window.cpp diff --git a/src/msw/window.cpp b/src/msw/window.cpp index e01ee082b2..88f2202250 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -1,6 +1,6 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: src/msw/windows.cpp -// Purpose: wxWindow +// Name: src/msw/window.cpp +// Purpose: wxWindowMSW // Author: Julian Smart // Modified by: VZ on 13.05.99: no more Default(), MSWOnXXX() reorganisation // Created: 04/01/98 @@ -17,10 +17,6 @@ // headers // --------------------------------------------------------------------------- -#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) - #pragma implementation "window.h" -#endif - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -127,6 +123,14 @@ // by setting this to 0 (in the future this should be removed completely) #define USE_DEFERRED_SIZING 1 +// set this to 1 to filter out duplicate mouse events, e.g. mouse move events +// when mouse position didnd't change +#ifdef __WXWINCE__ + #define wxUSE_MOUSEEVENT_HACK 0 +#else + #define wxUSE_MOUSEEVENT_HACK 1 +#endif + // --------------------------------------------------------------------------- // global variables // --------------------------------------------------------------------------- @@ -145,6 +149,18 @@ extern const wxChar *wxCanvasClassName; // wxGetStdColourMap() and wxWindow::OnSysColourChanged() (FIXME-MT) static bool gs_hasStdCmap = false; +// last mouse event information we need to filter out the duplicates +#if wxUSE_MOUSEEVENT_HACK +static struct MouseEventInfoDummy +{ + // mouse position (in screen coordinates) + wxPoint pos; + + // last mouse event type + wxEventType type; +} gs_lastMouseEvent; +#endif // wxUSE_MOUSEEVENT_HACK + // --------------------------------------------------------------------------- // private functions // --------------------------------------------------------------------------- @@ -165,8 +181,10 @@ wxWindow *wxFindWinFromHandle(WXHWND hWnd); // get the text metrics for the current font static TEXTMETRIC wxGetTextMetrics(const wxWindowMSW *win); +#ifdef __WXWINCE__ // find the window for the mouse event at the specified position -static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y); //TW:REQ:Univ +static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y); +#endif // __WXWINCE__ // wrapper around BringWindowToTop() API static inline void wxBringWindowToTop(HWND hwnd) @@ -202,7 +220,7 @@ static void EnsureParentHasControlParentStyle(wxWindow *parent) get back to the initial (focused) window: as we do have this style, GetNextDlgTabItem() will leave this window and continue in its parent, but if the parent doesn't have it, it wouldn't recurse inside it later - on and so wouldn't have a chance of getting back to this window neither. + on and so wouldn't have a chance of getting back to this window either. */ while ( parent && !parent->IsTopLevel() ) { @@ -376,7 +394,7 @@ wxWindow *wxWindowMSW::FindItem(long id) const wxControl *item = wxDynamicCastThis(wxControl); if ( item ) { - // is it we or one of our "internal" children? + // is it us or one of our "internal" children? if ( item->GetId() == id #ifndef __WXUNIVERSAL__ || (item->GetSubcontrols().Index(id) != wxNOT_FOUND) @@ -464,12 +482,6 @@ void wxWindowMSW::Init() m_xThumbSize = 0; m_yThumbSize = 0; -#if wxUSE_MOUSEEVENT_HACK - m_lastMouseX = - m_lastMouseY = -1; - m_lastMouseEvent = -1; -#endif // wxUSE_MOUSEEVENT_HACK - m_pendingPosition = wxDefaultPosition; m_pendingSize = wxDefaultSize; } @@ -501,7 +513,7 @@ wxWindowMSW::~wxWindowMSW() #endif // __WXUNIVERSAL__ // VS: destroy children first and _then_ detach *this from its parent. - // If we'd do it the other way around, children wouldn't be able + // If we did it the other way around, children wouldn't be able // find their parent frame (see above). DestroyChildren(); @@ -653,7 +665,7 @@ bool wxWindowMSW::Enable(bool enable) if ( enable ) { - // enable the child back unless it had been disabled before us + // re-enable the child unless it had been disabled before us if ( !m_childrenDisabled || !m_childrenDisabled->Find(child) ) child->Enable(); } @@ -692,12 +704,18 @@ bool wxWindowMSW::Show(bool show) return false; HWND hWnd = GetHwnd(); - int cshow = show ? SW_SHOW : SW_HIDE; - ::ShowWindow(hWnd, cshow); - if ( show && IsTopLevel() ) + // we could be called before the underlying window is created (this is + // actually useful to prevent it from being initially shown), e.g. + // + // wxFoo *foo = new wxFoo; + // foo->Hide(); + // foo->Create(parent, ...); + // + // should work without errors + if ( hWnd ) { - wxBringWindowToTop(hWnd); + ::ShowWindow(hWnd, show ? SW_SHOW : SW_HIDE); } return true; @@ -716,16 +734,6 @@ void wxWindowMSW::Lower() SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); } -void wxWindowMSW::SetTitle( const wxString& title) -{ - SetWindowText(GetHwnd(), title.c_str()); -} - -wxString wxWindowMSW::GetTitle() const -{ - return wxGetWindowText(GetHWND()); -} - void wxWindowMSW::DoCaptureMouse() { HWND hWnd = GetHwnd(); @@ -798,7 +806,7 @@ bool wxWindowMSW::SetCursor(const wxCursor& cursor) return true; } -void wxWindowMSW::WarpPointer (int x, int y) +void wxWindowMSW::WarpPointer(int x, int y) { ClientToScreen(&x, &y); @@ -808,6 +816,26 @@ void wxWindowMSW::WarpPointer (int x, int y) } } +void wxWindowMSW::MSWUpdateUIState(int action, int state) +{ + // WM_CHANGEUISTATE only appeared in Windows 2000 so it can do us no good + // to use it on older systems -- and could possibly do some harm + static int s_needToUpdate = -1; + if ( s_needToUpdate == -1 ) + { + int verMaj, verMin; + s_needToUpdate = wxGetOsVersion(&verMaj, &verMin) == wxWINDOWS_NT && + verMaj >= 5; + } + + if ( s_needToUpdate ) + { + // we send WM_CHANGEUISTATE so if nothing needs changing then the system + // won't send WM_UPDATEUISTATE + ::SendMessage(GetHwnd(), WM_CHANGEUISTATE, MAKEWPARAM(action, state), 0); + } +} + // --------------------------------------------------------------------------- // scrolling stuff // --------------------------------------------------------------------------- @@ -1011,7 +1039,7 @@ void wxWindowMSW::SubclassWin(WXHWND hWnd) } else { - // don't bother restoring it neither: this also makes it easy to + // don't bother restoring it either: this also makes it easy to // implement IsOfStandardClass() method which returns true for the // standard controls and false for the wxWidgets own windows as it can // simply check m_oldWndProc @@ -1092,8 +1120,8 @@ bool wxCheckWindowWndProc(WXHWND hWnd, str == wxMDIChildFrameClassNameNoRedraw || str == _T("wxTLWHiddenParent")) return true; // Effectively means don't subclass - else - return false; + + return false; #else WNDCLASS cls; if ( !::GetClassInfo(wxGetInstance(), wxGetWindowClass(hWnd), &cls) ) @@ -1175,7 +1203,7 @@ WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const // using this flag results in very significant reduction in flicker, // especially with controls inside the static boxes (as the interior of the - // box is not redrawn twice).but sometimes results in redraw problems, so + // box is not redrawn twice), but sometimes results in redraw problems, so // optionally allow the old code to continue to use it provided a special // system option is turned on if ( !wxSystemOptions::GetOptionInt(wxT("msw.window.no-clip-children")) @@ -1419,7 +1447,7 @@ void wxWindowMSW::SetDropTarget(wxDropTarget *pDropTarget) } #endif // wxUSE_DRAG_AND_DROP -// old style file-manager drag&drop support: we retain the old-style +// old-style file manager drag&drop support: we retain the old-style // DragAcceptFiles in parallel with SetDropTarget. void wxWindowMSW::DragAcceptFiles(bool WXUNUSED_IN_WINCE(accept)) { @@ -1450,6 +1478,17 @@ void wxWindowMSW::DoSetToolTip(wxToolTip *tooltip) // moving and resizing // --------------------------------------------------------------------------- +bool wxWindowMSW::IsSizeDeferred() const +{ +#if USE_DEFERRED_SIZING + if ( m_pendingPosition != wxDefaultPosition || + m_pendingSize != wxDefaultSize ) + return true; +#endif // USE_DEFERRED_SIZING + + return false; +} + // Get total size void wxWindowMSW::DoGetSize(int *x, int *y) const { @@ -1646,9 +1685,11 @@ void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags) GetPosition(¤tX, ¤tY); GetSize(¤tW, ¤tH); - // ... and don't do anything (avoiding flicker) if it's already ok + // ... and don't do anything (avoiding flicker) if it's already ok unless + // we're forced to resize the window if ( x == currentX && y == currentY && - width == currentW && height == currentH ) + width == currentW && height == currentH && + !(sizeFlags & wxSIZE_FORCE) ) { return; } @@ -1699,7 +1740,7 @@ void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags) void wxWindowMSW::DoSetClientSize(int width, int height) { - // setting the client size is less obvious than it it could have been + // setting the client size is less obvious than it could have been // because in the result of changing the total size the window scrollbar // may [dis]appear and/or its menubar may [un]wrap and so the client size // will not be correct as the difference between the total and client size @@ -1867,7 +1908,7 @@ bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y) #endif ::TrackPopupMenu(hMenu, flags, point.x, point.y, 0, hWnd, NULL); - // we need to do it righ now as otherwise the events are never going to be + // we need to do it right now as otherwise the events are never going to be // sent to wxCurrentPopupMenu from HandleCommand() // // note that even eliminating (ugly) wxCurrentPopupMenu global wouldn't @@ -1973,7 +2014,10 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) // it return false; } - else if ( lDlgCode & DLGC_BUTTON ) + + // currently active button should get enter press even + // if there is a default button elsewhere + if ( lDlgCode & DLGC_DEFPUSHBUTTON ) { // let IsDialogMessage() handle this for all // buttons except the owner-drawn ones which it @@ -1982,16 +2026,15 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) if ( (style & BS_OWNERDRAW) == BS_OWNERDRAW ) { // emulate the button click - wxWindow *btn = wxFindWinFromHandle((WXHWND)msg->hwnd); + wxWindow * + btn = wxFindWinFromHandle((WXHWND)msg->hwnd); if ( btn ) btn->MSWCommand(BN_CLICKED, 0 /* unused */); } bProcess = false; } - // FIXME: this should be handled by - // wxNavigationKeyEvent handler and not here! - else + else // not a button itself { #if wxUSE_BUTTON wxButton *btn = wxDynamicCast(GetDefaultItem(), @@ -2006,6 +2049,12 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) else // no default button #endif // wxUSE_BUTTON { +#ifdef __WXWINCE__ + wxJoystickEvent event(wxEVT_JOY_BUTTON_DOWN); + event.SetEventObject(this); + if(GetEventHandler()->ProcessEvent(event)) + return true; +#endif // this is a quick and dirty test for a text // control if ( !(lDlgCode & DLGC_HASSETSEL) ) @@ -2044,6 +2093,11 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) if ( GetEventHandler()->ProcessEvent(event) ) { + // as we don't call IsDialogMessage(), which would take of + // this by default, we need to manually send this message + // so that controls can change their UI state if needed + MSWUpdateUIState(UIS_CLEAR, UISF_HIDEFOCUS); + return true; } } @@ -2057,7 +2111,7 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) { // ::IsDialogMessage() is broken and may sometimes hang the // application by going into an infinite loop, so we try to detect - // [some of] the situatations when this may happen and not call it + // [some of] the situations when this may happen and not call it // then // assume we can call it by default @@ -2078,7 +2132,7 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) #if !defined(__WXWINCE__) if ( ::GetWindowLong(hwndFocus, GWL_EXSTYLE) & WS_EX_CONTROLPARENT ) { - // passimistic by default + // pessimistic by default canSafelyCallIsDlgMsg = false; for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); node; @@ -2488,8 +2542,10 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l int x = GET_X_LPARAM(lParam), y = GET_Y_LPARAM(lParam); +#ifdef __WXWINCE__ // redirect the event to a static control if necessary by - // finding one under mouse + // finding one under mouse because under CE the static controls + // don't generate mouse events (even with SS_NOTIFY) wxWindowMSW *win; if ( GetCapture() == this ) { @@ -2505,6 +2561,9 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l wxCHECK_MSG( win, 0, _T("FindWindowForMouseEvent() returned NULL") ); } +#else // !__WXWINCE__ + wxWindowMSW *win = this; +#endif // __WXWINCE__/!__WXWINCE__ processed = win->HandleMouseEvent(message, x, y, wParam); @@ -2623,7 +2682,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l { switch ( wParam ) { - // we consider these message "not interesting" to OnChar, so + // we consider these messages "not interesting" to OnChar, so // just don't do anything more with them case VK_SHIFT: case VK_CONTROL: @@ -3478,6 +3537,20 @@ bool wxWindowMSW::HandleKillFocus(WXHWND hwnd) return GetEventHandler()->ProcessEvent(event); } +// --------------------------------------------------------------------------- +// labels +// --------------------------------------------------------------------------- + +void wxWindowMSW::SetLabel( const wxString& label) +{ + SetWindowText(GetHwnd(), label.c_str()); +} + +wxString wxWindowMSW::GetLabel() const +{ + return wxGetWindowText(GetHWND()); +} + // --------------------------------------------------------------------------- // miscellaneous // --------------------------------------------------------------------------- @@ -4224,7 +4297,7 @@ bool wxWindowMSW::HandleSize(int WXUNUSED(w), int WXUNUSED(h), WXUINT wParam) useDefer = true; } } -#endif +#endif // USE_DEFERRED_SIZING // update this window size bool processed = false; @@ -4447,12 +4520,12 @@ void wxWindowMSW::InitMouseEvent(wxMouseEvent& event, event.SetId(GetId()); #if wxUSE_MOUSEEVENT_HACK - m_lastMouseX = x; - m_lastMouseY = y; - m_lastMouseEvent = event.GetEventType(); + gs_lastMouseEvent.pos = ClientToScreen(wxPoint(x, y)); + gs_lastMouseEvent.type = event.GetEventType(); #endif // wxUSE_MOUSEEVENT_HACK } +#ifdef __WXWINCE__ // Windows doesn't send the mouse events to the static controls (which are // transparent in the sense that their WM_NCHITTEST handler returns // HTTRANSPARENT) at all but we want all controls to receive the mouse events @@ -4463,7 +4536,7 @@ void wxWindowMSW::InitMouseEvent(wxMouseEvent& event, // Notice that this is not done for the mouse move events because this could // (would?) be too slow, but only for clicks which means that the static texts // still don't get move, enter nor leave events. -static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y) //TW:REQ:Univ +static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y) { wxCHECK_MSG( x && y, win, _T("NULL pointer in FindWindowForMouseEvent") ); @@ -4516,6 +4589,7 @@ static wxWindowMSW *FindWindowForMouseEvent(wxWindowMSW *win, int *x, int *y) // return win; } +#endif // __WXWINCE__ bool wxWindowMSW::HandleMouseEvent(WXUINT msg, int x, int y, WXUINT flags) { @@ -4573,19 +4647,36 @@ bool wxWindowMSW::HandleMouseMove(int x, int y, WXUINT flags) (void)GetEventHandler()->ProcessEvent(event); } } +#ifdef HAVE_TRACKMOUSEEVENT + else + { + // Check if we need to send a LEAVE event + // Windows doesn't send WM_MOUSELEAVE if the mouse has been captured so + // send it here if we are using native mouse leave tracking + if ( HasCapture() && !IsMouseInWindow() ) + { + GenerateMouseLeave(); + } + } +#endif // HAVE_TRACKMOUSEEVENT #if wxUSE_MOUSEEVENT_HACK - // Window gets a click down message followed by a mouse move message even - // if position isn't changed! We want to discard the trailing move event - // if x and y are the same. - if ( (m_lastMouseEvent == wxEVT_RIGHT_DOWN || - m_lastMouseEvent == wxEVT_LEFT_DOWN || - m_lastMouseEvent == wxEVT_MIDDLE_DOWN) && - (m_lastMouseX == x && m_lastMouseY == y) ) - { - m_lastMouseEvent = wxEVT_MOTION; + // Windows often generates mouse events even if mouse position hasn't + // changed (http://article.gmane.org/gmane.comp.lib.wxwidgets.devel/66576) + // + // Filter this out as it can result in unexpected behaviour compared to + // other platforms + if ( gs_lastMouseEvent.type == wxEVT_RIGHT_DOWN || + gs_lastMouseEvent.type == wxEVT_LEFT_DOWN || + gs_lastMouseEvent.type == wxEVT_MIDDLE_DOWN || + gs_lastMouseEvent.type == wxEVT_MOTION ) + { + if ( ClientToScreen(wxPoint(x, y)) == gs_lastMouseEvent.pos ) + { + gs_lastMouseEvent.type = wxEVT_MOTION; - return false; + return false; + } } #endif // wxUSE_MOUSEEVENT_HACK @@ -6116,4 +6207,3 @@ void wxWindowMSW::OnInitDialog( wxInitDialogEvent& event ) event.Skip(); } #endif -