X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/155ecd4c4221d3bbc7aa93d472d11948f21d21ab..6e9b091980fe67d20eb9dd862460b463738aae6f:/src/gtk/dcclient.cpp?ds=sidebyside diff --git a/src/gtk/dcclient.cpp b/src/gtk/dcclient.cpp index 805f66d495..2896f3c5b2 100644 --- a/src/gtk/dcclient.cpp +++ b/src/gtk/dcclient.cpp @@ -17,22 +17,21 @@ #include "wx/dcclient.h" #ifndef WX_PRECOMP + #include "wx/window.h" #include "wx/log.h" #include "wx/dcmemory.h" #include "wx/math.h" // for floating-point functions #include "wx/image.h" + #include "wx/module.h" #endif -#include "wx/module.h" #include "wx/fontutil.h" +#include "wx/scrolwin.h" #include "wx/gtk/win_gtk.h" #include "wx/gtk/private.h" -#include #include -#include -#include //----------------------------------------------------------------------------- // local defines @@ -82,6 +81,7 @@ static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; } #include "gdk/gdkprivate.h" +static void gdk_wx_draw_bitmap(GdkDrawable *drawable, GdkGC *gc, GdkDrawable *src, @@ -252,9 +252,13 @@ static void wxFreePoolGC( GdkGC *gc ) // wxWindowDC //----------------------------------------------------------------------------- +#if wxUSE_NEW_DC +IMPLEMENT_DYNAMIC_CLASS(wxGTKWindowImplDC, wxGTKImplDC) +#else IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC) +#endif -wxWindowDC::wxWindowDC() +wxGTKWindowImplDC::wxGTKWindowImplDC() { m_penGC = (GdkGC *) NULL; m_brushGC = (GdkGC *) NULL; @@ -269,7 +273,7 @@ wxWindowDC::wxWindowDC() m_fontdesc = (PangoFontDescription *)NULL; } -wxWindowDC::wxWindowDC( wxWindow *window ) +wxGTKWindowImplDC::wxGTKWindowImplDC( wxWindow *window ) { wxASSERT_MSG( window, wxT("DC needs a window") ); @@ -324,9 +328,18 @@ wxWindowDC::wxWindowDC( wxWindow *window ) standard (as e.g. wxStatusBar) */ m_owner = window; + + if (m_owner && m_owner->m_wxwindow && (m_owner->GetLayoutDirection() == wxLayout_RightToLeft)) + { + // reverse sense + m_signX = -1; + + // origin in the upper right corner + m_deviceOriginX = m_owner->GetClientSize().x; + } } -wxWindowDC::~wxWindowDC() +wxGTKWindowImplDC::~wxGTKWindowImplDC() { Destroy(); @@ -336,7 +349,7 @@ wxWindowDC::~wxWindowDC() pango_font_description_free( m_fontdesc ); } -void wxWindowDC::SetUpDC() +void wxGTKWindowImplDC::SetUpDC() { m_ok = true; @@ -383,6 +396,8 @@ void wxWindowDC::SetUpDC() gdk_gc_set_fill( m_textGC, GDK_SOLID ); + gdk_gc_set_colormap( m_textGC, m_cmap ); + /* m_penGC */ m_pen.GetColour().CalcPixel( m_cmap ); gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() ); @@ -426,7 +441,7 @@ void wxWindowDC::SetUpDC() } } -void wxWindowDC::DoGetSize( int* width, int* height ) const +void wxGTKWindowImplDC::DoGetSize( int* width, int* height ) const { wxCHECK_RET( m_owner, _T("GetSize() doesn't work without window") ); @@ -436,13 +451,13 @@ void wxWindowDC::DoGetSize( int* width, int* height ) const extern bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y, const wxColour & col, int style); -bool wxWindowDC::DoFloodFill(wxCoord x, wxCoord y, +bool wxGTKWindowImplDC::DoFloodFill(wxCoord x, wxCoord y, const wxColour& col, int style) { return wxDoFloodFill(this, x, y, col, style); } -bool wxWindowDC::DoGetPixel( wxCoord x1, wxCoord y1, wxColour *col ) const +bool wxGTKWindowImplDC::DoGetPixel( wxCoord x1, wxCoord y1, wxColour *col ) const { // Generic (and therefore rather inefficient) method. // Could be improved. @@ -457,7 +472,7 @@ bool wxWindowDC::DoGetPixel( wxCoord x1, wxCoord y1, wxColour *col ) const return true; } -void wxWindowDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 ) +void wxGTKWindowImplDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 ) { wxCHECK_RET( Ok(), wxT("invalid window dc") ); @@ -471,7 +486,7 @@ void wxWindowDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 ) } } -void wxWindowDC::DoCrossHair( wxCoord x, wxCoord y ) +void wxGTKWindowImplDC::DoCrossHair( wxCoord x, wxCoord y ) { wxCHECK_RET( Ok(), wxT("invalid window dc") ); @@ -490,7 +505,7 @@ void wxWindowDC::DoCrossHair( wxCoord x, wxCoord y ) } } -void wxWindowDC::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, +void wxGTKWindowImplDC::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord xc, wxCoord yc ) { wxCHECK_RET( Ok(), wxT("invalid window dc") ); @@ -573,8 +588,11 @@ void wxWindowDC::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, { gdk_draw_arc( m_window, m_penGC, FALSE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 ); - gdk_draw_line( m_window, m_penGC, xx1, yy1, xxc, yyc ); - gdk_draw_line( m_window, m_penGC, xxc, yyc, xx2, yy2 ); + if ((m_brush.GetStyle() != wxTRANSPARENT) && (alpha2 - alpha1 != 360*64)) + { + gdk_draw_line( m_window, m_penGC, xx1, yy1, xxc, yyc ); + gdk_draw_line( m_window, m_penGC, xxc, yyc, xx2, yy2 ); + } } } @@ -582,7 +600,7 @@ void wxWindowDC::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, CalcBoundingBox (x2, y2); } -void wxWindowDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double sa, double ea ) +void wxGTKWindowImplDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double sa, double ea ) { wxCHECK_RET( Ok(), wxT("invalid window dc") ); @@ -644,7 +662,7 @@ void wxWindowDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord width, wxCoord CalcBoundingBox (x + width, y + height); } -void wxWindowDC::DoDrawPoint( wxCoord x, wxCoord y ) +void wxGTKWindowImplDC::DoDrawPoint( wxCoord x, wxCoord y ) { wxCHECK_RET( Ok(), wxT("invalid window dc") ); @@ -654,7 +672,7 @@ void wxWindowDC::DoDrawPoint( wxCoord x, wxCoord y ) CalcBoundingBox (x, y); } -void wxWindowDC::DoDrawLines( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset ) +void wxGTKWindowImplDC::DoDrawLines( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset ) { wxCHECK_RET( Ok(), wxT("invalid window dc") ); @@ -662,98 +680,61 @@ void wxWindowDC::DoDrawLines( int n, wxPoint points[], wxCoord xoffset, wxCoord if (n <= 0) return; //Check, if scaling is necessary - bool doScale(true); - long val(10); - if (!xoffset) - if (!yoffset) - if (XLOG2DEV(val)==val) - if (YLOG2DEV(val)==val) - doScale = false; + const bool doScale = + xoffset != 0 || yoffset != 0 || XLOG2DEV(10) != 10 || YLOG2DEV(10) != 10; - GdkPoint *gpts = NULL; + // GdkPoint and wxPoint have the same memory layout, so we can cast one to the other + GdkPoint* gpts = reinterpret_cast(points); - if (doScale){ + if (doScale) gpts = new GdkPoint[n]; - if (! gpts) - { - wxFAIL_MSG( wxT("Cannot allocate PolyLine") ); - return; - } for (int i = 0; i < n; i++) { - wxCoord x1 = XLOG2DEV(points[i].x + xoffset); - wxCoord y1 = YLOG2DEV(points[i].y + yoffset); - - CalcBoundingBox( x1 + xoffset, y1 + yoffset ); - - gpts[i].x = x1; - gpts[i].y = y1; - } - } - else { - for (int i = 0; i < n; i++) { - CalcBoundingBox( points[i].x, points[i].y ); + if (doScale) + { + gpts[i].x = XLOG2DEV(points[i].x + xoffset); + gpts[i].y = YLOG2DEV(points[i].y + yoffset); } - - //GdkPoint and wxPoint have the same memory allignment, so we can cast one into another - gpts = reinterpret_cast(points); + CalcBoundingBox(points[i].x + xoffset, points[i].y + yoffset); } if (m_window) gdk_draw_lines( m_window, m_penGC, gpts, n); if (doScale) - delete[] gpts; + delete[] gpts; } -void wxWindowDC::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, int WXUNUSED(fillStyle) ) +void wxGTKWindowImplDC::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, int WXUNUSED(fillStyle) ) { wxCHECK_RET( Ok(), wxT("invalid window dc") ); if (n <= 0) return; //Check, if scaling is necessary - bool doScale(true); - long val(10); - if (!xoffset) - if (!yoffset) - if (XLOG2DEV(val)==val) - if (YLOG2DEV(val)==val){ - doScale = false; - } + const bool doScale = + xoffset != 0 || yoffset != 0 || XLOG2DEV(10) != 10 || YLOG2DEV(10) != 10; - GdkPoint *gdkpoints = NULL; + // GdkPoint and wxPoint have the same memory layout, so we can cast one to the other + GdkPoint* gdkpoints = reinterpret_cast(points); - if (doScale){ - gdkpoints = new GdkPoint[n+1]; //FIXME: Why the "+1" + if (doScale) + gdkpoints = new GdkPoint[n]; int i; for (i = 0 ; i < n ; i++) { - gdkpoints[i].x = XLOG2DEV(points[i].x + xoffset); - gdkpoints[i].y = YLOG2DEV(points[i].y + yoffset); - - CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset ); - } - } - else { - int i(0); - for (; i < n ; ++i) { - CalcBoundingBox( points[i].x, points[i].y ); + if (doScale) + { + gdkpoints[i].x = XLOG2DEV(points[i].x + xoffset); + gdkpoints[i].y = YLOG2DEV(points[i].y + yoffset); } - //GdkPoint and wxPoint have the same memory allignment, so we can cast one into another - gdkpoints = reinterpret_cast (points); + CalcBoundingBox(points[i].x + xoffset, points[i].y + yoffset); } if (m_window) { - //I think wxSOLID is the most often used style (it is for me), - //so I put it in front of the if ... ifelse's - if (m_brush.GetStyle() == wxSOLID) - { - gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n ); - }else if (m_brush.GetStyle() != wxTRANSPARENT) { if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask())) @@ -808,10 +789,10 @@ void wxWindowDC::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wxCoor } if (doScale) - delete[] gdkpoints; + delete[] gdkpoints; } -void wxWindowDC::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) +void wxGTKWindowImplDC::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) { wxCHECK_RET( Ok(), wxT("invalid window dc") ); @@ -866,14 +847,43 @@ void wxWindowDC::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord h } if (m_pen.GetStyle() != wxTRANSPARENT) - gdk_draw_rectangle( m_window, m_penGC, FALSE, xx, yy, ww-1, hh-1 ); + { +#if 1 + if ((m_pen.GetWidth() == 2) && (m_pen.GetCap() == wxCAP_ROUND) && + (m_pen.GetJoin() == wxJOIN_ROUND) && (m_pen.GetStyle() == wxSOLID)) + { + // Use 2 1-line rects instead + gdk_gc_set_line_attributes( m_penGC, 1, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND ); + + if (m_signX == -1) + { + // Different for RTL + gdk_draw_rectangle( m_window, m_penGC, FALSE, xx+1, yy, ww-2, hh-2 ); + gdk_draw_rectangle( m_window, m_penGC, FALSE, xx, yy-1, ww, hh ); + } + else + { + gdk_draw_rectangle( m_window, m_penGC, FALSE, xx, yy, ww-2, hh-2 ); + gdk_draw_rectangle( m_window, m_penGC, FALSE, xx-1, yy-1, ww, hh ); + } + + // reset + gdk_gc_set_line_attributes( m_penGC, 2, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND ); + } + else +#endif + { + // Just use X11 for other cases + gdk_draw_rectangle( m_window, m_penGC, FALSE, xx, yy, ww-1, hh-1 ); + } + } } CalcBoundingBox( x, y ); CalcBoundingBox( x + width, y + height ); } -void wxWindowDC::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius ) +void wxGTKWindowImplDC::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius ) { wxCHECK_RET( Ok(), wxT("invalid window dc") ); @@ -996,7 +1006,7 @@ void wxWindowDC::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord width, wx CalcBoundingBox( x + width, y + height ); } -void wxWindowDC::DoDrawEllipse( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) +void wxGTKWindowImplDC::DoDrawEllipse( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) { wxCHECK_RET( Ok(), wxT("invalid window dc") ); @@ -1055,13 +1065,13 @@ void wxWindowDC::DoDrawEllipse( wxCoord x, wxCoord y, wxCoord width, wxCoord hei CalcBoundingBox( x + width, y + height ); } -void wxWindowDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y ) +void wxGTKWindowImplDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y ) { // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why DoDrawBitmap( (const wxBitmap&)icon, x, y, true ); } -void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap, +void wxGTKWindowImplDC::DoDrawBitmap( const wxBitmap &bitmap, wxCoord x, wxCoord y, bool useMask ) { @@ -1078,6 +1088,9 @@ void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap, int w = bitmap.GetWidth(); int h = bitmap.GetHeight(); + if (m_owner && m_owner->GetLayoutDirection() == wxLayout_RightToLeft) + xx -= w; + CalcBoundingBox( x, y ); CalcBoundingBox( x + w, y + h ); @@ -1100,21 +1113,23 @@ void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap, if ((w != ww) || (h != hh)) use_bitmap = use_bitmap.Rescale( 0, 0, ww, hh, ww, hh ); -#if !GTK_CHECK_VERSION(2,2,0) // NB: We can't render pixbufs with GTK+ < 2.2, we need to use pixmaps code. // Pixbufs-based bitmaps with alpha channel don't have a mask, so we // have to call GetPixmap() here -- it converts the pixbuf into pixmap // and also creates the mask as a side-effect: - use_bitmap.GetPixmap(); -#endif + if (gtk_check_version(2,2,0)) + use_bitmap.GetPixmap(); // apply mask if any GdkBitmap *mask = (GdkBitmap *) NULL; - if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap(); + if (useMask && use_bitmap.GetMask()) + mask = use_bitmap.GetMask()->GetBitmap(); + + GdkGC* use_gc = is_mono ? m_textGC : m_penGC; GdkBitmap *new_mask = (GdkBitmap*) NULL; - if (useMask && mask) + if (mask != NULL) { if (!m_currentClippingRegion.IsNull()) { @@ -1133,25 +1148,12 @@ void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap, gdk_gc_set_fill( gc, GDK_OPAQUE_STIPPLED ); gdk_gc_set_stipple( gc, mask ); gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, ww, hh ); + mask = new_mask; g_object_unref (gc); } - if (is_mono) - { - if (new_mask) - gdk_gc_set_clip_mask( m_textGC, new_mask ); - else - gdk_gc_set_clip_mask( m_textGC, mask ); - gdk_gc_set_clip_origin( m_textGC, xx, yy ); - } - else - { - if (new_mask) - gdk_gc_set_clip_mask( m_penGC, new_mask ); - else - gdk_gc_set_clip_mask( m_penGC, mask ); - gdk_gc_set_clip_origin( m_penGC, xx, yy ); - } + gdk_gc_set_clip_mask(use_gc, mask); + gdk_gc_set_clip_origin(use_gc, xx, yy); } // Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For @@ -1164,7 +1166,7 @@ void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap, gdk_gc_set_background( gc, m_textBackgroundColour.GetColor() ); gdk_wx_draw_bitmap( bitmap2, gc, use_bitmap.GetPixmap(), 0, 0, 0, 0, -1, -1 ); - gdk_draw_drawable( m_window, m_textGC, bitmap2, 0, 0, xx, yy, -1, -1 ); + gdk_draw_drawable(m_window, use_gc, bitmap2, 0, 0, xx, yy, -1, -1); g_object_unref (bitmap2); g_object_unref (gc); @@ -1174,7 +1176,7 @@ void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap, #if GTK_CHECK_VERSION(2,2,0) if (!gtk_check_version(2,2,0) && use_bitmap.HasPixbuf()) { - gdk_draw_pixbuf(m_window, m_penGC, + gdk_draw_pixbuf(m_window, use_gc, use_bitmap.GetPixbuf(), 0, 0, xx, yy, -1, -1, GDK_RGB_DITHER_NORMAL, xx, yy); @@ -1182,36 +1184,25 @@ void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap, else #endif { - gdk_draw_drawable(m_window, m_penGC, + gdk_draw_drawable(m_window, use_gc, use_bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1); } } // remove mask again if any - if (useMask && mask) + if (mask != NULL) { - if (is_mono) - { - gdk_gc_set_clip_mask( m_textGC, (GdkBitmap *) NULL ); - gdk_gc_set_clip_origin( m_textGC, 0, 0 ); - if (!m_currentClippingRegion.IsNull()) - gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() ); - } - else - { - gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL ); - gdk_gc_set_clip_origin( m_penGC, 0, 0 ); - if (!m_currentClippingRegion.IsNull()) - gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() ); - } + gdk_gc_set_clip_mask(use_gc, NULL); + gdk_gc_set_clip_origin(use_gc, 0, 0); + if (!m_currentClippingRegion.IsNull()) + gdk_gc_set_clip_region(use_gc, m_currentClippingRegion.GetRegion()); + if (new_mask != NULL) + g_object_unref(new_mask); } - - if (new_mask) - g_object_unref (new_mask); } -bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, +bool wxGTKWindowImplDC::DoBlit( wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height, wxDC *source, wxCoord xsrc, wxCoord ysrc, @@ -1226,11 +1217,17 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, if (!m_window) return false; // transform the source DC coords to the device ones - xsrc = source->XLOG2DEV(xsrc); - ysrc = source->YLOG2DEV(ysrc); + xsrc = source->LogicalToDeviceX(xsrc); + ysrc = source->LogicalToDeviceY(ysrc); - wxClientDC *srcDC = (wxClientDC*)source; - wxMemoryDC *memDC = (wxMemoryDC*)source; + wxBitmap selected; + wxMemoryDC *memDC = wxDynamicCast(source, wxMemoryDC); + if ( memDC ) + { + selected = memDC->GetSelectedBitmap(); + if ( !selected.IsOk() ) + return false; + } bool use_bitmap_method = false; bool is_mono = false; @@ -1241,11 +1238,9 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, ysrcMask = ysrc; } - if (srcDC->m_isMemDC) + if (selected.Ok()) { - if (!memDC->m_selected.Ok()) return false; - - is_mono = (memDC->m_selected.GetDepth() == 1); + is_mono = (selected.GetDepth() == 1); // we use the "XCopyArea" way to copy a memory dc into // a different window if the memory dc BOTH @@ -1253,7 +1248,7 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, // b) it is clipped // c) is not 1-bit - if (useMask && (memDC->m_selected.GetMask())) + if (useMask && (selected.GetMask())) { // we HAVE TO use the direct way for memory dcs // that have mask since the XCopyArea doesn't know @@ -1268,8 +1263,8 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, use_bitmap_method = true; } else if ((xsrc == 0) && (ysrc == 0) && - (width == memDC->m_selected.GetWidth()) && - (height == memDC->m_selected.GetHeight())) + (width == selected.GetWidth()) && + (height == selected.GetHeight())) { // we SHOULD use the direct way if all of the bitmap // in the memory dc is copied in which case XCopyArea @@ -1277,10 +1272,6 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, // the area to be scaled use_bitmap_method = true; } - else - { - use_bitmap_method = false; - } } CalcBoundingBox( xdest, ydest ); @@ -1308,8 +1299,8 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, if (use_bitmap_method) { // scale/translate bitmap size - wxCoord bm_width = memDC->m_selected.GetWidth(); - wxCoord bm_height = memDC->m_selected.GetHeight(); + wxCoord bm_width = selected.GetWidth(); + wxCoord bm_height = selected.GetHeight(); // Get clip coords for the bitmap. If we don't // use wxBitmap::Rescale(), which can clip the @@ -1330,32 +1321,31 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, wxCoord bm_hh = YLOG2DEVREL( bm_height ); // Scale bitmap if required - wxBitmap use_bitmap; - if ((memDC->m_selected.GetWidth()!= bm_ww) || ( memDC->m_selected.GetHeight()!= bm_hh)) + wxBitmap use_bitmap = selected; + if ((selected.GetWidth()!= bm_ww) || ( selected.GetHeight()!= bm_hh)) { // This indicates that the blitting code below will get // a clipped bitmap and therefore needs to move the origin // accordingly wxRegion tmp( xx,yy,ww,hh ); - tmp.Intersect( m_currentClippingRegion ); + if (!m_currentClippingRegion.IsNull()) + tmp.Intersect( m_currentClippingRegion ); tmp.GetBox(cx,cy,cw,ch); // Scale and clipped bitmap - use_bitmap = memDC->m_selected.Rescale(cx-xx,cy-yy,cw,ch,bm_ww,bm_hh); - } - else - { - // Don't scale bitmap - use_bitmap = memDC->m_selected; + use_bitmap = selected.Rescale(cx-xx,cy-yy,cw,ch,bm_ww,bm_hh); } // apply mask if any GdkBitmap *mask = (GdkBitmap *) NULL; - if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap(); + if (useMask && use_bitmap.GetMask()) + mask = use_bitmap.GetMask()->GetBitmap(); + + GdkGC* use_gc = is_mono ? m_textGC : m_penGC; GdkBitmap *new_mask = (GdkBitmap*) NULL; - if (useMask && mask) + if (mask != NULL) { if (!m_currentClippingRegion.IsNull()) { @@ -1376,35 +1366,15 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, gdk_gc_set_fill( gc, GDK_OPAQUE_STIPPLED ); gdk_gc_set_stipple( gc, mask ); gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, bm_ww, bm_hh ); + mask = new_mask; g_object_unref (gc); } - if (is_mono) - { - if (new_mask) - { - gdk_gc_set_clip_mask( m_textGC, new_mask ); - gdk_gc_set_clip_origin( m_textGC, cx, cy ); - } - else - { - gdk_gc_set_clip_mask( m_textGC, mask ); - gdk_gc_set_clip_origin( m_textGC, cx-xsrcMask, cy-ysrcMask ); - } - } + gdk_gc_set_clip_mask(use_gc, mask); + if (new_mask != NULL) + gdk_gc_set_clip_origin(use_gc, cx, cy); else - { - if (new_mask) - { - gdk_gc_set_clip_mask( m_penGC, new_mask ); - gdk_gc_set_clip_origin( m_penGC, cx, cy ); - } - else - { - gdk_gc_set_clip_mask( m_penGC, mask ); - gdk_gc_set_clip_origin( m_penGC, cx-xsrcMask, cy-ysrcMask ); - } - } + gdk_gc_set_clip_origin(use_gc, cx - xsrcMask, cy - ysrcMask); } // Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For @@ -1418,7 +1388,7 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, gdk_gc_set_background( gc, m_textBackgroundColour.GetColor() ); gdk_wx_draw_bitmap( bitmap, gc, use_bitmap.GetPixmap(), 0, 0, 0, 0, -1, -1 ); - gdk_draw_drawable( m_window, m_textGC, bitmap, xsrc, ysrc, cx, cy, cw, ch ); + gdk_draw_drawable(m_window, use_gc, bitmap, xsrc, ysrc, cx, cy, cw, ch); g_object_unref (bitmap); g_object_unref (gc); @@ -1426,26 +1396,16 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, else { // was: gdk_draw_drawable( m_window, m_penGC, use_bitmap.GetPixmap(), xsrc, ysrc, xx, yy, ww, hh ); - gdk_draw_drawable( m_window, m_penGC, use_bitmap.GetPixmap(), xsrc, ysrc, cx, cy, cw, ch ); + gdk_draw_drawable(m_window, use_gc, use_bitmap.GetPixmap(), xsrc, ysrc, cx, cy, cw, ch); } // remove mask again if any - if (useMask && mask) + if (mask != NULL) { - if (is_mono) - { - gdk_gc_set_clip_mask( m_textGC, (GdkBitmap *) NULL ); - gdk_gc_set_clip_origin( m_textGC, 0, 0 ); - if (!m_currentClippingRegion.IsNull()) - gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() ); - } - else - { - gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL ); - gdk_gc_set_clip_origin( m_penGC, 0, 0 ); - if (!m_currentClippingRegion.IsNull()) - gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() ); - } + gdk_gc_set_clip_mask(use_gc, NULL); + gdk_gc_set_clip_origin(use_gc, 0, 0); + if (!m_currentClippingRegion.IsNull()) + gdk_gc_set_clip_region(use_gc, m_currentClippingRegion.GetRegion()); } if (new_mask) @@ -1453,7 +1413,7 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, } else // use_bitmap_method { - if ((width != ww) || (height != hh)) + if (selected.Ok() && ((width != ww) || (height != hh))) { // get clip coords wxRegion tmp( xx,yy,ww,hh ); @@ -1462,7 +1422,7 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, tmp.GetBox(cx,cy,cw,ch); // rescale bitmap - wxBitmap bitmap = memDC->m_selected.Rescale( cx-xx, cy-yy, cw, ch, ww, hh ); + wxBitmap bitmap = selected.Rescale( cx-xx, cy-yy, cw, ch, ww, hh ); // draw scaled bitmap // was: gdk_draw_drawable( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 ); @@ -1472,10 +1432,14 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, { // No scaling and not a memory dc with a mask either + GdkWindow* window = source->GetGDKWindow(); + if ( !window ) + return false; + // copy including child window contents gdk_gc_set_subwindow( m_penGC, GDK_INCLUDE_INFERIORS ); gdk_draw_drawable( m_window, m_penGC, - srcDC->GetWindow(), + window, xsrc, ysrc, xx, yy, width, height ); gdk_gc_set_subwindow( m_penGC, GDK_CLIP_BY_CHILDREN ); @@ -1487,7 +1451,7 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, return true; } -void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) +void wxGTKWindowImplDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) { wxCHECK_RET( Ok(), wxT("invalid window dc") ); @@ -1502,13 +1466,53 @@ void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) wxCHECK_RET( m_layout, wxT("no Pango layout") ); wxCHECK_RET( m_fontdesc, wxT("no Pango font description") ); + gdk_pango_context_set_colormap( m_context, m_cmap ); + bool underlined = m_font.Ok() && m_font.GetUnderlined(); const wxCharBuffer data = wxGTK_CONV( text ); if ( !data ) return; - const size_t datalen = strlen(data); - pango_layout_set_text( m_layout, data, datalen); + size_t datalen = strlen(data); + + // in Pango >= 1.16 the "underline of leading/trailing spaces" bug + // has been fixed and thus the hack implemented below should never be used + static bool pangoOk = !wx_pango_version_check(1, 16, 0); + + bool needshack = underlined && !pangoOk; + char *hackstring = NULL; + + if (needshack) + { + // a PangoLayout which has leading/trailing spaces with underlined font + // is not correctly drawn by this pango version: Pango won't underline the spaces. + // This can be a problem; e.g. wxHTML rendering of underlined text relies on + // this behaviour. To workaround this problem, we use a special hack here + // suggested by pango maintainer Behdad Esfahbod: we prepend and append two + // empty space characters and give them a dummy colour attribute. + // This will force Pango to underline the leading/trailing spaces, too. + + // need to realloc the string to prepend & append our special characters + hackstring = (char*)malloc((datalen+7)*sizeof(char)); + + // copy the leading U+200C ZERO WIDTH NON-JOINER encoded in UTF8 format + strcpy(hackstring, "\342\200\214"); + + // copy the user string + memcpy(&hackstring[3], data, datalen); + + // copy the trailing U+200C ZERO WIDTH NON-JOINER encoded in UTF8 format + strcpy(&hackstring[datalen+3], "\342\200\214"); + + // the special characters that we added require 6 additional bytes: + datalen += 6; + + pango_layout_set_text(m_layout, hackstring, datalen); + } + else + { + pango_layout_set_text(m_layout, data, datalen); + } if (underlined) { @@ -1517,6 +1521,22 @@ void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) a->start_index = 0; a->end_index = datalen; pango_attr_list_insert(attrs, a); + + if (needshack) + { + // dummy colour for the leading space + a = pango_attr_foreground_new (0x0057, 0x52A9, 0xD614); + a->start_index = 0; + a->end_index = 1; + pango_attr_list_insert(attrs, a); + + // dummy colour for the trailing space + a = pango_attr_foreground_new (0x0057, 0x52A9, 0xD614); + a->start_index = datalen - 1; + a->end_index = datalen; + pango_attr_list_insert(attrs, a); + } + pango_layout_set_attributes(m_layout, attrs); pango_attr_list_unref(attrs); } @@ -1546,7 +1566,10 @@ void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) } // Draw layout. - gdk_draw_layout( m_window, m_textGC, x, y, m_layout ); + if (m_owner && m_owner->GetLayoutDirection() == wxLayout_RightToLeft) + gdk_draw_layout( m_window, m_textGC, x-w, y, m_layout ); + else + gdk_draw_layout( m_window, m_textGC, x, y, m_layout ); // reset unscaled size pango_font_description_set_size( m_fontdesc, oldSize ); @@ -1563,8 +1586,12 @@ void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) gdk_draw_rectangle(m_window, m_textGC, TRUE, x, y, w, h); gdk_gc_set_foreground(m_textGC, m_textForegroundColour.GetColor()); } + // Draw layout. - gdk_draw_layout( m_window, m_textGC, x, y, m_layout ); + if (m_owner && m_owner->GetLayoutDirection() == wxLayout_RightToLeft) + gdk_draw_layout( m_window, m_textGC, x-w, y, m_layout ); + else + gdk_draw_layout( m_window, m_textGC, x, y, m_layout ); } if (underlined) @@ -1580,6 +1607,9 @@ void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) height = wxCoord(height / m_scaleY); CalcBoundingBox (x + width, y + height); CalcBoundingBox (x, y); + + if (hackstring) + free(hackstring); } @@ -1587,7 +1617,7 @@ void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) // a better approach here: // http://www.daa.com.au/pipermail/pygtk/2003-April/005052.html -void wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, double angle ) +void wxGTKWindowImplDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, double angle ) { if (!m_window || text.empty()) return; @@ -1689,10 +1719,10 @@ void wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, CalcBoundingBox(x + maxX, y + maxY); } -void wxWindowDC::DoGetTextExtent(const wxString &string, +void wxGTKWindowImplDC::DoGetTextExtent(const wxString &string, wxCoord *width, wxCoord *height, wxCoord *descent, wxCoord *externalLeading, - wxFont *theFont) const + const wxFont *theFont) const { if ( width ) *width = 0; @@ -1748,11 +1778,55 @@ void wxWindowDC::DoGetTextExtent(const wxString &string, } // Reset old font description - if (theFont) + if (theFont->IsOk()) pango_layout_set_font_description( m_layout, m_fontdesc ); } -wxCoord wxWindowDC::GetCharWidth() const + +bool wxGTKWindowImplDC::DoGetPartialTextExtents(const wxString& text, + wxArrayInt& widths) const +{ + const size_t len = text.length(); + widths.Empty(); + widths.Add(0, len); + + if (text.empty()) + return true; + + // Set layout's text + const wxCharBuffer dataUTF8 = wxGTK_CONV_FONT(text, m_font); + if ( !dataUTF8 ) + { + // hardly ideal, but what else can we do if conversion failed? + wxLogLastError(wxT("DoGetPartialTextExtents")); + return false; + } + + pango_layout_set_text( m_layout, dataUTF8, strlen(dataUTF8) ); + + // Calculate the position of each character based on the widths of + // the previous characters + + // Code borrowed from Scintilla's PlatGTK + PangoLayoutIter *iter = pango_layout_get_iter(m_layout); + PangoRectangle pos; + pango_layout_iter_get_cluster_extents(iter, NULL, &pos); + size_t i = 0; + while (pango_layout_iter_next_cluster(iter)) + { + pango_layout_iter_get_cluster_extents(iter, NULL, &pos); + int position = PANGO_PIXELS(pos.x); + widths[i++] = position; + } + while (i < len) + widths[i++] = PANGO_PIXELS(pos.x + pos.width); + pango_layout_iter_free(iter); + + return true; +} + + +wxCoord wxGTKWindowImplDC::GetCharWidth() const { pango_layout_set_text( m_layout, "H", 1 ); int w; @@ -1760,15 +1834,18 @@ wxCoord wxWindowDC::GetCharWidth() const return w; } -wxCoord wxWindowDC::GetCharHeight() const +wxCoord wxGTKWindowImplDC::GetCharHeight() const { - pango_layout_set_text( m_layout, "H", 1 ); - int h; - pango_layout_get_pixel_size( m_layout, NULL, &h ); + PangoFontMetrics *metrics = pango_context_get_metrics (m_context, m_fontdesc, pango_context_get_language(m_context)); + wxCHECK_MSG( metrics, -1, _T("failed to get pango font metrics") ); + + wxCoord h = PANGO_PIXELS (pango_font_metrics_get_descent (metrics) + + pango_font_metrics_get_ascent (metrics)); + pango_font_metrics_unref (metrics); return h; } -void wxWindowDC::Clear() +void wxGTKWindowImplDC::Clear() { wxCHECK_RET( Ok(), wxT("invalid window dc") ); @@ -1806,7 +1883,7 @@ void wxWindowDC::Clear() #endif // 0/1 } -void wxWindowDC::SetFont( const wxFont &font ) +void wxGTKWindowImplDC::SetFont( const wxFont &font ) { m_font = font; @@ -1840,7 +1917,7 @@ void wxWindowDC::SetFont( const wxFont &font ) } } -void wxWindowDC::SetPen( const wxPen &pen ) +void wxGTKWindowImplDC::SetPen( const wxPen &pen ) { wxCHECK_RET( Ok(), wxT("invalid window dc") ); @@ -1990,7 +2067,7 @@ void wxWindowDC::SetPen( const wxPen &pen ) gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() ); } -void wxWindowDC::SetBrush( const wxBrush &brush ) +void wxGTKWindowImplDC::SetBrush( const wxBrush &brush ) { wxCHECK_RET( Ok(), wxT("invalid window dc") ); @@ -2035,7 +2112,7 @@ void wxWindowDC::SetBrush( const wxBrush &brush ) } } -void wxWindowDC::SetBackground( const wxBrush &brush ) +void wxGTKWindowImplDC::SetBackground( const wxBrush &brush ) { /* CMB 21/7/98: Added SetBackground. Sets background brush * for Clear() and bg colour for shapes filled with cross-hatch brush */ @@ -2080,7 +2157,7 @@ void wxWindowDC::SetBackground( const wxBrush &brush ) } } -void wxWindowDC::SetLogicalFunction( int function ) +void wxGTKWindowImplDC::SetLogicalFunction( int function ) { wxCHECK_RET( Ok(), wxT("invalid window dc") ); @@ -2128,7 +2205,7 @@ void wxWindowDC::SetLogicalFunction( int function ) gdk_gc_set_function( m_textGC, mode ); } -void wxWindowDC::SetTextForeground( const wxColour &col ) +void wxGTKWindowImplDC::SetTextForeground( const wxColour &col ) { wxCHECK_RET( Ok(), wxT("invalid window dc") ); @@ -2147,7 +2224,7 @@ void wxWindowDC::SetTextForeground( const wxColour &col ) } } -void wxWindowDC::SetTextBackground( const wxColour &col ) +void wxGTKWindowImplDC::SetTextBackground( const wxColour &col ) { wxCHECK_RET( Ok(), wxT("invalid window dc") ); @@ -2164,7 +2241,7 @@ void wxWindowDC::SetTextBackground( const wxColour &col ) } } -void wxWindowDC::SetBackgroundMode( int mode ) +void wxGTKWindowImplDC::SetBackgroundMode( int mode ) { wxCHECK_RET( Ok(), wxT("invalid window dc") ); @@ -2182,12 +2259,12 @@ void wxWindowDC::SetBackgroundMode( int mode ) } } -void wxWindowDC::SetPalette( const wxPalette& WXUNUSED(palette) ) +void wxGTKWindowImplDC::SetPalette( const wxPalette& WXUNUSED(palette) ) { - wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") ); + wxFAIL_MSG( wxT("wxGTKWindowImplDC::SetPalette not implemented") ); } -void wxWindowDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) +void wxGTKWindowImplDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) { wxCHECK_RET( Ok(), wxT("invalid window dc") ); @@ -2199,6 +2276,11 @@ void wxWindowDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoo rect.width = XLOG2DEVREL(width); rect.height = YLOG2DEVREL(height); + if (m_owner && m_owner->m_wxwindow && (m_owner->GetLayoutDirection() == wxLayout_RightToLeft)) + { + rect.x -= rect.width; + } + if (!m_currentClippingRegion.IsNull()) m_currentClippingRegion.Intersect( rect ); else @@ -2219,7 +2301,7 @@ void wxWindowDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoo gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() ); } -void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion ®ion ) +void wxGTKWindowImplDC::DoSetClippingRegionAsRegion( const wxRegion ®ion ) { wxCHECK_RET( Ok(), wxT("invalid window dc") ); @@ -2251,7 +2333,7 @@ void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion ®ion ) gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() ); } -void wxWindowDC::DestroyClippingRegion() +void wxGTKWindowImplDC::DestroyClippingRegion() { wxCHECK_RET( Ok(), wxT("invalid window dc") ); @@ -2282,7 +2364,7 @@ void wxWindowDC::DestroyClippingRegion() } } -void wxWindowDC::Destroy() +void wxGTKWindowImplDC::Destroy() { if (m_penGC) wxFreePoolGC( m_penGC ); m_penGC = (GdkGC*) NULL; @@ -2294,7 +2376,26 @@ void wxWindowDC::Destroy() m_bgGC = (GdkGC*) NULL; } -void wxWindowDC::ComputeScaleAndOrigin() +void wxGTKWindowImplDC::SetDeviceOrigin( wxCoord x, wxCoord y ) +{ + m_deviceOriginX = x; + m_deviceOriginY = y; + + ComputeScaleAndOrigin(); +} + +void wxGTKWindowImplDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp ) +{ + m_signX = (xLeftRight ? 1 : -1); + m_signY = (yBottomUp ? -1 : 1); + + if (m_owner && m_owner->m_wxwindow && (m_owner->GetLayoutDirection() == wxLayout_RightToLeft)) + m_signX = -m_signX; + + ComputeScaleAndOrigin(); +} + +void wxGTKWindowImplDC::ComputeScaleAndOrigin() { const wxRealPoint origScale(m_scaleX, m_scaleY); @@ -2312,12 +2413,12 @@ void wxWindowDC::ComputeScaleAndOrigin() } // Resolution in pixels per logical inch -wxSize wxWindowDC::GetPPI() const +wxSize wxGTKWindowImplDC::GetPPI() const { return wxSize( (int) (m_mm_to_pix_x * 25.4 + 0.5), (int) (m_mm_to_pix_y * 25.4 + 0.5)); } -int wxWindowDC::GetDepth() const +int wxGTKWindowImplDC::GetDepth() const { return gdk_drawable_get_depth(m_window); } @@ -2327,7 +2428,11 @@ int wxWindowDC::GetDepth() const // wxPaintDC //----------------------------------------------------------------------------- +#if wxUSE_NEW_DC +IMPLEMENT_DYNAMIC_CLASS(wxGTKPaintImplDC, wxGTKClientImplDC) +#else IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxClientDC) +#endif // Limit the paint region to the window size. Sometimes // the paint region is too big, and this risks X11 errors @@ -2348,15 +2453,15 @@ static void wxLimitRegionToSize(wxRegion& region, const wxSize& sz) } } -wxPaintDC::wxPaintDC( wxWindow *win ) - : wxClientDC( win ) +wxGTKPaintImplDC::wxGTKPaintImplDC( wxWindow *win ) + : wxGTKClientImplDC( win ) { #if USE_PAINT_REGION if (!win->m_clipPaintRegion) return; wxSize sz = win->GetSize(); - m_paintClippingRegion = win->GetUpdateRegion(); + m_paintClippingRegion = win->m_nativeUpdateRegion; wxLimitRegionToSize(m_paintClippingRegion, sz); GdkRegion *region = m_paintClippingRegion.GetRegion(); @@ -2380,12 +2485,16 @@ wxPaintDC::wxPaintDC( wxWindow *win ) // wxClientDC //----------------------------------------------------------------------------- +#if wxUSE_NEW_DC +IMPLEMENT_DYNAMIC_CLASS(wxGTKClientImplDC, wxGTKWindowImplDC) +#else IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC) +#endif -wxClientDC::wxClientDC( wxWindow *win ) - : wxWindowDC( win ) +wxGTKClientImplDC::wxGTKClientImplDC( wxWindow *win ) + : wxGTKWindowImplDC( win ) { - wxCHECK_RET( win, _T("NULL window in wxClientDC::wxClientDC") ); + wxCHECK_RET( win, _T("NULL window in wxGTKClientImplDC::wxClientDC") ); #ifdef __WXUNIVERSAL__ wxPoint ptOrigin = win->GetClientAreaOrigin(); @@ -2395,7 +2504,7 @@ wxClientDC::wxClientDC( wxWindow *win ) #endif // __WXUNIVERSAL__ } -void wxClientDC::DoGetSize(int *width, int *height) const +void wxGTKClientImplDC::DoGetSize(int *width, int *height) const { wxCHECK_RET( m_owner, _T("GetSize() doesn't work without window") );