]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkimage.c
Move more text widget headers into the private header list
[~andy/gtk] / gtk / gtkimage.c
index 01154d9293fa0ad7e1ce214734869dfc63f1a182..504b2a2e118bb93810428884da1687b69e9af2bb 100644 (file)
 
 #include "gtkcontainer.h"
 #include "gtkimage.h"
+#include "gtkiconfactory.h"
 
+static void gtk_image_class_init   (GtkImageClass  *klass);
+static void gtk_image_init         (GtkImage       *image);
+static gint gtk_image_expose       (GtkWidget      *widget,
+                                    GdkEventExpose *event);
+static void gtk_image_size_request (GtkWidget      *widget,
+                                    GtkRequisition *requisition);
+static void gtk_image_clear        (GtkImage       *image);
+static void gtk_image_update_size  (GtkImage       *image,
+                                    gint            image_width,
+                                    gint            image_height);
 
-static void gtk_image_class_init (GtkImageClass  *klass);
-static void gtk_image_init       (GtkImage       *image);
-static gint gtk_image_expose     (GtkWidget      *widget,
-                                 GdkEventExpose *event);
-
+static gpointer parent_class;
 
 GtkType
 gtk_image_get_type (void)
@@ -64,9 +71,12 @@ gtk_image_class_init (GtkImageClass *class)
 {
   GtkWidgetClass *widget_class;
 
+  parent_class = g_type_class_peek_parent (class);
+  
   widget_class = (GtkWidgetClass*) class;
 
   widget_class->expose_event = gtk_image_expose;
+  widget_class->size_request = gtk_image_size_request;
 }
 
 static void
@@ -74,49 +84,371 @@ gtk_image_init (GtkImage *image)
 {
   GTK_WIDGET_SET_FLAGS (image, GTK_NO_WINDOW);
 
-  image->image = NULL;
-  image->mask = NULL;
+  image->storage_type = GTK_IMAGE_EMPTY;
 }
 
 GtkWidget*
-gtk_image_new (GdkImage  *val,
-              GdkBitmap *mask)
+gtk_image_new_from_pixmap (GdkPixmap *pixmap,
+                           GdkBitmap *mask)
 {
   GtkImage *image;
 
-  g_return_val_if_fail (val != NULL, NULL);
+  image = gtk_type_new (GTK_TYPE_IMAGE);
+
+  gtk_image_set_from_pixmap (image, pixmap, mask);
+
+  return GTK_WIDGET (image);
+}
+
+GtkWidget*
+gtk_image_new_from_image  (GdkImage  *gdk_image,
+                           GdkBitmap *mask)
+{
+  GtkImage *image;
 
   image = gtk_type_new (GTK_TYPE_IMAGE);
 
-  gtk_image_set (image, val, mask);
+  gtk_image_set_from_image (image, gdk_image, mask);
+
+  return GTK_WIDGET (image);
+}
+
+GtkWidget*
+gtk_image_new_from_file   (const gchar *filename)
+{
+  GtkImage *image;
+
+  image = gtk_type_new (GTK_TYPE_IMAGE);
+
+  gtk_image_set_from_file (image, filename);
+
+  return GTK_WIDGET (image);
+}
+
+GtkWidget*
+gtk_image_new_from_pixbuf (GdkPixbuf *pixbuf)
+{
+  GtkImage *image;
+
+  image = gtk_type_new (GTK_TYPE_IMAGE);
+
+  gtk_image_set_from_pixbuf (image, pixbuf);
+
+  return GTK_WIDGET (image);  
+}
+
+GtkWidget*
+gtk_image_new_from_stock (const gchar    *stock_id,
+                          const gchar    *size)
+{
+  GtkImage *image;
+
+  image = gtk_type_new (GTK_TYPE_IMAGE);
+
+  gtk_image_set_from_stock (image, stock_id, size);
+
+  return GTK_WIDGET (image);
+}
+
+GtkWidget*
+gtk_image_new_from_icon_set (GtkIconSet     *icon_set,
+                             const gchar    *size)
+{
+  GtkImage *image;
+
+  image = gtk_type_new (GTK_TYPE_IMAGE);
+
+  gtk_image_set_from_icon_set (image, icon_set, size);
 
   return GTK_WIDGET (image);
 }
 
 void
