/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Pix * * Copyright (C) 2009 Free Software Foundation, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include "actions.h" #include "callbacks.h" #define BROWSER_DATA_KEY "bookmarks-browser-data" static const GActionEntry actions[] = { { "bookmarks-add", gth_browser_activate_bookmarks_add }, { "bookmarks-edit", gth_browser_activate_bookmarks_edit } }; typedef struct { GthBrowser *browser; GtkBuilder *builder; guint bookmarks_changed_id; guint entry_points_changed_id; GMenu *system_bookmarks_menu; GMenu *entry_points_menu; GMenu *bookmarks_menu; } BrowserData; static void browser_data_free (BrowserData *data) { if (data->bookmarks_changed_id != 0) { g_signal_handler_disconnect (gth_main_get_default_monitor (), data->bookmarks_changed_id); data->bookmarks_changed_id = 0; } if (data->entry_points_changed_id != 0) { g_signal_handler_disconnect (gth_main_get_default_monitor (), data->entry_points_changed_id); data->entry_points_changed_id = 0; } _g_object_unref (data->builder); g_free (data); } #define BUFFER_SIZE 4096 typedef struct { GthBrowser *browser; GInputStream *stream; char buffer[BUFFER_SIZE]; GString *file_content; } UpdateBookmarksData; static void update_bookmakrs_data_free (UpdateBookmarksData *data) { g_input_stream_close (data->stream, NULL, NULL); g_object_unref (data->stream); g_string_free (data->file_content, TRUE); g_object_unref (data->browser); g_free (data); } static void update_system_bookmark_list_from_content (GthBrowser *browser, const char *content) { BrowserData *data; char **lines; int i; data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY); g_return_if_fail (data != NULL); lines = g_strsplit (content, "\n", -1); for (i = 0; lines[i] != NULL; i++) { char **line; char *uri; GFile *file; char *first_space; char *name; GMenuItem *item; line = g_strsplit (lines[i], " ", 2); uri = line[0]; if (uri == NULL) { g_strfreev (line); continue; } file = g_file_new_for_uri (uri); first_space = strchr (lines[i], ' '); name = (first_space != NULL) ? g_strdup (first_space + 1) : NULL; item = _g_menu_item_new_for_file (file, name); g_menu_item_set_action_and_target (item, "win.go-to-location", "s", uri); g_menu_append_item (data->system_bookmarks_menu, item); g_object_unref (item); g_free (name); g_object_unref (file); g_strfreev (line); } g_strfreev (lines); } static void update_system_bookmark_list_ready (GObject *source_object, GAsyncResult *result, gpointer user_data) { UpdateBookmarksData *data = user_data; gssize size; size = g_input_stream_read_finish (data->stream, result, NULL); if (size < 0) { update_bookmakrs_data_free (data); return; } if (size > 0) { data->buffer[size + 1] = '\0'; g_string_append (data->file_content, data->buffer); g_input_stream_read_async (data->stream, data->buffer, BUFFER_SIZE - 1, G_PRIORITY_DEFAULT, NULL, update_system_bookmark_list_ready, data); return; } update_system_bookmark_list_from_content (data->browser, data->file_content->str); update_bookmakrs_data_free (data); } static void _gth_browser_update_system_bookmark_list (GthBrowser *browser) { BrowserData *browser_data; GFile *bookmark_file; GFileInputStream *input_stream; UpdateBookmarksData *data; browser_data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY); g_return_if_fail (browser_data != NULL); g_menu_remove_all (browser_data->system_bookmarks_menu); /* give priority to XDG_CONFIG_HOME/gtk-3.0/bookmarks if not found * try the old ~/.gtk-bookmarks */ bookmark_file = gth_user_dir_get_file_for_read (GTH_DIR_CONFIG, "gtk-3.0", "bookmarks", NULL); if (! g_file_query_exists (bookmark_file, NULL)) { char *path; g_object_unref (bookmark_file); path = g_build_filename (g_get_home_dir (), ".gtk-bookmarks", NULL); bookmark_file = g_file_new_for_path (path); g_free (path); } input_stream = g_file_read (bookmark_file, NULL, NULL); g_object_unref (bookmark_file); if (input_stream == NULL) return; data = g_new0 (UpdateBookmarksData, 1); data->browser = g_object_ref (browser); data->stream = (GInputStream*) input_stream; data->file_content = g_string_new (""); g_input_stream_read_async (data->stream, data->buffer, BUFFER_SIZE - 1, G_PRIORITY_DEFAULT, NULL, update_system_bookmark_list_ready, data); } static void _gth_browser_update_bookmark_list (GthBrowser *browser) { BrowserData *data; GBookmarkFile *bookmarks; char **uris; int i; data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY); g_return_if_fail (data != NULL); g_menu_remove_all (data->bookmarks_menu); bookmarks = gth_main_get_default_bookmarks (); uris = g_bookmark_file_get_uris (bookmarks, NULL); for (i = 0; uris[i] != NULL; i++) { GFile *file; char *name; GMenuItem *item; file = g_file_new_for_uri (uris[i]); name = g_bookmark_file_get_title (bookmarks, uris[i], NULL); item = _g_menu_item_new_for_file (file, name); g_menu_item_set_action_and_target (item, "win.go-to-location", "s", uris[i]); g_menu_append_item (data->bookmarks_menu, item); g_object_unref (item); g_free (name); g_object_unref (file); } _gth_browser_update_system_bookmark_list (browser); g_strfreev (uris); } static void bookmarks_changed_cb (GthMonitor *monitor, gpointer user_data) { BrowserData *data = user_data; _gth_browser_update_bookmark_list (data->browser); } static void _gth_browser_update_entry_point_list (GthBrowser *browser) { BrowserData *data; GList *entry_points; GList *scan; data = g_object_get_data (G_OBJECT (browser), BROWSER_DATA_KEY); g_return_if_fail (data != NULL); g_menu_remove_all (data->entry_points_menu); entry_points = gth_main_get_all_entry_points (); for (scan = entry_points; scan; scan = scan->next) { GthFileData *file_data = scan->data; GMenuItem *item; char *uri; item = _g_menu_item_new_for_file_data (file_data); uri = g_file_get_uri (file_data->file); g_menu_item_set_action_and_target (item, "win.go-to-location", "s", uri); g_menu_append_item (data->entry_points_menu, item); g_free (uri); g_object_unref (item); } _g_object_list_unref (entry_points); } static void entry_points_changed_cb (GthMonitor *monitor, gpointer user_data) { BrowserData *data = user_data; call_when_idle ((DataFunc) _gth_browser_update_entry_point_list, data->browser); } void bookmarks__gth_browser_construct_cb (GthBrowser *browser) { BrowserData *data; g_return_if_fail (GTH_IS_BROWSER (browser)); data = g_new0 (BrowserData, 1); g_object_set_data_full (G_OBJECT (browser), BROWSER_DATA_KEY, data, (GDestroyNotify) browser_data_free); g_action_map_add_action_entries (G_ACTION_MAP (browser), actions, G_N_ELEMENTS (actions), browser); { GtkWidget *button; GMenuModel *menu; button = _gtk_menu_button_new_for_header_bar ("user-bookmarks-symbolic"); gtk_widget_set_tooltip_text (button, _("Bookmarks")); data->builder = gtk_builder_new_from_resource ("/org/x/Pix/bookmarks/data/ui/bookmarks-menu.ui"); data->system_bookmarks_menu = G_MENU (gtk_builder_get_object (data->builder, "system-bookmarks")); data->entry_points_menu = G_MENU (gtk_builder_get_object (data->builder, "entry-points")); data->bookmarks_menu = G_MENU (gtk_builder_get_object (data->builder, "bookmarks")); menu = G_MENU_MODEL (gtk_builder_get_object (data->builder, "bookmarks-menu")); gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (button), menu); _gtk_window_add_accelerators_from_menu ((GTK_WINDOW (browser)), menu); gtk_widget_show (button); gtk_box_pack_end (GTK_BOX (gth_browser_get_headerbar_section (browser, GTH_BROWSER_HEADER_SECTION_BROWSER_LOCATIONS)), button, FALSE, FALSE, 0); } data->browser = browser; data->bookmarks_changed_id = g_signal_connect (gth_main_get_default_monitor (), "bookmarks-changed", G_CALLBACK (bookmarks_changed_cb), data); data->entry_points_changed_id = g_signal_connect (gth_main_get_default_monitor (), "entry-points-changed", G_CALLBACK (entry_points_changed_cb), data); } void bookmarks__gth_browser_construct_idle_callback_cb (GthBrowser *browser) { _gth_browser_update_bookmark_list (browser); _gth_browser_update_entry_point_list (browser); }