merge_all_tap_menus() has been moved to menus.c.
[obnox/wireshark/wip.git] / gtk / profile_dlg.c
index 0704e6ddd58c7d5a2cc66e6f38a01b9443b8be10..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 <epan/prefs.h>
+
+#include "../simple_dialog.h"
+#include <wsutil/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>
+#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"
 
@@ -60,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;
 
@@ -75,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);
 }
 
@@ -90,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);
 }
@@ -115,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);
 }
 
@@ -143,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);
     }
 }
@@ -153,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;
@@ -163,30 +217,30 @@ fill_list(GtkWidget *main_w)
   const gchar   *profile_name = get_profile_name ();
   const gchar   *profiles_dir, *name;
   gchar         *filename;
-  
+
   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);
+  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);
-       
+       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) {
            /*
@@ -200,17 +254,34 @@ 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(gchar *name)
+profile_is_invalid_name(const gchar *name)
 {
   gchar  *message = NULL;
 
@@ -261,14 +332,14 @@ 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 (profile_exists (profile->name)) {
+      if (profile_exists (profile->name, FALSE) || profile_exists (profile->name, TRUE)) {
        /* The new profile exists, change */
        change_configuration_profile (profile->name);
-      } else if (!profile_exists (get_profile_name())) {
-       /* The new profile does not exist, and the previous profile has 
+      } 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);
       }
@@ -287,7 +358,7 @@ profile_select(GtkWidget *main_w, GtkTreeView *profile_l, gboolean destroy)
 static void
 profile_apply(GtkWidget *main_w, GtkTreeView *profile_l, gboolean destroy)
 {
-  char        *pf_dir_path, *pf_dir_path2;
+  char        *pf_dir_path, *pf_dir_path2, *pf_filename;
   GList       *fl1, *fl2;
   profile_def *profile1, *profile2;
   gboolean     found;
@@ -295,7 +366,6 @@ profile_apply(GtkWidget *main_w, GtkTreeView *profile_l, gboolean destroy)
   /* First validate all profile names */
   fl1 = g_list_first(edited_profiles);
   while (fl1) {
-    found = FALSE;
     profile1 = (profile_def *) fl1->data;
     g_strstrip(profile1->name);
     if (profile_is_invalid_name(profile1->name)) {
@@ -304,10 +374,44 @@ profile_apply(GtkWidget *main_w, GtkTreeView *profile_l, gboolean destroy)
     fl1 = g_list_next(fl1);
   }
 
+  /* 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);
+        }
+      }
+
+      g_free (profile1->reference);
+      profile1->reference = g_strdup(profile1->name);
+    }
+    fl1 = g_list_next(fl1);
+  }
+
+
   /* 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) {
@@ -316,14 +420,13 @@ profile_apply(GtkWidget *main_w, GtkTreeView *profile_l, gboolean destroy)
        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;
-       if (profile1->reference) {
-         g_free (profile1->reference);
-       }
+
+       g_free (profile1->reference);
        profile1->reference = g_strdup(profile1->name);
       }
     } else if (profile1->status == PROF_STAT_CHANGED) {
@@ -333,9 +436,10 @@ profile_apply(GtkWidget *main_w, GtkTreeView *profile_l, gboolean destroy)
                                        &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);
@@ -353,12 +457,14 @@ profile_apply(GtkWidget *main_w, GtkTreeView *profile_l, gboolean destroy)
     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;
     }
@@ -367,7 +473,7 @@ profile_apply(GtkWidget *main_w, GtkTreeView *profile_l, gboolean destroy)
       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);
       }
@@ -384,7 +490,7 @@ profile_dlg_ok_cb(GtkWidget *ok_bt, gpointer data _U_)
 {
   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));
-  
+
   /*
    * Apply the profile and destroy the dialog box.
    */
@@ -429,7 +535,7 @@ profile_dlg_destroy_cb(GtkWidget *w _U_, gpointer data _U_)
 }
 
 
-static gint
+static gboolean
 profile_button_press_cb(GtkWidget *list, GdkEventButton *event, gpointer data _U_)
 {
   if (event->type == GDK_2BUTTON_PRESS) {
@@ -441,7 +547,7 @@ profile_button_press_cb(GtkWidget *list, GdkEventButton *event, gpointer data _U
   return FALSE;
 }
 
-static gint
+static gboolean
 profile_key_release_cb(GtkWidget *list, GdkEventKey *event, gpointer data _U_)
 {
   if (event->keyval == GDK_Return || event->keyval == GDK_KP_Enter) {
@@ -461,7 +567,6 @@ profile_sel_list_cb(GtkTreeSelection *sel, gpointer data _U_)
   GtkTreeModel *model;
   GtkTreeIter   iter;
   GtkWidget    *name_te     = g_object_get_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY);
-  GtkWidget    *copy_bt     = g_object_get_data(G_OBJECT(main_w), E_PROF_COPY_BT_KEY);
   GtkWidget    *del_bt      = g_object_get_data(G_OBJECT(main_w), E_PROF_DEL_BT_KEY);
   profile_def  *profile;
   gchar        *name        = NULL;
@@ -469,11 +574,11 @@ profile_sel_list_cb(GtkTreeSelection *sel, gpointer data _U_)
   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;
       }
     }
@@ -501,12 +606,9 @@ 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
@@ -521,11 +623,11 @@ profile_new_bt_clicked_cb(GtkWidget *w, gpointer data _U_)
   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);
 
@@ -533,7 +635,6 @@ 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_)
 {
@@ -544,16 +645,39 @@ profile_copy_bt_clicked_cb(GtkWidget *w, gpointer data _U_)
   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);
 
