]> Pileus Git - ~andy/gtk/blob - gdk/gdkpixmap.c
Include <unistd.h> to get SEEK_END on SunOS.
[~andy/gtk] / gdk / gdkpixmap.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
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.
8  *
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.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18 #include "../config.h"
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <string.h>
22 /* Needed for SEEK_END in SunOS */
23 #include <unistd.h>
24 #include <X11/Xlib.h>
25
26 #include "gdk.h"
27 #include "gdkprivate.h"
28
29 typedef struct
30 {
31   gchar *color_string;
32   GdkColor color;
33   gint transparent;
34 } _GdkPixmapColor;
35
36 GdkPixmap*
37 gdk_pixmap_new (GdkWindow *window,
38                 gint       width,
39                 gint       height,
40                 gint       depth)
41 {
42   GdkPixmap *pixmap;
43   GdkWindowPrivate *private;
44   GdkWindowPrivate *window_private;
45
46   if (!window)
47     window = (GdkWindow*) &gdk_root_parent;
48
49   if (depth == -1)
50     gdk_window_get_geometry (window, NULL, NULL, NULL, NULL, &depth);
51
52   private = g_new (GdkWindowPrivate, 1);
53   pixmap = (GdkPixmap*) private;
54
55   window_private = (GdkWindowPrivate*) window;
56
57   private->xdisplay = window_private->xdisplay;
58   private->window_type = GDK_WINDOW_PIXMAP;
59   private->xwindow = XCreatePixmap (private->xdisplay, window_private->xwindow,
60                                     width, height, depth);
61   private->parent = NULL;
62   private->x = 0;
63   private->y = 0;
64   private->width = width;
65   private->height = height;
66   private->resize_count = 0;
67   private->ref_count = 1;
68   private->destroyed = 0;
69
70   gdk_xid_table_insert (&private->xwindow, pixmap);
71
72   return pixmap;
73 }
74
75 GdkPixmap *
76 gdk_bitmap_create_from_data (GdkWindow *window,
77                              gchar     *data,
78                              gint       width,
79                              gint       height)
80 {
81   GdkPixmap *pixmap;
82   GdkWindowPrivate *private;
83   GdkWindowPrivate *window_private;
84
85   g_return_val_if_fail (data != NULL, NULL);
86
87   if (!window)
88     window = (GdkWindow*) &gdk_root_parent;
89
90   private = g_new (GdkWindowPrivate, 1);
91   pixmap = (GdkPixmap*) private;
92
93   window_private = (GdkWindowPrivate*) window;
94
95   private->parent = NULL;
96   private->xdisplay = window_private->xdisplay;
97   private->window_type = GDK_WINDOW_PIXMAP;
98   private->x = 0;
99   private->y = 0;
100   private->width = width;
101   private->height = height;
102   private->resize_count = 0;
103   private->ref_count = 1;
104   private->destroyed = FALSE;
105
106   private->xwindow = XCreateBitmapFromData (private->xdisplay,
107                                             window_private->xwindow,
108                                             data, width, height);
109
110   gdk_xid_table_insert (&private->xwindow, pixmap);
111
112   return pixmap;
113 }
114
115 GdkPixmap*
116 gdk_pixmap_create_from_data (GdkWindow *window,
117                              gchar     *data,
118                              gint       width,
119                              gint       height,
120                              gint       depth,
121                              GdkColor  *fg,
122                              GdkColor  *bg)
123 {
124   GdkPixmap *pixmap;
125   GdkWindowPrivate *private;
126   GdkWindowPrivate *window_private;
127
128   g_return_val_if_fail (data != NULL, NULL);
129   g_return_val_if_fail (fg != NULL, NULL);
130   g_return_val_if_fail (bg != NULL, NULL);
131
132   if (!window)
133     window = (GdkWindow*) &gdk_root_parent;
134
135   if (depth == -1)
136     gdk_window_get_geometry (window, NULL, NULL, NULL, NULL, &depth);
137
138   private = g_new (GdkWindowPrivate, 1);
139   pixmap = (GdkPixmap*) private;
140
141   window_private = (GdkWindowPrivate*) window;
142
143   private->parent = NULL;
144   private->xdisplay = window_private->xdisplay;
145   private->window_type = GDK_WINDOW_PIXMAP;
146   private->x = 0;
147   private->y = 0;
148   private->width = width;
149   private->height = height;
150   private->resize_count = 0;
151   private->ref_count = 1;
152   private->destroyed = FALSE;
153
154   private->xwindow = XCreatePixmapFromBitmapData (private->xdisplay,
155                                                   window_private->xwindow,
156                                                   data, width, height,
157                                                   fg->pixel, bg->pixel, depth);
158
159   gdk_xid_table_insert (&private->xwindow, pixmap);
160
161   return pixmap;
162 }
163
164 gint
165 gdk_pixmap_seek_string (FILE  *infile,
166                         const gchar *str,
167                         gint   skip_comments)
168 {
169   char instr[1024];
170
171   while (!feof (infile))
172     {
173       fscanf (infile, "%s", instr);
174       if (skip_comments == TRUE && strcmp (instr, "/*") == 0)
175         {
176           fscanf (infile, "%s", instr);
177           while (!feof (infile) && strcmp (instr, "*/") != 0)
178             fscanf (infile, "%s", instr);
179           fscanf(infile, "%s", instr);
180         }
181       if (strcmp (instr, str)==0)
182         return TRUE;
183     }
184
185   return FALSE;
186 }
187
188 gint
189 gdk_pixmap_seek_char (FILE  *infile,
190                       gchar  c)
191 {
192   gchar b, oldb;
193
194   while (!feof (infile))
195     {
196       fscanf(infile, "%c", &b);
197       if (c != b && b == '/')
198         {
199           fscanf (infile, "%c", &b);
200           if (b == '*')
201             {
202               oldb = b;
203               while (!feof (infile) && !(oldb == '*' && b == '/'))
204                 {
205                   oldb = b;
206                   fscanf (infile, "%c", &b);
207                 }
208               fscanf (infile, "%c", &b);
209             }
210         }
211       if (c == b)
212         return TRUE;
213     }
214
215   return FALSE;
216 }
217
218 gint
219 gdk_pixmap_read_string (FILE  *infile,
220                         gchar **buffer,
221                         int *buffer_size)
222 {
223   gchar c;
224   gint cnt = 0;
225
226   if ((*buffer) == NULL)
227     {
228       (*buffer_size) = 10 * sizeof (gchar);
229       (*buffer) = (gchar *) malloc (*buffer_size);
230     }
231
232   do
233     fscanf (infile, "%c", &c);
234   while (!feof (infile) && c != '"');
235
236   if (c != '"')
237     return FALSE;
238
239   while (!feof (infile))
240     {
241       fscanf (infile, "%c", &c);
242
243       if (cnt == (*buffer_size))
244         {
245           (*buffer_size) *= 2;
246           (*buffer) = (gchar *) realloc ((*buffer), *buffer_size);        
247         }
248
249       if (c != '"')
250         (*buffer)[cnt++] = c;
251       else
252         {
253           (*buffer)[cnt++] = 0;
254           return TRUE;
255         }
256     }
257
258   return FALSE;
259 }
260
261 gchar*
262 gdk_pixmap_skip_whitespaces (gchar *buffer)
263 {
264   gint32 index = 0;
265
266   while (buffer[index] != 0 && (buffer[index] == 0x20 || buffer[index] == 0x09))
267     index++;
268
269   return &buffer[index];
270 }
271
272 gchar*
273 gdk_pixmap_skip_string (gchar *buffer)
274 {
275   gint32 index = 0;
276
277   while (buffer[index] != 0 && buffer[index] != 0x20 && buffer[index] != 0x09)
278     index++;
279
280   return &buffer[index];
281 }
282
283 gchar*
284 gdk_pixmap_extract_color (gchar *buffer)
285 {
286   gint counter, finished = FALSE, numnames;
287   gchar *ptr = NULL, ch, temp[128];
288   gchar color[128], *retcol;
289
290   counter = 0;
291   while (ptr == NULL)
292     {
293       if (buffer[counter] == 'c')
294         {
295           ch = buffer[counter + 1];
296           if (ch == 0x20 || ch == 0x09)
297             ptr = &buffer[counter + 1];
298         }
299       else if (buffer[counter] == 0)
300         return NULL;
301
302       counter++;
303     }
304
305   if (ptr == NULL)
306     return NULL;
307
308   ptr = gdk_pixmap_skip_whitespaces (ptr);
309
310   if (ptr[0] == 0)
311     return NULL;
312   else if (ptr[0] == '#')
313     {
314       retcol = g_new(gchar, strlen (ptr) + 1);
315       strcpy (retcol, ptr);
316       return retcol;
317     }
318
319   color[0] = 0;
320   numnames = 0;
321
322   while (finished == FALSE)
323     {
324       sscanf (ptr, "%s", temp);
325
326       if ((gint)ptr[0] == 0 || strcmp ("s", temp) == 0 || strcmp ("m", temp) == 0 ||
327           strcmp ("g", temp) == 0 || strcmp ("g4", temp) == 0)
328        finished = TRUE;
329       else
330         {
331           if (numnames > 0)
332             strcat (color, " ");
333           strcat (color, temp);
334           ptr = gdk_pixmap_skip_string (ptr);
335           ptr = gdk_pixmap_skip_whitespaces (ptr);
336           numnames++;
337         }
338     }
339
340   retcol = g_new(gchar, strlen (color) + 1);
341   strcpy (retcol, color);
342   return retcol;
343 }
344
345
346 GdkPixmap*
347 gdk_pixmap_create_from_xpm (GdkWindow  *window,
348                             GdkBitmap **mask,
349                             GdkColor   *transparent_color,
350                             const gchar *filename)
351 {
352   FILE *infile = NULL;
353   GdkPixmap *pixmap = NULL;
354   GdkImage *image = NULL;
355   GdkColormap *colormap;
356   GdkVisual *visual;
357   GdkGC *gc;
358   GdkColor tmp_color;
359   gint width, height, num_cols, cpp, cnt, n, ns, xcnt, ycnt;
360   gchar *buffer = NULL, *color_name = NULL, pixel_str[32];
361   guint buffer_size = 0;
362   _GdkPixmapColor *colors = NULL, *color = NULL;
363   gulong index;
364
365   if (!window)
366     window = (GdkWindow*) &gdk_root_parent;
367
368   infile = fopen (filename, "rb");
369   if (infile != NULL)
370     {
371       if (gdk_pixmap_seek_string (infile, "XPM", FALSE) == TRUE)
372         {
373           if (gdk_pixmap_seek_char (infile,'{') == TRUE)
374             {
375               gdk_pixmap_seek_char (infile, '"');
376               fseek (infile, -1, SEEK_CUR);
377               gdk_pixmap_read_string (infile, &buffer, &buffer_size);
378
379               sscanf (buffer,"%d %d %d %d", &width, &height, &num_cols, &cpp);
380
381               colors = g_new(_GdkPixmapColor, num_cols);
382
383               colormap = gdk_window_get_colormap (window);
384               visual = gdk_window_get_visual (window);
385
386               if (transparent_color == NULL) 
387                 {
388                   gdk_color_white (colormap, &tmp_color);
389                   transparent_color = &tmp_color;
390                 }
391
392               for (cnt = 0; cnt < num_cols; cnt++)
393                 {
394                   gdk_pixmap_seek_char (infile, '"');
395                   fseek (infile, -1, SEEK_CUR);
396                   gdk_pixmap_read_string (infile, &buffer, &buffer_size);
397
398                   colors[cnt].color_string = g_new(gchar, cpp + 1);
399                   for (n = 0; n < cpp; n++)
400                     colors[cnt].color_string[n] = buffer[n];
401                   colors[cnt].color_string[n] = 0;
402                   colors[cnt].transparent = FALSE;
403
404                   if (color_name != NULL)
405                     g_free (color_name);
406
407                   color_name = gdk_pixmap_extract_color (&buffer[cpp]);
408
409                   if (color_name != NULL)
410                     {
411                       if (gdk_color_parse (color_name, &colors[cnt].color) == FALSE)
412                         {
413                           colors[cnt].color = *transparent_color;
414                           colors[cnt].transparent = TRUE;
415                         }
416                     }
417                   else
418                     {
419                       colors[cnt].color = *transparent_color;
420                       colors[cnt].transparent = TRUE;
421                     }
422
423                   gdk_color_alloc (colormap, &colors[cnt].color);
424                 }
425
426               index = 0;
427               image = gdk_image_new (GDK_IMAGE_FASTEST, visual, width, height);
428
429               gc = NULL;
430               if (mask)
431                 {
432                   *mask = gdk_pixmap_new (window, width, height, 1);
433                   gc = gdk_gc_new (*mask);
434
435                   gdk_color_black (colormap, &tmp_color);
436                   gdk_gc_set_foreground (gc, &tmp_color);
437                   gdk_draw_rectangle (*mask, gc, TRUE, 0, 0, -1, -1);
438
439                   gdk_color_white (colormap, &tmp_color);
440                   gdk_gc_set_foreground (gc, &tmp_color);
441                 }
442
443               for (ycnt = 0; ycnt < height; ycnt++)
444                 {
445                   gdk_pixmap_read_string (infile, &buffer, &buffer_size);
446
447                   for (n = 0, cnt = 0, xcnt = 0; n < (width * cpp); n += cpp, xcnt++)
448                     {
449                       strncpy (pixel_str, &buffer[n], cpp);
450                       pixel_str[cpp] = 0;
451                       color = NULL;
452                       ns = 0;
453
454                       while (color == NULL)
455                         {
456                           if (strcmp (pixel_str, colors[ns].color_string) == 0)
457                             color = &colors[ns];
458                           else
459                             ns++;
460                         }
461
462                       gdk_image_put_pixel (image, xcnt, ycnt, color->color.pixel);
463
464                       if (mask && color->transparent)
465                         {
466                           if (cnt < xcnt)
467                             gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt);
468                           cnt = xcnt + 1;
469                         }
470                     }
471
472                   if (mask && (cnt < xcnt))
473                     gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt);
474                 }
475
476               if (mask)
477                 gdk_gc_destroy (gc);
478
479               pixmap = gdk_pixmap_new (window, width, height, visual->depth);
480
481               gc = gdk_gc_new (pixmap);
482               gdk_gc_set_foreground (gc, transparent_color);
483               gdk_draw_image (pixmap, gc, image, 0, 0, 0, 0, image->width, image->height);
484               gdk_gc_destroy (gc);
485               gdk_image_destroy (image);
486             }
487         }
488
489       fclose (infile);
490       free (buffer);
491
492       if (colors != NULL)
493         {
494           for (cnt = 0; cnt < num_cols; cnt++)
495             g_free (colors[cnt].color_string);
496           g_free (colors);
497         }
498     }
499
500   return pixmap;
501 }
502
503 GdkPixmap*
504 gdk_pixmap_create_from_xpm_d (GdkWindow  *window,
505                               GdkBitmap **mask,
506                               GdkColor   *transparent_color,
507                               gchar     **data)
508 {
509   GdkPixmap *pixmap = NULL;
510   GdkImage *image = NULL;
511   GdkColormap *colormap;
512   GdkVisual *visual;
513   GdkGC *gc;
514   GdkColor tmp_color;
515   gint width, height, num_cols, cpp, cnt, n, ns, xcnt, ycnt, i;
516   gchar *buffer, *color_name = NULL, pixel_str[32];
517   _GdkPixmapColor *colors = NULL, *color = NULL;
518   gulong index;
519
520   if (!window)
521     window = (GdkWindow*) &gdk_root_parent;
522
523   i = 0;
524   buffer = data[i++];
525   sscanf (buffer,"%d %d %d %d", &width, &height, &num_cols, &cpp);
526
527   colors = g_new(_GdkPixmapColor, num_cols);
528
529   colormap = gdk_window_get_colormap (window);
530   visual = gdk_window_get_visual (window);
531
532   if (transparent_color == NULL) 
533     {
534       gdk_color_white (colormap, &tmp_color);
535       transparent_color = &tmp_color;
536     }
537
538   for (cnt = 0; cnt < num_cols; cnt++)
539     {
540       buffer = data[i++];
541
542       colors[cnt].color_string = g_new(gchar, cpp + 1);
543       for (n = 0; n < cpp; n++)
544         colors[cnt].color_string[n] = buffer[n];
545       colors[cnt].color_string[n] = 0;
546       colors[cnt].transparent = FALSE;
547
548       if (color_name != NULL)
549         g_free (color_name);
550
551       color_name = gdk_pixmap_extract_color (&buffer[cpp]);
552
553       if (color_name != NULL)
554         {
555           if (gdk_color_parse (color_name, &colors[cnt].color) == FALSE)
556             {
557               colors[cnt].color = *transparent_color;
558               colors[cnt].transparent = TRUE;
559             }
560         }
561       else
562         {
563           colors[cnt].color = *transparent_color;
564           colors[cnt].transparent = TRUE;
565         }
566
567       gdk_color_alloc (colormap, &colors[cnt].color);
568     }
569
570   index = 0;
571   image = gdk_image_new (GDK_IMAGE_FASTEST, visual, width, height);
572
573   gc = NULL;
574   if (mask)
575     {
576       *mask = gdk_pixmap_new (window, width, height, 1);
577       gc = gdk_gc_new (*mask);
578
579       gdk_color_black (colormap, &tmp_color);
580       gdk_gc_set_foreground (gc, &tmp_color);
581       gdk_draw_rectangle (*mask, gc, TRUE, 0, 0, -1, -1);
582
583       gdk_color_white (colormap, &tmp_color);
584       gdk_gc_set_foreground (gc, &tmp_color);
585     }
586
587   for (ycnt = 0; ycnt < height; ycnt++)
588     {
589       buffer = data[i++];
590
591       for (n = 0, cnt = 0, xcnt = 0; n < (width * cpp); n += cpp, xcnt++)
592         {
593           strncpy (pixel_str, &buffer[n], cpp);
594           pixel_str[cpp] = 0;
595           color = NULL;
596           ns = 0;
597
598           while (color == NULL)
599             {
600               if (strcmp (pixel_str, colors[ns].color_string) == 0)
601                 color = &colors[ns];
602               else
603                 ns++;
604             }
605
606           gdk_image_put_pixel (image, xcnt, ycnt, color->color.pixel);
607
608           if (mask && color->transparent)
609             {
610               if (cnt < xcnt)
611                 gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt);
612               cnt = xcnt + 1;
613             }
614         }
615
616       if (mask && (cnt < xcnt))
617         gdk_draw_line (*mask, gc, cnt, ycnt, xcnt - 1, ycnt);
618     }
619
620   if (mask)
621     gdk_gc_destroy (gc);
622
623   pixmap = gdk_pixmap_new (window, width, height, visual->depth);
624
625   gc = gdk_gc_new (pixmap);
626   gdk_gc_set_foreground (gc, transparent_color);
627   gdk_draw_image (pixmap, gc, image, 0, 0, 0, 0, image->width, image->height);
628   gdk_gc_destroy (gc);
629   gdk_image_destroy (image);
630
631   if (colors != NULL)
632     {
633       for (cnt = 0; cnt < num_cols; cnt++)
634         g_free (colors[cnt].color_string);
635       g_free (colors);
636     }
637
638   return pixmap;
639 }
640
641 void
642 gdk_pixmap_destroy (GdkPixmap *pixmap)
643 {
644   GdkWindowPrivate *private;
645
646   g_return_if_fail (pixmap != NULL);
647
648   private = (GdkPixmapPrivate*) pixmap;
649   if (private->ref_count <= 0)
650     {
651       XFreePixmap (private->xdisplay, private->xwindow);
652       gdk_xid_table_remove (private->xwindow);
653       g_free (pixmap);
654     }
655   else
656     {
657       private->ref_count -= 1;
658     }
659 }