From d0e4d9279d7aa4be1ddec50c2a87c63638632712 Mon Sep 17 00:00:00 2001 From: Marco Pesenti Gritti Date: Thu, 30 Jun 2005 13:32:05 +0000 Subject: [PATCH] Metadata manager from gedit but modified to use GValue, so that we dont 2005-06-30 Marco Pesenti Gritti * shell/Makefile.am: * shell/ev-metadata-manager.c: (item_free), (ev_metadata_manager_init), (ev_metadata_manager_shutdown), (parse_value), (parseItem), (load_values), (ev_metadata_manager_get), (value_free), (ev_metadata_manager_set), (save_values), (save_item), (get_oldest), (resize_items), (ev_metadata_manager_save), (ev_metadata_manager_set_int): * shell/ev-metadata-manager.h: Metadata manager from gedit but modified to use GValue, so that we dont need to keep converting from strings. * configure.ac: ENABLE_METADATA conditional, on when dbus is on * shell/ev-application.c: (ev_application_open_uri): Show the window after load so that we can initialize window size before it's showed. * shell/ev-window.c: (ev_window_setup_from_metadata), (ev_window_open_uri), (window_configure_event_cb), (ev_window_init): Save and load metadata information about window size. Not yet keeping states in account. * shell/main.c: (main): Shutdown metadata manager. --- ChangeLog | 34 +++ configure.ac | 2 + shell/.cvsignore | 1 + shell/Makefile.am | 6 + shell/ev-application.c | 4 +- shell/ev-metadata-manager.c | 551 ++++++++++++++++++++++++++++++++++++ shell/ev-metadata-manager.h | 44 +++ shell/ev-window.c | 44 +++ shell/main.c | 4 + 9 files changed, 688 insertions(+), 2 deletions(-) create mode 100644 shell/ev-metadata-manager.c create mode 100644 shell/ev-metadata-manager.h diff --git a/ChangeLog b/ChangeLog index 446bab40..892f2722 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,37 @@ +2005-06-30 Marco Pesenti Gritti + + * shell/Makefile.am: + * shell/ev-metadata-manager.c: (item_free), + (ev_metadata_manager_init), (ev_metadata_manager_shutdown), + (parse_value), (parseItem), (load_values), + (ev_metadata_manager_get), (value_free), (ev_metadata_manager_set), + (save_values), (save_item), (get_oldest), (resize_items), + (ev_metadata_manager_save), (ev_metadata_manager_set_int): + * shell/ev-metadata-manager.h: + + Metadata manager from gedit but modified to use GValue, so that + we dont need to keep converting from strings. + + * configure.ac: + + ENABLE_METADATA conditional, on when dbus is on + + * shell/ev-application.c: (ev_application_open_uri): + + Show the window after load so that we can initialize + window size before it's showed. + + * shell/ev-window.c: (ev_window_setup_from_metadata), + (ev_window_open_uri), (window_configure_event_cb), + (ev_window_init): + + Save and load metadata information about window size. + Not yet keeping states in account. + + * shell/main.c: (main): + + Shutdown metadata manager. + 2005-06-24 Marco Pesenti Gritti * shell/ev-application-service.xml: diff --git a/configure.ac b/configure.ac index 823e5ce6..227b0206 100644 --- a/configure.ac +++ b/configure.ac @@ -58,10 +58,12 @@ AC_MSG_RESULT([$enable_dbus]) if test "x$enable_dbus" = "xyes" ; then AC_DEFINE([ENABLE_DBUS],[1],[Define if DBUS support is enabled]) + AC_DEFINE([ENABLE_METADATA],[1],[Define if metadata support is enabled]) PKG_CHECK_MODULES([DBUS], [dbus-glib-1 >= $DBUS_GLIB_REQUIRED]) fi AM_CONDITIONAL([ENABLE_DBUS], [test "x$enable_dbus" = "xyes"]) +AM_CONDITIONAL([ENABLE_METADATA], [test "x$enable_dbus" = "xyes"]) dnl Compile with disable-deprecated switches diff --git a/shell/.cvsignore b/shell/.cvsignore index 20713bab..c292c6ad 100644 --- a/shell/.cvsignore +++ b/shell/.cvsignore @@ -2,4 +2,5 @@ Makefile Makefile.in evince ev-marshal.[ch] +ev-application-service.h *pdf diff --git a/shell/Makefile.am b/shell/Makefile.am index 689199e6..71faed51 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -105,6 +105,12 @@ evince_SOURCES= \ main.c \ $(NULL) +if ENABLE_METADATA +evince_SOURCES += \ + ev-metadata-manager.h \ + ev-metadata-manager.c +endif + evince_LDADD= \ $(SHELL_LIBS) \ $(top_builddir)/cut-n-paste/recent-files/librecent.la \ diff --git a/shell/ev-application.c b/shell/ev-application.c index 6a106fcc..6b8ef370 100644 --- a/shell/ev-application.c +++ b/shell/ev-application.c @@ -177,10 +177,10 @@ ev_application_open_uri (EvApplication *application, new_window = EV_WINDOW (ev_window_new ()); } - gtk_window_present (GTK_WINDOW (new_window)); - ev_window_open_uri (new_window, uri); + gtk_window_present (GTK_WINDOW (new_window)); + if (page_label != NULL) { ev_window_open_page_label (new_window, page_label); } diff --git a/shell/ev-metadata-manager.c b/shell/ev-metadata-manager.c new file mode 100644 index 00000000..bbf5f762 --- /dev/null +++ b/shell/ev-metadata-manager.c @@ -0,0 +1,551 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * ev-metadata-manager.c + * This file is part of ev + * + * Copyright (C) 2003 Paolo Maggi + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the ev Team, 2003. See the AUTHORS file for a + * list of people on the ev Team. + * See the ChangeLog files for a list of changes. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include "ev-metadata-manager.h" +#include "ev-file-helpers.h" + +#define METADATA_FILE "ev-metadata.xml" + +#define MAX_ITEMS 50 + +typedef struct _GeditMetadataManager GeditMetadataManager; + +typedef struct _Item Item; + +struct _Item +{ + time_t atime; /* time of last access */ + + GHashTable *values; +}; + +struct _GeditMetadataManager +{ + gboolean values_loaded; /* It is true if the file + has been read */ + + gboolean modified; /* It is true if the file + has top be written */ + + guint timeout_id; + + GHashTable *items; +}; + +static void ev_metadata_manager_save (gpointer data); + + +static GeditMetadataManager *ev_metadata_manager = NULL; + +static void +item_free (gpointer data) +{ + Item *item; + + g_return_if_fail (data != NULL); + + item = (Item *)data; + + if (item->values != NULL) + g_hash_table_destroy (item->values); + + g_free (item); +} + +static gboolean +ev_metadata_manager_init (void) +{ + if (ev_metadata_manager != NULL) + return TRUE; + + ev_metadata_manager = g_new0 (GeditMetadataManager, 1); + + ev_metadata_manager->values_loaded = FALSE; + ev_metadata_manager->modified = FALSE; + + ev_metadata_manager->items = + g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + item_free); + + ev_metadata_manager->timeout_id = + g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, + 2000, /* 2 sec */ + (GSourceFunc)ev_metadata_manager_save, + NULL, + NULL); + + return TRUE; +} + +/* This function must be called before exiting ev */ +void +ev_metadata_manager_shutdown (void) +{ + if (ev_metadata_manager == NULL) + return; + + g_source_remove (ev_metadata_manager->timeout_id); + + ev_metadata_manager_save (NULL); + + if (ev_metadata_manager->items != NULL) + g_hash_table_destroy (ev_metadata_manager->items); + + g_free (ev_metadata_manager); + ev_metadata_manager = NULL; +} + +static GValue * +parse_value (xmlChar *value, xmlChar *type) +{ + GType ret_type; + GValue *ret; + + ret_type = g_type_from_name ((char *)type); + ret = g_new0 (GValue, 1); + g_value_init (ret, ret_type); + + switch (ret_type) { + case G_TYPE_STRING: + g_value_set_string (ret, (char *)value); + break; + case G_TYPE_INT: + g_value_set_int (ret, atoi ((char *)value)); + break; + } + + return ret; +} + +static void +parseItem (xmlDocPtr doc, xmlNodePtr cur) +{ + Item *item; + + xmlChar *uri; + xmlChar *atime; + + if (xmlStrcmp (cur->name, (const xmlChar *)"document") != 0) + return; + + uri = xmlGetProp (cur, (const xmlChar *)"uri"); + if (uri == NULL) + return; + + atime = xmlGetProp (cur, (const xmlChar *)"atime"); + if (atime == NULL) + { + xmlFree (uri); + return; + } + + item = g_new0 (Item, 1); + + item->atime = atol ((char *)atime); + + item->values = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_free); + + cur = cur->xmlChildrenNode; + + while (cur != NULL) + { + if (xmlStrcmp (cur->name, (const xmlChar *)"entry") == 0) + { + xmlChar *key; + xmlChar *xml_value; + xmlChar *type; + GValue *value; + + key = xmlGetProp (cur, (const xmlChar *)"key"); + xml_value = xmlGetProp (cur, (const xmlChar *)"value"); + type = xmlGetProp (cur, (const xmlChar *)"type"); + value = parse_value (xml_value, type); + + if ((key != NULL) && (value != NULL)) + g_hash_table_insert (item->values, + xmlStrdup (key), + value); + + if (key != NULL) + xmlFree (key); + if (xml_value != NULL) + xmlFree (xml_value); + } + + cur = cur->next; + } + + g_hash_table_insert (ev_metadata_manager->items, + xmlStrdup (uri), + item); + + xmlFree (uri); + xmlFree (atime); +} + +static gboolean +load_values () +{ + xmlDocPtr doc; + xmlNodePtr cur; + gchar *file_name; + + g_return_val_if_fail (ev_metadata_manager != NULL, FALSE); + g_return_val_if_fail (ev_metadata_manager->values_loaded == FALSE, FALSE); + + ev_metadata_manager->values_loaded = TRUE; + + xmlKeepBlanksDefault (0); + + /* FIXME: file locking - Paolo */ + file_name = g_build_filename (ev_dot_dir (), METADATA_FILE, NULL); + if (!g_file_test (file_name, G_FILE_TEST_EXISTS)) + { + g_free (file_name); + return FALSE; + } + + doc = xmlParseFile (file_name); + g_free (file_name); + + if (doc == NULL) + { + return FALSE; + } + + cur = xmlDocGetRootElement (doc); + if (cur == NULL) + { + g_message ("The metadata file '%s' is empty", METADATA_FILE); + xmlFreeDoc (doc); + + return FALSE; + } + + if (xmlStrcmp (cur->name, (const xmlChar *) "metadata")) + { + g_message ("File '%s' is of the wrong type", METADATA_FILE); + xmlFreeDoc (doc); + + return FALSE; + } + + cur = xmlDocGetRootElement (doc); + cur = cur->xmlChildrenNode; + + while (cur != NULL) + { + parseItem (doc, cur); + + cur = cur->next; + } + + xmlFreeDoc (doc); + + return TRUE; +} + +gboolean +ev_metadata_manager_get (const gchar *uri, + const gchar *key, + GValue *value) +{ + Item *item; + GValue *ret; + + g_return_val_if_fail (uri != NULL, FALSE); + g_return_val_if_fail (key != NULL, FALSE); + + if (ev_metadata_manager == NULL) + ev_metadata_manager_init (); + + if (!ev_metadata_manager->values_loaded) + { + gboolean res; + + res = load_values (); + + if (!res) + return FALSE; + } + + item = (Item *)g_hash_table_lookup (ev_metadata_manager->items, + uri); + + if (item == NULL) + return FALSE; + + item->atime = time (NULL); + + if (item->values == NULL) + return FALSE; + + ret = (GValue *)g_hash_table_lookup (item->values, key); + + if (ret == NULL) { + return FALSE; + } else { + g_value_init (value, G_VALUE_TYPE (ret)); + g_value_copy (ret, value); + + return TRUE; + } +} + +static void +value_free (gpointer data) +{ + GValue *value = (GValue *)data; + + g_value_unset (value); + g_free (value); +} + +void +ev_metadata_manager_set (const gchar *uri, + const gchar *key, + const GValue *value) +{ + Item *item; + + g_return_if_fail (uri != NULL); + g_return_if_fail (key != NULL); + + if (ev_metadata_manager == NULL) + ev_metadata_manager_init (); + + if (!ev_metadata_manager->values_loaded) + { + gboolean res; + + res = load_values (); + + if (!res) + return; + } + + item = (Item *)g_hash_table_lookup (ev_metadata_manager->items, + uri); + + if (item == NULL) + { + item = g_new0 (Item, 1); + + g_hash_table_insert (ev_metadata_manager->items, + g_strdup (uri), + item); + } + + if (item->values == NULL) + item->values = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + value_free); + if (value != NULL) { + GValue *new; + + new = g_new0 (GValue, 1); + g_value_init (new, G_VALUE_TYPE (value)); + g_value_copy (value, new); + + g_hash_table_insert (item->values, + g_strdup (key), + new); + } else { + g_hash_table_remove (item->values, + key); + } + + item->atime = time (NULL); + + ev_metadata_manager->modified = TRUE; +} + +static void +save_values (const gchar *key, GValue *value, xmlNodePtr parent) +{ + char *string_value; + xmlNodePtr xml_node; + + g_return_if_fail (key != NULL); + + if (value == NULL) + return; + + xml_node = xmlNewChild (parent, NULL, (const xmlChar *)"entry", NULL); + + xmlSetProp (xml_node, (const xmlChar *)"key", (const xmlChar *)key); + xmlSetProp (xml_node, + (const xmlChar *)"type", + (const xmlChar *)g_type_name (G_VALUE_TYPE (value))); + + switch (G_VALUE_TYPE (value)) { + case G_TYPE_STRING: + string_value = g_strdup (g_value_get_string (value)); + break; + case G_TYPE_INT: + string_value = g_strdup_printf ("%d", g_value_get_int (value)); + break; + default: + string_value = NULL; + g_assert_not_reached (); + } + + xmlSetProp (xml_node, (const xmlChar *)"value", (const xmlChar *)string_value); + + g_free (string_value); +} + +static void +save_item (const gchar *key, const gpointer *data, xmlNodePtr parent) +{ + xmlNodePtr xml_node; + const Item *item = (const Item *)data; + gchar *atime; + + g_return_if_fail (key != NULL); + + if (item == NULL) + return; + + xml_node = xmlNewChild (parent, NULL, (const xmlChar *)"document", NULL); + + xmlSetProp (xml_node, (const xmlChar *)"uri", (const xmlChar *)key); + + /* FIXME: is the cast right? - Paolo */ + atime = g_strdup_printf ("%d", (int)item->atime); + xmlSetProp (xml_node, (const xmlChar *)"atime", (const xmlChar *)atime); + + g_free (atime); + + g_hash_table_foreach (item->values, + (GHFunc)save_values, xml_node); +} + +static void +get_oldest (const gchar *key, const gpointer value, const gchar ** key_to_remove) +{ + const Item *item = (const Item *)value; + + if (*key_to_remove == NULL) + { + *key_to_remove = key; + } + else + { + const Item *item_to_remove = + g_hash_table_lookup (ev_metadata_manager->items, + *key_to_remove); + + g_return_if_fail (item_to_remove != NULL); + + if (item->atime < item_to_remove->atime) + { + *key_to_remove = key; + } + } +} + +static void +resize_items () +{ + while (g_hash_table_size (ev_metadata_manager->items) > MAX_ITEMS) + { + gpointer key_to_remove = NULL; + + g_hash_table_foreach (ev_metadata_manager->items, + (GHFunc)get_oldest, + &key_to_remove); + + g_return_if_fail (key_to_remove != NULL); + + g_hash_table_remove (ev_metadata_manager->items, + key_to_remove); + } +} + +static void +ev_metadata_manager_save (gpointer data) +{ + xmlDocPtr doc; + xmlNodePtr root; + gchar *file_name; + + if (!ev_metadata_manager->modified) + return; + + resize_items (); + + xmlIndentTreeOutput = TRUE; + + doc = xmlNewDoc ((const xmlChar *)"1.0"); + if (doc == NULL) + return; + + /* Create metadata root */ + root = xmlNewDocNode (doc, NULL, (const xmlChar *)"metadata", NULL); + xmlDocSetRootElement (doc, root); + + g_hash_table_foreach (ev_metadata_manager->items, + (GHFunc)save_item, root); + + /* FIXME: lock file - Paolo */ + file_name = g_build_filename (ev_dot_dir (), METADATA_FILE, NULL); + xmlSaveFormatFile (file_name, doc, 1); + g_free (file_name); + + xmlFreeDoc (doc); + + ev_metadata_manager->modified = FALSE; +} + +void +ev_metadata_manager_set_int (const gchar *uri, const gchar *key, int value) +{ + GValue val = { 0, }; + + g_value_init (&val, G_TYPE_INT); + g_value_set_int (&val, value); + + ev_metadata_manager_set (uri, key, &val); +} diff --git a/shell/ev-metadata-manager.h b/shell/ev-metadata-manager.h new file mode 100644 index 00000000..5c4d61d6 --- /dev/null +++ b/shell/ev-metadata-manager.h @@ -0,0 +1,44 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * ev-metadata-manager.h + * + * Copyright (C) 2003 Paolo Maggi + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EV_METADATA_MANAGER_H__ +#define __EV_METADATA_MANAGER_H__ + +#include +#include + +G_BEGIN_DECLS + +gboolean ev_metadata_manager_get (const gchar *uri, + const gchar *key, + GValue *value); +void ev_metadata_manager_set (const gchar *uri, + const gchar *key, + const GValue *value); +void ev_metadata_manager_set_int (const gchar *uri, + const gchar *key, + int value); +void ev_metadata_manager_shutdown (void); + +G_END_DECLS + +#endif /* __EV_METADATA_MANAGER_H__ */ diff --git a/shell/ev-window.c b/shell/ev-window.c index 11ee1ad4..63b1b9c1 100644 --- a/shell/ev-window.c +++ b/shell/ev-window.c @@ -60,6 +60,7 @@ #include "ev-application.h" #include "ev-stock-icons.h" #include "ev-file-helpers.h" +#include "ev-metadata-manager.h" #include @@ -906,6 +907,23 @@ ev_window_xfer_job_cb (EvJobXfer *job, } } +#ifdef ENABLE_METADATA +static void +ev_window_setup_from_metadata (EvWindow *window) +{ + char *uri = window->priv->uri; + GValue width = { 0, }; + GValue height = { 0, }; + + ev_metadata_manager_get (uri, "window_width", &width); + ev_metadata_manager_get (uri, "window_height", &height); + + gtk_window_set_default_size (GTK_WINDOW (window), + g_value_get_int (&width), + g_value_get_int (&height)); +} +#endif + void ev_window_open_uri (EvWindow *ev_window, const char *uri) { @@ -914,6 +932,10 @@ ev_window_open_uri (EvWindow *ev_window, const char *uri) g_free (ev_window->priv->uri); ev_window->priv->uri = g_strdup (uri); + +#ifdef ENABLE_METADATA + ev_window_setup_from_metadata (ev_window); +#endif ev_window_clear_jobs (ev_window); ev_window_clear_local_uri (ev_window); @@ -2975,6 +2997,25 @@ sidebar_page_main_widget_update_cb (GObject *ev_sidebar_page, } } +static gboolean +window_configure_event_cb (EvWindow *window, gpointer dummy) +{ +#ifdef ENABLE_METADATA + int width, height; + + if (window->priv->uri == NULL) { + return FALSE; + } + + gtk_window_get_size (GTK_WINDOW (window), &width, &height); + + ev_metadata_manager_set_int (window->priv->uri, "window_width", width); + ev_metadata_manager_set_int (window->priv->uri, "window_height", height); + + return FALSE; +#endif +} + static void ev_window_init (EvWindow *ev_window) { @@ -2986,6 +3027,9 @@ ev_window_init (EvWindow *ev_window) GConfClient *client; int sidebar_size; + g_signal_connect (ev_window, "configure_event", + G_CALLBACK (window_configure_event_cb), NULL); + ev_window->priv = EV_WINDOW_GET_PRIVATE (ev_window); ev_window->priv->page_mode = PAGE_MODE_DOCUMENT; diff --git a/shell/main.c b/shell/main.c index d412a5e5..0b50cbd0 100644 --- a/shell/main.c +++ b/shell/main.c @@ -21,6 +21,7 @@ #include "config.h" #include "ev-application.h" +#include "ev-metadata-manager.h" #include #include @@ -164,6 +165,9 @@ main (int argc, char *argv[]) gnome_accelerators_sync (); poptFreeContext (context); ev_file_helpers_shutdown (); +#if ENABLE_METADATA + ev_metadata_manager_shutdown (); +#endif return 0; } -- 2.43.5