From 377edb91b0af687f6ae5784d94bc2320b8f38d44 Mon Sep 17 00:00:00 2001 From: George Lebl Date: Mon, 24 Jul 2000 23:43:25 +0000 Subject: Allow adding overlapping subdirectories. What happens is that the real Mon Jul 24 16:39:01 2000 George Lebl * wrappers/gtk/gconf-client.[ch]: Allow adding overlapping subdirectories. What happens is that the real gconf notify is not added for subdirectories. When directories are added or removed the hash is traversed and fixed up. This is done in a simple and incredibly inefficent manner and needs to be fixed. Also this change adds an "err" argument to the _remove_dir call as errors can now happen. Also fix a minor warning by casting. * wrappers/gtk/testgconfclient.c: Add some testing of overlapping directories. Add buttons to add/remove the main directory and the subdirectory. This way you can see if things get proper notifications. --- wrappers/gtk/gconf-client.c | 168 +++++++++++++++++++++++++++++++++-------- wrappers/gtk/gconf-client.h | 3 +- wrappers/gtk/testgconfclient.c | 124 ++++++++++++++++++++++++++++-- 3 files changed, 258 insertions(+), 37 deletions(-) (limited to 'wrappers') diff --git a/wrappers/gtk/gconf-client.c b/wrappers/gtk/gconf-client.c index 9cf54515..9823fd2d 100644 --- a/wrappers/gtk/gconf-client.c +++ b/wrappers/gtk/gconf-client.c @@ -136,7 +136,8 @@ static gboolean gconf_client_lookup (GConfClient* client, GConfValue** valp); static void gconf_client_real_remove_dir (GConfClient* client, - Dir* d); + Dir* d, + GConfError** err); static guint client_signals[LAST_SIGNAL] = { 0 }; static GtkObjectClass* parent_class = NULL; @@ -228,7 +229,8 @@ destroy_dir_foreach_remove(gpointer key, gpointer value, gpointer user_data) /* remove notify for this dir */ - gconf_notify_remove(client->engine, d->notify_id); + if(d->notify_id != 0) + gconf_notify_remove(client->engine, d->notify_id); d->notify_id = 0; dir_destroy(value); @@ -478,25 +480,62 @@ gconf_client_get_for_engine (GConfEngine* engine) return client; } +typedef struct { + GConfClient *client; + Dir *lower_dir; + const char *dirname; +} OverlapData; -#ifdef GCONF_ENABLE_DEBUG static void -foreach_check_overlap(gpointer key, gpointer value, gpointer user_data) +foreach_setup_overlap(gpointer key, gpointer value, gpointer user_data) { - /* Disallow overlap */ - g_return_if_fail(!gconf_key_is_below(key, user_data)); - g_return_if_fail(!gconf_key_is_below(user_data, key)); + GConfClient *client; + Dir *dir = value; + OverlapData * od = user_data; + + client = od->client; + + /* if we have found the first (well there is only one anyway) directory + * that includes us that has a notify handler */ +#ifdef GCONF_ENABLE_DEBUG + if (dir->notify_id != 0 && + gconf_key_is_below(dir->name, od->dirname)) + { + g_assert(od->lower_dir == NULL); + od->lower_dir = dir; + } +#else + if (od->lower_dir == NULL && + dir->notify_id != 0 && + gconf_key_is_below(dir->name, od->dirname)) + od->lower_dir = dir; +#endif + /* if we have found a directory that we include and it has + * a notify_id, remove the notify handler now + * FIXME: this is a race, from now on we can miss notifies, it is + * not an incredible amount of time so this is not a showstopper */ + else if (dir->notify_id != 0 || + gconf_key_is_below(od->dirname, dir->name)) + { + if(dir->notify_id != 0) + gconf_notify_remove(client->engine, dir->notify_id); + dir->notify_id = 0; + } } -static void -check_overlap(GConfClient* client, const gchar* dirname) +static Dir * +setup_overlaps(GConfClient* client, const gchar* dirname) { - g_hash_table_foreach(client->dir_hash, foreach_check_overlap, - (gchar*)dirname); + OverlapData od; + + od.client = client; + od.lower_dir = NULL; + od.dirname = dirname; + + g_hash_table_foreach(client->dir_hash, foreach_setup_overlap, &od); + + return od.lower_dir; } -#else -#define check_overlap(x,y) -#endif void gconf_client_add_dir (GConfClient* client, @@ -514,23 +553,35 @@ gconf_client_add_dir (GConfClient* client, if (d == NULL) { - check_overlap(client, dirname); + Dir *overlap_dir; + + overlap_dir = setup_overlaps(client, dirname); - notify_id = gconf_notify_add(client->engine, - dirname, - notify_from_server_callback, - client, - &error); + /* only if there is no directory that includes us + * already add a notify */ + if (overlap_dir == NULL) + { + + notify_id = gconf_notify_add(client->engine, + dirname, + notify_from_server_callback, + client, + &error); - /* We got a notify ID or we got an error, not both */ - g_return_if_fail( (notify_id != 0 && error == NULL) || - (notify_id == 0 && error != NULL) ); + /* We got a notify ID or we got an error, not both */ + g_return_if_fail( (notify_id != 0 && error == NULL) || + (notify_id == 0 && error != NULL) ); - if (handle_error(client, error, err)) - return; + if (handle_error(client, error, err)) + return; - g_assert(error == NULL); + g_assert(error == NULL); + } + else + { + notify_id = 0; + } d = dir_new(dirname, notify_id); @@ -546,10 +597,55 @@ gconf_client_add_dir (GConfClient* client, d->add_count += 1; } +typedef struct { + GConfClient *client; + GConfError *error; +} AddNotifiesData; + +static void +foreach_add_notifies(gpointer key, gpointer value, gpointer user_data) +{ + AddNotifiesData *ad = user_data; + GConfClient *client; + Dir *dir = value; + + client = ad->client; + + if (ad->error != NULL) + return; + + if (dir->notify_id == 0) + { + Dir *overlap_dir; + overlap_dir = setup_overlaps(client, dir->name); + + /* only if there is no directory that includes us + * already add a notify */ + if (overlap_dir == NULL) + { + dir->notify_id = gconf_notify_add(client->engine, + dir->name, + notify_from_server_callback, + client, + &ad->error); + + /* We got a notify ID or we got an error, not both */ + g_return_if_fail( (dir->notify_id != 0 && ad->error == NULL) || + (dir->notify_id == 0 && ad->error != NULL) ); + + /* if error is returned, then we'll just ignore + * things until the end */ + } + } +} + static void gconf_client_real_remove_dir (GConfClient* client, - Dir* d) + Dir* d, + GConfError** err) { + AddNotifiesData ad; + g_return_if_fail(d != NULL); g_return_if_fail(d->add_count == 0); @@ -557,15 +653,24 @@ gconf_client_real_remove_dir (GConfClient* client, /* remove notify for this dir */ - gconf_notify_remove(client->engine, d->notify_id); + if(d->notify_id != 0) + gconf_notify_remove(client->engine, d->notify_id); d->notify_id = 0; dir_destroy(d); + + ad.client = client; + ad.error = NULL; + + g_hash_table_foreach(client->dir_hash, foreach_add_notifies, &ad); + + handle_error(client, ad.error, err); } void gconf_client_remove_dir (GConfClient* client, - const gchar* dirname) + const gchar* dirname, + GConfError** err) { Dir* found = NULL; @@ -579,7 +684,7 @@ gconf_client_remove_dir (GConfClient* client, found->add_count -= 1; if (found->add_count == 0) - gconf_client_real_remove_dir(client, found); + gconf_client_real_remove_dir(client, found, err); } #ifndef G_DISABLE_CHECKS else @@ -1130,7 +1235,8 @@ gconf_client_get_string(GConfClient* client, const gchar* key, g_assert(error == NULL); if (check_type(key, val, GCONF_VALUE_STRING, &error)) - retval = gconf_value_string(val); + /* we cheat here (look below) so we have to cast this */ + retval = (gchar *)gconf_value_string(val); else handle_error(client, error, err); diff --git a/wrappers/gtk/gconf-client.h b/wrappers/gtk/gconf-client.h index 6d6d46fd..9c1485b6 100644 --- a/wrappers/gtk/gconf-client.h +++ b/wrappers/gtk/gconf-client.h @@ -163,7 +163,8 @@ void gconf_client_add_dir (GConfClient* client, /* This removes any notifications associated with the dir */ void gconf_client_remove_dir (GConfClient* client, - const gchar* dir); + const gchar* dir, + GConfError** err); /* * The notification facility allows you to attach a callback to a single diff --git a/wrappers/gtk/testgconfclient.c b/wrappers/gtk/testgconfclient.c index 225d00c4..a3928aaf 100644 --- a/wrappers/gtk/testgconfclient.c +++ b/wrappers/gtk/testgconfclient.c @@ -153,14 +153,98 @@ quit_callback(GtkWidget* button, gpointer data) gtk_main_quit(); } + +static void +addsub_callback(GtkWidget* button, gpointer data) +{ + GtkWidget* win = data; + GConfClient* client = gtk_object_get_data(GTK_OBJECT(win), "client"); + GtkWidget* label = gtk_object_get_data(GTK_OBJECT(win), "label"); + int subdir = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(win), "subdir")); + int maindir = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(win), "maindir")); + char *s; + + subdir++; + + gtk_object_set_data(GTK_OBJECT(win), "subdir", GINT_TO_POINTER(subdir)); + + gconf_client_add_dir(client, "/apps/gnome/testgconfclient/subdir", GCONF_CLIENT_PRELOAD_NONE, NULL); + + s = g_strdup_printf("Maindir added %d times\nSubdir added %d times", maindir, subdir); + gtk_label_set(GTK_LABEL(label), s); + g_free(s); +} + +static void +removesub_callback(GtkWidget* button, gpointer data) +{ + GtkWidget* win = data; + GConfClient* client = gtk_object_get_data(GTK_OBJECT(win), "client"); + GtkWidget* label = gtk_object_get_data(GTK_OBJECT(win), "label"); + int subdir = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(win), "subdir")); + int maindir = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(win), "maindir")); + char *s; + + subdir--; + + gtk_object_set_data(GTK_OBJECT(win), "subdir", GINT_TO_POINTER(subdir)); + + gconf_client_remove_dir(client, "/apps/gnome/testgconfclient/subdir", NULL); + + s = g_strdup_printf("Maindir added %d times\nSubdir added %d times", maindir, subdir); + gtk_label_set(GTK_LABEL(label), s); + g_free(s); +} + +static void +addmain_callback(GtkWidget* button, gpointer data) +{ + GtkWidget* win = data; + GConfClient* client = gtk_object_get_data(GTK_OBJECT(win), "client"); + GtkWidget* label = gtk_object_get_data(GTK_OBJECT(win), "label"); + int subdir = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(win), "subdir")); + int maindir = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(win), "maindir")); + char *s; + + maindir++; + + gtk_object_set_data(GTK_OBJECT(win), "maindir", GINT_TO_POINTER(maindir)); + + gconf_client_add_dir(client, "/apps/gnome/testgconfclient", GCONF_CLIENT_PRELOAD_NONE, NULL); + + s = g_strdup_printf("Maindir added %d times\nSubdir added %d times", maindir, subdir); + gtk_label_set(GTK_LABEL(label), s); + g_free(s); +} +static void +removemain_callback(GtkWidget* button, gpointer data) +{ + GtkWidget* win = data; + GConfClient* client = gtk_object_get_data(GTK_OBJECT(win), "client"); + GtkWidget* label = gtk_object_get_data(GTK_OBJECT(win), "label"); + int subdir = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(win), "subdir")); + int maindir = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(win), "maindir")); + char *s; + + maindir--; + + gtk_object_set_data(GTK_OBJECT(win), "maindir", GINT_TO_POINTER(maindir)); + + gconf_client_remove_dir(client, "/apps/gnome/testgconfclient", NULL); + + s = g_strdup_printf("Maindir added %d times\nSubdir added %d times", maindir, subdir); + gtk_label_set(GTK_LABEL(label), s); + g_free(s); +} static void create_controls(GConfClient* client) { GtkWidget* win; + GtkWidget* label; GtkWidget* vbox; - GtkWidget* quit_button; + GtkWidget* button; GtkWidget* entry; /* Reference held by the window */ @@ -178,13 +262,37 @@ create_controls(GConfClient* client) gtk_container_add(GTK_CONTAINER(win), vbox); - quit_button = gtk_button_new_with_label("Quit"); + label = gtk_label_new("Maindir added 1 times\nSubdir added 0 times"); + gtk_box_pack_end(GTK_BOX(vbox), label, FALSE, FALSE, 0); + gtk_object_set_data(GTK_OBJECT(win), "label", label); + gtk_object_set_data(GTK_OBJECT(win), "subdir", GINT_TO_POINTER(0)); + gtk_object_set_data(GTK_OBJECT(win), "maindir", GINT_TO_POINTER(1)); - gtk_signal_connect(GTK_OBJECT(quit_button), "clicked", + button = gtk_button_new_with_label("Quit"); + gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(quit_callback), win); + gtk_box_pack_end(GTK_BOX(vbox), button, FALSE, FALSE, 0); - gtk_box_pack_end(GTK_BOX(vbox), quit_button, FALSE, FALSE, 0); - + button = gtk_button_new_with_label("Remove subdir"); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(removesub_callback), win); + gtk_box_pack_end(GTK_BOX(vbox), button, FALSE, FALSE, 0); + + button = gtk_button_new_with_label("Add subdir"); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(addsub_callback), win); + gtk_box_pack_end(GTK_BOX(vbox), button, FALSE, FALSE, 0); + + button = gtk_button_new_with_label("Remove maindir"); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(removemain_callback), win); + gtk_box_pack_end(GTK_BOX(vbox), button, FALSE, FALSE, 0); + + button = gtk_button_new_with_label("Add maindir"); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(addmain_callback), win); + gtk_box_pack_end(GTK_BOX(vbox), button, FALSE, FALSE, 0); + entry = entry_attached_to(client, "/apps/gnome/testgconfclient/blah"); gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0); @@ -193,6 +301,12 @@ create_controls(GConfClient* client) entry = entry_attached_to(client, "/apps/gnome/testgconfclient/bar"); gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0); + + entry = entry_attached_to(client, "/apps/gnome/testgconfclient/subdir/testsub1"); + gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0); + + entry = entry_attached_to(client, "/apps/gnome/testgconfclient/subdir/testsub2"); + gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0); gtk_widget_show_all(win); } -- cgit v1.2.1