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