[gtk+/zeitgeist] Start working on GtkRecentManagerAndZeitgeist.



commit 66ff8f87854d383e0d10eeb6923ad67d0f070908
Author: Siegfried-Angel Gevatter Pujals <rainct ubuntu com>
Date:   Tue Dec 27 20:54:23 2011 +0100

    Start working on GtkRecentManagerAndZeitgeist.

 gtk/gtkrecentmanager.c |  318 +++++++++++++++++++++++++++++++++++++++++++++++-
 gtk/gtkrecentmanager.h |   56 ++++++++-
 2 files changed, 370 insertions(+), 4 deletions(-)
---
diff --git a/gtk/gtkrecentmanager.c b/gtk/gtkrecentmanager.c
index a674b5d..931cb26 100644
--- a/gtk/gtkrecentmanager.c
+++ b/gtk/gtkrecentmanager.c
@@ -2,6 +2,8 @@
  * gtkrecentmanager.c: a manager for the recently used resources
  *
  * Copyright (C) 2006 Emmanuele Bassi
+ * Copyright (C) 2011 Collabora Ltd.
+ *               By Siegfried-Angel Gevatter <sgevatter gnome org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -119,6 +121,19 @@
 /* keep in sync with xdgmime */
 #define GTK_RECENT_DEFAULT_MIME	"application/octet-stream"
 
+/* Zeitgeist D-Bus constants */
+#define ZEITGEIST_BUS_NAME			"org.gnome.zeitgeist.Engine"
+#define ZEITGEIST_INTERFACE_NAME	"org.gnome.zeitgeist.Log"
+#define ZEITGEIST_OBJECT_PATH		"/org/gnome/zeitgeist/log/activity"
+#define ZEITGEIST_WAIT_TIMEOUT		1000
+
+/* Other Zeitgeist constants */
+#define ZEITGEIST_INTERPRETATION_CREATE_EVENT	"http://www.zeitgeist-project.com/ontologies/2010/01/27/zg#CreateEvent";
+#define ZEITGEIST_INTERPRETATION_ACCESS_EVENT	"http://www.zeitgeist-project.com/ontologies/2010/01/27/zg#AccessEvent";
+#define ZEITGEIST_INTERPRETATION_LEAVE_EVENT	"http://www.zeitgeist-project.com/ontologies/2010/01/27/zg#LeaveEvent";
+#define ZEITGEIST_INTERPRETATION_MODIFY_EVENT	"http://www.zeitgeist-project.com/ontologies/2010/01/27/zg#ModifyEvent";
+#define ZEITGEIST_MANIFESTATION_USER_ACTIVITY	"http://www.zeitgeist-project.com/ontologies/2010/01/27/zg#UserActivity";
+
 typedef struct
 {
   gchar *name;
@@ -179,6 +194,9 @@ struct _GtkRecentManagerPrivate
 
   guint changed_timeout;
   guint changed_age;
+
+  GDBusConnection *connection;
+  GCancellable *cancellable;
 };
 
 enum
@@ -337,6 +355,25 @@ gtk_recent_manager_class_init (GtkRecentManagerClass *klass)
   g_type_class_add_private (klass, sizeof (GtkRecentManagerPrivate));
 }
 
+static GDBusConnection *
+get_connection (void)
+{
+  GDBusConnection *connection;
+  GError *error = NULL;
+
+  connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
+
+  if (error)
+    {
+      g_debug ("Couldn't connect to D-Bus session bus, %s", error->message);
+      g_error_free (error);
+      return NULL;
+    }
+
+  return connection;
+
+}
+
 static void
 gtk_recent_manager_init (GtkRecentManager *manager)
 {
@@ -349,6 +386,8 @@ gtk_recent_manager_init (GtkRecentManager *manager)
 
   priv->size = 0;
   priv->filename = NULL;
+
+  priv->cancellable = g_cancellable_new ();
 }
 
 static void
