1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
30 #include "gdkprivate-x11.h"
31 #include "gdkregion-generic.h"
37 GDK_GC_DIRTY_CLIP = 1 << 0,
38 GDK_GC_DIRTY_TS = 1 << 1
41 static void gdk_x11_gc_values_to_xvalues (GdkGCValues *values,
44 unsigned long *xvalues_mask);
46 static void gdk_x11_gc_get_values (GdkGC *gc,
48 static void gdk_x11_gc_set_values (GdkGC *gc,
50 GdkGCValuesMask values_mask);
51 static void gdk_x11_gc_set_dashes (GdkGC *gc,
56 static void gdk_gc_x11_class_init (GdkGCX11Class *klass);
57 static void gdk_gc_x11_finalize (GObject *object);
59 static gpointer parent_class = NULL;
62 _gdk_gc_x11_get_type (void)
64 static GType object_type = 0;
68 static const GTypeInfo object_info =
70 sizeof (GdkGCX11Class),
72 (GBaseFinalizeFunc) NULL,
73 (GClassInitFunc) gdk_gc_x11_class_init,
74 NULL, /* class_finalize */
75 NULL, /* class_data */
78 (GInstanceInitFunc) NULL,
81 object_type = g_type_register_static (GDK_TYPE_GC,
90 gdk_gc_x11_class_init (GdkGCX11Class *klass)
92 GObjectClass *object_class = G_OBJECT_CLASS (klass);
93 GdkGCClass *gc_class = GDK_GC_CLASS (klass);
95 parent_class = g_type_class_peek_parent (klass);
97 object_class->finalize = gdk_gc_x11_finalize;
99 gc_class->get_values = gdk_x11_gc_get_values;
100 gc_class->set_values = gdk_x11_gc_set_values;
101 gc_class->set_dashes = gdk_x11_gc_set_dashes;
105 gdk_gc_x11_finalize (GObject *object)
107 GdkGCX11 *x11_gc = GDK_GC_X11 (object);
109 if (x11_gc->clip_region)
110 gdk_region_destroy (x11_gc->clip_region);
113 if (x11_gc->fg_picture != None)
114 XRenderFreePicture (GDK_GC_XDISPLAY (x11_gc), x11_gc->fg_picture);
117 XFreeGC (GDK_GC_XDISPLAY (x11_gc), GDK_GC_XGC (x11_gc));
119 G_OBJECT_CLASS (parent_class)->finalize (object);
124 _gdk_x11_gc_new (GdkDrawable *drawable,
126 GdkGCValuesMask values_mask)
132 unsigned long xvalues_mask;
134 /* NOTICE that the drawable here has to be the impl drawable,
135 * not the publically-visible drawables.
137 g_return_val_if_fail (GDK_IS_DRAWABLE_IMPL_X11 (drawable), NULL);
139 gc = g_object_new (_gdk_gc_x11_get_type (), NULL);
140 private = GDK_GC_X11 (gc);
142 private->dirty_mask = 0;
143 private->have_clip_mask = FALSE;
144 private->clip_region = NULL;
146 private->screen = GDK_DRAWABLE_IMPL_X11 (drawable)->screen;
148 if (values_mask & (GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN))
150 values_mask &= ~(GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN);
151 private->dirty_mask |= GDK_GC_DIRTY_CLIP;
154 if (values_mask & (GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN))
156 values_mask &= ~(GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN);
157 private->dirty_mask |= GDK_GC_DIRTY_TS;
160 if (values_mask & GDK_GC_FOREGROUND)
161 private->fg_pixel = values->foreground.pixel;
163 if ((values_mask & GDK_GC_CLIP_MASK) && values->clip_mask)
164 private->have_clip_mask = TRUE;
166 xvalues.function = GXcopy;
167 xvalues.fill_style = FillSolid;
168 xvalues.arc_mode = ArcPieSlice;
169 xvalues.subwindow_mode = ClipByChildren;
170 xvalues.graphics_exposures = False;
171 xvalues_mask = GCFunction | GCFillStyle | GCArcMode | GCSubwindowMode | GCGraphicsExposures;
173 gdk_x11_gc_values_to_xvalues (values, values_mask, &xvalues, &xvalues_mask);
175 private->xgc = XCreateGC (GDK_GC_XDISPLAY (gc),
176 GDK_DRAWABLE_IMPL_X11 (drawable)->xid,
177 xvalues_mask, &xvalues);
183 _gdk_x11_gc_flush (GdkGC *gc)
185 GdkGCX11 *private = GDK_GC_X11 (gc);
187 if (private->dirty_mask & GDK_GC_DIRTY_CLIP)
189 if (!private->clip_region)
190 XSetClipOrigin (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc),
191 gc->clip_x_origin, gc->clip_y_origin);
194 XRectangle *rectangles;
197 _gdk_region_get_xrectangles (private->clip_region,
203 XSetClipRectangles (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), 0, 0,
211 if (private->dirty_mask & GDK_GC_DIRTY_TS)
213 XSetTSOrigin (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc),
214 gc->ts_x_origin, gc->ts_y_origin);
217 private->dirty_mask = 0;
218 return GDK_GC_XGC (gc);
222 gdk_x11_gc_get_values (GdkGC *gc,
227 if (XGetGCValues (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc),
228 GCForeground | GCBackground | GCFont |
229 GCFunction | GCTile | GCStipple | /* GCClipMask | */
230 GCSubwindowMode | GCGraphicsExposures |
231 GCTileStipXOrigin | GCTileStipYOrigin |
232 GCClipXOrigin | GCClipYOrigin |
233 GCLineWidth | GCLineStyle | GCCapStyle |
234 GCFillStyle | GCJoinStyle, &xvalues))
236 values->foreground.pixel = xvalues.foreground;
237 values->background.pixel = xvalues.background;
238 values->font = gdk_font_lookup_for_display (GDK_GC_DISPLAY (gc),
241 switch (xvalues.function)
244 values->function = GDK_COPY;
247 values->function = GDK_INVERT;
250 values->function = GDK_XOR;
253 values->function = GDK_CLEAR;
256 values->function = GDK_AND;
259 values->function = GDK_AND_REVERSE;
262 values->function = GDK_AND_INVERT;
265 values->function = GDK_NOOP;
268 values->function = GDK_OR;
271 values->function = GDK_EQUIV;
274 values->function = GDK_OR_REVERSE;
277 values->function =GDK_COPY_INVERT;
280 values->function = GDK_OR_INVERT;
283 values->function = GDK_NAND;
286 values->function = GDK_SET;
289 values->function = GDK_NOR;
293 switch (xvalues.fill_style)
296 values->fill = GDK_SOLID;
299 values->fill = GDK_TILED;
302 values->fill = GDK_STIPPLED;
304 case FillOpaqueStippled:
305 values->fill = GDK_OPAQUE_STIPPLED;
309 values->tile = gdk_pixmap_lookup_for_display (GDK_GC_DISPLAY (gc),
311 values->stipple = gdk_pixmap_lookup_for_display (GDK_GC_DISPLAY (gc),
313 values->clip_mask = NULL;
314 values->subwindow_mode = xvalues.subwindow_mode;
315 values->ts_x_origin = xvalues.ts_x_origin;
316 values->ts_y_origin = xvalues.ts_y_origin;
317 values->clip_x_origin = xvalues.clip_x_origin;
318 values->clip_y_origin = xvalues.clip_y_origin;
319 values->graphics_exposures = xvalues.graphics_exposures;
320 values->line_width = xvalues.line_width;
322 switch (xvalues.line_style)
325 values->line_style = GDK_LINE_SOLID;
328 values->line_style = GDK_LINE_ON_OFF_DASH;
331 values->line_style = GDK_LINE_DOUBLE_DASH;
335 switch (xvalues.cap_style)
338 values->cap_style = GDK_CAP_NOT_LAST;
341 values->cap_style = GDK_CAP_BUTT;
344 values->cap_style = GDK_CAP_ROUND;
347 values->cap_style = GDK_CAP_PROJECTING;
351 switch (xvalues.join_style)
354 values->join_style = GDK_JOIN_MITER;
357 values->join_style = GDK_JOIN_ROUND;
360 values->join_style = GDK_JOIN_BEVEL;
366 memset (values, 0, sizeof (GdkGCValues));
372 gdk_x11_gc_set_values (GdkGC *gc,
374 GdkGCValuesMask values_mask)
378 unsigned long xvalues_mask = 0;
380 x11_gc = GDK_GC_X11 (gc);
382 if (values_mask & (GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN))
384 values_mask &= ~(GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN);
385 x11_gc->dirty_mask |= GDK_GC_DIRTY_CLIP;
388 if (values_mask & (GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN))
390 values_mask &= ~(GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN);
391 x11_gc->dirty_mask |= GDK_GC_DIRTY_TS;
394 if (values_mask & GDK_GC_CLIP_MASK)
396 if (x11_gc->clip_region)
398 gdk_region_destroy (x11_gc->clip_region);
399 x11_gc->clip_region = NULL;
402 x11_gc->have_clip_mask = values->clip_mask != NULL;
405 if (values_mask & GDK_GC_FOREGROUND)
406 x11_gc->fg_pixel = values->foreground.pixel;
408 gdk_x11_gc_values_to_xvalues (values, values_mask, &xvalues, &xvalues_mask);
410 XChangeGC (GDK_GC_XDISPLAY (gc),
417 gdk_x11_gc_set_dashes (GdkGC *gc,
422 g_return_if_fail (GDK_IS_GC (gc));
423 g_return_if_fail (dash_list != NULL);
425 XSetDashes (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc),
426 dash_offset, dash_list, n);
430 gdk_x11_gc_values_to_xvalues (GdkGCValues *values,
431 GdkGCValuesMask mask,
433 unsigned long *xvalues_mask)
435 /* Optimization for the common case (gdk_gc_new()) */
436 if (values == NULL || mask == 0)
439 if (mask & GDK_GC_FOREGROUND)
441 xvalues->foreground = values->foreground.pixel;
442 *xvalues_mask |= GCForeground;
444 if (mask & GDK_GC_BACKGROUND)
446 xvalues->background = values->background.pixel;
447 *xvalues_mask |= GCBackground;
449 if ((mask & GDK_GC_FONT) && (values->font->type == GDK_FONT_FONT))
451 xvalues->font = ((XFontStruct *) (GDK_FONT_XFONT (values->font)))->fid;
452 *xvalues_mask |= GCFont;
454 if (mask & GDK_GC_FUNCTION)
456 switch (values->function)
459 xvalues->function = GXcopy;
462 xvalues->function = GXinvert;
465 xvalues->function = GXxor;
468 xvalues->function = GXclear;
471 xvalues->function = GXand;
473 case GDK_AND_REVERSE:
474 xvalues->function = GXandReverse;
477 xvalues->function = GXandInverted;
480 xvalues->function = GXnoop;
483 xvalues->function = GXor;
486 xvalues->function = GXequiv;
489 xvalues->function = GXorReverse;
491 case GDK_COPY_INVERT:
492 xvalues->function = GXcopyInverted;
495 xvalues->function = GXorInverted;
498 xvalues->function = GXnand;
501 xvalues->function = GXset;
504 xvalues->function = GXnor;
507 *xvalues_mask |= GCFunction;
509 if (mask & GDK_GC_FILL)
511 switch (values->fill)
514 xvalues->fill_style = FillSolid;
517 xvalues->fill_style = FillTiled;
520 xvalues->fill_style = FillStippled;
522 case GDK_OPAQUE_STIPPLED:
523 xvalues->fill_style = FillOpaqueStippled;
526 *xvalues_mask |= GCFillStyle;
528 if (mask & GDK_GC_TILE)
531 xvalues->tile = GDK_DRAWABLE_XID (values->tile);
533 xvalues->tile = None;
535 *xvalues_mask |= GCTile;
537 if (mask & GDK_GC_STIPPLE)
540 xvalues->stipple = GDK_DRAWABLE_XID (values->stipple);
542 xvalues->stipple = None;
544 *xvalues_mask |= GCStipple;
546 if (mask & GDK_GC_CLIP_MASK)
548 if (values->clip_mask)
549 xvalues->clip_mask = GDK_DRAWABLE_XID (values->clip_mask);
551 xvalues->clip_mask = None;
553 *xvalues_mask |= GCClipMask;
556 if (mask & GDK_GC_SUBWINDOW)
558 xvalues->subwindow_mode = values->subwindow_mode;
559 *xvalues_mask |= GCSubwindowMode;
561 if (mask & GDK_GC_TS_X_ORIGIN)
563 xvalues->ts_x_origin = values->ts_x_origin;
564 *xvalues_mask |= GCTileStipXOrigin;
566 if (mask & GDK_GC_TS_Y_ORIGIN)
568 xvalues->ts_y_origin = values->ts_y_origin;
569 *xvalues_mask |= GCTileStipYOrigin;
571 if (mask & GDK_GC_CLIP_X_ORIGIN)
573 xvalues->clip_x_origin = values->clip_x_origin;
574 *xvalues_mask |= GCClipXOrigin;
576 if (mask & GDK_GC_CLIP_Y_ORIGIN)
578 xvalues->clip_y_origin = values->clip_y_origin;
579 *xvalues_mask |= GCClipYOrigin;
582 if (mask & GDK_GC_EXPOSURES)
584 xvalues->graphics_exposures = values->graphics_exposures;
585 *xvalues_mask |= GCGraphicsExposures;
588 if (mask & GDK_GC_LINE_WIDTH)
590 xvalues->line_width = values->line_width;
591 *xvalues_mask |= GCLineWidth;
593 if (mask & GDK_GC_LINE_STYLE)
595 switch (values->line_style)
598 xvalues->line_style = LineSolid;
600 case GDK_LINE_ON_OFF_DASH:
601 xvalues->line_style = LineOnOffDash;
603 case GDK_LINE_DOUBLE_DASH:
604 xvalues->line_style = LineDoubleDash;
607 *xvalues_mask |= GCLineStyle;
609 if (mask & GDK_GC_CAP_STYLE)
611 switch (values->cap_style)
613 case GDK_CAP_NOT_LAST:
614 xvalues->cap_style = CapNotLast;
617 xvalues->cap_style = CapButt;
620 xvalues->cap_style = CapRound;
622 case GDK_CAP_PROJECTING:
623 xvalues->cap_style = CapProjecting;
626 *xvalues_mask |= GCCapStyle;
628 if (mask & GDK_GC_JOIN_STYLE)
630 switch (values->join_style)
633 xvalues->join_style = JoinMiter;
636 xvalues->join_style = JoinRound;
639 xvalues->join_style = JoinBevel;
642 *xvalues_mask |= GCJoinStyle;
648 gdk_gc_set_clip_rectangle (GdkGC *gc,
649 GdkRectangle *rectangle)
652 gboolean had_region = FALSE;
654 g_return_if_fail (GDK_IS_GC (gc));
656 x11_gc = GDK_GC_X11 (gc);
658 if (x11_gc->clip_region)
661 gdk_region_destroy (x11_gc->clip_region);
665 x11_gc->clip_region = gdk_region_rectangle (rectangle);
667 x11_gc->clip_region = NULL;
669 /* Unset immediately, to make sure Xlib doesn't keep the
670 * XID of an old clip mask cached
672 if ((had_region && !rectangle) || x11_gc->have_clip_mask)
674 XSetClipMask (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), None);
675 x11_gc->have_clip_mask = FALSE;
678 gc->clip_x_origin = 0;
679 gc->clip_y_origin = 0;
681 x11_gc->dirty_mask |= GDK_GC_DIRTY_CLIP;
685 gdk_gc_set_clip_region (GdkGC *gc,
689 gboolean had_region = FALSE;
691 g_return_if_fail (GDK_IS_GC (gc));
693 x11_gc = GDK_GC_X11 (gc);
695 if (x11_gc->clip_region)
698 gdk_region_destroy (x11_gc->clip_region);
702 x11_gc->clip_region = gdk_region_copy (region);
704 x11_gc->clip_region = NULL;
706 /* Unset immediately, to make sure Xlib doesn't keep the
707 * XID of an old clip mask cached
709 if ((had_region && !region) || x11_gc->have_clip_mask)
711 XSetClipMask (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), None);
712 x11_gc->have_clip_mask = FALSE;
715 gc->clip_x_origin = 0;
716 gc->clip_y_origin = 0;
718 x11_gc->dirty_mask |= GDK_GC_DIRTY_CLIP;
723 gdk_gc_copy (GdkGC *dst_gc, GdkGC *src_gc)
725 GdkGCX11 *x11_src_gc;
726 GdkGCX11 *x11_dst_gc;
728 g_return_if_fail (GDK_IS_GC_X11 (dst_gc));
729 g_return_if_fail (GDK_IS_GC_X11 (src_gc));
731 x11_dst_gc = GDK_GC_X11 (dst_gc);
732 x11_src_gc = GDK_GC_X11 (src_gc);
734 XCopyGC (GDK_GC_XDISPLAY (src_gc), GDK_GC_XGC (src_gc), ~((~1) << GCLastBit),
735 GDK_GC_XGC (dst_gc));
737 dst_gc->clip_x_origin = src_gc->clip_x_origin;
738 dst_gc->clip_y_origin = src_gc->clip_y_origin;
739 dst_gc->ts_x_origin = src_gc->ts_x_origin;
740 dst_gc->ts_y_origin = src_gc->ts_y_origin;
742 if (src_gc->colormap)
743 g_object_ref (src_gc->colormap);
745 if (dst_gc->colormap)
746 g_object_unref (dst_gc->colormap);
748 dst_gc->colormap = src_gc->colormap;
750 if (x11_dst_gc->clip_region)
751 gdk_region_destroy (x11_dst_gc->clip_region);
753 if (x11_src_gc->clip_region)
754 x11_dst_gc->clip_region = gdk_region_copy (x11_src_gc->clip_region);
756 x11_dst_gc->clip_region = NULL;
758 x11_dst_gc->dirty_mask = x11_src_gc->dirty_mask;
759 x11_dst_gc->fg_pixel = x11_src_gc->fg_pixel;
766 * Gets the #GdkScreen for which @gc was created
768 * Returns: the #GdkScreen for @gc.
773 gdk_gc_get_screen (GdkGC *gc)
775 g_return_val_if_fail (GDK_IS_GC_X11 (gc), NULL);
777 return GDK_GC_X11 (gc)->screen;
781 * gdk_x11_gc_get_xdisplay:
784 * Returns the display of a #GdkGC.
786 * Return value: an Xlib <type>Display*</type>.
789 gdk_x11_gc_get_xdisplay (GdkGC *gc)
791 g_return_val_if_fail (GDK_IS_GC_X11 (gc), NULL);
793 return GDK_SCREEN_XDISPLAY (gdk_gc_get_screen (gc));
797 * gdk_x11_gc_get_xgc:
800 * Returns the X GC of a #GdkGC.
802 * Return value: an Xlib <type>GC</type>.
805 gdk_x11_gc_get_xgc (GdkGC *gc)
809 g_return_val_if_fail (GDK_IS_GC_X11 (gc), NULL);
811 gc_x11 = GDK_GC_X11 (gc);
813 if (gc_x11->dirty_mask)
814 _gdk_x11_gc_flush (gc);
820 /* Various bits of the below are roughly cribbed from XFree86
821 * lib/Xft/xftdraw.c, Copyright 2000, Keith Packard
824 static XRenderPictFormat *
825 foreground_format (GdkGC *gc)
827 XRenderPictFormat pf;
829 pf.type = PictTypeDirect;
831 pf.direct.redMask = 0xff;
832 pf.direct.greenMask = 0xff;
833 pf.direct.blueMask = 0xff;
834 pf.direct.alphaMask = 0xff;
836 return XRenderFindFormat (GDK_GC_XDISPLAY (gc),
840 PictFormatGreenMask |
842 PictFormatAlphaMask),
848 * _gdk_x11_gc_get_fg_picture:
851 * Gets a Xrender Picture object suitable for being the source
852 * drawable for drawing with the foreground the graphics context.
853 * (Currently, only foreground color is handled, but in the
854 * future we should handle tiles/stipples as well.)
856 * Return value: a Picture, owned by the GC; this cannot be
857 * used over subsequent modification of the GC.
860 _gdk_x11_gc_get_fg_picture (GdkGC *gc)
864 gboolean new = FALSE;
867 g_return_val_if_fail (GDK_IS_GC_X11 (gc), None);
869 if (!_gdk_x11_have_render (GDK_GC_DISPLAY (gc)))
872 x11_gc = GDK_GC_X11 (gc);
873 cmap = gdk_gc_get_colormap (gc);
875 if (x11_gc->fg_picture == None)
877 XRenderPictureAttributes pa;
878 XRenderPictFormat *pix_format = foreground_format (gc);
884 pix = XCreatePixmap (GDK_GC_XDISPLAY (gc),
885 GDK_SCREEN_XROOTWIN (x11_gc->screen),
886 1, 1, pix_format->depth);
888 x11_gc->fg_picture = XRenderCreatePicture (GDK_GC_XDISPLAY (gc),
892 XFreePixmap (GDK_GC_XDISPLAY (gc), pix);
897 gdk_colormap_query_color (cmap, x11_gc->fg_pixel, &color);
900 x11_gc->fg_picture_color.red != color.red ||
901 x11_gc->fg_picture_color.green != color.green ||
902 x11_gc->fg_picture_color.blue != color.blue)
904 x11_gc->fg_picture_color.red = color.red;
905 x11_gc->fg_picture_color.green = color.green;
906 x11_gc->fg_picture_color.blue = color.blue;
907 x11_gc->fg_picture_color.alpha = 0xffff;
909 XRenderFillRectangle (GDK_GC_XDISPLAY (gc), PictOpSrc,
910 x11_gc->fg_picture, &x11_gc->fg_picture_color,
914 return x11_gc->fg_picture;
918 * _gdk_gc_x11_get_fg_xft_color:
920 * @xftcolor: location to store the color
922 * Gets the foreground color of the GC as a XftColor.
925 _gdk_gc_x11_get_fg_xft_color (GdkGC *gc,
932 g_return_if_fail (GDK_IS_GC_X11 (gc));
934 x11_gc = GDK_GC_X11 (gc);
935 cmap = gdk_gc_get_colormap (gc);
937 xftcolor->pixel = x11_gc->fg_pixel;
939 gdk_colormap_query_color (cmap, xftcolor->pixel, &color);
940 xftcolor->color.red = color.red;
941 xftcolor->color.green = color.green;
942 xftcolor->color.blue = color.blue;
943 xftcolor->color.alpha = 0xffff;
946 #endif /* HAVE_XFT */