X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/c334a69083f81c8b4e598d533d7d5deb31783859..85d3d198c2fa866d39763ace3eebf14c0d164ba7:/src/msw/dc.cpp diff --git a/src/msw/dc.cpp b/src/msw/dc.cpp index 2984f14438..dd4750f6a0 100644 --- a/src/msw/dc.cpp +++ b/src/msw/dc.cpp @@ -25,6 +25,7 @@ #endif #ifndef WX_PRECOMP + #include "wx/msw/wrapcdlg.h" #include "wx/image.h" #include "wx/window.h" #include "wx/dc.h" @@ -35,11 +36,11 @@ #include "wx/dcmemory.h" #include "wx/log.h" #include "wx/icon.h" + #include "wx/dcprint.h" + #include "wx/module.h" #endif #include "wx/sysopt.h" -#include "wx/dcprint.h" -#include "wx/module.h" #include "wx/dynlib.h" #ifdef wxHAVE_RAW_BITMAP @@ -48,13 +49,16 @@ #include -#include "wx/msw/wrapcdlg.h" #ifndef __WIN32__ #include #endif #ifndef AC_SRC_ALPHA -#define AC_SRC_ALPHA 1 + #define AC_SRC_ALPHA 1 +#endif + +#ifndef LAYOUT_RTL + #define LAYOUT_RTL 1 #endif /* Quaternary raster codes */ @@ -196,36 +200,44 @@ private: DECLARE_NO_COPY_CLASS(StretchBltModeChanger) }; -// support for dynamic loading of msimg32.dll which we use for some functions -class wxMSImg32DLL +// helper class to cache dynamically loaded libraries and not attempt reloading +// them if it fails +class wxOnceOnlyDLLLoader { public: - // return the symbol with the given name if the DLL not loaded or symbol - // not present - static void *GetSymbol(const wxChar *name) + // ctor argument must be a literal string as we don't make a copy of it! + wxOnceOnlyDLLLoader(const wxChar *dllName) + : m_dllName(dllName) + { + }; + + + // return the symbol with the given name or NULL if the DLL not loaded + // or symbol not present + void *GetSymbol(const wxChar *name) { + // we're prepared to handle errors here wxLogNull noLog; - if ( !ms_triedToLoad ) + if ( m_dllName ) { - ms_triedToLoad = true; - ms_dll.Load(_T("msimg32")); + m_dll.Load(m_dllName); + + // reset the name whether we succeeded or failed so that we don't + // try again the next time + m_dllName = NULL; } - return ms_dll.IsLoaded() ? ms_dll.GetSymbol(name) : NULL; + return m_dll.IsLoaded() ? m_dll.GetSymbol(name) : NULL; } private: - static wxDynamicLibrary ms_dll; - static bool ms_triedToLoad; + wxDynamicLibrary m_dll; + const wxChar *m_dllName; }; -wxDynamicLibrary wxMSImg32DLL::ms_dll; -bool wxMSImg32DLL::ms_triedToLoad = false; - -// helper macro for getting the symbols from msimg32.dll: it supposes that a -// type "name_t" is defined and casts the returned symbol to it automatically -#define wxMSIMG32_SYMBOL(name) (name ## _t)wxMSImg32DLL::GetSymbol(_T(#name)) +static wxOnceOnlyDLLLoader wxGDI32DLL(_T("gdi32")); +static wxOnceOnlyDLLLoader wxMSIMG32DLL(_T("msimg32")); // =========================================================================== // implementation @@ -490,7 +502,7 @@ void wxDC::DestroyClippingRegion() // on desktop WIN32 also, since the WIN32 docs imply that the user // clipping region is independent from the paint clipping region. ::SelectClipRgn(GetHdc(), 0); -#else +#else // TODO: this should restore the previous clipping region, // so that OnPaint processing works correctly, and the update // clipping region doesn't get destroyed after the first @@ -498,7 +510,7 @@ void wxDC::DestroyClippingRegion() HRGN rgn = CreateRectRgn(0, 0, 32000, 32000); ::SelectClipRgn(GetHdc(), rgn); ::DeleteObject(rgn); -#endif +#endif } wxDCBase::DestroyClippingRegion(); @@ -554,9 +566,9 @@ void wxDC::Clear() if (!m_selectedBitmap.Ok()) return; - rect.left = 0; rect.top = 0; - rect.right = m_selectedBitmap.GetWidth(); - rect.bottom = m_selectedBitmap.GetHeight(); + rect.left = -m_deviceOriginX; rect.top = -m_deviceOriginY; + rect.right = m_selectedBitmap.GetWidth()-m_deviceOriginX; + rect.bottom = m_selectedBitmap.GetHeight()-m_deviceOriginY; } #ifndef __WXWINCE__ @@ -724,12 +736,13 @@ void wxDC::DoDrawArc(wxCoord x1, wxCoord y1, void wxDC::DoDrawCheckMark(wxCoord x1, wxCoord y1, wxCoord width, wxCoord height) { - WXMICROWIN_CHECK_HDC - + // cases when we don't have DrawFrameControl() +#if defined(__SYMANTEC__) || defined(__WXMICROWIN__) + return wxDCBase::DoDrawCheckMark(x1, y1, width, height); +#else // normal case wxCoord x2 = x1 + width, y2 = y1 + height; -#if defined(__WIN32__) && !defined(__SYMANTEC__) && !defined(__WXMICROWIN__) RECT rect; rect.left = x1; rect.top = y1; @@ -741,25 +754,10 @@ void wxDC::DoDrawCheckMark(wxCoord x1, wxCoord y1, #else DrawFrameControl(GetHdc(), &rect, DFC_MENU, DFCS_MENUCHECK); #endif -#else // Symantec-MicroWin - // draw a cross - HPEN blackPen = ::CreatePen(PS_SOLID, 1, RGB(0, 0, 0)); - HPEN whiteBrush = (HPEN)::GetStockObject(WHITE_BRUSH); - HPEN hPenOld = (HPEN)::SelectObject(GetHdc(), blackPen); - HPEN hBrushOld = (HPEN)::SelectObject(GetHdc(), whiteBrush); - ::SetROP2(GetHdc(), R2_COPYPEN); - Rectangle(GetHdc(), x1, y1, x2, y2); - MoveToEx(GetHdc(), x1, y1, NULL); - LineTo(GetHdc(), x2, y2); - MoveToEx(GetHdc(), x2, y1, NULL); - LineTo(GetHdc(), x1, y2); - ::SelectObject(GetHdc(), hPenOld); - ::SelectObject(GetHdc(), hBrushOld); - ::DeleteObject(blackPen); -#endif // Win32/Symantec-MicroWin CalcBoundingBox(x1, y1); CalcBoundingBox(x2, y2); +#endif // Microwin/Normal } void wxDC::DoDrawPoint(wxCoord x, wxCoord y) @@ -932,7 +930,7 @@ void wxDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height) // transparent pen) one pixel smaller in both directions and we want them // to have the same size regardless of which pen is used - adjust - // I wonder if this shouldn´t be done after the LOG2DEV() conversions. RR. + // I wonder if this shouldnt be done after the LOG2DEV() conversions. RR. if ( m_pen.GetStyle() == wxTRANSPARENT ) { // Apparently not needed for WinCE (see e.g. Life! demo) @@ -1247,7 +1245,8 @@ void wxDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool useMask // Rather than reproduce wxDC::Blit, let's do it at the wxWin API // level wxMemoryDC memDC; - memDC.SelectObject(bmp); + + memDC.SelectObjectAsSource(bmp); Blit(x, y, width, height, &memDC, 0, 0, wxCOPY, useMask); @@ -1502,7 +1501,7 @@ void wxDC::SetFont(const wxFont& font) else // selected ok { if ( !m_oldFont ) - m_oldFont = (WXHPEN)hfont; + m_oldFont = (WXHFONT)hfont; m_font = font; } @@ -1595,7 +1594,7 @@ void wxDC::SetBrush(const wxBrush& brush) else // selected ok { if ( !m_oldBrush ) - m_oldBrush = (WXHPEN)hbrush; + m_oldBrush = (WXHBRUSH)hbrush; m_brush = brush; } @@ -1753,10 +1752,42 @@ void wxDC::DoGetTextExtent(const wxString& string, wxCoord *x, wxCoord *y, } SIZE sizeRect; - TEXTMETRIC tm; + const size_t len = string.length(); + if ( !::GetTextExtentPoint32(GetHdc(), string, len, &sizeRect) ) + { + wxLogLastError(_T("GetTextExtentPoint32()")); + } + +#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) + // the result computed by GetTextExtentPoint32() may be too small as it + // accounts for under/overhang of the first/last character while we want + // just the bounding rect for this string so adjust the width as needed + // (using API not available in 2002 SDKs of WinCE) + if ( len > 0 ) + { + ABC width; + const wxChar chFirst = *string.begin(); + if ( ::GetCharABCWidths(GetHdc(), chFirst, chFirst, &width) ) + { + if ( width.abcA < 0 ) + sizeRect.cx -= width.abcA; - ::GetTextExtentPoint32(GetHdc(), string, string.length(), &sizeRect); - GetTextMetrics(GetHdc(), &tm); + if ( len > 1 ) + { + const wxChar chLast = *string.rbegin(); + ::GetCharABCWidths(GetHdc(), chLast, chLast, &width); + } + //else: we already have the width of the last character + + if ( width.abcC < 0 ) + sizeRect.cx -= width.abcC; + } + //else: GetCharABCWidths() failed, not a TrueType font? + } +#endif // !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) + + TEXTMETRIC tm; + ::GetTextMetrics(GetHdc(), &tm); if (x) *x = sizeRect.cx; @@ -1789,8 +1820,8 @@ bool wxDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) con { // Win9x and WinNT+ have different limits int version = wxGetOsVersion(); - maxLenText = version == wxWINDOWS_NT ? 65535 : 8192; - maxWidth = version == wxWINDOWS_NT ? INT_MAX : 32767; + maxLenText = version == wxOS_WINDOWS_NT ? 65535 : 8192; + maxWidth = version == wxOS_WINDOWS_NT ? INT_MAX : 32767; } widths.Empty(); @@ -2240,7 +2271,7 @@ bool wxDC::DoBlit(wxCoord xdest, wxCoord ydest, ds.dsBm.bmBits, (LPBITMAPINFO)&ds.dsBmih, DIB_RGB_COLORS, - SRCCOPY + dwRop ) == (int)GDI_ERROR ) { // On Win9x this API fails most (all?) of the time, so @@ -2523,7 +2554,8 @@ static bool AlphaBlt(HDC hdcDst, HDC,int,int,int,int, BLENDFUNCTION); - static AlphaBlend_t pfnAlphaBlend = wxMSIMG32_SYMBOL(AlphaBlend); + static AlphaBlend_t + pfnAlphaBlend = (AlphaBlend_t)wxMSIMG32DLL.GetSymbol(_T("AlphaBlend")); if ( pfnAlphaBlend ) { BLENDFUNCTION bf; @@ -2636,7 +2668,8 @@ void wxDC::DoGradientFillLinear (const wxRect& rect, #if defined(GRADIENT_FILL_RECT_H) && wxUSE_DYNLIB_CLASS typedef BOOL (WINAPI *GradientFill_t)(HDC, PTRIVERTEX, ULONG, PVOID, ULONG, ULONG); - static GradientFill_t pfnGradientFill = wxMSIMG32_SYMBOL(GradientFill); + static GradientFill_t pfnGradientFill = + (GradientFill_t)wxMSIMG32DLL.GetSymbol(_T("GradientFill")); if ( pfnGradientFill ) { @@ -2653,8 +2686,8 @@ void wxDC::DoGradientFillLinear (const wxRect& rect, vertices[0].x = rect.GetLeft(); vertices[0].y = rect.GetTop(); - vertices[1].x = rect.GetRight(); - vertices[1].y = rect.GetBottom(); + vertices[1].x = rect.GetRight()+1; + vertices[1].y = rect.GetBottom()+1; vertices[firstVertex].Red = (COLOR16)(initialColour.Red() << 8); vertices[firstVertex].Green = (COLOR16)(initialColour.Green() << 8); @@ -2687,3 +2720,46 @@ void wxDC::DoGradientFillLinear (const wxRect& rect, wxDCBase::DoGradientFillLinear(rect, initialColour, destColour, nDirection); } + +static DWORD wxGetDCLayout(HDC hdc) +{ + typedef DWORD (WINAPI *GetLayout_t)(HDC); + static GetLayout_t + pfnGetLayout = (GetLayout_t)wxGDI32DLL.GetSymbol(_T("GetLayout")); + + return pfnGetLayout ? pfnGetLayout(hdc) : (DWORD)-1; +} + +wxLayoutDirection wxDC::GetLayoutDirection() const +{ + DWORD layout = wxGetDCLayout(GetHdc()); + + if ( layout == (DWORD)-1 ) + return wxLayout_Default; + + return layout & LAYOUT_RTL ? wxLayout_RightToLeft : wxLayout_LeftToRight; +} + +void wxDC::SetLayoutDirection(wxLayoutDirection dir) +{ + typedef DWORD (WINAPI *SetLayout_t)(HDC, DWORD); + static SetLayout_t + pfnSetLayout = (SetLayout_t)wxGDI32DLL.GetSymbol(_T("SetLayout")); + if ( !pfnSetLayout ) + return; + + if ( dir == wxLayout_Default ) + { + dir = wxTheApp->GetLayoutDirection(); + if ( dir == wxLayout_Default ) + return; + } + + DWORD layout = wxGetDCLayout(GetHdc()); + if ( dir == wxLayout_RightToLeft ) + layout |= LAYOUT_RTL; + else + layout &= ~LAYOUT_RTL; + + pfnSetLayout(GetHdc(), layout); +}