X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/4a712ba3cfe27e8d39ee8fe8691ff67d1c96cb43..9f93b45e59e93e17850bbc37a8960240072bc1c0:/src/msw/window.cpp diff --git a/src/msw/window.cpp b/src/msw/window.cpp index e01ee082b2..3be9dd4b12 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" @@ -32,7 +28,6 @@ #include "wx/msw/wrapwin.h" #include "wx/window.h" #include "wx/accel.h" - #include "wx/setup.h" #include "wx/menu.h" #include "wx/dc.h" #include "wx/dcclient.h" @@ -115,6 +110,12 @@ #if defined(__WXWINCE__) #include "wx/msw/wince/missing.h" +#ifdef __POCKETPC__ + #include + #include + #include + #include +#endif #endif #if defined(TME_LEAVE) && defined(WM_MOUSELEAVE) @@ -125,7 +126,19 @@ // resizing complicated window hierarchies, but this can in theory result in // different behaviour than the old code so we keep the possibility to use it // by setting this to 0 (in the future this should be removed completely) +#ifdef __WXWINCE__ +#define USE_DEFERRED_SIZING 0 +#else #define USE_DEFERRED_SIZING 1 +#endif + +// 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 +158,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 +190,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 +229,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 +403,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,14 +491,12 @@ 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; + +#ifdef __POCKETPC__ + m_contextMenuEnabled = false; +#endif } // Destructor @@ -501,7 +526,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 +678,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 +717,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 +747,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(); @@ -777,28 +798,16 @@ bool wxWindowMSW::SetCursor(const wxCursor& cursor) return false; } - if ( m_cursor.Ok() ) + // don't "overwrite" busy cursor + if ( m_cursor.Ok() && !wxIsBusy() ) { - HWND hWnd = GetHwnd(); - - // Change the cursor NOW if we're within the correct window - POINT point; -#ifdef __WXWINCE__ - ::GetCursorPosWinCE(&point); -#else - ::GetCursorPos(&point); -#endif - - RECT rect = wxGetWindowRect(hWnd); - - if ( ::PtInRect(&rect, point) && !wxIsBusy() ) - ::SetCursor(GetHcursorOf(m_cursor)); + ::SetCursor(GetHcursorOf(m_cursor)); } return true; } -void wxWindowMSW::WarpPointer (int x, int y) +void wxWindowMSW::WarpPointer(int x, int y) { ClientToScreen(&x, &y); @@ -808,6 +817,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 // --------------------------------------------------------------------------- @@ -820,15 +849,10 @@ inline int GetScrollPosition(HWND hWnd, int wOrient) WinStruct scrollInfo; scrollInfo.cbSize = sizeof(SCROLLINFO); scrollInfo.fMask = SIF_POS; - if ( !::GetScrollInfo(hWnd, - wOrient, - &scrollInfo) ) - { - // Not necessarily an error, if there are no scrollbars yet. - // wxLogLastError(_T("GetScrollInfo")); - } + ::GetScrollInfo(hWnd, wOrient, &scrollInfo ); + return scrollInfo.nPos; -// return ::GetScrollPos(hWnd, wOrient); + #endif } @@ -915,11 +939,13 @@ void wxWindowMSW::SetScrollbar(int orient, HWND hWnd = GetHwnd(); if ( hWnd ) { + // We have to set the variables here to make them valid in events + // triggered by ::SetScrollInfo() + *(orient == wxHORIZONTAL ? &m_xThumbSize : &m_yThumbSize) = pageSize; + ::SetScrollInfo(hWnd, orient == wxHORIZONTAL ? SB_HORZ : SB_VERT, &info, refresh); } - - *(orient == wxHORIZONTAL ? &m_xThumbSize : &m_yThumbSize) = pageSize; } void wxWindowMSW::ScrollWindow(int dx, int dy, const wxRect *prect) @@ -1011,7 +1037,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 @@ -1065,20 +1091,19 @@ void wxWindowMSW::DissociateHandle() bool wxCheckWindowWndProc(WXHWND hWnd, - WXFARPROC WXUNUSED_IN_WINCE(wndProc)) + WXFARPROC WXUNUSED(wndProc)) { - // Unicows note: the code below works, but only because WNDCLASS contains - // original window handler rather that the unicows fake one. This may not - // be on purpose, though; if it stops working with future versions of - // unicows.dll, we can override unicows hooks by setting - // Unicows_{Set,Get}WindowLong and Unicows_RegisterClass to our own - // versions that keep track of fake<->real wnd proc mapping. +// TODO: This list of window class names should be factored out so they can be +// managed in one place and then accessed from here and other places, such as +// wxApp::RegisterWindowClasses() and wxApp::UnregisterWindowClasses() - // On WinCE (at least), the wndproc comparison doesn't work, - // so have to use something like this. #ifdef __WXWINCE__ extern wxChar *wxCanvasClassName; extern wxChar *wxCanvasClassNameNR; +#else + extern const wxChar *wxCanvasClassName; + extern const wxChar *wxCanvasClassNameNR; +#endif extern const wxChar *wxMDIFrameClassName; extern const wxChar *wxMDIFrameClassNameNoRedraw; extern const wxChar *wxMDIChildFrameClassName; @@ -1086,6 +1111,10 @@ bool wxCheckWindowWndProc(WXHWND hWnd, wxString str(wxGetWindowClass(hWnd)); if (str == wxCanvasClassName || str == wxCanvasClassNameNR || +#if wxUSE_GLCANVAS + str == _T("wxGLCanvasClass") || + str == _T("wxGLCanvasClassNR") || +#endif // wxUSE_GLCANVAS str == wxMDIFrameClassName || str == wxMDIFrameClassNameNoRedraw || str == wxMDIChildFrameClassName || @@ -1094,17 +1123,6 @@ bool wxCheckWindowWndProc(WXHWND hWnd, return true; // Effectively means don't subclass else return false; -#else - WNDCLASS cls; - if ( !::GetClassInfo(wxGetInstance(), wxGetWindowClass(hWnd), &cls) ) - { - wxLogLastError(_T("GetClassInfo")); - - return false; - } - - return wndProc == (WXFARPROC)cls.lpfnWndProc; -#endif } // ---------------------------------------------------------------------------- @@ -1125,6 +1143,9 @@ void wxWindowMSW::SetWindowStyleFlag(long flags) if ( !GetHwnd() ) return; + // we may need to call SetWindowPos() when we change some styles + bool callSWP = false; + WXDWORD exstyle, exstyleOld; long style = MSWGetStyle(flags, &exstyle), styleOld = MSWGetStyle(flagsOld, &exstyleOld); @@ -1140,17 +1161,40 @@ void wxWindowMSW::SetWindowStyleFlag(long flags) styleReal |= style; ::SetWindowLong(GetHwnd(), GWL_STYLE, styleReal); + + // If any of the style changes changed any of the frame styles: + // MSDN: SetWindowLong: + // Certain window data is cached, so changes you make using + // SetWindowLong will not take effect until you call the + // SetWindowPos function. Specifically, if you change any of + // the frame styles, you must call SetWindowPos with the + // SWP_FRAMECHANGED flag for the cache to be updated properly. + + callSWP = ((styleOld ^ style ) & (WS_BORDER | + WS_THICKFRAME | + WS_CAPTION | + WS_DLGFRAME | + WS_MAXIMIZEBOX | + WS_MINIMIZEBOX | + WS_SYSMENU) ) != 0; } // and the extended style + long exstyleReal = ::GetWindowLong(GetHwnd(), GWL_EXSTYLE); + if ( exstyle != exstyleOld ) { - long exstyleReal = ::GetWindowLong(GetHwnd(), GWL_EXSTYLE); exstyleReal &= ~exstyleOld; exstyleReal |= exstyle; ::SetWindowLong(GetHwnd(), GWL_EXSTYLE, exstyleReal); + // ex style changes don't take effect without calling SetWindowPos + callSWP = true; + } + + if ( callSWP ) + { // we must call SetWindowPos() to flush the cached extended style and // also to make the change to wxSTAY_ON_TOP style take effect: just // setting the style simply doesn't work @@ -1158,7 +1202,7 @@ void wxWindowMSW::SetWindowStyleFlag(long flags) exstyleReal & WS_EX_TOPMOST ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, - SWP_NOMOVE | SWP_NOSIZE) ) + SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED) ) { wxLogLastError(_T("SetWindowPos")); } @@ -1175,7 +1219,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")) @@ -1339,7 +1383,7 @@ void wxWindowMSW::Thaw() { wxASSERT_MSG( m_frozenness > 0, _T("Thaw() without matching Freeze()") ); - if ( !--m_frozenness ) + if ( --m_frozenness == 0 ) { if ( IsShown() ) { @@ -1404,6 +1448,26 @@ void wxWindowMSW::Update() // drag and drop // --------------------------------------------------------------------------- +// we need to lower the sibling static boxes so controls contained within can be +// a drop target +static inline void AdjustStaticBoxZOrder(wxWindow *parent) +{ + // no sibling static boxes if we have no parent (ie TLW) + if ( !parent ) + return; + + for ( wxWindowList::compatibility_iterator node = parent->GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + wxStaticBox *statbox = wxDynamicCast(node->GetData(), wxStaticBox); + if ( statbox ) + { + ::SetWindowPos(GetHwndOf(statbox), HWND_BOTTOM, 0, 0, 0, 0, + SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); + } + } +} #if wxUSE_DRAG_AND_DROP void wxWindowMSW::SetDropTarget(wxDropTarget *pDropTarget) @@ -1415,18 +1479,24 @@ void wxWindowMSW::SetDropTarget(wxDropTarget *pDropTarget) m_dropTarget = pDropTarget; if ( m_dropTarget != 0 ) + { + AdjustStaticBoxZOrder(GetParent()); m_dropTarget->Register(m_hWnd); + } } #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)) { #ifndef __WXWINCE__ HWND hWnd = GetHwnd(); if ( hWnd ) + { + AdjustStaticBoxZOrder(GetParent()); ::DragAcceptFiles(hWnd, (BOOL)accept); + } #endif } @@ -1450,6 +1520,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 { @@ -1477,14 +1558,36 @@ void wxWindowMSW::DoGetSize(int *x, int *y) const // Get size *available for subwindows* i.e. excluding menu bar etc. void wxWindowMSW::DoGetClientSize(int *x, int *y) const { - // this is only for top level windows whose resizing is never deferred, so - // we can safely use the current size here - RECT rect = wxGetClientRect(GetHwnd()); +#if USE_DEFERRED_SIZING + if ( IsTopLevel() || m_pendingSize == wxDefaultSize ) +#endif + { // top level windows resizing is never deferred, so we can safely use + // the current size here + RECT rect = wxGetClientRect(GetHwnd()); - if ( x ) - *x = rect.right; - if ( y ) - *y = rect.bottom; + if ( x ) + *x = rect.right; + if ( y ) + *y = rect.bottom; + } +#if USE_DEFERRED_SIZING + else // non top level and using deferred sizing + { + // we need to calculate the *pending* client size here + RECT rect; + rect.left = m_pendingPosition.x; + rect.top = m_pendingPosition.y; + rect.right = rect.left + m_pendingSize.x; + rect.bottom = rect.top + m_pendingSize.y; + + ::SendMessage(GetHwnd(), WM_NCCALCSIZE, FALSE, (LPARAM)&rect); + + if ( x ) + *x = rect.right - rect.left; + if ( y ) + *y = rect.bottom - rect.top; + } +#endif } void wxWindowMSW::DoGetPosition(int *x, int *y) const @@ -1579,7 +1682,7 @@ wxWindowMSW::DoMoveSibling(WXHWND hwnd, int x, int y, int width, int height) if ( hdwp ) { hdwp = ::DeferWindowPos(hdwp, (HWND)hwnd, NULL, x, y, width, height, - SWP_NOZORDER); + SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE); if ( !hdwp ) { wxLogLastError(_T("DeferWindowPos")); @@ -1646,9 +1749,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,11 +1804,12 @@ 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 - // changes - so we keep changing it until we get it right + // may [dis]appear and/or its menubar may [un]wrap (and AdjustWindowRect() + // doesn't take neither into account) and so the client size will not be + // correct as the difference between the total and client size changes -- + // so we keep changing it until we get it right // // normally this loop shouldn't take more than 3 iterations (usually 1 but // if scrollbars [dis]appear as the result of the first call, then 2 and it @@ -1744,7 +1850,9 @@ void wxWindowMSW::DoSetClientSize(int width, int height) } // don't call DoMoveWindow() because we want to move window immediately - // and not defer it here + // and not defer it here as otherwise the value returned by + // GetClient/WindowRect() wouldn't change as the window wouldn't be + // really resized if ( !::MoveWindow(GetHwnd(), rectWin.left, rectWin.top, @@ -1863,11 +1971,11 @@ bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y) #if defined(__WXWINCE__) UINT flags = 0; #else - UINT flags = TPM_RIGHTBUTTON; + UINT flags = TPM_RIGHTBUTTON | TPM_RECURSE; #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 +2081,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 +2093,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 +2116,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 +2160,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 +2178,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 +2199,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; @@ -2345,28 +2466,6 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l break; #endif // !__WXWINCE__ -#if !(defined(_WIN32_WCE) && _WIN32_WCE < 400) - case WM_WINDOWPOSCHANGED: - { - WINDOWPOS *lpPos = (WINDOWPOS *)lParam; - - if ( !(lpPos->flags & SWP_NOSIZE) ) - { - RECT rc; - ::GetClientRect(GetHwnd(), &rc); - - AutoHRGN hrgnClient(::CreateRectRgnIndirect(&rc)); - AutoHRGN hrgnNew(::CreateRectRgn(lpPos->x, lpPos->y, - lpPos->cx, lpPos->cy)); - - // we need to invalidate any new exposed areas here - // to force them to repaint - if ( ::CombineRgn(hrgnNew, hrgnNew, hrgnClient, RGN_DIFF) != NULLREGION ) - ::InvalidateRgn(GetHwnd(), hrgnNew, TRUE); - } - } - break; -#endif #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__) case WM_ACTIVATEAPP: // This implicitly sends a wxEVT_ACTIVATE_APP event @@ -2488,8 +2587,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 +2606,39 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l wxCHECK_MSG( win, 0, _T("FindWindowForMouseEvent() returned NULL") ); } +#ifdef __POCKETPC__ + if (IsContextMenuEnabled() && message == WM_LBUTTONDOWN) + { + SHRGINFO shrgi = {0}; + + shrgi.cbSize = sizeof(SHRGINFO); + shrgi.hwndClient = (HWND) GetHWND(); + shrgi.ptDown.x = x; + shrgi.ptDown.y = y; + + shrgi.dwFlags = SHRG_RETURNCMD; + // shrgi.dwFlags = SHRG_NOTIFYPARENT; + + if (GN_CONTEXTMENU == ::SHRecognizeGesture(&shrgi)) + { + wxPoint pt(x, y); + pt = ClientToScreen(pt); + + wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt); + + evtCtx.SetEventObject(this); + if (GetEventHandler()->ProcessEvent(evtCtx)) + { + processed = true; + return true; + } + } + } +#endif + +#else // !__WXWINCE__ + wxWindowMSW *win = this; +#endif // __WXWINCE__/!__WXWINCE__ processed = win->HandleMouseEvent(message, x, y, wParam); @@ -2623,7 +2757,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: @@ -2769,6 +2903,10 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l processed = HandleCaptureChanged((WXHWND) (HWND) lParam); break; + case WM_SETTINGCHANGE: + processed = HandleSettingChange(wParam, lParam); + break; + case WM_QUERYNEWPALETTE: processed = HandleQueryNewPalette(); break; @@ -3143,8 +3281,6 @@ bool wxWindowMSW::MSWCreate(const wxChar *wclass, // WM_NOTIFY // --------------------------------------------------------------------------- -#ifdef __WIN95__ - bool wxWindowMSW::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result) { #ifndef __WXMICROWIN__ @@ -3288,8 +3424,6 @@ bool wxWindowMSW::MSWOnNotify(int WXUNUSED(idCtrl), return false; } -#endif // __WIN95__ - // --------------------------------------------------------------------------- // end session messages // --------------------------------------------------------------------------- @@ -3478,6 +3612,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 // --------------------------------------------------------------------------- @@ -3843,6 +3991,30 @@ bool wxWindowMSW::HandleCaptureChanged(WXHWND hWndGainedCapture) return GetEventHandler()->ProcessEvent(event); } +bool wxWindowMSW::HandleSettingChange(WXWPARAM wParam, WXLPARAM lParam) +{ + // despite MSDN saying "(This message cannot be sent directly to a window.)" + // we need to send this to child windows (it is only sent to top-level + // windows) so {list,tree}ctrls can adjust their font size if necessary + // this is exactly how explorer does it to enable the font size changes + + wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + while ( node ) + { + // top-level windows already get this message from the system + wxWindow *win = node->GetData(); + if ( !win->IsTopLevel() ) + { + ::SendMessage(GetHwndOf(win), WM_SETTINGCHANGE, wParam, lParam); + } + + node = node->GetNext(); + } + + // let the system handle it + return false; +} + bool wxWindowMSW::HandleQueryNewPalette() { @@ -4019,14 +4191,11 @@ bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc) dc.SetHDC(hdc); dc.SetWindow((wxWindow *)this); - dc.BeginDrawing(); wxEraseEvent event(m_windowId, &dc); event.SetEventObject(this); bool rc = GetEventHandler()->ProcessEvent(event); - dc.EndDrawing(); - // must be called manually as ~wxDC doesn't do anything for wxDCTemp dc.SelectOldObjects(hdc); @@ -4224,7 +4393,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 +4616,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 +4632,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 +4685,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 +4743,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 @@ -4833,12 +5020,20 @@ int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel), MENUITEMINFO mii; wxZeroMemory(mii); mii.cbSize = sizeof(MENUITEMINFO); + + // 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 + // MIIM_FTYPE is not supported under Win95 mii.fMask = MIIM_TYPE | MIIM_DATA; // find if we have this letter in any owner drawn item const int count = ::GetMenuItemCount(hmenu); for ( int i = 0; i < count; i++ ) { + // previous loop iteration could modify it, reset it back before + // calling GetMenuItemInfo() to prevent it from overflowing dwTypeData + mii.cch = 0; + if ( ::GetMenuItemInfo(hmenu, i, TRUE, &mii) ) { if ( mii.fType == MFT_OWNERDRAW ) @@ -4876,8 +5071,7 @@ int wxWindowMSW::HandleMenuChar(int WXUNUSED_IN_WINCE(chAccel), } else // failed to get the menu text? { - // it's not fatal, so don't show error, but still log - // it + // it's not fatal, so don't show error, but still log it wxLogLastError(_T("GetMenuItemInfo")); } } @@ -5088,6 +5282,18 @@ void wxGetCharSize(WXHWND wnd, int *x, int *y, const wxFont& the_font) // the_font.ReleaseResource(); } +// use the "extended" bit (24) of lParam to distinguish extended keys +// from normal keys as the same key is sent +static inline +int ChooseNormalOrExtended(int lParam, int keyNormal, int keyExtended) +{ + // except that if lParam is 0, it means we don't have real lParam from + // WM_KEYDOWN but are just translating just a VK constant (e.g. done from + // msw/treectrl.cpp when processing TVN_KEYDOWN) -- then assume this is a + // non-numpad (hence extended) key as this is a more common case + return !lParam || (lParam & (1 << 24)) ? keyExtended : keyNormal; +} + // Returns 0 if was a normal ASCII value, not a special key. This indicates that // the key should be ignored by WM_KEYDOWN and processed by WM_CHAR instead. int wxCharCodeMSWToWX(int keySym, WXLPARAM lParam) @@ -5106,19 +5312,9 @@ int wxCharCodeMSWToWX(int keySym, WXLPARAM lParam) case VK_CAPITAL: id = WXK_CAPITAL; 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; @@ -5182,11 +5378,41 @@ int wxCharCodeMSWToWX(int keySym, WXLPARAM lParam) case VK_APPS: id = WXK_WINDOWS_MENU; break; #endif // VK_APPS defined + // handle extended keys + case VK_PRIOR: + id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_PAGEUP, WXK_PAGEUP); + break; + case VK_NEXT: + id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_PAGEDOWN, WXK_PAGEDOWN); + break; + case VK_END: + id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_END, WXK_END); + break; + case VK_HOME: + id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_HOME, WXK_HOME); + break; + case VK_LEFT: + id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_LEFT, WXK_LEFT); + break; + case VK_UP: + id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_UP, WXK_UP); + break; + case VK_RIGHT: + id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_RIGHT, WXK_RIGHT); + break; + case VK_DOWN: + id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DOWN, WXK_DOWN); + break; + case VK_INSERT: + id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_INSERT, WXK_INSERT); + break; + case VK_DELETE: + id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_DELETE, WXK_DELETE); + break; case VK_RETURN: - // the same key is sent for both the "return" key on the main - // keyboard and the numeric keypad but we want to distinguish - // between them: we do this using the "extended" bit (24) of lParam - id = lParam & (1 << 24) ? WXK_NUMPAD_ENTER : WXK_RETURN; + // don't use ChooseNormalOrExtended() here as the keys are reversed + // here: numpad enter is the extended one + id = lParam && (lParam & (1 << 24)) ? WXK_NUMPAD_ENTER : WXK_RETURN; break; default: @@ -5209,8 +5435,8 @@ WXWORD wxCharCodeWXToMSW(int id, bool *isVirtual) case WXK_ALT: keySym = VK_MENU; break; case WXK_PAUSE: keySym = VK_PAUSE; break; case WXK_CAPITAL: keySym = VK_CAPITAL; break; - case WXK_PRIOR: keySym = VK_PRIOR; break; - case WXK_NEXT : keySym = VK_NEXT; break; + case WXK_PAGEUP: keySym = VK_PRIOR; break; + case WXK_PAGEDOWN: keySym = VK_NEXT; break; case WXK_END: keySym = VK_END; break; case WXK_HOME : keySym = VK_HOME; break; case WXK_LEFT : keySym = VK_LEFT; break; @@ -5308,6 +5534,28 @@ bool wxGetKeyState(wxKeyCode key) #endif } + +wxMouseState wxGetMouseState() +{ + wxMouseState ms; + POINT pt; + GetCursorPos( &pt ); + + ms.SetX(pt.x); + ms.SetY(pt.y); + ms.SetLeftDown( (GetAsyncKeyState(VK_LBUTTON) & (1<<15)) != 0 ); + ms.SetMiddleDown( (GetAsyncKeyState(VK_MBUTTON) & (1<<15)) != 0 ); + ms.SetRightDown( (GetAsyncKeyState(VK_RBUTTON) & (1<<15)) != 0 ); + + ms.SetControlDown( (GetAsyncKeyState(VK_CONTROL) & (1<<15)) != 0 ); + ms.SetShiftDown( (GetAsyncKeyState(VK_SHIFT) & (1<<15)) != 0 ); + ms.SetAltDown( (GetAsyncKeyState(VK_MENU) & (1<<15)) != 0 ); +// ms.SetMetaDown(); + + return ms; +} + + wxWindow *wxGetActiveWindow() { HWND hWnd = GetActiveWindow(); @@ -6116,4 +6364,3 @@ void wxWindowMSW::OnInitDialog( wxInitDialogEvent& event ) event.Skip(); } #endif -