merge_all_tap_menus() has been moved to menus.c.
[obnox/wireshark/wip.git] / gtk / profile_dlg.c
index 5556dc2f26ee54e79f4890881ba9af46402b7249..16d719f5d4488fc08f94fc437930ffc8c809ed39 100644 (file)
@@ -1,6 +1,6 @@
 /* profile_dlg.c
  * Dialog box for profiles editing
- * Stig BjΓΈrlykke <stig@bjorlykke.org>, 2008
+ * Stig Bjorlykke <stig@bjorlykke.org>, 2008
  *
  * $Id$
  *
 
 #include <gtk/gtk.h>
 #include <gdk/gdkkeysyms.h>
+#if GTK_CHECK_VERSION(3,0,0)
+# include <gdk/gdkkeysyms-compat.h>
+#endif
 
 #include <epan/filesystem.h>
-#include <wiretap/file_util.h>
-
-#include "gtk/main.h"
-#include "profile_dlg.h"
-#include "dlg_utils.h"
-#include "gui_utils.h"
-#include "simple_dialog.h"
-#include "compat_macros.h"
-#include "gtkglobals.h"
-#include "help_dlg.h"
 #include <epan/prefs.h>
 
-#if GTK_MAJOR_VERSION >= 2
+#include "../simple_dialog.h"
+#include <wsutil/file_util.h>
+
+#include "gtk/main.h"
+#include "gtk/menus.h"
+#include "gtk/profile_dlg.h"
+#include "gtk/dlg_utils.h"
+#include "gtk/gui_utils.h"
+#include "gtk/gtkglobals.h"
+#include "gtk/help_dlg.h"
+#include "gtk/recent.h"
+#include "gtk/old-gtk-compat.h"
+enum {
+  NAME_COLUMN,
+  GLOBAL_COLUMN,
+  DATA_COLUMN,
+  NUM_COLUMNS
+};
 
 #define E_PROF_PROFILE_L_KEY        "profile_profile_l"
-#define E_PROF_COPY_BT_KEY          "profile_copy_bt"
 #define E_PROF_DEL_BT_KEY           "profile_del_bt"
 #define E_PROF_NAME_TE_KEY          "profile_name_te"
-#define E_PROF_SELFUNC_KEY          "profile_selfunc"
-#define E_PROF_SELARG_KEY           "profile_selarg"
 
 static GtkWidget *global_profile_w = NULL;
 static GList *current_profiles = NULL;
@@ -64,14 +71,20 @@ static GList *edited_profiles = NULL;
 #define PROF_STAT_CHANGED  4
 #define PROF_STAT_COPY     5
 
+#define PROF_OPERATION_NEW  1
+#define PROF_OPERATION_EDIT 2
+
 typedef struct {
   char *name;           /* profile name */
   char *reference;      /* profile reference */
   int   status;
+  gboolean is_global;
+  gboolean from_global;
 } profile_def;
 
 static GList *
-add_profile_entry(GList *fl, const char *profilename, const char *reference, int status)
+add_profile_entry(GList *fl, const char *profilename, const char *reference, int status, 
+                 gboolean is_global, gboolean from_global)
 {
     profile_def *profile;
 
@@ -79,6 +92,8 @@ add_profile_entry(GList *fl, const char *profilename, const char *reference, int
     profile->name = g_strdup(profilename);
     profile->reference = g_strdup(reference);
     profile->status = status;
+    profile->is_global = is_global;
+    profile->from_global = from_global;
     return g_list_append(fl, profile);
 }
 
@@ -94,10 +109,44 @@ remove_profile_entry(GList *fl, GList *fl_entry)
   return g_list_remove_link(fl, fl_entry);
 }
 
+static const gchar *
+get_profile_parent (const gchar *profilename)
+{
+  GList *fl_entry = g_list_first(edited_profiles);
+  guint no_edited = g_list_length(edited_profiles);
+  profile_def *profile;
+  guint i;
+
+  if (fl_entry) {
+    /* We have edited profiles, find parent */
+    for (i = 0; i < no_edited; i++) {
+      while (fl_entry) {
+       profile = (profile_def *) fl_entry->data;
+       if (strcmp (profile->name, profilename) == 0) {
+         if ((profile->status == PROF_STAT_NEW) ||
+             (profile->reference == NULL)) {
+           /* Copy from a new profile */
+           return NULL;
+         } else {
+           /* Found a parent, use this */
+           profilename = profile->reference;
+         }
+       }
+       fl_entry = g_list_next(fl_entry);
+      }
+      fl_entry = g_list_first(edited_profiles);
+    }
+  }
+
+  return profilename;
+}
+
 static GList *
-add_to_profile_list(const char *name, const char *expression, int status)
+add_to_profile_list(const char *name, const char *expression, int status, 
+                   gboolean is_global, gboolean from_global)
 {
-  edited_profiles = add_profile_entry(edited_profiles, name, expression, status);
+  edited_profiles = add_profile_entry(edited_profiles, name, expression, status,
+                                     is_global, from_global);
 
   return g_list_last(edited_profiles);
 }
@@ -119,16 +168,16 @@ empty_profile_list(gboolean edit_list)
     while(*flpp) {
       *flpp = remove_profile_entry(*flpp, g_list_first(*flpp));
     }
-    
+
     g_assert(g_list_length(*flpp) == 0);
-  } 
+  }
 
   flpp = &current_profiles;
 
   while(*flpp) {
     *flpp = remove_profile_entry(*flpp, g_list_first(*flpp));
   }
-  
+
   g_assert(g_list_length(*flpp) == 0);
 }
 
@@ -147,8 +196,9 @@ copy_profile_list(void)
     while(flp_src) {
         profile = (flp_src)->data;
 
-        current_profiles = add_profile_entry(current_profiles, profile->name, 
-                                            profile->reference, profile->status);
+        current_profiles = add_profile_entry(current_profiles, profile->name,
+                                            profile->reference, profile->status, 
+                                            profile->is_global, profile->from_global);
         flp_src = g_list_next(flp_src);
     }
 }
@@ -157,8 +207,8 @@ copy_profile_list(void)
 static GtkTreeIter *
 fill_list(GtkWidget *main_w)
 {
-  ETH_DIR       *dir;             /* scanned directory */
-  ETH_DIRENT    *file;            /* current file */
+  WS_DIR        *dir;             /* scanned directory */
+  WS_DIRENT     *file;            /* current file */
   GList         *fl_entry;
   profile_def   *profile;
   GtkTreeView   *profile_l;
@@ -167,31 +217,31 @@ fill_list(GtkWidget *main_w)
   const gchar   *profile_name = get_profile_name ();
   const gchar   *profiles_dir, *name;
   gchar         *filename;
-  
-  profile_l = GTK_TREE_VIEW(OBJECT_GET_DATA(main_w, E_PROF_PROFILE_L_KEY));
+
+  profile_l = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY));
   store = GTK_LIST_STORE(gtk_tree_view_get_model(profile_l));
-  
-  fl_entry = add_to_profile_list(DEFAULT_PROFILE, DEFAULT_PROFILE, PROF_STAT_DEFAULT);
+
+  fl_entry = add_to_profile_list(DEFAULT_PROFILE, DEFAULT_PROFILE, PROF_STAT_DEFAULT, FALSE, FALSE);
   gtk_list_store_append(store, &iter);
