Index: gtk/dw.c
===================================================================
--- gtk/dw.c	(revision 3063)
+++ gtk/dw.c	(working copy)
@@ -9221,6 +9221,12 @@
    DW_MUTEX_LOCK;
 #if GTK_MAJOR_VERSION > 1
    pixmap->pixbuf = gdk_pixbuf_new_from_file(file, NULL);
+   if(!pixmap->pixbuf)
+   {
+      free(pixmap);
+      DW_MUTEX_UNLOCK;
+      return NULL;
+   }
    pixmap->width = gdk_pixbuf_get_width(pixmap->pixbuf);
    pixmap->height = gdk_pixbuf_get_height(pixmap->pixbuf);
    gdk_pixbuf_render_pixmap_and_mask(pixmap->pixbuf, &pixmap->pixmap, &pixmap->bitmap, 1);
@@ -9262,7 +9268,7 @@
 #endif
    char template[] = "/tmp/dwpixmapXXXXXX";
 
-   if(!data || !(pixmap = calloc(1,sizeof(struct _hpixmap))))
+   if(!data || len < 1 || !(pixmap = calloc(1,sizeof(struct _hpixmap))))
       return NULL;
 
    DW_MUTEX_LOCK;
@@ -9278,11 +9284,21 @@
    /* Bail if we couldn't write full file */
    if(fd == -1 || written != len)
    {
+      if(fd != -1)
+         unlink(template);
+      free(pixmap);
       DW_MUTEX_UNLOCK;
-      return 0;
+      return NULL;
    }
 #if GTK_MAJOR_VERSION > 1
    pixbuf = gdk_pixbuf_new_from_file(template, NULL);
+   if(!pixbuf)
+   {
+      unlink(template);
+      free(pixmap);
+      DW_MUTEX_UNLOCK;
+      return NULL;
+   }
    pixmap->width = gdk_pixbuf_get_width(pixbuf);
    pixmap->height = gdk_pixbuf_get_height(pixbuf);
    gdk_pixbuf_render_pixmap_and_mask(pixbuf, &pixmap->pixmap, &pixmap->bitmap, 1);
Index: gtk3/dw.c
===================================================================
--- gtk3/dw.c	(revision 3063)
+++ gtk3/dw.c	(working copy)
@@ -8263,11 +8263,29 @@
       return 0;
    }
    pixmap->pixbuf = gdk_pixbuf_new_from_file(template, NULL);
-   pixmap->image = cairo_image_surface_create_from_png(template);
-   pixmap->width = gdk_pixbuf_get_width(pixmap->pixbuf);
-   pixmap->height = gdk_pixbuf_get_height(pixmap->pixbuf);
+   /* Decode once with GdkPixbuf, then create the Cairo drawing surface from
+    * that decoded image.  cairo_image_surface_create_from_png() made the
+    * previous implementation silently PNG-only for drawing even though
+    * GdkPixbuf had successfully decoded GIF, JPEG and other formats. */
+   if(pixmap->pixbuf)
+   {
+      pixmap->image = gdk_cairo_surface_create_from_pixbuf(pixmap->pixbuf, 1, NULL);
+      pixmap->width = gdk_pixbuf_get_width(pixmap->pixbuf);
+      pixmap->height = gdk_pixbuf_get_height(pixmap->pixbuf);
+   }
    /* remove our temporary file */
    unlink(template);
+   if(!pixmap->pixbuf || !pixmap->image ||
+      cairo_surface_status(pixmap->image) != CAIRO_STATUS_SUCCESS)
+   {
+      if(pixmap->pixbuf)
+         g_object_unref(pixmap->pixbuf);
+      if(pixmap->image)
+         cairo_surface_destroy(pixmap->image);
+      free(pixmap);
+      DW_MUTEX_UNLOCK;
+      return NULL;
+   }
    pixmap->handle = handle;
    DW_MUTEX_UNLOCK;
    return pixmap;
Index: gtk4/dw.c
===================================================================
--- gtk4/dw.c	(revision 3063)
+++ gtk4/dw.c	(working copy)
@@ -9026,6 +9026,146 @@
    DW_FUNCTION_RETURN_NOTHING;
 }
 
