]> spindle.queued.net Git - midori/commitdiff
Use only one GtkTreeStore for all browsers to improve performance
authorEnrico Tröger <enrico.troeger@uvena.de>
Sat, 6 Jun 2009 21:40:08 +0000 (23:40 +0200)
committerChristian Dywan <christian@twotoasts.de>
Sat, 6 Jun 2009 21:40:08 +0000 (23:40 +0200)
Split the code a bit more and use one GtkTreeStore for all
CookieManagerPage instances so we save some cycles when updating
the store when cookies have changed.

extensions/cookie-manager/cookie-manager-page.c
extensions/cookie-manager/cookie-manager-page.h
extensions/cookie-manager/cookie-manager.c
extensions/cookie-manager/cookie-manager.h
extensions/cookie-manager/main.c [new file with mode: 0644]
po/POTFILES.in

index 9e73fe3888d7cf91cfc841460c7fa2335622662e..71df49df2e7afdb70c5d5ad82ec979ec2b50ceea 100644 (file)
@@ -28,22 +28,17 @@ typedef struct _CookieManagerPagePrivate                    CookieManagerPagePrivate;
 
 #define CM_EMPTY_LABEL_TEXT "\n\n\n\n\n\n"
 
-enum
-{
-       COOKIE_MANAGER_COL_NAME,
-       COOKIE_MANAGER_COL_COOKIE,
-       COOKIE_MANAGER_COL_VISIBLE,
-       COOKIE_MANAGER_N_COLUMNS
-};
-
 
 struct _CookieManagerPagePrivate
 {
+       CookieManager *parent;
+
        GtkWidget *treeview;
        GtkTreeStore *store;
        GtkTreeModel *filter;
 
        GtkWidget *filter_entry;
+       gboolean ignore_changed_filter;
 
        GtkWidget *desc_label;
        GtkWidget *delete_button;
@@ -53,11 +48,13 @@ struct _CookieManagerPagePrivate
 
        GtkWidget *toolbar;
        GtkWidget *popup_menu;
+};
 
-       GSList *cookies;
-       SoupCookieJar *jar;
-       guint timer_id;
-       gint ignore_changed_count;
+enum
+{
+       PROP_0,
+       PROP_STORE,
+       PROP_PARENT
 };
 
 