-  gtk_list_store_set(store, &iter, 0, DEFAULT_PROFILE, 1, fl_entry, -1);
-  if (profile_name == NULL || strlen(profile_name) == 0) {
+  gtk_list_store_set(store, &iter, NAME_COLUMN, DEFAULT_PROFILE, GLOBAL_COLUMN, FALSE, DATA_COLUMN, fl_entry, -1);
+  if (strcmp (profile_name, DEFAULT_PROFILE)==0) {
     l_select = g_memdup(&iter, sizeof(iter));
   }
-  
+
   /* fill in data */
   profiles_dir = get_profiles_dir();
-  if ((dir = eth_dir_open(profiles_dir, 0, NULL)) != NULL) {
-    while ((file = eth_dir_read_name(dir)) != NULL) {
-      name = eth_dir_get_name(file);
+  if ((dir = ws_dir_open(profiles_dir, 0, NULL)) != NULL) {
+    while ((file = ws_dir_read_name(dir)) != NULL) {
+      name = ws_dir_get_name(file);
       filename = g_strdup_printf ("%s%s%s", profiles_dir, G_DIR_SEPARATOR_S, name);
 
       if (test_for_directory(filename) == EISDIR) {
-       fl_entry = add_to_profile_list(name, name, PROF_STAT_EXISTS);
-       profile    = (profile_def *) fl_entry->data;
+       fl_entry = add_to_profile_list(name, name, PROF_STAT_EXISTS, FALSE, FALSE);
+       profile = (profile_def *) fl_entry->data;
        gtk_list_store_append(store, &iter);
-       gtk_list_store_set(store, &iter, 0, profile->name, 1, fl_entry, -1);
-       
-       if (profile_name && profile->name) {
+       gtk_list_store_set(store, &iter, NAME_COLUMN, profile->name, GLOBAL_COLUMN, FALSE, DATA_COLUMN, fl_entry, -1);
+
+       if (profile->name) {
          if (strcmp(profile_name, profile->name) == 0) {
            /*
             * XXX - We're assuming that we can just copy a GtkTreeIter
@@ -204,15 +254,72 @@ fill_list(GtkWidget *main_w)
       }
       g_free (filename);
     }
-    eth_dir_close (dir);
+    ws_dir_close (dir);
   }
 
-  /* Make the current list an the edited list equal */
+  profiles_dir = get_global_profiles_dir();
+  if ((dir = ws_dir_open(profiles_dir, 0, NULL)) != NULL) {
+    while ((file = ws_dir_read_name(dir)) != NULL) {
+      name = ws_dir_get_name(file);
+      filename = g_strdup_printf ("%s%s%s", profiles_dir, G_DIR_SEPARATOR_S, name);
+
+      if (test_for_directory(filename) == EISDIR) {
+       fl_entry = add_to_profile_list(name, name, PROF_STAT_EXISTS, TRUE, TRUE);
+       profile = (profile_def *) fl_entry->data;
+       gtk_list_store_append(store, &iter);
+       gtk_list_store_set(store, &iter, NAME_COLUMN, profile->name, GLOBAL_COLUMN, TRUE, DATA_COLUMN, fl_entry, -1);
+      }
+      g_free (filename);
+    }
+    ws_dir_close (dir);
+  }
+
+  /* Make the current list and the edited list equal */
   copy_profile_list ();
-  
+
   return l_select;
 }
 
+static gboolean
+profile_is_invalid_name(const gchar *name)
+{
+  gchar  *message = NULL;
+
+#ifdef _WIN32
+  char *invalid_dir_char = "\\/:*?\"<>|";
+  gboolean invalid = FALSE;
+  int i;
+
+  for (i = 0; i < 9; i++) {
+    if (strchr(name, invalid_dir_char[i])) {
+      /* Invalid character in directory */
+      invalid = TRUE;
+    }
+  }
+  if (name[0] == '.' || name[strlen(name)-1] == '.') {
+    /* Profile name cannot start or end with period */
+    invalid = TRUE;
+  }
+  if (invalid) {
+    message = g_strdup_printf("start or end with period (.), or contain any of the following characters:\n"
+                             "   \\ / : * ? \" &lt; &gt; |");
+  }
+#else
+  if (strchr(name, '/')) {
+    /* Invalid character in directory */
+    message = g_strdup_printf("contain the '/' character.");
+  }
+#endif
+
+  if (message) {
+    simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "A profile name cannot %s\nProfiles unchanged.", message);
+    g_free(message);
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
 static void
 profile_select(GtkWidget *main_w, GtkTreeView *profile_l, gboolean destroy)
 {
@@ -225,12 +332,15 @@ profile_select(GtkWidget *main_w, GtkTreeView *profile_l, gboolean destroy)
   sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(profile_l));
 
   if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
-    gtk_tree_model_get(model, &iter, 1, &fl_entry, -1);
+    gtk_tree_model_get(model, &iter, DATA_COLUMN, &fl_entry, -1);
     if (fl_entry) {
       profile = (profile_def *) fl_entry->data;
-      if (strcmp(profile->name, DEFAULT_PROFILE)!=0) {
+      if (profile_exists (profile->name, FALSE) || profile_exists (profile->name, TRUE)) {
+       /* The new profile exists, change */
        change_configuration_profile (profile->name);
-      } else {
+      } else if (!profile_exists (get_profile_name(), FALSE)) {
+       /* The new profile does not exist, and the previous profile has
+          been deleted.  Change to the default profile */
        change_configuration_profile (NULL);
       }
     }
@@ -246,44 +356,78 @@ profile_select(GtkWidget *main_w, GtkTreeView *profile_l, gboolean destroy)
 }
 
 static void
-profile_dlg_select(GtkTreeView *profile_l, gpointer main_w_arg)
+profile_apply(GtkWidget *main_w, GtkTreeView *profile_l, gboolean destroy)
 {
-  GtkWidget *main_w = GTK_WIDGET(main_w_arg);
+  char        *pf_dir_path, *pf_dir_path2, *pf_filename;
+  GList       *fl1, *fl2;
+  profile_def *profile1, *profile2;
+  gboolean     found;
 
-  profile_select(main_w, profile_l, TRUE);
-}
+  /* First validate all profile names */
+  fl1 = g_list_first(edited_profiles);
+  while (fl1) {
+    profile1 = (profile_def *) fl1->data;
+    g_strstrip(profile1->name);
+    if (profile_is_invalid_name(profile1->name)) {
+      return;
+    }
+    fl1 = g_list_next(fl1);
+  }
 
-static void
-profile_apply(GtkWidget *main_w, gboolean destroy)
-{
-  GtkTreeView  *profile_l = GTK_TREE_VIEW(OBJECT_GET_DATA(main_w, E_PROF_PROFILE_L_KEY));
+  /* Then do all copy profiles */
+  fl1 = g_list_first(edited_profiles);
+  while (fl1) {
+    profile1 = (profile_def *) fl1->data;
+    g_strstrip(profile1->name);
+    if (profile1->status == PROF_STAT_COPY) {
+      if (create_persconffile_profile(profile1->name, &pf_dir_path) == -1) {
+        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+                      "Can't create directory\n\"%s\":\n%s.",
+                      pf_dir_path, g_strerror(errno));
+        
+        g_free(pf_dir_path);
+      }
+      profile1->status = PROF_STAT_EXISTS;
+
+      if (profile1->reference) {
+        if (copy_persconffile_profile(profile1->name, profile1->reference, profile1->from_global,
+                                     &pf_filename, &pf_dir_path, &pf_dir_path2) == -1) {
+          simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+                        "Can't copy file \"%s\" in directory\n\"%s\" to\n\"%s\":\n%s.",
+                        pf_filename, pf_dir_path2, pf_dir_path, g_strerror(errno));
+
+          g_free(pf_filename);
+          g_free(pf_dir_path);
+          g_free(pf_dir_path2);
+        }
+      }
 
-  profile_select(main_w, profile_l, destroy);
-}
+      g_free (profile1->reference);
+      profile1->reference = g_strdup(profile1->name);
+    }
+    fl1 = g_list_next(fl1);
+  }
 
-static void
-profile_dlg_save(void)
-{
-  char        *pf_dir_path, *pf_dir_path2;
-  GList       *fl1, *fl2;
-  profile_def *profile1, *profile2;
-  gboolean     found;
 
+  /* Then create new and rename changed */
   fl1 = g_list_first(edited_profiles);
   while (fl1) {
-    found = FALSE;
     profile1 = (profile_def *) fl1->data;
+    g_strstrip(profile1->name);
     if (profile1->status == PROF_STAT_NEW) {
       /* We do not create a directory for the default profile */
       if (strcmp(profile1->name, DEFAULT_PROFILE)!=0) {
        if (create_persconffile_profile(profile1->name, &pf_dir_path) == -1) {
          simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
                        "Can't create directory\n\"%s\":\n%s.",
-                       pf_dir_path, strerror(errno));
-         
+                       pf_dir_path, g_strerror(errno));
+
          g_free(pf_dir_path);
        }
        profile1->status = PROF_STAT_EXISTS;
+
+       g_free (profile1->reference);
+       profile1->reference = g_strdup(profile1->name);
       }
     } else if (profile1->status == PROF_STAT_CHANGED) {
       if (strcmp(profile1->reference, profile1->name)!=0) {
@@ -292,16 +436,20 @@ profile_dlg_save(void)
                                        &pf_dir_path, &pf_dir_path2) == -1) {
          simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
                        "Can't rename directory\n\"%s\" to\n\"%s\":\n%s.",
-                       pf_dir_path, pf_dir_path2, strerror(errno));
-         
+                       pf_dir_path, pf_dir_path2, g_strerror(errno));
+
          g_free(pf_dir_path);
+         g_free(pf_dir_path2);
        }
        profile1->status = PROF_STAT_EXISTS;
+       g_free (profile1->reference);
+       profile1->reference = g_strdup(profile1->name);
       }
     }
     fl1 = g_list_next(fl1);
   }
-      
+
+  /* Last remove deleted */
   fl1 = g_list_first(current_profiles);
   while (fl1) {
     found = FALSE;
@@ -309,12 +457,14 @@ profile_dlg_save(void)
     fl2 = g_list_first(edited_profiles);
     while (fl2) {
       profile2 = (profile_def *) fl2->data;
-      if (strcmp(profile1->name, profile2->name)==0) {
-       /* Profile exists in both lists */
-       found = TRUE;
-      } else if (strcmp(profile1->name, profile2->reference)==0) {
-       /* Profile has been renamed */
-       found = TRUE;
+      if (!profile2->is_global) {
+       if (strcmp(profile1->name, profile2->name)==0) {
+         /* Profile exists in both lists */
+         found = TRUE;
+       } else if (strcmp(profile1->name, profile2->reference)==0) {
+         /* Profile has been renamed */
+         found = TRUE;
+       }
       }
       fl2 = fl2->next;
     }
@@ -323,7 +473,7 @@ profile_dlg_save(void)
       if (delete_persconffile_profile(profile1->name, &pf_dir_path) == -1) {
        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
                      "Can't delete profile directory\n\"%s\":\n%s.",
-                     pf_dir_path, strerror(errno));
+                     pf_dir_path, g_strerror(errno));
 
        g_free(pf_dir_path);
       }
@@ -332,28 +482,31 @@ profile_dlg_save(void)
   }
 
   copy_profile_list();
+  profile_select(main_w, profile_l, destroy);
 }
 
 static void
 profile_dlg_ok_cb(GtkWidget *ok_bt, gpointer data _U_)
 {
-  profile_dlg_save();
+  GtkWidget    *main_w = gtk_widget_get_toplevel(ok_bt);
+  GtkTreeView  *profile_l = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY));
 
   /*
-   * Destroy the dialog box and apply the profile.
+   * Apply the profile and destroy the dialog box.
    */