-gtk_image_set (GtkImage  *image,
-              GdkImage  *val,
-              GdkBitmap *mask)
+gtk_image_set_from_pixmap (GtkImage  *image,
+                           GdkPixmap *pixmap,
+                           GdkBitmap *mask)
+{
+  g_return_if_fail (GTK_IS_IMAGE (image));
+  g_return_if_fail (pixmap == NULL ||
+                    GDK_IS_PIXMAP (pixmap));
+  g_return_if_fail (mask == NULL ||
+                    GDK_IS_PIXMAP (mask));
+  
+  if (pixmap)
+    g_object_ref (G_OBJECT (pixmap));
+
+  if (mask)
+    g_object_ref (G_OBJECT (mask));
+
+  gtk_image_clear (image);
+
+  if (pixmap)
+    {
+      int width;
+      int height;
+      
+      image->storage_type = GTK_IMAGE_PIXMAP;
+
+      image->data.pixmap.pixmap = pixmap;
+      image->data.pixmap.mask = mask;
+
+      gdk_drawable_get_size (GDK_DRAWABLE (pixmap), &width, &height);
+
+      gtk_image_update_size (image, width, height);
+    }
+  else
+    {
+      /* Clean up the mask if pixmap was NULL */
+      if (mask)
+        g_object_unref (G_OBJECT (mask));
+    }
+}
+
+void
+gtk_image_set_from_image  (GtkImage  *image,
+                           GdkImage  *gdk_image,
+                           GdkBitmap *mask)
 {
-  g_return_if_fail (image != NULL);
   g_return_if_fail (GTK_IS_IMAGE (image));
+  g_return_if_fail (gdk_image == NULL ||
+                    GDK_IS_IMAGE (gdk_image));
+  g_return_if_fail (mask == NULL ||
+                    GDK_IS_PIXMAP (mask));
+
+  
+  if (gdk_image)
+    g_object_ref (G_OBJECT (gdk_image));
+
+  if (mask)
+    g_object_ref (G_OBJECT (mask));
 
-  image->image = val;
-  image->mask = mask;
+  gtk_image_clear (image);
 
-  if (image->image)
+  if (gdk_image)
     {
-      GTK_WIDGET (image)->requisition.width = image->image->width + GTK_MISC (image)->xpad * 2;
-      GTK_WIDGET (image)->requisition.height = image->image->height + GTK_MISC (image)->ypad * 2;
+      image->storage_type = GTK_IMAGE_IMAGE;
+
+      image->data.image.image = gdk_image;
+      image->data.image.mask = mask;
+
+      gtk_image_update_size (image, gdk_image->width, gdk_image->height);
     }
   else
     {
-      GTK_WIDGET (image)->requisition.width = 0;
-      GTK_WIDGET (image)->requisition.height = 0;
+      /* Clean up the mask if gdk_image was NULL */
+      if (mask)
+        g_object_unref (G_OBJECT (mask));
     }
+}
 