+/* Internal function to copy a decoded GdkTexture into a new ARGB32 Cairo surface. */
+static cairo_surface_t *_dw_surface_from_texture(GdkTexture *texture)
+{
+   cairo_surface_t *surface;
+
+   if(!texture)
+      return NULL;
+
+   surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+                                        gdk_texture_get_width(texture),
+                                        gdk_texture_get_height(texture));
+   if(cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS)
+   {
+      cairo_surface_destroy(surface);
+      return NULL;
+   }
+   gdk_texture_download(texture, cairo_image_surface_get_data(surface),
+                        cairo_image_surface_get_stride(surface));
+   cairo_surface_mark_dirty(surface);
+   return surface;
+}
+
+/* Internal function to copy a decoded GdkPixbuf into a new ARGB32 Cairo surface.
+ * Converted by hand to a premultiplied native-endian ARGB32 so it does not
+ * depend on any GdkPixbuf/Cairo helper that GTK 4 may deprecate.
+ */
+static cairo_surface_t *_dw_surface_from_pixbuf(GdkPixbuf *pixbuf)
+{
+   cairo_surface_t *surface;
+   const guchar *src;
+   guchar *dst;
+   int x, y, width, height, srcstride, dststride, channels;
+
+   if(!pixbuf || gdk_pixbuf_get_colorspace(pixbuf) != GDK_COLORSPACE_RGB ||
+      gdk_pixbuf_get_bits_per_sample(pixbuf) != 8)
+      return NULL;
+
+   channels = gdk_pixbuf_get_n_channels(pixbuf);
+   if(channels < 3)
+      return NULL;
+
+   width = gdk_pixbuf_get_width(pixbuf);
+   height = gdk_pixbuf_get_height(pixbuf);
+   srcstride = gdk_pixbuf_get_rowstride(pixbuf);
+   src = gdk_pixbuf_read_pixels(pixbuf);
+
+   surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
+   if(cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS)
+   {
+      cairo_surface_destroy(surface);
+      return NULL;
+   }
+   cairo_surface_flush(surface);
+   dst = cairo_image_surface_get_data(surface);
+   dststride = cairo_image_surface_get_stride(surface);
+
+   for(y = 0; y < height; y++)
+   {
+      const guchar *s = src + (size_t)y * srcstride;
+      guint32 *d = (guint32 *)(dst + (size_t)y * dststride);
+
+      for(x = 0; x < width; x++, s += channels)
+      {
+         guint32 a = (channels == 4) ? s[3] : 255;
+         guint32 r = (s[0] * a + 127) / 255;
+         guint32 g = (s[1] * a + 127) / 255;
+         guint32 b = (s[2] * a + 127) / 255;
+
+         d[x] = (a << 24) | (r << 16) | (g << 8) | b;
+      }
+   }
+   cairo_surface_mark_dirty(surface);
+   return surface;
+}
+
+/* Internal function to create a Cairo surface from image data in memory.
+ * GdkTexture is tried first (PNG, JPEG and TIFF are guaranteed), then
+ * gdk-pixbuf is used for anything else it has a loader for (GIF, BMP, ICO,
+ * WebP with webp-pixbuf-loader, ...).  Animations yield the first frame.
+ */
+static cairo_surface_t *_dw_surface_from_memory(const char *data, gsize len)
+{
+   cairo_surface_t *surface = NULL;
+   GBytes *bytes = g_bytes_new(data, len);
+   GdkTexture *texture = gdk_texture_new_from_bytes(bytes, NULL);
+
+   g_bytes_unref(bytes);
+   if(texture)
+   {
+      surface = _dw_surface_from_texture(texture);
+      g_object_unref(G_OBJECT(texture));
+   }
+   else
+   {
+      GdkPixbufLoader *loader = gdk_pixbuf_loader_new();
+
+      if(loader)
+      {
+         GError *error = NULL;
+         gboolean ok = gdk_pixbuf_loader_write(loader, (const guchar *)data, len, &error);
+
+         g_clear_error(&error);
+         /* Always close the loader, even after a failed write */
+         if(!gdk_pixbuf_loader_close(loader, &error))
+            ok = FALSE;
+         g_clear_error(&error);
+         if(ok)
+            surface = _dw_surface_from_pixbuf(gdk_pixbuf_loader_get_pixbuf(loader));
+         g_object_unref(G_OBJECT(loader));
+      }
+   }
+   return surface;
+}
+
+/* Internal function to create a Cairo surface from an image file,
+ * with the same GdkTexture then gdk-pixbuf fallback order.
+ */
+static cairo_surface_t *_dw_surface_from_file(const char *file)
+{
+   cairo_surface_t *surface = NULL;
+   GdkTexture *texture = gdk_texture_new_from_filename(file, NULL);
+
+   if(texture)
+   {
+      surface = _dw_surface_from_texture(texture);
+      g_object_unref(G_OBJECT(texture));
+   }
+   else
+   {
+      GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(file, NULL);
+
+      if(pixbuf)
+      {
+         surface = _dw_surface_from_pixbuf(pixbuf);
+         g_object_unref(G_OBJECT(pixbuf));
+      }
+   }
+   return surface;
+}
+
 /*
  * Creates a pixmap with given parameters.
  * Parameters:
@@ -9078,7 +9218,6 @@
    if(filename && *filename && (pixmap = calloc(1,sizeof(struct _hpixmap))))
    {
       char *file = alloca(strlen(filename) + 6);
-      GdkTexture *texture = NULL;
 
       strcpy(file, filename);
 
@@ -9088,30 +9227,23 @@
          int i = 0;
 
          /* Try with various extentions */
