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 Lesser 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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
25  */
26 
27 #include "config.h"
28 
29 #include <locale.h>
30 #ifdef HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33 #include <sys/stat.h>
34 #ifdef HAVE_SYS_PARAM_H
35 #include <sys/param.h>
36 #endif
37 #include <fcntl.h>
38 #include <string.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 
42 
43 #include <glib.h>
44 #include <glib/gstdio.h>
45 #include "gdkconfig.h"
46 
47 #include "gtkversion.h"
48 #include "gtkrc.h"
49 #include "gtkbindings.h"
50 #include "gtkthemes.h"
51 #include "gtkintl.h"
52 #include "gtkiconfactory.h"
53 #include "gtkmain.h"
54 #include "gtkmodules.h"
55 #include "gtkprivate.h"
56 #include "gtksettings.h"
57 #include "gtkwindow.h"
58 
59 #include "gtkalias.h"
60 
61 #ifdef G_OS_WIN32
62 #include <io.h>
63 #endif
64 
65 typedef struct _GtkRcSet    GtkRcSet;
66 typedef struct _GtkRcNode   GtkRcNode;
67 typedef struct _GtkRcFile   GtkRcFile;
68 
69 enum
70 {
71   PATH_ELT_PSPEC,
72   PATH_ELT_UNRESOLVED,
73   PATH_ELT_TYPE
74 };
75 
76 typedef struct
77 {
78   gint type;
79   union
80   {
81     GType         class_type;
82     gchar        *class_name;
83     GPatternSpec *pspec;
84   } elt;
85 } PathElt;
86 
87 struct _GtkRcSet
88 {
89   GtkPathType   type;
90 
91   GPatternSpec *pspec;
92   GSList       *path;
93 
94   GtkRcStyle   *rc_style;
95   gint          priority;
96 };
97 
98 struct _GtkRcFile
99 {
100   time_t mtime;
101   gchar *name;
102   gchar *canonical_name;
103   gchar *directory;
104   guint  reload    : 1;
105   guint  is_string : 1;	/* If TRUE, name is a string to parse with gtk_rc_parse_string() */
106 };
107 
108 
109 struct _GtkRcContext
110 {
111   GHashTable *rc_style_ht;
112   GtkSettings *settings;
113   GSList *rc_sets_widget;
114   GSList *rc_sets_widget_class;
115   GSList *rc_sets_class;
116 
117   /* The files we have parsed, to reread later if necessary */
118   GSList *rc_files;
119 
120   gchar *theme_name;
121   gchar *key_theme_name;
122   gchar *font_name;
123 
124   gchar **pixmap_path;
125 
126   gint default_priority;
127   GtkStyle *default_style;
128 
129   GHashTable *color_hash;
130 
131   guint reloading : 1;
132 };
133 
134 #define GTK_RC_STYLE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_RC_STYLE, GtkRcStylePrivate))
135 
136 typedef struct _GtkRcStylePrivate GtkRcStylePrivate;
137 
138 struct _GtkRcStylePrivate
139 {
140   GSList *color_hashes;
141 };
142 
143 static GtkRcContext *gtk_rc_context_get              (GtkSettings     *settings);
144 
145 static guint       gtk_rc_style_hash                 (const gchar     *name);
146 static gboolean    gtk_rc_style_equal                (const gchar     *a,
147                                                       const gchar     *b);
148 static guint       gtk_rc_styles_hash                (const GSList    *rc_styles);
149 static gboolean    gtk_rc_styles_equal               (const GSList    *a,
150                                                       const GSList    *b);
151 static GtkRcStyle* gtk_rc_style_find                 (GtkRcContext    *context,
152 						      const gchar     *name);
153 static GSList *    gtk_rc_styles_match               (GSList          *rc_styles,
154                                                       GSList          *sets,
155                                                       guint            path_length,
156                                                       gchar           *path,
157                                                       gchar           *path_reversed);
158 static GtkStyle *  gtk_rc_style_to_style             (GtkRcContext    *context,
159 						      GtkRcStyle      *rc_style);
160 static GtkStyle*   gtk_rc_init_style                 (GtkRcContext    *context,
161 						      GSList          *rc_styles);
162 static void        gtk_rc_parse_default_files        (GtkRcContext    *context);
163 static void        gtk_rc_parse_named                (GtkRcContext    *context,
164 						      const gchar     *name,
165 						      const gchar     *type);
166 static void        gtk_rc_context_parse_file         (GtkRcContext    *context,
167 						      const gchar     *filename,
168 						      gint             priority,
169                                                       gboolean         reload);
170 static void        gtk_rc_parse_any                  (GtkRcContext    *context,
171 						      const gchar     *input_name,
172                                                       gint             input_fd,
173                                                       const gchar     *input_string);
174 static guint       gtk_rc_parse_statement            (GtkRcContext    *context,
175 						      GScanner        *scanner);
176 static guint       gtk_rc_parse_style                (GtkRcContext    *context,
177 						      GScanner        *scanner);
178 static guint       gtk_rc_parse_assignment           (GScanner        *scanner,
179                                                       GtkRcStyle      *style,
180 						      GtkRcProperty   *prop);
181 static guint       gtk_rc_parse_bg                   (GScanner        *scanner,
182                                                       GtkRcStyle      *style);
183 static guint       gtk_rc_parse_fg                   (GScanner        *scanner,
184                                                       GtkRcStyle      *style);
185 static guint       gtk_rc_parse_text                 (GScanner        *scanner,
186                                                       GtkRcStyle      *style);
187 static guint       gtk_rc_parse_base                 (GScanner        *scanner,
188                                                       GtkRcStyle      *style);
189 static guint       gtk_rc_parse_xthickness           (GScanner        *scanner,
190                                                       GtkRcStyle      *style);
191 static guint       gtk_rc_parse_ythickness           (GScanner        *scanner,
192                                                       GtkRcStyle      *style);
193 static guint       gtk_rc_parse_bg_pixmap            (GtkRcContext    *context,
194 						      GScanner        *scanner,
195                                                       GtkRcStyle      *rc_style);
196 static guint       gtk_rc_parse_font                 (GScanner        *scanner,
197                                                       GtkRcStyle      *rc_style);
198 static guint       gtk_rc_parse_fontset              (GScanner        *scanner,
199                                                       GtkRcStyle      *rc_style);
200 static guint       gtk_rc_parse_font_name            (GScanner        *scanner,
201                                                       GtkRcStyle      *rc_style);
202 static guint       gtk_rc_parse_engine               (GtkRcContext    *context,
203 						      GScanner        *scanner,
204                                                       GtkRcStyle     **rc_style);
205 static guint       gtk_rc_parse_pixmap_path          (GtkRcContext    *context,
206 						      GScanner        *scanner);
207 static void        gtk_rc_parse_pixmap_path_string   (GtkRcContext    *context,
208 						      GScanner        *scanner,
209 						      const gchar     *pix_path);
210 static guint       gtk_rc_parse_module_path          (GScanner        *scanner);
211 static guint       gtk_rc_parse_im_module_file       (GScanner        *scanner);
212 static guint       gtk_rc_parse_path_pattern         (GtkRcContext    *context,
213 						      GScanner        *scanner);
214 static guint       gtk_rc_parse_stock                (GtkRcContext    *context,
215 						      GScanner        *scanner,
216                                                       GtkRcStyle      *rc_style,
217                                                       GtkIconFactory  *factory);
218 static guint       gtk_rc_parse_logical_color        (GScanner        *scanner,
219                                                       GtkRcStyle      *rc_style,
220                                                       GHashTable      *hash);
221 
222 static void        gtk_rc_clear_hash_node            (gpointer         key,
223                                                       gpointer         data,
224                                                       gpointer         user_data);
225 static void        gtk_rc_clear_styles               (GtkRcContext    *context);
226 static void        gtk_rc_add_initial_default_files  (void);
227 
228 static void        gtk_rc_style_finalize             (GObject         *object);
229 static void        gtk_rc_style_real_merge           (GtkRcStyle      *dest,
230                                                       GtkRcStyle      *src);
231 static GtkRcStyle* gtk_rc_style_real_create_rc_style (GtkRcStyle      *rc_style);
232 static GtkStyle*   gtk_rc_style_real_create_style    (GtkRcStyle      *rc_style);
233 static void        gtk_rc_style_copy_icons_and_colors(GtkRcStyle      *rc_style,
234                                                       GtkRcStyle      *src_style,
235                                                       GtkRcContext    *context);
236 static gint	   gtk_rc_properties_cmp	     (gconstpointer    bsearch_node1,
237 						      gconstpointer    bsearch_node2);
238 static void        gtk_rc_set_free                   (GtkRcSet        *rc_set);
239 
240 static void	   insert_rc_property		     (GtkRcStyle      *style,
241 						      GtkRcProperty   *property,
242 						      gboolean         replace);
243 
244 
245 static const GScannerConfig gtk_rc_scanner_config =
246 {
247   (
248    " \t\r\n"
249    )			/* cset_skip_characters */,
250   (
251    "_"
252    G_CSET_a_2_z
253    G_CSET_A_2_Z
254    )			/* cset_identifier_first */,
255   (
256    G_CSET_DIGITS
257    "-_"
258    G_CSET_a_2_z
259    G_CSET_A_2_Z
260    )			/* cset_identifier_nth */,
261   ( "#\n" )		/* cpair_comment_single */,
262 
263   TRUE			/* case_sensitive */,
264 
265   TRUE			/* skip_comment_multi */,
266   TRUE			/* skip_comment_single */,
267   TRUE			/* scan_comment_multi */,
268   TRUE			/* scan_identifier */,
269   FALSE			/* scan_identifier_1char */,
270   FALSE			/* scan_identifier_NULL */,
271   TRUE			/* scan_symbols */,
272   TRUE			/* scan_binary */,
273   TRUE			/* scan_octal */,
274   TRUE			/* scan_float */,
275   TRUE			/* scan_hex */,
276   TRUE			/* scan_hex_dollar */,
277   TRUE			/* scan_string_sq */,
278   TRUE			/* scan_string_dq */,
279   TRUE			/* numbers_2_int */,
280   FALSE			/* int_2_float */,
281   FALSE			/* identifier_2_string */,
282   TRUE			/* char_2_token */,
283   TRUE			/* symbol_2_token */,
284   FALSE			/* scope_0_fallback */,
285 };
286 
287 static const gchar symbol_names[] =
288   "include\0"
289   "NORMAL\0"
290   "ACTIVE\0"
291   "PRELIGHT\0"
292   "SELECTED\0"
293   "INSENSITIVE\0"
294   "fg\0"
295   "bg\0"
296   "text\0"
297   "base\0"
298   "xthickness\0"
299   "ythickness\0"
300   "font\0"
301   "fontset\0"
302   "font_name\0"
303   "bg_pixmap\0"
304   "pixmap_path\0"
305   "style\0"
306   "binding\0"
307   "bind\0"
308   "widget\0"
309   "widget_class\0"
310   "class\0"
311   "lowest\0"
312   "gtk\0"
313   "application\0"
314   "theme\0"
315   "rc\0"
316   "highest\0"
317   "engine\0"
318   "module_path\0"
319   "stock\0"
320   "im_module_file\0"
321   "LTR\0"
322   "RTL\0"
323   "color\0"
324   "unbind\0";
325 
326 static const struct
327 {
328   guint name_offset;
329   guint token;
330 } symbols[] = {
331   {   0, GTK_RC_TOKEN_INCLUDE },
332   {   8, GTK_RC_TOKEN_NORMAL },
333   {  15, GTK_RC_TOKEN_ACTIVE },
334   {  22, GTK_RC_TOKEN_PRELIGHT },
335   {  31, GTK_RC_TOKEN_SELECTED },
336   {  40, GTK_RC_TOKEN_INSENSITIVE },
337   {  52, GTK_RC_TOKEN_FG },
338   {  55, GTK_RC_TOKEN_BG },
339   {  58, GTK_RC_TOKEN_TEXT },
340   {  63, GTK_RC_TOKEN_BASE },
341   {  68, GTK_RC_TOKEN_XTHICKNESS },
342   {  79, GTK_RC_TOKEN_YTHICKNESS },
343   {  90, GTK_RC_TOKEN_FONT },
344   {  95, GTK_RC_TOKEN_FONTSET },
345   { 103, GTK_RC_TOKEN_FONT_NAME },
346   { 113, GTK_RC_TOKEN_BG_PIXMAP },
347   { 123, GTK_RC_TOKEN_PIXMAP_PATH },
348   { 135, GTK_RC_TOKEN_STYLE },
349   { 141, GTK_RC_TOKEN_BINDING },
350   { 149, GTK_RC_TOKEN_BIND },
351   { 154, GTK_RC_TOKEN_WIDGET },
352   { 161, GTK_RC_TOKEN_WIDGET_CLASS },
353   { 174, GTK_RC_TOKEN_CLASS },
354   { 180, GTK_RC_TOKEN_LOWEST },
355   { 187, GTK_RC_TOKEN_GTK },
356   { 191, GTK_RC_TOKEN_APPLICATION },
357   { 203, GTK_RC_TOKEN_THEME },
358   { 209, GTK_RC_TOKEN_RC },
359   { 212, GTK_RC_TOKEN_HIGHEST },
360   { 220, GTK_RC_TOKEN_ENGINE },
361   { 227, GTK_RC_TOKEN_MODULE_PATH },
362   { 239, GTK_RC_TOKEN_STOCK },
363   { 245, GTK_RC_TOKEN_IM_MODULE_FILE },
364   { 260, GTK_RC_TOKEN_LTR },
365   { 264, GTK_RC_TOKEN_RTL },
366   { 268, GTK_RC_TOKEN_COLOR },
367   { 274, GTK_RC_TOKEN_UNBIND }
368 };
369 
370 static GHashTable *realized_style_ht = NULL;
371 
372 static gchar *im_module_file = NULL;
373 
374 static gint    max_default_files = 0;
375 static gchar **gtk_rc_default_files = NULL;
376 
377 /* A stack of information of RC files we are parsing currently.
378  * The directories for these files are implicitely added to the end of
379  * PIXMAP_PATHS.
380  */
381 static GSList *current_files_stack = NULL;
382 
383 /* RC files and strings that are parsed for every context
384  */
385 static GSList *global_rc_files = NULL;
386 
387 /* Keep list of all current RC contexts for convenience
388  */
389 static GSList *rc_contexts;
390 
391 /* RC file handling */
392 
393 static gchar *
gtk_rc_make_default_dir(const gchar * type)394 gtk_rc_make_default_dir (const gchar *type)
395 {
396   const gchar *var;
397   gchar *path;
398 
399   var = g_getenv ("GTK_EXE_PREFIX");
400 
401   if (var)
402     path = g_build_filename (var, "lib", "gtk-2.0", GTK_BINARY_VERSION, type, NULL);
403   else
404     path = g_build_filename (GTK_LIBDIR, "gtk-2.0", GTK_BINARY_VERSION, type, NULL);
405 
406   return path;
407 }
408 
409 /**
410  * gtk_rc_get_im_module_path:
411  * @returns: a newly-allocated string containing the path in which to
412  *    look for IM modules.
413  *
414  * Obtains the path in which to look for IM modules. See the documentation
415  * of the <link linkend="im-module-path"><envar>GTK_PATH</envar></link>
416  * environment variable for more details about looking up modules. This
417  * function is useful solely for utilities supplied with GTK+ and should
418  * not be used by applications under normal circumstances.
419  */
420 gchar *
gtk_rc_get_im_module_path(void)421 gtk_rc_get_im_module_path (void)
422 {
423   gchar **paths = _gtk_get_module_path ("immodules");
424   gchar *result = g_strjoinv (G_SEARCHPATH_SEPARATOR_S, paths);
425   g_strfreev (paths);
426 
427   return result;
428 }
429 
430 /**
431  * gtk_rc_get_im_module_file:
432  * @returns: a newly-allocated string containing the name of the file
433  * listing the IM modules available for loading
434  *
435  * Obtains the path to the IM modules file. See the documentation
436  * of the <link linkend="im-module-file"><envar>GTK_IM_MODULE_FILE</envar></link>
437  * environment variable for more details.
438  */
439 gchar *
gtk_rc_get_im_module_file(void)440 gtk_rc_get_im_module_file (void)
441 {
442   const gchar *var = g_getenv ("GTK_IM_MODULE_FILE");
443   gchar *result = NULL;
444 
445   if (var)
446     result = g_strdup (var);
447 
448   if (!result)
449     {
450       if (im_module_file)
451 	result = g_strdup (im_module_file);
452       else
453         result = gtk_rc_make_default_dir ("immodules.cache");
454     }
455 
456   return result;
457 }
458 
459 gchar *
gtk_rc_get_theme_dir(void)460 gtk_rc_get_theme_dir (void)
461 {
462   const gchar *var;
463   gchar *path;
464 
465   var = g_getenv ("GTK_DATA_PREFIX");
466 
467   if (var)
468     path = g_build_filename (var, "share", "themes", NULL);
469   else
470     path = g_build_filename (GTK_DATA_PREFIX, "share", "themes", NULL);
471 
472   return path;
473 }
474 
475 /**
476  * gtk_rc_get_module_dir:
477  *
478  * Returns a directory in which GTK+ looks for theme engines.
479  * For full information about the search for theme engines,
480  * see the docs for <envar>GTK_PATH</envar> in
481  * <xref linkend="gtk-running"/>.
482  *
483  * return value: the directory. (Must be freed with g_free())
484  **/
485 gchar *
gtk_rc_get_module_dir(void)486 gtk_rc_get_module_dir (void)
487 {
488   return gtk_rc_make_default_dir ("engines");
489 }
490 
491 static void
gtk_rc_add_initial_default_files(void)492 gtk_rc_add_initial_default_files (void)
493 {
494   static gint init = FALSE;
495   const gchar *var;
496   gchar *str;
497   gchar **files;
498   gint i;
499 
500   if (init)
501     return;
502 
503   gtk_rc_default_files = g_new (gchar*, 10);
504   max_default_files = 10;
505 
506   gtk_rc_default_files[0] = NULL;
507   init = TRUE;
508 
509   var = g_getenv ("GTK2_RC_FILES");
510 
511   if (var)
512     {
513       files = g_strsplit (var, G_SEARCHPATH_SEPARATOR_S, -1);
514       i=0;
515       while (files[i])
516 	{
517 	  gtk_rc_add_default_file (files[i]);
518 	  i++;
519 	}
520       g_strfreev (files);
521     }
522   else
523     {
524       const gchar *home;
525       const gchar * const *config_dirs;
526       const gchar *config_dir;
527 
528       str = g_build_filename (GTK_DATA_PREFIX, "share", "gtk-2.0", "gtkrc", NULL);
529       gtk_rc_add_default_file (str);
530       g_free (str);
531 
532       config_dirs = g_get_system_config_dirs ();
533       for (config_dir = *config_dirs; *config_dirs != NULL; config_dirs++)
534         {
535           str = g_build_filename (config_dir, "gtk-2.0", "gtkrc", NULL);
536           gtk_rc_add_default_file (str);
537           g_free (str);
538         }
539 
540       str = g_build_filename (GTK_SYSCONFDIR, "gtk-2.0", "gtkrc", NULL);
541       gtk_rc_add_default_file (str);
542       g_free (str);
543 
544       home = g_get_home_dir ();
545       if (home)
546 	{
547 	  str = g_build_filename (home, ".gtkrc-2.0", NULL);
548 	  gtk_rc_add_default_file (str);
549 	  g_free (str);
550 	}
551     }
552 }
553 
554 /**
555  * gtk_rc_add_default_file:
556  * @filename: the pathname to the file. If @filename is not absolute, it
557  *    is searched in the current directory.
558  *
559  * Adds a file to the list of files to be parsed at the
560  * end of gtk_init().
561  **/
562 void
gtk_rc_add_default_file(const gchar * filename)563 gtk_rc_add_default_file (const gchar *filename)
564 {
565   guint n;
566 
567   gtk_rc_add_initial_default_files ();
568 
569   for (n = 0; n < max_default_files; n++)
570     {
571       if (gtk_rc_default_files[n] == NULL)
572 	break;
573     }
574 
575   if (n == max_default_files)
576     {
577       max_default_files += 10;
578       gtk_rc_default_files = g_renew (gchar*, gtk_rc_default_files, max_default_files);
579     }
580 
581   gtk_rc_default_files[n++] = g_strdup (filename);
582   gtk_rc_default_files[n] = NULL;
583 }
584 
585 /**
586  * gtk_rc_set_default_files:
587  * @filenames: A %NULL-terminated list of filenames.
588  *
589  * Sets the list of files that GTK+ will read at the
590  * end of gtk_init().
591  **/
592 void
gtk_rc_set_default_files(gchar ** filenames)593 gtk_rc_set_default_files (gchar **filenames)
594 {
595   gint i;
596 
597   gtk_rc_add_initial_default_files ();
598 
599   i = 0;
600   while (gtk_rc_default_files[i])
601     {
602       g_free (gtk_rc_default_files[i]);
603       i++;
604     }
605 
606   gtk_rc_default_files[0] = NULL;
607 
608   i = 0;
609   while (filenames[i] != NULL)
610     {
611       gtk_rc_add_default_file (filenames[i]);
612       i++;
613     }
614 }
615 
616 /**
617  * gtk_rc_get_default_files:
618  *
619  * Retrieves the current list of RC files that will be parsed
620  * at the end of gtk_init().
621  *
622  * Return value: (transfer none)  (array zero-terminated=1) (element-type filename):
623  *     A %NULL-terminated array of filenames.
624  *     This memory is owned by GTK+ and must not be freed by the application.
625  *     If you want to store this information, you should make a copy.
626  **/
627 gchar **
gtk_rc_get_default_files(void)628 gtk_rc_get_default_files (void)
629 {
630   gtk_rc_add_initial_default_files ();
631 
632   return gtk_rc_default_files;
633 }
634 
635 static void
gtk_rc_settings_changed(GtkSettings * settings,GParamSpec * pspec,GtkRcContext * context)636 gtk_rc_settings_changed (GtkSettings  *settings,
637 			 GParamSpec   *pspec,
638 			 GtkRcContext *context)
639 {
640   gchar *new_theme_name;
641   gchar *new_key_theme_name;
642 
643   if (context->reloading)
644     return;
645 
646   g_object_get (settings,
647 		"gtk-theme-name", &new_theme_name,
648 		"gtk-key-theme-name", &new_key_theme_name,
649 		NULL);
650 
651   if ((new_theme_name != context->theme_name &&
652        !(new_theme_name && context->theme_name && strcmp (new_theme_name, context->theme_name) == 0)) ||
653       (new_key_theme_name != context->key_theme_name &&
654        !(new_key_theme_name && context->key_theme_name && strcmp (new_key_theme_name, context->key_theme_name) == 0)))
655     {
656       gtk_rc_reparse_all_for_settings (settings, TRUE);
657     }
658 
659   g_free (new_theme_name);
660   g_free (new_key_theme_name);
661 }
662 
663 static void
gtk_rc_font_name_changed(GtkSettings * settings,GParamSpec * pspec,GtkRcContext * context)664 gtk_rc_font_name_changed (GtkSettings  *settings,
665                           GParamSpec   *pspec,
666                           GtkRcContext *context)
667 {
668   if (!context->reloading)
669     _gtk_rc_context_get_default_font_name (settings);
670 }
671 
672 static void
gtk_rc_color_hash_changed(GtkSettings * settings,GParamSpec * pspec,GtkRcContext * context)673 gtk_rc_color_hash_changed (GtkSettings  *settings,
674 			   GParamSpec   *pspec,
675 			   GtkRcContext *context)
676 {
677   GHashTable *old_hash;
678 
679   old_hash = context->color_hash;
680 
681   g_object_get (settings, "color-hash", &context->color_hash, NULL);
682 
683   if (old_hash)
684     g_hash_table_unref (old_hash);
685 
686   gtk_rc_reparse_all_for_settings (settings, TRUE);
687 }
688 
689 static GtkRcContext *
gtk_rc_context_get(GtkSettings * settings)690 gtk_rc_context_get (GtkSettings *settings)
691 {
692   if (!settings->rc_context)
693     {
694       GtkRcContext *context = settings->rc_context = g_new (GtkRcContext, 1);
695 
696       context->settings = settings;
697       context->rc_style_ht = NULL;
698       context->rc_sets_widget = NULL;
699       context->rc_sets_widget_class = NULL;
700       context->rc_sets_class = NULL;
701       context->rc_files = NULL;
702       context->default_style = NULL;
703       context->reloading = FALSE;
704 
705       g_object_get (settings,
706 		    "gtk-theme-name", &context->theme_name,
707 		    "gtk-key-theme-name", &context->key_theme_name,
708 		    "gtk-font-name", &context->font_name,
709 		    "color-hash", &context->color_hash,
710 		    NULL);
711 
712       g_signal_connect (settings,
713 			"notify::gtk-theme-name",
714 			G_CALLBACK (gtk_rc_settings_changed),
715 			context);
716       g_signal_connect (settings,
717 			"notify::gtk-key-theme-name",
718 			G_CALLBACK (gtk_rc_settings_changed),
719 			context);
720       g_signal_connect (settings,
721 			"notify::gtk-font-name",
722 			G_CALLBACK (gtk_rc_font_name_changed),
723 			context);
724       g_signal_connect (settings,
725 			"notify::color-hash",
726 			G_CALLBACK (gtk_rc_color_hash_changed),
727 			context);
728 
729       context->pixmap_path = NULL;
730 
731       context->default_priority = GTK_PATH_PRIO_RC;
732 
733       rc_contexts = g_slist_prepend (rc_contexts, settings->rc_context);
734     }
735 
736   return settings->rc_context;
737 }
738 
739 static void
gtk_rc_clear_rc_files(GtkRcContext * context)740 gtk_rc_clear_rc_files (GtkRcContext *context)
741 {
742   GSList *list;
743 
744   list = context->rc_files;
745   while (list)
746     {
747       GtkRcFile *rc_file = list->data;
748 
749       if (rc_file->canonical_name != rc_file->name)
750 	g_free (rc_file->canonical_name);
751       g_free (rc_file->directory);
752       g_free (rc_file->name);
753       g_free (rc_file);
754 
755       list = list->next;
756     }
757 
758   g_slist_free (context->rc_files);
759   context->rc_files = NULL;
760 }
761 
762 void
_gtk_rc_context_destroy(GtkSettings * settings)763 _gtk_rc_context_destroy (GtkSettings *settings)
764 {
765   GtkRcContext *context;
766 
767   g_return_if_fail (GTK_IS_SETTINGS (settings));
768 
769   context = settings->rc_context;
770   if (!context)
771     return;
772 
773   _gtk_settings_reset_rc_values (context->settings);
774   gtk_rc_clear_styles (context);
775   gtk_rc_clear_rc_files (context);
776 
777   if (context->default_style)
778     g_object_unref (context->default_style);
779 
780   g_strfreev (context->pixmap_path);
781 
782   g_free (context->theme_name);
783   g_free (context->key_theme_name);
784   g_free (context->font_name);
785 
786   if (context->color_hash)
787     g_hash_table_unref (context->color_hash);
788 
789   g_signal_handlers_disconnect_by_func (settings,
790 					gtk_rc_settings_changed, context);
791   g_signal_handlers_disconnect_by_func (settings,
792 					gtk_rc_font_name_changed, context);
793   g_signal_handlers_disconnect_by_func (settings,
794 					gtk_rc_color_hash_changed, context);
795 
796   rc_contexts = g_slist_remove (rc_contexts, context);
797 
798   g_free (context);
799 
800   settings->rc_context = NULL;
801 }
802 
803 static void
gtk_rc_parse_named(GtkRcContext * context,const gchar * name,const gchar * type)804 gtk_rc_parse_named (GtkRcContext *context,
805 		    const gchar  *name,
806 		    const gchar  *type)
807 {
808   gchar *path = NULL;
809   const gchar *home_dir;
810   gchar *subpath;
811 
812   if (type)
813     subpath = g_strconcat ("gtk-2.0-", type,
814 			   G_DIR_SEPARATOR_S "gtkrc",
815 			   NULL);
816   else
817     subpath = g_strdup ("gtk-2.0" G_DIR_SEPARATOR_S "gtkrc");
818 
819   /* First look in the users home directory
820    */
821   home_dir = g_get_home_dir ();
822   if (home_dir)
823     {
824       path = g_build_filename (home_dir, ".themes", name, subpath, NULL);
825       if (!g_file_test (path, G_FILE_TEST_EXISTS))
826 	{
827 	  g_free (path);
828 	  path = NULL;
829 	}
830     }
831 
832   if (!path)
833     {
834       gchar *theme_dir = gtk_rc_get_theme_dir ();
835       path = g_build_filename (theme_dir, name, subpath, NULL);
836       g_free (theme_dir);
837 
838       if (!g_file_test (path, G_FILE_TEST_EXISTS))
839 	{
840 	  g_free (path);
841 	  path = NULL;
842 	}
843     }
844 
845   if (path)
846     {
847       gtk_rc_context_parse_file (context, path, GTK_PATH_PRIO_THEME, FALSE);
848       g_free (path);
849     }
850 
851   g_free (subpath);
852 }
853 
854 static void
gtk_rc_parse_default_files(GtkRcContext * context)855 gtk_rc_parse_default_files (GtkRcContext *context)
856 {
857   gint i;
858 
859   gtk_rc_add_initial_default_files ();
860 
861   for (i = 0; gtk_rc_default_files[i] != NULL; i++)
862     gtk_rc_context_parse_file (context, gtk_rc_default_files[i], GTK_PATH_PRIO_RC, FALSE);
863 }
864 
865 void
_gtk_rc_init(void)866 _gtk_rc_init (void)
867 {
868   static gboolean initialized = FALSE;
869 
870   if (!initialized)
871     {
872       initialized = TRUE;
873 
874       gtk_rc_add_initial_default_files ();
875     }
876 
877   /* Default RC string */
878   gtk_rc_parse_string ("style \"gtk-default-tooltips-style\" {\n"
879 		       "  bg[NORMAL] = \"#eee1b3\"\n"
880 		       "  fg[NORMAL] = \"#000000\"\n"
881 		       "}\n"
882 		       "\n"
883 		       "style \"gtk-default-progress-bar-style\" {\n"
884 		       "  bg[PRELIGHT] = \"#4b6983\"\n"
885 		       "  fg[PRELIGHT] = \"#ffffff\"\n"
886 		       "  bg[NORMAL]   = \"#c4c2bd\"\n"
887 		       "}\n"
888 		       "\n"
889 		       "style \"gtk-default-entry-style\" {\n"
890 		       "  bg[SELECTED] = \"#b7c3cd\"\n"
891 		       "  fg[SELECTED] = \"#000000\"\n"
892 		       "}\n"
893 		       "\n"
894 		       "style \"gtk-default-menu-bar-item-style\" {\n"
895 		       "  GtkMenuItem::horizontal_padding = 5\n"
896 		       "}\n"
897 		       "\n"
898 		       "style \"gtk-default-menu-item-style\" {\n"
899 		       "  bg[PRELIGHT] = \"#4b6983\"\n"
900 		       "  fg[PRELIGHT] = \"#ffffff\"\n"
901 		       "  base[PRELIGHT] = \"#4b6983\"\n"
902 		       "  text[PRELIGHT] = \"#ffffff\"\n"
903 		       "}\n"
904 		       "\n"
905                        /* Work around clipping of accelerator underlines */
906                        "style \"gtk-default-label-style\" {\n"
907                        "  GtkWidget::draw-border = {0,0,0,1}\n"
908                        "}\n"
909                        "\n"
910 		       "class \"GtkProgressBar\" style : gtk \"gtk-default-progress-bar-style\"\n"
911 		       "class \"GtkEntry\" style : gtk \"gtk-default-entry-style\"\n"
912 		       "widget \"gtk-tooltip*\" style : gtk \"gtk-default-tooltips-style\"\n"
913 		       "widget_class \"*<GtkMenuItem>*\" style : gtk \"gtk-default-menu-item-style\"\n"
914 		       "widget_class \"*<GtkMenuBar>*<GtkMenuItem>\" style : gtk \"gtk-default-menu-bar-item-style\"\n"
915                        "class \"GtkLabel\" style : gtk \"gtk-default-label-style\"\n"
916       );
917 }
918 
919 static void
gtk_rc_context_parse_string(GtkRcContext * context,const gchar * rc_string)920 gtk_rc_context_parse_string (GtkRcContext *context,
921 			     const gchar  *rc_string)
922 {
923   gtk_rc_parse_any (context, "-", -1, rc_string);
924 }
925 
926 void
gtk_rc_parse_string(const gchar * rc_string)927 gtk_rc_parse_string (const gchar *rc_string)
928 {
929   GtkRcFile *rc_file;
930   GSList *tmp_list;
931 
932   g_return_if_fail (rc_string != NULL);
933 
934   rc_file = g_new (GtkRcFile, 1);
935   rc_file->is_string = TRUE;
936   rc_file->name = g_strdup (rc_string);
937   rc_file->canonical_name = NULL;
938   rc_file->directory = NULL;
939   rc_file->mtime = 0;
940   rc_file->reload = TRUE;
941 
942   global_rc_files = g_slist_append (global_rc_files, rc_file);
943 
944   for (tmp_list = rc_contexts; tmp_list; tmp_list = tmp_list->next)
945     gtk_rc_context_parse_string (tmp_list->data, rc_string);
946 }
947 
948 static GtkRcFile *
add_to_rc_file_list(GSList ** rc_file_list,const char * filename,gboolean reload)949 add_to_rc_file_list (GSList     **rc_file_list,
950 		     const char  *filename,
951 		     gboolean     reload)
952 {
953   GSList *tmp_list;
954   GtkRcFile *rc_file;
955 
956   tmp_list = *rc_file_list;
957   while (tmp_list)
958     {
959       rc_file = tmp_list->data;
960       if (!strcmp (rc_file->name, filename))
961 	return rc_file;
962 
963       tmp_list = tmp_list->next;
964     }
965 
966   rc_file = g_new (GtkRcFile, 1);
967   rc_file->is_string = FALSE;
968   rc_file->name = g_strdup (filename);
969   rc_file->canonical_name = NULL;
970   rc_file->directory = NULL;
971   rc_file->mtime = 0;
972   rc_file->reload = reload;
973 
974   *rc_file_list = g_slist_append (*rc_file_list, rc_file);
975 
976   return rc_file;
977 }
978 
979 static void
gtk_rc_context_parse_one_file(GtkRcContext * context,const gchar * filename,gint priority,gboolean reload)980 gtk_rc_context_parse_one_file (GtkRcContext *context,
981 			       const gchar  *filename,
982 			       gint          priority,
983 			       gboolean      reload)
984 {
985   GtkRcFile *rc_file;
986   GStatBuf statbuf;
987   gint saved_priority;
988 
989   g_return_if_fail (filename != NULL);
990 
991   saved_priority = context->default_priority;
992   context->default_priority = priority;
993 
994   rc_file = add_to_rc_file_list (&context->rc_files, filename, reload);
995 
996   if (!rc_file->canonical_name)
997     {
998       /* Get the absolute pathname */
999 
1000       if (g_path_is_absolute (rc_file->name))
1001 	rc_file->canonical_name = rc_file->name;
1002       else
1003 	{
1004 	  gchar *cwd;
1005 
1006 	  cwd = g_get_current_dir ();
1007 	  rc_file->canonical_name = g_build_filename (cwd, rc_file->name, NULL);
1008 	  g_free (cwd);
1009 	}
1010 
1011       rc_file->directory = g_path_get_dirname (rc_file->canonical_name);
1012     }
1013 
1014   /* If the file is already being parsed (recursion), do nothing
1015    */
1016   if (g_slist_find (current_files_stack, rc_file))
1017     return;
1018 
1019   if (!g_lstat (rc_file->canonical_name, &statbuf))
1020     {
1021       gint fd;
1022 
1023       rc_file->mtime = statbuf.st_mtime;
1024 
1025       fd = g_open (rc_file->canonical_name, O_RDONLY, 0);
1026       if (fd < 0)
1027 	goto out;
1028 
1029       /* Temporarily push information for this file on
1030        * a stack of current files while parsing it.
1031        */
1032       current_files_stack = g_slist_prepend (current_files_stack, rc_file);
1033       gtk_rc_parse_any (context, filename, fd, NULL);
1034       current_files_stack = g_slist_delete_link (current_files_stack,
1035 						 current_files_stack);
1036 
1037       close (fd);
1038     }
1039 
1040  out:
1041   context->default_priority = saved_priority;
1042 }
1043 
1044 static gchar *
strchr_len(const gchar * str,gint len,char c)1045 strchr_len (const gchar *str, gint len, char c)
1046 {
1047   while (len--)
1048     {
1049       if (*str == c)
1050 	return (gchar *)str;
1051 
1052       str++;
1053     }
1054 
1055   return NULL;
1056 }
1057 
1058 static void
gtk_rc_context_parse_file(GtkRcContext * context,const gchar * filename,gint priority,gboolean reload)1059 gtk_rc_context_parse_file (GtkRcContext *context,
1060 			   const gchar  *filename,
1061 			   gint          priority,
1062 			   gboolean      reload)
1063 {
1064   gchar *locale_suffixes[2];
1065   gint n_locale_suffixes = 0;
1066   gchar *p;
1067   gchar *locale;
1068   gint length, j;
1069   gboolean found = FALSE;
1070 
1071   locale = _gtk_get_lc_ctype ();
1072 
1073   if (strcmp (locale, "C") && strcmp (locale, "POSIX"))
1074     {
1075       /* Determine locale-specific suffixes for RC files.
1076        */
1077       length = strlen (locale);
1078 
1079       p = strchr (locale, '@');
1080       if (p)
1081 	length = p - locale;
1082 
1083       p = strchr_len (locale, length, '.');
1084       if (p)
1085 	length = p - locale;
1086 
1087       locale_suffixes[n_locale_suffixes++] = g_strndup (locale, length);
1088 
1089       p = strchr_len (locale, length, '_');
1090       if (p)
1091 	{
1092 	  length = p - locale;
1093 	  locale_suffixes[n_locale_suffixes++] = g_strndup (locale, length);
1094 	}
1095     }
1096 
1097   g_free (locale);
1098 
1099   gtk_rc_context_parse_one_file (context, filename, priority, reload);
1100   for (j = 0; j < n_locale_suffixes; j++)
1101     {
1102       if (!found)
1103 	{
1104 	  gchar *name = g_strconcat (filename, ".", locale_suffixes[j], NULL);
1105 	  if (g_file_test (name, G_FILE_TEST_EXISTS))
1106 	    {
1107 	      gtk_rc_context_parse_one_file (context, name, priority, FALSE);
1108 	      found = TRUE;
1109 	    }
1110 
1111 	  g_free (name);
1112 	}
1113 
1114       g_free (locale_suffixes[j]);
1115     }
1116 }
1117 
1118 void
gtk_rc_parse(const gchar * filename)1119 gtk_rc_parse (const gchar *filename)
1120 {
1121   GSList *tmp_list;
1122 
1123   g_return_if_fail (filename != NULL);
1124 
1125   add_to_rc_file_list (&global_rc_files, filename, TRUE);
1126 
1127   for (tmp_list = rc_contexts; tmp_list; tmp_list = tmp_list->next)
1128     gtk_rc_context_parse_file (tmp_list->data, filename, GTK_PATH_PRIO_RC, TRUE);
1129 }
1130 
1131 /* Handling of RC styles */
1132 
G_DEFINE_TYPE(GtkRcStyle,gtk_rc_style,G_TYPE_OBJECT)1133 G_DEFINE_TYPE (GtkRcStyle, gtk_rc_style, G_TYPE_OBJECT)
1134 
1135 static void
1136 gtk_rc_style_init (GtkRcStyle *style)
1137 {
1138   GtkRcStylePrivate *priv = GTK_RC_STYLE_GET_PRIVATE (style);
1139   guint i;
1140 
1141   style->name = NULL;
1142   style->font_desc = NULL;
1143 
1144   for (i = 0; i < 5; i++)
1145     {
1146       static const GdkColor init_color = { 0, 0, 0, 0, };
1147 
1148       style->bg_pixmap_name[i] = NULL;
1149       style->color_flags[i] = 0;
1150       style->fg[i] = init_color;
1151       style->bg[i] = init_color;
1152       style->text[i] = init_color;
1153       style->base[i] = init_color;
1154     }
1155   style->xthickness = -1;
1156   style->ythickness = -1;
1157   style->rc_properties = NULL;
1158 
1159   style->rc_style_lists = NULL;
1160   style->icon_factories = NULL;
1161 
1162   priv->color_hashes = NULL;
1163 }
1164 
1165 static void
gtk_rc_style_class_init(GtkRcStyleClass * klass)1166 gtk_rc_style_class_init (GtkRcStyleClass *klass)
1167 {
1168   GObjectClass *object_class = G_OBJECT_CLASS (klass);
1169 
1170   object_class->finalize = gtk_rc_style_finalize;
1171 
1172   klass->parse = NULL;
1173   klass->create_rc_style = gtk_rc_style_real_create_rc_style;
1174   klass->merge = gtk_rc_style_real_merge;
1175   klass->create_style = gtk_rc_style_real_create_style;
1176 
1177   g_type_class_add_private (object_class, sizeof (GtkRcStylePrivate));
1178 }
1179 
1180 static void
gtk_rc_style_finalize(GObject * object)1181 gtk_rc_style_finalize (GObject *object)
1182 {
1183   GSList *tmp_list1, *tmp_list2;
1184   GtkRcStyle *rc_style;
1185   GtkRcStylePrivate *rc_priv;
1186   gint i;
1187 
1188   rc_style = GTK_RC_STYLE (object);
1189   rc_priv = GTK_RC_STYLE_GET_PRIVATE (rc_style);
1190 
1191   g_free (rc_style->name);
1192   if (rc_style->font_desc)
1193     pango_font_description_free (rc_style->font_desc);
1194 
1195   for (i = 0; i < 5; i++)
1196     g_free (rc_style->bg_pixmap_name[i]);
1197 
1198   /* Now remove all references to this rc_style from
1199    * realized_style_ht
1200    */
1201   tmp_list1 = rc_style->rc_style_lists;
1202   while (tmp_list1)
1203     {
1204       GSList *rc_styles = tmp_list1->data;
1205       GtkStyle *style = g_hash_table_lookup (realized_style_ht, rc_styles);
1206       g_object_unref (style);
1207 
1208       /* Remove the list of styles from the other rc_styles
1209        * in the list
1210        */
1211       tmp_list2 = rc_styles;
1212       while (tmp_list2)
1213         {
1214           GtkRcStyle *other_style = tmp_list2->data;
1215 
1216           if (other_style != rc_style)
1217             other_style->rc_style_lists = g_slist_remove_all (other_style->rc_style_lists,
1218 							      rc_styles);
1219           tmp_list2 = tmp_list2->next;
1220         }
1221 
1222       /* And from the hash table itself
1223        */
1224       g_hash_table_remove (realized_style_ht, rc_styles);
1225       g_slist_free (rc_styles);
1226 
1227       tmp_list1 = tmp_list1->next;
1228     }
1229   g_slist_free (rc_style->rc_style_lists);
1230 
1231   if (rc_style->rc_properties)
1232     {
1233       guint i;
1234 
1235       for (i = 0; i < rc_style->rc_properties->len; i++)
1236 	{
1237 	  GtkRcProperty *node = &g_array_index (rc_style->rc_properties, GtkRcProperty, i);
1238 
1239 	  g_free (node->origin);
1240 	  g_value_unset (&node->value);
1241 	}
1242       g_array_free (rc_style->rc_properties, TRUE);
1243       rc_style->rc_properties = NULL;
1244     }
1245 
1246   g_slist_foreach (rc_style->icon_factories, (GFunc) g_object_unref, NULL);
1247   g_slist_free (rc_style->icon_factories);
1248 
1249   g_slist_foreach (rc_priv->color_hashes, (GFunc) g_hash_table_unref, NULL);
1250   g_slist_free (rc_priv->color_hashes);
1251 
1252   G_OBJECT_CLASS (gtk_rc_style_parent_class)->finalize (object);
1253 }
1254 
1255 GtkRcStyle *
gtk_rc_style_new(void)1256 gtk_rc_style_new (void)
1257 {
1258   GtkRcStyle *style;
1259 
1260   style = g_object_new (GTK_TYPE_RC_STYLE, NULL);
1261 
1262   return style;
1263 }
1264 
1265 /**
1266  * gtk_rc_style_copy:
1267  * @orig: the style to copy
1268  *
1269  * Makes a copy of the specified #GtkRcStyle. This function
1270  * will correctly copy an RC style that is a member of a class
1271  * derived from #GtkRcStyle.
1272  *
1273  * Return value: (transfer full): the resulting #GtkRcStyle
1274  **/
1275 GtkRcStyle *
gtk_rc_style_copy(GtkRcStyle * orig)1276 gtk_rc_style_copy (GtkRcStyle *orig)
1277 {
1278   GtkRcStyle *style;
1279 
1280   g_return_val_if_fail (GTK_IS_RC_STYLE (orig), NULL);
1281 
1282   style = GTK_RC_STYLE_GET_CLASS (orig)->create_rc_style (orig);
1283   GTK_RC_STYLE_GET_CLASS (style)->merge (style, orig);
1284 
1285   gtk_rc_style_copy_icons_and_colors (style, orig, NULL);
1286 
1287   return style;
1288 }
1289 
1290 void
_gtk_rc_style_set_rc_property(GtkRcStyle * rc_style,GtkRcProperty * property)1291 _gtk_rc_style_set_rc_property (GtkRcStyle *rc_style,
1292 			       GtkRcProperty *property)
1293 {
1294   g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
1295   g_return_if_fail (property != NULL);
1296 
1297   insert_rc_property (rc_style, property, TRUE);
1298 }
1299 
1300 void
_gtk_rc_style_unset_rc_property(GtkRcStyle * rc_style,GQuark type_name,GQuark property_name)1301 _gtk_rc_style_unset_rc_property (GtkRcStyle *rc_style,
1302 				 GQuark      type_name,
1303 				 GQuark      property_name)
1304 {
1305   GtkRcProperty *node;
1306 
1307   g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
1308 
1309   node = (GtkRcProperty *) _gtk_rc_style_lookup_rc_property (rc_style,
1310                                                              type_name,
1311                                                              property_name);
1312 
1313   if (node != NULL)
1314     {
1315       guint index = node - (GtkRcProperty *) rc_style->rc_properties->data;
1316       g_value_unset (&node->value);
1317       g_free (node->origin);
1318       g_array_remove_index (rc_style->rc_properties, index);
1319     }
1320 }
1321 
1322 void
gtk_rc_style_ref(GtkRcStyle * rc_style)1323 gtk_rc_style_ref (GtkRcStyle *rc_style)
1324 {
1325   g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
1326 
1327   g_object_ref (rc_style);
1328 }
1329 
1330 void
gtk_rc_style_unref(GtkRcStyle * rc_style)1331 gtk_rc_style_unref (GtkRcStyle *rc_style)
1332 {
1333   g_return_if_fail (GTK_IS_RC_STYLE (rc_style));
1334 
1335   g_object_unref (rc_style);
1336 }
1337 
1338 static GtkRcStyle *
gtk_rc_style_real_create_rc_style(GtkRcStyle * style)1339 gtk_rc_style_real_create_rc_style (GtkRcStyle *style)
1340 {
1341   return g_object_new (G_OBJECT_TYPE (style), NULL);
1342 }
1343 
1344 GSList *
_gtk_rc_style_get_color_hashes(GtkRcStyle * rc_style)1345 _gtk_rc_style_get_color_hashes (GtkRcStyle *rc_style)
1346 {
1347   GtkRcStylePrivate *priv = GTK_RC_STYLE_GET_PRIVATE (rc_style);
1348 
1349   return priv->color_hashes;
1350 }
1351 
1352 static gint
gtk_rc_properties_cmp(gconstpointer bsearch_node1,gconstpointer bsearch_node2)1353 gtk_rc_properties_cmp (gconstpointer bsearch_node1,
1354 		       gconstpointer bsearch_node2)
1355 {
1356   const GtkRcProperty *prop1 = bsearch_node1;
1357   const GtkRcProperty *prop2 = bsearch_node2;
1358 
1359   if (prop1->type_name == prop2->type_name)
1360     return prop1->property_name < prop2->property_name ? -1 : prop1->property_name == prop2->property_name ? 0 : 1;
1361   else
1362     return prop1->type_name < prop2->type_name ? -1 : 1;
1363 }
1364 
1365 static void
insert_rc_property(GtkRcStyle * style,GtkRcProperty * property,gboolean replace)1366 insert_rc_property (GtkRcStyle    *style,
1367 		    GtkRcProperty *property,
1368 		    gboolean       replace)
1369 {
1370   guint i;
1371   GtkRcProperty *new_property = NULL;
1372   GtkRcProperty key = { 0, 0, NULL, { 0, }, };
1373 
1374   key.type_name = property->type_name;
1375   key.property_name = property->property_name;
1376 
1377   if (!style->rc_properties)
1378     style->rc_properties = g_array_new (FALSE, FALSE, sizeof (GtkRcProperty));
1379 
1380   i = 0;
1381   while (i < style->rc_properties->len)
1382     {
1383       gint cmp = gtk_rc_properties_cmp (&key, &g_array_index (style->rc_properties, GtkRcProperty, i));
1384 
1385       if (cmp == 0)
1386 	{
1387 	  if (replace)
1388 	    {
1389 	      new_property = &g_array_index (style->rc_properties, GtkRcProperty, i);
1390 
1391 	      g_free (new_property->origin);
1392 	      g_value_unset (&new_property->value);
1393 
1394 	      *new_property = key;
1395 	      break;
1396 	    }
1397 	  else
1398 	    return;
1399 	}
1400       else if (cmp < 0)
1401 	break;
1402 
1403       i++;
1404     }
1405 
1406   if (!new_property)
1407     {
1408       g_array_insert_val (style->rc_properties, i, key);
1409       new_property = &g_array_index (style->rc_properties, GtkRcProperty, i);
1410     }
1411 
1412   new_property->origin = g_strdup (property->origin);
1413   g_value_init (&new_property->value, G_VALUE_TYPE (&property->value));
1414   g_value_copy (&property->value, &new_property->value);
1415 }
1416 
1417 static void
gtk_rc_style_real_merge(GtkRcStyle * dest,GtkRcStyle * src)1418 gtk_rc_style_real_merge (GtkRcStyle *dest,
1419 			 GtkRcStyle *src)
1420 {
1421   gint i;
1422 
1423   for (i = 0; i < 5; i++)
1424     {
1425       if (!dest->bg_pixmap_name[i] && src->bg_pixmap_name[i])
1426 	dest->bg_pixmap_name[i] = g_strdup (src->bg_pixmap_name[i]);
1427 
1428       if (!(dest->color_flags[i] & GTK_RC_FG) &&
1429 	  src->color_flags[i] & GTK_RC_FG)
1430 	{
1431 	  dest->fg[i] = src->fg[i];
1432 	  dest->color_flags[i] |= GTK_RC_FG;
1433 	}
1434       if (!(dest->color_flags[i] & GTK_RC_BG) &&
1435 	  src->color_flags[i] & GTK_RC_BG)
1436 	{
1437 	  dest->bg[i] = src->bg[i];
1438 	  dest->color_flags[i] |= GTK_RC_BG;
1439 	}
1440       if (!(dest->color_flags[i] & GTK_RC_TEXT) &&
1441 	  src->color_flags[i] & GTK_RC_TEXT)
1442 	{
1443 	  dest->text[i] = src->text[i];
1444 	  dest->color_flags[i] |= GTK_RC_TEXT;
1445 	}
1446       if (!(dest->color_flags[i] & GTK_RC_BASE) &&
1447 	  src->color_flags[i] & GTK_RC_BASE)
1448 	{
1449 	  dest->base[i] = src->base[i];
1450 	  dest->color_flags[i] |= GTK_RC_BASE;
1451 	}
1452     }
1453 
1454   if (dest->xthickness < 0 && src->xthickness >= 0)
1455     dest->xthickness = src->xthickness;
1456   if (dest->ythickness < 0 && src->ythickness >= 0)
1457     dest->ythickness = src->ythickness;
1458 
1459   if (src->font_desc)
1460     {
1461       if (!dest->font_desc)
1462 	dest->font_desc = pango_font_description_copy (src->font_desc);
1463       else
1464 	pango_font_description_merge (dest->font_desc, src->font_desc, FALSE);
1465     }
1466 
1467   if (src->rc_properties)
1468     {
1469       guint i;
1470 
1471       for (i = 0; i < src->rc_properties->len; i++)
1472 	insert_rc_property (dest,
1473 			    &g_array_index (src->rc_properties, GtkRcProperty, i),
1474 			    FALSE);
1475     }
1476 }
1477 
1478 static GtkStyle *
gtk_rc_style_real_create_style(GtkRcStyle * rc_style)1479 gtk_rc_style_real_create_style (GtkRcStyle *rc_style)
1480 {
1481   return gtk_style_new ();
1482 }
1483 
1484 static void
gtk_rc_style_prepend_empty_icon_factory(GtkRcStyle * rc_style)1485 gtk_rc_style_prepend_empty_icon_factory (GtkRcStyle *rc_style)
1486 {
1487   GtkIconFactory *factory = gtk_icon_factory_new ();
1488 
1489   rc_style->icon_factories = g_slist_prepend (rc_style->icon_factories, factory);
1490 }
1491 
1492 static void
gtk_rc_style_prepend_empty_color_hash(GtkRcStyle * rc_style)1493 gtk_rc_style_prepend_empty_color_hash (GtkRcStyle *rc_style)
1494 {
1495   GtkRcStylePrivate *priv = GTK_RC_STYLE_GET_PRIVATE (rc_style);
1496   GHashTable        *hash = g_hash_table_new_full (g_str_hash, g_str_equal,
1497                                                    g_free,
1498                                                    (GDestroyNotify) gdk_color_free);
1499 
1500   priv->color_hashes = g_slist_prepend (priv->color_hashes, hash);
1501 }
1502 
1503 static void
gtk_rc_style_append_icon_factories(GtkRcStyle * rc_style,GtkRcStyle * src_style)1504 gtk_rc_style_append_icon_factories (GtkRcStyle *rc_style,
1505                                     GtkRcStyle *src_style)
1506 {
1507   GSList *concat = g_slist_copy (src_style->icon_factories);
1508 
1509   g_slist_foreach (concat, (GFunc) g_object_ref, NULL);
1510 
1511   rc_style->icon_factories = g_slist_concat (rc_style->icon_factories, concat);
1512 }
1513 
1514 static void
gtk_rc_style_append_color_hashes(GtkRcStyle * rc_style,GtkRcStyle * src_style)1515 gtk_rc_style_append_color_hashes (GtkRcStyle *rc_style,
1516                                   GtkRcStyle *src_style)
1517 {
1518   GtkRcStylePrivate *priv     = GTK_RC_STYLE_GET_PRIVATE (rc_style);
1519   GtkRcStylePrivate *src_priv = GTK_RC_STYLE_GET_PRIVATE (src_style);
1520   GSList            *concat   = g_slist_copy (src_priv->color_hashes);
1521 
1522   g_slist_foreach (concat, (GFunc) g_hash_table_ref, NULL);
1523 
1524   priv->color_hashes = g_slist_concat (priv->color_hashes, concat);
1525 }
1526 
1527 static void
gtk_rc_style_copy_icons_and_colors(GtkRcStyle * rc_style,GtkRcStyle * src_style,GtkRcContext * context)1528 gtk_rc_style_copy_icons_and_colors (GtkRcStyle   *rc_style,
1529                                     GtkRcStyle   *src_style,
1530                                     GtkRcContext *context)
1531 {
1532   GtkRcStylePrivate *priv = GTK_RC_STYLE_GET_PRIVATE (rc_style);
1533 
1534   if (src_style)
1535     {
1536       GtkRcStylePrivate *src_priv = GTK_RC_STYLE_GET_PRIVATE (src_style);
1537 
1538       /* Append src_style's factories, adding a ref to them */
1539       if (src_style->icon_factories != NULL)
1540         {
1541           /* Add a factory for ourselves if we have none,
1542            * in case we end up defining more stock icons.
1543            * I see no real way around this; we need to maintain
1544            * the invariant that the first factory in the list
1545            * is always our_factory, the one belonging to us,
1546            * and if we put src_style factories in the list we can't
1547            * do that if the style is reopened.
1548            */
1549           if (rc_style->icon_factories == NULL)
1550             gtk_rc_style_prepend_empty_icon_factory (rc_style);
1551 
1552           gtk_rc_style_append_icon_factories (rc_style, src_style);
1553         }
1554 
1555       /* Also append src_style's color hashes, adding a ref to them */
1556       if (src_priv->color_hashes != NULL)
1557         {
1558           /* See comment above .. */
1559           if (priv->color_hashes == NULL)
1560             gtk_rc_style_prepend_empty_color_hash (rc_style);
1561 
1562           gtk_rc_style_append_color_hashes (rc_style, src_style);
1563         }
1564     }
1565 
1566   /*  if we didn't get color hashes from the src_style, initialize
1567    *  the list with the settings' color scheme (if it exists)
1568    */
1569   if (priv->color_hashes == NULL && context && context->color_hash != NULL)
1570     {
1571       gtk_rc_style_prepend_empty_color_hash (rc_style);
1572 
1573       priv->color_hashes = g_slist_append (priv->color_hashes,
1574                                            g_hash_table_ref (context->color_hash));
1575     }
1576 }
1577 
1578 static void
gtk_rc_clear_hash_node(gpointer key,gpointer data,gpointer user_data)1579 gtk_rc_clear_hash_node (gpointer key,
1580 			gpointer data,
1581 			gpointer user_data)
1582 {
1583   g_object_unref (data);
1584 }
1585 
1586 static void
gtk_rc_free_rc_sets(GSList * slist)1587 gtk_rc_free_rc_sets (GSList *slist)
1588 {
1589   while (slist)
1590     {
1591       GtkRcSet *rc_set;
1592 
1593       rc_set = slist->data;
1594       gtk_rc_set_free (rc_set);
1595 
1596       slist = slist->next;
1597     }
1598 }
1599 
1600 static void
gtk_rc_clear_styles(GtkRcContext * context)1601 gtk_rc_clear_styles (GtkRcContext *context)
1602 {
1603   /* Clear out all old rc_styles */
1604 
1605   if (context->rc_style_ht)
1606     {
1607       g_hash_table_foreach (context->rc_style_ht, gtk_rc_clear_hash_node, NULL);
1608       g_hash_table_destroy (context->rc_style_ht);
1609       context->rc_style_ht = NULL;
1610     }
1611 
1612   gtk_rc_free_rc_sets (context->rc_sets_widget);
1613   g_slist_free (context->rc_sets_widget);
1614   context->rc_sets_widget = NULL;
1615 
1616   gtk_rc_free_rc_sets (context->rc_sets_widget_class);
1617   g_slist_free (context->rc_sets_widget_class);
1618   context->rc_sets_widget_class = NULL;
1619 
1620   gtk_rc_free_rc_sets (context->rc_sets_class);
1621   g_slist_free (context->rc_sets_class);
1622   context->rc_sets_class = NULL;
1623 }
1624 
1625 /* Reset all our widgets. Also, we have to invalidate cached icons in
1626  * icon sets so they get re-rendered.
1627  */
1628 static void
gtk_rc_reset_widgets(GtkSettings * settings)1629 gtk_rc_reset_widgets (GtkSettings *settings)
1630 {
1631   GList *list, *toplevels;
1632 
1633   _gtk_icon_set_invalidate_caches ();
1634 
1635   toplevels = gtk_window_list_toplevels ();
1636   g_list_foreach (toplevels, (GFunc)g_object_ref, NULL);
1637 
1638   for (list = toplevels; list; list = list->next)
1639     {
1640       if (gtk_widget_get_screen (list->data) == settings->screen)
1641 	{
1642 	  gtk_widget_reset_rc_styles (list->data);
1643 	}
1644 
1645       g_object_unref (list->data);
1646     }
1647   g_list_free (toplevels);
1648 }
1649 
1650 static void
gtk_rc_clear_realized_style(gpointer key,gpointer value,gpointer data)1651 gtk_rc_clear_realized_style (gpointer key,
1652 			     gpointer value,
1653 			     gpointer data)
1654 {
1655   GSList *rc_styles = key;
1656   GtkStyle *style = value;
1657   GSList *tmp_list = rc_styles;
1658 
1659   g_object_unref (style);
1660 
1661   while (tmp_list)
1662     {
1663       GtkRcStyle *rc_style = tmp_list->data;
1664 
1665       rc_style->rc_style_lists = g_slist_remove_all (rc_style->rc_style_lists,
1666 						     rc_styles);
1667       tmp_list = tmp_list->next;
1668     }
1669 
1670   g_slist_free (rc_styles);
1671 }
1672 
1673 /**
1674  * gtk_rc_reset_styles:
1675  * @settings: a #GtkSettings
1676  *
1677  * This function recomputes the styles for all widgets that use a
1678  * particular #GtkSettings object. (There is one #GtkSettings object
1679  * per #GdkScreen, see gtk_settings_get_for_screen()); It is useful
1680  * when some global parameter has changed that affects the appearance
1681  * of all widgets, because when a widget gets a new style, it will
1682  * both redraw and recompute any cached information about its
1683  * appearance. As an example, it is used when the default font size
1684  * set by the operating system changes. Note that this function
1685  * doesn't affect widgets that have a style set explicitely on them
1686  * with gtk_widget_set_style().
1687  *
1688  * Since: 2.4
1689  **/
1690 void
gtk_rc_reset_styles(GtkSettings * settings)1691 gtk_rc_reset_styles (GtkSettings *settings)
1692 {
1693   GtkRcContext *context;
1694   gboolean reset = FALSE;
1695 
1696   g_return_if_fail (GTK_IS_SETTINGS (settings));
1697 
1698   context = gtk_rc_context_get (settings);
1699 
1700   if (context->default_style)
1701     {
1702       g_object_unref (context->default_style);
1703       context->default_style = NULL;
1704       reset = TRUE;
1705     }
1706 
1707   /* Clear out styles that have been looked up already
1708    */
1709   if (realized_style_ht)
1710     {
1711       g_hash_table_foreach (realized_style_ht, gtk_rc_clear_realized_style, NULL);
1712       g_hash_table_destroy (realized_style_ht);
1713       realized_style_ht = NULL;
1714       reset = TRUE;
1715     }
1716 
1717   if (reset)
1718     gtk_rc_reset_widgets (settings);
1719 }
1720 
1721 const gchar*
_gtk_rc_context_get_default_font_name(GtkSettings * settings)1722 _gtk_rc_context_get_default_font_name (GtkSettings *settings)
1723 {
1724   GtkRcContext *context;
1725   gchar *new_font_name;
1726 
1727   g_return_val_if_fail (GTK_IS_SETTINGS (settings), NULL);
1728 
1729   context = gtk_rc_context_get (settings);
1730 
1731   g_object_get (context->settings,
1732                 "gtk-font-name", &new_font_name,
1733                 NULL);
1734 
1735   if (new_font_name != context->font_name && !(new_font_name && strcmp (context->font_name, new_font_name) == 0))
1736     {
1737        g_free (context->font_name);
1738        context->font_name = g_strdup (new_font_name);
1739 
1740        gtk_rc_reset_styles (settings);
1741     }
1742 
1743   g_free (new_font_name);
1744 
1745   return context->font_name;
1746 }
1747 
1748 /**
1749  * gtk_rc_reparse_all_for_settings:
1750  * @settings: a #GtkSettings
1751  * @force_load: load whether or not anything changed
1752  *
1753  * If the modification time on any previously read file
1754  * for the given #GtkSettings has changed, discard all style information
1755  * and then reread all previously read RC files.
1756  *
1757  * Return value: %TRUE if the files were reread.
1758  **/
1759 gboolean
gtk_rc_reparse_all_for_settings(GtkSettings * settings,gboolean force_load)1760 gtk_rc_reparse_all_for_settings (GtkSettings *settings,
1761 				 gboolean     force_load)
1762 {
1763   gboolean mtime_modified = FALSE;
1764   GtkRcFile *rc_file;
1765   GSList *tmp_list;
1766   GtkRcContext *context;
1767   GStatBuf statbuf;
1768 
1769   g_return_val_if_fail (GTK_IS_SETTINGS (settings), FALSE);
1770 
1771   context = gtk_rc_context_get (settings);
1772 
1773   if (context->reloading)
1774     return FALSE;
1775 
1776   if (!force_load)
1777     {
1778       /* Check through and see if any of the RC's have had their
1779        * mtime modified. If so, reparse everything.
1780        */
1781       tmp_list = context->rc_files;
1782       while (tmp_list)
1783 	{
1784 	  rc_file = tmp_list->data;
1785 
1786 	  if (!rc_file->is_string)
1787 	    {
1788 	      if (!g_lstat (rc_file->name, &statbuf) &&
1789 		  (statbuf.st_mtime != rc_file->mtime))
1790 		{
1791 		  mtime_modified = TRUE;
1792 		  break;
1793 		}
1794 	    }
1795 
1796 	  tmp_list = tmp_list->next;
1797 	}
1798     }
1799 
1800   if (force_load || mtime_modified)
1801     {
1802       _gtk_binding_reset_parsed ();
1803       gtk_rc_clear_styles (context);
1804       context->reloading = TRUE;
1805 
1806       _gtk_settings_reset_rc_values (context->settings);
1807       gtk_rc_clear_rc_files (context);
1808 
1809       gtk_rc_parse_default_files (context);
1810 
1811       tmp_list = global_rc_files;
1812       while (tmp_list)
1813 	{
1814 	  rc_file = tmp_list->data;
1815 
1816 	  if (rc_file->is_string)
1817 	    gtk_rc_context_parse_string (context, rc_file->name);
1818 	  else
1819 	    gtk_rc_context_parse_file (context, rc_file->name, GTK_PATH_PRIO_RC, FALSE);
1820 
1821 	  tmp_list = tmp_list->next;
1822 	}
1823 
1824       g_free (context->theme_name);
1825       g_free (context->key_theme_name);
1826 
1827       g_object_get (context->settings,
1828 		    "gtk-theme-name", &context->theme_name,
1829 		    "gtk-key-theme-name", &context->key_theme_name,
1830 		    NULL);
1831 
1832       if (context->theme_name && context->theme_name[0])
1833 	gtk_rc_parse_named (context, context->theme_name, NULL);
1834       if (context->key_theme_name && context->key_theme_name[0])
1835 	gtk_rc_parse_named (context, context->key_theme_name, "key");
1836 
1837       context->reloading = FALSE;
1838 
1839       gtk_rc_reset_widgets (context->settings);
1840     }
1841 
1842   return force_load || mtime_modified;
1843 }
1844 
1845 /**
1846  * gtk_rc_reparse_all:
1847  *
1848  * If the modification time on any previously read file for the
1849  * default #GtkSettings has changed, discard all style information
1850  * and then reread all previously read RC files.
1851  *
1852  * Return value:  %TRUE if the files were reread.
1853  **/
1854 gboolean
gtk_rc_reparse_all(void)1855 gtk_rc_reparse_all (void)
1856 {
1857   GSList *tmp_list;
1858   gboolean result = FALSE;
1859 
1860   for (tmp_list = rc_contexts; tmp_list; tmp_list = tmp_list->next)
1861     {
1862       GtkRcContext *context = tmp_list->data;
1863       if (gtk_rc_reparse_all_for_settings (context->settings, FALSE))
1864 	result = TRUE;
1865     }
1866 
1867   return result;
1868 }
1869 
1870 static GSList *
gtk_rc_styles_match(GSList * rc_styles,GSList * sets,guint path_length,gchar * path,gchar * path_reversed)1871 gtk_rc_styles_match (GSList       *rc_styles,
1872 		     GSList	  *sets,
1873 		     guint         path_length,
1874 		     gchar        *path,
1875 		     gchar        *path_reversed)
1876 
1877 {
1878   GtkRcSet *rc_set;
1879 
1880   while (sets)
1881     {
1882       rc_set = sets->data;
1883       sets = sets->next;
1884 
1885       if (rc_set->type == GTK_PATH_WIDGET_CLASS)
1886         {
1887           if (_gtk_rc_match_widget_class (rc_set->path, path_length, path, path_reversed))
1888 	    rc_styles = g_slist_append (rc_styles, rc_set);
1889         }
1890       else
1891         {
1892           if (g_pattern_match (rc_set->pspec, path_length, path, path_reversed))
1893 	    rc_styles = g_slist_append (rc_styles, rc_set);
1894 	}
1895     }
1896 
1897   return rc_styles;
1898 }
1899 
1900 static gint
rc_set_compare(gconstpointer a,gconstpointer b)1901 rc_set_compare (gconstpointer a, gconstpointer b)
1902 {
1903   const GtkRcSet *set_a = a;
1904   const GtkRcSet *set_b = b;
1905 
1906   return (set_a->priority < set_b->priority) ? 1 : (set_a->priority == set_b->priority ? 0 : -1);
1907 }
1908 
1909 static GSList *
sort_and_dereference_sets(GSList * styles)1910 sort_and_dereference_sets (GSList *styles)
1911 {
1912   GSList *tmp_list;
1913 
1914   /* At this point, the list of sets is ordered by:
1915    *
1916    * a) 'widget' patterns are earlier than 'widget_class' patterns
1917    *    which are ealier than 'class' patterns.
1918    * a) For two matches for class patterns, a match to a child type
1919    *    is before a match to a parent type
1920    * c) a match later in the RC file (or in a later RC file) is before a
1921    *    match earlier in the RC file.
1922    *
1923    * With a) taking precedence over b) which takes precendence over c).
1924    *
1925    * Now sort by priority, which has the highest precendence for sort order
1926    */
1927   styles = g_slist_sort (styles, rc_set_compare);
1928 
1929   /* Make styles->data = styles->data->rc_style
1930    */
1931   tmp_list = styles;
1932   while (tmp_list)
1933     {
1934       GtkRcSet *set = tmp_list->data;
1935       tmp_list->data = set->rc_style;
1936       tmp_list = tmp_list->next;
1937     }
1938 
1939   return styles;
1940 }
1941 
1942 /**
1943  * gtk_rc_get_style:
1944  * @widget: a #GtkWidget
1945  *
1946  * Finds all matching RC styles for a given widget,
1947  * composites them together, and then creates a
1948  * #GtkStyle representing the composite appearance.
1949  * (GTK+ actually keeps a cache of previously
1950  * created styles, so a new style may not be
1951  * created.)
1952  *
1953  * Returns: (transfer none): the resulting style. No refcount is added
1954  *   to the returned style, so if you want to save this
1955  *   style around, you should add a reference yourself.
1956  **/
1957 GtkStyle *
gtk_rc_get_style(GtkWidget * widget)1958 gtk_rc_get_style (GtkWidget *widget)
1959 {
1960   GtkRcStyle *widget_rc_style;
1961   GSList *rc_styles = NULL;
1962   GtkRcContext *context;
1963 
1964   static guint rc_style_key_id = 0;
1965 
1966   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
1967 
1968   context = gtk_rc_context_get (gtk_widget_get_settings (widget));
1969 
1970   /* We allow the specification of a single rc style to be bound
1971    * tightly to a widget, for application modifications
1972    */
1973   if (!rc_style_key_id)
1974     rc_style_key_id = g_quark_from_static_string ("gtk-rc-style");
1975 
1976   if (context->rc_sets_widget)
1977     {
1978       gchar *path, *path_reversed;
1979       guint path_length;
1980 
1981       gtk_widget_path (widget, &path_length, &path, &path_reversed);
1982       rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget, path_length, path, path_reversed);
1983       g_free (path);
1984       g_free (path_reversed);
1985     }
1986 
1987   if (context->rc_sets_widget_class)
1988     {
1989       gchar *path, *path_reversed;
1990       guint path_length;
1991 
1992       gtk_widget_class_path (widget, &path_length, &path, &path_reversed);
1993       rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget_class, path_length, path, path_reversed);
1994       g_free (path);
1995       g_free (path_reversed);
1996     }
1997 
1998   if (context->rc_sets_class)
1999     {
2000       GType type;
2001 
2002       type = G_TYPE_FROM_INSTANCE (widget);
2003       while (type)
2004 	{
2005 	  gchar *path;
2006           gchar *path_reversed;
2007 	  guint path_length;
2008 
2009 	  path = g_strdup (g_type_name (type));
2010 	  path_length = strlen (path);
2011 	  path_reversed = g_strdup (path);
2012 	  g_strreverse (path_reversed);
2013 
2014 	  rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_class, path_length, path, path_reversed);
2015 	  g_free (path);
2016 	  g_free (path_reversed);
2017 
2018 	  type = g_type_parent (type);
2019 	}
2020     }
2021 
2022   rc_styles = sort_and_dereference_sets (rc_styles);
2023 
2024   widget_rc_style = g_object_get_qdata (G_OBJECT (widget), rc_style_key_id);
2025 
2026   if (widget_rc_style)
2027     rc_styles = g_slist_prepend (rc_styles, widget_rc_style);
2028 
2029   if (rc_styles)
2030     return gtk_rc_init_style (context, rc_styles);
2031   else
2032     {
2033       if (!context->default_style)
2034 	{
2035 	  GtkStyle * style = gtk_style_new ();
2036 	  _gtk_style_init_for_settings (style, context->settings);
2037 
2038 	  /* Only after _gtk_style_init_for_settings() do we install the style
2039 	   * as the default, otherwise gtk_rc_reset_styles() can be called and
2040 	   * unref the style while initializing it, causing a segfault.
2041 	   */
2042 	  context->default_style = style;
2043 	}
2044 
2045       return context->default_style;
2046     }
2047 }
2048 
2049 /**
2050  * gtk_rc_get_style_by_paths:
2051  * @settings: a #GtkSettings object
2052  * @widget_path: (allow-none): the widget path to use when looking up the
2053  *     style, or %NULL if no matching against the widget path should be done
2054  * @class_path: (allow-none): the class path to use when looking up the style,
2055  *     or %NULL if no matching against the class path should be done.
2056  * @type: a type that will be used along with parent types of this type
2057  *     when matching against class styles, or #G_TYPE_NONE
2058  *
2059  * Creates up a #GtkStyle from styles defined in a RC file by providing
2060  * the raw components used in matching. This function may be useful
2061  * when creating pseudo-widgets that should be themed like widgets but
2062  * don't actually have corresponding GTK+ widgets. An example of this
2063  * would be items inside a GNOME canvas widget.
2064  *
2065  * The action of gtk_rc_get_style() is similar to:
2066  * |[
2067  *  gtk_widget_path (widget, NULL, &path, NULL);
2068  *  gtk_widget_class_path (widget, NULL, &class_path, NULL);
2069  *  gtk_rc_get_style_by_paths (gtk_widget_get_settings (widget),
2070  *                             path, class_path,
2071  *                             G_OBJECT_TYPE (widget));
2072  * ]|
2073  *
2074  * Return value: (transfer none): A style created by matching with the
2075  *     supplied paths, or %NULL if nothing matching was specified and the
2076  *     default style should be used. The returned value is owned by GTK+
2077  *     as part of an internal cache, so you must call g_object_ref() on
2078  *     the returned value if you want to keep a reference to it.
2079  **/
2080 GtkStyle *
gtk_rc_get_style_by_paths(GtkSettings * settings,const char * widget_path,const char * class_path,GType type)2081 gtk_rc_get_style_by_paths (GtkSettings *settings,
2082 			   const char  *widget_path,
2083 			   const char  *class_path,
2084 			   GType        type)
2085 {
2086   /* We duplicate the code from above to avoid slowing down the above
2087    * by generating paths when we don't need them. I don't know if
2088    * this is really worth it.
2089    */
2090   GSList *rc_styles = NULL;
2091   GtkRcContext *context;
2092 
2093   g_return_val_if_fail (GTK_IS_SETTINGS (settings), NULL);
2094 
2095   context = gtk_rc_context_get (settings);
2096 
2097   if (widget_path && context->rc_sets_widget)
2098     {
2099       gchar *path;
2100       gchar *path_reversed;
2101       guint path_length;
2102 
2103       path_length = strlen (widget_path);
2104       path = g_strdup (widget_path);
2105       path_reversed = g_strdup (widget_path);
2106       g_strreverse (path_reversed);
2107 
2108       rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget, path_length, path, path_reversed);
2109       g_free (path);
2110       g_free (path_reversed);
2111     }
2112 
2113   if (class_path && context->rc_sets_widget_class)
2114     {
2115       gchar *path;
2116       gchar *path_reversed;
2117       guint path_length;
2118 
2119       path = g_strdup (class_path);
2120       path_length = strlen (class_path);
2121       path_reversed = g_strdup (class_path);
2122       g_strreverse (path_reversed);
2123 
2124       rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_widget_class, path_length, path, path_reversed);
2125       g_free (path);
2126       g_free (path_reversed);
2127     }
2128 
2129   if (type != G_TYPE_NONE && context->rc_sets_class)
2130     {
2131       while (type)
2132 	{
2133 	  gchar *path;
2134           gchar *path_reversed;
2135 	  guint path_length;
2136 
2137 	  path = g_strdup (g_type_name (type));
2138 	  path_length = strlen (path);
2139 	  path_reversed = g_strdup (path);
2140 	  g_strreverse (path_reversed);
2141 
2142 	  rc_styles = gtk_rc_styles_match (rc_styles, context->rc_sets_class, path_length, path, path_reversed);
2143 	  g_free (path);
2144 	  g_free (path_reversed);
2145 
2146 	  type = g_type_parent (type);
2147 	}
2148     }
2149 
2150   rc_styles = sort_and_dereference_sets (rc_styles);
2151 
2152   if (rc_styles)
2153     return gtk_rc_init_style (context, rc_styles);
2154 
2155   return NULL;
2156 }
2157 
2158 static GSList *
gtk_rc_add_rc_sets(GSList * slist,GtkRcStyle * rc_style,const gchar * pattern,GtkPathType path_type)2159 gtk_rc_add_rc_sets (GSList      *slist,
2160 		    GtkRcStyle  *rc_style,
2161 		    const gchar *pattern,
2162 		    GtkPathType  path_type)
2163 {
2164   GtkRcStyle *new_style;
2165   GtkRcSet *rc_set;
2166   guint i;
2167 
2168   new_style = gtk_rc_style_new ();
2169   *new_style = *rc_style;
2170   new_style->name = g_strdup (rc_style->name);
2171   if (rc_style->font_desc)
2172     new_style->font_desc = pango_font_description_copy (rc_style->font_desc);
2173 
2174   for (i = 0; i < 5; i++)
2175     new_style->bg_pixmap_name[i] = g_strdup (rc_style->bg_pixmap_name[i]);
2176 
2177   rc_set = g_new (GtkRcSet, 1);
2178   rc_set->type = path_type;
2179 
2180   if (path_type == GTK_PATH_WIDGET_CLASS)
2181     {
2182       rc_set->pspec = NULL;
2183       rc_set->path = _gtk_rc_parse_widget_class_path (pattern);
2184     }
2185   else
2186     {
2187       rc_set->pspec = g_pattern_spec_new (pattern);
2188       rc_set->path = NULL;
2189     }
2190 
2191   rc_set->rc_style = rc_style;
2192 
2193   return g_slist_prepend (slist, rc_set);
2194 }
2195 
2196 void
gtk_rc_add_widget_name_style(GtkRcStyle * rc_style,const gchar * pattern)2197 gtk_rc_add_widget_name_style (GtkRcStyle  *rc_style,
2198 			      const gchar *pattern)
2199 {
2200   GtkRcContext *context;
2201 
2202   g_return_if_fail (rc_style != NULL);
2203   g_return_if_fail (pattern != NULL);
2204 
2205   context = gtk_rc_context_get (gtk_settings_get_default ());
2206 
2207   context->rc_sets_widget = gtk_rc_add_rc_sets (context->rc_sets_widget, rc_style, pattern, GTK_PATH_WIDGET);
2208 }
2209 
2210 void
gtk_rc_add_widget_class_style(GtkRcStyle * rc_style,const gchar * pattern)2211 gtk_rc_add_widget_class_style (GtkRcStyle  *rc_style,
2212 			       const gchar *pattern)
2213 {
2214   GtkRcContext *context;
2215 
2216   g_return_if_fail (rc_style != NULL);
2217   g_return_if_fail (pattern != NULL);
2218 
2219   context = gtk_rc_context_get (gtk_settings_get_default ());
2220 
2221   context->rc_sets_widget_class = gtk_rc_add_rc_sets (context->rc_sets_widget_class, rc_style, pattern, GTK_PATH_WIDGET_CLASS);
2222 }
2223 
2224 void
gtk_rc_add_class_style(GtkRcStyle * rc_style,const gchar * pattern)2225 gtk_rc_add_class_style (GtkRcStyle  *rc_style,
2226 			const gchar *pattern)
2227 {
2228   GtkRcContext *context;
2229 
2230   g_return_if_fail (rc_style != NULL);
2231   g_return_if_fail (pattern != NULL);
2232 
2233   context = gtk_rc_context_get (gtk_settings_get_default ());
2234 
2235   context->rc_sets_class = gtk_rc_add_rc_sets (context->rc_sets_class, rc_style, pattern, GTK_PATH_CLASS);
2236 }
2237 
2238 GScanner*
gtk_rc_scanner_new(void)2239 gtk_rc_scanner_new (void)
2240 {
2241   return g_scanner_new (&gtk_rc_scanner_config);
2242 }
2243 
2244 static void
gtk_rc_parse_any(GtkRcContext * context,const gchar * input_name,gint input_fd,const gchar * input_string)2245 gtk_rc_parse_any (GtkRcContext *context,
2246 		  const gchar  *input_name,
2247 		  gint		input_fd,
2248 		  const gchar  *input_string)
2249 {
2250   GScanner *scanner;
2251   guint	   i;
2252   gboolean done;
2253 
2254   scanner = gtk_rc_scanner_new ();
2255 
2256   if (input_fd >= 0)
2257     {
2258       g_assert (input_string == NULL);
2259 
2260       g_scanner_input_file (scanner, input_fd);
2261     }
2262   else
2263     {
2264       g_assert (input_string != NULL);
2265 
2266       g_scanner_input_text (scanner, input_string, strlen (input_string));
2267     }
2268   scanner->input_name = input_name;
2269 
2270   for (i = 0; i < G_N_ELEMENTS (symbols); i++)
2271     g_scanner_scope_add_symbol (scanner, 0, symbol_names + symbols[i].name_offset, GINT_TO_POINTER (symbols[i].token));
2272   done = FALSE;
2273   while (!done)
2274     {
2275       if (g_scanner_peek_next_token (scanner) == G_TOKEN_EOF)
2276 	done = TRUE;
2277       else
2278 	{
2279 	  guint expected_token;
2280 
2281 	  expected_token = gtk_rc_parse_statement (context, scanner);
2282 
2283 	  if (expected_token != G_TOKEN_NONE)
2284 	    {
2285 	      const gchar *symbol_name = NULL;
2286 	      gchar *msg = NULL;
2287 
2288 	      if (scanner->scope_id == 0)
2289 		{
2290 		  /* if we are in scope 0, we know the symbol names
2291 		   * that are associated with certain token values.
2292 		   * so we look them up to make the error messages
2293 		   * more readable.
2294 		   */
2295 		  if (expected_token > GTK_RC_TOKEN_INVALID &&
2296 		      expected_token < GTK_RC_TOKEN_LAST)
2297 		    {
2298                       const gchar *sym = NULL;
2299 
2300 		      for (i = 0; i < G_N_ELEMENTS (symbols); i++)
2301 			if (symbols[i].token == expected_token)
2302 			  sym = symbol_names + symbols[i].name_offset;
2303 
2304 		      if (sym)
2305 			msg = g_strconcat ("e.g. `", sym, "'", NULL);
2306 		    }
2307 
2308 		  if (scanner->token > (guint) GTK_RC_TOKEN_INVALID &&
2309 		      scanner->token < (guint) GTK_RC_TOKEN_LAST)
2310 		    {
2311 		      symbol_name = "???";
2312 		      for (i = 0; i < G_N_ELEMENTS (symbols); i++)
2313 			if (symbols[i].token == scanner->token)
2314 			  symbol_name = symbol_names + symbols[i].name_offset;
2315 		    }
2316 		}
2317 
2318 	      g_scanner_unexp_token (scanner,
2319 				     expected_token,
2320 				     NULL,
2321 				     "keyword",
2322 				     symbol_name,
2323 				     msg,
2324 				     TRUE);
2325 	      g_free (msg);
2326 	      done = TRUE;
2327 	    }
2328 	}
2329     }
2330 
2331   g_scanner_destroy (scanner);
2332 }
2333 
2334 static guint
gtk_rc_styles_hash(const GSList * rc_styles)2335 gtk_rc_styles_hash (const GSList *rc_styles)
2336 {
2337   guint result;
2338 
2339   result = 0;
2340   while (rc_styles)
2341     {
2342       result += (result << 9) + GPOINTER_TO_UINT (rc_styles->data);
2343       rc_styles = rc_styles->next;
2344     }
2345 
2346   return result;
2347 }
2348 
2349 static gboolean
gtk_rc_styles_equal(const GSList * a,const GSList * b)2350 gtk_rc_styles_equal (const GSList *a,
2351 		     const GSList *b)
2352 {
2353   while (a && b)
2354     {
2355       if (a->data != b->data)
2356 	return FALSE;
2357       a = a->next;
2358       b = b->next;
2359     }
2360 
2361   return (a == b);
2362 }
2363 
2364 static guint
gtk_rc_style_hash(const gchar * name)2365 gtk_rc_style_hash (const gchar *name)
2366 {
2367   guint result;
2368 
2369   result = 0;
2370   while (*name)
2371     result += (result << 3) + *name++;
2372 
2373   return result;
2374 }
2375 
2376 static gboolean
gtk_rc_style_equal(const gchar * a,const gchar * b)2377 gtk_rc_style_equal (const gchar *a,
2378 		    const gchar *b)
2379 {
2380   return (strcmp (a, b) == 0);
2381 }
2382 
2383 static GtkRcStyle*
gtk_rc_style_find(GtkRcContext * context,const gchar * name)2384 gtk_rc_style_find (GtkRcContext *context,
2385 		   const gchar  *name)
2386 {
2387   if (context->rc_style_ht)
2388     return g_hash_table_lookup (context->rc_style_ht, (gpointer) name);
2389   else
2390     return NULL;
2391 }
2392 
2393 static GtkStyle *
gtk_rc_style_to_style(GtkRcContext * context,GtkRcStyle * rc_style)2394 gtk_rc_style_to_style (GtkRcContext *context,
2395 		       GtkRcStyle   *rc_style)
2396 {
2397   GtkStyle *style;
2398 
2399   style = GTK_RC_STYLE_GET_CLASS (rc_style)->create_style (rc_style);
2400   _gtk_style_init_for_settings (style, context->settings);
2401 
2402   style->rc_style = g_object_ref (rc_style);
2403 
2404   GTK_STYLE_GET_CLASS (style)->init_from_rc (style, rc_style);
2405 
2406   return style;
2407 }
2408 
2409 /* Reuses or frees rc_styles */
2410 static GtkStyle *
gtk_rc_init_style(GtkRcContext * context,GSList * rc_styles)2411 gtk_rc_init_style (GtkRcContext *context,
2412 		   GSList       *rc_styles)
2413 {
2414   GtkStyle *style = NULL;
2415   gint i;
2416 
2417   g_return_val_if_fail (rc_styles != NULL, NULL);
2418 
2419   if (!realized_style_ht)
2420     realized_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_styles_hash,
2421  (GEqualFunc) gtk_rc_styles_equal);
2422 
2423   style = g_hash_table_lookup (realized_style_ht, rc_styles);
2424 
2425   if (!style)
2426     {
2427       GtkRcStyle *base_style = NULL;
2428       GtkRcStyle *proto_style;
2429       GtkRcStyleClass *proto_style_class;
2430       GSList *tmp_styles;
2431       GType rc_style_type = GTK_TYPE_RC_STYLE;
2432 
2433       /* Find the first style where the RC file specified engine "" {}
2434        * or the first derived style and use that to create the
2435        * merged style. If we only have raw GtkRcStyles, use the first
2436        * style to create the merged style.
2437        */
2438       base_style = rc_styles->data;
2439       tmp_styles = rc_styles;
2440       while (tmp_styles)
2441 	{
2442 	  GtkRcStyle *rc_style = tmp_styles->data;
2443 
2444 	  if (rc_style->engine_specified ||
2445 	      G_OBJECT_TYPE (rc_style) != rc_style_type)
2446 	    {
2447 	      base_style = rc_style;
2448 	      break;
2449 	    }
2450 
2451 	  tmp_styles = tmp_styles->next;
2452 	}
2453 
2454       proto_style_class = GTK_RC_STYLE_GET_CLASS (base_style);
2455       proto_style = proto_style_class->create_rc_style (base_style);
2456 
2457       tmp_styles = rc_styles;
2458       while (tmp_styles)
2459 	{
2460 	  GtkRcStyle *rc_style = tmp_styles->data;
2461 
2462 	  proto_style_class->merge (proto_style, rc_style);
2463 
2464 	  /* Point from each rc_style to the list of styles */
2465 	  if (!g_slist_find (rc_style->rc_style_lists, rc_styles))
2466 	    rc_style->rc_style_lists = g_slist_prepend (rc_style->rc_style_lists, rc_styles);
2467 
2468           gtk_rc_style_append_icon_factories (proto_style, rc_style);
2469           gtk_rc_style_append_color_hashes (proto_style, rc_style);
2470 
2471 	  tmp_styles = tmp_styles->next;
2472 	}
2473 
2474       for (i = 0; i < 5; i++)
2475 	if (proto_style->bg_pixmap_name[i] &&
2476 	    (strcmp (proto_style->bg_pixmap_name[i], "<none>") == 0))
2477 	  {
2478 	    g_free (proto_style->bg_pixmap_name[i]);
2479 	    proto_style->bg_pixmap_name[i] = NULL;
2480 	  }
2481 
2482       style = gtk_rc_style_to_style (context, proto_style);
2483       g_object_unref (proto_style);
2484 
2485       g_hash_table_insert (realized_style_ht, rc_styles, style);
2486     }
2487   else
2488     g_slist_free (rc_styles);
2489 
2490   return style;
2491 }
2492 
2493 /*********************
2494  * Parsing functions *
2495  *********************/
2496 
2497 static gboolean
lookup_color(GtkRcStyle * style,const char * color_name,GdkColor * color)2498 lookup_color (GtkRcStyle *style,
2499               const char *color_name,
2500               GdkColor   *color)
2501 {
2502   GtkRcStylePrivate *priv = GTK_RC_STYLE_GET_PRIVATE (style);
2503   GSList *iter;
2504 
2505   for (iter = priv->color_hashes; iter != NULL; iter = iter->next)
2506     {
2507       GHashTable *hash  = iter->data;
2508       GdkColor   *match = g_hash_table_lookup (hash, color_name);
2509 
2510       if (match)
2511         {
2512           color->red = match->red;
2513           color->green = match->green;
2514           color->blue = match->blue;
2515           return TRUE;
2516         }
2517     }
2518 
2519   return FALSE;
2520 }
2521 
2522 static guint
rc_parse_token_or_compound(GScanner * scanner,GtkRcStyle * style,GString * gstring,GTokenType delimiter)2523 rc_parse_token_or_compound (GScanner   *scanner,
2524                             GtkRcStyle *style,
2525 			    GString    *gstring,
2526 			    GTokenType  delimiter)
2527 {
2528   guint token = g_scanner_get_next_token (scanner);
2529 
2530   /* we either scan a single token (skipping comments)
2531    * or a compund statement.
2532    * compunds are enclosed in (), [] or {} braces, we read
2533    * them in via deep recursion.
2534    */
2535 
2536   switch (token)
2537     {
2538       gchar *string;
2539     case G_TOKEN_INT:
2540       g_string_append_printf (gstring, " 0x%lx", scanner->value.v_int);
2541       break;
2542     case G_TOKEN_FLOAT:
2543       {
2544 	gchar    fbuf[G_ASCII_DTOSTR_BUF_SIZE];
2545 	g_ascii_formatd (fbuf,
2546 			 sizeof (fbuf),
2547 			 "%f",
2548 			 scanner->value.v_float);
2549 	g_string_append_printf (gstring, " %s", (char*)fbuf);
2550       }
2551       break;
2552     case G_TOKEN_STRING:
2553       string = g_strescape (scanner->value.v_string, NULL);
2554       g_string_append (gstring, " \"");
2555       g_string_append (gstring, string);
2556       g_string_append_c (gstring, '"');
2557       g_free (string);
2558       break;
2559     case G_TOKEN_IDENTIFIER:
2560       g_string_append_c (gstring, ' ');
2561       g_string_append (gstring, scanner->value.v_identifier);
2562       break;
2563     case G_TOKEN_COMMENT_SINGLE:
2564     case G_TOKEN_COMMENT_MULTI:
2565       return rc_parse_token_or_compound (scanner, style, gstring, delimiter);
2566     case G_TOKEN_LEFT_PAREN:
2567       g_string_append_c (gstring, ' ');
2568       g_string_append_c (gstring, token);
2569       token = rc_parse_token_or_compound (scanner, style, gstring, G_TOKEN_RIGHT_PAREN);
2570       if (token != G_TOKEN_NONE)
2571 	return token;
2572       break;
2573     case G_TOKEN_LEFT_CURLY:
2574       g_string_append_c (gstring, ' ');
2575       g_string_append_c (gstring, token);
2576       token = rc_parse_token_or_compound (scanner, style, gstring, G_TOKEN_RIGHT_CURLY);
2577       if (token != G_TOKEN_NONE)
2578 	return token;
2579       break;
2580     case G_TOKEN_LEFT_BRACE:
2581       g_string_append_c (gstring, ' ');
2582       g_string_append_c (gstring, token);
2583       token = rc_parse_token_or_compound (scanner, style, gstring, G_TOKEN_RIGHT_BRACE);
2584       if (token != G_TOKEN_NONE)
2585 	return token;
2586       break;
2587     case '@':
2588       if (g_scanner_peek_next_token (scanner) == G_TOKEN_IDENTIFIER)
2589         {
2590           GdkColor color;
2591           gchar    rbuf[G_ASCII_DTOSTR_BUF_SIZE];
2592           gchar    gbuf[G_ASCII_DTOSTR_BUF_SIZE];
2593           gchar    bbuf[G_ASCII_DTOSTR_BUF_SIZE];
2594 
2595           g_scanner_get_next_token (scanner);
2596 
2597           if (!style || !lookup_color (style, scanner->value.v_identifier,
2598                                        &color))
2599             {
2600               g_scanner_warn (scanner, "Invalid symbolic color '%s'",
2601                               scanner->value.v_identifier);
2602               return G_TOKEN_IDENTIFIER;
2603             }
2604 
2605 
2606           g_string_append_printf (gstring, " { %s, %s, %s }",
2607                                   g_ascii_formatd (rbuf, sizeof (rbuf),
2608                                                    "%0.4f",
2609                                                    color.red / 65535.0),
2610                                   g_ascii_formatd (gbuf, sizeof (gbuf),
2611                                                    "%0.4f",
2612                                                    color.green / 65535.0),
2613                                   g_ascii_formatd (bbuf, sizeof (bbuf),
2614                                                    "%0.4f",
2615                                                    color.blue / 65535.0));
2616           break;
2617         }
2618       else
2619         return G_TOKEN_IDENTIFIER;
2620     default:
2621       if (token >= 256 || token < 1)
2622 	return delimiter ? delimiter : G_TOKEN_STRING;
2623       g_string_append_c (gstring, ' ');
2624       g_string_append_c (gstring, token);
2625       if (token == delimiter)
2626 	return G_TOKEN_NONE;
2627       break;
2628     }
2629   if (!delimiter)
2630     return G_TOKEN_NONE;
2631   else
2632     return rc_parse_token_or_compound (scanner, style, gstring, delimiter);
2633 }
2634 
2635 static guint
gtk_rc_parse_assignment(GScanner * scanner,GtkRcStyle * style,GtkRcProperty * prop)2636 gtk_rc_parse_assignment (GScanner      *scanner,
2637                          GtkRcStyle    *style,
2638 			 GtkRcProperty *prop)
2639 {
2640 #define MY_SCAN_IDENTIFIER      TRUE
2641 #define MY_SCAN_SYMBOLS         FALSE
2642 #define MY_IDENTIFIER_2_STRING  FALSE
2643 #define MY_CHAR_2_TOKEN         TRUE
2644 #define MY_SCAN_IDENTIFIER_NULL FALSE
2645 #define MY_NUMBERS_2_INT        TRUE
2646 
2647   gboolean scan_identifier      = scanner->config->scan_identifier;
2648   gboolean scan_symbols         = scanner->config->scan_symbols;
2649   gboolean identifier_2_string  = scanner->config->identifier_2_string;
2650   gboolean char_2_token         = scanner->config->char_2_token;
2651   gboolean scan_identifier_NULL = scanner->config->scan_identifier_NULL;
2652   gboolean numbers_2_int        = scanner->config->numbers_2_int;
2653   gboolean negate = FALSE;
2654   gboolean is_color = FALSE;
2655   guint    token;
2656 
2657   /* check that this is an assignment */
2658   if (g_scanner_get_next_token (scanner) != '=')
2659     return '=';
2660 
2661   /* adjust scanner mode */
2662   scanner->config->scan_identifier      = MY_SCAN_IDENTIFIER;
2663   scanner->config->scan_symbols         = MY_SCAN_SYMBOLS;
2664   scanner->config->identifier_2_string  = MY_IDENTIFIER_2_STRING;
2665   scanner->config->char_2_token         = MY_CHAR_2_TOKEN;
2666   scanner->config->scan_identifier_NULL = MY_SCAN_IDENTIFIER_NULL;
2667   scanner->config->numbers_2_int        = MY_NUMBERS_2_INT;
2668 
2669   /* record location */
2670   if (g_getenv ("GTK_DEBUG"))
2671     prop->origin = g_strdup_printf ("%s:%u", scanner->input_name, scanner->line);
2672   else
2673     prop->origin = NULL;
2674 
2675   /* parse optional symbolic color prefix */
2676   if (g_scanner_peek_next_token (scanner) == '@')
2677     {
2678       g_scanner_get_next_token (scanner); /* eat color prefix */
2679       is_color = TRUE;
2680     }
2681 
2682   /* parse optional sign */
2683   if (!is_color && g_scanner_peek_next_token (scanner) == '-')
2684     {
2685       g_scanner_get_next_token (scanner); /* eat sign */
2686       negate = TRUE;
2687     }
2688 
2689   /* parse one of LONG, DOUBLE and STRING or, if that fails, create an
2690    * unparsed compund
2691    */
2692   token = g_scanner_peek_next_token (scanner);
2693 
2694   if (is_color && token != G_TOKEN_IDENTIFIER)
2695     {
2696       token = G_TOKEN_IDENTIFIER;
2697       goto out;
2698     }
2699 
2700   switch (token)
2701     {
2702     case G_TOKEN_INT:
2703       g_scanner_get_next_token (scanner);
2704       g_value_init (&prop->value, G_TYPE_LONG);
2705       g_value_set_long (&prop->value, negate ? -scanner->value.v_int : scanner->value.v_int);
2706       token = G_TOKEN_NONE;
2707       break;
2708     case G_TOKEN_FLOAT:
2709       g_scanner_get_next_token (scanner);
2710       g_value_init (&prop->value, G_TYPE_DOUBLE);
2711       g_value_set_double (&prop->value, negate ? -scanner->value.v_float : scanner->value.v_float);
2712       token = G_TOKEN_NONE;
2713       break;
2714     case G_TOKEN_STRING:
2715       g_scanner_get_next_token (scanner);
2716       if (negate)
2717 	token = G_TOKEN_INT;
2718       else
2719 	{
2720 	  g_value_init (&prop->value, G_TYPE_STRING);
2721 	  g_value_set_string (&prop->value, scanner->value.v_string);
2722 	  token = G_TOKEN_NONE;
2723 	}
2724       break;
2725     case G_TOKEN_IDENTIFIER:
2726       if (is_color)
2727         {
2728           GdkColor  color;
2729           gchar     rbuf[G_ASCII_DTOSTR_BUF_SIZE];
2730           gchar     gbuf[G_ASCII_DTOSTR_BUF_SIZE];
2731           gchar     bbuf[G_ASCII_DTOSTR_BUF_SIZE];
2732           GString  *gstring;
2733 
2734           g_scanner_get_next_token (scanner);
2735 
2736           if (!style || !lookup_color (style, scanner->value.v_identifier,
2737                                        &color))
2738             {
2739               g_scanner_warn (scanner, "Invalid symbolic color '%s'",
2740                               scanner->value.v_identifier);
2741               token = G_TOKEN_IDENTIFIER;
2742               break;
2743             }
2744 
2745           gstring = g_string_new (NULL);
2746 
2747           g_string_append_printf (gstring, " { %s, %s, %s }",
2748                                   g_ascii_formatd (rbuf, sizeof (rbuf),
2749                                                    "%0.4f",
2750                                                    color.red / 65535.0),
2751                                   g_ascii_formatd (gbuf, sizeof (gbuf),
2752                                                    "%0.4f",
2753                                                    color.green / 65535.0),
2754                                   g_ascii_formatd (bbuf, sizeof (bbuf),
2755                                                    "%0.4f",
2756                                                    color.blue / 65535.0));
2757 
2758           g_value_init (&prop->value, G_TYPE_GSTRING);
2759           g_value_take_boxed (&prop->value, gstring);
2760           token = G_TOKEN_NONE;
2761           break;
2762         }
2763       /* fall through */
2764     case G_TOKEN_LEFT_PAREN:
2765     case G_TOKEN_LEFT_CURLY:
2766     case G_TOKEN_LEFT_BRACE:
2767       if (!negate)
2768 	{
2769           GString  *gstring  = g_string_new (NULL);
2770           gboolean  parse_on = TRUE;
2771 
2772           /*  allow identifier(foobar) to support color expressions  */
2773           if (token == G_TOKEN_IDENTIFIER)
2774             {
2775               g_scanner_get_next_token (scanner);
2776 
2777               g_string_append_c (gstring, ' ');
2778               g_string_append (gstring, scanner->value.v_identifier);
2779 
2780               /* temporarily reset scanner mode to default, so we
2781                * don't peek the next token in a mode that only makes
2782                * sense in this function; because if anything but
2783                * G_TOKEN_LEFT_PAREN follows, the next token will be
2784                * parsed by our caller.
2785                *
2786                * FIXME: right fix would be to call g_scanner_unget()
2787                *        but that doesn't exist
2788                */
2789               scanner->config->scan_identifier      = scan_identifier;
2790               scanner->config->scan_symbols         = scan_symbols;
2791               scanner->config->identifier_2_string  = identifier_2_string;
2792               scanner->config->char_2_token         = char_2_token;
2793               scanner->config->scan_identifier_NULL = scan_identifier_NULL;
2794               scanner->config->numbers_2_int        = numbers_2_int;
2795 
2796               token = g_scanner_peek_next_token (scanner);
2797 
2798               /* restore adjusted scanner mode */
2799               scanner->config->scan_identifier      = MY_SCAN_IDENTIFIER;
2800               scanner->config->scan_symbols         = MY_SCAN_SYMBOLS;
2801               scanner->config->identifier_2_string  = MY_IDENTIFIER_2_STRING;
2802               scanner->config->char_2_token         = MY_CHAR_2_TOKEN;
2803               scanner->config->scan_identifier_NULL = MY_SCAN_IDENTIFIER_NULL;
2804               scanner->config->numbers_2_int        = MY_NUMBERS_2_INT;
2805 
2806               if (token != G_TOKEN_LEFT_PAREN)
2807                 {
2808                   token = G_TOKEN_NONE;
2809                   parse_on = FALSE;
2810                 }
2811             }
2812 
2813           if (parse_on)
2814             token = rc_parse_token_or_compound (scanner, style, gstring, 0);
2815 
2816 	  if (token == G_TOKEN_NONE)
2817 	    {
2818 	      g_string_append_c (gstring, ' ');
2819 	      g_value_init (&prop->value, G_TYPE_GSTRING);
2820 	      g_value_take_boxed (&prop->value, gstring);
2821 	    }
2822 	  else
2823 	    g_string_free (gstring, TRUE);
2824 	  break;
2825 	}
2826       /* fall through */
2827     default:
2828       g_scanner_get_next_token (scanner);
2829       token = G_TOKEN_INT;
2830       break;
2831     }
2832 
2833  out:
2834 
2835   /* restore scanner mode */
2836   scanner->config->scan_identifier      = scan_identifier;
2837   scanner->config->scan_symbols         = scan_symbols;
2838   scanner->config->identifier_2_string  = identifier_2_string;
2839   scanner->config->char_2_token         = char_2_token;
2840   scanner->config->scan_identifier_NULL = scan_identifier_NULL;
2841   scanner->config->numbers_2_int        = numbers_2_int;
2842 
2843   return token;
2844 }
2845 
2846 static gboolean
is_c_identifier(const gchar * string)2847 is_c_identifier (const gchar *string)
2848 {
2849   const gchar *p;
2850   gboolean is_varname;
2851 
2852   is_varname = strchr ("_" G_CSET_a_2_z G_CSET_A_2_Z, string[0]) != NULL;
2853   for (p = string + 1; *p && is_varname; p++)
2854     is_varname &= strchr (G_CSET_DIGITS "-_" G_CSET_a_2_z G_CSET_A_2_Z, *p) != NULL;
2855 
2856   return is_varname;
2857 }
2858 
2859 static void
parse_include_file(GtkRcContext * context,GScanner * scanner,const gchar * filename)2860 parse_include_file (GtkRcContext *context,
2861 		    GScanner     *scanner,
2862 		    const gchar  *filename)
2863 {
2864   char *to_parse = NULL;
2865 
2866   if (g_path_is_absolute (filename))
2867     {
2868       /* For abolute paths, we call gtk_rc_context_parse_file unconditionally. We
2869        * don't print an error in this case.
2870        */
2871       to_parse = g_strdup (filename);
2872     }
2873   else
2874     {
2875       /* if a relative path, we look relative to all the RC files in the
2876        * include stack. We require the file to be found in this case
2877        * so we can give meaningful error messages, and because on reparsing
2878        * non-absolute paths don't make sense.
2879        */
2880       GSList *tmp_list = current_files_stack;
2881       while (tmp_list)
2882 	{
2883 	  GtkRcFile *curfile = tmp_list->data;
2884 	  gchar *tmpname = g_build_filename (curfile->directory, filename, NULL);
2885 
2886 	  if (g_file_test (tmpname, G_FILE_TEST_EXISTS))
2887 	    {
2888 	      to_parse = tmpname;
2889 	      break;
2890 	    }
2891 
2892 	  g_free (tmpname);
2893 
2894 	  tmp_list = tmp_list->next;
2895 	}
2896     }
2897 
2898   if (to_parse)
2899     {
2900       gtk_rc_context_parse_file (context, to_parse, context->default_priority, FALSE);
2901       g_free (to_parse);
2902     }
2903   else
2904     {
2905       g_scanner_warn (scanner,
2906 		      _("Unable to find include file: \"%s\""),
2907 		      filename);
2908     }
2909 
2910 }
2911 
2912 static guint
gtk_rc_parse_statement(GtkRcContext * context,GScanner * scanner)2913 gtk_rc_parse_statement (GtkRcContext *context,
2914 			GScanner     *scanner)
2915 {
2916   guint token;
2917 
2918   token = g_scanner_peek_next_token (scanner);
2919   switch (token)
2920     {
2921     case GTK_RC_TOKEN_INCLUDE:
2922       token = g_scanner_get_next_token (scanner);
2923       if (token != GTK_RC_TOKEN_INCLUDE)
2924 	return GTK_RC_TOKEN_INCLUDE;
2925       token = g_scanner_get_next_token (scanner);
2926       if (token != G_TOKEN_STRING)
2927 	return G_TOKEN_STRING;
2928       parse_include_file (context, scanner, scanner->value.v_string);
2929       return G_TOKEN_NONE;
2930 
2931     case GTK_RC_TOKEN_STYLE:
2932       return gtk_rc_parse_style (context, scanner);
2933 
2934     case GTK_RC_TOKEN_BINDING:
2935       return _gtk_binding_parse_binding (scanner);
2936 
2937     case GTK_RC_TOKEN_PIXMAP_PATH:
2938       return gtk_rc_parse_pixmap_path (context, scanner);
2939 
2940     case GTK_RC_TOKEN_WIDGET:
2941       return gtk_rc_parse_path_pattern (context, scanner);
2942 
2943     case GTK_RC_TOKEN_WIDGET_CLASS:
2944       return gtk_rc_parse_path_pattern (context, scanner);
2945 
2946     case GTK_RC_TOKEN_CLASS:
2947       return gtk_rc_parse_path_pattern (context, scanner);
2948 
2949     case GTK_RC_TOKEN_MODULE_PATH:
2950       return gtk_rc_parse_module_path (scanner);
2951 
2952     case GTK_RC_TOKEN_IM_MODULE_FILE:
2953       return gtk_rc_parse_im_module_file (scanner);
2954 
2955     case G_TOKEN_IDENTIFIER:
2956       if (is_c_identifier (scanner->next_value.v_identifier))
2957 	{
2958 	  GtkRcProperty prop = { 0, 0, NULL, { 0, }, };
2959 	  gchar *name;
2960 
2961 	  g_scanner_get_next_token (scanner); /* eat identifier */
2962 	  name = g_strdup (scanner->value.v_identifier);
2963 
2964 	  token = gtk_rc_parse_assignment (scanner, NULL, &prop);
2965 	  if (token == G_TOKEN_NONE)
2966 	    {
2967 	      GtkSettingsValue svalue;
2968 
2969 	      svalue.origin = prop.origin;
2970 	      memcpy (&svalue.value, &prop.value, sizeof (prop.value));
2971 	      g_strcanon (name, G_CSET_DIGITS "-" G_CSET_a_2_z G_CSET_A_2_Z, '-');
2972 	      _gtk_settings_set_property_value_from_rc (context->settings,
2973 							name,
2974 							&svalue);
2975 	    }
2976 	  g_free (prop.origin);
2977 	  if (G_VALUE_TYPE (&prop.value))
2978 	    g_value_unset (&prop.value);
2979 	  g_free (name);
2980 
2981 	  return token;
2982 	}
2983       else
2984 	{
2985 	  g_scanner_get_next_token (scanner);
2986 	  return G_TOKEN_IDENTIFIER;
2987 	}
2988     default:
2989       g_scanner_get_next_token (scanner);
2990       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_STYLE;
2991     }
2992 }
2993 
2994 static void
fixup_rc_set(GSList * list,GtkRcStyle * orig,GtkRcStyle * new)2995 fixup_rc_set (GSList     *list,
2996 	      GtkRcStyle *orig,
2997 	      GtkRcStyle *new)
2998 {
2999   while (list)
3000     {
3001       GtkRcSet *set = list->data;
3002       if (set->rc_style == orig)
3003 	set->rc_style = new;
3004       list = list->next;
3005     }
3006 }
3007 
3008 static void
fixup_rc_sets(GtkRcContext * context,GtkRcStyle * orig,GtkRcStyle * new)3009 fixup_rc_sets (GtkRcContext *context,
3010 	       GtkRcStyle   *orig,
3011 	       GtkRcStyle   *new)
3012 {
3013   fixup_rc_set (context->rc_sets_widget, orig, new);
3014   fixup_rc_set (context->rc_sets_widget_class, orig, new);
3015   fixup_rc_set (context->rc_sets_class, orig, new);
3016 }
3017 
3018 static guint
gtk_rc_parse_style(GtkRcContext * context,GScanner * scanner)3019 gtk_rc_parse_style (GtkRcContext *context,
3020 		    GScanner     *scanner)
3021 {
3022   GtkRcStyle *rc_style;
3023   GtkRcStyle *orig_style;
3024   GtkRcStyle *parent_style = NULL;
3025   GtkRcStylePrivate *rc_priv = NULL;
3026   guint token;
3027   gint i;
3028   GtkIconFactory *our_factory = NULL;
3029   GHashTable *our_hash = NULL;
3030 
3031   token = g_scanner_get_next_token (scanner);
3032   if (token != GTK_RC_TOKEN_STYLE)
3033     return GTK_RC_TOKEN_STYLE;
3034 
3035   token = g_scanner_get_next_token (scanner);
3036   if (token != G_TOKEN_STRING)
3037     return G_TOKEN_STRING;
3038 
3039   rc_style = gtk_rc_style_find (context, scanner->value.v_string);
3040   if (rc_style)
3041     orig_style = g_object_ref (rc_style);
3042   else
3043     orig_style = NULL;
3044 
3045   if (!rc_style)
3046     {
3047       rc_style = gtk_rc_style_new ();
3048       rc_style->name = g_strdup (scanner->value.v_string);
3049 
3050       for (i = 0; i < 5; i++)
3051 	rc_style->bg_pixmap_name[i] = NULL;
3052 
3053       for (i = 0; i < 5; i++)
3054 	rc_style->color_flags[i] = 0;
3055     }
3056 
3057   rc_priv = GTK_RC_STYLE_GET_PRIVATE (rc_style);
3058 
3059   /* If there's a list, its first member is always the factory belonging
3060    * to this RcStyle
3061    */
3062   if (rc_style->icon_factories)
3063     our_factory = rc_style->icon_factories->data;
3064   if (rc_priv->color_hashes)
3065     our_hash = rc_priv->color_hashes->data;
3066 
3067   token = g_scanner_peek_next_token (scanner);
3068   if (token == G_TOKEN_EQUAL_SIGN)
3069     {
3070       token = g_scanner_get_next_token (scanner);
3071 
3072       token = g_scanner_get_next_token (scanner);
3073       if (token != G_TOKEN_STRING)
3074 	{
3075 	  token = G_TOKEN_STRING;
3076 	  goto err;
3077 	}
3078 
3079       parent_style = gtk_rc_style_find (context, scanner->value.v_string);
3080       if (parent_style)
3081 	{
3082 	  for (i = 0; i < 5; i++)
3083 	    {
3084 	      rc_style->color_flags[i] = parent_style->color_flags[i];
3085 	      rc_style->fg[i] = parent_style->fg[i];
3086 	      rc_style->bg[i] = parent_style->bg[i];
3087 	      rc_style->text[i] = parent_style->text[i];
3088 	      rc_style->base[i] = parent_style->base[i];
3089 	    }
3090 
3091 	  rc_style->xthickness = parent_style->xthickness;
3092 	  rc_style->ythickness = parent_style->ythickness;
3093 
3094 	  if (parent_style->font_desc)
3095 	    {
3096 	      if (rc_style->font_desc)
3097 		pango_font_description_free (rc_style->font_desc);
3098 	      rc_style->font_desc = pango_font_description_copy (parent_style->font_desc);
3099 	    }
3100 
3101 	  if (parent_style->rc_properties)
3102 	    {
3103 	      guint i;
3104 
3105 	      for (i = 0; i < parent_style->rc_properties->len; i++)
3106 		insert_rc_property (rc_style,
3107 				    &g_array_index (parent_style->rc_properties, GtkRcProperty, i),
3108 				    TRUE);
3109 	    }
3110 
3111 	  for (i = 0; i < 5; i++)
3112 	    {
3113 	      g_free (rc_style->bg_pixmap_name[i]);
3114 	      rc_style->bg_pixmap_name[i] = g_strdup (parent_style->bg_pixmap_name[i]);
3115 	    }
3116 	}
3117     }
3118 
3119   /*  get icon_factories and color_hashes from the parent style;
3120    *  if the parent_style doesn't have color_hashes, initializes
3121    *  the color_hashes with the settings' color scheme (if it exists)
3122    */
3123   gtk_rc_style_copy_icons_and_colors (rc_style, parent_style, context);
3124 
3125   if (rc_style->icon_factories)
3126     our_factory = rc_style->icon_factories->data;
3127   if (rc_priv->color_hashes)
3128     our_hash = rc_priv->color_hashes->data;
3129 
3130   token = g_scanner_get_next_token (scanner);
3131   if (token != G_TOKEN_LEFT_CURLY)
3132     {
3133       token = G_TOKEN_LEFT_CURLY;
3134       goto err;
3135     }
3136 
3137   token = g_scanner_peek_next_token (scanner);
3138   while (token != G_TOKEN_RIGHT_CURLY)
3139     {
3140       switch (token)
3141 	{
3142 	case GTK_RC_TOKEN_BG:
3143 	  token = gtk_rc_parse_bg (scanner, rc_style);
3144 	  break;
3145 	case GTK_RC_TOKEN_FG:
3146 	  token = gtk_rc_parse_fg (scanner, rc_style);
3147 	  break;
3148 	case GTK_RC_TOKEN_TEXT:
3149 	  token = gtk_rc_parse_text (scanner, rc_style);
3150 	  break;
3151 	case GTK_RC_TOKEN_BASE:
3152 	  token = gtk_rc_parse_base (scanner, rc_style);
3153 	  break;
3154 	case GTK_RC_TOKEN_XTHICKNESS:
3155 	  token = gtk_rc_parse_xthickness (scanner, rc_style);
3156 	  break;
3157 	case GTK_RC_TOKEN_YTHICKNESS:
3158 	  token = gtk_rc_parse_ythickness (scanner, rc_style);
3159 	  break;
3160 	case GTK_RC_TOKEN_BG_PIXMAP:
3161 	  token = gtk_rc_parse_bg_pixmap (context, scanner, rc_style);
3162 	  break;
3163 	case GTK_RC_TOKEN_FONT:
3164 	  token = gtk_rc_parse_font (scanner, rc_style);
3165 	  break;
3166 	case GTK_RC_TOKEN_FONTSET:
3167 	  token = gtk_rc_parse_fontset (scanner, rc_style);
3168 	  break;
3169 	case GTK_RC_TOKEN_FONT_NAME:
3170 	  token = gtk_rc_parse_font_name (scanner, rc_style);
3171 	  break;
3172 	case GTK_RC_TOKEN_ENGINE:
3173 	  token = gtk_rc_parse_engine (context, scanner, &rc_style);
3174 	  break;
3175         case GTK_RC_TOKEN_STOCK:
3176           if (our_factory == NULL)
3177             gtk_rc_style_prepend_empty_icon_factory (rc_style);
3178           our_factory = rc_style->icon_factories->data;
3179           token = gtk_rc_parse_stock (context, scanner, rc_style, our_factory);
3180           break;
3181         case GTK_RC_TOKEN_COLOR:
3182           if (our_hash == NULL)
3183             {
3184               gtk_rc_style_prepend_empty_color_hash (rc_style);
3185               our_hash = rc_priv->color_hashes->data;
3186             }
3187           token = gtk_rc_parse_logical_color (scanner, rc_style, our_hash);
3188           break;
3189 	case G_TOKEN_IDENTIFIER:
3190 	  if (is_c_identifier (scanner->next_value.v_identifier))
3191 	    {
3192 	      GtkRcProperty prop = { 0, 0, NULL, { 0, }, };
3193 	      gchar *name;
3194 
3195 	      g_scanner_get_next_token (scanner); /* eat type name */
3196 	      prop.type_name = g_quark_from_string (scanner->value.v_identifier);
3197 	      if (g_scanner_get_next_token (scanner) != ':' ||
3198 		  g_scanner_get_next_token (scanner) != ':')
3199 		{
3200 		  token = ':';
3201 		  break;
3202 		}
3203 	      if (g_scanner_get_next_token (scanner) != G_TOKEN_IDENTIFIER ||
3204 		  !is_c_identifier (scanner->value.v_identifier))
3205 		{
3206 		  token = G_TOKEN_IDENTIFIER;
3207 		  break;
3208 		}
3209 
3210 	      /* it's important that we do the same canonification as GParamSpecPool here */
3211 	      name = g_strdup (scanner->value.v_identifier);
3212 	      g_strcanon (name, G_CSET_DIGITS "-" G_CSET_a_2_z G_CSET_A_2_Z, '-');
3213 	      prop.property_name = g_quark_from_string (name);
3214 	      g_free (name);
3215 
3216 	      token = gtk_rc_parse_assignment (scanner, rc_style, &prop);
3217 	      if (token == G_TOKEN_NONE)
3218 		{
3219 		  g_return_val_if_fail (G_VALUE_TYPE (&prop.value) != 0, G_TOKEN_ERROR);
3220 		  insert_rc_property (rc_style, &prop, TRUE);
3221 		}
3222 
3223 	      g_free (prop.origin);
3224 	      if (G_VALUE_TYPE (&prop.value))
3225 		g_value_unset (&prop.value);
3226 	    }
3227 	  else
3228 	    {
3229 	      g_scanner_get_next_token (scanner);
3230 	      token = G_TOKEN_IDENTIFIER;
3231 	    }
3232 	  break;
3233 	default:
3234 	  g_scanner_get_next_token (scanner);
3235 	  token = G_TOKEN_RIGHT_CURLY;
3236 	  break;
3237 	}
3238 
3239       if (token != G_TOKEN_NONE)
3240 	goto err;
3241 
3242       token = g_scanner_peek_next_token (scanner);
3243     } /* while (token != G_TOKEN_RIGHT_CURLY) */
3244 
3245   token = g_scanner_get_next_token (scanner);
3246   if (token != G_TOKEN_RIGHT_CURLY)
3247     {
3248       token = G_TOKEN_RIGHT_CURLY;
3249       goto err;
3250     }
3251 
3252   if (rc_style != orig_style)
3253     {
3254       if (!context->rc_style_ht)
3255 	context->rc_style_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash,
3256 						 (GEqualFunc) gtk_rc_style_equal);
3257 
3258       g_hash_table_replace (context->rc_style_ht, rc_style->name, rc_style);
3259 
3260       /* If we copied the data into a new rc style, fix up references to the old rc style
3261        * in bindings that we have.
3262        */
3263       if (orig_style)
3264 	fixup_rc_sets (context, orig_style, rc_style);
3265     }
3266 
3267   if (orig_style)
3268     g_object_unref (orig_style);
3269 
3270   return G_TOKEN_NONE;
3271 
3272  err:
3273   if (rc_style != orig_style)
3274     g_object_unref (rc_style);
3275 
3276   if (orig_style)
3277     g_object_unref (orig_style);
3278 
3279   return token;
3280 }
3281 
3282 const GtkRcProperty*
_gtk_rc_style_lookup_rc_property(GtkRcStyle * rc_style,GQuark type_name,GQuark property_name)3283 _gtk_rc_style_lookup_rc_property (GtkRcStyle *rc_style,
3284 				  GQuark      type_name,
3285 				  GQuark      property_name)
3286 {
3287   GtkRcProperty *node = NULL;
3288 
3289   g_return_val_if_fail (GTK_IS_RC_STYLE (rc_style), NULL);
3290 
3291   if (rc_style->rc_properties)
3292     {
3293       GtkRcProperty key;
3294 
3295       key.type_name = type_name;
3296       key.property_name = property_name;
3297 
3298       node = bsearch (&key,
3299 		      rc_style->rc_properties->data, rc_style->rc_properties->len,
3300 		      sizeof (GtkRcProperty), gtk_rc_properties_cmp);
3301     }
3302 
3303   return node;
3304 }
3305 
3306 static guint
gtk_rc_parse_bg(GScanner * scanner,GtkRcStyle * style)3307 gtk_rc_parse_bg (GScanner   *scanner,
3308 		 GtkRcStyle *style)
3309 {
3310   GtkStateType state;
3311   guint token;
3312 
3313   token = g_scanner_get_next_token (scanner);
3314   if (token != GTK_RC_TOKEN_BG)
3315     return GTK_RC_TOKEN_BG;
3316 
3317   token = gtk_rc_parse_state (scanner, &state);
3318   if (token != G_TOKEN_NONE)
3319     return token;
3320 
3321   token = g_scanner_get_next_token (scanner);
3322   if (token != G_TOKEN_EQUAL_SIGN)
3323     return G_TOKEN_EQUAL_SIGN;
3324 
3325   style->color_flags[state] |= GTK_RC_BG;
3326   return gtk_rc_parse_color_full (scanner, style, &style->bg[state]);
3327 }
3328 
3329 static guint
gtk_rc_parse_fg(GScanner * scanner,GtkRcStyle * style)3330 gtk_rc_parse_fg (GScanner   *scanner,
3331 		 GtkRcStyle *style)
3332 {
3333   GtkStateType state;
3334   guint token;
3335 
3336   token = g_scanner_get_next_token (scanner);
3337   if (token != GTK_RC_TOKEN_FG)
3338     return GTK_RC_TOKEN_FG;
3339 
3340   token = gtk_rc_parse_state (scanner, &state);
3341   if (token != G_TOKEN_NONE)
3342     return token;
3343 
3344   token = g_scanner_get_next_token (scanner);
3345   if (token != G_TOKEN_EQUAL_SIGN)
3346     return G_TOKEN_EQUAL_SIGN;
3347 
3348   style->color_flags[state] |= GTK_RC_FG;
3349   return gtk_rc_parse_color_full (scanner, style, &style->fg[state]);
3350 }
3351 
3352 static guint
gtk_rc_parse_text(GScanner * scanner,GtkRcStyle * style)3353 gtk_rc_parse_text (GScanner   *scanner,
3354 		   GtkRcStyle *style)
3355 {
3356   GtkStateType state;
3357   guint token;
3358 
3359   token = g_scanner_get_next_token (scanner);
3360   if (token != GTK_RC_TOKEN_TEXT)
3361     return GTK_RC_TOKEN_TEXT;
3362 
3363   token = gtk_rc_parse_state (scanner, &state);
3364   if (token != G_TOKEN_NONE)
3365     return token;
3366 
3367   token = g_scanner_get_next_token (scanner);
3368   if (token != G_TOKEN_EQUAL_SIGN)
3369     return G_TOKEN_EQUAL_SIGN;
3370 
3371   style->color_flags[state] |= GTK_RC_TEXT;
3372   return gtk_rc_parse_color_full (scanner, style, &style->text[state]);
3373 }
3374 
3375 static guint
gtk_rc_parse_base(GScanner * scanner,GtkRcStyle * style)3376 gtk_rc_parse_base (GScanner   *scanner,
3377 		   GtkRcStyle *style)
3378 {
3379   GtkStateType state;
3380   guint token;
3381 
3382   token = g_scanner_get_next_token (scanner);
3383   if (token != GTK_RC_TOKEN_BASE)
3384     return GTK_RC_TOKEN_BASE;
3385 
3386   token = gtk_rc_parse_state (scanner, &state);
3387   if (token != G_TOKEN_NONE)
3388     return token;
3389 
3390   token = g_scanner_get_next_token (scanner);
3391   if (token != G_TOKEN_EQUAL_SIGN)
3392     return G_TOKEN_EQUAL_SIGN;
3393 
3394   style->color_flags[state] |= GTK_RC_BASE;
3395   return gtk_rc_parse_color_full (scanner, style, &style->base[state]);
3396 }
3397 
3398 static guint
gtk_rc_parse_xthickness(GScanner * scanner,GtkRcStyle * style)3399 gtk_rc_parse_xthickness (GScanner   *scanner,
3400 			 GtkRcStyle *style)
3401 {
3402   if (g_scanner_get_next_token (scanner) != (guint) GTK_RC_TOKEN_XTHICKNESS)
3403     return GTK_RC_TOKEN_XTHICKNESS;
3404 
3405   if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
3406     return G_TOKEN_EQUAL_SIGN;
3407 
3408   if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
3409     return G_TOKEN_INT;
3410 
3411   style->xthickness = scanner->value.v_int;
3412 
3413   return G_TOKEN_NONE;
3414 }
3415 
3416 static guint
gtk_rc_parse_ythickness(GScanner * scanner,GtkRcStyle * style)3417 gtk_rc_parse_ythickness (GScanner   *scanner,
3418 			 GtkRcStyle *style)
3419 {
3420   if (g_scanner_get_next_token (scanner) != (guint) GTK_RC_TOKEN_YTHICKNESS)
3421     return GTK_RC_TOKEN_YTHICKNESS;
3422 
3423   if (g_scanner_get_next_token (scanner) != G_TOKEN_EQUAL_SIGN)
3424     return G_TOKEN_EQUAL_SIGN;
3425 
3426   if (g_scanner_get_next_token (scanner) != G_TOKEN_INT)
3427     return G_TOKEN_INT;
3428 
3429   style->ythickness = scanner->value.v_int;
3430 
3431   return G_TOKEN_NONE;
3432 }
3433 
3434 static guint
gtk_rc_parse_bg_pixmap(GtkRcContext * context,GScanner * scanner,GtkRcStyle * rc_style)3435 gtk_rc_parse_bg_pixmap (GtkRcContext *context,
3436 			GScanner     *scanner,
3437 			GtkRcStyle   *rc_style)
3438 {
3439   GtkStateType state;
3440   guint token;
3441   gchar *pixmap_file;
3442 
3443   token = g_scanner_get_next_token (scanner);
3444   if (token != GTK_RC_TOKEN_BG_PIXMAP)
3445     return GTK_RC_TOKEN_BG_PIXMAP;
3446 
3447   token = gtk_rc_parse_state (scanner, &state);
3448   if (token != G_TOKEN_NONE)
3449     return token;
3450 
3451   token = g_scanner_get_next_token (scanner);
3452   if (token != G_TOKEN_EQUAL_SIGN)
3453     return G_TOKEN_EQUAL_SIGN;
3454 
3455   token = g_scanner_get_next_token (scanner);
3456   if (token != G_TOKEN_STRING)
3457     return G_TOKEN_STRING;
3458 
3459   if ((strcmp (scanner->value.v_string, "<parent>") == 0) ||
3460       (strcmp (scanner->value.v_string, "<none>") == 0))
3461     pixmap_file = g_strdup (scanner->value.v_string);
3462   else
3463     pixmap_file = gtk_rc_find_pixmap_in_path (context->settings,
3464 					      scanner, scanner->value.v_string);
3465 
3466   if (pixmap_file)
3467     {
3468       g_free (rc_style->bg_pixmap_name[state]);
3469       rc_style->bg_pixmap_name[state] = pixmap_file;
3470     }
3471 
3472   return G_TOKEN_NONE;
3473 }
3474 
3475 static gchar*
gtk_rc_check_pixmap_dir(const gchar * dir,const gchar * pixmap_file)3476 gtk_rc_check_pixmap_dir (const gchar *dir,
3477 			 const gchar *pixmap_file)
3478 {
3479   gchar *buf;
3480 
3481   buf = g_build_filename (dir, pixmap_file, NULL);
3482 
3483   if (g_file_test (buf, G_FILE_TEST_EXISTS))
3484     return buf;
3485 
3486   g_free (buf);
3487 
3488    return NULL;
3489  }
3490 
3491 /**
3492  * gtk_rc_find_pixmap_in_path:
3493  * @settings: a #GtkSettings
3494  * @scanner: Scanner used to get line number information for the
3495  *   warning message, or %NULL
3496  * @pixmap_file: name of the pixmap file to locate.
3497  *
3498  * Looks up a file in pixmap path for the specified #GtkSettings.
3499  * If the file is not found, it outputs a warning message using
3500  * g_warning() and returns %NULL.
3501  *
3502  * Return value: the filename.
3503  **/
3504 gchar*
gtk_rc_find_pixmap_in_path(GtkSettings * settings,GScanner * scanner,const gchar * pixmap_file)3505 gtk_rc_find_pixmap_in_path (GtkSettings  *settings,
3506 			    GScanner     *scanner,
3507 			    const gchar  *pixmap_file)
3508 {
3509   gint i;
3510   gchar *filename;
3511   GSList *tmp_list;
3512 
3513   GtkRcContext *context = gtk_rc_context_get (settings);
3514 
3515   if (context->pixmap_path)
3516     for (i = 0; context->pixmap_path[i] != NULL; i++)
3517       {
3518 	filename = gtk_rc_check_pixmap_dir (context->pixmap_path[i], pixmap_file);
3519 	if (filename)
3520 	  return filename;
3521       }
3522 
3523   tmp_list = current_files_stack;
3524   while (tmp_list)
3525     {
3526       GtkRcFile *curfile = tmp_list->data;
3527       filename = gtk_rc_check_pixmap_dir (curfile->directory, pixmap_file);
3528       if (filename)
3529  	return filename;
3530 
3531       tmp_list = tmp_list->next;
3532     }
3533 
3534   if (scanner)
3535     g_scanner_warn (scanner,
3536                     _("Unable to locate image file in pixmap_path: \"%s\""),
3537                     pixmap_file);
3538   else
3539     g_warning (_("Unable to locate image file in pixmap_path: \"%s\""),
3540 	       pixmap_file);
3541 
3542   return NULL;
3543 }
3544 
3545 /**
3546  * gtk_rc_find_module_in_path:
3547  * @module_file: name of a theme engine
3548  *
3549  * Searches for a theme engine in the GTK+ search path. This function
3550  * is not useful for applications and should not be used.
3551  *
3552  * Return value: The filename, if found (must be freed with g_free()),
3553  *   otherwise %NULL.
3554  **/
3555 gchar*
gtk_rc_find_module_in_path(const gchar * module_file)3556 gtk_rc_find_module_in_path (const gchar *module_file)
3557 {
3558   return _gtk_find_module (module_file, "engines");
3559 }
3560 
3561 static guint
gtk_rc_parse_font(GScanner * scanner,GtkRcStyle * rc_style)3562 gtk_rc_parse_font (GScanner   *scanner,
3563 		   GtkRcStyle *rc_style)
3564 {
3565   guint token;
3566 
3567   token = g_scanner_get_next_token (scanner);
3568   if (token != GTK_RC_TOKEN_FONT)
3569     return GTK_RC_TOKEN_FONT;
3570 
3571   token = g_scanner_get_next_token (scanner);
3572   if (token != G_TOKEN_EQUAL_SIGN)
3573     return G_TOKEN_EQUAL_SIGN;
3574 
3575   token = g_scanner_get_next_token (scanner);
3576   if (token != G_TOKEN_STRING)
3577     return G_TOKEN_STRING;
3578 
3579   /* Ignore, do nothing */
3580 
3581   return G_TOKEN_NONE;
3582 }
3583 
3584 static guint
gtk_rc_parse_fontset(GScanner * scanner,GtkRcStyle * rc_style)3585 gtk_rc_parse_fontset (GScanner	 *scanner,
3586 		      GtkRcStyle *rc_style)
3587 {
3588   guint token;
3589 
3590   token = g_scanner_get_next_token (scanner);
3591   if (token != GTK_RC_TOKEN_FONTSET)
3592     return GTK_RC_TOKEN_FONTSET;
3593 
3594   token = g_scanner_get_next_token (scanner);
3595   if (token != G_TOKEN_EQUAL_SIGN)
3596     return G_TOKEN_EQUAL_SIGN;
3597 
3598   token = g_scanner_get_next_token (scanner);
3599   if (token != G_TOKEN_STRING)
3600     return G_TOKEN_STRING;
3601 
3602   /* Do nothing - silently ignore */
3603 
3604   return G_TOKEN_NONE;
3605 }
3606 
3607 static guint
gtk_rc_parse_font_name(GScanner * scanner,GtkRcStyle * rc_style)3608 gtk_rc_parse_font_name (GScanner   *scanner,
3609 			GtkRcStyle *rc_style)
3610 {
3611   guint token;
3612 
3613   token = g_scanner_get_next_token (scanner);
3614   if (token != GTK_RC_TOKEN_FONT_NAME)
3615     return GTK_RC_TOKEN_FONT;
3616 
3617   token = g_scanner_get_next_token (scanner);
3618   if (token != G_TOKEN_EQUAL_SIGN)
3619     return G_TOKEN_EQUAL_SIGN;
3620 
3621   token = g_scanner_get_next_token (scanner);
3622   if (token != G_TOKEN_STRING)
3623     return G_TOKEN_STRING;
3624 
3625   if (rc_style->font_desc)
3626     pango_font_description_free (rc_style->font_desc);
3627 
3628   rc_style->font_desc =
3629     pango_font_description_from_string (scanner->value.v_string);
3630 
3631   return G_TOKEN_NONE;
3632 }
3633 
3634 static guint
gtk_rc_parse_engine(GtkRcContext * context,GScanner * scanner,GtkRcStyle ** rc_style)3635 gtk_rc_parse_engine (GtkRcContext *context,
3636 		     GScanner	  *scanner,
3637 		     GtkRcStyle	 **rc_style)
3638 {
3639   guint token;
3640   GtkThemeEngine *engine;
3641   guint result = G_TOKEN_NONE;
3642   GtkRcStyle *new_style = NULL;
3643   gboolean parsed_curlies = FALSE;
3644   GtkRcStylePrivate *rc_priv, *new_priv;
3645 
3646   token = g_scanner_get_next_token (scanner);
3647   if (token != GTK_RC_TOKEN_ENGINE)
3648     return GTK_RC_TOKEN_ENGINE;
3649 
3650   token = g_scanner_get_next_token (scanner);
3651   if (token != G_TOKEN_STRING)
3652     return G_TOKEN_STRING;
3653 
3654   if (!scanner->value.v_string[0])
3655     {
3656       /* Support engine "" {} to mean override to the default engine
3657        */
3658       token = g_scanner_get_next_token (scanner);
3659       if (token != G_TOKEN_LEFT_CURLY)
3660 	return G_TOKEN_LEFT_CURLY;
3661 
3662       token = g_scanner_get_next_token (scanner);
3663       if (token != G_TOKEN_RIGHT_CURLY)
3664 	return G_TOKEN_RIGHT_CURLY;
3665 
3666       parsed_curlies = TRUE;
3667 
3668       rc_priv = GTK_RC_STYLE_GET_PRIVATE (*rc_style);
3669 
3670       if (G_OBJECT_TYPE (*rc_style) != GTK_TYPE_RC_STYLE)
3671 	{
3672 	  new_style = gtk_rc_style_new ();
3673 	  gtk_rc_style_real_merge (new_style, *rc_style);
3674 
3675           new_style->name = g_strdup ((*rc_style)->name);
3676 
3677           /* take over icon factories and color hashes
3678            * from the to-be-deleted style
3679            */
3680           new_style->icon_factories = (*rc_style)->icon_factories;
3681           (*rc_style)->icon_factories = NULL;
3682           new_priv = GTK_RC_STYLE_GET_PRIVATE (new_style);
3683           new_priv->color_hashes = rc_priv->color_hashes;
3684           rc_priv->color_hashes = NULL;
3685 	}
3686       else
3687 	(*rc_style)->engine_specified = TRUE;
3688     }
3689   else
3690     {
3691       engine = gtk_theme_engine_get (scanner->value.v_string);
3692 
3693       token = g_scanner_get_next_token (scanner);
3694       if (token != G_TOKEN_LEFT_CURLY)
3695 	return G_TOKEN_LEFT_CURLY;
3696 
3697       if (engine)
3698 	{
3699 	  GtkRcStyleClass *new_class;
3700 
3701 	  rc_priv = GTK_RC_STYLE_GET_PRIVATE (*rc_style);
3702 	  new_style = gtk_theme_engine_create_rc_style (engine);
3703 	  g_type_module_unuse (G_TYPE_MODULE (engine));
3704 
3705 	  new_class = GTK_RC_STYLE_GET_CLASS (new_style);
3706 
3707 	  new_class->merge (new_style, *rc_style);
3708 
3709           new_style->name = g_strdup ((*rc_style)->name);
3710 
3711           /* take over icon factories and color hashes
3712            * from the to-be-deleted style
3713            */
3714           new_style->icon_factories = (*rc_style)->icon_factories;
3715           (*rc_style)->icon_factories = NULL;
3716           new_priv = GTK_RC_STYLE_GET_PRIVATE (new_style);
3717           new_priv->color_hashes = rc_priv->color_hashes;
3718           rc_priv->color_hashes = NULL;
3719 
3720 	  if (new_class->parse)
3721 	    {
3722 	      parsed_curlies = TRUE;
3723 	      result = new_class->parse (new_style, context->settings, scanner);
3724 
3725 	      if (result != G_TOKEN_NONE)
3726 		{
3727                   /* copy icon factories and color hashes back
3728                    */
3729                   (*rc_style)->icon_factories = new_style->icon_factories;
3730                   new_style->icon_factories = NULL;
3731                   rc_priv->color_hashes = new_priv->color_hashes;
3732                   new_priv->color_hashes = NULL;
3733 
3734 		  g_object_unref (new_style);
3735 		  new_style = NULL;
3736 		}
3737 	    }
3738 	}
3739     }
3740 
3741   if (!parsed_curlies)
3742     {
3743       /* Skip over remainder, looking for nested {}'s
3744        */
3745       guint count = 1;
3746 
3747       result = G_TOKEN_RIGHT_CURLY;
3748       while ((token = g_scanner_get_next_token (scanner)) != G_TOKEN_EOF)
3749 	{
3750 	  if (token == G_TOKEN_LEFT_CURLY)
3751 	    count++;
3752 	  else if (token == G_TOKEN_RIGHT_CURLY)
3753 	    count--;
3754 
3755 	  if (count == 0)
3756 	    {
3757 	      result = G_TOKEN_NONE;
3758 	      break;
3759 	    }
3760 	}
3761     }
3762 
3763   if (new_style)
3764     {
3765       new_style->engine_specified = TRUE;
3766 
3767       g_object_unref (*rc_style);
3768       *rc_style = new_style;
3769     }
3770 
3771   return result;
3772 }
3773 
3774 guint
gtk_rc_parse_state(GScanner * scanner,GtkStateType * state)3775 gtk_rc_parse_state (GScanner	 *scanner,
3776 		    GtkStateType *state)
3777 {
3778   guint old_scope;
3779   guint token;
3780 
3781   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
3782   g_return_val_if_fail (state != NULL, G_TOKEN_ERROR);
3783 
3784   /* we don't know where we got called from, so we reset the scope here.
3785    * if we bail out due to errors, we *don't* reset the scope, so the
3786    * error messaging code can make sense of our tokens.
3787    */
3788   old_scope = g_scanner_set_scope (scanner, 0);
3789 
3790   token = g_scanner_get_next_token (scanner);
3791   if (token != G_TOKEN_LEFT_BRACE)
3792     return G_TOKEN_LEFT_BRACE;
3793 
3794   token = g_scanner_get_next_token (scanner);
3795   switch (token)
3796     {
3797     case GTK_RC_TOKEN_ACTIVE:
3798       *state = GTK_STATE_ACTIVE;
3799       break;
3800     case GTK_RC_TOKEN_INSENSITIVE:
3801       *state = GTK_STATE_INSENSITIVE;
3802       break;
3803     case GTK_RC_TOKEN_NORMAL:
3804       *state = GTK_STATE_NORMAL;
3805       break;
3806     case GTK_RC_TOKEN_PRELIGHT:
3807       *state = GTK_STATE_PRELIGHT;
3808       break;
3809     case GTK_RC_TOKEN_SELECTED:
3810       *state = GTK_STATE_SELECTED;
3811       break;
3812     default:
3813       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_NORMAL;
3814     }
3815 
3816   token = g_scanner_get_next_token (scanner);
3817   if (token != G_TOKEN_RIGHT_BRACE)
3818     return G_TOKEN_RIGHT_BRACE;
3819 
3820   g_scanner_set_scope (scanner, old_scope);
3821 
3822   return G_TOKEN_NONE;
3823 }
3824 
3825 guint
gtk_rc_parse_priority(GScanner * scanner,GtkPathPriorityType * priority)3826 gtk_rc_parse_priority (GScanner	           *scanner,
3827 		       GtkPathPriorityType *priority)
3828 {
3829   guint old_scope;
3830   guint token;
3831 
3832   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
3833   g_return_val_if_fail (priority != NULL, G_TOKEN_ERROR);
3834 
3835   /* we don't know where we got called from, so we reset the scope here.
3836    * if we bail out due to errors, we *don't* reset the scope, so the
3837    * error messaging code can make sense of our tokens.
3838    */
3839   old_scope = g_scanner_set_scope (scanner, 0);
3840 
3841   token = g_scanner_get_next_token (scanner);
3842   if (token != ':')
3843     return ':';
3844 
3845   token = g_scanner_get_next_token (scanner);
3846   switch (token)
3847     {
3848     case GTK_RC_TOKEN_LOWEST:
3849       *priority = GTK_PATH_PRIO_LOWEST;
3850       break;
3851     case GTK_RC_TOKEN_GTK:
3852       *priority = GTK_PATH_PRIO_GTK;
3853       break;
3854     case GTK_RC_TOKEN_APPLICATION:
3855       *priority = GTK_PATH_PRIO_APPLICATION;
3856       break;
3857     case GTK_RC_TOKEN_THEME:
3858       *priority = GTK_PATH_PRIO_THEME;
3859       break;
3860     case GTK_RC_TOKEN_RC:
3861       *priority = GTK_PATH_PRIO_RC;
3862       break;
3863     case GTK_RC_TOKEN_HIGHEST:
3864       *priority = GTK_PATH_PRIO_HIGHEST;
3865       break;
3866     default:
3867       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_APPLICATION;
3868     }
3869 
3870   g_scanner_set_scope (scanner, old_scope);
3871 
3872   return G_TOKEN_NONE;
3873 }
3874 
3875 /**
3876  * gtk_rc_parse_color:
3877  * @scanner: a #GScanner
3878  * @color: (out): a pointer to a #GdkColor structure in which to store
3879  *     the result
3880  *
3881  * Parses a color in the <link linkend="color=format">format</link> expected
3882  * in a RC file.
3883  *
3884  * Note that theme engines should use gtk_rc_parse_color_full() in
3885  * order to support symbolic colors.
3886  *
3887  * Returns: %G_TOKEN_NONE if parsing succeeded, otherwise the token
3888  *     that was expected but not found
3889  */
3890 guint
gtk_rc_parse_color(GScanner * scanner,GdkColor * color)3891 gtk_rc_parse_color (GScanner *scanner,
3892 		    GdkColor *color)
3893 {
3894   return gtk_rc_parse_color_full (scanner, NULL, color);
3895 }
3896 
3897 /**
3898  * gtk_rc_parse_color_full:
3899  * @scanner: a #GScanner
3900  * @style: (allow-none): a #GtkRcStyle, or %NULL
3901  * @color: (out): a pointer to a #GdkColor structure in which to store
3902  *     the result
3903  *
3904  * Parses a color in the <link linkend="color=format">format</link> expected
3905  * in a RC file. If @style is not %NULL, it will be consulted to resolve
3906  * references to symbolic colors.
3907  *
3908  * Returns: %G_TOKEN_NONE if parsing succeeded, otherwise the token
3909  *     that was expected but not found
3910  *
3911  * Since: 2.12
3912  */
3913 guint
gtk_rc_parse_color_full(GScanner * scanner,GtkRcStyle * style,GdkColor * color)3914 gtk_rc_parse_color_full (GScanner   *scanner,
3915                          GtkRcStyle *style,
3916                          GdkColor   *color)
3917 {
3918   guint token;
3919 
3920   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
3921 
3922   /* we don't need to set our own scope here, because
3923    * we don't need own symbols
3924    */
3925 
3926   token = g_scanner_get_next_token (scanner);
3927   switch (token)
3928     {
3929       gint token_int;
3930       GdkColor c1, c2;
3931       gboolean negate;
3932       gdouble l;
3933 
3934     case G_TOKEN_LEFT_CURLY:
3935       token = g_scanner_get_next_token (scanner);
3936       if (token == G_TOKEN_INT)
3937 	token_int = scanner->value.v_int;
3938       else if (token == G_TOKEN_FLOAT)
3939 	token_int = scanner->value.v_float * 65535.0;
3940       else
3941 	return G_TOKEN_FLOAT;
3942       color->red = CLAMP (token_int, 0, 65535);
3943 
3944       token = g_scanner_get_next_token (scanner);
3945       if (token != G_TOKEN_COMMA)
3946 	return G_TOKEN_COMMA;
3947 
3948       token = g_scanner_get_next_token (scanner);
3949       if (token == G_TOKEN_INT)
3950 	token_int = scanner->value.v_int;
3951       else if (token == G_TOKEN_FLOAT)
3952 	token_int = scanner->value.v_float * 65535.0;
3953       else
3954 	return G_TOKEN_FLOAT;
3955       color->green = CLAMP (token_int, 0, 65535);
3956 
3957       token = g_scanner_get_next_token (scanner);
3958       if (token != G_TOKEN_COMMA)
3959 	return G_TOKEN_COMMA;
3960 
3961       token = g_scanner_get_next_token (scanner);
3962       if (token == G_TOKEN_INT)
3963 	token_int = scanner->value.v_int;
3964       else if (token == G_TOKEN_FLOAT)
3965 	token_int = scanner->value.v_float * 65535.0;
3966       else
3967 	return G_TOKEN_FLOAT;
3968       color->blue = CLAMP (token_int, 0, 65535);
3969 
3970       token = g_scanner_get_next_token (scanner);
3971       if (token != G_TOKEN_RIGHT_CURLY)
3972 	return G_TOKEN_RIGHT_CURLY;
3973       return G_TOKEN_NONE;
3974 
3975     case G_TOKEN_STRING:
3976       if (!gdk_color_parse (scanner->value.v_string, color))
3977 	{
3978           g_scanner_warn (scanner, "Invalid color constant '%s'",
3979                           scanner->value.v_string);
3980           return G_TOKEN_STRING;
3981 	}
3982       return G_TOKEN_NONE;
3983 
3984     case '@':
3985       token = g_scanner_get_next_token (scanner);
3986       if (token != G_TOKEN_IDENTIFIER)
3987 	return G_TOKEN_IDENTIFIER;
3988 
3989       if (!style || !lookup_color (style, scanner->value.v_identifier, color))
3990         {
3991           g_scanner_warn (scanner, "Invalid symbolic color '%s'",
3992                           scanner->value.v_identifier);
3993           return G_TOKEN_IDENTIFIER;
3994         }
3995 
3996       return G_TOKEN_NONE;
3997 
3998     case G_TOKEN_IDENTIFIER:
3999       if (strcmp (scanner->value.v_identifier, "mix") == 0)
4000         {
4001           token = g_scanner_get_next_token (scanner);
4002           if (token != G_TOKEN_LEFT_PAREN)
4003             return G_TOKEN_LEFT_PAREN;
4004 
4005           negate = FALSE;
4006           if (g_scanner_peek_next_token (scanner) == '-')
4007             {
4008               g_scanner_get_next_token (scanner); /* eat sign */
4009               negate = TRUE;
4010             }
4011 
4012           token = g_scanner_get_next_token (scanner);
4013           if (token != G_TOKEN_FLOAT)
4014             return G_TOKEN_FLOAT;
4015 
4016           l = negate ? -scanner->value.v_float : scanner->value.v_float;
4017 
4018           token = g_scanner_get_next_token (scanner);
4019           if (token != G_TOKEN_COMMA)
4020             return G_TOKEN_COMMA;
4021 
4022           token = gtk_rc_parse_color_full (scanner, style, &c1);
4023           if (token != G_TOKEN_NONE)
4024             return token;
4025 
4026 	  token = g_scanner_get_next_token (scanner);
4027 	  if (token != G_TOKEN_COMMA)
4028             return G_TOKEN_COMMA;
4029 
4030 	  token = gtk_rc_parse_color_full (scanner, style, &c2);
4031 	  if (token != G_TOKEN_NONE)
4032             return token;
4033 
4034 	  token = g_scanner_get_next_token (scanner);
4035 	  if (token != G_TOKEN_RIGHT_PAREN)
4036             return G_TOKEN_RIGHT_PAREN;
4037 
4038 	  color->red   = l * c1.red   + (1.0 - l) * c2.red;
4039 	  color->green = l * c1.green + (1.0 - l) * c2.green;
4040 	  color->blue  = l * c1.blue  + (1.0 - l) * c2.blue;
4041 
4042 	  return G_TOKEN_NONE;
4043 	}
4044       else if (strcmp (scanner->value.v_identifier, "shade") == 0)
4045         {
4046 	  token = g_scanner_get_next_token (scanner);
4047           if (token != G_TOKEN_LEFT_PAREN)
4048             return G_TOKEN_LEFT_PAREN;
4049 
4050           negate = FALSE;
4051           if (g_scanner_peek_next_token (scanner) == '-')
4052             {
4053               g_scanner_get_next_token (scanner); /* eat sign */
4054               negate = TRUE;
4055             }
4056 
4057           token = g_scanner_get_next_token (scanner);
4058           if (token != G_TOKEN_FLOAT)
4059             return G_TOKEN_FLOAT;
4060 
4061           l = negate ? -scanner->value.v_float : scanner->value.v_float;
4062 
4063           token = g_scanner_get_next_token (scanner);
4064           if (token != G_TOKEN_COMMA)
4065             return G_TOKEN_COMMA;
4066 
4067           token = gtk_rc_parse_color_full (scanner, style, &c1);
4068           if (token != G_TOKEN_NONE)
4069             return token;
4070 
4071           token = g_scanner_get_next_token (scanner);
4072           if (token != G_TOKEN_RIGHT_PAREN)
4073             return G_TOKEN_RIGHT_PAREN;
4074 
4075           _gtk_style_shade (&c1, color, l);
4076 
4077           return G_TOKEN_NONE;
4078         }
4079       else if (strcmp (scanner->value.v_identifier, "lighter") == 0 ||
4080                strcmp (scanner->value.v_identifier, "darker") == 0)
4081         {
4082           if (scanner->value.v_identifier[0] == 'l')
4083             l = 1.3;
4084           else
4085 	    l = 0.7;
4086 
4087 	  token = g_scanner_get_next_token (scanner);
4088           if (token != G_TOKEN_LEFT_PAREN)
4089             return G_TOKEN_LEFT_PAREN;
4090 
4091           token = gtk_rc_parse_color_full (scanner, style, &c1);
4092           if (token != G_TOKEN_NONE)
4093             return token;
4094 
4095           token = g_scanner_get_next_token (scanner);
4096           if (token != G_TOKEN_RIGHT_PAREN)
4097             return G_TOKEN_RIGHT_PAREN;
4098 
4099           _gtk_style_shade (&c1, color, l);
4100 
4101           return G_TOKEN_NONE;
4102         }
4103       else
4104         return G_TOKEN_IDENTIFIER;
4105 
4106     default:
4107       return G_TOKEN_STRING;
4108     }
4109 }
4110 
4111 static guint
gtk_rc_parse_pixmap_path(GtkRcContext * context,GScanner * scanner)4112 gtk_rc_parse_pixmap_path (GtkRcContext *context,
4113 			  GScanner     *scanner)
4114 {
4115   guint token;
4116 
4117   token = g_scanner_get_next_token (scanner);
4118   if (token != GTK_RC_TOKEN_PIXMAP_PATH)
4119     return GTK_RC_TOKEN_PIXMAP_PATH;
4120 
4121   token = g_scanner_get_next_token (scanner);
4122   if (token != G_TOKEN_STRING)
4123     return G_TOKEN_STRING;
4124 
4125   gtk_rc_parse_pixmap_path_string (context, scanner, scanner->value.v_string);
4126 
4127   return G_TOKEN_NONE;
4128 }
4129 
4130 static void
gtk_rc_parse_pixmap_path_string(GtkRcContext * context,GScanner * scanner,const gchar * pix_path)4131 gtk_rc_parse_pixmap_path_string (GtkRcContext *context,
4132 				 GScanner     *scanner,
4133 				 const gchar  *pix_path)
4134 {
4135   g_strfreev (context->pixmap_path);
4136   context->pixmap_path = g_strsplit (pix_path, G_SEARCHPATH_SEPARATOR_S, -1);
4137 }
4138 
4139 static guint
gtk_rc_parse_module_path(GScanner * scanner)4140 gtk_rc_parse_module_path (GScanner *scanner)
4141 {
4142   guint token;
4143 
4144   token = g_scanner_get_next_token (scanner);
4145   if (token != GTK_RC_TOKEN_MODULE_PATH)
4146     return GTK_RC_TOKEN_MODULE_PATH;
4147 
4148   token = g_scanner_get_next_token (scanner);
4149   if (token != G_TOKEN_STRING)
4150     return G_TOKEN_STRING;
4151 
4152   g_warning ("module_path directive is now ignored\n");
4153 
4154   return G_TOKEN_NONE;
4155 }
4156 
4157 static guint
gtk_rc_parse_im_module_file(GScanner * scanner)4158 gtk_rc_parse_im_module_file (GScanner *scanner)
4159 {
4160   guint token;
4161 
4162   token = g_scanner_get_next_token (scanner);
4163   if (token != GTK_RC_TOKEN_IM_MODULE_FILE)
4164     return GTK_RC_TOKEN_IM_MODULE_FILE;
4165 
4166   token = g_scanner_get_next_token (scanner);
4167   if (token != G_TOKEN_STRING)
4168     return G_TOKEN_STRING;
4169 
4170   g_free (im_module_file);
4171 
4172   im_module_file = g_strdup (scanner->value.v_string);
4173 
4174   return G_TOKEN_NONE;
4175 }
4176 
4177 static guint
gtk_rc_parse_path_pattern(GtkRcContext * context,GScanner * scanner)4178 gtk_rc_parse_path_pattern (GtkRcContext *context,
4179 			   GScanner     *scanner)
4180 {
4181   guint token;
4182   GtkPathType path_type;
4183   gchar *pattern;
4184   gboolean is_binding;
4185   GtkPathPriorityType priority = context->default_priority;
4186 
4187   token = g_scanner_get_next_token (scanner);
4188   switch (token)
4189     {
4190     case GTK_RC_TOKEN_WIDGET:
4191       path_type = GTK_PATH_WIDGET;
4192       break;
4193     case GTK_RC_TOKEN_WIDGET_CLASS:
4194       path_type = GTK_PATH_WIDGET_CLASS;
4195       break;
4196     case GTK_RC_TOKEN_CLASS:
4197       path_type = GTK_PATH_CLASS;
4198       break;
4199     default:
4200       return GTK_RC_TOKEN_WIDGET_CLASS;
4201     }
4202 
4203   token = g_scanner_get_next_token (scanner);
4204   if (token != G_TOKEN_STRING)
4205     return G_TOKEN_STRING;
4206 
4207   pattern = g_strdup (scanner->value.v_string);
4208 
4209   token = g_scanner_get_next_token (scanner);
4210   if (token == GTK_RC_TOKEN_STYLE)
4211     is_binding = FALSE;
4212   else if (token == GTK_RC_TOKEN_BINDING)
4213     is_binding = TRUE;
4214   else
4215     {
4216       g_free (pattern);
4217       return GTK_RC_TOKEN_STYLE;
4218     }
4219 
4220   if (g_scanner_peek_next_token (scanner) == ':')
4221     {
4222       token = gtk_rc_parse_priority (scanner, &priority);
4223       if (token != G_TOKEN_NONE)
4224 	{
4225 	  g_free (pattern);
4226 	  return token;
4227 	}
4228     }
4229 
4230   token = g_scanner_get_next_token (scanner);
4231   if (token != G_TOKEN_STRING)
4232     {
4233       g_free (pattern);
4234       return G_TOKEN_STRING;
4235     }
4236 
4237   if (is_binding)
4238     {
4239       GtkBindingSet *binding;
4240 
4241       binding = gtk_binding_set_find (scanner->value.v_string);
4242       if (!binding)
4243 	{
4244 	  g_free (pattern);
4245 	  return G_TOKEN_STRING;
4246 	}
4247       gtk_binding_set_add_path (binding, path_type, pattern, priority);
4248     }
4249   else
4250     {
4251       GtkRcStyle *rc_style;
4252       GtkRcSet *rc_set;
4253 
4254       rc_style = gtk_rc_style_find (context, scanner->value.v_string);
4255 
4256       if (!rc_style)
4257 	{
4258 	  g_free (pattern);
4259 	  return G_TOKEN_STRING;
4260 	}
4261 
4262       rc_set = g_new (GtkRcSet, 1);
4263       rc_set->type = path_type;
4264 
4265       if (path_type == GTK_PATH_WIDGET_CLASS)
4266         {
4267           rc_set->pspec = NULL;
4268           rc_set->path = _gtk_rc_parse_widget_class_path (pattern);
4269         }
4270       else
4271         {
4272           rc_set->pspec = g_pattern_spec_new (pattern);
4273           rc_set->path = NULL;
4274         }
4275 
4276       rc_set->rc_style = rc_style;
4277       rc_set->priority = priority;
4278 
4279       if (path_type == GTK_PATH_WIDGET)
4280 	context->rc_sets_widget = g_slist_prepend (context->rc_sets_widget, rc_set);
4281       else if (path_type == GTK_PATH_WIDGET_CLASS)
4282 	context->rc_sets_widget_class = g_slist_prepend (context->rc_sets_widget_class, rc_set);
4283       else
4284 	context->rc_sets_class = g_slist_prepend (context->rc_sets_class, rc_set);
4285     }
4286 
4287   g_free (pattern);
4288   return G_TOKEN_NONE;
4289 }
4290 
4291 static guint
gtk_rc_parse_hash_key(GScanner * scanner,gchar ** hash_key)4292 gtk_rc_parse_hash_key (GScanner  *scanner,
4293                        gchar    **hash_key)
4294 {
4295   guint token;
4296 
4297   token = g_scanner_get_next_token (scanner);
4298   if (token != G_TOKEN_LEFT_BRACE)
4299     return G_TOKEN_LEFT_BRACE;
4300 
4301   token = g_scanner_get_next_token (scanner);
4302 
4303   if (token != G_TOKEN_STRING)
4304     return G_TOKEN_STRING;
4305 
4306   *hash_key = g_strdup (scanner->value.v_string);
4307 
4308   token = g_scanner_get_next_token (scanner);
4309   if (token != G_TOKEN_RIGHT_BRACE)
4310     {
4311       g_free (*hash_key);
4312       return G_TOKEN_RIGHT_BRACE;
4313     }
4314 
4315   return G_TOKEN_NONE;
4316 }
4317 
4318 static guint
gtk_rc_parse_icon_source(GtkRcContext * context,GScanner * scanner,GtkIconSet * icon_set,gboolean * icon_set_valid)4319 gtk_rc_parse_icon_source (GtkRcContext   *context,
4320 			  GScanner	 *scanner,
4321                           GtkIconSet     *icon_set,
4322                           gboolean       *icon_set_valid)
4323 {
4324   guint token;
4325   gchar *full_filename;
4326   GtkIconSource *source = NULL;
4327 
4328   token = g_scanner_get_next_token (scanner);
4329   if (token != G_TOKEN_LEFT_CURLY)
4330     return G_TOKEN_LEFT_CURLY;
4331 
4332   token = g_scanner_get_next_token (scanner);
4333 
4334   if (token != G_TOKEN_STRING && token != '@')
4335     return G_TOKEN_STRING;
4336 
4337   if (token == G_TOKEN_STRING)
4338     {
4339       /* Filename */
4340 
4341       source = gtk_icon_source_new ();
4342       full_filename = gtk_rc_find_pixmap_in_path (context->settings, scanner, scanner->value.v_string);
4343       if (full_filename)
4344 	{
4345 	  gtk_icon_source_set_filename (source, full_filename);
4346 	  g_free (full_filename);
4347 	}
4348     }
4349   else
4350     {
4351       /* Icon name */
4352 
4353       token = g_scanner_get_next_token (scanner);
4354 
4355       if (token != G_TOKEN_STRING)
4356 	return G_TOKEN_STRING;
4357 
4358       source = gtk_icon_source_new ();
4359       gtk_icon_source_set_icon_name (source, scanner->value.v_string);
4360     }
4361 
4362   /* We continue parsing even if we didn't find the pixmap so that rest of the
4363    * file is read, even if the syntax is bad. However we don't validate the
4364    * icon_set so the caller can choose not to install it.
4365    */
4366   token = g_scanner_get_next_token (scanner);
4367 
4368   if (token == G_TOKEN_RIGHT_CURLY)
4369     goto done;
4370   else if (token != G_TOKEN_COMMA)
4371     {
4372       gtk_icon_source_free (source);
4373       return G_TOKEN_COMMA;
4374     }
4375 
4376   /* Get the direction */
4377 
4378   token = g_scanner_get_next_token (scanner);
4379 
4380   switch (token)
4381     {
4382     case GTK_RC_TOKEN_RTL:
4383       gtk_icon_source_set_direction_wildcarded (source, FALSE);
4384       gtk_icon_source_set_direction (source, GTK_TEXT_DIR_RTL);
4385       break;
4386 
4387     case GTK_RC_TOKEN_LTR:
4388       gtk_icon_source_set_direction_wildcarded (source, FALSE);
4389       gtk_icon_source_set_direction (source, GTK_TEXT_DIR_LTR);
4390       break;
4391 
4392     case '*':
4393       break;
4394 
4395     default:
4396       gtk_icon_source_free (source);
4397       return GTK_RC_TOKEN_RTL;
4398       break;
4399     }
4400 
4401   token = g_scanner_get_next_token (scanner);
4402 
4403   if (token == G_TOKEN_RIGHT_CURLY)
4404     goto done;
4405   else if (token != G_TOKEN_COMMA)
4406     {
4407       gtk_icon_source_free (source);
4408       return G_TOKEN_COMMA;
4409     }
4410 
4411   /* Get the state */
4412 
4413   token = g_scanner_get_next_token (scanner);
4414 
4415   switch (token)
4416     {
4417     case GTK_RC_TOKEN_NORMAL:
4418       gtk_icon_source_set_state_wildcarded (source, FALSE);
4419       gtk_icon_source_set_state (source, GTK_STATE_NORMAL);
4420       break;
4421 
4422     case GTK_RC_TOKEN_PRELIGHT:
4423       gtk_icon_source_set_state_wildcarded (source, FALSE);
4424       gtk_icon_source_set_state (source, GTK_STATE_PRELIGHT);
4425       break;
4426 
4427 
4428     case GTK_RC_TOKEN_INSENSITIVE:
4429       gtk_icon_source_set_state_wildcarded (source, FALSE);
4430       gtk_icon_source_set_state (source, GTK_STATE_INSENSITIVE);
4431       break;
4432 
4433     case GTK_RC_TOKEN_ACTIVE:
4434       gtk_icon_source_set_state_wildcarded (source, FALSE);
4435       gtk_icon_source_set_state (source, GTK_STATE_ACTIVE);
4436       break;
4437 
4438     case GTK_RC_TOKEN_SELECTED:
4439       gtk_icon_source_set_state_wildcarded (source, FALSE);
4440       gtk_icon_source_set_state (source, GTK_STATE_SELECTED);
4441       break;
4442 
4443     case '*':
4444       break;
4445 
4446     default:
4447       gtk_icon_source_free (source);
4448       return GTK_RC_TOKEN_PRELIGHT;
4449       break;
4450     }
4451 
4452   token = g_scanner_get_next_token (scanner);
4453 
4454   if (token == G_TOKEN_RIGHT_CURLY)
4455     goto done;
4456   else if (token != G_TOKEN_COMMA)
4457     {
4458       gtk_icon_source_free (source);
4459       return G_TOKEN_COMMA;
4460     }
4461 
4462   /* Get the size */
4463 
4464   token = g_scanner_get_next_token (scanner);
4465 
4466   if (token != '*')
4467     {
4468       GtkIconSize size;
4469 
4470       if (token != G_TOKEN_STRING)
4471         {
4472           gtk_icon_source_free (source);
4473           return G_TOKEN_STRING;
4474         }
4475 
4476       size = gtk_icon_size_from_name (scanner->value.v_string);
4477 
4478       if (size != GTK_ICON_SIZE_INVALID)
4479         {
4480           gtk_icon_source_set_size_wildcarded (source, FALSE);
4481           gtk_icon_source_set_size (source, size);
4482         }
4483     }
4484 
4485   /* Check the close brace */
4486 
4487   token = g_scanner_get_next_token (scanner);
4488   if (token != G_TOKEN_RIGHT_CURLY)
4489     {
4490       gtk_icon_source_free (source);
4491       return G_TOKEN_RIGHT_CURLY;
4492     }
4493 
4494  done:
4495   if (gtk_icon_source_get_filename (source) ||
4496       gtk_icon_source_get_icon_name (source))
4497     {
4498       gtk_icon_set_add_source (icon_set, source);
4499       *icon_set_valid = TRUE;
4500     }
4501   gtk_icon_source_free (source);
4502 
4503   return G_TOKEN_NONE;
4504 }
4505 
4506 static guint
gtk_rc_parse_stock(GtkRcContext * context,GScanner * scanner,GtkRcStyle * rc_style,GtkIconFactory * factory)4507 gtk_rc_parse_stock (GtkRcContext   *context,
4508 		    GScanner       *scanner,
4509                     GtkRcStyle     *rc_style,
4510                     GtkIconFactory *factory)
4511 {
4512   GtkIconSet *icon_set = NULL;
4513   gboolean icon_set_valid = FALSE;
4514   gchar *stock_id = NULL;
4515   guint token;
4516 
4517   token = g_scanner_get_next_token (scanner);
4518   if (token != GTK_RC_TOKEN_STOCK)
4519     return GTK_RC_TOKEN_STOCK;
4520 
4521   token = gtk_rc_parse_hash_key (scanner, &stock_id);
4522   if (token != G_TOKEN_NONE)
4523     return token;
4524 
4525   token = g_scanner_get_next_token (scanner);
4526   if (token != G_TOKEN_EQUAL_SIGN)
4527     {
4528       g_free (stock_id);
4529       return G_TOKEN_EQUAL_SIGN;
4530     }
4531 
4532   token = g_scanner_get_next_token (scanner);
4533   if (token != G_TOKEN_LEFT_CURLY)
4534     {
4535       g_free (stock_id);
4536       return G_TOKEN_LEFT_CURLY;
4537     }
4538 
4539   token = g_scanner_peek_next_token (scanner);
4540   while (token != G_TOKEN_RIGHT_CURLY)
4541     {
4542       if (icon_set == NULL)
4543         icon_set = gtk_icon_set_new ();
4544 
4545       token = gtk_rc_parse_icon_source (context,
4546                                         scanner, icon_set, &icon_set_valid);
4547       if (token != G_TOKEN_NONE)
4548         {
4549           g_free (stock_id);
4550           gtk_icon_set_unref (icon_set);
4551           return token;
4552         }
4553 
4554       token = g_scanner_get_next_token (scanner);
4555 
4556       if (token != G_TOKEN_COMMA &&
4557           token != G_TOKEN_RIGHT_CURLY)
4558         {
4559           g_free (stock_id);
4560           gtk_icon_set_unref (icon_set);
4561           return G_TOKEN_RIGHT_CURLY;
4562         }
4563     }
4564 
4565   if (icon_set)
4566     {
4567       if (icon_set_valid)
4568         gtk_icon_factory_add (factory,
4569                               stock_id,
4570                               icon_set);
4571 
4572       gtk_icon_set_unref (icon_set);
4573     }
4574 
4575   g_free (stock_id);
4576 
4577   return G_TOKEN_NONE;
4578 }
4579 
4580 static guint
gtk_rc_parse_logical_color(GScanner * scanner,GtkRcStyle * rc_style,GHashTable * hash)4581 gtk_rc_parse_logical_color (GScanner   *scanner,
4582                             GtkRcStyle *rc_style,
4583                             GHashTable *hash)
4584 {
4585   gchar *color_id = NULL;
4586   guint token;
4587   GdkColor color;
4588 
4589   token = g_scanner_get_next_token (scanner);
4590   if (token != GTK_RC_TOKEN_COLOR)
4591     return GTK_RC_TOKEN_COLOR;
4592 
4593   token = gtk_rc_parse_hash_key (scanner, &color_id);
4594   if (token != G_TOKEN_NONE)
4595     return token;
4596 
4597   token = g_scanner_get_next_token (scanner);
4598   if (token != G_TOKEN_EQUAL_SIGN)
4599     {
4600       g_free (color_id);
4601       return G_TOKEN_EQUAL_SIGN;
4602     }
4603 
4604   token = gtk_rc_parse_color_full (scanner, rc_style, &color);
4605   if (token != G_TOKEN_NONE)
4606     {
4607       g_free (color_id);
4608       return token;
4609     }
4610 
4611   /* Because the hash is created with destroy functions,
4612    * g_hash_table_insert will free any old values for us,
4613    * if a mapping with the specified key already exists.
4614    */
4615   g_hash_table_insert (hash, color_id, gdk_color_copy (&color));
4616 
4617   return G_TOKEN_NONE;
4618 }
4619 
4620 
4621 GSList *
_gtk_rc_parse_widget_class_path(const gchar * pattern)4622 _gtk_rc_parse_widget_class_path (const gchar *pattern)
4623 {
4624   GSList *result;
4625   PathElt *path_elt;
4626   const gchar *current;
4627   const gchar *class_start;
4628   const gchar *class_end;
4629   const gchar *pattern_end;
4630   const gchar *pattern_start;
4631   gchar *sub_pattern;
4632 
4633   result = NULL;
4634   current = pattern;
4635   while ((class_start = strchr (current, '<')) &&
4636 	 (class_end = strchr (class_start, '>')))
4637     {
4638       /* Add patterns, but ignore single dots */
4639       if (!(class_start == current ||
4640 	    (class_start == current + 1 && current[0] == '.')))
4641         {
4642           pattern_end = class_start - 1;
4643           pattern_start = current;
4644 
4645           path_elt = g_new (PathElt, 1);
4646 
4647           sub_pattern = g_strndup (pattern_start, pattern_end - pattern_start + 1);
4648 	  path_elt->type = PATH_ELT_PSPEC;
4649           path_elt->elt.pspec = g_pattern_spec_new (sub_pattern);
4650           g_free (sub_pattern);
4651 
4652           result = g_slist_prepend (result, path_elt);
4653         }
4654 
4655       path_elt = g_new (PathElt, 1);
4656 
4657       /* The < > need to be removed from the string. */
4658       sub_pattern = g_strndup (class_start + 1, class_end - class_start - 1);
4659 
4660       path_elt->type = PATH_ELT_UNRESOLVED;
4661       path_elt->elt.class_name = sub_pattern;
4662 
4663       result = g_slist_prepend (result, path_elt);
4664 
4665       current = class_end + 1;
4666     }
4667 
4668   /* Add the rest, if anything is left */
4669   if (strlen (current) > 0)
4670     {
4671       path_elt = g_new (PathElt, 1);
4672       path_elt->type = PATH_ELT_PSPEC;
4673       path_elt->elt.pspec = g_pattern_spec_new (current);
4674 
4675       result = g_slist_prepend (result, path_elt);
4676     }
4677 
4678   return g_slist_reverse (result);
4679 }
4680 
4681 static void
free_path_elt(gpointer data,gpointer user_data)4682 free_path_elt (gpointer data,
4683 	       gpointer user_data)
4684 {
4685   PathElt *path_elt = data;
4686 
4687   switch (path_elt->type)
4688     {
4689     case PATH_ELT_PSPEC:
4690       g_pattern_spec_free (path_elt->elt.pspec);
4691       break;
4692     case PATH_ELT_UNRESOLVED:
4693       g_free (path_elt->elt.class_name);
4694       break;
4695     case PATH_ELT_TYPE:
4696       break;
4697     default:
4698       g_assert_not_reached ();
4699     }
4700 
4701   g_free (path_elt);
4702 }
4703 
4704 void
_gtk_rc_free_widget_class_path(GSList * list)4705 _gtk_rc_free_widget_class_path (GSList *list)
4706 {
4707   g_slist_foreach (list, free_path_elt, NULL);
4708   g_slist_free (list);
4709 }
4710 
4711 static void
gtk_rc_set_free(GtkRcSet * rc_set)4712 gtk_rc_set_free (GtkRcSet *rc_set)
4713 {
4714   if (rc_set->pspec)
4715     g_pattern_spec_free (rc_set->pspec);
4716 
4717   _gtk_rc_free_widget_class_path (rc_set->path);
4718 
4719   g_free (rc_set);
4720 }
4721 
4722 static gboolean
match_class(PathElt * path_elt,gchar * type_name)4723 match_class (PathElt *path_elt,
4724 	     gchar   *type_name)
4725 {
4726   GType type;
4727 
4728   if (path_elt->type == PATH_ELT_UNRESOLVED)
4729     {
4730       type = g_type_from_name (path_elt->elt.class_name);
4731       if (type != G_TYPE_INVALID)
4732         {
4733           g_free (path_elt->elt.class_name);
4734           path_elt->elt.class_type = type;
4735 	  path_elt->type = PATH_ELT_TYPE;
4736         }
4737       else
4738 	return g_str_equal (type_name, path_elt->elt.class_name);
4739     }
4740 
4741   return g_type_is_a (g_type_from_name (type_name), path_elt->elt.class_type);
4742 }
4743 
4744 static gboolean
match_widget_class_recursive(GSList * list,guint length,gchar * path,gchar * path_reversed)4745 match_widget_class_recursive (GSList *list,
4746 			      guint   length,
4747 			      gchar  *path,
4748 			      gchar  *path_reversed)
4749 {
4750   PathElt *path_elt;
4751 
4752   /* break out if we cannot match anymore. */
4753   if (list == NULL)
4754     {
4755       if (length > 0)
4756         return FALSE;
4757       else
4758         return TRUE;
4759     }
4760 
4761   /* there are two possibilities:
4762    *  1. The next pattern should match the class.
4763    *  2. First normal matching, and then maybe a class */
4764 
4765   path_elt = list->data;
4766 
4767   if (path_elt->type != PATH_ELT_PSPEC)
4768     {
4769       gchar *class_start = path;
4770       gchar *class_end;
4771 
4772       /* ignore leading dot */
4773       if (class_start[0] == '.')
4774         class_start++;
4775       class_end = strchr (class_start, '.');
4776 
4777       if (class_end == NULL)
4778         {
4779           if (!match_class (path_elt, class_start))
4780             return FALSE;
4781 	  else
4782 	    return match_widget_class_recursive (list->next, 0, "", "");
4783         }
4784       else
4785         {
4786           class_end[0] = '\0';
4787           if (!match_class (path_elt, class_start))
4788             {
4789               class_end[0] = '.';
4790               return FALSE;
4791             }
4792           else
4793             {
4794               gboolean result;
4795               gint new_length = length - (class_end - path);
4796               gchar old_char = path_reversed[new_length];
4797 
4798               class_end[0] = '.';
4799 
4800               path_reversed[new_length] = '\0';
4801               result = match_widget_class_recursive (list->next, new_length, class_end, path_reversed);
4802               path_reversed[new_length] = old_char;
4803 
4804               return result;
4805             }
4806         }
4807     }
4808   else
4809     {
4810       PathElt *class_elt;
4811       gchar *class_start;
4812       gchar *class_end;
4813       gboolean result = FALSE;
4814 
4815       /* If there is nothing after this (ie. no class match),
4816        * just compare the pspec.
4817        */
4818       if (list->next == NULL)
4819         return g_pattern_match (path_elt->elt.pspec, length, path, path_reversed);
4820 
4821       class_elt = (PathElt *)list->next->data;
4822       g_assert (class_elt->type != PATH_ELT_PSPEC);
4823 
4824       class_start = path;
4825       if (class_start[0] == '.')
4826         class_start++;
4827 
4828       while (TRUE)
4829         {
4830 	  class_end = strchr (class_start, '.');
4831 
4832           /* It should be cheaper to match the class first. (either the pattern
4833            * is simple, and will match most of the times, or it may be complex
4834            * and matching is slow)
4835 	   */
4836           if (class_end == NULL)
4837 	    {
4838 	      result = match_class (class_elt, class_start);
4839 	    }
4840           else
4841             {
4842               class_end[0] = '\0';
4843               result = match_class (class_elt, class_start);
4844               class_end[0] = '.';
4845             }
4846 
4847           if (result)
4848             {
4849               gchar old_char;
4850               result = FALSE;
4851 
4852               /* terminate the string in front of the class. It does not matter
4853                * that the class becomes unusable, because it is not needed
4854 	       * inside the recursion
4855 	       */
4856               old_char = class_start[0];
4857               class_start[0] = '\0';
4858 
4859               if (g_pattern_match (path_elt->elt.pspec, class_start - path, path, path_reversed + length - (class_start - path)))
4860                 {
4861                   if (class_end != NULL)
4862                     {
4863                       gint new_length = length - (class_end - path);
4864                       gchar path_reversed_char = path_reversed[new_length];
4865 
4866                       path_reversed[new_length] = '\0';
4867 
4868                       result = match_widget_class_recursive (list->next->next, new_length, class_end, path_reversed);
4869 
4870                       path_reversed[new_length] = path_reversed_char;
4871                     }
4872                   else
4873                     result = match_widget_class_recursive (list->next->next, 0, "", "");
4874                 }
4875 
4876               class_start[0] = old_char;
4877             }
4878 
4879           if (result)
4880             return TRUE;
4881 
4882           /* get next class in path, or break out */
4883           if (class_end != NULL)
4884             class_start = class_end + 1;
4885           else
4886             return FALSE;
4887         }
4888     }
4889 }
4890 
4891 gboolean
_gtk_rc_match_widget_class(GSList * list,gint length,gchar * path,gchar * path_reversed)4892 _gtk_rc_match_widget_class (GSList  *list,
4893                             gint     length,
4894                             gchar   *path,
4895                             gchar   *path_reversed)
4896 {
4897   return match_widget_class_recursive (list, length, path, path_reversed);
4898 }
4899 
4900 #if defined (G_OS_WIN32) && !defined (_WIN64)
4901 
4902 /* DLL ABI stability backward compatibility versions */
4903 
4904 #undef gtk_rc_add_default_file
4905 
4906 void
gtk_rc_add_default_file(const gchar * filename)4907 gtk_rc_add_default_file (const gchar *filename)
4908 {
4909   gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, NULL);
4910 
4911   gtk_rc_add_default_file_utf8 (utf8_filename);
4912 
4913   g_free (utf8_filename);
4914 }
4915 
4916 #undef gtk_rc_set_default_files
4917 
4918 void
gtk_rc_set_default_files(gchar ** filenames)4919 gtk_rc_set_default_files (gchar **filenames)
4920 {
4921   gchar **utf8_filenames;
4922   int n = 0, i;
4923 
4924   while (filenames[n++] != NULL)
4925     ;
4926 
4927   utf8_filenames = g_new (gchar *, n + 1);
4928 
4929   for (i = 0; i < n; i++)
4930     utf8_filenames[i] = g_locale_to_utf8 (filenames[i], -1, NULL, NULL, NULL);
4931 
4932   utf8_filenames[n] = NULL;
4933 
4934   gtk_rc_set_default_files_utf8 (utf8_filenames);
4935 
4936   g_strfreev (utf8_filenames);
4937 }
4938 
4939 #undef gtk_rc_parse
4940 
4941 void
gtk_rc_parse(const gchar * filename)4942 gtk_rc_parse (const gchar *filename)
4943 {
4944   gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, NULL);
4945 
4946   gtk_rc_parse_utf8 (utf8_filename);
4947 
4948   g_free (utf8_filename);
4949 }
4950 
4951 #endif
4952 
4953 #define __GTK_RC_C__
4954 #include "gtkaliasdef.c"
4955