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 */
36 #include "gdkprivate.h"
48 GdkColormap *colormap;
53 gdk_pixmap_new (GdkWindow *window,
59 GdkWindowPrivate *private;
60 GdkWindowPrivate *window_private;
62 g_return_val_if_fail ((window != NULL) || (depth != -1), NULL);
63 g_return_val_if_fail ((width != 0) && (height != 0), NULL);
66 window = (GdkWindow*) &gdk_root_parent;
68 window_private = (GdkWindowPrivate*) window;
69 if (window_private->destroyed)
73 depth = gdk_window_get_visual (window)->depth;
75 private = g_new0 (GdkWindowPrivate, 1);
76 pixmap = (GdkPixmap*) private;
78 private->xdisplay = window_private->xdisplay;
79 private->window_type = GDK_WINDOW_PIXMAP;
80 private->xwindow = XCreatePixmap (private->xdisplay, window_private->xwindow,
81 width, height, depth);
82 private->colormap = NULL;
83 private->parent = NULL;
86 private->width = width;
87 private->height = height;
88 private->resize_count = 0;
89 private->ref_count = 1;
90 private->destroyed = 0;
92 gdk_xid_table_insert (&private->xwindow, pixmap);
98 gdk_bitmap_create_from_data (GdkWindow *window,
104 GdkWindowPrivate *private;
105 GdkWindowPrivate *window_private;
107 g_return_val_if_fail (data != NULL, NULL);
108 g_return_val_if_fail ((width != 0) && (height != 0), NULL);
111 window = (GdkWindow*) &gdk_root_parent;
113 window_private = (GdkWindowPrivate*) window;
114 if (window_private->destroyed)
117 private = g_new0 (GdkWindowPrivate, 1);
118 pixmap = (GdkPixmap*) private;
120 private->parent = NULL;
121 private->xdisplay = window_private->xdisplay;
122 private->window_type = GDK_WINDOW_PIXMAP;
125 private->width = width;
126 private->height = height;
127 private->resize_count = 0;
128 private->ref_count = 1;
129 private->destroyed = FALSE;
131 private->xwindow = XCreateBitmapFromData (private->xdisplay,
132 window_private->xwindow,
133 (char *)data, width, height);
135 gdk_xid_table_insert (&private->xwindow, pixmap);
141 gdk_pixmap_create_from_data (GdkWindow *window,
150 GdkWindowPrivate *private;
151 GdkWindowPrivate *window_private;
153 g_return_val_if_fail (data != NULL, NULL);
154 g_return_val_if_fail (fg != NULL, NULL);
155 g_return_val_if_fail (bg != NULL, NULL);
156 g_return_val_if_fail ((window != NULL) || (depth != -1), NULL);
157 g_return_val_if_fail ((width != 0) && (height != 0), NULL);
160 window = (GdkWindow*) &gdk_root_parent;
162 window_private = (GdkWindowPrivate*) window;
163 if (window_private->destroyed)
167 depth = gdk_window_get_visual (window)->depth;
169 private = g_new0 (GdkWindowPrivate, 1);
170 pixmap = (GdkPixmap*) private;
172 private->parent = NULL;
173 private->xdisplay = window_private->xdisplay;
174 private->window_type = GDK_WINDOW_PIXMAP;
177 private->width = width;
178 private->height = height;
179 private->resize_count = 0;
180 private->ref_count = 1;
181 private->destroyed = FALSE;
183 private->xwindow = XCreatePixmapFromBitmapData (private->xdisplay,
184 window_private->xwindow,
185 (char *)data, width, height,
186 fg->pixel, bg->pixel, depth);
188 gdk_xid_table_insert (&private->xwindow, pixmap);
194 gdk_pixmap_seek_string (FILE *infile,
200 while (!feof (infile))
202 fscanf (infile, "%1023s", instr);
203 if (skip_comments == TRUE && strcmp (instr, "/*") == 0)
205 fscanf (infile, "%1023s", instr);
206 while (!feof (infile) && strcmp (instr, "*/") != 0)
207 fscanf (infile, "%1023s", instr);
208 fscanf(infile, "%1023s", instr);
210 if (strcmp (instr, str)==0)
218 gdk_pixmap_seek_char (FILE *infile,
223 while ((b = getc(infile)) != EOF)
225 if (c != b && b == '/')
230 else if (b == '*') /* we have a comment */
240 while (!(oldb == '*' && b == '/'));
250 gdk_pixmap_read_string (FILE *infile,
255 guint cnt = 0, bufsiz, ret = FALSE;
259 bufsiz = *buffer_size;
262 bufsiz = 10 * sizeof (gchar);
263 buf = g_new(gchar, bufsiz);
268 while (c != EOF && c != '"');
273 while ((c = getc(infile)) != EOF)
277 guint new_size = bufsiz * 2;
278 if (new_size > bufsiz)
283 buf = (gchar *) g_realloc (buf, bufsiz);
284 buf[bufsiz-1] = '\0';
298 buf[bufsiz-1] = '\0'; /* ensure null termination for errors */
300 *buffer_size = bufsiz;
305 gdk_pixmap_skip_whitespaces (gchar *buffer)
309 while (buffer[index] != 0 && (buffer[index] == 0x20 || buffer[index] == 0x09))
312 return &buffer[index];
316 gdk_pixmap_skip_string (gchar *buffer)
320 while (buffer[index] != 0 && buffer[index] != 0x20 && buffer[index] != 0x09)
323 return &buffer[index];
326 /* Xlib crashed ince at a color name lengths around 125 */
327 #define MAX_COLOR_LEN 120
330 gdk_pixmap_extract_color (gchar *buffer)
332 gint counter, numnames;
333 gchar *ptr = NULL, ch, temp[128];
334 gchar color[MAX_COLOR_LEN], *retcol;
340 if (buffer[counter] == 'c')
342 ch = buffer[counter + 1];
343 if (ch == 0x20 || ch == 0x09)
344 ptr = &buffer[counter + 1];
346 else if (buffer[counter] == 0)
352 ptr = gdk_pixmap_skip_whitespaces (ptr);
356 else if (ptr[0] == '#')
359 while (ptr[counter] != 0 &&
360 ((ptr[counter] >= '0' && ptr[counter] <= '9') ||
361 (ptr[counter] >= 'a' && ptr[counter] <= 'f') ||
362 (ptr[counter] >= 'A' && ptr[counter] <= 'F')))
365 retcol = g_new (gchar, counter+1);
366 strncpy (retcol, ptr, counter);
376 space = MAX_COLOR_LEN - 1;
379 sscanf (ptr, "%127s", temp);
381 if (((gint)ptr[0] == 0) ||
382 (strcmp ("s", temp) == 0) || (strcmp ("m", temp) == 0) ||
383 (strcmp ("g", temp) == 0) || (strcmp ("g4", temp) == 0))
394 strncat (color, temp, space);
395 space -= MIN (space, strlen (temp));
396 ptr = gdk_pixmap_skip_string (ptr);
397 ptr = gdk_pixmap_skip_whitespaces (ptr);
402 retcol = g_strdup (color);
416 gdk_xpm_destroy_notify (gpointer data)
418 _GdkPixmapInfo *info = (_GdkPixmapInfo *)data;
422 for (i=0; i<info->ncolors; i++)
424 color.pixel = info->pixels[i];
425 gdk_colormap_free_colors (info->colormap, &color, 1);
428 gdk_colormap_unref (info->colormap);
433 _gdk_pixmap_create_from_xpm (GdkWindow *window,
434 GdkColormap *colormap,
436 GdkColor *transparent_color,
437 gchar * (*get_buf) (enum buffer_op op,
441 GdkPixmap *pixmap = NULL;
442 GdkImage *image = NULL;
446 gint width, height, num_cols, cpp, n, ns, cnt, xcnt, ycnt, wbytes;
447 gchar *buffer, pixel_str[32];
449 _GdkPixmapColor *color = NULL, *fallbackcolor = NULL;
450 _GdkPixmapColor *colors = NULL;
452 GHashTable *color_hash = NULL;
453 _GdkPixmapInfo *color_info = NULL;
455 if ((window == NULL) && (colormap == NULL))
456 g_warning ("Creating pixmap from xpm with NULL window and colormap");
459 window = (GdkWindow *)&gdk_root_parent;
461 if (colormap == NULL)
463 colormap = gdk_window_get_colormap (window);
464 visual = gdk_window_get_visual (window);
467 visual = ((GdkColormapPrivate *)colormap)->visual;
469 buffer = (*get_buf) (op_header, handle);
473 sscanf (buffer,"%d %d %d %d", &width, &height, &num_cols, &cpp);
476 g_warning ("Pixmap has more than 31 characters per color\n");
480 color_hash = g_hash_table_new (g_str_hash, g_str_equal);
482 if (transparent_color == NULL)
484 gdk_color_white (colormap, &tmp_color);
485 transparent_color = &tmp_color;
488 /* For pseudo-color and grayscale visuals, we have to remember
489 * the colors we allocated, so we can free them later.
491 if ((visual->type == GDK_VISUAL_PSEUDO_COLOR) ||
492 (visual->type == GDK_VISUAL_GRAYSCALE))
494 color_info = g_malloc (sizeof (_GdkPixmapInfo) +
495 sizeof(gulong) * (num_cols - 1));
496 color_info->ncolors = num_cols;
497 color_info->colormap = colormap;
498 gdk_colormap_ref (colormap);
501 name_buf = g_new (gchar, num_cols * (cpp+1));
502 colors = g_new (_GdkPixmapColor, num_cols);
504 for (cnt = 0; cnt < num_cols; cnt++)
508 buffer = (*get_buf) (op_cmap, handle);
512 color = &colors[cnt];
513 color->color_string = &name_buf [cnt * (cpp + 1)];
514 strncpy (color->color_string, buffer, cpp);
515 color->color_string[cpp] = 0;
516 buffer += strlen (color->color_string);
517 color->transparent = FALSE;
519 color_name = gdk_pixmap_extract_color (buffer);
521 if (color_name == NULL ||
522 gdk_color_parse (color_name, &color->color) == FALSE)
524 color->color = *transparent_color;
525 color->transparent = TRUE;
530 /* FIXME: The remaining slowness appears to happen in this
532 gdk_color_alloc (colormap, &color->color);
535 color_info->pixels[cnt] = color->color.pixel;
537 g_hash_table_insert (color_hash, color->color_string, color);
539 fallbackcolor = color;
543 image = gdk_image_new (GDK_IMAGE_FASTEST, visual, width, height);
547 /* The pixmap mask is just a bits pattern.
548 * Color 0 is used for background and 1 for foreground.
549 * We don't care about the colormap, we just need 0 and 1.
551 GdkColor mask_pattern;
553 *mask = gdk_pixmap_new (window, width, height, 1);
554 gc = gdk_gc_new (*mask);
556 mask_pattern.pixel = 0;
557 gdk_gc_set_foreground (gc, &mask_pattern);
558 gdk_draw_rectangle (*mask, gc, TRUE, 0, 0, -1, -1);
560 mask_pattern.pixel = 1;
561 gdk_gc_set_foreground (gc, &mask_pattern);
564 wbytes = width * cpp;
565 for (ycnt = 0; ycnt < height; ycnt++)
567 buffer = (*get_buf) (op_body, handle);
569 /* FIXME: this slows things down a little - it could be
570 * integrated into the strncpy below, perhaps. OTOH, strlen
573 if ((buffer == NULL) || strlen (buffer) < wbytes)
576 for (n = 0, cnt = 0, xcnt = 0; n < wbytes; n += cpp, xcnt++)
578 strncpy (pixel_str, &buffer[n], cpp);
582 color = g_hash_table_lookup (color_hash, pixel_str);
584 if (!color) /* screwed up XPM file */
585 color = fallbackcolor;
587 gdk_image_put_pixel (image, xcnt, ycnt, color->color.pixel);
589 if (mask && color->transparent)
592 gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt);
597 if (mask && (cnt < xcnt))
598 gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt);
608 pixmap = gdk_pixmap_new (window, width, height, visual->depth);
611 gdk_drawable_set_data (pixmap, "gdk-xpm", color_info,
612 gdk_xpm_destroy_notify);
614 gc = gdk_gc_new (pixmap);
615 gdk_gc_set_foreground (gc, transparent_color);
616 gdk_draw_image (pixmap, gc, image, 0, 0, 0, 0, image->width, image->height);
618 gdk_image_destroy (image);
621 gdk_xpm_destroy_notify (color_info);
623 if (color_hash != NULL)
624 g_hash_table_destroy (color_hash);
629 if (name_buf != NULL)
645 file_buffer (enum buffer_op op, gpointer handle)
647 struct file_handle *h = handle;
652 if (gdk_pixmap_seek_string (h->infile, "XPM", FALSE) != TRUE)
655 if (gdk_pixmap_seek_char (h->infile,'{') != TRUE)
657 /* Fall through to the next gdk_pixmap_seek_char. */
660 gdk_pixmap_seek_char (h->infile, '"');
661 fseek (h->infile, -1, SEEK_CUR);
662 /* Fall through to the gdk_pixmap_read_string. */
665 gdk_pixmap_read_string (h->infile, &h->buffer, &h->buffer_size);
673 gdk_pixmap_colormap_create_from_xpm (GdkWindow *window,
674 GdkColormap *colormap,
676 GdkColor *transparent_color,
677 const gchar *filename)
679 struct file_handle h;
680 GdkPixmap *pixmap = NULL;
682 memset (&h, 0, sizeof (h));
683 h.infile = fopen (filename, "rb");
684 if (h.infile != NULL)
686 pixmap = _gdk_pixmap_create_from_xpm (window, colormap, mask,
697 gdk_pixmap_create_from_xpm (GdkWindow *window,
699 GdkColor *transparent_color,
700 const gchar *filename)
702 return gdk_pixmap_colormap_create_from_xpm (window, NULL, mask,
703 transparent_color, filename);
715 mem_buffer (enum buffer_op op, gpointer handle)
717 struct mem_handle *h = handle;
723 if (h->data[h->offset])
724 return h->data[h->offset ++];
731 gdk_pixmap_colormap_create_from_xpm_d (GdkWindow *window,
732 GdkColormap *colormap,
734 GdkColor *transparent_color,
738 GdkPixmap *pixmap = NULL;
740 memset (&h, 0, sizeof (h));
742 pixmap = _gdk_pixmap_create_from_xpm (window, colormap, mask,
750 gdk_pixmap_create_from_xpm_d (GdkWindow *window,
752 GdkColor *transparent_color,
755 return gdk_pixmap_colormap_create_from_xpm_d (window, NULL, mask,
756 transparent_color, data);
760 gdk_pixmap_foreign_new (guint32 anid)
763 GdkWindowPrivate *window_private;
764 GdkWindowPrivate *private;
767 unsigned int x_ret, y_ret, w_ret, h_ret, bw_ret, depth_ret;
769 /* check to make sure we were passed something at
770 least a little sane */
771 g_return_val_if_fail((anid != 0), NULL);
773 /* set the pixmap to the passed in value */
775 /* get the root window */
776 window_private = &gdk_root_parent;
778 /* get information about the Pixmap to fill in the structure for
780 if (!XGetGeometry(window_private->xdisplay, xpixmap, &root_return,
781 &x_ret, &y_ret, &w_ret, &h_ret, &bw_ret, &depth_ret))
784 /* allocate a new gdk pixmap */
785 private = g_new(GdkWindowPrivate, 1);
786 pixmap = (GdkPixmap *)private;
788 private->xdisplay = window_private->xdisplay;
789 private->window_type = GDK_WINDOW_PIXMAP;
790 private->xwindow = xpixmap;
791 private->colormap = NULL;
792 private->parent = NULL;
795 private->width = w_ret;
796 private->height = h_ret;
797 private->resize_count = 0;
798 private->ref_count = 1;
799 private->destroyed = 0;
801 gdk_xid_table_insert(&private->xwindow, pixmap);
807 gdk_pixmap_ref (GdkPixmap *pixmap)
809 GdkWindowPrivate *private = (GdkWindowPrivate *)pixmap;
810 g_return_val_if_fail (pixmap != NULL, NULL);
812 private->ref_count += 1;
817 gdk_pixmap_unref (GdkPixmap *pixmap)
819 GdkWindowPrivate *private = (GdkWindowPrivate *)pixmap;
820 g_return_if_fail(pixmap != NULL);
822 private->ref_count -= 1;
823 if (private->ref_count == 0)
825 XFreePixmap (private->xdisplay, private->xwindow);
826 gdk_xid_table_remove (private->xwindow);
827 g_dataset_destroy (private);
833 gdk_bitmap_ref (GdkBitmap *bitmap)
835 return (GdkBitmap *)gdk_pixmap_ref ((GdkPixmap *)bitmap);
839 gdk_bitmap_unref (GdkBitmap *bitmap)
841 gdk_pixmap_unref ((GdkPixmap *)bitmap);