]> git.saurik.com Git - wxWidgets.git/blobdiff - src/gtk/dcclient.cpp
Fix return value of wxCountingOutputStream::LastWrite().
[wxWidgets.git] / src / gtk / dcclient.cpp
index 656136d385e424828be662c4466bafd8b3e26bcb..35b0fd4ff67eafdf0640b9187e89a15ed34ecb47 100644 (file)
@@ -1,6 +1,6 @@
 /////////////////////////////////////////////////////////////////////////////
 // Name:        src/gtk/dcclient.cpp
-// Purpose:
+// Purpose:     wxWindowDCImpl implementation
 // Author:      Robert Roebling
 // RCS-ID:      $Id$
 // Copyright:   (c) 1998 Robert Roebling, Chris Breeze
 // For compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
-#ifdef __VMS
-#define XCopyPlane XCOPYPLANE
-#endif
-
 #include "wx/gtk/dcclient.h"
 
 #ifndef WX_PRECOMP
@@ -28,8 +24,8 @@
 #include "wx/fontutil.h"
 
 #include "wx/gtk/private.h"
-
-#include <gdk/gdkx.h>
+#include "wx/gtk/private/object.h"
+#include "wx/private/textmeasure.h"
 
 //-----------------------------------------------------------------------------
 // local defines
@@ -53,9 +49,7 @@
 #include "verti.xbm"
 #include "cross.xbm"
 
-static GdkPixmap* hatches[wxLAST_HATCH - wxFIRST_HATCH + 1];
-
-extern GtkWidget *wxGetRootWindow();
+static GdkPixmap* hatches[wxBRUSHSTYLE_LAST_HATCH - wxBRUSHSTYLE_FIRST_HATCH + 1];
 
 //-----------------------------------------------------------------------------
 // constants
@@ -74,63 +68,50 @@ static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
 
 static GdkPixmap* GetHatch(int style)
 {
-    wxASSERT(style >= wxFIRST_HATCH && style <= wxLAST_HATCH);
-    const int i = style - wxFIRST_HATCH;
+    wxASSERT(style >= wxBRUSHSTYLE_FIRST_HATCH && style <= wxBRUSHSTYLE_LAST_HATCH);
+    const int i = style - wxBRUSHSTYLE_FIRST_HATCH;
     if (hatches[i] == NULL)
     {
+        // This macro creates a bitmap from an XBM file included above. Notice
+        // the need for the cast because gdk_bitmap_create_from_data() doesn't
+        // accept unsigned data but the arrays in XBM need to be unsigned to
+        // avoid warnings (and even errors in C+0x mode) from g++.
+#define CREATE_FROM_XBM_DATA(name) \
+        gdk_bitmap_create_from_data \
+        ( \
+            NULL, \
+            reinterpret_cast<gchar *>(name ## _bits), \
+            name ## _width, \
+            name ## _height \
+        )
+
         switch (style)
         {
-        case wxBDIAGONAL_HATCH:
-            hatches[i] = gdk_bitmap_create_from_data(NULL, bdiag_bits, bdiag_width, bdiag_height);
+        case wxBRUSHSTYLE_BDIAGONAL_HATCH:
+            hatches[i] = CREATE_FROM_XBM_DATA(bdiag);
             break;
-        case wxCROSSDIAG_HATCH:
-            hatches[i] = gdk_bitmap_create_from_data(NULL, cdiag_bits, cdiag_width, cdiag_height);
+        case wxBRUSHSTYLE_CROSSDIAG_HATCH:
+            hatches[i] = CREATE_FROM_XBM_DATA(cdiag);
             break;
-        case wxCROSS_HATCH:
-            hatches[i] = gdk_bitmap_create_from_data(NULL, cross_bits, cross_width, cross_height);
+        case wxBRUSHSTYLE_CROSS_HATCH:
+            hatches[i] = CREATE_FROM_XBM_DATA(cross);
             break;
-        case wxFDIAGONAL_HATCH:
-            hatches[i] = gdk_bitmap_create_from_data(NULL, fdiag_bits, fdiag_width, fdiag_height);
+        case wxBRUSHSTYLE_FDIAGONAL_HATCH:
+            hatches[i] = CREATE_FROM_XBM_DATA(fdiag);
             break;
-        case wxHORIZONTAL_HATCH:
-            hatches[i] = gdk_bitmap_create_from_data(NULL, horiz_bits, horiz_width, horiz_height);
+        case wxBRUSHSTYLE_HORIZONTAL_HATCH:
+            hatches[i] = CREATE_FROM_XBM_DATA(horiz);
             break;
-        case wxVERTICAL_HATCH:
-            hatches[i] = gdk_bitmap_create_from_data(NULL, verti_bits, verti_width, verti_height);
+        case wxBRUSHSTYLE_VERTICAL_HATCH:
+            hatches[i] = CREATE_FROM_XBM_DATA(verti);
             break;
         }
+
+#undef CREATE_FROM_XBM_DATA
     }
     return hatches[i];
 }
 
-//-----------------------------------------------------------------------------
-// temporary implementation of the missing GDK function
-//-----------------------------------------------------------------------------
-
-static
-void gdk_wx_draw_bitmap(GdkDrawable  *drawable,
-                        GdkGC        *gc,
-                        GdkDrawable  *src,
-                        gint         xsrc,
-                        gint         ysrc)
-{
-    wxCHECK_RET( drawable, _T("NULL drawable in gdk_wx_draw_bitmap") );
-    wxCHECK_RET( src, _T("NULL src in gdk_wx_draw_bitmap") );
-    wxCHECK_RET( gc, _T("NULL gc in gdk_wx_draw_bitmap") );
-
-    gint src_width, src_height;
-    gdk_drawable_get_size(src, &src_width, &src_height);
-
-    XCopyPlane( GDK_WINDOW_XDISPLAY(drawable),
-                GDK_WINDOW_XID(src),
-                GDK_WINDOW_XID(drawable),
-                GDK_GC_XGC(gc),
-                xsrc, ysrc,
-                src_width, src_height,
-                0, 0,
-                1 );
-}
-
 //-----------------------------------------------------------------------------
 // Implement Pool of Graphic contexts. Creating them takes too much time.
 //-----------------------------------------------------------------------------
@@ -149,7 +130,11 @@ enum wxPoolGCType
    wxTEXT_SCREEN,
    wxBG_SCREEN,
    wxPEN_SCREEN,
-   wxBRUSH_SCREEN
+   wxBRUSH_SCREEN,
+   wxTEXT_COLOUR_ALPHA,
+   wxBG_COLOUR_ALPHA,
+   wxPEN_COLOUR_ALPHA,
+   wxBRUSH_COLOUR_ALPHA
 };
 
 struct wxGC
@@ -251,7 +236,7 @@ static GdkGC* wxGetPoolGC( GdkWindow *window, wxPoolGCType type )
     // The realloc failed.  Fall through to error.
     wxFAIL_MSG( wxT("No GC available") );
 
-    return (GdkGC*) NULL;
+    return NULL;
 }
 
 static void wxFreePoolGC( GdkGC *gc )
@@ -277,16 +262,16 @@ IMPLEMENT_ABSTRACT_CLASS(wxWindowDCImpl, wxGTKDCImpl)
 wxWindowDCImpl::wxWindowDCImpl( wxDC *owner ) :
    wxGTKDCImpl( owner )
 {
-    m_gdkwindow = (GdkWindow*) NULL;
-    m_penGC = (GdkGC *) NULL;
-    m_brushGC = (GdkGC *) NULL;
-    m_textGC = (GdkGC *) NULL;
-    m_bgGC = (GdkGC *) NULL;
-    m_cmap = (GdkColormap *) NULL;
+    m_gdkwindow = NULL;
+    m_penGC = NULL;
+    m_brushGC = NULL;
+    m_textGC = NULL;
+    m_bgGC = NULL;
+    m_cmap = NULL;
     m_isScreenDC = false;
-    m_context = (PangoContext *)NULL;
-    m_layout = (PangoLayout *)NULL;
-    m_fontdesc = (PangoFontDescription *)NULL;
+    m_context = NULL;
+    m_layout = NULL;
+    m_fontdesc = NULL;
 }
 
 wxWindowDCImpl::wxWindowDCImpl( wxDC *owner, wxWindow *window ) :
@@ -294,34 +279,35 @@ wxWindowDCImpl::wxWindowDCImpl( wxDC *owner, wxWindow *window ) :
 {
     wxASSERT_MSG( window, wxT("DC needs a window") );
 
-    m_gdkwindow = (GdkWindow*) NULL;
-    m_penGC = (GdkGC *) NULL;
-    m_brushGC = (GdkGC *) NULL;
-    m_textGC = (GdkGC *) NULL;
-    m_bgGC = (GdkGC *) NULL;
-    m_cmap = (GdkColormap *) NULL;
+    m_gdkwindow = NULL;
+    m_penGC = NULL;
+    m_brushGC = NULL;
+    m_textGC = NULL;
+    m_bgGC = NULL;
+    m_cmap = NULL;
     m_isScreenDC = false;
     m_font = window->GetFont();
 
     GtkWidget *widget = window->m_wxwindow;
+    m_gdkwindow = window->GTKGetDrawingWindow();
 
     // Some controls don't have m_wxwindow - like wxStaticBox, but the user
-    // code should still be able to create wxClientDCs for them, so we will
-    // use the parent window here then.
+    // code should still be able to create wxClientDCs for them
     if ( !widget )
     {
-        window = window->GetParent();
-        widget = window->m_wxwindow;
-    }
+        widget = window->m_widget;
 
-    wxASSERT_MSG( widget, wxT("DC needs a widget") );
+        wxCHECK_RET(widget, "DC needs a widget");
 
-    m_context = window->GtkGetPangoDefaultContext();
+        m_gdkwindow = widget->window;
+        if (!gtk_widget_get_has_window(widget))
+            SetDeviceLocalOrigin(widget->allocation.x, widget->allocation.y);
+    }
+
+    m_context = window->GTKGetPangoDefaultContext();
     m_layout = pango_layout_new( m_context );
     m_fontdesc = pango_font_description_copy( widget->style->font_desc );
 
-    m_gdkwindow = widget->window;
-
     // Window not realized ?
     if (!m_gdkwindow)
     {
@@ -331,7 +317,7 @@ wxWindowDCImpl::wxWindowDCImpl( wxDC *owner, wxWindow *window ) :
          return;
     }
 
-    m_cmap = gtk_widget_get_colormap( widget ? widget : window->m_widget );
+    m_cmap = gtk_widget_get_colormap(widget);
 
     SetUpDC();
 
@@ -344,7 +330,7 @@ wxWindowDCImpl::wxWindowDCImpl( wxDC *owner, wxWindow *window ) :
 
     m_window = window;
 
