Initial check-in to git.
[XDGStart.git] / src / main.c
blob2bb2993aa903eec14162ee4c95549205709a2ba9
1 /*
2 * By Tony Houghton, <h@realh.co.uk>.
3 */
5 #include "config.h"
7 #include <stdlib.h>
8 #include <string.h>
10 #include <glib/gstdio.h>
11 #include <gtk/gtk.h>
13 #include "dialogs.h"
14 #include "xxdgautostart.h"
16 #define VIEW_MAX_W 512
17 #define VIEW_MAX_H 320
19 typedef struct {
20 GList * desktop_entries;
21 GtkWidget * dialog;
22 GtkListStore * list_store;
23 GtkTreeView * tree_view;
24 GtkWidget * edit_button;
25 GtkWidget * remove_button;
26 } DesktopEntriesData;
28 enum {
29 ColData, /* Not shown */
30 ColName,
31 ColRoxOnly,
32 ColStartInRox,
33 /* Rest not shown */
34 ColRoxOnlySensitive,
35 ColStartInRoxSensitive,
37 NumCols
40 char *locale_name;
41 char *short_locale_name = NULL;
43 #if HAVE_GTK_WIDGET_SET_TOOLTIP_TEXT
44 inline static void set_tooltip(GtkWidget *widget, const char *text)
46 gtk_widget_set_tooltip_markup(widget, text);
48 #else
49 static void set_tooltip(GtkWidget *widget, const char *text)
51 static GtkTooltips *tooltips = NULL;
53 if (!tooltips)
54 tooltips = gtk_tooltips_new();
55 gtk_tooltips_set_tip(tooltips, widget, text, NULL);
57 #endif
59 static void set_keyfile_name(GKeyFile *kf, const char *name)
61 char *old_name = NULL;
63 if (locale_name)
65 g_key_file_set_locale_string(kf, _DE, "Name", locale_name, name);
66 old_name = g_key_file_get_string(kf, _DE, "Name", NULL);
67 if (!old_name || !old_name[0])
68 g_key_file_set_string(kf, _DE, "Name", name);
70 else
72 g_key_file_set_string(kf, _DE, "Name", name);
74 if (short_locale_name &&
75 ((old_name = g_key_file_get_locale_string(kf, _DE, "Name",
76 short_locale_name, NULL)) == NULL || !old_name[0]))
78 g_key_file_set_locale_string(kf, _DE, "Name", short_locale_name, name);
80 g_free(old_name);
83 static void get_entry_and_iter_from_path(DesktopEntriesData *ded,
84 DesktopEntry **entry_out, GtkTreeIter *iter_out, GtkTreePath *path)
86 GtkTreeIter iter;
88 gtk_tree_model_get_iter(GTK_TREE_MODEL(ded->list_store),
89 iter_out ? iter_out : &iter, path);
90 if (entry_out)
92 gtk_tree_model_get(GTK_TREE_MODEL(ded->list_store),
93 iter_out ? iter_out : &iter, ColData, entry_out, -1);
97 /* If no selection returns FALSE and *entry_out is set to NULL,
98 * *iter_out is unchanged
100 static gboolean get_selected_entry_and_iter(DesktopEntriesData *ded,
101 DesktopEntry **entry_out, GtkTreeIter *iter_out)
103 GtkTreeSelection *seln =
104 gtk_tree_view_get_selection(GTK_TREE_VIEW(ded->tree_view));
105 GList *selected = gtk_tree_selection_get_selected_rows(seln, NULL);
107 /* Only one node can be selected in this view, so just look at first
108 * selected item but be prepared to clean up after multiple just in case
110 if (selected)
112 get_entry_and_iter_from_path(ded, entry_out, iter_out, selected->data);
113 g_list_foreach(selected, (GFunc) gtk_tree_path_free, NULL);
114 g_list_free(selected);
115 return TRUE;
117 else
119 if (entry_out)
120 *entry_out = NULL;
122 return FALSE;
125 static void shade_buttons_for_selection(DesktopEntriesData *ded)
127 DesktopEntry *entry;
128 gboolean selected;
130 selected = get_selected_entry_and_iter(ded, &entry, NULL);
131 gtk_widget_set_sensitive(ded->edit_button, selected);
132 gtk_widget_set_sensitive(ded->remove_button, entry && entry->deletable);
135 static GKeyFile *new_de_keyfile(void)
137 GKeyFile *kf = g_key_file_new();
139 g_key_file_set_double(kf, _DE, "Version", 1.0);
140 g_key_file_set_string(kf, _DE, "Encoding", "UTF-8");
141 g_key_file_set_string(kf, _DE, "Name", "AutoStart Entry");
142 set_keyfile_name(kf, _("New AutoStart Entry"));
143 g_key_file_set_string(kf, _DE, "Exec", "rox");
144 g_key_file_set_string(kf, _DE, "OnlyShowIn", "ROX;");
145 return kf;
148 static DesktopEntry *new_desktop_entry(void)
150 DesktopEntry *de = g_new0(DesktopEntry, 1);
152 de->kf = new_de_keyfile();
153 desktop_entry_read_keyfile(de);
154 xdesktop_entry_read_name_from_keyfile(de);
155 return de;
158 static void rox_only_toggled_cb(GtkCellRendererToggle *cell,
159 const char *path, DesktopEntriesData *ded)
161 DesktopEntry *xde = g_list_nth_data(ded->desktop_entries, atoi(path));
162 gboolean active = !gtk_cell_renderer_toggle_get_active(cell);
163 GtkTreeIter iter;
165 g_return_if_fail(xde != NULL);
166 xdesktop_entry_set_only_in_rox(xde, active);
167 xdesktop_entry_save(xde);
168 g_return_if_fail(gtk_tree_model_get_iter_from_string(
169 GTK_TREE_MODEL(ded->list_store), &iter, path));
170 gtk_list_store_set(ded->list_store, &iter,
171 ColRoxOnly, active,
172 ColStartInRoxSensitive, !active,
173 -1);
176 static void start_in_rox_toggled_cb(GtkCellRendererToggle *cell,
177 const char *path, DesktopEntriesData *ded)
179 DesktopEntry *xde = g_list_nth_data(ded->desktop_entries, atoi(path));
180 gboolean active = !gtk_cell_renderer_toggle_get_active(cell);
181 GtkTreeIter iter;
183 g_return_if_fail(xde != NULL);
184 xdesktop_entry_set_start_in_rox(xde, active);
185 xdesktop_entry_save(xde);
186 g_return_if_fail(gtk_tree_model_get_iter_from_string(
187 GTK_TREE_MODEL(ded->list_store), &iter, path));
188 gtk_list_store_set(ded->list_store, &iter,
189 ColStartInRox, active,
190 ColRoxOnlySensitive, xdesktop_entry_can_set_only_in_rox(xde),
191 -1);
194 static void open_rs_as_dir(GtkWindow *parent)
196 GError *err;
197 char *argv[3];
199 argv[1] = g_build_filename(g_get_user_config_dir(),
200 "rox.sourceforge.net", "ROX-Session", "AutoStart", NULL);
201 if (!g_file_test(argv[1], G_FILE_TEST_IS_DIR))
203 message_dialog(parent, GTK_MESSAGE_WARNING,
204 _("ROX-Session AutoStart directory ('%s') doesn't exist"),
205 argv[1]);
206 g_free(argv[1]);
207 return;
209 argv[0] = g_find_program_in_path("rox");
210 if (!argv[0])
212 message_dialog(parent, GTK_MESSAGE_ERROR,
213 _("ROX-Filer ('rox') program not found"));
214 return;
216 argv[2] = NULL;
217 if (!gdk_spawn_on_screen(gdk_screen_get_default(), NULL, argv, NULL, 0,
218 NULL, NULL, NULL, &err))
220 message_dialog(parent, GTK_MESSAGE_ERROR,
221 _("Unable to run ROX-Filer: %s"),
222 err ? err->message : _("unknown error"));
224 g_free(argv[0]);
225 g_free(argv[1]);
228 static void set_entry(DesktopEntriesData *ded, DesktopEntry *xde,
229 GtkTreeIter *iter)
231 gtk_list_store_set(ded->list_store, iter,
232 ColData, xde, ColName, xde->name,
233 ColRoxOnly, xdesktop_entry_get_only_in_rox(xde),
234 ColStartInRox, desktop_entry_get_show_in_rox(xde),
235 ColRoxOnlySensitive, xdesktop_entry_can_set_only_in_rox(xde),
236 ColStartInRoxSensitive,
237 xdesktop_entry_can_set_start_in_rox(xde),
238 -1);
241 static void add_entry_to_list_store(DesktopEntriesData *ded,
242 DesktopEntry *xde)
244 GtkTreeIter iter;
246 gtk_list_store_append(ded->list_store, &iter);
247 set_entry(ded, xde, &iter);
250 static int create_or_edit_dialog(DesktopEntriesData *ded,
251 DesktopEntry *xde, gboolean create)
253 GtkWidget *dialog_w = gtk_dialog_new_with_buttons(
254 create ? _("New AutoStart Entry") : _("Edit AutoStart Entry"),
255 GTK_WINDOW(ded->dialog),
256 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
257 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
258 GTK_STOCK_APPLY, GTK_RESPONSE_ACCEPT,
259 NULL);
260 GtkDialog *dialog = GTK_DIALOG(dialog_w);
261 GtkBox *vbox = GTK_BOX(dialog->vbox);
262 GtkWidget *name_w = gtk_entry_new();
263 GtkWidget *command_w = gtk_entry_new();
264 GtkWidget *only_show_in = gtk_entry_new();
265 GtkWidget *not_show_in = gtk_entry_new();
266 GtkWidget *terminal_w = gtk_check_button_new_with_label(
267 _("Run in terminal"));
268 GtkTable *table = GTK_TABLE(gtk_table_new(2, 3, FALSE));
269 GtkWidget *expander_w = gtk_expander_new(_("Advanced"));
270 GtkExpander *expander = GTK_EXPANDER(expander_w);
271 GtkTable *adv_table = GTK_TABLE(gtk_table_new(2, 3, FALSE));
272 GtkWidget *label;
273 int response;
274 char *kfval;
275 gboolean valid = FALSE;
277 /* Tooltips */
278 set_tooltip(name_w, _("Edit the name of the entry here"));
279 set_tooltip(command_w, _("Set the command that this entry runs here"));
280 set_tooltip(only_show_in, _("This is a list of desktop environments in "
281 "which this entry will be started, separated (and terminated) "
282 "by semicolons (';'). This option must be blank if you use the "
283 "\"Don't start in\" option."));
284 #if HAVE_GTK_WIDGET_SET_TOOLTIP_TEXT
285 set_tooltip(not_show_in, _("This is a list of desktop environments in "
286 "which this entry will <b>not</b> be started, separated (and "
287 "terminated) by semicolons (';'). This option must be blank if "
288 "you use the \"Only start in\" option."));
289 #else
290 set_tooltip(not_show_in, _("This is a list of desktop environments in "
291 "which this entry will not be started, separated (and "
292 "terminated) by semicolons (';'). This option must be blank if "
293 "you use the \"Only start in\" option."));
294 #endif
295 set_tooltip(expander_w,
296 _("Click here to toggle the display of extra options"));
297 set_tooltip(terminal_w,
298 _("Whether the entry's command should be run in a terminal"));
300 gtk_dialog_set_default_response(dialog, GTK_RESPONSE_ACCEPT);
301 gtk_entry_set_activates_default(GTK_ENTRY(name_w), TRUE);
302 gtk_entry_set_activates_default(GTK_ENTRY(command_w), TRUE);
303 gtk_entry_set_activates_default(GTK_ENTRY(only_show_in), TRUE);
304 gtk_entry_set_activates_default(GTK_ENTRY(not_show_in), TRUE);
306 label = gtk_label_new(_("Name"));
307 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
308 gtk_table_attach(table, label, 0, 1, 0, 1,
309 GTK_FILL, GTK_FILL, 6, 6);
310 gtk_table_attach(table, name_w, 1, 2, 0, 1,
311 GTK_FILL | GTK_EXPAND, GTK_FILL, 6, 6);
312 label = gtk_label_new(_("Command"));
313 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
314 gtk_table_attach(table, label, 0, 1, 1, 2,
315 GTK_FILL, GTK_FILL, 6, 6);
316 gtk_table_attach(table, command_w, 1, 2, 1, 2,
317 GTK_FILL | GTK_EXPAND, GTK_FILL, 6, 6);
319 gtk_container_add(GTK_CONTAINER(expander), GTK_WIDGET(adv_table));
320 label = gtk_label_new(_("Only start in"));
321 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
322 gtk_table_attach(adv_table, label, 0, 1, 0, 1,
323 GTK_FILL, GTK_FILL, 6, 6);
324 gtk_table_attach(adv_table, only_show_in, 1, 2, 0, 1,
325 GTK_FILL | GTK_EXPAND, GTK_FILL, 6, 6);
326 label = gtk_label_new(_("Don't start in"));
327 gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
328 gtk_table_attach(adv_table, label, 0, 1, 1, 2,
329 GTK_FILL, GTK_FILL, 6, 6);
330 gtk_table_attach(adv_table, not_show_in, 1, 2, 1, 2,
331 GTK_FILL | GTK_EXPAND, GTK_FILL, 6, 6);
332 gtk_table_attach(adv_table, terminal_w, 0, 2, 2, 3,
333 GTK_FILL | GTK_EXPAND, GTK_FILL, 6, 6);
334 gtk_table_attach(table, GTK_WIDGET(expander), 0, 2, 2, 3,
335 GTK_FILL | GTK_EXPAND, GTK_SHRINK, 6, 6);
337 gtk_box_pack_start(vbox, GTK_WIDGET(table), TRUE, TRUE, 6);
339 gtk_entry_set_text(GTK_ENTRY(name_w), xde->name);
340 gtk_entry_set_text(GTK_ENTRY(command_w), xde->exec);
341 kfval = g_key_file_get_string(xde->kf, _DE, "OnlyShowIn", NULL);
342 gtk_entry_set_text(GTK_ENTRY(only_show_in), kfval ? kfval : "");
343 g_free(kfval);
344 kfval = g_key_file_get_string(xde->kf, _DE, "NotShowIn", NULL);
345 gtk_entry_set_text(GTK_ENTRY(not_show_in), kfval ? kfval : "");
346 g_free(kfval);
347 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(terminal_w),
348 xde->terminal);
350 gtk_widget_show_all(GTK_WIDGET(vbox));
351 while (!valid)
353 response = gtk_dialog_run(dialog);
354 if (response == GTK_RESPONSE_ACCEPT)
356 const char *name_str = gtk_entry_get_text(GTK_ENTRY(name_w));
357 const char *command_str = gtk_entry_get_text(GTK_ENTRY(command_w));
358 const char *only_show_in_str =
359 gtk_entry_get_text(GTK_ENTRY(only_show_in));
360 const char *not_show_in_str =
361 gtk_entry_get_text(GTK_ENTRY(not_show_in));
363 if (!name_str || !name_str[0])
365 message_dialog(GTK_WINDOW(dialog), GTK_MESSAGE_ERROR,
366 _("The entry must have a name"));
367 continue;
369 if (!command_str || !command_str[0])
371 message_dialog(GTK_WINDOW(dialog), GTK_MESSAGE_ERROR,
372 _("The entry must have a command"));
373 continue;
375 if (only_show_in_str && only_show_in_str[0] &&
376 not_show_in_str && not_show_in_str[0])
378 message_dialog(GTK_WINDOW(dialog), GTK_MESSAGE_ERROR,
379 _("You can't set both \"Don't start in\" and "
380 "\"Only start in\""));
381 continue;
383 set_keyfile_name(xde->kf, name_str);
384 g_key_file_set_string(xde->kf, _DE, "Exec", command_str);
385 if (only_show_in_str && only_show_in_str[0])
387 g_key_file_set_value(xde->kf, _DE, "OnlyShowIn",
388 only_show_in_str);
390 else
392 g_key_file_remove_key(xde->kf, _DE, "OnlyShowIn", NULL);
394 if (not_show_in_str && not_show_in_str[0])
396 g_key_file_set_value(xde->kf, _DE, "NotShowIn",
397 not_show_in_str);
399 else
401 g_key_file_remove_key(xde->kf, _DE, "NotShowIn", NULL);
403 g_key_file_set_boolean(xde->kf, _DE, "Terminal",
404 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(terminal_w)));
405 valid = TRUE;
407 else
409 valid = TRUE;
412 if (response != GTK_RESPONSE_DELETE_EVENT)
413 gtk_widget_destroy(dialog_w);
414 return response;
417 static void new_entry_dialog_for_entry(DesktopEntriesData *ded,
418 DesktopEntry *xde)
420 if (create_or_edit_dialog(ded, xde, TRUE) == GTK_RESPONSE_ACCEPT)
422 desktop_entry_read_keyfile(xde);
423 xdesktop_entry_read_name_from_keyfile(xde);
424 xdesktop_entry_filenames_from_name(xde, NULL);
425 xdesktop_entry_save(xde);
426 ded->desktop_entries = g_list_append(ded->desktop_entries, xde);
427 xde->deletable = TRUE;
428 add_entry_to_list_store(ded, xde);
429 shade_buttons_for_selection(ded);
431 else
433 desktop_entry_delete(xde);
437 static void new_entry_cb(DesktopEntriesData *ded)
439 new_entry_dialog_for_entry(ded, new_desktop_entry());
442 static void edit_entry(DesktopEntriesData *ded, DesktopEntry *xde,
443 GtkTreeIter *iter)
445 if (create_or_edit_dialog(ded, xde, FALSE) == GTK_RESPONSE_ACCEPT)
447 desktop_entry_read_keyfile(xde);
448 xdesktop_entry_read_name_from_keyfile(xde);
449 xdesktop_entry_save(xde);
450 set_entry(ded, xde, iter);
451 shade_buttons_for_selection(ded);
455 static void edit_entry_cb(DesktopEntriesData *ded)
457 DesktopEntry *xde;
458 GtkTreeIter iter;
460 g_return_if_fail(get_selected_entry_and_iter(ded, &xde, &iter));
461 edit_entry(ded, xde, &iter);
464 static void remove_entry_cb(DesktopEntriesData *ded)
466 DesktopEntry *xde;
467 GtkTreeIter iter;
469 g_return_if_fail(get_selected_entry_and_iter(ded, &xde, &iter));
470 gtk_list_store_remove(ded->list_store, &iter);
471 ded->desktop_entries = g_list_remove(ded->desktop_entries, xde);
472 shade_buttons_for_selection(ded);
473 g_unlink(xde->pathname);
474 desktop_entry_delete(xde);
477 static void row_activated_cb(GtkTreeView *tree_view, GtkTreePath *path,
478 GtkTreeViewColumn *column, DesktopEntriesData *ded)
480 DesktopEntry *xde;
481 GtkTreeIter iter;
483 get_entry_and_iter_from_path(ded, &xde, &iter, path);
484 edit_entry(ded, xde, &iter);
487 static DesktopEntry *desktop_entry_from_rox_app(const char *dir)
489 return NULL;
492 static DesktopEntry *desktop_entry_from_desktop_file(const char *filename)
494 return NULL;
497 static DesktopEntry *desktop_entry_from_executable(const char *dir)
499 return NULL;
502 static DesktopEntry *desktop_entry_from_uri(const char *uri)
504 DesktopEntry *entry = NULL;
506 if (g_str_has_prefix(uri, "file://"))
508 uri += 7;
510 else if (strchr(uri, ':'))
512 g_warning(_("Unrecognised URI %s"), uri);
513 return NULL;
515 if (g_file_test(uri, G_FILE_TEST_IS_DIR))
517 char *apprun = g_build_filename(uri, "AppRun", NULL);
519 if (g_file_test(apprun, G_FILE_TEST_IS_EXECUTABLE))
521 g_free(apprun);
522 return desktop_entry_from_rox_app(uri);
525 else if ((entry = desktop_entry_from_desktop_file(uri)) != NULL)
526 return entry;
527 else if (g_file_test(uri, G_FILE_TEST_IS_EXECUTABLE))
528 return desktop_entry_from_executable(uri);
529 g_warning(_("Unable to create an entry from %s"), uri);
530 return NULL;
533 enum {
534 DragUriList = 0
537 static void drag_received_cb(GtkWidget *widget, GdkDragContext *context,
538 gint x, gint y, GtkSelectionData *selection_data, guint info,
539 guint time, DesktopEntriesData *ded)
541 gboolean valid = FALSE;
543 if (selection_data->format != 8 || !selection_data->length)
545 g_critical(_("Invalid selection data (format %d, length %d)"),
546 selection_data->format, selection_data->length);
548 else if (info == DragUriList)
550 char **uris = gtk_selection_data_get_uris(selection_data);
552 if (uris)
554 int n, m;
555 DesktopEntry **entries = NULL;
557 for (n = 0; uris[n]; ++n);
558 entries = g_new0(DesktopEntry *, n + 1);
559 m = 0;
560 for (n = 0; uris[n]; ++n)
562 DesktopEntry *de = desktop_entry_from_uri(uris[n]);
564 if (de)
566 entries[m++] = de;
567 valid = TRUE;
570 if (valid)
572 gtk_drag_finish(context, FALSE, FALSE, time);
573 for (n = 0; entries[n]; ++n)
574 new_entry_dialog_for_entry(ded, entries[n]);
576 g_strfreev(uris);
577 g_free(entries);
580 if (!valid)
581 gtk_drag_finish(context, FALSE, FALSE, time);
584 static void set_up_drag_target(GtkWidget *widget, DesktopEntriesData *ded)
586 static GtkTargetEntry target_table[] = {
587 { (char *) "text/uri-list", 0, DragUriList }
590 gtk_drag_dest_set(widget, GTK_DEST_DEFAULT_ALL,
591 target_table, G_N_ELEMENTS(target_table),
592 GDK_ACTION_COPY | GDK_ACTION_MOVE);
593 g_signal_connect(widget, "drag-data-received",
594 G_CALLBACK(drag_received_cb), ded);
597 static DesktopEntriesData *build_dialog(GList *desktop_entries)
599 DesktopEntriesData *ded = g_new0(DesktopEntriesData, 1);
600 GList *node;
601 GtkCellRenderer *cell;
602 GtkTreeViewColumn *column;
603 GtkWidget *tvwidget;
604 GtkRequisition req;
605 GtkWidget *scroll;
606 GtkWidget *btn_hbox;
607 GtkWidget *btn_hbox2;
608 GtkBox *vbox;
609 GtkWidget *misc_w;
611 ded->desktop_entries = desktop_entries;
612 ded->dialog = gtk_dialog_new_with_buttons(_("XDG AutoStart Entries"),
613 NULL, 0, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
615 /* Set up list store */
616 ded->list_store = gtk_list_store_new(NumCols,
617 G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
618 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
619 for (node = ded->desktop_entries; node; node = g_list_next(node))
620 add_entry_to_list_store(ded, node->data);
622 /* Set up tree view */
623 tvwidget = gtk_tree_view_new_with_model(
624 GTK_TREE_MODEL(ded->list_store));
625 ded->tree_view = GTK_TREE_VIEW(tvwidget);
626 g_signal_connect_swapped(ded->tree_view, "cursor-changed",
627 G_CALLBACK(shade_buttons_for_selection), ded);
628 g_signal_connect(ded->tree_view, "row-activated",
629 G_CALLBACK(row_activated_cb), ded);
630 set_tooltip(tvwidget, _("The entries here are implemented as dektop "
631 "entry files according to the XDG specification"));
632 set_up_drag_target(tvwidget, ded);
634 cell = gtk_cell_renderer_text_new();
635 column = gtk_tree_view_column_new_with_attributes(_("Name"), cell,
636 "text", ColName, NULL);
637 gtk_tree_view_append_column(ded->tree_view, column);
639 cell = gtk_cell_renderer_toggle_new();
640 column = gtk_tree_view_column_new_with_attributes(_("Only in ROX"), cell,
641 "active", ColRoxOnly,
642 "activatable", ColRoxOnlySensitive,
643 "sensitive", ColRoxOnlySensitive,
644 NULL);
645 gtk_tree_view_append_column(ded->tree_view, column);
646 g_signal_connect(cell, "toggled", G_CALLBACK(rox_only_toggled_cb), ded);
648 cell = gtk_cell_renderer_toggle_new();
649 column = gtk_tree_view_column_new_with_attributes(_("Start in ROX"), cell,
650 "active", ColStartInRox,
651 "activatable", ColStartInRoxSensitive,
652 "sensitive", ColStartInRoxSensitive,
653 NULL);
654 gtk_tree_view_append_column(ded->tree_view, column);
655 g_signal_connect(cell, "toggled", G_CALLBACK(start_in_rox_toggled_cb), ded);
657 /* Create buttons */
658 btn_hbox = gtk_hbox_new(TRUE, 16);
659 ded->remove_button = gtk_button_new_from_stock(GTK_STOCK_DELETE);
660 g_signal_connect_swapped(ded->remove_button, "clicked",
661 G_CALLBACK(remove_entry_cb), ded);
662 gtk_box_pack_start_defaults(GTK_BOX(btn_hbox), ded->remove_button);
663 ded->edit_button = gtk_button_new_from_stock(GTK_STOCK_EDIT);
664 g_signal_connect_swapped(ded->edit_button, "clicked",
665 G_CALLBACK(edit_entry_cb), ded);
666 gtk_box_pack_start_defaults(GTK_BOX(btn_hbox), ded->edit_button);
667 misc_w = gtk_button_new_from_stock(GTK_STOCK_ADD);
668 g_signal_connect_swapped(misc_w, "clicked", G_CALLBACK(new_entry_cb), ded);
669 gtk_box_pack_start_defaults(GTK_BOX(btn_hbox), misc_w);
671 /* Lay out main TreeView widget */
672 gtk_widget_size_request(tvwidget, &req);
673 if (req.width < VIEW_MAX_W)
674 req.width += 32;
675 if (req.width > VIEW_MAX_W)
676 req.width = VIEW_MAX_W;
677 if (req.height < VIEW_MAX_H)
678 req.height += 32;
679 if (req.height > VIEW_MAX_H)
680 req.height = VIEW_MAX_H;
681 scroll = gtk_scrolled_window_new(NULL, NULL);
682 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll),
683 GTK_SHADOW_IN);
684 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
685 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
686 gtk_container_add(GTK_CONTAINER(scroll), tvwidget);
687 gtk_widget_set_size_request(tvwidget, req.width, req.height);
689 btn_hbox2 = gtk_hbox_new(FALSE, 16);
690 misc_w = gtk_button_new_with_label(
691 _("Open ROX-Session AutoStart directory"));
692 set_tooltip(misc_w, _("At start-up ROX-Session also automatically runs "
693 "any scripts, executables or ROX applications in its AutoStart "
694 "directory which can be opened with this button"));
695 g_signal_connect_swapped(misc_w, "clicked",
696 G_CALLBACK(open_rs_as_dir), ded->dialog);
697 gtk_box_pack_end(GTK_BOX(btn_hbox2), misc_w, FALSE, FALSE, 0);
699 /* Do master lay-out and show everything */
700 vbox = GTK_BOX(GTK_DIALOG(ded->dialog)->vbox);
701 gtk_box_pack_start(vbox, scroll, TRUE, TRUE, 6);
702 gtk_box_pack_start(vbox, btn_hbox, FALSE, FALSE, 6);
703 gtk_box_pack_start(vbox, btn_hbox2, FALSE, FALSE, 6);
704 shade_buttons_for_selection(ded);
705 gtk_widget_show_all(GTK_WIDGET(vbox));
707 return ded;
710 int main(int argc, char **argv)
712 GList *desl;
713 DesktopEntriesData *ded;
714 char *lang = getenv("LANG");
716 if (lang)
718 char *sep = strchr(lang, '.');
719 int l = sep ? sep - lang : strlen(lang);
721 locale_name = g_strdup_printf("%.*s", l, lang);
722 sep = strchr(locale_name, '_');
723 if (sep)
725 short_locale_name = g_strdup_printf("%.*s",
726 (int) (sep - locale_name), locale_name);
729 else
731 locale_name = NULL;
733 gtk_init(&argc, &argv);
734 desl = get_desktop_entries((DesktopEntryConstructor *) xdesktop_entry_new);
735 ded = build_dialog(desl);
736 if (gtk_dialog_run(GTK_DIALOG(ded->dialog)) != GTK_RESPONSE_DELETE_EVENT)
737 gtk_widget_destroy(ded->dialog);
739 return 0;