diff options
author | Tor Lillqvist <tml@src.gnome.org> | 1999-03-05 19:53:56 +0000 |
---|---|---|
committer | Tor Lillqvist <tml@src.gnome.org> | 1999-03-05 19:53:56 +0000 |
commit | 9f3b82e178d58786d754d814512db515b6c2f155 (patch) | |
tree | 1e92fa1cf0c05f5dad6744c0d802c20c16fb4962 /gdk/win32/gdkpixmap-win32.c | |
parent | ced58eb136565ad03326277a5248467dd9fe8eb3 (diff) | |
download | gdk-pixbuf-9f3b82e178d58786d754d814512db515b6c2f155.tar.gz |
Win32 version of GDK source files and resource files (cursors and icons).
Diffstat (limited to 'gdk/win32/gdkpixmap-win32.c')
-rw-r--r-- | gdk/win32/gdkpixmap-win32.c | 1059 |
1 files changed, 1059 insertions, 0 deletions
diff --git a/gdk/win32/gdkpixmap-win32.c b/gdk/win32/gdkpixmap-win32.c new file mode 100644 index 000000000..e8a6c0260 --- /dev/null +++ b/gdk/win32/gdkpixmap-win32.c @@ -0,0 +1,1059 @@ +/* GDK - The GIMP Drawing Kit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * Copyright (C) 1998-1999 Tor Lillqvist + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * 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> + +#include "gdk.h" +#include "gdkprivate.h" + +typedef struct +{ + gchar *color_string; + GdkColor color; + gint transparent; +} _GdkPixmapColor; + +typedef struct +{ + guint ncolors; + GdkColormap *colormap; + gulong pixels[1]; +} _GdkPixmapInfo; + +GdkPixmap* +gdk_pixmap_new (GdkWindow *window, + gint width, + gint height, + gint depth) +{ + GdkPixmap *pixmap; + GdkWindowPrivate *private; + GdkWindowPrivate *window_private; + struct { + BITMAPINFOHEADER bmiHeader; + union { + WORD bmiIndices[256]; + DWORD bmiMasks[3]; + RGBQUAD bmiColors[256]; + } u; + } bmi; + UINT iUsage; + HDC hdc; + GdkVisual *visual; + guchar *bits; + gint i; + + 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_private = (GdkWindowPrivate*) window; + if (window_private->destroyed) + return NULL; + + if (depth == -1) + depth = gdk_window_get_visual (window)->depth; + + GDK_NOTE (MISC, g_print ("gdk_pixmap_new: %dx%dx%d\n", width, height, depth)); + + private = g_new0 (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + private->window_type = GDK_WINDOW_PIXMAP; + + visual = gdk_window_get_visual (window); + +#if 0 + if (depth == 1) + { + if ((private->xwindow = + CreateBitmap (width, height, 1, 1, NULL)) == NULL) + { + g_warning ("gdk_pixmap_new: CreateBitmap failed"); + g_free (private); + return NULL; + } + + private->colormap = NULL; + } + else + { + if (depth != visual->depth) + g_warning ("gdk_pixmap_new: depth %d doesn't match display depth %d", + depth, visual->depth); + + if ((hdc = GetDC (window_private->xwindow)) == NULL) + { + g_warning ("gdk_pixmap_new: GetDC failed"); + g_free (private); + return NULL; + } + + if ((private->xwindow = + CreateCompatibleBitmap (hdc, width, height)) == NULL) + { + g_warning ("gdk_pixmap_new: %dx%d CreateCompatibleBitmap failed", + width, height); + ReleaseDC (window_private->xwindow, hdc); + g_free (private); + return NULL; + } + + ReleaseDC (window_private->xwindow, hdc); + + private->colormap = window_private->colormap; + if (private->colormap == NULL) + private->colormap = gdk_colormap_get_system (); + } +#else + + if ((hdc = GetDC (window_private->xwindow)) == NULL) + { + g_warning ("gdk_pixmap_new: GetDC failed"); + g_free (private); + return NULL; + } + + bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = width; + bmi.bmiHeader.biHeight = -height; + bmi.bmiHeader.biPlanes = 1; + if (depth == 15) + bmi.bmiHeader.biBitCount = 16; + else + bmi.bmiHeader.biBitCount = depth; +#if 1 + if (depth == 16) + bmi.bmiHeader.biCompression = BI_BITFIELDS; + else +#endif + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = 0; + bmi.bmiHeader.biXPelsPerMeter = + bmi.bmiHeader.biYPelsPerMeter = 0; + bmi.bmiHeader.biClrUsed = 0; + bmi.bmiHeader.biClrImportant = 0; + + iUsage = DIB_RGB_COLORS; + if (depth == 1) + { + bmi.u.bmiColors[0].rgbBlue = + bmi.u.bmiColors[0].rgbGreen = + bmi.u.bmiColors[0].rgbRed = 0x00; + bmi.u.bmiColors[0].rgbReserved = 0x00; + + bmi.u.bmiColors[1].rgbBlue = + bmi.u.bmiColors[1].rgbGreen = + bmi.u.bmiColors[1].rgbRed = 0xFF; + bmi.u.bmiColors[1].rgbReserved = 0x00; + private->colormap = NULL; + } + else + { + private->colormap = window_private->colormap; + if (private->colormap == NULL) + private->colormap = gdk_colormap_get_system (); + + if (depth == 8) + { + iUsage = DIB_PAL_COLORS; + for (i = 0; i < 256; i++) + bmi.u.bmiIndices[i] = i; + } + else + { + if (depth != visual->depth) + g_warning ("gdk_pixmap_new: depth %d doesn't match display depth %d", + depth, visual->depth); +#if 1 + if (depth == 16) + { + bmi.u.bmiMasks[0] = visual->red_mask; + bmi.u.bmiMasks[1] = visual->green_mask; + bmi.u.bmiMasks[2] = visual->blue_mask; + } +#endif + } + } + if ((private->xwindow = + CreateDIBSection (hdc, (BITMAPINFO *) &bmi, + iUsage, &bits, NULL, 0)) == NULL) + { + g_warning ("gdk_pixmap_new: CreateDIBSection failed: %d", GetLastError ()); + ReleaseDC (window_private->xwindow, hdc); + g_free (private); + return NULL; + } + ReleaseDC (window_private->xwindow, hdc); + +#endif + + GDK_NOTE (MISC, g_print ("... = %#x\n", private->xwindow)); + + private->parent = NULL; + private->x = 0; + private->y = 0; + private->width = width; + private->height = height; + private->resize_count = 0; + private->ref_count = 1; + private->destroyed = 0; + + gdk_xid_table_insert (&private->xwindow, pixmap); + + return pixmap; +} + +GdkPixmap * +gdk_pixmap_create_on_shared_image (GdkImage **image_return, + GdkWindow *window, + GdkVisual *visual, + gint width, + gint height, + gint depth) +{ + GdkPixmap *pixmap; + GdkImagePrivate *image_private; + GdkWindowPrivate *private; + GdkWindowPrivate *window_private; + + g_return_val_if_fail (window != NULL, NULL); + + window_private = (GdkWindowPrivate *) window; + + if (depth == 1) + *image_return = gdk_image_bitmap_new (GDK_IMAGE_SHARED_PIXMAP, visual, width, height); + else + { + g_return_val_if_fail (depth == visual->depth, NULL); + *image_return = gdk_image_new (GDK_IMAGE_SHARED_PIXMAP, visual, width, height); + } + + g_return_val_if_fail (*image_return != NULL, NULL); + + image_private = (GdkImagePrivate *) *image_return; + + private = g_new0 (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + private->xwindow = image_private->ximage; + private->window_type = GDK_WINDOW_PIXMAP; + private->colormap = window_private->colormap; + private->parent = NULL; + private->x = 0; + private->y = 0; + 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_NOTE (MISC, + g_print ("gdk_pixmap_create_on_shared_image: %dx%dx%d = %#x\n", + width, height, depth, private->xwindow)); + + return pixmap; +} + +static unsigned char mirror[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff +}; + +GdkPixmap * +gdk_bitmap_create_from_data (GdkWindow *window, + const gchar *data, + gint width, + gint height) +{ + GdkPixmap *pixmap; + GdkWindowPrivate *private; + GdkWindowPrivate *window_private; + gint i, j, bpl, aligned_bpl; + guchar *bits; + + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail ((width != 0) && (height != 0), NULL); + + if (!window) + window = (GdkWindow*) &gdk_root_parent; + + window_private = (GdkWindowPrivate*) window; + if (window_private->destroyed) + return NULL; + + private = g_new0 (GdkWindowPrivate, 1); + pixmap = (GdkPixmap*) private; + + private->parent = NULL; + 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; + + bpl = ((width - 1) / 8 + 1); + aligned_bpl = ((bpl - 1) / 2 + 1) * 2; + bits = g_malloc (aligned_bpl * height); + for (i = 0; i < height; i++) + for (j = 0; j < bpl; j++) + bits[i*aligned_bpl + j] = mirror[(guchar) data[i*bpl + j]]; + private->xwindow = CreateBitmap (width, height, 1, 1, bits); + + GDK_NOTE (MISC, g_print ("gdk_bitmap_create_from_data: %dx%d = %#x\n", + width, height, private->xwindow)); + + g_free (bits); + + private->colormap = NULL; + gdk_xid_table_insert (&private->xwindow, pixmap); + + return pixmap; +} + +GdkPixmap* +gdk_pixmap_create_from_data (GdkWindow *window, + const gchar *data, + gint width, + gint height, + gint depth, + GdkColor *fg, + GdkColor *bg) +{ + /* Oh wow. I struggled with dozens of lines of code trying to get + * this right using a monochrome Win32 bitmap created from data, and + * a colour DIB section as the result, trying setting pens, + * background colors, whatnot and BitBlt:ing. Nope. Then finally I + * realized it's much easier to do it using gdk...: + */ + + GdkPixmap *result = gdk_pixmap_new (window, width, height, depth); + GdkPixmap *source = gdk_bitmap_create_from_data (window, data, width, height); + GdkGC *gc = gdk_gc_new (result); + gdk_gc_set_foreground (gc, fg); + gdk_gc_set_background (gc, bg); + gdk_draw_pixmap (result, gc, source, 0, 0, 0, 0, width, height); + gdk_pixmap_unref (source); + gdk_gc_unref (gc); + + GDK_NOTE (MISC, g_print ("gdk_pixmap_create_from_data: %dx%dx%d = %#x\n", + width, height, depth, + ((GdkPixmapPrivate *) result)->xwindow)); + return result; +} + +static gint +gdk_pixmap_seek_string (FILE *infile, + const gchar *str, + gint skip_comments) +{ + char instr[1024]; + + while (!feof (infile)) + { + fscanf (infile, "%1023s", instr); + 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); + } + if (strcmp (instr, str)==0) + return TRUE; + } + + return FALSE; +} + +static gint +gdk_pixmap_seek_char (FILE *infile, + gchar c) +{ + gint b, oldb; + + while ((b = getc(infile)) != EOF) + { + if (c != b && 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 == '/')); + } + } + else if (c == b) + return TRUE; + } + return FALSE; +} + +static gint +gdk_pixmap_read_string (FILE *infile, + gchar **buffer, + guint *buffer_size) +{ + gint c; + guint cnt = 0, bufsiz, ret = FALSE; + gchar *buf; + + buf = *buffer; + bufsiz = *buffer_size; + if (buf == NULL) + { + bufsiz = 10 * sizeof (gchar); + buf = g_new(gchar, bufsiz); + } + + do + c = getc (infile); + while (c != EOF && c != '"'); + + if (c != '"') + goto out; + + while ((c = getc(infile)) != EOF) + { + if (cnt == bufsiz) + { + 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 != '"') + buf[cnt++] = c; + else + { + buf[cnt] = 0; + ret = TRUE; + break; + } + } + + out: + buf[bufsiz-1] = '\0'; /* ensure null termination for errors */ + *buffer = buf; + *buffer_size = bufsiz; + return ret; +} + +static gchar* +gdk_pixmap_skip_whitespaces (gchar *buffer) +{ + gint32 index = 0; + + while (buffer[index] != 0 && (buffer[index] == 0x20 || buffer[index] == 0x09)) + index++; + + return &buffer[index]; +} + +static gchar* +gdk_pixmap_skip_string (gchar *buffer) +{ + gint32 index = 0; + + while (buffer[index] != 0 && buffer[index] != 0x20 && buffer[index] != 0x09) + index++; + + return &buffer[index]; +} + +#define MAX_COLOR_LEN 120 + +static gchar* +gdk_pixmap_extract_color (gchar *buffer) +{ + gint counter, numnames; + gchar *ptr = NULL, ch, temp[128]; + gchar color[MAX_COLOR_LEN], *retcol; + gint space; + + counter = 0; + while (ptr == NULL) + { + if (buffer[counter] == 'c') + { + ch = buffer[counter + 1]; + if (ch == 0x20 || ch == 0x09) + ptr = &buffer[counter + 1]; + } + else if (buffer[counter] == 0) + return NULL; + + counter++; + } + + ptr = gdk_pixmap_skip_whitespaces (ptr); + + if (ptr[0] == 0) + return NULL; + else if (ptr[0] == '#') + { + 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; + + space = MAX_COLOR_LEN - 1; + while (space > 0) + { + 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)) + { + break; + } + else + { + if (numnames > 0) + { + 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_strdup (color); + return retcol; +} + + +enum buffer_op +{ + op_header, + op_cmap, + 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, + GdkColormap *colormap, + GdkBitmap **mask, + GdkColor *transparent_color, + gchar * (*get_buf) (enum buffer_op op, + gpointer handle), + gpointer handle) +{ + GdkPixmap *pixmap = NULL; + GdkImage *image = NULL; + GdkVisual *visual; + GdkGC *gc = NULL; + 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 *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; + + if (colormap == NULL) + { + colormap = gdk_window_get_colormap (window); + visual = gdk_window_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); + if (cpp >= 32) + { + g_warning ("Pixmap has more than 31 characters per color"); + 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 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; + + 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 || + gdk_color_parse (color_name, &color->color) == FALSE) + { + color->color = *transparent_color; + color->transparent = TRUE; + } + + 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); + + 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); + } + + wbytes = width * cpp; + for (ycnt = 0; ycnt < height; ycnt++) + { + 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; + ns = 0; + + 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) + 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); + } + + error: + + if (mask) + gdk_gc_destroy (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); + } + else if (color_info) + gdk_xpm_destroy_notify (color_info); + + if (color_hash != NULL) + g_hash_table_destroy (color_hash); + + if (colors != NULL) + g_free (colors); + + if (name_buf != NULL) + g_free (name_buf); + + 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) + { + pixmap = _gdk_pixmap_create_from_xpm (window, colormap, mask, + transparent_color, + file_buffer, &h); + fclose (h.infile); + g_free (h.buffer); + } + + return 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 +{ + gchar **data; + int offset; +}; + + +static gchar * +mem_buffer (enum buffer_op op, gpointer handle) +{ + struct mem_handle *h = handle; + switch (op) + { + 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; + GdkWindowPrivate *window_private; + GdkWindowPrivate *private; + HBITMAP xpixmap; + SIZE size; + 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 = (HBITMAP) anid; + /* get the root window */ + window_private = &gdk_root_parent; + + /* get information about the BITMAP to fill in the structure for + the gdk window */ + GetBitmapDimensionEx (xpixmap, &size); + w_ret = size.cx; + h_ret = size.cy; + + /* allocate a new gdk pixmap */ + private = g_new(GdkWindowPrivate, 1); + pixmap = (GdkPixmap *)private; + + private->window_type = GDK_WINDOW_PIXMAP; + private->xwindow = xpixmap; + private->colormap = NULL; + private->parent = NULL; + private->x = 0; + private->y = 0; + private->width = w_ret; + private->height = h_ret; + private->resize_count = 0; + private->ref_count = 1; + private->destroyed = 0; + + gdk_xid_table_insert(&private->xwindow, pixmap); + + return pixmap; +} + +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) +{ + GdkWindowPrivate *private = (GdkWindowPrivate *)pixmap; + g_return_if_fail(pixmap != NULL); + + private->ref_count -= 1; + + GDK_NOTE (MISC, g_print ("gdk_pixmap_unref: %#x %d%s\n", + private->xwindow, private->ref_count, + (private->ref_count == 0 ? " freeing" : ""))); + + if (private->ref_count == 0) + { + if (!DeleteObject (private->xwindow)) + g_warning ("gdk_pixmap_unref: DeleteObject failed"); + gdk_xid_table_remove (private->xwindow); + g_dataset_destroy (private); + g_free (private); + } +} + +GdkBitmap * +gdk_bitmap_ref (GdkBitmap *bitmap) +{ + return (GdkBitmap *)gdk_pixmap_ref ((GdkPixmap *)bitmap); +} + +void +gdk_bitmap_unref (GdkBitmap *bitmap) +{ + gdk_pixmap_unref ((GdkPixmap *)bitmap); +} |