X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/a1e101d0561ec98f807f176c5c3b2383ecbd9349..ac0c512d865e6236fc81882cb84cc38d09f8f0ec:/src/gtk/dcclient.cpp?ds=sidebyside diff --git a/src/gtk/dcclient.cpp b/src/gtk/dcclient.cpp index 94df22e7d9..2edcb8c804 100644 --- a/src/gtk/dcclient.cpp +++ b/src/gtk/dcclient.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: gtk/dcclient.cpp +// Name: src/gtk/dcclient.cpp // Purpose: // Author: Robert Roebling // RCS-ID: $Id$ @@ -7,10 +7,6 @@ // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) -#pragma implementation "dcclient.h" -#endif - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -19,25 +15,33 @@ #endif #include "wx/dcclient.h" -#include "wx/dcmemory.h" -#include "wx/image.h" -#include "wx/module.h" -#include "wx/log.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 // for floating-point functions - -#include #include -#include -#include //----------------------------------------------------------------------------- // local defines //----------------------------------------------------------------------------- +#define XLOG2DEV(x) LogicalToDeviceX(x) +#define XLOG2DEVREL(x) LogicalToDeviceXRel(x) +#define YLOG2DEV(y) LogicalToDeviceY(y) +#define YLOG2DEVREL(y) LogicalToDeviceYRel(y) + #define USE_PAINT_REGION 1 //----------------------------------------------------------------------------- @@ -82,6 +86,7 @@ static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; } #include "gdk/gdkprivate.h" +static void gdk_wx_draw_bitmap(GdkDrawable *drawable, GdkGC *gc, GdkDrawable *src, @@ -92,11 +97,10 @@ void gdk_wx_draw_bitmap(GdkDrawable *drawable, gint width, gint height) { - g_return_if_fail (drawable != NULL); - g_return_if_fail (src != NULL); - g_return_if_fail (gc != NULL); - -#ifdef __WXGTK20__ + 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; @@ -110,41 +114,12 @@ void gdk_wx_draw_bitmap(GdkDrawable *drawable, width, height, 0, 0, 1 ); -#else - GdkWindowPrivate *drawable_private; - GdkWindowPrivate *src_private; - GdkGCPrivate *gc_private; - - drawable_private = (GdkWindowPrivate*) drawable; - src_private = (GdkWindowPrivate*) src; - if (drawable_private->destroyed || src_private->destroyed) - return; - - gint src_width = src_private->width; - gint src_height = src_private->height; - - gc_private = (GdkGCPrivate*) gc; - - if (width == -1) width = src_width; - if (height == -1) height = src_height; - - XCopyPlane( drawable_private->xdisplay, - src_private->xwindow, - drawable_private->xwindow, - gc_private->xgc, - xsrc, ysrc, - width, height, - xdest, ydest, - 1 ); -#endif } //----------------------------------------------------------------------------- // Implement Pool of Graphic contexts. Creating them takes too much time. //----------------------------------------------------------------------------- -#define GC_POOL_SIZE 200 - enum wxPoolGCType { wxGC_ERROR = 0, @@ -180,10 +155,10 @@ static void wxInitGCPool() // This really could wait until the first call to // wxGetPoolGC, but we will make the first allocation // now when other initialization is being performed. - + // Set initial pool size. wxGCPoolSize = GC_POOL_ALLOC_SIZE; - + // Allocate initial pool. wxGCPool = (wxGC *)malloc(wxGCPoolSize * sizeof(wxGC)); if (wxGCPool == NULL) @@ -195,7 +170,7 @@ static void wxInitGCPool() wxFAIL_MSG( wxT("Cannot allocate GC pool") ); return; } - + // Zero initial pool. memset(wxGCPool, 0, wxGCPoolSize * sizeof(wxGC)); } @@ -205,7 +180,7 @@ static void wxCleanUpGCPool() for (int i = 0; i < wxGCPoolSize; i++) { if (wxGCPool[i].m_gc) - gdk_gc_unref( wxGCPool[i].m_gc ); + g_object_unref (wxGCPool[i].m_gc); } free(wxGCPool); @@ -216,7 +191,7 @@ static void wxCleanUpGCPool() static GdkGC* wxGetPoolGC( GdkWindow *window, wxPoolGCType type ) { wxGC *pptr; - + // Look for an available GC. for (int i = 0; i < wxGCPoolSize; i++) { @@ -225,11 +200,11 @@ static GdkGC* wxGetPoolGC( GdkWindow *window, wxPoolGCType type ) 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; + wxGCPool[i].m_used = false; } if ((!wxGCPool[i].m_used) && (wxGCPool[i].m_type == type)) { - wxGCPool[i].m_used = TRUE; + wxGCPool[i].m_used = true; return wxGCPool[i].m_gc; } } @@ -244,20 +219,20 @@ static GdkGC* wxGetPoolGC( GdkWindow *window, wxPoolGCType type ) wxGCPool = pptr; memset(&wxGCPool[wxGCPoolSize], 0, GC_POOL_ALLOC_SIZE*sizeof(wxGC)); - - // Initialize entry we will return. + + // 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; - + 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") ); @@ -270,7 +245,7 @@ static void wxFreePoolGC( GdkGC *gc ) { if (wxGCPool[i].m_gc == gc) { - wxGCPool[i].m_used = FALSE; + wxGCPool[i].m_used = false; return; } } @@ -282,26 +257,37 @@ static void wxFreePoolGC( GdkGC *gc ) // wxWindowDC //----------------------------------------------------------------------------- -IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC) +#if wxUSE_NEW_DC +IMPLEMENT_ABSTRACT_CLASS(wxGTKWindowImplDC, wxGTKImplDC) +#else +IMPLEMENT_ABSTRACT_CLASS(wxWindowDC, wxDC) +#endif +#if wxUSE_NEW_DC +wxGTKWindowImplDC::wxGTKWindowImplDC( wxDC *owner ) : + wxGTKImplDC( owner ) +#else wxWindowDC::wxWindowDC() +#endif { m_penGC = (GdkGC *) NULL; m_brushGC = (GdkGC *) NULL; m_textGC = (GdkGC *) NULL; m_bgGC = (GdkGC *) NULL; m_cmap = (GdkColormap *) NULL; - m_isMemDC = FALSE; - m_isScreenDC = FALSE; - m_owner = (wxWindow *)NULL; -#ifdef __WXGTK20__ + m_isScreenDC = false; + m_owningWindow = (wxWindow *)NULL; m_context = (PangoContext *)NULL; m_layout = (PangoLayout *)NULL; m_fontdesc = (PangoFontDescription *)NULL; -#endif } +#if wxUSE_NEW_DC +wxGTKWindowImplDC::wxGTKWindowImplDC( wxDC *owner, wxWindow *window ) : + wxGTKImplDC( owner ) +#else wxWindowDC::wxWindowDC( wxWindow *window ) +#endif { wxASSERT_MSG( window, wxT("DC needs a window") ); @@ -310,9 +296,8 @@ wxWindowDC::wxWindowDC( wxWindow *window ) m_textGC = (GdkGC *) NULL; m_bgGC = (GdkGC *) NULL; m_cmap = (GdkColormap *) NULL; - m_owner = (wxWindow *)NULL; - m_isMemDC = FALSE; - m_isScreenDC = FALSE; + m_owningWindow = (wxWindow *)NULL; + m_isScreenDC = false; m_font = window->GetFont(); GtkWidget *widget = window->m_wxwindow; @@ -328,11 +313,9 @@ wxWindowDC::wxWindowDC( wxWindow *window ) wxASSERT_MSG( widget, wxT("DC needs a widget") ); -#ifdef __WXGTK20__ m_context = window->GtkGetPangoDefaultContext(); m_layout = pango_layout_new( m_context ); m_fontdesc = pango_font_description_copy( widget->style->font_desc ); -#endif GtkPizza *pizza = GTK_PIZZA( widget ); m_window = pizza->bin_window; @@ -341,7 +324,7 @@ wxWindowDC::wxWindowDC( wxWindow *window ) if (!m_window) { // Don't report problems as per MSW. - m_ok = TRUE; + m_ok = true; return; } @@ -357,54 +340,76 @@ wxWindowDC::wxWindowDC( wxWindow *window ) is white whereas a window might assume gray to be the standard (as e.g. wxStatusBar) */ - m_owner = window; + m_owningWindow = window; + + if (m_owningWindow && m_owningWindow->m_wxwindow && + (m_owningWindow->GetLayoutDirection() == wxLayout_RightToLeft)) + { + // reverse sense + m_signX = -1; + + // origin in the upper right corner + m_deviceOriginX = m_owningWindow->GetClientSize().x; + } } -wxWindowDC::~wxWindowDC() +wxGTKWindowImplDC::~wxGTKWindowImplDC() { Destroy(); - -#ifdef __WXGTK20__ + if (m_layout) - g_object_unref( G_OBJECT( m_layout ) ); + g_object_unref (m_layout); if (m_fontdesc) pango_font_description_free( m_fontdesc ); -#endif } -void wxWindowDC::SetUpDC() +void wxGTKWindowImplDC::SetUpDC( bool isMemDC ) { - m_ok = TRUE; + m_ok = true; wxASSERT_MSG( !m_penGC, wxT("GCs already created") ); - if (m_isScreenDC) - { - m_penGC = wxGetPoolGC( m_window, wxPEN_SCREEN ); - m_brushGC = wxGetPoolGC( m_window, wxBRUSH_SCREEN ); - m_textGC = wxGetPoolGC( m_window, wxTEXT_SCREEN ); - m_bgGC = wxGetPoolGC( m_window, wxBG_SCREEN ); - } - else - if (m_isMemDC && (((wxMemoryDC*)this)->m_selected.GetDepth() == 1)) + bool done = false; + + if (isMemDC) { - 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 ); + wxGTKMemoryImplDC *mem_dc = (wxGTKMemoryImplDC*) this; + if (mem_dc->GetSelectedBitmap().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 ); + done = true; + } } - 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 ); + + if (!done) + { + 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 + { + 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 ); - GdkColor *bg_col = m_backgroundBrush.GetColour().GetColor(); +#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 ); @@ -415,6 +420,8 @@ void wxWindowDC::SetUpDC() gdk_gc_set_fill( m_textGC, GDK_SOLID ); + gdk_gc_set_colormap( m_textGC, m_cmap ); + /* m_penGC */ m_pen.GetColour().CalcPixel( m_cmap ); gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() ); @@ -458,24 +465,29 @@ void wxWindowDC::SetUpDC() } } -void wxWindowDC::DoGetSize( int* width, int* height ) const +void wxGTKWindowImplDC::DoGetSize( int* width, int* height ) const { - wxCHECK_RET( m_owner, _T("GetSize() doesn't work without window") ); + wxCHECK_RET( m_owningWindow, _T("GetSize() doesn't work without window") ); - m_owner->GetSize(width, height); + m_owningWindow->GetSize(width, height); } -extern bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y, - const wxColour & col, int style); - -bool wxWindowDC::DoFloodFill(wxCoord x, wxCoord y, +bool wxGTKWindowImplDC::DoFloodFill(wxCoord x, wxCoord y, const wxColour& col, int style) { - return wxDoFloodFill(this, x, y, col, style); +#if wxUSE_IMAGE + extern bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y, + const wxColour & col, int style); + + return wxDoFloodFill( GetOwner(), x, y, col, style); +#else + return false; +#endif } -bool wxWindowDC::DoGetPixel( wxCoord x1, wxCoord y1, wxColour *col ) const +bool wxGTKWindowImplDC::DoGetPixel( wxCoord x1, wxCoord y1, wxColour *col ) const { +#if wxUSE_IMAGE // Generic (and therefore rather inefficient) method. // Could be improved. wxMemoryDC memdc; @@ -486,12 +498,15 @@ bool wxWindowDC::DoGetPixel( wxCoord x1, wxCoord y1, wxColour *col ) const wxImage image = bitmap.ConvertToImage(); col->Set(image.GetRed(0, 0), image.GetGreen(0, 0), image.GetBlue(0, 0)); - return TRUE; + return true; +#else // !wxUSE_IMAGE + return false; +#endif // wxUSE_IMAGE/!wxUSE_IMAGE } -void wxWindowDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 ) +void wxGTKWindowImplDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); if (m_pen.GetStyle() != wxTRANSPARENT) { @@ -503,15 +518,15 @@ void wxWindowDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 ) } } -void wxWindowDC::DoCrossHair( wxCoord x, wxCoord y ) +void wxGTKWindowImplDC::DoCrossHair( wxCoord x, wxCoord y ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); if (m_pen.GetStyle() != wxTRANSPARENT) { int w = 0; int h = 0; - GetSize( &w, &h ); + GetOwner()->GetSize( &w, &h ); wxCoord xx = XLOG2DEV(x); wxCoord yy = YLOG2DEV(y); if (m_window) @@ -522,10 +537,10 @@ void wxWindowDC::DoCrossHair( wxCoord x, wxCoord y ) } } -void wxWindowDC::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, +void wxGTKWindowImplDC::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord xc, wxCoord yc ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); wxCoord xx1 = XLOG2DEV(x1); wxCoord yy1 = YLOG2DEV(y1); @@ -544,10 +559,10 @@ void wxWindowDC::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord 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 { @@ -605,8 +620,11 @@ void wxWindowDC::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, { gdk_draw_arc( m_window, m_penGC, FALSE, xxc-r, yyc-r, 2*r,2*r, alpha1, alpha2 ); - gdk_draw_line( m_window, m_penGC, xx1, yy1, xxc, yyc ); - gdk_draw_line( m_window, m_penGC, xxc, yyc, xx2, yy2 ); + if ((m_brush.GetStyle() != wxTRANSPARENT) && (alpha2 - alpha1 != 360*64)) + { + gdk_draw_line( m_window, m_penGC, xx1, yy1, xxc, yyc ); + gdk_draw_line( m_window, m_penGC, xxc, yyc, xx2, yy2 ); + } } } @@ -614,9 +632,9 @@ void wxWindowDC::DoDrawArc( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, CalcBoundingBox (x2, y2); } -void wxWindowDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double sa, double ea ) +void wxGTKWindowImplDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double sa, double ea ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); wxCoord xx = XLOG2DEV(x); wxCoord yy = YLOG2DEV(y); @@ -676,9 +694,9 @@ void wxWindowDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord width, wxCoord CalcBoundingBox (x + width, y + height); } -void wxWindowDC::DoDrawPoint( wxCoord x, wxCoord y ) +void wxGTKWindowImplDC::DoDrawPoint( wxCoord x, wxCoord y ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); if ((m_pen.GetStyle() != wxTRANSPARENT) && m_window) gdk_draw_point( m_window, m_penGC, XLOG2DEV(x), YLOG2DEV(y) ); @@ -686,51 +704,65 @@ void wxWindowDC::DoDrawPoint( wxCoord x, wxCoord y ) CalcBoundingBox (x, y); } -void wxWindowDC::DoDrawLines( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset ) +void wxGTKWindowImplDC::DoDrawLines( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); if (m_pen.GetStyle() == wxTRANSPARENT) return; if (n <= 0) return; - GdkPoint *gpts = new GdkPoint[n]; - if (! gpts) - { - wxFAIL_MSG( wxT("Cannot allocate PolyLine") ); - return; - } + //Check, if scaling is necessary + const bool doScale = + xoffset != 0 || yoffset != 0 || XLOG2DEV(10) != 10 || YLOG2DEV(10) != 10; - for (int i = 0; i < n; i++) - { - wxCoord x1 = XLOG2DEV(points[i].x + xoffset); - wxCoord y1 = YLOG2DEV(points[i].y + yoffset); + // GdkPoint and wxPoint have the same memory layout, so we can cast one to the other + GdkPoint* gpts = reinterpret_cast(points); - CalcBoundingBox( x1 + xoffset, y1 + yoffset ); + if (doScale) + gpts = new GdkPoint[n]; - gpts[i].x = x1; - gpts[i].y = y1; + 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); - delete[] gpts; + if (doScale) + delete[] gpts; } -void wxWindowDC::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, int WXUNUSED(fillStyle) ) +void wxGTKWindowImplDC::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, int WXUNUSED(fillStyle) ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), 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_window) @@ -784,16 +816,17 @@ void wxWindowDC::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wxCoor } */ gdk_draw_polygon( m_window, m_penGC, FALSE, gdkpoints, n ); - + } } - delete[] gdkpoints; + if (doScale) + delete[] gdkpoints; } -void wxWindowDC::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) +void wxGTKWindowImplDC::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); wxCoord xx = XLOG2DEV(x); wxCoord yy = YLOG2DEV(y); @@ -846,16 +879,45 @@ void wxWindowDC::DoDrawRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord h } if (m_pen.GetStyle() != wxTRANSPARENT) - gdk_draw_rectangle( m_window, m_penGC, FALSE, xx, yy, ww-1, hh-1 ); + { +#if 1 + if ((m_pen.GetWidth() == 2) && (m_pen.GetCap() == wxCAP_ROUND) && + (m_pen.GetJoin() == wxJOIN_ROUND) && (m_pen.GetStyle() == wxSOLID)) + { + // Use 2 1-line rects instead + gdk_gc_set_line_attributes( m_penGC, 1, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND ); + + if (m_signX == -1) + { + // Different for RTL + gdk_draw_rectangle( m_window, m_penGC, FALSE, xx+1, yy, ww-2, hh-2 ); + gdk_draw_rectangle( m_window, m_penGC, FALSE, xx, yy-1, ww, hh ); + } + else + { + gdk_draw_rectangle( m_window, m_penGC, FALSE, xx, yy, ww-2, hh-2 ); + gdk_draw_rectangle( m_window, m_penGC, FALSE, xx-1, yy-1, ww, hh ); + } + + // reset + gdk_gc_set_line_attributes( m_penGC, 2, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_ROUND ); + } + else +#endif + { + // Just use X11 for other cases + gdk_draw_rectangle( m_window, m_penGC, FALSE, xx, yy, ww-1, hh-1 ); + } + } } CalcBoundingBox( x, y ); CalcBoundingBox( x + width, y + height ); } -void wxWindowDC::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius ) +void wxGTKWindowImplDC::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); if (radius < 0.0) radius = - radius * ((width < height) ? width : height); @@ -873,7 +935,7 @@ void wxWindowDC::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord width, wx // X drawing errors with small radii if (rr == 0) { - DrawRectangle( x, y, width, height ); + DoDrawRectangle( x, y, width, height ); return; } @@ -976,9 +1038,9 @@ void wxWindowDC::DoDrawRoundedRectangle( wxCoord x, wxCoord y, wxCoord width, wx CalcBoundingBox( x + width, y + height ); } -void wxWindowDC::DoDrawEllipse( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) +void wxGTKWindowImplDC::DoDrawEllipse( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); wxCoord xx = XLOG2DEV(x); wxCoord yy = YLOG2DEV(y); @@ -1035,21 +1097,21 @@ void wxWindowDC::DoDrawEllipse( wxCoord x, wxCoord y, wxCoord width, wxCoord hei CalcBoundingBox( x + width, y + height ); } -void wxWindowDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y ) +void wxGTKWindowImplDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y ) { // VZ: egcs 1.0.3 refuses to compile this without cast, no idea why - DoDrawBitmap( (const wxBitmap&)icon, x, y, (bool)TRUE ); + DoDrawBitmap( (const wxBitmap&)icon, x, y, true ); } -void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap, +void wxGTKWindowImplDC::DoDrawBitmap( const wxBitmap &bitmap, wxCoord x, wxCoord y, bool useMask ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); - wxCHECK_RET( bitmap.Ok(), wxT("invalid bitmap") ); + wxCHECK_RET( bitmap.IsOk(), wxT("invalid bitmap") ); - bool is_mono = (bitmap.GetBitmap() != NULL); + bool is_mono = bitmap.GetDepth() == 1; // scale/translate size and position int xx = XLOG2DEV(x); @@ -1058,6 +1120,9 @@ void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap, int w = bitmap.GetWidth(); int h = bitmap.GetHeight(); + if (m_owningWindow && m_owningWindow->GetLayoutDirection() == wxLayout_RightToLeft) + xx -= w; + CalcBoundingBox( x, y ); CalcBoundingBox( x + w, y + h ); @@ -1075,18 +1140,28 @@ void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap, return; } - // scale bitmap if required + // 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 (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap(); + if (useMask && use_bitmap.GetMask()) + mask = use_bitmap.GetMask()->GetBitmap(); + + GdkGC* use_gc = is_mono ? m_textGC : m_penGC; GdkBitmap *new_mask = (GdkBitmap*) NULL; - - if (useMask && mask) + + if (mask != NULL) { if (!m_currentClippingRegion.IsNull()) { @@ -1105,75 +1180,61 @@ void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap, gdk_gc_set_fill( gc, GDK_OPAQUE_STIPPLED ); gdk_gc_set_stipple( gc, mask ); gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, ww, hh ); - gdk_gc_unref( gc ); - } - - if (is_mono) - { - if (new_mask) - gdk_gc_set_clip_mask( m_textGC, new_mask ); - else - gdk_gc_set_clip_mask( m_textGC, mask ); - gdk_gc_set_clip_origin( m_textGC, xx, yy ); - } - else - { - if (new_mask) - gdk_gc_set_clip_mask( m_penGC, new_mask ); - else - gdk_gc_set_clip_mask( m_penGC, mask ); - gdk_gc_set_clip_origin( m_penGC, xx, yy ); + mask = new_mask; + g_object_unref (gc); } + + 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) { -#ifdef __WXGTK20__ - GdkPixmap *bitmap = gdk_pixmap_new( wxGetRootWindow()->window, ww, hh, -1 ); - GdkGC *gc = gdk_gc_new( bitmap ); + 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( bitmap, gc, use_bitmap.GetBitmap(), 0, 0, 0, 0, -1, -1 ); - - gdk_draw_drawable( m_window, m_textGC, bitmap, 0, 0, xx, yy, -1, -1 ); - - gdk_bitmap_unref( bitmap ); - gdk_gc_unref( gc ); -#else - gdk_wx_draw_bitmap( m_window, m_textGC, use_bitmap.GetBitmap(), 0, 0, xx, yy, -1, -1 ); -#endif + 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 { - gdk_draw_pixmap( m_window, m_penGC, use_bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 ); - } - - // remove mask again if any - if (useMask && mask) - { - if (is_mono) +#if GTK_CHECK_VERSION(2,2,0) + if (!gtk_check_version(2,2,0) && use_bitmap.HasPixbuf()) { - gdk_gc_set_clip_mask( m_textGC, (GdkBitmap *) NULL ); - gdk_gc_set_clip_origin( m_textGC, 0, 0 ); - if (!m_currentClippingRegion.IsNull()) - gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() ); + 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_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL ); - gdk_gc_set_clip_origin( m_penGC, 0, 0 ); - if (!m_currentClippingRegion.IsNull()) - gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() ); + gdk_draw_drawable(m_window, use_gc, + use_bitmap.GetPixmap(), + 0, 0, xx, yy, -1, -1); } } - - if (new_mask) - gdk_bitmap_unref( new_mask ); + + // 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); + } } -bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, +bool wxGTKWindowImplDC::DoBlit( wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height, wxDC *source, wxCoord xsrc, wxCoord ysrc, @@ -1181,34 +1242,37 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, bool useMask, wxCoord xsrcMask, wxCoord ysrcMask ) { - wxCHECK_MSG( Ok(), FALSE, wxT("invalid window dc") ); + wxCHECK_MSG( IsOk(), false, wxT("invalid window dc") ); - wxCHECK_MSG( source, FALSE, wxT("invalid source dc") ); + wxCHECK_MSG( source, false, wxT("invalid source dc") ); - if (!m_window) return FALSE; + if (!m_window) return false; // transform the source DC coords to the device ones - xsrc = source->XLOG2DEV(xsrc); - ysrc = source->YLOG2DEV(ysrc); + xsrc = source->LogicalToDeviceX(xsrc); + ysrc = source->LogicalToDeviceY(ysrc); - wxClientDC *srcDC = (wxClientDC*)source; - wxMemoryDC *memDC = (wxMemoryDC*)source; + wxBitmap selected; + wxMemoryDC *memDC = wxDynamicCast(source, wxMemoryDC); + if ( memDC ) + { + selected = memDC->GetSelectedBitmap(); + if ( !selected.IsOk() ) + return false; + } - bool use_bitmap_method = FALSE; - bool is_mono = FALSE; + bool use_bitmap_method = false; + bool is_mono = false; - // TODO: use the mask origin when drawing transparently if (xsrcMask == -1 && ysrcMask == -1) { xsrcMask = xsrc; ysrcMask = ysrc; } - if (srcDC->m_isMemDC) + if (selected.IsOk()) { - if (!memDC->m_selected.Ok()) return FALSE; - - is_mono = (memDC->m_selected.GetDepth() == 1); + is_mono = (selected.GetDepth() == 1); // we use the "XCopyArea" way to copy a memory dc into // a different window if the memory dc BOTH @@ -1216,33 +1280,29 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, // b) it is clipped // c) is not 1-bit - if (useMask && (memDC->m_selected.GetMask())) + if (useMask && (selected.GetMask())) { // we HAVE TO use the direct way for memory dcs // that have mask since the XCopyArea doesn't know // about masks - use_bitmap_method = TRUE; + 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; + use_bitmap_method = true; } else if ((xsrc == 0) && (ysrc == 0) && - (width == memDC->m_selected.GetWidth()) && - (height == memDC->m_selected.GetHeight())) + (width == selected.GetWidth()) && + (height == selected.GetHeight())) { // we SHOULD use the direct way if all of the bitmap // in the memory dc is copied in which case XCopyArea // wouldn't be able able to boost performace by reducing // the area to be scaled - use_bitmap_method = TRUE; - } - else - { - use_bitmap_method = FALSE; + use_bitmap_method = true; } } @@ -1262,7 +1322,7 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, wxRegion tmp( xx,yy,ww,hh ); tmp.Intersect( m_currentClippingRegion ); if (tmp.IsEmpty()) - return TRUE; + return true; } int old_logical_func = m_logicalFunction; @@ -1271,8 +1331,8 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, if (use_bitmap_method) { // scale/translate bitmap size - wxCoord bm_width = memDC->m_selected.GetWidth(); - wxCoord bm_height = memDC->m_selected.GetHeight(); + wxCoord bm_width = selected.GetWidth(); + wxCoord bm_height = selected.GetHeight(); // Get clip coords for the bitmap. If we don't // use wxBitmap::Rescale(), which can clip the @@ -1282,7 +1342,7 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, wxCoord cy = yy; wxCoord cw = ww; wxCoord ch = hh; - + // interpret userscale of src too double xsc,ysc; memDC->GetUserScale(&xsc,&ysc); @@ -1293,32 +1353,31 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, wxCoord bm_hh = YLOG2DEVREL( bm_height ); // Scale bitmap if required - wxBitmap use_bitmap; - if ((bm_width != bm_ww) || (bm_height != bm_hh)) + wxBitmap use_bitmap = selected; + if ((selected.GetWidth()!= bm_ww) || ( selected.GetHeight()!= bm_hh)) { // This indicates that the blitting code below will get // a clipped bitmap and therefore needs to move the origin // accordingly wxRegion tmp( xx,yy,ww,hh ); - tmp.Intersect( m_currentClippingRegion ); + if (!m_currentClippingRegion.IsNull()) + tmp.Intersect( m_currentClippingRegion ); tmp.GetBox(cx,cy,cw,ch); - + // Scale and clipped bitmap - use_bitmap = memDC->m_selected.Rescale(cx-xx,cy-yy,cw,ch,bm_ww,bm_hh); - } - else - { - // Don't scale bitmap - use_bitmap = memDC->m_selected; + use_bitmap = selected.Rescale(cx-xx,cy-yy,cw,ch,bm_ww,bm_hh); } // apply mask if any GdkBitmap *mask = (GdkBitmap *) NULL; - if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap(); + if (useMask && use_bitmap.GetMask()) + mask = use_bitmap.GetMask()->GetBitmap(); + + GdkGC* use_gc = is_mono ? m_textGC : m_penGC; GdkBitmap *new_mask = (GdkBitmap*) NULL; - - if (useMask && mask) + + if (mask != NULL) { if (!m_currentClippingRegion.IsNull()) { @@ -1327,6 +1386,7 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, 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 ); @@ -1338,27 +1398,15 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, gdk_gc_set_fill( gc, GDK_OPAQUE_STIPPLED ); gdk_gc_set_stipple( gc, mask ); gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, bm_ww, bm_hh ); - gdk_gc_unref( gc ); + mask = new_mask; + g_object_unref (gc); } - if (is_mono) - { - if (new_mask) - gdk_gc_set_clip_mask( m_textGC, new_mask ); - else - gdk_gc_set_clip_mask( m_textGC, mask ); - // was: gdk_gc_set_clip_origin( m_textGC, xx, yy ); - gdk_gc_set_clip_origin( m_textGC, cx, cy ); - } + gdk_gc_set_clip_mask(use_gc, mask); + if (new_mask != NULL) + gdk_gc_set_clip_origin(use_gc, cx, cy); else - { - if (new_mask) - gdk_gc_set_clip_mask( m_penGC, new_mask ); - else - gdk_gc_set_clip_mask( m_penGC, mask ); - // was: gdk_gc_set_clip_origin( m_penGC, xx, yy ); - gdk_gc_set_clip_origin( m_penGC, cx, cy ); - } + gdk_gc_set_clip_origin(use_gc, cx - xsrcMask, cy - ysrcMask); } // Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For @@ -1366,131 +1414,188 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, if (is_mono) { -#ifdef __WXGTK20__ 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.GetBitmap(), 0, 0, 0, 0, -1, -1 ); - - gdk_draw_drawable( m_window, m_textGC, bitmap, xsrc, ysrc, cx, cy, cw, ch ); - - gdk_bitmap_unref( bitmap ); - gdk_gc_unref( gc ); -#else - // was: gdk_wx_draw_bitmap( m_window, m_textGC, use_bitmap.GetBitmap(), xsrc, ysrc, xx, yy, ww, hh ); - gdk_wx_draw_bitmap( m_window, m_textGC, use_bitmap.GetBitmap(), xsrc, ysrc, cx, cy, cw, ch ); -#endif + gdk_wx_draw_bitmap( bitmap, gc, use_bitmap.GetPixmap(), 0, 0, 0, 0, -1, -1 ); + + gdk_draw_drawable(m_window, use_gc, bitmap, xsrc, ysrc, cx, cy, cw, ch); + + g_object_unref (bitmap); + g_object_unref (gc); } else { - // was: gdk_draw_pixmap( m_window, m_penGC, use_bitmap.GetPixmap(), xsrc, ysrc, xx, yy, ww, hh ); - gdk_draw_pixmap( m_window, m_penGC, use_bitmap.GetPixmap(), xsrc, ysrc, cx, cy, cw, ch ); + // 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); } // remove mask again if any - if (useMask && mask) + if (mask != NULL) { - if (is_mono) - { - gdk_gc_set_clip_mask( m_textGC, (GdkBitmap *) NULL ); - gdk_gc_set_clip_origin( m_textGC, 0, 0 ); - if (!m_currentClippingRegion.IsNull()) - gdk_gc_set_clip_region( m_textGC, m_currentClippingRegion.GetRegion() ); - } - else - { - gdk_gc_set_clip_mask( m_penGC, (GdkBitmap *) NULL ); - gdk_gc_set_clip_origin( m_penGC, 0, 0 ); - if (!m_currentClippingRegion.IsNull()) - gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() ); - } + gdk_gc_set_clip_mask(use_gc, NULL); + gdk_gc_set_clip_origin(use_gc, 0, 0); + if (!m_currentClippingRegion.IsNull()) + gdk_gc_set_clip_region(use_gc, m_currentClippingRegion.GetRegion()); } - + if (new_mask) - gdk_bitmap_unref( new_mask ); + g_object_unref (new_mask); } else // use_bitmap_method { - if ((width != ww) || (height != hh)) + if (selected.IsOk() && ((width != ww) || (height != hh))) { // get clip coords wxRegion tmp( xx,yy,ww,hh ); tmp.Intersect( m_currentClippingRegion ); wxCoord cx,cy,cw,ch; tmp.GetBox(cx,cy,cw,ch); - - // rescale bitmap - wxBitmap bitmap = memDC->m_selected.Rescale( cx-xx, cy-yy, cw, ch, ww, hh ); + + // rescale bitmap + wxBitmap bitmap = selected.Rescale( cx-xx, cy-yy, cw, ch, ww, hh ); // draw scaled bitmap - // was: gdk_draw_pixmap( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 ); - gdk_draw_pixmap( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, cx, cy, -1, -1 ); + // was: gdk_draw_drawable( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 ); + gdk_draw_drawable( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, cx, cy, -1, -1 ); } else { - // No scaling and not a memory dc with a mask either + // No scaling and not a memory dc with a mask either +#if wxUSE_NEW_DC + GdkWindow* window = NULL; + wxImplDC *impl = source->GetImpl(); + wxGTKWindowImplDC *gtk_impl = wxDynamicCast(impl, wxGTKWindowImplDC); + if (gtk_impl) + window = gtk_impl->GetGDKWindow(); +#else + GdkWindow* window = source->GetGDKWindow(); +#endif + if ( !window ) + return false; // copy including child window contents gdk_gc_set_subwindow( m_penGC, GDK_INCLUDE_INFERIORS ); - gdk_window_copy_area( m_window, m_penGC, xx, yy, - srcDC->GetWindow(), - xsrc, ysrc, width, height ); + gdk_draw_drawable( m_window, m_penGC, + window, + xsrc, ysrc, xx, yy, + width, height ); gdk_gc_set_subwindow( m_penGC, GDK_CLIP_BY_CHILDREN ); } } SetLogicalFunction( old_logical_func ); - - return TRUE; + + return true; } -void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) +void wxGTKWindowImplDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); if (!m_window) return; - - if (text.empty()) return; - -#ifndef __WXGTK20__ - GdkFont *font = m_font.GetInternalFont( m_scaleY ); - wxCHECK_RET( font, wxT("invalid font") ); -#endif + if (text.empty()) return; x = XLOG2DEV(x); y = YLOG2DEV(y); -#ifdef __WXGTK20__ 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") ); -#if wxUSE_UNICODE - const wxCharBuffer data = wxConvUTF8.cWC2MB( text ); -#else - const wxWCharBuffer wdata = wxConvLocal.cMB2WC( text ); - const wxCharBuffer data = wxConvUTF8.cWC2MB( wdata ); -#endif - pango_layout_set_text( m_layout, (const char*) data, strlen( (const char*) data )); + gdk_pango_context_set_colormap( m_context, m_cmap ); + + bool underlined = m_font.IsOk() && m_font.GetUnderlined(); + + const wxCharBuffer data = wxGTK_CONV( text ); + if ( !data ) + return; + size_t datalen = strlen(data); + + // in Pango >= 1.16 the "underline of leading/trailing spaces" bug + // has been fixed and thus the hack implemented below should never be used + static bool pangoOk = !wx_pango_version_check(1, 16, 0); + + bool needshack = underlined && !pangoOk; + char *hackstring = NULL; + + if (needshack) + { + // a PangoLayout which has leading/trailing spaces with underlined font + // is not correctly drawn by this pango version: Pango won't underline the spaces. + // This can be a problem; e.g. wxHTML rendering of underlined text relies on + // this behaviour. To workaround this problem, we use a special hack here + // suggested by pango maintainer Behdad Esfahbod: we prepend and append two + // empty space characters and give them a dummy colour attribute. + // This will force Pango to underline the leading/trailing spaces, too. + + // need to realloc the string to prepend & append our special characters + hackstring = (char*)malloc((datalen+7)*sizeof(char)); + + // copy the leading U+200C ZERO WIDTH NON-JOINER encoded in UTF8 format + strcpy(hackstring, "\342\200\214"); + + // copy the user string + memcpy(&hackstring[3], data, datalen); + + // copy the trailing U+200C ZERO WIDTH NON-JOINER encoded in UTF8 format + strcpy(&hackstring[datalen+3], "\342\200\214"); + + // the special characters that we added require 6 additional bytes: + datalen += 6; + + pango_layout_set_text(m_layout, hackstring, datalen); + } + else + { + pango_layout_set_text(m_layout, data, datalen); + } + + if (underlined) + { + PangoAttrList *attrs = pango_attr_list_new(); + PangoAttribute *a = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); + a->start_index = 0; + a->end_index = datalen; + pango_attr_list_insert(attrs, a); + + if (needshack) + { + // dummy colour for the leading space + a = pango_attr_foreground_new (0x0057, 0x52A9, 0xD614); + a->start_index = 0; + a->end_index = 1; + pango_attr_list_insert(attrs, a); + + // dummy colour for the trailing space + a = pango_attr_foreground_new (0x0057, 0x52A9, 0xD614); + a->start_index = datalen - 1; + a->end_index = datalen; + pango_attr_list_insert(attrs, a); + } + + pango_layout_set_attributes(m_layout, attrs); + pango_attr_list_unref(attrs); + } int w,h; - - if (fabs(m_scaleY - 1.0) < 0.00001) + + 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 ) { @@ -1498,13 +1603,16 @@ void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) gdk_draw_rectangle(m_window, m_textGC, TRUE, x, y, w, h); gdk_gc_set_foreground(m_textGC, m_textForegroundColour.GetColor()); } - + // Draw layout. - gdk_draw_layout( m_window, m_textGC, x, y, m_layout ); - + if (m_owningWindow && m_owningWindow->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 ); } @@ -1517,74 +1625,66 @@ void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) gdk_draw_rectangle(m_window, m_textGC, TRUE, x, y, w, h); gdk_gc_set_foreground(m_textGC, m_textForegroundColour.GetColor()); } + // Draw layout. - gdk_draw_layout( m_window, m_textGC, x, y, m_layout ); + if (m_owningWindow && m_owningWindow->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 ); } - - wxCoord width = w; - wxCoord height = h; - -#else // GTK+ 1.x - wxCoord width = gdk_string_width( font, text.mbc_str() ); - wxCoord height = font->ascent + font->descent; - if ( m_backgroundMode == wxSOLID ) + if (underlined) { - 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() ); + // undo underline attributes setting: + pango_layout_set_attributes(m_layout, NULL); } - 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()) - { - wxCoord 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); - } -#endif // GTK+ 2.0/1.x + wxCoord width = w; + wxCoord height = h; width = wxCoord(width / m_scaleX); height = wxCoord(height / m_scaleY); CalcBoundingBox (x + width, y + height); CalcBoundingBox (x, y); + + if (hackstring) + free(hackstring); } -void wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, double angle ) + +// TODO: There is an example of rotating text with GTK2 that would probably be +// a better approach here: +// http://www.daa.com.au/pipermail/pygtk/2003-April/005052.html + +void wxGTKWindowImplDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, double angle ) { - if (angle == 0.0) - { - DrawText(text, x, y); +#if wxUSE_IMAGE + if (!m_window || text.empty()) return; - } - - wxCHECK_RET( Ok(), wxT("invalid window dc") ); - if (!m_window) return; + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); -#ifdef __WXGTK20__ - // implement later without GdkFont for GTK 2.0 - return; -#else - GdkFont *font = m_font.GetInternalFont( m_scaleY ); + if ( wxIsNullDouble(angle) ) + { + DoDrawText(text, x, y); + return; + } - wxCHECK_RET( font, wxT("invalid font") ); + wxCoord w; + wxCoord h; - // the size of the text - wxCoord w = gdk_string_width( font, text.mbc_str() ); - wxCoord h = font->ascent + font->descent; + // TODO: implement later without GdkFont for GTK 2.0 + DoGetTextExtent(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(*wxWHITE_BRUSH); + dc.SetBackground(*wxBLACK_BRUSH); dc.SetBrush(*wxBLACK_BRUSH); dc.Clear(); + dc.SetTextForeground( *wxWHITE ); dc.DrawText(text, 0, 0); dc.SelectObject(wxNullBitmap); @@ -1608,47 +1708,40 @@ void wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, minX = (wxCoord)(dmin(x2, dmin(x3, x4)) - 0.5), minY = (wxCoord)(dmin(y2, dmin(y3, y4)) - 0.5); - // prepare to blit-with-rotate the bitmap to the DC - wxImage image = src.ConvertToImage(); - - GdkColor *colText = m_textForegroundColour.GetColor(), - *colBack = m_textBackgroundColour.GetColor(); - - bool textColSet = TRUE; - - unsigned char *data = image.GetData(); - // paint pixel by pixel - for ( wxCoord srcX = 0; srcX < w; srcX++ ) - { - for ( wxCoord srcY = 0; srcY < h; srcY++ ) - { - // transform source coords to dest coords - double r = sqrt((double)srcX*srcX + srcY*srcY); - double angleOrig = atan2((double)srcY, (double)srcX) - rad; - wxCoord dstX = (wxCoord)(r*cos(angleOrig) + 0.5), - dstY = (wxCoord)(r*sin(angleOrig) + 0.5); - - // black pixel? - bool textPixel = data[(srcY*w + srcX)*3] == 0; - if ( textPixel || (m_backgroundMode == wxSOLID) ) - { - // change colour if needed - if ( textPixel != textColSet ) - { - gdk_gc_set_foreground( m_textGC, textPixel ? colText - : colBack ); + wxImage image = src.ConvertToImage(); - textColSet = textPixel; - } + 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 ); - // don't use DrawPoint() because it uses the current pen - // colour, and we don't need it here - gdk_draw_point( m_window, m_textGC, - XLOG2DEV(x) + dstX, YLOG2DEV(y) + dstY ); - } - } - } // it would be better to draw with non underlined font and draw the line // manually here (it would be more straight...) @@ -1661,44 +1754,45 @@ void wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, } #endif // 0 - // restore the font colour - gdk_gc_set_foreground( m_textGC, colText ); - // update the bounding box CalcBoundingBox(x + minX, y + minY); CalcBoundingBox(x + maxX, y + maxY); -#endif +#endif // wxUSE_IMAGE } -void wxWindowDC::DoGetTextExtent(const wxString &string, +void wxGTKWindowImplDC::DoGetTextExtent(const wxString &string, wxCoord *width, wxCoord *height, wxCoord *descent, wxCoord *externalLeading, - wxFont *theFont) const + const wxFont *theFont) const { - if (string.IsEmpty()) - { - if (width) (*width) = 0; - if (height) (*height) = 0; + if ( width ) + *width = 0; + if ( height ) + *height = 0; + if ( descent ) + *descent = 0; + if ( externalLeading ) + *externalLeading = 0; + + if (string.empty()) return; + + // ensure that theFont is always non-NULL + if ( !theFont || !theFont->IsOk() ) + theFont = wx_const_cast(wxFont *, &m_font); + + // and use it if it's valid + if ( theFont->IsOk() ) + { + pango_layout_set_font_description + ( + m_layout, + theFont->GetNativeFontInfo()->description + ); } - -#ifdef __WXGTK20__ - // Set new font description - if (theFont) - pango_layout_set_font_description( m_layout, theFont->GetNativeFontInfo()->description ); - - // Set layout's text -#if wxUSE_UNICODE - const wxCharBuffer data = wxConvUTF8.cWC2MB( string ); - const char *dataUTF8 = (const char *)data; -#else - const wxWCharBuffer wdata = wxConvLocal.cMB2WC( string ); - if ( !wdata ) - return; - const wxCharBuffer data = wxConvUTF8.cWC2MB( wdata ); - const char *dataUTF8 = (const char *)data; -#endif + // Set layout's text + const wxCharBuffer dataUTF8 = wxGTK_CONV_FONT(string, *theFont); if ( !dataUTF8 ) { // hardly ideal, but what else can we do if conversion failed? @@ -1706,155 +1800,146 @@ void wxWindowDC::DoGetTextExtent(const wxString &string, } pango_layout_set_text( m_layout, dataUTF8, strlen(dataUTF8) ); - - int w,h; - pango_layout_get_pixel_size( m_layout, &w, &h ); - - if (width) - *width = (wxCoord) w; - if (height) - *height = (wxCoord) h; + if (descent) { - // Do something about metrics here. TODO. - *descent = 0; + 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 + { + pango_layout_get_pixel_size( m_layout, width, height ); } - if (externalLeading) - *externalLeading = 0; // ?? - + // Reset old font description - if (theFont) + if (theFont->IsOk()) pango_layout_set_font_description( m_layout, m_fontdesc ); -#else // GTK+ 1.x - wxFont fontToUse = m_font; - if (theFont) fontToUse = *theFont; - - GdkFont *font = fontToUse.GetInternalFont( m_scaleY ); - if (width) (*width) = wxCoord(gdk_string_width( font, string.mbc_str() ) / m_scaleX); - if (height) (*height) = wxCoord((font->ascent + font->descent) / m_scaleY); - if (descent) (*descent) = wxCoord(font->descent / m_scaleY); - if (externalLeading) (*externalLeading) = 0; // ?? -#endif // GTK+ 2/1 } -wxCoord wxWindowDC::GetCharWidth() const + +bool wxGTKWindowImplDC::DoGetPartialTextExtents(const wxString& text, + wxArrayInt& widths) const { -#ifdef __WXGTK20__ - pango_layout_set_text( m_layout, "H", 1 ); - int w,h; - pango_layout_get_pixel_size( m_layout, &w, &h ); - return w; -#else - GdkFont *font = m_font.GetInternalFont( m_scaleY ); - wxCHECK_MSG( font, -1, wxT("invalid font") ); + const size_t len = text.length(); + widths.Empty(); + widths.Add(0, len); - return wxCoord(gdk_string_width( font, "H" ) / m_scaleX); -#endif + if (text.empty()) + return true; + + // Set layout's text + const wxCharBuffer dataUTF8 = wxGTK_CONV_FONT(text, m_font); + if ( !dataUTF8 ) + { + // hardly ideal, but what else can we do if conversion failed? + wxLogLastError(wxT("DoGetPartialTextExtents")); + return false; + } + + pango_layout_set_text( m_layout, dataUTF8, strlen(dataUTF8) ); + + // Calculate the position of each character based on the widths of + // the previous characters + + // Code borrowed from Scintilla's PlatGTK + PangoLayoutIter *iter = pango_layout_get_iter(m_layout); + PangoRectangle pos; + pango_layout_iter_get_cluster_extents(iter, NULL, &pos); + size_t i = 0; + while (pango_layout_iter_next_cluster(iter)) + { + pango_layout_iter_get_cluster_extents(iter, NULL, &pos); + int position = PANGO_PIXELS(pos.x); + widths[i++] = position; + } + while (i < len) + widths[i++] = PANGO_PIXELS(pos.x + pos.width); + pango_layout_iter_free(iter); + + return true; } -wxCoord wxWindowDC::GetCharHeight() const + +wxCoord wxGTKWindowImplDC::GetCharWidth() const { -#ifdef __WXGTK20__ pango_layout_set_text( m_layout, "H", 1 ); - int w,h; - pango_layout_get_pixel_size( m_layout, &w, &h ); - return h; -#else - GdkFont *font = m_font.GetInternalFont( m_scaleY ); - wxCHECK_MSG( font, -1, wxT("invalid font") ); - - return wxCoord((font->ascent + font->descent) / m_scaleY); -#endif + int w; + pango_layout_get_pixel_size( m_layout, &w, NULL ); + return w; } -void wxWindowDC::Clear() +wxCoord wxGTKWindowImplDC::GetCharHeight() const { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + 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") ); - if (!m_window) return; + wxCoord h = PANGO_PIXELS (pango_font_metrics_get_descent (metrics) + + pango_font_metrics_get_ascent (metrics)); + pango_font_metrics_unref (metrics); + return h; +} - // VZ: the code below results in infinite recursion and crashes when - // dc.Clear() is done from OnPaint() so I disable it for now. - // I don't know what the correct fix is but Clear() surely should not - // reenter OnPaint()! -#if 0 - /* - we either are a memory dc or have a window as the - owner. anything else shouldn't happen. - - we don't use gdk_window_clear() as we don't set - the window's background colour anymore. it is too - much pain to keep the DC's and the window's back- - ground colour in synch. */ +void wxGTKWindowImplDC::Clear() +{ + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); - if (m_owner) - { - m_owner->Clear(); - return; - } + if (!m_window) return; - if (m_isMemDC) - { - int width,height; - GetSize( &width, &height ); - gdk_draw_rectangle( m_window, m_bgGC, TRUE, 0, 0, width, height ); - return; - } -#else // 1 int width,height; - GetSize( &width, &height ); + DoGetSize( &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; - -#ifdef __WXGTK20__ - if (m_font.Ok()) + + if (m_font.IsOk()) { if (m_fontdesc) pango_font_description_free( m_fontdesc ); - + m_fontdesc = pango_font_description_copy( m_font.GetNativeFontInfo()->description ); - - - if (m_owner) + + + if (m_owningWindow) { PangoContext *oldContext = m_context; - - // We might want to use the X11 context for faster - // rendering on screen - if (m_font.GetNoAntiAliasing()) - m_context = m_owner->GtkGetPangoX11Context(); - else - m_context = m_owner->GtkGetPangoDefaultContext(); - + + m_context = m_owningWindow->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. + // at least, and it doesn't hurt to do it. if (oldContext != m_context) { if (m_layout) - g_object_unref( G_OBJECT( m_layout ) ); - + g_object_unref (m_layout); + m_layout = pango_layout_new( m_context ); } } - + pango_layout_set_font_description( m_layout, m_fontdesc ); } -#endif } -void wxWindowDC::SetPen( const wxPen &pen ) +void wxGTKWindowImplDC::SetPen( const wxPen &pen ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); if (m_pen == pen) return; m_pen = pen; - if (!m_pen.Ok()) return; + if (!m_pen.IsOk()) return; if (!m_window) return; @@ -1943,7 +2028,6 @@ void wxWindowDC::SetPen( const wxPen &pen ) } } -#if (GTK_MINOR_VERSION > 0) || (GTK_MAJOR_VERSION > 1) if (req_dash && req_nb_dash) { wxGTKDash *real_req_dash = new wxGTKDash[req_nb_dash]; @@ -1960,7 +2044,6 @@ void wxWindowDC::SetPen( const wxPen &pen ) gdk_gc_set_dashes( m_penGC, 0, (wxGTKDash*)req_dash, req_nb_dash ); } } -#endif // GTK+ > 1.0 GdkCapStyle capStyle = GDK_CAP_ROUND; switch (m_pen.GetCap()) @@ -1998,15 +2081,15 @@ void wxWindowDC::SetPen( const wxPen &pen ) gdk_gc_set_foreground( m_penGC, m_pen.GetColour().GetColor() ); } -void wxWindowDC::SetBrush( const wxBrush &brush ) +void wxGTKWindowImplDC::SetBrush( const wxBrush &brush ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); if (m_brush == brush) return; m_brush = brush; - if (!m_brush.Ok()) return; + if (!m_brush.IsOk()) return; if (!m_window) return; @@ -2015,9 +2098,9 @@ void wxWindowDC::SetBrush( const wxBrush &brush ) gdk_gc_set_fill( m_brushGC, GDK_SOLID ); - if ((m_brush.GetStyle() == wxSTIPPLE) && (m_brush.GetStipple()->Ok())) + if ((m_brush.GetStyle() == wxSTIPPLE) && (m_brush.GetStipple()->IsOk())) { - 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() ); @@ -2025,7 +2108,7 @@ 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() ); } } @@ -2035,7 +2118,7 @@ void wxWindowDC::SetBrush( const wxBrush &brush ) gdk_gc_set_stipple( m_textGC, m_brush.GetStipple()->GetMask()->GetBitmap() ); } - if (IS_HATCH(m_brush.GetStyle())) + if (m_brush.IsHatch()) { gdk_gc_set_fill( m_brushGC, GDK_STIPPLED ); int num = m_brush.GetStyle() - wxBDIAGONAL_HATCH; @@ -2043,18 +2126,18 @@ 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(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); if (m_backgroundBrush == brush) return; m_backgroundBrush = brush; - if (!m_backgroundBrush.Ok()) return; + if (!m_backgroundBrush.IsOk()) return; if (!m_window) return; @@ -2066,9 +2149,9 @@ void wxWindowDC::SetBackground( const wxBrush &brush ) gdk_gc_set_fill( m_bgGC, GDK_SOLID ); - if ((m_backgroundBrush.GetStyle() == wxSTIPPLE) && (m_backgroundBrush.GetStipple()->Ok())) + if ((m_backgroundBrush.GetStyle() == wxSTIPPLE) && (m_backgroundBrush.GetStipple()->IsOk())) { - 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() ); @@ -2076,11 +2159,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; @@ -2088,9 +2171,9 @@ void wxWindowDC::SetBackground( const wxBrush &brush ) } } -void wxWindowDC::SetLogicalFunction( int function ) +void wxGTKWindowImplDC::SetLogicalFunction( int function ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); if (m_logicalFunction == function) return; @@ -2104,7 +2187,6 @@ void wxWindowDC::SetLogicalFunction( int function ) { case wxXOR: mode = GDK_XOR; break; case wxINVERT: mode = GDK_INVERT; break; -#if (GTK_MINOR_VERSION > 0) || (GTK_MAJOR_VERSION > 1) case wxOR_REVERSE: mode = GDK_OR_REVERSE; break; case wxAND_REVERSE: mode = GDK_AND_REVERSE; break; case wxCLEAR: mode = GDK_CLEAR; break; @@ -2121,7 +2203,6 @@ void wxWindowDC::SetLogicalFunction( int function ) // unsupported by GTK case wxNOR: mode = GDK_COPY; break; -#endif // GTK+ > 1.0 default: wxFAIL_MSG( wxT("unsupported logical function") ); mode = GDK_COPY; @@ -2138,14 +2219,14 @@ void wxWindowDC::SetLogicalFunction( int function ) gdk_gc_set_function( m_textGC, mode ); } -void wxWindowDC::SetTextForeground( const wxColour &col ) +void wxGTKWindowImplDC::SetTextForeground( const wxColour &col ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); // don't set m_textForegroundColour to an invalid colour as we'd crash // later then (we use m_textForegroundColour.GetColor() without checking // in a few places) - if ( !col.Ok() || (m_textForegroundColour == col) ) + if ( !col.IsOk() || (m_textForegroundColour == col) ) return; m_textForegroundColour = col; @@ -2157,12 +2238,12 @@ void wxWindowDC::SetTextForeground( const wxColour &col ) } } -void wxWindowDC::SetTextBackground( const wxColour &col ) +void wxGTKWindowImplDC::SetTextBackground( const wxColour &col ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); // same as above - if ( !col.Ok() || (m_textBackgroundColour == col) ) + if ( !col.IsOk() || (m_textBackgroundColour == col) ) return; m_textBackgroundColour = col; @@ -2174,9 +2255,9 @@ void wxWindowDC::SetTextBackground( const wxColour &col ) } } -void wxWindowDC::SetBackgroundMode( int mode ) +void wxGTKWindowImplDC::SetBackgroundMode( int mode ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); m_backgroundMode = mode; @@ -2192,14 +2273,14 @@ void wxWindowDC::SetBackgroundMode( int mode ) } } -void wxWindowDC::SetPalette( const wxPalette& WXUNUSED(palette) ) +void wxGTKWindowImplDC::SetPalette( const wxPalette& WXUNUSED(palette) ) { - wxFAIL_MSG( wxT("wxWindowDC::SetPalette not implemented") ); + wxFAIL_MSG( wxT("wxGTKWindowImplDC::SetPalette not implemented") ); } -void wxWindowDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) +void wxGTKWindowImplDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoord height ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); if (!m_window) return; @@ -2209,6 +2290,12 @@ void wxWindowDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoo rect.width = XLOG2DEVREL(width); rect.height = YLOG2DEVREL(height); + if (m_owningWindow && m_owningWindow->m_wxwindow && + (m_owningWindow->GetLayoutDirection() == wxLayout_RightToLeft)) + { + rect.x -= rect.width; + } + if (!m_currentClippingRegion.IsNull()) m_currentClippingRegion.Intersect( rect ); else @@ -2221,7 +2308,11 @@ void wxWindowDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoo wxCoord xx, yy, ww, hh; m_currentClippingRegion.GetBox( xx, yy, ww, hh ); +#if wxUSE_NEW_DC + wxImplDC::DoSetClippingRegion( xx, yy, ww, hh ); +#else wxDC::DoSetClippingRegion( xx, yy, ww, hh ); +#endif gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() ); gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() ); @@ -2229,9 +2320,9 @@ void wxWindowDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord width, wxCoo gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() ); } -void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion ®ion ) +void wxGTKWindowImplDC::DoSetClippingRegionAsRegion( const wxRegion ®ion ) { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); if (region.Empty()) { @@ -2253,7 +2344,11 @@ void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion ®ion ) wxCoord xx, yy, ww, hh; m_currentClippingRegion.GetBox( xx, yy, ww, hh ); +#if wxUSE_NEW_DC + wxImplDC::DoSetClippingRegion( xx, yy, ww, hh ); +#else wxDC::DoSetClippingRegion( xx, yy, ww, hh ); +#endif gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() ); gdk_gc_set_clip_region( m_brushGC, m_currentClippingRegion.GetRegion() ); @@ -2261,11 +2356,15 @@ void wxWindowDC::DoSetClippingRegionAsRegion( const wxRegion ®ion ) gdk_gc_set_clip_region( m_bgGC, m_currentClippingRegion.GetRegion() ); } -void wxWindowDC::DestroyClippingRegion() +void wxGTKWindowImplDC::DestroyClippingRegion() { - wxCHECK_RET( Ok(), wxT("invalid window dc") ); + wxCHECK_RET( IsOk(), wxT("invalid window dc") ); +#if wxUSE_NEW_DC + wxImplDC::DestroyClippingRegion(); +#else wxDC::DestroyClippingRegion(); +#endif m_currentClippingRegion.Clear(); @@ -2292,7 +2391,7 @@ void wxWindowDC::DestroyClippingRegion() } } -void wxWindowDC::Destroy() +void wxGTKWindowImplDC::Destroy() { if (m_penGC) wxFreePoolGC( m_penGC ); m_penGC = (GdkGC*) NULL; @@ -2304,45 +2403,113 @@ void wxWindowDC::Destroy() m_bgGC = (GdkGC*) NULL; } -void wxWindowDC::ComputeScaleAndOrigin() +void wxGTKWindowImplDC::SetDeviceOrigin( wxCoord x, wxCoord y ) +{ + m_deviceOriginX = x; + m_deviceOriginY = y; + + ComputeScaleAndOrigin(); +} + +void wxGTKWindowImplDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp ) +{ + m_signX = (xLeftRight ? 1 : -1); + m_signY = (yBottomUp ? -1 : 1); + + if (m_owningWindow && m_owningWindow->m_wxwindow && + (m_owningWindow->GetLayoutDirection() == wxLayout_RightToLeft)) + m_signX = -m_signX; + + ComputeScaleAndOrigin(); +} + +void wxGTKWindowImplDC::ComputeScaleAndOrigin() { - /* CMB: copy scale to see if it changes */ - double origScaleX = m_scaleX; - double origScaleY = m_scaleY; + const wxRealPoint origScale(m_scaleX, m_scaleY); +#if wxUSE_NEW_DC + wxImplDC::ComputeScaleAndOrigin(); +#else wxDC::ComputeScaleAndOrigin(); +#endif - /* CMB: if scale has changed call SetPen to recalulate the line width */ - if ((m_scaleX != origScaleX || m_scaleY != origScaleY) && - (m_pen.Ok())) + // if scale has changed call SetPen to recalulate the line width + if ( wxRealPoint(m_scaleX, m_scaleY) != origScale && m_pen.IsOk() ) { - /* this is a bit artificial, but we need to force wxDC to think - the pen has changed */ - wxPen pen = m_pen; - m_pen = wxNullPen; - SetPen( pen ); - } + // 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 ); + } } // Resolution in pixels per logical inch -wxSize wxWindowDC::GetPPI() const +wxSize wxGTKWindowImplDC::GetPPI() const { return wxSize( (int) (m_mm_to_pix_x * 25.4 + 0.5), (int) (m_mm_to_pix_y * 25.4 + 0.5)); } -int wxWindowDC::GetDepth() const +int wxGTKWindowImplDC::GetDepth() const { - wxFAIL_MSG(wxT("not implemented")); + return gdk_drawable_get_depth(m_window); +} + - return -1; +//----------------------------------------------------------------------------- +// wxClientDC +//----------------------------------------------------------------------------- + +#if wxUSE_NEW_DC +IMPLEMENT_ABSTRACT_CLASS(wxGTKClientImplDC, wxGTKWindowImplDC) +#else +IMPLEMENT_ABSTRACT_CLASS(wxClientDC, wxWindowDC) +#endif + +#if wxUSE_NEW_DC +wxGTKClientImplDC::wxGTKClientImplDC( wxDC *owner ) + : wxGTKWindowImplDC( owner ) +{ } +wxGTKClientImplDC::wxGTKClientImplDC( wxDC *owner, wxWindow *win ) + : wxGTKWindowImplDC( owner, win ) +#else +wxClientDC::wxClientDC() +{ +} + +wxClientDC::wxClientDC( wxWindow *win ) + : wxWindowDC( win ) +#endif + +{ + wxCHECK_RET( win, _T("NULL window in wxGTKClientImplDC::wxClientDC") ); + +#ifdef __WXUNIVERSAL__ + wxPoint ptOrigin = win->GetClientAreaOrigin(); + SetDeviceOrigin(ptOrigin.x, ptOrigin.y); + wxSize size = win->GetClientSize(); + SetClippingRegion(wxPoint(0, 0), size); +#endif // __WXUNIVERSAL__ +} + +void wxGTKClientImplDC::DoGetSize(int *width, int *height) const +{ + wxCHECK_RET( m_owningWindow, _T("GetSize() doesn't work without window") ); + + m_owningWindow->GetClientSize( width, height ); +} //----------------------------------------------------------------------------- // wxPaintDC //----------------------------------------------------------------------------- -IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxClientDC) +#if wxUSE_NEW_DC +IMPLEMENT_ABSTRACT_CLASS(wxGTKPaintImplDC, wxGTKClientImplDC) +#else +IMPLEMENT_ABSTRACT_CLASS(wxPaintDC, wxClientDC) +#endif // Limit the paint region to the window size. Sometimes // the paint region is too big, and this risks X11 errors @@ -2363,17 +2530,32 @@ static void wxLimitRegionToSize(wxRegion& region, const wxSize& sz) } } +#if wxUSE_NEW_DC +wxGTKPaintImplDC::wxGTKPaintImplDC( wxDC *owner ) + : wxGTKClientImplDC( owner ) +{ +} + +wxGTKPaintImplDC::wxGTKPaintImplDC( wxDC *owner, wxWindow *win ) + : wxGTKClientImplDC( owner, win ) +#else +wxPaintDC::wxPaintDC() + : wxClientDC() +{ +} + wxPaintDC::wxPaintDC( wxWindow *win ) : wxClientDC( win ) +#endif { #if USE_PAINT_REGION if (!win->m_clipPaintRegion) return; wxSize sz = win->GetSize(); - m_paintClippingRegion = win->GetUpdateRegion(); + m_paintClippingRegion = win->m_nativeUpdateRegion; wxLimitRegionToSize(m_paintClippingRegion, sz); - + GdkRegion *region = m_paintClippingRegion.GetRegion(); if ( region ) { @@ -2391,32 +2573,6 @@ wxPaintDC::wxPaintDC( wxWindow *win ) #endif // USE_PAINT_REGION } -//----------------------------------------------------------------------------- -// wxClientDC -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC) - -wxClientDC::wxClientDC( wxWindow *win ) - : wxWindowDC( win ) -{ - wxCHECK_RET( win, _T("NULL window in wxClientDC::wxClientDC") ); - -#ifdef __WXUNIVERSAL__ - wxPoint ptOrigin = win->GetClientAreaOrigin(); - SetDeviceOrigin(ptOrigin.x, ptOrigin.y); - wxSize size = win->GetClientSize(); - SetClippingRegion(wxPoint(0, 0), size); -#endif // __WXUNIVERSAL__ -} - -void wxClientDC::DoGetSize(int *width, int *height) const -{ - wxCHECK_RET( m_owner, _T("GetSize() doesn't work without window") ); - - m_owner->GetClientSize( width, height ); -} - // ---------------------------------------------------------------------------- // wxDCModule // ---------------------------------------------------------------------------- @@ -2436,7 +2592,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule) bool wxDCModule::OnInit() { wxInitGCPool(); - return TRUE; + return true; } void wxDCModule::OnExit()