-  profile_apply(gtk_widget_get_toplevel(ok_bt), TRUE);
+  profile_apply(main_w, profile_l, TRUE);
 }
 
 static void
 profile_dlg_apply_cb(GtkWidget *apply_bt, gpointer data _U_)
 {
-  profile_dlg_save();
+  GtkWidget    *main_w    = gtk_widget_get_toplevel(apply_bt);
+  GtkTreeView  *profile_l = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY));
 
   /*
    * Apply the profile, but don't destroy the dialog box.
    */
-  profile_apply(gtk_widget_get_toplevel(apply_bt), FALSE);
+  profile_apply(main_w, profile_l, FALSE);
 }
 
 /* cancel button pressed, revert changes and exit dialog */
@@ -382,36 +535,25 @@ profile_dlg_destroy_cb(GtkWidget *w _U_, gpointer data _U_)
 }
 
 
-static gint
-profile_sel_list_button_cb(GtkWidget *list, GdkEventButton *event,
-                          gpointer data _U_)
+static gboolean
+profile_button_press_cb(GtkWidget *list, GdkEventButton *event, gpointer data _U_)
 {
-  void (* func)(GtkWidget *, gpointer);
-  gpointer func_arg;
-
   if (event->type == GDK_2BUTTON_PRESS) {
-    func = OBJECT_GET_DATA(list, E_PROF_SELFUNC_KEY);
-    func_arg = OBJECT_GET_DATA(list, E_PROF_SELARG_KEY);
+    GtkWidget *main_w = gtk_widget_get_toplevel(list);
 
-    if (func)
-      (*func)(list, func_arg);
+    profile_apply (main_w, GTK_TREE_VIEW(list), TRUE);
   }
 
   return FALSE;
 }
 