@@ -69,7 +66,6 @@ static void cm_button_delete_all_clicked_cb(GtkToolButton *button, CookieManager
 static void cm_tree_popup_collapse_activate_cb(GtkMenuItem *item, CookieManagerPage *cmp);
 static void cm_tree_popup_expand_activate_cb(GtkMenuItem *item, CookieManagerPage *cmp);
 static void cm_filter_tree(CookieManagerPage *cmp, const gchar *filter_text);
-static void cm_jar_changed_cb(SoupCookieJar *jar, SoupCookie *old, SoupCookie *new, CookieManagerPage *cmp);
 
 
 G_DEFINE_TYPE_WITH_CODE(CookieManagerPage, cookie_manager_page, GTK_TYPE_VBOX,
@@ -90,22 +86,6 @@ static const gchar *cookie_manager_page_get_stock_id(MidoriViewable *viewable)
 }
 
 
-static void cm_free_cookie_list(CookieManagerPage *cmp)
-{
-       CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(cmp);
-
-       if (priv->cookies != NULL)
-       {
-               GSList *l;
-
-               for (l = priv->cookies; l != NULL; l = g_slist_next(l))
-                       soup_cookie_free(l->data);
-               g_slist_free(priv->cookies);
-               priv->cookies = NULL;
-       }
-}
-
-
 static void cm_create_toolbar(CookieManagerPage *cmp)
 {
        CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(cmp);
@@ -174,74 +154,20 @@ static void cookie_manager_page_viewable_iface_init(MidoriViewableIface* iface)
 }
 
 
-static void cookie_manager_page_finalize(GObject *object)
+static void cookie_manager_page_pre_cookies_change_cb(CookieManager *cm, CookieManagerPage *cmp)
 {
-       CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(object);
-
-       g_signal_handlers_disconnect_by_func(priv->jar, cm_jar_changed_cb, object);
-
-       if (priv->timer_id > 0)
-               g_source_remove(priv->timer_id);
-
-       cm_free_cookie_list(COOKIE_MANAGER_PAGE(object));
-
-       gtk_widget_destroy(priv->popup_menu);
+       CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(cmp);
 
-       G_OBJECT_CLASS(cookie_manager_page_parent_class)->finalize(object);
+       g_object_ref(priv->filter);
+       gtk_tree_view_set_model(GTK_TREE_VIEW(priv->treeview), NULL);
 }
 
 
-static void cm_refresh_store(CookieManagerPage *cmp)
+static void cookie_manager_page_cookies_changed_cb(CookieManager *cm, CookieManagerPage *cmp)
 {
-       GSList *l;
-       GHashTable *parents;
-       GtkTreeIter iter;
-       GtkTreeIter *parent_iter;
-       SoupCookie *cookie;
        const gchar *filter_text;
        CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(cmp);
 
-       g_object_ref(priv->filter);
-       gtk_tree_view_set_model(GTK_TREE_VIEW(priv->treeview), NULL);
-
-       gtk_tree_store_clear(priv->store);
-
-       /* free the old list */
-       cm_free_cookie_list(cmp);
-
-       priv->cookies = soup_cookie_jar_all_cookies(priv->jar);
-
-       /* Hashtable holds domain names as keys, the corresponding tree iters as values */
-       parents = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
-
-       for (l = priv->cookies; l != NULL; l = g_slist_next(l))
-       {
-               cookie = l->data;
-
-               /* look for the parent item for the current domain name and create it if it doesn't exist */
-               if ((parent_iter = (GtkTreeIter*) g_hash_table_lookup(parents, cookie->domain)) == NULL)
-               {
-                       parent_iter = g_new0(GtkTreeIter, 1);
-
-                       gtk_tree_store_append(priv->store, parent_iter, NULL);
-                       gtk_tree_store_set(priv->store, parent_iter,
-                               COOKIE_MANAGER_COL_NAME, cookie->domain,
-                               COOKIE_MANAGER_COL_COOKIE, NULL,
-                               COOKIE_MANAGER_COL_VISIBLE, TRUE,
-                               -1);
-
-                       g_hash_table_insert(parents, g_strdup(cookie->domain), parent_iter);
-               }
-
-               gtk_tree_store_append(priv->store, &iter, parent_iter);
-               gtk_tree_store_set(priv->store, &iter,
-                       COOKIE_MANAGER_COL_NAME, cookie->name,
-                       COOKIE_MANAGER_COL_COOKIE, cookie,
-                       COOKIE_MANAGER_COL_VISIBLE, TRUE,
-                       -1);
-       }
-       g_hash_table_destroy(parents);
-
        gtk_tree_view_set_model(GTK_TREE_VIEW(priv->treeview), GTK_TREE_MODEL(priv->filter));
        g_object_unref(priv->filter);
 
@@ -255,32 +181,78 @@ static void cm_refresh_store(CookieManagerPage *cmp)
 }
 
 
-static gboolean cm_delayed_refresh(CookieManagerPage *cmp)
+static void cookie_manager_page_filter_changed_cb(CookieManager *cm, const gchar *text,
+                                                                                                 CookieManagerPage *cmp)
 {
        CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(cmp);
 
-       cm_refresh_store(cmp);
-       priv->timer_id = 0;
-
-       return FALSE;
+       priv->ignore_changed_filter = TRUE;
+       gtk_entry_set_text(GTK_ENTRY(priv->filter_entry), text);
+       priv->ignore_changed_filter = FALSE;
 }
 
 
-static void cm_jar_changed_cb(SoupCookieJar *jar, SoupCookie *old, SoupCookie *new,
-                                                         CookieManagerPage *cmp)
+static void cookie_manager_page_finalize(GObject *object)
 {
-       CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(cmp);
+       CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(object);
+
+       gtk_widget_destroy(priv->popup_menu);
+
+       g_signal_handlers_disconnect_by_func(priv->parent,
+               cookie_manager_page_pre_cookies_change_cb, object);
+       g_signal_handlers_disconnect_by_func(priv->parent,
+               cookie_manager_page_cookies_changed_cb, object);
+       g_signal_handlers_disconnect_by_func(priv->parent,
+               cookie_manager_page_filter_changed_cb, object);
 
-       if (priv->ignore_changed_count > 0)
+       G_OBJECT_CLASS(cookie_manager_page_parent_class)->finalize(object);
+}
+
+
+static void cookie_manager_page_set_property(GObject *object, guint prop_id, const GValue *value,
+                                                                                        GParamSpec *pspec)
+{
+       CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(object);
+       switch (prop_id)
        {
-               priv->ignore_changed_count--;
-               return;
-       }
+               case PROP_STORE:
+               {
+                       priv->store = g_value_get_object(value);
 
-       /* We delay these events a little bit to avoid too many rebuilds of the tree.
-        * Some websites (like Flyspray bugtrackers sent a whole bunch of cookies at once. */
-       if (priv->timer_id == 0)
-               priv->timer_id = g_timeout_add_seconds(1, (GSourceFunc) cm_delayed_refresh, cmp);
+                       /* setting filter and model */
+                       priv->filter = gtk_tree_model_filter_new(GTK_TREE_MODEL(priv->store), NULL);
+                       gtk_tree_model_filter_set_visible_column(GTK_TREE_MODEL_FILTER(priv->filter),
+                               COOKIE_MANAGER_COL_VISIBLE);
+                       gtk_tree_view_set_model(GTK_TREE_VIEW(priv->treeview), GTK_TREE_MODEL(priv->filter));
+                       g_object_unref(priv->filter);
+
+                       break;
+               }
+               case PROP_PARENT:
+               {
+                       if (priv->parent != NULL)
+                       {
+                               g_signal_handlers_disconnect_by_func(priv->parent,
+                                       cookie_manager_page_pre_cookies_change_cb, object);
+                               g_signal_handlers_disconnect_by_func(priv->parent,
+                                       cookie_manager_page_cookies_changed_cb, object);
+                               g_signal_handlers_disconnect_by_func(priv->parent,
+                                       cookie_manager_page_filter_changed_cb, object);
+                       }
+                       priv->parent = g_value_get_object(value);
+
+                       g_signal_connect(priv->parent, "pre-cookies-change",
+                               G_CALLBACK(cookie_manager_page_pre_cookies_change_cb), object);
+                       g_signal_connect(priv->parent, "cookies-changed",
+                               G_CALLBACK(cookie_manager_page_cookies_changed_cb), object);
+                       g_signal_connect(priv->parent, "filter-changed",
+                               G_CALLBACK(cookie_manager_page_filter_changed_cb), object);
+                       break;
+               }
+               default:
+                       G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
+                       break;
+       }
 }
 
 
