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