From 42634ee7355c628f88908a9c4a73f3b4ee0335c5 Mon Sep 17 00:00:00 2001 From: Owen Taylor Date: Mon, 5 Nov 2001 17:48:58 +0000 Subject: [PATCH] Redo Xft support to go directly to Picture objects instead of using Mon Nov 5 12:46:44 2001 Owen Taylor * gdk/x11/gdkdrawable-x11.[ch] gdk/x11/gdkgc-x11.c gdk/x11/gdkpixmap-x11.c gdk/x11/gdkprivate-x11.h gdk/x11/gdkwindow-x11.c: Redo Xft support to go directly to Picture objects instead of using XftDraw. This fixes the problem where we weren't able to properly destroy XftDraw objects before destroying the accompanying windows, and probably improves efficiency a bit too. (#50214) --- ChangeLog | 11 +++ ChangeLog.pre-2-0 | 11 +++ ChangeLog.pre-2-10 | 11 +++ ChangeLog.pre-2-2 | 11 +++ ChangeLog.pre-2-4 | 11 +++ ChangeLog.pre-2-6 | 11 +++ ChangeLog.pre-2-8 | 11 +++ gdk/x11/gdkdrawable-x11.c | 136 ++++++++++++++++++++------------------ gdk/x11/gdkdrawable-x11.h | 10 +++ gdk/x11/gdkgc-x11.c | 102 +++++++++++++++++++++++++--- gdk/x11/gdkpixmap-x11.c | 9 +++ gdk/x11/gdkprivate-x11.h | 16 +++-- gdk/x11/gdkwindow-x11.c | 9 +++ 13 files changed, 282 insertions(+), 77 deletions(-) diff --git a/ChangeLog b/ChangeLog index e8912c4145..2f34bfae10 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +Mon Nov 5 12:46:44 2001 Owen Taylor + + * gdk/x11/gdkdrawable-x11.[ch] gdk/x11/gdkgc-x11.c + gdk/x11/gdkpixmap-x11.c gdk/x11/gdkprivate-x11.h + gdk/x11/gdkwindow-x11.c: Redo Xft support to go + directly to Picture objects instead of using XftDraw. + This fixes the problem where we weren't able to + properly destroy XftDraw objects before destroying + the accompanying windows, and probably improves + efficiency a bit too. (#50214) + Mon Nov 5 10:01:49 2001 Owen Taylor * gdk/x11/gdkgeometry-x11.c (gdk_window_compute_position): diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index e8912c4145..2f34bfae10 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,14 @@ +Mon Nov 5 12:46:44 2001 Owen Taylor + + * gdk/x11/gdkdrawable-x11.[ch] gdk/x11/gdkgc-x11.c + gdk/x11/gdkpixmap-x11.c gdk/x11/gdkprivate-x11.h + gdk/x11/gdkwindow-x11.c: Redo Xft support to go + directly to Picture objects instead of using XftDraw. + This fixes the problem where we weren't able to + properly destroy XftDraw objects before destroying + the accompanying windows, and probably improves + efficiency a bit too. (#50214) + Mon Nov 5 10:01:49 2001 Owen Taylor * gdk/x11/gdkgeometry-x11.c (gdk_window_compute_position): diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index e8912c4145..2f34bfae10 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,14 @@ +Mon Nov 5 12:46:44 2001 Owen Taylor + + * gdk/x11/gdkdrawable-x11.[ch] gdk/x11/gdkgc-x11.c + gdk/x11/gdkpixmap-x11.c gdk/x11/gdkprivate-x11.h + gdk/x11/gdkwindow-x11.c: Redo Xft support to go + directly to Picture objects instead of using XftDraw. + This fixes the problem where we weren't able to + properly destroy XftDraw objects before destroying + the accompanying windows, and probably improves + efficiency a bit too. (#50214) + Mon Nov 5 10:01:49 2001 Owen Taylor * gdk/x11/gdkgeometry-x11.c (gdk_window_compute_position): diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index e8912c4145..2f34bfae10 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,14 @@ +Mon Nov 5 12:46:44 2001 Owen Taylor + + * gdk/x11/gdkdrawable-x11.[ch] gdk/x11/gdkgc-x11.c + gdk/x11/gdkpixmap-x11.c gdk/x11/gdkprivate-x11.h + gdk/x11/gdkwindow-x11.c: Redo Xft support to go + directly to Picture objects instead of using XftDraw. + This fixes the problem where we weren't able to + properly destroy XftDraw objects before destroying + the accompanying windows, and probably improves + efficiency a bit too. (#50214) + Mon Nov 5 10:01:49 2001 Owen Taylor * gdk/x11/gdkgeometry-x11.c (gdk_window_compute_position): diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index e8912c4145..2f34bfae10 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,14 @@ +Mon Nov 5 12:46:44 2001 Owen Taylor + + * gdk/x11/gdkdrawable-x11.[ch] gdk/x11/gdkgc-x11.c + gdk/x11/gdkpixmap-x11.c gdk/x11/gdkprivate-x11.h + gdk/x11/gdkwindow-x11.c: Redo Xft support to go + directly to Picture objects instead of using XftDraw. + This fixes the problem where we weren't able to + properly destroy XftDraw objects before destroying + the accompanying windows, and probably improves + efficiency a bit too. (#50214) + Mon Nov 5 10:01:49 2001 Owen Taylor * gdk/x11/gdkgeometry-x11.c (gdk_window_compute_position): diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index e8912c4145..2f34bfae10 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,14 @@ +Mon Nov 5 12:46:44 2001 Owen Taylor + + * gdk/x11/gdkdrawable-x11.[ch] gdk/x11/gdkgc-x11.c + gdk/x11/gdkpixmap-x11.c gdk/x11/gdkprivate-x11.h + gdk/x11/gdkwindow-x11.c: Redo Xft support to go + directly to Picture objects instead of using XftDraw. + This fixes the problem where we weren't able to + properly destroy XftDraw objects before destroying + the accompanying windows, and probably improves + efficiency a bit too. (#50214) + Mon Nov 5 10:01:49 2001 Owen Taylor * gdk/x11/gdkgeometry-x11.c (gdk_window_compute_position): diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index e8912c4145..2f34bfae10 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,14 @@ +Mon Nov 5 12:46:44 2001 Owen Taylor + + * gdk/x11/gdkdrawable-x11.[ch] gdk/x11/gdkgc-x11.c + gdk/x11/gdkpixmap-x11.c gdk/x11/gdkprivate-x11.h + gdk/x11/gdkwindow-x11.c: Redo Xft support to go + directly to Picture objects instead of using XftDraw. + This fixes the problem where we weren't able to + properly destroy XftDraw objects before destroying + the accompanying windows, and probably improves + efficiency a bit too. (#50214) + Mon Nov 5 10:01:49 2001 Owen Taylor * gdk/x11/gdkgeometry-x11.c (gdk_window_compute_position): diff --git a/gdk/x11/gdkdrawable-x11.c b/gdk/x11/gdkdrawable-x11.c index f5589dcb0a..0ca8d12201 100644 --- a/gdk/x11/gdkdrawable-x11.c +++ b/gdk/x11/gdkdrawable-x11.c @@ -203,6 +203,70 @@ gdk_drawable_impl_x11_finalize (GObject *object) G_OBJECT_CLASS (parent_class)->finalize (object); } +#ifdef HAVE_XFT +static Picture +gdk_x11_drawable_get_picture (GdkDrawable *drawable) +{ + GdkDrawableImplX11 *impl = GDK_DRAWABLE_IMPL_X11 (drawable); + + if (impl->picture == None) + { + GdkVisual *visual = gdk_drawable_get_visual (drawable); + XRenderPictFormat *format; + + if (!visual) + { + g_warning ("Using Xft rendering requires the drawable argument to\n" + "have a specified colormap. All windows have a colormap,\n" + "however, pixmaps only have colormap by default if they\n" + "were created with a non-NULL window argument. Otherwise\n" + "a colormap must be set on them with gdk_drawable_set_colormap"); + return None; + } + + format = XRenderFindVisualFormat (impl->xdisplay, GDK_VISUAL_XVISUAL (visual)); + impl->picture = XRenderCreatePicture (impl->xdisplay, impl->xid, format, 0, NULL); + } + + return impl->picture; +} + +static void +gdk_x11_drawable_update_picture_clip (GdkDrawable *drawable, + GdkGC *gc) +{ + GdkGCX11 *gc_private = GDK_GC_X11 (gc); + GdkDrawableImplX11 *impl = GDK_DRAWABLE_IMPL_X11 (drawable); + Picture picture = gdk_x11_drawable_get_picture (drawable); + + if (gc_private->clip_region) + { + GdkRegionBox *boxes = gc_private->clip_region->rects; + gint n_boxes = gc_private->clip_region->numRects; + XRectangle *rects = g_new (XRectangle, n_boxes); + int i; + + for (i=0; i < n_boxes; i++) + { + rects[i].x = CLAMP (boxes[i].x1 + gc->clip_x_origin, G_MINSHORT, G_MAXSHORT); + rects[i].y = CLAMP (boxes[i].y1 + gc->clip_y_origin, G_MINSHORT, G_MAXSHORT); + rects[i].width = CLAMP (boxes[i].x2 + gc->clip_x_origin, G_MINSHORT, G_MAXSHORT) - rects[i].x; + rects[i].height = CLAMP (boxes[i].y2 + gc->clip_y_origin, G_MINSHORT, G_MAXSHORT) - rects[i].y; + } + + XRenderSetPictureClipRectangles (impl->xdisplay, picture, 0, 0, rects, n_boxes); + + g_free (rects); + } + else + { + XRenderPictureAttributes pa; + pa.clip_mask = None; + XRenderChangePicture (impl->xdisplay, picture, CPClipMask, &pa); + } +} +#endif + /***************************************************** * X11 specific implementations of generic functions * *****************************************************/ @@ -581,40 +645,6 @@ gdk_x11_draw_lines (GdkDrawable *drawable, g_free (tmp_points); } -#if HAVE_XFT -static void -update_xft_draw_clip (GdkGC *gc) -{ - GdkGCX11 *private = GDK_GC_X11 (gc); - int i; - - if (private->xft_draw) - { - if (private->clip_region) - { - GdkRegionBox *boxes = private->clip_region->rects; - Region region = XCreateRegion (); - - for (i=0; iclip_region->numRects; i++) - { - XRectangle rect; - - rect.x = CLAMP (boxes[i].x1 + gc->clip_x_origin, G_MINSHORT, G_MAXSHORT); - rect.y = CLAMP (boxes[i].y1 + gc->clip_y_origin, G_MINSHORT, G_MAXSHORT); - rect.width = CLAMP (boxes[i].x2 + gc->clip_x_origin, G_MINSHORT, G_MAXSHORT) - rect.x; - rect.height = CLAMP (boxes[i].y2 + gc->clip_y_origin, G_MINSHORT, G_MAXSHORT) - rect.y; - XUnionRectWithRegion (&rect, region, region); - } - - XftDrawSetClip (private->xft_draw, region); - XDestroyRegion (region); - } - else - XftDrawSetClip (private->xft_draw, NULL); - } -} -#endif - static void gdk_x11_draw_glyphs (GdkDrawable *drawable, GdkGC *gc, @@ -630,39 +660,15 @@ gdk_x11_draw_glyphs (GdkDrawable *drawable, #if HAVE_XFT if (PANGO_XFT_IS_FONT (font)) { - GdkGCX11 *gc_x11 = GDK_GC_X11 (gc); - XftColor xft_color; - GdkColormap *cmap; - GdkColor color; - - cmap = gdk_gc_get_colormap (gc); + Picture src_picture; + Picture dest_picture; - _gdk_x11_gc_flush (gc); + src_picture = _gdk_x11_gc_get_fg_picture (gc); + + gdk_x11_drawable_update_picture_clip (drawable, gc); + dest_picture = gdk_x11_drawable_get_picture (drawable); - if (!gc_x11->xft_draw) - { - gc_x11->xft_draw = XftDrawCreate (impl->xdisplay, - impl->xid, - GDK_VISUAL_XVISUAL (gdk_colormap_get_visual (cmap)), - GDK_COLORMAP_XCOLORMAP (cmap)); - update_xft_draw_clip (gc); - } - - else - { - XftDrawChange (gc_x11->xft_draw, impl->xid); - update_xft_draw_clip (gc); - } - - gdk_colormap_query_color (cmap, gc_x11->fg_pixel, &color); - - xft_color.color.red = color.red; - xft_color.color.green = color.green; - xft_color.color.blue = color.blue; - xft_color.color.alpha = 0xffff; - - pango_xft_render (gc_x11->xft_draw, &xft_color, - font, glyphs, x, y); + pango_xft_picture_render (impl->xdisplay, src_picture, dest_picture, font, glyphs, x, y); } else #endif /* !HAVE_XFT */ diff --git a/gdk/x11/gdkdrawable-x11.h b/gdk/x11/gdkdrawable-x11.h index 7d20d50d52..aa681585d4 100644 --- a/gdk/x11/gdkdrawable-x11.h +++ b/gdk/x11/gdkdrawable-x11.h @@ -27,9 +27,15 @@ #ifndef __GDK_DRAWABLE_X11_H__ #define __GDK_DRAWABLE_X11_H__ +#include + #include #include +#ifdef HAVE_XFT +#include +#endif + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ @@ -57,6 +63,10 @@ struct _GdkDrawableImplX11 Window xid; Display *xdisplay; + +#ifdef HAVE_XFT + Picture picture; +#endif }; struct _GdkDrawableImplX11Class diff --git a/gdk/x11/gdkgc-x11.c b/gdk/x11/gdkgc-x11.c index ce3c60490e..f6c4da625c 100644 --- a/gdk/x11/gdkgc-x11.c +++ b/gdk/x11/gdkgc-x11.c @@ -26,10 +26,6 @@ #include -#if HAVE_XFT -#include -#endif - #include "gdkgc.h" #include "gdkprivate-x11.h" #include "gdkregion-generic.h" @@ -112,13 +108,13 @@ gdk_gc_x11_finalize (GObject *object) if (x11_gc->clip_region) gdk_region_destroy (x11_gc->clip_region); - XFreeGC (GDK_GC_XDISPLAY (x11_gc), GDK_GC_XGC (x11_gc)); - #if HAVE_XFT - if (x11_gc->xft_draw) - XftDrawDestroy (x11_gc->xft_draw); + if (x11_gc->fg_picture != None) + XRenderFreePicture (x11_gc->xdisplay, x11_gc->fg_picture); #endif + XFreeGC (GDK_GC_XDISPLAY (x11_gc), GDK_GC_XGC (x11_gc)); + G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -757,3 +753,93 @@ gdk_x11_gc_get_xgc (GdkGC *gc) return gc_x11->xgc; } + +/* Various bits of the below are roughly cribbed from XFree86 + * lib/Xft/xftdraw.c, Copyright 2000, Keith Packard + */ + +static XRenderPictFormat * +foreground_format (GdkGC *gc) +{ + XRenderPictFormat pf; + + pf.type = PictTypeDirect; + pf.depth = 32; + pf.direct.redMask = 0xff; + pf.direct.greenMask = 0xff; + pf.direct.blueMask = 0xff; + pf.direct.alphaMask = 0xff; + + return XRenderFindFormat (GDK_GC_XDISPLAY (gc), + (PictFormatType | + PictFormatDepth | + PictFormatRedMask | + PictFormatGreenMask | + PictFormatBlueMask | + PictFormatAlphaMask), + &pf, + 0); +} + +#ifdef HAVE_XFT +/** + * _gdk_x11_gc_get_fg_picture: + * @gc: a #GdkGC + * + * Gets a Xrender Picture object suitable for being the source + * drawable for drawing with the foreground the graphics context. + * (Currently, only foreground color is handled, but in the + * future we should handle tiles/stipples as well.) + * + * Return value: a Picture, owned by the GC; this cannot be + * used over subsequent modification of the GC. + **/ +Picture +_gdk_x11_gc_get_fg_picture (GdkGC *gc) +{ + GdkGCX11 *x11_gc; + GdkColormap *cmap = gdk_gc_get_colormap (gc); + gboolean new = FALSE; + GdkColor color; + + g_return_val_if_fail (GDK_IS_GC_X11 (gc), None); + + x11_gc = GDK_GC_X11 (gc); + + if (x11_gc->fg_picture == None) + { + XRenderPictureAttributes pa; + XRenderPictFormat *pix_format = foreground_format (gc); + + Pixmap pix = XCreatePixmap (x11_gc->xdisplay, _gdk_root_window, + 1, 1, pix_format->depth); + pa.repeat = True; + x11_gc->fg_picture = XRenderCreatePicture (x11_gc->xdisplay, + pix, + pix_format, + CPRepeat, &pa); + XFreePixmap (x11_gc->xdisplay, pix); + + new = TRUE; + } + + gdk_colormap_query_color (cmap, x11_gc->fg_pixel, &color); + + if (new || + x11_gc->fg_picture_color.red != color.red || + x11_gc->fg_picture_color.green != color.green || + x11_gc->fg_picture_color.blue != color.blue) + { + x11_gc->fg_picture_color.red = color.red; + x11_gc->fg_picture_color.green = color.green; + x11_gc->fg_picture_color.blue = color.blue; + x11_gc->fg_picture_color.alpha = 0xffff; + + XRenderFillRectangle (x11_gc->xdisplay, PictOpSrc, + x11_gc->fg_picture, &x11_gc->fg_picture_color, + 0, 0, 1, 1); + } + + return x11_gc->fg_picture; +} +#endif /* HAVE_XFT */ diff --git a/gdk/x11/gdkpixmap-x11.c b/gdk/x11/gdkpixmap-x11.c index 15804ce8a4..ae50cc3375 100644 --- a/gdk/x11/gdkpixmap-x11.c +++ b/gdk/x11/gdkpixmap-x11.c @@ -122,6 +122,15 @@ gdk_pixmap_impl_x11_finalize (GObject *object) GdkPixmapImplX11 *impl = GDK_PIXMAP_IMPL_X11 (object); GdkPixmap *wrapper = GDK_PIXMAP (GDK_DRAWABLE_IMPL_X11 (impl)->wrapper); +#ifdef HAVE_XFT + { + GdkDrawableImplX11 *draw_impl = GDK_DRAWABLE_IMPL_X11 (impl); + + if (draw_impl->picture) + XRenderFreePicture (draw_impl->xdisplay, draw_impl->picture); + } +#endif /* HAVE_XFT */ + if (!impl->is_foreign) XFreePixmap (GDK_PIXMAP_XDISPLAY (wrapper), GDK_PIXMAP_XID (wrapper)); diff --git a/gdk/x11/gdkprivate-x11.h b/gdk/x11/gdkprivate-x11.h index 8b960974fb..6552ff5383 100644 --- a/gdk/x11/gdkprivate-x11.h +++ b/gdk/x11/gdkprivate-x11.h @@ -39,6 +39,10 @@ #include +#if HAVE_XFT +#include +#endif + #define GDK_TYPE_GC_X11 (_gdk_gc_x11_get_type ()) #define GDK_GC_X11(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_GC_X11, GdkGCX11)) #define GDK_GC_X11_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_GC_X11, GdkGCX11Class)) @@ -60,10 +64,10 @@ struct _GdkGCX11 GdkRegion *clip_region; guint dirty_mask; - /* We can't conditionalize on HAVE_XFT here, so we simply always - * have this here as a gpointer. - */ - gpointer xft_draw; +#ifdef HAVE_XFT + Picture fg_picture; + XRenderColor fg_picture_color; +#endif gulong fg_pixel; }; @@ -95,6 +99,10 @@ gint gdk_send_xevent (Window window, GType _gdk_gc_x11_get_type (void); +#ifdef HAVE_XFT +Picture _gdk_x11_gc_get_fg_picture (GdkGC *gc); +#endif /* HAVE_XFT */ + GdkGC *_gdk_x11_gc_new (GdkDrawable *drawable, GdkGCValues *values, GdkGCValuesMask values_mask); diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c index f6d6d89d90..49a6636943 100644 --- a/gdk/x11/gdkwindow-x11.c +++ b/gdk/x11/gdkwindow-x11.c @@ -738,6 +738,15 @@ _gdk_windowing_window_destroy (GdkWindow *window, if (private->extension_events != 0) gdk_input_window_destroy (window); +#ifdef HAVE_XFT + { + GdkDrawableImplX11 *draw_impl = GDK_DRAWABLE_IMPL_X11 (private->impl); + + if (draw_impl->picture) + XRenderFreePicture (draw_impl->xdisplay, draw_impl->picture); + } +#endif /* HAVE_XFT */ + if (private->window_type == GDK_WINDOW_FOREIGN) { if (!foreign_destroy && (private->parent != NULL))