@@ -562,7 +686,6 @@ 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_)
@@ -583,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);
        }
       }
     }
@@ -615,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);
@@ -643,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,
@@ -655,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);
 
@@ -692,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 = gtk_button_new_from_stock(GTK_STOCK_NEW);
-  SIGNAL_CONNECT(new_bt, "clicked", profile_new_bt_clicked_cb, NULL);
+  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);
+  gtk_widget_set_tooltip_text (new_bt, "Create a new profile (with default properties)");
 
-#if 0
   copy_bt = gtk_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);
-  g_object_set_data(G_OBJECT(main_w), E_PROF_COPY_BT_KEY, copy_bt);
+  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 = 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);
+  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);
@@ -734,18 +848,28 @@ 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_button_press_cb, NULL);
-  SIGNAL_CONNECT(profile_l, "key_release_event", profile_key_release_cb, NULL);
+  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);
@@ -760,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);
 
@@ -776,11 +900,11 @@ profile_dialog_new(void)
   name_te = gtk_entry_new();
   gtk_box_pack_start(GTK_BOX(middle_hb), name_te, TRUE, TRUE, 0);
   g_object_set_data(G_OBJECT(main_w), E_PROF_NAME_TE_KEY, name_te);
-  SIGNAL_CONNECT(name_te, "changed", profile_name_te_changed_cb, NULL);
+  g_signal_connect(name_te, "changed", G_CALLBACK(profile_name_te_changed_cb), NULL);
 #ifdef _WIN32
-  gtk_tooltips_set_tip (tooltips, name_te, "A profile name cannot start or end with a period (.), and cannot contain any of the following characters:\n   \\ / : * ? \" < > |", NULL);
+  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_tooltips_set_tip (tooltips, name_te, "A profile name cannot contain the '/' character", NULL);
+  gtk_widget_set_tooltip_text (name_te, "A profile name cannot contain the '/' character");
 #endif
   gtk_widget_show(name_te);
 
@@ -790,8 +914,8 @@ profile_dialog_new(void)
   gtk_widget_show(bbox);
 
   ok_bt = g_object_get_data(G_OBJECT(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);
+  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
@@ -801,17 +925,17 @@ profile_dialog_new(void)
   dlg_set_activate(name_te, ok_bt);
 
   apply_bt = g_object_get_data(G_OBJECT(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);
+  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 = g_object_get_data(G_OBJECT(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);
+  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 = g_object_get_data(G_OBJECT(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);
+  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);
@@ -829,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);
 
@@ -840,6 +964,398 @@ profile_dialog_new(void)
 }
 
 
+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