]> Pileus Git - ~andy/gtk/blobdiff - gdk/x11/gdkpixmap-x11.c
Merges from gtk-1-2
[~andy/gtk] / gdk / x11 / gdkpixmap-x11.c
index 799bd8d462192f57598cf92771d2cae2c26183ab..45807cb6136ceb6051577fc62afb7c92448634fd 100644 (file)
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
-#include "../config.h"
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "config.h"
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -24,8 +32,9 @@
 #include <unistd.h>
 #include <X11/Xlib.h>
 
-#include "gdk.h"
+#include "gdkpixmap.h"
 #include "gdkprivate.h"
+#include "gdkx.h"
 
 typedef struct
 {
@@ -34,6 +43,51 @@ typedef struct
   gint transparent;
 } _GdkPixmapColor;
 
+typedef struct
+{
+  guint ncolors;
+  GdkColormap *colormap;
+  gulong pixels[1];
+} _GdkPixmapInfo;
+
+GdkDrawableClass _gdk_x11_pixmap_class;
+
+static void
+gdk_x11_pixmap_destroy (GdkPixmap *pixmap)
+{
+  XFreePixmap (GDK_DRAWABLE_XDISPLAY (pixmap), GDK_DRAWABLE_XID (pixmap));
+  gdk_xid_table_remove (GDK_DRAWABLE_XID (pixmap));
+
+  g_free (GDK_DRAWABLE_XDATA (pixmap));
+}
+
+static GdkDrawable *
+gdk_x11_pixmap_alloc (void)
+{
+  GdkDrawable *drawable;
+  GdkDrawablePrivate *private;
+  
+  static GdkDrawableClass klass;
+  static gboolean initialized = FALSE;
+
+  if (!initialized)
+    {
+      initialized = TRUE;
+      
+      klass = _gdk_x11_drawable_class;
+      klass.destroy = gdk_x11_pixmap_destroy;
+    }
+
+  drawable = gdk_drawable_alloc ();
+  private = (GdkDrawablePrivate *)drawable;
+
+  private->klass = &klass;
+  private->klass_data = g_new (GdkDrawableXData, 1);
+  private->window_type = GDK_DRAWABLE_PIXMAP;
+
+  return drawable;
+}
+
 GdkPixmap*
 gdk_pixmap_new (GdkWindow *window,
                gint       width,
@@ -41,100 +95,84 @@ gdk_pixmap_new (GdkWindow *window,
                gint       depth)
 {
   GdkPixmap *pixmap;
-  GdkWindowPrivate *private;
-  GdkWindowPrivate *window_private;
+  GdkDrawablePrivate *private;
 
+  g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
   g_return_val_if_fail ((window != NULL) || (depth != -1), NULL);
   g_return_val_if_fail ((width != 0) && (height != 0), NULL);
-
+  
   if (!window)
-    window = (GdkWindow*) &gdk_root_parent;
+    window = gdk_parent_root;
 
-  window_private = (GdkWindowPrivate*) window;
-  if (window_private->destroyed)
+  if (GDK_DRAWABLE_DESTROYED (window))
     return NULL;
 
   if (depth == -1)
-    depth = gdk_window_get_visual (window)->depth;
-
-  private = g_new (GdkWindowPrivate, 1);
-  pixmap = (GdkPixmap*) private;
-
-  private->xdisplay = window_private->xdisplay;
-  private->window_type = GDK_WINDOW_PIXMAP;
-  private->xwindow = XCreatePixmap (private->xdisplay, window_private->xwindow,
-                                   width, height, depth);
-  private->colormap = NULL;
-  private->parent = NULL;
-  private->x = 0;
-  private->y = 0;
+    depth = gdk_drawable_get_visual (window)->depth;
+
+  pixmap = gdk_x11_pixmap_alloc ();
+  private = (GdkDrawablePrivate *)pixmap;
+
+  GDK_DRAWABLE_XDATA (private)->xdisplay = GDK_DRAWABLE_XDISPLAY (window);
+  GDK_DRAWABLE_XDATA (private)->xid = XCreatePixmap (GDK_DRAWABLE_XDISPLAY (pixmap),
+                                                    GDK_DRAWABLE_XID (window),
+                                                    width, height, depth);
   private->width = width;
   private->height = height;
-  private->resize_count = 0;
-  private->ref_count = 1;
-  private->destroyed = 0;
 
-  gdk_xid_table_insert (&private->xwindow, pixmap);
+  gdk_xid_table_insert (&GDK_DRAWABLE_XID (pixmap), pixmap);
 
   return pixmap;
 }
 
 GdkPixmap *
-gdk_bitmap_create_from_data (GdkWindow *window,
-                            gchar     *data,
-                            gint       width,
-                            gint       height)
+gdk_bitmap_create_from_data (GdkWindow   *window,
+                            const gchar *data,
+                            gint         width,
+                            gint         height)
 {
   GdkPixmap *pixmap;
-  GdkWindowPrivate *private;
-  GdkWindowPrivate *window_private;
+  GdkDrawablePrivate *private;
 
   g_return_val_if_fail (data != NULL, NULL);
   g_return_val_if_fail ((width != 0) && (height != 0), NULL);
+  g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
 
   if (!window)
-    window = (GdkWindow*) &gdk_root_parent;
+    window = gdk_parent_root;
 
-  window_private = (GdkWindowPrivate*) window;
-  if (window_private->destroyed)
+  if (GDK_DRAWABLE_DESTROYED (window))
     return NULL;
 
-  private = g_new (GdkWindowPrivate, 1);
-  pixmap = (GdkPixmap*) private;
+  pixmap = gdk_x11_pixmap_alloc ();
+  private = (GdkDrawablePrivate *)pixmap;
 
-  private->parent = NULL;
-  private->xdisplay = window_private->xdisplay;
-  private->window_type = GDK_WINDOW_PIXMAP;
-  private->x = 0;
-  private->y = 0;
   private->width = width;
   private->height = height;
-  private->resize_count = 0;
-  private->ref_count = 1;
-  private->destroyed = FALSE;
 
-  private->xwindow = XCreateBitmapFromData (private->xdisplay,
-                                           window_private->xwindow,
-                                           data, width, height);
+  GDK_DRAWABLE_XDATA (private)->xdisplay = GDK_DRAWABLE_XDISPLAY (window);
+  GDK_DRAWABLE_XDATA (private)->xid = XCreateBitmapFromData (GDK_DRAWABLE_XDISPLAY (window),
+                                                            GDK_DRAWABLE_XID (window),
+                                                            (char *)data, width, height);
 
-  gdk_xid_table_insert (&private->xwindow, pixmap);
+  gdk_xid_table_insert (&GDK_DRAWABLE_XID (pixmap), pixmap);
 
   return pixmap;
 }
 
 GdkPixmap*
-gdk_pixmap_create_from_data (GdkWindow *window,
-                            gchar     *data,
-                            gint       width,
-                            gint       height,
-                            gint       depth,
-                            GdkColor  *fg,
-                            GdkColor  *bg)
+gdk_pixmap_create_from_data (GdkWindow   *window,
+                            const gchar *data,
+                            gint         width,
+                            gint         height,
+                            gint         depth,
+                            GdkColor    *fg,
+                            GdkColor    *bg)
 {
   GdkPixmap *pixmap;
-  GdkWindowPrivate *private;
-  GdkWindowPrivate *window_private;
+  GdkDrawablePrivate *private;
 
+  g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
   g_return_val_if_fail (data != NULL, NULL);
   g_return_val_if_fail (fg != NULL, NULL);
   g_return_val_if_fail (bg != NULL, NULL);
@@ -142,64 +180,58 @@ gdk_pixmap_create_from_data (GdkWindow *window,
   g_return_val_if_fail ((width != 0) && (height != 0), NULL);
 
   if (!window)
-    window = (GdkWindow*) &gdk_root_parent;
+    window = gdk_parent_root;
 
-  window_private = (GdkWindowPrivate*) window;
-  if (window_private->destroyed)
+  if (GDK_DRAWABLE_DESTROYED (window))
     return NULL;
 
   if (depth == -1)
-    depth = gdk_window_get_visual (window)->depth;
+    depth = gdk_drawable_get_visual (window)->depth;
 
-  private = g_new (GdkWindowPrivate, 1);
-  pixmap = (GdkPixmap*) private;
+  pixmap = gdk_x11_pixmap_alloc ();
+  private = (GdkDrawablePrivate *)pixmap;
 
-  private->parent = NULL;
-  private->xdisplay = window_private->xdisplay;
-  private->window_type = GDK_WINDOW_PIXMAP;
-  private->x = 0;
-  private->y = 0;
   private->width = width;
   private->height = height;
-  private->resize_count = 0;
-  private->ref_count = 1;
-  private->destroyed = FALSE;
 
-  private->xwindow = XCreatePixmapFromBitmapData (private->xdisplay,
-                                                 window_private->xwindow,
-                                                 data, width, height,
-                                                 fg->pixel, bg->pixel, depth);
+  GDK_DRAWABLE_XDATA (private)->xdisplay = GDK_DRAWABLE_XDISPLAY (window);
+  GDK_DRAWABLE_XDATA (private)->xid = XCreatePixmapFromBitmapData (GDK_DRAWABLE_XDISPLAY (window),
+                                                                  GDK_DRAWABLE_XID (window),
+                                                                  (char *)data, width, height,
+                                                                  fg->pixel, bg->pixel, depth);
 
-  gdk_xid_table_insert (&private->xwindow, pixmap);
+  gdk_xid_table_insert (&GDK_DRAWABLE_XID (pixmap), pixmap);
 
   return pixmap;
 }
 
-gint
+static gint
 gdk_pixmap_seek_string (FILE  *infile,
                         const gchar *str,
                         gint   skip_comments)
 {
   char instr[1024];
 
-  while (!feof (infile))
+  while (1)
     {
-      fscanf (infile, "%1023s", instr);
+      if (fscanf (infile, "%1023s", instr) != 1)
+       return FALSE;
+         
       if (skip_comments == TRUE && strcmp (instr, "/*") == 0)
         {
-          fscanf (infile, "%1023s", instr);
-          while (!feof (infile) && strcmp (instr, "*/") != 0)
-            fscanf (infile, "%1023s", instr);
-          fscanf(infile, "%1023s", instr);
+         do
+           {
+             if (fscanf (infile, "%1023s", instr) != 1)
+               return FALSE;
+           }
+         while (strcmp (instr, "*/") != 0);
         }
-      if (strcmp (instr, str)==0)
+      else if (strcmp (instr, str) == 0)
         return TRUE;
     }
-
-  return FALSE;
 }
 
-gint
+static gint
 gdk_pixmap_seek_char (FILE  *infile,
                       gchar  c)
 {
@@ -231,7 +263,7 @@ gdk_pixmap_seek_char (FILE  *infile,
   return FALSE;
 }
 
-gint
+static gint
 gdk_pixmap_read_string (FILE  *infile,
                         gchar **buffer,
                        guint *buffer_size)
@@ -286,7 +318,7 @@ gdk_pixmap_read_string (FILE  *infile,
   return ret;
 }
 
-gchar*
+static gchar*
 gdk_pixmap_skip_whitespaces (gchar *buffer)
 {
   gint32 index = 0;
@@ -297,7 +329,7 @@ gdk_pixmap_skip_whitespaces (gchar *buffer)
   return &buffer[index];
 }
 
-gchar*
+static gchar*
 gdk_pixmap_skip_string (gchar *buffer)
 {
   gint32 index = 0;
@@ -311,7 +343,7 @@ gdk_pixmap_skip_string (gchar *buffer)
 /* Xlib crashed ince at a color name lengths around 125 */
 #define MAX_COLOR_LEN 120
 
-gchar*
+static gchar*
 gdk_pixmap_extract_color (gchar *buffer)
 {
   gint counter, numnames;
@@ -388,13 +420,6 @@ gdk_pixmap_extract_color (gchar *buffer)
   return retcol;
 }
 
-static void
-free_color (gpointer key, gpointer value, gpointer user_data)
-{
-  g_free (key);
-  g_free (value);
-}
-  
 
 enum buffer_op
 {
@@ -403,6 +428,23 @@ enum buffer_op
   op_body
 };
   
+
+static void 
+gdk_xpm_destroy_notify (gpointer data)
+{
+  _GdkPixmapInfo *info = (_GdkPixmapInfo *)data;
+  GdkColor color;
+  int i;
+
+  for (i=0; i<info->ncolors; i++)
+    {
+      color.pixel = info->pixels[i];
+      gdk_colormap_free_colors (info->colormap, &color, 1);
+    }
+
+  gdk_colormap_unref (info->colormap);
+  g_free (info);
+}
   
 static GdkPixmap *
 _gdk_pixmap_create_from_xpm (GdkWindow  *window,
@@ -420,20 +462,23 @@ _gdk_pixmap_create_from_xpm (GdkWindow  *window,
   GdkColor tmp_color;
   gint width, height, num_cols, cpp, n, ns, cnt, xcnt, ycnt, wbytes;
   gchar *buffer, pixel_str[32];
+  gchar *name_buf;
   _GdkPixmapColor *color = NULL, *fallbackcolor = NULL;
+  _GdkPixmapColor *colors = NULL;
   gulong index;
-  GHashTable *colors = NULL;
+  GHashTable *color_hash = NULL;
+  _GdkPixmapInfo *color_info = NULL;
   
   if ((window == NULL) && (colormap == NULL))
     g_warning ("Creating pixmap from xpm with NULL window and colormap");
   
   if (window == NULL)
-    window = (GdkWindow *)&gdk_root_parent;
+    window = gdk_parent_root;
   
   if (colormap == NULL)
     {
-      colormap = gdk_window_get_colormap (window);
-      visual = gdk_window_get_visual (window);
+      colormap = gdk_drawable_get_colormap (window);
+      visual = gdk_drawable_get_visual (window);
     }
   else
     visual = ((GdkColormapPrivate *)colormap)->visual;
@@ -449,14 +494,30 @@ _gdk_pixmap_create_from_xpm (GdkWindow  *window,
       return NULL;
     }
   
-  colors = g_hash_table_new (g_str_hash, g_str_equal);
+  color_hash = g_hash_table_new (g_str_hash, g_str_equal);
   
   if (transparent_color == NULL)
     {
       gdk_color_white (colormap, &tmp_color);
       transparent_color = &tmp_color;
     }
-  
+
+  /* For pseudo-color and grayscale visuals, we have to remember
+   * the colors we allocated, so we can free them later.
+   */
+  if ((visual->type == GDK_VISUAL_PSEUDO_COLOR) ||
+      (visual->type == GDK_VISUAL_GRAYSCALE))
+    {
+      color_info = g_malloc (sizeof (_GdkPixmapInfo) + 
+                            sizeof(gulong) * (num_cols - 1));
+      color_info->ncolors = num_cols;
+      color_info->colormap = colormap;
+      gdk_colormap_ref (colormap);
+    }
+
+  name_buf = g_new (gchar, num_cols * (cpp+1));
+  colors = g_new (_GdkPixmapColor, num_cols);
+
   for (cnt = 0; cnt < num_cols; cnt++)
     {
       gchar *color_name;
@@ -465,8 +526,8 @@ _gdk_pixmap_create_from_xpm (GdkWindow  *window,
       if (buffer == NULL)
        goto error;
       
-      color = g_new (_GdkPixmapColor, 1);
-      color->color_string = g_new (gchar, cpp + 1);
+      color = &colors[cnt];
+      color->color_string = &name_buf [cnt * (cpp + 1)];
       strncpy (color->color_string, buffer, cpp);
       color->color_string[cpp] = 0;
       buffer += strlen (color->color_string);
@@ -474,7 +535,7 @@ _gdk_pixmap_create_from_xpm (GdkWindow  *window,
       
       color_name = gdk_pixmap_extract_color (buffer);
       
-      if (color_name == NULL ||
+      if (color_name == NULL || g_strcasecmp (color_name, "None") == 0 ||
          gdk_color_parse (color_name, &color->color) == FALSE)
        {
          color->color = *transparent_color;
@@ -486,7 +547,11 @@ _gdk_pixmap_create_from_xpm (GdkWindow  *window,
       /* FIXME: The remaining slowness appears to happen in this
          function. */
       gdk_color_alloc (colormap, &color->color);
-      g_hash_table_insert (colors, color->color_string, color);
+
+      if (color_info)
+       color_info->pixels[cnt] = color->color.pixel;
+      
+      g_hash_table_insert (color_hash, color->color_string, color);
       if (cnt == 0)
        fallbackcolor = color;
     }
@@ -531,7 +596,7 @@ _gdk_pixmap_create_from_xpm (GdkWindow  *window,
          pixel_str[cpp] = 0;
          ns = 0;
          
-         color = g_hash_table_lookup (colors, pixel_str);
+         color = g_hash_table_lookup (color_hash, pixel_str);
          
          if (!color) /* screwed up XPM file */
            color = fallbackcolor;
@@ -553,25 +618,34 @@ _gdk_pixmap_create_from_xpm (GdkWindow  *window,
  error:
   
   if (mask)
-    gdk_gc_destroy (gc);
+    gdk_gc_unref (gc);
   
   if (image != NULL)
     {
       pixmap = gdk_pixmap_new (window, width, height, visual->depth);
+
+      if (color_info)
+       gdk_drawable_set_data (pixmap, "gdk-xpm", color_info, 
+                              gdk_xpm_destroy_notify);
       
       gc = gdk_gc_new (pixmap);
       gdk_gc_set_foreground (gc, transparent_color);
       gdk_draw_image (pixmap, gc, image, 0, 0, 0, 0, image->width, image->height);
-      gdk_gc_destroy (gc);
-      gdk_image_destroy (image);
+      gdk_gc_unref (gc);
+      gdk_image_unref (image);
     }
+  else if (color_info)
+    gdk_xpm_destroy_notify (color_info);
   
+  if (color_hash != NULL)
+    g_hash_table_destroy (color_hash);
+
   if (colors != NULL)
-    {
-      g_hash_table_foreach (colors, free_color, 0);
-      g_hash_table_destroy (colors);
-    }
-  
+    g_free (colors);
+
+  if (name_buf != NULL)
+    g_free (name_buf);
+
   return pixmap;
 }
 
@@ -700,38 +774,38 @@ gdk_pixmap_create_from_xpm_d (GdkWindow  *window,
 }
 
 GdkPixmap*
-gdk_pixmap_ref (GdkPixmap *pixmap)
-{
-  GdkWindowPrivate *private = (GdkWindowPrivate *)pixmap;
-  g_return_val_if_fail (pixmap != NULL, NULL);
-
-  private->ref_count += 1;
-  return pixmap;
-}
-
-void
-gdk_pixmap_unref (GdkPixmap *pixmap)
+gdk_pixmap_foreign_new (guint32 anid)
 {
-  GdkWindowPrivate *private = (GdkWindowPrivate *)pixmap;
-  g_return_if_fail(pixmap != NULL);
+  GdkPixmap *pixmap;
+  GdkDrawablePrivate *private;
+  Pixmap xpixmap;
+  Window root_return;
+  unsigned int x_ret, y_ret, w_ret, h_ret, bw_ret, depth_ret;
+
+  /* check to make sure we were passed something at
+     least a little sane */
+  g_return_val_if_fail((anid != 0), NULL);
+  
+  /* set the pixmap to the passed in value */
+  xpixmap = anid;
+
+  /* get information about the Pixmap to fill in the structure for
+     the gdk window */
+  if (!XGetGeometry(GDK_DISPLAY(),
+                   xpixmap, &root_return,
+                   &x_ret, &y_ret, &w_ret, &h_ret, &bw_ret, &depth_ret))
+      return NULL;
+      
+  pixmap = gdk_x11_pixmap_alloc ();
+  private = (GdkDrawablePrivate *)pixmap;
 
-  private->ref_count -= 1;
-  if (private->ref_count == 0)
-    {
-      XFreePixmap (private->xdisplay, private->xwindow);
-      gdk_xid_table_remove (private->xwindow);
-      g_free (private);
-    }
-}
+  GDK_DRAWABLE_XDATA (private)->xdisplay = GDK_DISPLAY ();
+  GDK_DRAWABLE_XDATA (private)->xid = xpixmap;
 
-GdkBitmap *
-gdk_bitmap_ref (GdkBitmap *bitmap)
-{
-  return (GdkBitmap *)gdk_pixmap_ref ((GdkPixmap *)bitmap);
-}
+  private->width = w_ret;
+  private->height = h_ret;
+  
+  gdk_xid_table_insert(&GDK_DRAWABLE_XID (pixmap), pixmap);
 
-void
-gdk_bitmap_unref (GdkBitmap *bitmap)
-{
-  gdk_pixmap_unref ((GdkPixmap *)bitmap);
+  return pixmap;
 }