-static gint
+static gboolean
 profile_key_release_cb(GtkWidget *list, GdkEventKey *event, gpointer data _U_)
 {
-  void (* func)(GtkWidget *, gpointer);
-  gpointer func_arg;
-
   if (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter) {
-    func = OBJECT_GET_DATA(list, E_PROF_SELFUNC_KEY);
-    func_arg = OBJECT_GET_DATA(list, E_PROF_SELARG_KEY);
+    GtkWidget    *main_w = gtk_widget_get_toplevel(list);
 
-    if (func)
-      (*func)(list, func_arg);
+    profile_apply (main_w, GTK_TREE_VIEW(list), TRUE);
   }
 
   return FALSE;
@@ -420,24 +562,23 @@ profile_key_release_cb(GtkWidget *list, GdkEventKey *event, gpointer data _U_)
 static void
 profile_sel_list_cb(GtkTreeSelection *sel, gpointer data _U_)
 {
-  GtkWidget    *profile_l = GTK_WIDGET(gtk_tree_selection_get_tree_view(sel));
-  GtkWidget    *main_w = gtk_widget_get_toplevel(profile_l);
+  GtkWidget    *profile_l   = GTK_WIDGET(gtk_tree_selection_get_tree_view(sel));
+  GtkWidget    *main_w      = gtk_widget_get_toplevel(profile_l);
   GtkTreeModel *model;
   GtkTreeIter   iter;
-  GtkWidget    *name_te = OBJECT_GET_DATA(main_w, E_PROF_NAME_TE_KEY);
-  GtkWidget    *copy_bt = OBJECT_GET_DATA(main_w, E_PROF_COPY_BT_KEY);
-  GtkWidget    *del_bt = OBJECT_GET_DATA(main_w, E_PROF_DEL_BT_KEY);
+  GtkWidget    *name_te     = g_object_get_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY);
+  GtkWidget    *del_bt      = g_object_get_data(G_OBJECT(main_w), E_PROF_DEL_BT_KEY);
   profile_def  *profile;
-  gchar        *name = NULL;
+  gchar        *name        = NULL;
   GList        *fl_entry;
   gint          sensitivity = FALSE;
 
   if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
-    gtk_tree_model_get(model, &iter, 1, &fl_entry, -1);
+    gtk_tree_model_get(model, &iter, DATA_COLUMN, &fl_entry, -1);
     if (fl_entry) {
-      profile= (profile_def *) fl_entry->data;
-      name   = g_strdup(profile->name);
-      if (profile->status!=PROF_STAT_DEFAULT) {
+      profile = (profile_def *) fl_entry->data;
+      name = g_strdup(profile->name);
+      if ((profile->status != PROF_STAT_DEFAULT) && !profile->is_global) {
        sensitivity = TRUE;
       }
     }
@@ -465,31 +606,28 @@ profile_sel_list_cb(GtkTreeSelection *sel, gpointer data _U_)
     gtk_entry_set_text(GTK_ENTRY(name_te), name ? name : "");
     gtk_widget_set_sensitive(name_te, sensitivity);
   }
-  if (copy_bt != NULL)
-    gtk_widget_set_sensitive(copy_bt, sensitivity);
   if (del_bt != NULL)
     gtk_widget_set_sensitive(del_bt, sensitivity);
-  if (name != NULL)
-    g_free(name);
+  g_free(name);
 }
 
 static void
 profile_new_bt_clicked_cb(GtkWidget *w, gpointer data _U_)
 {
   GtkWidget    *main_w = gtk_widget_get_toplevel(w);
-  GtkWidget    *name_te = OBJECT_GET_DATA(main_w, E_PROF_NAME_TE_KEY);
-  GtkTreeView  *profile_l = GTK_TREE_VIEW(OBJECT_GET_DATA(main_w, E_PROF_PROFILE_L_KEY));
+  GtkWidget    *name_te = g_object_get_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY);
+  GtkTreeView  *profile_l = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY));
   GtkListStore *store;
   GtkTreeIter   iter;
   GList        *fl_entry;
   const gchar  *name = "New profile";
 
   /* Add a new entry to the profile list. */
-  fl_entry = add_to_profile_list(name, "", PROF_STAT_NEW);
+  fl_entry = add_to_profile_list(name, "", PROF_STAT_NEW, FALSE, FALSE);
 
   store = GTK_LIST_STORE(gtk_tree_view_get_model(profile_l));
   gtk_list_store_append(store, &iter);
-  gtk_list_store_set(store, &iter, 0, name, 1, fl_entry, -1);
+  gtk_list_store_set(store, &iter, NAME_COLUMN, name, GLOBAL_COLUMN, FALSE, DATA_COLUMN, fl_entry, -1);
   /* Select the item. */
   gtk_tree_selection_select_iter(gtk_tree_view_get_selection(profile_l), &iter);
 
@@ -497,27 +635,49 @@ profile_new_bt_clicked_cb(GtkWidget *w, gpointer data _U_)
   gtk_widget_grab_focus(name_te);
 }
 
-#if 0
 static void
 profile_copy_bt_clicked_cb(GtkWidget *w, gpointer data _U_)
 {
   GtkWidget    *main_w = gtk_widget_get_toplevel(w);
-  GtkWidget    *name_te = OBJECT_GET_DATA(main_w, E_PROF_NAME_TE_KEY);
-  GtkTreeView  *profile_l = GTK_TREE_VIEW(OBJECT_GET_DATA(main_w, E_PROF_PROFILE_L_KEY));
+  GtkWidget    *name_te = g_object_get_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY);
+  GtkTreeView  *profile_l = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY));
   GtkListStore *store;
   GtkTreeIter   iter;
   GList        *fl_entry;
   const gchar  *name = gtk_entry_get_text(GTK_ENTRY(name_te));
+  const gchar  *parent = NULL;
   gchar        *new_name;
 
-  new_name = g_strdup_printf ("%s (copy)", name);
+  GtkTreeSelection *sel;
+  GtkTreeModel     *model;
+  profile_def   *profile = NULL;
+
+  sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(profile_l));
+  if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
+    gtk_tree_model_get(model, &iter, DATA_COLUMN, &fl_entry, -1);
+    if (fl_entry) {
+      profile = (profile_def *) fl_entry->data;
+    }
+  }
+
+  if (profile && profile->is_global) {
+    parent = profile->name;
+  } else {
+    parent = get_profile_parent (name);
+  }
+
+  if (profile && profile->is_global && !profile_exists (parent, FALSE)) {
+    new_name = g_strdup (name);
+  } else {
+    new_name = g_strdup_printf ("%s (copy)", name);
+  }
 
   /* Add a new entry to the profile list. */
-  fl_entry = add_to_profile_list(new_name, name, PROF_STAT_COPY);
+  fl_entry = add_to_profile_list(new_name, parent, PROF_STAT_COPY, FALSE, profile ? profile->from_global : FALSE);
 
   store = GTK_LIST_STORE(gtk_tree_view_get_model(profile_l));
   gtk_list_store_append(store, &iter);
-  gtk_list_store_set(store, &iter, 0, new_name, 1, fl_entry, -1);
+  gtk_list_store_set(store, &iter, NAME_COLUMN, new_name, GLOBAL_COLUMN, FALSE, DATA_COLUMN, fl_entry, -1);
   /* Select the item. */
   gtk_tree_selection_select_iter(gtk_tree_view_get_selection(profile_l), &iter);
 
@@ -526,14 +686,13 @@ profile_copy_bt_clicked_cb(GtkWidget *w, gpointer data _U_)
 
   g_free (new_name);
 }
-#endif
 
 static void
 profile_name_te_changed_cb(GtkWidget *w, gpointer data _U_)
 {
   GtkWidget   *main_w = gtk_widget_get_toplevel(w);
-  GtkWidget   *name_te = OBJECT_GET_DATA(main_w, E_PROF_NAME_TE_KEY);
-  GtkWidget   *profile_l = OBJECT_GET_DATA(main_w, E_PROF_PROFILE_L_KEY);
+  GtkWidget   *name_te = g_object_get_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY);
+  GtkWidget   *profile_l = g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY);
   profile_def *profile;
   GList       *fl_entry;
   const gchar *name = "";
@@ -547,18 +706,19 @@ profile_name_te_changed_cb(GtkWidget *w, gpointer data _U_)
 
   /* if something was selected */
   if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
-    gtk_tree_model_get(model, &iter, 1, &fl_entry, -1);
+    gtk_tree_model_get(model, &iter, DATA_COLUMN, &fl_entry, -1);
     if (fl_entry != NULL) {
       profile = (profile_def *) fl_entry->data;
-      
-      if (strlen(name) > 0 && profile) {
+
+      if (strlen(name) > 0 && profile && !profile->is_global) {
        if (profile->status != PROF_STAT_DEFAULT) {
          g_free(profile->name);
          profile->name = g_strdup(name);
-         if (profile->status != PROF_STAT_NEW) {
+         if ((profile->status != PROF_STAT_NEW) &&
+             (profile->status != PROF_STAT_COPY)) {
            profile->status = PROF_STAT_CHANGED;
          }
-         gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, name, -1);
+         gtk_list_store_set(GTK_LIST_STORE(model), &iter, NAME_COLUMN, name, -1);
        }
       }
     }
@@ -569,7 +729,7 @@ static void
 profile_del_bt_clicked_cb(GtkWidget *w, gpointer data _U_)
 {
   GtkWidget  *main_w = gtk_widget_get_toplevel(w);
-  GtkWidget  *profile_l = OBJECT_GET_DATA(main_w, E_PROF_PROFILE_L_KEY);
+  GtkWidget  *profile_l = g_object_get_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY);
   GList      *fl_entry;
 
   GtkTreeSelection  *sel;
@@ -579,7 +739,7 @@ profile_del_bt_clicked_cb(GtkWidget *w, gpointer data _U_)
   sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(profile_l));
   /* If something was selected */
   if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