@@ -288,7 +260,27 @@ static void cookie_manager_page_class_init(CookieManagerPageClass *klass)
 {
        GObjectClass *g_object_class;
        g_object_class = G_OBJECT_CLASS(klass);
+
        g_object_class->finalize = cookie_manager_page_finalize;
+       g_object_class->set_property = cookie_manager_page_set_property;
+
+       g_object_class_install_property(g_object_class,
+               PROP_STORE,
+               g_param_spec_object(
+               "store",
+               "Treestore",
+               "The tree store",
+               GTK_TYPE_TREE_STORE,
+               G_PARAM_WRITABLE));
+
+       g_object_class_install_property(g_object_class,
+               PROP_PARENT,
+               g_param_spec_object(
+               "parent",
+               "Parent",
+               "The CookieManager parent instance",
+               COOKIE_MANAGER_TYPE,
+               G_PARAM_WRITABLE));
 
        g_type_class_add_private(klass, sizeof(CookieManagerPagePrivate));
 }
@@ -346,13 +338,7 @@ static void cm_delete_cookie(CookieManagerPage *cmp, GtkTreeModel *model, GtkTre
 
        gtk_tree_model_get(model, child, COOKIE_MANAGER_COL_COOKIE, &cookie, -1);
 
-       if (cookie != NULL)
-       {
-               priv->ignore_changed_count++;
-
-               soup_cookie_jar_delete_cookie(priv->jar, cookie);
-               /* the SoupCookie object is freed when the whole list gets updated */
-       }
+       cookie_manager_delete_cookie(priv->parent, cookie);
 }
 
 
@@ -670,11 +656,17 @@ static void cm_filter_tree(CookieManagerPage *cmp, const gchar *filter_text)
 
 static void cm_filter_entry_changed_cb(GtkEditable *editable, CookieManagerPage *cmp)
 {
-       const gchar *text = gtk_entry_get_text(GTK_ENTRY(editable));
+       const gchar *text;
        CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(cmp);
 
+       if (priv->ignore_changed_filter)
+               return;
+
+       text = gtk_entry_get_text(GTK_ENTRY(editable));
        cm_filter_tree(cmp, text);
 
+       cookie_manager_update_filter(priv->parent, text);
+
        if (*text != '\0')
                gtk_tree_view_expand_all(GTK_TREE_VIEW(priv->treeview));
        else
@@ -830,20 +822,6 @@ static GtkWidget *cm_tree_prepare(CookieManagerPage *cmp)
        sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
        gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
 
-       /* create the main store */
-       priv->store = gtk_tree_store_new(COOKIE_MANAGER_N_COLUMNS,
-               G_TYPE_STRING, SOUP_TYPE_COOKIE, G_TYPE_BOOLEAN);
-       gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(priv->store),
-               COOKIE_MANAGER_COL_NAME, GTK_SORT_ASCENDING);
-
-       /* setting filter and model */
-       priv->filter = gtk_tree_model_filter_new(GTK_TREE_MODEL(priv->store), NULL);
-       gtk_tree_model_filter_set_visible_column(GTK_TREE_MODEL_FILTER(priv->filter),
-               COOKIE_MANAGER_COL_VISIBLE);
-       gtk_tree_view_set_model(GTK_TREE_VIEW(priv->treeview), GTK_TREE_MODEL(priv->filter));
-       g_object_unref(priv->store);
-       g_object_unref(priv->filter);
-
        /* signals */
        g_signal_connect(sel, "changed", G_CALLBACK(cm_tree_selection_changed_cb), cmp);
        g_signal_connect(treeview, "button-press-event", G_CALLBACK(cm_tree_button_press_event_cb), cmp);
