X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gdk%2Fx11%2Fgdkpixmap-x11.c;h=45807cb6136ceb6051577fc62afb7c92448634fd;hb=10ba4fd066042b4335ae45e7560565872f71ba9b;hp=b1eaba214d329e9531c77c62d905793ca38ddef5;hpb=244e4fe4c7faa35b4680703106097012afea47bb;p=~andy%2Fgtk diff --git a/gdk/x11/gdkpixmap-x11.c b/gdk/x11/gdkpixmap-x11.c index b1eaba214..45807cb61 100644 --- a/gdk/x11/gdkpixmap-x11.c +++ b/gdk/x11/gdkpixmap-x11.c @@ -12,10 +12,19 @@ * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * License along with this library; if not, write to the + * 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 #include #include @@ -23,8 +32,9 @@ #include #include -#include "gdk.h" +#include "gdkpixmap.h" #include "gdkprivate.h" +#include "gdkx.h" typedef struct { @@ -33,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, @@ -40,225 +95,230 @@ 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; - if (depth == -1) - gdk_window_get_geometry (window, NULL, NULL, NULL, NULL, &depth); + if (GDK_DRAWABLE_DESTROYED (window)) + return NULL; - private = g_new (GdkWindowPrivate, 1); - pixmap = (GdkPixmap*) private; + if (depth == -1) + depth = gdk_drawable_get_visual (window)->depth; - window_private = (GdkWindowPrivate*) window; + pixmap = gdk_x11_pixmap_alloc (); + private = (GdkDrawablePrivate *)pixmap; - private->xdisplay = window_private->xdisplay; - private->window_type = GDK_WINDOW_PIXMAP; - private->xwindow = XCreatePixmap (private->xdisplay, window_private->xwindow, - width, height, depth); - private->parent = NULL; - private->x = 0; - private->y = 0; + 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; - private = g_new (GdkWindowPrivate, 1); - pixmap = (GdkPixmap*) private; + if (GDK_DRAWABLE_DESTROYED (window)) + return NULL; - window_private = (GdkWindowPrivate*) window; + 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); + 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; - if (depth == -1) - gdk_window_get_geometry (window, NULL, NULL, NULL, NULL, &depth); + if (GDK_DRAWABLE_DESTROYED (window)) + return NULL; - private = g_new (GdkWindowPrivate, 1); - pixmap = (GdkPixmap*) private; + if (depth == -1) + depth = gdk_drawable_get_visual (window)->depth; - window_private = (GdkWindowPrivate*) window; + 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, "%s", instr); + if (fscanf (infile, "%1023s", instr) != 1) + return FALSE; + if (skip_comments == TRUE && strcmp (instr, "/*") == 0) { - fscanf (infile, "%s", instr); - while (!feof (infile) && strcmp (instr, "*/") != 0) - fscanf (infile, "%s", instr); - fscanf(infile, "%s", 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) { - gchar b, oldb; + gint b, oldb; - while (!feof (infile)) + while ((b = getc(infile)) != EOF) { - fscanf(infile, "%c", &b); if (c != b && b == '/') - { - fscanf (infile, "%c", &b); - if (b == '*') - { - oldb = b; - while (!feof (infile) && !(oldb == '*' && b == '/')) - { - oldb = b; - fscanf (infile, "%c", &b); - } - fscanf (infile, "%c", &b); - } + { + b = getc (infile); + if (b == EOF) + return FALSE; + else if (b == '*') /* we have a comment */ + { + b = -1; + do + { + oldb = b; + b = getc (infile); + if (b == EOF) + return FALSE; + } + while (!(oldb == '*' && b == '/')); + } } - if (c == b) - return TRUE; + else if (c == b) + return TRUE; } - return FALSE; } -gint +static gint gdk_pixmap_read_string (FILE *infile, gchar **buffer, - int *buffer_size) + guint *buffer_size) { - gchar c; - gint cnt = 0; + gint c; + guint cnt = 0, bufsiz, ret = FALSE; + gchar *buf; - if ((*buffer) == NULL) + buf = *buffer; + bufsiz = *buffer_size; + if (buf == NULL) { - (*buffer_size) = 10 * sizeof (gchar); - (*buffer) = (gchar *) malloc (*buffer_size); + bufsiz = 10 * sizeof (gchar); + buf = g_new(gchar, bufsiz); } do - fscanf (infile, "%c", &c); - while (!feof (infile) && c != '"'); + c = getc (infile); + while (c != EOF && c != '"'); if (c != '"') - return FALSE; + goto out; - while (!feof (infile)) + while ((c = getc(infile)) != EOF) { - fscanf (infile, "%c", &c); - - if (cnt == (*buffer_size)) + if (cnt == bufsiz) { - (*buffer_size) *= 2; - (*buffer) = (gchar *) realloc ((*buffer), *buffer_size); + guint new_size = bufsiz * 2; + if (new_size > bufsiz) + bufsiz = new_size; + else + goto out; + + buf = (gchar *) g_realloc (buf, bufsiz); + buf[bufsiz-1] = '\0'; } if (c != '"') - (*buffer)[cnt++] = c; + buf[cnt++] = c; else { - (*buffer)[cnt++] = 0; - return TRUE; + buf[cnt] = 0; + ret = TRUE; + break; } } - return FALSE; + out: + buf[bufsiz-1] = '\0'; /* ensure null termination for errors */ + *buffer = buf; + *buffer_size = bufsiz; + return ret; } -gchar* +static gchar* gdk_pixmap_skip_whitespaces (gchar *buffer) { gint32 index = 0; @@ -269,7 +329,7 @@ gdk_pixmap_skip_whitespaces (gchar *buffer) return &buffer[index]; } -gchar* +static gchar* gdk_pixmap_skip_string (gchar *buffer) { gint32 index = 0; @@ -280,12 +340,16 @@ gdk_pixmap_skip_string (gchar *buffer) return &buffer[index]; } -gchar* +/* Xlib crashed ince at a color name lengths around 125 */ +#define MAX_COLOR_LEN 120 + +static gchar* gdk_pixmap_extract_color (gchar *buffer) { - gint counter, finished = FALSE, numnames; + gint counter, numnames; gchar *ptr = NULL, ch, temp[128]; - gchar color[128], *retcol; + gchar color[MAX_COLOR_LEN], *retcol; + gint space; counter = 0; while (ptr == NULL) @@ -302,281 +366,199 @@ gdk_pixmap_extract_color (gchar *buffer) counter++; } - if (ptr == NULL) - return NULL; - ptr = gdk_pixmap_skip_whitespaces (ptr); if (ptr[0] == 0) return NULL; else if (ptr[0] == '#') { - retcol = g_new(gchar, strlen (ptr) + 1); - strcpy (retcol, ptr); + counter = 1; + while (ptr[counter] != 0 && + ((ptr[counter] >= '0' && ptr[counter] <= '9') || + (ptr[counter] >= 'a' && ptr[counter] <= 'f') || + (ptr[counter] >= 'A' && ptr[counter] <= 'F'))) + counter++; + + retcol = g_new (gchar, counter+1); + strncpy (retcol, ptr, counter); + + retcol[counter] = 0; + return retcol; } color[0] = 0; numnames = 0; - while (finished == FALSE) + space = MAX_COLOR_LEN - 1; + while (space > 0) { - sscanf (ptr, "%s", temp); + sscanf (ptr, "%127s", temp); - if ((gint)ptr[0] == 0 || strcmp ("s", temp) == 0 || strcmp ("m", temp) == 0 || - strcmp ("g", temp) == 0 || strcmp ("g4", temp) == 0) - finished = TRUE; + if (((gint)ptr[0] == 0) || + (strcmp ("s", temp) == 0) || (strcmp ("m", temp) == 0) || + (strcmp ("g", temp) == 0) || (strcmp ("g4", temp) == 0)) + { + break; + } else { if (numnames > 0) - strcat (color, " "); - strcat (color, temp); + { + space -= 1; + strcat (color, " "); + } + strncat (color, temp, space); + space -= MIN (space, strlen (temp)); ptr = gdk_pixmap_skip_string (ptr); ptr = gdk_pixmap_skip_whitespaces (ptr); numnames++; } } - retcol = g_new(gchar, strlen (color) + 1); - strcpy (retcol, color); + retcol = g_strdup (color); return retcol; } -GdkPixmap* -gdk_pixmap_create_from_xpm (GdkWindow *window, - GdkBitmap **mask, - GdkColor *transparent_color, - const gchar *filename) +enum buffer_op { - FILE *infile = NULL; - GdkPixmap *pixmap = NULL; - GdkImage *image = NULL; - GdkColormap *colormap; - GdkVisual *visual; - GdkGC *gc; - GdkColor tmp_color; - gint width, height, num_cols, cpp, cnt, n, ns, xcnt, ycnt; - gchar *buffer = NULL, *color_name = NULL, pixel_str[32]; - guint buffer_size = 0; - _GdkPixmapColor *colors = NULL, *color = NULL; - gulong index; - - if (!window) - window = (GdkWindow*) &gdk_root_parent; + op_header, + op_cmap, + op_body +}; + + +static void +gdk_xpm_destroy_notify (gpointer data) +{ + _GdkPixmapInfo *info = (_GdkPixmapInfo *)data; + GdkColor color; + int i; - infile = fopen (filename, "rb"); - if (infile != NULL) + for (i=0; incolors; i++) { - if (gdk_pixmap_seek_string (infile, "XPM", FALSE) == TRUE) - { - if (gdk_pixmap_seek_char (infile,'{') == TRUE) - { - gdk_pixmap_seek_char (infile, '"'); - fseek (infile, -1, SEEK_CUR); - gdk_pixmap_read_string (infile, &buffer, &buffer_size); - - sscanf (buffer,"%d %d %d %d", &width, &height, &num_cols, &cpp); - - colors = g_new(_GdkPixmapColor, num_cols); - - colormap = gdk_window_get_colormap (window); - visual = gdk_window_get_visual (window); - - if (transparent_color == NULL) - { - gdk_color_white (colormap, &tmp_color); - transparent_color = &tmp_color; - } - - for (cnt = 0; cnt < num_cols; cnt++) - { - gdk_pixmap_seek_char (infile, '"'); - fseek (infile, -1, SEEK_CUR); - gdk_pixmap_read_string (infile, &buffer, &buffer_size); - - colors[cnt].color_string = g_new(gchar, cpp + 1); - for (n = 0; n < cpp; n++) - colors[cnt].color_string[n] = buffer[n]; - colors[cnt].color_string[n] = 0; - colors[cnt].transparent = FALSE; - - if (color_name != NULL) - g_free (color_name); - - color_name = gdk_pixmap_extract_color (&buffer[cpp]); - - if (color_name != NULL) - { - if (gdk_color_parse (color_name, &colors[cnt].color) == FALSE) - { - colors[cnt].color = *transparent_color; - colors[cnt].transparent = TRUE; - } - } - else - { - colors[cnt].color = *transparent_color; - colors[cnt].transparent = TRUE; - } - - gdk_color_alloc (colormap, &colors[cnt].color); - } - - index = 0; - image = gdk_image_new (GDK_IMAGE_FASTEST, visual, width, height); - - gc = NULL; - if (mask) - { - /* The pixmap mask is just a bits pattern. - * Color 0 is used for background and 1 for foreground. - * We don't care about the colormap, we just need 0 and 1. - */ - GdkColor mask_pattern; - - *mask = gdk_pixmap_new (window, width, height, 1); - gc = gdk_gc_new (*mask); - - mask_pattern.pixel = 0; - gdk_gc_set_foreground (gc, &mask_pattern); - gdk_draw_rectangle (*mask, gc, TRUE, 0, 0, -1, -1); - - mask_pattern.pixel = 1; - gdk_gc_set_foreground (gc, &mask_pattern); - } - - for (ycnt = 0; ycnt < height; ycnt++) - { - gdk_pixmap_read_string (infile, &buffer, &buffer_size); - - for (n = 0, cnt = 0, xcnt = 0; n < (width * cpp); n += cpp, xcnt++) - { - strncpy (pixel_str, &buffer[n], cpp); - pixel_str[cpp] = 0; - color = NULL; - ns = 0; - - while (color == NULL) - { - if (strcmp (pixel_str, colors[ns].color_string) == 0) - color = &colors[ns]; - else - ns++; - } - - gdk_image_put_pixel (image, xcnt, ycnt, color->color.pixel); - - if (mask && color->transparent) - { - if (cnt < xcnt) - gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); - cnt = xcnt + 1; - } - } - - if (mask && (cnt < xcnt)) - gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); - } - - if (mask) - gdk_gc_destroy (gc); - - pixmap = gdk_pixmap_new (window, width, height, visual->depth); - - 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); - } - } - - fclose (infile); - free (buffer); - - if (colors != NULL) - { - for (cnt = 0; cnt < num_cols; cnt++) - g_free (colors[cnt].color_string); - g_free (colors); - } + color.pixel = info->pixels[i]; + gdk_colormap_free_colors (info->colormap, &color, 1); } - return pixmap; + gdk_colormap_unref (info->colormap); + g_free (info); } - -GdkPixmap* -gdk_pixmap_create_from_xpm_d (GdkWindow *window, - GdkBitmap **mask, - GdkColor *transparent_color, - gchar **data) + +static GdkPixmap * +_gdk_pixmap_create_from_xpm (GdkWindow *window, + GdkColormap *colormap, + GdkBitmap **mask, + GdkColor *transparent_color, + gchar * (*get_buf) (enum buffer_op op, + gpointer handle), + gpointer handle) { GdkPixmap *pixmap = NULL; GdkImage *image = NULL; - GdkColormap *colormap; GdkVisual *visual; - GdkGC *gc; + GdkGC *gc = NULL; GdkColor tmp_color; - gint width, height, num_cols, cpp, cnt, n, ns, xcnt, ycnt, i; - gchar *buffer, *color_name = NULL, pixel_str[32]; - _GdkPixmapColor *colors = NULL, *color = NULL; + 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; - - if (!window) - window = (GdkWindow*) &gdk_root_parent; - - i = 0; - buffer = data[i++]; + 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 = gdk_parent_root; + + if (colormap == NULL) + { + colormap = gdk_drawable_get_colormap (window); + visual = gdk_drawable_get_visual (window); + } + else + visual = ((GdkColormapPrivate *)colormap)->visual; + + buffer = (*get_buf) (op_header, handle); + if (buffer == NULL) + return NULL; + sscanf (buffer,"%d %d %d %d", &width, &height, &num_cols, &cpp); - - colors = g_new(_GdkPixmapColor, num_cols); - - colormap = gdk_window_get_colormap (window); - visual = gdk_window_get_visual (window); - - if (transparent_color == NULL) + if (cpp >= 32) + { + g_warning ("Pixmap has more than 31 characters per color\n"); + return NULL; + } + + 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 (cnt = 0; cnt < num_cols; cnt++) + /* 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)) { - buffer = data[i++]; - - colors[cnt].color_string = g_new(gchar, cpp + 1); - for (n = 0; n < cpp; n++) - colors[cnt].color_string[n] = buffer[n]; - colors[cnt].color_string[n] = 0; - colors[cnt].transparent = FALSE; - - if (color_name != NULL) - g_free (color_name); + color_info = g_malloc (sizeof (_GdkPixmapInfo) + + sizeof(gulong) * (num_cols - 1)); + color_info->ncolors = num_cols; + color_info->colormap = colormap; + gdk_colormap_ref (colormap); + } - color_name = gdk_pixmap_extract_color (&buffer[cpp]); + name_buf = g_new (gchar, num_cols * (cpp+1)); + colors = g_new (_GdkPixmapColor, num_cols); - if (color_name != NULL) - { - if (gdk_color_parse (color_name, &colors[cnt].color) == FALSE) - { - colors[cnt].color = *transparent_color; - colors[cnt].transparent = TRUE; - } - } - else + for (cnt = 0; cnt < num_cols; cnt++) + { + gchar *color_name; + + buffer = (*get_buf) (op_cmap, handle); + if (buffer == NULL) + goto error; + + 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); + color->transparent = FALSE; + + color_name = gdk_pixmap_extract_color (buffer); + + if (color_name == NULL || g_strcasecmp (color_name, "None") == 0 || + gdk_color_parse (color_name, &color->color) == FALSE) { - colors[cnt].color = *transparent_color; - colors[cnt].transparent = TRUE; + color->color = *transparent_color; + color->transparent = TRUE; } - - gdk_color_alloc (colormap, &colors[cnt].color); + + g_free (color_name); + + /* FIXME: The remaining slowness appears to happen in this + function. */ + gdk_color_alloc (colormap, &color->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; } - + index = 0; image = gdk_image_new (GDK_IMAGE_FASTEST, visual, width, height); - - gc = NULL; + if (mask) { /* The pixmap mask is just a bits pattern. @@ -584,39 +566,43 @@ gdk_pixmap_create_from_xpm_d (GdkWindow *window, * We don't care about the colormap, we just need 0 and 1. */ GdkColor mask_pattern; - + *mask = gdk_pixmap_new (window, width, height, 1); gc = gdk_gc_new (*mask); - + mask_pattern.pixel = 0; gdk_gc_set_foreground (gc, &mask_pattern); gdk_draw_rectangle (*mask, gc, TRUE, 0, 0, -1, -1); - + mask_pattern.pixel = 1; gdk_gc_set_foreground (gc, &mask_pattern); } - + + wbytes = width * cpp; for (ycnt = 0; ycnt < height; ycnt++) { - buffer = data[i++]; - - for (n = 0, cnt = 0, xcnt = 0; n < (width * cpp); n += cpp, xcnt++) + buffer = (*get_buf) (op_body, handle); + + /* FIXME: this slows things down a little - it could be + * integrated into the strncpy below, perhaps. OTOH, strlen + * is fast. + */ + if ((buffer == NULL) || strlen (buffer) < wbytes) + continue; + + for (n = 0, cnt = 0, xcnt = 0; n < wbytes; n += cpp, xcnt++) { strncpy (pixel_str, &buffer[n], cpp); pixel_str[cpp] = 0; - color = NULL; ns = 0; - - while (color == NULL) - { - if (strcmp (pixel_str, colors[ns].color_string) == 0) - color = &colors[ns]; - else - ns++; - } - + + color = g_hash_table_lookup (color_hash, pixel_str); + + if (!color) /* screwed up XPM file */ + color = fallbackcolor; + gdk_image_put_pixel (image, xcnt, ycnt, color->color.pixel); - + if (mask && color->transparent) { if (cnt < xcnt) @@ -624,48 +610,202 @@ gdk_pixmap_create_from_xpm_d (GdkWindow *window, cnt = xcnt + 1; } } - + if (mask && (cnt < xcnt)) gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt); } - + + 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_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); - pixmap = gdk_pixmap_new (window, width, height, visual->depth); + if (colors != NULL) + g_free (colors); - 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); + if (name_buf != NULL) + g_free (name_buf); - if (colors != NULL) + return pixmap; +} + + +struct file_handle +{ + FILE *infile; + gchar *buffer; + guint buffer_size; +}; + + +static gchar * +file_buffer (enum buffer_op op, gpointer handle) +{ + struct file_handle *h = handle; + + switch (op) + { + case op_header: + if (gdk_pixmap_seek_string (h->infile, "XPM", FALSE) != TRUE) + break; + + if (gdk_pixmap_seek_char (h->infile,'{') != TRUE) + break; + /* Fall through to the next gdk_pixmap_seek_char. */ + + case op_cmap: + gdk_pixmap_seek_char (h->infile, '"'); + fseek (h->infile, -1, SEEK_CUR); + /* Fall through to the gdk_pixmap_read_string. */ + + case op_body: + gdk_pixmap_read_string (h->infile, &h->buffer, &h->buffer_size); + return h->buffer; + } + return 0; +} + + +GdkPixmap* +gdk_pixmap_colormap_create_from_xpm (GdkWindow *window, + GdkColormap *colormap, + GdkBitmap **mask, + GdkColor *transparent_color, + const gchar *filename) +{ + struct file_handle h; + GdkPixmap *pixmap = NULL; + + memset (&h, 0, sizeof (h)); + h.infile = fopen (filename, "rb"); + if (h.infile != NULL) { - for (cnt = 0; cnt < num_cols; cnt++) - g_free (colors[cnt].color_string); - g_free (colors); + pixmap = _gdk_pixmap_create_from_xpm (window, colormap, mask, + transparent_color, + file_buffer, &h); + fclose (h.infile); + g_free (h.buffer); } return pixmap; } -void -gdk_pixmap_destroy (GdkPixmap *pixmap) +GdkPixmap* +gdk_pixmap_create_from_xpm (GdkWindow *window, + GdkBitmap **mask, + GdkColor *transparent_color, + const gchar *filename) +{ + return gdk_pixmap_colormap_create_from_xpm (window, NULL, mask, + transparent_color, filename); +} + + +struct mem_handle { - GdkWindowPrivate *private; + gchar **data; + int offset; +}; - g_return_if_fail (pixmap != NULL); - private = (GdkPixmapPrivate*) pixmap; - if (private->ref_count <= 0) - { - XFreePixmap (private->xdisplay, private->xwindow); - gdk_xid_table_remove (private->xwindow); - g_free (pixmap); - } - else +static gchar * +mem_buffer (enum buffer_op op, gpointer handle) +{ + struct mem_handle *h = handle; + switch (op) { - private->ref_count -= 1; + case op_header: + case op_cmap: + case op_body: + if (h->data[h->offset]) + return h->data[h->offset ++]; } + return 0; +} + + +GdkPixmap* +gdk_pixmap_colormap_create_from_xpm_d (GdkWindow *window, + GdkColormap *colormap, + GdkBitmap **mask, + GdkColor *transparent_color, + gchar **data) +{ + struct mem_handle h; + GdkPixmap *pixmap = NULL; + + memset (&h, 0, sizeof (h)); + h.data = data; + pixmap = _gdk_pixmap_create_from_xpm (window, colormap, mask, + transparent_color, + mem_buffer, &h); + return pixmap; +} + + +GdkPixmap* +gdk_pixmap_create_from_xpm_d (GdkWindow *window, + GdkBitmap **mask, + GdkColor *transparent_color, + gchar **data) +{ + return gdk_pixmap_colormap_create_from_xpm_d (window, NULL, mask, + transparent_color, data); +} + +GdkPixmap* +gdk_pixmap_foreign_new (guint32 anid) +{ + 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; + + GDK_DRAWABLE_XDATA (private)->xdisplay = GDK_DISPLAY (); + GDK_DRAWABLE_XDATA (private)->xid = xpixmap; + + private->width = w_ret; + private->height = h_ret; + + gdk_xid_table_insert(&GDK_DRAWABLE_XID (pixmap), pixmap); + + return pixmap; }