-    gtk_tree_model_get(model, &iter, 1, &fl_entry, -1);
+    gtk_tree_model_get(model, &iter, DATA_COLUMN, &fl_entry, -1);
 
     if (fl_entry != NULL) {
       remove_from_profile_list (fl_entry);
@@ -607,9 +767,7 @@ profile_dialog_new(void)
   GtkWidget  *top_hb,
     *list_bb,
     *new_bt,
-#if 0
     *copy_bt,
-#endif
     *del_bt,
     *profile_sc,
     *profile_l,
@@ -619,30 +777,28 @@ profile_dialog_new(void)
     *profile_fr,
     *edit_fr,
     *props_fr;
-  GtkTooltips       *tooltips;
   GtkListStore      *store;
   GtkCellRenderer   *renderer;
   GtkTreeViewColumn *column;
   GtkTreeSelection  *sel;
   GtkTreeIter       *l_select;
+  gboolean           has_global = has_global_profiles();
   
   /* Get a pointer to a static variable holding the type of profile on
      which we're working, so we can pass that pointer to callback
      routines. */
-  
-  tooltips = gtk_tooltips_new ();
-  
-  main_w = dlg_window_new("Wireshark: Configuration Profiles");
+
+  main_w = dlg_conf_window_new("Wireshark: Configuration Profiles");
   gtk_window_set_default_size(GTK_WINDOW(main_w), 400, 400);
-  
+
   main_vb = gtk_vbox_new(FALSE, 0);
-  gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
+  gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
   gtk_container_add(GTK_CONTAINER(main_w), main_vb);
   gtk_widget_show(main_vb);
 
   /* Container for each row of widgets */
   profile_vb = gtk_vbox_new(FALSE, 0);
-  gtk_container_border_width(GTK_CONTAINER(profile_vb), 0);
+  gtk_container_set_border_width(GTK_CONTAINER(profile_vb), 0);
   gtk_container_add(GTK_CONTAINER(main_vb), profile_vb);
   gtk_widget_show(profile_vb);
 
@@ -656,35 +812,29 @@ profile_dialog_new(void)
   gtk_widget_show(edit_fr);
 
   list_bb = gtk_vbox_new(TRUE, 0);
-  gtk_container_border_width(GTK_CONTAINER(list_bb), 5);
+  gtk_container_set_border_width(GTK_CONTAINER(list_bb), 5);
   gtk_container_add(GTK_CONTAINER(edit_fr), list_bb);
   gtk_widget_show(list_bb);
 
-  new_bt = BUTTON_NEW_FROM_STOCK(GTK_STOCK_NEW);
-  SIGNAL_CONNECT(new_bt, "clicked", profile_new_bt_clicked_cb, NULL);
+  new_bt = gtk_button_new_from_stock(GTK_STOCK_NEW);
+  g_signal_connect(new_bt, "clicked", G_CALLBACK(profile_new_bt_clicked_cb), NULL);
   gtk_widget_show(new_bt);
   gtk_box_pack_start (GTK_BOX (list_bb), new_bt, FALSE, FALSE, 0);
-  gtk_tooltips_set_tip (tooltips, new_bt,
-                       "Create a new profile (with default properties)", NULL);
-
-#if 0
-  copy_bt = BUTTON_NEW_FROM_STOCK(GTK_STOCK_COPY);
-  gtk_widget_set_sensitive(copy_bt, FALSE);
-  SIGNAL_CONNECT(copy_bt, "clicked", profile_copy_bt_clicked_cb, NULL);
-  OBJECT_SET_DATA(main_w, E_PROF_COPY_BT_KEY, copy_bt);
+  gtk_widget_set_tooltip_text (new_bt, "Create a new profile (with default properties)");
+
+  copy_bt = gtk_button_new_from_stock(GTK_STOCK_COPY);
+  g_signal_connect(copy_bt, "clicked", G_CALLBACK(profile_copy_bt_clicked_cb), NULL);
   gtk_widget_show(copy_bt);
   gtk_box_pack_start (GTK_BOX (list_bb), copy_bt, FALSE, FALSE, 0);
-  gtk_tooltips_set_tip (tooltips, copy_bt,
-                       "Copy the selected profile", NULL);
-#endif
+  gtk_widget_set_tooltip_text (copy_bt,        "Copy the selected profile");
 
-  del_bt = BUTTON_NEW_FROM_STOCK(GTK_STOCK_DELETE);
+  del_bt = gtk_button_new_from_stock(GTK_STOCK_DELETE);
   gtk_widget_set_sensitive(del_bt, FALSE);
-  SIGNAL_CONNECT(del_bt, "clicked", profile_del_bt_clicked_cb, NULL);
-  OBJECT_SET_DATA(main_w, E_PROF_DEL_BT_KEY, del_bt);
+  g_signal_connect(del_bt, "clicked", G_CALLBACK(profile_del_bt_clicked_cb), NULL);
+  g_object_set_data(G_OBJECT(main_w), E_PROF_DEL_BT_KEY, del_bt);
   gtk_widget_show(del_bt);
   gtk_box_pack_start (GTK_BOX (list_bb), del_bt, FALSE, FALSE, 0);
-  gtk_tooltips_set_tip (tooltips, del_bt, "Delete the selected profile", NULL);
+  gtk_widget_set_tooltip_text (del_bt, "Delete the selected profile");
 
   profile_fr = gtk_frame_new("Configuration Profiles");
   gtk_box_pack_start(GTK_BOX(top_hb), profile_fr, TRUE, TRUE, 0);
@@ -698,25 +848,32 @@ profile_dialog_new(void)
   gtk_container_add(GTK_CONTAINER(profile_fr), profile_sc);
   gtk_widget_show(profile_sc);
 
-  store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
+  store = gtk_list_store_new(NUM_COLUMNS, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_POINTER);
   profile_l = tree_view_new(GTK_TREE_MODEL(store));
-  gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(profile_l), FALSE);
+  /* Only show headers if having more than one column */
+  gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(profile_l), has_global);
+
   renderer = gtk_cell_renderer_text_new();
-  column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, NULL);
-  gtk_tree_view_column_set_sort_column_id(column, 0);
+  column = gtk_tree_view_column_new_with_attributes("Name", renderer, "text", NAME_COLUMN, NULL);
+  gtk_tree_view_column_set_expand(column, TRUE);
+  gtk_tree_view_column_set_sort_column_id(column, NAME_COLUMN);
+  gtk_tree_view_append_column(GTK_TREE_VIEW(profile_l), column);
+
+  renderer = gtk_cell_renderer_toggle_new();
+  column = gtk_tree_view_column_new_with_attributes("Global", renderer, "active", GLOBAL_COLUMN, NULL);
   gtk_tree_view_append_column(GTK_TREE_VIEW(profile_l), column);
+  gtk_widget_set_tooltip_text(gtk_tree_view_column_get_button(column), "Global profiles will be copied to users profiles when used");
+  gtk_tree_view_column_set_visible(column, has_global);
+
   sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(profile_l));
   gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