@@ -909,9 +887,12 @@ static void cookie_manager_page_init(CookieManagerPage *self)
        GtkWidget *filter_hbox;
        GtkWidget *filter_label;
        GtkWidget *treeview;
-       SoupSession *session;
        CookieManagerPagePrivate *priv = COOKIE_MANAGER_PAGE_GET_PRIVATE(self);
 
+       priv->parent = NULL;
+       priv->store = NULL;
+       priv->ignore_changed_filter = FALSE;
+
        cm_create_toolbar(self);
 
        priv->desc_label = gtk_label_new(CM_EMPTY_LABEL_TEXT);
@@ -968,18 +949,19 @@ static void cookie_manager_page_init(CookieManagerPage *self)
 
        gtk_box_pack_start(GTK_BOX(self), filter_hbox, FALSE, FALSE, 5);
        gtk_box_pack_start(GTK_BOX(self), paned, TRUE, TRUE, 0);
-
-       /* setup soup */
-       session = webkit_get_default_session();
-       priv->jar = SOUP_COOKIE_JAR(soup_session_get_feature(session, soup_cookie_jar_get_type()));
-       g_signal_connect(priv->jar, "changed", G_CALLBACK(cm_jar_changed_cb), self);
-
-       cm_refresh_store(self);
 }
 
 
-GtkWidget *cookie_manager_page_new(void)
+GtkWidget *cookie_manager_page_new(CookieManager *parent, GtkTreeStore *store,
+                                                                  const gchar *filter_text)
 {
-       return g_object_new(COOKIE_MANAGER_PAGE_TYPE, NULL);
+       GtkWidget *cmp;
+
+       cmp = g_object_new(COOKIE_MANAGER_PAGE_TYPE, "parent", parent, "store", store, NULL);
+
+       if (filter_text != NULL)
+               cookie_manager_page_filter_changed_cb(parent, filter_text, COOKIE_MANAGER_PAGE(cmp));
+
+       return cmp;
 }
 
index 37e02c0d764dc8e6a8d7e88d9ae6f0521b7d2ab1..7c307d1e9bd22623ba54c38f4ed99b8700483d66 100644 (file)
@@ -38,7 +38,9 @@ struct _CookieManagerPageClass
 };
 
 GType          cookie_manager_page_get_type            (void);
-GtkWidget*     cookie_manager_page_new                         (void);
+GtkWidget*     cookie_manager_page_new                         (CookieManager *parent,
+                                                                                                GtkTreeStore *store,
+                                                                                                const gchar *filter_text);
 
 G_END_DECLS
 
index 38d557a620e2a3de28314f8ae104cf612cdf6304..dc2567221d3d578a1ef8a3823fdacbe5c19541f8 100644 (file)
 #include "cookie-manager.h"
 #include "cookie-manager-page.h"
 
+typedef struct _CookieManagerPrivate                   CookieManagerPrivate;
 
+#define COOKIE_MANAGER_GET_PRIVATE(obj)                (G_TYPE_INSTANCE_GET_PRIVATE((obj),\
+                       COOKIE_MANAGER_TYPE, CookieManagerPrivate))
 
-typedef struct
+struct _CookieManager
+{
+       GObject parent;
+};
+
+struct _CookieManagerClass
+{
+       GObjectClass parent_class;
+};
+
+struct _CookieManagerPrivate
 {
        MidoriApp *app;
-       MidoriBrowser *browser;
        MidoriExtension *extension;
-       GtkWidget *panel_page;
-} CMData;
 
-static void cm_app_add_browser_cb(MidoriApp *app, MidoriBrowser *browser, MidoriExtension *ext);
-static void cm_deactivate_cb(MidoriExtension *extension, CMData *cmdata);
+       GSList *panel_pages;
+
+       GtkTreeStore *store;
+       GSList *cookies;
+       SoupCookieJar *jar;
+       guint timer_id;
+       gint ignore_changed_count;
 
+       gchar *filter_text;
+};
 
+static void cookie_manager_finalize(GObject *object);
+static void cookie_manager_app_add_browser_cb(MidoriApp *app, MidoriBrowser *browser,
+                                                                                         CookieManager *cm);
 