-  if (GTK_WIDGET_VISIBLE (image))
-    gtk_widget_queue_resize (GTK_WIDGET (image));
+void
+gtk_image_set_from_file   (GtkImage    *image,
+                           const gchar *filename)
+{
+  GdkPixbuf *pixbuf;
+  
+  g_return_if_fail (GTK_IS_IMAGE (image));
+  g_return_if_fail (filename != NULL);
+  
+  gtk_image_clear (image);
+
+  if (filename == NULL)
+    return;
+  
+  pixbuf = gdk_pixbuf_new_from_file (filename);
+
+  if (pixbuf == NULL)
+    return;
+
+  gtk_image_set_from_pixbuf (image, pixbuf);
+
+  g_object_unref (G_OBJECT (pixbuf));
+}
+
+void
+gtk_image_set_from_pixbuf (GtkImage  *image,
+                           GdkPixbuf *pixbuf)
+{
+  g_return_if_fail (GTK_IS_IMAGE (image));
+  g_return_if_fail (pixbuf == NULL ||
+                    GDK_IS_PIXBUF (pixbuf));
+  
+  if (pixbuf)
+    g_object_ref (G_OBJECT (pixbuf));
+
+  gtk_image_clear (image);
+
+  if (pixbuf != NULL)
+    {
+      image->storage_type = GTK_IMAGE_PIXBUF;
+
+      image->data.pixbuf.pixbuf = pixbuf;
+
+      gtk_image_update_size (image,
+                             gdk_pixbuf_get_width (pixbuf),
+                             gdk_pixbuf_get_height (pixbuf));
+    }
+}
+
+void
+gtk_image_set_from_stock  (GtkImage       *image,
+                           const gchar    *stock_id,
+                           const gchar    *size)
+{
+  g_return_if_fail (GTK_IS_IMAGE (image));
+  
+  gtk_image_clear (image);
+
+  if (stock_id)
+    {      
+      image->storage_type = GTK_IMAGE_STOCK;
+      
+      image->data.stock.stock_id = g_strdup (stock_id);
+      image->data.stock.size = g_strdup (size);
+
+      /* Size is demand-computed in size request method
+       * if we're a stock image, since changing the
+       * style impacts the size request
+       */
+    }
+}
+
+void
+gtk_image_set_from_icon_set  (GtkImage       *image,
+                              GtkIconSet     *icon_set,
+                              const gchar    *size)
+{
+  g_return_if_fail (GTK_IS_IMAGE (image));
+
+  if (icon_set)
+    gtk_icon_set_ref (icon_set);
+  
+  gtk_image_clear (image);
+
+  if (icon_set)
+    {      
+      image->storage_type = GTK_IMAGE_ICON_SET;
+      
+      image->data.icon_set.icon_set = icon_set;
+      image->data.icon_set.size = g_strdup (size);
+
+      /* Size is demand-computed in size request method
+       * if we're an icon set
+       */
+    }
+}
+
+GtkImageType
+gtk_image_get_storage_type (GtkImage *image)
+{
+  g_return_val_if_fail (GTK_IS_IMAGE (image), GTK_IMAGE_EMPTY);
+
+  return image->storage_type;
+}
+
+void
+gtk_image_get_pixmap (GtkImage   *image,
+                      GdkPixmap **pixmap,
+                      GdkBitmap **mask)
+{
+  g_return_if_fail (GTK_IS_IMAGE (image)); 
+  g_return_if_fail (image->storage_type == GTK_IMAGE_PIXMAP ||
+                    image->storage_type == GTK_IMAGE_EMPTY);
+  
+  if (pixmap)
+    *pixmap = image->data.pixmap.pixmap;
+  
+  if (mask)
+    *mask = image->data.pixmap.mask;
+}
+
+void
+gtk_image_get_image  (GtkImage   *image,
+                      GdkImage  **gdk_image,
+                      GdkBitmap **mask)
+{
+  g_return_if_fail (GTK_IS_IMAGE (image));
+  g_return_if_fail (image->storage_type == GTK_IMAGE_IMAGE ||
+                    image->storage_type == GTK_IMAGE_EMPTY);
+
+  if (gdk_image)
+    *gdk_image = image->data.image.image;
+  
+  if (mask)
+    *mask = image->data.image.mask;
+}
+
+GdkPixbuf*
+gtk_image_get_pixbuf (GtkImage *image)
+{
+  g_return_val_if_fail (GTK_IS_IMAGE (image), NULL);
+  g_return_val_if_fail (image->storage_type == GTK_IMAGE_PIXBUF ||
+                        image->storage_type == GTK_IMAGE_EMPTY, NULL);
+
+  if (image->storage_type == GTK_IMAGE_EMPTY)
+    image->data.pixbuf.pixbuf = NULL;
+  
+  return image->data.pixbuf.pixbuf;
+}
+
+void
+gtk_image_get_stock  (GtkImage        *image,
+                      gchar          **stock_id,
+                      gchar          **size)
+{
+  g_return_if_fail (GTK_IS_IMAGE (image));
+  g_return_if_fail (image->storage_type == GTK_IMAGE_STOCK ||
+                    image->storage_type == GTK_IMAGE_EMPTY);
+
+  if (image->storage_type == GTK_IMAGE_EMPTY)
+    image->data.stock.stock_id = NULL;
+  
+  if (stock_id)
+    *stock_id = g_strdup (image->data.stock.stock_id);
+
+  if (size)
+    *size = image->data.stock.size;
+}
+
+void
+gtk_image_get_icon_set  (GtkImage        *image,
+                         GtkIconSet     **icon_set,
+                         gchar          **size)
+{
+  g_return_if_fail (GTK_IS_IMAGE (image));
+  g_return_if_fail (image->storage_type == GTK_IMAGE_ICON_SET ||
+                    image->storage_type == GTK_IMAGE_EMPTY);
+      
+  if (icon_set)    
+    *icon_set = image->data.icon_set.icon_set;
+
+  if (size)
+    *size = g_strdup (image->data.icon_set.size);
+}
+
+GtkWidget*
+gtk_image_new (GdkImage  *val,
+              GdkBitmap *mask)
+{
+  GtkImage *image;
+
+  g_return_val_if_fail (val != NULL, NULL);
+
+  image = gtk_type_new (GTK_TYPE_IMAGE);
+
+  gtk_image_set (image, val, mask);
+
+  return GTK_WIDGET (image);
+}
+
+void
+gtk_image_set (GtkImage  *image,
+              GdkImage  *val,
+              GdkBitmap *mask)
+{
+  g_return_if_fail (GTK_IS_IMAGE (image));
+
+  gtk_image_set_from_image (image, val, mask);
 }
 
 void
