Reading name from desktop entry file is now done by desktop_entry_read_keyfile.
[AutoStart.git] / src / xxdgautostart.c
blob038b5f35f3b75ce93d497551b8a4ec168ec54d36
1 /*
2 * By Tony Houghton, <h@realh.co.uk>.
3 */
5 #include "config.h"
7 #include <ctype.h>
8 #include <stdlib.h>
9 #include <string.h>
11 #include <unistd.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <fcntl.h>
16 #include "dialogs.h"
17 #include "xxdgautostart.h"
19 DesktopEntry *xdesktop_entry_new(const char *pathname, const char *basename,
20 gboolean savable)
22 DesktopEntry *xde = g_new0(DesktopEntry, 1);
24 if (!desktop_entry_load(xde, pathname, basename, TRUE, savable))
26 desktop_entry_delete(xde);
27 xde = NULL;
29 return xde;
32 gboolean xdesktop_entry_get_only_in_rox(DesktopEntry *xde)
34 return (xde->only_show_in && xde->only_show_in[0] &&
35 !strcmp(xde->only_show_in[0], "ROX") &&
36 (!xde->only_show_in[1] || !xde->only_show_in[1][0]));
39 gboolean xdesktop_entry_can_set_only_in_rox(DesktopEntry *xde)
41 return xdesktop_entry_get_only_in_rox(xde) ||
42 (desktop_entry_get_show_in_rox(xde) &&
43 str_v_is_empty(xde->only_show_in));
46 static int str_v_len(char const **str_v)
48 int n;
50 for (n = 0; str_v && str_v[n]; ++n);
51 return n;
54 static void update_kf_from_show_ins(DesktopEntry *xde)
56 if (!xde->only_show_in)
58 g_key_file_remove_key(xde->kf, _DE, "OnlyShowIn", NULL);
60 else
62 g_key_file_set_string_list(xde->kf, _DE, "OnlyShowIn",
63 (char const **) xde->only_show_in,
64 str_v_len((char const **) xde->only_show_in));
66 if (!xde->not_show_in)
68 g_key_file_remove_key(xde->kf, _DE, "NotShowIn", NULL);
70 else
72 g_key_file_set_string_list(xde->kf, _DE, "NotShowIn",
73 (char const **) xde->not_show_in,
74 str_v_len((char const **) xde->not_show_in));
78 void xdesktop_entry_set_only_in_rox(DesktopEntry *xde, gboolean state)
80 g_strfreev(xde->only_show_in);
81 xde->only_show_in = NULL;
82 g_strfreev(xde->not_show_in);
83 xde->not_show_in = NULL;
84 if (state)
86 xde->only_show_in = g_new0(char *, 2);
87 xde->only_show_in[0] = g_strdup("ROX");
89 update_kf_from_show_ins(xde);
92 static void remove_rox_from_strv(char ***p_str_v)
94 if (!str_v_is_empty(*p_str_v))
96 char **ps;
97 gboolean moving = FALSE;
99 for (ps = *p_str_v; *ps; ++ps)
101 if (moving)
103 *(ps - 1) = *ps;
104 *ps = NULL;
106 else if (!strcmp(*ps, "ROX"))
108 g_free(*ps);
109 *ps = NULL;
110 moving = TRUE;
113 if (str_v_is_empty(*p_str_v))
115 g_strfreev(*p_str_v);
116 *p_str_v = NULL;
121 static void add_rox_to_strv(char ***p_str_v, gboolean force)
123 char **ps;
125 if (!str_v_is_empty(*p_str_v))
127 gboolean contains_rox = FALSE;
129 for (ps = *p_str_v; *ps; ++ps)
131 if (!strcmp(*ps, "ROX"))
133 contains_rox = TRUE;
134 break;
137 if (!contains_rox)
139 int l = str_v_len((char const **) *p_str_v);
141 *p_str_v = g_renew(char *, *p_str_v, l + 2);
142 (*p_str_v)[l] = g_strdup("ROX");
143 (*p_str_v)[l + 1] = NULL;
146 else if (force)
148 g_strfreev(*p_str_v);
149 *p_str_v = g_new0(char *, 2);
150 (*p_str_v)[0] = g_strdup("ROX");
155 static void show_strv(char **strv)
157 char **ps;
159 for (ps = strv; ps && *ps; ++ps)
161 g_print("%s ; ", *ps);
163 g_print("\n");
167 void xdesktop_entry_set_start_in_rox(DesktopEntry *xde, gboolean state)
169 if (state)
171 add_rox_to_strv(&xde->only_show_in, FALSE);
172 remove_rox_from_strv(&xde->not_show_in);
174 else
176 remove_rox_from_strv(&xde->only_show_in);
177 add_rox_to_strv(&xde->not_show_in, TRUE);
179 update_kf_from_show_ins(xde);
182 void xdesktop_entry_save(DesktopEntry *xde)
184 char *buffer = NULL;
185 gsize buflen = 0;
186 GError *err = NULL;
188 if (!xde->savable)
190 g_free(xde->pathname);
191 xde->pathname = g_build_filename(g_get_user_config_dir(),
192 xde->basename, NULL);
193 xde->savable = TRUE;
195 buffer = g_key_file_to_data(xde->kf, &buflen, &err);
196 if (!buffer || err)
198 message_dialog(NULL, GTK_MESSAGE_ERROR,
199 _("Unable to prepare Desktop Entry for saving to '%s': %s"),
200 xde->pathname, err ? err->message : _("unknown reason"));
201 g_error_free(err);
202 g_free(buffer);
203 return;
205 if (!g_file_set_contents(xde->pathname, buffer, buflen, &err))
207 message_dialog(NULL, GTK_MESSAGE_ERROR,
208 _("Unable to save '%s': %s"),
209 xde->pathname, err ? err->message : _("unknown reason"));
210 g_error_free(err);
211 g_free(buffer);
212 return;
216 inline static char *add_desktop_extension(const char *basename)
218 return g_strjoin(".", basename, "desktop", NULL);
221 /* basename doesn't include .desktop extension */
222 static char *xdg_autostart_pathname(const char *basename)
224 char *leafname = add_desktop_extension(basename);
225 char *pathname = g_build_filename(g_get_user_config_dir(), "autostart",
226 leafname, NULL);
228 g_free(leafname);
229 return pathname;
232 /* This has side-effect of creating file if it doesn't clash,
233 * so it must be overwritten or deleted */
234 static int filename_clash(const char *basename)
236 static char *dir = NULL;
237 char *pathname;
238 const char * const *dirs;
239 const char * const *d;
240 int result = 0;
242 dirs = g_get_system_config_dirs();
243 for (d = dirs; *d; ++d)
245 char *leafname = add_desktop_extension(basename);
247 pathname = g_build_filename(*d, "autostart", leafname, NULL);
248 g_free(leafname);
249 if (g_file_test(pathname, G_FILE_TEST_EXISTS))
250 result = -1;
251 g_free(pathname);
252 if (result == -1)
253 return -1;
255 if (!dir)
257 dir = g_build_filename(g_get_user_config_dir(), "autostart", NULL);
258 if (g_mkdir_with_parents(dir, 0755) == -1)
260 message_dialog(NULL, GTK_MESSAGE_ERROR,
261 _("Unable to create '%s' directory"), dir);
264 if (!g_file_test(dir, G_FILE_TEST_IS_DIR))
265 return -2;
266 pathname = xdg_autostart_pathname(basename);
267 result = open(pathname, O_WRONLY| O_EXCL|O_CREAT, 0644);
268 if (result != -1)
269 close(result);
270 g_free(pathname);
271 return result;
274 static char *add_number_ext(const char *basename)
276 int l = strlen(basename);
277 int n;
278 int number = 1;
280 for (n = l - 1; n >= 0 && isdigit(basename[n]); --n);
281 /* This will also accept a trailing - with no subsequent digits,
282 * but that's OK */
283 if (basename[n] == '-')
285 if (n != l - 1)
287 number = atoi(basename + n + 1) + 1;
289 l = n;
291 return g_strdup_printf("%.*s-%d", l, basename, number);
294 void xdesktop_entry_filenames_from_name(DesktopEntry *de, const char *leafname)
296 int n;
297 char *basename = NULL;
298 int fd;
300 if (leafname)
302 char *sep;
304 basename = g_strdup(leafname);
305 sep = strrchr(basename, '.');
306 if (sep && sep[1] && !strcmp(sep + 1, "desktop"))
307 *sep = 0;
309 else
311 basename = g_filename_from_utf8(de->name, -1, NULL, NULL, NULL);
313 if (!basename || !basename[0])
315 if (basename)
316 g_free(basename);
317 basename = g_strdup(_("rox-session-autostart"));
319 else
321 for (n = 0; basename[n]; ++n)
323 if (isspace(basename[n]))
324 basename[n] = '-';
325 else
326 basename[n] = tolower(basename[n]);
329 while ((fd = filename_clash(basename)) == -1)
331 char *old = basename;
333 old = basename;
334 basename = add_number_ext(basename);
335 g_free(old);
337 g_free(de->basename);
338 de->basename = add_desktop_extension(basename);
339 g_free(de->pathname);
340 de->pathname = xdg_autostart_pathname(basename);
341 g_free(basename);
342 de->savable = TRUE;