-static void cm_browser_close_cb(GtkObject *browser, CMData *cmdata)
+enum
 {
-       g_signal_handlers_disconnect_by_func(cmdata->extension, cm_deactivate_cb, cmdata);
-       g_signal_handlers_disconnect_by_func(cmdata->browser, cm_browser_close_cb, cmdata);
+       COOKIES_CHANGED,
+       PRE_COOKIES_CHANGE,
+       FILTER_CHANGED,
 
-       /* the panel_page widget gets destroyed automatically when a browser is closed but not
-        * when the extension is deactivated */
-       if (cmdata->panel_page != NULL && IS_COOKIE_MANAGER_PAGE(cmdata->panel_page))
-               gtk_widget_destroy(cmdata->panel_page);
+       LAST_SIGNAL
+};
+static guint signals[LAST_SIGNAL];
 
-       g_free(cmdata);
+
+G_DEFINE_TYPE(CookieManager, cookie_manager, G_TYPE_OBJECT);
+
+
+static void cookie_manager_class_init(CookieManagerClass *klass)
+{
+       GObjectClass *g_object_class;
+
+       g_object_class = G_OBJECT_CLASS(klass);
+
+       g_object_class->finalize = cookie_manager_finalize;
+
+       signals[COOKIES_CHANGED] = g_signal_new(
+               "cookies-changed",
+               G_TYPE_FROM_CLASS(klass),
+               (GSignalFlags) 0,
+               0,
+               0,
+               NULL,
+               g_cclosure_marshal_VOID__VOID,
+               G_TYPE_NONE, 0);
+
+       signals[PRE_COOKIES_CHANGE] = g_signal_new(
+               "pre-cookies-change",
+               G_TYPE_FROM_CLASS(klass),
+               (GSignalFlags) 0,
+               0,
+               0,
+               NULL,
+               g_cclosure_marshal_VOID__VOID,
+               G_TYPE_NONE, 0);
+
+       signals[FILTER_CHANGED] = g_signal_new(
+               "filter-changed",
+               G_TYPE_FROM_CLASS(klass),
+               (GSignalFlags) 0,
+               0,
+               0,
+               NULL,
+               g_cclosure_marshal_VOID__STRING,
+               G_TYPE_NONE, 1, G_TYPE_STRING);
+
+       g_type_class_add_private(klass, sizeof(CookieManagerPrivate));
 }
 
 
-static void cm_deactivate_cb(MidoriExtension *extension, CMData *cmdata)
+static void cookie_manager_panel_pages_foreach(gpointer ptr, gpointer data)
 {
-       g_signal_handlers_disconnect_by_func(cmdata->app, cm_app_add_browser_cb, extension);
-       cm_browser_close_cb(NULL, cmdata);
+       if (ptr != NULL && GTK_IS_WIDGET(ptr))
+               gtk_widget_destroy(GTK_WIDGET(ptr));
 }
 
 
-static void cm_app_add_browser_cb(MidoriApp *app, MidoriBrowser *browser, MidoriExtension *ext)
+static void cookie_manager_page_destroy_cb(GtkObject *page, CookieManager *cm)
 {
-       GtkWidget *panel;
+       CookieManagerPrivate *priv = COOKIE_MANAGER_GET_PRIVATE(cm);
+
+       priv->panel_pages = g_slist_remove(priv->panel_pages, page);
+}
+
+
+static void cookie_manager_app_add_browser_cb(MidoriApp *app, MidoriBrowser *browser,
+                                                                                         CookieManager *cm)
+{
+       MidoriPanel *panel;
        GtkWidget *page;
-       CMData *cmdata;
+       CookieManagerPrivate *priv = COOKIE_MANAGER_GET_PRIVATE(cm);
 
        panel = katze_object_get_object(browser, "panel");
 
-       page = cookie_manager_page_new();
+       page = cookie_manager_page_new(cm, priv->store, priv->filter_text);
        gtk_widget_show(page);
-       midori_panel_append_page(MIDORI_PANEL(panel), MIDORI_VIEWABLE(page));
-
-       cmdata = g_new0(CMData, 1);
-       cmdata->app = app;
-       cmdata->browser = browser;
-       cmdata->extension = ext;
-       cmdata->panel_page = page;
+       midori_panel_append_page(panel, MIDORI_VIEWABLE(page));
+       g_signal_connect(page, "destroy", G_CALLBACK(cookie_manager_page_destroy_cb), cm);
 
-       g_signal_connect(browser, "destroy", G_CALLBACK(cm_browser_close_cb), cmdata);
-       g_signal_connect(ext, "deactivate", G_CALLBACK(cm_deactivate_cb), cmdata);
+       priv->panel_pages = g_slist_append(priv->panel_pages, page);
 
        g_object_unref(panel);
 }
 
 