-    if (m_window && m_window->m_wxwindow && 
+    if (m_window && m_window->m_wxwindow &&
         (m_window->GetLayoutDirection() == wxLayout_RightToLeft))
     {
         // reverse sense
@@ -386,7 +372,7 @@ void wxWindowDCImpl::SetUpDC( bool isMemDC )
     }
 
     if (!done)
-    {    
+    {
         if (m_isScreenDC)
         {
             m_penGC = wxGetPoolGC( m_gdkwindow, wxPEN_SCREEN );
@@ -394,6 +380,18 @@ void wxWindowDCImpl::SetUpDC( bool isMemDC )
             m_textGC = wxGetPoolGC( m_gdkwindow, wxTEXT_SCREEN );
             m_bgGC = wxGetPoolGC( m_gdkwindow, wxBG_SCREEN );
         }
+#if GTK_CHECK_VERSION(2,12,0)
+        // gdk_screen_get_rgba_colormap was added in 2.8, but this code is for
+        // compositing which requires 2.12
+        else if (gtk_check_version(2,12,0) == NULL &&
+            m_cmap == gdk_screen_get_rgba_colormap(gdk_colormap_get_screen(m_cmap)))
+        {
+            m_penGC = wxGetPoolGC( m_gdkwindow, wxPEN_COLOUR_ALPHA );
+            m_brushGC = wxGetPoolGC( m_gdkwindow, wxBRUSH_COLOUR_ALPHA );
+            m_textGC = wxGetPoolGC( m_gdkwindow, wxTEXT_COLOUR_ALPHA );
+            m_bgGC = wxGetPoolGC( m_gdkwindow, wxBG_COLOUR_ALPHA );
+        }
+#endif
         else
         {
             m_penGC = wxGetPoolGC( m_gdkwindow, wxPEN_COLOUR );
@@ -445,25 +443,25 @@ void wxWindowDCImpl::SetUpDC( bool isMemDC )
     gdk_gc_set_function( m_penGC, GDK_COPY );
 
     /* clipping */
-    gdk_gc_set_clip_rectangle( m_penGC, (GdkRectangle *) NULL );
-    gdk_gc_set_clip_rectangle( m_brushGC, (GdkRectangle *) NULL );
-    gdk_gc_set_clip_rectangle( m_textGC, (GdkRectangle *) NULL );
-    gdk_gc_set_clip_rectangle( m_bgGC, (GdkRectangle *) NULL );
+    gdk_gc_set_clip_rectangle( m_penGC, NULL );
+    gdk_gc_set_clip_rectangle( m_brushGC, NULL );
+    gdk_gc_set_clip_rectangle( m_textGC, NULL );
+    gdk_gc_set_clip_rectangle( m_bgGC, NULL );
 }
 
 void wxWindowDCImpl::DoGetSize( int* width, int* height ) const
 {
-    wxCHECK_RET( m_window, _T("GetSize() doesn't work without window") );
+    wxCHECK_RET( m_window, wxT("GetSize() doesn't work without window") );
 
     m_window->GetSize(width, height);
 }
 
 bool wxWindowDCImpl::DoFloodFill(wxCoord x, wxCoord y,
-                             const wxColour& col, int style)
+                                 const wxColour& col, wxFloodFillStyle style)
 {
 #if wxUSE_IMAGE
     extern bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y,
-                              const wxColour & col, int style);
+                              const wxColour & col, wxFloodFillStyle style);
 
     return wxDoFloodFill( GetOwner(), x, y, col, style);
 #else
@@ -478,32 +476,40 @@ bool wxWindowDCImpl::DoFloodFill(wxCoord x, wxCoord y,
 
 bool wxWindowDCImpl::DoGetPixel( wxCoord x1, wxCoord y1, wxColour *col ) const
 {
-#if wxUSE_IMAGE
-    // Generic (and therefore rather inefficient) method.
-    // Could be improved.
-    wxMemoryDC memdc;
-    wxBitmap bitmap(1, 1);
-    memdc.SelectObject(bitmap);
-    memdc.Blit(0, 0, 1, 1, GetOwner(), x1, y1);
-    memdc.SelectObject(wxNullBitmap);
-
-    wxImage image = bitmap.ConvertToImage();
-    col->Set(image.GetRed(0, 0), image.GetGreen(0, 0), image.GetBlue(0, 0));
+    GdkImage* image = NULL;
+    if (m_gdkwindow)
+    {
+        const int x = LogicalToDeviceX(x1);
+        const int y = LogicalToDeviceY(y1);
+        wxRect rect;
+        gdk_drawable_get_size(m_gdkwindow, &rect.width, &rect.height);
+        if (rect.Contains(x, y))
+            image = gdk_drawable_get_image(m_gdkwindow, x, y, 1, 1);
+    }
+    if (image == NULL)
+    {
+        *col = wxColour();
+        return false;
+    }
+    GdkColormap* colormap = gdk_image_get_colormap(image);
+    const unsigned pixel = gdk_image_get_pixel(image, 0, 0);
+    if (colormap == NULL)
+        *col = pixel ? m_textForegroundColour : m_textBackgroundColour;
+    else
+    {
+        GdkColor c;
+        gdk_colormap_query_color(colormap, pixel, &c);
+        col->Set(c.red >> 8, c.green >> 8, c.blue >> 8);
+    }
+    g_object_unref(image);
     return true;
-#else // !wxUSE_IMAGE
-    wxUnusedVar(x1);
-    wxUnusedVar(y1);
-    wxUnusedVar(col);
-
-    return false;
-#endif // wxUSE_IMAGE/!wxUSE_IMAGE
 }
 
 void wxWindowDCImpl::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 )
 {
     wxCHECK_RET( IsOk(), wxT("invalid window dc") );
 
-    if (m_pen.GetStyle() != wxTRANSPARENT)
+    if ( m_pen.IsNonTransparent() )
     {
         if (m_gdkwindow)
             gdk_draw_line( m_gdkwindow, m_penGC, XLOG2DEV(x1), YLOG2DEV(y1), XLOG2DEV(x2), YLOG2DEV(y2) );
@@ -517,7 +523,7 @@ void wxWindowDCImpl::DoCrossHair( wxCoord x, wxCoord y )
 {
     wxCHECK_RET( IsOk(), wxT("invalid window dc") );
 
-    if (m_pen.GetStyle() != wxTRANSPARENT)
+    if ( m_pen.IsNonTransparent() )
     {
         int w = 0;
         int h = 0;
@@ -538,12 +544,12 @@ void wxWindowDCImpl::DrawingSetup(GdkGC*& gc, bool& originChanged)
     GdkPixmap* pixmap = NULL;
     const int style = m_brush.GetStyle();
 
-    if (style == wxSTIPPLE || style == wxSTIPPLE_MASK_OPAQUE)
+    if (style == wxBRUSHSTYLE_STIPPLE || style == wxBRUSHSTYLE_STIPPLE_MASK_OPAQUE)
     {
         const wxBitmap* stipple = m_brush.GetStipple();
         if (stipple->IsOk())
         {
-            if (style == wxSTIPPLE)
+            if (style == wxBRUSHSTYLE_STIPPLE)
                 pixmap = stipple->GetPixmap();
             else if (stipple->GetMask())
             {
@@ -615,7 +621,7 @@ void wxWindowDCImpl::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2,
 
     if (m_gdkwindow)
     {
-        if (m_brush.GetStyle() != wxTRANSPARENT)
+        if ( m_brush.IsNonTransparent() )
         {
             GdkGC* gc;
             bool originChanged;
@@ -627,11 +633,11 @@ void wxWindowDCImpl::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2,
                 gdk_gc_set_ts_origin(gc, 0, 0);
         }
 
-        if (m_pen.GetStyle() != wxTRANSPARENT)
+        if ( m_pen.IsNonTransparent() )
         {
             gdk_draw_arc( m_gdkwindow, m_penGC, FALSE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 );
 
-            if ((m_brush.GetStyle() != wxTRANSPARENT) && (alpha2 - alpha1 != 360*64))
+            if ( m_brush.IsNonTransparent() && (alpha2 - alpha1 != 360*64) )
             {
                 gdk_draw_line( m_gdkwindow, m_penGC, xx1, yy1, xxc, yyc );
                 gdk_draw_line( m_gdkwindow, m_penGC, xxc, yyc, xx2, yy2 );
@@ -661,7 +667,7 @@ void wxWindowDCImpl::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord width, wxC
         wxCoord start = wxCoord(sa * 64.0);
         wxCoord end = wxCoord((ea-sa) * 64.0);
 
-        if (m_brush.GetStyle() != wxTRANSPARENT)
+        if ( m_brush.IsNonTransparent() )
         {
             GdkGC* gc;
             bool originChanged;
@@ -673,7 +679,7 @@ void wxWindowDCImpl::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord width, wxC
                 gdk_gc_set_ts_origin(gc, 0, 0);
         }
 
-        if (m_pen.GetStyle() != wxTRANSPARENT)
+        if ( m_pen.IsNonTransparent() )
             gdk_draw_arc( m_gdkwindow, m_penGC, FALSE, xx, yy, ww, hh, start, end );
     }
 
@@ -685,47 +691,54 @@ void wxWindowDCImpl::DoDrawPoint( wxCoord x, wxCoord y )
 {
     wxCHECK_RET( IsOk(), wxT("invalid window dc") );
 
-    if ((m_pen.GetStyle() != wxTRANSPARENT) && m_gdkwindow)
+    if ( m_pen.IsNonTransparent() && m_gdkwindow )
         gdk_draw_point( m_gdkwindow, m_penGC, XLOG2DEV(x), YLOG2DEV(y) );
 
     CalcBoundingBox (x, y);
 }
 
-void wxWindowDCImpl::DoDrawLines( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset )
+void wxWindowDCImpl::DoDrawLines( int n, const wxPoint points[], wxCoord xoffset, wxCoord yoffset )
 {
     wxCHECK_RET( IsOk(), wxT("invalid window dc") );
 
-    if (m_pen.GetStyle() == wxTRANSPARENT) return;
     if (n <= 0) return;
 
+    if ( m_pen.IsTransparent() )
+        return;
+
     //Check, if scaling is necessary
     const bool doScale =
         xoffset != 0 || yoffset != 0 || XLOG2DEV(10) != 10 || YLOG2DEV(10) != 10;
 
     // GdkPoint and wxPoint have the same memory layout, so we can cast one to the other
-    GdkPoint* gpts = reinterpret_cast<GdkPoint*>(points);
+    const GdkPoint* gpts = reinterpret_cast<const GdkPoint*>(points);
+    GdkPoint* gpts_alloc = NULL;
 
     if (doScale)
-        gpts = new GdkPoint[n];
+    {
+        gpts_alloc = new GdkPoint[n];
+        gpts = gpts_alloc;
+    }
 
     for (int i = 0; i < n; i++)
     {
         if (doScale)
         {
-            gpts[i].x = XLOG2DEV(points[i].x + xoffset);
-            gpts[i].y = YLOG2DEV(points[i].y + yoffset);
+            gpts_alloc[i].x = XLOG2DEV(points[i].x + xoffset);
+            gpts_alloc[i].y = YLOG2DEV(points[i].y + yoffset);
         }
         CalcBoundingBox(points[i].x + xoffset, points[i].y + yoffset);
     }
 
     if (m_gdkwindow)
-        gdk_draw_lines( m_gdkwindow, m_penGC, gpts, n);
+        gdk_draw_lines( m_gdkwindow, m_penGC, (GdkPoint*) gpts, n);
 
-    if (doScale)
-        delete[] gpts;
+    delete[] gpts_alloc;
 }
 
-void wxWindowDCImpl::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, int WXUNUSED(fillStyle) )
+void wxWindowDCImpl::DoDrawPolygon( int n, const wxPoint points[],
+                                    wxCoord xoffset, wxCoord yoffset,
+                                    wxPolygonFillMode WXUNUSED(fillStyle) )
 {
     wxCHECK_RET( IsOk(), wxT("invalid window dc") );
 
@@ -736,37 +749,41 @@ void wxWindowDCImpl::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wx
         xoffset != 0 || yoffset != 0 || XLOG2DEV(10) != 10 || YLOG2DEV(10) != 10;
 
     // GdkPoint and wxPoint have the same memory layout, so we can cast one to the other
-    GdkPoint* gdkpoints = reinterpret_cast<GdkPoint*>(points);
+    const GdkPoint* gdkpoints = reinterpret_cast<const GdkPoint*>(points);
+    GdkPoint* gdkpoints_alloc = NULL;
 
     if (doScale)
-        gdkpoints = new GdkPoint[n];
+    {
+        gdkpoints_alloc = new GdkPoint[n];
+        gdkpoints = gdkpoints_alloc;
+    }
 
     int i;
     for (i = 0 ; i < n ; i++)
     {
         if (doScale)
         {
-            gdkpoints[i].x = XLOG2DEV(points[i].x + xoffset);
-            gdkpoints[i].y = YLOG2DEV(points[i].y + yoffset);
+            gdkpoints_alloc[i].x = XLOG2DEV(points[i].x + xoffset);
+            gdkpoints_alloc[i].y = YLOG2DEV(points[i].y + yoffset);
         }
         CalcBoundingBox(points[i].x + xoffset, points[i].y + yoffset);
     }
 
     if (m_gdkwindow)
     {
-        if (m_brush.GetStyle() != wxTRANSPARENT)
+        if ( m_brush.IsNonTransparent() )
         {
             GdkGC* gc;
             bool originChanged;
             DrawingSetup(gc, originChanged);
 
-            gdk_draw_polygon(m_gdkwindow, gc, true, gdkpoints, n);
+            gdk_draw_polygon(m_gdkwindow, gc, true, (GdkPoint*) gdkpoints, n);
 
             if (originChanged)
                 gdk_gc_set_ts_origin(gc, 0, 0);
         }
 
-        if (m_pen.GetStyle() != wxTRANSPARENT)
+        if ( m_pen.IsNonTransparent() )
         {
 /*
             for (i = 0 ; i < n ; i++)
@@ -778,13 +795,12 @@ void wxWindowDCImpl::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wx
                                gdkpoints[(i+1)%n].y);
             }
 */
-            gdk_draw_polygon( m_gdkwindow, m_penGC, FALSE, gdkpoints, n );
+            gdk_draw_polygon( m_gdkwindow, m_penGC, FALSE, (GdkPoint*) gdkpoints, n );
 
         }
     }
 
-    if (doScale)
-        delete[] gdkpoints;
+    delete[] gdkpoints_alloc;
 }
 
 void wxWindowDCImpl::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height )
@@ -805,7 +821,7 @@ void wxWindowDCImpl::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoo
 
     if (m_gdkwindow)
     {
-        if (m_brush.GetStyle() != wxTRANSPARENT)
+        if ( m_brush.IsNonTransparent() )
         {
             GdkGC* gc;
             bool originChanged;
@@ -817,11 +833,10 @@ void wxWindowDCImpl::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoo
                 gdk_gc_set_ts_origin(gc, 0, 0);
         }
 
-        if (m_pen.GetStyle() != wxTRANSPARENT)
+        if ( m_pen.IsNonTransparent() )
         {
-#if 1
             if ((m_pen.GetWidth() == 2) && (m_pen.GetCap() == wxCAP_ROUND) &&
-                (m_pen.GetJoin() == wxJOIN_ROUND) && (m_pen.GetStyle() == wxSOLID))
+                (m_pen.GetJoin() == wxJOIN_ROUND) && (m_pen.GetStyle() == wxPENSTYLE_SOLID))
             {
                 // Use 2 1-line rects instead
                 gdk_gc_set_line_attributes( m_penGC, 1, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND );
@@ -842,7 +857,6 @@ void wxWindowDCImpl::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoo
                 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_gdkwindow, m_penGC, FALSE, xx, yy, ww-1, hh-1 );
@@ -883,7 +897,7 @@ void wxWindowDCImpl::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord width
 
     // CMB: adjust size if outline is drawn otherwise the result is
     // 1 pixel too wide and high
-    if (m_pen.GetStyle() != wxTRANSPARENT)
+    if ( m_pen.IsNonTransparent() )
     {
         ww--;
         hh--;
@@ -898,7 +912,7 @@ void wxWindowDCImpl::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord width
         if (dd > hh) dd = hh;
         rr = dd / 2;
 
-        if (m_brush.GetStyle() != wxTRANSPARENT)
+        if ( m_brush.IsNonTransparent() )
         {
             GdkGC* gc;
             bool originChanged;
@@ -915,7 +929,7 @@ void wxWindowDCImpl::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord width
                 gdk_gc_set_ts_origin(gc, 0, 0);
         }
 
-        if (m_pen.GetStyle() != wxTRANSPARENT)
+        if ( m_pen.IsNonTransparent() )
         {
             gdk_draw_line( m_gdkwindow, m_penGC, xx+rr+1, yy, xx+ww-rr, yy );
             gdk_draw_line( m_gdkwindow, m_penGC, xx+rr+1, yy+hh, xx+ww-rr, yy+hh );
@@ -948,20 +962,28 @@ void wxWindowDCImpl::DoDrawEllipse( wxCoord x, wxCoord y, wxCoord width, wxCoord
 
     if (m_gdkwindow)
     {
-        if (m_brush.GetStyle() != wxTRANSPARENT)
+        if ( m_brush.IsNonTransparent() )
         {
             GdkGC* gc;
             bool originChanged;
             DrawingSetup(gc, originChanged);
 
+            // If the pen is transparent pen we increase the size
+            // for better compatibility with other platforms.
+            if (m_pen.IsTransparent())
+            {
+                ++ww;
+                ++hh;
+            }
+
             gdk_draw_arc(m_gdkwindow, gc, true, xx, yy, ww, hh, 0, 360*64);
 
             if (originChanged)
                 gdk_gc_set_ts_origin(gc, 0, 0);
         }
 
-        if (m_pen.GetStyle() != wxTRANSPARENT)
-            gdk_draw_arc( m_gdkwindow, m_penGC, FALSE, xx, yy, ww, hh, 0, 360*64 );
+        if ( m_pen.IsNonTransparent() )
+            gdk_draw_arc( m_gdkwindow, m_penGC, false, xx, yy, ww, hh, 0, 360*64 );
     }
 
     CalcBoundingBox( x, y );
@@ -974,125 +996,217 @@ void wxWindowDCImpl::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y )
     DoDrawBitmap( (const wxBitmap&)icon, x, y, true );
 }
 
+// scale a pixbuf
+static GdkPixbuf*
+Scale(GdkPixbuf* pixbuf, int dst_w, int dst_h, double sx, double sy)
+{
+    GdkPixbuf* pixbuf_scaled = gdk_pixbuf_new(
+        GDK_COLORSPACE_RGB, gdk_pixbuf_get_has_alpha(pixbuf), 8, dst_w, dst_h);
+    gdk_pixbuf_scale(pixbuf, pixbuf_scaled,
+        0, 0, dst_w, dst_h, 0, 0, sx, sy, GDK_INTERP_NEAREST);
+    return pixbuf_scaled;
+}
+
+// scale part of a pixmap using pixbuf scaling
+static GdkPixbuf*
+Scale(GdkPixmap* pixmap, int x, int y, int w, int h, int dst_w, int dst_h, double sx, double sy)
+{
+    GdkPixbuf* pixbuf = gdk_pixbuf_get_from_drawable(
+        NULL, pixmap, NULL, x, y, 0, 0, w, h);
+    GdkPixbuf* pixbuf2 = Scale(pixbuf, dst_w, dst_h, sx, sy);
+    g_object_unref(pixbuf);
+    return pixbuf2;
+}
+
+// scale part of a mask pixmap
+static GdkPixmap*
+ScaleMask(GdkPixmap* mask, int x, int y, int w, int h, int dst_w, int dst_h, double sx, double sy)
+{
+    GdkPixbuf* pixbuf = Scale(mask, x, y, w, h, dst_w, dst_h, sx, sy);
+
+    // convert black and white pixbuf back to a mono pixmap
+    const unsigned out_rowstride = (dst_w + 7) / 8;
+    const size_t data_size = out_rowstride * size_t(dst_h);
+    char* data = new char[data_size];
+    char* out = data;
+    const guchar* row = gdk_pixbuf_get_pixels(pixbuf);
+    const int rowstride = gdk_pixbuf_get_rowstride(pixbuf);
+    memset(data, 0, data_size);
+    for (int j = 0; j < dst_h; j++, row += rowstride, out += out_rowstride)
+    {
+        const guchar* in = row;
+        for (int i = 0; i < dst_w; i++, in += 3)
+            if (*in)
+                out[i >> 3] |= 1 << (i & 7);
+    }
+    g_object_unref(pixbuf);
+    GdkPixmap* pixmap = gdk_bitmap_create_from_data(mask, data, dst_w, dst_h);
+    delete[] data;
+    return pixmap;
+}
+
+// Make a new mask from part of a mask and a clip region.
+static GdkPixmap*
+ClipMask(GdkPixmap* mask, GdkRegion* clipRegion, int x, int y, int dst_x, int dst_y, int w, int h)
+{
+    GdkGCValues gcValues;
+    gcValues.foreground.pixel = 0;
+    GdkGC* gc = gdk_gc_new_with_values(mask, &gcValues, GDK_GC_FOREGROUND);
+    GdkPixmap* pixmap = gdk_pixmap_new(mask, w, h, 1);
+    // clear new mask, so clipped areas will be masked
+    gdk_draw_rectangle(pixmap, gc, true, 0, 0, w, h);
+    gdk_gc_set_clip_region(gc, clipRegion);
+    gdk_gc_set_clip_origin(gc, -dst_x, -dst_y);
+    // draw old mask onto new one, with clip
+    gdk_draw_drawable(pixmap, gc, mask, x, y, 0, 0, w, h);
+    g_object_unref(gc);
+    return pixmap;
+}
+
+// make a color pixmap from part of a mono one, using text fg/bg colors
+GdkPixmap*
+wxWindowDCImpl::MonoToColor(GdkPixmap* monoPixmap, int x, int y, int w, int h) const
+{
+    GdkPixmap* pixmap = gdk_pixmap_new(m_gdkwindow, w, h, -1);
+    GdkGCValues gcValues;
+    gcValues.foreground.pixel = m_textForegroundColour.GetColor()->pixel;
+    gcValues.background.pixel = m_textBackgroundColour.GetColor()->pixel;
+    gcValues.stipple = monoPixmap;
+    gcValues.fill = GDK_OPAQUE_STIPPLED;
+    gcValues.ts_x_origin = -x;
+    gcValues.ts_y_origin = -y;
+    GdkGC* gc = gdk_gc_new_with_values(pixmap, &gcValues, GdkGCValuesMask(
+        GDK_GC_FOREGROUND | GDK_GC_BACKGROUND | GDK_GC_STIPPLE | GDK_GC_FILL |
+        GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN));
+    gdk_draw_rectangle(pixmap, gc, true, 0, 0, w, h);
+    g_object_unref(gc);
+    return pixmap;
+}
+
 void wxWindowDCImpl::DoDrawBitmap( const wxBitmap &bitmap,
                                wxCoord x, wxCoord y,
                                bool useMask )
 {
     wxCHECK_RET( IsOk(), wxT("invalid window dc") );
-
     wxCHECK_RET( bitmap.IsOk(), wxT("invalid bitmap") );
 
-    bool is_mono = bitmap.GetDepth() == 1;
-
-    // scale/translate size and position
-    int xx = XLOG2DEV(x);
-    int yy = YLOG2DEV(y);
-
-    int w = bitmap.GetWidth();
-    int h = bitmap.GetHeight();
+    if (!m_gdkwindow) return;
 
-    if (m_window && m_window->GetLayoutDirection() == wxLayout_RightToLeft)
-        xx -= w;
+    const int w = bitmap.GetWidth();
+    const int h = bitmap.GetHeight();
 
-    CalcBoundingBox( x, y );
-    CalcBoundingBox( x + w, y + h );
+    // notice that as the bitmap is not drawn upside down (or right to left)
+    // even if the corresponding axis direction is inversed, we need to take it
+    // into account when calculating its bounding box
+    CalcBoundingBox(x, y);
+    CalcBoundingBox(x + m_signX*w, y + m_signY*h);
 
-    if (!m_gdkwindow) return;
+    // device coords
+    int xx = LogicalToDeviceX(x);
+    const int yy = LogicalToDeviceY(y);
+    const int ww = LogicalToDeviceXRel(w);
+    const int hh = LogicalToDeviceYRel(h);
 
-    int ww = XLOG2DEVREL(w);
-    int hh = YLOG2DEVREL(h);
+    if (m_window && m_window->GetLayoutDirection() == wxLayout_RightToLeft)
+        xx -= ww;
 
-    // compare to current clipping region
-    if (!m_currentClippingRegion.IsNull())
+    GdkRegion* const clipRegion = m_currentClippingRegion.GetRegion();
+    // determine clip region overlap
+    int overlap = wxInRegion;
+    if (clipRegion)
     {
-        wxRegion tmp( xx,yy,ww,hh );
-        tmp.Intersect( m_currentClippingRegion );
-        if (tmp.IsEmpty())
+        overlap = m_currentClippingRegion.Contains(xx, yy, ww, hh);
+        if (overlap == wxOutRegion)
             return;
     }
 
-    // scale bitmap if required
-    wxBitmap use_bitmap = bitmap;
-    if ((w != ww) || (h != hh))
-        use_bitmap = use_bitmap.Rescale( 0, 0, ww, hh, ww, hh );
-
-    // apply mask if any
-    GdkBitmap *mask = (GdkBitmap *) NULL;
-    if (useMask && use_bitmap.GetMask())
-        mask = use_bitmap.GetMask()->GetBitmap();
+    const bool isScaled = ww != w || hh != h;
+    const bool hasAlpha = bitmap.HasAlpha();
+    GdkGC* const use_gc = m_penGC;
 
-    GdkGC* use_gc = is_mono ? m_textGC : m_penGC;
-
-    GdkBitmap *new_mask = (GdkBitmap*) NULL;
+    GdkPixmap* mask = NULL;
+    // mask does not work when drawing a pixbuf with alpha
+    if (useMask && !hasAlpha)
+    {
+        wxMask* m = bitmap.GetMask();
+        if (m)
+            mask = *m;
+    }
 
-    if (mask != NULL)
+    GdkPixmap* mask_new = NULL;
+    if (mask)
     {
-        if (!m_currentClippingRegion.IsNull())
+        if (isScaled)
         {
-            GdkColor col;
-            new_mask = gdk_pixmap_new( wxGetRootWindow()->window, ww, hh, 1 );
-            GdkGC *gc = gdk_gc_new( new_mask );
-            col.pixel = 0;
-            gdk_gc_set_foreground( gc, &col );
-            gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, ww, hh );
-            col.pixel = 0;
-            gdk_gc_set_background( gc, &col );
-            col.pixel = 1;
-            gdk_gc_set_foreground( gc, &col );
-            gdk_gc_set_clip_region( gc, m_currentClippingRegion.GetRegion() );
-            gdk_gc_set_clip_origin( gc, -xx, -yy );
-            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);
+            mask = ScaleMask(mask, 0, 0, w, h, ww, hh, m_scaleX, m_scaleY);
+            mask_new = mask;
+        }
+        if (overlap == wxPartRegion)
+        {
+            // need a new mask that also masks the clipped area,
+            // because gc can't have both a mask and a clip region
+            mask = ClipMask(mask, clipRegion, 0, 0, xx, yy, ww, hh);
+            if (mask_new)
+                g_object_unref(mask_new);
+            mask_new = mask;
         }
-
         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
-    // drawing a mono-bitmap (XBitmap) we use the current text GC
-    if (is_mono)
+    // determine whether to use pixmap or pixbuf
+    GdkPixmap* pixmap = NULL;
+    GdkPixmap* pixmap_new = NULL;
+    GdkPixbuf* pixbuf = NULL;
+    GdkPixbuf* pixbuf_new = NULL;
+    if (bitmap.HasPixmap())
+        pixmap = bitmap.GetPixmap();
+    if (pixmap && gdk_drawable_get_depth(pixmap) == 1)
+    {
+        if (gdk_drawable_get_depth(m_gdkwindow) != 1)
+        {
+            // convert mono pixmap to color using text fg/bg colors
+            pixmap = MonoToColor(pixmap, 0, 0, w, h);
+            pixmap_new = pixmap;
+        }
+    }
+    else if (hasAlpha || pixmap == NULL)
+        pixbuf = bitmap.GetPixbuf();
+
+    if (isScaled)
     {
-        GdkPixmap *bitmap2 = gdk_pixmap_new( wxGetRootWindow()->window, ww, hh, -1 );
-        GdkGC *gc = gdk_gc_new( bitmap2 );
-        gdk_gc_set_foreground( gc, m_textForegroundColour.GetColor() );
-        gdk_gc_set_background( gc, m_textBackgroundColour.GetColor() );
-        gdk_wx_draw_bitmap(bitmap2, gc, use_bitmap.GetPixmap(), 0, 0);
+        if (pixbuf)
+            pixbuf = Scale(pixbuf, ww, hh, m_scaleX, m_scaleY);
+        else
+            pixbuf = Scale(pixmap, 0, 0, w, h, ww, hh, m_scaleX, m_scaleY);
 
-        gdk_draw_drawable(m_gdkwindow, use_gc, bitmap2, 0, 0, xx, yy, -1, -1);
+        pixbuf_new = pixbuf;
+    }
 
-        g_object_unref (bitmap2);
-        g_object_unref (gc);
+    if (pixbuf)
+    {
+        gdk_draw_pixbuf(m_gdkwindow, use_gc, pixbuf,
+            0, 0, xx, yy, ww, hh, GDK_RGB_DITHER_NORMAL, 0, 0);
     }
     else
     {
-        if (use_bitmap.HasPixbuf())
-        {
-            gdk_draw_pixbuf(m_gdkwindow, use_gc,
-                            use_bitmap.GetPixbuf(),
-                            0, 0, xx, yy, -1, -1,
-                            GDK_RGB_DITHER_NORMAL, xx, yy);
-        }
-        else
-        {
-            gdk_draw_drawable(m_gdkwindow, use_gc,
-                              use_bitmap.GetPixmap(),
-                              0, 0, xx, yy, -1, -1);
-        }
+        gdk_draw_drawable(m_gdkwindow, use_gc, pixmap, 0, 0, xx, yy, ww, hh);
     }
 
-    // remove mask again if any
-    if (mask != NULL)
+    if (pixbuf_new)
+        g_object_unref(pixbuf_new);
+    if (pixmap_new)
+        g_object_unref(pixmap_new);
+    if (mask)
     {
-        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);
+        gdk_gc_set_clip_region(use_gc, clipRegion);
+
+        // Notice that we can only release the mask now, we can't do it before
+        // the calls to gdk_draw_xxx() above as they crash with X error with
+        // GTK+ up to 2.20.1 (i.e. it works with 2.20 but is known to not work
+        // with 2.16.1 and below).
+        if (mask_new)
+            g_object_unref(mask_new);
     }
 }
 
@@ -1100,258 +1214,188 @@ bool wxWindowDCImpl::DoBlit( wxCoord xdest, wxCoord ydest,
                          wxCoord width, wxCoord height,
                          wxDC *source,
                          wxCoord xsrc, wxCoord ysrc,
-                         int logical_func,
+                         wxRasterOperationMode logical_func,
                          bool useMask,
                          wxCoord xsrcMask, wxCoord ysrcMask )
 {
     wxCHECK_MSG( IsOk(), false, wxT("invalid window dc") );
-
     wxCHECK_MSG( source, false, wxT("invalid source dc") );
 
     if (!m_gdkwindow) return false;
 
-    // transform the source DC coords to the device ones
-    xsrc = source->LogicalToDeviceX(xsrc);
-    ysrc = source->LogicalToDeviceY(ysrc);
-
-    wxBitmap selected;
-    wxMemoryDC *memDC = wxDynamicCast(source, wxMemoryDC);
-    if ( memDC )
+    GdkDrawable* srcDrawable = NULL;
+    GdkPixmap* mask = NULL;
+    wxMemoryDC* memDC = wxDynamicCast(source, wxMemoryDC);
+    if (memDC)
     {
-        selected = memDC->GetSelectedBitmap();
-        if ( !selected.IsOk() )
+        const wxBitmap& bitmap = memDC->GetSelectedBitmap();
+        if (!bitmap.IsOk())
             return false;
+        srcDrawable = bitmap.GetPixmap();
+        if (useMask)
+        {
+            wxMask* m = bitmap.GetMask();
+            if (m)
+                mask = *m;
+        }
     }
-
-    bool use_bitmap_method = false;
-    bool is_mono = false;
-
-    if (xsrcMask == -1 && ysrcMask == -1)
+    else
     {
-        xsrcMask = xsrc;
-        ysrcMask = ysrc;
+        wxDCImpl* impl = source->GetImpl();
+        wxWindowDCImpl* gtk_impl = wxDynamicCast(impl, wxWindowDCImpl);
+        if (gtk_impl)
+            srcDrawable = gtk_impl->GetGDKWindow();
+        if (srcDrawable == NULL)
+            return false;
     }
 
-    if (selected.IsOk())
-    {
-        is_mono = (selected.GetDepth() == 1);
+    CalcBoundingBox(xdest, ydest);
+    CalcBoundingBox(xdest + width, ydest + height);
 
-        // we use the "XCopyArea" way to copy a memory dc into
-        // a different window if the memory dc BOTH
-        // a) doesn't have any mask or its mask isn't used
-        // b) it is clipped
-        // c) is not 1-bit
+    // source device coords
+    int src_x = source->LogicalToDeviceX(xsrc);
+    int src_y = source->LogicalToDeviceY(ysrc);
+    int src_w = source->LogicalToDeviceXRel(width);
+    int src_h = source->LogicalToDeviceYRel(height);
 
-        if (useMask && (selected.GetMask()))
-        {
-            // we HAVE TO use the direct way for memory dcs
-            // that have mask since the XCopyArea doesn't know
-            // about masks
-            use_bitmap_method = true;
-        }
-        else if (is_mono)
-        {
-            // we HAVE TO use the direct way for memory dcs
-            // that are bitmaps because XCopyArea doesn't cope
-            // with different bit depths
-            use_bitmap_method = true;
-        }
-        else if ((xsrc == 0) && (ysrc == 0) &&
-                 (width == selected.GetWidth()) &&
-                 (height == selected.GetHeight()))
+    // Clip source rect to source dc.
+    // Only necessary when scaling, to avoid GDK errors when
+    // converting to pixbuf, but no harm in always doing it.
+    // If source rect changes, it also changes the dest rect.
+    wxRect clip;
+    gdk_drawable_get_size(srcDrawable, &clip.width, &clip.height);
+    clip.Intersect(wxRect(src_x, src_y, src_w, src_h));
+    if (src_w != clip.width || src_h != clip.height)
+    {
+        if (clip.width == 0)
+            return true;
+
+        src_w = clip.width;
+        src_h = clip.height;
+        width  = source->DeviceToLogicalXRel(src_w);
+        height = source->DeviceToLogicalYRel(src_h);
+        if (src_x != clip.x || src_y != clip.y)
         {
-            // we SHOULD use the direct way if all of the bitmap
-            // in the memory dc is copied in which case XCopyArea
-            // wouldn't be able able to boost performace by reducing
-            // the area to be scaled
-            use_bitmap_method = true;
+            xdest += source->DeviceToLogicalXRel(clip.x - src_x);
+            ydest += source->DeviceToLogicalYRel(clip.y - src_y);
+            src_x = clip.x;
+            src_y = clip.y;
         }
     }
 
-    CalcBoundingBox( xdest, ydest );
-    CalcBoundingBox( xdest + width, ydest + height );
-
-    // scale/translate size and position
-    wxCoord xx = XLOG2DEV(xdest);
-    wxCoord yy = YLOG2DEV(ydest);
-
-    wxCoord ww = XLOG2DEVREL(width);
-    wxCoord hh = YLOG2DEVREL(height);
+    // destination device coords
+    const int dst_x = LogicalToDeviceX(xdest);
+    const int dst_y = LogicalToDeviceY(ydest);
+    const int dst_w = LogicalToDeviceXRel(width);
+    const int dst_h = LogicalToDeviceYRel(height);
 
-    // compare to current clipping region
-    if (!m_currentClippingRegion.IsNull())
+    GdkRegion* const clipRegion = m_currentClippingRegion.GetRegion();
+    // determine dest clip region overlap
+    int overlap = wxInRegion;
+    if (clipRegion)
     {
-        wxRegion tmp( xx,yy,ww,hh );
-        tmp.Intersect( m_currentClippingRegion );
-        if (tmp.IsEmpty())
+        overlap = m_currentClippingRegion.Contains(dst_x, dst_y, dst_w, dst_h);
+        if (overlap == wxOutRegion)
             return true;
     }
 
-    int old_logical_func = m_logicalFunction;
-    SetLogicalFunction( logical_func );
-
-    if (use_bitmap_method)
+    const bool isScaled = src_w != dst_w || src_h != dst_h;
+    double scale_x = 0;
+    double scale_y = 0;
+    if (isScaled)
     {
-        // scale/translate bitmap size
-        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
-        // bitmap, these are the same as the original
-        // coordinates
-        wxCoord cx = xx;
-        wxCoord cy = yy;
-        wxCoord cw = ww;
-        wxCoord ch = hh;
-
-        // interpret userscale of src too
-        double xsc,ysc;
-        memDC->GetUserScale(&xsc,&ysc);
-        bm_width = (int) (bm_width / xsc);
-        bm_height = (int) (bm_height / ysc);
-
-        wxCoord bm_ww = XLOG2DEVREL( bm_width );
-        wxCoord bm_hh = YLOG2DEVREL( bm_height );
-
-        // Scale bitmap if required
-        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 );
-            if (!m_currentClippingRegion.IsNull())
-                tmp.Intersect( m_currentClippingRegion );
-            tmp.GetBox(cx,cy,cw,ch);
-
-            // Scale and clipped bitmap
-            use_bitmap = selected.Rescale(cx-xx,cy-yy,cw,ch,bm_ww,bm_hh);
-        }
-
-        // apply mask if any
-        GdkBitmap *mask = (GdkBitmap *) NULL;
-        if (useMask && use_bitmap.GetMask())
-            mask = use_bitmap.GetMask()->GetBitmap();
-
-        GdkGC* use_gc = is_mono ? m_textGC : m_penGC;
+        // get source to dest scale
+        double usx, usy, lsx, lsy;
+        source->GetUserScale(&usx, &usy);
+        source->GetLogicalScale(&lsx, &lsy);
+        scale_x = m_scaleX / (usx * lsx);
+        scale_y = m_scaleY / (usy * lsy);
+    }
 
-        GdkBitmap *new_mask = (GdkBitmap*) NULL;
+    GdkGC* const use_gc = m_penGC;
 
-        if (mask != NULL)
+    if (mask)
+    {
+        int srcMask_x = src_x;
+        int srcMask_y = src_y;
+        if (xsrcMask != -1 || ysrcMask != -1)
         {
-            if (!m_currentClippingRegion.IsNull())
-            {
-                GdkColor col;
-                new_mask = gdk_pixmap_new( wxGetRootWindow()->window, bm_ww, bm_hh, 1 );
-                GdkGC *gc = gdk_gc_new( new_mask );
-                col.pixel = 0;
-                gdk_gc_set_foreground( gc, &col );
-                gdk_gc_set_ts_origin( gc, -xsrcMask, -ysrcMask);
-                gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, bm_ww, bm_hh );
-                col.pixel = 0;
-                gdk_gc_set_background( gc, &col );
-                col.pixel = 1;
-                gdk_gc_set_foreground( gc, &col );
-                gdk_gc_set_clip_region( gc, m_currentClippingRegion.GetRegion() );
-                // was: gdk_gc_set_clip_origin( gc, -xx, -yy );
-                gdk_gc_set_clip_origin( gc, -cx, -cy );
-                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);
-            }
-
-            gdk_gc_set_clip_mask(use_gc, mask);
-            if (new_mask != NULL)
-                gdk_gc_set_clip_origin(use_gc, cx, cy);
-            else
-                gdk_gc_set_clip_origin(use_gc, cx - xsrcMask, cy - ysrcMask);
+            srcMask_x = source->LogicalToDeviceX(xsrcMask);
+            srcMask_y = source->LogicalToDeviceY(ysrcMask);
         }
-
-        // Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For
-        // drawing a mono-bitmap (XBitmap) we use the current text GC
-
-        if (is_mono)
+        GdkPixmap* mask_new = NULL;
+        if (isScaled)
         {
-            GdkPixmap *bitmap = gdk_pixmap_new( wxGetRootWindow()->window, bm_ww, bm_hh, -1 );
-            GdkGC *gc = gdk_gc_new( bitmap );
-            gdk_gc_set_foreground( gc, m_textForegroundColour.GetColor() );
-            gdk_gc_set_background( gc, m_textBackgroundColour.GetColor() );
-            gdk_wx_draw_bitmap(bitmap, gc, use_bitmap.GetPixmap(), 0, 0);
-
-            gdk_draw_drawable(m_gdkwindow, use_gc, bitmap, xsrc, ysrc, cx, cy, cw, ch);
-
-            g_object_unref (bitmap);
-            g_object_unref (gc);
+            mask = ScaleMask(mask, srcMask_x, srcMask_y,
+                src_w, src_h, dst_w, dst_h, scale_x, scale_y);
+            mask_new = mask;
+            srcMask_x = 0;
+            srcMask_y = 0;
         }
-        else
+        if (overlap == wxPartRegion)
         {
-            // was: gdk_draw_drawable( m_gdkwindow, m_penGC, use_bitmap.GetPixmap(), xsrc, ysrc, xx, yy, ww, hh );
-            gdk_draw_drawable(m_gdkwindow, use_gc, use_bitmap.GetPixmap(), xsrc, ysrc, cx, cy, cw, ch);
+            // need a new mask that also masks the clipped area,
+            // because gc can't have both a mask and a clip region
+            mask = ClipMask(mask, clipRegion,
+                srcMask_x, srcMask_y, dst_x, dst_y, dst_w, dst_h);
+            if (mask_new)
+                g_object_unref(mask_new);
+            mask_new = mask;
+            srcMask_x = 0;
+            srcMask_y = 0;
         }
+        gdk_gc_set_clip_mask(use_gc, mask);
+        gdk_gc_set_clip_origin(use_gc, dst_x - srcMask_x, dst_y - srcMask_y);
+        if (mask_new)
+            g_object_unref(mask_new);
+    }
 
-        // remove mask again if any
-        if (mask != NULL)
-        {
-            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());
-        }
+    GdkPixmap* pixmap = NULL;
+    if (gdk_drawable_get_depth(srcDrawable) == 1 &&
+        (gdk_drawable_get_depth(m_gdkwindow) != 1 || isScaled))
+    {
+        // Convert mono pixmap to color using text fg/bg colors.
+        // Scaling/drawing is simpler if this is done first.
+        pixmap = MonoToColor(srcDrawable, src_x, src_y, src_w, src_h);
+        srcDrawable = pixmap;
+        src_x = 0;
+        src_y = 0;
+    }
 
-        if (new_mask)
-            g_object_unref (new_mask);
+    const wxRasterOperationMode logical_func_save = m_logicalFunction;
+    SetLogicalFunction(logical_func);
+    if (memDC == NULL)
+        gdk_gc_set_subwindow(use_gc, GDK_INCLUDE_INFERIORS);
+
+    if (isScaled)
+    {
+        GdkPixbuf* pixbuf = Scale(srcDrawable,
+            src_x, src_y, src_w, src_h, dst_w, dst_h, scale_x, scale_y);
+        gdk_draw_pixbuf(m_gdkwindow, use_gc, pixbuf,
+            0, 0, dst_x, dst_y, dst_w, dst_h, GDK_RGB_DITHER_NONE, 0, 0);
+        g_object_unref(pixbuf);
     }
-    else // use_bitmap_method
+    else
     {
-        if (selected.IsOk() && ((width != ww) || (height != hh)))
-        {
-            // get clip coords
-            wxRegion tmp( xx,yy,ww,hh );
-            tmp.Intersect( m_currentClippingRegion );
-            wxCoord cx,cy,cw,ch;
-            tmp.GetBox(cx,cy,cw,ch);
-
-            // rescale bitmap
-            wxBitmap bitmap = selected.Rescale( cx-xx, cy-yy, cw, ch, ww, hh );
-
-            // draw scaled bitmap
-            // was: gdk_draw_drawable( m_gdkwindow, m_penGC, bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 );
-            gdk_draw_drawable( m_gdkwindow, m_penGC, bitmap.GetPixmap(), 0, 0, cx, cy, -1, -1 );
-        }
-        else
-        {
-            // No scaling and not a memory dc with a mask either
-            GdkWindow* window = NULL;
-            wxDCImpl *impl = source->GetImpl();
-            wxWindowDCImpl *gtk_impl = wxDynamicCast(impl, wxWindowDCImpl);
-            if (gtk_impl)
-                window = gtk_impl->GetGDKWindow();
-            if ( !window )
-            {
-                SetLogicalFunction( old_logical_func );
-                return false;
-            }
-
-            // copy including child window contents
-            gdk_gc_set_subwindow( m_penGC, GDK_INCLUDE_INFERIORS );
-            gdk_draw_drawable( m_gdkwindow, m_penGC,
-                               window,
-                               xsrc, ysrc, xx, yy,
-                               width, height );
-            gdk_gc_set_subwindow( m_penGC, GDK_CLIP_BY_CHILDREN );
-        }
+        gdk_draw_drawable(m_gdkwindow, use_gc, srcDrawable,
+            src_x, src_y, dst_x, dst_y, dst_w, dst_h);
     }
 
-    SetLogicalFunction( old_logical_func );
+    SetLogicalFunction(logical_func_save);
+    if (memDC == NULL)
+        gdk_gc_set_subwindow(use_gc, GDK_CLIP_BY_CHILDREN);
+
+    if (pixmap)
+        g_object_unref(pixmap);
+    if (mask)
+        gdk_gc_set_clip_region(use_gc, clipRegion);
 
     return true;
 }
 
-void wxWindowDCImpl::DoDrawText( const wxString &text, wxCoord x, wxCoord y )
+void wxWindowDCImpl::DoDrawText(const wxString& text,
+                                wxCoord xLogical,
+                                wxCoord yLogical)
 {
     wxCHECK_RET( IsOk(), wxT("invalid window dc") );
 
@@ -1359,108 +1403,50 @@ void wxWindowDCImpl::DoDrawText( const wxString &text, wxCoord x, wxCoord y )
 
     if (text.empty()) return;
 
-    x = XLOG2DEV(x);
-    y = YLOG2DEV(y);
+    wxCoord x = XLOG2DEV(xLogical),
+            y = YLOG2DEV(yLogical);
 
     wxCHECK_RET( m_context, wxT("no Pango context") );
     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.IsOk() && m_font.GetUnderlined();
+    gdk_pango_context_set_colormap( m_context, m_cmap );  // not needed in gtk+ >= 2.6
 
     wxCharBuffer data = wxGTK_CONV(text);
     if ( !data )
         return;
-    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;
-
-    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.
-
-        wxCharBuffer data_tmp(datalen + 6);
-        // copy the leading U+200C ZERO WIDTH NON-JOINER encoded in UTF8 format
-        memcpy(data_tmp.data(), "\342\200\214", 3);
-        // copy the user string
-        memcpy(data_tmp.data() + 3, data, datalen);
-        // copy the trailing U+200C ZERO WIDTH NON-JOINER encoded in UTF8 format
-        memcpy(data_tmp.data() + 3 + datalen, "\342\200\214", 3);
-
-        data = data_tmp;
-        datalen += 6;
-    }
-
-    pango_layout_set_text(m_layout, data, datalen);
-
-    if (underlined)
-    {
-        PangoAttrList *attrs = pango_attr_list_new();
-        PangoAttribute *a = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
-        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);
-    }
+    pango_layout_set_text(m_layout, data, data.length());
+    const bool setAttrs = m_font.GTKSetPangoAttrs(m_layout);
 
     int oldSize = 0;
     const bool isScaled = fabs(m_scaleY - 1.0) > 0.00001;
     if (isScaled)
     {
-         // If there is a user or actually any scale applied to
-         // the device context, scale the font.
+        // If there is a user or actually any scale applied to
+        // the device context, scale the font.
 
-         // scale font description
+        // scale font description
         oldSize = pango_font_description_get_size(m_fontdesc);
         pango_font_description_set_size(m_fontdesc, int(oldSize * m_scaleY));
 
-         // actually apply scaled font
-         pango_layout_set_font_description( m_layout, m_fontdesc );
+        // actually apply scaled font
+        pango_layout_set_font_description( m_layout, m_fontdesc );
     }
 
     int w, h;
     pango_layout_get_pixel_size(m_layout, &w, &h);
-    if (m_backgroundMode == wxSOLID)
-    {
-        gdk_gc_set_foreground(m_textGC, m_textBackgroundColour.GetColor());
-        gdk_draw_rectangle(m_gdkwindow, m_textGC, true, x, y, w, h);
-        gdk_gc_set_foreground(m_textGC, m_textForegroundColour.GetColor());
-    }
 
     // Draw layout.
     int x_rtl = x;
     if (m_window && m_window->GetLayoutDirection() == wxLayout_RightToLeft)
         x_rtl -= w;
-    gdk_draw_layout(m_gdkwindow, m_textGC, x_rtl, y, m_layout);
+
+    const GdkColor* bg_col = NULL;
+    if (m_backgroundMode == wxBRUSHSTYLE_SOLID)
+        bg_col = m_textBackgroundColour.GetColor();
+
+    gdk_draw_layout_with_colors(m_gdkwindow, m_textGC, x_rtl, y, m_layout, NULL, bg_col);
 
     if (isScaled)
     {
@@ -1470,128 +1456,99 @@ void wxWindowDCImpl::DoDrawText( const wxString &text, wxCoord x, wxCoord y )
          // actually apply unscaled font
          pango_layout_set_font_description( m_layout, m_fontdesc );
     }
-    if (underlined)
+    if (setAttrs)
     {
         // undo underline attributes setting:
         pango_layout_set_attributes(m_layout, NULL);
     }
 
-    CalcBoundingBox(x + int(w / m_scaleX), y + int(h / m_scaleY));
-    CalcBoundingBox(x, y);
+    CalcBoundingBox(xLogical + int(w / m_scaleX), yLogical + int(h / m_scaleY));
+    CalcBoundingBox(xLogical, yLogical);
 }
 
-
-// TODO: There is an example of rotating text with GTK2 that would probably be
-// a better approach here:
-//           http://www.daa.com.au/pipermail/pygtk/2003-April/005052.html
-
+// TODO: When GTK2.6 is required, merge DoDrawText and DoDrawRotatedText to
+// avoid code duplication
 void wxWindowDCImpl::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, double angle )
 {
-#if wxUSE_IMAGE
     if (!m_gdkwindow || text.empty())
         return;
 
     wxCHECK_RET( IsOk(), wxT("invalid window dc") );
 
-    if ( wxIsNullDouble(angle) )
+    x = XLOG2DEV(x);
+    y = YLOG2DEV(y);
+
+    pango_layout_set_text(m_layout, wxGTK_CONV(text), -1);
+    const bool setAttrs = m_font.GTKSetPangoAttrs(m_layout);
+    int oldSize = 0;
+    const bool isScaled = fabs(m_scaleY - 1.0) > 0.00001;
+    if (isScaled)
     {
-        DoDrawText(text, x, y);
-        return;
-    }
+        //TODO: when Pango >= 1.6 is required, use pango_matrix_scale()
+         // If there is a user or actually any scale applied to
+         // the device context, scale the font.
 
-    wxCoord w;
-    wxCoord h;
+         // scale font description
+        oldSize = pango_font_description_get_size(m_fontdesc);
+        pango_font_description_set_size(m_fontdesc, int(oldSize * m_scaleY));
 
-    // TODO: implement later without GdkFont for GTK 2.0
-    DoGetTextExtent(text, &w, &h, NULL,NULL, &m_font);
+         // actually apply scaled font
+         pango_layout_set_font_description( m_layout, m_fontdesc );
+    }
 
-    // draw the string normally
-    wxBitmap src(w, h);
-    wxMemoryDC dc;
-    dc.SelectObject(src);
-    dc.SetFont(GetFont());
-    dc.SetBackground(*wxBLACK_BRUSH);
-    dc.SetBrush(*wxBLACK_BRUSH);
-    dc.Clear();
-    dc.SetTextForeground( *wxWHITE );
-    dc.DrawText(text, 0, 0);
-    dc.SelectObject(wxNullBitmap);
+    int w, h;
+    pango_layout_get_pixel_size(m_layout, &w, &h);
 
-    // Calculate the size of the rotated bounding box.
+    const GdkColor* bg_col = NULL;
+    if (m_backgroundMode == wxBRUSHSTYLE_SOLID)
+        bg_col = m_textBackgroundColour.GetColor();
+
+    // rotate the text
+    PangoMatrix matrix = PANGO_MATRIX_INIT;
+    pango_matrix_rotate (&matrix, angle);
+    pango_context_set_matrix (m_context, &matrix);
+    pango_layout_context_changed (m_layout);
+
+    // To be compatible with MSW, the rotation axis must be in the old
+    // top-left corner.
+    // Calculate the vertices of the rotated rectangle containing the text,
+    // relative to the old top-left vertex.
+    // We could use the matrix for this, but it's simpler with trignonometry.
     double rad = DegToRad(angle);
-    double dx = cos(rad),
-           dy = sin(rad);
-
-    // the rectngle vertices are counted clockwise with the first one being at
-    // (0, 0) (or, rather, at (x, y))
-    double x2 = w*dx,
-           y2 = -w*dy;      // y axis points to the bottom, hence minus
-    double x4 = h*dy,
-           y4 = h*dx;
-    double x3 = x4 + x2,
-           y3 = y4 + y2;
-
-    // calc max and min
-    wxCoord maxX = (wxCoord)(dmax(x2, dmax(x3, x4)) + 0.5),
-            maxY = (wxCoord)(dmax(y2, dmax(y3, y4)) + 0.5),
-            minX = (wxCoord)(dmin(x2, dmin(x3, x4)) - 0.5),
-            minY = (wxCoord)(dmin(y2, dmin(y3, y4)) - 0.5);
-
-
-    wxImage image = src.ConvertToImage();
-
-    image.ConvertColourToAlpha( m_textForegroundColour.Red(),
-                                m_textForegroundColour.Green(),
-                                m_textForegroundColour.Blue() );
-    image = image.Rotate( rad, wxPoint(0,0) );
-
-    int i_angle = (int) angle;
-    i_angle = i_angle % 360;
-    if (i_angle < 0)
-        i_angle += 360;
-    int xoffset = 0;
-    if ((i_angle >= 90.0) && (i_angle < 270.0))
-        xoffset = image.GetWidth();
-    int yoffset = 0;
-    if ((i_angle >= 0.0) && (i_angle < 180.0))
-        yoffset = image.GetHeight();
-
-    if ((i_angle >= 0) && (i_angle < 90))
-        yoffset -= (int)( cos(rad)*h );
-    if ((i_angle >= 90) && (i_angle < 180))
-        xoffset -= (int)( sin(rad)*h );
-    if ((i_angle >= 180) && (i_angle < 270))
-        yoffset -= (int)( cos(rad)*h );
-    if ((i_angle >= 270) && (i_angle < 360))
-        xoffset -= (int)( sin(rad)*h );
-
-    int i_x = x - xoffset;
-    int i_y = y - yoffset;
-
-    src = image;
-    DoDrawBitmap( src, i_x, i_y, true );
-
-
-    // it would be better to draw with non underlined font and draw the line
-    // manually here (it would be more straight...)
-#if 0
-    if ( m_font.GetUnderlined() )
-    {
-        gdk_draw_line( m_gdkwindow, m_textGC,
-                       XLOG2DEV(x + x4), YLOG2DEV(y + y4 + font->descent),
-                       XLOG2DEV(x + x3), YLOG2DEV(y + y3 + font->descent));
-    }
-#endif // 0
-
-    // update the bounding box
-    CalcBoundingBox(x + minX, y + minY);
-    CalcBoundingBox(x + maxX, y + maxY);
-#else // !wxUSE_IMAGE
-    wxUnusedVar(text);
-    wxUnusedVar(x);
-    wxUnusedVar(y);
-    wxUnusedVar(angle);
-#endif // wxUSE_IMAGE/!wxUSE_IMAGE
+    // the rectangle vertices are counted clockwise with the first one
+    // being at (0, 0)
+    double x2 = w * cos(rad);
+    double y2 = -w * sin(rad);   // y axis points to the bottom, hence minus
+    double x4 = h * sin(rad);
+    double y4 = h * cos(rad);
+    double x3 = x4 + x2;
+    double y3 = y4 + y2;
+    // Then we calculate max and min of the rotated rectangle.
+    wxCoord maxX = (wxCoord)(dmax(dmax(0, x2), dmax(x3, x4)) + 0.5),
+            maxY = (wxCoord)(dmax(dmax(0, y2), dmax(y3, y4)) + 0.5),
+            minX = (wxCoord)(dmin(dmin(0, x2), dmin(x3, x4)) - 0.5),
+            minY = (wxCoord)(dmin(dmin(0, y2), dmin(y3, y4)) - 0.5);
+
+    gdk_draw_layout_with_colors(m_gdkwindow, m_textGC, x+minX, y+minY,
+                                m_layout, NULL, bg_col);
+
+    if (setAttrs)
+        pango_layout_set_attributes(m_layout, NULL);
+
+    // clean up the transformation matrix
+    pango_context_set_matrix(m_context, NULL);
+
+    if (isScaled)
+    {
+         // reset unscaled size
+         pango_font_description_set_size( m_fontdesc, oldSize );
+
+         // actually apply unscaled font
+         pango_layout_set_font_description( m_layout, m_fontdesc );
+    }
+
+    CalcBoundingBox(x+minX, y+minY);
+    CalcBoundingBox(x+maxX, y+maxY);
 }
 
 void wxWindowDCImpl::DoGetTextExtent(const wxString &string,
@@ -1599,105 +1556,27 @@ void wxWindowDCImpl::DoGetTextExtent(const wxString &string,
                                  wxCoord *descent, wxCoord *externalLeading,
                                  const wxFont *theFont) const
 {
-    if ( width )
-        *width = 0;
-    if ( height )
-        *height = 0;
-    if ( descent )
-        *descent = 0;
-    if ( externalLeading )
-        *externalLeading = 0;
-
-    if (string.empty())
-        return;
-
-    // ensure that theFont is always non-NULL
+    // ensure we work with a valid font
+    const wxFont *fontToUse;
     if ( !theFont || !theFont->IsOk() )
-        theFont = wx_const_cast(wxFont *, &m_font);
-
-    // and use it if it's valid
-    if ( theFont->IsOk() )
-    {
-        pango_layout_set_font_description
-        (
-            m_layout,
-            theFont->GetNativeFontInfo()->description
-        );
-    }
-
-    // Set layout's text
-    const wxCharBuffer dataUTF8 = wxGTK_CONV_FONT(string, *theFont);
-    if ( !dataUTF8 )
-    {
-        // hardly ideal, but what else can we do if conversion failed?
-        return;
-    }
-
-    pango_layout_set_text( m_layout, dataUTF8, strlen(dataUTF8) );
-
-    if (descent)
-    {
-        int h;
-        pango_layout_get_pixel_size( m_layout, width, &h );
-        PangoLayoutIter *iter = pango_layout_get_iter(m_layout);
-        int baseline = pango_layout_iter_get_baseline(iter);
-        pango_layout_iter_free(iter);
-        *descent = h - PANGO_PIXELS(baseline);
-
-        if (height)
-            *height = (wxCoord) h;
-    }
+        fontToUse = &m_font;
     else
-    {
-        pango_layout_get_pixel_size( m_layout, width, height );
-    }
+        fontToUse = theFont;
 
-    // Reset old font description
-    if (theFont->IsOk())
-        pango_layout_set_font_description( m_layout, m_fontdesc );
+    wxCHECK_RET( fontToUse->IsOk(), wxT("invalid font") );
+
+    wxTextMeasure txm(GetOwner(), fontToUse);
+    txm.GetTextExtent(string, width, height, descent, externalLeading);
 }
 
 
 bool wxWindowDCImpl::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);
