]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkgc-x11.c
Initial client-side-windows work
[~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       values->font = gdk_font_lookup_for_display (GDK_GC_DISPLAY (gc),
210                                                   xvalues.font);
211
212       switch (xvalues.function)
213         {
214         case GXcopy:
215           values->function = GDK_COPY;
216           break;
217         case GXinvert:
218           values->function = GDK_INVERT;
219           break;
220         case GXxor:
221           values->function = GDK_XOR;
222           break;
223         case GXclear:
224           values->function = GDK_CLEAR;
225           break;
226         case GXand:
227           values->function = GDK_AND;
228           break;
229         case GXandReverse:
230           values->function = GDK_AND_REVERSE;
231           break;
232         case GXandInverted:
233           values->function = GDK_AND_INVERT;
234           break;
235         case GXnoop:
236           values->function = GDK_NOOP;
237           break;
238         case GXor:
239           values->function = GDK_OR;
240           break;
241         case GXequiv:
242           values->function = GDK_EQUIV;
243           break;
244         case GXorReverse:
245           values->function = GDK_OR_REVERSE;
246           break;
247         case GXcopyInverted:
248           values->function =GDK_COPY_INVERT;
249           break;
250         case GXorInverted:
251           values->function = GDK_OR_INVERT;
252           break;
253         case GXnand:
254           values->function = GDK_NAND;
255           break;
256         case GXset:
257           values->function = GDK_SET;
258           break;
259         case GXnor:
260           values->function = GDK_NOR;
261           break;
262         }
263
264       switch (xvalues.fill_style)
265         {
266         case FillSolid:
267           values->fill = GDK_SOLID;
268           break;
269         case FillTiled:
270           values->fill = GDK_TILED;
271           break;
272         case FillStippled:
273           values->fill = GDK_STIPPLED;
274           break;
275         case FillOpaqueStippled:
276           values->fill = GDK_OPAQUE_STIPPLED;
277           break;
278         }
279
280       values->tile = gdk_pixmap_lookup_for_display (GDK_GC_DISPLAY (gc),
281                                                     xvalues.tile);
282       values->stipple = gdk_pixmap_lookup_for_display (GDK_GC_DISPLAY (gc),
283                                                        xvalues.stipple);
284       values->clip_mask = NULL;
285       values->subwindow_mode = xvalues.subwindow_mode;
286       values->ts_x_origin = xvalues.ts_x_origin;
287       values->ts_y_origin = xvalues.ts_y_origin;
288       values->clip_x_origin = xvalues.clip_x_origin;
289       values->clip_y_origin = xvalues.clip_y_origin;
290       values->graphics_exposures = xvalues.graphics_exposures;
291       values->line_width = xvalues.line_width;
292
293       switch (xvalues.line_style)
294         {
295         case LineSolid:
296           values->line_style = GDK_LINE_SOLID;
297           break;
298         case LineOnOffDash:
299           values->line_style = GDK_LINE_ON_OFF_DASH;
300           break;
301         case LineDoubleDash:
302           values->line_style = GDK_LINE_DOUBLE_DASH;
303           break;
304         }
305
306       switch (xvalues.cap_style)
307         {
308         case CapNotLast:
309           values->cap_style = GDK_CAP_NOT_LAST;
310           break;
311         case CapButt:
312           values->cap_style = GDK_CAP_BUTT;
313           break;
314         case CapRound:
315           values->cap_style = GDK_CAP_ROUND;
316           break;
317         case CapProjecting:
318           values->cap_style = GDK_CAP_PROJECTING;
319           break;
320         }
321
322       switch (xvalues.join_style)
323         {
324         case JoinMiter:
325           values->join_style = GDK_JOIN_MITER;
326           break;
327         case JoinRound:
328           values->join_style = GDK_JOIN_ROUND;
329           break;
330         case JoinBevel:
331           values->join_style = GDK_JOIN_BEVEL;
332           break;
333         }
334     }
335   else
336     {
337       memset (values, 0, sizeof (GdkGCValues));
338     }
339 }
340
341 static void
342 gdk_x11_gc_set_values (GdkGC           *gc,
343                        GdkGCValues     *values,
344                        GdkGCValuesMask  values_mask)
345 {
346   GdkGCX11 *x11_gc;
347   XGCValues xvalues;
348   unsigned long xvalues_mask = 0;
349
350   x11_gc = GDK_GC_X11 (gc);
351
352   if (values_mask & (GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN))
353     {
354       values_mask &= ~(GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN);
355       x11_gc->dirty_mask |= GDK_GC_DIRTY_CLIP;
356     }
357
358   if (values_mask & (GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN))
359     {
360       values_mask &= ~(GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN);
361       x11_gc->dirty_mask |= GDK_GC_DIRTY_TS;
362     }
363
364   if (values_mask & GDK_GC_CLIP_MASK)
365     {
366       x11_gc->have_clip_region = FALSE;
367       x11_gc->have_clip_mask = values->clip_mask != NULL;
368     }
369
370   gdk_x11_gc_values_to_xvalues (values, values_mask, &xvalues, &xvalues_mask);
371
372   XChangeGC (GDK_GC_XDISPLAY (gc),
373              GDK_GC_XGC (gc),
374              xvalues_mask,
375              &xvalues);
376 }
377
378 static void
379 gdk_x11_gc_set_dashes (GdkGC *gc,
380                        gint   dash_offset,
381                        gint8  dash_list[],
382                        gint   n)
383 {
384   g_return_if_fail (GDK_IS_GC (gc));
385   g_return_if_fail (dash_list != NULL);
386
387   XSetDashes (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc),
388               dash_offset, (char *)dash_list, n);
389 }
390
391 static void
392 gdk_x11_gc_values_to_xvalues (GdkGCValues    *values,
393                               GdkGCValuesMask mask,
394                               XGCValues      *xvalues,
395                               unsigned long  *xvalues_mask)
396 {
397   /* Optimization for the common case (gdk_gc_new()) */
398   if (values == NULL || mask == 0)
399     return;
400   
401   if (mask & GDK_GC_FOREGROUND)
402     {
403       xvalues->foreground = values->foreground.pixel;
404       *xvalues_mask |= GCForeground;
405     }
406   if (mask & GDK_GC_BACKGROUND)
407     {
408       xvalues->background = values->background.pixel;
409       *xvalues_mask |= GCBackground;
410     }
411   if ((mask & GDK_GC_FONT) && (values->font->type == GDK_FONT_FONT))
412     {
413       xvalues->font = ((XFontStruct *) (GDK_FONT_XFONT (values->font)))->fid;
414       *xvalues_mask |= GCFont;
415     }
416   if (mask & GDK_GC_FUNCTION)
417     {
418       switch (values->function)
419         {
420         case GDK_COPY:
421           xvalues->function = GXcopy;
422           break;
423         case GDK_INVERT:
424           xvalues->function = GXinvert;
425           break;
426         case GDK_XOR:
427           xvalues->function = GXxor;
428           break;
429         case GDK_CLEAR:
430           xvalues->function = GXclear;
431           break;
432         case GDK_AND:
433           xvalues->function = GXand;
434           break;
435         case GDK_AND_REVERSE:
436           xvalues->function = GXandReverse;
437           break;
438         case GDK_AND_INVERT:
439           xvalues->function = GXandInverted;
440           break;
441         case GDK_NOOP:
442           xvalues->function = GXnoop;
443           break;
444         case GDK_OR:
445           xvalues->function = GXor;
446           break;
447         case GDK_EQUIV:
448           xvalues->function = GXequiv;
449           break;
450         case GDK_OR_REVERSE:
451           xvalues->function = GXorReverse;
452           break;
453         case GDK_COPY_INVERT:
454           xvalues->function = GXcopyInverted;
455           break;
456         case GDK_OR_INVERT:
457           xvalues->function = GXorInverted;
458           break;
459         case GDK_NAND:
460           xvalues->function = GXnand;
461           break;
462         case GDK_SET:
463           xvalues->function = GXset;
464           break;
465         case GDK_NOR:
466           xvalues->function = GXnor;
467           break;
468         }
469       *xvalues_mask |= GCFunction;
470     }
471   if (mask & GDK_GC_FILL)
472     {
473       switch (values->fill)
474         {
475         case GDK_SOLID:
476           xvalues->fill_style = FillSolid;
477           break;
478         case GDK_TILED:
479           xvalues->fill_style = FillTiled;
480           break;
481         case GDK_STIPPLED:
482           xvalues->fill_style = FillStippled;
483           break;
484         case GDK_OPAQUE_STIPPLED:
485           xvalues->fill_style = FillOpaqueStippled;
486           break;
487         }
488       *xvalues_mask |= GCFillStyle;
489     }
490   if (mask & GDK_GC_TILE)
491     {
492       if (values->tile)
493         xvalues->tile = GDK_DRAWABLE_XID (values->tile);
494       else
495         xvalues->tile = None;
496       
497       *xvalues_mask |= GCTile;
498     }
499   if (mask & GDK_GC_STIPPLE)
500     {
501       if (values->stipple)
502         xvalues->stipple = GDK_DRAWABLE_XID (values->stipple);
503       else
504         xvalues->stipple = None;
505       
506       *xvalues_mask |= GCStipple;
507     }
508   if (mask & GDK_GC_CLIP_MASK)
509     {
510       if (values->clip_mask)
511         xvalues->clip_mask = GDK_DRAWABLE_XID (values->clip_mask);
512       else
513         xvalues->clip_mask = None;
514
515       *xvalues_mask |= GCClipMask;
516       
517     }
518   if (mask & GDK_GC_SUBWINDOW)
519     {
520       xvalues->subwindow_mode = values->subwindow_mode;
521       *xvalues_mask |= GCSubwindowMode;
522     }
523   if (mask & GDK_GC_TS_X_ORIGIN)
524     {
525       xvalues->ts_x_origin = values->ts_x_origin;
526       *xvalues_mask |= GCTileStipXOrigin;
527     }
528   if (mask & GDK_GC_TS_Y_ORIGIN)
529     {
530       xvalues->ts_y_origin = values->ts_y_origin;
531       *xvalues_mask |= GCTileStipYOrigin;
532     }
533   if (mask & GDK_GC_CLIP_X_ORIGIN)
534     {
535       xvalues->clip_x_origin = values->clip_x_origin;
536       *xvalues_mask |= GCClipXOrigin;
537     }
538   if (mask & GDK_GC_CLIP_Y_ORIGIN)
539     {
540       xvalues->clip_y_origin = values->clip_y_origin;
541       *xvalues_mask |= GCClipYOrigin;
542     }
543
544   if (mask & GDK_GC_EXPOSURES)
545     {
546       xvalues->graphics_exposures = values->graphics_exposures;
547       *xvalues_mask |= GCGraphicsExposures;
548     }
549
550   if (mask & GDK_GC_LINE_WIDTH)
551     {
552       xvalues->line_width = values->line_width;
553       *xvalues_mask |= GCLineWidth;
554     }
555   if (mask & GDK_GC_LINE_STYLE)
556     {
557       switch (values->line_style)
558         {
559         case GDK_LINE_SOLID:
560           xvalues->line_style = LineSolid;
561           break;
562         case GDK_LINE_ON_OFF_DASH:
563           xvalues->line_style = LineOnOffDash;
564           break;
565         case GDK_LINE_DOUBLE_DASH:
566           xvalues->line_style = LineDoubleDash;
567           break;
568         }
569       *xvalues_mask |= GCLineStyle;
570     }
571   if (mask & GDK_GC_CAP_STYLE)
572     {
573       switch (values->cap_style)
574         {
575         case GDK_CAP_NOT_LAST:
576           xvalues->cap_style = CapNotLast;
577           break;
578         case GDK_CAP_BUTT:
579           xvalues->cap_style = CapButt;
580           break;
581         case GDK_CAP_ROUND:
582           xvalues->cap_style = CapRound;
583           break;
584         case GDK_CAP_PROJECTING:
585           xvalues->cap_style = CapProjecting;
586           break;
587         }
588       *xvalues_mask |= GCCapStyle;
589     }
590   if (mask & GDK_GC_JOIN_STYLE)
591     {
592       switch (values->join_style)
593         {
594         case GDK_JOIN_MITER:
595           xvalues->join_style = JoinMiter;
596           break;
597         case GDK_JOIN_ROUND:
598           xvalues->join_style = JoinRound;
599           break;
600         case GDK_JOIN_BEVEL:
601           xvalues->join_style = JoinBevel;
602           break;
603         }
604       *xvalues_mask |= GCJoinStyle;
605     }
606
607 }
608
609 void
610 _gdk_windowing_gc_set_clip_region (GdkGC           *gc,
611                                    const GdkRegion *region,
612                                    gboolean reset_origin)
613 {
614   GdkGCX11 *x11_gc = GDK_GC_X11 (gc);
615
616   /* Unset immediately, to make sure Xlib doesn't keep the
617    * XID of an old clip mask cached
618    */
619   if ((x11_gc->have_clip_region && !region) || x11_gc->have_clip_mask)
620     {
621       XSetClipMask (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), None);
622       x11_gc->have_clip_mask = FALSE;
623     }
624
625   x11_gc->have_clip_region = region != NULL;
626
627   if (reset_origin)
628     {
629       gc->clip_x_origin = 0;
630       gc->clip_y_origin = 0;
631     }
632
633   x11_gc->dirty_mask |= GDK_GC_DIRTY_CLIP;
634 }
635
636 void
637 _gdk_windowing_gc_copy (GdkGC *dst_gc,
638                         GdkGC *src_gc)
639 {
640   GdkGCX11 *x11_src_gc = GDK_GC_X11 (src_gc);
641   GdkGCX11 *x11_dst_gc = GDK_GC_X11 (dst_gc);
642
643   XCopyGC (GDK_GC_XDISPLAY (src_gc), GDK_GC_XGC (src_gc), ~((~1) << GCLastBit),
644            GDK_GC_XGC (dst_gc));
645
646   x11_dst_gc->dirty_mask = x11_src_gc->dirty_mask;
647   x11_dst_gc->have_clip_region = x11_src_gc->have_clip_region;
648   x11_dst_gc->have_clip_mask = x11_src_gc->have_clip_mask;
649 }
650
651 /**
652  * gdk_gc_get_screen:
653  * @gc: a #GdkGC.
654  *
655  * Gets the #GdkScreen for which @gc was created
656  *
657  * Returns: the #GdkScreen for @gc.
658  *
659  * Since: 2.2
660  */
661 GdkScreen *  
662 gdk_gc_get_screen (GdkGC *gc)
663 {
664   g_return_val_if_fail (GDK_IS_GC_X11 (gc), NULL);
665   
666   return GDK_GC_X11 (gc)->screen;
667 }
668
669 /**
670  * gdk_x11_gc_get_xdisplay:
671  * @gc: a #GdkGC.
672  * 
673  * Returns the display of a #GdkGC.
674  * 
675  * Return value: an Xlib <type>Display*</type>.
676  **/
677 Display *
678 gdk_x11_gc_get_xdisplay (GdkGC *gc)
679 {
680   g_return_val_if_fail (GDK_IS_GC_X11 (gc), NULL);
681
682   return GDK_SCREEN_XDISPLAY (gdk_gc_get_screen (gc));
683 }
684
685 /**
686  * gdk_x11_gc_get_xgc:
687  * @gc: a #GdkGC.
688  * 
689  * Returns the X GC of a #GdkGC.
690  * 
691  * Return value: an Xlib <type>GC</type>.
692  **/
693 GC
694 gdk_x11_gc_get_xgc (GdkGC *gc)
695 {
696   GdkGCX11 *gc_x11;
697   
698   g_return_val_if_fail (GDK_IS_GC_X11 (gc), NULL);
699
700   gc_x11 = GDK_GC_X11 (gc);
701
702   if (gc_x11->dirty_mask)
703     _gdk_x11_gc_flush (gc);
704
705   return gc_x11->xgc;
706 }
707
708 #define __GDK_GC_X11_C__
709 #include "gdkaliasdef.c"