-static void cm_activate_cb(MidoriExtension *extension, MidoriApp *app, gpointer data)
+static void cookie_manager_free_cookie_list(CookieManager *cm)
 {
+       CookieManagerPrivate *priv = COOKIE_MANAGER_GET_PRIVATE(cm);
+
+       if (priv->cookies != NULL)
+       {
+               GSList *l;
+
+               for (l = priv->cookies; l != NULL; l = g_slist_next(l))
+                       soup_cookie_free(l->data);
+               g_slist_free(priv->cookies);
+               priv->cookies = NULL;
+       }
+}
+
+
+static void cookie_manager_refresh_store(CookieManager *cm)
+{
+       GSList *l;
+       GHashTable *parents;
+       GtkTreeIter iter;
+       GtkTreeIter *parent_iter;
+       SoupCookie *cookie;
+       CookieManagerPrivate *priv = COOKIE_MANAGER_GET_PRIVATE(cm);
+
+       g_signal_emit(cm, signals[PRE_COOKIES_CHANGE], 0);
+
+       gtk_tree_store_clear(priv->store);
+
+       /* free the old list */
+       cookie_manager_free_cookie_list(cm);
+
+       priv->cookies = soup_cookie_jar_all_cookies(priv->jar);
+
+       /* Hashtable holds domain names as keys, the corresponding tree iters as values */
+       parents = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+
+       for (l = priv->cookies; l != NULL; l = g_slist_next(l))
+       {
+               cookie = l->data;
+
+               /* look for the parent item for the current domain name and create it if it doesn't exist */
+               if ((parent_iter = (GtkTreeIter*) g_hash_table_lookup(parents, cookie->domain)) == NULL)
+               {
+                       parent_iter = g_new0(GtkTreeIter, 1);
+
+                       gtk_tree_store_append(priv->store, parent_iter, NULL);
+                       gtk_tree_store_set(priv->store, parent_iter,
+                               COOKIE_MANAGER_COL_NAME, cookie->domain,
+                               COOKIE_MANAGER_COL_COOKIE, NULL,
+                               COOKIE_MANAGER_COL_VISIBLE, TRUE,
+                               -1);
+
+                       g_hash_table_insert(parents, g_strdup(cookie->domain), parent_iter);
+               }
+
+               gtk_tree_store_append(priv->store, &iter, parent_iter);
+               gtk_tree_store_set(priv->store, &iter,
+                       COOKIE_MANAGER_COL_NAME, cookie->name,
+                       COOKIE_MANAGER_COL_COOKIE, cookie,
+                       COOKIE_MANAGER_COL_VISIBLE, TRUE,
+                       -1);
+       }
+       g_hash_table_destroy(parents);
+
+       g_signal_emit(cm, signals[COOKIES_CHANGED], 0);
+}
+
+
+static gboolean cookie_manager_delayed_refresh(CookieManager *cm)
+{
+       CookieManagerPrivate *priv = COOKIE_MANAGER_GET_PRIVATE(cm);
+
+       cookie_manager_refresh_store(cm);
+       priv->timer_id = 0;
+
+       return FALSE;
+}
+
+
+static void cookie_manager_jar_changed_cb(SoupCookieJar *jar, SoupCookie *old, SoupCookie *new,
+                                                         CookieManager *cm)
+{
+       CookieManagerPrivate *priv = COOKIE_MANAGER_GET_PRIVATE(cm);
+
+       if (priv->ignore_changed_count > 0)
+       {
+               priv->ignore_changed_count--;
+               return;
+       }
+
+       /* We delay these events a little bit to avoid too many rebuilds of the tree.
+        * Some websites (like Flyspray bugtrackers sent a whole bunch of cookies at once. */
+       if (priv->timer_id == 0)
+               priv->timer_id = g_timeout_add_seconds(1, (GSourceFunc) cookie_manager_delayed_refresh, cm);
+}
+
+
+static void cookie_manager_finalize(GObject *object)
+{
+       CookieManager *cm = COOKIE_MANAGER(object);
+       CookieManagerPrivate *priv = COOKIE_MANAGER_GET_PRIVATE(cm);
+
+       g_signal_handlers_disconnect_by_func(priv->app, cookie_manager_app_add_browser_cb, cm);
+       g_signal_handlers_disconnect_by_func(priv->jar, cookie_manager_jar_changed_cb, cm);
+
+       /* remove all panel pages from open windows */
+       g_slist_foreach(priv->panel_pages, cookie_manager_panel_pages_foreach, NULL);
+       g_slist_free(priv->panel_pages);
+
+       /* clean cookies */
+       if (priv->timer_id > 0)
+               g_source_remove(priv->timer_id);
+
+       cookie_manager_free_cookie_list(cm);
+
+       g_object_unref(priv->store);
+       g_free(priv->filter_text);
+
+       G_OBJECT_CLASS(cookie_manager_parent_class)->finalize(object);
+}
+
+
+static void cookie_manager_init(CookieManager *self)
+{
+       CookieManagerPrivate *priv = COOKIE_MANAGER_GET_PRIVATE(self);
+       SoupSession *session;
+
+       priv->filter_text = NULL;
+       priv->panel_pages = NULL;
+       /* create the main store */
+       priv->store = gtk_tree_store_new(COOKIE_MANAGER_N_COLUMNS,
+               G_TYPE_STRING, SOUP_TYPE_COOKIE, G_TYPE_BOOLEAN);
+       gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(priv->store),
+               COOKIE_MANAGER_COL_NAME, GTK_SORT_ASCENDING);
+
+       /* setup soup */
+       session = webkit_get_default_session();
+       priv->jar = SOUP_COOKIE_JAR(soup_session_get_feature(session, soup_cookie_jar_get_type()));
+       g_signal_connect(priv->jar, "changed", G_CALLBACK(cookie_manager_jar_changed_cb), self);
+
+       cookie_manager_refresh_store(self);
+}
+
+
+void cookie_manager_update_filter(CookieManager *cm, const gchar *text)
+{
+       CookieManagerPrivate *priv = COOKIE_MANAGER_GET_PRIVATE(cm);
+
+       katze_assign(priv->filter_text, g_strdup(text));
+
+       g_signal_emit(cm, signals[FILTER_CHANGED], 0, text);
+}
+
+
+void cookie_manager_delete_cookie(CookieManager *cm, SoupCookie *cookie)
+{
+       CookieManagerPrivate *priv = COOKIE_MANAGER_GET_PRIVATE(cm);
+
+       if (cookie != NULL)
+       {
+               priv->ignore_changed_count++;
+
+               soup_cookie_jar_delete_cookie(priv->jar, cookie);
+               /* the SoupCookie object is freed when the whole list gets updated */
+       }
+}
+
+
+CookieManager *cookie_manager_new(MidoriExtension *extension, MidoriApp *app)
+{
+       CookieManager *cm;
+       CookieManagerPrivate *priv;
        guint i;
        KatzeArray *browsers;
        MidoriBrowser *browser;
 
+       cm = g_object_new(COOKIE_MANAGER_TYPE, NULL);
+
+       priv = COOKIE_MANAGER_GET_PRIVATE(cm);
+       priv->app = app;
+       priv->extension = extension;
+
        /* add the cookie manager panel page to existing browsers */
        browsers = katze_object_get_object(app, "browsers");
        i = 0;
        while ((browser = katze_array_get_nth_item(browsers, i++)))
-               cm_app_add_browser_cb(app, browser, extension);
+               cookie_manager_app_add_browser_cb(app, browser, cm);
        g_object_unref(browsers);
 
-       g_signal_connect(app, "add-browser", G_CALLBACK(cm_app_add_browser_cb), extension);
-}
-
+       g_signal_connect(app, "add-browser", G_CALLBACK(cookie_manager_app_add_browser_cb), cm);
 
