]> spindle.queued.net Git - midori/commitdiff
Implement the bookmarks panel with editing capabilities.
authorChristian Dywan <christian@twotoasts.de>
Mon, 31 Dec 2007 22:49:22 +0000 (23:49 +0100)
committerChristian Dywan <christian@twotoasts.de>
Mon, 31 Dec 2007 22:53:02 +0000 (23:53 +0100)
The bookmarks panel can display a tree of bookmarks and allows
editing and deleting of bookmarks via a context menu.

The XBEL implementation has been altered to work with a
reference count model to allow panels to update on their own.

src/browser.c
src/browser.h
src/main.c
src/ui.h
src/webView.c
src/xbel.c
src/xbel.h

index 66a29d405f232452a1753d94de013c6442a10a64..1e0a9d99215fc2f9bcf6128db989d5d8e0078e86 100644 (file)
@@ -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", "<i>Separator</i>", 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;
index 0d08b3528d3fe5464751d5fcd4cd9d2bbf170945..f25cebd20efca5ef8f9f57a3615f107ecb17262d 100644 (file)
@@ -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", "<Ctrl>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" },
 
index e23eece8cf52ae3e6c5d29a72671740dfb8dcf15..1edd038ed9e393890fd67d5f99970550c27b3f0c 100755 (executable)
@@ -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))
index e57b71396b1bcaa5eab3470998c31aea80d5f120..a5832109e7c4c612302559da69f5a3df7a72e253 100644 (file)
--- a/src/ui.h
+++ b/src/ui.h
@@ -166,6 +166,14 @@ static const gchar* ui_markup =
    "<toolitem action='PanelExtensions'/>"
    "<toolitem action='PanelConsole'/>"
   "</toolbar>"
+  "<popup name='popup_bookmark'>"
+   "<menuitem action='BookmarkOpen'/>"
+   "<menuitem action='BookmarkOpenTab'/>"
+   "<menuitem action='BookmarkOpenWindow'/>"
+   "<separator/>"
+   "<menuitem action='BookmarkEdit'/>"
+   "<menuitem action='BookmarkDelete'/>"
+  "</popup>"
   "<popup name='popup_webView'>"
    "<menuitem action='Back'/>"
    "<menuitem action='Forward'/>"
index 038452182c3dfb0532ef8b50f7bcec4f1ef9dd9e..24a2809b8ece59cc01dccd37ad547efe79cb4027 100644 (file)
@@ -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));
index f788e4ca2cdd487b875027932b5a259079ed866e..07b625da26a5a4e26c448041bc3472dc9142fd7e 100644 (file)
@@ -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
  **/
index cf593ea0ffed962f8a1bde784ce36d3bfd89372c..2fb6bf40ef4642ab23b96e6618b2cf18a71d6e55 100644 (file)
@@ -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*);