-  SIGNAL_CONNECT(sel, "changed", profile_sel_list_cb, profile_vb);
-  SIGNAL_CONNECT(profile_l, "button_press_event", profile_sel_list_button_cb, NULL);
-  SIGNAL_CONNECT(profile_l, "key_release_event", profile_key_release_cb, NULL);
-  OBJECT_SET_DATA(main_w, E_PROF_PROFILE_L_KEY, profile_l);
+  g_signal_connect(sel, "changed", G_CALLBACK(profile_sel_list_cb), profile_vb);
+  g_signal_connect(profile_l, "button_press_event", G_CALLBACK(profile_button_press_cb), NULL);
+  g_signal_connect(profile_l, "key_release_event", G_CALLBACK(profile_key_release_cb), NULL);
+  g_object_set_data(G_OBJECT(main_w), E_PROF_PROFILE_L_KEY, profile_l);
   gtk_container_add(GTK_CONTAINER(profile_sc), profile_l);
   gtk_widget_show(profile_l);
 
-  OBJECT_SET_DATA(profile_l, E_PROF_SELFUNC_KEY, profile_dlg_select);
-  OBJECT_SET_DATA(profile_l, E_PROF_SELARG_KEY, main_w);
-
   /* fill in data */
   l_select = fill_list(main_w);
 
@@ -727,7 +884,7 @@ profile_dialog_new(void)
   gtk_widget_show(props_fr);
 
   props_vb = gtk_vbox_new(FALSE, 3);
-  gtk_container_border_width(GTK_CONTAINER(props_vb), 5);
+  gtk_container_set_border_width(GTK_CONTAINER(props_vb), 5);
   gtk_container_add(GTK_CONTAINER(props_fr), props_vb);
   gtk_widget_show(props_vb);
 
@@ -742,8 +899,13 @@ profile_dialog_new(void)
 
   name_te = gtk_entry_new();
   gtk_box_pack_start(GTK_BOX(middle_hb), name_te, TRUE, TRUE, 0);
-  OBJECT_SET_DATA(main_w, E_PROF_NAME_TE_KEY, name_te);
-  SIGNAL_CONNECT(name_te, "changed", profile_name_te_changed_cb, NULL);
+  g_object_set_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY, name_te);
+  g_signal_connect(name_te, "changed", G_CALLBACK(profile_name_te_changed_cb), NULL);
+#ifdef _WIN32
+  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   \\ / : * ? \" < > |");
+#else
+  gtk_widget_set_tooltip_text (name_te, "A profile name cannot contain the '/' character");
+#endif
   gtk_widget_show(name_te);
 
   /* button row (create all possible buttons and hide the unrequired later - it's a lot easier) */
@@ -751,9 +913,9 @@ profile_dialog_new(void)
   gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 5);
   gtk_widget_show(bbox);
 
-  ok_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_OK);
-  SIGNAL_CONNECT(ok_bt, "clicked", profile_dlg_ok_cb, NULL);
-  gtk_tooltips_set_tip (tooltips, ok_bt, "Apply the profiles and close this dialog", NULL);
+  ok_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_OK);
+  g_signal_connect(ok_bt, "clicked", G_CALLBACK(profile_dlg_ok_cb), NULL);
+  gtk_widget_set_tooltip_text (ok_bt, "Apply the profiles and close this dialog");
 
   /* Catch the "activate" signal on the profile name and profile
      list entries, so that if the user types Return
@@ -762,18 +924,18 @@ profile_dialog_new(void)
      handle the Return key has the input focus. */
   dlg_set_activate(name_te, ok_bt);
 
-  apply_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_APPLY);
-  SIGNAL_CONNECT(apply_bt, "clicked", profile_dlg_apply_cb, NULL);
-  gtk_tooltips_set_tip (tooltips, apply_bt, "Apply the profiles and keep this dialog open", NULL);
+  apply_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_APPLY);
+  g_signal_connect(apply_bt, "clicked", G_CALLBACK(profile_dlg_apply_cb), NULL);
+  gtk_widget_set_tooltip_text (apply_bt, "Apply the profiles and keep this dialog open");
 
-  cancel_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_CANCEL);
-  gtk_tooltips_set_tip (tooltips, cancel_bt, "Cancel the changes", NULL);
-  SIGNAL_CONNECT(cancel_bt, "clicked", profile_dlg_cancel_cb, NULL);
+  cancel_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CANCEL);
+  gtk_widget_set_tooltip_text (cancel_bt, "Cancel the changes");
+  g_signal_connect(cancel_bt, "clicked", G_CALLBACK(profile_dlg_cancel_cb), NULL);
   window_set_cancel_button(main_w, cancel_bt, NULL);
 
-  help_bt = OBJECT_GET_DATA(bbox, GTK_STOCK_HELP);
-  SIGNAL_CONNECT(help_bt, "clicked", topic_cb, HELP_CONFIG_PROFILES_DIALOG);
-  gtk_tooltips_set_tip (tooltips, help_bt, "Show topic specific help", NULL);
+  help_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
+  g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb), (gpointer)HELP_CONFIG_PROFILES_DIALOG);
+  gtk_widget_set_tooltip_text (help_bt, "Show topic specific help");
 
   if(ok_bt) {
     gtk_widget_grab_default(ok_bt);
@@ -791,8 +953,8 @@ profile_dialog_new(void)
     gtk_widget_grab_focus(profile_l);
   }
 
-  SIGNAL_CONNECT(main_w, "delete_event", profile_dlg_delete_event_cb, NULL);
-  SIGNAL_CONNECT(main_w, "destroy", profile_dlg_destroy_cb, NULL);
+  g_signal_connect(main_w, "delete_event", G_CALLBACK(profile_dlg_delete_event_cb), NULL);
+  g_signal_connect(main_w, "destroy", G_CALLBACK(profile_dlg_destroy_cb), NULL);
 
   gtk_widget_show(main_w);
 
@@ -801,15 +963,404 @@ profile_dialog_new(void)
   return main_w;
 }
 
