1 /*
2  * Copyright (C) 1999 Dave Camp <dave@davec.dhs.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program 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
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #include <config.h>
20 #include <string.h>
21 #include <ctype.h>
22 #include <gtk/gtk.h>
23 #include <gio/gio.h>
24 #include "geyes.h"
25 
26 #define GET_WIDGET(x) (GTK_WIDGET (gtk_builder_get_object (builder, (x))))
27 #define NUM_THEME_DIRECTORIES 2
28 
29 static char *theme_directories[NUM_THEME_DIRECTORIES];
30 
31 enum {
32     COL_THEME_DIR = 0,
33     COL_THEME_NAME,
34     TOTAL_COLS
35 };
36 
37 void
theme_dirs_create(void)38 theme_dirs_create (void)
39 {
40     static gboolean themes_created = FALSE;
41 
42     if (themes_created == TRUE)
43         return;
44 
45     theme_directories[0] = g_build_filename (GEYES_THEMES_DIR, NULL);
46 
47     theme_directories[1] = g_build_filename (g_get_user_config_dir (), "mate",
48                                              "geyes-themes", NULL);
49 
50     themes_created = TRUE;
51 }
52 
53 static void
parse_theme_file(EyesApplet * eyes_applet,FILE * theme_file)54 parse_theme_file (EyesApplet *eyes_applet,
55                   FILE       *theme_file)
56 {
57     gchar line_buf[512]; /* prolly overkill */
58     gchar *token;
59 
60     if (fgets (line_buf, 512, theme_file) == NULL)
61         g_debug ("fgets error");
62 
63     while (!feof (theme_file)) {
64         token = strtok (line_buf, "=");
65         if (strncmp (token, "wall-thickness", strlen ("wall-thickness")) == 0) {
66             token += strlen ("wall-thickness");
67             while (!isdigit (*token)) {
68                 token++;
69             }
70             sscanf (token, "%d", &eyes_applet->wall_thickness);
71         } else if (strncmp (token, "num-eyes", strlen ("num-eyes")) == 0) {
72             token += strlen ("num-eyes");
73             while (!isdigit (*token)) {
74                 token++;
75             }
76             sscanf (token, "%" G_GSIZE_FORMAT, &eyes_applet->num_eyes);
77             if (eyes_applet->num_eyes > MAX_EYES)
78                 eyes_applet->num_eyes = MAX_EYES;
79         } else if (strncmp (token, "eye-pixmap", strlen ("eye-pixmap")) == 0) {
80             token = strtok (NULL, "\"");
81             token = strtok (NULL, "\"");
82             if (eyes_applet->eye_filename != NULL)
83                 g_free (eyes_applet->eye_filename);
84             eyes_applet->eye_filename
85                 = g_build_filename (eyes_applet->theme_dir, token, NULL);
86         } else if (strncmp (token, "pupil-pixmap", strlen ("pupil-pixmap")) == 0) {
87             token = strtok (NULL, "\"");
88             token = strtok (NULL, "\"");
89             if (eyes_applet->pupil_filename != NULL)
90                 g_free (eyes_applet->pupil_filename);
91             eyes_applet->pupil_filename
92                 = g_build_filename (eyes_applet->theme_dir, token, NULL);
93         }
94         if (fgets (line_buf, 512, theme_file) == NULL)
95             g_debug ("fgets error");
96     }
97 }
98 
99 int
load_theme(EyesApplet * eyes_applet,const gchar * theme_dir)100 load_theme (EyesApplet  *eyes_applet,
101             const gchar *theme_dir)
102 {
103     GtkWidget *dialog;
104     FILE      *theme_file;
105     gchar     *file_name;
106 
107     eyes_applet->theme_dir = g_strdup (theme_dir);
108 
109     file_name = g_build_filename (theme_dir, "config", NULL);
110     if ((theme_file = fopen (file_name, "r")) == NULL) {
111         g_free (eyes_applet->theme_dir);
112         eyes_applet->theme_dir = g_build_filename (GEYES_THEMES_DIR, "Default-tiny", NULL);
113         theme_file = fopen (GEYES_THEMES_DIR "Default-tiny/config", "r");
114     }
115     g_free (file_name);
116 
117     /* if it's still NULL we've got a major problem */
118     if (theme_file == NULL) {
119         dialog = gtk_message_dialog_new_with_markup (NULL,
120                                                      GTK_DIALOG_DESTROY_WITH_PARENT,
121                                                      GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
122                                                      "<b>%s</b>\n\n%s",
123                                                      _("Can not launch the eyes applet."),
124                                                      _("There was a fatal error while trying to load the theme."));
125 
126         gtk_dialog_run (GTK_DIALOG (dialog));
127         gtk_widget_destroy (dialog);
128 
129         gtk_widget_destroy (GTK_WIDGET (eyes_applet->applet));
130 
131         return FALSE;
132     }
133 
134     parse_theme_file (eyes_applet, theme_file);
135     fclose (theme_file);
136 
137     eyes_applet->theme_name = g_strdup (theme_dir);
138 
139     if (eyes_applet->eye_image)
140         g_object_unref (eyes_applet->eye_image);
141 
142     eyes_applet->eye_image
143         = gdk_pixbuf_new_from_file (eyes_applet->eye_filename,
144                                     NULL);
145 
146     if (eyes_applet->pupil_image)
147         g_object_unref (eyes_applet->pupil_image);
148 
149     eyes_applet->pupil_image
150         = gdk_pixbuf_new_from_file (eyes_applet->pupil_filename,
151                                     NULL);
152 
153     eyes_applet->eye_height = gdk_pixbuf_get_height (eyes_applet->eye_image);
154     eyes_applet->eye_width = gdk_pixbuf_get_width (eyes_applet->eye_image);
155     eyes_applet->pupil_height = gdk_pixbuf_get_height (eyes_applet->pupil_image);
156     eyes_applet->pupil_width = gdk_pixbuf_get_width (eyes_applet->pupil_image);
157 
158     return TRUE;
159 }
160 
161 static void
destroy_theme(EyesApplet * eyes_applet)162 destroy_theme (EyesApplet *eyes_applet)
163 {
164     /* Dunno about this - to unref or not to unref? */
165     if (eyes_applet->eye_image != NULL) {
166         g_object_unref (eyes_applet->eye_image);
167         eyes_applet->eye_image = NULL;
168     }
169     if (eyes_applet->pupil_image != NULL) {
170         g_object_unref (eyes_applet->pupil_image);
171         eyes_applet->pupil_image = NULL;
172     }
173 
174     g_free (eyes_applet->theme_dir);
175     g_free (eyes_applet->theme_name);
176 }
177 
178 static void
theme_selected_cb(GtkTreeSelection * selection,gpointer data)179 theme_selected_cb (GtkTreeSelection *selection,
180                    gpointer          data)
181 {
182     EyesApplet *eyes_applet = data;
183     GtkTreeModel *model;
184     GtkTreeIter iter;
185     gchar *theme;
186 
187     if (!gtk_tree_selection_get_selected (selection, &model, &iter))
188         return;
189 
190     gtk_tree_model_get (model, &iter, COL_THEME_DIR, &theme, -1);
191 
192     g_return_if_fail (theme);
193 
194     if (!g_ascii_strncasecmp (theme, eyes_applet->theme_dir,
195                               strlen (theme))) {
196         g_free (theme);
197         return;
198     }
199 
200     destroy_eyes (eyes_applet);
201     destroy_theme (eyes_applet);
202     load_theme (eyes_applet, theme);
203     setup_eyes (eyes_applet);
204 
205     g_settings_set_string (eyes_applet->settings,
206                            GEYES_SETTINGS_THEME_PATH_KEY,
207                            theme);
208 
209     g_free (theme);
210 }
211 
212 static void
phelp_cb(GtkDialog * dialog)213 phelp_cb (GtkDialog *dialog)
214 {
215     GError *error = NULL;
216 
217     gtk_show_uri_on_window (GTK_WINDOW (dialog), "help:mate-geyes/geyes-settings",
218                             gtk_get_current_event_time (),
219                             &error);
220 
221     if (error) {
222         GtkWidget *error_dialog
223             = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
224                                       GTK_MESSAGE_ERROR,
225                                       GTK_BUTTONS_CLOSE,
226                                       _("There was an error displaying help: %s"),
227                                       error->message);
228         g_signal_connect (error_dialog, "response",
229                           G_CALLBACK (gtk_widget_destroy),
230                           NULL);
231         gtk_window_set_resizable (GTK_WINDOW (error_dialog), FALSE);
232         gtk_window_set_screen (GTK_WINDOW (error_dialog),
233                                gtk_widget_get_screen (GTK_WIDGET (dialog)));
234         gtk_widget_show (error_dialog);
235         g_clear_error (&error);
236     }
237 }
238 
239 static void
presponse_cb(GtkDialog * dialog,gint id,gpointer data)240 presponse_cb (GtkDialog *dialog,
241               gint       id,
242               gpointer   data)
243 {
244     EyesApplet *eyes_applet = data;
245     if (id == GTK_RESPONSE_HELP) {
246         phelp_cb (dialog);
247         return;
248     }
249 
250     gtk_widget_destroy (GTK_WIDGET (dialog));
251 
252     eyes_applet->prop_box.pbox = NULL;
253 }
254 
255 void
properties_cb(GtkAction * action,EyesApplet * eyes_applet)256 properties_cb (GtkAction  *action,
257                EyesApplet *eyes_applet)
258 {
259     GtkBuilder *builder;
260     GtkWidget *tree;
261     GtkWidget *label;
262     GtkListStore *model;
263     GtkTreeViewColumn *column;
264     GtkCellRenderer *cell;
265     GtkTreeIter iter;
266     GDir *dfd;
267     const char *dp;
268     GError *error = NULL;
269     int i;
270 
271     if (eyes_applet->prop_box.pbox) {
272         gtk_window_set_screen (GTK_WINDOW (eyes_applet->prop_box.pbox),
273                                gtk_widget_get_screen (GTK_WIDGET (eyes_applet->applet)));
274 
275         gtk_window_present (GTK_WINDOW (eyes_applet->prop_box.pbox));
276         return;
277     }
278 
279     builder = gtk_builder_new_from_resource (GEYES_RESOURCE_PATH "themes.ui");
280 
281     eyes_applet->prop_box.pbox = GET_WIDGET("preferences_dialog");
282     tree = GET_WIDGET("themes_treeview");
283     label = GET_WIDGET("select_theme_label");
284 
285     model = gtk_list_store_new (TOTAL_COLS, G_TYPE_STRING, G_TYPE_STRING);
286     gtk_tree_view_set_model (GTK_TREE_VIEW (tree), GTK_TREE_MODEL (model));
287     cell = gtk_cell_renderer_text_new ();
288     column = gtk_tree_view_column_new_with_attributes ("not used", cell, "text",
289                                                        COL_THEME_NAME,
290                                                        NULL);
291     gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
292 
293     if (!g_settings_is_writable (eyes_applet->settings, GEYES_SETTINGS_THEME_PATH_KEY)) {
294         gtk_widget_set_sensitive (tree, FALSE);
295         gtk_widget_set_sensitive (label, FALSE);
296     }
297 
298     for (i = 0; i < NUM_THEME_DIRECTORIES; i++) {
299         dfd = g_dir_open (theme_directories[i], 0, &error);
300         if (error) {
301             g_debug ("Could not open the folder: %s", error->message);
302             g_clear_error (&error);
303             continue;
304         }
305         while ((dp = g_dir_read_name (dfd)) != NULL) {
306             if (dp[0] != '.') {
307                 gchar *theme_dir;
308 
309                 theme_dir = g_build_filename (theme_directories[i], dp, NULL);
310                 gtk_list_store_append (model, &iter);
311                 gtk_list_store_set (model, &iter,
312                                     COL_THEME_DIR, theme_dir,
313                                     COL_THEME_NAME, dp,
314                                     -1);
315 
316                 if (!g_ascii_strncasecmp (eyes_applet->theme_dir, theme_dir,
317                                           strlen (theme_dir))) {
318                     GtkTreePath *path;
319 
320                     path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter);
321                     gtk_tree_view_set_cursor (GTK_TREE_VIEW (tree),
322                                               path, NULL, FALSE);
323                     gtk_tree_path_free (path);
324                 }
325                 g_free (theme_dir);
326             }
327         }
328         g_dir_close (dfd);
329     }
330     g_object_unref (model);
331 
332     /* signals */
333     gtk_builder_add_callback_symbols (builder, "on_preferences_dialog_response",
334                                       G_CALLBACK (presponse_cb),
335                                       "on_themes_treeselection_changed",
336                                       G_CALLBACK (theme_selected_cb),
337                                       NULL);
338     gtk_builder_connect_signals (builder, eyes_applet);
339 
340     g_object_unref (builder);
341 
342     gtk_widget_show_all (eyes_applet->prop_box.pbox);
343 
344     return;
345 }
346