+    wxCHECK_MSG( m_font.IsOk(), false, wxT("Invalid font") );
 
-    return true;
+    wxTextMeasure txm(GetOwner(), &m_font);
+    return txm.GetPartialTextExtents(text, widths, m_scaleX);
 }
 
 
@@ -1712,10 +1591,10 @@ wxCoord wxWindowDCImpl::GetCharWidth() const
 wxCoord wxWindowDCImpl::GetCharHeight() const
 {
     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") );
+    wxCHECK_MSG( metrics, -1, wxT("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_get_ascent (metrics));
     pango_font_metrics_unref (metrics);
     return h;
 }
@@ -1747,7 +1626,7 @@ void wxWindowDCImpl::SetFont( const wxFont &font )
         {
             PangoContext *oldContext = m_context;
 
-            m_context = m_window->GtkGetPangoDefaultContext();
+            m_context = m_window->GTKGetPangoDefaultContext();
 
             // If we switch back/forth between different contexts
             // we also have to create a new layout. I think so,
@@ -1809,57 +1688,39 @@ void wxWindowDCImpl::SetPen( const wxPen &pen )
     int req_nb_dash;
     const wxGTKDash *req_dash;
 
-    GdkLineStyle lineStyle = GDK_LINE_SOLID;
+    GdkLineStyle lineStyle = GDK_LINE_ON_OFF_DASH;
     switch (m_pen.GetStyle())
     {
-        case wxUSER_DASH:
-        {
-            lineStyle = GDK_LINE_ON_OFF_DASH;
+        case wxPENSTYLE_USER_DASH:
             req_nb_dash = m_pen.GetDashCount();
             req_dash = (wxGTKDash*)m_pen.GetDash();
             break;
-        }
-        case wxDOT:
-        {
-            lineStyle = GDK_LINE_ON_OFF_DASH;
+        case wxPENSTYLE_DOT:
             req_nb_dash = 2;
             req_dash = dotted;
             break;
-        }
-        case wxLONG_DASH:
-        {
-            lineStyle = GDK_LINE_ON_OFF_DASH;
+        case wxPENSTYLE_LONG_DASH:
             req_nb_dash = 2;
             req_dash = wxCoord_dashed;
             break;
-        }
-        case wxSHORT_DASH:
-        {
-            lineStyle = GDK_LINE_ON_OFF_DASH;
+        case wxPENSTYLE_SHORT_DASH:
             req_nb_dash = 2;
             req_dash = short_dashed;
             break;
-        }
-        case wxDOT_DASH:
-        {
-//            lineStyle = GDK_LINE_DOUBLE_DASH;
-            lineStyle = GDK_LINE_ON_OFF_DASH;
+        case wxPENSTYLE_DOT_DASH:
             req_nb_dash = 4;
             req_dash = dotted_dashed;
             break;
-        }
 
-        case wxTRANSPARENT:
-        case wxSTIPPLE_MASK_OPAQUE:
-        case wxSTIPPLE:
-        case wxSOLID:
+        case wxPENSTYLE_TRANSPARENT:
+        case wxPENSTYLE_STIPPLE_MASK_OPAQUE:
+        case wxPENSTYLE_STIPPLE:
+        case wxPENSTYLE_SOLID:
         default:
-        {
             lineStyle = GDK_LINE_SOLID;
-            req_dash = (wxGTKDash*)NULL;
+            req_dash = NULL;
             req_nb_dash = 0;
             break;
-        }
     }
 
     if (req_dash && req_nb_dash)
@@ -1886,18 +1747,12 @@ void wxWindowDCImpl::SetPen( const wxPen &pen )
         case wxCAP_BUTT:       { capStyle = GDK_CAP_BUTT;       break; }
         case wxCAP_ROUND:
         default:
-        {
             if (width <= 1)
             {
                 width = 0;
                 capStyle = GDK_CAP_NOT_LAST;
             }
-            else
-            {
-                capStyle = GDK_CAP_ROUND;
-            }
             break;
-        }
     }
 
     GdkJoinStyle joinStyle = GDK_JOIN_ROUND;
@@ -1932,7 +1787,7 @@ void wxWindowDCImpl::SetBrush( const wxBrush &brush )
 
     gdk_gc_set_fill( m_brushGC, GDK_SOLID );
 
-    if ((m_brush.GetStyle() == wxSTIPPLE) && (m_brush.GetStipple()->IsOk()))
+    if ((m_brush.GetStyle() == wxBRUSHSTYLE_STIPPLE) && (m_brush.GetStipple()->IsOk()))
     {
         if (m_brush.GetStipple()->GetDepth() != 1)
         {
@@ -1946,10 +1801,10 @@ void wxWindowDCImpl::SetBrush( const wxBrush &brush )
         }
     }
 
-    if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
+    if ((m_brush.GetStyle() == wxBRUSHSTYLE_STIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask()))
     {
         gdk_gc_set_fill( m_textGC, GDK_OPAQUE_STIPPLED);
-        gdk_gc_set_stipple( m_textGC, m_brush.GetStipple()->GetMask()->GetBitmap() );
+        gdk_gc_set_stipple( m_textGC, *m_brush.GetStipple()->GetMask() );
     }
 
     if (m_brush.IsHatch())
@@ -1974,36 +1829,42 @@ void wxWindowDCImpl::SetBackground( const wxBrush &brush )
 
     if (!m_gdkwindow) return;
 
-    m_backgroundBrush.GetColour().CalcPixel( m_cmap );
-    gdk_gc_set_background( m_brushGC, m_backgroundBrush.GetColour().GetColor() );
-    gdk_gc_set_background( m_penGC, m_backgroundBrush.GetColour().GetColor() );
-    gdk_gc_set_background( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
-    gdk_gc_set_foreground( m_bgGC, m_backgroundBrush.GetColour().GetColor() );
+    wxColor color = m_backgroundBrush.GetColour();
+    color.CalcPixel(m_cmap);
+    const GdkColor* gdkColor = color.GetColor();
+    gdk_gc_set_background(m_brushGC, gdkColor);
+    gdk_gc_set_background(m_penGC,   gdkColor);
+    gdk_gc_set_background(m_bgGC,    gdkColor);
+    gdk_gc_set_foreground(m_bgGC,    gdkColor);
+
 
     gdk_gc_set_fill( m_bgGC, GDK_SOLID );
 
-    if ((m_backgroundBrush.GetStyle() == wxSTIPPLE) && (m_backgroundBrush.GetStipple()->IsOk()))
+    if (m_backgroundBrush.GetStyle() == wxBRUSHSTYLE_STIPPLE)
     {
-        if (m_backgroundBrush.GetStipple()->GetDepth() != 1)
-        {
-            gdk_gc_set_fill( m_bgGC, GDK_TILED );
-            gdk_gc_set_tile( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() );
-        }
-        else
+        const wxBitmap* stipple = m_backgroundBrush.GetStipple();
+        if (stipple->IsOk())
         {
-            gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
-            gdk_gc_set_stipple( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() );
+            if (stipple->GetDepth() != 1)
+            {
+                gdk_gc_set_fill(m_bgGC, GDK_TILED);
+                gdk_gc_set_tile(m_bgGC, stipple->GetPixmap());
+            }
+            else
+            {
+                gdk_gc_set_fill(m_bgGC, GDK_STIPPLED);
+                gdk_gc_set_stipple(m_bgGC, stipple->GetPixmap());
+            }
         }
     }
-
-    if (m_backgroundBrush.IsHatch())
+    else if (m_backgroundBrush.IsHatch())
     {
         gdk_gc_set_fill( m_bgGC, GDK_STIPPLED );
         gdk_gc_set_stipple(m_bgGC, GetHatch(m_backgroundBrush.GetStyle()));
     }
 }
 
-void wxWindowDCImpl::SetLogicalFunction( int function )
+void wxWindowDCImpl::SetLogicalFunction( wxRasterOperationMode function )
 {
     wxCHECK_RET( IsOk(), wxT("invalid window dc") );
 
@@ -2032,12 +1893,10 @@ void wxWindowDCImpl::SetLogicalFunction( int function )
         case wxCOPY:         mode = GDK_COPY;          break;
         case wxNO_OP:        mode = GDK_NOOP;          break;
         case wxSRC_INVERT:   mode = GDK_COPY_INVERT;   break;
-
-        // unsupported by GTK
-        case wxNOR:          mode = GDK_COPY;          break;
+        case wxNOR:          mode = GDK_NOR;           break;
         default:
-           wxFAIL_MSG( wxT("unsupported logical function") );
-           mode = GDK_COPY;
+            wxFAIL_MSG("unknown mode");
+            return;
     }
 
     m_logicalFunction = function;
@@ -2092,17 +1951,6 @@ void wxWindowDCImpl::SetBackgroundMode( int mode )
     wxCHECK_RET( IsOk(), wxT("invalid window dc") );
 
     m_backgroundMode = mode;
-
-    if (!m_gdkwindow) return;
-
-    // CMB 21/7/98: fill style of cross-hatch brushes is affected by
-    // transparent/solid background mode
-
-    if (m_brush.GetStyle() != wxSOLID && m_brush.GetStyle() != wxTRANSPARENT)
-    {
-        gdk_gc_set_fill( m_brushGC,
-          (m_backgroundMode == wxTRANSPARENT) ? GDK_STIPPLED : GDK_OPAQUE_STIPPLED);
-    }
 }
 
 void wxWindowDCImpl::SetPalette( const wxPalette& WXUNUSED(palette) )
@@ -2122,37 +1970,16 @@ void wxWindowDCImpl::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, w
     rect.width = XLOG2DEVREL(width);
     rect.height = YLOG2DEVREL(height);
 
-    if (m_window && m_window->m_wxwindow && 
+    if (m_window && m_window->m_wxwindow &&
         (m_window->GetLayoutDirection() == wxLayout_RightToLeft))
     {
         rect.x -= rect.width;
     }
 
-    if (!m_currentClippingRegion.IsNull())
-        m_currentClippingRegion.Intersect( rect );
-    else
-        m_currentClippingRegion.Union( rect );
-
-#if USE_PAINT_REGION
-    if (!m_paintClippingRegion.IsNull())
-        m_currentClippingRegion.Intersect( m_paintClippingRegion );
-#endif
-
-    wxCoord xx, yy, ww, hh;
-    m_currentClippingRegion.GetBox( xx, yy, ww, hh );
-#if wxUSE_NEW_DC
-    wxGTKDCImpl::DoSetClippingRegion( xx, yy, ww, hh );
-#else
-    wxDC::DoSetClippingRegion( xx, yy, ww, hh );
-#endif
-
-    gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
-    gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
-    gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
-    gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
+    DoSetDeviceClippingRegion(wxRegion(rect));
 }
 
-void wxWindowDCImpl::DoSetClippingRegionAsRegion( const wxRegion &region  )
+void wxWindowDCImpl::DoSetDeviceClippingRegion( const wxRegion &region  )
 {
     wxCHECK_RET( IsOk(), wxT("invalid window dc") );
 
@@ -2176,27 +2003,20 @@ void wxWindowDCImpl::DoSetClippingRegionAsRegion( const wxRegion &region  )
 
     wxCoord xx, yy, ww, hh;
     m_currentClippingRegion.GetBox( xx, yy, ww, hh );
-#if wxUSE_NEW_DC
     wxGTKDCImpl::DoSetClippingRegion( xx, yy, ww, hh );
-#else
-    wxDC::DoSetClippingRegion( xx, yy, ww, hh );
-#endif
 
-    gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
-    gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
-    gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
-    gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
+    GdkRegion* gdkRegion = m_currentClippingRegion.GetRegion();
+    gdk_gc_set_clip_region(m_penGC,   gdkRegion);
+    gdk_gc_set_clip_region(m_brushGC, gdkRegion);
+    gdk_gc_set_clip_region(m_textGC,  gdkRegion);
+    gdk_gc_set_clip_region(m_bgGC,    gdkRegion);
 }
 
 void wxWindowDCImpl::DestroyClippingRegion()
 {
     wxCHECK_RET( IsOk(), wxT("invalid window dc") );
 
-#if wxUSE_NEW_DC
     wxDCImpl::DestroyClippingRegion();
-#else
-    wxDC::DestroyClippingRegion();
-#endif
 
     m_currentClippingRegion.Clear();
 
@@ -2207,32 +2027,26 @@ void wxWindowDCImpl::DestroyClippingRegion()
 
     if (!m_gdkwindow) return;
 
-    if (m_currentClippingRegion.IsEmpty())
-    {
-        gdk_gc_set_clip_rectangle( m_penGC, (GdkRectangle *) NULL );
-        gdk_gc_set_clip_rectangle( m_brushGC, (GdkRectangle *) NULL );
-        gdk_gc_set_clip_rectangle( m_textGC, (GdkRectangle *) NULL );
-        gdk_gc_set_clip_rectangle( m_bgGC, (GdkRectangle *) NULL );
-    }
-    else
-    {
-        gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() );
-        gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() );
-        gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() );
-        gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() );
-    }
+    GdkRegion* gdkRegion = NULL;
+    if (!m_currentClippingRegion.IsEmpty())
+        gdkRegion = m_currentClippingRegion.GetRegion();
+
+    gdk_gc_set_clip_region(m_penGC,   gdkRegion);
+    gdk_gc_set_clip_region(m_brushGC, gdkRegion);
+    gdk_gc_set_clip_region(m_textGC,  gdkRegion);
+    gdk_gc_set_clip_region(m_bgGC,    gdkRegion);
 }
 
 void wxWindowDCImpl::Destroy()
 {
     if (m_penGC) wxFreePoolGC( m_penGC );
-    m_penGC = (GdkGC*) NULL;
+    m_penGC = NULL;
     if (m_brushGC) wxFreePoolGC( m_brushGC );
-    m_brushGC = (GdkGC*) NULL;
+    m_brushGC = NULL;
     if (m_textGC) wxFreePoolGC( m_textGC );
-    m_textGC = (GdkGC*) NULL;
+    m_textGC = NULL;
     if (m_bgGC) wxFreePoolGC( m_bgGC );
-    m_bgGC = (GdkGC*) NULL;
+    m_bgGC = NULL;
 }
 
 void wxWindowDCImpl::SetDeviceOrigin( wxCoord x, wxCoord y )