+
+static void
+select_profile_cb (GtkWidget *w _U_, gpointer data)
+{
+  const gchar *current_profile = get_profile_name ();
+  gchar       *selected_profile = (gchar *) data;
+
+  if (strcmp (selected_profile, current_profile) != 0) {
+    change_configuration_profile (selected_profile);
+  }
+}
+
+gboolean
+profile_show_popup_cb (GtkWidget *w _U_, GdkEvent *event, gpointer user_data _U_)
+{
+  GdkEventButton *bevent = (GdkEventButton *)event;
+  const gchar    *profile_name = get_profile_name ();
+  const gchar    *profiles_dir, *name;
+  WS_DIR         *dir;             /* scanned directory */
+  WS_DIRENT      *file;            /* current file */
+  GtkWidget      *menu;
+  GtkWidget      *menu_item;
+
+  menu = gtk_menu_new ();
+
+  if (bevent->button != 1) {
+    GtkWidget *change_menu = menus_get_profiles_change_menu ();
+
+#if GTK_CHECK_VERSION(2,16,0)
+    GtkWidget *edit_menu = menus_get_profiles_edit_menu ();
+    GtkWidget *delete_menu = menus_get_profiles_delete_menu ();
+    if (strcmp (profile_name, DEFAULT_PROFILE) != 0) {
+      gchar *label;
+      label = g_strdup_printf ("Edit \"%s\"...", profile_name);
+      gtk_menu_item_set_label (GTK_MENU_ITEM(edit_menu), label);
+      g_free (label);
+      label = g_strdup_printf ("Delete \"%s\"", profile_name);
+      gtk_menu_item_set_label (GTK_MENU_ITEM(delete_menu), label);
+      g_free (label);
+    } else {
+      gtk_menu_item_set_label (GTK_MENU_ITEM(edit_menu), "Edit...");
+      gtk_menu_item_set_label (GTK_MENU_ITEM(delete_menu), "Delete");
+    }
+#endif
+    gtk_menu_item_set_submenu (GTK_MENU_ITEM(change_menu), menu);
+  }
+
+  /* Add a menu item for the Default profile */
+  menu_item = gtk_check_menu_item_new_with_label (DEFAULT_PROFILE);
+  if (strcmp (profile_name, DEFAULT_PROFILE) == 0) {
+    /* Check current profile */
+    gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(menu_item), TRUE);
+  }
+  g_object_set (G_OBJECT(menu_item), "draw-as-radio", TRUE, NULL);
+  g_signal_connect (menu_item, "activate", G_CALLBACK(select_profile_cb), g_strdup (DEFAULT_PROFILE));
+  gtk_menu_shell_append (GTK_MENU_SHELL(menu), menu_item);
+  gtk_widget_show (menu_item);
+
+  profiles_dir = get_profiles_dir();
+  if ((dir = ws_dir_open(profiles_dir, 0, NULL)) != NULL) {
+    while ((file = ws_dir_read_name(dir)) != NULL) {
+      name = ws_dir_get_name(file);
+
+      if (profile_exists(name, FALSE)) {
+       menu_item = gtk_check_menu_item_new_with_label (name);
+       if (strcmp (name, profile_name)==0) {
+         /* Check current profile */
+         gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM(menu_item), TRUE);
+       }
+       g_object_set (G_OBJECT(menu_item), "draw-as-radio", TRUE, NULL);
+       g_signal_connect (menu_item, "activate", G_CALLBACK(select_profile_cb), g_strdup (name));
+       gtk_menu_shell_append  (GTK_MENU_SHELL (menu), menu_item);
+       gtk_widget_show (menu_item);
+      }
+    }
+    ws_dir_close (dir);
+  }
+
+  profiles_dir = get_global_profiles_dir();
+  if ((dir = ws_dir_open(profiles_dir, 0, NULL)) != NULL) {
+    GtkWidget *sub_menu = NULL;
+    gboolean   added_submenu = FALSE;
+  
+    while ((file = ws_dir_read_name(dir)) != NULL) {
+      name = ws_dir_get_name(file);
+
+      if (profile_exists(name, TRUE)) {
+       if (!added_submenu) {
+         menu_item =  gtk_separator_menu_item_new ();
+         gtk_menu_shell_append  (GTK_MENU_SHELL (menu), menu_item);
+         gtk_widget_show (menu_item);
+         
+         menu_item = gtk_menu_item_new_with_label ("New from Global");
+         gtk_menu_shell_append  (GTK_MENU_SHELL (menu), menu_item);
+         gtk_widget_show (menu_item);
+
+         sub_menu = gtk_menu_new ();
+         gtk_menu_item_set_submenu (GTK_MENU_ITEM(menu_item), sub_menu);
+
+         added_submenu = TRUE;
+       }
+
+       menu_item = gtk_menu_item_new_with_label (name);
+       g_signal_connect (menu_item, "activate", G_CALLBACK(select_profile_cb), g_strdup (name));
+       if (profile_exists(name, FALSE)) {
+         gtk_widget_set_sensitive(menu_item, FALSE);
+       }
+       gtk_menu_shell_append  (GTK_MENU_SHELL (sub_menu), menu_item);
+       gtk_widget_show (menu_item);
+      }
+    }
+    ws_dir_close (dir);
+  }
+
+  if (bevent->button != 1) {
+    /* Second-click is handled in popup_menu_handler() */
+    return FALSE;
+  }
+
+  gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL,
+                 bevent->button, bevent->time);
+
+  return TRUE;
+}
+
+static void
+profile_name_edit_ok (GtkWidget *w _U_, gpointer parent_w)
+{
+  gint operation = GPOINTER_TO_INT(g_object_get_data (G_OBJECT(w), "operation"));
+  GtkComboBox  *combo_box = g_object_get_data (G_OBJECT(w), "create_from");
+  GtkWidget    *entry = g_object_get_data (G_OBJECT(w), "entry");
+  GtkTreeStore *store;
+  GtkTreeIter iter;
+  const gchar *new_name =  gtk_entry_get_text(GTK_ENTRY(entry));
+  const gchar *profile_name = "";
+  gboolean     from_global = FALSE;
+  char        *pf_dir_path, *pf_dir_path2, *pf_filename;
+
+  if (strlen(new_name) == 0 || profile_is_invalid_name(new_name)) {
+    return;
+  }
+
+  switch (operation) {
+  case PROF_OPERATION_NEW:
+    if (gtk_combo_box_get_active_iter(combo_box, &iter)) {
+      store = GTK_TREE_STORE(gtk_combo_box_get_model(combo_box));
+      gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 0, &profile_name, 1, &from_global, -1);
+    }
+    break;
+  case PROF_OPERATION_EDIT:
+    profile_name = get_profile_name();
+    if (strcmp(new_name, profile_name) == 0) {
+      /* Rename without a change, do nothing */
+      window_destroy(GTK_WIDGET(parent_w));
+      return;
+    }
+    break;
+  default:
+    g_assert_not_reached();
+  }
+
+  if (profile_exists (new_name, FALSE)) {
+    simple_dialog(ESD_TYPE_WARN, ESD_BTN_OK,
+                 "The profile already exists:\n%s.", new_name);
+    return;
+  }
+
+  /* Write recent file for profile we are leaving */
+  write_profile_recent();
+
+  switch (operation) {
+  case PROF_OPERATION_NEW:
+    if (create_persconffile_profile(new_name, &pf_dir_path) == -1) {
+      simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+                   "Can't create directory\n\"%s\":\n%s.",
+                   pf_dir_path, g_strerror(errno));
+      
+      g_free(pf_dir_path);
+    } else if (strlen (profile_name) && 
+              copy_persconffile_profile(new_name, profile_name, from_global, &pf_filename,
+                                        &pf_dir_path, &pf_dir_path2) == -1)
+    {
+      simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+                   "Can't copy file \"%s\" in directory\n\"%s\" to\n\"%s\":\n%s.",
+                   pf_filename, pf_dir_path2, pf_dir_path, g_strerror(errno));
+       
+      g_free(pf_filename);
+      g_free(pf_dir_path);
+      g_free(pf_dir_path2);
+    } else {
+      change_configuration_profile (new_name);
+    }
+    break;
+  case PROF_OPERATION_EDIT:
+    if (rename_persconffile_profile(profile_name, new_name,
+                                   &pf_dir_path, &pf_dir_path2) == -1) {
+      simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+                   "Can't rename directory\n\"%s\" to\n\"%s\":\n%s.",
+                   pf_dir_path, pf_dir_path2, g_strerror(errno));
+      
+      g_free(pf_dir_path);
+      g_free(pf_dir_path2);
+    } else {
+      change_configuration_profile (new_name);
+    }
+    break;
+  default:
+    g_assert_not_reached();
+  }
+
+  window_destroy(GTK_WIDGET(parent_w));
+}
+
+static void
+profile_name_edit_cancel (GtkWidget *w _U_, gpointer parent_w)
+{
+  window_destroy(GTK_WIDGET(parent_w));
+}
+
+static void
+profile_name_edit_dlg (gint operation)
+{
+  WS_DIR      *dir;             /* scanned directory */
+  WS_DIRENT   *file;            /* current file */
+  GtkWidget   *win, *main_tb, *main_vb, *bbox, *cancel_bt, *ok_bt;
+  GtkWidget   *entry, *label, *combo_box=NULL;
+  GtkCellRenderer *cell;
+  GtkTreeStore    *store;
+  GtkTreeIter   iter, parent;
+  gchar       *window_title=NULL;
+  const gchar *profile_name, *profiles_dir, *name;
+  gboolean     has_global = has_global_profiles();
+
+  profile_name = get_profile_name();
+
+  switch (operation) {
+  case PROF_OPERATION_NEW:
+    window_title = g_strdup ("Create New Profile");
+    break;
+  case PROF_OPERATION_EDIT:
+    window_title = g_strdup_printf ("Edit: %s", profile_name);
+    break;
+  default:
+    g_assert_not_reached();
+  }
+
+  win = dlg_window_new(window_title);
+  g_free (window_title);
+
+  gtk_window_set_resizable(GTK_WINDOW(win),FALSE);
+  gtk_window_resize(GTK_WINDOW(win), 400, 100);
+
+  main_vb = gtk_vbox_new(FALSE, 5);
+  gtk_container_add(GTK_CONTAINER(win), main_vb);
+  gtk_container_set_border_width(GTK_CONTAINER(main_vb), 6);
+
+  main_tb = gtk_table_new(2, 2, FALSE);
+  gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
+  gtk_table_set_col_spacings(GTK_TABLE(main_tb), 10);
+  gtk_table_set_row_spacings(GTK_TABLE(main_tb), 5);
+
+  if (operation == PROF_OPERATION_NEW) {
+    label = gtk_label_new("Create from:");
+    gtk_widget_set_tooltip_text (label, "All configuration files will be copied from this profile");
+    gtk_table_attach_defaults(GTK_TABLE(main_tb), label, 0, 1, 0, 1);
+    gtk_misc_set_alignment(GTK_MISC(label), 1.0f, 0.5f);
+
+    store = gtk_tree_store_new(3, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
+    combo_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL (store));
+    gtk_widget_set_tooltip_text (combo_box, "All configuration files will be copied from this profile");
+
+    cell = gtk_cell_renderer_text_new();
+    gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo_box), cell, TRUE);
+    gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo_box), cell,
+                                   "text", 0, "sensitive", 2,
+                                   NULL);
+
+    gtk_tree_store_append(store, &iter, NULL);
+    gtk_tree_store_set(store, &iter, 0, "", 1, FALSE, 2, TRUE, -1);
+
+    if (has_global) {
+      gtk_tree_store_append(store, &parent, NULL);
+      gtk_tree_store_set(store, &parent, 0, "Personal", 1, FALSE, 2, FALSE, -1);
+    }
+
+    gtk_tree_store_append(store, &iter, has_global ? &parent : NULL);
+    gtk_tree_store_set(store, &iter, 0, DEFAULT_PROFILE, 1, FALSE, 2, TRUE, -1);
+    profiles_dir = get_profiles_dir();
+    if ((dir = ws_dir_open(profiles_dir, 0, NULL)) != NULL) {
+      while ((file = ws_dir_read_name(dir)) != NULL) {
+       name = ws_dir_get_name(file);
+       if (profile_exists(name, FALSE)) {
+         gtk_tree_store_append(store, &iter, has_global ? &parent : NULL);
+         gtk_tree_store_set(store, &iter, 0, name, 1, FALSE, 2, TRUE, -1);
+       }
+      }
+      ws_dir_close (dir);
+    }
+
+    if (has_global) {
+      gtk_tree_store_append(store, &parent, NULL);
+      gtk_tree_store_set(store, &parent, 0, "Global", 1, FALSE, 2, FALSE, -1);
+      profiles_dir = get_global_profiles_dir();
+      if ((dir = ws_dir_open(profiles_dir, 0, NULL)) != NULL) {
+       while ((file = ws_dir_read_name(dir)) != NULL) {
+         name = ws_dir_get_name(file);
+         if (profile_exists(name, TRUE)) {
+           gtk_tree_store_append(store, &iter, &parent);
+           gtk_tree_store_set(store, &iter, 0, name, 1, TRUE, 2, TRUE, -1);
+         }
+       }
+       ws_dir_close (dir);
+      }
+    }
+    gtk_table_attach_defaults(GTK_TABLE(main_tb), combo_box, 1, 2, 0, 1);
+    g_object_unref(store);
+  }
+
+  label = gtk_label_new("Profile name:");
+  gtk_table_attach_defaults(GTK_TABLE(main_tb), label, 0, 1, 1, 2);
+  gtk_misc_set_alignment(GTK_MISC(label), 1.0f, 0.5f);
+
+  entry = gtk_entry_new();
+  gtk_table_attach_defaults(GTK_TABLE(main_tb), entry, 1, 2, 1, 2);
+  switch (operation) {
+  case PROF_OPERATION_NEW:
+    gtk_entry_set_text(GTK_ENTRY(entry), "New profile");
+    break;
+  case PROF_OPERATION_EDIT:
+    gtk_entry_set_text(GTK_ENTRY(entry), profile_name);
+    break;
+  default:
+    g_assert_not_reached();
+    break;
+  }
+#ifdef _WIN32
+  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   \\ / : * ? \" < > |");
+#else
+  gtk_widget_set_tooltip_text (entry, "A profile name cannot contain the '/' character");
 #endif
 
