X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/c8dbe0aee2a10e468fad01a25e2ce041d992d62a..0b92df7943aeb25e6511cec28343a1512c45b519:/src/gtk/dcclient.cpp diff --git a/src/gtk/dcclient.cpp b/src/gtk/dcclient.cpp index 929d71bfb9..47c3ec2174 100644 --- a/src/gtk/dcclient.cpp +++ b/src/gtk/dcclient.cpp @@ -3,14 +3,17 @@ // 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__ +#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) #pragma implementation "dcclient.h" #endif +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + #ifdef __VMS #define XCopyPlane XCOPYPLANE #endif @@ -20,6 +23,7 @@ #include "wx/image.h" #include "wx/module.h" #include "wx/log.h" +#include "wx/fontutil.h" #include "wx/gtk/win_gtk.h" @@ -170,25 +174,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) { @@ -204,6 +239,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; @@ -211,7 +271,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) { @@ -241,6 +301,7 @@ wxWindowDC::wxWindowDC() m_owner = (wxWindow *)NULL; #ifdef __WXGTK20__ m_context = (PangoContext *)NULL; + m_layout = (PangoLayout *)NULL; m_fontdesc = (PangoFontDescription *)NULL; #endif } @@ -261,9 +322,9 @@ wxWindowDC::wxWindowDC( wxWindow *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(); @@ -273,17 +334,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; + 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; - /* not realized ? */ + // Window not realized ? if (!m_window) { - /* don't report problems */ + // Don't report problems as per MSW. m_ok = TRUE; return; @@ -306,6 +368,13 @@ wxWindowDC::wxWindowDC( wxWindow *window ) wxWindowDC::~wxWindowDC() { Destroy(); + +#ifdef __WXGTK20__ + if (m_layout) + g_object_unref( G_OBJECT( m_layout ) ); + if (m_fontdesc) + pango_font_description_free( m_fontdesc ); +#endif } void wxWindowDC::SetUpDC() @@ -401,37 +470,13 @@ void wxWindowDC::DoGetSize( int* width, int* height ) const m_owner->GetSize(width, height); } -void wxWindowDC::DoFloodFill( wxCoord x, wxCoord y, - const wxColour & col, int style ) -{ - if (GetBrush().GetStyle() == wxTRANSPARENT) - { - wxLogDebug(wxT("In FloodFill, current Brush is transparent, no filling done")); - return ; - } - int height = 0; - int width = 0; - this->GetSize(&width, &height); - //it would be nice to fail if we don't get a sensible size... - if (width < 1 || height < 1) - { - wxLogError(wxT("In FloodFill, dc.GetSize routine failed, method not supported by this DC")); - return ; - } - - //this is much faster than doing the individual pixels - wxMemoryDC memdc; - wxBitmap bitmap(width, height); - memdc.SelectObject(bitmap); - memdc.Blit(0, 0, width, height, (wxDC*) this, 0, 0); - memdc.SelectObject(wxNullBitmap); +extern bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y, + const wxColour & col, int style); - wxImage image = bitmap.ConvertToImage(); - image.DoFloodFill (x,y, GetBrush(), col, style, GetLogicalFunction()); - bitmap = wxBitmap(image); - memdc.SelectObject(bitmap); - Blit(0, 0, width, height, &memdc, 0, 0); - memdc.SelectObject(wxNullBitmap); +bool wxWindowDC::DoFloodFill(wxCoord x, wxCoord y, + const wxColour& col, int style) +{ + return wxDoFloodFill(this, x, y, col, style); } bool wxWindowDC::DoGetPixel( wxCoord x1, wxCoord y1, wxColour *col ) const @@ -653,20 +698,28 @@ 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 ); + GdkPoint *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; } + + if (m_window) + gdk_draw_lines( m_window, m_penGC, gpts, n); + + delete[] gpts; } void wxWindowDC::DoDrawPolygon( int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, int WXUNUSED(fillStyle) ) @@ -1376,32 +1429,80 @@ void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) wxCHECK_RET( Ok(), 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") ); - -#if defined(__WXGTK20__) - wxCHECK_RET( m_context, wxT("no Pango context") ); #endif x = XLOG2DEV(x); y = YLOG2DEV(y); -#if defined(__WXGTK20__) && wxUSE_WCHAR_T - // 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); +#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 )); + + int w,h; + + if (m_scaleY != 1.0) { - const 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 + { + 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 ); + } + + 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; @@ -1413,7 +1514,6 @@ void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) 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 // GTK+ 2.0/1.x /* CMB 17/7/98: simple underline: ignores scaling and underlying X font's XA_UNDERLINE_POSITION and XA_UNDERLINE_THICKNESS @@ -1424,10 +1524,7 @@ 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); } - -#if defined(__WXGTK20__) && wxUSE_WCHAR_T - g_object_unref( G_OBJECT( layout ) ); -#endif +#endif // GTK+ 2.0/1.x width = wxCoord(width / m_scaleX); height = wxCoord(height / m_scaleY); @@ -1447,6 +1544,10 @@ void wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, if (!m_window) return; +#ifdef __WXGTK20__ + // implement later without GdkFont for GTK 2.0 + return; +#else GdkFont *font = m_font.GetInternalFont( m_scaleY ); wxCHECK_RET( font, wxT("invalid font") ); @@ -1523,7 +1624,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 ); } } } @@ -1545,6 +1646,7 @@ void wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, // update the bounding box CalcBoundingBox(x + minX, y + minY); CalcBoundingBox(x + maxX, y + maxY); +#endif } void wxWindowDC::DoGetTextExtent(const wxString &string, @@ -1552,30 +1654,83 @@ void wxWindowDC::DoGetTextExtent(const wxString &string, wxCoord *descent, wxCoord *externalLeading, wxFont *theFont) const { + if (string.IsEmpty()) + { + if (width) (*width) = 0; + if (height) (*height) = 0; + return; + } + +#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 ); + pango_layout_set_text( m_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( m_layout, (const char*) data, strlen( (const char*) data )); +#endif + + 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; + } + if (externalLeading) (*externalLeading) = 0; // ?? + + // Reset old font description + if (theFont) + pango_layout_set_font_description( m_layout, m_fontdesc ); +#else 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 } wxCoord wxWindowDC::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 w; +#else GdkFont *font = m_font.GetInternalFont( m_scaleY ); wxCHECK_MSG( font, -1, wxT("invalid font") ); return wxCoord(gdk_string_width( font, "H" ) / m_scaleX); +#endif } wxCoord wxWindowDC::GetCharHeight() 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 } void wxWindowDC::Clear() @@ -1584,6 +1739,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 @@ -1593,9 +1753,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; } @@ -1606,15 +1764,51 @@ 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 ) { - wxCHECK_RET( font.Ok(), _T("invalid font in wxWindowDC::SetFont") ); - m_font = font; + #ifdef __WXGTK20__ - // fix fontdesc? + 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; + + // 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(); + + // 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 ); + } #endif } @@ -1726,7 +1920,7 @@ void wxWindowDC::SetPen( const wxPen &pen ) gdk_gc_set_dashes( m_penGC, 0, (wxGTKDash*)req_dash, req_nb_dash ); } } -#endif +#endif // GTK+ > 1.0 GdkCapStyle capStyle = GDK_CAP_ROUND; switch (m_pen.GetCap()) @@ -1865,12 +2059,12 @@ 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) +#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; @@ -1887,12 +2081,10 @@ void wxWindowDC::SetLogicalFunction( int function ) // unsupported by GTK case wxNOR: mode = GDK_COPY; break; -#endif +#endif // GTK+ > 1.0 default: - { wxFAIL_MSG( wxT("unsupported logical function") ); - break; - } + mode = GDK_COPY; } m_logicalFunction = function;