1 /**********************************************************************
2  Freeciv - Copyright (C) 2005 The Freeciv Team
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2, or (at your option)
6    any later version.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 ***********************************************************************/
13 #ifdef HAVE_CONFIG_H
14 #include <fc_config.h>
15 #endif
16 
17 #include <dirent.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <unistd.h>
21 
22 #include <gtk/gtk.h>
23 
24 /* utility */
25 #include "mem.h"
26 #include "string_vector.h"
27 #include "support.h"
28 
29 /* client */
30 #include "themes_common.h"
31 
32 /* gui-gtk-3.0 */
33 #include "gui_main.h"
34 
35 #include "themes_g.h"
36 
37 /*****************************************************************************
38   Loads a gtk theme directory/theme_name
39 *****************************************************************************/
gui_load_theme(const char * directory,const char * theme_name)40 void gui_load_theme(const char *directory, const char *theme_name)
41 {
42   static GtkCssProvider *fc_css_provider = NULL;
43   GError *error = NULL;
44   char buf[strlen(directory) + strlen(theme_name) + 32];
45 
46   if (fc_css_provider == NULL) {
47     fc_css_provider = gtk_css_provider_new();
48     gtk_style_context_add_provider(gtk_widget_get_style_context(toplevel),
49         GTK_STYLE_PROVIDER(fc_css_provider),
50         GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
51   }
52 
53   /* Gtk theme is a directory containing gtk-3.0/gtk.css file */
54   fc_snprintf(buf, sizeof(buf), "%s/%s/gtk-3.0/gtk.css", directory,
55               theme_name);
56 
57   gtk_css_provider_load_from_file(fc_css_provider, g_file_new_for_path(buf), &error);
58 
59   if (error) {
60     g_warning("%s\n", error->message);
61   }
62 
63   gtk_style_context_invalidate(gtk_widget_get_style_context(toplevel));
64 }
65 
66 /*****************************************************************************
67   Clears a theme (sets default system theme)
68 *****************************************************************************/
gui_clear_theme(void)69 void gui_clear_theme(void)
70 {
71   bool theme_loaded;
72 
73   /* try to load user defined theme */
74   theme_loaded = load_theme(gui_options.gui_gtk3_default_theme_name);
75 
76   /* no user defined theme loaded -> try to load Freeciv default theme */
77   if (!theme_loaded) {
78     theme_loaded = load_theme(FC_GTK3_DEFAULT_THEME_NAME);
79     if (theme_loaded) {
80       sz_strlcpy(gui_options.gui_gtk3_default_theme_name, FC_GTK3_DEFAULT_THEME_NAME);
81     }
82   }
83 
84   /* still no theme loaded -> load system default theme */
85   if (!theme_loaded) {
86     static GtkCssProvider *default_provider = NULL;
87 
88     if (default_provider == NULL) {
89       default_provider = gtk_css_provider_new();
90     }
91     gtk_style_context_add_provider_for_screen(
92         gtk_widget_get_screen(toplevel),
93         GTK_STYLE_PROVIDER(default_provider),
94         GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
95   }
96 }
97 
98 /*****************************************************************************
99   Each gui has its own themes directories.
100   For gtk3 these are:
101   - /usr/share/themes
102   - ~/.themes
103   Returns an array containing these strings and sets array size in count.
104   The caller is responsible for freeing the array and the paths.
105 *****************************************************************************/
get_gui_specific_themes_directories(int * count)106 char **get_gui_specific_themes_directories(int *count)
107 {
108   gchar *standard_dir;
109   char *home_dir;
110   const struct strvec *data_dirs = get_data_dirs();
111   char **directories = fc_malloc((2 + strvec_size(data_dirs))
112                                  * sizeof(char *));
113 
114   *count = 0;
115 
116   /* Freeciv-specific GTK3 themes directories */
117   strvec_iterate(data_dirs, dir_name) {
118     char buf[strlen(dir_name) + strlen("/themes/gui-gtk-3.0") + 1];
119 
120     fc_snprintf(buf, sizeof(buf), "%s/themes/gui-gtk-3.0", dir_name);
121 
122     directories[(*count)++] = fc_strdup(buf);
123   } strvec_iterate_end;
124 
125   /* standard GTK+ themes directory */
126 #ifdef CROSSER
127   standard_dir = "../share/themes";
128 #else  /* CROSSER */
129   standard_dir = "/usr/share/themes";
130 #endif /* CROSSER */
131   directories[(*count)++] = fc_strdup(standard_dir);
132 
133   /* user GTK+ themes directory (~/.themes) */
134   home_dir = user_home_dir();
135   if (home_dir) {
136     char buf[strlen(home_dir) + 16];
137 
138     fc_snprintf(buf, sizeof(buf), "%s/.themes/", home_dir);
139     directories[(*count)++] = fc_strdup(buf);
140   }
141 
142   return directories;
143 }
144 
145 /*****************************************************************************
146   Return an array of names of usable themes in the given directory.
147   Array size is stored in count.
148   Useable theme for gtk+ is a directory which contains file gtk-3.0/gtk.css.
149   The caller is responsible for freeing the array and the names
150 *****************************************************************************/
get_useable_themes_in_directory(const char * directory,int * count)151 char **get_useable_themes_in_directory(const char *directory, int *count)
152 {
153   DIR *dir;
154   struct dirent *entry;
155 
156   char **theme_names = fc_malloc(sizeof(char *) * 2);
157   /* Allocated memory size */
158   int t_size = 2;
159 
160 
161   *count = 0;
162 
163   dir = fc_opendir(directory);
164   if (!dir) {
165     /* This isn't directory or we can't list it */
166     return theme_names;
167   }
168 
169   while ((entry = readdir(dir))) {
170     char buf[strlen(directory) + strlen(entry->d_name) + 32];
171     struct stat stat_result;
172 
173     fc_snprintf(buf, sizeof(buf),
174                 "%s/%s/gtk-3.0/gtk.css", directory, entry->d_name);
175 
176     if (fc_stat(buf, &stat_result) != 0) {
177       /* File doesn't exist */
178       continue;
179     }
180 
181     if (!S_ISREG(stat_result.st_mode)) {
182       /* Not a regular file */
183       continue;
184     }
185 
186     /* Otherwise it's ok */
187 
188     /* Increase array size if needed */
189     if (*count == t_size) {
190       theme_names = fc_realloc(theme_names, t_size * 2 * sizeof(char *));
191       t_size *= 2;
192     }
193 
194     theme_names[*count] = fc_strdup(entry->d_name);
195     (*count)++;
196   }
197 
198   closedir(dir);
199 
200   return theme_names;
201 }
202