X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/f469b27cacd2b167397917fcf9df1df23751b9be..50f151d726bce4dc4179fbf98f8ee7c34691229c:/src/gtk/dcclient.cpp diff --git a/src/gtk/dcclient.cpp b/src/gtk/dcclient.cpp index 62924c7ca7..57bce1de01 100644 --- a/src/gtk/dcclient.cpp +++ b/src/gtk/dcclient.cpp @@ -3,13 +3,12 @@ // Purpose: // Author: Robert Roebling // RCS-ID: $Id$ -// Copyright: (c) 1998 Robert Roebling, Markus Holzem, Chris Breeze +// Copyright: (c) 1998 Robert Roebling, Chris Breeze // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ -#pragma implementation "dcclient.h" -#endif +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" #ifdef __VMS #define XCopyPlane XCOPYPLANE @@ -19,10 +18,12 @@ #include "wx/dcmemory.h" #include "wx/image.h" #include "wx/module.h" +#include "wx/log.h" +#include "wx/fontutil.h" #include "wx/gtk/win_gtk.h" -#include // for floating-point functions +#include "wx/math.h" // for floating-point functions #include #include @@ -54,7 +55,7 @@ static GdkPixmap *hatches[num_hatches]; static GdkPixmap **hatch_bitmap = (GdkPixmap **) NULL; -extern GtkWidget *wxRootWindow; +extern GtkWidget *wxGetRootWindow(); //----------------------------------------------------------------------------- // constants @@ -77,74 +78,39 @@ static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; } #include "gdk/gdkprivate.h" -void gdk_wx_draw_bitmap (GdkDrawable *drawable, - GdkGC *gc, - GdkDrawable *src, - gint xsrc, - gint ysrc, - gint xdest, - gint ydest, - gint width, - gint height) +void gdk_wx_draw_bitmap(GdkDrawable *drawable, + GdkGC *gc, + GdkDrawable *src, + gint xsrc, + gint ysrc, + gint xdest, + gint ydest, + gint width, + gint height) { - gint src_width, src_height; -#ifndef __WXGTK20__ - GdkWindowPrivate *drawable_private; - GdkWindowPrivate *src_private; - GdkGCPrivate *gc_private; -#endif - - g_return_if_fail (drawable != NULL); - g_return_if_fail (src != NULL); - g_return_if_fail (gc != NULL); - -#ifdef __WXGTK20__ - if (GDK_WINDOW_DESTROYED(drawable) || GDK_WINDOW_DESTROYED(src)) - return; + 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); -#else - drawable_private = (GdkWindowPrivate*) drawable; - src_private = (GdkWindowPrivate*) src; - if (drawable_private->destroyed || src_private->destroyed) - return; - - src_width = src_private->width; - src_height = src_private->height; - - gc_private = (GdkGCPrivate*) gc; -#endif - if (width == -1) width = src_width; if (height == -1) height = src_height; -#ifdef __WXGTK20__ XCopyPlane( GDK_WINDOW_XDISPLAY(drawable), GDK_WINDOW_XID(src), GDK_WINDOW_XID(drawable), GDK_GC_XGC(gc), xsrc, ysrc, width, height, - xdest, ydest, - 1 ); -#else - XCopyPlane( drawable_private->xdisplay, - src_private->xwindow, - drawable_private->xwindow, - gc_private->xgc, - xsrc, ysrc, - width, height, - xdest, ydest, + 0, 0, 1 ); -#endif } //----------------------------------------------------------------------------- // Implement Pool of Graphic contexts. Creating them takes too much time. //----------------------------------------------------------------------------- -#define GC_POOL_SIZE 200 - enum wxPoolGCType { wxGC_ERROR = 0, @@ -169,40 +135,96 @@ struct wxGC bool m_used; }; -static wxGC wxGCPool[GC_POOL_SIZE]; +#define GC_POOL_ALLOC_SIZE 100 + +static int wxGCPoolSize = 0; + +static wxGC *wxGCPool = NULL; static void wxInitGCPool() { - memset( wxGCPool, 0, GC_POOL_SIZE*sizeof(wxGC) ); + // 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) + { + // 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; + } + + // Zero initial pool. + memset(wxGCPool, 0, wxGCPoolSize * sizeof(wxGC)); } static void wxCleanUpGCPool() { - for (int i = 0; i < GC_POOL_SIZE; i++) + for (int i = 0; i < wxGCPoolSize; i++) { if (wxGCPool[i].m_gc) gdk_gc_unref( wxGCPool[i].m_gc ); } + + free(wxGCPool); + wxGCPool = NULL; + wxGCPoolSize = 0; } static GdkGC* wxGetPoolGC( GdkWindow *window, wxPoolGCType type ) { - for (int i = 0; i < GC_POOL_SIZE; i++) + 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; + 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; } } + // 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; @@ -210,11 +232,11 @@ static GdkGC* wxGetPoolGC( GdkWindow *window, wxPoolGCType type ) static void wxFreePoolGC( GdkGC *gc ) { - for (int i = 0; i < GC_POOL_SIZE; i++) + for (int i = 0; i < wxGCPoolSize; i++) { if (wxGCPool[i].m_gc == gc) { - wxGCPool[i].m_used = FALSE; + wxGCPool[i].m_used = false; return; } } @@ -235,34 +257,33 @@ wxWindowDC::wxWindowDC() m_textGC = (GdkGC *) NULL; m_bgGC = (GdkGC *) NULL; m_cmap = (GdkColormap *) NULL; - m_isMemDC = FALSE; - m_isScreenDC = FALSE; + m_isMemDC = false; + m_isScreenDC = false; m_owner = (wxWindow *)NULL; -#ifdef __WXGTK20__ m_context = (PangoContext *)NULL; + m_layout = (PangoLayout *)NULL; m_fontdesc = (PangoFontDescription *)NULL; -#endif } wxWindowDC::wxWindowDC( 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_isScreenDC = FALSE; + m_isMemDC = false; + m_isScreenDC = false; m_font = window->GetFont(); - wxASSERT_MSG( window, wxT("DC needs a window") ); - GtkWidget *widget = window->m_wxwindow; - // some controls don't have m_wxwindow - like wxStaticBox, but the user + // 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 + // use the parent window here then. if ( !widget ) { window = window->GetParent(); @@ -271,19 +292,18 @@ wxWindowDC::wxWindowDC( wxWindow *window ) wxASSERT_MSG( widget, wxT("DC needs a widget") ); -#ifdef __WXGTK20__ - m_context = gtk_widget_get_pango_context( widget ); - m_fontdesc = widget->style->font_desc; -#endif + m_context = window->GtkGetPangoDefaultContext(); + m_layout = pango_layout_new( m_context ); + m_fontdesc = pango_font_description_copy( widget->style->font_desc ); GtkPizza *pizza = GTK_PIZZA( widget ); m_window = pizza->bin_window; - /* 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; } @@ -305,11 +325,16 @@ wxWindowDC::wxWindowDC( wxWindow *window ) wxWindowDC::~wxWindowDC() { Destroy(); + + if (m_layout) + g_object_unref( G_OBJECT( m_layout ) ); + if (m_fontdesc) + pango_font_description_free( m_fontdesc ); } void wxWindowDC::SetUpDC() { - m_ok = TRUE; + m_ok = true; wxASSERT_MSG( !m_penGC, wxT("GCs already created") ); @@ -400,10 +425,13 @@ void wxWindowDC::DoGetSize( int* width, int* height ) const m_owner->GetSize(width, height); } -void wxWindowDC::DoFloodFill( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), - const wxColour &WXUNUSED(col), int WXUNUSED(style) ) +extern bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y, + const wxColour & col, int style); + +bool wxWindowDC::DoFloodFill(wxCoord x, wxCoord y, + const wxColour& col, int style) { - wxFAIL_MSG( wxT("wxWindowDC::DoFloodFill not implemented") ); + return wxDoFloodFill(this, x, y, col, style); } bool wxWindowDC::DoGetPixel( wxCoord x1, wxCoord y1, wxColour *col ) const @@ -415,9 +443,10 @@ bool wxWindowDC::DoGetPixel( wxCoord x1, wxCoord y1, wxColour *col ) const memdc.SelectObject(bitmap); memdc.Blit(0, 0, 1, 1, (wxDC*) this, x1, y1); memdc.SelectObject(wxNullBitmap); - wxImage image(bitmap); + + wxImage image = bitmap.ConvertToImage(); col->Set(image.GetRed(0, 0), image.GetGreen(0, 0), image.GetBlue(0, 0)); - return TRUE; + return true; } void wxWindowDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 ) @@ -475,10 +504,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 { @@ -624,20 +653,50 @@ void wxWindowDC::DoDrawLines( int n, wxPoint points[], wxCoord xoffset, wxCoord if (m_pen.GetStyle() == wxTRANSPARENT) return; if (n <= 0) return; - CalcBoundingBox( points[0].x + xoffset, points[0].y + yoffset ); + //Check, if scaling is necessary + bool doScale(true); + long val(10); + if (!xoffset) + if (!yoffset) + if (XLOG2DEV(val)==val) + if (YLOG2DEV(val)==val) + doScale = false; + + GdkPoint *gpts = NULL; + + if (doScale){ + gpts = new GdkPoint[n]; + if (! gpts) + { + wxFAIL_MSG( wxT("Cannot allocate PolyLine") ); + return; + } - for (int i = 0; i < n-1; i++) + for (int i = 0; i < n; i++) { wxCoord x1 = XLOG2DEV(points[i].x + xoffset); - wxCoord x2 = XLOG2DEV(points[i+1].x + xoffset); - wxCoord y1 = YLOG2DEV(points[i].y + yoffset); // oh, what a waste - wxCoord y2 = YLOG2DEV(points[i+1].y + yoffset); + wxCoord y1 = YLOG2DEV(points[i].y + yoffset); - if (m_window) - gdk_draw_line( m_window, m_penGC, x1, y1, x2, y2 ); + CalcBoundingBox( x1 + xoffset, y1 + yoffset ); - CalcBoundingBox( points[i+1].x + xoffset, points[i+1].y + yoffset ); + gpts[i].x = x1; + gpts[i].y = y1; + } } + else { + for (int i = 0; i < n; i++) { + CalcBoundingBox( points[i].x, points[i].y ); + } + + //GdkPoint and wxPoint have the same memory allignment, so we can cast one into another + gpts = reinterpret_cast(points); + } + + if (m_window) + gdk_draw_lines( m_window, m_penGC, gpts, n); + + if (doScale) + delete[] gpts; } void wxWindowDC::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, int WXUNUSED(fillStyle) ) @@ -646,7 +705,21 @@ void wxWindowDC::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wxCoor if (n <= 0) return; - GdkPoint *gdkpoints = new GdkPoint[n+1]; + //Check, if scaling is necessary + bool doScale(true); + long val(10); + if (!xoffset) + if (!yoffset) + if (XLOG2DEV(val)==val) + if (YLOG2DEV(val)==val){ + doScale = false; + } + + GdkPoint *gdkpoints = NULL; + + if (doScale){ + gdkpoints = new GdkPoint[n+1]; //FIXME: Why the "+1" + int i; for (i = 0 ; i < n ; i++) { @@ -655,9 +728,24 @@ void wxWindowDC::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wxCoor CalcBoundingBox( points[i].x + xoffset, points[i].y + yoffset ); } + } + else { + int i(0); + for (; i < n ; ++i) { + CalcBoundingBox( points[i].x, points[i].y ); + } + //GdkPoint and wxPoint have the same memory allignment, so we can cast one into another + gdkpoints = reinterpret_cast (points); + } if (m_window) { + //I think wxSOLID is the most often used style (it is for me), + //so I put it in front of the if ... ifelse's + if (m_brush.GetStyle() == wxSOLID) + { + gdk_draw_polygon( m_window, m_brushGC, TRUE, gdkpoints, n ); + }else if (m_brush.GetStyle() != wxTRANSPARENT) { if ((m_brush.GetStyle() == wxSTIPPLE_MASK_OPAQUE) && (m_brush.GetStipple()->GetMask())) @@ -696,6 +784,7 @@ void wxWindowDC::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wxCoor if (m_pen.GetStyle() != wxTRANSPARENT) { +/* for (i = 0 ; i < n ; i++) { gdk_draw_line( m_window, m_penGC, @@ -704,9 +793,13 @@ void wxWindowDC::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wxCoor gdkpoints[(i+1)%n].x, gdkpoints[(i+1)%n].y); } +*/ + gdk_draw_polygon( m_window, m_penGC, FALSE, gdkpoints, n ); + } } + if (doScale) delete[] gdkpoints; } @@ -950,14 +1043,14 @@ void wxWindowDC::DoDrawEllipse( wxCoord x, wxCoord y, wxCoord width, wxCoord hei 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, 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, @@ -970,7 +1063,7 @@ void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap, bool is_mono = (bitmap.GetBitmap() != NULL); - /* scale/translate size and position */ + // scale/translate size and position int xx = XLOG2DEV(x); int yy = YLOG2DEV(y); @@ -985,7 +1078,7 @@ void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap, int ww = XLOG2DEVREL(w); int hh = YLOG2DEVREL(h); - /* compare to current clipping region */ + // compare to current clipping region if (!m_currentClippingRegion.IsNull()) { wxRegion tmp( xx,yy,ww,hh ); @@ -994,77 +1087,100 @@ void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap, return; } - /* scale bitmap if required */ - wxBitmap use_bitmap; + // scale bitmap if required + wxBitmap use_bitmap = bitmap; if ((w != ww) || (h != hh)) - { - wxImage image( bitmap ); - image.Rescale( ww, hh ); - if (is_mono) - use_bitmap = image.ConvertToMonoBitmap(255,255,255); - else - use_bitmap = image.ConvertToBitmap(); - } - else - { - use_bitmap = bitmap; - } + use_bitmap = use_bitmap.Rescale( 0, 0, ww, hh, ww, hh ); + +#if !GTK_CHECK_VERSION(2,2,0) + // NB: We can't render pixbufs with GTK+ < 2.2, we need to use pixmaps code. + // Pixbufs-based bitmaps with alpha channel don't have a mask, so we + // have to call GetPixmap() here -- it converts the pixbuf into pixmap + // and also creates the mask as a side-effect: + use_bitmap.GetPixmap(); +#endif - /* apply mask if any */ + // apply mask if any GdkBitmap *mask = (GdkBitmap *) NULL; if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap(); - if (useMask && mask) + GdkBitmap *new_mask = (GdkBitmap*) NULL; + + if (useMask && mask) + { + if (!m_currentClippingRegion.IsNull()) { - GdkBitmap *new_mask = (GdkBitmap*) NULL; - if (!m_currentClippingRegion.IsNull()) - { - GdkColor col; - new_mask = gdk_pixmap_new( wxRootWindow->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 ); - gdk_gc_unref( gc ); - } + 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 ); + 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 ); - } + if (is_mono) + { + if (new_mask) + gdk_gc_set_clip_mask( m_textGC, new_mask ); else - { - if (new_mask) - gdk_gc_set_clip_mask( m_penGC, new_mask ); - else - gdk_gc_set_clip_mask( m_penGC, mask ); - gdk_gc_set_clip_origin( m_penGC, xx, yy ); - } + gdk_gc_set_clip_mask( m_textGC, mask ); + gdk_gc_set_clip_origin( m_textGC, xx, yy ); + } + else + { if (new_mask) - gdk_bitmap_unref( 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 ); } + } - /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For - drawing a mono-bitmap (XBitmap) we use the current text GC */ + // 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) - gdk_wx_draw_bitmap( m_window, m_textGC, use_bitmap.GetBitmap(), 0, 0, xx, yy, -1, -1 ); + { + GdkPixmap *bitmap2 = gdk_pixmap_new( wxGetRootWindow()->window, ww, hh, -1 ); + GdkGC *gc = gdk_gc_new( bitmap2 ); + gdk_gc_set_foreground( gc, m_textForegroundColour.GetColor() ); + gdk_gc_set_background( gc, m_textBackgroundColour.GetColor() ); + gdk_wx_draw_bitmap( bitmap2, gc, use_bitmap.GetBitmap(), 0, 0, 0, 0, -1, -1 ); + + gdk_draw_drawable( m_window, m_textGC, bitmap2, 0, 0, xx, yy, -1, -1 ); + + gdk_bitmap_unref( bitmap2 ); + gdk_gc_unref( gc ); + } else - gdk_draw_pixmap( m_window, m_penGC, use_bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 ); + { +#if GTK_CHECK_VERSION(2,2,0) + if (!gtk_check_version(2,2,0) && use_bitmap.HasPixbuf()) + { + gdk_draw_pixbuf(m_window, m_penGC, + use_bitmap.GetPixbuf(), + 0, 0, xx, yy, -1, -1, + GDK_RGB_DITHER_NORMAL, xx, yy); + } + else +#endif + { + gdk_draw_pixmap(m_window, m_penGC, + use_bitmap.GetPixmap(), + 0, 0, xx, yy, -1, -1); + } + } - /* remove mask again if any */ + // remove mask again if any if (useMask && mask) { if (is_mono) @@ -1082,87 +1198,100 @@ void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap, gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() ); } } + + if (new_mask) + gdk_bitmap_unref( new_mask ); } -bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height, - wxDC *source, wxCoord xsrc, wxCoord ysrc, - int logical_func, bool useMask ) +bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, + wxCoord width, wxCoord height, + wxDC *source, + wxCoord xsrc, wxCoord ysrc, + int logical_func, + bool useMask, + wxCoord xsrcMask, wxCoord ysrcMask ) { - /* 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. */ + wxCHECK_MSG( Ok(), false, wxT("invalid window dc") ); - wxCHECK_MSG( Ok(), 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); wxClientDC *srcDC = (wxClientDC*)source; wxMemoryDC *memDC = (wxMemoryDC*)source; - bool use_bitmap_method = FALSE; - bool is_mono = FALSE; + bool use_bitmap_method = false; + bool is_mono = false; + + if (xsrcMask == -1 && ysrcMask == -1) + { + xsrcMask = xsrc; + ysrcMask = ysrc; + } if (srcDC->m_isMemDC) { - if (!memDC->m_selected.Ok()) return FALSE; + if (!memDC->m_selected.Ok()) return false; + + is_mono = (memDC->m_selected.GetDepth() == 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 */ + // 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 && (memDC->m_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; + // 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 (memDC->m_selected.GetDepth() == 1) + 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 */ - is_mono = TRUE; - use_bitmap_method = TRUE; + // 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 == memDC->m_selected.GetWidth()) && (height == memDC->m_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; + // 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 = false; } } CalcBoundingBox( xdest, ydest ); CalcBoundingBox( xdest + width, ydest + height ); - /* scale/translate size and position */ + // 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 */ + // compare to current clipping region if (!m_currentClippingRegion.IsNull()) { wxRegion tmp( xx,yy,ww,hh ); tmp.Intersect( m_currentClippingRegion ); if (tmp.IsEmpty()) - return TRUE; + return true; } int old_logical_func = m_logicalFunction; @@ -1170,52 +1299,72 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord he if (use_bitmap_method) { - /* scale/translate bitmap size */ + // scale/translate bitmap size wxCoord bm_width = memDC->m_selected.GetWidth(); wxCoord bm_height = memDC->m_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 */ + // Scale bitmap if required wxBitmap use_bitmap; - - if ((bm_width != bm_ww) || (bm_height != bm_hh)) + if ((memDC->m_selected.GetWidth()!= bm_ww) || ( memDC->m_selected.GetHeight()!= bm_hh)) { - wxImage image( memDC->m_selected ); - image = image.Scale( bm_ww, bm_hh ); - - if (is_mono) - use_bitmap = image.ConvertToMonoBitmap(255,255,255); - else - use_bitmap = image.ConvertToBitmap(); + // 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 ); + 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; } - /* apply mask if any */ + // apply mask if any GdkBitmap *mask = (GdkBitmap *) NULL; if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap(); + GdkBitmap *new_mask = (GdkBitmap*) NULL; + if (useMask && mask) { - GdkBitmap *new_mask = (GdkBitmap*) NULL; if (!m_currentClippingRegion.IsNull()) { GdkColor col; - new_mask = gdk_pixmap_new( wxRootWindow->window, bm_ww, bm_hh, 1 ); + 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() ); - gdk_gc_set_clip_origin( gc, -xx, -yy ); + // 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 ); @@ -1225,32 +1374,54 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord he if (is_mono) { if (new_mask) + { gdk_gc_set_clip_mask( m_textGC, new_mask ); + gdk_gc_set_clip_origin( m_textGC, cx, cy ); + } else + { gdk_gc_set_clip_mask( m_textGC, mask ); - gdk_gc_set_clip_origin( m_textGC, xx, yy ); + gdk_gc_set_clip_origin( m_textGC, cx-xsrcMask, cy-ysrcMask ); + } } else { if (new_mask) + { gdk_gc_set_clip_mask( m_penGC, new_mask ); + gdk_gc_set_clip_origin( m_penGC, cx, cy ); + } else + { gdk_gc_set_clip_mask( m_penGC, mask ); - gdk_gc_set_clip_origin( m_penGC, xx, yy ); + gdk_gc_set_clip_origin( m_penGC, cx-xsrcMask, cy-ysrcMask ); + } } - if (new_mask) - gdk_bitmap_unref( new_mask ); } - /* Draw XPixmap or XBitmap, depending on what the wxBitmap contains. For - drawing a mono-bitmap (XBitmap) we use the current text GC */ + // 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) - gdk_wx_draw_bitmap( m_window, m_textGC, use_bitmap.GetBitmap(), xsrc, ysrc, xx, yy, ww, hh ); + { + 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 - gdk_draw_pixmap( m_window, m_penGC, use_bitmap.GetPixmap(), xsrc, ysrc, xx, yy, ww, hh ); + { + // 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 ); + } - /* remove mask again if any */ + // remove mask again if any if (useMask && mask) { if (is_mono) @@ -1268,49 +1439,32 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord he gdk_gc_set_clip_region( m_penGC, m_currentClippingRegion.GetRegion() ); } } + + if (new_mask) + gdk_bitmap_unref( new_mask ); } - else /* use_bitmap_method */ + else // use_bitmap_method { if ((width != ww) || (height != hh)) { - /* 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. */ - - wxBitmap bitmap( width, height ); - - /* copy including child window contents */ - gdk_gc_set_subwindow( m_penGC, GDK_INCLUDE_INFERIORS ); - gdk_window_copy_area( bitmap.GetPixmap(), m_penGC, 0, 0, - srcDC->GetWindow(), - xsrc, ysrc, width, height ); - gdk_gc_set_subwindow( m_penGC, GDK_CLIP_BY_CHILDREN ); - - /* scale image */ - wxImage image( bitmap ); - image = image.Scale( ww, hh ); - - /* convert to bitmap */ - bitmap = image.ConvertToBitmap(); - - /* draw scaled bitmap */ - gdk_draw_pixmap( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 ); - + // 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 ); + + // 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 ); } else { - /* No scaling and not a memory dc with a mask either */ + // No scaling and not a memory dc with a mask either - /* copy including child window contents */ + // 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(), @@ -1320,7 +1474,8 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord he } SetLogicalFunction( old_logical_func ); - return TRUE; + + return true; } void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) @@ -1329,57 +1484,93 @@ void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) if (!m_window) return; - GdkFont *font = m_font.GetInternalFont( m_scaleY ); + if (text.empty()) return; - wxCHECK_RET( font, wxT("invalid font") ); + 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") ); + + bool underlined = m_font.Ok() && m_font.GetUnderlined(); + +#if wxUSE_UNICODE + const wxCharBuffer data = wxConvUTF8.cWC2MB( text ); +#else + const wxWCharBuffer wdata = wxConvLocal.cMB2WC( text ); + if ( !wdata ) + return; + const wxCharBuffer data = wxConvUTF8.cWC2MB( wdata ); #endif + size_t datalen = strlen((const char*)data); + pango_layout_set_text( m_layout, (const char*) data, datalen); - x = XLOG2DEV(x); - y = YLOG2DEV(y); + 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); + pango_layout_set_attributes(m_layout, attrs); + pango_attr_list_unref(attrs); + } -#ifdef __WXGTK20__ - /* FIXME: the layout engine should probably be abstracted at a higher level in wxDC... */ - PangoLayout *layout = pango_layout_new(m_context); - pango_layout_set_font_description(layout, m_fontdesc); + int w,h; + + if (fabs(m_scaleY - 1.0) > 0.00001) { - wxWX2MBbuf data = text.mb_str(wxConvUTF8); - pango_layout_set_text(layout, data, strlen(data)); + // 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. + 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 ); } - PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data; - PangoRectangle rect; - pango_layout_line_get_extents(line, NULL, &rect); - wxCoord width = rect.width; - wxCoord height = rect.height; - gdk_draw_layout( m_window, m_textGC, x, y, layout ); -#else - wxCoord width = gdk_string_width( font, text.mbc_str() ); - wxCoord height = font->ascent + font->descent; - /* CMB 21/5/98: draw text background if mode is wxSOLID */ - if (m_backgroundMode == wxSOLID) + else { - 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() ); + 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. + gdk_draw_layout( m_window, m_textGC, x, y, m_layout ); } - gdk_draw_string( m_window, font, m_textGC, x, y + font->ascent, text.mbc_str() ); -#endif - /* 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()) + if (underlined) { - 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); + // undo underline attributes setting: + pango_layout_set_attributes(m_layout, NULL); } -#ifdef __WXGTK20__ - g_object_unref( G_OBJECT( layout ) ); -#endif + wxCoord width = w; + wxCoord height = h; width = wxCoord(width / m_scaleX); height = wxCoord(height / m_scaleY); @@ -1387,9 +1578,14 @@ void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) CalcBoundingBox (x, y); } + +// 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 wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, double angle ) { - if (angle == 0.0) + if ( wxIsNullDouble(angle) ) { DrawText(text, x, y); return; @@ -1399,24 +1595,22 @@ void wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, if (!m_window) return; - GdkFont *font = m_font.GetInternalFont( m_scaleY ); + wxCoord w; + wxCoord h; - wxCHECK_RET( font, wxT("invalid font") ); - - // 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 + 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(*wxWHITE_BRUSH); + dc.SetBackground(*wxBLACK_BRUSH); dc.SetBrush(*wxBLACK_BRUSH); dc.Clear(); + dc.SetTextForeground( *wxWHITE ); dc.DrawText(text, 0, 0); - dc.SetFont(wxNullFont); dc.SelectObject(wxNullBitmap); // Calculate the size of the rotated bounding box. @@ -1439,47 +1633,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); - GdkColor *colText = m_textForegroundColour.GetColor(), - *colBack = m_textBackgroundColour.GetColor(); + wxImage image = src.ConvertToImage(); - bool textColSet = TRUE; + image.ConvertColourToAlpha( m_textForegroundColour.Red(), + m_textForegroundColour.Green(), + m_textForegroundColour.Blue() ); + image = image.Rotate( rad, wxPoint(0,0) ); - unsigned char *data = image.GetData(); + 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(); - // 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 ); + 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 ); - textColSet = textPixel; - } + 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...) @@ -1492,9 +1679,6 @@ 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); @@ -1505,30 +1689,81 @@ void wxWindowDC::DoGetTextExtent(const wxString &string, wxCoord *descent, wxCoord *externalLeading, wxFont *theFont) const { - 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; // ?? + if ( width ) + *width = 0; + if ( height ) + *height = 0; + if ( descent ) + *descent = 0; + if ( externalLeading ) + *externalLeading = 0; + + if (string.empty()) + { + return; + } + + // 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 + + if ( !dataUTF8 ) + { + // hardly ideal, but what else can we do if conversion failed? + return; + } + + pango_layout_set_text( m_layout, dataUTF8, strlen(dataUTF8) ); + + if (descent) + { + int h; + pango_layout_get_pixel_size( m_layout, width, &h ); + PangoLayoutIter *iter = pango_layout_get_iter(m_layout); + int baseline = pango_layout_iter_get_baseline(iter); + pango_layout_iter_free(iter); + *descent = h - PANGO_PIXELS(baseline); + + if (height) + *height = (wxCoord) h; + } + else + { + pango_layout_get_pixel_size( m_layout, width, height ); + } + + // Reset old font description + if (theFont) + pango_layout_set_font_description( m_layout, m_fontdesc ); } wxCoord wxWindowDC::GetCharWidth() const { - GdkFont *font = m_font.GetInternalFont( m_scaleY ); - wxCHECK_MSG( font, -1, wxT("invalid font") ); - - return wxCoord(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; } wxCoord wxWindowDC::GetCharHeight() const { - GdkFont *font = m_font.GetInternalFont( m_scaleY ); - wxCHECK_MSG( font, -1, wxT("invalid font") ); - - return wxCoord((font->ascent + font->descent) / m_scaleY); + pango_layout_set_text( m_layout, "H", 1 ); + int h; + pango_layout_get_pixel_size( m_layout, NULL, &h ); + return h; } void wxWindowDC::Clear() @@ -1537,6 +1772,11 @@ void wxWindowDC::Clear() 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 @@ -1546,9 +1786,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; } @@ -1559,14 +1797,45 @@ 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 ) { m_font = font; -#ifdef __WXGTK20__ - // fix fontdesc? -#endif + + 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( G_OBJECT( m_layout ) ); + + m_layout = pango_layout_new( m_context ); + } + } + + pango_layout_set_font_description( m_layout, m_fontdesc ); + } } void wxWindowDC::SetPen( const wxPen &pen ) @@ -1595,6 +1864,12 @@ 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 wxGTKDash dotted[] = {1, 1}; @@ -1660,7 +1935,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]; @@ -1677,7 +1951,6 @@ void wxWindowDC::SetPen( const wxPen &pen ) gdk_gc_set_dashes( m_penGC, 0, (wxGTKDash*)req_dash, req_nb_dash ); } } -#endif GdkCapStyle capStyle = GDK_CAP_ROUND; switch (m_pen.GetCap()) @@ -1752,7 +2025,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; @@ -1797,7 +2070,7 @@ void wxWindowDC::SetBackground( const wxBrush &brush ) } } - 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; @@ -1816,12 +2089,11 @@ void wxWindowDC::SetLogicalFunction( int function ) 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; @@ -1838,12 +2110,9 @@ void wxWindowDC::SetLogicalFunction( int function ) // unsupported by GTK case wxNOR: mode = GDK_COPY; break; -#endif default: - { wxFAIL_MSG( wxT("unsupported logical function") ); - break; - } + mode = GDK_COPY; } m_logicalFunction = function; @@ -1861,30 +2130,36 @@ void wxWindowDC::SetTextForeground( const wxColour &col ) { 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 ) { 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 ) @@ -2019,213 +2294,58 @@ void wxWindowDC::Destroy() void wxWindowDC::ComputeScaleAndOrigin() { - /* CMB: copy scale to see if it changes */ - double origScaleX = m_scaleX; - double origScaleY = m_scaleY; + const wxRealPoint origScale(m_scaleX, m_scaleY); wxDC::ComputeScaleAndOrigin(); - /* 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.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 ); - } + // 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 { - return wxSize(100, 100); + 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 { - wxFAIL_MSG(wxT("not implemented")); - - return -1; + return gdk_drawable_get_depth(m_window); } -#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 - -/* iterative version */ -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); - } - } -} - -/* 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() -{ - wx_stack_top = wx_spline_stack; - wx_stack_count = 0; -} - -void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) -{ - 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++; -} - -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) -{ - 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(); - } -} +IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxClientDC) -void wxWindowDC::DoDrawSpline( wxList *points ) +// 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) { - wxCHECK_RET( Ok(), wxT("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); - - wx_spline_add_point(x1, y1); - - while ((node = node->Next()) != NULL) + 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) { - 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; - - wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4); - - cx1 = cx4; - cy1 = cy4; - cx2 = (double)(cx1 + x2) / 2; - cy2 = (double)(cy1 + y2) / 2; + 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); } - - wx_spline_add_point( cx1, cy1 ); - wx_spline_add_point( x2, y2 ); - - wx_spline_draw_point_array( this ); } -#endif // wxUSE_SPLINE - -//----------------------------------------------------------------------------- -// wxPaintDC -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxClientDC) - wxPaintDC::wxPaintDC( wxWindow *win ) : wxClientDC( win ) { @@ -2233,18 +2353,25 @@ wxPaintDC::wxPaintDC( wxWindow *win ) if (!win->m_clipPaintRegion) return; + wxSize sz = win->GetSize(); m_paintClippingRegion = win->GetUpdateRegion(); + wxLimitRegionToSize(m_paintClippingRegion, sz); + GdkRegion *region = m_paintClippingRegion.GetRegion(); if ( region ) { m_currentClippingRegion.Union( m_paintClippingRegion ); + wxLimitRegionToSize(m_currentClippingRegion, sz); + + if (sz.x <= 0 || sz.y <= 0) + return ; 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 ); } -#endif +#endif // USE_PAINT_REGION } //----------------------------------------------------------------------------- @@ -2256,13 +2383,21 @@ 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 ); + m_owner->GetClientSize( width, height ); } // ---------------------------------------------------------------------------- @@ -2284,7 +2419,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxDCModule, wxModule) bool wxDCModule::OnInit() { wxInitGCPool(); - return TRUE; + return true; } void wxDCModule::OnExit()