@@ -124,13 +456,9 @@ gtk_image_get (GtkImage   *image,
               GdkImage  **val,
               GdkBitmap **mask)
 {
-  g_return_if_fail (image != NULL);
   g_return_if_fail (GTK_IS_IMAGE (image));
 
-  if (val)
-    *val = image->image;
-  if (mask)
-    *mask = image->mask;
+  gtk_image_get_image (image, val, mask);
 }
 
 
@@ -141,13 +469,16 @@ gtk_image_expose (GtkWidget      *widget,
   g_return_val_if_fail (widget != NULL, FALSE);
   g_return_val_if_fail (GTK_IS_IMAGE (widget), FALSE);
   g_return_val_if_fail (event != NULL, FALSE);
-
-  if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget))
+  
+  if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget) &&
+      GTK_IMAGE (widget)->storage_type != GTK_IMAGE_EMPTY)
     {
       GtkImage *image;
       GtkMisc *misc;
       GdkRectangle area, image_bound, intersection;
       gint x, y;
+      GdkBitmap *mask = NULL;
+      GdkPixbuf *stock_pixbuf = NULL;
       
       image = GTK_IMAGE (widget);
       misc = GTK_MISC (widget);
@@ -161,35 +492,265 @@ gtk_image_expose (GtkWidget      *widget,
            - (widget->requisition.height - misc->ypad * 2)) *
           misc->yalign) + 0.5;
 
-      if (image->mask)
+      image_bound.x = x;
+      image_bound.y = y;      
+
+      switch (image->storage_type)
+        {
+        case GTK_IMAGE_PIXMAP:
+          mask = image->data.pixmap.mask;
+          gdk_drawable_get_size (image->data.pixmap.pixmap,
+                                 &image_bound.width,
+                                 &image_bound.height);
+          break;
+
+        case GTK_IMAGE_IMAGE:
+          mask = image->data.image.mask;
+          image_bound.width = image->data.image.image->width;
+          image_bound.height = image->data.image.image->height;
+          break;
+
+        case GTK_IMAGE_PIXBUF:
+          image_bound.width = gdk_pixbuf_get_width (image->data.pixbuf.pixbuf);
+          image_bound.height = gdk_pixbuf_get_height (image->data.pixbuf.pixbuf);
+          break;
+
+        case GTK_IMAGE_STOCK:
+          stock_pixbuf = gtk_widget_render_stock_icon (widget,
+                                                       image->data.stock.stock_id,
+                                                       image->data.stock.size,
+                                                       NULL);
+
+          if (stock_pixbuf)
+            {
+              image_bound.width = gdk_pixbuf_get_width (stock_pixbuf);
+              image_bound.height = gdk_pixbuf_get_height (stock_pixbuf);
+            }
+          break;
+
+        case GTK_IMAGE_ICON_SET:
+          stock_pixbuf =
+            gtk_icon_set_render_icon (image->data.icon_set.icon_set,
+                                      widget->style,
+                                      gtk_widget_get_direction (widget),
+                                      GTK_WIDGET_STATE (widget),
+                                      image->data.icon_set.size,
+                                      widget,
+                                      NULL);
+
+          if (stock_pixbuf)
+            {
+              image_bound.width = gdk_pixbuf_get_width (stock_pixbuf);
+              image_bound.height = gdk_pixbuf_get_height (stock_pixbuf);
+            }
+          break;
+          
+        default:
+          break;
+        }
+
+      if (mask)
        {
-         gdk_gc_set_clip_mask (widget->style->black_gc, image->mask);
+         gdk_gc_set_clip_mask (widget->style->black_gc, mask);
          gdk_gc_set_clip_origin (widget->style->black_gc, x, y);
        }
 
