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