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