X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/d90c9596c1476f4bb1c728dc0169ef16f4d622d4..82a16d7e5e5c83e95a4caa7314de2dbfbd1debdc:/src/gtk1/dcclient.cpp?ds=inline diff --git a/src/gtk1/dcclient.cpp b/src/gtk1/dcclient.cpp index 802358014e..3af3e2924f 100644 --- a/src/gtk1/dcclient.cpp +++ b/src/gtk1/dcclient.cpp @@ -191,7 +191,7 @@ static void wxInitGCPool() // 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. + // in wxGetPoolGC. wxFAIL_MSG( wxT("Cannot allocate GC pool") ); return; } @@ -237,13 +237,13 @@ 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)); + (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)); + memset(&wxGCPool[wxGCPoolSize], 0, + GC_POOL_ALLOC_SIZE*sizeof(wxGC)); // Initialize entry we will return. wxGCPool[wxGCPoolSize].m_gc = gdk_gc_new( window ); @@ -773,6 +773,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, @@ -781,6 +782,9 @@ 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 ); + } } @@ -1075,6 +1079,14 @@ void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap, wxBitmap use_bitmap = bitmap; if ((w != ww) || (h != hh)) 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 GdkBitmap *mask = (GdkBitmap *) NULL; @@ -1143,7 +1155,21 @@ void wxWindowDC::DoDrawBitmap( const wxBitmap &bitmap, } 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 (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 @@ -1270,11 +1296,14 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, wxCoord bm_width = memDC->m_selected.GetWidth(); wxCoord bm_height = memDC->m_selected.GetHeight(); - // get clip coords - wxRegion tmp( xx,yy,ww,hh ); - tmp.Intersect( m_currentClippingRegion ); - wxCoord cx,cy,cw,ch; - tmp.GetBox(cx,cy,cw,ch); + // 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; @@ -1285,16 +1314,23 @@ bool wxWindowDC::DoBlit( wxCoord xdest, wxCoord ydest, 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)) { - use_bitmap = memDC->m_selected.Rescale(cx-xx,cy-yy,cw,ch,bm_ww,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 ); + 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 { - // FIXME: use cx,cy,cw,ch here, too? + // Don't scale bitmap use_bitmap = memDC->m_selected; } @@ -1453,17 +1489,33 @@ void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) 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 - pango_layout_set_text( m_layout, (const char*) data, strlen( (const char*) data )); + size_t datalen = strlen((const char*)data); + pango_layout_set_text( m_layout, (const char*) 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); + pango_layout_set_attributes(m_layout, attrs); + pango_attr_list_unref(attrs); + } int w,h; - - if (abs(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. @@ -1506,6 +1558,12 @@ void wxWindowDC::DoDrawText( const wxString &text, wxCoord x, wxCoord y ) // Draw layout. gdk_draw_layout( m_window, m_textGC, x, y, m_layout ); } + + if (underlined) + { + // undo underline attributes setting: + pango_layout_set_attributes(m_layout, NULL); + } wxCoord width = w; wxCoord height = h; @@ -1539,6 +1597,11 @@ 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) @@ -1551,26 +1614,31 @@ void wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, if (!m_window) return; -#ifdef __WXGTK20__ + wxCoord w; + wxCoord h; + +#ifdef __WXGTK20__ // implement later without GdkFont for GTK 2.0 - return; + GetTextExtent(text, &w, &h, NULL,NULL, &m_font); + #else GdkFont *font = m_font.GetInternalFont( m_scaleY ); 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; - + w = gdk_string_width( font, text.mbc_str() ); + h = font->ascent + font->descent; +#endif // 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); @@ -1587,54 +1655,45 @@ void wxWindowDC::DoDrawRotatedText( const wxString &text, wxCoord x, wxCoord y, y4 = h*dx; double x3 = x4 + x2, y3 = y4 + y2; - + // calc max and min wxCoord maxX = (wxCoord)(dmax(x2, dmax(x3, x4)) + 0.5), maxY = (wxCoord)(dmax(y2, dmax(y3, y4)) + 0.5), minX = (wxCoord)(dmin(x2, dmin(x3, x4)) - 0.5), minY = (wxCoord)(dmin(y2, dmin(y3, y4)) - 0.5); - // 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; + wxImage image = src.ConvertToImage(); - unsigned char *data = image.GetData(); + 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; + 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 ); - // 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 ); - - textColSet = textPixel; - } - - // 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...) @@ -1647,13 +1706,9 @@ 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 } void wxWindowDC::DoGetTextExtent(const wxString &string, @@ -1661,10 +1716,17 @@ void wxWindowDC::DoGetTextExtent(const wxString &string, wxCoord *descent, wxCoord *externalLeading, wxFont *theFont) const { + if ( width ) + *width = 0; + if ( height ) + *height = 0; + if ( descent ) + *descent = 0; + if ( externalLeading ) + *externalLeading = 0; + if (string.IsEmpty()) { - if (width) (*width) = 0; - if (height) (*height) = 0; return; } @@ -1676,38 +1738,61 @@ void wxWindowDC::DoGetTextExtent(const wxString &string, // 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 )); + const char *dataUTF8 = (const char *)data; #else const wxWCharBuffer wdata = wxConvLocal.cMB2WC( string ); + if ( !wdata ) + { + if (width) (*width) = 0; + if (height) (*height) = 0; + return; + } const wxCharBuffer data = wxConvUTF8.cWC2MB( wdata ); - pango_layout_set_text( m_layout, (const char*) data, strlen( (const char*) data )); + 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) ); int w,h; pango_layout_get_pixel_size( m_layout, &w, &h ); - if (width) (*width) = (wxCoord) w; - if (height) (*height) = (wxCoord) h; + if (width) + *width = (wxCoord) w; + if (height) + *height = (wxCoord) h; if (descent) { - // Do something about metrics here. TODO. - (*descent) = 0; + 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 (externalLeading) (*externalLeading) = 0; // ?? // Reset old font description if (theFont) pango_layout_set_font_description( m_layout, m_fontdesc ); -#else +#else // GTK+ 1.x wxFont fontToUse = m_font; - if (theFont) fontToUse = *theFont; + 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 + if ( !font ) + return; + + 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); +#endif // GTK+ 2/1 } wxCoord wxWindowDC::GetCharWidth() const @@ -2317,6 +2402,25 @@ int wxWindowDC::GetDepth() const IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxClientDC) +// 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) +{ + wxRect originalRect = region.GetBox(); + wxRect rect(originalRect); + if (rect.width + rect.x > sz.x) + rect.width = sz.x - rect.x; + if (rect.height + rect.y > sz.y) + rect.height = sz.y - rect.y; + if (rect != originalRect) + { + region = wxRegion(rect); + wxLogTrace(wxT("painting"), wxT("Limiting region from %d, %d, %d, %d to %d, %d, %d, %d\n"), + originalRect.x, originalRect.y, originalRect.width, originalRect.height, + rect.x, rect.y, rect.width, rect.height); + } +} + wxPaintDC::wxPaintDC( wxWindow *win ) : wxClientDC( win ) { @@ -2324,21 +2428,23 @@ 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_paintClippingRegion = win->GetUpdateRegion(); - GdkRegion *region = m_paintClippingRegion.GetRegion(); - if ( region ) - { - m_currentClippingRegion.Union( m_paintClippingRegion ); + m_currentClippingRegion.Union( m_paintClippingRegion ); + wxLimitRegionToSize(m_currentClippingRegion, sz); - 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 ); - } + 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 // USE_PAINT_REGION }