]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkgc-x11.c
Add GdkPangoRenderer, a subclass of PangoRenderer targeting GDK drawables.
[~andy/gtk] / gdk / x11 / gdkgc-x11.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 /*
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/. 
25  */
26
27 #include <config.h>
28
29 #include "gdkalias.h"
30 #include "gdkgc.h"
31 #include "gdkprivate-x11.h"
32 #include "gdkregion-generic.h"
33 #include "gdkx.h"
34
35 #include <string.h>
36
37 typedef enum {
38   GDK_GC_DIRTY_CLIP = 1 << 0,
39   GDK_GC_DIRTY_TS = 1 << 1
40 } GdkGCDirtyValues;
41
42 static void gdk_x11_gc_values_to_xvalues (GdkGCValues    *values,
43                                           GdkGCValuesMask mask,
44                                           XGCValues      *xvalues,
45                                           unsigned long  *xvalues_mask);
46
47 static void gdk_x11_gc_get_values (GdkGC           *gc,
48                                    GdkGCValues     *values);
49 static void gdk_x11_gc_set_values (GdkGC           *gc,
50                                    GdkGCValues     *values,
51                                    GdkGCValuesMask  values_mask);
52 static void gdk_x11_gc_set_dashes (GdkGC           *gc,
53                                    gint             dash_offset,
54                                    gint8            dash_list[],
55                                    gint             n);
56
57 static void gdk_gc_x11_class_init (GdkGCX11Class *klass);
58 static void gdk_gc_x11_finalize   (GObject           *object);
59
60 static gpointer parent_class = NULL;
61
62 GType
63 _gdk_gc_x11_get_type (void)
64 {
65   static GType object_type = 0;
66
67   if (!object_type)
68     {
69       static const GTypeInfo object_info =
70       {
71         sizeof (GdkGCX11Class),
72         (GBaseInitFunc) NULL,
73         (GBaseFinalizeFunc) NULL,
74         (GClassInitFunc) gdk_gc_x11_class_init,
75         NULL,           /* class_finalize */
76         NULL,           /* class_data */
77         sizeof (GdkGCX11),
78         0,              /* n_preallocs */
79         (GInstanceInitFunc) NULL,
80       };
81       
82       object_type = g_type_register_static (GDK_TYPE_GC,
83                                             "GdkGCX11",
84                                             &object_info, 0);
85     }
86   
87   return object_type;
88 }
89
90 static void
91 gdk_gc_x11_class_init (GdkGCX11Class *klass)
92 {
93   GObjectClass *object_class = G_OBJECT_CLASS (klass);
94   GdkGCClass *gc_class = GDK_GC_CLASS (klass);
95   
96   parent_class = g_type_class_peek_parent (klass);
97
98   object_class->finalize = gdk_gc_x11_finalize;
99
100   gc_class->get_values = gdk_x11_gc_get_values;
101   gc_class->set_values = gdk_x11_gc_set_values;
102   gc_class->set_dashes = gdk_x11_gc_set_dashes;
103 }
104
105 static void
106 gdk_gc_x11_finalize (GObject *object)
107 {
108   GdkGCX11 *x11_gc = GDK_GC_X11 (object);
109   
110   if (x11_gc->clip_region)
111     gdk_region_destroy (x11_gc->clip_region);
112   
113   if (x11_gc->fg_picture != None)
114     XRenderFreePicture (GDK_GC_XDISPLAY (x11_gc), x11_gc->fg_picture);
115
116   if (x11_gc->stipple)
117     g_object_unref (x11_gc->stipple);
118   if (x11_gc->tile)
119     g_object_unref (x11_gc->tile);
120   
121   XFreeGC (GDK_GC_XDISPLAY (x11_gc), GDK_GC_XGC (x11_gc));
122
123   G_OBJECT_CLASS (parent_class)->finalize (object);
124 }
125
126
127 GdkGC *
128 _gdk_x11_gc_new (GdkDrawable      *drawable,
129                  GdkGCValues      *values,
130                  GdkGCValuesMask   values_mask)
131 {
132   GdkGC *gc;
133   GdkGCX11 *private;
134   
135   XGCValues xvalues;
136   unsigned long xvalues_mask;
137
138   /* NOTICE that the drawable here has to be the impl drawable,
139    * not the publically-visible drawables.
140    */
141   g_return_val_if_fail (GDK_IS_DRAWABLE_IMPL_X11 (drawable), NULL);
142
143   gc = g_object_new (_gdk_gc_x11_get_type (), NULL);
144   private = GDK_GC_X11 (gc);
145
146   private->dirty_mask = 0;
147   private->have_clip_mask = FALSE;
148   private->clip_region = NULL;
149     
150   private->screen = GDK_DRAWABLE_IMPL_X11 (drawable)->screen;
151
152   private->depth = gdk_drawable_get_depth (drawable);
153
154   if (values_mask & (GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN))
155     {
156       values_mask &= ~(GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN);
157       private->dirty_mask |= GDK_GC_DIRTY_CLIP;
158     }
159
160   if (values_mask & (GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN))
161     {
162       values_mask &= ~(GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN);
163       private->dirty_mask |= GDK_GC_DIRTY_TS;
164     }
165
166   if (values_mask & GDK_GC_FOREGROUND)
167     private->fg_pixel = values->foreground.pixel;
168
169   if (values_mask & GDK_GC_BACKGROUND)
170     private->bg_pixel = values->background.pixel;
171
172   if (values_mask & GDK_GC_FILL)
173     private->fill = values->fill;
174   
175   if (values_mask & GDK_GC_STIPPLE)
176     {
177       private->stipple = values->stipple;
178       if (private->stipple)
179         g_object_ref (private->stipple);
180     }
181   
182   if (values_mask & GDK_GC_TILE)
183     {
184       private->tile = values->tile;
185       if (private->tile)
186         g_object_ref (private->tile);
187     }
188   
189   if ((values_mask & GDK_GC_CLIP_MASK) && values->clip_mask)
190     private->have_clip_mask = TRUE;
191
192   xvalues.function = GXcopy;
193   xvalues.fill_style = FillSolid;
194   xvalues.arc_mode = ArcPieSlice;
195   xvalues.subwindow_mode = ClipByChildren;
196   xvalues.graphics_exposures = False;
197   xvalues_mask = GCFunction | GCFillStyle | GCArcMode | GCSubwindowMode | GCGraphicsExposures;
198
199   gdk_x11_gc_values_to_xvalues (values, values_mask, &xvalues, &xvalues_mask);
200   
201   private->xgc = XCreateGC (GDK_GC_XDISPLAY (gc),
202                             GDK_DRAWABLE_IMPL_X11 (drawable)->xid,
203                             xvalues_mask, &xvalues);
204
205   return gc;
206 }
207
208 GC
209 _gdk_x11_gc_flush (GdkGC *gc)
210 {
211   GdkGCX11 *private = GDK_GC_X11 (gc);
212
213   if (private->dirty_mask & GDK_GC_DIRTY_CLIP)
214     {
215       if (!private->clip_region)
216         XSetClipOrigin (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc),
217                         gc->clip_x_origin, gc->clip_y_origin);
218       else
219         {
220           XRectangle *rectangles;
221           gint n_rects;
222
223           _gdk_region_get_xrectangles (private->clip_region,
224                                        gc->clip_x_origin,
225                                        gc->clip_y_origin,
226                                        &rectangles,
227                                        &n_rects);
228           
229           XSetClipRectangles (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), 0, 0,
230                               rectangles,
231                               n_rects, YXBanded);
232           
233           g_free (rectangles);
234         }
235     }
236
237   if (private->dirty_mask & GDK_GC_DIRTY_TS)
238     {
239       XSetTSOrigin (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc),
240                     gc->ts_x_origin, gc->ts_y_origin);
241     }
242
243   private->dirty_mask = 0;
244   return GDK_GC_XGC (gc);
245 }
246
247 static void
248 gdk_x11_gc_get_values (GdkGC       *gc,
249                        GdkGCValues *values)
250 {
251   XGCValues xvalues;
252   
253   if (XGetGCValues (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc),
254                     GCForeground | GCBackground | GCFont |
255                     GCFunction | GCTile | GCStipple | /* GCClipMask | */
256                     GCSubwindowMode | GCGraphicsExposures |
257                     GCTileStipXOrigin | GCTileStipYOrigin |
258                     GCClipXOrigin | GCClipYOrigin |
259                     GCLineWidth | GCLineStyle | GCCapStyle |
260                     GCFillStyle | GCJoinStyle, &xvalues))
261     {
262       values->foreground.pixel = xvalues.foreground;
263       values->background.pixel = xvalues.background;
264       values->font = gdk_font_lookup_for_display (GDK_GC_DISPLAY (gc),
265                                                   xvalues.font);
266
267       switch (xvalues.function)
268         {
269         case GXcopy:
270           values->function = GDK_COPY;
271           break;
272         case GXinvert:
273           values->function = GDK_INVERT;
274           break;
275         case GXxor:
276           values->function = GDK_XOR;
277           break;
278         case GXclear:
279           values->function = GDK_CLEAR;
280           break;
281         case GXand:
282           values->function = GDK_AND;
283           break;
284         case GXandReverse:
285           values->function = GDK_AND_REVERSE;
286           break;
287         case GXandInverted:
288           values->function = GDK_AND_INVERT;
289           break;
290         case GXnoop:
291           values->function = GDK_NOOP;
292           break;
293         case GXor:
294           values->function = GDK_OR;
295           break;
296         case GXequiv:
297           values->function = GDK_EQUIV;
298           break;
299         case GXorReverse:
300           values->function = GDK_OR_REVERSE;
301           break;
302         case GXcopyInverted:
303           values->function =GDK_COPY_INVERT;
304           break;
305         case GXorInverted:
306           values->function = GDK_OR_INVERT;
307           break;
308         case GXnand:
309           values->function = GDK_NAND;
310           break;
311         case GXset:
312           values->function = GDK_SET;
313           break;
314         case GXnor:
315           values->function = GDK_NOR;
316           break;
317         }
318
319       switch (xvalues.fill_style)
320         {
321         case FillSolid:
322           values->fill = GDK_SOLID;
323           break;
324         case FillTiled:
325           values->fill = GDK_TILED;
326           break;
327         case FillStippled:
328           values->fill = GDK_STIPPLED;
329           break;
330         case FillOpaqueStippled:
331           values->fill = GDK_OPAQUE_STIPPLED;
332           break;
333         }
334
335       values->tile = gdk_pixmap_lookup_for_display (GDK_GC_DISPLAY (gc),
336                                                     xvalues.tile);
337       values->stipple = gdk_pixmap_lookup_for_display (GDK_GC_DISPLAY (gc),
338                                                        xvalues.stipple);
339       values->clip_mask = NULL;
340       values->subwindow_mode = xvalues.subwindow_mode;
341       values->ts_x_origin = xvalues.ts_x_origin;
342       values->ts_y_origin = xvalues.ts_y_origin;
343       values->clip_x_origin = xvalues.clip_x_origin;
344       values->clip_y_origin = xvalues.clip_y_origin;
345       values->graphics_exposures = xvalues.graphics_exposures;
346       values->line_width = xvalues.line_width;
347
348       switch (xvalues.line_style)
349         {
350         case LineSolid:
351           values->line_style = GDK_LINE_SOLID;
352           break;
353         case LineOnOffDash:
354           values->line_style = GDK_LINE_ON_OFF_DASH;
355           break;
356         case LineDoubleDash:
357           values->line_style = GDK_LINE_DOUBLE_DASH;
358           break;
359         }
360
361       switch (xvalues.cap_style)
362         {
363         case CapNotLast:
364           values->cap_style = GDK_CAP_NOT_LAST;
365           break;
366         case CapButt:
367           values->cap_style = GDK_CAP_BUTT;
368           break;
369         case CapRound:
370           values->cap_style = GDK_CAP_ROUND;
371           break;
372         case CapProjecting:
373           values->cap_style = GDK_CAP_PROJECTING;
374           break;
375         }
376
377       switch (xvalues.join_style)
378         {
379         case JoinMiter:
380           values->join_style = GDK_JOIN_MITER;
381           break;
382         case JoinRound:
383           values->join_style = GDK_JOIN_ROUND;
384           break;
385         case JoinBevel:
386           values->join_style = GDK_JOIN_BEVEL;
387           break;
388         }
389     }
390   else
391     {
392       memset (values, 0, sizeof (GdkGCValues));
393     }
394 }
395
396 static void
397 clear_fg_picture (GdkGC *gc)
398 {
399   GdkGCX11 *x11_gc = GDK_GC_X11 (gc);
400
401   if (x11_gc->fg_picture != None)
402     {
403       XRenderFreePicture (GDK_GC_XDISPLAY (x11_gc), x11_gc->fg_picture);
404       x11_gc->fg_picture = None;
405     }
406 }
407
408 static void
409 gdk_x11_gc_set_values (GdkGC           *gc,
410                        GdkGCValues     *values,
411                        GdkGCValuesMask  values_mask)
412 {
413   GdkGCX11 *x11_gc;
414   XGCValues xvalues;
415   unsigned long xvalues_mask = 0;
416
417   x11_gc = GDK_GC_X11 (gc);
418
419   if (values_mask & (GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN))
420     {
421       values_mask &= ~(GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN);
422       x11_gc->dirty_mask |= GDK_GC_DIRTY_CLIP;
423     }
424
425   if (values_mask & (GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN))
426     {
427       values_mask &= ~(GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN);
428       x11_gc->dirty_mask |= GDK_GC_DIRTY_TS;
429     }
430
431   if (values_mask & GDK_GC_CLIP_MASK)
432     {
433       if (x11_gc->clip_region)
434         {
435           gdk_region_destroy (x11_gc->clip_region);
436           x11_gc->clip_region = NULL;
437         }
438
439       x11_gc->have_clip_mask = values->clip_mask != NULL;
440     }
441
442   if (values_mask & GDK_GC_FOREGROUND)
443     x11_gc->fg_pixel = values->foreground.pixel;
444
445   if (values_mask & GDK_GC_BACKGROUND)
446     {
447       if (x11_gc->bg_pixel != values->background.pixel)
448         {
449           x11_gc->bg_pixel = values->background.pixel;
450           if (x11_gc->fill == GDK_OPAQUE_STIPPLED)
451             clear_fg_picture (gc);
452         }
453     }
454
455   if (values_mask & GDK_GC_FILL)
456     {
457       if (x11_gc->fill != values->fill)
458         {
459           clear_fg_picture (gc);
460           x11_gc->fill = values->fill;
461         }
462     }
463   
464   if (values_mask & GDK_GC_STIPPLE)
465     {
466       if (x11_gc->stipple != values->stipple)
467         {
468           if (x11_gc->fill == GDK_STIPPLED || x11_gc->fill == GDK_OPAQUE_STIPPLED)
469             clear_fg_picture (gc);
470           if (x11_gc->stipple)
471             g_object_unref (x11_gc->stipple);
472           x11_gc->stipple = values->stipple;
473           if (x11_gc->stipple)
474             g_object_ref (x11_gc->stipple);
475         }
476     }
477   
478   if (values_mask & GDK_GC_TILE)
479     {
480       if (x11_gc->tile != values->tile)
481         {
482           if (x11_gc->fill == GDK_TILED)
483             clear_fg_picture (gc);
484           if (x11_gc->tile)
485             g_object_unref (x11_gc->tile);
486           x11_gc->tile = values->tile;
487           if (x11_gc->tile)
488             g_object_ref (x11_gc->tile);
489         }
490     }
491   
492   gdk_x11_gc_values_to_xvalues (values, values_mask, &xvalues, &xvalues_mask);
493
494   XChangeGC (GDK_GC_XDISPLAY (gc),
495              GDK_GC_XGC (gc),
496              xvalues_mask,
497              &xvalues);
498 }
499
500 static void
501 gdk_x11_gc_set_dashes (GdkGC *gc,
502                        gint   dash_offset,
503                        gint8  dash_list[],
504                        gint   n)
505 {
506   g_return_if_fail (GDK_IS_GC (gc));
507   g_return_if_fail (dash_list != NULL);
508
509   XSetDashes (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc),
510               dash_offset, dash_list, n);
511 }
512
513 static void
514 gdk_x11_gc_values_to_xvalues (GdkGCValues    *values,
515                               GdkGCValuesMask mask,
516                               XGCValues      *xvalues,
517                               unsigned long  *xvalues_mask)
518 {
519   /* Optimization for the common case (gdk_gc_new()) */
520   if (values == NULL || mask == 0)
521     return;
522   
523   if (mask & GDK_GC_FOREGROUND)
524     {
525       xvalues->foreground = values->foreground.pixel;
526       *xvalues_mask |= GCForeground;
527     }
528   if (mask & GDK_GC_BACKGROUND)
529     {
530       xvalues->background = values->background.pixel;
531       *xvalues_mask |= GCBackground;
532     }
533   if ((mask & GDK_GC_FONT) && (values->font->type == GDK_FONT_FONT))
534     {
535       xvalues->font = ((XFontStruct *) (GDK_FONT_XFONT (values->font)))->fid;
536       *xvalues_mask |= GCFont;
537     }
538   if (mask & GDK_GC_FUNCTION)
539     {
540       switch (values->function)
541         {
542         case GDK_COPY:
543           xvalues->function = GXcopy;
544           break;
545         case GDK_INVERT:
546           xvalues->function = GXinvert;
547           break;
548         case GDK_XOR:
549           xvalues->function = GXxor;
550           break;
551         case GDK_CLEAR:
552           xvalues->function = GXclear;
553           break;
554         case GDK_AND:
555           xvalues->function = GXand;
556           break;
557         case GDK_AND_REVERSE:
558           xvalues->function = GXandReverse;
559           break;
560         case GDK_AND_INVERT:
561           xvalues->function = GXandInverted;
562           break;
563         case GDK_NOOP:
564           xvalues->function = GXnoop;
565           break;
566         case GDK_OR:
567           xvalues->function = GXor;
568           break;
569         case GDK_EQUIV:
570           xvalues->function = GXequiv;
571           break;
572         case GDK_OR_REVERSE:
573           xvalues->function = GXorReverse;
574           break;
575         case GDK_COPY_INVERT:
576           xvalues->function = GXcopyInverted;
577           break;
578         case GDK_OR_INVERT:
579           xvalues->function = GXorInverted;
580           break;
581         case GDK_NAND:
582           xvalues->function = GXnand;
583           break;
584         case GDK_SET:
585           xvalues->function = GXset;
586           break;
587         case GDK_NOR:
588           xvalues->function = GXnor;
589           break;
590         }
591       *xvalues_mask |= GCFunction;
592     }
593   if (mask & GDK_GC_FILL)
594     {
595       switch (values->fill)
596         {
597         case GDK_SOLID:
598           xvalues->fill_style = FillSolid;
599           break;
600         case GDK_TILED:
601           xvalues->fill_style = FillTiled;
602           break;
603         case GDK_STIPPLED:
604           xvalues->fill_style = FillStippled;
605           break;
606         case GDK_OPAQUE_STIPPLED:
607           xvalues->fill_style = FillOpaqueStippled;
608           break;
609         }
610       *xvalues_mask |= GCFillStyle;
611     }
612   if (mask & GDK_GC_TILE)
613     {
614       if (values->tile)
615         xvalues->tile = GDK_DRAWABLE_XID (values->tile);
616       else
617         xvalues->tile = None;
618       
619       *xvalues_mask |= GCTile;
620     }
621   if (mask & GDK_GC_STIPPLE)
622     {
623       if (values->stipple)
624         xvalues->stipple = GDK_DRAWABLE_XID (values->stipple);
625       else
626         xvalues->stipple = None;
627       
628       *xvalues_mask |= GCStipple;
629     }
630   if (mask & GDK_GC_CLIP_MASK)
631     {
632       if (values->clip_mask)
633         xvalues->clip_mask = GDK_DRAWABLE_XID (values->clip_mask);
634       else
635         xvalues->clip_mask = None;
636
637       *xvalues_mask |= GCClipMask;
638       
639     }
640   if (mask & GDK_GC_SUBWINDOW)
641     {
642       xvalues->subwindow_mode = values->subwindow_mode;
643       *xvalues_mask |= GCSubwindowMode;
644     }
645   if (mask & GDK_GC_TS_X_ORIGIN)
646     {
647       xvalues->ts_x_origin = values->ts_x_origin;
648       *xvalues_mask |= GCTileStipXOrigin;
649     }
650   if (mask & GDK_GC_TS_Y_ORIGIN)
651     {
652       xvalues->ts_y_origin = values->ts_y_origin;
653       *xvalues_mask |= GCTileStipYOrigin;
654     }
655   if (mask & GDK_GC_CLIP_X_ORIGIN)
656     {
657       xvalues->clip_x_origin = values->clip_x_origin;
658       *xvalues_mask |= GCClipXOrigin;
659     }
660   if (mask & GDK_GC_CLIP_Y_ORIGIN)
661     {
662       xvalues->clip_y_origin = values->clip_y_origin;
663       *xvalues_mask |= GCClipYOrigin;
664     }
665
666   if (mask & GDK_GC_EXPOSURES)
667     {
668       xvalues->graphics_exposures = values->graphics_exposures;
669       *xvalues_mask |= GCGraphicsExposures;
670     }
671
672   if (mask & GDK_GC_LINE_WIDTH)
673     {
674       xvalues->line_width = values->line_width;
675       *xvalues_mask |= GCLineWidth;
676     }
677   if (mask & GDK_GC_LINE_STYLE)
678     {
679       switch (values->line_style)
680         {
681         case GDK_LINE_SOLID:
682           xvalues->line_style = LineSolid;
683           break;
684         case GDK_LINE_ON_OFF_DASH:
685           xvalues->line_style = LineOnOffDash;
686           break;
687         case GDK_LINE_DOUBLE_DASH:
688           xvalues->line_style = LineDoubleDash;
689           break;
690         }
691       *xvalues_mask |= GCLineStyle;
692     }
693   if (mask & GDK_GC_CAP_STYLE)
694     {
695       switch (values->cap_style)
696         {
697         case GDK_CAP_NOT_LAST:
698           xvalues->cap_style = CapNotLast;
699           break;
700         case GDK_CAP_BUTT:
701           xvalues->cap_style = CapButt;
702           break;
703         case GDK_CAP_ROUND:
704           xvalues->cap_style = CapRound;
705           break;
706         case GDK_CAP_PROJECTING:
707           xvalues->cap_style = CapProjecting;
708           break;
709         }
710       *xvalues_mask |= GCCapStyle;
711     }
712   if (mask & GDK_GC_JOIN_STYLE)
713     {
714       switch (values->join_style)
715         {
716         case GDK_JOIN_MITER:
717           xvalues->join_style = JoinMiter;
718           break;
719         case GDK_JOIN_ROUND:
720           xvalues->join_style = JoinRound;
721           break;
722         case GDK_JOIN_BEVEL:
723           xvalues->join_style = JoinBevel;
724           break;
725         }
726       *xvalues_mask |= GCJoinStyle;
727     }
728
729 }
730
731 /**
732  * gdk_gc_set_clip_rectangle:
733  * @gc: a #GdkGC.
734  * @rectangle: the rectangle to clip to.
735  * 
736  * Sets the clip mask for a graphics context from a
737  * rectangle. The clip mask is interpreted relative to the clip
738  * origin. (See gdk_gc_set_clip_origin()).
739  **/
740 void
741 gdk_gc_set_clip_rectangle (GdkGC        *gc,
742                            GdkRectangle *rectangle)
743 {
744   GdkGCX11 *x11_gc;
745   gboolean had_region = FALSE;
746   
747   g_return_if_fail (GDK_IS_GC (gc));
748
749   x11_gc = GDK_GC_X11 (gc);
750
751   if (x11_gc->clip_region)
752     {
753       had_region = TRUE;
754       gdk_region_destroy (x11_gc->clip_region);
755     }
756
757   if (rectangle)
758     x11_gc->clip_region = gdk_region_rectangle (rectangle);
759   else
760     x11_gc->clip_region = NULL;
761
762   /* Unset immediately, to make sure Xlib doesn't keep the
763    * XID of an old clip mask cached
764    */
765   if ((had_region && !rectangle) || x11_gc->have_clip_mask)
766     {
767       XSetClipMask (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), None);
768       x11_gc->have_clip_mask = FALSE;
769     }
770
771   gc->clip_x_origin = 0;
772   gc->clip_y_origin = 0;
773   
774   x11_gc->dirty_mask |= GDK_GC_DIRTY_CLIP;
775 }
776
777 /**
778  * gdk_gc_set_clip_region:
779  * @gc: a #GdkGC.
780  * @region: the #GdkRegion. 
781  * 
782  * Sets the clip mask for a graphics context from a region structure.
783  * The clip mask is interpreted relative to the clip origin. (See
784  * gdk_gc_set_clip_origin()).
785  **/
786 void
787 gdk_gc_set_clip_region (GdkGC     *gc,
788                         GdkRegion *region)
789 {
790   GdkGCX11 *x11_gc;
791   gboolean had_region = FALSE;
792
793   g_return_if_fail (GDK_IS_GC (gc));
794
795   x11_gc = GDK_GC_X11 (gc);
796
797   if (x11_gc->clip_region)
798     {
799       had_region = TRUE;
800       gdk_region_destroy (x11_gc->clip_region);
801     }
802
803   if (region)
804     x11_gc->clip_region = gdk_region_copy (region);
805   else
806     x11_gc->clip_region = NULL;    
807
808   /* Unset immediately, to make sure Xlib doesn't keep the
809    * XID of an old clip mask cached
810    */
811   if ((had_region && !region) || x11_gc->have_clip_mask)
812     {
813       XSetClipMask (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), None);
814       x11_gc->have_clip_mask = FALSE;
815     }
816
817   gc->clip_x_origin = 0;
818   gc->clip_y_origin = 0;
819   
820   x11_gc->dirty_mask |= GDK_GC_DIRTY_CLIP;
821 }
822
823
824 /**
825  * gdk_gc_copy:
826  * @dst_gc: the destination graphics context.
827  * @src_gc: the source graphics context.
828  * 
829  * Copy the set of values from one graphics context
830  * onto another graphics context.
831  **/
832 void
833 gdk_gc_copy (GdkGC *dst_gc, GdkGC *src_gc)
834 {
835   GdkGCX11 *x11_src_gc;
836   GdkGCX11 *x11_dst_gc;
837   
838   g_return_if_fail (GDK_IS_GC_X11 (dst_gc));
839   g_return_if_fail (GDK_IS_GC_X11 (src_gc));
840
841   x11_dst_gc = GDK_GC_X11 (dst_gc);
842   x11_src_gc = GDK_GC_X11 (src_gc);
843   
844   XCopyGC (GDK_GC_XDISPLAY (src_gc), GDK_GC_XGC (src_gc), ~((~1) << GCLastBit),
845            GDK_GC_XGC (dst_gc));
846
847   dst_gc->clip_x_origin = src_gc->clip_x_origin;
848   dst_gc->clip_y_origin = src_gc->clip_y_origin;
849   dst_gc->ts_x_origin = src_gc->ts_x_origin;
850   dst_gc->ts_y_origin = src_gc->ts_y_origin;
851
852   if (src_gc->colormap)
853     g_object_ref (src_gc->colormap);
854
855   if (dst_gc->colormap)
856     g_object_unref (dst_gc->colormap);
857
858   dst_gc->colormap = src_gc->colormap;
859
860   if (x11_dst_gc->clip_region)
861     gdk_region_destroy (x11_dst_gc->clip_region);
862
863   if (x11_src_gc->clip_region)
864     x11_dst_gc->clip_region = gdk_region_copy (x11_src_gc->clip_region);
865   else
866     x11_dst_gc->clip_region = NULL;
867
868   x11_dst_gc->dirty_mask = x11_src_gc->dirty_mask;
869   x11_dst_gc->fg_pixel = x11_src_gc->fg_pixel;
870   x11_dst_gc->fill = x11_src_gc->fill;
871   
872   if (x11_dst_gc->stipple)
873     g_object_unref (x11_dst_gc->stipple);
874   x11_dst_gc->stipple = x11_src_gc->stipple;
875   if (x11_dst_gc->stipple)
876     g_object_ref (x11_dst_gc->stipple);
877   
878   if (x11_dst_gc->tile)
879     g_object_unref (x11_dst_gc->tile);
880   x11_dst_gc->tile = x11_src_gc->tile;
881   if (x11_dst_gc->tile)
882     g_object_ref (x11_dst_gc->tile);
883
884   clear_fg_picture (dst_gc);
885 }
886
887 /**
888  * gdk_gc_get_screen:
889  * @gc: a #GdkGC.
890  *
891  * Gets the #GdkScreen for which @gc was created
892  *
893  * Returns: the #GdkScreen for @gc.
894  *
895  * Since: 2.2
896  */
897 GdkScreen *  
898 gdk_gc_get_screen (GdkGC *gc)
899 {
900   g_return_val_if_fail (GDK_IS_GC_X11 (gc), NULL);
901   
902   return GDK_GC_X11 (gc)->screen;
903 }
904
905 /**
906  * gdk_x11_gc_get_xdisplay:
907  * @gc: a #GdkGC.
908  * 
909  * Returns the display of a #GdkGC.
910  * 
911  * Return value: an Xlib <type>Display*</type>.
912  **/
913 Display *
914 gdk_x11_gc_get_xdisplay (GdkGC *gc)
915 {
916   g_return_val_if_fail (GDK_IS_GC_X11 (gc), NULL);
917
918   return GDK_SCREEN_XDISPLAY (gdk_gc_get_screen (gc));
919 }
920
921 /**
922  * gdk_x11_gc_get_xgc:
923  * @gc: a #GdkGC.
924  * 
925  * Returns the X GC of a #GdkGC.
926  * 
927  * Return value: an Xlib <type>GC</type>.
928  **/
929 GC
930 gdk_x11_gc_get_xgc (GdkGC *gc)
931 {
932   GdkGCX11 *gc_x11;
933   
934   g_return_val_if_fail (GDK_IS_GC_X11 (gc), NULL);
935
936   gc_x11 = GDK_GC_X11 (gc);
937
938   if (gc_x11->dirty_mask)
939     _gdk_x11_gc_flush (gc);
940
941   return gc_x11->xgc;
942 }
943
944 /* Various bits of the below are roughly cribbed from XFree86
945  * lib/Xft/xftdraw.c, Copyright 2000, Keith Packard
946  */
947
948 static XRenderPictFormat *
949 foreground_format (GdkGC *gc)
950 {
951   XRenderPictFormat pf;
952
953   pf.type = PictTypeDirect;
954   pf.depth = 32;
955   pf.direct.redMask = 0xff;
956   pf.direct.greenMask = 0xff;
957   pf.direct.blueMask = 0xff;
958   pf.direct.alphaMask = 0xff;
959
960   return XRenderFindFormat (GDK_GC_XDISPLAY (gc),
961                             (PictFormatType |
962                              PictFormatDepth |
963                              PictFormatRedMask |
964                              PictFormatGreenMask |
965                              PictFormatBlueMask |
966                              PictFormatAlphaMask),
967                             &pf,
968                             0);
969 }
970
971 static Picture
972 make_fg_tile_picture (GdkGC *gc)
973 {
974   GdkGCX11 *x11_gc = GDK_GC_X11 (gc);
975   GdkVisual *visual = gdk_drawable_get_visual (x11_gc->tile);
976   XRenderPictFormat *format = NULL;
977
978   if (visual)
979     {
980       format = XRenderFindVisualFormat (GDK_GC_XDISPLAY (gc),
981                                         GDK_VISUAL_XVISUAL (visual));
982     }
983   else if (x11_gc->depth == 1)
984     {
985       format = XRenderFindStandardFormat (GDK_GC_XDISPLAY (gc),
986                                           PictStandardA1);
987     }
988
989   if (format)
990     {
991       XRenderPictureAttributes pa;
992       pa.repeat = True;
993
994       return XRenderCreatePicture (GDK_GC_XDISPLAY (gc), 
995                                    GDK_PIXMAP_XID (x11_gc->tile),
996                                    format,
997                                    CPRepeat, &pa);
998     }
999 }
1000
1001 static Picture
1002 make_stipple_picture (GdkGC *gc)
1003 {
1004   GdkGCX11 *x11_gc = GDK_GC_X11 (gc);
1005   XRenderPictFormat *format = NULL;
1006   XRenderPictureAttributes pa;
1007   
1008   format = XRenderFindStandardFormat (GDK_GC_XDISPLAY (gc),
1009                                       PictStandardA1);
1010
1011   pa.repeat = True;
1012   return XRenderCreatePicture (GDK_GC_XDISPLAY (gc), 
1013                                GDK_PIXMAP_XID (x11_gc->stipple),
1014                                format,
1015                                CPRepeat, &pa);
1016 }
1017
1018 static Picture
1019 make_color_picture (GdkGC        *gc,
1020                     XRenderColor *color)
1021 {
1022   GdkGCX11 *x11_gc = GDK_GC_X11 (gc);
1023   XRenderPictureAttributes pa;
1024   XRenderPictFormat *pix_format = foreground_format (gc);
1025   Pixmap pix;
1026   Picture picture;
1027   
1028   if (!pix_format)
1029     return None;
1030   
1031   pix = XCreatePixmap (GDK_GC_XDISPLAY (gc),
1032                        GDK_SCREEN_XROOTWIN (x11_gc->screen),
1033                        1, 1, pix_format->depth);
1034   pa.repeat = True;
1035   picture = XRenderCreatePicture (GDK_GC_XDISPLAY (gc),
1036                                   pix,
1037                                   pix_format,
1038                                   CPRepeat, &pa);
1039   XFreePixmap (GDK_GC_XDISPLAY (gc), pix);
1040   
1041   XRenderFillRectangle (GDK_GC_XDISPLAY (gc), PictOpSrc, 
1042                         picture, color,
1043                         0, 0, 1, 1);
1044
1045   return picture;
1046 }
1047
1048 static void
1049 get_bg_color (GdkGC        *gc,
1050               XRenderColor *render_color)
1051 {
1052   GdkGCX11 *x11_gc = GDK_GC_X11 (gc);
1053   GdkColormap *cmap;
1054   
1055   cmap = gdk_gc_get_colormap (gc);
1056
1057   if (cmap)
1058     {
1059       GdkColor color;
1060       
1061       gdk_colormap_query_color (cmap, x11_gc->bg_pixel, &color);
1062       
1063       render_color->alpha = 0xffff;
1064       render_color->red = color.red;
1065       render_color->green = color.green;
1066       render_color->blue = color.blue;
1067     }
1068   else                          /* Not worth warning, just use black */
1069     {
1070       render_color->alpha = 0xffff;
1071       render_color->red = 0;
1072       render_color->green = 0;
1073       render_color->blue = 0;
1074     }
1075 }
1076
1077 /**
1078  * _gdk_x11_gc_get_fg_picture:
1079  * @gc: a #GdkGC
1080  * 
1081  * Gets a Xrender Picture object suitable for being the source
1082  * drawable for drawing with the foreground the graphics context.
1083  * 
1084  * Return value: a Picture, owned by the GC; this cannot be
1085  *   used over subsequent modification of the GC.
1086  **/
1087 Picture
1088 _gdk_x11_gc_get_fg_picture (GdkGC *gc)
1089 {
1090   GdkGCX11 *x11_gc;
1091   gboolean new = FALSE;
1092   XftColor xftcolor;
1093   GdkFill fill;
1094   int width, height;
1095   
1096   g_return_val_if_fail (GDK_IS_GC_X11 (gc), None);
1097
1098   if (!_gdk_x11_have_render (GDK_GC_DISPLAY (gc)))
1099     return None;
1100
1101   x11_gc = GDK_GC_X11 (gc);
1102
1103   fill = GDK_SOLID;
1104   width = 1;
1105   height = 1;
1106   
1107   switch (x11_gc->fill)
1108     {
1109     case GDK_SOLID:
1110       break;
1111     case GDK_TILED:
1112       if (x11_gc->tile)
1113         {
1114           if (!x11_gc->fg_picture)
1115             x11_gc->fg_picture = make_fg_tile_picture (gc);
1116
1117           if (x11_gc->fg_picture != None)
1118             return x11_gc->fg_picture;
1119         }
1120       break;
1121     case GDK_STIPPLED:
1122     case GDK_OPAQUE_STIPPLED:
1123       if (x11_gc->stipple)
1124         {
1125           gdk_drawable_get_size (x11_gc->stipple, &width, &height);
1126           fill = x11_gc->fill;
1127         }
1128       break;
1129     }
1130   
1131   if (x11_gc->fg_picture == None)
1132     {
1133       XRenderPictureAttributes pa;
1134       XRenderPictFormat *pix_format = foreground_format (gc);
1135       Pixmap pix;
1136
1137       if (!pix_format)
1138         return None;
1139
1140       pix = XCreatePixmap (GDK_GC_XDISPLAY (gc), 
1141                            GDK_SCREEN_XROOTWIN (x11_gc->screen),
1142                            width, height, pix_format->depth);
1143       pa.repeat = True;
1144       x11_gc->fg_picture = XRenderCreatePicture (GDK_GC_XDISPLAY (gc), 
1145                                                  pix,
1146                                                  pix_format,
1147                                                  CPRepeat, &pa);
1148       XFreePixmap (GDK_GC_XDISPLAY (gc), pix);
1149       
1150       new = TRUE;
1151     }
1152
1153   _gdk_gc_x11_get_fg_xft_color (gc, &xftcolor);
1154   
1155   if (x11_gc->fg_picture_color.alpha != 0xffff ||
1156       x11_gc->fg_picture_color.red != xftcolor.color.red ||
1157       x11_gc->fg_picture_color.green != xftcolor.color.green ||
1158       x11_gc->fg_picture_color.blue != xftcolor.color.blue)
1159     {
1160       x11_gc->fg_picture_color.alpha = 0xffff;
1161       x11_gc->fg_picture_color.red = xftcolor.color.red;
1162       x11_gc->fg_picture_color.green = xftcolor.color.green;
1163       x11_gc->fg_picture_color.blue = xftcolor.color.blue;
1164
1165       new = TRUE;
1166     }
1167
1168   switch (fill)
1169     {
1170     case GDK_SOLID:
1171       XRenderFillRectangle (GDK_GC_XDISPLAY (gc), PictOpSrc, 
1172                             x11_gc->fg_picture, &x11_gc->fg_picture_color,
1173                             0, 0, width, height);
1174       break;
1175     case GDK_STIPPLED:
1176       {
1177         Picture stipple_picture = make_stipple_picture (gc);
1178         
1179         XRenderFillRectangle (GDK_GC_XDISPLAY (gc), PictOpSrc, 
1180                               x11_gc->fg_picture, &x11_gc->fg_picture_color,
1181                               0, 0, width, height);
1182         XRenderComposite (GDK_GC_XDISPLAY (gc),
1183                           PictOpInReverse,
1184                           stipple_picture, None, x11_gc->fg_picture,
1185                           0, 0, 0, 0, 0, 0, width, height);
1186         
1187         XRenderFreePicture (GDK_GC_XDISPLAY (x11_gc), stipple_picture);
1188       }
1189       break;
1190     case GDK_OPAQUE_STIPPLED:
1191       {
1192         XRenderColor bg_color;
1193
1194         Picture stipple_picture = make_stipple_picture (gc);
1195         Picture fg_picture = make_color_picture (gc, &x11_gc->fg_picture_color);
1196
1197         get_bg_color (gc, &bg_color);
1198         
1199         XRenderFillRectangle (GDK_GC_XDISPLAY (gc), PictOpSrc, 
1200                               x11_gc->fg_picture, &bg_color,
1201                               0, 0, width, height);
1202         XRenderComposite (GDK_GC_XDISPLAY (gc),
1203                           PictOpOver,
1204                           fg_picture, stipple_picture, x11_gc->fg_picture,
1205                           0, 0, 0, 0, 0, 0, width, height);
1206
1207         XRenderFreePicture (GDK_GC_XDISPLAY (x11_gc), stipple_picture);
1208         XRenderFreePicture (GDK_GC_XDISPLAY (x11_gc), fg_picture);
1209       }
1210       break;
1211     case GDK_TILED:
1212       g_assert_not_reached ();  /* handled above */
1213       break;
1214     }
1215
1216   return x11_gc->fg_picture;
1217 }
1218
1219 /**
1220  * _gdk_gc_x11_get_fg_xft_color:
1221  * @gc: a #GdkGC
1222  * @xftcolor: location to store the color
1223  * 
1224  * Gets the foreground color of the GC as a XftColor.
1225  **/
1226 void
1227 _gdk_gc_x11_get_fg_xft_color (GdkGC    *gc,
1228                               XftColor *xftcolor)
1229 {
1230   GdkGCX11 *x11_gc;
1231   GdkColormap *cmap;
1232   GdkColor color;
1233   
1234   g_return_if_fail (GDK_IS_GC_X11 (gc));
1235
1236   x11_gc = GDK_GC_X11 (gc);
1237
1238   cmap = gdk_gc_get_colormap (gc);
1239
1240   xftcolor->pixel = x11_gc->fg_pixel;
1241
1242   if (cmap)
1243     {
1244       gdk_colormap_query_color (cmap, xftcolor->pixel, &color);
1245       xftcolor->color.alpha = 0xffff;
1246       xftcolor->color.red = color.red;
1247       xftcolor->color.green = color.green;
1248       xftcolor->color.blue = color.blue;
1249     }
1250   else if (x11_gc->depth == 1)
1251     {
1252       /* Drawing with Xft on a bitmap is a bit bizzare; it
1253        * takes alpha >= 0x8000 to mean 'set to 1' and
1254        * alpha < 0x8000 to mean 'set to 0'.
1255        */
1256       if (xftcolor->pixel)
1257         {
1258           xftcolor->color.red = 0xffff;
1259           xftcolor->color.green = 0xffff;
1260           xftcolor->color.blue = 0xffff;
1261           xftcolor->color.alpha = 0xffff;
1262         }
1263       else
1264         {
1265           xftcolor->color.red = 0;
1266           xftcolor->color.green = 0;
1267           xftcolor->color.blue = 0;
1268           xftcolor->color.alpha = 0;
1269         }
1270     }
1271   else
1272     {
1273       g_warning ("Using Xft rendering requires the GC argument to have a\n"
1274                  "specified colormap. If the GC was created for a drawable\n"
1275                  "with a colormap, the colormap will be set on the GC\n"
1276                  "automatically. Otherwise, a colormap must be set on it with"
1277                  "gdk_gc_set_colormap");
1278     }
1279 }
1280
1281 void
1282 _gdk_windowing_gc_get_foreground (GdkGC    *gc,
1283                                   GdkColor *color)
1284 {
1285   GdkGCX11 *x11_gc;
1286   GdkColormap *cmap;
1287   
1288   g_return_if_fail (GDK_IS_GC_X11 (gc));
1289
1290   x11_gc = GDK_GC_X11 (gc);
1291
1292   color->pixel = x11_gc->fg_pixel;
1293
1294   cmap = gdk_gc_get_colormap (gc);
1295
1296   if (cmap)
1297     gdk_colormap_query_color (cmap, x11_gc->fg_pixel, color);
1298   else
1299     g_warning ("No colormap in _gdk_windowing_gc_get_foreground");
1300 }