X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/9a83f860948059b0273b5cc6d9e43fadad3ebfca..b2edb8f3c524f302b727386bb0a694c44fb57e7d:/src/msw/window.cpp diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 84c0e32811..da62175805 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -173,13 +173,16 @@ extern wxMenu *wxCurrentPopupMenu; #endif +namespace +{ + // true if we had already created the std colour map, used by // wxGetStdColourMap() and wxWindow::OnSysColourChanged() (FIXME-MT) -static bool gs_hasStdCmap = false; +bool gs_hasStdCmap = false; // last mouse event information we need to filter out the duplicates #if wxUSE_MOUSEEVENT_HACK -static struct MouseEventInfoDummy +struct MouseEventInfoDummy { // mouse position (in screen coordinates) wxPoint pos; @@ -194,14 +197,29 @@ WX_DECLARE_HASH_MAP(int, wxWindow::MSWMessageHandler, wxIntegerHash, wxIntegerEqual, MSWMessageHandlers); -static MSWMessageHandlers gs_messageHandlers; +MSWMessageHandlers gs_messageHandlers; // hash containing all our windows, it uses HWND keys and wxWindow* values WX_DECLARE_HASH_MAP(HWND, wxWindow *, wxPointerHash, wxPointerEqual, WindowHandles); -static WindowHandles gs_windowHandles; +WindowHandles gs_windowHandles; + +#ifdef wxHAS_MSW_BACKGROUND_ERASE_HOOK + +// temporary override for WM_ERASEBKGND processing: we don't store this in +// wxWindow itself as we don't need it during most of the time so don't +// increase the size of all window objects unnecessarily +WX_DECLARE_HASH_MAP(wxWindow *, wxWindow *, + wxPointerHash, wxPointerEqual, + EraseBgHooks); + +EraseBgHooks gs_eraseBgHooks; + +#endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK + +} // anonymous namespace // --------------------------------------------------------------------------- // private functions @@ -724,6 +742,9 @@ wxWindowMSW::MSWShowWithEffect(bool show, wxShowEffect effect, unsigned timeout) { + if ( effect == wxSHOW_EFFECT_NONE ) + return Show(show); + if ( !wxWindowBase::Show(show) ) return false; @@ -2021,7 +2042,7 @@ void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags) { if ( sizeFlags & wxSIZE_AUTO_WIDTH ) { - size = DoGetBestSize(); + size = GetBestSize(); width = size.x; } else @@ -2037,9 +2058,9 @@ void wxWindowMSW::DoSetSize(int x, int y, int width, int height, int sizeFlags) { if ( size.x == wxDefaultCoord ) { - size = DoGetBestSize(); + size = GetBestSize(); } - //else: already called DoGetBestSize() above + //else: already called GetBestSize() above height = size.y; } @@ -2317,7 +2338,7 @@ bool wxWindowMSW::MSWProcessMessage(WXMSG* pMsg) // combinations which are always processed) LONG lDlgCode = ::SendMessage(msg->hwnd, WM_GETDLGCODE, 0, 0); - // surprizingly, DLGC_WANTALLKEYS bit mask doesn't contain the + // surprisingly, DLGC_WANTALLKEYS bit mask doesn't contain the // DLGC_WANTTAB nor DLGC_WANTARROWS bits although, logically, // it, of course, implies them if ( lDlgCode & DLGC_WANTALLKEYS ) @@ -2682,7 +2703,7 @@ LRESULT WXDLLEXPORT APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, WPARAM w // trace all messages: useful for the debugging but noticeably slows down // the code so don't do it by default #if wxDEBUG_LEVEL >= 2 - wxLogTrace(wxTraceMessages, + wxLogTrace("winmsg", wxT("Processing %s(hWnd=%p, wParam=%08lx, lParam=%08lx)"), wxGetMessageName(message), hWnd, (long)wParam, lParam); #endif // wxDEBUG_LEVEL >= 2 @@ -3117,6 +3138,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l case VK_SUBTRACT: case VK_MULTIPLY: case VK_DIVIDE: + case VK_DECIMAL: case VK_NUMPAD0: case VK_NUMPAD1: case VK_NUMPAD2: @@ -3265,7 +3287,17 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l break; case WM_ERASEBKGND: - processed = HandleEraseBkgnd((WXHDC)wParam); + { +#ifdef wxHAS_MSW_BACKGROUND_ERASE_HOOK + // check if an override was configured for this window + EraseBgHooks::const_iterator it = gs_eraseBgHooks.find(this); + if ( it != gs_eraseBgHooks.end() ) + processed = it->second->MSWEraseBgHook((WXHDC)wParam); + else +#endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK + processed = HandleEraseBkgnd((WXHDC)wParam); + } + if ( processed ) { // we processed the message, i.e. erased the background @@ -3445,9 +3477,10 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l // now alter the client size making room for drawing a // themed border RECT *rect; + NCCALCSIZE_PARAMS *csparam = NULL; if ( wParam ) { - NCCALCSIZE_PARAMS *csparam = (NCCALCSIZE_PARAMS *)lParam; + csparam = (NCCALCSIZE_PARAMS *)lParam; rect = &csparam->rgrc[0]; } else @@ -3470,8 +3503,14 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l &rcClient) == S_OK ) { InflateRect(&rcClient, -1, -1); - *rect = rcClient; - rc.result = WVR_REDRAW; + if (wParam) + csparam->rgrc[0] = rcClient; + else + *((RECT*)lParam) = rcClient; + + // WVR_REDRAW triggers a bug whereby child windows are moved up and left, + // so don't use. + // rc.result = WVR_REDRAW; } } } @@ -3538,7 +3577,7 @@ WXLRESULT wxWindowMSW::MSWWindowProc(WXUINT message, WXWPARAM wParam, WXLPARAM l if ( !processed ) { #if wxDEBUG_LEVEL >= 2 - wxLogTrace(wxTraceMessages, wxT("Forwarding %s to DefWindowProc."), + wxLogTrace("winmsg", wxT("Forwarding %s to DefWindowProc."), wxGetMessageName(message)); #endif // wxDEBUG_LEVEL >= 2 rc.result = MSWDefWindowProc(message, wParam, lParam); @@ -4185,6 +4224,8 @@ bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd), y = pt.y; ScreenToClient(&x, &y); wxSetCursorEvent event(x, y); + event.SetId(GetId()); + event.SetEventObject(this); bool processedEvtSetCursor = HandleWindowEvent(event); if ( processedEvtSetCursor && event.HasCursor() ) @@ -4690,10 +4731,82 @@ extern wxCOLORMAP *wxGetStdColourMap() return s_cmap; } +#if wxUSE_UXTHEME && !defined(TMT_FILLCOLOR) + #define TMT_FILLCOLOR 3802 + #define TMT_TEXTCOLOR 3803 + #define TMT_BORDERCOLOR 3801 +#endif + +wxColour wxWindowMSW::MSWGetThemeColour(const wchar_t *themeName, + int themePart, + int themeState, + MSWThemeColour themeColour, + wxSystemColour fallback) const +{ +#if wxUSE_UXTHEME + const wxUxThemeEngine* theme = wxUxThemeEngine::GetIfActive(); + if ( theme ) + { + int themeProperty = 0; + + // TODO: Convert this into a table? Sure would be faster. + switch ( themeColour ) + { + case ThemeColourBackground: + themeProperty = TMT_FILLCOLOR; + break; + case ThemeColourText: + themeProperty = TMT_TEXTCOLOR; + break; + case ThemeColourBorder: + themeProperty = TMT_BORDERCOLOR; + break; + default: + wxFAIL_MSG(wxT("unsupported theme colour")); + }; + + wxUxThemeHandle hTheme((const wxWindow *)this, themeName); + COLORREF col; + HRESULT hr = theme->GetThemeColor + ( + hTheme, + themePart, + themeState, + themeProperty, + &col + ); + + if ( SUCCEEDED(hr) ) + return wxRGBToColour(col); + + wxLogApiError( + wxString::Format( + "GetThemeColor(%s, %i, %i, %i)", + themeName, themePart, themeState, themeProperty), + hr); + } +#else + wxUnusedVar(themeName); + wxUnusedVar(themePart); + wxUnusedVar(themeState); + wxUnusedVar(themeColour); +#endif + return wxSystemSettings::GetColour(fallback); +} + // --------------------------------------------------------------------------- // painting // --------------------------------------------------------------------------- +// this variable is used to check that a paint event handler which processed +// the event did create a wxPaintDC inside its code and called BeginPaint() to +// validate the invalidated window area as otherwise we'd keep getting an +// endless stream of WM_PAINT messages for this window resulting in a lot of +// difficult to debug problems (e.g. impossibility to repaint other windows, +// lack of timer and idle events and so on) +extern bool wxDidCreatePaintDC; +bool wxDidCreatePaintDC = false; + bool wxWindowMSW::HandlePaint() { HRGN hRegion = ::CreateRectRgn(0, 0, 0, 0); // Dummy call to get a handle @@ -4708,11 +4821,20 @@ bool wxWindowMSW::HandlePaint() m_updateRegion = wxRegion((WXHRGN) hRegion); + wxDidCreatePaintDC = false; + wxPaintEvent event(m_windowId); event.SetEventObject(this); bool processed = HandleWindowEvent(event); + if ( processed && !wxDidCreatePaintDC ) + { + // do call MSWDefWindowProc() to validate the update region to avoid + // the problems mentioned above + processed = false; + } + // note that we must generate NC event after the normal one as otherwise // BeginPaint() will happily overwrite our decorations with the background // colour @@ -4743,15 +4865,10 @@ void wxWindowMSW::OnPaint(wxPaintEvent& event) bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc) { - // standard non top level controls (i.e. except the dialogs) always erase - // their background themselves in HandleCtlColor() or have some control- - // specific ways to set the colours (common controls) - if ( IsOfStandardClass() && !IsTopLevel() ) - return false; - switch ( GetBackgroundStyle() ) { case wxBG_STYLE_ERASE: + case wxBG_STYLE_COLOUR: // we need to generate an erase background event { wxDCTemp dc(hdc, GetClientSize()); @@ -4770,7 +4887,7 @@ bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc) if ( rc ) { - // background erase by the user-defined handler + // background erased by the user-defined handler return true; } } @@ -4786,6 +4903,7 @@ bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc) break; case wxBG_STYLE_PAINT: + case wxBG_STYLE_TRANSPARENT: // no need to do anything here at all, background will be entirely // redrawn in WM_PAINT handler break; @@ -4797,19 +4915,53 @@ bool wxWindowMSW::HandleEraseBkgnd(WXHDC hdc) return true; } +#ifdef wxHAS_MSW_BACKGROUND_ERASE_HOOK + +bool wxWindowMSW::MSWHasEraseBgHook() const +{ + return gs_eraseBgHooks.find(this) != gs_eraseBgHooks.end(); +} + +void wxWindowMSW::MSWSetEraseBgHook(wxWindow *child) +{ + if ( child ) + { + if ( !gs_eraseBgHooks.insert( + EraseBgHooks::value_type(this, child)).second ) + { + wxFAIL_MSG( wxT("Setting erase background hook twice?") ); + } + } + else // reset the hook + { + if ( gs_eraseBgHooks.erase(this) != 1 ) + { + wxFAIL_MSG( wxT("Resetting erase background which was not set?") ); + } + } +} + +#endif // wxHAS_MSW_BACKGROUND_ERASE_HOOK + bool wxWindowMSW::DoEraseBackground(WXHDC hDC) { HBRUSH hbr = (HBRUSH)MSWGetBgBrush(hDC); if ( !hbr ) return false; - wxFillRect(GetHwnd(), (HDC)hDC, hbr); + // erase just the client area of the window, this is important for the + // frames to avoid drawing over the toolbar part of the window (you might + // think using WS_CLIPCHILDREN would prevent this from happening, but it + // clearly doesn't) + RECT rc; + wxCopyRectToRECT(GetClientRect(), rc); + ::FillRect((HDC)hDC, &rc, hbr); return true; } WXHBRUSH -wxWindowMSW::MSWGetBgBrushForChild(WXHDC WXUNUSED(hDC), WXHWND hWnd) +wxWindowMSW::MSWGetBgBrushForChild(WXHDC WXUNUSED(hDC), wxWindowMSW *child) { if ( m_hasBgCol ) { @@ -4821,11 +4973,10 @@ wxWindowMSW::MSWGetBgBrushForChild(WXHDC WXUNUSED(hDC), WXHWND hWnd) // children because it would look wrong if a child of non // transparent child would show our bg colour when the child itself // does not - wxWindow *win = wxFindWinFromHandle(hWnd); - if ( win == this || + if ( child == this || m_inheritBgCol || - (win && win->HasTransparentBackground() && - win->GetParent() == this) ) + (child->HasTransparentBackground() && + child->GetParent() == this) ) { // draw children with the same colour as the parent wxBrush * @@ -4838,14 +4989,11 @@ wxWindowMSW::MSWGetBgBrushForChild(WXHDC WXUNUSED(hDC), WXHWND hWnd) return 0; } -WXHBRUSH wxWindowMSW::MSWGetBgBrush(WXHDC hDC, WXHWND hWndToPaint) +WXHBRUSH wxWindowMSW::MSWGetBgBrush(WXHDC hDC, wxWindowMSW *child) { - if ( !hWndToPaint ) - hWndToPaint = GetHWND(); - for ( wxWindowMSW *win = this; win; win = win->GetParent() ) { - WXHBRUSH hBrush = win->MSWGetBgBrushForChild(hDC, hWndToPaint); + WXHBRUSH hBrush = win->MSWGetBgBrushForChild(hDC, child); if ( hBrush ) return hBrush; @@ -6088,11 +6236,8 @@ int wxCharCodeMSWToWX(int vk, WXLPARAM lParam) return wxk; } -WXWORD wxCharCodeWXToMSW(int wxk, bool *isVirtual) +WXWORD wxCharCodeWXToMSW(int wxk) { - if ( isVirtual ) - *isVirtual = true; - // check the table first for ( size_t n = 0; n < WXSIZEOF(gs_specialKeys); n++ ) { @@ -6167,8 +6312,6 @@ WXWORD wxCharCodeWXToMSW(int wxk, bool *isVirtual) else #endif // !__WXWINCE__ { - if ( isVirtual ) - *isVirtual = false; vk = (WXWORD)wxk; } }