]> Pileus Git - ~andy/gtk/blob - gtk/gtkrc.c
5f726bd23f4828d9bd5de3d6be11434aa598b043
[~andy/gtk] / gtk / gtkrc.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU 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 #ifdef G_OS_WIN32
60 #include <io.h>
61 #endif
62
63 enum 
64 {
65   PATH_ELT_PSPEC,
66   PATH_ELT_UNRESOLVED,
67   PATH_ELT_TYPE
68 };
69
70 typedef struct
71 {
72   gint type;
73   union 
74   {
75     GType         class_type;
76     gchar        *class_name;
77     GPatternSpec *pspec;
78   } elt;
79 } PathElt;
80
81 #define GTK_RC_STYLE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_RC_STYLE, GtkRcStylePrivate))
82
83 typedef struct _GtkRcStylePrivate GtkRcStylePrivate;
84
85 struct _GtkRcStylePrivate
86 {
87   GSList *color_hashes;
88 };
89
90 static void        gtk_rc_style_finalize             (GObject         *object);
91 static void        gtk_rc_style_real_merge           (GtkRcStyle      *dest,
92                                                       GtkRcStyle      *src);
93 static GtkRcStyle* gtk_rc_style_real_create_rc_style (GtkRcStyle      *rc_style);
94 static GtkStyle*   gtk_rc_style_real_create_style    (GtkRcStyle      *rc_style);
95 static gint        gtk_rc_properties_cmp             (gconstpointer    bsearch_node1,
96                                                       gconstpointer    bsearch_node2);
97
98 static void        insert_rc_property                (GtkRcStyle      *style,
99                                                       GtkRcProperty   *property,
100                                                       gboolean         replace);
101
102
103 static const GScannerConfig gtk_rc_scanner_config =
104 {
105   (
106    " \t\r\n"
107    )                    /* cset_skip_characters */,
108   (
109    "_"
110    G_CSET_a_2_z
111    G_CSET_A_2_Z
112    )                    /* cset_identifier_first */,
113   (
114    G_CSET_DIGITS
115    "-_"
116    G_CSET_a_2_z
117    G_CSET_A_2_Z
118    )                    /* cset_identifier_nth */,
119   ( "#\n" )             /* cpair_comment_single */,
120   
121   TRUE                  /* case_sensitive */,
122   
123   TRUE                  /* skip_comment_multi */,
124   TRUE                  /* skip_comment_single */,
125   TRUE                  /* scan_comment_multi */,
126   TRUE                  /* scan_identifier */,
127   FALSE                 /* scan_identifier_1char */,
128   FALSE                 /* scan_identifier_NULL */,
129   TRUE                  /* scan_symbols */,
130   TRUE                  /* scan_binary */,
131   TRUE                  /* scan_octal */,
132   TRUE                  /* scan_float */,
133   TRUE                  /* scan_hex */,
134   TRUE                  /* scan_hex_dollar */,
135   TRUE                  /* scan_string_sq */,
136   TRUE                  /* scan_string_dq */,
137   TRUE                  /* numbers_2_int */,
138   FALSE                 /* int_2_float */,
139   FALSE                 /* identifier_2_string */,
140   TRUE                  /* char_2_token */,
141   TRUE                  /* symbol_2_token */,
142   FALSE                 /* scope_0_fallback */,
143 };
144  
145 static const gchar symbol_names[] = 
146   "include\0"
147   "NORMAL\0"
148   "ACTIVE\0"
149   "PRELIGHT\0"
150   "SELECTED\0"
151   "INSENSITIVE\0"
152   "fg\0"
153   "bg\0"
154   "text\0"
155   "base\0"
156   "xthickness\0"
157   "ythickness\0"
158   "font\0"
159   "fontset\0"
160   "font_name\0"
161   "bg_pixmap\0"
162   "pixmap_path\0"
163   "style\0"
164   "binding\0"
165   "bind\0"
166   "widget\0"
167   "widget_class\0"
168   "class\0"
169   "lowest\0"
170   "gtk\0"
171   "application\0"
172   "theme\0"
173   "rc\0"
174   "highest\0"
175   "engine\0"
176   "module_path\0"
177   "stock\0"
178   "im_module_file\0"
179   "LTR\0"
180   "RTL\0"
181   "color\0"
182   "unbind\0";
183
184 static const struct
185 {
186   guint name_offset;
187   guint token;
188 } symbols[] = {
189   {   0, GTK_RC_TOKEN_INCLUDE },
190   {   8, GTK_RC_TOKEN_NORMAL },
191   {  15, GTK_RC_TOKEN_ACTIVE },
192   {  22, GTK_RC_TOKEN_PRELIGHT },
193   {  31, GTK_RC_TOKEN_SELECTED },
194   {  40, GTK_RC_TOKEN_INSENSITIVE },
195   {  52, GTK_RC_TOKEN_FG },
196   {  55, GTK_RC_TOKEN_BG },
197   {  58, GTK_RC_TOKEN_TEXT },
198   {  63, GTK_RC_TOKEN_BASE },
199   {  68, GTK_RC_TOKEN_XTHICKNESS },
200   {  79, GTK_RC_TOKEN_YTHICKNESS },
201   {  90, GTK_RC_TOKEN_FONT },
202   {  95, GTK_RC_TOKEN_FONTSET },
203   { 103, GTK_RC_TOKEN_FONT_NAME },
204   { 113, GTK_RC_TOKEN_BG_PIXMAP },
205   { 123, GTK_RC_TOKEN_PIXMAP_PATH },
206   { 135, GTK_RC_TOKEN_STYLE },
207   { 141, GTK_RC_TOKEN_BINDING },
208   { 149, GTK_RC_TOKEN_BIND },
209   { 154, GTK_RC_TOKEN_WIDGET },
210   { 161, GTK_RC_TOKEN_WIDGET_CLASS },
211   { 174, GTK_RC_TOKEN_CLASS },
212   { 180, GTK_RC_TOKEN_LOWEST },
213   { 187, GTK_RC_TOKEN_GTK },
214   { 191, GTK_RC_TOKEN_APPLICATION },
215   { 203, GTK_RC_TOKEN_THEME },
216   { 209, GTK_RC_TOKEN_RC },
217   { 212, GTK_RC_TOKEN_HIGHEST },
218   { 220, GTK_RC_TOKEN_ENGINE },
219   { 227, GTK_RC_TOKEN_MODULE_PATH },
220   { 239, GTK_RC_TOKEN_STOCK },
221   { 245, GTK_RC_TOKEN_IM_MODULE_FILE },
222   { 260, GTK_RC_TOKEN_LTR },
223   { 264, GTK_RC_TOKEN_RTL },
224   { 268, GTK_RC_TOKEN_COLOR },
225   { 274, GTK_RC_TOKEN_UNBIND }
226 };
227
228 static GHashTable *realized_style_ht = NULL;
229
230 static gchar *im_module_file = NULL;
231
232 static gchar **gtk_rc_default_files = NULL;
233
234 /* RC file handling */
235
236 static gchar *
237 gtk_rc_make_default_dir (const gchar *type)
238 {
239   const gchar *var;
240   gchar *path;
241
242   var = g_getenv ("GTK_EXE_PREFIX");
243
244   if (var)
245     path = g_build_filename (var, "lib", "gtk-3.0", GTK_BINARY_VERSION, type, NULL);
246   else
247     path = g_build_filename (GTK_LIBDIR, "gtk-3.0", GTK_BINARY_VERSION, type, NULL);
248
249   return path;
250 }
251
252 /**
253  * gtk_rc_get_im_module_path:
254  * @returns: a newly-allocated string containing the path in which to 
255  *    look for IM modules.
256  *
257  * Obtains the path in which to look for IM modules. See the documentation
258  * of the <link linkend="im-module-path"><envar>GTK_PATH</envar></link>
259  * environment variable for more details about looking up modules. This
260  * function is useful solely for utilities supplied with GTK+ and should
261  * not be used by applications under normal circumstances.
262  */
263 gchar *
264 gtk_rc_get_im_module_path (void)
265 {
266   gchar **paths = _gtk_get_module_path ("immodules");
267   gchar *result = g_strjoinv (G_SEARCHPATH_SEPARATOR_S, paths);
268   g_strfreev (paths);
269
270   return result;
271 }
272
273 /**
274  * gtk_rc_get_im_module_file:
275  * @returns: a newly-allocated string containing the name of the file
276  * listing the IM modules available for loading
277  *
278  * Obtains the path to the IM modules file. See the documentation
279  * of the <link linkend="im-module-file"><envar>GTK_IM_MODULE_FILE</envar></link>
280  * environment variable for more details.
281  */
282 gchar *
283 gtk_rc_get_im_module_file (void)
284 {
285   const gchar *var = g_getenv ("GTK_IM_MODULE_FILE");
286   gchar *result = NULL;
287
288   if (var)
289     result = g_strdup (var);
290
291   if (!result)
292     {
293       if (im_module_file)
294         result = g_strdup (im_module_file);
295       else
296         result = gtk_rc_make_default_dir ("immodules.cache");
297     }
298
299   return result;
300 }
301
302 gchar *
303 gtk_rc_get_theme_dir (void)
304 {
305   const gchar *var;
306   gchar *path;
307
308   var = g_getenv ("GTK_DATA_PREFIX");
309
310   if (var)
311     path = g_build_filename (var, "share", "themes", NULL);
312   else
313     path = g_build_filename (GTK_DATA_PREFIX, "share", "themes", NULL);
314
315   return path;
316 }
317
318 /**
319  * gtk_rc_get_module_dir:
320  * 
321  * Returns a directory in which GTK+ looks for theme engines.
322  * For full information about the search for theme engines,
323  * see the docs for <envar>GTK_PATH</envar> in
324  * <xref linkend="gtk-running"/>.
325  * 
326  * return value: the directory. (Must be freed with g_free())
327  **/
328 gchar *
329 gtk_rc_get_module_dir (void)
330 {
331   return gtk_rc_make_default_dir ("engines");
332 }
333
334 /**
335  * gtk_rc_add_default_file:
336  * @filename: the pathname to the file. If @filename is not absolute, it
337  *    is searched in the current directory.
338  *
339  * Adds a file to the list of files to be parsed at the
340  * end of gtk_init().
341  *
342  * Deprecated:3.0: Use #GtkStyleContext with a custom #GtkStyleProvider instead
343  **/
344 void
345 gtk_rc_add_default_file (const gchar *filename)
346 {
347 }
348
349 /**
350  * gtk_rc_set_default_files:
351  * @filenames: A %NULL-terminated list of filenames.
352  *
353  * Sets the list of files that GTK+ will read at the
354  * end of gtk_init().
355  *
356  * Deprecated:3.0: Use #GtkStyleContext with a custom #GtkStyleProvider instead
357  **/
358 void
359 gtk_rc_set_default_files (gchar **filenames)
360 {
361 }
362
363 /**
364  * gtk_rc_get_default_files:
365  *
366  * Retrieves the current list of RC files that will be parsed
367  * at the end of gtk_init().
368  *
369  * Return value: (transfer none): A %NULL-terminated array of filenames.
370  *     This memory is owned by GTK+ and must not be freed by the application.
371  *     If you want to store this information, you should make a copy.
372  *
373  * Deprecated:3.0: Use #GtkStyleContext instead
374  **/
375 gchar **
376 gtk_rc_get_default_files (void)
377 {
378   return gtk_rc_default_files;
379 }
380
381 void
382 gtk_rc_parse_string (const gchar *rc_string)
383 {
384   g_return_if_fail (rc_string != NULL);
385 }
386
387 void
388 gtk_rc_parse (const gchar *filename)
389 {
390   g_return_if_fail (filename != NULL);
391 }
392
393 /* Handling of RC styles */
394
395 G_DEFINE_TYPE (GtkRcStyle, gtk_rc_style, G_TYPE_OBJECT)
396
397 static void
398 gtk_rc_style_init (GtkRcStyle *style)
399 {
400   GtkRcStylePrivate *priv = GTK_RC_STYLE_GET_PRIVATE (style);
401   guint i;
402
403   style->name = NULL;
404   style->font_desc = NULL;
405
406   for (i = 0; i < 5; i++)
407     {
408       static const GdkColor init_color = { 0, 0, 0, 0, };
409
410       style->bg_pixmap_name[i] = NULL;
411       style->color_flags[i] = 0;
412       style->fg[i] = init_color;
413       style->bg[i] = init_color;
414       style->text[i] = init_color;
415       style->base[i] = init_color;
416     }
417   style->xthickness = -1;
418   style->ythickness = -1;
419   style->rc_properties = NULL;
420
421   style->rc_style_lists = NULL;
422   style->icon_factories = NULL;
423
424   priv->color_hashes = NULL;
425 }
426
427 static void
428 gtk_rc_style_class_init (GtkRcStyleClass *klass)
429 {
430   GObjectClass *object_class = G_OBJECT_CLASS (klass);
431   
432   object_class->finalize = gtk_rc_style_finalize;
433
434   klass->parse = NULL;
435   klass->create_rc_style = gtk_rc_style_real_create_rc_style;
436   klass->merge = gtk_rc_style_real_merge;
437   klass->create_style = gtk_rc_style_real_create_style;
438
439   g_type_class_add_private (object_class, sizeof (GtkRcStylePrivate));
440 }
441
442 static void
443 gtk_rc_style_finalize (GObject *object)
444 {
445   GSList *tmp_list1, *tmp_list2;
446   GtkRcStyle *rc_style;
447   GtkRcStylePrivate *rc_priv;
448   gint i;
449
450   rc_style = GTK_RC_STYLE (object);
451   rc_priv = GTK_RC_STYLE_GET_PRIVATE (rc_style);
452
453   g_free (rc_style->name);
454   if (rc_style->font_desc)
455     pango_font_description_free (rc_style->font_desc);
456       
457   for (i = 0; i < 5; i++)
458     g_free (rc_style->bg_pixmap_name[i]);
459   
460   /* Now remove all references to this rc_style from
461    * realized_style_ht
462    */
463   tmp_list1 = rc_style->rc_style_lists;
464   while (tmp_list1)
465     {
466       GSList *rc_styles = tmp_list1->data;
467       GtkStyle *style = g_hash_table_lookup (realized_style_ht, rc_styles);
468       g_object_unref (style);
469
470       /* Remove the list of styles from the other rc_styles
471        * in the list
472        */
473       tmp_list2 = rc_styles;
474       while (tmp_list2)
475         {
476           GtkRcStyle *other_style = tmp_list2->data;
477
478           if (other_style != rc_style)
479             other_style->rc_style_lists = g_slist_remove_all (other_style->rc_style_lists,
480                                                               rc_styles);
481           tmp_list2 = tmp_list2->next;
482         }
483
484       /* And from the hash table itself
485        */
486       g_hash_table_remove (realized_style_ht, rc_styles);
487       g_slist_free (rc_styles);
488
489       tmp_list1 = tmp_list1->next;
490     }
491   g_slist_free (rc_style->rc_style_lists);
492
493   if (rc_style->rc_properties)
494     {
495       guint i;
496
497       for (i = 0; i < rc_style->rc_properties->len; i++)
498         {
499           GtkRcProperty *node = &g_array_index (rc_style->rc_properties, GtkRcProperty, i);
500
501           g_free (node->origin);
502           g_value_unset (&node->value);
503         }
504       g_array_free (rc_style->rc_properties, TRUE);
505       rc_style->rc_properties = NULL;
506     }
507
508   g_slist_foreach (rc_style->icon_factories, (GFunc) g_object_unref, NULL);
509   g_slist_free (rc_style->icon_factories);
510
511   g_slist_foreach (rc_priv->color_hashes, (GFunc) g_hash_table_unref, NULL);
512   g_slist_free (rc_priv->color_hashes);
513
514   G_OBJECT_CLASS (gtk_rc_style_parent_class)->finalize (object);
515 }
516
517 GtkRcStyle *
518 gtk_rc_style_new (void)
519 {
520   GtkRcStyle *style;
521   
522   style = g_object_new (GTK_TYPE_RC_STYLE, NULL);
523   
524   return style;
525 }
526
527 /**
528  * gtk_rc_style_copy:
529  * @orig: the style to copy
530  *
531  * Makes a copy of the specified #GtkRcStyle. This function
532  * will correctly copy an RC style that is a member of a class
533  * derived from #GtkRcStyle.
534  *
535  * Return value: (transfer full): the resulting #GtkRcStyle
536  **/
537 GtkRcStyle *
538 gtk_rc_style_copy (GtkRcStyle *orig)
539 {
540   GtkRcStyle *style;
541
542   g_return_val_if_fail (GTK_IS_RC_STYLE (orig), NULL);
543   
544   style = GTK_RC_STYLE_GET_CLASS (orig)->create_rc_style (orig);
545   GTK_RC_STYLE_GET_CLASS (style)->merge (style, orig);
546
547   return style;
548 }
549
550 static GtkRcStyle *
551 gtk_rc_style_real_create_rc_style (GtkRcStyle *style)
552 {
553   return g_object_new (G_OBJECT_TYPE (style), NULL);
554 }
555
556 static gint
557 gtk_rc_properties_cmp (gconstpointer bsearch_node1,
558                        gconstpointer bsearch_node2)
559 {
560   const GtkRcProperty *prop1 = bsearch_node1;
561   const GtkRcProperty *prop2 = bsearch_node2;
562
563   if (prop1->type_name == prop2->type_name)
564     return prop1->property_name < prop2->property_name ? -1 : prop1->property_name == prop2->property_name ? 0 : 1;
565   else
566     return prop1->type_name < prop2->type_name ? -1 : 1;
567 }
568
569 static void
570 insert_rc_property (GtkRcStyle    *style,
571                     GtkRcProperty *property,
572                     gboolean       replace)
573 {
574   guint i;
575   GtkRcProperty *new_property = NULL;
576   GtkRcProperty key = { 0, 0, NULL, { 0, }, };
577
578   key.type_name = property->type_name;
579   key.property_name = property->property_name;
580
581   if (!style->rc_properties)
582     style->rc_properties = g_array_new (FALSE, FALSE, sizeof (GtkRcProperty));
583
584   i = 0;
585   while (i < style->rc_properties->len)
586     {
587       gint cmp = gtk_rc_properties_cmp (&key, &g_array_index (style->rc_properties, GtkRcProperty, i));
588
589       if (cmp == 0)
590         {
591           if (replace)
592             {
593               new_property = &g_array_index (style->rc_properties, GtkRcProperty, i);
594               
595               g_free (new_property->origin);
596               g_value_unset (&new_property->value);
597               
598               *new_property = key;
599               break;
600             }
601           else
602             return;
603         }
604       else if (cmp < 0)
605         break;
606
607       i++;
608     }
609
610   if (!new_property)
611     {
612       g_array_insert_val (style->rc_properties, i, key);
613       new_property = &g_array_index (style->rc_properties, GtkRcProperty, i);
614     }
615
616   new_property->origin = g_strdup (property->origin);
617   g_value_init (&new_property->value, G_VALUE_TYPE (&property->value));
618   g_value_copy (&property->value, &new_property->value);
619 }
620
621 static void
622 gtk_rc_style_real_merge (GtkRcStyle *dest,
623                          GtkRcStyle *src)
624 {
625   gint i;
626
627   for (i = 0; i < 5; i++)
628     {
629       if (!dest->bg_pixmap_name[i] && src->bg_pixmap_name[i])
630         dest->bg_pixmap_name[i] = g_strdup (src->bg_pixmap_name[i]);
631       
632       if (!(dest->color_flags[i] & GTK_RC_FG) && 
633           src->color_flags[i] & GTK_RC_FG)
634         {
635           dest->fg[i] = src->fg[i];
636           dest->color_flags[i] |= GTK_RC_FG;
637         }
638       if (!(dest->color_flags[i] & GTK_RC_BG) && 
639           src->color_flags[i] & GTK_RC_BG)
640         {
641           dest->bg[i] = src->bg[i];
642           dest->color_flags[i] |= GTK_RC_BG;
643         }
644       if (!(dest->color_flags[i] & GTK_RC_TEXT) && 
645           src->color_flags[i] & GTK_RC_TEXT)
646         {
647           dest->text[i] = src->text[i];
648           dest->color_flags[i] |= GTK_RC_TEXT;
649         }
650       if (!(dest->color_flags[i] & GTK_RC_BASE) && 
651           src->color_flags[i] & GTK_RC_BASE)
652         {
653           dest->base[i] = src->base[i];
654           dest->color_flags[i] |= GTK_RC_BASE;
655         }
656     }
657
658   if (dest->xthickness < 0 && src->xthickness >= 0)
659     dest->xthickness = src->xthickness;
660   if (dest->ythickness < 0 && src->ythickness >= 0)
661     dest->ythickness = src->ythickness;
662
663   if (src->font_desc)
664     {
665       if (!dest->font_desc)
666         dest->font_desc = pango_font_description_copy (src->font_desc);
667       else
668         pango_font_description_merge (dest->font_desc, src->font_desc, FALSE);
669     }
670
671   if (src->rc_properties)
672     {
673       guint i;
674
675       for (i = 0; i < src->rc_properties->len; i++)
676         insert_rc_property (dest,
677                             &g_array_index (src->rc_properties, GtkRcProperty, i),
678                             FALSE);
679     }
680 }
681
682 static GtkStyle *
683 gtk_rc_style_real_create_style (GtkRcStyle *rc_style)
684 {
685   return gtk_style_new ();
686 }
687
688 /**
689  * gtk_rc_reset_styles:
690  * @settings: a #GtkSettings
691  * 
692  * This function recomputes the styles for all widgets that use a
693  * particular #GtkSettings object. (There is one #GtkSettings object
694  * per #GdkScreen, see gtk_settings_get_for_screen()); It is useful
695  * when some global parameter has changed that affects the appearance
696  * of all widgets, because when a widget gets a new style, it will
697  * both redraw and recompute any cached information about its
698  * appearance. As an example, it is used when the default font size
699  * set by the operating system changes. Note that this function
700  * doesn't affect widgets that have a style set explicitely on them
701  * with gtk_widget_set_style().
702  *
703  * Since: 2.4
704  **/
705 void
706 gtk_rc_reset_styles (GtkSettings *settings)
707 {
708   gtk_style_context_reset_widgets (_gtk_settings_get_screen (settings));
709 }
710
711 /**
712  * gtk_rc_reparse_all_for_settings:
713  * @settings: a #GtkSettings
714  * @force_load: load whether or not anything changed
715  * 
716  * If the modification time on any previously read file
717  * for the given #GtkSettings has changed, discard all style information
718  * and then reread all previously read RC files.
719  * 
720  * Return value: %TRUE if the files were reread.
721  **/
722 gboolean
723 gtk_rc_reparse_all_for_settings (GtkSettings *settings,
724                                  gboolean     force_load)
725 {
726   return FALSE;
727 }
728
729 /**
730  * gtk_rc_reparse_all:
731  * 
732  * If the modification time on any previously read file for the
733  * default #GtkSettings has changed, discard all style information
734  * and then reread all previously read RC files.
735  * 
736  * Return value:  %TRUE if the files were reread.
737  **/
738 gboolean
739 gtk_rc_reparse_all (void)
740 {
741   return FALSE;
742 }
743
744 /**
745  * gtk_rc_get_style:
746  * @widget: a #GtkWidget
747  *
748  * Finds all matching RC styles for a given widget,
749  * composites them together, and then creates a
750  * #GtkStyle representing the composite appearance.
751  * (GTK+ actually keeps a cache of previously
752  * created styles, so a new style may not be
753  * created.)
754  *
755  * Returns: the resulting style. No refcount is added
756  *   to the returned style, so if you want to save this
757  *   style around, you should add a reference yourself.
758  *
759  * Deprecated:3.0: Use #GtkStyleContext instead
760  **/
761 GtkStyle *
762 gtk_rc_get_style (GtkWidget *widget)
763 {
764   g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
765
766   gtk_widget_ensure_style (widget);
767
768   return gtk_widget_get_style (widget);
769 }
770
771 /**
772  * gtk_rc_get_style_by_paths:
773  * @settings: a #GtkSettings object
774  * @widget_path: (allow-none): the widget path to use when looking up the
775  *     style, or %NULL if no matching against the widget path should be done
776  * @class_path: (allow-none): the class path to use when looking up the style,
777  *     or %NULL if no matching against the class path should be done.
778  * @type: a type that will be used along with parent types of this type
779  *     when matching against class styles, or #G_TYPE_NONE
780  *
781  * Creates up a #GtkStyle from styles defined in a RC file by providing
782  * the raw components used in matching. This function may be useful
783  * when creating pseudo-widgets that should be themed like widgets but
784  * don't actually have corresponding GTK+ widgets. An example of this
785  * would be items inside a GNOME canvas widget.
786  *
787  * The action of gtk_rc_get_style() is similar to:
788  * |[
789  *  gtk_widget_path (widget, NULL, &path, NULL);
790  *  gtk_widget_class_path (widget, NULL, &class_path, NULL);
791  *  gtk_rc_get_style_by_paths (gtk_widget_get_settings (widget),
792  *                             path, class_path,
793  *                             G_OBJECT_TYPE (widget));
794  * ]|
795  *
796  * Return value: (transfer none): A style created by matching with the
797  *     supplied paths, or %NULL if nothing matching was specified and the
798  *     default style should be used. The returned value is owned by GTK+
799  *     as part of an internal cache, so you must call g_object_ref() on
800  *     the returned value if you want to keep a reference to it.
801  *
802  * Deprecated:3.0: Use #GtkStyleContext instead
803  **/
804 GtkStyle *
805 gtk_rc_get_style_by_paths (GtkSettings *settings,
806                            const char  *widget_path,
807                            const char  *class_path,
808                            GType        type)
809 {
810   return NULL;
811 }
812
813 /**
814  * gtk_rc_scanner_new:
815  *
816  * Deprecated:3.0: Use #GtkCssProvider instead
817  */
818 GScanner*
819 gtk_rc_scanner_new (void)
820 {
821   return g_scanner_new (&gtk_rc_scanner_config);
822 }
823
824 /*********************
825  * Parsing functions *
826  *********************/
827
828 static gboolean
829 lookup_color (GtkRcStyle *style,
830               const char *color_name,
831               GdkColor   *color)
832 {
833   GtkRcStylePrivate *priv = GTK_RC_STYLE_GET_PRIVATE (style);
834   GSList *iter;
835
836   for (iter = priv->color_hashes; iter != NULL; iter = iter->next)
837     {
838       GHashTable *hash  = iter->data;
839       GdkColor   *match = g_hash_table_lookup (hash, color_name);
840
841       if (match)
842         {
843           color->red = match->red;
844           color->green = match->green;
845           color->blue = match->blue;
846           return TRUE;
847         }
848     }
849
850   return FALSE;
851 }
852
853 /**
854  * gtk_rc_find_pixmap_in_path:
855  * @settings: a #GtkSettings
856  * @scanner: Scanner used to get line number information for the
857  *   warning message, or %NULL
858  * @pixmap_file: name of the pixmap file to locate.
859  * 
860  * Looks up a file in pixmap path for the specified #GtkSettings.
861  * If the file is not found, it outputs a warning message using
862  * g_warning() and returns %NULL.
863  *
864  * Return value: the filename. 
865  **/
866 gchar*
867 gtk_rc_find_pixmap_in_path (GtkSettings  *settings,
868                             GScanner     *scanner,
869                             const gchar  *pixmap_file)
870 {
871   g_warning (_("Unable to locate image file in pixmap_path: \"%s\""),
872              pixmap_file);
873   return NULL;
874 }
875
876 /**
877  * gtk_rc_find_module_in_path:
878  * @module_file: name of a theme engine
879  * 
880  * Searches for a theme engine in the GTK+ search path. This function
881  * is not useful for applications and should not be used.
882  * 
883  * Return value: The filename, if found (must be freed with g_free()),
884  *   otherwise %NULL.
885  **/
886 gchar*
887 gtk_rc_find_module_in_path (const gchar *module_file)
888 {
889   return _gtk_find_module (module_file, "engines");
890 }
891
892 /**
893  * gtk_rc_parse_state:
894  * @scanner:
895  * @state:
896  *
897  * Deprecated:3.0: Use #GtkCssProvider instead
898  */
899 guint
900 gtk_rc_parse_state (GScanner     *scanner,
901                     GtkStateType *state)
902 {
903   guint old_scope;
904   guint token;
905
906   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
907   g_return_val_if_fail (state != NULL, G_TOKEN_ERROR);
908   
909   /* we don't know where we got called from, so we reset the scope here.
910    * if we bail out due to errors, we *don't* reset the scope, so the
911    * error messaging code can make sense of our tokens.
912    */
913   old_scope = g_scanner_set_scope (scanner, 0);
914   
915   token = g_scanner_get_next_token (scanner);
916   if (token != G_TOKEN_LEFT_BRACE)
917     return G_TOKEN_LEFT_BRACE;
918   
919   token = g_scanner_get_next_token (scanner);
920   switch (token)
921     {
922     case GTK_RC_TOKEN_ACTIVE:
923       *state = GTK_STATE_ACTIVE;
924       break;
925     case GTK_RC_TOKEN_INSENSITIVE:
926       *state = GTK_STATE_INSENSITIVE;
927       break;
928     case GTK_RC_TOKEN_NORMAL:
929       *state = GTK_STATE_NORMAL;
930       break;
931     case GTK_RC_TOKEN_PRELIGHT:
932       *state = GTK_STATE_PRELIGHT;
933       break;
934     case GTK_RC_TOKEN_SELECTED:
935       *state = GTK_STATE_SELECTED;
936       break;
937     default:
938       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_NORMAL;
939     }
940   
941   token = g_scanner_get_next_token (scanner);
942   if (token != G_TOKEN_RIGHT_BRACE)
943     return G_TOKEN_RIGHT_BRACE;
944   
945   g_scanner_set_scope (scanner, old_scope);
946
947   return G_TOKEN_NONE;
948 }
949
950 /**
951  * gtk_rc_parse_priority:
952  * @scanner:
953  * @priority:
954  *
955  * Deprecated:3.0: Use #GtkCssProvider instead
956  */
957 guint
958 gtk_rc_parse_priority (GScanner            *scanner,
959                        GtkPathPriorityType *priority)
960 {
961   guint old_scope;
962   guint token;
963
964   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
965   g_return_val_if_fail (priority != NULL, G_TOKEN_ERROR);
966
967   /* we don't know where we got called from, so we reset the scope here.
968    * if we bail out due to errors, we *don't* reset the scope, so the
969    * error messaging code can make sense of our tokens.
970    */
971   old_scope = g_scanner_set_scope (scanner, 0);
972   
973   token = g_scanner_get_next_token (scanner);
974   if (token != ':')
975     return ':';
976   
977   token = g_scanner_get_next_token (scanner);
978   switch (token)
979     {
980     case GTK_RC_TOKEN_LOWEST:
981       *priority = GTK_PATH_PRIO_LOWEST;
982       break;
983     case GTK_RC_TOKEN_GTK:
984       *priority = GTK_PATH_PRIO_GTK;
985       break;
986     case GTK_RC_TOKEN_APPLICATION:
987       *priority = GTK_PATH_PRIO_APPLICATION;
988       break;
989     case GTK_RC_TOKEN_THEME:
990       *priority = GTK_PATH_PRIO_THEME;
991       break;
992     case GTK_RC_TOKEN_RC:
993       *priority = GTK_PATH_PRIO_RC;
994       break;
995     case GTK_RC_TOKEN_HIGHEST:
996       *priority = GTK_PATH_PRIO_HIGHEST;
997       break;
998     default:
999       return /* G_TOKEN_SYMBOL */ GTK_RC_TOKEN_APPLICATION;
1000     }
1001   
1002   g_scanner_set_scope (scanner, old_scope);
1003
1004   return G_TOKEN_NONE;
1005 }
1006
1007 /**
1008  * gtk_rc_parse_color:
1009  * @scanner: a #GScanner
1010  * @color: a pointer to a #GdkColor structure in which to store the result
1011  *
1012  * Parses a color in the <link linkend="color=format">format</link> expected
1013  * in a RC file. 
1014  *
1015  * Note that theme engines should use gtk_rc_parse_color_full() in 
1016  * order to support symbolic colors.
1017  *
1018  * Returns: %G_TOKEN_NONE if parsing succeeded, otherwise the token
1019  *     that was expected but not found
1020  *
1021  * Deprecated:3.0: Use #GtkCssProvider instead
1022  */
1023 guint
1024 gtk_rc_parse_color (GScanner *scanner,
1025                     GdkColor *color)
1026 {
1027   return gtk_rc_parse_color_full (scanner, NULL, color);
1028 }
1029
1030 /**
1031  * gtk_rc_parse_color_full:
1032  * @scanner: a #GScanner
1033  * @style: (allow-none): a #GtkRcStyle, or %NULL
1034  * @color: a pointer to a #GdkColor structure in which to store the result
1035  *
1036  * Parses a color in the <link linkend="color=format">format</link> expected
1037  * in a RC file. If @style is not %NULL, it will be consulted to resolve
1038  * references to symbolic colors.
1039  *
1040  * Returns: %G_TOKEN_NONE if parsing succeeded, otherwise the token
1041  *     that was expected but not found
1042  *
1043  * Since: 2.12
1044  *
1045  * Deprecated:3.0: Use #GtkCssProvider instead
1046  */
1047 guint
1048 gtk_rc_parse_color_full (GScanner   *scanner,
1049                          GtkRcStyle *style,
1050                          GdkColor   *color)
1051 {
1052   guint token;
1053
1054   g_return_val_if_fail (scanner != NULL, G_TOKEN_ERROR);
1055
1056   /* we don't need to set our own scope here, because
1057    * we don't need own symbols
1058    */
1059   
1060   token = g_scanner_get_next_token (scanner);
1061   switch (token)
1062     {
1063       gint token_int;
1064       GdkColor c1, c2;
1065       gboolean negate;
1066       gdouble l;
1067
1068     case G_TOKEN_LEFT_CURLY:
1069       token = g_scanner_get_next_token (scanner);
1070       if (token == G_TOKEN_INT)
1071         token_int = scanner->value.v_int;
1072       else if (token == G_TOKEN_FLOAT)
1073         token_int = scanner->value.v_float * 65535.0;
1074       else
1075         return G_TOKEN_FLOAT;
1076       color->red = CLAMP (token_int, 0, 65535);
1077       
1078       token = g_scanner_get_next_token (scanner);
1079       if (token != G_TOKEN_COMMA)
1080         return G_TOKEN_COMMA;
1081       
1082       token = g_scanner_get_next_token (scanner);
1083       if (token == G_TOKEN_INT)
1084         token_int = scanner->value.v_int;
1085       else if (token == G_TOKEN_FLOAT)
1086         token_int = scanner->value.v_float * 65535.0;
1087       else
1088         return G_TOKEN_FLOAT;
1089       color->green = CLAMP (token_int, 0, 65535);
1090       
1091       token = g_scanner_get_next_token (scanner);
1092       if (token != G_TOKEN_COMMA)
1093         return G_TOKEN_COMMA;
1094       
1095       token = g_scanner_get_next_token (scanner);
1096       if (token == G_TOKEN_INT)
1097         token_int = scanner->value.v_int;
1098       else if (token == G_TOKEN_FLOAT)
1099         token_int = scanner->value.v_float * 65535.0;
1100       else
1101         return G_TOKEN_FLOAT;
1102       color->blue = CLAMP (token_int, 0, 65535);
1103       
1104       token = g_scanner_get_next_token (scanner);
1105       if (token != G_TOKEN_RIGHT_CURLY)
1106         return G_TOKEN_RIGHT_CURLY;
1107       return G_TOKEN_NONE;
1108       
1109     case G_TOKEN_STRING:
1110       if (!gdk_color_parse (scanner->value.v_string, color))
1111         {
1112           g_scanner_warn (scanner, "Invalid color constant '%s'",
1113                           scanner->value.v_string);
1114           return G_TOKEN_STRING;
1115         }
1116       return G_TOKEN_NONE;
1117
1118     case '@':
1119       token = g_scanner_get_next_token (scanner);
1120       if (token != G_TOKEN_IDENTIFIER)
1121         return G_TOKEN_IDENTIFIER;
1122
1123       if (!style || !lookup_color (style, scanner->value.v_identifier, color))
1124         {
1125           g_scanner_warn (scanner, "Invalid symbolic color '%s'",
1126                           scanner->value.v_identifier);
1127           return G_TOKEN_IDENTIFIER;
1128         }
1129
1130       return G_TOKEN_NONE;
1131
1132     case G_TOKEN_IDENTIFIER:
1133       if (strcmp (scanner->value.v_identifier, "mix") == 0)
1134         {
1135           token = g_scanner_get_next_token (scanner);
1136           if (token != G_TOKEN_LEFT_PAREN)
1137             return G_TOKEN_LEFT_PAREN;
1138
1139           negate = FALSE;
1140           if (g_scanner_peek_next_token (scanner) == '-')
1141             {
1142               g_scanner_get_next_token (scanner); /* eat sign */
1143               negate = TRUE;
1144             }
1145
1146           token = g_scanner_get_next_token (scanner);
1147           if (token != G_TOKEN_FLOAT)
1148             return G_TOKEN_FLOAT;
1149
1150           l = negate ? -scanner->value.v_float : scanner->value.v_float;
1151
1152           token = g_scanner_get_next_token (scanner);
1153           if (token != G_TOKEN_COMMA)
1154             return G_TOKEN_COMMA;
1155
1156           token = gtk_rc_parse_color_full (scanner, style, &c1);
1157           if (token != G_TOKEN_NONE)
1158             return token;
1159
1160           token = g_scanner_get_next_token (scanner);
1161           if (token != G_TOKEN_COMMA)
1162             return G_TOKEN_COMMA;
1163
1164           token = gtk_rc_parse_color_full (scanner, style, &c2);
1165           if (token != G_TOKEN_NONE)
1166             return token;
1167
1168           token = g_scanner_get_next_token (scanner);
1169           if (token != G_TOKEN_RIGHT_PAREN)
1170             return G_TOKEN_RIGHT_PAREN;
1171
1172           color->red   = l * c1.red   + (1.0 - l) * c2.red;
1173           color->green = l * c1.green + (1.0 - l) * c2.green;
1174           color->blue  = l * c1.blue  + (1.0 - l) * c2.blue;
1175
1176           return G_TOKEN_NONE;
1177         }
1178       else if (strcmp (scanner->value.v_identifier, "shade") == 0)
1179         {
1180           token = g_scanner_get_next_token (scanner);
1181           if (token != G_TOKEN_LEFT_PAREN)
1182             return G_TOKEN_LEFT_PAREN;
1183
1184           negate = FALSE;
1185           if (g_scanner_peek_next_token (scanner) == '-')
1186             {
1187               g_scanner_get_next_token (scanner); /* eat sign */
1188               negate = TRUE;
1189             }
1190
1191           token = g_scanner_get_next_token (scanner);
1192           if (token != G_TOKEN_FLOAT)
1193             return G_TOKEN_FLOAT;
1194
1195           l = negate ? -scanner->value.v_float : scanner->value.v_float;
1196
1197           token = g_scanner_get_next_token (scanner);
1198           if (token != G_TOKEN_COMMA)
1199             return G_TOKEN_COMMA;
1200
1201           token = gtk_rc_parse_color_full (scanner, style, &c1);
1202           if (token != G_TOKEN_NONE)
1203             return token;
1204
1205           token = g_scanner_get_next_token (scanner);
1206           if (token != G_TOKEN_RIGHT_PAREN)
1207             return G_TOKEN_RIGHT_PAREN;
1208
1209           _gtk_style_shade (&c1, color, l);
1210
1211           return G_TOKEN_NONE;
1212         }
1213       else if (strcmp (scanner->value.v_identifier, "lighter") == 0 ||
1214                strcmp (scanner->value.v_identifier, "darker") == 0)
1215         {
1216           if (scanner->value.v_identifier[0] == 'l')
1217             l = 1.3;
1218           else
1219             l = 0.7;
1220
1221           token = g_scanner_get_next_token (scanner);
1222           if (token != G_TOKEN_LEFT_PAREN)
1223             return G_TOKEN_LEFT_PAREN;
1224
1225           token = gtk_rc_parse_color_full (scanner, style, &c1);
1226           if (token != G_TOKEN_NONE)
1227             return token;
1228
1229           token = g_scanner_get_next_token (scanner);
1230           if (token != G_TOKEN_RIGHT_PAREN)
1231             return G_TOKEN_RIGHT_PAREN;
1232
1233           _gtk_style_shade (&c1, color, l);
1234
1235           return G_TOKEN_NONE;
1236         }
1237       else
1238         return G_TOKEN_IDENTIFIER;
1239
1240     default:
1241       return G_TOKEN_STRING;
1242     }
1243 }