X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gdk%2Fgdkgc.c;h=ec53dec702f340d3ad35aca1ccb358516006977f;hb=2e098756c1717e9e0e735ee7ea77cbaeba463550;hp=e8772cfe9bb7ba8fbb47528ee5a16daf6cd17c3e;hpb=f903bdf1a745021df882b4f5ba2724e7536a3c5d;p=~andy%2Fgtk diff --git a/gdk/gdkgc.c b/gdk/gdkgc.c index e8772cfe9..ec53dec70 100644 --- a/gdk/gdkgc.c +++ b/gdk/gdkgc.c @@ -2,739 +2,764 @@ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public + * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. + * Lesser General Public License for more details. * - * You should have received a copy of the GNU Library General Public + * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /* - * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS * file for a list of people on the GTK+ Team. See the ChangeLog * files for a list of changes. These files are distributed with * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ +#include #include -#include +#include "gdkcairo.h" #include "gdkgc.h" +#include "gdkinternals.h" +#include "gdkpixmap.h" +#include "gdkrgb.h" #include "gdkprivate.h" -#include "gdkx.h" +#include "gdkalias.h" +static void gdk_gc_finalize (GObject *object); + +typedef struct _GdkGCPrivate GdkGCPrivate; + +struct _GdkGCPrivate +{ + GdkRegion *clip_region; + + GdkFill fill; + GdkBitmap *stipple; + GdkPixmap *tile; + + guint32 fg_pixel; + guint32 bg_pixel; +}; + +#define GDK_GC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDK_TYPE_GC, GdkGCPrivate)) + +G_DEFINE_TYPE (GdkGC, gdk_gc, G_TYPE_OBJECT) + +static void +gdk_gc_class_init (GdkGCClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->finalize = gdk_gc_finalize; + + g_type_class_add_private (object_class, sizeof (GdkGCPrivate)); +} + +static void +gdk_gc_init (GdkGC *gc) +{ + GdkGCPrivate *priv = GDK_GC_GET_PRIVATE (gc); + + priv->fill = GDK_SOLID; + + /* These are the default X11 value, which we match. They are clearly + * wrong for TrueColor displays, so apps have to change them. + */ + priv->fg_pixel = 0; + priv->bg_pixel = 1; +} + +/** + * gdk_gc_new: + * @drawable: a #GdkDrawable. The created GC must always be used + * with drawables of the same depth as this one. + * + * Create a new graphics context with default values. + * + * Returns: the new graphics context. + **/ GdkGC* -gdk_gc_new (GdkWindow *window) +gdk_gc_new (GdkDrawable *drawable) { - return gdk_gc_new_with_values (window, NULL, 0); + g_return_val_if_fail (drawable != NULL, NULL); + + return gdk_gc_new_with_values (drawable, NULL, 0); } +/** + * gdk_gc_new_with_values: + * @drawable: a #GdkDrawable. The created GC must always be used + * with drawables of the same depth as this one. + * @values: a structure containing initial values for the GC. + * @values_mask: a bit mask indicating which fields in @values + * are set. + * + * Create a new GC with the given initial values. + * + * Return value: the new graphics context. + **/ GdkGC* -gdk_gc_new_with_values (GdkWindow *window, +gdk_gc_new_with_values (GdkDrawable *drawable, GdkGCValues *values, GdkGCValuesMask values_mask) { - GdkGC *gc; - GdkGCPrivate *private; - Window xwindow; - XGCValues xvalues; - unsigned long xvalues_mask; - - g_return_val_if_fail (window != NULL, NULL); + g_return_val_if_fail (drawable != NULL, NULL); - if (GDK_DRAWABLE_DESTROYED (window)) - return NULL; + return GDK_DRAWABLE_GET_CLASS (drawable)->create_gc (drawable, + values, + values_mask); +} - private = g_new (GdkGCPrivate, 1); - gc = (GdkGC*) private; +/** + * _gdk_gc_init: + * @gc: a #GdkGC + * @drawable: a #GdkDrawable. + * @values: a structure containing initial values for the GC. + * @values_mask: a bit mask indicating which fields in @values + * are set. + * + * Does initialization of the generic portions of a #GdkGC + * created with the specified values and values_mask. This + * should be called out of the implementation of + * GdkDrawable.create_gc() immediately after creating the + * #GdkGC object. + **/ +void +_gdk_gc_init (GdkGC *gc, + GdkDrawable *drawable, + GdkGCValues *values, + GdkGCValuesMask values_mask) +{ + GdkGCPrivate *priv; - xwindow = GDK_DRAWABLE_XID (window); - private->xdisplay = GDK_DRAWABLE_XDISPLAY (window); - private->ref_count = 1; + g_return_if_fail (GDK_IS_GC (gc)); - xvalues.function = GXcopy; - xvalues.fill_style = FillSolid; - xvalues.arc_mode = ArcPieSlice; - xvalues.subwindow_mode = ClipByChildren; - xvalues.graphics_exposures = True; - xvalues_mask = GCFunction | GCFillStyle | GCArcMode | GCSubwindowMode | GCGraphicsExposures; + priv = GDK_GC_GET_PRIVATE (gc); - if (values_mask & GDK_GC_FOREGROUND) - { - xvalues.foreground = values->foreground.pixel; - xvalues_mask |= GCForeground; - } - if (values_mask & GDK_GC_BACKGROUND) - { - xvalues.background = values->background.pixel; - xvalues_mask |= GCBackground; - } - if ((values_mask & GDK_GC_FONT) && (values->font->type == GDK_FONT_FONT)) - { - xvalues.font = ((XFontStruct *) ((GdkFontPrivate*) values->font)->xfont)->fid; - xvalues_mask |= GCFont; - } - if (values_mask & GDK_GC_FUNCTION) - { - switch (values->function) - { - case GDK_COPY: - xvalues.function = GXcopy; - break; - case GDK_INVERT: - xvalues.function = GXinvert; - break; - case GDK_XOR: - xvalues.function = GXxor; - break; - case GDK_CLEAR: - xvalues.function = GXclear; - break; - case GDK_AND: - xvalues.function = GXand; - break; - case GDK_AND_REVERSE: - xvalues.function = GXandReverse; - break; - case GDK_AND_INVERT: - xvalues.function = GXandInverted; - break; - case GDK_NOOP: - xvalues.function = GXnoop; - break; - case GDK_OR: - xvalues.function = GXor; - break; - case GDK_EQUIV: - xvalues.function = GXequiv; - break; - case GDK_OR_REVERSE: - xvalues.function = GXorReverse; - break; - case GDK_COPY_INVERT: - xvalues.function = GXcopyInverted; - break; - case GDK_OR_INVERT: - xvalues.function = GXorInverted; - break; - case GDK_NAND: - xvalues.function = GXnand; - break; - case GDK_SET: - xvalues.function = GXset; - break; - } - xvalues_mask |= GCFunction; - } - if (values_mask & GDK_GC_FILL) - { - switch (values->fill) - { - case GDK_SOLID: - xvalues.fill_style = FillSolid; - break; - case GDK_TILED: - xvalues.fill_style = FillTiled; - break; - case GDK_STIPPLED: - xvalues.fill_style = FillStippled; - break; - case GDK_OPAQUE_STIPPLED: - xvalues.fill_style = FillOpaqueStippled; - break; - } - xvalues_mask |= GCFillStyle; - } - if (values_mask & GDK_GC_TILE) - { - xvalues.tile = GDK_DRAWABLE_XID (values->tile); - xvalues_mask |= GCTile; - } - if (values_mask & GDK_GC_STIPPLE) - { - xvalues.stipple = GDK_DRAWABLE_XID (values->stipple); - xvalues_mask |= GCStipple; - } - if (values_mask & GDK_GC_CLIP_MASK) - { - xvalues.clip_mask = GDK_DRAWABLE_XID (values->clip_mask); - xvalues_mask |= GCClipMask; - } - if (values_mask & GDK_GC_SUBWINDOW) - { - xvalues.subwindow_mode = values->subwindow_mode; - xvalues_mask |= GCSubwindowMode; - } - if (values_mask & GDK_GC_TS_X_ORIGIN) - { - xvalues.ts_x_origin = values->ts_x_origin; - xvalues_mask |= GCTileStipXOrigin; - } - if (values_mask & GDK_GC_TS_Y_ORIGIN) - { - xvalues.ts_y_origin = values->ts_y_origin; - xvalues_mask |= GCTileStipYOrigin; - } if (values_mask & GDK_GC_CLIP_X_ORIGIN) - { - xvalues.clip_x_origin = values->clip_x_origin; - xvalues_mask |= GCClipXOrigin; - } + gc->clip_x_origin = values->clip_x_origin; if (values_mask & GDK_GC_CLIP_Y_ORIGIN) + gc->clip_y_origin = values->clip_y_origin; + if (values_mask & GDK_GC_TS_X_ORIGIN) + gc->ts_x_origin = values->ts_x_origin; + if (values_mask & GDK_GC_TS_Y_ORIGIN) + gc->ts_y_origin = values->ts_y_origin; + if (values_mask & GDK_GC_FILL) + priv->fill = values->fill; + if (values_mask & GDK_GC_STIPPLE) { - xvalues.clip_y_origin = values->clip_y_origin; - xvalues_mask |= GCClipYOrigin; - } - - if (values_mask & GDK_GC_EXPOSURES) - xvalues.graphics_exposures = values->graphics_exposures; - else - xvalues.graphics_exposures = False; - xvalues_mask |= GCGraphicsExposures; - - if (values_mask & GDK_GC_LINE_WIDTH) - { - xvalues.line_width = values->line_width; - xvalues_mask |= GCLineWidth; - } - if (values_mask & GDK_GC_LINE_STYLE) - { - switch (values->line_style) - { - case GDK_LINE_SOLID: - xvalues.line_style = LineSolid; - break; - case GDK_LINE_ON_OFF_DASH: - xvalues.line_style = LineOnOffDash; - break; - case GDK_LINE_DOUBLE_DASH: - xvalues.line_style = LineDoubleDash; - break; - } - xvalues_mask |= GCLineStyle; - } - if (values_mask & GDK_GC_CAP_STYLE) - { - switch (values->cap_style) - { - case GDK_CAP_NOT_LAST: - xvalues.cap_style = CapNotLast; - break; - case GDK_CAP_BUTT: - xvalues.cap_style = CapButt; - break; - case GDK_CAP_ROUND: - xvalues.cap_style = CapRound; - break; - case GDK_CAP_PROJECTING: - xvalues.cap_style = CapProjecting; - break; - } - xvalues_mask |= GCCapStyle; + priv->stipple = values->stipple; + if (priv->stipple) + g_object_ref (priv->stipple); } - if (values_mask & GDK_GC_JOIN_STYLE) + if (values_mask & GDK_GC_TILE) { - switch (values->join_style) - { - case GDK_JOIN_MITER: - xvalues.join_style = JoinMiter; - break; - case GDK_JOIN_ROUND: - xvalues.join_style = JoinRound; - break; - case GDK_JOIN_BEVEL: - xvalues.join_style = JoinBevel; - break; - } - xvalues_mask |= GCJoinStyle; + priv->tile = values->tile; + if (priv->tile) + g_object_ref (priv->tile); } + if (values_mask & GDK_GC_FOREGROUND) + priv->fg_pixel = values->foreground.pixel; + if (values_mask & GDK_GC_BACKGROUND) + priv->bg_pixel = values->background.pixel; - private->xgc = XCreateGC (private->xdisplay, xwindow, xvalues_mask, &xvalues); - - return gc; + gc->colormap = gdk_drawable_get_colormap (drawable); + if (gc->colormap) + g_object_ref (gc->colormap); } -void -gdk_gc_destroy (GdkGC *gc) +static void +gdk_gc_finalize (GObject *object) { - gdk_gc_unref (gc); + GdkGC *gc = GDK_GC (object); + GdkGCPrivate *priv = GDK_GC_GET_PRIVATE (gc); + + if (priv->clip_region) + gdk_region_destroy (priv->clip_region); + if (gc->colormap) + g_object_unref (gc->colormap); + if (priv->tile) + g_object_unref (priv->tile); + if (priv->stipple) + g_object_unref (priv->stipple); + + G_OBJECT_CLASS (gdk_gc_parent_class)->finalize (object); } +/** + * gdk_gc_ref: + * @gc: a #GdkGC + * + * Deprecated function; use g_object_ref() instead. + * + * Return value: the gc. + **/ GdkGC * gdk_gc_ref (GdkGC *gc) { - GdkGCPrivate *private = (GdkGCPrivate*) gc; - - g_return_val_if_fail (gc != NULL, NULL); - private->ref_count += 1; - - return gc; + return (GdkGC *) g_object_ref (gc); } +/** + * gdk_gc_unref: + * @gc: a #GdkGC + * + * Decrement the reference count of @gc. + * + * Deprecated: Use g_object_unref() instead. + **/ void gdk_gc_unref (GdkGC *gc) { - GdkGCPrivate *private = (GdkGCPrivate*) gc; - - g_return_if_fail (gc != NULL); - g_return_if_fail (private->ref_count > 0); - - if (private->ref_count > 1) - private->ref_count -= 1; - else - { - XFreeGC (private->xdisplay, private->xgc); - memset (gc, 0, sizeof (GdkGCPrivate)); - g_free (gc); - } + g_object_unref (gc); } +/** + * gdk_gc_get_values: + * @gc: a #GdkGC. + * @values: the #GdkGCValues structure in which to store the results. + * + * Retrieves the current values from a graphics context. Note that + * only the pixel values of the @values->foreground and @values->background + * are filled, use gdk_colormap_query_color() to obtain the rgb values + * if you need them. + **/ void gdk_gc_get_values (GdkGC *gc, GdkGCValues *values) { - GdkGCPrivate *private; - XGCValues xvalues; - - g_return_if_fail (gc != NULL); + g_return_if_fail (GDK_IS_GC (gc)); g_return_if_fail (values != NULL); - private = (GdkGCPrivate*) gc; - - if (XGetGCValues (private->xdisplay, private->xgc, - GCForeground | GCBackground | GCFont | - GCFunction | GCTile | GCStipple | /* GCClipMask | */ - GCSubwindowMode | GCGraphicsExposures | - GCTileStipXOrigin | GCTileStipYOrigin | - GCClipXOrigin | GCClipYOrigin | - GCLineWidth | GCLineStyle | GCCapStyle | - GCFillStyle | GCJoinStyle, &xvalues)) - { - values->foreground.pixel = xvalues.foreground; - values->background.pixel = xvalues.background; - values->font = gdk_font_lookup (xvalues.font); + GDK_GC_GET_CLASS (gc)->get_values (gc, values); +} - switch (xvalues.function) - { - case GXcopy: - values->function = GDK_COPY; - break; - case GXinvert: - values->function = GDK_INVERT; - break; - case GXxor: - values->function = GDK_XOR; - break; - case GXclear: - values->function = GDK_CLEAR; - break; - case GXand: - values->function = GDK_AND; - break; - case GXandReverse: - values->function = GDK_AND_REVERSE; - break; - case GXandInverted: - values->function = GDK_AND_INVERT; - break; - case GXnoop: - values->function = GDK_NOOP; - break; - case GXor: - values->function = GDK_OR; - break; - case GXequiv: - values->function = GDK_EQUIV; - break; - case GXorReverse: - values->function = GDK_OR_REVERSE; - break; - case GXcopyInverted: - values->function =GDK_COPY_INVERT; - break; - case GXorInverted: - values->function = GDK_OR_INVERT; - break; - case GXnand: - values->function = GDK_NAND; - break; - case GXset: - values->function = GDK_SET; - break; - } +/** + * gdk_gc_set_values: + * @gc: a #GdkGC + * @values: struct containing the new values + * @values_mask: mask indicating which struct fields are to be used + * + * Sets attributes of a graphics context in bulk. For each flag set in + * @values_mask, the corresponding field will be read from @values and + * set as the new value for @gc. If you're only setting a few values + * on @gc, calling individual "setter" functions is likely more + * convenient. + * + **/ +void +gdk_gc_set_values (GdkGC *gc, + GdkGCValues *values, + GdkGCValuesMask values_mask) +{ + GdkGCPrivate *priv; - switch (xvalues.fill_style) - { - case FillSolid: - values->fill = GDK_SOLID; - break; - case FillTiled: - values->fill = GDK_TILED; - break; - case FillStippled: - values->fill = GDK_STIPPLED; - break; - case FillOpaqueStippled: - values->fill = GDK_OPAQUE_STIPPLED; - break; - } + g_return_if_fail (GDK_IS_GC (gc)); + g_return_if_fail (values != NULL); - values->tile = gdk_pixmap_lookup (xvalues.tile); - values->stipple = gdk_pixmap_lookup (xvalues.stipple); - values->clip_mask = NULL; - values->subwindow_mode = xvalues.subwindow_mode; - values->ts_x_origin = xvalues.ts_x_origin; - values->ts_y_origin = xvalues.ts_y_origin; - values->clip_x_origin = xvalues.clip_x_origin; - values->clip_y_origin = xvalues.clip_y_origin; - values->graphics_exposures = xvalues.graphics_exposures; - values->line_width = xvalues.line_width; - - switch (xvalues.line_style) - { - case LineSolid: - values->line_style = GDK_LINE_SOLID; - break; - case LineOnOffDash: - values->line_style = GDK_LINE_ON_OFF_DASH; - break; - case LineDoubleDash: - values->line_style = GDK_LINE_DOUBLE_DASH; - break; - } + priv = GDK_GC_GET_PRIVATE (gc); - switch (xvalues.cap_style) + if (values_mask & GDK_GC_CLIP_X_ORIGIN) + gc->clip_x_origin = values->clip_x_origin; + if (values_mask & GDK_GC_CLIP_Y_ORIGIN) + gc->clip_y_origin = values->clip_y_origin; + if (values_mask & GDK_GC_TS_X_ORIGIN) + gc->ts_x_origin = values->ts_x_origin; + if (values_mask & GDK_GC_TS_Y_ORIGIN) + gc->ts_y_origin = values->ts_y_origin; + if (values_mask & GDK_GC_CLIP_MASK) + { + if (priv->clip_region) { - case CapNotLast: - values->cap_style = GDK_CAP_NOT_LAST; - break; - case CapButt: - values->cap_style = GDK_CAP_BUTT; - break; - case CapRound: - values->cap_style = GDK_CAP_ROUND; - break; - case CapProjecting: - values->cap_style = GDK_CAP_PROJECTING; - break; + gdk_region_destroy (priv->clip_region); + priv->clip_region = NULL; } - - switch (xvalues.join_style) + } + if (values_mask & GDK_GC_FILL) + priv->fill = values->fill; + if (values_mask & GDK_GC_STIPPLE) + { + if (priv->stipple != values->stipple) { - case JoinMiter: - values->join_style = GDK_JOIN_MITER; - break; - case JoinRound: - values->join_style = GDK_JOIN_ROUND; - break; - case JoinBevel: - values->join_style = GDK_JOIN_BEVEL; - break; + if (priv->stipple) + g_object_unref (priv->stipple); + priv->stipple = values->stipple; + if (priv->stipple) + g_object_ref (priv->stipple); } } - else + if (values_mask & GDK_GC_TILE) { - memset (values, 0, sizeof (GdkGCValues)); + if (priv->tile != values->tile) + { + if (priv->tile) + g_object_unref (priv->tile); + priv->tile = values->tile; + if (priv->tile) + g_object_ref (priv->tile); + } } + if (values_mask & GDK_GC_FOREGROUND) + priv->fg_pixel = values->foreground.pixel; + if (values_mask & GDK_GC_BACKGROUND) + priv->bg_pixel = values->background.pixel; + + GDK_GC_GET_CLASS (gc)->set_values (gc, values, values_mask); } +/** + * gdk_gc_set_foreground: + * @gc: a #GdkGC. + * @color: the new foreground color. + * + * Sets the foreground color for a graphics context. + * Note that this function uses @color->pixel, use + * gdk_gc_set_rgb_fg_color() to specify the foreground + * color as red, green, blue components. + **/ void -gdk_gc_set_foreground (GdkGC *gc, - GdkColor *color) +gdk_gc_set_foreground (GdkGC *gc, + const GdkColor *color) { - GdkGCPrivate *private; + GdkGCValues values; - g_return_if_fail (gc != NULL); + g_return_if_fail (GDK_IS_GC (gc)); g_return_if_fail (color != NULL); - private = (GdkGCPrivate*) gc; - XSetForeground (private->xdisplay, private->xgc, color->pixel); + values.foreground = *color; + gdk_gc_set_values (gc, &values, GDK_GC_FOREGROUND); } +/** + * gdk_gc_set_background: + * @gc: a #GdkGC. + * @color: the new background color. + * + * Sets the background color for a graphics context. + * Note that this function uses @color->pixel, use + * gdk_gc_set_rgb_bg_color() to specify the background + * color as red, green, blue components. + **/ void -gdk_gc_set_background (GdkGC *gc, - GdkColor *color) +gdk_gc_set_background (GdkGC *gc, + const GdkColor *color) { - GdkGCPrivate *private; + GdkGCValues values; - g_return_if_fail (gc != NULL); + g_return_if_fail (GDK_IS_GC (gc)); g_return_if_fail (color != NULL); - private = (GdkGCPrivate*) gc; - XSetBackground (private->xdisplay, private->xgc, color->pixel); + values.background = *color; + gdk_gc_set_values (gc, &values, GDK_GC_BACKGROUND); } +/** + * gdk_gc_set_font: + * @gc: a #GdkGC. + * @font: the new font. + * + * Sets the font for a graphics context. (Note that + * all text-drawing functions in GDK take a @font + * argument; the value set here is used when that + * argument is %NULL.) + **/ void gdk_gc_set_font (GdkGC *gc, GdkFont *font) { - GdkGCPrivate *gc_private; - GdkFontPrivate *font_private; + GdkGCValues values; - g_return_if_fail (gc != NULL); + g_return_if_fail (GDK_IS_GC (gc)); g_return_if_fail (font != NULL); - if (font->type == GDK_FONT_FONT) - { - gc_private = (GdkGCPrivate*) gc; - font_private = (GdkFontPrivate*) font; - - XSetFont (gc_private->xdisplay, gc_private->xgc, - ((XFontStruct *) font_private->xfont)->fid); - } + values.font = font; + gdk_gc_set_values (gc, &values, GDK_GC_FONT); } +/** + * gdk_gc_set_function: + * @gc: a #GdkGC. + * @function: the #GdkFunction to use + * + * Determines how the current pixel values and the + * pixel values being drawn are combined to produce + * the final pixel values. + **/ void gdk_gc_set_function (GdkGC *gc, GdkFunction function) { - GdkGCPrivate *private; + GdkGCValues values; - g_return_if_fail (gc != NULL); + g_return_if_fail (GDK_IS_GC (gc)); - private = (GdkGCPrivate*) gc; - - switch (function) - { - case GDK_COPY: - XSetFunction (private->xdisplay, private->xgc, GXcopy); - break; - case GDK_INVERT: - XSetFunction (private->xdisplay, private->xgc, GXinvert); - break; - case GDK_XOR: - XSetFunction (private->xdisplay, private->xgc, GXxor); - break; - case GDK_CLEAR: - XSetFunction (private->xdisplay, private->xgc, GXclear); - break; - case GDK_AND: - XSetFunction (private->xdisplay, private->xgc, GXand); - break; - case GDK_AND_REVERSE: - XSetFunction (private->xdisplay, private->xgc, GXandReverse); - break; - case GDK_AND_INVERT: - XSetFunction (private->xdisplay, private->xgc, GXandInverted); - break; - case GDK_NOOP: - XSetFunction (private->xdisplay, private->xgc, GXnoop); - break; - case GDK_OR: - XSetFunction (private->xdisplay, private->xgc, GXor); - break; - case GDK_EQUIV: - XSetFunction (private->xdisplay, private->xgc, GXequiv); - break; - case GDK_OR_REVERSE: - XSetFunction (private->xdisplay, private->xgc, GXorReverse); - break; - case GDK_COPY_INVERT: - XSetFunction (private->xdisplay, private->xgc, GXcopyInverted); - break; - case GDK_OR_INVERT: - XSetFunction (private->xdisplay, private->xgc, GXorInverted); - break; - case GDK_NAND: - XSetFunction (private->xdisplay, private->xgc, GXnand); - break; - case GDK_SET: - XSetFunction (private->xdisplay, private->xgc, GXset); - break; - } + values.function = function; + gdk_gc_set_values (gc, &values, GDK_GC_FUNCTION); } +/** + * gdk_gc_set_fill: + * @gc: a #GdkGC. + * @fill: the new fill mode. + * + * Set the fill mode for a graphics context. + **/ void gdk_gc_set_fill (GdkGC *gc, GdkFill fill) { - GdkGCPrivate *private; - - g_return_if_fail (gc != NULL); + GdkGCValues values; - private = (GdkGCPrivate*) gc; + g_return_if_fail (GDK_IS_GC (gc)); - switch (fill) - { - case GDK_SOLID: - XSetFillStyle (private->xdisplay, private->xgc, FillSolid); - break; - case GDK_TILED: - XSetFillStyle (private->xdisplay, private->xgc, FillTiled); - break; - case GDK_STIPPLED: - XSetFillStyle (private->xdisplay, private->xgc, FillStippled); - break; - case GDK_OPAQUE_STIPPLED: - XSetFillStyle (private->xdisplay, private->xgc, FillOpaqueStippled); - break; - } + values.fill = fill; + gdk_gc_set_values (gc, &values, GDK_GC_FILL); } +/** + * gdk_gc_set_tile: + * @gc: a #GdkGC. + * @tile: the new tile pixmap. + * + * Set a tile pixmap for a graphics context. + * This will only be used if the fill mode + * is %GDK_TILED. + **/ void gdk_gc_set_tile (GdkGC *gc, GdkPixmap *tile) { - GdkGCPrivate *private; - Pixmap pixmap; - - g_return_if_fail (gc != NULL); + GdkGCValues values; - private = (GdkGCPrivate*) gc; + g_return_if_fail (GDK_IS_GC (gc)); - pixmap = None; - if (tile) - pixmap = GDK_DRAWABLE_XID (tile); - - XSetTile (private->xdisplay, private->xgc, pixmap); + values.tile = tile; + gdk_gc_set_values (gc, &values, GDK_GC_TILE); } +/** + * gdk_gc_set_stipple: + * @gc: a #GdkGC. + * @stipple: the new stipple bitmap. + * + * Set the stipple bitmap for a graphics context. The + * stipple will only be used if the fill mode is + * %GDK_STIPPLED or %GDK_OPAQUE_STIPPLED. + **/ void gdk_gc_set_stipple (GdkGC *gc, GdkPixmap *stipple) { - GdkGCPrivate *private; - Pixmap pixmap; - - g_return_if_fail (gc != NULL); + GdkGCValues values; - private = (GdkGCPrivate*) gc; + g_return_if_fail (GDK_IS_GC (gc)); - pixmap = None; - if (stipple) - pixmap = GDK_DRAWABLE_XID (stipple); - - XSetStipple (private->xdisplay, private->xgc, pixmap); + values.stipple = stipple; + gdk_gc_set_values (gc, &values, GDK_GC_STIPPLE); } +/** + * gdk_gc_set_ts_origin: + * @gc: a #GdkGC. + * @x: the x-coordinate of the origin. + * @y: the y-coordinate of the origin. + * + * Set the origin when using tiles or stipples with + * the GC. The tile or stipple will be aligned such + * that the upper left corner of the tile or stipple + * will coincide with this point. + **/ void gdk_gc_set_ts_origin (GdkGC *gc, gint x, gint y) { - GdkGCPrivate *private; - - g_return_if_fail (gc != NULL); + GdkGCValues values; - private = (GdkGCPrivate*) gc; + g_return_if_fail (GDK_IS_GC (gc)); - XSetTSOrigin (private->xdisplay, private->xgc, x, y); + values.ts_x_origin = x; + values.ts_y_origin = y; + + gdk_gc_set_values (gc, &values, + GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN); } +/** + * gdk_gc_set_clip_origin: + * @gc: a #GdkGC. + * @x: the x-coordinate of the origin. + * @y: the y-coordinate of the origin. + * + * Sets the origin of the clip mask. The coordinates are + * interpreted relative to the upper-left corner of + * the destination drawable of the current operation. + **/ void gdk_gc_set_clip_origin (GdkGC *gc, gint x, gint y) { - GdkGCPrivate *private; + GdkGCValues values; - g_return_if_fail (gc != NULL); + g_return_if_fail (GDK_IS_GC (gc)); - private = (GdkGCPrivate*) gc; - - XSetClipOrigin (private->xdisplay, private->xgc, x, y); + values.clip_x_origin = x; + values.clip_y_origin = y; + + gdk_gc_set_values (gc, &values, + GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN); } +/** + * gdk_gc_set_clip_mask: + * @gc: the #GdkGC. + * @mask: a bitmap. + * + * Sets the clip mask for a graphics context from a bitmap. + * The clip mask is interpreted relative to the clip + * origin. (See gdk_gc_set_clip_origin()). + **/ void gdk_gc_set_clip_mask (GdkGC *gc, GdkBitmap *mask) { - GdkGCPrivate *private; - Pixmap xmask; + GdkGCValues values; - g_return_if_fail (gc != NULL); + g_return_if_fail (GDK_IS_GC (gc)); - if (mask) - xmask = GDK_DRAWABLE_XID (mask); - else - xmask = None; - - private = (GdkGCPrivate*) gc; - - XSetClipMask (private->xdisplay, private->xgc, xmask); + values.clip_mask = mask; + gdk_gc_set_values (gc, &values, GDK_GC_CLIP_MASK); } +static void +_gdk_gc_set_clip_region_internal (GdkGC *gc, + GdkRegion *region) +{ + GdkGCPrivate *priv = GDK_GC_GET_PRIVATE (gc); + + if (priv->clip_region) + gdk_region_destroy (priv->clip_region); + priv->clip_region = region; + + _gdk_windowing_gc_set_clip_region (gc, region); +} + +/** + * gdk_gc_set_clip_rectangle: + * @gc: a #GdkGC. + * @rectangle: the rectangle to clip to. + * + * Sets the clip mask for a graphics context from a + * rectangle. The clip mask is interpreted relative to the clip + * origin. (See gdk_gc_set_clip_origin()). + **/ void gdk_gc_set_clip_rectangle (GdkGC *gc, GdkRectangle *rectangle) { - GdkGCPrivate *private; - XRectangle xrectangle; - - g_return_if_fail (gc != NULL); - - private = (GdkGCPrivate*) gc; + GdkRegion *region; + + g_return_if_fail (GDK_IS_GC (gc)); if (rectangle) - { - xrectangle.x = rectangle->x; - xrectangle.y = rectangle->y; - xrectangle.width = rectangle->width; - xrectangle.height = rectangle->height; - - XSetClipRectangles (private->xdisplay, private->xgc, 0, 0, - &xrectangle, 1, Unsorted); - } + region = gdk_region_rectangle (rectangle); else - XSetClipMask (private->xdisplay, private->xgc, None); -} + region = NULL; + _gdk_gc_set_clip_region_internal (gc, region); +} + +/** + * gdk_gc_set_clip_region: + * @gc: a #GdkGC. + * @region: the #GdkRegion. + * + * Sets the clip mask for a graphics context from a region structure. + * The clip mask is interpreted relative to the clip origin. (See + * gdk_gc_set_clip_origin()). + **/ void -gdk_gc_set_clip_region (GdkGC *gc, - GdkRegion *region) +gdk_gc_set_clip_region (GdkGC *gc, + GdkRegion *region) { - GdkGCPrivate *private; + g_return_if_fail (GDK_IS_GC (gc)); + + if (region) + region = gdk_region_copy (region); + + _gdk_gc_set_clip_region_internal (gc, region); +} - g_return_if_fail (gc != NULL); +/** + * _gdk_gc_get_clip_region: + * @gc: a #GdkGC + * + * Gets the current clip region for @gc, if any. + * + * Return value: the clip region for the GC, or %NULL. + * (if a clip mask is set, the return will be %NULL) + * This value is owned by the GC and must not be freed. + **/ +GdkRegion * +_gdk_gc_get_clip_region (GdkGC *gc) +{ + g_return_val_if_fail (GDK_IS_GC (gc), NULL); - private = (GdkGCPrivate*) gc; + return GDK_GC_GET_PRIVATE (gc)->clip_region; +} - if (region) - { - GdkRegionPrivate *region_private; +/** + * _gdk_gc_get_fill: + * @gc: a #GdkGC + * + * Gets the current file style for the GC + * + * Return value: the file style for the GC + **/ +GdkFill +_gdk_gc_get_fill (GdkGC *gc) +{ + g_return_val_if_fail (GDK_IS_GC (gc), GDK_SOLID); - region_private = (GdkRegionPrivate*) region; - XSetRegion (private->xdisplay, private->xgc, region_private->xregion); - } - else - XSetClipMask (private->xdisplay, private->xgc, None); + return GDK_GC_GET_PRIVATE (gc)->fill; +} + +/** + * _gdk_gc_get_tile: + * @gc: a #GdkGC + * + * Gets the tile pixmap for @gc, if any + * + * Return value: the tile set on the GC, or %NULL. The + * value is owned by the GC and must not be freed. + **/ +GdkPixmap * +_gdk_gc_get_tile (GdkGC *gc) +{ + g_return_val_if_fail (GDK_IS_GC (gc), NULL); + + return GDK_GC_GET_PRIVATE (gc)->tile; +} + +/** + * _gdk_gc_get_stipple: + * @gc: a #GdkGC + * + * Gets the stipple pixmap for @gc, if any + * + * Return value: the stipple set on the GC, or %NULL. The + * value is owned by the GC and must not be freed. + **/ +GdkBitmap * +_gdk_gc_get_stipple (GdkGC *gc) +{ + g_return_val_if_fail (GDK_IS_GC (gc), NULL); + + return GDK_GC_GET_PRIVATE (gc)->stipple; +} + +/** + * _gdk_gc_get_fg_pixel: + * @gc: a #GdkGC + * + * Gets the foreground pixel value for @gc. If the + * foreground pixel has never been set, returns the + * default value 0. + * + * Return value: the foreground pixel value of the GC + **/ +guint32 +_gdk_gc_get_fg_pixel (GdkGC *gc) +{ + g_return_val_if_fail (GDK_IS_GC (gc), 0); + + return GDK_GC_GET_PRIVATE (gc)->fg_pixel; } +/** + * _gdk_gc_get_bg_pixel: + * @gc: a #GdkGC + * + * Gets the background pixel value for @gc.If the + * foreground pixel has never been set, returns the + * default value 1. + * + * Return value: the foreground pixel value of the GC + **/ +guint32 +_gdk_gc_get_bg_pixel (GdkGC *gc) +{ + g_return_val_if_fail (GDK_IS_GC (gc), 0); + + return GDK_GC_GET_PRIVATE (gc)->bg_pixel; +} + +/** + * gdk_gc_set_subwindow: + * @gc: a #GdkGC. + * @mode: the subwindow mode. + * + * Sets how drawing with this GC on a window will affect child + * windows of that window. + **/ void gdk_gc_set_subwindow (GdkGC *gc, GdkSubwindowMode mode) { - GdkGCPrivate *private; - - g_return_if_fail (gc != NULL); + GdkGCValues values; - private = (GdkGCPrivate*) gc; + g_return_if_fail (GDK_IS_GC (gc)); - XSetSubwindowMode (private->xdisplay, private->xgc, mode); + values.subwindow_mode = mode; + gdk_gc_set_values (gc, &values, GDK_GC_SUBWINDOW); } +/** + * gdk_gc_set_exposures: + * @gc: a #GdkGC. + * @exposures: if %TRUE, exposure events will be generated. + * + * Sets whether copying non-visible portions of a drawable + * using this graphics context generate exposure events + * for the corresponding regions of the destination + * drawable. (See gdk_draw_drawable()). + **/ void -gdk_gc_set_exposures (GdkGC *gc, - gint exposures) +gdk_gc_set_exposures (GdkGC *gc, + gboolean exposures) { - GdkGCPrivate *private; - - g_return_if_fail (gc != NULL); + GdkGCValues values; - private = (GdkGCPrivate*) gc; + g_return_if_fail (GDK_IS_GC (gc)); - XSetGraphicsExposures (private->xdisplay, private->xgc, exposures); + values.graphics_exposures = exposures; + gdk_gc_set_values (gc, &values, GDK_GC_EXPOSURES); } +/** + * gdk_gc_set_line_attributes: + * @gc: a #GdkGC. + * @line_width: the width of lines. + * @line_style: the dash-style for lines. + * @cap_style: the manner in which the ends of lines are drawn. + * @join_style: the in which lines are joined together. + * + * Sets various attributes of how lines are drawn. See + * the corresponding members of #GdkGCValues for full + * explanations of the arguments. + **/ void gdk_gc_set_line_attributes (GdkGC *gc, gint line_width, @@ -742,91 +767,483 @@ gdk_gc_set_line_attributes (GdkGC *gc, GdkCapStyle cap_style, GdkJoinStyle join_style) { - GdkGCPrivate *private; - int xline_style; - int xcap_style; - int xjoin_style; + GdkGCValues values; + + values.line_width = line_width; + values.line_style = line_style; + values.cap_style = cap_style; + values.join_style = join_style; + + gdk_gc_set_values (gc, &values, + GDK_GC_LINE_WIDTH | + GDK_GC_LINE_STYLE | + GDK_GC_CAP_STYLE | + GDK_GC_JOIN_STYLE); +} - g_return_if_fail (gc != NULL); +/** + * gdk_gc_set_dashes: + * @gc: a #GdkGC. + * @dash_offset: the phase of the dash pattern. + * @dash_list: an array of dash lengths. + * @n: the number of elements in @dash_list. + * + * Sets the way dashed-lines are drawn. Lines will be + * drawn with alternating on and off segments of the + * lengths specified in @dash_list. The manner in + * which the on and off segments are drawn is determined + * by the @line_style value of the GC. (This can + * be changed with gdk_gc_set_line_attributes().) + * + * The @dash_offset defines the phase of the pattern, + * specifying how many pixels into the dash-list the pattern + * should actually begin. + **/ +void +gdk_gc_set_dashes (GdkGC *gc, + gint dash_offset, + gint8 dash_list[], + gint n) +{ + g_return_if_fail (GDK_IS_GC (gc)); + g_return_if_fail (dash_list != NULL); - private = (GdkGCPrivate*) gc; + GDK_GC_GET_CLASS (gc)->set_dashes (gc, dash_offset, dash_list, n); +} - switch (line_style) +/** + * gdk_gc_offset: + * @gc: a #GdkGC + * @x_offset: amount by which to offset the GC in the X direction + * @y_offset: amount by which to offset the GC in the Y direction + * + * Offset attributes such as the clip and tile-stipple origins + * of the GC so that drawing at x - x_offset, y - y_offset with + * the offset GC has the same effect as drawing at x, y with the original + * GC. + **/ +void +gdk_gc_offset (GdkGC *gc, + gint x_offset, + gint y_offset) +{ + if (x_offset != 0 || y_offset != 0) { - case GDK_LINE_SOLID: - xline_style = LineSolid; - break; - case GDK_LINE_ON_OFF_DASH: - xline_style = LineOnOffDash; - break; - case GDK_LINE_DOUBLE_DASH: - xline_style = LineDoubleDash; - break; - default: - xline_style = None; + GdkGCValues values; + + values.clip_x_origin = gc->clip_x_origin - x_offset; + values.clip_y_origin = gc->clip_y_origin - y_offset; + values.ts_x_origin = gc->ts_x_origin - x_offset; + values.ts_y_origin = gc->ts_y_origin - y_offset; + + gdk_gc_set_values (gc, &values, + GDK_GC_CLIP_X_ORIGIN | + GDK_GC_CLIP_Y_ORIGIN | + GDK_GC_TS_X_ORIGIN | + GDK_GC_TS_Y_ORIGIN); } +} + +/** + * gdk_gc_copy: + * @dst_gc: the destination graphics context. + * @src_gc: the source graphics context. + * + * Copy the set of values from one graphics context + * onto another graphics context. + **/ +void +gdk_gc_copy (GdkGC *dst_gc, + GdkGC *src_gc) +{ + GdkGCPrivate *dst_priv, *src_priv; + + g_return_if_fail (GDK_IS_GC (dst_gc)); + g_return_if_fail (GDK_IS_GC (src_gc)); + + dst_priv = GDK_GC_GET_PRIVATE (dst_gc); + src_priv = GDK_GC_GET_PRIVATE (src_gc); + + _gdk_windowing_gc_copy (dst_gc, src_gc); + + dst_gc->clip_x_origin = src_gc->clip_x_origin; + dst_gc->clip_y_origin = src_gc->clip_y_origin; + dst_gc->ts_x_origin = src_gc->ts_x_origin; + dst_gc->ts_y_origin = src_gc->ts_y_origin; + + if (src_gc->colormap) + g_object_ref (src_gc->colormap); + + if (dst_gc->colormap) + g_object_unref (dst_gc->colormap); + + dst_gc->colormap = src_gc->colormap; - switch (cap_style) + if (dst_priv->clip_region) + gdk_region_destroy (dst_priv->clip_region); + + if (src_priv->clip_region) + dst_priv->clip_region = gdk_region_copy (src_priv->clip_region); + else + dst_priv->clip_region = NULL; + + dst_priv->fill = src_priv->fill; + + if (dst_priv->stipple) + g_object_unref (dst_priv->stipple); + dst_priv->stipple = src_priv->stipple; + if (dst_priv->stipple) + g_object_ref (dst_priv->stipple); + + if (dst_priv->tile) + g_object_unref (dst_priv->tile); + dst_priv->tile = src_priv->tile; + if (dst_priv->tile) + g_object_ref (dst_priv->tile); + + dst_priv->fg_pixel = src_priv->fg_pixel; + dst_priv->bg_pixel = src_priv->bg_pixel; +} + +/** + * gdk_gc_set_colormap: + * @gc: a #GdkGC + * @colormap: a #GdkColormap + * + * Sets the colormap for the GC to the given colormap. The depth + * of the colormap's visual must match the depth of the drawable + * for which the GC was created. + **/ +void +gdk_gc_set_colormap (GdkGC *gc, + GdkColormap *colormap) +{ + g_return_if_fail (GDK_IS_GC (gc)); + g_return_if_fail (GDK_IS_COLORMAP (colormap)); + + if (gc->colormap != colormap) { - case GDK_CAP_NOT_LAST: - xcap_style = CapNotLast; - break; - case GDK_CAP_BUTT: - xcap_style = CapButt; - break; - case GDK_CAP_ROUND: - xcap_style = CapRound; - break; - case GDK_CAP_PROJECTING: - xcap_style = CapProjecting; - break; - default: - xcap_style = None; + if (gc->colormap) + g_object_unref (gc->colormap); + + gc->colormap = colormap; + g_object_ref (gc->colormap); } + +} - switch (join_style) +/** + * gdk_gc_get_colormap: + * @gc: a #GdkGC + * + * Retrieves the colormap for a given GC, if it exists. + * A GC will have a colormap if the drawable for which it was created + * has a colormap, or if a colormap was set explicitely with + * gdk_gc_set_colormap. + * + * Return value: the colormap of @gc, or %NULL if @gc doesn't have one. + **/ +GdkColormap * +gdk_gc_get_colormap (GdkGC *gc) +{ + g_return_val_if_fail (GDK_IS_GC (gc), NULL); + + return gc->colormap; +} + +static GdkColormap * +gdk_gc_get_colormap_warn (GdkGC *gc) +{ + GdkColormap *colormap = gdk_gc_get_colormap (gc); + if (!colormap) { - case GDK_JOIN_MITER: - xjoin_style = JoinMiter; - break; - case GDK_JOIN_ROUND: - xjoin_style = JoinRound; - break; - case GDK_JOIN_BEVEL: - xjoin_style = JoinBevel; - break; - default: - xjoin_style = None; + g_warning ("gdk_gc_set_rgb_fg_color() and gdk_gc_set_rgb_bg_color() can\n" + "only be used on GC's with a colormap. A GC will have a colormap\n" + "if it is created for a drawable with a colormap, or if a\n" + "colormap has been set explicitly with gdk_gc_set_colormap.\n"); + return NULL; } - XSetLineAttributes (private->xdisplay, private->xgc, line_width, - xline_style, xcap_style, xjoin_style); + return colormap; } +/** + * gdk_gc_set_rgb_fg_color: + * @gc: a #GdkGC + * @color: an unallocated #GdkColor. + * + * Set the foreground color of a GC using an unallocated color. The + * pixel value for the color will be determined using GdkRGB. If the + * colormap for the GC has not previously been initialized for GdkRGB, + * then for pseudo-color colormaps (colormaps with a small modifiable + * number of colors), a colorcube will be allocated in the colormap. + * + * Calling this function for a GC without a colormap is an error. + **/ void -gdk_gc_set_dashes (GdkGC *gc, - gint dash_offset, - gchar dash_list[], - gint n) +gdk_gc_set_rgb_fg_color (GdkGC *gc, + const GdkColor *color) { - GdkGCPrivate *private; + GdkColormap *cmap; + GdkColor tmp_color; - g_return_if_fail (gc != NULL); - g_return_if_fail (dash_list != NULL); + g_return_if_fail (GDK_IS_GC (gc)); + g_return_if_fail (color != NULL); - private = (GdkGCPrivate*) gc; + cmap = gdk_gc_get_colormap_warn (gc); + if (!cmap) + return; - XSetDashes (private->xdisplay, private->xgc, dash_offset, dash_list, n); + tmp_color = *color; + gdk_rgb_find_color (cmap, &tmp_color); + gdk_gc_set_foreground (gc, &tmp_color); } +/** + * gdk_gc_set_rgb_bg_color: + * @gc: a #GdkGC + * @color: an unallocated #GdkColor. + * + * Set the background color of a GC using an unallocated color. The + * pixel value for the color will be determined using GdkRGB. If the + * colormap for the GC has not previously been initialized for GdkRGB, + * then for pseudo-color colormaps (colormaps with a small modifiable + * number of colors), a colorcube will be allocated in the colormap. + * + * Calling this function for a GC without a colormap is an error. + **/ void -gdk_gc_copy (GdkGC *dst_gc, GdkGC *src_gc) +gdk_gc_set_rgb_bg_color (GdkGC *gc, + const GdkColor *color) +{ + GdkColormap *cmap; + GdkColor tmp_color; + + g_return_if_fail (GDK_IS_GC (gc)); + g_return_if_fail (color != NULL); + + cmap = gdk_gc_get_colormap_warn (gc); + if (!cmap) + return; + + tmp_color = *color; + gdk_rgb_find_color (cmap, &tmp_color); + gdk_gc_set_background (gc, &tmp_color); +} + +static cairo_surface_t * +make_stipple_tile_surface (cairo_t *cr, + GdkBitmap *stipple, + GdkColor *foreground, + GdkColor *background) +{ + cairo_t *tmp_cr; + cairo_surface_t *surface; + cairo_surface_t *alpha_surface; + gint width, height; + + gdk_drawable_get_size (stipple, + &width, &height); + + alpha_surface = _gdk_drawable_ref_cairo_surface (stipple); + + surface = cairo_surface_create_similar (cairo_get_target (cr), + CAIRO_CONTENT_COLOR_ALPHA, + width, height); + + tmp_cr = cairo_create (surface); + + cairo_set_operator (tmp_cr, CAIRO_OPERATOR_SOURCE); + + if (background) + gdk_cairo_set_source_color (tmp_cr, background); + else + cairo_set_source_rgba (tmp_cr, 0, 0, 0 ,0); + + cairo_paint (tmp_cr); + + cairo_set_operator (tmp_cr, CAIRO_OPERATOR_OVER); + + gdk_cairo_set_source_color (tmp_cr, foreground); + cairo_mask_surface (tmp_cr, alpha_surface, 0, 0); + + cairo_destroy (tmp_cr); + cairo_surface_destroy (alpha_surface); + + return surface; +} + +static void +gc_get_foreground (GdkGC *gc, + GdkColor *color) { - GdkGCPrivate *dst_private, *src_private; + GdkGCPrivate *priv = GDK_GC_GET_PRIVATE (gc); + + color->pixel = priv->bg_pixel; + + if (gc->colormap) + gdk_colormap_query_color (gc->colormap, priv->fg_pixel, color); + else + g_warning ("No colormap in gc_get_foreground"); +} - src_private = (GdkGCPrivate *) src_gc; - dst_private = (GdkGCPrivate *) dst_gc; +static void +gc_get_background (GdkGC *gc, + GdkColor *color) +{ + GdkGCPrivate *priv = GDK_GC_GET_PRIVATE (gc); + + color->pixel = priv->bg_pixel; - XCopyGC (src_private->xdisplay, src_private->xgc, ~((~1) << GCLastBit), - dst_private->xgc); + if (gc->colormap) + gdk_colormap_query_color (gc->colormap, priv->bg_pixel, color); + else + g_warning ("No colormap in gc_get_background"); } + +/** + * _gdk_gc_update_context: + * @gc: a #GdkGC + * @cr: a #cairo_t + * @override_foreground: a foreground color to use to override the + * foreground color of the GC + * @override_stipple: a stipple pattern to use to override the + * stipple from the GC. If this is present and the fill mode + * of the GC isn't %GDK_STIPPLED or %GDK_OPAQUE_STIPPLED + * the fill mode will be forced to %GDK_STIPPLED + * @gc_changed: pass %FALSE if the @gc has not changed since the + * last call to this function + * + * Set the attributes of a cairo context to match those of a #GdkGC + * as far as possible. Some aspects of a #GdkGC, such as clip masks + * and functions other than %GDK_COPY are not currently handled. + **/ +void +_gdk_gc_update_context (GdkGC *gc, + cairo_t *cr, + GdkColor *override_foreground, + GdkBitmap *override_stipple, + gboolean gc_changed) +{ + GdkGCPrivate *priv; + GdkFill fill; + GdkColor foreground; + GdkColor background; + cairo_surface_t *tile_surface = NULL; + GdkBitmap *stipple = NULL; + + g_return_if_fail (GDK_IS_GC (gc)); + g_return_if_fail (cr != NULL); + g_return_if_fail (override_stipple == NULL || GDK_IS_PIXMAP (override_stipple)); + + priv = GDK_GC_GET_PRIVATE (gc); + + fill = priv->fill; + if (override_stipple && fill != GDK_OPAQUE_STIPPLED) + fill = GDK_STIPPLED; + + if (fill != GDK_TILED) + { + if (override_foreground) + foreground = *override_foreground; + else + gc_get_foreground (gc, &foreground); + } + + if (fill == GDK_OPAQUE_STIPPLED) + gc_get_background (gc, &background); + + + switch (fill) + { + case GDK_SOLID: + break; + case GDK_TILED: + if (!priv->tile) + fill = GDK_SOLID; + break; + case GDK_STIPPLED: + case GDK_OPAQUE_STIPPLED: + if (override_stipple) + stipple = override_stipple; + else + stipple = priv->stipple; + + if (!stipple) + fill = GDK_SOLID; + break; + } + + switch (fill) + { + case GDK_SOLID: + gdk_cairo_set_source_color (cr, &foreground); + break; + case GDK_TILED: + tile_surface = _gdk_drawable_ref_cairo_surface (priv->tile); + break; + case GDK_STIPPLED: + tile_surface = make_stipple_tile_surface (cr, stipple, &foreground, NULL); + break; + case GDK_OPAQUE_STIPPLED: + tile_surface = make_stipple_tile_surface (cr, stipple, &foreground, &background); + break; + } + + /* Tiles, stipples, and clip regions are all specified in device space, + * not user space. For the clip region, we can simply change the matrix, + * clip, then clip back, but for the source pattern, we need to + * compute the right matrix. + * + * What we want is: + * + * CTM_inverse * Pattern_matrix = Translate(- ts_x, - ts_y) + * + * (So that ts_x, ts_y in device space is taken to 0,0 in pattern + * space). So, pattern_matrix = CTM * Translate(- ts_x, - tx_y); + */ + + if (tile_surface) + { + cairo_pattern_t *pattern = cairo_pattern_create_for_surface (tile_surface); + cairo_matrix_t user_to_device; + cairo_matrix_t user_to_pattern; + cairo_matrix_t device_to_pattern; + + cairo_get_matrix (cr, &user_to_device); + cairo_matrix_init_translate (&device_to_pattern, + - gc->ts_x_origin, - gc->ts_y_origin); + cairo_matrix_multiply (&user_to_pattern, + &user_to_device, &device_to_pattern); + + cairo_pattern_set_matrix (pattern, &user_to_pattern); + cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT); + cairo_set_source (cr, pattern); + + cairo_surface_destroy (tile_surface); + cairo_pattern_destroy (pattern); + } + + if (!gc_changed) + return; + + cairo_reset_clip (cr); + if (priv->clip_region) + { + cairo_save (cr); + + cairo_identity_matrix (cr); + cairo_translate (cr, gc->clip_x_origin, gc->clip_y_origin); + + cairo_new_path (cr); + gdk_cairo_region (cr, priv->clip_region); + + cairo_restore (cr); + + cairo_clip (cr); + } +} + + +#define __GDK_GC_C__ +#include "gdkaliasdef.c"