@@ -2248,7 +2062,7 @@ void wxWindowDCImpl::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
     m_signX = (xLeftRight ?  1 : -1);
     m_signY = (yBottomUp  ? -1 :  1);
 
-    if (m_window && m_window->m_wxwindow && 
+    if (m_window && m_window->m_wxwindow &&
         (m_window->GetLayoutDirection() == wxLayout_RightToLeft))
         m_signX = -m_signX;
 
@@ -2259,11 +2073,7 @@ void wxWindowDCImpl::ComputeScaleAndOrigin()
 {
     const wxRealPoint origScale(m_scaleX, m_scaleY);
 
-#if wxUSE_NEW_DC
     wxDCImpl::ComputeScaleAndOrigin();
-#else
-    wxDC::ComputeScaleAndOrigin();
-#endif
 
     // if scale has changed call SetPen to recalulate the line width
     if ( wxRealPoint(m_scaleX, m_scaleY) != origScale && m_pen.IsOk() )
@@ -2287,7 +2097,6 @@ int wxWindowDCImpl::GetDepth() const
     return gdk_drawable_get_depth(m_gdkwindow);
 }
 
-
 //-----------------------------------------------------------------------------
 // wxClientDCImpl
 //-----------------------------------------------------------------------------
@@ -2302,22 +2111,22 @@ wxClientDCImpl::wxClientDCImpl( wxDC *owner )
 wxClientDCImpl::wxClientDCImpl( wxDC *owner, wxWindow *win )
           : wxWindowDCImpl( owner, win )
 {
-    wxCHECK_RET( win, _T("NULL window in wxClientDCImpl::wxClientDC") );
+    wxCHECK_RET( win, wxT("NULL window in wxClientDCImpl::wxClientDC") );
 
 #ifdef __WXUNIVERSAL__
     wxPoint ptOrigin = win->GetClientAreaOrigin();
     SetDeviceOrigin(ptOrigin.x, ptOrigin.y);
     wxSize size = win->GetClientSize();
     DoSetClippingRegion(0, 0, size.x, size.y);
-#endif 
+#endif
     // __WXUNIVERSAL__
 }
 
 void wxClientDCImpl::DoGetSize(int *width, int *height) const
 {
-    wxCHECK_RET( m_window, _T("GetSize() doesn't work without window") );
+    wxCHECK_RET( m_window, wxT("GetSize() doesn't work without window") );
 
-    m_window->GetClientSize( width, height );
+    m_window->GetClientSize(width, height);
 }
 
 //-----------------------------------------------------------------------------
@@ -2375,7 +2184,7 @@ wxPaintDCImpl::wxPaintDCImpl( wxDC *owner, wxWindow *win )
         gdk_gc_set_clip_region( m_textGC, region );
         gdk_gc_set_clip_region( m_bgGC, region );
     }
-#endif 
+#endif
 }
 
 // ----------------------------------------------------------------------------
@@ -2404,7 +2213,7 @@ void wxDCModule::OnExit()
 {
     wxCleanUpGCPool();
 
-    for (int i = wxLAST_HATCH - wxFIRST_HATCH; i--; )
+    for (int i = wxBRUSHSTYLE_LAST_HATCH - wxBRUSHSTYLE_FIRST_HATCH; i--; )
     {
         if (hatches[i])
             g_object_unref(hatches[i]);