/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
/* GTK - The GIMP Toolkit
* gtkbookmarksmanager . c : Utilities to manage and monitor ~ / . gtk - bookmarks
* Copyright ( C ) 2003 , Red Hat , Inc .
* Copyright ( C ) 2007 - 2008 Carlos Garnacho
* Copyright ( C ) 2011 Suse
*
* This program 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 .
*
* 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 Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program ; if not , see < http : //www.gnu.org/licenses/>.
*
* Authors : Federico Mena Quintero < federico @ gnome . org >
*/
#include "config.h"
#include <string.h>
#include <glib/gi18n-lib.h>
#include "gtkbookmarksmanagerprivate.h"
#include "deprecated/gtkfilechooser.h" /* for the GError types */
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
static void
_gtk_bookmark_free (gpointer data)
{
GtkBookmark *bookmark = data;
g_object_unref (bookmark->file);
g_free (bookmark->label);
g_free (bookmark);
}
static void
set_error_bookmark_doesnt_exist (GFile *file, GError **error)
{
char *uri = g_file_get_uri (file);
g_set_error (error,
GTK_FILE_CHOOSER_ERROR,
GTK_FILE_CHOOSER_ERROR_NONEXISTENT,
_("%s does not exist in the bookmarks list" ),
uri);
g_free (uri);
}
static GFile *
get_legacy_bookmarks_file (void )
{
GFile *file;
char *filename;
filename = g_build_filename (g_get_home_dir (), ".gtk-bookmarks" , NULL);
file = g_file_new_for_path (filename);
g_free (filename);
return file;
}
static GFile *
get_bookmarks_file (void )
{
GFile *file;
char *filename;
/* Use gtk-3.0's bookmarks file as the format didn't change.
* Add the 3 . 0 file format to get_legacy_bookmarks_file ( ) when
* the format does change .
*/
filename = g_build_filename (g_get_user_config_dir (), "gtk-3.0" , "bookmarks" , NULL);
file = g_file_new_for_path (filename);
g_free (filename);
return file;
}
static GSList *
parse_bookmarks (const char *contents)
{
char **lines, *space;
GSList *bookmarks = NULL;
int i;
lines = g_strsplit (contents, "\n" , -1 );
for (i = 0 ; lines[i]; i++)
{
GtkBookmark *bookmark;
if (!*lines[i])
continue ;
if (!g_utf8_validate (lines[i], -1 , NULL))
continue ;
bookmark = g_new0 (GtkBookmark, 1 );
if ((space = strchr (lines[i], ' ' )) != NULL)
{
space[0 ] = '\0' ;
bookmark->label = g_strdup (space + 1 );
}
bookmark->file = g_file_new_for_uri (lines[i]);
bookmarks = g_slist_prepend (bookmarks, bookmark);
}
bookmarks = g_slist_reverse (bookmarks);
g_strfreev (lines);
return bookmarks;
}
static GSList *
read_bookmarks (GFile *file)
{
char *contents;
GSList *bookmarks = NULL;
if (!g_file_load_contents (file, NULL, &contents,
NULL, NULL, NULL))
return NULL;
bookmarks = parse_bookmarks (contents);
g_free (contents);
return bookmarks;
}
static void
notify_changed (GtkBookmarksManager *manager)
{
if (manager->changed_func)
manager->changed_func (manager->changed_func_data);
}
static void
read_bookmarks_finish (GObject *source,
GAsyncResult *result,
gpointer data)
{
GFile *file = G_FILE (source);
GtkBookmarksManager *manager = data;
char *contents = NULL;
GError *error = NULL;
if (!g_file_load_contents_finish (file, result, &contents, NULL, NULL, &error))
{
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
g_warning ("Failed to load '%s': %s" , g_file_peek_path (file), error->message);
g_error_free (error);
return ;
}
g_slist_free_full (manager->bookmarks, _gtk_bookmark_free);
manager->bookmarks = parse_bookmarks (contents);
g_free (contents);
notify_changed (manager);
}
static void
save_bookmarks (GFile *bookmarks_file,
GSList *bookmarks)
{
GError *error = NULL;
GString *contents;
GSList *l;
GFile *parent = NULL;
contents = g_string_new ("" );
for (l = bookmarks; l; l = l->next)
{
GtkBookmark *bookmark = l->data;
char *uri;
uri = g_file_get_uri (bookmark->file);
if (!uri)
continue ;
g_string_append (contents, uri);
if (bookmark->label && g_utf8_validate (bookmark->label, -1 , NULL))
g_string_append_printf (contents, " %s" , bookmark->label);
g_string_append_c (contents, '\n' );
g_free (uri);
}
parent = g_file_get_parent (bookmarks_file);
if (!g_file_make_directory_with_parents (parent, NULL, &error))
{
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
g_clear_error (&error);
else
goto out;
}
if (!g_file_replace_contents (bookmarks_file,
contents->str,
contents->len,
NULL, FALSE , 0 , NULL,
NULL, &error))
goto out;
out:
if (error)
{
g_critical ("%s" , error->message);
g_error_free (error);
}
g_clear_object (&parent);
g_string_free (contents, TRUE );
}
static void
bookmarks_file_changed (GFileMonitor *monitor,
GFile *file,
GFile *other_file,
GFileMonitorEvent event,
gpointer data)
{
GtkBookmarksManager *manager = data;
switch (event)
{
case G_FILE_MONITOR_EVENT_CHANGED:
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
case G_FILE_MONITOR_EVENT_CREATED:
g_file_load_contents_async (file, manager->cancellable, read_bookmarks_finish, manager);
break ;
case G_FILE_MONITOR_EVENT_DELETED:
case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
case G_FILE_MONITOR_EVENT_UNMOUNTED:
case G_FILE_MONITOR_EVENT_MOVED:
case G_FILE_MONITOR_EVENT_RENAMED:
case G_FILE_MONITOR_EVENT_MOVED_IN:
case G_FILE_MONITOR_EVENT_MOVED_OUT:
default :
/* ignore at the moment */
break ;
}
}
GtkBookmarksManager *
_gtk_bookmarks_manager_new (GtkBookmarksChangedFunc changed_func, gpointer changed_func_data)
{
GtkBookmarksManager *manager;
GFile *bookmarks_file;
GError *error;
manager = g_new0 (GtkBookmarksManager, 1 );
manager->changed_func = changed_func;
manager->changed_func_data = changed_func_data;
manager->cancellable = g_cancellable_new ();
bookmarks_file = get_bookmarks_file ();
if (!g_file_query_exists (bookmarks_file, NULL))
{
GFile *legacy_bookmarks_file;
/* Read the legacy one and write it to the new one */
legacy_bookmarks_file = get_legacy_bookmarks_file ();
manager->bookmarks = read_bookmarks (legacy_bookmarks_file);
if (manager->bookmarks)
save_bookmarks (bookmarks_file, manager->bookmarks);
g_object_unref (legacy_bookmarks_file);
}
else
g_file_load_contents_async (bookmarks_file, manager->cancellable, read_bookmarks_finish, manager);
error = NULL;
manager->bookmarks_monitor = g_file_monitor_file (bookmarks_file,
G_FILE_MONITOR_NONE,
NULL, &error);
if (error)
{
g_warning ("%s" , error->message);
g_error_free (error);
}
else
manager->bookmarks_monitor_changed_id = g_signal_connect (manager->bookmarks_monitor, "changed" ,
G_CALLBACK (bookmarks_file_changed), manager);
g_object_unref (bookmarks_file);
return manager;
}
void
_gtk_bookmarks_manager_free (GtkBookmarksManager *manager)
{
g_return_if_fail (manager != NULL);
g_cancellable_cancel (manager->cancellable);
g_object_unref (manager->cancellable);
if (manager->bookmarks_monitor)
{
g_file_monitor_cancel (manager->bookmarks_monitor);
g_clear_signal_handler (&manager->bookmarks_monitor_changed_id, manager->bookmarks_monitor);
g_object_unref (manager->bookmarks_monitor);
}
g_slist_free_full (manager->bookmarks, _gtk_bookmark_free);
g_free (manager);
}
GSList *
_gtk_bookmarks_manager_list_bookmarks (GtkBookmarksManager *manager)
{
GSList *bookmarks, *files = NULL;
g_return_val_if_fail (manager != NULL, NULL);
bookmarks = manager->bookmarks;
while (bookmarks)
{
GtkBookmark *bookmark;
bookmark = bookmarks->data;
bookmarks = bookmarks->next;
files = g_slist_prepend (files, g_object_ref (bookmark->file));
}
return g_slist_reverse (files);
}
static GSList *
find_bookmark_link_for_file (GSList *bookmarks, GFile *file, int *position_ret)
{
int pos;
pos = 0 ;
for (; bookmarks; bookmarks = bookmarks->next)
{
GtkBookmark *bookmark = bookmarks->data;
if (g_file_equal (file, bookmark->file))
{
if (position_ret)
*position_ret = pos;
return bookmarks;
}
pos++;
}
if (position_ret)
*position_ret = -1 ;
return NULL;
}
gboolean
_gtk_bookmarks_manager_has_bookmark (GtkBookmarksManager *manager,
GFile *file)
{
GSList *link;
link = find_bookmark_link_for_file (manager->bookmarks, file, NULL);
return (link != NULL);
}
gboolean
_gtk_bookmarks_manager_insert_bookmark (GtkBookmarksManager *manager,
GFile *file,
int position,
GError **error)
{
GSList *link;
GtkBookmark *bookmark;
GFile *bookmarks_file;
g_return_val_if_fail (manager != NULL, FALSE );
g_return_val_if_fail (error == NULL || *error == NULL, FALSE );
link = find_bookmark_link_for_file (manager->bookmarks, file, NULL);
if (link)
{
char *uri;
bookmark = link->data;
uri = g_file_get_uri (bookmark->file);
g_set_error (error,
GTK_FILE_CHOOSER_ERROR,
GTK_FILE_CHOOSER_ERROR_ALREADY_EXISTS,
_("%s already exists in the bookmarks list" ),
uri);
g_free (uri);
return FALSE ;
}
bookmark = g_new0 (GtkBookmark, 1 );
bookmark->file = g_object_ref (file);
manager->bookmarks = g_slist_insert (manager->bookmarks, bookmark, position);
bookmarks_file = get_bookmarks_file ();
save_bookmarks (bookmarks_file, manager->bookmarks);
g_object_unref (bookmarks_file);
notify_changed (manager);
return TRUE ;
}
gboolean
_gtk_bookmarks_manager_remove_bookmark (GtkBookmarksManager *manager,
GFile *file,
GError **error)
{
GSList *link;
GFile *bookmarks_file;
g_return_val_if_fail (manager != NULL, FALSE );
g_return_val_if_fail (error == NULL || *error == NULL, FALSE );
if (!manager->bookmarks)
return FALSE ;
link = find_bookmark_link_for_file (manager->bookmarks, file, NULL);
if (link)
{
GtkBookmark *bookmark = link->data;
manager->bookmarks = g_slist_remove_link (manager->bookmarks, link);
_gtk_bookmark_free (bookmark);
g_slist_free_1 (link);
}
else
{
set_error_bookmark_doesnt_exist (file, error);
return FALSE ;
}
bookmarks_file = get_bookmarks_file ();
save_bookmarks (bookmarks_file, manager->bookmarks);
g_object_unref (bookmarks_file);
notify_changed (manager);
return TRUE ;
}
gboolean
_gtk_bookmarks_manager_reorder_bookmark (GtkBookmarksManager *manager,
GFile *file,
int new_position,
GError **error)
{
GSList *link;
GFile *bookmarks_file;
int old_position;
g_return_val_if_fail (manager != NULL, FALSE );
g_return_val_if_fail (error == NULL || *error == NULL, FALSE );
g_return_val_if_fail (new_position >= 0 , FALSE );
if (!manager->bookmarks)
return FALSE ;
link = find_bookmark_link_for_file (manager->bookmarks, file, &old_position);
if (new_position == old_position)
return TRUE ;
if (link)
{
GtkBookmark *bookmark = link->data;
manager->bookmarks = g_slist_remove_link (manager->bookmarks, link);
g_slist_free_1 (link);
if (new_position > old_position)
new_position--;
manager->bookmarks = g_slist_insert (manager->bookmarks, bookmark, new_position);
}
else
{
set_error_bookmark_doesnt_exist (file, error);
return FALSE ;
}
bookmarks_file = get_bookmarks_file ();
save_bookmarks (bookmarks_file, manager->bookmarks);
g_object_unref (bookmarks_file);
notify_changed (manager);
return TRUE ;
}
char *
_gtk_bookmarks_manager_get_bookmark_label (GtkBookmarksManager *manager,
GFile *file)
{
GSList *bookmarks;
char *label = NULL;
g_return_val_if_fail (manager != NULL, NULL);
g_return_val_if_fail (file != NULL, NULL);
bookmarks = manager->bookmarks;
while (bookmarks)
{
GtkBookmark *bookmark;
bookmark = bookmarks->data;
bookmarks = bookmarks->next;
if (g_file_equal (file, bookmark->file))
{
label = g_strdup (bookmark->label);
break ;
}
}
return label;
}
gboolean
_gtk_bookmarks_manager_set_bookmark_label (GtkBookmarksManager *manager,
GFile *file,
const char *label,
GError **error)
{
GFile *bookmarks_file;
GSList *link;
g_return_val_if_fail (manager != NULL, FALSE );
g_return_val_if_fail (file != NULL, FALSE );
link = find_bookmark_link_for_file (manager->bookmarks, file, NULL);
if (link)
{
GtkBookmark *bookmark = link->data;
g_free (bookmark->label);
bookmark->label = g_strdup (label);
}
else
{
set_error_bookmark_doesnt_exist (file, error);
return FALSE ;
}
bookmarks_file = get_bookmarks_file ();
save_bookmarks (bookmarks_file, manager->bookmarks);
g_object_unref (bookmarks_file);
notify_changed (manager);
return TRUE ;
}
static gboolean
_gtk_bookmarks_manager_get_xdg_type (GtkBookmarksManager *manager,
GFile *file,
GUserDirectory *directory)
{
GSList *link;
gboolean match;
GFile *location;
const char *path;
GUserDirectory dir;
GtkBookmark *bookmark;
link = find_bookmark_link_for_file (manager->bookmarks, file, NULL);
if (!link)
return FALSE ;
match = FALSE ;
bookmark = link->data;
for (dir = 0 ; dir < G_USER_N_DIRECTORIES; dir++)
{
path = g_get_user_special_dir (dir);
if (!path)
continue ;
location = g_file_new_for_path (path);
match = g_file_equal (location, bookmark->file);
g_object_unref (location);
if (match)
break ;
}
if (match && directory != NULL)
*directory = dir;
return match;
}
gboolean
_gtk_bookmarks_manager_get_is_builtin (GtkBookmarksManager *manager,
GFile *file)
{
GUserDirectory xdg_type;
/* if this is not an XDG dir, it's never builtin */
if (!_gtk_bookmarks_manager_get_xdg_type (manager, file, &xdg_type))
return FALSE ;
/* exclude XDG locations we don't display by default */
return _gtk_bookmarks_manager_get_is_xdg_dir_builtin (xdg_type);
}
gboolean
_gtk_bookmarks_manager_get_is_xdg_dir_builtin (GUserDirectory xdg_type)
{
return (xdg_type != G_USER_DIRECTORY_DESKTOP) &&
(xdg_type != G_USER_DIRECTORY_TEMPLATES) &&
(xdg_type != G_USER_DIRECTORY_PUBLIC_SHARE);
}
Messung V0.5 in Prozent C=98 H=95 G=96
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-07-02)
¤
*© Formatika GbR, Deutschland