]> Pileus Git - ~andy/gtk/blob - gtk/gtkrc.c
- Show selection correctly when starting selection with arrows
[~andy/gtk] / gtk / gtkrc.c
1 /* GTK - The GIMP Toolkit
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 <ctype.h>
19 #include <unistd.h>
20 #include <fcntl.h>
21 #include <string.h>
22 #include <stdio.h>
23 #include "gtkrc.h"
24
25
26 enum {
27   TOKEN_INVALID = G_TOKEN_LAST,
28   TOKEN_ACTIVE,
29   TOKEN_BASE,
30   TOKEN_BG,
31   TOKEN_BG_PIXMAP,
32   TOKEN_FG,
33   TOKEN_FONT,
34   TOKEN_FONTSET,
35   TOKEN_INSENSITIVE,
36   TOKEN_NORMAL,
37   TOKEN_PIXMAP_PATH,
38   TOKEN_PRELIGHT,
39   TOKEN_SELECTED,
40   TOKEN_STYLE,
41   TOKEN_TEXT,
42   TOKEN_WIDGET,
43   TOKEN_WIDGET_CLASS
44 };
45
46 enum {
47   PARSE_OK,
48   PARSE_ERROR,
49   PARSE_SYNTAX
50 };
51
52 enum {
53   PARSE_START,
54   PARSE_COMMENT,
55   PARSE_STRING,
56   PARSE_SYMBOL,
57   PARSE_NUMBER
58 };
59
60
61 typedef struct _GtkRcStyle  GtkRcStyle;
62 typedef struct _GtkRcSet    GtkRcSet;
63 typedef struct _GtkRcNode   GtkRcNode;
64
65 struct _GtkRcNode
66 {
67   GdkColormap *cmap;
68   GtkStyle *style;
69 };
70
71 struct _GtkRcStyle
72 {
73   char *name;
74   char *font_name;
75   char *fontset_name;
76   char *bg_pixmap_name[5];
77   GtkStyle *proto_style;
78   GList *styles;
79 };
80
81 struct _GtkRcSet
82 {
83   char *set;
84   GtkRcStyle *rc_style;
85 };
86
87
88 static guint       gtk_rc_style_hash               (const char   *name);
89 static gint        gtk_rc_style_compare            (const char   *a,
90                                                     const char   *b);
91 static GtkRcStyle* gtk_rc_style_find               (const char   *name);
92 static GtkRcStyle* gtk_rc_styles_match             (GSList       *sets,
93                                                     const char   *path);
94 static gint        gtk_rc_style_match              (const char   *set,
95                                                     const char   *path);
96 static GtkStyle*   gtk_rc_style_init               (GtkRcStyle   *rc_style,
97                                                     GdkColormap  *cmap);
98 static void        gtk_rc_parse_any                (const gchar  *input_name,
99                                                     gint          input_fd,
100                                                     const gchar  *input_string);
101 static gint        gtk_rc_parse_statement          (GScanner     *scanner);
102 static gint        gtk_rc_parse_style              (GScanner     *scanner);
103 static gint        gtk_rc_parse_style_option       (GScanner     *scanner,
104                                                     GtkRcStyle   *rc_style);
105 static gint        gtk_rc_parse_base               (GScanner     *scanner,
106                                                     GtkStyle     *style);
107 static gint        gtk_rc_parse_bg                 (GScanner     *scanner,
108                                                     GtkStyle     *style);
109 static gint        gtk_rc_parse_fg                 (GScanner     *scanner,
110                                                     GtkStyle     *style);
111 static gint        gtk_rc_parse_text               (GScanner     *scanner,
112                                                     GtkStyle     *style);
113 static gint        gtk_rc_parse_bg_pixmap          (GScanner     *scanner,
114                                                     GtkRcStyle   *rc_style);
115 static gint        gtk_rc_parse_font               (GScanner     *scanner,
116                                                     GtkRcStyle   *rc_style);
117 static gint        gtk_rc_parse_fontset            (GScanner     *scanner,
118                                                     GtkRcStyle   *rc_style);
119 static gint        gtk_rc_parse_state              (GScanner     *scanner,
120                                                     GtkStateType *state);
121 static gint        gtk_rc_parse_color              (GScanner     *scanner,
122                                                     GdkColor     *color);
123 static gint        gtk_rc_parse_pixmap_path        (GScanner     *scanner);
124 static void        gtk_rc_parse_pixmap_path_string (gchar *pix_path);
125 static char*       gtk_rc_find_pixmap_in_path      (GScanner     *scanner,
126                                                     gchar *pixmap_file);
127 static gint        gtk_rc_parse_widget_style       (GScanner     *scanner);
128 static gint        gtk_rc_parse_widget_class_style (GScanner     *scanner);
129 static char*       gtk_rc_widget_path              (GtkWidget *widget);
130 static char*       gtk_rc_widget_class_path        (GtkWidget *widget);
131
132
133 static  GScannerConfig  gtk_rc_scanner_config =
134 {
135   (
136    " \t\n"
137    )                    /* cset_skip_characters */,
138   (
139    G_CSET_a_2_z
140    "_"
141    G_CSET_A_2_Z
142    )                    /* cset_identifier_first */,
143   (
144    G_CSET_a_2_z
145    "_0123456789"
146    G_CSET_A_2_Z
147    G_CSET_LATINS
148    G_CSET_LATINC
149    )                    /* cset_identifier_nth */,
150   ( "#\n" )             /* cpair_comment_single */,
151   
152   TRUE                  /* case_sensitive */,
153   
154   TRUE                  /* skip_comment_multi */,
155   TRUE                  /* skip_comment_single */,
156   TRUE                  /* scan_comment_multi */,
157   TRUE                  /* scan_identifier */,
158   FALSE                 /* scan_identifier_1char */,
159   FALSE                 /* scan_identifier_NULL */,
160   TRUE                  /* scan_symbols */,
161   TRUE                  /* scan_binary */,
162   TRUE                  /* scan_octal */,
163   TRUE                  /* scan_float */,
164   TRUE                  /* scan_hex */,
165   TRUE                  /* scan_hex_dollar */,
166   TRUE                  /* scan_string_sq */,
167   TRUE                  /* scan_string_dq */,
168   TRUE                  /* numbers_2_int */,
169   FALSE                 /* int_2_float */,
170   TRUE                  /* identifier_2_string */,
171   TRUE                  /* char_2_token */,
172   TRUE                  /* symbol_2_token */,
173 };
174
175 static struct
176 {
177   char *name;
178   int token;
179 } symbols[] =
180   {
181     { "ACTIVE", TOKEN_ACTIVE },
182     { "base", TOKEN_BASE },
183     { "bg", TOKEN_BG },
184     { "bg_pixmap", TOKEN_BG_PIXMAP },
185     { "fg", TOKEN_FG },
186     { "font", TOKEN_FONT },
187     { "fontset", TOKEN_FONTSET },
188     { "INSENSITIVE", TOKEN_INSENSITIVE },
189     { "NORMAL", TOKEN_NORMAL },
190     { "pixmap_path", TOKEN_PIXMAP_PATH },
191     { "PRELIGHT", TOKEN_PRELIGHT },
192     { "SELECTED", TOKEN_SELECTED },
193     { "style", TOKEN_STYLE },
194     { "text", TOKEN_TEXT },
195     { "widget", TOKEN_WIDGET },
196     { "widget_class", TOKEN_WIDGET_CLASS },
197   };
198 static int nsymbols = sizeof (symbols) / sizeof (symbols[0]);
199
200 static int done;
201
202 static GHashTable *rc_style_ht = NULL;
203 static GSList *widget_sets = NULL;
204 static GSList *widget_class_sets = NULL;
205
206 #define GTK_RC_MAX_PIXMAP_PATHS 128
207 static gchar *pixmap_path[GTK_RC_MAX_PIXMAP_PATHS];
208
209
210 void
211 gtk_rc_init ()
212 {
213   rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash,
214                                   (GCompareFunc) gtk_rc_style_compare);
215 }
216
217 void
218 gtk_rc_parse_string (const gchar *rc_string)
219 {
220   g_return_if_fail (rc_string != NULL);
221
222   gtk_rc_parse_any ("-", -1, rc_string);
223 }
224
225 void
226 gtk_rc_parse (const gchar *filename)
227 {
228   gint     fd;
229
230   g_return_if_fail (filename != NULL);
231
232   fd = open (filename, O_RDONLY);
233   if (fd < 0)
234     return;
235
236   gtk_rc_parse_any (filename, fd, NULL);
237
238   close (fd);
239 }
240
241 GtkStyle*
242 gtk_rc_get_style (GtkWidget *widget)
243 {
244   GtkRcStyle *rc_style;
245   char *path;
246   
247   if (widget_sets)
248     {
249       path = gtk_rc_widget_path (widget);
250       if (path)
251         {
252           rc_style = gtk_rc_styles_match (widget_sets, path);
253           g_free (path);
254           
255           if (rc_style)
256             {
257               return gtk_rc_style_init (rc_style,
258                                         gtk_widget_get_colormap (widget));
259             }
260         }
261     }
262   
263   if (widget_class_sets)
264     {
265       path = gtk_rc_widget_class_path (widget);
266       if (path)
267         {
268           rc_style = gtk_rc_styles_match (widget_class_sets, path);
269           g_free (path);
270           
271           if (rc_style)
272             {
273               return gtk_rc_style_init (rc_style,
274                                         gtk_widget_get_colormap (widget));
275             }
276         }
277     }
278   
279   return NULL;
280 }
281
282 void
283 gtk_rc_add_widget_name_style (GtkStyle   *style,
284                               const char *pattern)
285 {
286   GtkRcStyle *rc_style;
287   GtkRcSet *rc_set;
288   int i;
289   
290   gtk_style_ref (style);
291   
292   rc_style = g_new (GtkRcStyle, 1);
293   rc_style->name = NULL;
294   rc_style->font_name = NULL;
295   rc_style->fontset_name = NULL;
296   
297   for (i = 0; i < 5; i++)
298     rc_style->bg_pixmap_name[i] = NULL;
299   
300   rc_style->styles = g_list_append (NULL, style);
301   
302   rc_set = g_new (GtkRcSet, 1);
303   rc_set->set = g_strdup (pattern);
304   rc_set->rc_style = rc_style;
305   
306   widget_sets = g_slist_append (widget_sets, rc_set);
307 }
308
309 void
310 gtk_rc_add_widget_class_style (GtkStyle *style,
311                                const char     *pattern)
312 {
313   GtkRcStyle *rc_style;
314   GtkRcSet *rc_set;
315   int i;
316   
317   gtk_style_ref (style);
318   
319   rc_style = g_new (GtkRcStyle, 1);
320   rc_style->name = NULL;
321   rc_style->font_name = NULL;
322   rc_style->fontset_name = NULL;
323   
324   for (i = 0; i < 5; i++)
325     rc_style->bg_pixmap_name[i] = NULL;
326   
327   rc_style->styles = g_list_append (NULL, style);
328   
329   rc_set = g_new (GtkRcSet, 1);
330   rc_set->set = g_strdup (pattern);
331   rc_set->rc_style = rc_style;
332   
333   widget_class_sets = g_slist_append (widget_class_sets, rc_set);
334 }
335
336 static void
337 gtk_rc_parse_any (const gchar  *input_name,
338                   gint          input_fd,
339                   const gchar  *input_string)
340 {
341   GScanner *scanner;
342   guint    i;
343   
344   scanner = g_scanner_new (&gtk_rc_scanner_config);
345   
346   if (input_fd >= 0)
347     {
348       g_assert (input_string == NULL);
349       
350       g_scanner_input_file (scanner, input_fd);
351     }
352   else
353     {
354       g_assert (input_string != NULL);
355       
356       g_scanner_input_text (scanner, input_string, strlen (input_string));
357     }
358   
359   for (i = 0; i < nsymbols; i++)
360     g_scanner_add_symbol (scanner, symbols[i].name, (gpointer) symbols[i].token);
361   
362   done = FALSE;
363   while (!done)
364     {
365       if (gtk_rc_parse_statement (scanner) != PARSE_OK)
366         {
367           if (scanner->next_token != G_TOKEN_NONE)
368             g_scanner_get_next_token (scanner);
369           
370           if (input_string)
371             g_warning ("rc string parse error: line %d",
372                        scanner->line);
373           else
374             g_warning ("rc file parse error: \"%s\" line %d",
375                        input_name,
376                        scanner->line);
377           
378           done = TRUE;
379         }
380     }
381   g_scanner_destroy (scanner);
382 }
383
384 static guint
385 gtk_rc_style_hash (const char *name)
386 {
387   guint result;
388   
389   result = 0;
390   while (*name)
391     result += (result << 3) + *name++;
392   
393   return result;
394 }
395
396 static gint
397 gtk_rc_style_compare (const char *a,
398                       const char *b)
399 {
400   return (strcmp (a, b) == 0);
401 }
402
403 static GtkRcStyle*
404 gtk_rc_style_find (const char *name)
405 {
406   GtkRcStyle *rc_style;
407   
408   rc_style = g_hash_table_lookup (rc_style_ht, (gpointer) name);
409   
410   return rc_style;
411 }
412
413 static GtkRcStyle*
414 gtk_rc_styles_match (GSList       *sets,
415                      const char   *path)
416 {
417   GtkRcSet *rc_set;
418   
419   while (sets)
420     {
421       rc_set = sets->data;
422       sets = sets->next;
423       
424       if (gtk_rc_style_match (rc_set->set, path))
425         return rc_set->rc_style;
426     }
427   
428   return NULL;
429 }
430
431 static gint
432 gtk_rc_style_match (const char *set,
433                     const char *path)
434 {
435   char ch;
436   
437   while (1)
438     {
439       ch = *set++;
440       if (ch == '\0')
441         return (*path == '\0');
442       
443       switch (ch)
444         {
445         case '*':
446           while (*set == '*')
447             set++;
448           
449           ch = *set++;
450           if (ch == '\0')
451             return TRUE;
452           
453           while (*path)
454             {
455               while (*path && (ch != *path))
456                 path++;
457               
458               if (!(*path))
459                 return FALSE;
460               
461               path++;
462               if (gtk_rc_style_match (set, path))
463                 return TRUE;
464             }
465           break;
466           
467         case '?':
468           break;
469           
470         default:
471           if (ch == *path)
472             path++;
473           else
474             return FALSE;
475           break;
476         }
477     }
478   
479   return TRUE;
480 }
481
482 static GtkStyle *
483 gtk_rc_style_init (GtkRcStyle *rc_style, GdkColormap *cmap)
484 {
485   GdkFont *old_font;
486   gint i;
487
488   GList *tmp_list;
489   GtkStyle *style = NULL;
490
491   tmp_list = rc_style->styles;
492
493   while (tmp_list)
494     {
495       GtkRcNode *node = (GtkRcNode *)tmp_list->data;
496
497       if (node->cmap == cmap)
498         style = node->style;
499
500       tmp_list = tmp_list->next;
501     }
502   
503   if (!style)
504     {
505       style = gtk_style_copy (rc_style->proto_style);
506       
507       if (rc_style->fontset_name)
508         {
509           old_font = style->font;
510           style->font = gdk_fontset_load (rc_style->fontset_name);
511           if (style->font)
512             gdk_font_unref (old_font);
513           else
514             style->font = old_font;
515         }
516       else if (rc_style->font_name)
517         {
518           old_font = style->font;
519           style->font = gdk_font_load (rc_style->font_name);
520           if (style->font)
521             gdk_font_unref (old_font);
522           else
523             style->font = old_font;
524         }
525       
526       for (i = 0; i < 5; i++)
527         if (rc_style->bg_pixmap_name[i])
528           {
529             if (strcmp (rc_style->bg_pixmap_name[i], "<parent>") == 0)
530               style->bg_pixmap[i] = (GdkPixmap*) GDK_PARENT_RELATIVE;
531             else
532               style->bg_pixmap[i] = 
533                 gdk_pixmap_colormap_create_from_xpm (NULL, cmap,
534                                                      NULL,
535                                                      &style->bg[i],
536                                                      rc_style->bg_pixmap_name[i]);
537           }
538
539       rc_style->styles = g_list_append (rc_style->styles, style);
540
541       /* FIXME, this leaks colormaps, but if we don't do this, then we'll
542        * be screwed, because we identify colormaps by address equality
543        */
544       gdk_colormap_ref (cmap);
545     }
546
547   return style;
548 }
549
550 static gint
551 gtk_rc_parse_statement (GScanner *scanner)
552 {
553   gint token;
554   gint error;
555   
556   token = g_scanner_peek_next_token (scanner);
557   if (token == G_TOKEN_EOF)
558     {
559       done = TRUE;
560       return PARSE_OK;
561     }
562   
563   error = gtk_rc_parse_style (scanner);
564   if (error != PARSE_SYNTAX)
565     return error;
566   
567   error = gtk_rc_parse_pixmap_path (scanner);
568   if (error != PARSE_SYNTAX)
569     return error;
570   
571   error = gtk_rc_parse_widget_style (scanner);
572   if (error != PARSE_SYNTAX)
573     return error;
574   
575   error = gtk_rc_parse_widget_class_style (scanner);
576   
577   return error;
578 }
579
580 static gint
581 gtk_rc_parse_style (GScanner *scanner)
582 {
583   GtkRcStyle *rc_style;
584   GtkRcStyle *parent_style;
585   gint token;
586   gint error;
587   gint insert;
588   gint i;
589   
590   token = g_scanner_peek_next_token (scanner);
591   if (token == G_TOKEN_EOF || token == G_TOKEN_ERROR)
592     return PARSE_ERROR;
593   if (token != TOKEN_STYLE)
594     return PARSE_SYNTAX;
595   token = g_scanner_get_next_token (scanner);
596   
597   token = g_scanner_get_next_token (scanner);
598   if (token != G_TOKEN_STRING)
599     return PARSE_ERROR;
600   
601   insert = FALSE;
602   rc_style = g_hash_table_lookup (rc_style_ht, scanner->value.v_string);
603   
604   if (!rc_style)
605     {
606       insert = TRUE;
607       rc_style = g_new (GtkRcStyle, 1);
608       rc_style->name = g_strdup (scanner->value.v_string);
609       rc_style->font_name = NULL;
610       rc_style->fontset_name = NULL;
611       
612       for (i = 0; i < 5; i++)
613         rc_style->bg_pixmap_name[i] = NULL;
614
615       rc_style->proto_style = gtk_style_new();
616       rc_style->styles = NULL;
617     }
618   
619   token = g_scanner_peek_next_token (scanner);
620   if (token == G_TOKEN_EQUAL_SIGN)
621     {
622       token = g_scanner_get_next_token (scanner);
623       
624       token = g_scanner_get_next_token (scanner);
625       if (token != G_TOKEN_STRING)
626         {
627           if (insert)
628             {
629               gtk_style_unref (rc_style->proto_style);
630               g_free (rc_style);
631             }
632           return PARSE_ERROR;
633         }
634       
635       parent_style = g_hash_table_lookup (rc_style_ht, scanner->value.v_string);
636       if (parent_style)
637         {
638           for (i = 0; i < 5; i++)
639             {
640               rc_style->proto_style->fg[i] = parent_style->proto_style->fg[i];
641               rc_style->proto_style->bg[i] = parent_style->proto_style->bg[i];
642               rc_style->proto_style->light[i] = parent_style->proto_style->light[i];
643               rc_style->proto_style->dark[i] = parent_style->proto_style->dark[i];
644               rc_style->proto_style->mid[i] = parent_style->proto_style->mid[i];
645               rc_style->proto_style->text[i] = parent_style->proto_style->text[i];
646               rc_style->proto_style->base[i] = parent_style->proto_style->base[i];
647             }
648           
649           rc_style->proto_style->black = parent_style->proto_style->black;
650           rc_style->proto_style->white = parent_style->proto_style->white;
651           
652           if (rc_style->fontset_name)
653             {
654               g_free (rc_style->fontset_name);
655               rc_style->fontset_name = g_strdup (parent_style->fontset_name);
656             }
657           else if (rc_style->font_name)
658             {
659               g_free (rc_style->font_name);
660               rc_style->font_name = g_strdup (parent_style->font_name);
661             }
662           
663           for (i = 0; i < 5; i++)
664             {
665               if (rc_style->bg_pixmap_name[i])
666                 g_free (rc_style->bg_pixmap_name[i]);
667               rc_style->bg_pixmap_name[i] = g_strdup (parent_style->bg_pixmap_name[i]);
668             }
669         }
670     }
671   
672   token = g_scanner_get_next_token (scanner);
673   if (token != G_TOKEN_LEFT_CURLY)
674     {
675       if (insert)
676         {
677           gtk_style_unref (rc_style->proto_style);
678           g_free (rc_style);
679         }
680       return PARSE_ERROR;
681     }
682   
683   while (1)
684     {
685       error = gtk_rc_parse_style_option (scanner, rc_style);
686       if (error == PARSE_SYNTAX)
687         break;
688       if (error == PARSE_ERROR)
689         {
690           if (insert)
691             {
692               gtk_style_unref (rc_style->proto_style);
693               g_free (rc_style);
694             }
695           return error;
696         }
697     }
698   
699   token = g_scanner_get_next_token (scanner);
700   if (token != G_TOKEN_RIGHT_CURLY)
701     {
702       if (insert)
703         {
704           if (rc_style->fontset_name)
705             g_free (rc_style->fontset_name);
706           else if (rc_style->font_name)
707             g_free (rc_style->font_name);
708           
709           for (i = 0; i < 5; i++)
710             if (rc_style->bg_pixmap_name[i])
711               g_free (rc_style->bg_pixmap_name[i]);
712           
713           gtk_style_unref (rc_style->proto_style);
714           g_free (rc_style);
715         }
716       return PARSE_ERROR;
717     }
718   
719   if (insert)
720     g_hash_table_insert (rc_style_ht, rc_style->name, rc_style);
721   
722   return PARSE_OK;
723 }
724
725 static gint
726 gtk_rc_parse_style_option (GScanner   *scanner,
727                            GtkRcStyle *rc_style)
728 {
729   gint token;
730   gint error;
731   
732   token = g_scanner_peek_next_token (scanner);
733   if (token == G_TOKEN_EOF || token == G_TOKEN_ERROR)
734     return PARSE_ERROR;
735   
736   error = gtk_rc_parse_base (scanner, rc_style->proto_style);
737   if (error != PARSE_SYNTAX)
738     return error;
739   
740   error = gtk_rc_parse_bg (scanner, rc_style->proto_style);
741   if (error != PARSE_SYNTAX)
742     return error;
743   
744   error = gtk_rc_parse_fg (scanner, rc_style->proto_style);
745   if (error != PARSE_SYNTAX)
746     return error;
747   
748   error = gtk_rc_parse_text (scanner, rc_style->proto_style);
749   if (error != PARSE_SYNTAX)
750     return error;
751   
752   error = gtk_rc_parse_bg_pixmap (scanner, rc_style);
753   if (error != PARSE_SYNTAX)
754     return error;
755   
756   error = gtk_rc_parse_font (scanner, rc_style);
757   if (error != PARSE_SYNTAX)
758     return error;
759   
760   error = gtk_rc_parse_fontset (scanner, rc_style);
761   
762   return error;
763 }
764
765 static gint
766 gtk_rc_parse_base (GScanner *scanner,
767                    GtkStyle *style)
768 {
769   GtkStateType state;
770   gint token;
771   gint error;
772   
773   token = g_scanner_peek_next_token (scanner);
774   if (token == G_TOKEN_EOF || token == G_TOKEN_ERROR)
775     return PARSE_ERROR;
776   if (token != TOKEN_BASE)
777     return PARSE_SYNTAX;
778   token = g_scanner_get_next_token (scanner);
779   
780   error = gtk_rc_parse_state (scanner, &state);
781   if (error != PARSE_OK)
782     return error;
783   
784   token = g_scanner_get_next_token (scanner);
785   if (token != G_TOKEN_EQUAL_SIGN)
786     return PARSE_ERROR;
787   
788   error = gtk_rc_parse_color (scanner, &style->base[state]);
789   
790   return error;
791 }
792
793 static gint
794 gtk_rc_parse_bg (GScanner *scanner,
795                  GtkStyle *style)
796 {
797   GtkStateType state;
798   gint token;
799   gint error;
800   
801   token = g_scanner_peek_next_token (scanner);
802   if (token == G_TOKEN_EOF || token == G_TOKEN_ERROR)
803     return PARSE_ERROR;
804   if (token != TOKEN_BG)
805     return PARSE_SYNTAX;
806   token = g_scanner_get_next_token (scanner);
807   
808   error = gtk_rc_parse_state (scanner, &state);
809   if (error != PARSE_OK)
810     return error;
811   
812   token = g_scanner_get_next_token (scanner);
813   if (token != G_TOKEN_EQUAL_SIGN)
814     return PARSE_ERROR;
815   
816   error = gtk_rc_parse_color (scanner, &style->bg[state]);
817   
818   return error;
819 }
820
821 static gint
822 gtk_rc_parse_fg (GScanner *scanner,
823                  GtkStyle *style)
824 {
825   GtkStateType state;
826   gint token;
827   gint error;
828   
829   token = g_scanner_peek_next_token (scanner);
830   if (token == G_TOKEN_EOF || token == G_TOKEN_ERROR)
831     return PARSE_ERROR;
832   if (token != TOKEN_FG)
833     return PARSE_SYNTAX;
834   token = g_scanner_get_next_token (scanner);
835   
836   error = gtk_rc_parse_state (scanner, &state);
837   if (error != PARSE_OK)
838     return error;
839   
840   token = g_scanner_get_next_token (scanner);
841   if (token != G_TOKEN_EQUAL_SIGN)
842     return PARSE_ERROR;
843   
844   error = gtk_rc_parse_color (scanner, &style->fg[state]);
845   
846   return error;
847 }
848
849 static gint
850 gtk_rc_parse_text (GScanner *scanner,
851                    GtkStyle *style)
852 {
853   GtkStateType state;
854   gint token;
855   gint error;
856   
857   token = g_scanner_peek_next_token (scanner);
858   if (token == G_TOKEN_EOF || token == G_TOKEN_ERROR)
859     return PARSE_ERROR;
860   if (token != TOKEN_TEXT)
861     return PARSE_SYNTAX;
862   token = g_scanner_get_next_token (scanner);
863   
864   error = gtk_rc_parse_state (scanner, &state);
865   if (error != PARSE_OK)
866     return error;
867   
868   token = g_scanner_get_next_token (scanner);
869   if (token != G_TOKEN_EQUAL_SIGN)
870     return PARSE_ERROR;
871   
872   error = gtk_rc_parse_color (scanner, &style->text[state]);
873   
874   return error;
875 }
876
877 static gint
878 gtk_rc_parse_bg_pixmap (GScanner   *scanner,
879                         GtkRcStyle *rc_style)
880 {
881   GtkStateType state;
882   gint token;
883   gint error;
884   gchar *pixmap_file;
885   
886   token = g_scanner_peek_next_token (scanner);
887   if (token == G_TOKEN_EOF || token == G_TOKEN_ERROR)
888     return PARSE_ERROR;
889   if (token != TOKEN_BG_PIXMAP)
890     return PARSE_SYNTAX;
891   token = g_scanner_get_next_token (scanner);
892   
893   error = gtk_rc_parse_state (scanner, &state);
894   if (error != PARSE_OK)
895     return error;
896   
897   token = g_scanner_get_next_token (scanner);
898   if (token != G_TOKEN_EQUAL_SIGN)
899     return PARSE_ERROR;
900   
901   token = g_scanner_get_next_token (scanner);
902   if (token != G_TOKEN_STRING)
903     return PARSE_ERROR;
904   
905   if (strcmp (scanner->value.v_string, "<parent>"))
906     pixmap_file = gtk_rc_find_pixmap_in_path (scanner, scanner->value.v_string);
907   else
908     pixmap_file = g_strdup (scanner->value.v_string);
909   
910   if (pixmap_file)
911     {
912       if (rc_style->bg_pixmap_name[state])
913         g_free (rc_style->bg_pixmap_name[state]);
914       rc_style->bg_pixmap_name[state] = pixmap_file;
915     }
916   
917   return PARSE_OK;
918 }
919
920 static char*
921 gtk_rc_find_pixmap_in_path (GScanner *scanner,
922                             gchar    *pixmap_file)
923 {
924   gint i;
925   gint fd;
926   gchar *buf;
927   
928   for (i = 0; (i < GTK_RC_MAX_PIXMAP_PATHS) && (pixmap_path[i] != NULL); i++)
929     {
930       buf = g_malloc (strlen (pixmap_path[i]) + strlen (pixmap_file) + 2);
931       sprintf (buf, "%s%c%s", pixmap_path[i], '/', pixmap_file);
932       
933       fd = open (buf, O_RDONLY);
934       if (fd >= 0)
935         {
936           close (fd);
937           return buf;
938         }
939       
940       g_free (buf);
941     }
942   
943   g_warning ("Unable to locate image file in pixmap_path: \"%s\" line %d",
944              pixmap_file, scanner->line);
945   
946   return NULL;
947 }
948
949 static gint
950 gtk_rc_parse_font (GScanner   *scanner,
951                    GtkRcStyle *rc_style)
952 {
953   gint token;
954   
955   token = g_scanner_peek_next_token (scanner);
956   if (token == G_TOKEN_EOF || token == G_TOKEN_ERROR)
957     return PARSE_ERROR;
958   if (token != TOKEN_FONT)
959     return PARSE_SYNTAX;
960   token = g_scanner_get_next_token (scanner);
961   
962   token = g_scanner_get_next_token (scanner);
963   if (token != G_TOKEN_EQUAL_SIGN)
964     return PARSE_ERROR;
965   
966   token = g_scanner_get_next_token (scanner);
967   if (token != G_TOKEN_STRING)
968     return PARSE_ERROR;
969   
970   if (rc_style->font_name)
971     g_free (rc_style->font_name);
972   rc_style->font_name = g_strdup (scanner->value.v_string);
973   
974   return PARSE_OK;
975 }
976
977 static gint
978 gtk_rc_parse_fontset (GScanner   *scanner,
979                       GtkRcStyle *rc_style)
980 {
981   gint token;
982   
983   token = g_scanner_peek_next_token (scanner);
984   if (token == G_TOKEN_EOF || token == G_TOKEN_ERROR)
985     return PARSE_ERROR;
986   if (token != TOKEN_FONTSET)
987     return PARSE_SYNTAX;
988   token = g_scanner_get_next_token (scanner);
989   
990   token = g_scanner_get_next_token (scanner);
991   if (token != G_TOKEN_EQUAL_SIGN)
992     return PARSE_ERROR;
993   
994   token = g_scanner_get_next_token (scanner);
995   if (token != G_TOKEN_STRING)
996     return PARSE_ERROR;
997   
998   if (rc_style->fontset_name)
999     g_free (rc_style->fontset_name);
1000   rc_style->fontset_name = g_strdup (scanner->value.v_string);
1001   
1002   return PARSE_OK;
1003 }
1004
1005 static gint
1006 gtk_rc_parse_state (GScanner     *scanner,
1007                     GtkStateType *state)
1008 {
1009   gint token;
1010   
1011   token = g_scanner_peek_next_token (scanner);
1012   if (token == G_TOKEN_EOF || token == G_TOKEN_ERROR)
1013     return PARSE_ERROR;
1014   if (token != G_TOKEN_LEFT_BRACE)
1015     return PARSE_SYNTAX;
1016   token = g_scanner_get_next_token (scanner);
1017   
1018   token = g_scanner_get_next_token (scanner);
1019   if (token == TOKEN_ACTIVE)
1020     *state = GTK_STATE_ACTIVE;
1021   else if (token == TOKEN_INSENSITIVE)
1022     *state = GTK_STATE_INSENSITIVE;
1023   else if (token == TOKEN_NORMAL)
1024     *state = GTK_STATE_NORMAL;
1025   else if (token == TOKEN_PRELIGHT)
1026     *state = GTK_STATE_PRELIGHT;
1027   else if (token == TOKEN_SELECTED)
1028     *state = GTK_STATE_SELECTED;
1029   else
1030     return PARSE_ERROR;
1031   
1032   token = g_scanner_get_next_token (scanner);
1033   if (token != G_TOKEN_RIGHT_BRACE)
1034     return PARSE_ERROR;
1035   
1036   return PARSE_OK;
1037 }
1038
1039 static gint
1040 gtk_rc_parse_color (GScanner *scanner,
1041                     GdkColor *color)
1042 {
1043   gint token;
1044   gint token_int;
1045   gint length;
1046   gint temp;
1047   gchar buf[9];
1048   gint i, j;
1049   
1050   token = g_scanner_peek_next_token (scanner);
1051   if (token == G_TOKEN_EOF || token == G_TOKEN_ERROR)
1052     return PARSE_ERROR;
1053   
1054   switch (token)
1055     {
1056     case G_TOKEN_LEFT_CURLY:
1057       token = g_scanner_get_next_token (scanner);
1058       
1059       token = g_scanner_get_next_token (scanner);
1060       if (token == G_TOKEN_INT)
1061         token_int = scanner->value.v_int;
1062       else if (token == G_TOKEN_FLOAT)
1063         token_int = scanner->value.v_float * 65535.0;
1064       else
1065         return PARSE_ERROR;
1066       color->red = CLAMP (token_int, 0, 65535);
1067       
1068       token = g_scanner_get_next_token (scanner);
1069       if (token != G_TOKEN_COMMA)
1070         return PARSE_ERROR;
1071       
1072       token = g_scanner_get_next_token (scanner);
1073       if (token == G_TOKEN_INT)
1074         token_int = scanner->value.v_int;
1075       else if (token == G_TOKEN_FLOAT)
1076         token_int = scanner->value.v_float * 65535.0;
1077       else
1078         return PARSE_ERROR;
1079       color->green = CLAMP (token_int, 0, 65535);
1080       
1081       token = g_scanner_get_next_token (scanner);
1082       if (token != G_TOKEN_COMMA)
1083         return PARSE_ERROR;
1084       
1085       token = g_scanner_get_next_token (scanner);
1086       if (token == G_TOKEN_INT)
1087         token_int = scanner->value.v_int;
1088       else if (token == G_TOKEN_FLOAT)
1089         token_int = scanner->value.v_float * 65535.0;
1090       else
1091         return PARSE_ERROR;
1092       color->blue = CLAMP (token_int, 0, 65535);
1093       
1094       token = g_scanner_get_next_token (scanner);
1095       if (token != G_TOKEN_RIGHT_CURLY)
1096         return PARSE_ERROR;
1097       break;
1098       
1099     case G_TOKEN_STRING:
1100       token = g_scanner_get_next_token (scanner);
1101       
1102       if (scanner->value.v_string[0] != '#')
1103         return PARSE_ERROR;
1104       
1105       length = strlen (scanner->value.v_string) - 1;
1106       if (((length % 3) != 0) || (length > 12))
1107         return PARSE_ERROR;
1108       length /= 3;
1109       
1110       for (i = 0, j = 1; i < length; i++, j++)
1111         buf[i] = scanner->value.v_string[j];
1112       buf[i] = '\0';
1113       
1114       sscanf (buf, "%x", &temp);
1115       color->red = temp;
1116       
1117       for (i = 0; i < length; i++, j++)
1118         buf[i] = scanner->value.v_string[j];
1119       buf[i] = '\0';
1120       
1121       sscanf (buf, "%x", &temp);
1122       color->green = temp;
1123       
1124       for (i = 0; i < length; i++, j++)
1125         buf[i] = scanner->value.v_string[j];
1126       buf[i] = '\0';
1127       
1128       sscanf (buf, "%x", &temp);
1129       color->blue = temp;
1130       
1131       if (length == 1)
1132         {
1133           color->red *= 4369;
1134           color->green *= 4369;
1135           color->blue *= 4369;
1136         }
1137       else if (length == 2)
1138         {
1139           color->red *= 257;
1140           color->green *= 257;
1141           color->blue *= 257;
1142         }
1143       else if (length == 3)
1144         {
1145           color->red *= 16;
1146           color->green *= 16;
1147           color->blue *= 16;
1148         }
1149       break;
1150       
1151     case G_TOKEN_ERROR:
1152       return PARSE_ERROR;
1153       
1154     default:
1155       return PARSE_SYNTAX;
1156     }
1157   
1158   return PARSE_OK;
1159 }
1160
1161 static gint
1162 gtk_rc_parse_pixmap_path (GScanner *scanner)
1163 {
1164   gint token;
1165   
1166   token = g_scanner_peek_next_token (scanner);
1167   if (token == G_TOKEN_EOF || token == G_TOKEN_ERROR)
1168     return PARSE_ERROR;
1169   if (token != TOKEN_PIXMAP_PATH)
1170     return PARSE_SYNTAX;
1171   token = g_scanner_get_next_token (scanner);
1172   
1173   token = g_scanner_get_next_token (scanner);
1174   
1175   if (token != G_TOKEN_STRING)
1176     return PARSE_ERROR;
1177   
1178   gtk_rc_parse_pixmap_path_string (scanner->value.v_string);
1179   
1180   return PARSE_OK;
1181 }
1182
1183 static void
1184 gtk_rc_parse_pixmap_path_string (gchar *pix_path)
1185 {
1186   gchar *buf;
1187   gint end_offset;
1188   gint start_offset = 0;
1189   gint path_len;
1190   gint path_num;
1191   
1192   /* free the old one, or just add to the old one ? */
1193   for (path_num=0; pixmap_path[path_num]; path_num++)
1194     {
1195       g_free (pixmap_path[path_num]);
1196       pixmap_path[path_num] = NULL;
1197     }
1198   
1199   path_num = 0;
1200   
1201   path_len = strlen (pix_path);
1202   
1203   buf = g_strdup (pix_path);
1204   
1205   for (end_offset = 0; end_offset <= path_len; end_offset++)
1206     {
1207       if ((buf[end_offset] == ':') ||
1208           (end_offset == path_len))
1209         {
1210           buf[end_offset] = '\0';
1211           pixmap_path[path_num] = g_strdup (buf + start_offset);
1212           path_num++;
1213           pixmap_path[path_num] = NULL;
1214           start_offset = end_offset + 1;
1215         }
1216     }
1217   g_free (buf);
1218 }
1219
1220 static gint
1221 gtk_rc_parse_widget_style (GScanner *scanner)
1222 {
1223   GtkRcSet *rc_set;
1224   gint token;
1225   
1226   token = g_scanner_peek_next_token (scanner);
1227   if (token == G_TOKEN_EOF || token == G_TOKEN_ERROR)
1228     return PARSE_ERROR;
1229   if (token != TOKEN_WIDGET)
1230     return PARSE_SYNTAX;
1231   token = g_scanner_get_next_token (scanner);
1232   
1233   token = g_scanner_get_next_token (scanner);
1234   if (token != G_TOKEN_STRING)
1235     return PARSE_ERROR;
1236   
1237   rc_set = g_new (GtkRcSet, 1);
1238   rc_set->set = g_strdup (scanner->value.v_string);
1239   
1240   token = g_scanner_get_next_token (scanner);
1241   if (token != TOKEN_STYLE)
1242     {
1243       g_free (rc_set->set);
1244       g_free (rc_set);
1245       return PARSE_ERROR;
1246     }
1247   
1248   token = g_scanner_get_next_token (scanner);
1249   if (token != G_TOKEN_STRING)
1250     {
1251       g_free (rc_set->set);
1252       g_free (rc_set);
1253       return PARSE_ERROR;
1254     }
1255   
1256   rc_set->rc_style = gtk_rc_style_find (scanner->value.v_string);
1257   if (!rc_set->rc_style)
1258     {
1259       g_free (rc_set->set);
1260       g_free (rc_set);
1261       return PARSE_ERROR;
1262     }
1263   
1264   widget_sets = g_slist_append (widget_sets, rc_set);
1265   
1266   return PARSE_OK;
1267 }
1268
1269 static gint
1270 gtk_rc_parse_widget_class_style (GScanner *scanner)
1271 {
1272   GtkRcSet *rc_set;
1273   gint token;
1274   
1275   token = g_scanner_peek_next_token (scanner);
1276   if (token == G_TOKEN_EOF || token == G_TOKEN_ERROR)
1277     return PARSE_ERROR;
1278   if (token != TOKEN_WIDGET_CLASS)
1279     return PARSE_SYNTAX;
1280   token = g_scanner_get_next_token (scanner);
1281   
1282   token = g_scanner_get_next_token (scanner);
1283   if (token != G_TOKEN_STRING)
1284     return PARSE_ERROR;
1285   
1286   rc_set = g_new (GtkRcSet, 1);
1287   rc_set->set = g_strdup (scanner->value.v_string);
1288   
1289   token = g_scanner_get_next_token (scanner);
1290   if (token != TOKEN_STYLE)
1291     {
1292       g_free (rc_set->set);
1293       g_free (rc_set);
1294       return PARSE_ERROR;
1295     }
1296   
1297   token = g_scanner_get_next_token (scanner);
1298   if (token != G_TOKEN_STRING)
1299     {
1300       g_free (rc_set->set);
1301       g_free (rc_set);
1302       return PARSE_ERROR;
1303     }
1304   
1305   rc_set->rc_style = gtk_rc_style_find (scanner->value.v_string);
1306   if (!rc_set->rc_style)
1307     {
1308       g_free (rc_set->set);
1309       g_free (rc_set);
1310       return PARSE_ERROR;
1311     }
1312   
1313   widget_class_sets = g_slist_append (widget_class_sets, rc_set);
1314   
1315   return PARSE_OK;
1316 }
1317
1318 static char*
1319 gtk_rc_widget_path (GtkWidget *widget)
1320 {
1321   GtkWidget *tmp_widget;
1322   char *path;
1323   char *name;
1324   int pathlength;
1325   int namelength;
1326   
1327   path = NULL;
1328   pathlength = 0;
1329   
1330   tmp_widget = widget;
1331   while (tmp_widget)
1332     {
1333       name = gtk_widget_get_name (tmp_widget);
1334       pathlength += strlen (name);
1335       
1336       tmp_widget = tmp_widget->parent;
1337       
1338       if (tmp_widget)
1339         pathlength += 1;
1340     }
1341   
1342   path = g_new (char, pathlength + 1);
1343   path[pathlength] = '\0';
1344   
1345   tmp_widget = widget;
1346   while (tmp_widget)
1347     {
1348       name = gtk_widget_get_name (tmp_widget);
1349       namelength = strlen (name);
1350       
1351       strncpy (&path[pathlength - namelength], name, namelength);
1352       pathlength -= namelength;
1353       
1354       tmp_widget = tmp_widget->parent;
1355       
1356       if (tmp_widget)
1357         {
1358           pathlength -= 1;
1359           path[pathlength] = '.';
1360         }
1361     }
1362   
1363   return path;
1364 }
1365
1366 static char*
1367 gtk_rc_widget_class_path (GtkWidget *widget)
1368 {
1369   GtkWidget *tmp_widget;
1370   char *path;
1371   char *name;
1372   int pathlength;
1373   int namelength;
1374   
1375   path = NULL;
1376   pathlength = 0;
1377   
1378   tmp_widget = widget;
1379   while (tmp_widget)
1380     {
1381       name = gtk_type_name (GTK_WIDGET_TYPE (tmp_widget));
1382       pathlength += strlen (name);
1383       
1384       tmp_widget = tmp_widget->parent;
1385       
1386       if (tmp_widget)
1387         pathlength += 1;
1388     }
1389   
1390   path = g_new (char, pathlength + 1);
1391   path[pathlength] = '\0';
1392   
1393   tmp_widget = widget;
1394   while (tmp_widget)
1395     {
1396       name = gtk_type_name (GTK_WIDGET_TYPE (tmp_widget));
1397       namelength = strlen (name);
1398       
1399       strncpy (&path[pathlength - namelength], name, namelength);
1400       pathlength -= namelength;
1401       
1402       tmp_widget = tmp_widget->parent;
1403       
1404       if (tmp_widget)
1405         {
1406           pathlength -= 1;
1407           path[pathlength] = '.';
1408         }
1409     }
1410   
1411   return path;
1412 }