]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkgc-x11.c
fec9784dfd2063afa12b00cc6eb396475134c99d
[~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   XFreeGC (GDK_GC_XDISPLAY (x11_gc), GDK_GC_XGC (x11_gc));
117
118   G_OBJECT_CLASS (parent_class)->finalize (object);
119 }
120
121
122 GdkGC *
123 _gdk_x11_gc_new (GdkDrawable      *drawable,
124                  GdkGCValues      *values,
125                  GdkGCValuesMask   values_mask)
126 {
127   GdkGC *gc;
128   GdkGCX11 *private;
129   
130   XGCValues xvalues;
131   unsigned long xvalues_mask;
132
133   /* NOTICE that the drawable here has to be the impl drawable,
134    * not the publically-visible drawables.
135    */
136   g_return_val_if_fail (GDK_IS_DRAWABLE_IMPL_X11 (drawable), NULL);
137
138   gc = g_object_new (_gdk_gc_x11_get_type (), NULL);
139   private = GDK_GC_X11 (gc);
140
141   private->dirty_mask = 0;
142   private->have_clip_mask = FALSE;
143   private->clip_region = NULL;
144     
145   private->screen = GDK_DRAWABLE_IMPL_X11 (drawable)->screen;
146
147   private->depth = gdk_drawable_get_depth (drawable);
148
149   if (values_mask & (GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN))
150     {
151       values_mask &= ~(GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN);
152       private->dirty_mask |= GDK_GC_DIRTY_CLIP;
153     }
154
155   if (values_mask & (GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN))
156     {
157       values_mask &= ~(GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN);
158       private->dirty_mask |= GDK_GC_DIRTY_TS;
159     }
160
161   if (values_mask & GDK_GC_FOREGROUND)
162     private->fg_pixel = values->foreground.pixel;
163
164   if ((values_mask & GDK_GC_CLIP_MASK) && values->clip_mask)
165     private->have_clip_mask = TRUE;
166
167   xvalues.function = GXcopy;
168   xvalues.fill_style = FillSolid;
169   xvalues.arc_mode = ArcPieSlice;
170   xvalues.subwindow_mode = ClipByChildren;
171   xvalues.graphics_exposures = False;
172   xvalues_mask = GCFunction | GCFillStyle | GCArcMode | GCSubwindowMode | GCGraphicsExposures;
173
174   gdk_x11_gc_values_to_xvalues (values, values_mask, &xvalues, &xvalues_mask);
175   
176   private->xgc = XCreateGC (GDK_GC_XDISPLAY (gc),
177                             GDK_DRAWABLE_IMPL_X11 (drawable)->xid,
178                             xvalues_mask, &xvalues);
179
180   return gc;
181 }
182
183 GC
184 _gdk_x11_gc_flush (GdkGC *gc)
185 {
186   GdkGCX11 *private = GDK_GC_X11 (gc);
187
188   if (private->dirty_mask & GDK_GC_DIRTY_CLIP)
189     {
190       if (!private->clip_region)
191         XSetClipOrigin (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc),
192                         gc->clip_x_origin, gc->clip_y_origin);
193       else
194         {
195           XRectangle *rectangles;
196           gint n_rects;
197
198           _gdk_region_get_xrectangles (private->clip_region,
199                                        gc->clip_x_origin,
200                                        gc->clip_y_origin,
201                                        &rectangles,
202                                        &n_rects);
203           
204           XSetClipRectangles (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), 0, 0,
205                               rectangles,
206                               n_rects, YXBanded);
207           
208           g_free (rectangles);
209         }
210     }
211
212   if (private->dirty_mask & GDK_GC_DIRTY_TS)
213     {
214       XSetTSOrigin (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc),
215                     gc->ts_x_origin, gc->ts_y_origin);
216     }
217
218   private->dirty_mask = 0;
219   return GDK_GC_XGC (gc);
220 }
221
222 static void
223 gdk_x11_gc_get_values (GdkGC       *gc,
224                        GdkGCValues *values)
225 {
226   XGCValues xvalues;
227   
228   if (XGetGCValues (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc),
229                     GCForeground | GCBackground | GCFont |
230                     GCFunction | GCTile | GCStipple | /* GCClipMask | */
231                     GCSubwindowMode | GCGraphicsExposures |
232                     GCTileStipXOrigin | GCTileStipYOrigin |
233                     GCClipXOrigin | GCClipYOrigin |
234                     GCLineWidth | GCLineStyle | GCCapStyle |
235                     GCFillStyle | GCJoinStyle, &xvalues))
236     {
237       values->foreground.pixel = xvalues.foreground;
238       values->background.pixel = xvalues.background;
239       values->font = gdk_font_lookup_for_display (GDK_GC_DISPLAY (gc),
240                                                   xvalues.font);
241
242       switch (xvalues.function)
243         {
244         case GXcopy:
245           values->function = GDK_COPY;
246           break;
247         case GXinvert:
248           values->function = GDK_INVERT;
249           break;
250         case GXxor:
251           values->function = GDK_XOR;
252           break;
253         case GXclear:
254           values->function = GDK_CLEAR;
255           break;
256         case GXand:
257           values->function = GDK_AND;
258           break;
259         case GXandReverse:
260           values->function = GDK_AND_REVERSE;
261           break;
262         case GXandInverted:
263           values->function = GDK_AND_INVERT;
264           break;
265         case GXnoop:
266           values->function = GDK_NOOP;
267           break;
268         case GXor:
269           values->function = GDK_OR;
270           break;
271         case GXequiv:
272           values->function = GDK_EQUIV;
273           break;
274         case GXorReverse:
275           values->function = GDK_OR_REVERSE;
276           break;
277         case GXcopyInverted:
278           values->function =GDK_COPY_INVERT;
279           break;
280         case GXorInverted:
281           values->function = GDK_OR_INVERT;
282           break;
283         case GXnand:
284           values->function = GDK_NAND;
285           break;
286         case GXset:
287           values->function = GDK_SET;
288           break;
289         case GXnor:
290           values->function = GDK_NOR;
291           break;
292         }
293
294       switch (xvalues.fill_style)
295         {
296         case FillSolid:
297           values->fill = GDK_SOLID;
298           break;
299         case FillTiled:
300           values->fill = GDK_TILED;
301           break;
302         case FillStippled:
303           values->fill = GDK_STIPPLED;
304           break;
305         case FillOpaqueStippled:
306           values->fill = GDK_OPAQUE_STIPPLED;
307           break;
308         }
309
310       values->tile = gdk_pixmap_lookup_for_display (GDK_GC_DISPLAY (gc),
311                                                     xvalues.tile);
312       values->stipple = gdk_pixmap_lookup_for_display (GDK_GC_DISPLAY (gc),
313                                                        xvalues.stipple);
314       values->clip_mask = NULL;
315       values->subwindow_mode = xvalues.subwindow_mode;
316       values->ts_x_origin = xvalues.ts_x_origin;
317       values->ts_y_origin = xvalues.ts_y_origin;
318       values->clip_x_origin = xvalues.clip_x_origin;
319       values->clip_y_origin = xvalues.clip_y_origin;
320       values->graphics_exposures = xvalues.graphics_exposures;
321       values->line_width = xvalues.line_width;
322
323       switch (xvalues.line_style)
324         {
325         case LineSolid:
326           values->line_style = GDK_LINE_SOLID;
327           break;
328         case LineOnOffDash:
329           values->line_style = GDK_LINE_ON_OFF_DASH;
330           break;
331         case LineDoubleDash:
332           values->line_style = GDK_LINE_DOUBLE_DASH;
333           break;
334         }
335
336       switch (xvalues.cap_style)
337         {
338         case CapNotLast:
339           values->cap_style = GDK_CAP_NOT_LAST;
340           break;
341         case CapButt:
342           values->cap_style = GDK_CAP_BUTT;
343           break;
344         case CapRound:
345           values->cap_style = GDK_CAP_ROUND;
346           break;
347         case CapProjecting:
348           values->cap_style = GDK_CAP_PROJECTING;
349           break;
350         }
351
352       switch (xvalues.join_style)
353         {
354         case JoinMiter:
355           values->join_style = GDK_JOIN_MITER;
356           break;
357         case JoinRound:
358           values->join_style = GDK_JOIN_ROUND;
359           break;
360         case JoinBevel:
361           values->join_style = GDK_JOIN_BEVEL;
362           break;
363         }
364     }
365   else
366     {
367       memset (values, 0, sizeof (GdkGCValues));
368     }
369 }
370
371
372 static void
373 gdk_x11_gc_set_values (GdkGC           *gc,
374                        GdkGCValues     *values,
375                        GdkGCValuesMask  values_mask)
376 {
377   GdkGCX11 *x11_gc;
378   XGCValues xvalues;
379   unsigned long xvalues_mask = 0;
380
381   x11_gc = GDK_GC_X11 (gc);
382
383   if (values_mask & (GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN))
384     {
385       values_mask &= ~(GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN);
386       x11_gc->dirty_mask |= GDK_GC_DIRTY_CLIP;
387     }
388
389   if (values_mask & (GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN))
390     {
391       values_mask &= ~(GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN);
392       x11_gc->dirty_mask |= GDK_GC_DIRTY_TS;
393     }
394
395   if (values_mask & GDK_GC_CLIP_MASK)
396     {
397       if (x11_gc->clip_region)
398         {
399           gdk_region_destroy (x11_gc->clip_region);
400           x11_gc->clip_region = NULL;
401         }
402
403       x11_gc->have_clip_mask = values->clip_mask != NULL;
404     }
405
406   if (values_mask & GDK_GC_FOREGROUND)
407     x11_gc->fg_pixel = values->foreground.pixel;
408   
409   gdk_x11_gc_values_to_xvalues (values, values_mask, &xvalues, &xvalues_mask);
410
411   XChangeGC (GDK_GC_XDISPLAY (gc),
412              GDK_GC_XGC (gc),
413              xvalues_mask,
414              &xvalues);
415 }
416
417 static void
418 gdk_x11_gc_set_dashes (GdkGC *gc,
419                        gint   dash_offset,
420                        gint8  dash_list[],
421                        gint   n)
422 {
423   g_return_if_fail (GDK_IS_GC (gc));
424   g_return_if_fail (dash_list != NULL);
425
426   XSetDashes (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc),
427               dash_offset, dash_list, n);
428 }
429
430 static void
431 gdk_x11_gc_values_to_xvalues (GdkGCValues    *values,
432                               GdkGCValuesMask mask,
433                               XGCValues      *xvalues,
434                               unsigned long  *xvalues_mask)
435 {
436   /* Optimization for the common case (gdk_gc_new()) */
437   if (values == NULL || mask == 0)
438     return;
439   
440   if (mask & GDK_GC_FOREGROUND)
441     {
442       xvalues->foreground = values->foreground.pixel;
443       *xvalues_mask |= GCForeground;
444     }
445   if (mask & GDK_GC_BACKGROUND)
446     {
447       xvalues->background = values->background.pixel;
448       *xvalues_mask |= GCBackground;
449     }
450   if ((mask & GDK_GC_FONT) && (values->font->type == GDK_FONT_FONT))
451     {
452       xvalues->font = ((XFontStruct *) (GDK_FONT_XFONT (values->font)))->fid;
453       *xvalues_mask |= GCFont;
454     }
455   if (mask & GDK_GC_FUNCTION)
456     {
457       switch (values->function)
458         {
459         case GDK_COPY:
460           xvalues->function = GXcopy;
461           break;
462         case GDK_INVERT:
463           xvalues->function = GXinvert;
464           break;
465         case GDK_XOR:
466           xvalues->function = GXxor;
467           break;
468         case GDK_CLEAR:
469           xvalues->function = GXclear;
470           break;
471         case GDK_AND:
472           xvalues->function = GXand;
473           break;
474         case GDK_AND_REVERSE:
475           xvalues->function = GXandReverse;
476           break;
477         case GDK_AND_INVERT:
478           xvalues->function = GXandInverted;
479           break;
480         case GDK_NOOP:
481           xvalues->function = GXnoop;
482           break;
483         case GDK_OR:
484           xvalues->function = GXor;
485           break;
486         case GDK_EQUIV:
487           xvalues->function = GXequiv;
488           break;
489         case GDK_OR_REVERSE:
490           xvalues->function = GXorReverse;
491           break;
492         case GDK_COPY_INVERT:
493           xvalues->function = GXcopyInverted;
494           break;
495         case GDK_OR_INVERT:
496           xvalues->function = GXorInverted;
497           break;
498         case GDK_NAND:
499           xvalues->function = GXnand;
500           break;
501         case GDK_SET:
502           xvalues->function = GXset;
503           break;
504         case GDK_NOR:
505           xvalues->function = GXnor;
506           break;
507         }
508       *xvalues_mask |= GCFunction;
509     }
510   if (mask & GDK_GC_FILL)
511     {
512       switch (values->fill)
513         {
514         case GDK_SOLID:
515           xvalues->fill_style = FillSolid;
516           break;
517         case GDK_TILED:
518           xvalues->fill_style = FillTiled;
519           break;
520         case GDK_STIPPLED:
521           xvalues->fill_style = FillStippled;
522           break;
523         case GDK_OPAQUE_STIPPLED:
524           xvalues->fill_style = FillOpaqueStippled;
525           break;
526         }
527       *xvalues_mask |= GCFillStyle;
528     }
529   if (mask & GDK_GC_TILE)
530     {
531       if (values->tile)
532         xvalues->tile = GDK_DRAWABLE_XID (values->tile);
533       else
534         xvalues->tile = None;
535       
536       *xvalues_mask |= GCTile;
537     }
538   if (mask & GDK_GC_STIPPLE)
539     {
540       if (values->stipple)
541         xvalues->stipple = GDK_DRAWABLE_XID (values->stipple);
542       else
543         xvalues->stipple = None;
544       
545       *xvalues_mask |= GCStipple;
546     }
547   if (mask & GDK_GC_CLIP_MASK)
548     {
549       if (values->clip_mask)
550         xvalues->clip_mask = GDK_DRAWABLE_XID (values->clip_mask);
551       else
552         xvalues->clip_mask = None;
553
554       *xvalues_mask |= GCClipMask;
555       
556     }
557   if (mask & GDK_GC_SUBWINDOW)
558     {
559       xvalues->subwindow_mode = values->subwindow_mode;
560       *xvalues_mask |= GCSubwindowMode;
561     }
562   if (mask & GDK_GC_TS_X_ORIGIN)
563     {
564       xvalues->ts_x_origin = values->ts_x_origin;
565       *xvalues_mask |= GCTileStipXOrigin;
566     }
567   if (mask & GDK_GC_TS_Y_ORIGIN)
568     {
569       xvalues->ts_y_origin = values->ts_y_origin;
570       *xvalues_mask |= GCTileStipYOrigin;
571     }
572   if (mask & GDK_GC_CLIP_X_ORIGIN)
573     {
574       xvalues->clip_x_origin = values->clip_x_origin;
575       *xvalues_mask |= GCClipXOrigin;
576     }
577   if (mask & GDK_GC_CLIP_Y_ORIGIN)
578     {
579       xvalues->clip_y_origin = values->clip_y_origin;
580       *xvalues_mask |= GCClipYOrigin;
581     }
582
583   if (mask & GDK_GC_EXPOSURES)
584     {
585       xvalues->graphics_exposures = values->graphics_exposures;
586       *xvalues_mask |= GCGraphicsExposures;
587     }
588
589   if (mask & GDK_GC_LINE_WIDTH)
590     {
591       xvalues->line_width = values->line_width;
592       *xvalues_mask |= GCLineWidth;
593     }
594   if (mask & GDK_GC_LINE_STYLE)
595     {
596       switch (values->line_style)
597         {
598         case GDK_LINE_SOLID:
599           xvalues->line_style = LineSolid;
600           break;
601         case GDK_LINE_ON_OFF_DASH:
602           xvalues->line_style = LineOnOffDash;
603           break;
604         case GDK_LINE_DOUBLE_DASH:
605           xvalues->line_style = LineDoubleDash;
606           break;
607         }
608       *xvalues_mask |= GCLineStyle;
609     }
610   if (mask & GDK_GC_CAP_STYLE)
611     {
612       switch (values->cap_style)
613         {
614         case GDK_CAP_NOT_LAST:
615           xvalues->cap_style = CapNotLast;
616           break;
617         case GDK_CAP_BUTT:
618           xvalues->cap_style = CapButt;
619           break;
620         case GDK_CAP_ROUND:
621           xvalues->cap_style = CapRound;
622           break;
623         case GDK_CAP_PROJECTING:
624           xvalues->cap_style = CapProjecting;
625           break;
626         }
627       *xvalues_mask |= GCCapStyle;
628     }
629   if (mask & GDK_GC_JOIN_STYLE)
630     {
631       switch (values->join_style)
632         {
633         case GDK_JOIN_MITER:
634           xvalues->join_style = JoinMiter;
635           break;
636         case GDK_JOIN_ROUND:
637           xvalues->join_style = JoinRound;
638           break;
639         case GDK_JOIN_BEVEL:
640           xvalues->join_style = JoinBevel;
641           break;
642         }
643       *xvalues_mask |= GCJoinStyle;
644     }
645
646 }
647
648 /**
649  * gdk_gc_set_clip_rectangle:
650  * @gc: a #GdkGC.
651  * @rectangle: the rectangle to clip to.
652  * 
653  * Sets the clip mask for a graphics context from a
654  * rectangle. The clip mask is interpreted relative to the clip
655  * origin. (See gdk_gc_set_clip_origin()).
656  **/
657 void
658 gdk_gc_set_clip_rectangle (GdkGC        *gc,
659                            GdkRectangle *rectangle)
660 {
661   GdkGCX11 *x11_gc;
662   gboolean had_region = FALSE;
663   
664   g_return_if_fail (GDK_IS_GC (gc));
665
666   x11_gc = GDK_GC_X11 (gc);
667
668   if (x11_gc->clip_region)
669     {
670       had_region = TRUE;
671       gdk_region_destroy (x11_gc->clip_region);
672     }
673
674   if (rectangle)
675     x11_gc->clip_region = gdk_region_rectangle (rectangle);
676   else
677     x11_gc->clip_region = NULL;
678
679   /* Unset immediately, to make sure Xlib doesn't keep the
680    * XID of an old clip mask cached
681    */
682   if ((had_region && !rectangle) || x11_gc->have_clip_mask)
683     {
684       XSetClipMask (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), None);
685       x11_gc->have_clip_mask = FALSE;
686     }
687
688   gc->clip_x_origin = 0;
689   gc->clip_y_origin = 0;
690   
691   x11_gc->dirty_mask |= GDK_GC_DIRTY_CLIP;
692 }
693
694 /**
695  * gdk_gc_set_clip_region:
696  * @gc: a #GdkGC.
697  * @region: the #GdkRegion. 
698  * 
699  * Sets the clip mask for a graphics context from a region structure.
700  * The clip mask is interpreted relative to the clip origin. (See
701  * gdk_gc_set_clip_origin()).
702  **/
703 void
704 gdk_gc_set_clip_region (GdkGC     *gc,
705                         GdkRegion *region)
706 {
707   GdkGCX11 *x11_gc;
708   gboolean had_region = FALSE;
709
710   g_return_if_fail (GDK_IS_GC (gc));
711
712   x11_gc = GDK_GC_X11 (gc);
713
714   if (x11_gc->clip_region)
715     {
716       had_region = TRUE;
717       gdk_region_destroy (x11_gc->clip_region);
718     }
719
720   if (region)
721     x11_gc->clip_region = gdk_region_copy (region);
722   else
723     x11_gc->clip_region = NULL;    
724
725   /* Unset immediately, to make sure Xlib doesn't keep the
726    * XID of an old clip mask cached
727    */
728   if ((had_region && !region) || x11_gc->have_clip_mask)
729     {
730       XSetClipMask (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), None);
731       x11_gc->have_clip_mask = FALSE;
732     }
733
734   gc->clip_x_origin = 0;
735   gc->clip_y_origin = 0;
736   
737   x11_gc->dirty_mask |= GDK_GC_DIRTY_CLIP;
738 }
739
740
741 /**
742  * gdk_gc_copy:
743  * @dst_gc: the destination graphics context.
744  * @src_gc: the source graphics context.
745  * 
746  * Copy the set of values from one graphics context
747  * onto another graphics context.
748  **/
749 void
750 gdk_gc_copy (GdkGC *dst_gc, GdkGC *src_gc)
751 {
752   GdkGCX11 *x11_src_gc;
753   GdkGCX11 *x11_dst_gc;
754   
755   g_return_if_fail (GDK_IS_GC_X11 (dst_gc));
756   g_return_if_fail (GDK_IS_GC_X11 (src_gc));
757
758   x11_dst_gc = GDK_GC_X11 (dst_gc);
759   x11_src_gc = GDK_GC_X11 (src_gc);
760   
761   XCopyGC (GDK_GC_XDISPLAY (src_gc), GDK_GC_XGC (src_gc), ~((~1) << GCLastBit),
762            GDK_GC_XGC (dst_gc));
763
764   dst_gc->clip_x_origin = src_gc->clip_x_origin;
765   dst_gc->clip_y_origin = src_gc->clip_y_origin;
766   dst_gc->ts_x_origin = src_gc->ts_x_origin;
767   dst_gc->ts_y_origin = src_gc->ts_y_origin;
768
769   if (src_gc->colormap)
770     g_object_ref (src_gc->colormap);
771
772   if (dst_gc->colormap)
773     g_object_unref (dst_gc->colormap);
774
775   dst_gc->colormap = src_gc->colormap;
776
777   if (x11_dst_gc->clip_region)
778     gdk_region_destroy (x11_dst_gc->clip_region);
779
780   if (x11_src_gc->clip_region)
781     x11_dst_gc->clip_region = gdk_region_copy (x11_src_gc->clip_region);
782   else
783     x11_dst_gc->clip_region = NULL;
784
785   x11_dst_gc->dirty_mask = x11_src_gc->dirty_mask;
786   x11_dst_gc->fg_pixel = x11_src_gc->fg_pixel;
787 }
788
789 /**
790  * gdk_gc_get_screen:
791  * @gc: a #GdkGC.
792  *
793  * Gets the #GdkScreen for which @gc was created
794  *
795  * Returns: the #GdkScreen for @gc.
796  *
797  * Since: 2.2
798  */
799 GdkScreen *  
800 gdk_gc_get_screen (GdkGC *gc)
801 {
802   g_return_val_if_fail (GDK_IS_GC_X11 (gc), NULL);
803   
804   return GDK_GC_X11 (gc)->screen;
805 }
806
807 /**
808  * gdk_x11_gc_get_xdisplay:
809  * @gc: a #GdkGC.
810  * 
811  * Returns the display of a #GdkGC.
812  * 
813  * Return value: an Xlib <type>Display*</type>.
814  **/
815 Display *
816 gdk_x11_gc_get_xdisplay (GdkGC *gc)
817 {
818   g_return_val_if_fail (GDK_IS_GC_X11 (gc), NULL);
819
820   return GDK_SCREEN_XDISPLAY (gdk_gc_get_screen (gc));
821 }
822
823 /**
824  * gdk_x11_gc_get_xgc:
825  * @gc: a #GdkGC.
826  * 
827  * Returns the X GC of a #GdkGC.
828  * 
829  * Return value: an Xlib <type>GC</type>.
830  **/
831 GC
832 gdk_x11_gc_get_xgc (GdkGC *gc)
833 {
834   GdkGCX11 *gc_x11;
835   
836   g_return_val_if_fail (GDK_IS_GC_X11 (gc), NULL);
837
838   gc_x11 = GDK_GC_X11 (gc);
839
840   if (gc_x11->dirty_mask)
841     _gdk_x11_gc_flush (gc);
842
843   return gc_x11->xgc;
844 }
845
846 /* Various bits of the below are roughly cribbed from XFree86
847  * lib/Xft/xftdraw.c, Copyright 2000, Keith Packard
848  */
849
850 static XRenderPictFormat *
851 foreground_format (GdkGC *gc)
852 {
853   XRenderPictFormat pf;
854
855   pf.type = PictTypeDirect;
856   pf.depth = 32;
857   pf.direct.redMask = 0xff;
858   pf.direct.greenMask = 0xff;
859   pf.direct.blueMask = 0xff;
860   pf.direct.alphaMask = 0xff;
861
862   return XRenderFindFormat (GDK_GC_XDISPLAY (gc),
863                             (PictFormatType |
864                              PictFormatDepth |
865                              PictFormatRedMask |
866                              PictFormatGreenMask |
867                              PictFormatBlueMask |
868                              PictFormatAlphaMask),
869                             &pf,
870                             0);
871 }
872
873 /**
874  * _gdk_x11_gc_get_fg_picture:
875  * @gc: a #GdkGC
876  * 
877  * Gets a Xrender Picture object suitable for being the source
878  * drawable for drawing with the foreground the graphics context.
879  * (Currently, only foreground color is handled, but in the
880  * future we should handle tiles/stipples as well.)
881  * 
882  * Return value: a Picture, owned by the GC; this cannot be
883  *   used over subsequent modification of the GC.
884  **/
885 Picture
886 _gdk_x11_gc_get_fg_picture (GdkGC *gc)
887 {
888   GdkGCX11 *x11_gc;
889   gboolean new = FALSE;
890   XftColor xftcolor;
891   
892   g_return_val_if_fail (GDK_IS_GC_X11 (gc), None);
893
894   if (!_gdk_x11_have_render (GDK_GC_DISPLAY (gc)))
895     return None;
896
897   x11_gc = GDK_GC_X11 (gc);
898
899   if (x11_gc->fg_picture == None)
900     {
901       XRenderPictureAttributes pa;
902       XRenderPictFormat *pix_format = foreground_format (gc);
903       Pixmap pix;
904
905       if (!pix_format)
906         return None;
907
908       pix = XCreatePixmap (GDK_GC_XDISPLAY (gc), 
909                            GDK_SCREEN_XROOTWIN (x11_gc->screen),
910                            1, 1, pix_format->depth);
911       pa.repeat = True;
912       x11_gc->fg_picture = XRenderCreatePicture (GDK_GC_XDISPLAY (gc), 
913                                                  pix,
914                                                  pix_format,
915                                                  CPRepeat, &pa);
916       XFreePixmap (GDK_GC_XDISPLAY (gc), pix);
917       
918       new = TRUE;
919     }
920
921   _gdk_gc_x11_get_fg_xft_color (gc, &xftcolor);
922   
923   if (new ||
924       x11_gc->fg_picture_color.red != xftcolor.color.red ||
925       x11_gc->fg_picture_color.green != xftcolor.color.green ||
926       x11_gc->fg_picture_color.blue != xftcolor.color.blue)
927     {
928       x11_gc->fg_picture_color.red = xftcolor.color.red;
929       x11_gc->fg_picture_color.green = xftcolor.color.green;
930       x11_gc->fg_picture_color.blue = xftcolor.color.blue;
931
932       XRenderFillRectangle (GDK_GC_XDISPLAY (gc), PictOpSrc, 
933                             x11_gc->fg_picture, &x11_gc->fg_picture_color,
934                             0, 0, 1, 1); 
935     }
936
937   return x11_gc->fg_picture;
938 }
939
940 /**
941  * _gdk_gc_x11_get_fg_xft_color:
942  * @gc: a #GdkGC
943  * @xftcolor: location to store the color
944  * 
945  * Gets the foreground color of the GC as a XftColor.
946  **/
947 void
948 _gdk_gc_x11_get_fg_xft_color (GdkGC    *gc,
949                               XftColor *xftcolor)
950 {
951   GdkGCX11 *x11_gc;
952   GdkColormap *cmap;
953   GdkColor color;
954   
955   g_return_if_fail (GDK_IS_GC_X11 (gc));
956
957   x11_gc = GDK_GC_X11 (gc);
958
959   cmap = gdk_gc_get_colormap (gc);
960
961   xftcolor->pixel = x11_gc->fg_pixel;
962
963   if (cmap)
964     {
965       gdk_colormap_query_color (cmap, xftcolor->pixel, &color);
966       xftcolor->color.alpha = 0xffff;
967       xftcolor->color.red = color.red;
968       xftcolor->color.green = color.green;
969       xftcolor->color.blue = color.blue;
970     }
971   else if (x11_gc->depth == 1)
972     {
973       /* Drawing with Xft on a bitmap is a bit bizzare; it
974        * takes alpha >= 0x8000 to mean 'set to 1' and
975        * alpha < 0x8000 to mean 'set to 0'.
976        */
977       if (xftcolor->pixel)
978         {
979           xftcolor->color.red = 0xffff;
980           xftcolor->color.green = 0xffff;
981           xftcolor->color.blue = 0xffff;
982           xftcolor->color.alpha = 0xffff;
983         }
984       else
985         {
986           xftcolor->color.red = 0;
987           xftcolor->color.green = 0;
988           xftcolor->color.blue = 0;
989           xftcolor->color.alpha = 0;
990         }
991     }
992   else
993     {
994       g_warning ("Using Xft rendering requires the GC argument to have a\n"
995                  "specified colormap. If the GC was created for a drawable\n"
996                  "with a colormap, the colormap will be set on the GC\n"
997                  "automatically. Otherwise, a colormap must be set on it with"
998                  "gdk_gc_set_colormap");
999     }
1000 }