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