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