2 * Dialog box for profiles editing
3 * Stig Bjorlykke <stig@bjorlykke.org>, 2008
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
33 #include <gdk/gdkkeysyms.h>
34 #if GTK_CHECK_VERSION(3,0,0)
35 # include <gdk/gdkkeysyms-compat.h>
38 #include <epan/filesystem.h>
39 #include <epan/prefs.h>
41 #include "../simple_dialog.h"
42 #include <wsutil/file_util.h>
45 #include "gtk/menus.h"
46 #include "gtk/profile_dlg.h"
47 #include "gtk/dlg_utils.h"
48 #include "gtk/gui_utils.h"
49 #include "gtk/gtkglobals.h"
50 #include "gtk/help_dlg.h"
51 #include "gtk/recent.h"
60 #define E_PROF_PROFILE_L_KEY "profile_profile_l"
61 #define E_PROF_DEL_BT_KEY "profile_del_bt"
62 #define E_PROF_NAME_TE_KEY "profile_name_te"
64 static GtkWidget *global_profile_w = NULL;
65 static GList *current_profiles = NULL;
66 static GList *edited_profiles = NULL;
68 #define PROF_STAT_DEFAULT 1
69 #define PROF_STAT_EXISTS 2
70 #define PROF_STAT_NEW 3
71 #define PROF_STAT_CHANGED 4
72 #define PROF_STAT_COPY 5
74 #define PROF_OPERATION_NEW 1
75 #define PROF_OPERATION_EDIT 2
78 char *name; /* profile name */
79 char *reference; /* profile reference */
86 add_profile_entry(GList *fl, const char *profilename, const char *reference, int status,
87 gboolean is_global, gboolean from_global)
91 profile = (profile_def *) g_malloc(sizeof(profile_def));
92 profile->name = g_strdup(profilename);
93 profile->reference = g_strdup(reference);
94 profile->status = status;
95 profile->is_global = is_global;
96 profile->from_global = from_global;
97 return g_list_append(fl, profile);
101 remove_profile_entry(GList *fl, GList *fl_entry)
103 profile_def *profile;
105 profile = (profile_def *) fl_entry->data;
106 g_free(profile->name);
107 g_free(profile->reference);
109 return g_list_remove_link(fl, fl_entry);
113 get_profile_parent (const gchar *profilename)
115 GList *fl_entry = g_list_first(edited_profiles);
116 guint no_edited = g_list_length(edited_profiles);
117 profile_def *profile;
121 /* We have edited profiles, find parent */
122 for (i = 0; i < no_edited; i++) {
124 profile = (profile_def *) fl_entry->data;
125 if (strcmp (profile->name, profilename) == 0) {
126 if ((profile->status == PROF_STAT_NEW) ||
127 (profile->reference == NULL)) {
128 /* Copy from a new profile */
131 /* Found a parent, use this */
132 profilename = profile->reference;
135 fl_entry = g_list_next(fl_entry);
137 fl_entry = g_list_first(edited_profiles);
145 add_to_profile_list(const char *name, const char *expression, int status,
146 gboolean is_global, gboolean from_global)
148 edited_profiles = add_profile_entry(edited_profiles, name, expression, status,
149 is_global, from_global);
151 return g_list_last(edited_profiles);
155 remove_from_profile_list(GList *fl_entry)
157 edited_profiles = remove_profile_entry(edited_profiles, fl_entry);
161 empty_profile_list(gboolean edit_list)
166 flpp = &edited_profiles;
169 *flpp = remove_profile_entry(*flpp, g_list_first(*flpp));
172 g_assert(g_list_length(*flpp) == 0);
175 flpp = ¤t_profiles;
178 *flpp = remove_profile_entry(*flpp, g_list_first(*flpp));
181 g_assert(g_list_length(*flpp) == 0);
185 copy_profile_list(void)
188 profile_def *profile;
190 flp_src = edited_profiles;
192 /* throw away the "old" destination list - a NULL list is ok here */
193 empty_profile_list(FALSE);
195 /* copy the list entries */
197 profile = (flp_src)->data;
199 current_profiles = add_profile_entry(current_profiles, profile->name,
200 profile->reference, profile->status,
201 profile->is_global, profile->from_global);
202 flp_src = g_list_next(flp_src);
208 fill_list(GtkWidget *main_w)
210 WS_DIR *dir; /* scanned directory */
211 WS_DIRENT *file; /* current file */
213 profile_def *profile;
214 GtkTreeView *profile_l;
216 GtkTreeIter iter, *l_select = NULL;
217 const gchar *profile_name = get_profile_name ();
218 const gchar *profiles_dir, *name;
221 profile_l = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY));
222 store = GTK_LIST_STORE(gtk_tree_view_get_model(profile_l));
224 fl_entry = add_to_profile_list(DEFAULT_PROFILE, DEFAULT_PROFILE, PROF_STAT_DEFAULT, FALSE, FALSE);
225 gtk_list_store_append(store, &iter);
226 gtk_list_store_set(store, &iter, NAME_COLUMN, DEFAULT_PROFILE, GLOBAL_COLUMN, FALSE, DATA_COLUMN, fl_entry, -1);
227 if (strcmp (profile_name, DEFAULT_PROFILE)==0) {
228 l_select = g_memdup(&iter, sizeof(iter));
232 profiles_dir = get_profiles_dir();
233 if ((dir = ws_dir_open(profiles_dir, 0, NULL)) != NULL) {
234 while ((file = ws_dir_read_name(dir)) != NULL) {
235 name = ws_dir_get_name(file);
236 filename = g_strdup_printf ("%s%s%s", profiles_dir, G_DIR_SEPARATOR_S, name);
238 if (test_for_directory(filename) == EISDIR) {
239 fl_entry = add_to_profile_list(name, name, PROF_STAT_EXISTS, FALSE, FALSE);
240 profile = (profile_def *) fl_entry->data;
241 gtk_list_store_append(store, &iter);
242 gtk_list_store_set(store, &iter, NAME_COLUMN, profile->name, GLOBAL_COLUMN, FALSE, DATA_COLUMN, fl_entry, -1);
245 if (strcmp(profile_name, profile->name) == 0) {
247 * XXX - We're assuming that we can just copy a GtkTreeIter
248 * and use it later without any crashes. This may not be a
251 l_select = g_memdup(&iter, sizeof(iter));
260 profiles_dir = get_global_profiles_dir();
261 if ((dir = ws_dir_open(profiles_dir, 0, NULL)) != NULL) {
262 while ((file = ws_dir_read_name(dir)) != NULL) {
263 name = ws_dir_get_name(file);
264 filename = g_strdup_printf ("%s%s%s", profiles_dir, G_DIR_SEPARATOR_S, name);
266 if (test_for_directory(filename) == EISDIR) {
267 fl_entry = add_to_profile_list(name, name, PROF_STAT_EXISTS, TRUE, TRUE);
268 profile = (profile_def *) fl_entry->data;
269 gtk_list_store_append(store, &iter);
270 gtk_list_store_set(store, &iter, NAME_COLUMN, profile->name, GLOBAL_COLUMN, TRUE, DATA_COLUMN, fl_entry, -1);
277 /* Make the current list and the edited list equal */
278 copy_profile_list ();
284 profile_is_invalid_name(const gchar *name)
286 gchar *message = NULL;
289 char *invalid_dir_char = "\\/:*?\"<>|";
290 gboolean invalid = FALSE;
293 for (i = 0; i < 9; i++) {
294 if (strchr(name, invalid_dir_char[i])) {
295 /* Invalid character in directory */
299 if (name[0] == '.' || name[strlen(name)-1] == '.') {
300 /* Profile name cannot start or end with period */
304 message = g_strdup_printf("start or end with period (.), or contain any of the following characters:\n"
305 " \\ / : * ? \" < > |");
308 if (strchr(name, '/')) {
309 /* Invalid character in directory */
310 message = g_strdup_printf("contain the '/' character.");
315 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "A profile name cannot %s\nProfiles unchanged.", message);
324 profile_select(GtkWidget *main_w, GtkTreeView *profile_l, gboolean destroy)
327 profile_def *profile;
328 GtkTreeSelection *sel;
332 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(profile_l));
334 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
335 gtk_tree_model_get(model, &iter, DATA_COLUMN, &fl_entry, -1);
337 profile = (profile_def *) fl_entry->data;
338 if (profile_exists (profile->name, FALSE) || profile_exists (profile->name, TRUE)) {
339 /* The new profile exists, change */
340 change_configuration_profile (profile->name);
341 } else if (!profile_exists (get_profile_name(), FALSE)) {
342 /* The new profile does not exist, and the previous profile has
343 been deleted. Change to the default profile */
344 change_configuration_profile (NULL);
351 * Destroy the profile dialog box.
353 empty_profile_list (TRUE);
354 window_destroy(main_w);
359 profile_apply(GtkWidget *main_w, GtkTreeView *profile_l, gboolean destroy)
361 char *pf_dir_path, *pf_dir_path2, *pf_filename;
363 profile_def *profile1, *profile2;
366 /* First validate all profile names */
367 fl1 = g_list_first(edited_profiles);
369 profile1 = (profile_def *) fl1->data;
370 g_strstrip(profile1->name);
371 if (profile_is_invalid_name(profile1->name)) {
374 fl1 = g_list_next(fl1);
377 /* Then do all copy profiles */
378 fl1 = g_list_first(edited_profiles);
380 profile1 = (profile_def *) fl1->data;
381 g_strstrip(profile1->name);
382 if (profile1->status == PROF_STAT_COPY) {
383 if (create_persconffile_profile(profile1->name, &pf_dir_path) == -1) {
384 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
385 "Can't create directory\n\"%s\":\n%s.",
386 pf_dir_path, g_strerror(errno));
390 profile1->status = PROF_STAT_EXISTS;
392 if (profile1->reference) {
393 if (copy_persconffile_profile(profile1->name, profile1->reference, profile1->from_global,
394 &pf_filename, &pf_dir_path, &pf_dir_path2) == -1) {
395 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
396 "Can't copy file \"%s\" in directory\n\"%s\" to\n\"%s\":\n%s.",
397 pf_filename, pf_dir_path2, pf_dir_path, g_strerror(errno));
401 g_free(pf_dir_path2);
405 g_free (profile1->reference);
406 profile1->reference = g_strdup(profile1->name);
408 fl1 = g_list_next(fl1);
412 /* Then create new and rename changed */
413 fl1 = g_list_first(edited_profiles);
415 profile1 = (profile_def *) fl1->data;
416 g_strstrip(profile1->name);
417 if (profile1->status == PROF_STAT_NEW) {
418 /* We do not create a directory for the default profile */
419 if (strcmp(profile1->name, DEFAULT_PROFILE)!=0) {
420 if (create_persconffile_profile(profile1->name, &pf_dir_path) == -1) {
421 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
422 "Can't create directory\n\"%s\":\n%s.",
423 pf_dir_path, g_strerror(errno));
427 profile1->status = PROF_STAT_EXISTS;
429 g_free (profile1->reference);
430 profile1->reference = g_strdup(profile1->name);
432 } else if (profile1->status == PROF_STAT_CHANGED) {
433 if (strcmp(profile1->reference, profile1->name)!=0) {
434 /* Rename old profile directory to new */
435 if (rename_persconffile_profile(profile1->reference, profile1->name,
436 &pf_dir_path, &pf_dir_path2) == -1) {
437 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
438 "Can't rename directory\n\"%s\" to\n\"%s\":\n%s.",
439 pf_dir_path, pf_dir_path2, g_strerror(errno));
442 g_free(pf_dir_path2);
444 profile1->status = PROF_STAT_EXISTS;
445 g_free (profile1->reference);
446 profile1->reference = g_strdup(profile1->name);
449 fl1 = g_list_next(fl1);
452 /* Last remove deleted */
453 fl1 = g_list_first(current_profiles);
456 profile1 = (profile_def *) fl1->data;
457 fl2 = g_list_first(edited_profiles);
459 profile2 = (profile_def *) fl2->data;
460 if (!profile2->is_global) {
461 if (strcmp(profile1->name, profile2->name)==0) {
462 /* Profile exists in both lists */
464 } else if (strcmp(profile1->name, profile2->reference)==0) {
465 /* Profile has been renamed */
472 /* Exists in existing list and not in edited, this is a deleted profile */
473 if (delete_persconffile_profile(profile1->name, &pf_dir_path) == -1) {
474 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
475 "Can't delete profile directory\n\"%s\":\n%s.",
476 pf_dir_path, g_strerror(errno));
481 fl1 = g_list_next(fl1);
485 profile_select(main_w, profile_l, destroy);
489 profile_dlg_ok_cb(GtkWidget *ok_bt, gpointer data _U_)
491 GtkWidget *main_w = gtk_widget_get_toplevel(ok_bt);
492 GtkTreeView *profile_l = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY));
495 * Apply the profile and destroy the dialog box.
497 profile_apply(main_w, profile_l, TRUE);
501 profile_dlg_apply_cb(GtkWidget *apply_bt, gpointer data _U_)
503 GtkWidget *main_w = gtk_widget_get_toplevel(apply_bt);
504 GtkTreeView *profile_l = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY));
507 * Apply the profile, but don't destroy the dialog box.
509 profile_apply(main_w, profile_l, FALSE);
512 /* cancel button pressed, revert changes and exit dialog */
514 profile_dlg_cancel_cb(GtkWidget *cancel_bt, gpointer data _U_)
516 GtkWidget *main_w = gtk_widget_get_toplevel(cancel_bt);
518 empty_profile_list (TRUE);
519 window_destroy(GTK_WIDGET(main_w));
522 /* Treat this as a cancel, by calling "profile_dlg_cancel_cb()" */
524 profile_dlg_delete_event_cb(GtkWidget *main_w, GdkEvent *event _U_,
527 profile_dlg_cancel_cb(main_w, data);
532 profile_dlg_destroy_cb(GtkWidget *w _U_, gpointer data _U_)
534 global_profile_w = NULL;
539 profile_button_press_cb(GtkWidget *list, GdkEventButton *event, gpointer data _U_)
541 if (event->type == GDK_2BUTTON_PRESS) {
542 GtkWidget *main_w = gtk_widget_get_toplevel(list);
544 profile_apply (main_w, GTK_TREE_VIEW(list), TRUE);
551 profile_key_release_cb(GtkWidget *list, GdkEventKey *event, gpointer data _U_)
553 if (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter) {
554 GtkWidget *main_w = gtk_widget_get_toplevel(list);
556 profile_apply (main_w, GTK_TREE_VIEW(list), TRUE);
563 profile_sel_list_cb(GtkTreeSelection *sel, gpointer data _U_)
565 GtkWidget *profile_l = GTK_WIDGET(gtk_tree_selection_get_tree_view(sel));
566 GtkWidget *main_w = gtk_widget_get_toplevel(profile_l);
569 GtkWidget *name_te = g_object_get_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY);
570 GtkWidget *del_bt = g_object_get_data(G_OBJECT(main_w), E_PROF_DEL_BT_KEY);
571 profile_def *profile;
574 gint sensitivity = FALSE;
576 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
577 gtk_tree_model_get(model, &iter, DATA_COLUMN, &fl_entry, -1);
579 profile = (profile_def *) fl_entry->data;
580 name = g_strdup(profile->name);
581 if ((profile->status != PROF_STAT_DEFAULT) && !profile->is_global) {
588 * Did you know that this function is called when the window is destroyed?
590 * This means that we have to:
592 * attach to the top-level window data items containing pointers to
593 * the widgets we affect here;
595 * give each of those widgets their own destroy callbacks;
597 * clear that pointer when the widget is destroyed;
599 * don't do anything to the widget if the pointer we get back is
602 * so that if we're called after any of the widgets we'd affect are
603 * destroyed, we know that we shouldn't do anything to those widgets.
605 if (name_te != NULL) {
606 gtk_entry_set_text(GTK_ENTRY(name_te), name ? name : "");
607 gtk_widget_set_sensitive(name_te, sensitivity);
610 gtk_widget_set_sensitive(del_bt, sensitivity);
615 profile_new_bt_clicked_cb(GtkWidget *w, gpointer data _U_)
617 GtkWidget *main_w = gtk_widget_get_toplevel(w);
618 GtkWidget *name_te = g_object_get_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY);
619 GtkTreeView *profile_l = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY));
623 const gchar *name = "New profile";
625 /* Add a new entry to the profile list. */
626 fl_entry = add_to_profile_list(name, "", PROF_STAT_NEW, FALSE, FALSE);
628 store = GTK_LIST_STORE(gtk_tree_view_get_model(profile_l));
629 gtk_list_store_append(store, &iter);
630 gtk_list_store_set(store, &iter, NAME_COLUMN, name, GLOBAL_COLUMN, FALSE, DATA_COLUMN, fl_entry, -1);
631 /* Select the item. */
632 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(profile_l), &iter);
634 gtk_editable_select_region(GTK_EDITABLE(name_te), 0, -1);
635 gtk_widget_grab_focus(name_te);
639 profile_copy_bt_clicked_cb(GtkWidget *w, gpointer data _U_)
641 GtkWidget *main_w = gtk_widget_get_toplevel(w);
642 GtkWidget *name_te = g_object_get_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY);
643 GtkTreeView *profile_l = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY));
647 const gchar *name = gtk_entry_get_text(GTK_ENTRY(name_te));
648 const gchar *parent = NULL;
651 GtkTreeSelection *sel;
653 profile_def *profile = NULL;
655 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(profile_l));
656 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
657 gtk_tree_model_get(model, &iter, DATA_COLUMN, &fl_entry, -1);
659 profile = (profile_def *) fl_entry->data;
663 if (profile && profile->is_global) {
664 parent = profile->name;
666 parent = get_profile_parent (name);
669 if (profile && profile->is_global && !profile_exists (parent, FALSE)) {
670 new_name = g_strdup (name);
672 new_name = g_strdup_printf ("%s (copy)", name);
675 /* Add a new entry to the profile list. */
676 fl_entry = add_to_profile_list(new_name, parent, PROF_STAT_COPY, FALSE, profile ? profile->from_global : FALSE);
678 store = GTK_LIST_STORE(gtk_tree_view_get_model(profile_l));
679 gtk_list_store_append(store, &iter);
680 gtk_list_store_set(store, &iter, NAME_COLUMN, new_name, GLOBAL_COLUMN, FALSE, DATA_COLUMN, fl_entry, -1);
681 /* Select the item. */
682 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(profile_l), &iter);
684 gtk_editable_select_region(GTK_EDITABLE(name_te), 0, -1);
685 gtk_widget_grab_focus(name_te);
691 profile_name_te_changed_cb(GtkWidget *w, gpointer data _U_)
693 GtkWidget *main_w = gtk_widget_get_toplevel(w);
694 GtkWidget *name_te = g_object_get_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY);
695 GtkWidget *profile_l = g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY);
696 profile_def *profile;
698 const gchar *name = "";
700 GtkTreeSelection *sel;
704 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(profile_l));
705 name = gtk_entry_get_text(GTK_ENTRY(name_te));
707 /* if something was selected */
708 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
709 gtk_tree_model_get(model, &iter, DATA_COLUMN, &fl_entry, -1);
710 if (fl_entry != NULL) {
711 profile = (profile_def *) fl_entry->data;
713 if (strlen(name) > 0 && profile && !profile->is_global) {
714 if (profile->status != PROF_STAT_DEFAULT) {
715 g_free(profile->name);
716 profile->name = g_strdup(name);
717 if ((profile->status != PROF_STAT_NEW) &&
718 (profile->status != PROF_STAT_COPY)) {
719 profile->status = PROF_STAT_CHANGED;
721 gtk_list_store_set(GTK_LIST_STORE(model), &iter, NAME_COLUMN, name, -1);
729 profile_del_bt_clicked_cb(GtkWidget *w, gpointer data _U_)
731 GtkWidget *main_w = gtk_widget_get_toplevel(w);
732 GtkWidget *profile_l = g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY);
735 GtkTreeSelection *sel;
739 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(profile_l));
740 /* If something was selected */
741 if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
742 gtk_tree_model_get(model, &iter, DATA_COLUMN, &fl_entry, -1);
744 if (fl_entry != NULL) {
745 remove_from_profile_list (fl_entry);
746 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
750 if (gtk_tree_model_get_iter_first (model, &iter)) {
751 gtk_tree_selection_select_iter(sel, &iter);
756 profile_dialog_new(void)
758 GtkWidget *main_w, /* main window */
759 *main_vb, /* main container */
760 *bbox, /* button container */
761 *ok_bt, /* "OK" button */
762 *apply_bt, /* "Apply" button */
763 *cancel_bt, /* "Cancel" button */
764 *help_bt; /* "Help" button */
765 GtkWidget *profile_vb, /* profile settings box */
781 GtkCellRenderer *renderer;
782 GtkTreeViewColumn *column;
783 GtkTreeSelection *sel;
784 GtkTreeIter *l_select;
785 gboolean has_global = has_global_profiles();
787 /* Get a pointer to a static variable holding the type of profile on
788 which we're working, so we can pass that pointer to callback
791 main_w = dlg_conf_window_new("Wireshark: Configuration Profiles");
792 gtk_window_set_default_size(GTK_WINDOW(main_w), 400, 400);
794 main_vb = gtk_vbox_new(FALSE, 0);
795 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
796 gtk_container_add(GTK_CONTAINER(main_w), main_vb);
797 gtk_widget_show(main_vb);
799 /* Container for each row of widgets */
800 profile_vb = gtk_vbox_new(FALSE, 0);
801 gtk_container_set_border_width(GTK_CONTAINER(profile_vb), 0);
802 gtk_container_add(GTK_CONTAINER(main_vb), profile_vb);
803 gtk_widget_show(profile_vb);
805 /* Top row: Buttons and profile list */
806 top_hb = gtk_hbox_new(FALSE, 0);
807 gtk_container_add(GTK_CONTAINER(profile_vb), top_hb);
808 gtk_widget_show(top_hb);
810 edit_fr = gtk_frame_new("Edit");
811 gtk_box_pack_start(GTK_BOX(top_hb), edit_fr, FALSE, FALSE, 0);
812 gtk_widget_show(edit_fr);
814 list_bb = gtk_vbox_new(TRUE, 0);
815 gtk_container_set_border_width(GTK_CONTAINER(list_bb), 5);
816 gtk_container_add(GTK_CONTAINER(edit_fr), list_bb);
817 gtk_widget_show(list_bb);
819 new_bt = gtk_button_new_from_stock(GTK_STOCK_NEW);
820 g_signal_connect(new_bt, "clicked", G_CALLBACK(profile_new_bt_clicked_cb), NULL);
821 gtk_widget_show(new_bt);
822 gtk_box_pack_start (GTK_BOX (list_bb), new_bt, FALSE, FALSE, 0);
823 gtk_widget_set_tooltip_text (new_bt, "Create a new profile (with default properties)");
825 copy_bt = gtk_button_new_from_stock(GTK_STOCK_COPY);
826 g_signal_connect(copy_bt, "clicked", G_CALLBACK(profile_copy_bt_clicked_cb), NULL);
827 gtk_widget_show(copy_bt);
828 gtk_box_pack_start (GTK_BOX (list_bb), copy_bt, FALSE, FALSE, 0);
829 gtk_widget_set_tooltip_text (copy_bt, "Copy the selected profile");
831 del_bt = gtk_button_new_from_stock(GTK_STOCK_DELETE);
832 gtk_widget_set_sensitive(del_bt, FALSE);
833 g_signal_connect(del_bt, "clicked", G_CALLBACK(profile_del_bt_clicked_cb), NULL);
834 g_object_set_data(G_OBJECT(main_w), E_PROF_DEL_BT_KEY, del_bt);
835 gtk_widget_show(del_bt);
836 gtk_box_pack_start (GTK_BOX (list_bb), del_bt, FALSE, FALSE, 0);
837 gtk_widget_set_tooltip_text (del_bt, "Delete the selected profile");
839 profile_fr = gtk_frame_new("Configuration Profiles");
840 gtk_box_pack_start(GTK_BOX(top_hb), profile_fr, TRUE, TRUE, 0);
841 gtk_widget_show(profile_fr);
843 profile_sc = scrolled_window_new(NULL, NULL);
844 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(profile_sc),
847 gtk_container_set_border_width (GTK_CONTAINER (profile_sc), 5);
848 gtk_container_add(GTK_CONTAINER(profile_fr), profile_sc);
849 gtk_widget_show(profile_sc);
851 store = gtk_list_store_new(NUM_COLUMNS, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_POINTER);
852 profile_l = tree_view_new(GTK_TREE_MODEL(store));
853 /* Only show headers if having more than one column */
854 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(profile_l), has_global);
856 renderer = gtk_cell_renderer_text_new();
857 column = gtk_tree_view_column_new_with_attributes("Name", renderer, "text", NAME_COLUMN, NULL);
858 gtk_tree_view_column_set_expand(column, TRUE);
859 gtk_tree_view_column_set_sort_column_id(column, NAME_COLUMN);
860 gtk_tree_view_append_column(GTK_TREE_VIEW(profile_l), column);
862 renderer = gtk_cell_renderer_toggle_new();
863 column = gtk_tree_view_column_new_with_attributes("Global", renderer, "active", GLOBAL_COLUMN, NULL);
864 gtk_tree_view_append_column(GTK_TREE_VIEW(profile_l), column);
865 gtk_widget_set_tooltip_text(column->button, "Global profiles will be copied to users profiles when used");
866 gtk_tree_view_column_set_visible(column, has_global);
868 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(profile_l));
869 gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
870 g_signal_connect(sel, "changed", G_CALLBACK(profile_sel_list_cb), profile_vb);
871 g_signal_connect(profile_l, "button_press_event", G_CALLBACK(profile_button_press_cb), NULL);
872 g_signal_connect(profile_l, "key_release_event", G_CALLBACK(profile_key_release_cb), NULL);
873 g_object_set_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY, profile_l);
874 gtk_container_add(GTK_CONTAINER(profile_sc), profile_l);
875 gtk_widget_show(profile_l);
878 l_select = fill_list(main_w);
880 g_object_unref(G_OBJECT(store));
882 props_fr = gtk_frame_new("Properties");
883 gtk_box_pack_start(GTK_BOX(profile_vb), props_fr, FALSE, FALSE, 0);
884 gtk_widget_show(props_fr);
886 props_vb = gtk_vbox_new(FALSE, 3);
887 gtk_container_set_border_width(GTK_CONTAINER(props_vb), 5);
888 gtk_container_add(GTK_CONTAINER(props_fr), props_vb);
889 gtk_widget_show(props_vb);
891 /* row: Profile name entry */
892 middle_hb = gtk_hbox_new(FALSE, 3);
893 gtk_container_add(GTK_CONTAINER(props_vb), middle_hb);
894 gtk_widget_show(middle_hb);
896 name_lb = gtk_label_new("Profile name:");
897 gtk_box_pack_start(GTK_BOX(middle_hb), name_lb, FALSE, FALSE, 0);
898 gtk_widget_show(name_lb);
900 name_te = gtk_entry_new();
901 gtk_box_pack_start(GTK_BOX(middle_hb), name_te, TRUE, TRUE, 0);
902 g_object_set_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY, name_te);
903 g_signal_connect(name_te, "changed", G_CALLBACK(profile_name_te_changed_cb), NULL);
905 gtk_widget_set_tooltip_text (name_te, "A profile name cannot start or end with a period (.), and cannot contain any of the following characters:\n \\ / : * ? \" < > |");
907 gtk_widget_set_tooltip_text (name_te, "A profile name cannot contain the '/' character");
909 gtk_widget_show(name_te);
911 /* button row (create all possible buttons and hide the unrequired later - it's a lot easier) */
912 bbox = dlg_button_row_new(GTK_STOCK_OK, GTK_STOCK_APPLY, GTK_STOCK_CANCEL, GTK_STOCK_HELP, NULL);
913 gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 5);
914 gtk_widget_show(bbox);
916 ok_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_OK);
917 g_signal_connect(ok_bt, "clicked", G_CALLBACK(profile_dlg_ok_cb), NULL);
918 gtk_widget_set_tooltip_text (ok_bt, "Apply the profiles and close this dialog");
920 /* Catch the "activate" signal on the profile name and profile
921 list entries, so that if the user types Return
922 there, we act as if the "OK" button had been selected, as
923 happens if Return is typed if some widget that *doesn't*
924 handle the Return key has the input focus. */
925 dlg_set_activate(name_te, ok_bt);
927 apply_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_APPLY);
928 g_signal_connect(apply_bt, "clicked", G_CALLBACK(profile_dlg_apply_cb), NULL);
929 gtk_widget_set_tooltip_text (apply_bt, "Apply the profiles and keep this dialog open");
931 cancel_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CANCEL);
932 gtk_widget_set_tooltip_text (cancel_bt, "Cancel the changes");
933 g_signal_connect(cancel_bt, "clicked", G_CALLBACK(profile_dlg_cancel_cb), NULL);
934 window_set_cancel_button(main_w, cancel_bt, NULL);
936 help_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
937 g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb), (gpointer)HELP_CONFIG_PROFILES_DIALOG);
938 gtk_widget_set_tooltip_text (help_bt, "Show topic specific help");
941 gtk_widget_grab_default(ok_bt);
945 /* DO SELECTION THINGS *AFTER* SHOWING THE DIALOG! */
946 /* otherwise the updatings can get confused */
948 gtk_tree_selection_select_iter(sel, l_select);
953 gtk_widget_grab_focus(profile_l);
956 g_signal_connect(main_w, "delete_event", G_CALLBACK(profile_dlg_delete_event_cb), NULL);
957 g_signal_connect(main_w, "destroy", G_CALLBACK(profile_dlg_destroy_cb), NULL);
959 gtk_widget_show(main_w);
961 window_present(main_w);
968 select_profile_cb (GtkWidget *w _U_, gpointer data)
970 const gchar *current_profile = get_profile_name ();
971 gchar *selected_profile = (gchar *) data;
973 if (strcmp (selected_profile, current_profile) != 0) {
974 change_configuration_profile (selected_profile);
979 profile_show_popup_cb (GtkWidget *w _U_, GdkEvent *event, gpointer user_data _U_)
981 GdkEventButton *bevent = (GdkEventButton *)event;
982 const gchar *profile_name = get_profile_name ();
983 const gchar *profiles_dir, *name;
984 WS_DIR *dir; /* scanned directory */
985 WS_DIRENT *file; /* current file */
987 GtkWidget *menu_item;
989 menu = gtk_menu_new ();
991 if (bevent->button != 1) {
992 GtkWidget *change_menu = menus_get_profiles_change_menu ();
994 #if GTK_CHECK_VERSION(2,16,0)
995 GtkWidget *edit_menu = menus_get_profiles_edit_menu ();
996 GtkWidget *delete_menu = menus_get_profiles_delete_menu ();
997 if (strcmp (profile_name, DEFAULT_PROFILE) != 0) {
999 label = g_strdup_printf ("Edit \"%s\"...", profile_name);
1000 gtk_menu_item_set_label (GTK_MENU_ITEM(edit_menu), label);
1002 label = g_strdup_printf ("Delete \"%s\"", profile_name);
1003 gtk_menu_item_set_label (GTK_MENU_ITEM(delete_menu), label);
1006 gtk_menu_item_set_label (GTK_MENU_ITEM(edit_menu), "Edit...");
1007 gtk_menu_item_set_label (GTK_MENU_ITEM(delete_menu), "Delete");
1010 gtk_menu_item_set_submenu (GTK_MENU_ITEM(change_menu), menu);
1013 /* Add a menu item for the Default profile */
1014 menu_item = gtk_check_menu_item_new_with_label (DEFAULT_PROFILE);
1015 if (strcmp (profile_name, DEFAULT_PROFILE) == 0) {
1016 /* Check current profile */
1017 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(menu_item), TRUE);
1019 g_object_set (G_OBJECT(menu_item), "draw-as-radio", TRUE, NULL);
1020 g_signal_connect (menu_item, "activate", G_CALLBACK(select_profile_cb), g_strdup (DEFAULT_PROFILE));
1021 gtk_menu_shell_append (GTK_MENU_SHELL(menu), menu_item);
1022 gtk_widget_show (menu_item);
1024 profiles_dir = get_profiles_dir();
1025 if ((dir = ws_dir_open(profiles_dir, 0, NULL)) != NULL) {
1026 while ((file = ws_dir_read_name(dir)) != NULL) {
1027 name = ws_dir_get_name(file);
1029 if (profile_exists(name, FALSE)) {
1030 menu_item = gtk_check_menu_item_new_with_label (name);
1031 if (strcmp (name, profile_name)==0) {
1032 /* Check current profile */
1033 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(menu_item), TRUE);
1035 g_object_set (G_OBJECT(menu_item), "draw-as-radio", TRUE, NULL);
1036 g_signal_connect (menu_item, "activate", G_CALLBACK(select_profile_cb), g_strdup (name));
1037 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
1038 gtk_widget_show (menu_item);
1044 profiles_dir = get_global_profiles_dir();
1045 if ((dir = ws_dir_open(profiles_dir, 0, NULL)) != NULL) {
1046 GtkWidget *sub_menu = NULL;
1047 gboolean added_submenu = FALSE;
1049 while ((file = ws_dir_read_name(dir)) != NULL) {
1050 name = ws_dir_get_name(file);
1052 if (profile_exists(name, TRUE)) {
1053 if (!added_submenu) {
1054 menu_item = gtk_separator_menu_item_new ();
1055 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
1056 gtk_widget_show (menu_item);
1058 menu_item = gtk_menu_item_new_with_label ("New from Global");
1059 gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
1060 gtk_widget_show (menu_item);
1062 sub_menu = gtk_menu_new ();
1063 gtk_menu_item_set_submenu (GTK_MENU_ITEM(menu_item), sub_menu);
1065 added_submenu = TRUE;
1068 menu_item = gtk_menu_item_new_with_label (name);
1069 g_signal_connect (menu_item, "activate", G_CALLBACK(select_profile_cb), g_strdup (name));
1070 if (profile_exists(name, FALSE)) {
1071 gtk_widget_set_sensitive(menu_item, FALSE);
1073 gtk_menu_shell_append (GTK_MENU_SHELL (sub_menu), menu_item);
1074 gtk_widget_show (menu_item);
1080 if (bevent->button != 1) {
1081 /* Second-click is handled in popup_menu_handler() */
1085 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL,
1086 bevent->button, bevent->time);
1092 profile_name_edit_ok (GtkWidget *w _U_, gpointer parent_w)
1094 gint operation = GPOINTER_TO_INT(g_object_get_data (G_OBJECT(w), "operation"));
1095 GtkComboBox *combo_box = g_object_get_data (G_OBJECT(w), "create_from");
1096 GtkWidget *entry = g_object_get_data (G_OBJECT(w), "entry");
1097 GtkTreeStore *store;
1099 const gchar *new_name = gtk_entry_get_text(GTK_ENTRY(entry));
1100 const gchar *profile_name = "";
1101 gboolean from_global = FALSE;
1102 char *pf_dir_path, *pf_dir_path2, *pf_filename;
1104 if (strlen(new_name) == 0 || profile_is_invalid_name(new_name)) {
1108 switch (operation) {
1109 case PROF_OPERATION_NEW:
1110 if (gtk_combo_box_get_active_iter(combo_box, &iter)) {
1111 store = GTK_TREE_STORE(gtk_combo_box_get_model(combo_box));
1112 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 0, &profile_name, 1, &from_global, -1);
1115 case PROF_OPERATION_EDIT:
1116 profile_name = get_profile_name();
1117 if (strcmp(new_name, profile_name) == 0) {
1118 /* Rename without a change, do nothing */
1119 window_destroy(GTK_WIDGET(parent_w));
1124 g_assert_not_reached();
1127 if (profile_exists (new_name, FALSE)) {
1128 simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
1129 "The profile already exists:\n%s.", new_name);
1133 /* Write recent file for profile we are leaving */
1134 write_profile_recent();
1136 switch (operation) {
1137 case PROF_OPERATION_NEW:
1138 if (create_persconffile_profile(new_name, &pf_dir_path) == -1) {
1139 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1140 "Can't create directory\n\"%s\":\n%s.",
1141 pf_dir_path, g_strerror(errno));
1143 g_free(pf_dir_path);
1144 } else if (strlen (profile_name) &&
1145 copy_persconffile_profile(new_name, profile_name, from_global, &pf_filename,
1146 &pf_dir_path, &pf_dir_path2) == -1)
1148 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1149 "Can't copy file \"%s\" in directory\n\"%s\" to\n\"%s\":\n%s.",
1150 pf_filename, pf_dir_path2, pf_dir_path, g_strerror(errno));
1152 g_free(pf_filename);
1153 g_free(pf_dir_path);
1154 g_free(pf_dir_path2);
1156 change_configuration_profile (new_name);
1159 case PROF_OPERATION_EDIT:
1160 if (rename_persconffile_profile(profile_name, new_name,
1161 &pf_dir_path, &pf_dir_path2) == -1) {
1162 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1163 "Can't rename directory\n\"%s\" to\n\"%s\":\n%s.",
1164 pf_dir_path, pf_dir_path2, g_strerror(errno));
1166 g_free(pf_dir_path);
1167 g_free(pf_dir_path2);
1169 change_configuration_profile (new_name);
1173 g_assert_not_reached();
1176 window_destroy(GTK_WIDGET(parent_w));
1180 profile_name_edit_cancel (GtkWidget *w _U_, gpointer parent_w)
1182 window_destroy(GTK_WIDGET(parent_w));
1186 profile_name_edit_dlg (gint operation)
1188 WS_DIR *dir; /* scanned directory */
1189 WS_DIRENT *file; /* current file */
1190 GtkWidget *win, *main_tb, *main_vb, *bbox, *cancel_bt, *ok_bt;
1191 GtkWidget *entry, *label, *combo_box=NULL;
1192 GtkCellRenderer *cell;
1193 GtkTreeStore *store;
1194 GtkTreeIter iter, parent;
1195 gchar *window_title=NULL;
1196 const gchar *profile_name, *profiles_dir, *name;
1197 gboolean has_global = has_global_profiles();
1199 profile_name = get_profile_name();
1201 switch (operation) {
1202 case PROF_OPERATION_NEW:
1203 window_title = g_strdup ("Create New Profile");
1205 case PROF_OPERATION_EDIT:
1206 window_title = g_strdup_printf ("Edit: %s", profile_name);
1209 g_assert_not_reached();
1212 win = dlg_window_new(window_title);
1213 g_free (window_title);
1215 gtk_window_set_resizable(GTK_WINDOW(win),FALSE);
1216 gtk_window_resize(GTK_WINDOW(win), 400, 100);
1218 main_vb = gtk_vbox_new(FALSE, 5);
1219 gtk_container_add(GTK_CONTAINER(win), main_vb);
1220 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 6);
1222 main_tb = gtk_table_new(2, 2, FALSE);
1223 gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
1224 gtk_table_set_col_spacings(GTK_TABLE(main_tb), 10);
1225 gtk_table_set_row_spacings(GTK_TABLE(main_tb), 5);
1227 if (operation == PROF_OPERATION_NEW) {
1228 label = gtk_label_new("Create from:");
1229 gtk_widget_set_tooltip_text (label, "All configuration files will be copied from this profile");
1230 gtk_table_attach_defaults(GTK_TABLE(main_tb), label, 0, 1, 0, 1);
1231 gtk_misc_set_alignment(GTK_MISC(label), 1.0f, 0.5f);
1233 store = gtk_tree_store_new(3, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
1234 combo_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL (store));
1235 gtk_widget_set_tooltip_text (combo_box, "All configuration files will be copied from this profile");
1237 cell = gtk_cell_renderer_text_new();
1238 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo_box), cell, TRUE);
1239 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo_box), cell,
1240 "text", 0, "sensitive", 2,
1243 gtk_tree_store_append(store, &iter, NULL);
1244 gtk_tree_store_set(store, &iter, 0, "", 1, FALSE, 2, TRUE, -1);
1247 gtk_tree_store_append(store, &parent, NULL);
1248 gtk_tree_store_set(store, &parent, 0, "Personal", 1, FALSE, 2, FALSE, -1);
1251 gtk_tree_store_append(store, &iter, has_global ? &parent : NULL);
1252 gtk_tree_store_set(store, &iter, 0, DEFAULT_PROFILE, 1, FALSE, 2, TRUE, -1);
1253 profiles_dir = get_profiles_dir();
1254 if ((dir = ws_dir_open(profiles_dir, 0, NULL)) != NULL) {
1255 while ((file = ws_dir_read_name(dir)) != NULL) {
1256 name = ws_dir_get_name(file);
1257 if (profile_exists(name, FALSE)) {
1258 gtk_tree_store_append(store, &iter, has_global ? &parent : NULL);
1259 gtk_tree_store_set(store, &iter, 0, name, 1, FALSE, 2, TRUE, -1);
1266 gtk_tree_store_append(store, &parent, NULL);
1267 gtk_tree_store_set(store, &parent, 0, "Global", 1, FALSE, 2, FALSE, -1);
1268 profiles_dir = get_global_profiles_dir();
1269 if ((dir = ws_dir_open(profiles_dir, 0, NULL)) != NULL) {
1270 while ((file = ws_dir_read_name(dir)) != NULL) {
1271 name = ws_dir_get_name(file);
1272 if (profile_exists(name, TRUE)) {
1273 gtk_tree_store_append(store, &iter, &parent);
1274 gtk_tree_store_set(store, &iter, 0, name, 1, TRUE, 2, TRUE, -1);
1280 gtk_table_attach_defaults(GTK_TABLE(main_tb), combo_box, 1, 2, 0, 1);
1281 g_object_unref(store);
1284 label = gtk_label_new("Profile name:");
1285 gtk_table_attach_defaults(GTK_TABLE(main_tb), label, 0, 1, 1, 2);
1286 gtk_misc_set_alignment(GTK_MISC(label), 1.0f, 0.5f);
1288 entry = gtk_entry_new();
1289 gtk_table_attach_defaults(GTK_TABLE(main_tb), entry, 1, 2, 1, 2);
1290 switch (operation) {
1291 case PROF_OPERATION_NEW:
1292 gtk_entry_set_text(GTK_ENTRY(entry), "New profile");
1294 case PROF_OPERATION_EDIT:
1295 gtk_entry_set_text(GTK_ENTRY(entry), profile_name);
1298 g_assert_not_reached();
1302 gtk_widget_set_tooltip_text (entry, "A profile name cannot start or end with a period (.), and cannot contain any of the following characters:\n \\ / : * ? \" < > |");
1304 gtk_widget_set_tooltip_text (entry, "A profile name cannot contain the '/' character");
1307 bbox = dlg_button_row_new(GTK_STOCK_CANCEL,GTK_STOCK_OK, NULL);
1308 gtk_box_pack_end(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
1310 ok_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_OK);
1311 g_object_set_data (G_OBJECT(ok_bt), "entry", entry);
1312 g_object_set_data (G_OBJECT(ok_bt), "create_from", combo_box);
1313 g_object_set_data (G_OBJECT(ok_bt), "operation", GINT_TO_POINTER(operation));
1314 g_signal_connect(ok_bt, "clicked", G_CALLBACK(profile_name_edit_ok), win);
1316 dlg_set_activate(entry, ok_bt);
1317 gtk_widget_grab_focus(entry);
1319 cancel_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CANCEL);
1320 g_signal_connect(cancel_bt, "clicked", G_CALLBACK(profile_name_edit_cancel), win);
1321 window_set_cancel_button(win, cancel_bt, NULL);
1323 gtk_widget_grab_default(ok_bt);
1324 gtk_widget_show_all(win);
1328 profile_new_cb (GtkWidget *w _U_, gpointer data _U_)
1330 profile_name_edit_dlg (PROF_OPERATION_NEW);
1334 profile_delete_cb (GtkWidget *w _U_, gpointer data _U_)
1336 const gchar *name = get_profile_name();
1339 if (profile_exists(name, FALSE) && strcmp (name, DEFAULT_PROFILE) != 0) {
1340 if (delete_persconffile_profile(name, &pf_dir_path) == -1) {
1341 simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
1342 "Can't delete profile directory\n\"%s\":\n%s.",
1343 pf_dir_path, g_strerror(errno));
1345 g_free(pf_dir_path);
1348 /* Change to the default profile */
1349 change_configuration_profile (NULL);
1354 profile_edit_cb (GtkWidget *w _U_, gpointer data _U_)
1356 profile_name_edit_dlg (PROF_OPERATION_EDIT);
1359 /* Create a profile dialog for editing display profiles; this is to be used
1360 as a callback for menu items, toolbars, etc.. */
1362 profile_dialog_cb(GtkWidget *w _U_)
1364 /* Has a profiles dialog box already been opened */
1365 if (global_profile_w != NULL) {
1366 /* Yes. Just reactivate it. */
1367 reactivate_window(global_profile_w);
1369 global_profile_w = profile_dialog_new ();