]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkpixmap.c
Add new keysyms from X11R6.4 (including EuroSign).
[~andy/gtk] / gdk / win32 / gdkpixmap.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  * Copyright (C) 1998-1999 Tor Lillqvist
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /*
22  * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
23  * file for a list of people on the GTK+ Team.  See the ChangeLog
24  * files for a list of changes.  These files are distributed with
25  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
26  */
27
28 #include "config.h"
29
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33
34 #include "gdkpixmap.h"
35 #include "gdkprivate.h"
36 #include "gdkx.h"
37
38 typedef struct
39 {
40   gchar *color_string;
41   GdkColor color;
42   gint transparent;
43 } _GdkPixmapColor;
44
45 typedef struct
46 {
47   guint ncolors;
48   GdkColormap *colormap;
49   gulong pixels[1];
50 } _GdkPixmapInfo;
51
52 GdkPixmap*
53 gdk_pixmap_new (GdkWindow *window,
54                 gint       width,
55                 gint       height,
56                 gint       depth)
57 {
58   GdkPixmap *pixmap;
59   GdkDrawablePrivate *private;
60   GdkWindowPrivate *window_private;
61   struct {
62     BITMAPINFOHEADER bmiHeader;
63     union {
64       WORD bmiIndices[256];
65       DWORD bmiMasks[3];
66       RGBQUAD bmiColors[256];
67     } u;
68   } bmi;
69   UINT iUsage;
70   HDC hdc;
71   GdkVisual *visual;
72   guchar *bits;
73   gint i;
74
75   g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
76   g_return_val_if_fail ((window != NULL) || (depth != -1), NULL);
77   g_return_val_if_fail ((width != 0) && (height != 0), NULL);
78
79   if (!window)
80     window = (GdkWindow*) gdk_root_parent;
81
82   if (GDK_DRAWABLE_DESTROYED (window))
83     return NULL;
84   window_private = (GdkWindowPrivate*) window;
85
86   if (depth == -1)
87     depth = gdk_drawable_get_visual (window)->depth;
88
89   GDK_NOTE (MISC, g_print ("gdk_pixmap_new: %dx%dx%d\n",
90                            width, height, depth));
91
92   private = g_new0 (GdkDrawablePrivate, 1);
93   pixmap = (GdkPixmap*) private;
94
95   private->window_type = GDK_DRAWABLE_PIXMAP;
96
97   visual = gdk_drawable_get_visual (window);
98
99   if ((hdc = GetDC (GDK_DRAWABLE_XID (window))) == NULL)
100     {
101       g_warning ("gdk_pixmap_new: GetDC failed");
102       g_free (private);
103       return NULL;
104     }
105
106   bmi.bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
107   bmi.bmiHeader.biWidth = width;
108   bmi.bmiHeader.biHeight = -height;
109   bmi.bmiHeader.biPlanes = 1;
110   if (depth == 15)
111     bmi.bmiHeader.biBitCount = 16;
112   else
113     bmi.bmiHeader.biBitCount = depth;
114 #if 1
115   if (depth == 16)
116     bmi.bmiHeader.biCompression = BI_BITFIELDS;
117   else
118 #endif
119     bmi.bmiHeader.biCompression = BI_RGB;
120   bmi.bmiHeader.biSizeImage = 0;
121   bmi.bmiHeader.biXPelsPerMeter =
122     bmi.bmiHeader.biYPelsPerMeter = 0;
123   bmi.bmiHeader.biClrUsed = 0;
124   bmi.bmiHeader.biClrImportant = 0;
125
126   iUsage = DIB_RGB_COLORS;
127   if (depth == 1)
128     {
129       bmi.u.bmiColors[0].rgbBlue =
130         bmi.u.bmiColors[0].rgbGreen =
131         bmi.u.bmiColors[0].rgbRed = 0x00;
132       bmi.u.bmiColors[0].rgbReserved = 0x00;
133
134       bmi.u.bmiColors[1].rgbBlue =
135         bmi.u.bmiColors[1].rgbGreen =
136       bmi.u.bmiColors[1].rgbRed = 0xFF;
137       bmi.u.bmiColors[1].rgbReserved = 0x00;
138       private->colormap = NULL;
139     }
140   else
141     {
142       private->colormap = window_private->drawable.colormap;
143       if (private->colormap == NULL)
144         private->colormap = gdk_colormap_get_system ();
145
146       if (depth == 8)
147         {
148           iUsage = DIB_PAL_COLORS;
149           for (i = 0; i < 256; i++)
150             bmi.u.bmiIndices[i] = i;
151         }
152       else
153         {
154           if (depth != visual->depth)
155             g_warning ("gdk_pixmap_new: depth %d doesn't match display depth %d",
156                        depth, visual->depth);
157 #if 1
158           if (depth == 16)
159             {
160               bmi.u.bmiMasks[0] = visual->red_mask;
161               bmi.u.bmiMasks[1] = visual->green_mask;
162               bmi.u.bmiMasks[2] = visual->blue_mask;
163             }
164 #endif
165         }
166     }
167   if ((private->xwindow =
168        CreateDIBSection (hdc, (BITMAPINFO *) &bmi,
169                          iUsage, (PVOID *) &bits, NULL, 0)) == NULL)
170     {
171       g_warning ("gdk_pixmap_new: CreateDIBSection failed: %d", GetLastError ());
172       ReleaseDC (GDK_DRAWABLE_XID (window), hdc);
173       g_free (private);
174       return NULL;
175     }
176   ReleaseDC (GDK_DRAWABLE_XID (window), hdc);
177
178   GDK_NOTE (MISC, g_print ("... = %#x\n", private->xwindow));
179
180   private->width = width;
181   private->height = height;
182   private->ref_count = 1;
183   private->destroyed = 0;
184
185   gdk_xid_table_insert (&private->xwindow, pixmap);
186
187   return pixmap;
188 }
189
190 GdkPixmap *
191 gdk_pixmap_create_on_shared_image (GdkImage **image_return,
192                                    GdkWindow *window,
193                                    GdkVisual *visual,
194                                    gint       width,
195                                    gint       height,
196                                    gint       depth)
197 {
198   GdkPixmap *pixmap;
199   GdkImagePrivate *image_private;
200   GdkDrawablePrivate *private;
201   GdkWindowPrivate *window_private;
202
203   g_return_val_if_fail (window != NULL, NULL);
204
205   window_private = (GdkWindowPrivate *) window;
206
207   if (depth == 1)
208     *image_return = gdk_image_bitmap_new (GDK_IMAGE_SHARED_PIXMAP, visual, width, height);
209   else
210     {
211       g_return_val_if_fail (depth == visual->depth, NULL);
212       *image_return = gdk_image_new (GDK_IMAGE_SHARED_PIXMAP, visual, width, height);
213     }
214
215   g_return_val_if_fail (*image_return != NULL, NULL);
216
217   image_private = (GdkImagePrivate *) *image_return;
218
219   private = g_new0 (GdkDrawablePrivate, 1);
220   pixmap = (GdkPixmap*) private;
221
222   private->xwindow = image_private->ximage;
223   private->window_type = GDK_DRAWABLE_PIXMAP;
224   private->colormap = window_private->drawable.colormap;
225   private->width = width;
226   private->height = height;
227   private->ref_count = 1;
228   private->destroyed = 0;
229
230   gdk_xid_table_insert (&private->xwindow, pixmap);
231
232   GDK_NOTE (MISC,
233             g_print ("gdk_pixmap_create_on_shared_image: %dx%dx%d = %#x\n",
234                      width, height, depth, private->xwindow));
235
236   return pixmap;
237 }
238
239 static unsigned char mirror[256] = {
240   0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
241   0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
242   0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
243   0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
244   0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
245   0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
246   0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
247   0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
248   0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
249   0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
250   0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
251   0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
252   0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
253   0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
254   0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
255   0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
256   0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
257   0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
258   0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
259   0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
260   0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
261   0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
262   0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
263   0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
264   0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
265   0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
266   0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
267   0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
268   0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
269   0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
270   0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
271   0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
272 };
273
274 GdkPixmap *
275 gdk_bitmap_create_from_data (GdkWindow   *window,
276                              const gchar *data,
277                              gint         width,
278                              gint         height)
279 {
280   GdkPixmap *pixmap;
281   GdkDrawablePrivate *private;
282   gint i, j, bpl, aligned_bpl;
283   guchar *bits;
284
285   g_return_val_if_fail (data != NULL, NULL);
286   g_return_val_if_fail ((width != 0) && (height != 0), NULL);
287   g_return_val_if_fail (window == NULL || GDK_IS_WINDOW (window), NULL);
288
289   if (!window)
290     window = (GdkWindow*) gdk_root_parent;
291
292   if (GDK_DRAWABLE_DESTROYED (window))
293     return NULL;
294
295   private = g_new0 (GdkDrawablePrivate, 1);
296   pixmap = (GdkPixmap*) private;
297
298   private->window_type = GDK_DRAWABLE_PIXMAP;
299   private->width = width;
300   private->height = height;
301   private->ref_count = 1;
302   private->destroyed = FALSE;
303
304   bpl = ((width - 1) / 8 + 1);
305   aligned_bpl = ((bpl - 1) / 2 + 1) * 2;
306   bits = g_malloc (aligned_bpl * height);
307   for (i = 0; i < height; i++)
308     for (j = 0; j < bpl; j++)
309       bits[i*aligned_bpl + j] = mirror[(guchar) data[i*bpl + j]];
310   private->xwindow = CreateBitmap (width, height, 1, 1, bits);
311
312   GDK_NOTE (MISC, g_print ("gdk_bitmap_create_from_data: %dx%d = %#x\n",
313                            width, height, private->xwindow));
314
315   g_free (bits);
316
317   private->colormap = NULL;
318   gdk_xid_table_insert (&private->xwindow, pixmap);
319
320   return pixmap;
321 }
322
323 GdkPixmap*
324 gdk_pixmap_create_from_data (GdkWindow   *window,
325                              const gchar *data,
326                              gint         width,
327                              gint         height,
328                              gint         depth,
329                              GdkColor    *fg,
330                              GdkColor    *bg)
331 {
332   /* Oh wow. I struggled with dozens of lines of code trying to get
333    * this right using a monochrome Win32 bitmap created from data, and
334    * a colour DIB section as the result, trying setting pens,
335    * background colors, whatnot and BitBlt:ing.  Nope. Then finally I
336    * realized it's much easier to do it using gdk...:
337    */
338
339   GdkPixmap *result = gdk_pixmap_new (window, width, height, depth);
340   GdkPixmap *source = gdk_bitmap_create_from_data (window, data, width, height);
341   GdkGC *gc = gdk_gc_new (result);
342   gdk_gc_set_foreground (gc, fg);
343   gdk_gc_set_background (gc, bg);
344   gdk_draw_pixmap (result, gc, source, 0, 0, 0, 0, width, height);
345   gdk_pixmap_unref (source);
346   gdk_gc_unref (gc);
347
348   GDK_NOTE (MISC, g_print ("gdk_pixmap_create_from_data: %dx%dx%d = %#x\n",
349                            width, height, depth,
350                            GDK_DRAWABLE_XID (result)));
351   return result;
352 }
353
354 static gint
355 gdk_pixmap_seek_string (FILE  *infile,
356                         const gchar *str,
357                         gint   skip_comments)
358 {
359   char instr[1024];
360
361   while (!feof (infile))
362     {
363       fscanf (infile, "%1023s", instr);
364       if (skip_comments == TRUE && strcmp (instr, "/*") == 0)
365         {
366           fscanf (infile, "%1023s", instr);
367           while (!feof (infile) && strcmp (instr, "*/") != 0)
368             fscanf (infile, "%1023s", instr);
369           fscanf(infile, "%1023s", instr);
370         }
371       if (strcmp (instr, str)==0)
372         return TRUE;
373     }
374
375   return FALSE;
376 }
377
378 static gint
379 gdk_pixmap_seek_char (FILE  *infile,
380                       gchar  c)
381 {
382   gint b, oldb;
383
384   while ((b = getc(infile)) != EOF)
385     {
386       if (c != b && b == '/')
387         {
388           b = getc (infile);
389           if (b == EOF)
390             return FALSE;
391           else if (b == '*')    /* we have a comment */
392             {
393               b = -1;
394               do
395                 {
396                   oldb = b;
397                   b = getc (infile);
398                   if (b == EOF)
399                     return FALSE;
400                 }
401               while (!(oldb == '*' && b == '/'));
402             }
403         }
404       else if (c == b)
405         return TRUE;
406     }
407   return FALSE;
408 }
409
410 static gint
411 gdk_pixmap_read_string (FILE  *infile,
412                         gchar **buffer,
413                         guint *buffer_size)
414 {
415   gint c;
416   guint cnt = 0, bufsiz, ret = FALSE;
417   gchar *buf;
418
419   buf = *buffer;
420   bufsiz = *buffer_size;
421   if (buf == NULL)
422     {
423       bufsiz = 10 * sizeof (gchar);
424       buf = g_new(gchar, bufsiz);
425     }
426
427   do
428     c = getc (infile);
429   while (c != EOF && c != '"');
430
431   if (c != '"')
432     goto out;
433
434   while ((c = getc(infile)) != EOF)
435     {
436       if (cnt == bufsiz)
437         {
438           guint new_size = bufsiz * 2;
439           if (new_size > bufsiz)
440             bufsiz = new_size;
441           else
442             goto out;
443         
444           buf = (gchar *) g_realloc (buf, bufsiz);
445           buf[bufsiz-1] = '\0';
446         }
447
448       if (c != '"')
449         buf[cnt++] = c;
450       else
451         {
452           buf[cnt] = 0;
453           ret = TRUE;
454           break;
455         }
456     }
457
458  out:
459   buf[bufsiz-1] = '\0';         /* ensure null termination for errors */
460   *buffer = buf;
461   *buffer_size = bufsiz;
462   return ret;
463 }
464
465 static gchar*
466 gdk_pixmap_skip_whitespaces (gchar *buffer)
467 {
468   gint32 index = 0;
469
470   while (buffer[index] != 0 && (buffer[index] == 0x20 || buffer[index] == 0x09))
471     index++;
472
473   return &buffer[index];
474 }
475
476 static gchar*
477 gdk_pixmap_skip_string (gchar *buffer)
478 {
479   gint32 index = 0;
480
481   while (buffer[index] != 0 && buffer[index] != 0x20 && buffer[index] != 0x09)
482     index++;
483
484   return &buffer[index];
485 }
486
487 #define MAX_COLOR_LEN 120
488
489 static gchar*
490 gdk_pixmap_extract_color (gchar *buffer)
491 {
492   gint counter, numnames;
493   gchar *ptr = NULL, ch, temp[128];
494   gchar color[MAX_COLOR_LEN], *retcol;
495   gint space;
496
497   counter = 0;
498   while (ptr == NULL)
499     {
500       if (buffer[counter] == 'c')
501         {
502           ch = buffer[counter + 1];
503           if (ch == 0x20 || ch == 0x09)
504             ptr = &buffer[counter + 1];
505         }
506       else if (buffer[counter] == 0)
507         return NULL;
508
509       counter++;
510     }
511
512   ptr = gdk_pixmap_skip_whitespaces (ptr);
513
514   if (ptr[0] == 0)
515     return NULL;
516   else if (ptr[0] == '#')
517     {
518       counter = 1;
519       while (ptr[counter] != 0 &&
520              ((ptr[counter] >= '0' && ptr[counter] <= '9') ||
521               (ptr[counter] >= 'a' && ptr[counter] <= 'f') ||
522               (ptr[counter] >= 'A' && ptr[counter] <= 'F')))
523         counter++;
524
525       retcol = g_new (gchar, counter+1);
526       strncpy (retcol, ptr, counter);
527
528       retcol[counter] = 0;
529
530       return retcol;
531     }
532
533   color[0] = 0;
534   numnames = 0;
535
536   space = MAX_COLOR_LEN - 1;
537   while (space > 0)
538     {
539       sscanf (ptr, "%127s", temp);
540
541       if (((gint)ptr[0] == 0) ||
542           (strcmp ("s", temp) == 0) || (strcmp ("m", temp) == 0) ||
543           (strcmp ("g", temp) == 0) || (strcmp ("g4", temp) == 0))
544         {
545           break;
546         }
547       else
548         {
549           if (numnames > 0)
550             {
551               space -= 1;
552               strcat (color, " ");
553             }
554           strncat (color, temp, space);
555           space -= MIN (space, strlen (temp));
556           ptr = gdk_pixmap_skip_string (ptr);
557           ptr = gdk_pixmap_skip_whitespaces (ptr);
558           numnames++;
559         }
560     }
561
562   retcol = g_strdup (color);
563   return retcol;
564 }
565
566
567 enum buffer_op
568 {
569   op_header,
570   op_cmap,
571   op_body
572 };
573
574
575 static void
576 gdk_xpm_destroy_notify (gpointer data)
577 {
578   _GdkPixmapInfo *info = (_GdkPixmapInfo *)data;
579   GdkColor color;
580   int i;
581
582   for (i=0; i<info->ncolors; i++)
583     {
584       color.pixel = info->pixels[i];
585       gdk_colormap_free_colors (info->colormap, &color, 1);
586     }
587
588   gdk_colormap_unref (info->colormap);
589   g_free (info);
590 }
591
592 static GdkPixmap *
593 _gdk_pixmap_create_from_xpm (GdkWindow   *window,
594                              GdkColormap *colormap,
595                              GdkBitmap  **mask,
596                              GdkColor    *transparent_color,
597                              gchar *    (*get_buf) (enum buffer_op op,
598                                                     gpointer       handle),
599                              gpointer     handle)
600 {
601   GdkPixmap *pixmap = NULL;
602   GdkImage *image = NULL;
603   GdkVisual *visual;
604   GdkGC *gc = NULL;
605   GdkColor tmp_color;
606   gint width, height, num_cols, cpp, n, ns, cnt, xcnt, ycnt, wbytes;
607   gchar *buffer, pixel_str[32];
608   gchar *name_buf;
609   _GdkPixmapColor *color = NULL, *fallbackcolor = NULL;
610   _GdkPixmapColor *colors = NULL;
611   gulong index;
612   GHashTable *color_hash = NULL;
613   _GdkPixmapInfo *color_info = NULL;
614
615   if ((window == NULL) && (colormap == NULL))
616     g_warning ("Creating pixmap from xpm with NULL window and colormap");
617
618   if (window == NULL)
619     window = (GdkWindow *) gdk_root_parent;
620
621   if (colormap == NULL)
622     {
623       colormap = gdk_window_get_colormap (window);
624       visual = gdk_window_get_visual (window);
625     }
626   else
627     visual = ((GdkColormapPrivate *)colormap)->visual;
628
629   buffer = (*get_buf) (op_header, handle);
630   if (buffer == NULL)
631     return NULL;
632
633   sscanf (buffer,"%d %d %d %d", &width, &height, &num_cols, &cpp);
634   if (cpp >= 32)
635     {
636       g_warning ("Pixmap has more than 31 characters per color");
637       return NULL;
638     }
639
640   color_hash = g_hash_table_new (g_str_hash, g_str_equal);
641
642   if (transparent_color == NULL)
643     {
644       gdk_color_white (colormap, &tmp_color);
645       transparent_color = &tmp_color;
646     }
647
648   /* For pseudo-color and grayscale visuals, we have to remember
649    * the colors we allocated, so we can free them later.
650    */
651   if ((visual->type == GDK_VISUAL_PSEUDO_COLOR) ||
652       (visual->type == GDK_VISUAL_GRAYSCALE))
653     {
654       color_info = g_malloc (sizeof (_GdkPixmapInfo) +
655                              sizeof(gulong) * (num_cols - 1));
656       color_info->ncolors = num_cols;
657       color_info->colormap = colormap;
658       gdk_colormap_ref (colormap);
659     }
660
661   name_buf = g_new (gchar, num_cols * (cpp+1));
662   colors = g_new (_GdkPixmapColor, num_cols);
663
664   for (cnt = 0; cnt < num_cols; cnt++)
665     {
666       gchar *color_name;
667
668       buffer = (*get_buf) (op_cmap, handle);
669       if (buffer == NULL)
670         goto error;
671
672       color = &colors[cnt];
673       color->color_string = &name_buf [cnt * (cpp + 1)];
674       strncpy (color->color_string, buffer, cpp);
675       color->color_string[cpp] = 0;
676       buffer += strlen (color->color_string);
677       color->transparent = FALSE;
678
679       color_name = gdk_pixmap_extract_color (buffer);
680
681       if (color_name == NULL ||
682           gdk_color_parse (color_name, &color->color) == FALSE)
683         {
684           color->color = *transparent_color;
685           color->transparent = TRUE;
686         }
687
688       g_free (color_name);
689
690       /* FIXME: The remaining slowness appears to happen in this
691          function. */
692       gdk_color_alloc (colormap, &color->color);
693
694       if (color_info)
695         color_info->pixels[cnt] = color->color.pixel;
696
697       g_hash_table_insert (color_hash, color->color_string, color);
698       if (cnt == 0)
699         fallbackcolor = color;
700     }
701
702   index = 0;
703   image = gdk_image_new (GDK_IMAGE_FASTEST, visual, width, height);
704
705   if (mask)
706     {
707       /* The pixmap mask is just a bits pattern.
708        * Color 0 is used for background and 1 for foreground.
709        * We don't care about the colormap, we just need 0 and 1.
710        */
711       GdkColor mask_pattern;
712
713       *mask = gdk_pixmap_new (window, width, height, 1);
714       gc = gdk_gc_new (*mask);
715
716       mask_pattern.pixel = 0;
717       gdk_gc_set_foreground (gc, &mask_pattern);
718       gdk_draw_rectangle (*mask, gc, TRUE, 0, 0, -1, -1);
719
720       mask_pattern.pixel = 1;
721       gdk_gc_set_foreground (gc, &mask_pattern);
722     }
723
724   wbytes = width * cpp;
725   for (ycnt = 0; ycnt < height; ycnt++)
726     {
727       buffer = (*get_buf) (op_body, handle);
728
729       /* FIXME: this slows things down a little - it could be
730        * integrated into the strncpy below, perhaps. OTOH, strlen
731        * is fast.
732        */
733       if ((buffer == NULL) || strlen (buffer) < wbytes)
734         continue;
735
736       for (n = 0, cnt = 0, xcnt = 0; n < wbytes; n += cpp, xcnt++)
737         {
738           strncpy (pixel_str, &buffer[n], cpp);
739           pixel_str[cpp] = 0;
740           ns = 0;
741         
742           color = g_hash_table_lookup (color_hash, pixel_str);
743         
744           if (!color) /* screwed up XPM file */
745             color = fallbackcolor;
746         
747           gdk_image_put_pixel (image, xcnt, ycnt, color->color.pixel);
748         
749           if (mask && color->transparent)
750             {
751               if (cnt < xcnt)
752                 gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt);
753               cnt = xcnt + 1;
754             }
755         }
756
757       if (mask && (cnt < xcnt))
758         gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt);
759     }
760
761  error:
762
763   if (mask)
764     gdk_gc_destroy (gc);
765
766   if (image != NULL)
767     {
768       pixmap = gdk_pixmap_new (window, width, height, visual->depth);
769
770       if (color_info)
771         gdk_drawable_set_data (pixmap, "gdk-xpm", color_info,
772                                gdk_xpm_destroy_notify);
773
774       gc = gdk_gc_new (pixmap);
775       gdk_gc_set_foreground (gc, transparent_color);
776       gdk_draw_image (pixmap, gc, image, 0, 0, 0, 0, image->width, image->height);
777       gdk_gc_destroy (gc);
778       gdk_image_destroy (image);
779     }
780   else if (color_info)
781     gdk_xpm_destroy_notify (color_info);
782
783   if (color_hash != NULL)
784     g_hash_table_destroy (color_hash);
785
786   if (colors != NULL)
787     g_free (colors);
788
789   if (name_buf != NULL)
790     g_free (name_buf);
791
792   return pixmap;
793 }
794
795
796 struct file_handle
797 {
798   FILE *infile;
799   gchar *buffer;
800   guint buffer_size;
801 };
802
803
804 static gchar *
805 file_buffer (enum buffer_op op, gpointer handle)
806 {
807   struct file_handle *h = handle;
808
809   switch (op)
810     {
811     case op_header:
812       if (gdk_pixmap_seek_string (h->infile, "XPM", FALSE) != TRUE)
813         break;
814
815       if (gdk_pixmap_seek_char (h->infile,'{') != TRUE)
816         break;
817       /* Fall through to the next gdk_pixmap_seek_char. */
818
819     case op_cmap:
820       gdk_pixmap_seek_char (h->infile, '"');
821       fseek (h->infile, -1, SEEK_CUR);
822       /* Fall through to the gdk_pixmap_read_string. */
823
824     case op_body:
825       gdk_pixmap_read_string (h->infile, &h->buffer, &h->buffer_size);
826       return h->buffer;
827     }
828   return 0;
829 }
830
831 GdkPixmap*
832 gdk_pixmap_colormap_create_from_xpm (GdkWindow   *window,
833                                      GdkColormap *colormap,
834                                      GdkBitmap  **mask,
835                                      GdkColor    *transparent_color,
836                                      const gchar *filename)
837 {
838   struct file_handle h;
839   GdkPixmap *pixmap = NULL;
840
841   memset (&h, 0, sizeof (h));
842   h.infile = fopen (filename, "rb");
843   if (h.infile != NULL)
844     {
845       pixmap = _gdk_pixmap_create_from_xpm (window, colormap, mask,
846                                             transparent_color,
847                                             file_buffer, &h);
848       fclose (h.infile);
849       g_free (h.buffer);
850     }
851
852   return pixmap;
853 }
854
855 GdkPixmap*
856 gdk_pixmap_create_from_xpm (GdkWindow  *window,
857                             GdkBitmap **mask,
858                             GdkColor   *transparent_color,
859                             const gchar *filename)
860 {
861   return gdk_pixmap_colormap_create_from_xpm (window, NULL, mask,
862                                        transparent_color, filename);
863 }
864
865 struct mem_handle
866 {
867   gchar **data;
868   int offset;
869 };
870
871
872 static gchar *
873 mem_buffer (enum buffer_op op, gpointer handle)
874 {
875   struct mem_handle *h = handle;
876   switch (op)
877     {
878     case op_header:
879     case op_cmap:
880     case op_body:
881       if (h->data[h->offset])
882         return h->data[h->offset ++];
883     }
884   return 0;
885 }
886
887 GdkPixmap*
888 gdk_pixmap_colormap_create_from_xpm_d (GdkWindow  *window,
889                                        GdkColormap *colormap,
890                                        GdkBitmap **mask,
891                                        GdkColor   *transparent_color,
892                                        gchar     **data)
893 {
894   struct mem_handle h;
895   GdkPixmap *pixmap = NULL;
896
897   memset (&h, 0, sizeof (h));
898   h.data = data;
899   pixmap = _gdk_pixmap_create_from_xpm (window, colormap, mask,
900                                         transparent_color,
901                                         mem_buffer, &h);
902   return pixmap;
903 }
904
905 GdkPixmap*
906 gdk_pixmap_create_from_xpm_d (GdkWindow  *window,
907                               GdkBitmap **mask,
908                               GdkColor   *transparent_color,
909                               gchar     **data)
910 {
911   return gdk_pixmap_colormap_create_from_xpm_d (window, NULL, mask,
912                                                 transparent_color, data);
913 }
914
915 GdkPixmap*
916 gdk_pixmap_foreign_new (guint32 anid)
917 {
918   GdkPixmap *pixmap;
919   GdkDrawablePrivate *private;
920   GdkWindowPrivate *window_private;
921   HBITMAP xpixmap;
922   SIZE size;
923   unsigned int x_ret, y_ret, w_ret, h_ret, bw_ret, depth_ret;
924
925   /* check to make sure we were passed something at
926      least a little sane */
927   g_return_val_if_fail((anid != 0), NULL);
928
929   /* set the pixmap to the passed in value */
930   xpixmap = (HBITMAP) anid;
931   /* get the root window */
932   window_private = gdk_root_parent;
933
934   /* get information about the BITMAP to fill in the structure for
935      the gdk window */
936   GetBitmapDimensionEx (xpixmap, &size);
937   w_ret = size.cx;
938   h_ret = size.cy;
939
940   /* allocate a new gdk pixmap */
941   private = g_new (GdkDrawablePrivate, 1);
942   pixmap = (GdkPixmap *)private;
943
944   private->window_type = GDK_DRAWABLE_PIXMAP;
945   private->xwindow = xpixmap;
946   private->colormap = NULL;
947   private->width = w_ret;
948   private->height = h_ret;
949   private->ref_count = 1;
950   private->destroyed = 0;
951
952   gdk_xid_table_insert(&private->xwindow, pixmap);
953
954   return pixmap;
955 }
956
957 GdkPixmap*
958 gdk_pixmap_ref (GdkPixmap *pixmap)
959 {
960   GdkDrawablePrivate *private = (GdkDrawablePrivate *)pixmap;
961   g_return_val_if_fail (pixmap != NULL, NULL);
962   g_return_val_if_fail (GDK_IS_PIXMAP (private), NULL);
963
964   private->ref_count += 1;
965   return pixmap;
966 }
967
968 void
969 gdk_pixmap_unref (GdkPixmap *pixmap)
970 {
971   GdkDrawablePrivate *private = (GdkDrawablePrivate *)pixmap;
972   g_return_if_fail (pixmap != NULL);
973   g_return_if_fail (GDK_IS_PIXMAP (private));
974   g_return_if_fail (private->ref_count > 0);
975
976   private->ref_count -= 1;
977
978   GDK_NOTE (MISC, g_print ("gdk_pixmap_unref: %#x %d%s\n",
979                            private->xwindow, private->ref_count,
980                            (private->ref_count == 0 ? " freeing" : "")));
981
982   if (private->ref_count == 0)
983     {
984       if (!DeleteObject (private->xwindow))
985         g_warning ("gdk_pixmap_unref: DeleteObject failed");
986       gdk_xid_table_remove (private->xwindow);
987       g_dataset_destroy (private);
988       g_free (private);
989     }
990 }
991
992 GdkBitmap *
993 gdk_bitmap_ref (GdkBitmap *bitmap)
994 {
995   return (GdkBitmap *)gdk_pixmap_ref ((GdkPixmap *)bitmap);
996 }
997
998 void
999 gdk_bitmap_unref (GdkBitmap *bitmap)
1000 {
1001   gdk_pixmap_unref ((GdkPixmap *)bitmap);
1002 }