]> Pileus Git - ~andy/gtk/blob - gtk/gtkimage.c
New function to create a pixbuf pointing to a subregion of another pixbuf.
[~andy/gtk] / gtk / gtkimage.c
1 /* GTK - The GIMP Toolkit
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 "gtkcontainer.h"
28 #include "gtkimage.h"
29 #include "gtkiconfactory.h"
30
31 static void gtk_image_class_init   (GtkImageClass  *klass);
32 static void gtk_image_init         (GtkImage       *image);
33 static gint gtk_image_expose       (GtkWidget      *widget,
34                                     GdkEventExpose *event);
35 static void gtk_image_size_request (GtkWidget      *widget,
36                                     GtkRequisition *requisition);
37 static void gtk_image_clear        (GtkImage       *image);
38 static void gtk_image_update_size  (GtkImage       *image,
39                                     gint            image_width,
40                                     gint            image_height);
41
42 static gpointer parent_class;
43
44 GtkType
45 gtk_image_get_type (void)
46 {
47   static GtkType image_type = 0;
48
49   if (!image_type)
50     {
51       static const GtkTypeInfo image_info =
52       {
53         "GtkImage",
54         sizeof (GtkImage),
55         sizeof (GtkImageClass),
56         (GtkClassInitFunc) gtk_image_class_init,
57         (GtkObjectInitFunc) gtk_image_init,
58         /* reserved_1 */ NULL,
59         /* reserved_2 */ NULL,
60         (GtkClassInitFunc) NULL,
61       };
62
63       image_type = gtk_type_unique (GTK_TYPE_MISC, &image_info);
64     }
65
66   return image_type;
67 }
68
69 static void
70 gtk_image_class_init (GtkImageClass *class)
71 {
72   GtkWidgetClass *widget_class;
73
74   parent_class = g_type_class_peek_parent (class);
75   
76   widget_class = (GtkWidgetClass*) class;
77
78   widget_class->expose_event = gtk_image_expose;
79   widget_class->size_request = gtk_image_size_request;
80 }
81
82 static void
83 gtk_image_init (GtkImage *image)
84 {
85   GTK_WIDGET_SET_FLAGS (image, GTK_NO_WINDOW);
86
87   image->storage_type = GTK_IMAGE_EMPTY;
88 }
89
90 GtkWidget*
91 gtk_image_new_from_pixmap (GdkPixmap *pixmap,
92                            GdkBitmap *mask)
93 {
94   GtkImage *image;
95
96   image = gtk_type_new (GTK_TYPE_IMAGE);
97
98   gtk_image_set_from_pixmap (image, pixmap, mask);
99
100   return GTK_WIDGET (image);
101 }
102
103 GtkWidget*
104 gtk_image_new_from_image  (GdkImage  *gdk_image,
105                            GdkBitmap *mask)
106 {
107   GtkImage *image;
108
109   image = gtk_type_new (GTK_TYPE_IMAGE);
110
111   gtk_image_set_from_image (image, gdk_image, mask);
112
113   return GTK_WIDGET (image);
114 }
115
116 GtkWidget*
117 gtk_image_new_from_file   (const gchar *filename)
118 {
119   GtkImage *image;
120
121   image = gtk_type_new (GTK_TYPE_IMAGE);
122
123   gtk_image_set_from_file (image, filename);
124
125   return GTK_WIDGET (image);
126 }
127
128 GtkWidget*
129 gtk_image_new_from_pixbuf (GdkPixbuf *pixbuf)
130 {
131   GtkImage *image;
132
133   image = gtk_type_new (GTK_TYPE_IMAGE);
134
135   gtk_image_set_from_pixbuf (image, pixbuf);
136
137   return GTK_WIDGET (image);  
138 }
139
140 GtkWidget*
141 gtk_image_new_from_stock (const gchar    *stock_id,
142                           const gchar    *size)
143 {
144   GtkImage *image;
145
146   image = gtk_type_new (GTK_TYPE_IMAGE);
147
148   gtk_image_set_from_stock (image, stock_id, size);
149
150   return GTK_WIDGET (image);
151 }
152
153 GtkWidget*
154 gtk_image_new_from_icon_set (GtkIconSet     *icon_set,
155                              const gchar    *size)
156 {
157   GtkImage *image;
158
159   image = gtk_type_new (GTK_TYPE_IMAGE);
160
161   gtk_image_set_from_icon_set (image, icon_set, size);
162
163   return GTK_WIDGET (image);
164 }
165
166 void
167 gtk_image_set_from_pixmap (GtkImage  *image,
168                            GdkPixmap *pixmap,
169                            GdkBitmap *mask)
170 {
171   g_return_if_fail (GTK_IS_IMAGE (image));
172   g_return_if_fail (pixmap == NULL ||
173                     GDK_IS_PIXMAP (pixmap));
174   g_return_if_fail (mask == NULL ||
175                     GDK_IS_PIXMAP (mask));
176   
177   if (pixmap)
178     g_object_ref (G_OBJECT (pixmap));
179
180   if (mask)
181     g_object_ref (G_OBJECT (mask));
182
183   gtk_image_clear (image);
184
185   if (pixmap)
186     {
187       int width;
188       int height;
189       
190       image->storage_type = GTK_IMAGE_PIXMAP;
191
192       image->data.pixmap.pixmap = pixmap;
193       image->data.pixmap.mask = mask;
194
195       gdk_drawable_get_size (GDK_DRAWABLE (pixmap), &width, &height);
196
197       gtk_image_update_size (image, width, height);
198     }
199   else
200     {
201       /* Clean up the mask if pixmap was NULL */
202       if (mask)
203         g_object_unref (G_OBJECT (mask));
204     }
205 }
206
207 void
208 gtk_image_set_from_image  (GtkImage  *image,
209                            GdkImage  *gdk_image,
210                            GdkBitmap *mask)
211 {
212   g_return_if_fail (GTK_IS_IMAGE (image));
213   g_return_if_fail (gdk_image == NULL ||
214                     GDK_IS_IMAGE (gdk_image));
215   g_return_if_fail (mask == NULL ||
216                     GDK_IS_PIXMAP (mask));
217
218   
219   if (gdk_image)
220     g_object_ref (G_OBJECT (gdk_image));
221
222   if (mask)
223     g_object_ref (G_OBJECT (mask));
224
225   gtk_image_clear (image);
226
227   if (gdk_image)
228     {
229       image->storage_type = GTK_IMAGE_IMAGE;
230
231       image->data.image.image = gdk_image;
232       image->data.image.mask = mask;
233
234       gtk_image_update_size (image, gdk_image->width, gdk_image->height);
235     }
236   else
237     {
238       /* Clean up the mask if gdk_image was NULL */
239       if (mask)
240         g_object_unref (G_OBJECT (mask));
241     }
242 }
243
244 void
245 gtk_image_set_from_file   (GtkImage    *image,
246                            const gchar *filename)
247 {
248   GdkPixbuf *pixbuf;
249   
250   g_return_if_fail (GTK_IS_IMAGE (image));
251   g_return_if_fail (filename != NULL);
252   
253   gtk_image_clear (image);
254
255   if (filename == NULL)
256     return;
257   
258   pixbuf = gdk_pixbuf_new_from_file (filename, NULL);
259
260   if (pixbuf == NULL)
261     return;
262
263   gtk_image_set_from_pixbuf (image, pixbuf);
264
265   g_object_unref (G_OBJECT (pixbuf));
266 }
267
268 void
269 gtk_image_set_from_pixbuf (GtkImage  *image,
270                            GdkPixbuf *pixbuf)
271 {
272   g_return_if_fail (GTK_IS_IMAGE (image));
273   g_return_if_fail (pixbuf == NULL ||
274                     GDK_IS_PIXBUF (pixbuf));
275   
276   if (pixbuf)
277     g_object_ref (G_OBJECT (pixbuf));
278
279   gtk_image_clear (image);
280
281   if (pixbuf != NULL)
282     {
283       image->storage_type = GTK_IMAGE_PIXBUF;
284
285       image->data.pixbuf.pixbuf = pixbuf;
286
287       gtk_image_update_size (image,
288                              gdk_pixbuf_get_width (pixbuf),
289                              gdk_pixbuf_get_height (pixbuf));
290     }
291 }
292
293 void
294 gtk_image_set_from_stock  (GtkImage       *image,
295                            const gchar    *stock_id,
296                            const gchar    *size)
297 {
298   g_return_if_fail (GTK_IS_IMAGE (image));
299   
300   gtk_image_clear (image);
301
302   if (stock_id)
303     {      
304       image->storage_type = GTK_IMAGE_STOCK;
305       
306       image->data.stock.stock_id = g_strdup (stock_id);
307       image->data.stock.size = g_strdup (size);
308
309       /* Size is demand-computed in size request method
310        * if we're a stock image, since changing the
311        * style impacts the size request
312        */
313     }
314 }
315
316 void
317 gtk_image_set_from_icon_set  (GtkImage       *image,
318                               GtkIconSet     *icon_set,
319                               const gchar    *size)
320 {
321   g_return_if_fail (GTK_IS_IMAGE (image));
322
323   if (icon_set)
324     gtk_icon_set_ref (icon_set);
325   
326   gtk_image_clear (image);
327
328   if (icon_set)
329     {      
330       image->storage_type = GTK_IMAGE_ICON_SET;
331       
332       image->data.icon_set.icon_set = icon_set;
333       image->data.icon_set.size = g_strdup (size);
334
335       /* Size is demand-computed in size request method
336        * if we're an icon set
337        */
338     }
339 }
340
341 GtkImageType
342 gtk_image_get_storage_type (GtkImage *image)
343 {
344   g_return_val_if_fail (GTK_IS_IMAGE (image), GTK_IMAGE_EMPTY);
345
346   return image->storage_type;
347 }
348
349 void
350 gtk_image_get_pixmap (GtkImage   *image,
351                       GdkPixmap **pixmap,
352                       GdkBitmap **mask)
353 {
354   g_return_if_fail (GTK_IS_IMAGE (image)); 
355   g_return_if_fail (image->storage_type == GTK_IMAGE_PIXMAP ||
356                     image->storage_type == GTK_IMAGE_EMPTY);
357   
358   if (pixmap)
359     *pixmap = image->data.pixmap.pixmap;
360   
361   if (mask)
362     *mask = image->data.pixmap.mask;
363 }
364
365 void
366 gtk_image_get_image  (GtkImage   *image,
367                       GdkImage  **gdk_image,
368                       GdkBitmap **mask)
369 {
370   g_return_if_fail (GTK_IS_IMAGE (image));
371   g_return_if_fail (image->storage_type == GTK_IMAGE_IMAGE ||
372                     image->storage_type == GTK_IMAGE_EMPTY);
373
374   if (gdk_image)
375     *gdk_image = image->data.image.image;
376   
377   if (mask)
378     *mask = image->data.image.mask;
379 }
380
381 GdkPixbuf*
382 gtk_image_get_pixbuf (GtkImage *image)
383 {
384   g_return_val_if_fail (GTK_IS_IMAGE (image), NULL);
385   g_return_val_if_fail (image->storage_type == GTK_IMAGE_PIXBUF ||
386                         image->storage_type == GTK_IMAGE_EMPTY, NULL);
387
388   if (image->storage_type == GTK_IMAGE_EMPTY)
389     image->data.pixbuf.pixbuf = NULL;
390   
391   return image->data.pixbuf.pixbuf;
392 }
393
394 void
395 gtk_image_get_stock  (GtkImage        *image,
396                       gchar          **stock_id,
397                       gchar          **size)
398 {
399   g_return_if_fail (GTK_IS_IMAGE (image));
400   g_return_if_fail (image->storage_type == GTK_IMAGE_STOCK ||
401                     image->storage_type == GTK_IMAGE_EMPTY);
402
403   if (image->storage_type == GTK_IMAGE_EMPTY)
404     image->data.stock.stock_id = NULL;
405   
406   if (stock_id)
407     *stock_id = g_strdup (image->data.stock.stock_id);
408
409   if (size)
410     *size = image->data.stock.size;
411 }
412
413 void
414 gtk_image_get_icon_set  (GtkImage        *image,
415                          GtkIconSet     **icon_set,
416                          gchar          **size)
417 {
418   g_return_if_fail (GTK_IS_IMAGE (image));
419   g_return_if_fail (image->storage_type == GTK_IMAGE_ICON_SET ||
420                     image->storage_type == GTK_IMAGE_EMPTY);
421       
422   if (icon_set)    
423     *icon_set = image->data.icon_set.icon_set;
424
425   if (size)
426     *size = g_strdup (image->data.icon_set.size);
427 }
428
429 GtkWidget*
430 gtk_image_new (GdkImage  *val,
431                GdkBitmap *mask)
432 {
433   GtkImage *image;
434
435   g_return_val_if_fail (val != NULL, NULL);
436
437   image = gtk_type_new (GTK_TYPE_IMAGE);
438
439   gtk_image_set (image, val, mask);
440
441   return GTK_WIDGET (image);
442 }
443
444 void
445 gtk_image_set (GtkImage  *image,
446                GdkImage  *val,
447                GdkBitmap *mask)
448 {
449   g_return_if_fail (GTK_IS_IMAGE (image));
450
451   gtk_image_set_from_image (image, val, mask);
452 }
453
454 void
455 gtk_image_get (GtkImage   *image,
456                GdkImage  **val,
457                GdkBitmap **mask)
458 {
459   g_return_if_fail (GTK_IS_IMAGE (image));
460
461   gtk_image_get_image (image, val, mask);
462 }
463
464
465 static gint
466 gtk_image_expose (GtkWidget      *widget,
467                   GdkEventExpose *event)
468 {
469   g_return_val_if_fail (widget != NULL, FALSE);
470   g_return_val_if_fail (GTK_IS_IMAGE (widget), FALSE);
471   g_return_val_if_fail (event != NULL, FALSE);
472   
473   if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget) &&
474       GTK_IMAGE (widget)->storage_type != GTK_IMAGE_EMPTY)
475     {
476       GtkImage *image;
477       GtkMisc *misc;
478       GdkRectangle area, image_bound, intersection;
479       gint x, y;
480       GdkBitmap *mask = NULL;
481       GdkPixbuf *stock_pixbuf = NULL;
482       
483       image = GTK_IMAGE (widget);
484       misc = GTK_MISC (widget);
485
486       x = (widget->allocation.x * (1.0 - misc->xalign) +
487            (widget->allocation.x + widget->allocation.width
488             - (widget->requisition.width - misc->xpad * 2)) *
489            misc->xalign) + 0.5;
490       y = (widget->allocation.y * (1.0 - misc->yalign) +
491            (widget->allocation.y + widget->allocation.height
492             - (widget->requisition.height - misc->ypad * 2)) *
493            misc->yalign) + 0.5;
494
495       image_bound.x = x;
496       image_bound.y = y;      
497
498       switch (image->storage_type)
499         {
500         case GTK_IMAGE_PIXMAP:
501           mask = image->data.pixmap.mask;
502           gdk_drawable_get_size (image->data.pixmap.pixmap,
503                                  &image_bound.width,
504                                  &image_bound.height);
505           break;
506
507         case GTK_IMAGE_IMAGE:
508           mask = image->data.image.mask;
509           image_bound.width = image->data.image.image->width;
510           image_bound.height = image->data.image.image->height;
511           break;
512
513         case GTK_IMAGE_PIXBUF:
514           image_bound.width = gdk_pixbuf_get_width (image->data.pixbuf.pixbuf);
515           image_bound.height = gdk_pixbuf_get_height (image->data.pixbuf.pixbuf);
516           break;
517
518         case GTK_IMAGE_STOCK:
519           stock_pixbuf = gtk_widget_render_stock_icon (widget,
520                                                        image->data.stock.stock_id,
521                                                        image->data.stock.size,
522                                                        NULL);
523           if (stock_pixbuf)
524             {              
525               image_bound.width = gdk_pixbuf_get_width (stock_pixbuf);
526               image_bound.height = gdk_pixbuf_get_height (stock_pixbuf);
527             }
528           break;
529
530         case GTK_IMAGE_ICON_SET:
531           stock_pixbuf =
532             gtk_icon_set_render_icon (image->data.icon_set.icon_set,
533                                       widget->style,
534                                       gtk_widget_get_direction (widget),
535                                       GTK_WIDGET_STATE (widget),
536                                       image->data.icon_set.size,
537                                       widget,
538                                       NULL);
539
540           if (stock_pixbuf)
541             {
542               image_bound.width = gdk_pixbuf_get_width (stock_pixbuf);
543               image_bound.height = gdk_pixbuf_get_height (stock_pixbuf);
544             }
545           break;
546           
547         default:
548           break;
549         }
550
551       if (mask)
552         {
553           gdk_gc_set_clip_mask (widget->style->black_gc, mask);
554           gdk_gc_set_clip_origin (widget->style->black_gc, x, y);
555         }
556
557       area = event->area;
558       
559       if (gdk_rectangle_intersect (&image_bound, &area, &intersection))
560         {
561
562           switch (image->storage_type)
563             {
564             case GTK_IMAGE_PIXMAP:
565               gdk_draw_drawable (widget->window,
566                                  widget->style->black_gc,
567                                  image->data.pixmap.pixmap,
568                                  image_bound.x - x, image_bound.y - y,
569                                  image_bound.x, image_bound.y,
570                                  image_bound.width, image_bound.height);
571               break;
572               
573             case GTK_IMAGE_IMAGE:
574               gdk_draw_image (widget->window,
575                               widget->style->black_gc,
576                               image->data.image.image,
577                               image_bound.x - x, image_bound.y - y,
578                               image_bound.x, image_bound.y,
579                               image_bound.width, image_bound.height);
580               break;
581
582             case GTK_IMAGE_PIXBUF:
583               gdk_pixbuf_render_to_drawable_alpha (image->data.pixbuf.pixbuf,
584                                                    widget->window,
585                                                    image_bound.x - x,
586                                                    image_bound.y - y,
587                                                    image_bound.x,
588                                                    image_bound.y,
589                                                    image_bound.width, image_bound.height,
590                                                    GDK_PIXBUF_ALPHA_FULL,
591                                                    128,
592                                                    GDK_RGB_DITHER_NORMAL,
593                                                    0, 0);
594               break;
595
596             case GTK_IMAGE_STOCK: /* fall thru */
597             case GTK_IMAGE_ICON_SET:
598               if (stock_pixbuf)
599                 {
600                   gdk_pixbuf_render_to_drawable_alpha (stock_pixbuf,
601                                                        widget->window,
602                                                        image_bound.x - x,
603                                                        image_bound.y - y,
604                                                        image_bound.x - 4,
605                                                        image_bound.y - 4,
606                                                        image_bound.width, image_bound.height,
607                                                        GDK_PIXBUF_ALPHA_FULL,
608                                                        128,
609                                                        GDK_RGB_DITHER_NORMAL,
610                                                        0, 0);
611                   
612                   g_object_unref (G_OBJECT (stock_pixbuf));
613                 }
614               break;
615
616             default:
617               break;
618             }
619         } /* if rectangle intersects */      
620       if (mask)
621         {
622           gdk_gc_set_clip_mask (widget->style->black_gc, NULL);
623           gdk_gc_set_clip_origin (widget->style->black_gc, 0, 0);
624         }
625     } /* if widget is drawable */
626
627   return FALSE;
628 }
629
630 static void
631 gtk_image_clear (GtkImage *image)
632 {
633   switch (image->storage_type)
634     {
635     case GTK_IMAGE_PIXMAP:
636
637       if (image->data.pixmap.pixmap)
638         g_object_unref (G_OBJECT (image->data.pixmap.pixmap));
639
640       if (image->data.pixmap.mask)
641         g_object_unref (G_OBJECT (image->data.pixmap.mask));
642
643       image->data.pixmap.pixmap = NULL;
644       image->data.pixmap.mask = NULL;
645
646       break;
647
648     case GTK_IMAGE_IMAGE:
649
650       if (image->data.image.image)
651         g_object_unref (G_OBJECT (image->data.image.image));
652
653       if (image->data.image.mask)
654         g_object_unref (G_OBJECT (image->data.image.mask));
655
656       image->data.image.image = NULL;
657       image->data.image.mask = NULL;
658
659       break;
660
661     case GTK_IMAGE_PIXBUF:
662
663       if (image->data.pixbuf.pixbuf)
664         g_object_unref (G_OBJECT (image->data.pixbuf.pixbuf));
665
666       image->data.pixbuf.pixbuf = NULL;
667
668       break;
669
670     case GTK_IMAGE_STOCK:
671
672       g_free (image->data.stock.size);
673       g_free (image->data.stock.stock_id);
674
675       image->data.stock.stock_id = NULL;
676       image->data.stock.size = NULL;
677       
678       break;
679
680     case GTK_IMAGE_ICON_SET:
681       if (image->data.icon_set.icon_set)
682         gtk_icon_set_unref (image->data.icon_set.icon_set);
683
684       g_free (image->data.icon_set.size);
685
686       image->data.icon_set.size = NULL;
687       image->data.icon_set.icon_set = NULL;
688       
689       break;
690       
691     case GTK_IMAGE_EMPTY:
692     default:
693       break;
694       
695     }
696
697   image->storage_type = GTK_IMAGE_EMPTY;
698
699   GTK_WIDGET (image)->requisition.width = 0;
700   GTK_WIDGET (image)->requisition.height = 0;
701   
702   if (GTK_WIDGET_VISIBLE (image))
703     gtk_widget_queue_resize (GTK_WIDGET (image));
704 }
705
706 static void
707 gtk_image_size_request (GtkWidget      *widget,
708                         GtkRequisition *requisition)
709 {
710   GtkImage *image;
711   GdkPixbuf *pixbuf = NULL;
712   
713   image = GTK_IMAGE (widget);
714
715   switch (image->storage_type)
716     {
717     case GTK_IMAGE_STOCK:
718       pixbuf = gtk_widget_render_stock_icon (GTK_WIDGET (image),
719                                              image->data.stock.stock_id,
720                                              image->data.stock.size,
721                                              NULL);
722       break;
723
724     case GTK_IMAGE_ICON_SET:
725       pixbuf = gtk_icon_set_render_icon (image->data.icon_set.icon_set,
726                                          widget->style,
727                                          gtk_widget_get_direction (widget),
728                                          GTK_WIDGET_STATE (widget),
729                                          image->data.icon_set.size,
730                                          widget,
731                                          NULL);
732       break;
733       
734     default:
735       break;
736     }
737
738   if (pixbuf)
739     {
740       gtk_image_update_size (image,
741                              gdk_pixbuf_get_width (pixbuf),
742                              gdk_pixbuf_get_height (pixbuf));
743       g_object_unref (G_OBJECT (pixbuf));
744     }
745
746   /* Chain up to default that simply reads current requisition */
747   GTK_WIDGET_CLASS (parent_class)->size_request (widget, requisition);
748 }
749
750 static void
751 gtk_image_update_size (GtkImage *image,
752                        gint      image_width,
753                        gint      image_height)
754 {
755   GTK_WIDGET (image)->requisition.width = image_width + GTK_MISC (image)->xpad * 2;
756   GTK_WIDGET (image)->requisition.height = image_height + GTK_MISC (image)->ypad * 2;
757 }
758
759