diff --git a/src/browser.c b/src/browser.c
index 66a29d40..1e0a9d99 100644
--- a/src/browser.c
+++ b/src/browser.c
@@ -414,8 +414,7 @@ void on_menu_tabsClosed_item_activate(GtkWidget* menuitem, CBrowser* browser)
const gchar* uri = xbel_bookmark_get_href(item);
CBrowser* curBrowser = browser_new(browser);
webView_open(curBrowser->webView, uri);
- xbel_folder_remove_item(tabtrash, item);
- xbel_item_free(item);
+ xbel_item_unref(item);
update_browser_actions(curBrowser);
}
@@ -426,15 +425,14 @@ void on_action_tabsClosed_undo_activate(GtkAction* action, CBrowser* browser)
const gchar* uri = xbel_bookmark_get_href(item);
CBrowser* curBrowser = browser_new(browser);
webView_open(curBrowser->webView, uri);
- xbel_folder_remove_item(tabtrash, item);
- xbel_item_free(item);
+ xbel_item_unref(item);
update_browser_actions(curBrowser);
}
void on_action_tabsClosed_clear_activate(GtkAction* action, CBrowser* browser)
{
// Clear the closed tabs list
- xbel_item_free(tabtrash);
+ xbel_item_unref(tabtrash);
tabtrash = xbel_folder_new();
update_browser_actions(browser);
}
@@ -494,11 +492,14 @@ static void browser_editBookmark_dialog_new(XbelItem* bookmark, CBrowser* browse
GtkWidget* entry_title = gtk_entry_new();
gtk_entry_set_activates_default(GTK_ENTRY(entry_title), TRUE);
if(!newBookmark)
- gtk_entry_set_text(GTK_ENTRY(entry_title), xbel_item_get_title(bookmark));
+ {
+ const gchar* title = xbel_item_get_title(bookmark);
+ gtk_entry_set_text(GTK_ENTRY(entry_title), title ? title : "");
+ }
gtk_box_pack_start(GTK_BOX(hbox), entry_title, TRUE, TRUE, 0);
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
gtk_widget_show_all(hbox);
-
+
hbox = gtk_hbox_new(FALSE, 8);
gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
label = gtk_label_new_with_mnemonic("_Description:");
@@ -507,30 +508,38 @@ static void browser_editBookmark_dialog_new(XbelItem* bookmark, CBrowser* browse
GtkWidget* entry_desc = gtk_entry_new();
gtk_entry_set_activates_default(GTK_ENTRY(entry_desc), TRUE);
if(!newBookmark)
- gtk_entry_set_text(GTK_ENTRY(entry_desc), xbel_item_get_desc(bookmark));
+ {
+ const gchar* desc = xbel_item_get_desc(bookmark);
+ gtk_entry_set_text(GTK_ENTRY(entry_desc), desc ? desc : "");
+ }
gtk_box_pack_start(GTK_BOX(hbox), entry_desc, TRUE, TRUE, 0);
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
gtk_widget_show_all(hbox);
-
- hbox = gtk_hbox_new(FALSE, 8);
- gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
- label = gtk_label_new_with_mnemonic("_Uri:");
- gtk_size_group_add_widget(sizegroup, label);
- gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
- GtkWidget* entry_uri = gtk_entry_new();
- gtk_entry_set_activates_default(GTK_ENTRY(entry_uri), TRUE);
- if(!newBookmark)
- gtk_entry_set_text(GTK_ENTRY(entry_uri), xbel_bookmark_get_href(bookmark));
- gtk_box_pack_start(GTK_BOX(hbox), entry_uri, TRUE, TRUE, 0);
- gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
- gtk_widget_show_all(hbox);
+
+ GtkWidget* entry_uri = NULL;
+ if(xbel_item_is_bookmark(bookmark))
+ {
+ hbox = gtk_hbox_new(FALSE, 8);
+ gtk_container_set_border_width(GTK_CONTAINER(hbox), 5);
+ label = gtk_label_new_with_mnemonic("_Uri:");
+ gtk_size_group_add_widget(sizegroup, label);
+ gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+ entry_uri = gtk_entry_new();
+ gtk_entry_set_activates_default(GTK_ENTRY(entry_uri), TRUE);
+ if(!newBookmark)
+ gtk_entry_set_text(GTK_ENTRY(entry_uri), xbel_bookmark_get_href(bookmark));
+ gtk_box_pack_start(GTK_BOX(hbox), entry_uri, TRUE, TRUE, 0);
+ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
+ gtk_widget_show_all(hbox);
+ }
gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
{
xbel_item_set_title(bookmark, gtk_entry_get_text(GTK_ENTRY(entry_title)));
xbel_item_set_desc(bookmark, gtk_entry_get_text(GTK_ENTRY(entry_desc)));
- xbel_bookmark_set_href(bookmark, gtk_entry_get_text(GTK_ENTRY(entry_uri)));
+ if(xbel_item_is_bookmark(bookmark))
+ xbel_bookmark_set_href(bookmark, gtk_entry_get_text(GTK_ENTRY(entry_uri)));
// FIXME: We want to choose a folder
if(newBookmark)
@@ -539,6 +548,230 @@ static void browser_editBookmark_dialog_new(XbelItem* bookmark, CBrowser* browse
gtk_widget_destroy(dialog);
}
+static void on_panel_bookmarks_row_activated(GtkTreeView* treeview
+ , GtkTreePath* path, GtkTreeViewColumn* column, CBrowser* browser)
+{
+ GtkTreeModel* model = gtk_tree_view_get_model(treeview);
+ GtkTreeIter iter;
+ if(gtk_tree_model_get_iter(model, &iter, path))
+ {
+ XbelItem* item;
+ gtk_tree_model_get(model, &iter, 0, &item, -1);
+ if(xbel_item_is_bookmark(item))
+ webView_open(get_nth_webView(-1, browser), xbel_bookmark_get_href(item));
+ }
+}
+
+static void panel_bookmarks_popup(GtkWidget* widget, GdkEventButton* event
+ , XbelItem* item, CBrowser* browser)
+{
+ gboolean isBookmark = xbel_item_is_bookmark(item);
+ gboolean isSeparator = xbel_item_is_separator(item);
+
+ action_set_sensitive("BookmarkOpen", isBookmark, browser);
+ action_set_sensitive("BookmarkOpenTab", isBookmark, browser);
+ action_set_sensitive("BookmarkOpenWindow", isBookmark, browser);
+
+ action_set_sensitive("BookmarkEdit", !isSeparator, browser);
+
+ sokoke_widget_popup(widget, GTK_MENU(browser->popup_bookmark), event);
+}
+
+static gboolean on_panel_bookmarks_button_release(GtkWidget* widget
+ , GdkEventButton* event, CBrowser* browser)
+{
+ if(event->button != 2 && event->button != 3)
+ return FALSE;
+
+ GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
+ if(selection)
+ {
+ GtkTreeModel* model;
+ GtkTreeIter iter;
+ gtk_tree_selection_get_selected(selection, &model, &iter);
+ XbelItem* item;
+ gtk_tree_model_get(model, &iter, 0, &item, -1);
+ if(event->button == 2 && xbel_item_is_bookmark(item))
+ {
+ CBrowser* newBrowser = browser_new(browser);
+ const gchar* uri = xbel_bookmark_get_href(item);
+ webView_open(newBrowser->webView, uri);
+ }
+ else
+ panel_bookmarks_popup(widget, event, item, browser);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void on_panel_bookmarks_popup(GtkWidget* widget, CBrowser* browser)
+{
+ GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
+ if(selection)
+ {
+ GtkTreeModel* model;
+ GtkTreeIter iter;
+ gtk_tree_selection_get_selected(selection, &model, &iter);
+ XbelItem* item;
+ gtk_tree_model_get(model, &iter, 0, &item, -1);
+ panel_bookmarks_popup(widget, NULL, item, browser);
+ }
+}
+
+void on_action_bookmarkOpen_activate(GtkAction* action, CBrowser* browser)
+{
+ GtkTreeView* treeview = GTK_TREE_VIEW(browser->panel_bookmarks);
+ GtkTreeSelection* selection = gtk_tree_view_get_selection(treeview);
+ if(selection)
+ {
+ GtkTreeModel* model;
+ GtkTreeIter iter;
+ gtk_tree_selection_get_selected(selection, &model, &iter);
+ XbelItem* item;
+ gtk_tree_model_get(model, &iter, 0, &item, -1);
+ if(xbel_item_is_bookmark(item))
+ webView_open(get_nth_webView(-1, browser), xbel_bookmark_get_href(item));
+ }
+}
+
+void on_action_bookmarkOpenTab_activate(GtkAction* action, CBrowser* browser)
+{
+ GtkTreeView* treeview = GTK_TREE_VIEW(browser->panel_bookmarks);
+ GtkTreeSelection* selection = gtk_tree_view_get_selection(treeview);
+ if(selection)
+ {
+ GtkTreeModel* model;
+ GtkTreeIter iter;
+ gtk_tree_selection_get_selected(selection, &model, &iter);
+ XbelItem* item;
+ gtk_tree_model_get(model, &iter, 0, &item, -1);
+ if(xbel_item_is_bookmark(item))
+ {
+ CBrowser* newBrowser = browser_new(browser);
+ const gchar* uri = xbel_bookmark_get_href(item);
+ webView_open(newBrowser->webView, uri);
+ }
+ }
+}
+
+void on_action_bookmarkOpenWindow_activate(GtkAction* action, CBrowser* browser)
+{
+ GtkTreeView* treeview = GTK_TREE_VIEW(browser->panel_bookmarks);
+ GtkTreeSelection* selection = gtk_tree_view_get_selection(treeview);
+ if(selection)
+ {
+ GtkTreeModel* model;
+ GtkTreeIter iter;
+ gtk_tree_selection_get_selected(selection, &model, &iter);
+ XbelItem* item;
+ gtk_tree_model_get(model, &iter, 0, &item, -1);
+ if(xbel_item_is_bookmark(item))
+ {
+ CBrowser* newBrowser = browser_new(NULL);
+ const gchar* uri = xbel_bookmark_get_href(item);
+ webView_open(newBrowser->webView, uri);
+ }
+ }
+}
+
+void on_action_bookmarkEdit_activate(GtkAction* action, CBrowser* browser)
+{
+ GtkTreeView* treeview = GTK_TREE_VIEW(browser->panel_bookmarks);
+ GtkTreeSelection* selection = gtk_tree_view_get_selection(treeview);
+ if(selection)
+ {
+ GtkTreeModel* model;
+ GtkTreeIter iter;
+ gtk_tree_selection_get_selected(selection, &model, &iter);
+ XbelItem* item;
+ gtk_tree_model_get(model, &iter, 0, &item, -1);
+ if(!xbel_item_is_separator(item))
+ browser_editBookmark_dialog_new(item, browser);
+ }
+}
+
+void on_action_bookmarkDelete_activate(GtkAction* action, CBrowser* browser)
+{
+ GtkTreeView* treeview = GTK_TREE_VIEW(browser->panel_bookmarks);
+ GtkTreeSelection* selection = gtk_tree_view_get_selection(treeview);
+ if(selection)
+ {
+ GtkTreeModel* model;
+ GtkTreeIter iter;
+ gtk_tree_selection_get_selected(selection, &model, &iter);
+ XbelItem* item;
+ gtk_tree_model_get(model, &iter, 0, &item, -1);
+ XbelItem* parent = xbel_item_get_parent(item);
+ xbel_folder_remove_item(parent, item);
+ xbel_item_unref(item);
+ }
+}
+
+static void tree_store_insert_folder(GtkTreeStore* treestore, GtkTreeIter* parent
+ , XbelItem* folder)
+{
+ guint n = xbel_folder_get_n_items(folder);
+ guint i;
+ for(i = 0; i < n; i++)
+ {
+ XbelItem* item = xbel_folder_get_nth_item(folder, i);
+ GtkTreeIter iter;
+ gtk_tree_store_insert_with_values(treestore, &iter, parent, n, 0, item, -1);
+ xbel_item_ref(item);
+ if(xbel_item_is_folder(item))
+ tree_store_insert_folder(treestore, &iter, item);
+ }
+}
+
+static void on_bookmarks_item_render_icon(GtkTreeViewColumn* column
+ , GtkCellRenderer* renderer, GtkTreeModel* model, GtkTreeIter* iter
+ , GtkWidget* treeview)
+{
+ XbelItem* item;
+ gtk_tree_model_get(model, iter, 0, &item, -1);
+
+ if(!xbel_item_get_parent(item))
+ {
+ gtk_tree_store_remove(GTK_TREE_STORE(model), iter);
+ xbel_item_unref(item);
+ return;
+ }
+
+ // TODO: Would it be better to not do this on every redraw?
+ GdkPixbuf* pixbuf = NULL;
+ if(xbel_item_is_bookmark(item))
+ pixbuf = gtk_widget_render_icon(treeview, STOCK_BOOKMARK
+ , GTK_ICON_SIZE_MENU, NULL);
+ else if(xbel_item_is_folder(item))
+ pixbuf = gtk_widget_render_icon(treeview, GTK_STOCK_DIRECTORY
+ , GTK_ICON_SIZE_MENU, NULL);
+ g_object_set(renderer, "pixbuf", pixbuf, NULL);
+ if(pixbuf)
+ g_object_unref(pixbuf);
+}
+
+static void on_bookmarks_item_render_text(GtkTreeViewColumn* column
+ , GtkCellRenderer* renderer, GtkTreeModel* model, GtkTreeIter* iter
+ , GtkWidget* treeview)
+{
+ XbelItem* item;
+ gtk_tree_model_get(model, iter, 0, &item, -1);
+
+ if(!xbel_item_get_parent(item))
+ {
+ gtk_tree_store_remove(GTK_TREE_STORE(model), iter);
+ xbel_item_unref(item);
+ return;
+ }
+
+ if(xbel_item_is_separator(item))
+ g_object_set(renderer
+ , "markup", "Separator", NULL);
+ else
+ g_object_set(renderer
+ , "markup", NULL, "text", xbel_item_get_title(item), NULL);
+}
+
static void create_bookmark_menu(XbelItem*, GtkWidget*, CBrowser*);
static void on_bookmark_menu_folder_activate(GtkWidget* menuitem, CBrowser* browser)
@@ -972,6 +1205,8 @@ CBrowser* browser_new(CBrowser* oldBrowser)
menuitem = gtk_separator_menu_item_new();
gtk_widget_show(menuitem);
gtk_menu_shell_append(GTK_MENU_SHELL(browser->menu_bookmarks), menuitem);
+ browser->popup_bookmark = gtk_ui_manager_get_widget(ui_manager, "/popup_bookmark");
+ g_object_ref(browser->popup_bookmark);
browser->menu_window = gtk_menu_item_get_submenu(
GTK_MENU_ITEM(gtk_ui_manager_get_widget(ui_manager, "/menubar/Window")));
menuitem = gtk_separator_menu_item_new();
@@ -1142,6 +1377,40 @@ CBrowser* browser_new(CBrowser* oldBrowser)
// Dummy: This is the "fallback" panel for now
page = gtk_notebook_append_page(GTK_NOTEBOOK(browser->panels_notebook)
, gtk_label_new("empty"), NULL);
+ // Bookmarks
+ GtkTreeViewColumn* column;
+ GtkCellRenderer* renderer_text; GtkCellRenderer* renderer_pixbuf;
+ GtkTreeStore* treestore = gtk_tree_store_new(1, G_TYPE_XBEL_ITEM);
+ GtkWidget* treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(treestore));
+ gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
+ column = gtk_tree_view_column_new();
+ renderer_pixbuf = gtk_cell_renderer_pixbuf_new();
+ gtk_tree_view_column_pack_start(column, renderer_pixbuf, FALSE);
+ gtk_tree_view_column_set_cell_data_func(column, renderer_pixbuf
+ , (GtkTreeCellDataFunc)on_bookmarks_item_render_icon, treeview, NULL);
+ renderer_text = gtk_cell_renderer_text_new();
+ gtk_tree_view_column_pack_start(column, renderer_text, FALSE);
+ gtk_tree_view_column_set_cell_data_func(column, renderer_text
+ , (GtkTreeCellDataFunc)on_bookmarks_item_render_text, treeview, NULL);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
+ GtkWidget* scrolled = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled)
+ , GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_container_add(GTK_CONTAINER(scrolled), treeview);
+ gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN);
+ tree_store_insert_folder(GTK_TREE_STORE(treestore), NULL, bookmarks);
+ g_object_unref(treestore);
+ g_signal_connect(treeview, "row-activated"
+ , G_CALLBACK(on_panel_bookmarks_row_activated), browser);
+ g_signal_connect(treeview, "button-release-event"
+ , G_CALLBACK(on_panel_bookmarks_button_release), browser);
+ g_signal_connect(treeview, "popup-menu"
+ , G_CALLBACK(on_panel_bookmarks_popup), browser);
+ browser->panel_bookmarks = treeview;
+ page = gtk_notebook_append_page(GTK_NOTEBOOK(browser->panels_notebook)
+ , scrolled, NULL);
+ action = gtk_action_group_get_action(browser->actiongroup, "PanelBookmarks");
+ g_object_set_data(G_OBJECT(action), "iPage", GINT_TO_POINTER(page));
// Pageholder
browser->panel_pageholder = webView_new(&scrolled);
page = gtk_notebook_append_page(GTK_NOTEBOOK(browser->panels_notebook)
@@ -1242,6 +1511,7 @@ CBrowser* browser_new(CBrowser* oldBrowser)
browser->actiongroup = oldBrowser->actiongroup;
browser->menubar = oldBrowser->menubar;
browser->menu_bookmarks = oldBrowser->menu_bookmarks;
+ browser->popup_bookmark = oldBrowser->popup_bookmark;
browser->menu_window = oldBrowser->menu_window;
browser->popup_webView = oldBrowser->popup_webView;
browser->popup_element = oldBrowser->popup_element;
diff --git a/src/browser.h b/src/browser.h
index 0d08b352..f25cebd2 100644
--- a/src/browser.h
+++ b/src/browser.h
@@ -26,6 +26,7 @@ typedef struct _CBrowser
// menus
GtkWidget* menubar;
GtkWidget* menu_bookmarks;
+ GtkWidget* popup_bookmark;
GtkWidget* menu_window;
GtkWidget* popup_webView;
GtkWidget* popup_element;
@@ -42,6 +43,7 @@ typedef struct _CBrowser
// panels
GtkWidget* panels;
GtkWidget* panels_notebook;
+ GtkWidget* panel_bookmarks;
GtkWidget* panel_pageholder;
GtkWidget* webViews;
// findbox
@@ -203,6 +205,21 @@ on_action_link_saveWith_activate(GtkAction*, CBrowser*);
void
on_action_link_copy_activate(GtkAction*, CBrowser*);
+void
+on_action_bookmarkOpen_activate(GtkAction*, CBrowser*);
+
+void
+on_action_bookmarkOpenTab_activate(GtkAction*, CBrowser*);
+
+void
+on_action_bookmarkOpenWindow_activate(GtkAction*, CBrowser*);
+
+void
+on_action_bookmarkEdit_activate(GtkAction*, CBrowser*);
+
+void
+on_action_bookmarkDelete_activate(GtkAction*, CBrowser*);
+
void
on_menu_bookmarks_item_activate(GtkWidget*, CBrowser*);
@@ -438,6 +455,21 @@ static const GtkActionEntry entries[] = {
{ "BookmarksManage", STOCK_BOOKMARKS
, "_Manage Bookmarks", "b"
, "hm?", NULL/*G_CALLBACK(on_action_bookmarks_manage_activate)*/ },
+ { "BookmarkOpen", GTK_STOCK_OPEN
+ , NULL, ""
+ , "hm?", G_CALLBACK(on_action_bookmarkOpen_activate) },
+ { "BookmarkOpenTab", STOCK_TAB_NEW
+ , "Open in New _Tab", ""
+ , "hm?", G_CALLBACK(on_action_bookmarkOpenTab_activate) },
+ { "BookmarkOpenWindow", STOCK_WINDOW_NEW
+ , "Open in New _Window", ""
+ , "hm?", G_CALLBACK(on_action_bookmarkOpenWindow_activate) },
+ { "BookmarkEdit", GTK_STOCK_EDIT
+ , NULL, ""
+ , "hm?", G_CALLBACK(on_action_bookmarkEdit_activate) },
+ { "BookmarkDelete", GTK_STOCK_DELETE
+ , NULL, ""
+ , "hm?", G_CALLBACK(on_action_bookmarkDelete_activate) },
{ "Tools", NULL, "_Tools" },
diff --git a/src/main.c b/src/main.c
index e23eece8..1edd038e 100755
--- a/src/main.c
+++ b/src/main.c
@@ -204,8 +204,8 @@ int main(int argc, char** argv)
{
config_free(config);
search_engines_free(searchEngines);
- xbel_item_free(bookmarks);
- xbel_item_free(_session);
+ xbel_item_unref(bookmarks);
+ xbel_item_unref(_session);
g_string_free(errorMessages, TRUE);
return 0;
}
@@ -254,7 +254,7 @@ int main(int argc, char** argv)
browser = browser_new(browser);
webView_open(browser->webView, xbel_bookmark_get_href(item));
}
- xbel_item_free(_session);
+ xbel_item_unref(_session);
gtk_main();
@@ -277,7 +277,7 @@ int main(int argc, char** argv)
g_warning("Bookmarks couldn't be saved. %s", error->message);
g_error_free(error);
}
- xbel_item_free(bookmarks);
+ xbel_item_unref(bookmarks);
g_free(configFile);
configFile = g_build_filename(configPath, "tabtrash.xbel", NULL);
error = NULL;
@@ -286,7 +286,7 @@ int main(int argc, char** argv)
g_warning("Tabtrash couldn't be saved. %s", error->message);
g_error_free(error);
}
- xbel_item_free(tabtrash);
+ xbel_item_unref(tabtrash);
g_free(configFile);
if(config->startup == CONFIG_STARTUP_SESSION)
{
@@ -299,7 +299,7 @@ int main(int argc, char** argv)
}
g_free(configFile);
}
- xbel_item_free(session);
+ xbel_item_unref(session);
configFile = g_build_filename(configPath, "config", NULL);
error = NULL;
if(!config_to_file(config, configFile, &error))
diff --git a/src/ui.h b/src/ui.h
index e57b7139..a5832109 100644
--- a/src/ui.h
+++ b/src/ui.h
@@ -166,6 +166,14 @@ static const gchar* ui_markup =
""
""
""
+ ""
+ ""
+ ""
+ ""
+ ""
+ ""
+ ""
+ ""
""
""
""
diff --git a/src/webView.c b/src/webView.c
index 03845218..24a2809b 100644
--- a/src/webView.c
+++ b/src/webView.c
@@ -292,12 +292,18 @@ void on_webView_destroy(GtkWidget* widget, CBrowser* browser)
browsers = g_list_delete_link(browsers, tmp);
g_free(browser->elementUri);
g_free(browser->statusMessage);
- if(!g_list_length(browsers))
+ // FIXME: Multiple windows are not taken into account
+ if(!g_list_nth(browsers, 0))
{
g_object_unref(browser->actiongroup);
+ g_object_unref(browser->popup_bookmark);
g_object_unref(browser->popup_webView);
g_object_unref(browser->popup_element);
g_object_unref(browser->popup_editable);
+ guint i;
+ guint n = xbel_folder_get_n_items(bookmarks);
+ for(i = 0; i < n; i++)
+ xbel_item_unref(xbel_folder_get_nth_item(bookmarks, i));
gtk_main_quit();
}
}
@@ -340,12 +346,11 @@ void webView_close(GtkWidget* webView, CBrowser* browser)
if(n > 10)
{
XbelItem* item = xbel_folder_get_nth_item(tabtrash, n - 1);
- xbel_folder_remove_item(tabtrash, item);
- xbel_item_free(item);
+ xbel_item_unref(item);
}
}
else
- xbel_item_free(browser->sessionItem);
+ xbel_item_unref(browser->sessionItem);
gtk_widget_destroy(browser->webView_menu);
gtk_notebook_remove_page(GTK_NOTEBOOK(browser->webViews)
, get_webView_index(webView, browser));
diff --git a/src/xbel.c b/src/xbel.c
index f788e4ca..07b625da 100644
--- a/src/xbel.c
+++ b/src/xbel.c
@@ -38,6 +38,7 @@
static XbelItem* xbel_item_new(XbelItemKind kind)
{
XbelItem* item = g_new(XbelItem, 1);
+ item->refs = 1;
item->parent = NULL;
item->kind = kind;
if(kind == XBEL_ITEM_FOLDER)
@@ -220,18 +221,41 @@ static gboolean xbel_folder_from_xmlDocPtr(XbelItem* folder, xmlDocPtr doc)
}
/**
- * xbel_item_free:
+ * xbel_item_ref:
* @item: a valid item
*
- * Free an XbelItem. If @item is a folder all of its children will also
- * be freed automatically.
+ * Ref an XbelItem.
*
- * The item must not be contained in a folder or attempting to free it will fail.
+ * Ref means that the reference count is increased by one.
+ *
+ * This has no effect on children of a folder.
**/
-void xbel_item_free(XbelItem* item)
+void xbel_item_ref(XbelItem* item)
{
g_return_if_fail(item);
- g_return_if_fail(!xbel_item_get_parent(item));
+ item->refs++;
+}
+
+/**
+ * xbel_item_unref:
+ * @item: a valid item
+ *
+ * Unref an XbelItem. If @item is a folder all of its children will also
+ * be unreffed automatically.
+ *
+ * Unref means that the reference count is decreased. If there are no
+ * references left, the memory will be freed and if needed removed from
+ * its containing folder.
+ **/
+void xbel_item_unref(XbelItem* item)
+{
+ g_return_if_fail(item);
+ item->refs--;
+ if(item->refs)
+ return;
+ XbelItem* parent = xbel_item_get_parent(item);
+ if(parent)
+ xbel_folder_remove_item(parent, item);
if(xbel_item_is_folder(item))
{
guint n = xbel_folder_get_n_items(item);
@@ -240,7 +264,7 @@ void xbel_item_free(XbelItem* item)
{
XbelItem* _item = xbel_folder_get_nth_item(item, i);
_item->parent = NULL;
- xbel_item_free(_item);
+ xbel_item_unref(_item);
}
g_list_free(item->items);
}
@@ -260,7 +284,7 @@ void xbel_item_free(XbelItem* item)
*
* Copy an XbelItem.
*
- * The returned item must be freed eventually.
+ * The returned item must be unreffed eventually.
*
* Return value: a copy of @item
**/
diff --git a/src/xbel.h b/src/xbel.h
index cf593ea0..2fb6bf40 100644
--- a/src/xbel.h
+++ b/src/xbel.h
@@ -37,6 +37,7 @@ typedef enum
// Note: This structure is entirely private.
typedef struct
{
+ guint refs;
XbelItemKind kind;
struct XbelItem* parent;
@@ -60,7 +61,10 @@ XbelItem*
xbel_folder_new(void);
void
-xbel_item_free(XbelItem*);
+xbel_item_ref(XbelItem*);
+
+void
+xbel_item_unref(XbelItem*);
XbelItem*
xbel_item_copy(XbelItem*);