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