X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/0cbff1201aa47e2b73ec90a97886f18e88270ea6..c19b738e74e01e7301aec7815b5bac9782b3c9db:/src/gtk/dcclient.cpp?ds=sidebyside diff --git a/src/gtk/dcclient.cpp b/src/gtk/dcclient.cpp index f318b34c92..8a33377614 100644 --- a/src/gtk/dcclient.cpp +++ b/src/gtk/dcclient.cpp @@ -19,6 +19,8 @@ #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" @@ -169,25 +171,56 @@ 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) { @@ -203,6 +236,31 @@ static GdkGC* wxGetPoolGC( GdkWindow *window, wxPoolGCType type ) } } + // 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,7 +268,7 @@ 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) { @@ -246,6 +304,8 @@ wxWindowDC::wxWindowDC() wxWindowDC::wxWindowDC( wxWindow *window ) { + wxASSERT_MSG( window, wxT("DC needs a window") ); + m_penGC = (GdkGC *) NULL; m_brushGC = (GdkGC *) NULL; m_textGC = (GdkGC *) NULL; @@ -256,8 +316,6 @@ wxWindowDC::wxWindowDC( wxWindow *window ) 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 @@ -273,6 +331,11 @@ wxWindowDC::wxWindowDC( wxWindow *window ) #ifdef __WXGTK20__ m_context = gtk_widget_get_pango_context( widget ); + + // Always take Xft context to get matching fonts + // for display and printing. + // m_context = pango_xft_get_context (GDK_DISPLAY (), DefaultScreen (GDK_DISPLAY ())); + m_fontdesc = widget->style->font_desc; #endif @@ -400,10 +463,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 @@ -416,7 +482,7 @@ bool wxWindowDC::DoGetPixel( wxCoord x1, wxCoord y1, wxColour *col ) const 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; } @@ -999,18 +1065,18 @@ void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap, wxBitmap use_bitmap; if ((w != ww) || (h != hh)) { - wxImage image( bitmap ); + wxImage image = bitmap.ConvertToImage(); image.Rescale( ww, hh ); if (is_mono) - use_bitmap = image.ConvertToMonoBitmap(255,255,255); + use_bitmap = wxBitmap(image.ConvertToMono(255,255,255), 1); else - use_bitmap = image.ConvertToBitmap(); + use_bitmap = wxBitmap(image); } else { use_bitmap = bitmap; } - + /* apply mask if any */ GdkBitmap *mask = (GdkBitmap *) NULL; if (use_bitmap.GetMask()) mask = use_bitmap.GetMask()->GetBitmap(); @@ -1018,6 +1084,7 @@ void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap, if (useMask && mask) { GdkBitmap *new_mask = (GdkBitmap*) NULL; +#ifndef __WXGTK20__ // TODO fix crash if (!m_currentClippingRegion.IsNull()) { GdkColor col; @@ -1037,7 +1104,7 @@ void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap, gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, ww, hh ); gdk_gc_unref( gc ); } - +#endif if (is_mono) { if (new_mask) @@ -1054,6 +1121,7 @@ void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap, gdk_gc_set_clip_mask( m_penGC, mask ); gdk_gc_set_clip_origin( m_penGC, xx, yy ); } + if (new_mask) gdk_bitmap_unref( new_mask ); } @@ -1104,10 +1172,10 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, if (!m_window) return FALSE; -#if 0 +#if 1 // transform the source DC coords to the device ones - xsrc = XLOG2DEV(xsrc); - ysrc = YLOG2DEV(ysrc); + xsrc = source->XLOG2DEV(xsrc); + ysrc = source->YLOG2DEV(ysrc); #endif wxClientDC *srcDC = (wxClientDC*)source; @@ -1199,13 +1267,13 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, if ((bm_width != bm_ww) || (bm_height != bm_hh)) { - wxImage image( memDC->m_selected ); + wxImage image = memDC->m_selected.ConvertToImage(); image = image.Scale( bm_ww, bm_hh ); if (is_mono) - use_bitmap = image.ConvertToMonoBitmap(255,255,255); + use_bitmap = wxBitmap(image.ConvertToMono(255,255,255), 1); else - use_bitmap = image.ConvertToBitmap(); + use_bitmap = wxBitmap(image); } else { @@ -1219,6 +1287,7 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, if (useMask && mask) { GdkBitmap *new_mask = (GdkBitmap*) NULL; +#ifndef __WXGTK20__ // TODO fix crash if (!m_currentClippingRegion.IsNull()) { GdkColor col; @@ -1238,7 +1307,7 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, gdk_draw_rectangle( new_mask, gc, TRUE, 0, 0, bm_ww, bm_hh ); gdk_gc_unref( gc ); } - +#endif if (is_mono) { if (new_mask) @@ -1313,11 +1382,11 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, gdk_gc_set_subwindow( m_penGC, GDK_CLIP_BY_CHILDREN ); /* scale image */ - wxImage image( bitmap ); + wxImage image = bitmap.ConvertToImage(); image = image.Scale( ww, hh ); /* convert to bitmap */ - bitmap = image.ConvertToBitmap(); + bitmap = wxBitmap(image); /* draw scaled bitmap */ gdk_draw_pixmap( m_window, m_penGC, bitmap.GetPixmap(), 0, 0, xx, yy, -1, -1 ); @@ -1357,13 +1426,19 @@ void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) x = XLOG2DEV(x); y = YLOG2DEV(y); -#if defined(__WXGTK20__) && wxUSE_WCHAR_T - /* FIXME: the layout engine should probably be abstracted at a higher level in wxDC... */ +#if defined(__WXGTK20__) + // TODO: the layout engine should be abstracted at a higher level! PangoLayout *layout = pango_layout_new(m_context); pango_layout_set_font_description(layout, m_fontdesc); { - wxWX2MBbuf data = text.mb_str(wxConvUTF8); - pango_layout_set_text(layout, data, strlen(data)); +#if wxUSE_UNICODE + const wxCharBuffer data = wxConvUTF8.cWC2MB( text ); + pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data )); +#else + const wxWCharBuffer wdata = wxConvLocal.cMB2WC( text ); + const wxCharBuffer data = wxConvUTF8.cWC2MB( wdata ); + pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data )); +#endif } PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data; PangoRectangle rect; @@ -1371,18 +1446,17 @@ void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) wxCoord width = rect.width; wxCoord height = rect.height; gdk_draw_layout( m_window, m_textGC, x, y, layout ); -#else +#else // GTK+ 1.x 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) + + if ( m_backgroundMode == wxSOLID ) { 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() ); } 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 @@ -1393,8 +1467,9 @@ void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) 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 -#if defined(__WXGTK20__) && wxUSE_WCHAR_T +#if defined(__WXGTK20__) g_object_unref( G_OBJECT( layout ) ); #endif @@ -1433,7 +1508,6 @@ void wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, dc.SetBrush(*wxBLACK_BRUSH); dc.Clear(); dc.DrawText(text, 0, 0); - dc.SetFont(wxNullFont); dc.SelectObject(wxNullBitmap); // Calculate the size of the rotated bounding box. @@ -1457,7 +1531,7 @@ void wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, minY = (wxCoord)(dmin(y2, dmin(y3, y4)) - 0.5); // prepare to blit-with-rotate the bitmap to the DC - wxImage image(src); + wxImage image = src.ConvertToImage(); GdkColor *colText = m_textForegroundColour.GetColor(), *colBack = m_textBackgroundColour.GetColor(); @@ -1493,7 +1567,7 @@ void wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, // 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) ); + XLOG2DEV(x) + dstX, YLOG2DEV(y) + dstY ); } } } @@ -1524,12 +1598,48 @@ void wxWindowDC::DoGetTextExtent(const wxString &string, { wxFont fontToUse = m_font; if (theFont) fontToUse = *theFont; - + if (string.IsEmpty()) + { + if (width) (*width) = 0; + if (height) (*height) = 0; + return; + } + +#ifdef __WXGTK20__ + PangoFontDescription *desc = fontToUse.GetNativeFontInfo()->description; + PangoLayout *layout = pango_layout_new(m_context); + pango_layout_set_font_description(layout, desc); +#if wxUSE_UNICODE + const wxCharBuffer data = wxConvUTF8.cWC2MB( string ); + pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data )); +#else + const wxWCharBuffer wdata = wxConvLocal.cMB2WC( string ); + const wxCharBuffer data = wxConvUTF8.cWC2MB( wdata ); + pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data )); +#endif + PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data; + + PangoRectangle rect; + pango_layout_line_get_extents(line, NULL, &rect); + + + if (width) (*width) = (wxCoord) (rect.width / PANGO_SCALE); + if (height) (*height) = (wxCoord) (rect.height / PANGO_SCALE); + if (descent) + { + // Do something about metrics here + (*descent) = 0; + } + if (externalLeading) (*externalLeading) = 0; // ?? + + g_object_unref( G_OBJECT( layout ) ); +#else 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 } wxCoord wxWindowDC::GetCharWidth() const @@ -1554,6 +1664,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 @@ -1563,9 +1678,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; } @@ -1576,13 +1689,22 @@ 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 ) { + // It is common practice to set the font to wxNullFont, so + // don't consider it to be an error + // wxCHECK_RET( font.Ok(), _T("invalid font in wxWindowDC::SetFont") ); + m_font = font; #ifdef __WXGTK20__ - // fix fontdesc? + m_fontdesc = m_font.GetNativeFontInfo()->description; #endif } @@ -1878,30 +2000,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 )