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.
23 /* Needed for SEEK_END in SunOS */
28 #include "gdkprivate.h"
40 GdkColormap *colormap;
45 gdk_pixmap_new (GdkWindow *window,
51 GdkWindowPrivate *private;
52 GdkWindowPrivate *window_private;
54 g_return_val_if_fail ((window != NULL) || (depth != -1), NULL);
55 g_return_val_if_fail ((width != 0) && (height != 0), NULL);
58 window = (GdkWindow*) &gdk_root_parent;
60 window_private = (GdkWindowPrivate*) window;
61 if (window_private->destroyed)
65 depth = gdk_window_get_visual (window)->depth;
67 private = g_new (GdkWindowPrivate, 1);
68 pixmap = (GdkPixmap*) private;
70 private->xdisplay = window_private->xdisplay;
71 private->window_type = GDK_WINDOW_PIXMAP;
72 private->xwindow = XCreatePixmap (private->xdisplay, window_private->xwindow,
73 width, height, depth);
74 private->colormap = NULL;
75 private->parent = NULL;
78 private->width = width;
79 private->height = height;
80 private->resize_count = 0;
81 private->ref_count = 1;
82 private->destroyed = 0;
84 gdk_xid_table_insert (&private->xwindow, pixmap);
90 gdk_bitmap_create_from_data (GdkWindow *window,
96 GdkWindowPrivate *private;
97 GdkWindowPrivate *window_private;
99 g_return_val_if_fail (data != NULL, NULL);
100 g_return_val_if_fail ((width != 0) && (height != 0), NULL);
103 window = (GdkWindow*) &gdk_root_parent;
105 window_private = (GdkWindowPrivate*) window;
106 if (window_private->destroyed)
109 private = g_new (GdkWindowPrivate, 1);
110 pixmap = (GdkPixmap*) private;
112 private->parent = NULL;
113 private->xdisplay = window_private->xdisplay;
114 private->window_type = GDK_WINDOW_PIXMAP;
117 private->width = width;
118 private->height = height;
119 private->resize_count = 0;
120 private->ref_count = 1;
121 private->destroyed = FALSE;
123 private->xwindow = XCreateBitmapFromData (private->xdisplay,
124 window_private->xwindow,
125 data, width, height);
127 gdk_xid_table_insert (&private->xwindow, pixmap);
133 gdk_pixmap_create_from_data (GdkWindow *window,
142 GdkWindowPrivate *private;
143 GdkWindowPrivate *window_private;
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 window_private = (GdkWindowPrivate*) window;
155 if (window_private->destroyed)
159 depth = gdk_window_get_visual (window)->depth;
161 private = g_new (GdkWindowPrivate, 1);
162 pixmap = (GdkPixmap*) private;
164 private->parent = NULL;
165 private->xdisplay = window_private->xdisplay;
166 private->window_type = GDK_WINDOW_PIXMAP;
169 private->width = width;
170 private->height = height;
171 private->resize_count = 0;
172 private->ref_count = 1;
173 private->destroyed = FALSE;
175 private->xwindow = XCreatePixmapFromBitmapData (private->xdisplay,
176 window_private->xwindow,
178 fg->pixel, bg->pixel, depth);
180 gdk_xid_table_insert (&private->xwindow, pixmap);
186 gdk_pixmap_seek_string (FILE *infile,
192 while (!feof (infile))
194 fscanf (infile, "%1023s", instr);
195 if (skip_comments == TRUE && strcmp (instr, "/*") == 0)
197 fscanf (infile, "%1023s", instr);
198 while (!feof (infile) && strcmp (instr, "*/") != 0)
199 fscanf (infile, "%1023s", instr);
200 fscanf(infile, "%1023s", instr);
202 if (strcmp (instr, str)==0)
210 gdk_pixmap_seek_char (FILE *infile,
215 while ((b = getc(infile)) != EOF)
217 if (c != b && b == '/')
222 else if (b == '*') /* we have a comment */
232 while (!(oldb == '*' && b == '/'));
242 gdk_pixmap_read_string (FILE *infile,
247 guint cnt = 0, bufsiz, ret = FALSE;
251 bufsiz = *buffer_size;
254 bufsiz = 10 * sizeof (gchar);
255 buf = g_new(gchar, bufsiz);
260 while (c != EOF && c != '"');
265 while ((c = getc(infile)) != EOF)
269 guint new_size = bufsiz * 2;
270 if (new_size > bufsiz)
275 buf = (gchar *) g_realloc (buf, bufsiz);
276 buf[bufsiz-1] = '\0';
290 buf[bufsiz-1] = '\0'; /* ensure null termination for errors */
292 *buffer_size = bufsiz;
297 gdk_pixmap_skip_whitespaces (gchar *buffer)
301 while (buffer[index] != 0 && (buffer[index] == 0x20 || buffer[index] == 0x09))
304 return &buffer[index];
308 gdk_pixmap_skip_string (gchar *buffer)
312 while (buffer[index] != 0 && buffer[index] != 0x20 && buffer[index] != 0x09)
315 return &buffer[index];
318 /* Xlib crashed ince at a color name lengths around 125 */
319 #define MAX_COLOR_LEN 120
322 gdk_pixmap_extract_color (gchar *buffer)
324 gint counter, numnames;
325 gchar *ptr = NULL, ch, temp[128];
326 gchar color[MAX_COLOR_LEN], *retcol;
332 if (buffer[counter] == 'c')
334 ch = buffer[counter + 1];
335 if (ch == 0x20 || ch == 0x09)
336 ptr = &buffer[counter + 1];
338 else if (buffer[counter] == 0)
344 ptr = gdk_pixmap_skip_whitespaces (ptr);
348 else if (ptr[0] == '#')
351 while (ptr[counter] != 0 &&
352 ((ptr[counter] >= '0' && ptr[counter] <= '9') ||
353 (ptr[counter] >= 'a' && ptr[counter] <= 'f') ||
354 (ptr[counter] >= 'A' && ptr[counter] <= 'F')))
357 retcol = g_new (gchar, counter+1);
358 strncpy (retcol, ptr, counter);
368 space = MAX_COLOR_LEN - 1;
371 sscanf (ptr, "%127s", temp);
373 if (((gint)ptr[0] == 0) ||
374 (strcmp ("s", temp) == 0) || (strcmp ("m", temp) == 0) ||
375 (strcmp ("g", temp) == 0) || (strcmp ("g4", temp) == 0))
386 strncat (color, temp, space);
387 space -= MIN (space, strlen (temp));
388 ptr = gdk_pixmap_skip_string (ptr);
389 ptr = gdk_pixmap_skip_whitespaces (ptr);
394 retcol = g_strdup (color);
408 gdk_xpm_destroy_notify (gpointer data)
410 _GdkPixmapInfo *info = (_GdkPixmapInfo *)data;
414 for (i=0; i<info->ncolors; i++)
416 color.pixel = info->pixels[i];
417 gdk_colormap_free_colors (info->colormap, &color, 1);
420 gdk_colormap_unref (info->colormap);
425 _gdk_pixmap_create_from_xpm (GdkWindow *window,
426 GdkColormap *colormap,
428 GdkColor *transparent_color,
429 gchar * (*get_buf) (enum buffer_op op,
433 GdkPixmap *pixmap = NULL;
434 GdkImage *image = NULL;
438 gint width, height, num_cols, cpp, n, ns, cnt, xcnt, ycnt, wbytes;
439 gchar *buffer, pixel_str[32];
441 _GdkPixmapColor *color = NULL, *fallbackcolor = NULL;
442 _GdkPixmapColor *colors = NULL;
444 GHashTable *color_hash = NULL;
445 _GdkPixmapInfo *color_info = NULL;
447 if ((window == NULL) && (colormap == NULL))
448 g_warning ("Creating pixmap from xpm with NULL window and colormap");
451 window = (GdkWindow *)&gdk_root_parent;
453 if (colormap == NULL)
455 colormap = gdk_window_get_colormap (window);
456 visual = gdk_window_get_visual (window);
459 visual = ((GdkColormapPrivate *)colormap)->visual;
461 buffer = (*get_buf) (op_header, handle);
465 sscanf (buffer,"%d %d %d %d", &width, &height, &num_cols, &cpp);
468 g_warning ("Pixmap has more than 31 characters per color\n");
472 color_hash = g_hash_table_new (g_str_hash, g_str_equal);
474 if (transparent_color == NULL)
476 gdk_color_white (colormap, &tmp_color);
477 transparent_color = &tmp_color;
480 /* For pseudo-color and grayscale visuals, we have to remember
481 * the colors we allocated, so we can free them later.
483 if ((visual->type == GDK_VISUAL_PSEUDO_COLOR) ||
484 (visual->type == GDK_VISUAL_GRAYSCALE))
486 color_info = g_malloc (sizeof (_GdkPixmapInfo) +
487 sizeof(gulong) * (num_cols - 1));
488 color_info->ncolors = num_cols;
489 color_info->colormap = colormap;
490 gdk_colormap_ref (colormap);
493 name_buf = g_new (gchar, num_cols * (cpp+1));
494 colors = g_new (_GdkPixmapColor, num_cols);
496 for (cnt = 0; cnt < num_cols; cnt++)
500 buffer = (*get_buf) (op_cmap, handle);
504 color = &colors[cnt];
505 color->color_string = &name_buf [cnt * (cpp + 1)];
506 strncpy (color->color_string, buffer, cpp);
507 color->color_string[cpp] = 0;
508 buffer += strlen (color->color_string);
509 color->transparent = FALSE;
511 color_name = gdk_pixmap_extract_color (buffer);
513 if (color_name == NULL ||
514 gdk_color_parse (color_name, &color->color) == FALSE)
516 color->color = *transparent_color;
517 color->transparent = TRUE;
522 /* FIXME: The remaining slowness appears to happen in this
524 gdk_color_alloc (colormap, &color->color);
527 color_info->pixels[cnt] = color->color.pixel;
529 g_hash_table_insert (color_hash, color->color_string, color);
531 fallbackcolor = color;
535 image = gdk_image_new (GDK_IMAGE_FASTEST, visual, width, height);
539 /* The pixmap mask is just a bits pattern.
540 * Color 0 is used for background and 1 for foreground.
541 * We don't care about the colormap, we just need 0 and 1.
543 GdkColor mask_pattern;
545 *mask = gdk_pixmap_new (window, width, height, 1);
546 gc = gdk_gc_new (*mask);
548 mask_pattern.pixel = 0;
549 gdk_gc_set_foreground (gc, &mask_pattern);
550 gdk_draw_rectangle (*mask, gc, TRUE, 0, 0, -1, -1);
552 mask_pattern.pixel = 1;
553 gdk_gc_set_foreground (gc, &mask_pattern);
556 wbytes = width * cpp;
557 for (ycnt = 0; ycnt < height; ycnt++)
559 buffer = (*get_buf) (op_body, handle);
561 /* FIXME: this slows things down a little - it could be
562 * integrated into the strncpy below, perhaps. OTOH, strlen
565 if ((buffer == NULL) || strlen (buffer) < wbytes)
568 for (n = 0, cnt = 0, xcnt = 0; n < wbytes; n += cpp, xcnt++)
570 strncpy (pixel_str, &buffer[n], cpp);
574 color = g_hash_table_lookup (color_hash, pixel_str);
576 if (!color) /* screwed up XPM file */
577 color = fallbackcolor;
579 gdk_image_put_pixel (image, xcnt, ycnt, color->color.pixel);
581 if (mask && color->transparent)
584 gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt);
589 if (mask && (cnt < xcnt))
590 gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt);
600 pixmap = gdk_pixmap_new (window, width, height, visual->depth);
603 gdk_drawable_set_data (pixmap, "gdk-xpm", color_info,
604 gdk_xpm_destroy_notify);
606 gc = gdk_gc_new (pixmap);
607 gdk_gc_set_foreground (gc, transparent_color);
608 gdk_draw_image (pixmap, gc, image, 0, 0, 0, 0, image->width, image->height);
610 gdk_image_destroy (image);
613 gdk_xpm_destroy_notify (color_info);
615 if (color_hash != NULL)
616 g_hash_table_destroy (color_hash);
621 if (name_buf != NULL)
637 file_buffer (enum buffer_op op, gpointer handle)
639 struct file_handle *h = handle;
644 if (gdk_pixmap_seek_string (h->infile, "XPM", FALSE) != TRUE)
647 if (gdk_pixmap_seek_char (h->infile,'{') != TRUE)
649 /* Fall through to the next gdk_pixmap_seek_char. */
652 gdk_pixmap_seek_char (h->infile, '"');
653 fseek (h->infile, -1, SEEK_CUR);
654 /* Fall through to the gdk_pixmap_read_string. */
657 gdk_pixmap_read_string (h->infile, &h->buffer, &h->buffer_size);
665 gdk_pixmap_colormap_create_from_xpm (GdkWindow *window,
666 GdkColormap *colormap,
668 GdkColor *transparent_color,
669 const gchar *filename)
671 struct file_handle h;
672 GdkPixmap *pixmap = NULL;
674 memset (&h, 0, sizeof (h));
675 h.infile = fopen (filename, "rb");
676 if (h.infile != NULL)
678 pixmap = _gdk_pixmap_create_from_xpm (window, colormap, mask,
689 gdk_pixmap_create_from_xpm (GdkWindow *window,
691 GdkColor *transparent_color,
692 const gchar *filename)
694 return gdk_pixmap_colormap_create_from_xpm (window, NULL, mask,
695 transparent_color, filename);
707 mem_buffer (enum buffer_op op, gpointer handle)
709 struct mem_handle *h = handle;
715 if (h->data[h->offset])
716 return h->data[h->offset ++];
723 gdk_pixmap_colormap_create_from_xpm_d (GdkWindow *window,
724 GdkColormap *colormap,
726 GdkColor *transparent_color,
730 GdkPixmap *pixmap = NULL;
732 memset (&h, 0, sizeof (h));
734 pixmap = _gdk_pixmap_create_from_xpm (window, colormap, mask,
742 gdk_pixmap_create_from_xpm_d (GdkWindow *window,
744 GdkColor *transparent_color,
747 return gdk_pixmap_colormap_create_from_xpm_d (window, NULL, mask,
748 transparent_color, data);
752 gdk_pixmap_foreign_new (guint32 anid)
755 GdkWindowPrivate *window_private;
756 GdkWindowPrivate *private;
759 unsigned int x_ret, y_ret, w_ret, h_ret, bw_ret, depth_ret;
761 /* check to make sure we were passed something at
762 least a little sane */
763 g_return_val_if_fail((anid != 0), NULL);
765 /* set the pixmap to the passed in value */
767 /* get the root window */
768 window_private = &gdk_root_parent;
770 /* get information about the Pixmap to fill in the structure for
772 if (!XGetGeometry(window_private->xdisplay, xpixmap, &root_return,
773 &x_ret, &y_ret, &w_ret, &h_ret, &bw_ret, &depth_ret))
776 /* allocate a new gdk pixmap */
777 private = g_new(GdkWindowPrivate, 1);
778 pixmap = (GdkPixmap *)private;
780 private->xdisplay = window_private->xdisplay;
781 private->window_type = GDK_WINDOW_PIXMAP;
782 private->xwindow = xpixmap;
783 private->colormap = NULL;
784 private->parent = NULL;
787 private->width = w_ret;
788 private->height = h_ret;
789 private->resize_count = 0;
790 private->ref_count = 1;
791 private->destroyed = 0;
793 gdk_xid_table_insert(&private->xwindow, pixmap);
799 gdk_pixmap_ref (GdkPixmap *pixmap)
801 GdkWindowPrivate *private = (GdkWindowPrivate *)pixmap;
802 g_return_val_if_fail (pixmap != NULL, NULL);
804 private->ref_count += 1;
809 gdk_pixmap_unref (GdkPixmap *pixmap)
811 GdkWindowPrivate *private = (GdkWindowPrivate *)pixmap;
812 g_return_if_fail(pixmap != NULL);
814 private->ref_count -= 1;
815 if (private->ref_count == 0)
817 XFreePixmap (private->xdisplay, private->xwindow);
818 gdk_xid_table_remove (private->xwindow);
819 g_dataset_destroy (private);
825 gdk_bitmap_ref (GdkBitmap *bitmap)
827 return (GdkBitmap *)gdk_pixmap_ref ((GdkPixmap *)bitmap);
831 gdk_bitmap_unref (GdkBitmap *bitmap)
833 gdk_pixmap_unref ((GdkPixmap *)bitmap);