+  bbox = dlg_button_row_new(GTK_STOCK_CANCEL,GTK_STOCK_OK, NULL);
+  gtk_box_pack_end(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
+
+  ok_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_OK);
+  g_object_set_data (G_OBJECT(ok_bt), "entry", entry);
+  g_object_set_data (G_OBJECT(ok_bt), "create_from", combo_box);
+  g_object_set_data (G_OBJECT(ok_bt), "operation", GINT_TO_POINTER(operation));
+  g_signal_connect(ok_bt, "clicked", G_CALLBACK(profile_name_edit_ok), win);
+
+  dlg_set_activate(entry, ok_bt);
+  gtk_widget_grab_focus(entry);
+
+  cancel_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CANCEL);
+  g_signal_connect(cancel_bt, "clicked", G_CALLBACK(profile_name_edit_cancel), win);
+  window_set_cancel_button(win, cancel_bt, NULL);
+
+  gtk_widget_grab_default(ok_bt);
+  gtk_widget_show_all(win);
+}
+
+void
+profile_new_cb (GtkWidget *w _U_, gpointer data _U_)
+{
+  profile_name_edit_dlg (PROF_OPERATION_NEW);
+}
+
+void
+profile_delete_cb (GtkWidget *w _U_, gpointer data _U_)
+{
+  const gchar *name = get_profile_name();
+  char        *pf_dir_path;
+
+  if (profile_exists(name, FALSE) && strcmp (name, DEFAULT_PROFILE) != 0) {
+    if (delete_persconffile_profile(name, &pf_dir_path) == -1) {
+      simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+                   "Can't delete profile directory\n\"%s\":\n%s.",
+                   pf_dir_path, g_strerror(errno));
+      
+      g_free(pf_dir_path);
+    }
+
+    /* Change to the default profile */
+    change_configuration_profile (NULL);
+  }
+}
+
+void
+profile_edit_cb (GtkWidget *w _U_, gpointer data _U_)
+{
+  profile_name_edit_dlg (PROF_OPERATION_EDIT);
+}
 
 /* Create a profile dialog for editing display profiles; this is to be used
    as a callback for menu items, toolbars, etc.. */
 void
 profile_dialog_cb(GtkWidget *w _U_)
 {
-#if GTK_MAJOR_VERSION >= 2
   /* Has a profiles dialog box already been opened */
   if (global_profile_w != NULL) {
     /* Yes.  Just reactivate it. */
@@ -817,6 +1368,5 @@ profile_dialog_cb(GtkWidget *w _U_)
   } else {
     global_profile_w = profile_dialog_new ();
   }
-#endif
 }