]> icculus.org git repositories - dana/obconf.git/blob - src/theme.c
fix
[dana/obconf.git] / src / theme.c
1 #include "theme.h"
2 #include "main.h"
3 #include "gettext.h"
4
5 #include <string.h>
6 #include <errno.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <unistd.h>
11 #include <zlib.h>
12 #include <libtar.h>
13
14 static gzFile gzf = NULL;
15
16 #define gtk_msg(type, args...) \
17 {                                                                        \
18     GtkWidget *msgw;                                                     \
19     msgw = gtk_message_dialog_new(GTK_WINDOW(mainwin),                   \
20                                   GTK_DIALOG_DESTROY_WITH_PARENT |       \
21                                   GTK_DIALOG_MODAL,                      \
22                                   type,                                  \
23                                   GTK_BUTTONS_OK,                        \
24                                   args);                                 \
25     gtk_dialog_run(GTK_DIALOG(msgw));                                    \
26     gtk_widget_destroy(msgw);                                            \
27 }
28
29 static int gzopen_frontend(const char *path, int oflags, int mode);
30 static int gzclose_frontend(int nothing);
31 static ssize_t gzread_frontend(int nothing, void *buf, size_t s);
32 static ssize_t gzwrite_frontend(int nothing, const void *buf, size_t s);
33 static gchar *get_theme_dir();
34 static gboolean change_dir(const gchar *dir);
35 static gboolean install_theme_to(gchar *theme, gchar *file, gchar *to);
36 static gchar* name_from_file(const gchar *path);
37 static gchar* name_from_dir(const gchar *dir);
38 static gboolean create_theme_archive(gchar *dir, gchar *name, gchar *to);
39
40 tartype_t funcs = {
41     (openfunc_t) gzopen_frontend,
42     (closefunc_t) gzclose_frontend,
43     (readfunc_t) gzread_frontend,
44     (writefunc_t) gzwrite_frontend
45 };
46
47 gchar* theme_install(gchar *path)
48 {
49     gchar *dest;
50     gchar *curdir;
51     gchar *name;
52
53     if (!(dest = get_theme_dir()))
54         return NULL;
55
56     curdir = g_get_current_dir();
57     if (!change_dir(dest)) {
58         g_free(curdir);
59         return NULL;
60     }
61
62     if (!(name = name_from_file(path)))
63         return NULL;
64
65     if (install_theme_to(name, path, dest)) {
66         gtk_msg(GTK_MESSAGE_INFO, _("\"%s\" was installed to %s"), name, dest);
67     } else {
68         g_free(name);
69         name = NULL;
70     }
71
72     g_free(dest);
73
74     change_dir(curdir);
75     g_free(curdir);
76
77     return name;
78 }
79
80 void theme_archive(gchar *path)
81 {
82     gchar *name;
83     gchar *dest;
84
85     if (!(name = name_from_dir(path)))
86         return;
87
88     {
89         gchar *file;
90         file = g_strdup_printf("%s.obt", name);
91         dest = g_build_path(G_DIR_SEPARATOR_S,
92                             g_get_current_dir(), file, NULL);
93         g_free(file);
94     }
95
96     if (create_theme_archive(path, name, dest))
97         gtk_msg(GTK_MESSAGE_INFO, _("\"%s\" was successfully created"),
98                 dest);
99
100     g_free(dest);
101     g_free(name);
102 }
103
104 static gboolean create_theme_archive(gchar *dir, gchar *name, gchar *to)
105 {
106     TAR *t;
107     gint r;
108
109     if (tar_open(&t, to, &funcs, O_WRONLY | O_CREAT, 0666, TAR_GNU) == -1) {
110         gtk_msg(GTK_MESSAGE_ERROR,
111                 _("Unable to create the file \"%s\": %s"),
112                 to, strerror(errno));
113         return;
114     }
115
116     r = tar_append_tree(t, dir, name);
117     tar_close(t);
118
119     if (r != 0) {
120         gtk_msg(GTK_MESSAGE_ERROR,
121                 _("Unable to create the theme archive \"%s\": %s"),
122                 to, strerror(errno));
123     }
124
125     return r == 0;
126 }
127
128 static gchar *get_theme_dir()
129 {
130     gchar *dir;
131     gint r;
132
133     dir = g_build_path(G_DIR_SEPARATOR_S, g_get_home_dir(), ".themes", NULL);
134     r = mkdir(dir, 0777);
135     if (r == -1 && errno != EEXIST) {
136         gtk_msg(GTK_MESSAGE_ERROR,
137                 _("Unable to create directory \"%s\": %s"),
138                 dir, strerror(errno));
139         g_free(dir);
140         dir = NULL;
141     }
142
143     return dir;
144 }
145
146 static gchar* name_from_dir(const gchar *dir)
147 {
148     gchar *rc;
149     struct stat st;
150     gboolean r;
151
152     rc = g_build_path(G_DIR_SEPARATOR_S, dir, "openbox-3", "themerc", NULL);
153
154     r = (stat(rc, &st) == 0 && S_ISREG(st.st_mode));
155     g_free(rc);
156
157     if (!r) {
158         gtk_msg(GTK_MESSAGE_ERROR,
159                 _("\"%s\" does not appear to be a valid Openbox theme directory"),
160                 dir);
161         return NULL;
162     }
163     return g_path_get_basename(dir);
164 }
165
166 static gchar* name_from_file(const gchar *path)
167 {
168     /* decipher the theme name from the file name */
169     gchar *fname = g_path_get_basename(path);
170     gint len = strlen(fname);
171     gchar *name = NULL;
172
173     if (len > 4 &&
174         (fname[len-4] == '.' && fname[len-3] == 'o' &&
175          fname[len-2] == 'b' && fname[len-1] == 't'))
176     {
177         fname[len-4] = '\0';
178         name = g_strdup(fname);
179         fname[len-4] = '.';
180     }
181
182     if (name == NULL)
183         gtk_msg(GTK_MESSAGE_ERROR,
184                 _("Unable to determine the theme's name from \"%s\".  File name should be ThemeName.obt."), fname);
185
186     return name;
187 }
188
189 static gboolean change_dir(const gchar *dir)
190 {
191     if (chdir(dir) == -1) {
192         gtk_msg(GTK_MESSAGE_ERROR, _("Unable to move to directory \"%s\": %s"),
193                 dir, strerror(errno));
194         return FALSE;
195     }
196     return TRUE;
197 }
198
199 static gboolean install_theme_to(gchar *theme, gchar *file, gchar *to)
200 {
201     TAR *t;
202     gchar *glob;
203     gint r;
204
205     if (tar_open(&t, file, &funcs, O_RDONLY, 0666, TAR_GNU) == -1) {
206         gtk_msg(GTK_MESSAGE_ERROR,
207                 _("Unable to open the file \"%s\": %s"),
208                 file, strerror(errno));
209         return FALSE;
210     }
211
212     glob = g_strdup_printf("%s/openbox-3/*", theme);
213     r = tar_extract_glob(t, glob, to);
214     g_free(glob);
215
216     tar_close(t);
217
218     if (r != 0)
219         gtk_msg(GTK_MESSAGE_ERROR,
220                 _("Unable to extract the file \"%s\".\nPlease ensure that \"%s\" is writable and that the file is a valid Openbox theme archive"),
221                 file, strerror(errno));
222
223     return r == 0;
224 }
225
226 static int gzopen_frontend(const char *path, int oflags, int mode)
227 {
228     int fd;
229     const char *gzflags;
230
231     if ((oflags & O_ACCMODE) == O_RDONLY)
232         gzflags = "rb";
233     else if ((oflags & O_ACCMODE) == O_WRONLY)
234         gzflags = "wb";
235     else
236         g_assert_not_reached();
237
238     if ((fd = open(path, oflags, mode)) < 0) return -1;
239     if (!(gzf = gzdopen(fd, gzflags))) return -1;
240     return 1;
241 }
242
243 static int gzclose_frontend(int nothing)
244 {
245     g_return_val_if_fail(gzf != NULL, 0);
246     return gzclose(gzf);
247 }
248
249 static ssize_t gzread_frontend(int nothing, void *buf, size_t s)
250 {
251     return gzread(gzf, buf, s);
252 }
253
254 static ssize_t gzwrite_frontend(int nothing, const void *buf, size_t s)
255 {
256     return gzwrite(gzf, buf, s);
257 }
258