-         while(_dw_image_exts[i] && !texture)
+         while(_dw_image_exts[i] && !pixmap->image)
          {
             strcpy(file, filename);
             strcat(file, _dw_image_exts[i]);
             if(access(file, 04) == 0)
-               texture = gdk_texture_new_from_filename(file, NULL);
+               pixmap->image = _dw_surface_from_file(file);
             i++;
          }
       }
       else
-         texture = gdk_texture_new_from_filename(file, NULL);
+         pixmap->image = _dw_surface_from_file(file);
 
-      if(texture)
+      if(pixmap->image)
       {
-         pixmap->width = gdk_texture_get_width(texture);
-         pixmap->height = gdk_texture_get_height(texture);
-         pixmap->image = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
-                                      pixmap->width,
-                                      pixmap->height);
-         gdk_texture_download(texture, cairo_image_surface_get_data(pixmap->image), 
-                              cairo_image_surface_get_stride(pixmap->image));
-         cairo_surface_mark_dirty(pixmap->image);
+         pixmap->width = cairo_image_surface_get_width(pixmap->image);
+         pixmap->height = cairo_image_surface_get_height(pixmap->image);
          pixmap->handle = handle;
-         g_object_unref(G_OBJECT(texture));
       }
       else
       {
@@ -9141,34 +9273,12 @@
 
    if(data && len > 0 && (pixmap = calloc(1,sizeof(struct _hpixmap))))
    {
-      int fd, written = -1;
-      char template[] = "/tmp/dwpixmapXXXXXX";
-      GdkTexture *texture;
-
-      /*
-       * A real hack; create a temporary file and write the contents
-       * of the data to the file
-       */
-      if((fd = mkstemp(template)) != -1)
+      /* Decode directly from memory, no temporary file required */
+      if((pixmap->image = _dw_surface_from_memory(data, (gsize)len)))
       {
-         written = write(fd, data, len);
-         close(fd);
-      }
-      /* Bail if we couldn't write full file */
-      if(fd != -1 && written == len &&
-         (texture = gdk_texture_new_from_filename(template, NULL)))
-      {
-         pixmap->width = gdk_texture_get_width(texture);
-         pixmap->height = gdk_texture_get_height(texture);
-         pixmap->image = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
-                                                    pixmap->width, pixmap->height);
-         gdk_texture_download(texture, cairo_image_surface_get_data(pixmap->image), 
-                              cairo_image_surface_get_stride(pixmap->image));
-         cairo_surface_mark_dirty(pixmap->image);
-         /* remove our temporary file */
-         unlink(template);
+         pixmap->width = cairo_image_surface_get_width(pixmap->image);
+         pixmap->height = cairo_image_surface_get_height(pixmap->image);
          pixmap->handle = handle;
-         g_object_unref(G_OBJECT(texture));
       }
       else
       {
@@ -9210,15 +9320,20 @@
    if((pixmap = calloc(1,sizeof(struct _hpixmap))))
    {
       GdkTexture *texture = _dw_find_texture((HICN)id, 0, 0);
-      pixmap->width = gdk_texture_get_width(texture);
-      pixmap->height = gdk_texture_get_height(texture);
-      pixmap->image = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
-                                                 pixmap->width, pixmap->height);
-      gdk_texture_download(texture, cairo_image_surface_get_data(pixmap->image), 
-                           cairo_image_surface_get_stride(pixmap->image));
-      cairo_surface_mark_dirty(pixmap->image);
-      pixmap->handle = handle;
-      g_object_unref(G_OBJECT(texture));
+
+      if(texture && (pixmap->image = _dw_surface_from_texture(texture)))
+      {
+         pixmap->width = gdk_texture_get_width(texture);
+         pixmap->height = gdk_texture_get_height(texture);
+         pixmap->handle = handle;
+      }
+      else
+      {
+         free(pixmap);
+         pixmap = 0;
+      }
+      if(texture)
+         g_object_unref(G_OBJECT(texture));
    }
    DW_FUNCTION_RETURN_THIS(pixmap);
 }