-      image_bound.x = x;
-      image_bound.y = y;      
-      image_bound.width = image->image->width;
-      image_bound.height = image->image->height;      
-
       area = event->area;
       
-      if(gdk_rectangle_intersect(&image_bound, &area, &intersection))
+      if (gdk_rectangle_intersect (&image_bound, &area, &intersection))
         {
-          gdk_draw_image (widget->window,
-                          widget->style->black_gc,
-                          image->image,
-                          image_bound.x - x, image_bound.y - y,
-                          image_bound.x, image_bound.y,
-                          image_bound.width, image_bound.height);
+
+          switch (image->storage_type)
+            {
+            case GTK_IMAGE_PIXMAP:
+              gdk_draw_drawable (widget->window,
+                                 widget->style->black_gc,
+                                 image->data.pixmap.pixmap,
+                                 image_bound.x - x, image_bound.y - y,
+                                 image_bound.x, image_bound.y,
+                                 image_bound.width, image_bound.height);
+              break;
+              
+            case GTK_IMAGE_IMAGE:
+              gdk_draw_image (widget->window,
+                              widget->style->black_gc,
+                              image->data.image.image,
+                              image_bound.x - x, image_bound.y - y,
+                              image_bound.x, image_bound.y,
+                              image_bound.width, image_bound.height);
+              break;
+
+            case GTK_IMAGE_PIXBUF:
+              gdk_pixbuf_render_to_drawable_alpha (image->data.pixbuf.pixbuf,
+                                                   widget->window,
+                                                   image_bound.x - x, image_bound.y - y,
+                                                   image_bound.x, image_bound.y,
+                                                   image_bound.width, image_bound.height,
+                                                   GDK_PIXBUF_ALPHA_FULL,
+                                                   128,
+                                                   GDK_RGB_DITHER_NORMAL,
+                                                   0, 0);
+              break;
+
+            case GTK_IMAGE_STOCK: /* fall thru */
+            case GTK_IMAGE_ICON_SET:
+              if (stock_pixbuf)
+                {
+                  gdk_pixbuf_render_to_drawable_alpha (stock_pixbuf,
+                                                       widget->window,
+                                                       image_bound.x - x, image_bound.y - y,
+                                                       image_bound.x, image_bound.y,
+                                                       image_bound.width, image_bound.height,
+                                                       GDK_PIXBUF_ALPHA_FULL,
+                                                       128,
+                                                       GDK_RGB_DITHER_NORMAL,
+                                                       0, 0);
+                  
+                  g_object_unref (G_OBJECT (stock_pixbuf));
+                }
+              break;
+
+            default:
+              break;
+            }
+        } /* if rectangle intersects */      
+      if (mask)
+        {
+          gdk_gc_set_clip_mask (widget->style->black_gc, NULL);
+          gdk_gc_set_clip_origin (widget->style->black_gc, 0, 0);
         }
