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