-MidoriExtension *extension_init(void)
-{
-       MidoriExtension *extension;
-       GtkIconFactory *factory;
-       GtkIconSource *icon_source;
-       GtkIconSet *icon_set;
-       static GtkStockItem items[] =
-       {
-               { STOCK_COOKIE_MANAGER, N_("_Cookie Manager"), 0, 0, NULL }
-       };
-
-       factory = gtk_icon_factory_new();
-       gtk_stock_add(items, G_N_ELEMENTS(items));
-       icon_set = gtk_icon_set_new();
-       icon_source = gtk_icon_source_new();
-       gtk_icon_source_set_icon_name(icon_source, GTK_STOCK_DIALOG_AUTHENTICATION);
-       gtk_icon_set_add_source(icon_set, icon_source);
-       gtk_icon_source_free(icon_source);
-       gtk_icon_factory_add(factory, STOCK_COOKIE_MANAGER, icon_set);
-       gtk_icon_set_unref(icon_set);
-       gtk_icon_factory_add_default(factory);
-       g_object_unref(factory);
-
-       extension = g_object_new(MIDORI_TYPE_EXTENSION,
-               "name", _("Cookie Manager"),
-               "description", _("List, view and delete cookies"),
-               "version", "0.2",
-               "authors", "Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>",
-               NULL);
-
-       g_signal_connect(extension, "activate", G_CALLBACK(cm_activate_cb), NULL);
-
-       return extension;
+       return cm;
 }