+    } /* if widget is drawable */
+
+  return FALSE;
+}
+
+static void
+gtk_image_clear (GtkImage *image)
+{
+  switch (image->storage_type)
+    {
+    case GTK_IMAGE_PIXMAP:
+
+      if (image->data.pixmap.pixmap)
+        g_object_unref (G_OBJECT (image->data.pixmap.pixmap));
+
+      if (image->data.pixmap.mask)
+        g_object_unref (G_OBJECT (image->data.pixmap.mask));
+
+      image->data.pixmap.pixmap = NULL;
+      image->data.pixmap.mask = NULL;
+
+      break;
+
+    case GTK_IMAGE_IMAGE:
+
+      if (image->data.image.image)
+        g_object_unref (G_OBJECT (image->data.image.image));
+
+      if (image->data.image.mask)
+        g_object_unref (G_OBJECT (image->data.image.mask));
+
+      image->data.image.image = NULL;
+      image->data.image.mask = NULL;
+
+      break;
+
+    case GTK_IMAGE_PIXBUF:
+
+      if (image->data.pixbuf.pixbuf)
+        g_object_unref (G_OBJECT (image->data.pixbuf.pixbuf));
+
+      image->data.pixbuf.pixbuf = NULL;
+
+      break;
+
+    case GTK_IMAGE_STOCK:
+
+      g_free (image->data.stock.size);
+      g_free (image->data.stock.stock_id);
+
+      image->data.stock.stock_id = NULL;
+      image->data.stock.size = NULL;
+      
+      break;
+
+    case GTK_IMAGE_ICON_SET:
+      if (image->data.icon_set.icon_set)
+        gtk_icon_set_unref (image->data.icon_set.icon_set);
+
+      g_free (image->data.icon_set.size);
+
+      image->data.icon_set.size = NULL;
+      image->data.icon_set.icon_set = NULL;
+      
+      break;
+      
+    case GTK_IMAGE_EMPTY:
+    default:
+      break;
       
-      if (image->mask)
-       {
-         gdk_gc_set_clip_mask (widget->style->black_gc, NULL);
-         gdk_gc_set_clip_origin (widget->style->black_gc, 0, 0);
-       }
     }
 
-  return FALSE;
+  image->storage_type = GTK_IMAGE_EMPTY;
+
+  GTK_WIDGET (image)->requisition.width = 0;
+  GTK_WIDGET (image)->requisition.height = 0;
+  
+  if (GTK_WIDGET_VISIBLE (image))
+    gtk_widget_queue_resize (GTK_WIDGET (image));
+}
+
+static void
+gtk_image_size_request (GtkWidget      *widget,
+                        GtkRequisition *requisition)
+{
+  GtkImage *image;
+  GdkPixbuf *pixbuf = NULL;
+  
+  image = GTK_IMAGE (widget);
+
+  switch (image->storage_type)
+    {
+    case GTK_IMAGE_STOCK:
+      pixbuf = gtk_widget_render_stock_icon (GTK_WIDGET (image),
+                                             image->data.stock.stock_id,
+                                             image->data.stock.size,
+                                             NULL);
+      break;
+
+    case GTK_IMAGE_ICON_SET:
+      pixbuf = gtk_icon_set_render_icon (image->data.icon_set.icon_set,
+                                         widget->style,
+                                         gtk_widget_get_direction (widget),
+                                         GTK_WIDGET_STATE (widget),
+                                         image->data.icon_set.size,
+                                         widget,
+                                         NULL);
+      break;
+      
+    default:
+      break;
+    }
+
+  if (pixbuf)
+    {
+      gtk_image_update_size (image,
+                             gdk_pixbuf_get_width (pixbuf),
+                             gdk_pixbuf_get_height (pixbuf));
+      g_object_unref (G_OBJECT (pixbuf));
+    }
+
+  /* Chain up to default that simply reads current requisition */
+  GTK_WIDGET_CLASS (parent_class)->size_request (widget, requisition);
 }
+
+static void
+gtk_image_update_size (GtkImage *image,
+                       gint      image_width,
+                       gint      image_height)
+{
+  GTK_WIDGET (image)->requisition.width = image_width + GTK_MISC (image)->xpad * 2;
+  GTK_WIDGET (image)->requisition.height = image_height + GTK_MISC (image)->ypad * 2;
+}
+
+