X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/7dd40b6f4b31e6bc9c7f626f1461aff8adf7714c..27b436242eb0257ef471839961250bb3f184fafc:/src/msw/window.cpp diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 2ee65a51cf..919f3c3c8a 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -28,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" @@ -111,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) @@ -121,7 +126,11 @@ // 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 @@ -484,6 +493,10 @@ void wxWindowMSW::Init() m_pendingPosition = wxDefaultPosition; m_pendingSize = wxDefaultSize; + +#ifdef __POCKETPC__ + m_contextMenuEnabled = false; +#endif } // Destructor @@ -785,22 +798,10 @@ 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; @@ -938,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) @@ -1088,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; @@ -1109,25 +1111,18 @@ 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 || str == wxMDIChildFrameClassNameNoRedraw || str == _T("wxTLWHiddenParent")) return true; // Effectively means don't subclass - - return false; -#else - WNDCLASS cls; - if ( !::GetClassInfo(wxGetInstance(), wxGetWindowClass(hWnd), &cls) ) - { - wxLogLastError(_T("GetClassInfo")); - + else return false; - } - - return wndProc == (WXFARPROC)cls.lpfnWndProc; -#endif } // ---------------------------------------------------------------------------- @@ -1148,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); @@ -1163,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 @@ -1181,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")); } @@ -1362,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() ) { @@ -1427,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) @@ -1438,7 +1479,10 @@ void wxWindowMSW::SetDropTarget(wxDropTarget *pDropTarget) m_dropTarget = pDropTarget; if ( m_dropTarget != 0 ) + { + AdjustStaticBoxZOrder(GetParent()); m_dropTarget->Register(m_hWnd); + } } #endif // wxUSE_DRAG_AND_DROP @@ -1449,7 +1493,10 @@ void wxWindowMSW::DragAcceptFiles(bool WXUNUSED_IN_WINCE(accept)) #ifndef __WXWINCE__ HWND hWnd = GetHwnd(); if ( hWnd ) + { + AdjustStaticBoxZOrder(GetParent()); ::DragAcceptFiles(hWnd, (BOOL)accept); + } #endif } @@ -1511,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 @@ -1613,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")); @@ -1737,9 +1806,10 @@ void wxWindowMSW::DoSetClientSize(int width, int height) { // 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 @@ -1780,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, @@ -1899,7 +1971,7 @@ 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); @@ -2394,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 @@ -2556,6 +2606,36 @@ 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__ @@ -2823,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; @@ -3907,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() { @@ -4083,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); @@ -4915,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 ) @@ -4958,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")); } } @@ -5170,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) @@ -5188,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; @@ -5264,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_PRIOR, WXK_PRIOR); + break; + case VK_NEXT: + id = ChooseNormalOrExtended(lParam, WXK_NUMPAD_NEXT, WXK_NEXT); + 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: @@ -5402,12 +5546,12 @@ wxMouseState wxGetMouseState() 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; }