+
index 9f6a399676a0580ff49142727844febe90f9542a..4e2ba32b421b75edd2906ce38d23ac97a07f0502 100644 (file)
 #ifndef __COOKIE_MANAGER_H__
 #define __COOKIE_MANAGER_H__
 
+G_BEGIN_DECLS
 
 #define STOCK_COOKIE_MANAGER "cookie-manager"
 
+enum
+{
+       COOKIE_MANAGER_COL_NAME,
+       COOKIE_MANAGER_COL_COOKIE,
+       COOKIE_MANAGER_COL_VISIBLE,
+       COOKIE_MANAGER_N_COLUMNS
+};
 
-#endif /* __COOKIE_MANAGER_H__ */
+
+#define COOKIE_MANAGER_TYPE                            (cookie_manager_get_type())
+#define COOKIE_MANAGER(obj)                            (G_TYPE_CHECK_INSTANCE_CAST((obj),\
+                       COOKIE_MANAGER_TYPE, CookieManager))
+#define COOKIE_MANAGER_CLASS(klass)            (G_TYPE_CHECK_CLASS_CAST((klass),\
+                       COOKIE_MANAGER_TYPE, CookieManagerClass))
+#define IS_COOKIE_MANAGER(obj)                 (G_TYPE_CHECK_INSTANCE_TYPE((obj),\
+                       COOKIE_MANAGER_TYPE))
+#define IS_COOKIE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),\
+                       COOKIE_MANAGER_TYPE))
+
+typedef struct _CookieManager                  CookieManager;
+typedef struct _CookieManagerClass             CookieManagerClass;
+
+GType                  cookie_manager_get_type         (void);
+CookieManager* cookie_manager_new                      (MidoriExtension *extension, MidoriApp *app);
+
+void                   cookie_manager_delete_cookie(CookieManager *cm, SoupCookie *cookie);
+void                   cookie_manager_update_filter(CookieManager *cm, const gchar *text);
+
+G_END_DECLS
+
+#endif /* __COOKIE-MANAGER_H__ */
diff --git a/extensions/cookie-manager/main.c b/extensions/cookie-manager/main.c
new file mode 100644 (file)
index 0000000..39d058e
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ Copyright (C) 2009 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ See the file COPYING for the full license text.
+*/
+
+#include "config.h"
+#include <midori/midori.h>
+
+#include "cookie-manager.h"
+
+CookieManager *cm = NULL;
+
+
+static void cm_deactivate_cb(MidoriExtension *extension, gpointer data)
+{
+       g_object_unref(cm);
+}
+
+
+static void cm_activate_cb(MidoriExtension *extension, MidoriApp *app, gpointer data)
+{
+       cm = cookie_manager_new(extension, app);
+}
+
+
+MidoriExtension *extension_init(void)
+{
+       MidoriExtension *extension;
+       GtkIconFactory *factory;
+       GtkIconSource *icon_source;
+       GtkIconSet *icon_set;
+       static GtkStockItem items[] =
+       {
+               { STOCK_COOKIE_MANAGER, N_("_Cookie Manager"), 0, 0, NULL }
+       };
+
+       factory = gtk_icon_factory_new();
+       gtk_stock_add(items, G_N_ELEMENTS(items));
+       icon_set = gtk_icon_set_new();
+       icon_source = gtk_icon_source_new();
+       gtk_icon_source_set_icon_name(icon_source, GTK_STOCK_DIALOG_AUTHENTICATION);
+       gtk_icon_set_add_source(icon_set, icon_source);
+       gtk_icon_source_free(icon_source);
+       gtk_icon_factory_add(factory, STOCK_COOKIE_MANAGER, icon_set);
+       gtk_icon_set_unref(icon_set);
+       gtk_icon_factory_add_default(factory);
+       g_object_unref(factory);
+
+       extension = g_object_new(MIDORI_TYPE_EXTENSION,
+               "name", _("Cookie Manager"),
+               "description", _("List, view and delete cookies"),
+               "version", "0.2",
+               "authors", "Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>",
+               NULL);
+
+       g_signal_connect(extension, "activate", G_CALLBACK(cm_activate_cb), NULL);
+       g_signal_connect(extension, "deactivate", G_CALLBACK(cm_deactivate_cb), NULL);
+
+       return extension;
+}
index 0ae02a7b397ea15113a8082a372be855c012e052..b461abc2da3885da4dbd59300a3c31e22b5bef90 100644 (file)
@@ -30,6 +30,7 @@ extensions/adblock.c
 extensions/colorful-tabs.c
 extensions/cookie-manager/cookie-manager.c
 extensions/cookie-manager/cookie-manager-page.c
+extensions/cookie-manager/main.c
 extensions/feed-panel/feed-atom.c
 extensions/feed-panel/feed-panel.c
 extensions/feed-panel/feed-parse.c