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