]> Pileus Git - ~andy/gtk/blob - gdk/gdkpixmap.c
#136672, reported by Christian Persch; fixes based on a patch by Soeren
[~andy/gtk] / gdk / gdkpixmap.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 #include "gdkpixmap.h"
29 #include "gdkinternals.h"
30 #include "gdkpixbuf.h"
31 #include "gdkscreen.h"
32
33 static GdkGC *gdk_pixmap_create_gc      (GdkDrawable     *drawable,
34                                          GdkGCValues     *values,
35                                          GdkGCValuesMask  mask);
36 static void   gdk_pixmap_draw_rectangle (GdkDrawable     *drawable,
37                                          GdkGC           *gc,
38                                          gboolean         filled,
39                                          gint             x,
40                                          gint             y,
41                                          gint             width,
42                                          gint             height);
43 static void   gdk_pixmap_draw_arc       (GdkDrawable     *drawable,
44                                          GdkGC           *gc,
45                                          gboolean         filled,
46                                          gint             x,
47                                          gint             y,
48                                          gint             width,
49                                          gint             height,
50                                          gint             angle1,
51                                          gint             angle2);
52 static void   gdk_pixmap_draw_polygon   (GdkDrawable     *drawable,
53                                          GdkGC           *gc,
54                                          gboolean         filled,
55                                          GdkPoint        *points,
56                                          gint             npoints);
57 static void   gdk_pixmap_draw_text      (GdkDrawable     *drawable,
58                                          GdkFont         *font,
59                                          GdkGC           *gc,
60                                          gint             x,
61                                          gint             y,
62                                          const gchar     *text,
63                                          gint             text_length);
64 static void   gdk_pixmap_draw_text_wc   (GdkDrawable     *drawable,
65                                          GdkFont         *font,
66                                          GdkGC           *gc,
67                                          gint             x,
68                                          gint             y,
69                                          const GdkWChar  *text,
70                                          gint             text_length);
71 static void   gdk_pixmap_draw_drawable  (GdkDrawable     *drawable,
72                                          GdkGC           *gc,
73                                          GdkPixmap       *src,
74                                          gint             xsrc,
75                                          gint             ysrc,
76                                          gint             xdest,
77                                          gint             ydest,
78                                          gint             width,
79                                          gint             height);
80 static void   gdk_pixmap_draw_points    (GdkDrawable     *drawable,
81                                          GdkGC           *gc,
82                                          GdkPoint        *points,
83                                          gint             npoints);
84 static void   gdk_pixmap_draw_segments  (GdkDrawable     *drawable,
85                                          GdkGC           *gc,
86                                          GdkSegment      *segs,
87                                          gint             nsegs);
88 static void   gdk_pixmap_draw_lines     (GdkDrawable     *drawable,
89                                          GdkGC           *gc,
90                                          GdkPoint        *points,
91                                          gint             npoints);
92 static void   gdk_pixmap_draw_glyphs    (GdkDrawable      *drawable,
93                                          GdkGC            *gc,
94                                          PangoFont        *font,
95                                          gint              x,
96                                          gint              y,
97                                          PangoGlyphString *glyphs);
98 static void   gdk_pixmap_draw_image     (GdkDrawable     *drawable,
99                                          GdkGC           *gc,
100                                          GdkImage        *image,
101                                          gint             xsrc,
102                                          gint             ysrc,
103                                          gint             xdest,
104                                          gint             ydest,
105                                          gint             width,
106                                          gint             height);
107 static void   gdk_pixmap_draw_pixbuf    (GdkDrawable     *drawable,
108                                          GdkGC           *gc,
109                                          GdkPixbuf       *pixbuf,
110                                          gint             src_x,
111                                          gint             src_y,
112                                          gint             dest_x,
113                                          gint             dest_y,
114                                          gint             width,
115                                          gint             height,
116                                          GdkRgbDither     dither,
117                                          gint             x_dither,
118                                          gint             y_dither);
119
120
121 static void   gdk_pixmap_real_get_size  (GdkDrawable     *drawable,
122                                          gint            *width,
123                                          gint            *height);
124
125 static GdkImage* gdk_pixmap_copy_to_image (GdkDrawable *drawable,
126                                            GdkImage    *image,
127                                            gint         src_x,
128                                            gint         src_y,
129                                            gint         dest_x,
130                                            gint         dest_y,
131                                            gint         width,
132                                            gint         height);
133
134 static GdkVisual*   gdk_pixmap_real_get_visual   (GdkDrawable *drawable);
135 static gint         gdk_pixmap_real_get_depth    (GdkDrawable *drawable);
136 static void         gdk_pixmap_real_set_colormap (GdkDrawable *drawable,
137                                                   GdkColormap *cmap);
138 static GdkColormap* gdk_pixmap_real_get_colormap (GdkDrawable *drawable);
139 static GdkScreen*   gdk_pixmap_real_get_screen   (GdkDrawable *drawable);
140
141 static void gdk_pixmap_init       (GdkPixmapObject      *pixmap);
142 static void gdk_pixmap_class_init (GdkPixmapObjectClass *klass);
143 static void gdk_pixmap_finalize   (GObject              *object);
144
145 static gpointer parent_class = NULL;
146
147 GType
148 gdk_pixmap_get_type (void)
149 {
150   static GType object_type = 0;
151
152   if (!object_type)
153     {
154       static const GTypeInfo object_info =
155       {
156         sizeof (GdkPixmapObjectClass),
157         (GBaseInitFunc) NULL,
158         (GBaseFinalizeFunc) NULL,
159         (GClassInitFunc) gdk_pixmap_class_init,
160         NULL,           /* class_finalize */
161         NULL,           /* class_data */
162         sizeof (GdkPixmapObject),
163         0,              /* n_preallocs */
164         (GInstanceInitFunc) gdk_pixmap_init,
165       };
166       
167       object_type = g_type_register_static (GDK_TYPE_DRAWABLE,
168                                             "GdkPixmap",
169                                             &object_info, 0);
170     }
171   
172   return object_type;
173 }
174
175 static void
176 gdk_pixmap_init (GdkPixmapObject *pixmap)
177 {
178   /* 0-initialization is good for all other fields. */
179   pixmap->impl = g_object_new (_gdk_pixmap_impl_get_type (), NULL);
180 }
181
182 static void
183 gdk_pixmap_class_init (GdkPixmapObjectClass *klass)
184 {
185   GObjectClass *object_class = G_OBJECT_CLASS (klass);
186   GdkDrawableClass *drawable_class = GDK_DRAWABLE_CLASS (klass);
187   
188   parent_class = g_type_class_peek_parent (klass);
189
190   object_class->finalize = gdk_pixmap_finalize;
191
192   drawable_class->create_gc = gdk_pixmap_create_gc;
193   drawable_class->draw_rectangle = gdk_pixmap_draw_rectangle;
194   drawable_class->draw_arc = gdk_pixmap_draw_arc;
195   drawable_class->draw_polygon = gdk_pixmap_draw_polygon;
196   drawable_class->draw_text = gdk_pixmap_draw_text;
197   drawable_class->draw_text_wc = gdk_pixmap_draw_text_wc;
198   drawable_class->draw_drawable = gdk_pixmap_draw_drawable;
199   drawable_class->draw_points = gdk_pixmap_draw_points;
200   drawable_class->draw_segments = gdk_pixmap_draw_segments;
201   drawable_class->draw_lines = gdk_pixmap_draw_lines;
202   drawable_class->draw_glyphs = gdk_pixmap_draw_glyphs;
203   drawable_class->draw_image = gdk_pixmap_draw_image;
204   drawable_class->draw_pixbuf = gdk_pixmap_draw_pixbuf;
205   drawable_class->get_depth = gdk_pixmap_real_get_depth;
206   drawable_class->get_screen = gdk_pixmap_real_get_screen;
207   drawable_class->get_size = gdk_pixmap_real_get_size;
208   drawable_class->set_colormap = gdk_pixmap_real_set_colormap;
209   drawable_class->get_colormap = gdk_pixmap_real_get_colormap;
210   drawable_class->get_visual = gdk_pixmap_real_get_visual;
211   drawable_class->_copy_to_image = gdk_pixmap_copy_to_image;
212 }
213
214 static void
215 gdk_pixmap_finalize (GObject *object)
216 {
217   GdkPixmapObject *obj = (GdkPixmapObject *) object;
218
219   g_object_unref (obj->impl);
220   obj->impl = NULL;
221   
222   G_OBJECT_CLASS (parent_class)->finalize (object);
223 }
224
225 static GdkGC *
226 gdk_pixmap_create_gc (GdkDrawable     *drawable,
227                       GdkGCValues     *values,
228                       GdkGCValuesMask  mask)
229 {
230   return gdk_gc_new_with_values (((GdkPixmapObject *) drawable)->impl,
231                                  values, mask);
232 }
233
234 static void
235 gdk_pixmap_draw_rectangle (GdkDrawable *drawable,
236                            GdkGC       *gc,
237                            gboolean     filled,
238                            gint         x,
239                            gint         y,
240                            gint         width,
241                            gint         height)
242 {
243   GdkPixmapObject *private = (GdkPixmapObject *)drawable;
244
245   gdk_draw_rectangle (private->impl, gc, filled,
246                       x, y, width, height);
247 }
248
249 static void
250 gdk_pixmap_draw_arc (GdkDrawable *drawable,
251                      GdkGC       *gc,
252                      gboolean     filled,
253                      gint         x,
254                      gint         y,
255                      gint         width,
256                      gint         height,
257                      gint         angle1,
258                      gint         angle2)
259 {
260   GdkPixmapObject *private = (GdkPixmapObject *)drawable;
261
262   gdk_draw_arc (private->impl, gc, filled,
263                 x, y,
264                 width, height, angle1, angle2);
265 }
266
267 static void
268 gdk_pixmap_draw_polygon (GdkDrawable *drawable,
269                          GdkGC       *gc,
270                          gboolean     filled,
271                          GdkPoint    *points,
272                          gint         npoints)
273 {
274   GdkPixmapObject *private = (GdkPixmapObject *)drawable;
275
276   gdk_draw_polygon (private->impl, gc, filled, points, npoints);
277 }
278
279 static void
280 gdk_pixmap_draw_text (GdkDrawable *drawable,
281                       GdkFont     *font,
282                       GdkGC       *gc,
283                       gint         x,
284                       gint         y,
285                       const gchar *text,
286                       gint         text_length)
287 {
288   GdkPixmapObject *private = (GdkPixmapObject *)drawable;
289
290   gdk_draw_text (private->impl, font, gc,
291                  x, y, text, text_length);
292 }
293
294 static void
295 gdk_pixmap_draw_text_wc (GdkDrawable    *drawable,
296                          GdkFont        *font,
297                          GdkGC          *gc,
298                          gint            x,
299                          gint            y,
300                          const GdkWChar *text,
301                          gint            text_length)
302 {
303   GdkPixmapObject *private = (GdkPixmapObject *)drawable;
304
305   gdk_draw_text_wc (private->impl, font, gc,
306                     x, y, text, text_length);
307 }
308
309 static void
310 gdk_pixmap_draw_drawable (GdkDrawable *drawable,
311                           GdkGC       *gc,
312                           GdkPixmap   *src,
313                           gint         xsrc,
314                           gint         ysrc,
315                           gint         xdest,
316                           gint         ydest,
317                           gint         width,
318                           gint         height)
319 {
320   GdkPixmapObject *private = (GdkPixmapObject *)drawable;
321
322   gdk_draw_drawable (private->impl, gc, src, xsrc, ysrc,
323                      xdest, ydest,
324                      width, height);
325 }
326
327 static void
328 gdk_pixmap_draw_points (GdkDrawable *drawable,
329                         GdkGC       *gc,
330                         GdkPoint    *points,
331                         gint         npoints)
332 {
333   GdkPixmapObject *private = (GdkPixmapObject *)drawable;
334
335   gdk_draw_points (private->impl, gc, points, npoints);
336 }
337
338 static void
339 gdk_pixmap_draw_segments (GdkDrawable *drawable,
340                           GdkGC       *gc,
341                           GdkSegment  *segs,
342                           gint         nsegs)
343 {
344   GdkPixmapObject *private = (GdkPixmapObject *)drawable;
345
346   gdk_draw_segments (private->impl, gc, segs, nsegs);
347 }
348
349 static void
350 gdk_pixmap_draw_lines (GdkDrawable *drawable,
351                        GdkGC       *gc,
352                        GdkPoint    *points,
353                        gint         npoints)
354 {
355   GdkPixmapObject *private = (GdkPixmapObject *)drawable;
356
357   gdk_draw_lines (private->impl, gc, points, npoints);
358 }
359
360 static void
361 gdk_pixmap_draw_glyphs (GdkDrawable      *drawable,
362                         GdkGC            *gc,
363                         PangoFont        *font,
364                         gint              x,
365                         gint              y,
366                         PangoGlyphString *glyphs)
367 {
368   GdkPixmapObject *private = (GdkPixmapObject *)drawable;
369
370   gdk_draw_glyphs (private->impl, gc, font, x, y, glyphs);
371 }
372
373 static void
374 gdk_pixmap_draw_image (GdkDrawable     *drawable,
375                        GdkGC           *gc,
376                        GdkImage        *image,
377                        gint             xsrc,
378                        gint             ysrc,
379                        gint             xdest,
380                        gint             ydest,
381                        gint             width,
382                        gint             height)
383 {
384   GdkPixmapObject *private = (GdkPixmapObject *)drawable;
385
386   gdk_draw_image (private->impl, gc, image, xsrc, ysrc, xdest, ydest,
387                   width, height);
388 }
389
390 static void
391 gdk_pixmap_draw_pixbuf (GdkDrawable     *drawable,
392                         GdkGC           *gc,
393                         GdkPixbuf       *pixbuf,
394                         gint             src_x,
395                         gint             src_y,
396                         gint             dest_x,
397                         gint             dest_y,
398                         gint             width,
399                         gint             height,
400                         GdkRgbDither     dither,
401                         gint             x_dither,
402                         gint             y_dither)
403 {
404   GdkPixmapObject *private = (GdkPixmapObject *)drawable;
405
406   gdk_draw_pixbuf (private->impl, gc, pixbuf,
407                    src_x, src_y, dest_x, dest_y, width, height,
408                    dither, x_dither, y_dither);
409 }
410
411 static void
412 gdk_pixmap_real_get_size (GdkDrawable *drawable,
413                           gint *width,
414                           gint *height)
415 {
416   g_return_if_fail (GDK_IS_PIXMAP (drawable));
417
418   gdk_drawable_get_size (GDK_DRAWABLE (((GdkPixmapObject*)drawable)->impl),
419                          width, height);
420 }
421
422 static GdkVisual*
423 gdk_pixmap_real_get_visual (GdkDrawable *drawable)
424 {
425   GdkColormap *colormap;
426
427   g_return_val_if_fail (GDK_IS_PIXMAP (drawable), NULL);
428
429   colormap = gdk_drawable_get_colormap (drawable);
430   return colormap ? gdk_colormap_get_visual (colormap) : NULL;
431 }
432
433 static gint
434 gdk_pixmap_real_get_depth (GdkDrawable *drawable)
435 {
436   gint depth;
437   
438   g_return_val_if_fail (GDK_IS_PIXMAP (drawable), 0);
439
440   depth = GDK_PIXMAP_OBJECT (drawable)->depth;
441
442   return depth;
443 }
444
445 static void
446 gdk_pixmap_real_set_colormap (GdkDrawable *drawable,
447                               GdkColormap *cmap)
448 {
449   g_return_if_fail (GDK_IS_PIXMAP (drawable));  
450   
451   gdk_drawable_set_colormap (((GdkPixmapObject*)drawable)->impl, cmap);
452 }
453
454 static GdkColormap*
455 gdk_pixmap_real_get_colormap (GdkDrawable *drawable)
456 {
457   g_return_val_if_fail (GDK_IS_PIXMAP (drawable), NULL);
458   
459   return gdk_drawable_get_colormap (((GdkPixmapObject*)drawable)->impl);
460 }
461
462 static GdkImage*
463 gdk_pixmap_copy_to_image (GdkDrawable     *drawable,
464                           GdkImage        *image,
465                           gint             src_x,
466                           gint             src_y,
467                           gint             dest_x,
468                           gint             dest_y,
469                           gint             width,
470                           gint             height)
471 {
472   g_return_val_if_fail (GDK_IS_PIXMAP (drawable), NULL);
473   
474   return gdk_drawable_copy_to_image (((GdkPixmapObject*)drawable)->impl,
475                                      image,
476                                      src_x, src_y, dest_x, dest_y,
477                                      width, height);
478 }
479
480 static GdkBitmap *
481 make_solid_mask (GdkScreen *screen, gint width, gint height)
482 {
483   GdkBitmap *bitmap;
484   GdkGC *gc;
485   GdkGCValues gc_values;
486   
487   bitmap = gdk_pixmap_new (gdk_screen_get_root_window (screen),
488                            width, height, 1);
489
490   gc_values.foreground.pixel = 1;
491   gc = gdk_gc_new_with_values (bitmap, &gc_values, GDK_GC_FOREGROUND);
492   
493   gdk_draw_rectangle (bitmap, gc, TRUE, 0, 0, width, height);
494   
495   g_object_unref (gc);
496   
497   return bitmap;
498 }
499
500 #define PACKED_COLOR(c) ((((c)->red   & 0xff00)  << 8) |   \
501                           ((c)->green & 0xff00)        |   \
502                           ((c)->blue             >> 8))
503
504 static GdkPixmap *
505 gdk_pixmap_colormap_new_from_pixbuf (GdkColormap    *colormap,
506                                      GdkBitmap     **mask,
507                                      const GdkColor *transparent_color,
508                                      GdkPixbuf      *pixbuf)
509 {
510   GdkPixmap *pixmap;
511   GdkPixbuf *render_pixbuf;
512   GdkGC *tmp_gc;
513   GdkScreen *screen = gdk_colormap_get_screen (colormap);
514   
515   pixmap = gdk_pixmap_new (gdk_screen_get_root_window (screen),
516                            gdk_pixbuf_get_width (pixbuf),
517                            gdk_pixbuf_get_height (pixbuf),
518                            gdk_colormap_get_visual (colormap)->depth);
519   gdk_drawable_set_colormap (pixmap, colormap);
520   
521   if (transparent_color)
522     {
523       guint32 packed_color = PACKED_COLOR (transparent_color);
524       render_pixbuf = gdk_pixbuf_composite_color_simple (pixbuf,
525                                                          gdk_pixbuf_get_width (pixbuf),
526                                                          gdk_pixbuf_get_height (pixbuf),
527                                                          GDK_INTERP_NEAREST,
528                                                          255, 16, packed_color, packed_color);
529     }
530   else
531     render_pixbuf = pixbuf;
532
533   tmp_gc = _gdk_drawable_get_scratch_gc (pixmap, FALSE);
534   gdk_draw_pixbuf (pixmap, tmp_gc, render_pixbuf, 0, 0, 0, 0,
535                    gdk_pixbuf_get_width (render_pixbuf),
536                    gdk_pixbuf_get_height (render_pixbuf),
537                    GDK_RGB_DITHER_NORMAL, 0, 0);
538
539   if (render_pixbuf != pixbuf)
540     g_object_unref (render_pixbuf);
541
542   if (mask)
543     gdk_pixbuf_render_pixmap_and_mask_for_colormap (pixbuf, colormap, NULL, mask, 128);
544
545   if (mask && !*mask)
546     *mask = make_solid_mask (screen,
547                              gdk_pixbuf_get_width (pixbuf),
548                              gdk_pixbuf_get_height (pixbuf));
549
550   return pixmap;
551 }
552
553 GdkPixmap*
554 gdk_pixmap_colormap_create_from_xpm (GdkDrawable    *drawable,
555                                      GdkColormap    *colormap,
556                                      GdkBitmap     **mask,
557                                      const GdkColor *transparent_color,
558                                      const gchar    *filename)
559 {
560   GdkPixbuf *pixbuf;
561   GdkPixmap *pixmap;
562
563   g_return_val_if_fail (drawable != NULL || colormap != NULL, NULL);
564   g_return_val_if_fail (drawable == NULL || GDK_IS_DRAWABLE (drawable), NULL);
565   g_return_val_if_fail (colormap == NULL || GDK_IS_COLORMAP (colormap), NULL);
566
567   if (colormap == NULL)
568     colormap = gdk_drawable_get_colormap (drawable);
569   
570   pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
571   if (!pixbuf)
572     return NULL;
573
574   pixmap = gdk_pixmap_colormap_new_from_pixbuf (colormap, mask, transparent_color, pixbuf);
575
576   g_object_unref (pixbuf);
577   
578   return pixmap;
579 }
580
581 GdkPixmap*
582 gdk_pixmap_create_from_xpm (GdkDrawable    *drawable,
583                             GdkBitmap     **mask,
584                             const GdkColor *transparent_color,
585                             const gchar    *filename)
586 {
587   return gdk_pixmap_colormap_create_from_xpm (drawable, NULL, mask,
588                                               transparent_color, filename);
589 }
590
591 GdkPixmap*
592 gdk_pixmap_colormap_create_from_xpm_d (GdkDrawable    *drawable,
593                                        GdkColormap    *colormap,
594                                        GdkBitmap     **mask,
595                                        const GdkColor *transparent_color,
596                                        gchar         **data)
597 {
598   GdkPixbuf *pixbuf;
599   GdkPixmap *pixmap;
600
601   g_return_val_if_fail (drawable != NULL || colormap != NULL, NULL);
602   g_return_val_if_fail (drawable == NULL || GDK_IS_DRAWABLE (drawable), NULL);
603   g_return_val_if_fail (colormap == NULL || GDK_IS_COLORMAP (colormap), NULL);
604
605   if (colormap == NULL)
606     colormap = gdk_drawable_get_colormap (drawable);
607   
608   pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **)data);
609   if (!pixbuf)
610     return NULL;
611
612   pixmap = gdk_pixmap_colormap_new_from_pixbuf (colormap, mask, transparent_color, pixbuf);
613
614   g_object_unref (pixbuf);
615
616   return pixmap;
617 }
618
619 GdkPixmap*
620 gdk_pixmap_create_from_xpm_d (GdkDrawable    *drawable,
621                               GdkBitmap     **mask,
622                               const GdkColor *transparent_color,
623                               gchar         **data)
624 {
625   return gdk_pixmap_colormap_create_from_xpm_d (drawable, NULL, mask,
626                                                 transparent_color, data);
627 }
628
629 static GdkScreen*
630 gdk_pixmap_real_get_screen (GdkDrawable *drawable)
631 {
632     return gdk_drawable_get_screen (GDK_PIXMAP_OBJECT (drawable)->impl);
633 }