@@ -398,6 +437,19 @@ gtk_recent_manager_finalize (GObject *object)
   GtkRecentManager *manager = GTK_RECENT_MANAGER (object);
   GtkRecentManagerPrivate *priv = manager->priv;
 
+  if (priv->cancellable)
+    {
+      g_cancellable_cancel (priv->cancellable);
+      g_object_unref (priv->cancellable);
+      priv->cancellable = NULL;
+    }
+
+  if (priv->connection)
+    {
+      g_object_unref (priv->connection);
+      priv->connection = NULL;
+    }
+
   g_free (priv->filename);
 
   if (priv->recent_items != NULL)
@@ -958,6 +1010,164 @@ gtk_recent_manager_add_full (GtkRecentManager     *manager,
 }
 
 /**
+ * gtk_recent_manager_add_activity:
+ * @manager: a #GtkRecentManager
+ * @type: a GtkRecentManagerType
+ * @recent_data: information to be logged.
+ *
+ * Adds an activity to the system's activity log.
+ *
+ * Since: FIXME
+ */
+void
+gtk_recent_manager_add_activity (GtkRecentManager  *manager,
+			     const gchar                       type,
+                 const GtkRecentActivityData       *data)
+{
+  GtkRecentManagerPrivate *priv;
+
+  g_return_if_fail (GTK_IS_RECENT_MANAGER (manager));
+  g_return_if_fail (data != NULL);
+
+  /* sanity checks */
+  if (!data->uri)
+    {
+      g_warning ("Attempting to log an activity but no URI was defined");
+      return;
+    }
+
+  if ((data->uri) &&
+      (!g_utf8_validate (data->uri, -1, NULL)))
+    {
+      g_warning ("Attempting to log an activity, but the URI (`%s')"
+        "is not a valid UTF-8 encoded string", data->uri);
+      return;
+    }
+
+  if ((data->display_name) &&
+      (!g_utf8_validate (data->display_name, -1, NULL)))
+    {
+      g_warning ("Attempting to log an activity concerning `%s', but the "
+        "display name is not a valid UTF-8 encoded string",
+        data->uri);
+      return;
+    }
+
+  if (!data->mime_type)
+    {
+      g_warning ("Attempting to log an activity concerning `%s', but "
+        "no MIME-type was defined", data->uri);
+      return;
+    }
+
+  if (data->application && (
+      (!g_str_has_prefix (data->application, "application://")) ||
+      (!g_str_has_suffix (data->application, ".desktop"))))
+    {
+      g_warning ("Attempting to log an activity concerning `%s', but "
+         " the given application identifier is invalid.", data->uri);
+      return;
+    }
+
+  priv = manager->priv;
+
+  /* get missing info */
+  // FIXME: uncomment this
+  /*if (!data->mime_type)
+    {
+      GFile* file;
+      file = g_file_new_for_uri (data->uri);
+
+      // FIXME: use g_file_query_info_async
+      g_file_query_info (file,
+                           G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+                           //G_PRIORITY_DEFAULT,
+                           G_FILE_QUERY_INFO_NONE,
+                           priv->cancellable,
+                           NULL);
+                           //gtk_recent_manager_add_activity_query_info,
+                           //g_object_ref (manager));
+
+      g_object_unref (file);
+  }*/
+
+  // FIXME: figure out data->application if it's NULL
+
+  /* send event to Zeitgeist */
+  if (!priv->connection)
+    {
+      priv->connection = get_connection ();
+      if (!priv->connection)
+        return;
+    }
+
+  GError *error = NULL;
+
+  GVariantBuilder vb;
+  GVariant *parameters;
+
+  // FIXME: coalesce insertions?
+  g_variant_builder_init (&vb, G_VARIANT_TYPE ("a(asaasay)"));
+  g_variant_builder_open (&vb, G_VARIANT_TYPE ("a(asaasay)"));
+
+  // Event
+  g_variant_builder_open (&vb, G_VARIANT_TYPE ("as"));
+  g_variant_builder_add (&vb, "s", "" /*timestamp_str, sprintf*/); // FIXME
+  if (type == GTK_RECENT_MANAGER_ACTIVITY_TYPE_CREATED)
+    g_variant_builder_add (&vb, "s", ZEITGEIST_INTERPRETATION_CREATE_EVENT);
+  else if (type == GTK_RECENT_MANAGER_ACTIVITY_TYPE_OPENED)
+    g_variant_builder_add (&vb, "s", ZEITGEIST_INTERPRETATION_ACCESS_EVENT);
+  else if (type == GTK_RECENT_MANAGER_ACTIVITY_TYPE_CLOSED)
+    g_variant_builder_add (&vb, "s", ZEITGEIST_INTERPRETATION_LEAVE_EVENT);
+  else if (type == GTK_RECENT_MANAGER_ACTIVITY_TYPE_MODIFIED)
+    g_variant_builder_add (&vb, "s", ZEITGEIST_INTERPRETATION_MODIFY_EVENT);
+  else
+    {
+      g_warning ("Attempted to log an activity concerning `%s', but the ",
+        "given activity type is invalid.", data->uri);
+      return;
+    }
+  g_variant_builder_add(&vb, "s", ZEITGEIST_MANIFESTATION_USER_ACTIVITY);
+  g_variant_builder_add(&vb, "s", data->application);
+  g_variant_builder_close (&vb);
+
+  // Subject
+  g_variant_builder_open (&vb, G_VARIANT_TYPE ("aas"));
+  g_variant_builder_open (&vb, G_VARIANT_TYPE ("as"));
+  g_variant_builder_add (&vb, "s", data->uri);
+  g_variant_builder_add (&vb, "s", ""); // empty interpretation, new enough
+                                        // ZG will guess it from MIME-type
+  g_variant_builder_add (&vb, "s", ""); // empty manifestation, new enough ZG
+                                        // will guess it from URI
+  g_variant_builder_add (&vb, "s", ""); // no origin - FIXME: add option for it?
+  g_variant_builder_add (&vb, "s", data->mime_type);
+  g_variant_builder_add (&vb, "s", (data->display_name) ? data->display_name : "");
+  g_variant_builder_add (&vb, "s", ""); // empty storage, ZG will guess it
+  g_variant_builder_close (&vb);
+  g_variant_builder_close (&vb);
+
+  // Payload
+  g_variant_builder_open (&vb, G_VARIANT_TYPE ("ay"));
+  g_variant_builder_close (&vb);
+
+  g_variant_builder_close (&vb);
+  parameters = g_variant_builder_end (&vb);
+
+  // FIXME: make async
+  g_dbus_connection_call_sync (priv->connection,
+                                       ZEITGEIST_BUS_NAME,
+                                       ZEITGEIST_OBJECT_PATH,
+                                       ZEITGEIST_INTERFACE_NAME,
+                                       "InsertEvents",
+                                       parameters,
+                                       NULL, // reply type, we don't care
+                                       G_DBUS_CALL_FLAGS_NONE,
+                                       ZEITGEIST_WAIT_TIMEOUT,
+                                       priv->cancellable,
+                                       &error);
+}
+
+/**
  * gtk_recent_manager_remove_item:
  * @manager: a #GtkRecentManager
  * @uri: the URI of the item you wish to remove
@@ -1257,6 +1467,112 @@ gtk_recent_manager_get_items (GtkRecentManager *manager)
 {
   GtkRecentManagerPrivate *priv;
   GList *retval = NULL;
+  //gchar **uris;
+  gsize n_events, i;
+
+  g_return_val_if_fail (GTK_IS_RECENT_MANAGER (manager), NULL);
+
+  priv = manager->priv;
+  //if (!priv->recent_items)
+  //  return NULL;
+
+  if (!priv->connection)
+    {
+      priv->connection = get_connection ();
+      // FIXME: if (!priv->connection) ????
+    }
+
+  GError *error = NULL;
+  GVariant *reply;
+
+  GVariantBuilder vb;
+  GVariant *parameters;
+
+  g_variant_builder_init (&vb, G_VARIANT_TYPE ("((xx)a(asaasay)uuu)"));
+  g_variant_builder_add (&vb, "(xx)", 0, 1000000000000000);
+  g_variant_builder_open (&vb, G_VARIANT_TYPE ("a(asaasay)"));
+  g_variant_builder_close (&vb);
+  g_variant_builder_add (&vb, "u", 0); // storage state
+  g_variant_builder_add (&vb, "u", 100); // num. events
+  g_variant_builder_add (&vb, "u", 2); // MOST_RECENT_SUBJECTS
+  parameters = g_variant_builder_end (&vb);
+
+  reply = g_dbus_connection_call_sync (priv->connection,
+                                       ZEITGEIST_BUS_NAME,
+                                       ZEITGEIST_OBJECT_PATH,
+                                       ZEITGEIST_INTERFACE_NAME,
+                                       "FindEvents",
+                                       parameters,
+                                       NULL, // a(asaasay)
+                                       G_DBUS_CALL_FLAGS_NONE,
+                                       ZEITGEIST_WAIT_TIMEOUT,
+                                       priv->cancellable,
+                                       &error);
+
+  if (error)
+    {
+      g_warning ("Couldn't request events from Zeitgeist: %s", error->message);
+      g_error_free (error);
+      return NULL;
+    }
+
+  GVariant *events;
+  events = g_variant_get_child_value (reply, 0);
+  g_variant_unref (reply);
+
+  n_events = g_variant_n_children (events);
+  for (i = 0; i < n_events; ++i)
+    {
+      GVariant *event, *event_data, *subjects;
+      GVariantIter iter, subjects_iter, *subject_data_iter;
+
+      event = g_variant_get_child_value (events, i);
+      g_variant_iter_init (&iter, event);
+      event_data = g_variant_iter_next_value (&iter);
+      subjects = g_variant_iter_next_value (&iter);
+
+      g_variant_iter_init (&subjects_iter, subjects);
+      while (g_variant_iter_loop (&subjects_iter, "as", &subject_data_iter))
+        {
+          gchar *uri = NULL;
+          GtkRecentInfo *info;
+
+          g_variant_iter_next (subject_data_iter, "s", &uri);
+          info = gtk_recent_info_new (uri);
+          retval = g_list_prepend (retval, info);
+
+          g_free (uri);
+        }
+
+      g_variant_unref (event);
+      g_variant_unref (event_data);
+      g_variant_unref (subjects);
+    }
+  retval = g_list_reverse (retval);
+
+  g_variant_unref (events);
+
+  return retval;
+}
+
+/**
+ * gtk_recent_manager_get_items:
+ * @manager: a #GtkRecentManager
+ *
+ * Gets the list of recently used resources.
+ *
+ * Return value:  (element-type GtkRecentInfo) (transfer full): a list of
+ *   newly allocated #GtkRecentInfo objects. Use
+ *   gtk_recent_info_unref() on each item inside the list, and then
+ *   free the list itself using g_list_free().
+ *
+ * Since: 2.10
+ */
+/*GList *
+gtk_recent_manager_get_items_old (GtkRecentManager *manager)
+{
+  GtkRecentManagerPrivate *priv;
+  GList *retval = NULL;
   gchar **uris;
   gsize uris_len, i;
   
@@ -1280,7 +1596,7 @@ gtk_recent_manager_get_items (GtkRecentManager *manager)
   g_strfreev (uris);
   
   return retval;
-}
+}*/
 
 static void
 purge_recent_items_list (GtkRecentManager  *manager,
diff --git a/gtk/gtkrecentmanager.h b/gtk/gtkrecentmanager.h
index 6d7bda6..a27fb24 100644
--- a/gtk/gtkrecentmanager.h
+++ b/gtk/gtkrecentmanager.h
@@ -40,8 +40,9 @@ G_BEGIN_DECLS
 #define GTK_IS_RECENT_MANAGER_CLASS(klass)	(G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_RECENT_MANAGER))
 #define GTK_RECENT_MANAGER_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_RECENT_MANAGER, GtkRecentManagerClass))
 
-typedef struct _GtkRecentInfo		GtkRecentInfo;
-typedef struct _GtkRecentData		GtkRecentData;
+typedef struct _GtkRecentInfo			GtkRecentInfo;
+typedef struct _GtkRecentData			GtkRecentData;
+typedef struct _GtkRecentActivityData	GtkRecentActivityData;
 typedef struct _GtkRecentManager	GtkRecentManager;
 typedef struct _GtkRecentManagerClass	GtkRecentManagerClass;
 typedef struct _GtkRecentManagerPrivate GtkRecentManagerPrivate;
@@ -74,14 +75,60 @@ struct _GtkRecentData
   gchar *mime_type;
 
   gchar *app_name;
+
+  // FIXME: deprecate
   gchar *app_exec;
 
+  // FIXME: deprecate
   gchar **groups;
 
+  // FIXME: deprecate
   gboolean is_private;
 };
 
 /**
+ * GtkRecentActivityData:
+ * @uri: a UTF-8 encoded string, containing the URI of the resource,
+ *   or %NULL,
+ * @display_name: a UTF-8 encoded string, containing the name of
+ *   the resource to be displayed, or %NULL;
+ * @mime_type: the MIME type of the resource;
+ * @application: the identifier of the application that is registering
+ *   this activity (format: "application://<name>.actor"), or %NULL.
+ *
+ * Information to be passed to gtk_recent_manager_add() when
+ * registering an activity.
+ **/
+struct _GtkRecentActivityData
+{
+  gchar *uri;
+  gchar *display_name;
+
+  gchar *mime_type;
+
+  gchar *application;
+};
+
+/**
+ * GtkRecentManagerActivityType:
+ *
+ *  - GTK_RECENT_MANAGER_ACTIVITY_TYPE_CREATED:
+ *    A new resource has been created.
+ *  - GTK_RECENT_MANAGER_ACTIVITY_TYPE_OPENED:
+ *    An existing resource has been opened for viewing/editing/etc.
+ *  - GTK_RECENT_MANAGER_ACTIVITY_TYPE_MODIFIED:
+ *    An existing resource has been modified.
+ *  - GTK_RECENT_MANAGER_ACTIVITY_TYPE_CLOSED:
+ *    A previously opened resource has been closed.
+ **/
+enum GtkRecentManagerActivityType {
+	GTK_RECENT_MANAGER_ACTIVITY_TYPE_CREATED,
+	GTK_RECENT_MANAGER_ACTIVITY_TYPE_OPENED,
+	GTK_RECENT_MANAGER_ACTIVITY_TYPE_CLOSED,
+	GTK_RECENT_MANAGER_ACTIVITY_TYPE_MODIFIED
+};
+
+/**
  * GtkRecentManager:
  *
  * #GtkRecentManager contains only private data
@@ -168,7 +215,10 @@ gboolean          gtk_recent_manager_add_item       (GtkRecentManager     *manag
 						     const gchar          *uri);
 gboolean          gtk_recent_manager_add_full       (GtkRecentManager     *manager,
 						     const gchar          *uri,
-						     const GtkRecentData  *recent_data);
+						     const GtkRecentData  *data);
+void              gtk_recent_manager_add_activity  (GtkRecentManager     *manager,
+						     const gchar type, // GtkRecentManagerActivityType
+						     const GtkRecentActivityData *recent_data);
 gboolean          gtk_recent_manager_remove_item    (GtkRecentManager     *manager,
 						     const gchar          *uri,
 						     GError              **error);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]