X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/2970ae54d3ac3989cd47180229bc7d6cc0f65f51..0d53638f7147c18153f63fdfc096b17be6e22a27:/src/gtk/dcclient.cpp?ds=sidebyside diff --git a/src/gtk/dcclient.cpp b/src/gtk/dcclient.cpp index f76c0f040a..a11615391e 100644 --- a/src/gtk/dcclient.cpp +++ b/src/gtk/dcclient.cpp @@ -1,8 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// // Name: src/gtk/dcclient.cpp -// Purpose: +// Purpose: wxWindowDCImpl implementation // Author: Robert Roebling -// RCS-ID: $Id$ // Copyright: (c) 1998 Robert Roebling, Chris Breeze // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -10,33 +9,32 @@ // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" -#ifdef __VMS -#define XCopyPlane XCOPYPLANE -#endif - -#include "wx/dcclient.h" +#include "wx/gtk/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/math.h" #include "wx/image.h" #include "wx/module.h" #endif #include "wx/fontutil.h" -#include "wx/scrolwin.h" -#include "wx/gtk/win_gtk.h" #include "wx/gtk/private.h" - -#include +#include "wx/gtk/private/object.h" +#include "wx/private/textmeasure.h" //----------------------------------------------------------------------------- // local defines //----------------------------------------------------------------------------- +#define XLOG2DEV(x) LogicalToDeviceX(x) +#define XLOG2DEVREL(x) LogicalToDeviceXRel(x) +#define YLOG2DEV(y) LogicalToDeviceY(y) +#define YLOG2DEVREL(y) LogicalToDeviceYRel(y) + #define USE_PAINT_REGION 1 //----------------------------------------------------------------------------- @@ -49,22 +47,14 @@ #include "horiz.xbm" #include "verti.xbm" #include "cross.xbm" -#define num_hatches 6 - -#define IS_15_PIX_HATCH(s) ((s)==wxCROSSDIAG_HATCH || (s)==wxHORIZONTAL_HATCH || (s)==wxVERTICAL_HATCH) -#define IS_16_PIX_HATCH(s) ((s)!=wxCROSSDIAG_HATCH && (s)!=wxHORIZONTAL_HATCH && (s)!=wxVERTICAL_HATCH) - - -static GdkPixmap *hatches[num_hatches]; -static GdkPixmap **hatch_bitmap = (GdkPixmap **) NULL; -extern GtkWidget *wxGetRootWindow(); +static GdkPixmap* hatches[wxBRUSHSTYLE_LAST_HATCH - wxBRUSHSTYLE_FIRST_HATCH + 1]; //----------------------------------------------------------------------------- // constants //----------------------------------------------------------------------------- -const double RAD2DEG = 180.0 / M_PI; +static const double RAD2DEG = 180.0 / M_PI; // ---------------------------------------------------------------------------- // private functions @@ -73,42 +63,50 @@ const double RAD2DEG = 180.0 / M_PI; static inline double dmax(double a, double b) { return a > b ? a : b; } static inline double dmin(double a, double b) { return a < b ? a : b; } -static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; } - -//----------------------------------------------------------------------------- -// temporary implementation of the missing GDK function -//----------------------------------------------------------------------------- +static GdkPixmap* GetHatch(int style) +{ + 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(name ## _bits), \ + name ## _width, \ + name ## _height \ + ) + + switch (style) + { + case wxBRUSHSTYLE_BDIAGONAL_HATCH: + hatches[i] = CREATE_FROM_XBM_DATA(bdiag); + break; + case wxBRUSHSTYLE_CROSSDIAG_HATCH: + hatches[i] = CREATE_FROM_XBM_DATA(cdiag); + break; + case wxBRUSHSTYLE_CROSS_HATCH: + hatches[i] = CREATE_FROM_XBM_DATA(cross); + break; + case wxBRUSHSTYLE_FDIAGONAL_HATCH: + hatches[i] = CREATE_FROM_XBM_DATA(fdiag); + break; + case wxBRUSHSTYLE_HORIZONTAL_HATCH: + hatches[i] = CREATE_FROM_XBM_DATA(horiz); + break; + case wxBRUSHSTYLE_VERTICAL_HATCH: + hatches[i] = CREATE_FROM_XBM_DATA(verti); + break; + } -#include "gdk/gdkprivate.h" - -static -void gdk_wx_draw_bitmap(GdkDrawable *drawable, - GdkGC *gc, - GdkDrawable *src, - gint xsrc, - gint ysrc, - gint xdest, - gint ydest, - gint width, - gint height) -{ - 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); - if (width == -1) width = src_width; - if (height == -1) height = src_height; - - XCopyPlane( GDK_WINDOW_XDISPLAY(drawable), - GDK_WINDOW_XID(src), - GDK_WINDOW_XID(drawable), - GDK_GC_XGC(gc), - xsrc, ysrc, - width, height, - 0, 0, - 1 ); +#undef CREATE_FROM_XBM_DATA + } + return hatches[i]; } //----------------------------------------------------------------------------- @@ -129,7 +127,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 @@ -231,7 +233,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 ) @@ -252,63 +254,59 @@ static void wxFreePoolGC( GdkGC *gc ) // wxWindowDC //----------------------------------------------------------------------------- -#if wxUSE_NEW_DC -IMPLEMENT_DYNAMIC_CLASS(wxGTKWindowImplDC, wxGTKImplDC) -#else -IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC) -#endif +IMPLEMENT_ABSTRACT_CLASS(wxWindowDCImpl, wxGTKDCImpl) -wxGTKWindowImplDC::wxGTKWindowImplDC() +wxWindowDCImpl::wxWindowDCImpl( wxDC *owner ) : + wxGTKDCImpl( owner ) { - m_penGC = (GdkGC *) NULL; - m_brushGC = (GdkGC *) NULL; - m_textGC = (GdkGC *) NULL; - m_bgGC = (GdkGC *) NULL; - m_cmap = (GdkColormap *) NULL; - m_isMemDC = false; + m_gdkwindow = NULL; + m_penGC = NULL; + m_brushGC = NULL; + m_textGC = NULL; + m_bgGC = NULL; + m_cmap = NULL; m_isScreenDC = false; - m_owner = (wxWindow *)NULL; - m_context = (PangoContext *)NULL; - m_layout = (PangoLayout *)NULL; - m_fontdesc = (PangoFontDescription *)NULL; + m_context = NULL; + m_layout = NULL; + m_fontdesc = NULL; } -wxGTKWindowImplDC::wxGTKWindowImplDC( wxWindow *window ) +wxWindowDCImpl::wxWindowDCImpl( wxDC *owner, wxWindow *window ) : + wxGTKDCImpl( owner ) { wxASSERT_MSG( window, wxT("DC needs a window") ); - m_penGC = (GdkGC *) NULL; - m_brushGC = (GdkGC *) NULL; - m_textGC = (GdkGC *) NULL; - m_bgGC = (GdkGC *) NULL; - m_cmap = (GdkColormap *) NULL; - m_owner = (wxWindow *)NULL; - m_isMemDC = false; + 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; + + wxCHECK_RET(widget, "DC needs a widget"); - wxASSERT_MSG( widget, wxT("DC needs a widget") ); + m_gdkwindow = widget->window; + if (!gtk_widget_get_has_window(widget)) + SetDeviceLocalOrigin(widget->allocation.x, widget->allocation.y); + } - m_context = window->GtkGetPangoDefaultContext(); + m_context = window->GTKGetPangoDefaultContext(); m_layout = pango_layout_new( m_context ); m_fontdesc = pango_font_description_copy( widget->style->font_desc ); - GtkPizza *pizza = GTK_PIZZA( widget ); - m_window = pizza->bin_window; - // Window not realized ? - if (!m_window) + if (!m_gdkwindow) { // Don't report problems as per MSW. m_ok = true; @@ -316,7 +314,7 @@ wxGTKWindowImplDC::wxGTKWindowImplDC( wxWindow *window ) return; } - m_cmap = gtk_widget_get_colormap( widget ? widget : window->m_widget ); + m_cmap = gtk_widget_get_colormap(widget); SetUpDC(); @@ -327,19 +325,20 @@ wxGTKWindowImplDC::wxGTKWindowImplDC( wxWindow *window ) is white whereas a window might assume gray to be the standard (as e.g. wxStatusBar) */ - m_owner = window; + m_window = window; - if (m_owner && m_owner->m_wxwindow && (m_owner->GetLayoutDirection() == wxLayout_RightToLeft)) + if (m_window && m_window->m_wxwindow && + (m_window->GetLayoutDirection() == wxLayout_RightToLeft)) { // reverse sense m_signX = -1; // origin in the upper right corner - m_deviceOriginX = m_owner->GetClientSize().x; + m_deviceOriginX = m_window->GetClientSize().x; } } -wxGTKWindowImplDC::~wxGTKWindowImplDC() +wxWindowDCImpl::~wxWindowDCImpl() { Destroy(); @@ -349,43 +348,60 @@ wxGTKWindowImplDC::~wxGTKWindowImplDC() pango_font_description_free( m_fontdesc ); } -void wxGTKWindowImplDC::SetUpDC() +void wxWindowDCImpl::SetUpDC( bool isMemDC ) { m_ok = true; wxASSERT_MSG( !m_penGC, wxT("GCs already created") ); - if (m_isScreenDC) - { - m_penGC = wxGetPoolGC( m_window, wxPEN_SCREEN ); - m_brushGC = wxGetPoolGC( m_window, wxBRUSH_SCREEN ); - m_textGC = wxGetPoolGC( m_window, wxTEXT_SCREEN ); - m_bgGC = wxGetPoolGC( m_window, wxBG_SCREEN ); - } - else - if (m_isMemDC && (((wxMemoryDC*)this)->m_selected.GetDepth() == 1)) + bool done = false; + + if ((isMemDC) && (GetSelectedBitmap().IsOk())) { - m_penGC = wxGetPoolGC( m_window, wxPEN_MONO ); - m_brushGC = wxGetPoolGC( m_window, wxBRUSH_MONO ); - m_textGC = wxGetPoolGC( m_window, wxTEXT_MONO ); - m_bgGC = wxGetPoolGC( m_window, wxBG_MONO ); + if (GetSelectedBitmap().GetDepth() == 1) + { + m_penGC = wxGetPoolGC( m_gdkwindow, wxPEN_MONO ); + m_brushGC = wxGetPoolGC( m_gdkwindow, wxBRUSH_MONO ); + m_textGC = wxGetPoolGC( m_gdkwindow, wxTEXT_MONO ); + m_bgGC = wxGetPoolGC( m_gdkwindow, wxBG_MONO ); + done = true; + } } - else + + if (!done) { - m_penGC = wxGetPoolGC( m_window, wxPEN_COLOUR ); - m_brushGC = wxGetPoolGC( m_window, wxBRUSH_COLOUR ); - m_textGC = wxGetPoolGC( m_window, wxTEXT_COLOUR ); - m_bgGC = wxGetPoolGC( m_window, wxBG_COLOUR ); + if (m_isScreenDC) + { + m_penGC = wxGetPoolGC( m_gdkwindow, wxPEN_SCREEN ); + m_brushGC = wxGetPoolGC( m_gdkwindow, wxBRUSH_SCREEN ); + 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 ); + m_brushGC = wxGetPoolGC( m_gdkwindow, wxBRUSH_COLOUR ); + m_textGC = wxGetPoolGC( m_gdkwindow, wxTEXT_COLOUR ); + m_bgGC = wxGetPoolGC( m_gdkwindow, wxBG_COLOUR ); + } } /* background colour */ m_backgroundBrush = *wxWHITE_BRUSH; m_backgroundBrush.GetColour().CalcPixel( m_cmap ); -#ifdef __WXGTK24__ const GdkColor *bg_col = m_backgroundBrush.GetColour().GetColor(); -#else - GdkColor *bg_col = m_backgroundBrush.GetColour().GetColor(); -#endif /* m_textGC */ m_textForegroundColour.CalcPixel( m_cmap ); @@ -424,91 +440,145 @@ void wxGTKWindowImplDC::SetUpDC() 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 ); - - if (!hatch_bitmap) - { - hatch_bitmap = hatches; - hatch_bitmap[0] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, bdiag_bits, bdiag_width, bdiag_height ); - hatch_bitmap[1] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cdiag_bits, cdiag_width, cdiag_height ); - hatch_bitmap[2] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, fdiag_bits, fdiag_width, fdiag_height ); - hatch_bitmap[3] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, cross_bits, cross_width, cross_height ); - hatch_bitmap[4] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, horiz_bits, horiz_width, horiz_height ); - hatch_bitmap[5] = gdk_bitmap_create_from_data( (GdkWindow *) NULL, verti_bits, verti_width, verti_height ); - } + 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 wxGTKWindowImplDC::DoGetSize( int* width, int* height ) const +void wxWindowDCImpl::DoGetSize( int* width, int* height ) const { - wxCHECK_RET( m_owner, _T("GetSize() doesn't work without window") ); + wxCHECK_RET( m_window, wxT("GetSize() doesn't work without window") ); - m_owner->GetSize(width, height); + m_window->GetSize(width, height); } -extern bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y, - const wxColour & col, int style); - -bool wxGTKWindowImplDC::DoFloodFill(wxCoord x, wxCoord y, - const wxColour& col, int style) +bool wxWindowDCImpl::DoFloodFill(wxCoord x, wxCoord y, + const wxColour& col, wxFloodFillStyle style) { - return wxDoFloodFill(this, x, y, col, style); +#if wxUSE_IMAGE + extern bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y, + const wxColour & col, wxFloodFillStyle style); + + return wxDoFloodFill( GetOwner(), x, y, col, style); +#else + wxUnusedVar(x); + wxUnusedVar(y); + wxUnusedVar(col); + wxUnusedVar(style); + + return false; +#endif } -bool wxGTKWindowImplDC::DoGetPixel( wxCoord x1, wxCoord y1, wxColour *col ) const +bool wxWindowDCImpl::DoGetPixel( wxCoord x1, wxCoord y1, wxColour *col ) const { - // Generic (and therefore rather inefficient) method. - // Could be improved. - wxMemoryDC memdc; - wxBitmap bitmap(1, 1); - memdc.SelectObject(bitmap); - memdc.Blit(0, 0, 1, 1, (wxDC*) this, 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; } -void wxGTKWindowImplDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 ) +void wxWindowDCImpl::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); - if (m_pen.GetStyle() != wxTRANSPARENT) + if ( m_pen.IsNonTransparent() ) { - if (m_window) - gdk_draw_line( m_window, m_penGC, XLOG2DEV(x1), YLOG2DEV(y1), XLOG2DEV(x2), YLOG2DEV(y2) ); + if (m_gdkwindow) + gdk_draw_line( m_gdkwindow, m_penGC, XLOG2DEV(x1), YLOG2DEV(y1), XLOG2DEV(x2), YLOG2DEV(y2) ); CalcBoundingBox(x1, y1); CalcBoundingBox(x2, y2); } } -void wxGTKWindowImplDC::DoCrossHair( wxCoord x, wxCoord y ) +void wxWindowDCImpl::DoCrossHair( wxCoord x, wxCoord y ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); - if (m_pen.GetStyle() != wxTRANSPARENT) + if ( m_pen.IsNonTransparent() ) { int w = 0; int h = 0; - GetSize( &w, &h ); + GetOwner()->GetSize( &w, &h ); wxCoord xx = XLOG2DEV(x); wxCoord yy = YLOG2DEV(y); - if (m_window) + if (m_gdkwindow) { - gdk_draw_line( m_window, m_penGC, 0, yy, XLOG2DEVREL(w), yy ); - gdk_draw_line( m_window, m_penGC, xx, 0, xx, YLOG2DEVREL(h) ); + gdk_draw_line( m_gdkwindow, m_penGC, 0, yy, XLOG2DEVREL(w), yy ); + gdk_draw_line( m_gdkwindow, m_penGC, xx, 0, xx, YLOG2DEVREL(h) ); } } } -void wxGTKWindowImplDC::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, +void wxWindowDCImpl::DrawingSetup(GdkGC*& gc, bool& originChanged) +{ + gc = m_brushGC; + GdkPixmap* pixmap = NULL; + const int style = m_brush.GetStyle(); + + if (style == wxBRUSHSTYLE_STIPPLE || style == wxBRUSHSTYLE_STIPPLE_MASK_OPAQUE) + { + const wxBitmap* stipple = m_brush.GetStipple(); + if (stipple->IsOk()) + { + if (style == wxBRUSHSTYLE_STIPPLE) + pixmap = stipple->GetPixmap(); + else if (stipple->GetMask()) + { + pixmap = stipple->GetPixmap(); + gc = m_textGC; + } + } + } + else if (m_brush.IsHatch()) + { + pixmap = GetHatch(style); + } + + int origin_x = 0; + int origin_y = 0; + if (pixmap) + { + int w, h; + gdk_drawable_get_size(pixmap, &w, &h); + origin_x = m_deviceOriginX % w; + origin_y = m_deviceOriginY % h; + } + + originChanged = origin_x || origin_y; + if (originChanged) + gdk_gc_set_ts_origin(gc, origin_x, origin_y); +} + +void wxWindowDCImpl::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord xc, wxCoord yc ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); wxCoord xx1 = XLOG2DEV(x1); wxCoord yy1 = YLOG2DEV(y1); @@ -546,52 +616,28 @@ void wxGTKWindowImplDC::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y while (alpha2 <= 0) alpha2 += 360*64; while (alpha1 > 360*64) alpha1 -= 360*64; - if (m_window) + if (m_gdkwindow) { - if (m_brush.GetStyle() != wxTRANSPARENT) + if ( m_brush.IsNonTransparent() ) { - if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask())) - { - gdk_gc_set_ts_origin( m_textGC, - m_deviceOriginX % m_brush.GetStipple()->GetWidth(), - m_deviceOriginY % m_brush.GetStipple()->GetHeight() ); - gdk_draw_arc( m_window, m_textGC, TRUE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 ); - gdk_gc_set_ts_origin( m_textGC, 0, 0 ); - } else - if (IS_15_PIX_HATCH(m_brush.GetStyle())) - { - gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 ); - gdk_draw_arc( m_window, m_brushGC, TRUE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 ); - gdk_gc_set_ts_origin( m_brushGC, 0, 0 ); - } else - if (IS_16_PIX_HATCH(m_brush.GetStyle())) - { - gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 ); - gdk_draw_arc( m_window, m_brushGC, TRUE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 ); - gdk_gc_set_ts_origin( m_brushGC, 0, 0 ); - } else - if (m_brush.GetStyle() == wxSTIPPLE) - { - gdk_gc_set_ts_origin( m_brushGC, - m_deviceOriginX % m_brush.GetStipple()->GetWidth(), - m_deviceOriginY % m_brush.GetStipple()->GetHeight() ); - gdk_draw_arc( m_window, m_brushGC, TRUE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 ); - gdk_gc_set_ts_origin( m_brushGC, 0, 0 ); - } - else - { - gdk_draw_arc( m_window, m_brushGC, TRUE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 ); - } + GdkGC* gc; + bool originChanged; + DrawingSetup(gc, originChanged); + + gdk_draw_arc(m_gdkwindow, gc, true, xxc-r, yyc-r, 2*r, 2*r, alpha1, alpha2); + + if (originChanged) + gdk_gc_set_ts_origin(gc, 0, 0); } - if (m_pen.GetStyle() != wxTRANSPARENT) + if ( m_pen.IsNonTransparent() ) { - gdk_draw_arc( m_window, m_penGC, FALSE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 ); + 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_window, m_penGC, xx1, yy1, xxc, yyc ); - gdk_draw_line( m_window, m_penGC, xxc, yyc, xx2, yy2 ); + gdk_draw_line( m_gdkwindow, m_penGC, xx1, yy1, xxc, yyc ); + gdk_draw_line( m_gdkwindow, m_penGC, xxc, yyc, xx2, yy2 ); } } } @@ -600,9 +646,9 @@ void wxGTKWindowImplDC::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y CalcBoundingBox (x2, y2); } -void wxGTKWindowImplDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double sa, double ea ) +void wxWindowDCImpl::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double sa, double ea ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); wxCoord xx = XLOG2DEV(x); wxCoord yy = YLOG2DEV(y); @@ -613,102 +659,85 @@ void wxGTKWindowImplDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord width, if (ww < 0) { ww = -ww; xx = xx - ww; } if (hh < 0) { hh = -hh; yy = yy - hh; } - if (m_window) + if (m_gdkwindow) { wxCoord start = wxCoord(sa * 64.0); wxCoord end = wxCoord((ea-sa) * 64.0); - if (m_brush.GetStyle() != wxTRANSPARENT) + if ( m_brush.IsNonTransparent() ) { - if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask())) - { - gdk_gc_set_ts_origin( m_textGC, - m_deviceOriginX % m_brush.GetStipple()->GetWidth(), - m_deviceOriginY % m_brush.GetStipple()->GetHeight() ); - gdk_draw_arc( m_window, m_textGC, TRUE, xx, yy, ww, hh, start, end ); - gdk_gc_set_ts_origin( m_textGC, 0, 0 ); - } else - if (IS_15_PIX_HATCH(m_brush.GetStyle())) - { - gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 ); - gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end ); - gdk_gc_set_ts_origin( m_brushGC, 0, 0 ); - } else - if (IS_16_PIX_HATCH(m_brush.GetStyle())) - { - gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 ); - gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end ); - gdk_gc_set_ts_origin( m_brushGC, 0, 0 ); - } else - if (m_brush.GetStyle() == wxSTIPPLE) - { - gdk_gc_set_ts_origin( m_brushGC, - m_deviceOriginX % m_brush.GetStipple()->GetWidth(), - m_deviceOriginY % m_brush.GetStipple()->GetHeight() ); - gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end ); - gdk_gc_set_ts_origin( m_brushGC, 0, 0 ); - } - else - { - gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end ); - } + GdkGC* gc; + bool originChanged; + DrawingSetup(gc, originChanged); + + gdk_draw_arc(m_gdkwindow, gc, true, xx, yy, ww, hh, start, end); + + if (originChanged) + gdk_gc_set_ts_origin(gc, 0, 0); } - if (m_pen.GetStyle() != wxTRANSPARENT) - gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, start, end ); + if ( m_pen.IsNonTransparent() ) + gdk_draw_arc( m_gdkwindow, m_penGC, FALSE, xx, yy, ww, hh, start, end ); } CalcBoundingBox (x, y); CalcBoundingBox (x + width, y + height); } -void wxGTKWindowImplDC::DoDrawPoint( wxCoord x, wxCoord y ) +void wxWindowDCImpl::DoDrawPoint( wxCoord x, wxCoord y ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); - if ((m_pen.GetStyle() != wxTRANSPARENT) && m_window) - gdk_draw_point( m_window, m_penGC, XLOG2DEV(x), YLOG2DEV(y) ); + if ( m_pen.IsNonTransparent() && m_gdkwindow ) + gdk_draw_point( m_gdkwindow, m_penGC, XLOG2DEV(x), YLOG2DEV(y) ); CalcBoundingBox (x, y); } -void wxGTKWindowImplDC::DoDrawLines( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset ) +void wxWindowDCImpl::DoDrawLines( int n, const wxPoint points[], wxCoord xoffset, wxCoord yoffset ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + 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(points); + const GdkPoint* gpts = reinterpret_cast(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_window) - gdk_draw_lines( m_window, m_penGC, gpts, n); + if (m_gdkwindow) + gdk_draw_lines( m_gdkwindow, m_penGC, (GdkPoint*) gpts, n); - if (doScale) - delete[] gpts; + delete[] gpts_alloc; } -void wxGTKWindowImplDC::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( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); if (n <= 0) return; @@ -717,84 +746,63 @@ void wxGTKWindowImplDC::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, 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(points); + const GdkPoint* gdkpoints = reinterpret_cast(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_window) + if (m_gdkwindow) { - if (m_brush.GetStyle() != wxTRANSPARENT) + if ( m_brush.IsNonTransparent() ) { - if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask())) - { - gdk_gc_set_ts_origin( m_textGC, - m_deviceOriginX % m_brush.GetStipple()->GetWidth(), - m_deviceOriginY % m_brush.GetStipple()->GetHeight() ); - gdk_draw_polygon( m_window, m_textGC, TRUE, gdkpoints, n ); - gdk_gc_set_ts_origin( m_textGC, 0, 0 ); - } else - if (IS_15_PIX_HATCH(m_brush.GetStyle())) - { - gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 ); - gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n ); - gdk_gc_set_ts_origin( m_brushGC, 0, 0 ); - } else - if (IS_16_PIX_HATCH(m_brush.GetStyle())) - { - gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 ); - gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n ); - gdk_gc_set_ts_origin( m_brushGC, 0, 0 ); - } else - if (m_brush.GetStyle() == wxSTIPPLE) - { - gdk_gc_set_ts_origin( m_brushGC, - m_deviceOriginX % m_brush.GetStipple()->GetWidth(), - m_deviceOriginY % m_brush.GetStipple()->GetHeight() ); - gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n ); - gdk_gc_set_ts_origin( m_brushGC, 0, 0 ); - } - else - { - gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n ); - } + GdkGC* gc; + bool originChanged; + DrawingSetup(gc, originChanged); + + 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++) { - gdk_draw_line( m_window, m_penGC, + gdk_draw_line( m_gdkwindow, m_penGC, gdkpoints[i%n].x, gdkpoints[i%n].y, gdkpoints[(i+1)%n].x, gdkpoints[(i+1)%n].y); } */ - gdk_draw_polygon( m_window, m_penGC, FALSE, gdkpoints, n ); + gdk_draw_polygon( m_gdkwindow, m_penGC, FALSE, (GdkPoint*) gdkpoints, n ); } } - if (doScale) - delete[] gdkpoints; + delete[] gdkpoints_alloc; } -void wxGTKWindowImplDC::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) +void wxWindowDCImpl::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); wxCoord xx = XLOG2DEV(x); wxCoord yy = YLOG2DEV(y); @@ -808,49 +816,24 @@ void wxGTKWindowImplDC::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wx if (ww < 0) { ww = -ww; xx = xx - ww; } if (hh < 0) { hh = -hh; yy = yy - hh; } - if (m_window) + if (m_gdkwindow) { - if (m_brush.GetStyle() != wxTRANSPARENT) + if ( m_brush.IsNonTransparent() ) { - if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask())) - { - gdk_gc_set_ts_origin( m_textGC, - m_deviceOriginX % m_brush.GetStipple()->GetWidth(), - m_deviceOriginY % m_brush.GetStipple()->GetHeight() ); - gdk_draw_rectangle( m_window, m_textGC, TRUE, xx, yy, ww, hh ); - gdk_gc_set_ts_origin( m_textGC, 0, 0 ); - } else - if (IS_15_PIX_HATCH(m_brush.GetStyle())) - { - gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 ); - gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh ); - gdk_gc_set_ts_origin( m_brushGC, 0, 0 ); - } else - if (IS_16_PIX_HATCH(m_brush.GetStyle())) - { - gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 ); - gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh ); - gdk_gc_set_ts_origin( m_brushGC, 0, 0 ); - } else - if (m_brush.GetStyle() == wxSTIPPLE) - { - gdk_gc_set_ts_origin( m_brushGC, - m_deviceOriginX % m_brush.GetStipple()->GetWidth(), - m_deviceOriginY % m_brush.GetStipple()->GetHeight() ); - gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh ); - gdk_gc_set_ts_origin( m_brushGC, 0, 0 ); - } - else - { - gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh ); - } + GdkGC* gc; + bool originChanged; + DrawingSetup(gc, originChanged); + + gdk_draw_rectangle(m_gdkwindow, gc, true, xx, yy, ww, hh); + + if (originChanged) + 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 ); @@ -858,23 +841,22 @@ void wxGTKWindowImplDC::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wx 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 ); + gdk_draw_rectangle( m_gdkwindow, m_penGC, FALSE, xx+1, yy, ww-2, hh-2 ); + gdk_draw_rectangle( m_gdkwindow, 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 ); + gdk_draw_rectangle( m_gdkwindow, m_penGC, FALSE, xx, yy, ww-2, hh-2 ); + gdk_draw_rectangle( m_gdkwindow, 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 ); + gdk_draw_rectangle( m_gdkwindow, m_penGC, FALSE, xx, yy, ww-1, hh-1 ); } } } @@ -883,9 +865,9 @@ void wxGTKWindowImplDC::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wx CalcBoundingBox( x + width, y + height ); } -void wxGTKWindowImplDC::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius ) +void wxWindowDCImpl::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); if (radius < 0.0) radius = - radius * ((width < height) ? width : height); @@ -903,7 +885,7 @@ void wxGTKWindowImplDC::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord wi // X drawing errors with small radii if (rr == 0) { - DrawRectangle( x, y, width, height ); + DoDrawRectangle( x, y, width, height ); return; } @@ -912,13 +894,13 @@ void wxGTKWindowImplDC::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord wi // 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--; } - if (m_window) + if (m_gdkwindow) { // CMB: ensure dd is not larger than rectangle otherwise we // get an hour glass shape @@ -927,77 +909,33 @@ void wxGTKWindowImplDC::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord wi if (dd > hh) dd = hh; rr = dd / 2; - if (m_brush.GetStyle() != wxTRANSPARENT) + if ( m_brush.IsNonTransparent() ) { - if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask())) - { - gdk_gc_set_ts_origin( m_textGC, - m_deviceOriginX % m_brush.GetStipple()->GetWidth(), - m_deviceOriginY % m_brush.GetStipple()->GetHeight() ); - gdk_draw_rectangle( m_window, m_textGC, TRUE, xx+rr, yy, ww-dd+1, hh ); - gdk_draw_rectangle( m_window, m_textGC, TRUE, xx, yy+rr, ww, hh-dd+1 ); - gdk_draw_arc( m_window, m_textGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 ); - gdk_draw_arc( m_window, m_textGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 ); - gdk_draw_arc( m_window, m_textGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 ); - gdk_draw_arc( m_window, m_textGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 ); - gdk_gc_set_ts_origin( m_textGC, 0, 0 ); - } else - if (IS_15_PIX_HATCH(m_brush.GetStyle())) - { - gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 ); - gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh ); - gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 ); - gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 ); - gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 ); - gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 ); - gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 ); - gdk_gc_set_ts_origin( m_brushGC, 0, 0 ); - } else - if (IS_16_PIX_HATCH(m_brush.GetStyle())) - { - gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 ); - gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh ); - gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 ); - gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 ); - gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 ); - gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 ); - gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 ); - gdk_gc_set_ts_origin( m_brushGC, 0, 0 ); - } else - if (m_brush.GetStyle() == wxSTIPPLE) - { - gdk_gc_set_ts_origin( m_brushGC, - m_deviceOriginX % m_brush.GetStipple()->GetWidth(), - m_deviceOriginY % m_brush.GetStipple()->GetHeight() ); - gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh ); - gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 ); - gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 ); - gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 ); - gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 ); - gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 ); - gdk_gc_set_ts_origin( m_brushGC, 0, 0 ); - } - else - { - gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx+rr, yy, ww-dd+1, hh ); - gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy+rr, ww, hh-dd+1 ); - gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, dd, dd, 90*64, 90*64 ); - gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy, dd, dd, 0, 90*64 ); - gdk_draw_arc( m_window, m_brushGC, TRUE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 ); - gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 ); - } + GdkGC* gc; + bool originChanged; + DrawingSetup(gc, originChanged); + + gdk_draw_rectangle(m_gdkwindow, gc, true, xx+rr, yy, ww-dd+1, hh); + gdk_draw_rectangle(m_gdkwindow, gc, true, xx, yy+rr, ww, hh-dd+1); + gdk_draw_arc(m_gdkwindow, gc, true, xx, yy, dd, dd, 90*64, 90*64); + gdk_draw_arc(m_gdkwindow, gc, true, xx+ww-dd, yy, dd, dd, 0, 90*64); + gdk_draw_arc(m_gdkwindow, gc, true, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64); + gdk_draw_arc(m_gdkwindow, gc, true, xx, yy+hh-dd, dd, dd, 180*64, 90*64); + + if (originChanged) + gdk_gc_set_ts_origin(gc, 0, 0); } - if (m_pen.GetStyle() != wxTRANSPARENT) + if ( m_pen.IsNonTransparent() ) { - gdk_draw_line( m_window, m_penGC, xx+rr+1, yy, xx+ww-rr, yy ); - gdk_draw_line( m_window, m_penGC, xx+rr+1, yy+hh, xx+ww-rr, yy+hh ); - gdk_draw_line( m_window, m_penGC, xx, yy+rr+1, xx, yy+hh-rr ); - gdk_draw_line( m_window, m_penGC, xx+ww, yy+rr+1, xx+ww, yy+hh-rr ); - gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, dd, dd, 90*64, 90*64 ); - gdk_draw_arc( m_window, m_penGC, FALSE, xx+ww-dd, yy, dd, dd, 0, 90*64 ); - gdk_draw_arc( m_window, m_penGC, FALSE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 ); - gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 ); + 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 ); + gdk_draw_line( m_gdkwindow, m_penGC, xx, yy+rr+1, xx, yy+hh-rr ); + gdk_draw_line( m_gdkwindow, m_penGC, xx+ww, yy+rr+1, xx+ww, yy+hh-rr ); + gdk_draw_arc( m_gdkwindow, m_penGC, FALSE, xx, yy, dd, dd, 90*64, 90*64 ); + gdk_draw_arc( m_gdkwindow, m_penGC, FALSE, xx+ww-dd, yy, dd, dd, 0, 90*64 ); + gdk_draw_arc( m_gdkwindow, m_penGC, FALSE, xx+ww-dd, yy+hh-dd, dd, dd, 270*64, 90*64 ); + gdk_draw_arc( m_gdkwindow, m_penGC, FALSE, xx, yy+hh-dd, dd, dd, 180*64, 90*64 ); } } @@ -1006,9 +944,9 @@ void wxGTKWindowImplDC::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord wi CalcBoundingBox( x + width, y + height ); } -void wxGTKWindowImplDC::DoDrawEllipse( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) +void wxWindowDCImpl::DoDrawEllipse( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); wxCoord xx = XLOG2DEV(x); wxCoord yy = YLOG2DEV(y); @@ -1019,815 +957,544 @@ void wxGTKWindowImplDC::DoDrawEllipse( wxCoord x, wxCoord y, wxCoord width, wxCo if (ww < 0) { ww = -ww; xx = xx - ww; } if (hh < 0) { hh = -hh; yy = yy - hh; } - if (m_window) + if (m_gdkwindow) { - if (m_brush.GetStyle() != wxTRANSPARENT) + if ( m_brush.IsNonTransparent() ) { - if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask())) - { - gdk_gc_set_ts_origin( m_textGC, - m_deviceOriginX % m_brush.GetStipple()->GetWidth(), - m_deviceOriginY % m_brush.GetStipple()->GetHeight() ); - gdk_draw_arc( m_window, m_textGC, TRUE, xx, yy, ww, hh, 0, 360*64 ); - gdk_gc_set_ts_origin( m_textGC, 0, 0 ); - } else - if (IS_15_PIX_HATCH(m_brush.GetStyle())) - { - gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 15, m_deviceOriginY % 15 ); - gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 ); - gdk_gc_set_ts_origin( m_brushGC, 0, 0 ); - } else - if (IS_16_PIX_HATCH(m_brush.GetStyle())) - { - gdk_gc_set_ts_origin( m_brushGC, m_deviceOriginX % 16, m_deviceOriginY % 16 ); - gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 ); - gdk_gc_set_ts_origin( m_brushGC, 0, 0 ); - } else - if (m_brush.GetStyle() == wxSTIPPLE) - { - gdk_gc_set_ts_origin( m_brushGC, - m_deviceOriginX % m_brush.GetStipple()->GetWidth(), - m_deviceOriginY % m_brush.GetStipple()->GetHeight() ); - gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 ); - gdk_gc_set_ts_origin( m_brushGC, 0, 0 ); - } - else + 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()) { - gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 ); + ++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_window, 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 ); CalcBoundingBox( x + width, y + height ); } -void wxGTKWindowImplDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y ) +void wxWindowDCImpl::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 wxGTKWindowImplDC::DoDrawBitmap( const wxBitmap &bitmap, - wxCoord x, wxCoord y, - bool useMask ) +// scale a pixbuf +static GdkPixbuf* +Scale(GdkPixbuf* pixbuf, int dst_w, int dst_h, double sx, double sy) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + 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; +} - wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") ); +// 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; +} - bool is_mono = bitmap.GetDepth() == 1; +// 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; +} - // scale/translate size and position - int xx = XLOG2DEV(x); - int yy = YLOG2DEV(y); +// 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; +} - int w = bitmap.GetWidth(); - int h = bitmap.GetHeight(); +// 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; +} - if (m_owner && m_owner->GetLayoutDirection() == wxLayout_RightToLeft) - xx -= w; +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") ); - CalcBoundingBox( x, y ); - CalcBoundingBox( x + w, y + h ); + if (!m_gdkwindow) return; - if (!m_window) return; + const int w = bitmap.GetWidth(); + const int h = bitmap.GetHeight(); - int ww = XLOG2DEVREL(w); - int hh = YLOG2DEVREL(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); - // compare to current clipping region - if (!m_currentClippingRegion.IsNull()) + // device coords + int xx = LogicalToDeviceX(x); + const int yy = LogicalToDeviceY(y); + const int ww = LogicalToDeviceXRel(w); + const int hh = LogicalToDeviceYRel(h); + + if (m_window && m_window->GetLayoutDirection() == wxLayout_RightToLeft) + xx -= ww; + + 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 ); - -#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 + const bool isScaled = ww != w || hh != h; + const bool hasAlpha = bitmap.HasAlpha(); + GdkGC* const use_gc = m_penGC; - // 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; - - 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) { - 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, 0, 0, -1, -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(); - gdk_draw_drawable(m_window, use_gc, bitmap2, 0, 0, xx, yy, -1, -1); + if (isScaled) + { + 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); - g_object_unref (bitmap2); - g_object_unref (gc); + pixbuf_new = pixbuf; + } + + if (pixbuf) + { + gdk_draw_pixbuf(m_gdkwindow, use_gc, pixbuf, + 0, 0, xx, yy, ww, hh, GDK_RGB_DITHER_NORMAL, 0, 0); } else { -#if GTK_CHECK_VERSION(2,2,0) - if (!gtk_check_version(2,2,0) && use_bitmap.HasPixbuf()) - { - gdk_draw_pixbuf(m_window, use_gc, - use_bitmap.GetPixbuf(), - 0, 0, xx, yy, -1, -1, - GDK_RGB_DITHER_NORMAL, xx, yy); - } - else -#endif - { - gdk_draw_drawable(m_window, 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); } } -bool wxGTKWindowImplDC::DoBlit( wxCoord xdest, wxCoord ydest, +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( Ok(), false, wxT("invalid window dc") ); - + wxCHECK_MSG( IsOk(), false, wxT("invalid window dc") ); wxCHECK_MSG( source, false, wxT("invalid source dc") ); - if (!m_window) return false; + 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.Ok()) - { - 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, 0, 0, -1, -1 ); - - gdk_draw_drawable(m_window, 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_window, m_penGC, use_bitmap.GetPixmap(), xsrc, ysrc, xx, yy, ww, hh ); - gdk_draw_drawable(m_window, 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.Ok() && ((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_window, m_penGC, bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 ); - gdk_draw_drawable( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, cx, cy, -1, -1 ); - } - else - { - // 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, - 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 wxGTKWindowImplDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) +void wxWindowDCImpl::DoDrawText(const wxString& text, + wxCoord xLogical, + wxCoord yLogical) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); - - if (!m_window) return; - - if (text.empty()) return; - - x = XLOG2DEV(x); - y = YLOG2DEV(y); - - 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.Ok() && m_font.GetUnderlined(); + DoDrawRotatedText(text, xLogical, yLogical, 0); +} - const wxCharBuffer data = wxGTK_CONV( text ); - if ( !data ) +void wxWindowDCImpl::DoDrawRotatedText(const wxString& text, int xLogical, int yLogical, double angle) +{ + if (!m_gdkwindow || text.empty()) 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; - 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); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); - // copy the trailing U+200C ZERO WIDTH NON-JOINER encoded in UTF8 format - strcpy(&hackstring[datalen+3], "\342\200\214"); + pango_layout_set_text(m_layout, wxGTK_CONV(text), -1); + const bool setAttrs = m_font.GTKSetPangoAttrs(m_layout); - // the special characters that we added require 6 additional bytes: - datalen += 6; + const GdkColor* bg_col = NULL; + if (m_backgroundMode == wxBRUSHSTYLE_SOLID) + bg_col = m_textBackgroundColour.GetColor(); - pango_layout_set_text(m_layout, hackstring, datalen); - } - else + PangoMatrix matrix = PANGO_MATRIX_INIT; + if (!wxIsSameDouble(m_scaleX, 1) || !wxIsSameDouble(m_scaleY, 1) || !wxIsNullDouble(angle)) { - pango_layout_set_text(m_layout, data, datalen); + pango_matrix_scale(&matrix, m_scaleX, m_scaleY); + pango_matrix_rotate(&matrix, angle); + pango_context_set_matrix(m_context, &matrix); + pango_layout_context_changed(m_layout); } - 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); + int w, h; + pango_layout_get_pixel_size(m_layout, &w, &h); - 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); - } + int x = LogicalToDeviceX(xLogical); + int y = LogicalToDeviceY(yLogical); + if (m_window && m_window->GetLayoutDirection() == wxLayout_RightToLeft) + x -= LogicalToDeviceXRel(w); - int w,h; - - if (fabs(m_scaleY - 1.0) > 0.00001) + if (wxIsNullDouble(angle)) { - // If there is a user or actually any scale applied to - // the device context, scale the font. - - // scale font description - gint oldSize = pango_font_description_get_size( m_fontdesc ); - double size = oldSize; - size = size * m_scaleY; - pango_font_description_set_size( m_fontdesc, (gint)size ); - - // actually apply scaled font - pango_layout_set_font_description( m_layout, m_fontdesc ); - - 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_window, m_textGC, TRUE, x, y, w, h); - gdk_gc_set_foreground(m_textGC, m_textForegroundColour.GetColor()); - } - - // Draw 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 ); - - // actually apply unscaled font - pango_layout_set_font_description( m_layout, m_fontdesc ); + CalcBoundingBox(xLogical, yLogical); + CalcBoundingBox(xLogical + w, yLogical + h); } else { - 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_window, m_textGC, TRUE, x, y, w, h); - gdk_gc_set_foreground(m_textGC, m_textForegroundColour.GetColor()); - } - - // Draw 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) - { - // undo underline attributes setting: + // 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. + // the rectangle vertices are counted clockwise with the first one + // being at (0, 0) + double x2 = w * matrix.xx; + double y2 = w * matrix.yx; + double x4 = h * matrix.xy; + double y4 = h * matrix.yy; + 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); + x += minX; + y += minY; + CalcBoundingBox(DeviceToLogicalX(x), DeviceToLogicalY(y)); + CalcBoundingBox(DeviceToLogicalX(x + maxX - minX), DeviceToLogicalY(y + maxY - minY)); + } + + gdk_draw_layout_with_colors(m_gdkwindow, m_textGC, x, y, m_layout, NULL, bg_col); + + pango_context_set_matrix(m_context, NULL); + if (setAttrs) pango_layout_set_attributes(m_layout, NULL); - } - - wxCoord width = w; - wxCoord height = h; - - width = wxCoord(width / m_scaleX); - height = wxCoord(height / m_scaleY); - CalcBoundingBox (x + width, y + height); - CalcBoundingBox (x, y); - - if (hackstring) - free(hackstring); } - -// 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 - -void wxGTKWindowImplDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, double angle ) -{ - if (!m_window || text.empty()) - return; - - wxCHECK_RET( Ok(), wxT("invalid window dc") ); - - if ( wxIsNullDouble(angle) ) - { - DrawText(text, x, y); - return; - } - - wxCoord w; - wxCoord h; - - // TODO: implement later without GdkFont for GTK 2.0 - GetTextExtent(text, &w, &h, NULL,NULL, &m_font); - - // 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); - - // Calculate the size of the rotated bounding box. - 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_window, 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); -} - -void wxGTKWindowImplDC::DoGetTextExtent(const wxString &string, +void wxWindowDCImpl::DoGetTextExtent(const wxString &string, wxCoord *width, wxCoord *height, 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 - if ( !theFont || !theFont->Ok() ) - theFont = wx_const_cast(wxFont *, &m_font); - - // and use it if it's valid - if ( theFont->Ok() ) - { - 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; - } + // ensure we work with a valid font + const wxFont *fontToUse; + if ( !theFont || !theFont->IsOk() ) + 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 wxGTKWindowImplDC::DoGetPartialTextExtents(const wxString& text, +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); } -wxCoord wxGTKWindowImplDC::GetCharWidth() const +wxCoord wxWindowDCImpl::GetCharWidth() const { pango_layout_set_text( m_layout, "H", 1 ); int w; @@ -1835,60 +1502,33 @@ wxCoord wxGTKWindowImplDC::GetCharWidth() const return w; } -wxCoord wxGTKWindowImplDC::GetCharHeight() 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; } -void wxGTKWindowImplDC::Clear() +void wxWindowDCImpl::Clear() { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); - - if (!m_window) return; + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); - // VZ: the code below results in infinite recursion and crashes when - // dc.Clear() is done from OnPaint() so I disable it for now. - // I don't know what the correct fix is but Clear() surely should not - // reenter OnPaint()! -#if 0 - /* - we either are a memory dc or have a window as the - owner. anything else shouldn't happen. - - we don't use gdk_window_clear() as we don't set - the window's background colour anymore. it is too - much pain to keep the DC's and the window's back- - ground colour in synch. */ + if (!m_gdkwindow) return; - if (m_owner) - { - m_owner->Clear(); - return; - } - - if (m_isMemDC) - { - int width,height; - GetSize( &width, &height ); - gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height ); - return; - } -#else // 1 int width,height; - GetSize( &width, &height ); - gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height ); -#endif // 0/1 + DoGetSize( &width, &height ); + gdk_draw_rectangle( m_gdkwindow, m_bgGC, TRUE, 0, 0, width, height ); } -void wxGTKWindowImplDC::SetFont( const wxFont &font ) +void wxWindowDCImpl::SetFont( const wxFont &font ) { m_font = font; - if (m_font.Ok()) + if (m_font.IsOk()) { if (m_fontdesc) pango_font_description_free( m_fontdesc ); @@ -1896,11 +1536,11 @@ void wxGTKWindowImplDC::SetFont( const wxFont &font ) m_fontdesc = pango_font_description_copy( m_font.GetNativeFontInfo()->description ); - if (m_owner) + if (m_window) { PangoContext *oldContext = m_context; - m_context = m_owner->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, @@ -1918,17 +1558,17 @@ void wxGTKWindowImplDC::SetFont( const wxFont &font ) } } -void wxGTKWindowImplDC::SetPen( const wxPen &pen ) +void wxWindowDCImpl::SetPen( const wxPen &pen ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); if (m_pen == pen) return; m_pen = pen; - if (!m_pen.Ok()) return; + if (!m_pen.IsOk()) return; - if (!m_window) return; + if (!m_gdkwindow) return; gint width = m_pen.GetWidth(); if (width <= 0) @@ -1962,57 +1602,39 @@ void wxGTKWindowImplDC::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) @@ -2039,18 +1661,12 @@ void wxGTKWindowImplDC::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; @@ -2068,24 +1684,24 @@ void wxGTKWindowImplDC::SetPen( const wxPen &pen ) gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() ); } -void wxGTKWindowImplDC::SetBrush( const wxBrush &brush ) +void wxWindowDCImpl::SetBrush( const wxBrush &brush ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); if (m_brush == brush) return; m_brush = brush; - if (!m_brush.Ok()) return; + if (!m_brush.IsOk()) return; - if (!m_window) return; + if (!m_gdkwindow) return; m_brush.GetColour().CalcPixel( m_cmap ); gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() ); gdk_gc_set_fill( m_brushGC, GDK_SOLID ); - if ((m_brush.GetStyle() == wxSTIPPLE) && (m_brush.GetStipple()->Ok())) + if ((m_brush.GetStyle() == wxBRUSHSTYLE_STIPPLE) && (m_brush.GetStipple()->IsOk())) { if (m_brush.GetStipple()->GetDepth() != 1) { @@ -2099,74 +1715,78 @@ void wxGTKWindowImplDC::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()) { gdk_gc_set_fill( m_brushGC, GDK_STIPPLED ); - int num = m_brush.GetStyle() - wxBDIAGONAL_HATCH; - gdk_gc_set_stipple( m_brushGC, hatches[num] ); + gdk_gc_set_stipple(m_brushGC, GetHatch(m_brush.GetStyle())); } } -void wxGTKWindowImplDC::SetBackground( const wxBrush &brush ) +void wxWindowDCImpl::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 */ - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); if (m_backgroundBrush == brush) return; m_backgroundBrush = brush; - if (!m_backgroundBrush.Ok()) return; + if (!m_backgroundBrush.IsOk()) return; - if (!m_window) return; + if (!m_gdkwindow) return; + + 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); - 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() ); gdk_gc_set_fill( m_bgGC, GDK_SOLID ); - if ((m_backgroundBrush.GetStyle() == wxSTIPPLE) && (m_backgroundBrush.GetStipple()->Ok())) + if (m_backgroundBrush.GetStyle() == wxBRUSHSTYLE_STIPPLE) { - if (m_backgroundBrush.GetStipple()->GetDepth() != 1) + const wxBitmap* stipple = m_backgroundBrush.GetStipple(); + if (stipple->IsOk()) { - gdk_gc_set_fill( m_bgGC, GDK_TILED ); - gdk_gc_set_tile( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() ); - } - else - { - 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 ); - int num = m_backgroundBrush.GetStyle() - wxBDIAGONAL_HATCH; - gdk_gc_set_stipple( m_bgGC, hatches[num] ); + gdk_gc_set_stipple(m_bgGC, GetHatch(m_backgroundBrush.GetStyle())); } } -void wxGTKWindowImplDC::SetLogicalFunction( int function ) +void wxWindowDCImpl::SetLogicalFunction( wxRasterOperationMode function ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); if (m_logicalFunction == function) return; // VZ: shouldn't this be a CHECK? - if (!m_window) + if (!m_gdkwindow) return; GdkFunction mode; @@ -2187,12 +1807,10 @@ void wxGTKWindowImplDC::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; @@ -2206,70 +1824,59 @@ void wxGTKWindowImplDC::SetLogicalFunction( int function ) gdk_gc_set_function( m_textGC, mode ); } -void wxGTKWindowImplDC::SetTextForeground( const wxColour &col ) +void wxWindowDCImpl::SetTextForeground( const wxColour &col ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); // don't set m_textForegroundColour to an invalid colour as we'd crash // later then (we use m_textForegroundColour.GetColor() without checking // in a few places) - if ( !col.Ok() || (m_textForegroundColour == col) ) + if ( !col.IsOk() || (m_textForegroundColour == col) ) return; m_textForegroundColour = col; - if ( m_window ) + if ( m_gdkwindow ) { m_textForegroundColour.CalcPixel( m_cmap ); gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() ); } } -void wxGTKWindowImplDC::SetTextBackground( const wxColour &col ) +void wxWindowDCImpl::SetTextBackground( const wxColour &col ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); // same as above - if ( !col.Ok() || (m_textBackgroundColour == col) ) + if ( !col.IsOk() || (m_textBackgroundColour == col) ) return; m_textBackgroundColour = col; - if ( m_window ) + if ( m_gdkwindow ) { m_textBackgroundColour.CalcPixel( m_cmap ); gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() ); } } -void wxGTKWindowImplDC::SetBackgroundMode( int mode ) +void wxWindowDCImpl::SetBackgroundMode( int mode ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); m_backgroundMode = mode; - - if (!m_window) 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 wxGTKWindowImplDC::SetPalette( const wxPalette& WXUNUSED(palette) ) +void wxWindowDCImpl::SetPalette( const wxPalette& WXUNUSED(palette) ) { - wxFAIL_MSG( wxT("wxGTKWindowImplDC::SetPalette not implemented") ); + wxFAIL_MSG( wxT("wxWindowDCImpl::SetPalette not implemented") ); } -void wxGTKWindowImplDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) +void wxWindowDCImpl::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); - if (!m_window) return; + if (!m_gdkwindow) return; wxRect rect; rect.x = XLOG2DEV(x); @@ -2277,34 +1884,18 @@ void wxGTKWindowImplDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width rect.width = XLOG2DEVREL(width); rect.height = YLOG2DEVREL(height); - if (m_owner && m_owner->m_wxwindow && (m_owner->GetLayoutDirection() == wxLayout_RightToLeft)) + 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 ); - wxDC::DoSetClippingRegion( xx, yy, ww, hh ); - - 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 wxGTKWindowImplDC::DoSetClippingRegionAsRegion( const wxRegion ®ion ) +void wxWindowDCImpl::DoSetDeviceClippingRegion( const wxRegion ®ion ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); if (region.Empty()) { @@ -2312,7 +1903,7 @@ void wxGTKWindowImplDC::DoSetClippingRegionAsRegion( const wxRegion ®ion ) return; } - if (!m_window) return; + if (!m_gdkwindow) return; if (!m_currentClippingRegion.IsNull()) m_currentClippingRegion.Intersect( region ); @@ -2326,19 +1917,20 @@ void wxGTKWindowImplDC::DoSetClippingRegionAsRegion( const wxRegion ®ion ) wxCoord xx, yy, ww, hh; m_currentClippingRegion.GetBox( xx, yy, ww, hh ); - wxDC::DoSetClippingRegion( xx, yy, ww, hh ); + wxGTKDCImpl::DoSetClippingRegion( xx, yy, ww, hh ); - 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 wxGTKWindowImplDC::DestroyClippingRegion() +void wxWindowDCImpl::DestroyClippingRegion() { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); - wxDC::DestroyClippingRegion(); + wxDCImpl::DestroyClippingRegion(); m_currentClippingRegion.Clear(); @@ -2347,37 +1939,31 @@ void wxGTKWindowImplDC::DestroyClippingRegion() m_currentClippingRegion.Union( m_paintClippingRegion ); #endif - if (!m_window) return; + 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 wxGTKWindowImplDC::Destroy() +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 wxGTKWindowImplDC::SetDeviceOrigin( wxCoord x, wxCoord y ) +void wxWindowDCImpl::SetDeviceOrigin( wxCoord x, wxCoord y ) { m_deviceOriginX = x; m_deviceOriginY = y; @@ -2385,25 +1971,26 @@ void wxGTKWindowImplDC::SetDeviceOrigin( wxCoord x, wxCoord y ) ComputeScaleAndOrigin(); } -void wxGTKWindowImplDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp ) +void wxWindowDCImpl::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)) + if (m_window && m_window->m_wxwindow && + (m_window->GetLayoutDirection() == wxLayout_RightToLeft)) m_signX = -m_signX; ComputeScaleAndOrigin(); } -void wxGTKWindowImplDC::ComputeScaleAndOrigin() +void wxWindowDCImpl::ComputeScaleAndOrigin() { const wxRealPoint origScale(m_scaleX, m_scaleY); - wxDC::ComputeScaleAndOrigin(); + wxDCImpl::ComputeScaleAndOrigin(); // if scale has changed call SetPen to recalulate the line width - if ( wxRealPoint(m_scaleX, m_scaleY) != origScale && m_pen.Ok() ) + if ( wxRealPoint(m_scaleX, m_scaleY) != origScale && m_pen.IsOk() ) { // this is a bit artificial, but we need to force wxDC to think the pen // has changed @@ -2414,26 +2001,53 @@ void wxGTKWindowImplDC::ComputeScaleAndOrigin() } // Resolution in pixels per logical inch -wxSize wxGTKWindowImplDC::GetPPI() const +wxSize wxWindowDCImpl::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 wxGTKWindowImplDC::GetDepth() const +int wxWindowDCImpl::GetDepth() const { - return gdk_drawable_get_depth(m_window); + return gdk_drawable_get_depth(m_gdkwindow); } - //----------------------------------------------------------------------------- -// wxPaintDC +// wxClientDCImpl //----------------------------------------------------------------------------- -#if wxUSE_NEW_DC -IMPLEMENT_DYNAMIC_CLASS(wxGTKPaintImplDC, wxGTKClientImplDC) -#else -IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxClientDC) +IMPLEMENT_ABSTRACT_CLASS(wxClientDCImpl, wxWindowDCImpl) + +wxClientDCImpl::wxClientDCImpl( wxDC *owner ) + : wxWindowDCImpl( owner ) +{ +} + +wxClientDCImpl::wxClientDCImpl( wxDC *owner, wxWindow *win ) + : wxWindowDCImpl( owner, win ) +{ + 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 + // __WXUNIVERSAL__ +} + +void wxClientDCImpl::DoGetSize(int *width, int *height) const +{ + wxCHECK_RET( m_window, wxT("GetSize() doesn't work without window") ); + + m_window->GetClientSize(width, height); +} + +//----------------------------------------------------------------------------- +// wxPaintDCImpl +//----------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxPaintDCImpl, wxClientDCImpl) // Limit the paint region to the window size. Sometimes // the paint region is too big, and this risks X11 errors @@ -2454,8 +2068,13 @@ static void wxLimitRegionToSize(wxRegion& region, const wxSize& sz) } } -wxGTKPaintImplDC::wxGTKPaintImplDC( wxWindow *win ) - : wxGTKClientImplDC( win ) +wxPaintDCImpl::wxPaintDCImpl( wxDC *owner ) + : wxClientDCImpl( owner ) +{ +} + +wxPaintDCImpl::wxPaintDCImpl( wxDC *owner, wxWindow *win ) + : wxClientDCImpl( owner, win ) { #if USE_PAINT_REGION if (!win->m_clipPaintRegion) @@ -2479,37 +2098,7 @@ wxGTKPaintImplDC::wxGTKPaintImplDC( wxWindow *win ) gdk_gc_set_clip_region( m_textGC, region ); gdk_gc_set_clip_region( m_bgGC, region ); } -#endif // USE_PAINT_REGION -} - -//----------------------------------------------------------------------------- -// wxClientDC -//----------------------------------------------------------------------------- - -#if wxUSE_NEW_DC -IMPLEMENT_DYNAMIC_CLASS(wxGTKClientImplDC, wxGTKWindowImplDC) -#else -IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC) #endif - -wxGTKClientImplDC::wxGTKClientImplDC( wxWindow *win ) - : wxGTKWindowImplDC( win ) -{ - wxCHECK_RET( win, _T("NULL window in wxGTKClientImplDC::wxClientDC") ); - -#ifdef __WXUNIVERSAL__ - wxPoint ptOrigin = win->GetClientAreaOrigin(); - SetDeviceOrigin(ptOrigin.x, ptOrigin.y); - wxSize size = win->GetClientSize(); - SetClippingRegion(wxPoint(0, 0), size); -#endif // __WXUNIVERSAL__ -} - -void wxGTKClientImplDC::DoGetSize(int *width, int *height) const -{ - wxCHECK_RET( m_owner, _T("GetSize() doesn't work without window") ); - - m_owner->GetClientSize( width, height ); } // ---------------------------------------------------------------------------- @@ -2537,4 +2126,10 @@ bool wxDCModule::OnInit() void wxDCModule::OnExit() { wxCleanUpGCPool(); + + for (int i = wxBRUSHSTYLE_LAST_HATCH - wxBRUSHSTYLE_FIRST_HATCH; i--; ) + { + if (hatches[i]) + g_object_unref(hatches[i]); + } }