X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/e90c1d2a19361551eb07778280f22be3e759cf64..03a126c68c940c13a7a6c9ee183fa88e9b575a21:/src/gtk/dcclient.cpp diff --git a/src/gtk/dcclient.cpp b/src/gtk/dcclient.cpp index d0d94aaaf4..f192e6e05c 100644 --- a/src/gtk/dcclient.cpp +++ b/src/gtk/dcclient.cpp @@ -1,23 +1,43 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: dcclient.cpp +// Name: src/gtk/dcclient.cpp // Purpose: // Author: Robert Roebling // RCS-ID: $Id$ -// Copyright: (c) 1998 Robert Roebling, Markus Holzem, Chris Breeze -// Licence: wxWindows licence +// Copyright: (c) 1998 Robert Roebling, Chris Breeze +// Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ -#pragma implementation "dcclient.h" +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __VMS +#define XCopyPlane XCOPYPLANE #endif #include "wx/dcclient.h" -#include "wx/dcmemory.h" -#include "wx/image.h" -#include // for floating-point functions -#include "gdk/gdk.h" -#include "gtk/gtk.h" +#ifndef WX_PRECOMP + #include "wx/window.h" + #include "wx/log.h" + #include "wx/dcmemory.h" + #include "wx/math.h" // for floating-point functions + #include "wx/image.h" + #include "wx/module.h" +#endif + +#include "wx/fontutil.h" +#include "wx/scrolwin.h" + +#include "wx/gtk/win_gtk.h" +#include "wx/gtk/private.h" + +#include + +//----------------------------------------------------------------------------- +// local defines +//----------------------------------------------------------------------------- + +#define USE_PAINT_REGION 1 //----------------------------------------------------------------------------- // local data @@ -31,14 +51,29 @@ #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(); + //----------------------------------------------------------------------------- // constants //----------------------------------------------------------------------------- -#define RAD2DEG 57.2957795131 +const double RAD2DEG = 180.0 / M_PI; + +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +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 @@ -46,93 +81,242 @@ static GdkPixmap **hatch_bitmap = (GdkPixmap **) NULL; #include "gdk/gdkprivate.h" -void gdk_draw_bitmap (GdkDrawable *drawable, - GdkGC *gc, - GdkDrawable *src, - gint xsrc, - gint ysrc, - gint xdest, - gint ydest, - gint width, - gint height) +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 ); +} + +//----------------------------------------------------------------------------- +// Implement Pool of Graphic contexts. Creating them takes too much time. +//----------------------------------------------------------------------------- + +enum wxPoolGCType +{ + wxGC_ERROR = 0, + wxTEXT_MONO, + wxBG_MONO, + wxPEN_MONO, + wxBRUSH_MONO, + wxTEXT_COLOUR, + wxBG_COLOUR, + wxPEN_COLOUR, + wxBRUSH_COLOUR, + wxTEXT_SCREEN, + wxBG_SCREEN, + wxPEN_SCREEN, + wxBRUSH_SCREEN +}; + +struct wxGC +{ + GdkGC *m_gc; + wxPoolGCType m_type; + bool m_used; +}; + +#define GC_POOL_ALLOC_SIZE 100 + +static int wxGCPoolSize = 0; + +static wxGC *wxGCPool = NULL; + +static void wxInitGCPool() { - GdkWindowPrivate *drawable_private; - GdkWindowPrivate *src_private; - GdkGCPrivate *gc_private; + // This really could wait until the first call to + // wxGetPoolGC, but we will make the first allocation + // now when other initialization is being performed. - g_return_if_fail (drawable != NULL); - g_return_if_fail (src != NULL); - g_return_if_fail (gc != NULL); + // Set initial pool size. + wxGCPoolSize = GC_POOL_ALLOC_SIZE; - drawable_private = (GdkWindowPrivate*) drawable; - src_private = (GdkWindowPrivate*) src; - if (drawable_private->destroyed || src_private->destroyed) + // Allocate initial pool. + wxGCPool = (wxGC *)malloc(wxGCPoolSize * sizeof(wxGC)); + if (wxGCPool == NULL) + { + // If we cannot malloc, then fail with error + // when debug is enabled. If debug is not enabled, + // the problem will eventually get caught + // in wxGetPoolGC. + wxFAIL_MSG( wxT("Cannot allocate GC pool") ); return; + } - gc_private = (GdkGCPrivate*) gc; + // Zero initial pool. + memset(wxGCPool, 0, wxGCPoolSize * sizeof(wxGC)); +} - if (width == -1) width = src_private->width; - if (height == -1) height = src_private->height; +static void wxCleanUpGCPool() +{ + for (int i = 0; i < wxGCPoolSize; i++) + { + if (wxGCPool[i].m_gc) + g_object_unref (wxGCPool[i].m_gc); + } - XCopyPlane( drawable_private->xdisplay, - src_private->xwindow, - drawable_private->xwindow, - gc_private->xgc, - xsrc, ysrc, - width, height, - xdest, ydest, - 1 ); + free(wxGCPool); + wxGCPool = NULL; + wxGCPoolSize = 0; +} + +static GdkGC* wxGetPoolGC( GdkWindow *window, wxPoolGCType type ) +{ + wxGC *pptr; + + // Look for an available GC. + for (int i = 0; i < wxGCPoolSize; i++) + { + if (!wxGCPool[i].m_gc) + { + wxGCPool[i].m_gc = gdk_gc_new( window ); + gdk_gc_set_exposures( wxGCPool[i].m_gc, FALSE ); + wxGCPool[i].m_type = type; + wxGCPool[i].m_used = false; + } + if ((!wxGCPool[i].m_used) && (wxGCPool[i].m_type == type)) + { + wxGCPool[i].m_used = true; + return wxGCPool[i].m_gc; + } + } + + // We did not find an available GC. + // We need to grow the GC pool. + pptr = (wxGC *)realloc(wxGCPool, + (wxGCPoolSize + GC_POOL_ALLOC_SIZE)*sizeof(wxGC)); + if (pptr != NULL) + { + // Initialize newly allocated pool. + wxGCPool = pptr; + memset(&wxGCPool[wxGCPoolSize], 0, + GC_POOL_ALLOC_SIZE*sizeof(wxGC)); + + // Initialize entry we will return. + wxGCPool[wxGCPoolSize].m_gc = gdk_gc_new( window ); + gdk_gc_set_exposures( wxGCPool[wxGCPoolSize].m_gc, FALSE ); + wxGCPool[wxGCPoolSize].m_type = type; + wxGCPool[wxGCPoolSize].m_used = true; + + // Set new value of pool size. + wxGCPoolSize += GC_POOL_ALLOC_SIZE; + + // Return newly allocated entry. + return wxGCPool[wxGCPoolSize-GC_POOL_ALLOC_SIZE].m_gc; + } + + // The realloc failed. Fall through to error. + wxFAIL_MSG( wxT("No GC available") ); + + return (GdkGC*) NULL; +} + +static void wxFreePoolGC( GdkGC *gc ) +{ + for (int i = 0; i < wxGCPoolSize; i++) + { + if (wxGCPool[i].m_gc == gc) + { + wxGCPool[i].m_used = false; + return; + } + } + + wxFAIL_MSG( wxT("Wrong GC") ); } //----------------------------------------------------------------------------- // wxWindowDC //----------------------------------------------------------------------------- +#if wxUSE_NEW_DC +IMPLEMENT_DYNAMIC_CLASS(wxGTKWindowImplDC, wxGTKImplDC) +#else IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC) +#endif -wxWindowDC::wxWindowDC() +wxGTKWindowImplDC::wxGTKWindowImplDC() { m_penGC = (GdkGC *) NULL; m_brushGC = (GdkGC *) NULL; m_textGC = (GdkGC *) NULL; m_bgGC = (GdkGC *) NULL; m_cmap = (GdkColormap *) NULL; - m_isMemDC = FALSE; + m_isMemDC = false; + m_isScreenDC = false; m_owner = (wxWindow *)NULL; + m_context = (PangoContext *)NULL; + m_layout = (PangoLayout *)NULL; + m_fontdesc = (PangoFontDescription *)NULL; } -wxWindowDC::wxWindowDC( wxWindow *window ) +wxGTKWindowImplDC::wxGTKWindowImplDC( wxWindow *window ) { + 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_isMemDC = false; + m_isScreenDC = false; m_font = window->GetFont(); - wxASSERT_MSG( window, T("DC needs a window") ); - GtkWidget *widget = window->m_wxwindow; - wxASSERT_MSG( widget, T("DC needs a widget") ); + // 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. + if ( !widget ) + { + window = window->GetParent(); + widget = window->m_wxwindow; + } + + wxASSERT_MSG( widget, wxT("DC needs a widget") ); + + m_context = window->GtkGetPangoDefaultContext(); + m_layout = pango_layout_new( m_context ); + m_fontdesc = pango_font_description_copy( widget->style->font_desc ); - m_window = widget->window; + GtkPizza *pizza = GTK_PIZZA( widget ); + m_window = pizza->bin_window; - /* not realized ? */ + // Window not realized ? if (!m_window) { - /* don't report problems */ - m_ok = TRUE; + // Don't report problems as per MSW. + m_ok = true; return; } - if (window->m_wxwindow) - m_cmap = gtk_widget_get_colormap( window->m_wxwindow ); - else - m_cmap = gtk_widget_get_colormap( window->m_widget ); + m_cmap = gtk_widget_get_colormap( widget ? widget : window->m_widget ); SetUpDC(); @@ -144,28 +328,161 @@ wxWindowDC::wxWindowDC( wxWindow *window ) standard (as e.g. wxStatusBar) */ m_owner = window; + + if (m_owner && m_owner->m_wxwindow && (m_owner->GetLayoutDirection() == wxLayout_RightToLeft)) + { + // reverse sense + m_signX = -1; + + // origin in the upper right corner + m_deviceOriginX = m_owner->GetClientSize().x; + } } -wxWindowDC::~wxWindowDC() +wxGTKWindowImplDC::~wxGTKWindowImplDC() { Destroy(); + + if (m_layout) + g_object_unref (m_layout); + if (m_fontdesc) + pango_font_description_free( m_fontdesc ); } -void wxWindowDC::DoFloodFill( long WXUNUSED(x), long WXUNUSED(y), - const wxColour &WXUNUSED(col), int WXUNUSED(style) ) +void wxGTKWindowImplDC::SetUpDC() { - wxFAIL_MSG( T("wxWindowDC::DoFloodFill not implemented") ); + 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)) + { + 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 ); + } + else + { + 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 ); + } + + /* 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 ); + gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() ); + + m_textBackgroundColour.CalcPixel( m_cmap ); + gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() ); + + gdk_gc_set_fill( m_textGC, GDK_SOLID ); + + gdk_gc_set_colormap( m_textGC, m_cmap ); + + /* m_penGC */ + m_pen.GetColour().CalcPixel( m_cmap ); + gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() ); + gdk_gc_set_background( m_penGC, bg_col ); + + gdk_gc_set_line_attributes( m_penGC, 0, GDK_LINE_SOLID, GDK_CAP_NOT_LAST, GDK_JOIN_ROUND ); + + /* m_brushGC */ + m_brush.GetColour().CalcPixel( m_cmap ); + gdk_gc_set_foreground( m_brushGC, m_brush.GetColour().GetColor() ); + gdk_gc_set_background( m_brushGC, bg_col ); + + gdk_gc_set_fill( m_brushGC, GDK_SOLID ); + + /* m_bgGC */ + gdk_gc_set_background( m_bgGC, bg_col ); + gdk_gc_set_foreground( m_bgGC, bg_col ); + + gdk_gc_set_fill( m_bgGC, GDK_SOLID ); + + /* ROPs */ + gdk_gc_set_function( m_textGC, GDK_COPY ); + gdk_gc_set_function( m_brushGC, GDK_COPY ); + 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 ); + } } -bool wxWindowDC::DoGetPixel( long WXUNUSED(x1), long WXUNUSED(y1), wxColour *WXUNUSED(col) ) const +void wxGTKWindowImplDC::DoGetSize( int* width, int* height ) const { - wxFAIL_MSG( T("wxWindowDC::DoGetPixel not implemented") ); - return FALSE; + wxCHECK_RET( m_owner, _T("GetSize() doesn't work without window") ); + + m_owner->GetSize(width, height); +} + +bool wxGTKWindowImplDC::DoFloodFill(wxCoord x, wxCoord y, + const wxColour& col, int style) +{ +#if wxUSE_IMAGE + extern bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y, + const wxColour & col, int style); + + return wxDoFloodFill(this, x, y, col, style); +#else + return false; +#endif +} + +bool wxGTKWindowImplDC::DoGetPixel( wxCoord x1, wxCoord y1, wxColour *col ) const +{ +#if wxUSE_IMAGE + // Generic (and therefore rather inefficient) method. + // Could be improved. + wxMemoryDC memdc; + wxBitmap bitmap(1, 1); + memdc.SelectObject(bitmap); + memdc.Blit(0, 0, 1, 1, (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)); + return true; +#else // !wxUSE_IMAGE + return false; +#endif // wxUSE_IMAGE/!wxUSE_IMAGE } -void wxWindowDC::DoDrawLine( long x1, long y1, long x2, long y2 ) +void wxGTKWindowImplDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 ) { - wxCHECK_RET( Ok(), T("invalid window dc") ); + wxCHECK_RET( Ok(), wxT("invalid window dc") ); if (m_pen.GetStyle() != wxTRANSPARENT) { @@ -177,17 +494,17 @@ void wxWindowDC::DoDrawLine( long x1, long y1, long x2, long y2 ) } } -void wxWindowDC::DoCrossHair( long x, long y ) +void wxGTKWindowImplDC::DoCrossHair( wxCoord x, wxCoord y ) { - wxCHECK_RET( Ok(), T("invalid window dc") ); + wxCHECK_RET( Ok(), wxT("invalid window dc") ); if (m_pen.GetStyle() != wxTRANSPARENT) { int w = 0; int h = 0; GetSize( &w, &h ); - long xx = XLOG2DEV(x); - long yy = YLOG2DEV(y); + wxCoord xx = XLOG2DEV(x); + wxCoord yy = YLOG2DEV(y); if (m_window) { gdk_draw_line( m_window, m_penGC, 0, yy, XLOG2DEVREL(w), yy ); @@ -196,21 +513,21 @@ void wxWindowDC::DoCrossHair( long x, long y ) } } -void wxWindowDC::DoDrawArc( long x1, long y1, long x2, long y2, - long xc, long yc ) +void wxGTKWindowImplDC::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, + wxCoord xc, wxCoord yc ) { - wxCHECK_RET( Ok(), T("invalid window dc") ); - - long xx1 = XLOG2DEV(x1); - long yy1 = YLOG2DEV(y1); - long xx2 = XLOG2DEV(x2); - long yy2 = YLOG2DEV(y2); - long xxc = XLOG2DEV(xc); - long yyc = YLOG2DEV(yc); + wxCHECK_RET( Ok(), wxT("invalid window dc") ); + + wxCoord xx1 = XLOG2DEV(x1); + wxCoord yy1 = YLOG2DEV(y1); + wxCoord xx2 = XLOG2DEV(x2); + wxCoord yy2 = YLOG2DEV(y2); + wxCoord xxc = XLOG2DEV(xc); + wxCoord yyc = YLOG2DEV(yc); double dx = xx1 - xxc; double dy = yy1 - yyc; - double radius = sqrt(dx*dx+dy*dy); - long r = (long)radius; + double radius = sqrt((double)(dx*dx+dy*dy)); + wxCoord r = (wxCoord)radius; double radius1, radius2; if (xx1 == xx2 && yy1 == yy2) @@ -218,10 +535,10 @@ void wxWindowDC::DoDrawArc( long x1, long y1, long x2, long y2, radius1 = 0.0; radius2 = 360.0; } - else - if (radius == 0.0) + else if ( wxIsNullDouble(radius) ) { - radius1 = radius2 = 0.0; + radius1 = + radius2 = 0.0; } else { @@ -232,32 +549,73 @@ void wxWindowDC::DoDrawArc( long x1, long y1, long x2, long y2, (yy2 - yyc < 0) ? 90.0 : -90.0 : -atan2(double(yy2-yyc), double(xx2-xxc)) * RAD2DEG; } - long alpha1 = long(radius1 * 64.0); - long alpha2 = long((radius2 - radius1) * 64.0); + wxCoord alpha1 = wxCoord(radius1 * 64.0); + wxCoord alpha2 = wxCoord((radius2 - radius1) * 64.0); while (alpha2 <= 0) alpha2 += 360*64; while (alpha1 > 360*64) alpha1 -= 360*64; if (m_window) { if (m_brush.GetStyle() != wxTRANSPARENT) - gdk_draw_arc( m_window, m_brushGC, TRUE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 ); + { + 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 ); + } + } if (m_pen.GetStyle() != wxTRANSPARENT) + { gdk_draw_arc( m_window, m_penGC, FALSE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 ); + + if ((m_brush.GetStyle() != wxTRANSPARENT) && (alpha2 - alpha1 != 360*64)) + { + gdk_draw_line( m_window, m_penGC, xx1, yy1, xxc, yyc ); + gdk_draw_line( m_window, m_penGC, xxc, yyc, xx2, yy2 ); + } + } } CalcBoundingBox (x1, y1); CalcBoundingBox (x2, y2); } -void wxWindowDC::DoDrawEllipticArc( long x, long y, long width, long height, double sa, double ea ) +void wxGTKWindowImplDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double sa, double ea ) { - wxCHECK_RET( Ok(), T("invalid window dc") ); + wxCHECK_RET( Ok(), wxT("invalid window dc") ); - long xx = XLOG2DEV(x); - long yy = YLOG2DEV(y); - long ww = m_signX * XLOG2DEVREL(width); - long hh = m_signY * YLOG2DEVREL(height); + wxCoord xx = XLOG2DEV(x); + wxCoord yy = YLOG2DEV(y); + wxCoord ww = m_signX * XLOG2DEVREL(width); + wxCoord hh = m_signY * YLOG2DEVREL(height); // CMB: handle -ve width and/or height if (ww < 0) { ww = -ww; xx = xx - ww; } @@ -265,11 +623,44 @@ void wxWindowDC::DoDrawEllipticArc( long x, long y, long width, long height, dou if (m_window) { - long start = long(sa * 64.0); - long end = long(ea * 64.0); + wxCoord start = wxCoord(sa * 64.0); + wxCoord end = wxCoord((ea-sa) * 64.0); if (m_brush.GetStyle() != wxTRANSPARENT) - gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, start, end ); + { + 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 ); + } + } if (m_pen.GetStyle() != wxTRANSPARENT) gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, start, end ); @@ -279,9 +670,9 @@ void wxWindowDC::DoDrawEllipticArc( long x, long y, long width, long height, dou CalcBoundingBox (x + width, y + height); } -void wxWindowDC::DoDrawPoint( long x, long y ) +void wxGTKWindowImplDC::DoDrawPoint( wxCoord x, wxCoord y ) { - wxCHECK_RET( Ok(), T("invalid window dc") ); + wxCHECK_RET( Ok(), wxT("invalid window dc") ); if ((m_pen.GetStyle() != wxTRANSPARENT) && m_window) gdk_draw_point( m_window, m_penGC, XLOG2DEV(x), YLOG2DEV(y) ); @@ -289,73 +680,134 @@ void wxWindowDC::DoDrawPoint( long x, long y ) CalcBoundingBox (x, y); } -void wxWindowDC::DoDrawLines( int n, wxPoint points[], long xoffset, long yoffset ) +void wxGTKWindowImplDC::DoDrawLines( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset ) { - wxCHECK_RET( Ok(), T("invalid window dc") ); + wxCHECK_RET( Ok(), wxT("invalid window dc") ); if (m_pen.GetStyle() == wxTRANSPARENT) return; if (n <= 0) return; - CalcBoundingBox( points[0].x + xoffset, points[0].y + yoffset ); + //Check, if scaling is necessary + const bool doScale = + xoffset != 0 || yoffset != 0 || XLOG2DEV(10) != 10 || YLOG2DEV(10) != 10; - for (int i = 0; i < n-1; i++) - { - long x1 = XLOG2DEV(points[i].x + xoffset); - long x2 = XLOG2DEV(points[i+1].x + xoffset); - long y1 = YLOG2DEV(points[i].y + yoffset); // oh, what a waste - long y2 = YLOG2DEV(points[i+1].y + yoffset); + // GdkPoint and wxPoint have the same memory layout, so we can cast one to the other + GdkPoint* gpts = reinterpret_cast(points); - if (m_window) - gdk_draw_line( m_window, m_penGC, x1, y1, x2, y2 ); + if (doScale) + gpts = new GdkPoint[n]; - CalcBoundingBox( points[i+1].x + xoffset, points[i+1].y + yoffset ); + 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); + } + CalcBoundingBox(points[i].x + xoffset, points[i].y + yoffset); } + + if (m_window) + gdk_draw_lines( m_window, m_penGC, gpts, n); + + if (doScale) + delete[] gpts; } -void wxWindowDC::DoDrawPolygon( int n, wxPoint points[], long xoffset, long yoffset, int WXUNUSED(fillStyle) ) +void wxGTKWindowImplDC::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, int WXUNUSED(fillStyle) ) { - wxCHECK_RET( Ok(), T("invalid window dc") ); + wxCHECK_RET( Ok(), wxT("invalid window dc") ); if (n <= 0) return; - GdkPoint *gdkpoints = new GdkPoint[n+1]; + //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* gdkpoints = reinterpret_cast(points); + + if (doScale) + gdkpoints = new GdkPoint[n]; + int i; for (i = 0 ; i < n ; i++) { - gdkpoints[i].x = XLOG2DEV(points[i].x + xoffset); - gdkpoints[i].y = YLOG2DEV(points[i].y + yoffset); - - CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset ); + if (doScale) + { + gdkpoints[i].x = XLOG2DEV(points[i].x + xoffset); + gdkpoints[i].y = YLOG2DEV(points[i].y + yoffset); + } + CalcBoundingBox(points[i].x + xoffset, points[i].y + yoffset); } - if ((m_brush.GetStyle() != wxTRANSPARENT) && m_window) - gdk_draw_polygon (m_window, m_brushGC, TRUE, gdkpoints, n); - - // To do: Fillstyle - - if ((m_pen.GetStyle() != wxTRANSPARENT) && m_window) + if (m_window) { - for (i = 0 ; i < n ; i++) + if (m_brush.GetStyle() != wxTRANSPARENT) { - gdk_draw_line( m_window, m_penGC, - gdkpoints[i%n].x, - gdkpoints[i%n].y, - gdkpoints[(i+1)%n].x, - gdkpoints[(i+1)%n].y); + 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 ); + } + } + + if (m_pen.GetStyle() != wxTRANSPARENT) + { +/* + for (i = 0 ; i < n ; i++) + { + gdk_draw_line( m_window, 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 ); + } } - delete[] gdkpoints; + if (doScale) + delete[] gdkpoints; } -void wxWindowDC::DoDrawRectangle( long x, long y, long width, long height ) +void wxGTKWindowImplDC::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) { - wxCHECK_RET( Ok(), T("invalid window dc") ); + wxCHECK_RET( Ok(), wxT("invalid window dc") ); - long xx = XLOG2DEV(x); - long yy = YLOG2DEV(y); - long ww = m_signX * XLOG2DEVREL(width); - long hh = m_signY * YLOG2DEVREL(height); + wxCoord xx = XLOG2DEV(x); + wxCoord yy = YLOG2DEV(y); + wxCoord ww = m_signX * XLOG2DEVREL(width); + wxCoord hh = m_signY * YLOG2DEVREL(height); // CMB: draw nothing if transformed w or h is 0 if (ww == 0 || hh == 0) return; @@ -367,27 +819,89 @@ void wxWindowDC::DoDrawRectangle( long x, long y, long width, long height ) if (m_window) { if (m_brush.GetStyle() != wxTRANSPARENT) - gdk_draw_rectangle( m_window, m_brushGC, TRUE, xx, yy, ww, hh ); + { + 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 ); + } + } if (m_pen.GetStyle() != wxTRANSPARENT) - gdk_draw_rectangle( m_window, m_penGC, FALSE, xx, yy, ww-1, hh-1 ); + { +#if 1 + if ((m_pen.GetWidth() == 2) && (m_pen.GetCap() == wxCAP_ROUND) && + (m_pen.GetJoin() == wxJOIN_ROUND) && (m_pen.GetStyle() == wxSOLID)) + { + // Use 2 1-line rects instead + gdk_gc_set_line_attributes( m_penGC, 1, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND ); + + if (m_signX == -1) + { + // Different for RTL + gdk_draw_rectangle( m_window, m_penGC, FALSE, xx+1, yy, ww-2, hh-2 ); + gdk_draw_rectangle( m_window, m_penGC, FALSE, xx, yy-1, ww, hh ); + } + else + { + gdk_draw_rectangle( m_window, m_penGC, FALSE, xx, yy, ww-2, hh-2 ); + gdk_draw_rectangle( m_window, m_penGC, FALSE, xx-1, yy-1, ww, hh ); + } + + // reset + gdk_gc_set_line_attributes( m_penGC, 2, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND ); + } + else +#endif + { + // Just use X11 for other cases + gdk_draw_rectangle( m_window, m_penGC, FALSE, xx, yy, ww-1, hh-1 ); + } + } } CalcBoundingBox( x, y ); CalcBoundingBox( x + width, y + height ); } -void wxWindowDC::DoDrawRoundedRectangle( long x, long y, long width, long height, double radius ) +void wxGTKWindowImplDC::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius ) { - wxCHECK_RET( Ok(), T("invalid window dc") ); + wxCHECK_RET( Ok(), wxT("invalid window dc") ); if (radius < 0.0) radius = - radius * ((width < height) ? width : height); - long xx = XLOG2DEV(x); - long yy = YLOG2DEV(y); - long ww = m_signX * XLOG2DEVREL(width); - long hh = m_signY * YLOG2DEVREL(height); - long rr = XLOG2DEVREL((long)radius); + wxCoord xx = XLOG2DEV(x); + wxCoord yy = YLOG2DEV(y); + wxCoord ww = m_signX * XLOG2DEVREL(width); + wxCoord hh = m_signY * YLOG2DEVREL(height); + wxCoord rr = XLOG2DEVREL((wxCoord)radius); // CMB: handle -ve width and/or height if (ww < 0) { ww = -ww; xx = xx - ww; } @@ -416,27 +930,78 @@ void wxWindowDC::DoDrawRoundedRectangle( long x, long y, long width, long height { // CMB: ensure dd is not larger than rectangle otherwise we // get an hour glass shape - long dd = 2 * rr; + wxCoord dd = 2 * rr; if (dd > ww) dd = ww; if (dd > hh) dd = hh; rr = dd / 2; if (m_brush.GetStyle() != wxTRANSPARENT) { - 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 ); + 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 ); + } } if (m_pen.GetStyle() != wxTRANSPARENT) { - gdk_draw_line( m_window, m_penGC, xx+rr, yy, xx+ww-rr, yy ); - gdk_draw_line( m_window, m_penGC, xx+rr, yy+hh, xx+ww-rr, yy+hh ); - gdk_draw_line( m_window, m_penGC, xx, yy+rr, xx, yy+hh-rr ); - gdk_draw_line( m_window, m_penGC, xx+ww, yy+rr, xx+ww, yy+hh-rr ); + 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 ); @@ -449,14 +1014,14 @@ void wxWindowDC::DoDrawRoundedRectangle( long x, long y, long width, long height CalcBoundingBox( x + width, y + height ); } -void wxWindowDC::DoDrawEllipse( long x, long y, long width, long height ) +void wxGTKWindowImplDC::DoDrawEllipse( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) { - wxCHECK_RET( Ok(), T("invalid window dc") ); + wxCHECK_RET( Ok(), wxT("invalid window dc") ); - long xx = XLOG2DEV(x); - long yy = YLOG2DEV(y); - long ww = m_signX * XLOG2DEVREL(width); - long hh = m_signY * YLOG2DEVREL(height); + wxCoord xx = XLOG2DEV(x); + wxCoord yy = YLOG2DEV(y); + wxCoord ww = m_signX * XLOG2DEVREL(width); + wxCoord hh = m_signY * YLOG2DEVREL(height); // CMB: handle -ve width and/or height if (ww < 0) { ww = -ww; xx = xx - ww; } @@ -465,38 +1030,75 @@ void wxWindowDC::DoDrawEllipse( long x, long y, long width, long height ) if (m_window) { if (m_brush.GetStyle() != wxTRANSPARENT) - gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 ); + { + 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 + { + gdk_draw_arc( m_window, m_brushGC, TRUE, xx, yy, ww, hh, 0, 360*64 ); + } + } if (m_pen.GetStyle() != wxTRANSPARENT) gdk_draw_arc( m_window, m_penGC, FALSE, xx, yy, ww, hh, 0, 360*64 ); } - CalcBoundingBox( x - width, y - height ); + CalcBoundingBox( x, y ); CalcBoundingBox( x + width, y + height ); } -void wxWindowDC::DoDrawIcon( const wxIcon &icon, long x, long y ) +void wxGTKWindowImplDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y ) { // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why - DoDrawBitmap( (const wxBitmap&)icon, x, y, (bool)TRUE ); + DoDrawBitmap( (const wxBitmap&)icon, x, y, true ); } -void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap, - long x, long y, +void wxGTKWindowImplDC::DoDrawBitmap( const wxBitmap &bitmap, + wxCoord x, wxCoord y, bool useMask ) { - wxCHECK_RET( Ok(), T("invalid window dc") ); + wxCHECK_RET( Ok(), wxT("invalid window dc") ); - wxCHECK_RET( bitmap.Ok(), T("invalid bitmap") ); + wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") ); - /* scale/translate size and position */ + bool is_mono = bitmap.GetDepth() == 1; + // scale/translate size and position int xx = XLOG2DEV(x); int yy = YLOG2DEV(y); int w = bitmap.GetWidth(); int h = bitmap.GetHeight(); + if (m_owner && m_owner->GetLayoutDirection() == wxLayout_RightToLeft) + xx -= w; + CalcBoundingBox( x, y ); CalcBoundingBox( x + w, y + h ); @@ -505,324 +1107,765 @@ void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap, int ww = XLOG2DEVREL(w); int hh = YLOG2DEVREL(h); - /* scale bitmap if required */ - - wxBitmap use_bitmap; + // compare to current clipping region + if (!m_currentClippingRegion.IsNull()) + { + wxRegion tmp( xx,yy,ww,hh ); + tmp.Intersect( m_currentClippingRegion ); + if (tmp.IsEmpty()) + 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 ); + + // 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: + if (gtk_check_version(2,2,0)) + use_bitmap.GetPixmap(); + + // 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; + + if (mask != NULL) { - wxImage image( bitmap ); - image = image.Scale( ww, hh ); + if (!m_currentClippingRegion.IsNull()) + { + 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); + } - use_bitmap = image.ConvertToBitmap(); + 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) + { + 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 ); + + gdk_draw_drawable(m_window, use_gc, bitmap2, 0, 0, xx, yy, -1, -1); + + g_object_unref (bitmap2); + g_object_unref (gc); } else { - use_bitmap = bitmap; +#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); + } + } + + // 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()); + if (new_mask != NULL) + g_object_unref(new_mask); } +} - /* apply mask if any */ +bool wxGTKWindowImplDC::DoBlit( wxCoord xdest, wxCoord ydest, + wxCoord width, wxCoord height, + wxDC *source, + wxCoord xsrc, wxCoord ysrc, + int logical_func, + bool useMask, + wxCoord xsrcMask, wxCoord ysrcMask ) +{ + wxCHECK_MSG( Ok(), false, wxT("invalid window dc") ); - GdkBitmap *mask = (GdkBitmap *) NULL; - if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap(); + wxCHECK_MSG( source, false, wxT("invalid source dc") ); + + if (!m_window) return false; + + // transform the source DC coords to the device ones + xsrc = source->LogicalToDeviceX(xsrc); + ysrc = source->LogicalToDeviceY(ysrc); - if (useMask && mask) + wxBitmap selected; + wxMemoryDC *memDC = wxDynamicCast(source, wxMemoryDC); + if ( memDC ) { - gdk_gc_set_clip_mask( m_penGC, mask ); - gdk_gc_set_clip_origin( m_penGC, xx, yy ); + selected = memDC->GetSelectedBitmap(); + if ( !selected.IsOk() ) + return false; } - /* draw XPixmap or XBitmap, depending on what the wxBitmap contains */ + bool use_bitmap_method = false; + bool is_mono = false; - GdkPixmap *pm = use_bitmap.GetPixmap(); - if (pm) + if (xsrcMask == -1 && ysrcMask == -1) { - gdk_draw_pixmap( m_window, m_penGC, pm, 0, 0, xx, yy, -1, -1 ); + xsrcMask = xsrc; + ysrcMask = ysrc; } - else + + if (selected.Ok()) + { + is_mono = (selected.GetDepth() == 1); + + // 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 + + 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())) + { + // 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; + } + } + + 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); + + // compare to current clipping region + if (!m_currentClippingRegion.IsNull()) + { + wxRegion tmp( xx,yy,ww,hh ); + tmp.Intersect( m_currentClippingRegion ); + if (tmp.IsEmpty()) + return true; + } + + int old_logical_func = m_logicalFunction; + SetLogicalFunction( logical_func ); + + if (use_bitmap_method) { - GdkBitmap *bm = use_bitmap.GetBitmap(); - if (bm) + // 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)) { - gdk_draw_bitmap( m_window, m_penGC, bm, 0, 0, xx, yy, -1, -1 ); + // 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); } - } - - /* remove mask again if any */ - - if (useMask && mask) - { - gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL ); - gdk_gc_set_clip_origin( m_penGC, 0, 0 ); - } -} -bool wxWindowDC::DoBlit( long xdest, long ydest, long width, long height, - wxDC *source, long xsrc, long ysrc, - int logical_func, bool useMask ) -{ - /* this is the nth try to get this utterly useless function to - work. it now completely ignores the scaling or translation - of the source dc, but scales correctly on the target dc and - knows about possible mask information in a memory dc. */ + // apply mask if any + GdkBitmap *mask = (GdkBitmap *) NULL; + if (useMask && use_bitmap.GetMask()) + mask = use_bitmap.GetMask()->GetBitmap(); - wxCHECK_MSG( Ok(), FALSE, T("invalid window dc") ); + GdkGC* use_gc = is_mono ? m_textGC : m_penGC; - wxCHECK_MSG( source, FALSE, T("invalid source dc") ); + GdkBitmap *new_mask = (GdkBitmap*) NULL; - if (!m_window) return FALSE; + if (mask != NULL) + { + 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); + } - wxClientDC *srcDC = (wxClientDC*)source; - wxMemoryDC *memDC = (wxMemoryDC*)source; + 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); + } - bool use_bitmap_method = FALSE; + // Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For + // drawing a mono-bitmap (XBitmap) we use the current text GC - if (srcDC->m_isMemDC) - { - if (!memDC->m_selected.Ok()) return FALSE; + if (is_mono) + { + 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 ); - /* we use the "XCopyArea" way to copy a memory dc into - y 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 */ + gdk_draw_drawable(m_window, use_gc, bitmap, xsrc, ysrc, cx, cy, cw, ch); - if (useMask && (memDC->m_selected.GetMask())) + g_object_unref (bitmap); + g_object_unref (gc); + } + else { - /* 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; + // 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); } - else if (memDC->m_selected.GetDepth() == 1) + + // remove mask again if any + if (mask != NULL) { - /* 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; + 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()); } - else if ((xsrc == 0) && (ysrc == 0) && - (width == memDC->m_selected.GetWidth()) && - (height == memDC->m_selected.GetHeight())) + + if (new_mask) + g_object_unref (new_mask); + } + else // use_bitmap_method + { + if (selected.Ok() && ((width != ww) || (height != hh))) { - /* 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; + // 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 { - use_bitmap_method = FALSE; + // 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 ); } } - CalcBoundingBox( xdest, ydest ); - CalcBoundingBox( xdest + width, ydest + height ); + SetLogicalFunction( old_logical_func ); - int old_logical_func = m_logicalFunction; - SetLogicalFunction( logical_func ); + return true; +} - if (use_bitmap_method) - { - /* scale/translate bitmap size */ +void wxGTKWindowImplDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) +{ + wxCHECK_RET( Ok(), wxT("invalid window dc") ); + + if (!m_window) return; - long bm_width = memDC->m_selected.GetWidth(); - long bm_height = memDC->m_selected.GetHeight(); + if (text.empty()) return; - long bm_ww = XLOG2DEVREL( bm_width ); - long bm_hh = YLOG2DEVREL( bm_height ); + x = XLOG2DEV(x); + y = YLOG2DEV(y); - /* scale bitmap if required */ + 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") ); - wxBitmap use_bitmap; + gdk_pango_context_set_colormap( m_context, m_cmap ); - if ((bm_width != bm_ww) || (bm_height != bm_hh)) - { - wxImage image( memDC->m_selected ); - image = image.Scale( bm_ww, bm_hh ); + bool underlined = m_font.Ok() && m_font.GetUnderlined(); - use_bitmap = image.ConvertToBitmap(); - } - else - { - use_bitmap = memDC->m_selected; - } + const wxCharBuffer data = wxGTK_CONV( text ); + if ( !data ) + return; + size_t datalen = strlen(data); - /* scale/translate size and position */ + // 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); - long xx = XLOG2DEV(xdest); - long yy = YLOG2DEV(ydest); + bool needshack = underlined && !pangoOk; + char *hackstring = NULL; - long ww = XLOG2DEVREL(width); - long hh = YLOG2DEVREL(height); + 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. - /* apply mask if any */ + // need to realloc the string to prepend & append our special characters + hackstring = (char*)malloc((datalen+7)*sizeof(char)); - GdkBitmap *mask = (GdkBitmap *) NULL; - if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap(); + // copy the leading U+200C ZERO WIDTH NON-JOINER encoded in UTF8 format + strcpy(hackstring, "\342\200\214"); - if (useMask && mask) - { - gdk_gc_set_clip_mask( m_penGC, mask ); - gdk_gc_set_clip_origin( m_penGC, xx, yy ); - } + // copy the user string + memcpy(&hackstring[3], data, datalen); - /* draw XPixmap or XBitmap, depending on what the wxBitmap contains */ + // copy the trailing U+200C ZERO WIDTH NON-JOINER encoded in UTF8 format + strcpy(&hackstring[datalen+3], "\342\200\214"); - GdkPixmap *pm = use_bitmap.GetPixmap(); - if (pm) - { - gdk_draw_pixmap( m_window, m_penGC, pm, xsrc, ysrc, xx, yy, ww, hh ); - } - else - { - GdkBitmap *bm = use_bitmap.GetBitmap(); - if (bm) - { - /* we use the textGC here because blitting a bitmap is done - using the current text colour */ - gdk_draw_bitmap( m_window, m_textGC, bm, xsrc, ysrc, xx, yy, ww, hh ); - } - } + // the special characters that we added require 6 additional bytes: + datalen += 6; + + pango_layout_set_text(m_layout, hackstring, datalen); + } + else + { + pango_layout_set_text(m_layout, data, datalen); + } - /* remove mask again if any */ + if (underlined) + { + PangoAttrList *attrs = pango_attr_list_new(); + PangoAttribute *a = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); + a->start_index = 0; + a->end_index = datalen; + pango_attr_list_insert(attrs, a); - if (useMask && mask) + if (needshack) { - gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL ); - gdk_gc_set_clip_origin( m_penGC, 0, 0 ); + // 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); } - } - else /* use_bitmap_method */ - { - /* scale/translate size and position */ - long xx = XLOG2DEV(xdest); - long yy = YLOG2DEV(ydest); + pango_layout_set_attributes(m_layout, attrs); + pango_attr_list_unref(attrs); + } - long ww = XLOG2DEVREL(width); - long hh = YLOG2DEVREL(height); + int w,h; - if ((width != ww) || (height != hh)) + if (fabs(m_scaleY - 1.0) > 0.00001) + { + // 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 ); + } + else + { + pango_layout_get_pixel_size( m_layout, &w, &h ); + if ( m_backgroundMode == wxSOLID ) { - /* draw source window into a bitmap as we cannot scale - a window in contrast to a bitmap. this would actually - work with memory dcs as well, but we'd lose the mask - information and waste one step in this process since - a memory already has a bitmap. all this is slightly - inefficient as we could take an XImage directly from - an X window, but we'd then also have to care that - the window is not outside the screen (in which case - we'd get a BadMatch or what not). - Is a double XGetImage and combined XGetPixel and - XPutPixel really faster? I'm not sure. look at wxXt - for a different implementation of the same problem. */ + 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 ); + } - wxBitmap bitmap( width, height ); - gdk_window_copy_area( bitmap.GetPixmap(), m_penGC, 0, 0, - srcDC->GetWindow(), - xsrc, ysrc, width, height ); + if (underlined) + { + // undo underline attributes setting: + pango_layout_set_attributes(m_layout, NULL); + } - /* scale image */ + wxCoord width = w; + wxCoord height = h; - wxImage image( bitmap ); - image = image.Scale( ww, hh ); + width = wxCoord(width / m_scaleX); + height = wxCoord(height / m_scaleY); + CalcBoundingBox (x + width, y + height); + CalcBoundingBox (x, y); - /* convert to bitmap */ + if (hackstring) + free(hackstring); +} - bitmap = image.ConvertToBitmap(); - /* draw scaled bitmap */ +// 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 - gdk_draw_pixmap( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 ); +void wxGTKWindowImplDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, double angle ) +{ +#if wxUSE_IMAGE + if (!m_window || text.empty()) + return; - } - else - { - /* no scaling and not a memory dc with a mask either */ + wxCHECK_RET( Ok(), wxT("invalid window dc") ); - gdk_window_copy_area( m_window, m_penGC, xx, yy, - srcDC->GetWindow(), - xsrc, ysrc, width, height ); - } + if ( wxIsNullDouble(angle) ) + { + DrawText(text, x, y); + return; } - SetLogicalFunction( old_logical_func ); - return TRUE; + 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); +#endif // wxUSE_IMAGE } -void wxWindowDC::DoDrawText( const wxString &text, long x, long y ) +void wxGTKWindowImplDC::DoGetTextExtent(const wxString &string, + wxCoord *width, wxCoord *height, + wxCoord *descent, wxCoord *externalLeading, + const wxFont *theFont) const { - wxCHECK_RET( Ok(), T("invalid window dc") ); - - if (!m_window) return; + if ( width ) + *width = 0; + if ( height ) + *height = 0; + if ( descent ) + *descent = 0; + if ( externalLeading ) + *externalLeading = 0; + + if (string.empty()) + return; - GdkFont *font = m_font.GetInternalFont( m_scaleY ); + // ensure that theFont is always non-NULL + if ( !theFont || !theFont->Ok() ) + theFont = wx_const_cast(wxFont *, &m_font); - x = XLOG2DEV(x); - y = YLOG2DEV(y); + // and use it if it's valid + if ( theFont->Ok() ) + { + pango_layout_set_font_description + ( + m_layout, + theFont->GetNativeFontInfo()->description + ); + } - /* CMB 21/5/98: draw text background if mode is wxSOLID */ - if (m_backgroundMode == wxSOLID) + // Set layout's text + const wxCharBuffer dataUTF8 = wxGTK_CONV_FONT(string, *theFont); + if ( !dataUTF8 ) { - long width = gdk_string_width( font, text.mbc_str() ); - long height = font->ascent + font->descent; - gdk_gc_set_foreground( m_textGC, m_textBackgroundColour.GetColor() ); - gdk_draw_rectangle( m_window, m_textGC, TRUE, x, y, width, height ); - gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() ); + // hardly ideal, but what else can we do if conversion failed? + return; } - gdk_draw_string( m_window, font, m_textGC, x, y + font->ascent, text.mbc_str() ); - /* CMB 17/7/98: simple underline: ignores scaling and underlying - X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS - properties (see wxXt implementation) */ - if (m_font.GetUnderlined()) + 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; + } + else { - long width = gdk_string_width( font, text.mbc_str() ); - long ul_y = y + font->ascent; - if (font->descent > 0) ul_y++; - gdk_draw_line( m_window, m_textGC, x, ul_y, x + width, ul_y); + pango_layout_get_pixel_size( m_layout, width, height ); } - long w, h; - GetTextExtent (text, &w, &h); - CalcBoundingBox (x + w, y + h); - CalcBoundingBox (x, y); + // Reset old font description + if (theFont->IsOk()) + pango_layout_set_font_description( m_layout, m_fontdesc ); } -void wxWindowDC::GetTextExtent( const wxString &string, long *width, long *height, - long *descent, long *externalLeading, - wxFont *theFont ) const + +bool wxGTKWindowImplDC::DoGetPartialTextExtents(const wxString& text, + wxArrayInt& widths) const { - wxFont fontToUse = m_font; - if (theFont) fontToUse = *theFont; - - GdkFont *font = fontToUse.GetInternalFont( m_scaleY ); - if (width) (*width) = long(gdk_string_width( font, string.mbc_str() ) / m_scaleX); - if (height) (*height) = long((font->ascent + font->descent) / m_scaleY); - if (descent) (*descent) = long(font->descent / m_scaleY); - if (externalLeading) (*externalLeading) = 0; // ?? + const size_t len = text.length(); + widths.Empty(); + widths.Add(0, len); + + if (text.empty()) + return true; + + // Set layout's text + const wxCharBuffer dataUTF8 = wxGTK_CONV_FONT(text, m_font); + if ( !dataUTF8 ) + { + // hardly ideal, but what else can we do if conversion failed? + wxLogLastError(wxT("DoGetPartialTextExtents")); + return false; + } + + pango_layout_set_text( m_layout, dataUTF8, strlen(dataUTF8) ); + + // Calculate the position of each character based on the widths of + // the previous characters + + // Code borrowed from Scintilla's PlatGTK + PangoLayoutIter *iter = pango_layout_get_iter(m_layout); + PangoRectangle pos; + pango_layout_iter_get_cluster_extents(iter, NULL, &pos); + size_t i = 0; + while (pango_layout_iter_next_cluster(iter)) + { + pango_layout_iter_get_cluster_extents(iter, NULL, &pos); + int position = PANGO_PIXELS(pos.x); + widths[i++] = position; + } + while (i < len) + widths[i++] = PANGO_PIXELS(pos.x + pos.width); + pango_layout_iter_free(iter); + + return true; } -long wxWindowDC::GetCharWidth() const + +wxCoord wxGTKWindowImplDC::GetCharWidth() const { - GdkFont *font = m_font.GetInternalFont( m_scaleY ); - return long(gdk_string_width( font, "H" ) / m_scaleX); + pango_layout_set_text( m_layout, "H", 1 ); + int w; + pango_layout_get_pixel_size( m_layout, &w, NULL ); + return w; } -long wxWindowDC::GetCharHeight() const +wxCoord wxGTKWindowImplDC::GetCharHeight() const { - GdkFont *font = m_font.GetInternalFont( m_scaleY ); - return long((font->ascent + font->descent) / m_scaleY); + PangoFontMetrics *metrics = pango_context_get_metrics (m_context, m_fontdesc, pango_context_get_language(m_context)); + wxCHECK_MSG( metrics, -1, _T("failed to get pango font metrics") ); + + wxCoord h = PANGO_PIXELS (pango_font_metrics_get_descent (metrics) + + pango_font_metrics_get_ascent (metrics)); + pango_font_metrics_unref (metrics); + return h; } -void wxWindowDC::Clear() +void wxGTKWindowImplDC::Clear() { - wxCHECK_RET( Ok(), T("invalid window dc") ); + wxCHECK_RET( Ok(), wxT("invalid window dc") ); if (!m_window) return; + // 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 @@ -832,9 +1875,7 @@ void wxWindowDC::Clear() if (m_owner) { - int width,height; - m_owner->GetSize( &width, &height ); - gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height ); + m_owner->Clear(); return; } @@ -845,16 +1886,50 @@ void wxWindowDC::Clear() 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 } -void wxWindowDC::SetFont( const wxFont &font ) +void wxGTKWindowImplDC::SetFont( const wxFont &font ) { m_font = font; + + if (m_font.Ok()) + { + if (m_fontdesc) + pango_font_description_free( m_fontdesc ); + + m_fontdesc = pango_font_description_copy( m_font.GetNativeFontInfo()->description ); + + + if (m_owner) + { + PangoContext *oldContext = m_context; + + m_context = m_owner->GtkGetPangoDefaultContext(); + + // If we switch back/forth between different contexts + // we also have to create a new layout. I think so, + // at least, and it doesn't hurt to do it. + if (oldContext != m_context) + { + if (m_layout) + g_object_unref (m_layout); + + m_layout = pango_layout_new( m_context ); + } + } + + pango_layout_set_font_description( m_layout, m_fontdesc ); + } } -void wxWindowDC::SetPen( const wxPen &pen ) +void wxGTKWindowImplDC::SetPen( const wxPen &pen ) { - wxCHECK_RET( Ok(), T("invalid window dc") ); + wxCHECK_RET( Ok(), wxT("invalid window dc") ); if (m_pen == pen) return; @@ -878,17 +1953,23 @@ void wxWindowDC::SetPen( const wxPen &pen ) ( fabs((double) XLOG2DEVREL(width)) + fabs((double) YLOG2DEVREL(width)) ) / 2.0; width = (int)w; + if ( !width ) + { + // width can't be 0 or an internal GTK error occurs inside + // gdk_gc_set_dashes() below + width = 1; + } } - static const char dotted[] = {1, 1}; - static const char short_dashed[] = {2, 2}; - static const char long_dashed[] = {2, 4}; - static const char dotted_dashed[] = {3, 3, 1, 3}; + static const wxGTKDash dotted[] = {1, 1}; + static const wxGTKDash short_dashed[] = {2, 2}; + static const wxGTKDash wxCoord_dashed[] = {2, 4}; + static const wxGTKDash dotted_dashed[] = {3, 3, 1, 3}; // We express dash pattern in pen width unit, so we are // independent of zoom factor and so on... int req_nb_dash; - const char *req_dash; + const wxGTKDash *req_dash; GdkLineStyle lineStyle = GDK_LINE_SOLID; switch (m_pen.GetStyle()) @@ -897,7 +1978,7 @@ void wxWindowDC::SetPen( const wxPen &pen ) { lineStyle = GDK_LINE_ON_OFF_DASH; req_nb_dash = m_pen.GetDashCount(); - req_dash = m_pen.GetDash(); + req_dash = (wxGTKDash*)m_pen.GetDash(); break; } case wxDOT: @@ -911,7 +1992,7 @@ void wxWindowDC::SetPen( const wxPen &pen ) { lineStyle = GDK_LINE_ON_OFF_DASH; req_nb_dash = 2; - req_dash = long_dashed; + req_dash = wxCoord_dashed; break; } case wxSHORT_DASH: @@ -931,21 +2012,21 @@ void wxWindowDC::SetPen( const wxPen &pen ) } case wxTRANSPARENT: + case wxSTIPPLE_MASK_OPAQUE: case wxSTIPPLE: case wxSOLID: default: { lineStyle = GDK_LINE_SOLID; - req_dash = (wxDash*)NULL; + req_dash = (wxGTKDash*)NULL; req_nb_dash = 0; break; } } -#if (GTK_MINOR_VERSION > 0) if (req_dash && req_nb_dash) { - char *real_req_dash = new char[req_nb_dash]; + wxGTKDash *real_req_dash = new wxGTKDash[req_nb_dash]; if (real_req_dash) { for (int i = 0; i < req_nb_dash; i++) @@ -956,25 +2037,38 @@ void wxWindowDC::SetPen( const wxPen &pen ) else { // No Memory. We use non-scaled dash pattern... - gdk_gc_set_dashes( m_penGC, 0, (char*)req_dash, req_nb_dash ); + gdk_gc_set_dashes( m_penGC, 0, (wxGTKDash*)req_dash, req_nb_dash ); } } -#endif GdkCapStyle capStyle = GDK_CAP_ROUND; switch (m_pen.GetCap()) { - case wxCAP_ROUND: { capStyle = (width <= 1) ? GDK_CAP_NOT_LAST : GDK_CAP_ROUND; break; } case wxCAP_PROJECTING: { capStyle = GDK_CAP_PROJECTING; break; } 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; switch (m_pen.GetJoin()) { case wxJOIN_BEVEL: { joinStyle = GDK_JOIN_BEVEL; break; } - case wxJOIN_ROUND: { joinStyle = GDK_JOIN_ROUND; break; } case wxJOIN_MITER: { joinStyle = GDK_JOIN_MITER; break; } + case wxJOIN_ROUND: + default: { joinStyle = GDK_JOIN_ROUND; break; } } gdk_gc_set_line_attributes( m_penGC, width, lineStyle, capStyle, joinStyle ); @@ -983,9 +2077,9 @@ void wxWindowDC::SetPen( const wxPen &pen ) gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() ); } -void wxWindowDC::SetBrush( const wxBrush &brush ) +void wxGTKWindowImplDC::SetBrush( const wxBrush &brush ) { - wxCHECK_RET( Ok(), T("invalid window dc") ); + wxCHECK_RET( Ok(), wxT("invalid window dc") ); if (m_brush == brush) return; @@ -1002,7 +2096,7 @@ void wxWindowDC::SetBrush( const wxBrush &brush ) if ((m_brush.GetStyle() == wxSTIPPLE) && (m_brush.GetStipple()->Ok())) { - if (m_brush.GetStipple()->GetPixmap()) + if (m_brush.GetStipple()->GetDepth() != 1) { gdk_gc_set_fill( m_brushGC, GDK_TILED ); gdk_gc_set_tile( m_brushGC, m_brush.GetStipple()->GetPixmap() ); @@ -1010,11 +2104,17 @@ void wxWindowDC::SetBrush( const wxBrush &brush ) else { gdk_gc_set_fill( m_brushGC, GDK_STIPPLED ); - gdk_gc_set_stipple( m_brushGC, m_brush.GetStipple()->GetBitmap() ); + gdk_gc_set_stipple( m_brushGC, m_brush.GetStipple()->GetPixmap() ); } } - if (IS_HATCH(m_brush.GetStyle())) + if ((m_brush.GetStyle() == wxSTIPPLE_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() ); + } + + if (m_brush.IsHatch()) { gdk_gc_set_fill( m_brushGC, GDK_STIPPLED ); int num = m_brush.GetStyle() - wxBDIAGONAL_HATCH; @@ -1022,12 +2122,12 @@ void wxWindowDC::SetBrush( const wxBrush &brush ) } } -void wxWindowDC::SetBackground( const wxBrush &brush ) +void wxGTKWindowImplDC::SetBackground( const wxBrush &brush ) { /* CMB 21/7/98: Added SetBackground. Sets background brush * for Clear() and bg colour for shapes filled with cross-hatch brush */ - wxCHECK_RET( Ok(), T("invalid window dc") ); + wxCHECK_RET( Ok(), wxT("invalid window dc") ); if (m_backgroundBrush == brush) return; @@ -1047,7 +2147,7 @@ void wxWindowDC::SetBackground( const wxBrush &brush ) if ((m_backgroundBrush.GetStyle() == wxSTIPPLE) && (m_backgroundBrush.GetStipple()->Ok())) { - if (m_backgroundBrush.GetStipple()->GetPixmap()) + if (m_backgroundBrush.GetStipple()->GetDepth() != 1) { gdk_gc_set_fill( m_bgGC, GDK_TILED ); gdk_gc_set_tile( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() ); @@ -1055,11 +2155,11 @@ void wxWindowDC::SetBackground( const wxBrush &brush ) else { gdk_gc_set_fill( m_bgGC, GDK_STIPPLED ); - gdk_gc_set_stipple( m_bgGC, m_backgroundBrush.GetStipple()->GetBitmap() ); + gdk_gc_set_stipple( m_bgGC, m_backgroundBrush.GetStipple()->GetPixmap() ); } } - if (IS_HATCH(m_backgroundBrush.GetStyle())) + if (m_backgroundBrush.IsHatch()) { gdk_gc_set_fill( m_bgGC, GDK_STIPPLED ); int num = m_backgroundBrush.GetStyle() - wxBDIAGONAL_HATCH; @@ -1067,26 +2167,28 @@ void wxWindowDC::SetBackground( const wxBrush &brush ) } } -void wxWindowDC::SetLogicalFunction( int function ) +void wxGTKWindowImplDC::SetLogicalFunction( int function ) { - wxCHECK_RET( Ok(), T("invalid window dc") ); + wxCHECK_RET( Ok(), wxT("invalid window dc") ); + + if (m_logicalFunction == function) + return; - if (m_logicalFunction == function) return; + // VZ: shouldn't this be a CHECK? + if (!m_window) + return; - GdkFunction mode = GDK_COPY; + GdkFunction mode; switch (function) { case wxXOR: mode = GDK_XOR; break; case wxINVERT: mode = GDK_INVERT; break; -#if (GTK_MINOR_VERSION > 0) case wxOR_REVERSE: mode = GDK_OR_REVERSE; break; case wxAND_REVERSE: mode = GDK_AND_REVERSE; break; case wxCLEAR: mode = GDK_CLEAR; break; case wxSET: mode = GDK_SET; break; case wxOR_INVERT: mode = GDK_OR_INVERT; break; - case wxSRC_AND: case wxAND: mode = GDK_AND; break; - case wxSRC_OR: case wxOR: mode = GDK_OR; break; case wxEQUIV: mode = GDK_EQUIV; break; case wxNAND: mode = GDK_NAND; break; @@ -1094,56 +2196,64 @@ void wxWindowDC::SetLogicalFunction( int function ) case wxCOPY: mode = GDK_COPY; break; case wxNO_OP: mode = GDK_NOOP; break; case wxSRC_INVERT: mode = GDK_COPY_INVERT; break; -#endif + + // unsupported by GTK + case wxNOR: mode = GDK_COPY; break; default: - { - wxFAIL_MSG( T("unsupported logical function") ); - break; - } + wxFAIL_MSG( wxT("unsupported logical function") ); + mode = GDK_COPY; } m_logicalFunction = function; - if (!m_window) return; - gdk_gc_set_function( m_penGC, mode ); gdk_gc_set_function( m_brushGC, mode ); + + // to stay compatible with wxMSW, we don't apply ROPs to the text + // operations (i.e. DrawText/DrawRotatedText). + // True, but mono-bitmaps use the m_textGC and they use ROPs as well. gdk_gc_set_function( m_textGC, mode ); } -void wxWindowDC::SetTextForeground( const wxColour &col ) +void wxGTKWindowImplDC::SetTextForeground( const wxColour &col ) { - wxCHECK_RET( Ok(), T("invalid window dc") ); + wxCHECK_RET( Ok(), wxT("invalid window dc") ); - if (m_textForegroundColour == col) return; + // 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) ) + return; m_textForegroundColour = col; - if (!m_textForegroundColour.Ok()) return; - - if (!m_window) return; - m_textForegroundColour.CalcPixel( m_cmap ); - gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() ); + if ( m_window ) + { + m_textForegroundColour.CalcPixel( m_cmap ); + gdk_gc_set_foreground( m_textGC, m_textForegroundColour.GetColor() ); + } } -void wxWindowDC::SetTextBackground( const wxColour &col ) +void wxGTKWindowImplDC::SetTextBackground( const wxColour &col ) { - wxCHECK_RET( Ok(), T("invalid window dc") ); + wxCHECK_RET( Ok(), wxT("invalid window dc") ); - if (m_textBackgroundColour == col) return; + // same as above + if ( !col.Ok() || (m_textBackgroundColour == col) ) + return; m_textBackgroundColour = col; - if (!m_textBackgroundColour.Ok()) return; - - if (!m_window) return; - m_textBackgroundColour.CalcPixel( m_cmap ); - gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() ); + if ( m_window ) + { + m_textBackgroundColour.CalcPixel( m_cmap ); + gdk_gc_set_background( m_textGC, m_textBackgroundColour.GetColor() ); + } } -void wxWindowDC::SetBackgroundMode( int mode ) +void wxGTKWindowImplDC::SetBackgroundMode( int mode ) { - wxCHECK_RET( Ok(), T("invalid window dc") ); + wxCHECK_RET( Ok(), wxT("invalid window dc") ); m_backgroundMode = mode; @@ -1159,33 +2269,51 @@ void wxWindowDC::SetBackgroundMode( int mode ) } } -void wxWindowDC::SetPalette( const wxPalette& WXUNUSED(palette) ) +void wxGTKWindowImplDC::SetPalette( const wxPalette& WXUNUSED(palette) ) { - wxFAIL_MSG( T("wxWindowDC::SetPalette not implemented") ); + wxFAIL_MSG( wxT("wxGTKWindowImplDC::SetPalette not implemented") ); } -void wxWindowDC::DoSetClippingRegion( long x, long y, long width, long height ) +void wxGTKWindowImplDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) { - wxCHECK_RET( Ok(), T("invalid window dc") ); - - wxDC::DoSetClippingRegion( x, y, width, height ); + wxCHECK_RET( Ok(), wxT("invalid window dc") ); if (!m_window) return; - GdkRectangle rect; + wxRect rect; rect.x = XLOG2DEV(x); rect.y = YLOG2DEV(y); rect.width = XLOG2DEVREL(width); rect.height = YLOG2DEVREL(height); - gdk_gc_set_clip_rectangle( m_penGC, &rect ); - gdk_gc_set_clip_rectangle( m_brushGC, &rect ); - gdk_gc_set_clip_rectangle( m_textGC, &rect ); - gdk_gc_set_clip_rectangle( m_bgGC, &rect ); + + if (m_owner && m_owner->m_wxwindow && (m_owner->GetLayoutDirection() == wxLayout_RightToLeft)) + { + rect.x -= rect.width; + } + + if (!m_currentClippingRegion.IsNull()) + m_currentClippingRegion.Intersect( rect ); + else + 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() ); } -void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion ®ion ) +void wxGTKWindowImplDC::DoSetClippingRegionAsRegion( const wxRegion ®ion ) { - wxCHECK_RET( Ok(), T("invalid window dc") ); + wxCHECK_RET( Ok(), wxT("invalid window dc") ); if (region.Empty()) { @@ -1195,321 +2323,227 @@ void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion ®ion ) if (!m_window) return; - gdk_gc_set_clip_region( m_penGC, region.GetRegion() ); - gdk_gc_set_clip_region( m_brushGC, region.GetRegion() ); - gdk_gc_set_clip_region( m_textGC, region.GetRegion() ); - gdk_gc_set_clip_region( m_bgGC, region.GetRegion() ); + if (!m_currentClippingRegion.IsNull()) + m_currentClippingRegion.Intersect( region ); + else + m_currentClippingRegion.Union( region ); + +#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() ); } -void wxWindowDC::DestroyClippingRegion() +void wxGTKWindowImplDC::DestroyClippingRegion() { - wxCHECK_RET( Ok(), T("invalid window dc") ); + wxCHECK_RET( Ok(), wxT("invalid window dc") ); wxDC::DestroyClippingRegion(); - if (!m_window) return; - - 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 ); -} + m_currentClippingRegion.Clear(); -void wxWindowDC::SetUpDC() -{ - Destroy(); - m_ok = TRUE; - m_logicalFunction = wxCOPY; - m_penGC = gdk_gc_new( m_window ); - m_brushGC = gdk_gc_new( m_window ); - m_textGC = gdk_gc_new( m_window ); - m_bgGC = gdk_gc_new( m_window ); - - wxColour tmp_col( m_textForegroundColour ); - m_textForegroundColour = wxNullColour; - SetTextForeground( tmp_col ); - tmp_col = m_textBackgroundColour; - m_textBackgroundColour = wxNullColour; - SetTextBackground( tmp_col ); - - wxPen tmp_pen( m_pen ); - m_pen = wxNullPen; - SetPen( tmp_pen ); - - wxFont tmp_font( m_font ); - m_font = wxNullFont; - SetFont( tmp_font ); - - wxBrush tmp_brush( m_brush ); - m_brush = wxNullBrush; - SetBrush( tmp_brush ); +#if USE_PAINT_REGION + if (!m_paintClippingRegion.IsEmpty()) + m_currentClippingRegion.Union( m_paintClippingRegion ); +#endif -/* - tmp_brush = m_backgroundBrush; - m_backgroundBrush = wxNullBrush; - SetBackground( tmp_brush ); -*/ - tmp_brush = m_backgroundBrush; - m_backgroundBrush = wxNullBrush; - SetBackground( *wxWHITE_BRUSH ); - m_backgroundBrush = tmp_brush; + if (!m_window) return; - if (!hatch_bitmap) + if (m_currentClippingRegion.IsEmpty()) { - 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, (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() ); } } -void wxWindowDC::Destroy() +void wxGTKWindowImplDC::Destroy() { - if (m_penGC) gdk_gc_unref( m_penGC ); + if (m_penGC) wxFreePoolGC( m_penGC ); m_penGC = (GdkGC*) NULL; - if (m_brushGC) gdk_gc_unref( m_brushGC ); + if (m_brushGC) wxFreePoolGC( m_brushGC ); m_brushGC = (GdkGC*) NULL; - if (m_textGC) gdk_gc_unref( m_textGC ); + if (m_textGC) wxFreePoolGC( m_textGC ); m_textGC = (GdkGC*) NULL; - if (m_bgGC) gdk_gc_unref( m_bgGC ); + if (m_bgGC) wxFreePoolGC( m_bgGC ); m_bgGC = (GdkGC*) NULL; } -void wxWindowDC::ComputeScaleAndOrigin() +void wxGTKWindowImplDC::SetDeviceOrigin( wxCoord x, wxCoord y ) { - /* CMB: copy scale to see if it changes */ - double origScaleX = m_scaleX; - double origScaleY = m_scaleY; - - wxDC::ComputeScaleAndOrigin(); + m_deviceOriginX = x; + m_deviceOriginY = y; - /* CMB: if scale has changed call SetPen to recalulate the line width */ - if ((m_scaleX != origScaleX || m_scaleY != origScaleY) && - (m_pen.Ok())) - { - /* this is a bit artificial, but we need to force wxDC to think - the pen has changed */ - wxPen pen = m_pen; - m_pen = wxNullPen; - SetPen( pen ); - } + ComputeScaleAndOrigin(); } -// Resolution in pixels per logical inch -wxSize wxWindowDC::GetPPI() const +void wxGTKWindowImplDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp ) { - return wxSize(100, 100); -} + m_signX = (xLeftRight ? 1 : -1); + m_signY = (yBottomUp ? -1 : 1); -int wxWindowDC::GetDepth() const -{ - wxFAIL_MSG(T("not implemented")); + if (m_owner && m_owner->m_wxwindow && (m_owner->GetLayoutDirection() == wxLayout_RightToLeft)) + m_signX = -m_signX; - return -1; + ComputeScaleAndOrigin(); } -#if wxUSE_SPLINES -// ----------------------------------- spline code ---------------------------------------- - -void wx_quadratic_spline(double a1, double b1, double a2, double b2, - double a3, double b3, double a4, double b4); -void wx_clear_stack(); -int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3, - double *y3, double *x4, double *y4); -void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, - double x4, double y4); -static bool wx_spline_add_point(double x, double y); -static void wx_spline_draw_point_array(wxDC *dc); - -wxList wx_spline_point_list; - -#define half(z1, z2) ((z1+z2)/2.0) -#define THRESHOLD 5 +void wxGTKWindowImplDC::ComputeScaleAndOrigin() +{ + const wxRealPoint origScale(m_scaleX, m_scaleY); -/* iterative version */ + wxDC::ComputeScaleAndOrigin(); -void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4, - double b4) -{ - register double xmid, ymid; - double x1, y1, x2, y2, x3, y3, x4, y4; - - wx_clear_stack(); - wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4); - - while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) { - xmid = (double)half(x2, x3); - ymid = (double)half(y2, y3); - if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD && - fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) { - wx_spline_add_point( x1, y1 ); - wx_spline_add_point( xmid, ymid ); - } else { - wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3), - (double)half(x3, x4), (double)half(y3, y4), x4, y4); - wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2), - (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid); - } + // if scale has changed call SetPen to recalulate the line width + if ( wxRealPoint(m_scaleX, m_scaleY) != origScale && m_pen.Ok() ) + { + // this is a bit artificial, but we need to force wxDC to think the pen + // has changed + wxPen pen = m_pen; + m_pen = wxNullPen; + SetPen( pen ); } } -/* utilities used by spline drawing routines */ - -typedef struct wx_spline_stack_struct { - double x1, y1, x2, y2, x3, y3, x4, y4; -} Stack; - -#define SPLINE_STACK_DEPTH 20 -static Stack wx_spline_stack[SPLINE_STACK_DEPTH]; -static Stack *wx_stack_top; -static int wx_stack_count; - -void wx_clear_stack() +// Resolution in pixels per logical inch +wxSize wxGTKWindowImplDC::GetPPI() const { - wx_stack_top = wx_spline_stack; - wx_stack_count = 0; + return wxSize( (int) (m_mm_to_pix_x * 25.4 + 0.5), (int) (m_mm_to_pix_y * 25.4 + 0.5)); } -void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) +int wxGTKWindowImplDC::GetDepth() const { - wx_stack_top->x1 = x1; - wx_stack_top->y1 = y1; - wx_stack_top->x2 = x2; - wx_stack_top->y2 = y2; - wx_stack_top->x3 = x3; - wx_stack_top->y3 = y3; - wx_stack_top->x4 = x4; - wx_stack_top->y4 = y4; - wx_stack_top++; - wx_stack_count++; + return gdk_drawable_get_depth(m_window); } -int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, - double *x3, double *y3, double *x4, double *y4) -{ - if (wx_stack_count == 0) - return (0); - wx_stack_top--; - wx_stack_count--; - *x1 = wx_stack_top->x1; - *y1 = wx_stack_top->y1; - *x2 = wx_stack_top->x2; - *y2 = wx_stack_top->y2; - *x3 = wx_stack_top->x3; - *y3 = wx_stack_top->y3; - *x4 = wx_stack_top->x4; - *y4 = wx_stack_top->y4; - return (1); -} -static bool wx_spline_add_point(double x, double y) -{ - wxPoint *point = new wxPoint ; - point->x = (int) x; - point->y = (int) y; - wx_spline_point_list.Append((wxObject*)point); - return TRUE; -} +//----------------------------------------------------------------------------- +// wxPaintDC +//----------------------------------------------------------------------------- -static void wx_spline_draw_point_array(wxDC *dc) +#if wxUSE_NEW_DC +IMPLEMENT_DYNAMIC_CLASS(wxGTKPaintImplDC, wxGTKClientImplDC) +#else +IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxClientDC) +#endif + +// Limit the paint region to the window size. Sometimes +// the paint region is too big, and this risks X11 errors +static void wxLimitRegionToSize(wxRegion& region, const wxSize& sz) { - dc->DrawLines(&wx_spline_point_list, 0, 0 ); - wxNode *node = wx_spline_point_list.First(); - while (node) - { - wxPoint *point = (wxPoint *)node->Data(); - delete point; - delete node; - node = wx_spline_point_list.First(); - } + wxRect originalRect = region.GetBox(); + wxRect rect(originalRect); + if (rect.width + rect.x > sz.x) + rect.width = sz.x - rect.x; + if (rect.height + rect.y > sz.y) + rect.height = sz.y - rect.y; + if (rect != originalRect) + { + region = wxRegion(rect); + wxLogTrace(wxT("painting"), wxT("Limiting region from %d, %d, %d, %d to %d, %d, %d, %d\n"), + originalRect.x, originalRect.y, originalRect.width, originalRect.height, + rect.x, rect.y, rect.width, rect.height); + } } -void wxWindowDC::DoDrawSpline( wxList *points ) +wxGTKPaintImplDC::wxGTKPaintImplDC( wxWindow *win ) + : wxGTKClientImplDC( win ) { - wxCHECK_RET( Ok(), T("invalid window dc") ); - - wxPoint *p; - double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4; - double x1, y1, x2, y2; - - wxNode *node = points->First(); - p = (wxPoint *)node->Data(); - - x1 = p->x; - y1 = p->y; - - node = node->Next(); - p = (wxPoint *)node->Data(); - - x2 = p->x; - y2 = p->y; - cx1 = (double)((x1 + x2) / 2); - cy1 = (double)((y1 + y2) / 2); - cx2 = (double)((cx1 + x2) / 2); - cy2 = (double)((cy1 + y2) / 2); +#if USE_PAINT_REGION + if (!win->m_clipPaintRegion) + return; - wx_spline_add_point(x1, y1); + wxSize sz = win->GetSize(); + m_paintClippingRegion = win->m_nativeUpdateRegion; + wxLimitRegionToSize(m_paintClippingRegion, sz); - while ((node = node->Next()) != NULL) + GdkRegion *region = m_paintClippingRegion.GetRegion(); + if ( region ) { - p = (wxPoint *)node->Data(); - x1 = x2; - y1 = y2; - x2 = p->x; - y2 = p->y; - cx4 = (double)(x1 + x2) / 2; - cy4 = (double)(y1 + y2) / 2; - cx3 = (double)(x1 + cx4) / 2; - cy3 = (double)(y1 + cy4) / 2; + m_currentClippingRegion.Union( m_paintClippingRegion ); + wxLimitRegionToSize(m_currentClippingRegion, sz); - wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4); + if (sz.x <= 0 || sz.y <= 0) + return ; - cx1 = cx4; - cy1 = cy4; - cx2 = (double)(cx1 + x2) / 2; - cy2 = (double)(cy1 + y2) / 2; + gdk_gc_set_clip_region( m_penGC, region ); + gdk_gc_set_clip_region( m_brushGC, region ); + gdk_gc_set_clip_region( m_textGC, region ); + gdk_gc_set_clip_region( m_bgGC, region ); } - - wx_spline_add_point( cx1, cy1 ); - wx_spline_add_point( x2, y2 ); - - wx_spline_draw_point_array( this ); +#endif // USE_PAINT_REGION } -#endif // wxUSE_SPLINE - //----------------------------------------------------------------------------- -// wxPaintDC +// wxClientDC //----------------------------------------------------------------------------- -IMPLEMENT_DYNAMIC_CLASS(wxPaintDC,wxWindowDC) +#if wxUSE_NEW_DC +IMPLEMENT_DYNAMIC_CLASS(wxGTKClientImplDC, wxGTKWindowImplDC) +#else +IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC) +#endif -wxPaintDC::wxPaintDC() - : wxWindowDC() +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__ } -wxPaintDC::wxPaintDC( wxWindow *win ) - : wxWindowDC( win ) +void wxGTKClientImplDC::DoGetSize(int *width, int *height) const { + wxCHECK_RET( m_owner, _T("GetSize() doesn't work without window") ); + + m_owner->GetClientSize( width, height ); } -//----------------------------------------------------------------------------- -// wxClientDC -//----------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- +// wxDCModule +// ---------------------------------------------------------------------------- -IMPLEMENT_DYNAMIC_CLASS(wxClientDC,wxWindowDC) +class wxDCModule : public wxModule +{ +public: + bool OnInit(); + void OnExit(); + +private: + DECLARE_DYNAMIC_CLASS(wxDCModule) +}; -wxClientDC::wxClientDC() - : wxWindowDC() +IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule) + +bool wxDCModule::OnInit() { + wxInitGCPool(); + return true; } -wxClientDC::wxClientDC( wxWindow *win ) - : wxWindowDC( win ) +void wxDCModule::OnExit() { + wxCleanUpGCPool(); } -