]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkgc-x11.c
Implement GdkRegion in terms of cairo_region_t
[~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 "gdkx.h"
32 #include "gdkalias.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_finalize   (GObject         *object);
57
58 G_DEFINE_TYPE (GdkGCX11, _gdk_gc_x11, GDK_TYPE_GC)
59
60 static void
61 _gdk_gc_x11_class_init (GdkGCX11Class *klass)
62 {
63   GObjectClass *object_class = G_OBJECT_CLASS (klass);
64   GdkGCClass *gc_class = GDK_GC_CLASS (klass);
65   
66   object_class->finalize = gdk_gc_x11_finalize;
67
68   gc_class->get_values = gdk_x11_gc_get_values;
69   gc_class->set_values = gdk_x11_gc_set_values;
70   gc_class->set_dashes = gdk_x11_gc_set_dashes;
71 }
72
73 static void
74 _gdk_gc_x11_init (GdkGCX11 *gc)
75 {
76 }
77
78 static void
79 gdk_gc_x11_finalize (GObject *object)
80 {
81   GdkGCX11 *x11_gc = GDK_GC_X11 (object);
82   
83   XFreeGC (GDK_GC_XDISPLAY (x11_gc), GDK_GC_XGC (x11_gc));
84
85   G_OBJECT_CLASS (_gdk_gc_x11_parent_class)->finalize (object);
86 }
87
88
89 GdkGC *
90 _gdk_x11_gc_new (GdkDrawable      *drawable,
91                  GdkGCValues      *values,
92                  GdkGCValuesMask   values_mask)
93 {
94   GdkGC *gc;
95   GdkGCX11 *private;
96   
97   XGCValues xvalues;
98   unsigned long xvalues_mask;
99
100   /* NOTICE that the drawable here has to be the impl drawable,
101    * not the publically-visible drawables.
102    */
103   g_return_val_if_fail (GDK_IS_DRAWABLE_IMPL_X11 (drawable), NULL);
104
105   gc = g_object_new (_gdk_gc_x11_get_type (), NULL);
106   private = GDK_GC_X11 (gc);
107
108   _gdk_gc_init (gc, drawable, values, values_mask);
109
110   private->dirty_mask = 0;
111   private->have_clip_mask = FALSE;
112     
113   private->screen = GDK_DRAWABLE_IMPL_X11 (drawable)->screen;
114
115   private->depth = gdk_drawable_get_depth (drawable);
116
117   if (values_mask & (GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN))
118     {
119       values_mask &= ~(GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN);
120       private->dirty_mask |= GDK_GC_DIRTY_CLIP;
121     }
122
123   if (values_mask & (GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN))
124     {
125       values_mask &= ~(GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN);
126       private->dirty_mask |= GDK_GC_DIRTY_TS;
127     }
128
129   if ((values_mask & GDK_GC_CLIP_MASK) && values->clip_mask)
130     private->have_clip_mask = TRUE;
131
132   xvalues.function = GXcopy;
133   xvalues.fill_style = FillSolid;
134   xvalues.arc_mode = ArcPieSlice;
135   xvalues.subwindow_mode = ClipByChildren;
136   xvalues.graphics_exposures = False;
137   xvalues_mask = GCFunction | GCFillStyle | GCArcMode | GCSubwindowMode | GCGraphicsExposures;
138
139   gdk_x11_gc_values_to_xvalues (values, values_mask, &xvalues, &xvalues_mask);
140   
141   private->xgc = XCreateGC (GDK_GC_XDISPLAY (gc),
142                             GDK_DRAWABLE_IMPL_X11 (drawable)->xid,
143                             xvalues_mask, &xvalues);
144
145   return gc;
146 }
147
148 GC
149 _gdk_x11_gc_flush (GdkGC *gc)
150 {
151   Display *xdisplay = GDK_GC_XDISPLAY (gc);
152   GdkGCX11 *private = GDK_GC_X11 (gc);
153   GC xgc = private->xgc;
154
155   if (private->dirty_mask & GDK_GC_DIRTY_CLIP)
156     {
157       GdkRegion *clip_region = _gdk_gc_get_clip_region (gc);
158       
159       if (!clip_region)
160         XSetClipOrigin (xdisplay, xgc,
161                         gc->clip_x_origin, gc->clip_y_origin);
162       else
163         {
164           XRectangle *rectangles;
165           gint n_rects;
166
167           _gdk_region_get_xrectangles (clip_region,
168                                        gc->clip_x_origin,
169                                        gc->clip_y_origin,
170                                        &rectangles,
171                                        &n_rects);
172           
173           XSetClipRectangles (xdisplay, xgc, 0, 0,
174                               rectangles,
175                               n_rects, YXBanded);
176           
177           g_free (rectangles);
178         }
179     }
180
181   if (private->dirty_mask & GDK_GC_DIRTY_TS)
182     {
183       XSetTSOrigin (xdisplay, xgc,
184                     gc->ts_x_origin, gc->ts_y_origin);
185     }
186
187   private->dirty_mask = 0;
188   return xgc;
189 }
190
191 static void
192 gdk_x11_gc_get_values (GdkGC       *gc,
193                        GdkGCValues *values)
194 {
195   XGCValues xvalues;
196   
197   if (XGetGCValues (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc),
198                     GCForeground | GCBackground | GCFont |
199                     GCFunction | GCTile | GCStipple | /* GCClipMask | */
200                     GCSubwindowMode | GCGraphicsExposures |
201                     GCTileStipXOrigin | GCTileStipYOrigin |
202                     GCClipXOrigin | GCClipYOrigin |
203                     GCLineWidth | GCLineStyle | GCCapStyle |
204                     GCFillStyle | GCJoinStyle, &xvalues))
205     {
206       values->foreground.pixel = xvalues.foreground;
207       values->background.pixel = xvalues.background;
208
209       switch (xvalues.function)
210         {
211         case GXcopy:
212           values->function = GDK_COPY;
213           break;
214         case GXinvert:
215           values->function = GDK_INVERT;
216           break;
217         case GXxor:
218           values->function = GDK_XOR;
219           break;
220         case GXclear:
221           values->function = GDK_CLEAR;
222           break;
223         case GXand:
224           values->function = GDK_AND;
225           break;
226         case GXandReverse:
227           values->function = GDK_AND_REVERSE;
228           break;
229         case GXandInverted:
230           values->function = GDK_AND_INVERT;
231           break;
232         case GXnoop:
233           values->function = GDK_NOOP;
234           break;
235         case GXor:
236           values->function = GDK_OR;
237           break;
238         case GXequiv:
239           values->function = GDK_EQUIV;
240           break;
241         case GXorReverse:
242           values->function = GDK_OR_REVERSE;
243           break;
244         case GXcopyInverted:
245           values->function =GDK_COPY_INVERT;
246           break;
247         case GXorInverted:
248           values->function = GDK_OR_INVERT;
249           break;
250         case GXnand:
251           values->function = GDK_NAND;
252           break;
253         case GXset:
254           values->function = GDK_SET;
255           break;
256         case GXnor:
257           values->function = GDK_NOR;
258           break;
259         }
260
261       switch (xvalues.fill_style)
262         {
263         case FillSolid:
264           values->fill = GDK_SOLID;
265           break;
266         case FillTiled:
267           values->fill = GDK_TILED;
268           break;
269         case FillStippled:
270           values->fill = GDK_STIPPLED;
271           break;
272         case FillOpaqueStippled:
273           values->fill = GDK_OPAQUE_STIPPLED;
274           break;
275         }
276
277       values->tile = gdk_pixmap_lookup_for_display (GDK_GC_DISPLAY (gc),
278                                                     xvalues.tile);
279       values->stipple = gdk_pixmap_lookup_for_display (GDK_GC_DISPLAY (gc),
280                                                        xvalues.stipple);
281       values->clip_mask = NULL;
282       values->subwindow_mode = xvalues.subwindow_mode;
283       values->ts_x_origin = xvalues.ts_x_origin;
284       values->ts_y_origin = xvalues.ts_y_origin;
285       values->clip_x_origin = xvalues.clip_x_origin;
286       values->clip_y_origin = xvalues.clip_y_origin;
287       values->graphics_exposures = xvalues.graphics_exposures;
288       values->line_width = xvalues.line_width;
289
290       switch (xvalues.line_style)
291         {
292         case LineSolid:
293           values->line_style = GDK_LINE_SOLID;
294           break;
295         case LineOnOffDash:
296           values->line_style = GDK_LINE_ON_OFF_DASH;
297           break;
298         case LineDoubleDash:
299           values->line_style = GDK_LINE_DOUBLE_DASH;
300           break;
301         }
302
303       switch (xvalues.cap_style)
304         {
305         case CapNotLast:
306           values->cap_style = GDK_CAP_NOT_LAST;
307           break;
308         case CapButt:
309           values->cap_style = GDK_CAP_BUTT;
310           break;
311         case CapRound:
312           values->cap_style = GDK_CAP_ROUND;
313           break;
314         case CapProjecting:
315           values->cap_style = GDK_CAP_PROJECTING;
316           break;
317         }
318
319       switch (xvalues.join_style)
320         {
321         case JoinMiter:
322           values->join_style = GDK_JOIN_MITER;
323           break;
324         case JoinRound:
325           values->join_style = GDK_JOIN_ROUND;
326           break;
327         case JoinBevel:
328           values->join_style = GDK_JOIN_BEVEL;
329           break;
330         }
331     }
332   else
333     {
334       memset (values, 0, sizeof (GdkGCValues));
335     }
336 }
337
338 static void
339 gdk_x11_gc_set_values (GdkGC           *gc,
340                        GdkGCValues     *values,
341                        GdkGCValuesMask  values_mask)
342 {
343   GdkGCX11 *x11_gc;
344   XGCValues xvalues;
345   unsigned long xvalues_mask = 0;
346
347   x11_gc = GDK_GC_X11 (gc);
348
349   if (values_mask & (GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN))
350     {
351       values_mask &= ~(GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN);
352       x11_gc->dirty_mask |= GDK_GC_DIRTY_CLIP;
353     }
354
355   if (values_mask & (GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN))
356     {
357       values_mask &= ~(GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN);
358       x11_gc->dirty_mask |= GDK_GC_DIRTY_TS;
359     }
360
361   if (values_mask & GDK_GC_CLIP_MASK)
362     {
363       x11_gc->have_clip_region = FALSE;
364       x11_gc->have_clip_mask = values->clip_mask != NULL;
365     }
366
367   gdk_x11_gc_values_to_xvalues (values, values_mask, &xvalues, &xvalues_mask);
368
369   XChangeGC (GDK_GC_XDISPLAY (gc),
370              GDK_GC_XGC (gc),
371              xvalues_mask,
372              &xvalues);
373 }
374
375 static void
376 gdk_x11_gc_set_dashes (GdkGC *gc,
377                        gint   dash_offset,
378                        gint8  dash_list[],
379                        gint   n)
380 {
381   g_return_if_fail (GDK_IS_GC (gc));
382   g_return_if_fail (dash_list != NULL);
383
384   XSetDashes (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc),
385               dash_offset, (char *)dash_list, n);
386 }
387
388 static void
389 gdk_x11_gc_values_to_xvalues (GdkGCValues    *values,
390                               GdkGCValuesMask mask,
391                               XGCValues      *xvalues,
392                               unsigned long  *xvalues_mask)
393 {
394   /* Optimization for the common case (gdk_gc_new()) */
395   if (values == NULL || mask == 0)
396     return;
397   
398   if (mask & GDK_GC_FOREGROUND)
399     {
400       xvalues->foreground = values->foreground.pixel;
401       *xvalues_mask |= GCForeground;
402     }
403   if (mask & GDK_GC_BACKGROUND)
404     {
405       xvalues->background = values->background.pixel;
406       *xvalues_mask |= GCBackground;
407     }
408   if (mask & GDK_GC_FUNCTION)
409     {
410       switch (values->function)
411         {
412         case GDK_COPY:
413           xvalues->function = GXcopy;
414           break;
415         case GDK_INVERT:
416           xvalues->function = GXinvert;
417           break;
418         case GDK_XOR:
419           xvalues->function = GXxor;
420           break;
421         case GDK_CLEAR:
422           xvalues->function = GXclear;
423           break;
424         case GDK_AND:
425           xvalues->function = GXand;
426           break;
427         case GDK_AND_REVERSE:
428           xvalues->function = GXandReverse;
429           break;
430         case GDK_AND_INVERT:
431           xvalues->function = GXandInverted;
432           break;
433         case GDK_NOOP:
434           xvalues->function = GXnoop;
435           break;
436         case GDK_OR:
437           xvalues->function = GXor;
438           break;
439         case GDK_EQUIV:
440           xvalues->function = GXequiv;
441           break;
442         case GDK_OR_REVERSE:
443           xvalues->function = GXorReverse;
444           break;
445         case GDK_COPY_INVERT:
446           xvalues->function = GXcopyInverted;
447           break;
448         case GDK_OR_INVERT:
449           xvalues->function = GXorInverted;
450           break;
451         case GDK_NAND:
452           xvalues->function = GXnand;
453           break;
454         case GDK_SET:
455           xvalues->function = GXset;
456           break;
457         case GDK_NOR:
458           xvalues->function = GXnor;
459           break;
460         }
461       *xvalues_mask |= GCFunction;
462     }
463   if (mask & GDK_GC_FILL)
464     {
465       switch (values->fill)
466         {
467         case GDK_SOLID:
468           xvalues->fill_style = FillSolid;
469           break;
470         case GDK_TILED:
471           xvalues->fill_style = FillTiled;
472           break;
473         case GDK_STIPPLED:
474           xvalues->fill_style = FillStippled;
475           break;
476         case GDK_OPAQUE_STIPPLED:
477           xvalues->fill_style = FillOpaqueStippled;
478           break;
479         }
480       *xvalues_mask |= GCFillStyle;
481     }
482   if (mask & GDK_GC_TILE)
483     {
484       if (values->tile)
485         xvalues->tile = GDK_DRAWABLE_XID (values->tile);
486       else
487         xvalues->tile = None;
488       
489       *xvalues_mask |= GCTile;
490     }
491   if (mask & GDK_GC_STIPPLE)
492     {
493       if (values->stipple)
494         xvalues->stipple = GDK_DRAWABLE_XID (values->stipple);
495       else
496         xvalues->stipple = None;
497       
498       *xvalues_mask |= GCStipple;
499     }
500   if (mask & GDK_GC_CLIP_MASK)
501     {
502       if (values->clip_mask)
503         xvalues->clip_mask = GDK_DRAWABLE_XID (values->clip_mask);
504       else
505         xvalues->clip_mask = None;
506
507       *xvalues_mask |= GCClipMask;
508       
509     }
510   if (mask & GDK_GC_SUBWINDOW)
511     {
512       xvalues->subwindow_mode = values->subwindow_mode;
513       *xvalues_mask |= GCSubwindowMode;
514     }
515   if (mask & GDK_GC_TS_X_ORIGIN)
516     {
517       xvalues->ts_x_origin = values->ts_x_origin;
518       *xvalues_mask |= GCTileStipXOrigin;
519     }
520   if (mask & GDK_GC_TS_Y_ORIGIN)
521     {
522       xvalues->ts_y_origin = values->ts_y_origin;
523       *xvalues_mask |= GCTileStipYOrigin;
524     }
525   if (mask & GDK_GC_CLIP_X_ORIGIN)
526     {
527       xvalues->clip_x_origin = values->clip_x_origin;
528       *xvalues_mask |= GCClipXOrigin;
529     }
530   if (mask & GDK_GC_CLIP_Y_ORIGIN)
531     {
532       xvalues->clip_y_origin = values->clip_y_origin;
533       *xvalues_mask |= GCClipYOrigin;
534     }
535
536   if (mask & GDK_GC_EXPOSURES)
537     {
538       xvalues->graphics_exposures = values->graphics_exposures;
539       *xvalues_mask |= GCGraphicsExposures;
540     }
541
542   if (mask & GDK_GC_LINE_WIDTH)
543     {
544       xvalues->line_width = values->line_width;
545       *xvalues_mask |= GCLineWidth;
546     }
547   if (mask & GDK_GC_LINE_STYLE)
548     {
549       switch (values->line_style)
550         {
551         case GDK_LINE_SOLID:
552           xvalues->line_style = LineSolid;
553           break;
554         case GDK_LINE_ON_OFF_DASH:
555           xvalues->line_style = LineOnOffDash;
556           break;
557         case GDK_LINE_DOUBLE_DASH:
558           xvalues->line_style = LineDoubleDash;
559           break;
560         }
561       *xvalues_mask |= GCLineStyle;
562     }
563   if (mask & GDK_GC_CAP_STYLE)
564     {
565       switch (values->cap_style)
566         {
567         case GDK_CAP_NOT_LAST:
568           xvalues->cap_style = CapNotLast;
569           break;
570         case GDK_CAP_BUTT:
571           xvalues->cap_style = CapButt;
572           break;
573         case GDK_CAP_ROUND:
574           xvalues->cap_style = CapRound;
575           break;
576         case GDK_CAP_PROJECTING:
577           xvalues->cap_style = CapProjecting;
578           break;
579         }
580       *xvalues_mask |= GCCapStyle;
581     }
582   if (mask & GDK_GC_JOIN_STYLE)
583     {
584       switch (values->join_style)
585         {
586         case GDK_JOIN_MITER:
587           xvalues->join_style = JoinMiter;
588           break;
589         case GDK_JOIN_ROUND:
590           xvalues->join_style = JoinRound;
591           break;
592         case GDK_JOIN_BEVEL:
593           xvalues->join_style = JoinBevel;
594           break;
595         }
596       *xvalues_mask |= GCJoinStyle;
597     }
598
599 }
600
601 void
602 _gdk_windowing_gc_set_clip_region (GdkGC           *gc,
603                                    const GdkRegion *region,
604                                    gboolean reset_origin)
605 {
606   GdkGCX11 *x11_gc = GDK_GC_X11 (gc);
607
608   /* Unset immediately, to make sure Xlib doesn't keep the
609    * XID of an old clip mask cached
610    */
611   if ((x11_gc->have_clip_region && !region) || x11_gc->have_clip_mask)
612     {
613       XSetClipMask (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), None);
614       x11_gc->have_clip_mask = FALSE;
615     }
616
617   x11_gc->have_clip_region = region != NULL;
618
619   if (reset_origin)
620     {
621       gc->clip_x_origin = 0;
622       gc->clip_y_origin = 0;
623     }
624
625   x11_gc->dirty_mask |= GDK_GC_DIRTY_CLIP;
626 }
627
628 void
629 _gdk_windowing_gc_copy (GdkGC *dst_gc,
630                         GdkGC *src_gc)
631 {
632   GdkGCX11 *x11_src_gc = GDK_GC_X11 (src_gc);
633   GdkGCX11 *x11_dst_gc = GDK_GC_X11 (dst_gc);
634
635   XCopyGC (GDK_GC_XDISPLAY (src_gc), GDK_GC_XGC (src_gc), ~((~1) << GCLastBit),
636            GDK_GC_XGC (dst_gc));
637
638   x11_dst_gc->dirty_mask = x11_src_gc->dirty_mask;
639   x11_dst_gc->have_clip_region = x11_src_gc->have_clip_region;
640   x11_dst_gc->have_clip_mask = x11_src_gc->have_clip_mask;
641 }
642
643 /**
644  * gdk_gc_get_screen:
645  * @gc: a #GdkGC.
646  *
647  * Gets the #GdkScreen for which @gc was created
648  *
649  * Returns: the #GdkScreen for @gc.
650  *
651  * Since: 2.2
652  */
653 GdkScreen *  
654 gdk_gc_get_screen (GdkGC *gc)
655 {
656   g_return_val_if_fail (GDK_IS_GC_X11 (gc), NULL);
657   
658   return GDK_GC_X11 (gc)->screen;
659 }
660
661 /**
662  * gdk_x11_gc_get_xdisplay:
663  * @gc: a #GdkGC.
664  * 
665  * Returns the display of a #GdkGC.
666  * 
667  * Return value: an Xlib <type>Display*</type>.
668  **/
669 Display *
670 gdk_x11_gc_get_xdisplay (GdkGC *gc)
671 {
672   g_return_val_if_fail (GDK_IS_GC_X11 (gc), NULL);
673
674   return GDK_SCREEN_XDISPLAY (gdk_gc_get_screen (gc));
675 }
676
677 /**
678  * gdk_x11_gc_get_xgc:
679  * @gc: a #GdkGC.
680  * 
681  * Returns the X GC of a #GdkGC.
682  * 
683  * Return value: an Xlib <type>GC</type>.
684  **/
685 GC
686 gdk_x11_gc_get_xgc (GdkGC *gc)
687 {
688   GdkGCX11 *gc_x11;
689   
690   g_return_val_if_fail (GDK_IS_GC_X11 (gc), NULL);
691
692   gc_x11 = GDK_GC_X11 (gc);
693
694   if (gc_x11->dirty_mask)
695     _gdk_x11_gc_flush (gc);
696
697   return gc_x11->xgc;
698 }
699
700 #define __GDK_GC_X11_C__
701 #include "gdkaliasdef.c"