1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library 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.
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 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library 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.
21 * Modified by the GTK+ Team and others 1997-1999. 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/.
31 /* Needed for SEEK_END in SunOS */
35 #include "gdkpixmap.h"
36 #include "gdkprivate.h"
49 GdkColormap *colormap;
54 gdk_pixmap_new (GdkWindow *window,
60 GdkDrawablePrivate *private;
62 g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
63 g_return_val_if_fail ((window != NULL) || (depth != -1), NULL);
64 g_return_val_if_fail ((width != 0) && (height != 0), NULL);
67 window = (GdkWindow*) &gdk_root_parent;
69 if (GDK_DRAWABLE_DESTROYED (window))
73 depth = gdk_drawable_get_visual (window)->depth;
75 private = g_new0 (GdkDrawablePrivate, 1);
76 pixmap = (GdkPixmap*) private;
78 private->xdisplay = GDK_DRAWABLE_XDISPLAY (window);
79 private->window_type = GDK_DRAWABLE_PIXMAP;
80 private->xwindow = XCreatePixmap (private->xdisplay,
81 GDK_DRAWABLE_XID (window),
82 width, height, depth);
83 private->colormap = NULL;
84 private->width = width;
85 private->height = height;
86 private->ref_count = 1;
87 private->destroyed = 0;
89 gdk_xid_table_insert (&private->xwindow, pixmap);
95 gdk_bitmap_create_from_data (GdkWindow *window,
101 GdkDrawablePrivate *private;
103 g_return_val_if_fail (data != NULL, NULL);
104 g_return_val_if_fail ((width != 0) && (height != 0), NULL);
105 g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
108 window = (GdkWindow*) &gdk_root_parent;
110 if (GDK_DRAWABLE_DESTROYED (window))
113 private = g_new0 (GdkDrawablePrivate, 1);
114 pixmap = (GdkPixmap*) private;
116 private->xdisplay = GDK_DRAWABLE_XDISPLAY (window);
117 private->window_type = GDK_DRAWABLE_PIXMAP;
118 private->width = width;
119 private->height = height;
120 private->ref_count = 1;
121 private->destroyed = FALSE;
123 private->xwindow = XCreateBitmapFromData (private->xdisplay,
124 GDK_DRAWABLE_XID (window),
125 (char *)data, width, height);
127 gdk_xid_table_insert (&private->xwindow, pixmap);
133 gdk_pixmap_create_from_data (GdkWindow *window,
142 GdkDrawablePrivate *private;
144 g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
145 g_return_val_if_fail (data != NULL, NULL);
146 g_return_val_if_fail (fg != NULL, NULL);
147 g_return_val_if_fail (bg != NULL, NULL);
148 g_return_val_if_fail ((window != NULL) || (depth != -1), NULL);
149 g_return_val_if_fail ((width != 0) && (height != 0), NULL);
152 window = (GdkWindow*) &gdk_root_parent;
154 if (GDK_DRAWABLE_DESTROYED (window))
158 depth = gdk_drawable_get_visual (window)->depth;
160 private = g_new0 (GdkDrawablePrivate, 1);
161 pixmap = (GdkPixmap*) private;
163 private->xdisplay = GDK_DRAWABLE_XDISPLAY (window);
164 private->window_type = GDK_DRAWABLE_PIXMAP;
165 private->width = width;
166 private->height = height;
167 private->ref_count = 1;
168 private->destroyed = FALSE;
170 private->xwindow = XCreatePixmapFromBitmapData (private->xdisplay,
171 GDK_DRAWABLE_XID (window),
172 (char *)data, width, height,
173 fg->pixel, bg->pixel, depth);
175 gdk_xid_table_insert (&private->xwindow, pixmap);
181 gdk_pixmap_seek_string (FILE *infile,
187 while (!feof (infile))
189 fscanf (infile, "%1023s", instr);
190 if (skip_comments == TRUE && strcmp (instr, "/*") == 0)
192 fscanf (infile, "%1023s", instr);
193 while (!feof (infile) && strcmp (instr, "*/") != 0)
194 fscanf (infile, "%1023s", instr);
195 fscanf(infile, "%1023s", instr);
197 if (strcmp (instr, str)==0)
205 gdk_pixmap_seek_char (FILE *infile,
210 while ((b = getc(infile)) != EOF)
212 if (c != b && b == '/')
217 else if (b == '*') /* we have a comment */
227 while (!(oldb == '*' && b == '/'));
237 gdk_pixmap_read_string (FILE *infile,
242 guint cnt = 0, bufsiz, ret = FALSE;
246 bufsiz = *buffer_size;
249 bufsiz = 10 * sizeof (gchar);
250 buf = g_new(gchar, bufsiz);
255 while (c != EOF && c != '"');
260 while ((c = getc(infile)) != EOF)
264 guint new_size = bufsiz * 2;
265 if (new_size > bufsiz)
270 buf = (gchar *) g_realloc (buf, bufsiz);
271 buf[bufsiz-1] = '\0';
285 buf[bufsiz-1] = '\0'; /* ensure null termination for errors */
287 *buffer_size = bufsiz;
292 gdk_pixmap_skip_whitespaces (gchar *buffer)
296 while (buffer[index] != 0 && (buffer[index] == 0x20 || buffer[index] == 0x09))
299 return &buffer[index];
303 gdk_pixmap_skip_string (gchar *buffer)
307 while (buffer[index] != 0 && buffer[index] != 0x20 && buffer[index] != 0x09)
310 return &buffer[index];
313 /* Xlib crashed ince at a color name lengths around 125 */
314 #define MAX_COLOR_LEN 120
317 gdk_pixmap_extract_color (gchar *buffer)
319 gint counter, numnames;
320 gchar *ptr = NULL, ch, temp[128];
321 gchar color[MAX_COLOR_LEN], *retcol;
327 if (buffer[counter] == 'c')
329 ch = buffer[counter + 1];
330 if (ch == 0x20 || ch == 0x09)
331 ptr = &buffer[counter + 1];
333 else if (buffer[counter] == 0)
339 ptr = gdk_pixmap_skip_whitespaces (ptr);
343 else if (ptr[0] == '#')
346 while (ptr[counter] != 0 &&
347 ((ptr[counter] >= '0' && ptr[counter] <= '9') ||
348 (ptr[counter] >= 'a' && ptr[counter] <= 'f') ||
349 (ptr[counter] >= 'A' && ptr[counter] <= 'F')))
352 retcol = g_new (gchar, counter+1);
353 strncpy (retcol, ptr, counter);
363 space = MAX_COLOR_LEN - 1;
366 sscanf (ptr, "%127s", temp);
368 if (((gint)ptr[0] == 0) ||
369 (strcmp ("s", temp) == 0) || (strcmp ("m", temp) == 0) ||
370 (strcmp ("g", temp) == 0) || (strcmp ("g4", temp) == 0))
381 strncat (color, temp, space);
382 space -= MIN (space, strlen (temp));
383 ptr = gdk_pixmap_skip_string (ptr);
384 ptr = gdk_pixmap_skip_whitespaces (ptr);
389 retcol = g_strdup (color);
403 gdk_xpm_destroy_notify (gpointer data)
405 _GdkPixmapInfo *info = (_GdkPixmapInfo *)data;
409 for (i=0; i<info->ncolors; i++)
411 color.pixel = info->pixels[i];
412 gdk_colormap_free_colors (info->colormap, &color, 1);
415 gdk_colormap_unref (info->colormap);
420 _gdk_pixmap_create_from_xpm (GdkWindow *window,
421 GdkColormap *colormap,
423 GdkColor *transparent_color,
424 gchar * (*get_buf) (enum buffer_op op,
428 GdkPixmap *pixmap = NULL;
429 GdkImage *image = NULL;
433 gint width, height, num_cols, cpp, n, ns, cnt, xcnt, ycnt, wbytes;
434 gchar *buffer, pixel_str[32];
436 _GdkPixmapColor *color = NULL, *fallbackcolor = NULL;
437 _GdkPixmapColor *colors = NULL;
439 GHashTable *color_hash = NULL;
440 _GdkPixmapInfo *color_info = NULL;
442 if ((window == NULL) && (colormap == NULL))
443 g_warning ("Creating pixmap from xpm with NULL window and colormap");
446 window = (GdkWindow *)&gdk_root_parent;
448 if (colormap == NULL)
450 colormap = gdk_drawable_get_colormap (window);
451 visual = gdk_drawable_get_visual (window);
454 visual = ((GdkColormapPrivate *)colormap)->visual;
456 buffer = (*get_buf) (op_header, handle);
460 sscanf (buffer,"%d %d %d %d", &width, &height, &num_cols, &cpp);
463 g_warning ("Pixmap has more than 31 characters per color\n");
467 color_hash = g_hash_table_new (g_str_hash, g_str_equal);
469 if (transparent_color == NULL)
471 gdk_color_white (colormap, &tmp_color);
472 transparent_color = &tmp_color;
475 /* For pseudo-color and grayscale visuals, we have to remember
476 * the colors we allocated, so we can free them later.
478 if ((visual->type == GDK_VISUAL_PSEUDO_COLOR) ||
479 (visual->type == GDK_VISUAL_GRAYSCALE))
481 color_info = g_malloc (sizeof (_GdkPixmapInfo) +
482 sizeof(gulong) * (num_cols - 1));
483 color_info->ncolors = num_cols;
484 color_info->colormap = colormap;
485 gdk_colormap_ref (colormap);
488 name_buf = g_new (gchar, num_cols * (cpp+1));
489 colors = g_new (_GdkPixmapColor, num_cols);
491 for (cnt = 0; cnt < num_cols; cnt++)
495 buffer = (*get_buf) (op_cmap, handle);
499 color = &colors[cnt];
500 color->color_string = &name_buf [cnt * (cpp + 1)];
501 strncpy (color->color_string, buffer, cpp);
502 color->color_string[cpp] = 0;
503 buffer += strlen (color->color_string);
504 color->transparent = FALSE;
506 color_name = gdk_pixmap_extract_color (buffer);
508 if (color_name == NULL || g_strcasecmp (color_name, "None") == 0 ||
509 gdk_color_parse (color_name, &color->color) == FALSE)
511 color->color = *transparent_color;
512 color->transparent = TRUE;
517 /* FIXME: The remaining slowness appears to happen in this
519 gdk_color_alloc (colormap, &color->color);
522 color_info->pixels[cnt] = color->color.pixel;
524 g_hash_table_insert (color_hash, color->color_string, color);
526 fallbackcolor = color;
530 image = gdk_image_new (GDK_IMAGE_FASTEST, visual, width, height);
534 /* The pixmap mask is just a bits pattern.
535 * Color 0 is used for background and 1 for foreground.
536 * We don't care about the colormap, we just need 0 and 1.
538 GdkColor mask_pattern;
540 *mask = gdk_pixmap_new (window, width, height, 1);
541 gc = gdk_gc_new (*mask);
543 mask_pattern.pixel = 0;
544 gdk_gc_set_foreground (gc, &mask_pattern);
545 gdk_draw_rectangle (*mask, gc, TRUE, 0, 0, -1, -1);
547 mask_pattern.pixel = 1;
548 gdk_gc_set_foreground (gc, &mask_pattern);
551 wbytes = width * cpp;
552 for (ycnt = 0; ycnt < height; ycnt++)
554 buffer = (*get_buf) (op_body, handle);
556 /* FIXME: this slows things down a little - it could be
557 * integrated into the strncpy below, perhaps. OTOH, strlen
560 if ((buffer == NULL) || strlen (buffer) < wbytes)
563 for (n = 0, cnt = 0, xcnt = 0; n < wbytes; n += cpp, xcnt++)
565 strncpy (pixel_str, &buffer[n], cpp);
569 color = g_hash_table_lookup (color_hash, pixel_str);
571 if (!color) /* screwed up XPM file */
572 color = fallbackcolor;
574 gdk_image_put_pixel (image, xcnt, ycnt, color->color.pixel);
576 if (mask && color->transparent)
579 gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt);
584 if (mask && (cnt < xcnt))
585 gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt);
595 pixmap = gdk_pixmap_new (window, width, height, visual->depth);
598 gdk_drawable_set_data (pixmap, "gdk-xpm", color_info,
599 gdk_xpm_destroy_notify);
601 gc = gdk_gc_new (pixmap);
602 gdk_gc_set_foreground (gc, transparent_color);
603 gdk_draw_image (pixmap, gc, image, 0, 0, 0, 0, image->width, image->height);
605 gdk_image_destroy (image);
608 gdk_xpm_destroy_notify (color_info);
610 if (color_hash != NULL)
611 g_hash_table_destroy (color_hash);
616 if (name_buf != NULL)
632 file_buffer (enum buffer_op op, gpointer handle)
634 struct file_handle *h = handle;
639 if (gdk_pixmap_seek_string (h->infile, "XPM", FALSE) != TRUE)
642 if (gdk_pixmap_seek_char (h->infile,'{') != TRUE)
644 /* Fall through to the next gdk_pixmap_seek_char. */
647 gdk_pixmap_seek_char (h->infile, '"');
648 fseek (h->infile, -1, SEEK_CUR);
649 /* Fall through to the gdk_pixmap_read_string. */
652 gdk_pixmap_read_string (h->infile, &h->buffer, &h->buffer_size);
660 gdk_pixmap_colormap_create_from_xpm (GdkWindow *window,
661 GdkColormap *colormap,
663 GdkColor *transparent_color,
664 const gchar *filename)
666 struct file_handle h;
667 GdkPixmap *pixmap = NULL;
669 memset (&h, 0, sizeof (h));
670 h.infile = fopen (filename, "rb");
671 if (h.infile != NULL)
673 pixmap = _gdk_pixmap_create_from_xpm (window, colormap, mask,
684 gdk_pixmap_create_from_xpm (GdkWindow *window,
686 GdkColor *transparent_color,
687 const gchar *filename)
689 return gdk_pixmap_colormap_create_from_xpm (window, NULL, mask,
690 transparent_color, filename);
702 mem_buffer (enum buffer_op op, gpointer handle)
704 struct mem_handle *h = handle;
710 if (h->data[h->offset])
711 return h->data[h->offset ++];
718 gdk_pixmap_colormap_create_from_xpm_d (GdkWindow *window,
719 GdkColormap *colormap,
721 GdkColor *transparent_color,
725 GdkPixmap *pixmap = NULL;
727 memset (&h, 0, sizeof (h));
729 pixmap = _gdk_pixmap_create_from_xpm (window, colormap, mask,
737 gdk_pixmap_create_from_xpm_d (GdkWindow *window,
739 GdkColor *transparent_color,
742 return gdk_pixmap_colormap_create_from_xpm_d (window, NULL, mask,
743 transparent_color, data);
747 gdk_pixmap_foreign_new (guint32 anid)
750 GdkDrawablePrivate *private;
753 unsigned int x_ret, y_ret, w_ret, h_ret, bw_ret, depth_ret;
755 /* check to make sure we were passed something at
756 least a little sane */
757 g_return_val_if_fail((anid != 0), NULL);
759 /* set the pixmap to the passed in value */
762 /* get information about the Pixmap to fill in the structure for
764 if (!XGetGeometry(GDK_DISPLAY(),
765 xpixmap, &root_return,
766 &x_ret, &y_ret, &w_ret, &h_ret, &bw_ret, &depth_ret))
769 /* allocate a new gdk pixmap */
770 private = g_new(GdkDrawablePrivate, 1);
771 pixmap = (GdkPixmap *)private;
773 private->xdisplay = GDK_DISPLAY();
774 private->window_type = GDK_DRAWABLE_PIXMAP;
775 private->xwindow = xpixmap;
776 private->colormap = NULL;
777 private->width = w_ret;
778 private->height = h_ret;
779 private->ref_count = 1;
780 private->destroyed = 0;
782 gdk_xid_table_insert(&private->xwindow, pixmap);
788 gdk_pixmap_ref (GdkPixmap *pixmap)
790 GdkDrawablePrivate *private = (GdkDrawablePrivate *)pixmap;
791 g_return_val_if_fail (pixmap != NULL, NULL);
792 g_return_val_if_fail (GDK_IS_PIXMAP (private), NULL);
794 private->ref_count += 1;
799 gdk_pixmap_unref (GdkPixmap *pixmap)
801 GdkDrawablePrivate *private = (GdkDrawablePrivate *)pixmap;
802 g_return_if_fail (pixmap != NULL);
803 g_return_if_fail (GDK_IS_PIXMAP (private));
804 g_return_if_fail (private->ref_count > 0);
806 private->ref_count -= 1;
807 if (private->ref_count == 0)
809 XFreePixmap (private->xdisplay, private->xwindow);
810 gdk_xid_table_remove (private->xwindow);
811 g_dataset_destroy (private);
817 gdk_bitmap_ref (GdkBitmap *bitmap)
819 return (GdkBitmap *)gdk_pixmap_ref ((GdkPixmap *)bitmap);
823 gdk_bitmap_unref (GdkBitmap *bitmap)
825 gdk_pixmap_unref ((GdkPixmap *)bitmap);