[devhelp: 2/36] book-manager: Move book event monitoring to the book object



commit 11bb88448701035981f43dae758aee26c1c1136e
Author: Aleksander Morgado <aleksander lanedo com>
Date:   Thu Dec 2 15:40:41 2010 +0100

    book-manager: Move book event monitoring to the book object

 src/dh-book-manager.c |   93 ++++++++++-----------------
 src/dh-book-manager.h |   16 +++--
 src/dh-book.c         |  169 +++++++++++++++++++++++++++++++++++++++++++++----
 src/dh-book.h         |   35 ++++++-----
 4 files changed, 220 insertions(+), 93 deletions(-)
---
diff --git a/src/dh-book-manager.c b/src/dh-book-manager.c
index e425097..f0af2b0 100644
--- a/src/dh-book-manager.c
+++ b/src/dh-book-manager.c
@@ -223,38 +223,16 @@ book_manager_booklist_monitor_event_cb (GFileMonitor      *file_monitor,
         file_uri = g_file_get_uri (file);
 
         g_debug ("CHANGED BOOKLIST DIR '%s'", file_uri);
-}
-
-static void
-book_manager_book_monitor_event_cb (GFileMonitor      *file_monitor,
-                                    GFile             *file,
-                                    GFile             *other_file,
-                                    GFileMonitorEvent  event_type,
-                                    gpointer	       user_data)
-{
-        gchar *file_uri;
-
-        file_uri = g_file_get_uri (file);
-
-        g_debug ("CHANGED BOOK DIR '%s'", file_uri);
-        switch (event_type) {
-        case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
-                /* An existing file got modified */
-                break;
-        default:
-                break;
-        }
+        g_free (file_uri);
 }
 
 static void
 book_manager_monitor_path (DhBookManager *book_manager,
-                           const gchar   *path,
-                           gboolean       is_file)
+                           const gchar   *path)
 {
         GFileMonitor      *file_monitor;
         GFile             *file;
         DhBookManagerPriv *priv;
-        GError            *error = NULL;
 
         priv = GET_PRIVATE (book_manager);
 
@@ -266,17 +244,15 @@ book_manager_monitor_path (DhBookManager *book_manager,
                 return;
         }
 
-        /* Create new monitor for the given directory/file */
-        file_monitor = g_file_monitor (file,
-                                       G_FILE_MONITOR_NONE,
-                                       NULL,
-                                       &error);
+        /* Create new monitor for the given directory */
+        file_monitor = g_file_monitor_directory (file,
+                                                 G_FILE_MONITOR_NONE,
+                                                 NULL,
+                                                 NULL);
         if (file_monitor) {
                 /* Setup changed signal callback */
                 g_signal_connect (file_monitor, "changed",
-                                  (is_file ?
-                                   G_CALLBACK (book_manager_book_monitor_event_cb) :
-                                   G_CALLBACK (book_manager_booklist_monitor_event_cb)),
+                                  G_CALLBACK (book_manager_booklist_monitor_event_cb),
                                   book_manager);
 
                 /* Create HT if not already there */
@@ -292,10 +268,8 @@ book_manager_monitor_path (DhBookManager *book_manager,
                                      g_object_ref (file),
                                      file_monitor);
         } else {
-                g_warning ("Couldn't setup to monitor changes on %s '%s': %s",
-                           is_file ? "file" : "directory",
-                           path,
-                           error ? error->message : "unknown");
+                g_warning ("Couldn't setup to monitor changes on directory '%s'",
+                           path);
         }
 
         g_object_unref (file);
@@ -318,7 +292,7 @@ book_manager_add_from_dir (DhBookManager *book_manager,
         }
 
         /* Monitor the directory for changes */
-        book_manager_monitor_path (book_manager, dir_path, FALSE);
+        book_manager_monitor_path (book_manager, dir_path);
 
         /* And iterate it */
         while ((name = g_dir_read_name (dir)) != NULL) {
@@ -337,10 +311,6 @@ book_manager_add_from_dir (DhBookManager *book_manager,
                         /* Add book from filepath */
                         book_manager_add_from_filepath (book_manager,
                                                         book_path);
-
-                        /* Add monitor only if we actually got a valid book */
-                        book_manager_monitor_path (book_manager, book_dir_path, FALSE);
-
                         g_free (book_path);
                 }
                 g_free (book_dir_path);
@@ -396,9 +366,10 @@ book_manager_add_from_xcode_docset (DhBookManager *book_manager,
                 return;
         }
 
-        /* Monitor the directory for changes (if it works on MacOSX, which
-         *  I truly don't know if they support something like inotify */
-        book_manager_monitor_path (book_manager, dir_path, FALSE);
+        /* Monitor the directory for changes (if it works on MacOSX,
+         * not sure if GIO implements GFileMonitor based on FSEvents
+         * or what */
+        book_manager_monitor_path (book_manager, dir_path);
 
         /* And iterate it, looking for files ending with .devhelp2 */
         while ((name = g_dir_read_name (dir)) != NULL) {
@@ -454,9 +425,6 @@ book_manager_add_from_filepath (DhBookManager *book_manager,
         priv->books = g_list_insert_sorted (priv->books,
                                             book,
                                             (GCompareFunc)dh_book_cmp_by_title);
-
-        /* Add monitor for the specific file */
-        book_manager_monitor_path (book_manager, book_path, TRUE);
 }
 
 GList *
@@ -469,23 +437,32 @@ dh_book_manager_get_books (DhBookManager *book_manager)
 
 DhBook *
 dh_book_manager_get_book_by_name (DhBookManager *book_manager,
-                                  const gchar *name)
+                                  const gchar   *name)
 {
-        DhBook *book = NULL;
         GList  *l;
 
         g_return_val_if_fail (book_manager, NULL);
 
-        for (l = GET_PRIVATE (book_manager)->books;
-             l && !book;
-             l = g_list_next (l)) {
-                if (g_strcmp0 (name,
-                               dh_book_get_name (DH_BOOK (l->data))) == 0) {
-                        book = l->data;
-                }
-        }
+        l = g_list_find_custom (GET_PRIVATE (book_manager)->books,
+                                name,
+                                (GCompareFunc)dh_book_cmp_by_name_str);
+
+        return l ? l->data : NULL;
+}
+
+DhBook *
+dh_book_manager_get_book_by_path (DhBookManager *book_manager,
+                                  const gchar   *path)
+{
+        GList  *l;
+
+        g_return_val_if_fail (book_manager, NULL);
+
+        l = g_list_find_custom (GET_PRIVATE (book_manager)->books,
+                                path,
+                                (GCompareFunc)dh_book_cmp_by_path_str);
 
-        return book;
+        return l ? l->data : NULL;
 }
 
 void
diff --git a/src/dh-book-manager.h b/src/dh-book-manager.h
index 3fec290..13e40e6 100644
--- a/src/dh-book-manager.h
+++ b/src/dh-book-manager.h
@@ -48,13 +48,15 @@ struct _DhBookManagerClass {
         void (* disabled_book_list_updated) (DhBookManager *book_manager);
 };
 
-GType          dh_book_manager_get_type         (void) G_GNUC_CONST;
-DhBookManager *dh_book_manager_new              (void);
-void           dh_book_manager_populate         (DhBookManager *book_manager);
-GList         *dh_book_manager_get_books        (DhBookManager *book_manager);
-DhBook        *dh_book_manager_get_book_by_name (DhBookManager *book_manager,
-                                                 const gchar *name);
-void           dh_book_manager_update           (DhBookManager *book_manager);
+GType          dh_book_manager_get_type             (void) G_GNUC_CONST;
+DhBookManager *dh_book_manager_new                  (void);
+void           dh_book_manager_populate             (DhBookManager *book_manager);
+GList         *dh_book_manager_get_books            (DhBookManager *book_manager);
+DhBook        *dh_book_manager_get_book_by_name     (DhBookManager *book_manager,
+                                                     const gchar   *name);
+DhBook        *dh_book_manager_get_book_by_path     (DhBookManager *book_manager,
+                                                     const gchar   *path);
+void           dh_book_manager_update               (DhBookManager *book_manager);
 
 G_END_DECLS
 
diff --git a/src/dh-book.c b/src/dh-book.c
index 179fdd2..5c54366 100644
--- a/src/dh-book.c
+++ b/src/dh-book.c
@@ -28,20 +28,33 @@
 #include "dh-parser.h"
 #include "dh-book.h"
 
+/* Timeout to wait for new events in the book so that
+ * they are merged and we don't spam unneeded signals */
+#define EVENT_MERGE_TIMEOUT_SECS 2
+
 /* Structure defining basic contents to store about every book */
 typedef struct {
         /* File path of the book */
-        gchar    *path;
+        gchar        *path;
         /* Enable or disabled? */
-        gboolean  enabled;
+        gboolean      enabled;
         /* Book name */
-        gchar    *name;
+        gchar        *name;
         /* Book title */
-        gchar    *title;
+        gchar        *title;
         /* Generated book tree */
-        GNode    *tree;
+        GNode        *tree;
         /* Generated list of keywords in the book */
-        GList    *keywords;
+        GList        *keywords;
+
+        /* Monitor of this specific book */
+        GFileMonitor *monitor;
+        /* Last received events */
+        gboolean      is_deleted;
+        gboolean      is_updated;
+        /* ID of the event source */
+        guint         monitor_event_timeout_id;
+
 } DhBookPriv;
 
 G_DEFINE_TYPE (DhBook, dh_book, G_TYPE_OBJECT);
@@ -49,11 +62,16 @@ G_DEFINE_TYPE (DhBook, dh_book, G_TYPE_OBJECT);
 #define GET_PRIVATE(instance) G_TYPE_INSTANCE_GET_PRIVATE       \
         (instance, DH_TYPE_BOOK, DhBookPriv)
 
-static void    dh_book_init       (DhBook      *book);
-static void    dh_book_class_init (DhBookClass *klass);
+static void    dh_book_init          (DhBook            *book);
+static void    dh_book_class_init    (DhBookClass       *klass);
+static void    book_monitor_event_cb (GFileMonitor      *file_monitor,
+                                      GFile             *file,
+                                      GFile             *other_file,
+                                      GFileMonitorEvent  event_type,
+                                      gpointer	         user_data);
 
-static void    unref_node_link    (GNode *node,
-                                   gpointer data);
+static void    unref_node_link       (GNode             *node,
+                                      gpointer           data);
 
 static void
 book_finalize (GObject *object)
@@ -77,6 +95,10 @@ book_finalize (GObject *object)
                 g_list_free (priv->keywords);
         }
 
+        if (priv->monitor) {
+                g_object_unref (priv->monitor);
+        }
+
         g_free (priv->title);
 
         g_free (priv->path);
@@ -105,21 +127,26 @@ dh_book_init (DhBook *book)
         priv->enabled = TRUE;
         priv->tree = NULL;
         priv->keywords = NULL;
+        priv->monitor = NULL;
+        priv->is_deleted = FALSE;
+        priv->is_updated = FALSE;
+        priv->monitor_event_timeout_id = 0;
 }
 
 static void
-unref_node_link (GNode *node,
-                 gpointer data)
+unref_node_link (GNode    *node,
+                 gpointer  data)
 {
         dh_link_unref (node->data);
 }
 
 DhBook *
-dh_book_new (const gchar  *book_path)
+dh_book_new (const gchar *book_path)
 {
         DhBookPriv *priv;
         DhBook     *book;
         GError     *error = NULL;
+        GFile      *book_path_file;
 
         g_return_val_if_fail (book_path, NULL);
 
@@ -150,9 +177,95 @@ dh_book_new (const gchar  *book_path)
         /* Setup name */
         priv->name = g_strdup (dh_link_get_book_id ((DhLink *)priv->tree->data));
 
+        /* Setup monitor for changes */
+        book_path_file = g_file_new_for_path (book_path);
+        priv->monitor = g_file_monitor_file (book_path_file,
+                                             G_FILE_MONITOR_NONE,
+                                             NULL,
+                                             NULL);
+        if (priv->monitor) {
+                /* Setup changed signal callback */
+                g_signal_connect (priv->monitor,
+                                  "changed",
+                                  G_CALLBACK (book_monitor_event_cb),
+                                  book);
+        } else {
+                g_warning ("Couldn't setup monitoring of changes in book '%s'",
+                           priv->title);
+        }
+        g_object_unref (book_path_file);
+
         return book;
 }
 
+static gboolean
+book_monitor_event_timeout_cb  (gpointer data)
+{
+        DhBook *book = data;
+        DhBookPriv *priv;
+
+        priv = GET_PRIVATE (book);
+
+        /* We'll get either is_deleted OR is_updated,
+         * not possible to have both or none */
+        if (priv->is_deleted) {
+                g_debug ("Book '%s' was deleted",
+                         dh_book_get_title (book));
+        } else if (priv->is_updated) {
+                g_debug ("Book '%s' was updated",
+                         dh_book_get_title (book));
+        } else {
+                g_warn_if_reached ();
+        }
+
+        return FALSE;
+}
+
+static void
+book_monitor_event_cb (GFileMonitor      *file_monitor,
+                       GFile             *file,
+                       GFile             *other_file,
+                       GFileMonitorEvent  event_type,
+                       gpointer	          user_data)
+{
+        DhBook *book = user_data;
+        DhBookPriv *priv;
+        gboolean reset_timer = FALSE;
+
+        priv = GET_PRIVATE (book);
+
+        switch (event_type) {
+        case G_FILE_MONITOR_EVENT_CREATED:
+                /* This may happen if the file is deleted and then
+                 * created right away, as we're merging events.
+                 * Treat in the same way as a CHANGES_DONE_HINT, so
+                 * fall through the case.  */
+        case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
+                priv->is_deleted = FALSE; /* Reset any previous one */
+                priv->is_updated = TRUE;
+                reset_timer = TRUE;
+                break;
+        case G_FILE_MONITOR_EVENT_DELETED:
+                priv->is_deleted = TRUE;
+                priv->is_updated = FALSE; /* Reset any previous one */
+                reset_timer = TRUE;
+                break;
+        default:
+                /* Ignore all the other events */
+                break;
+        }
+
+        /* Reset timer if any of the flags changed */
+        if (reset_timer) {
+                if (priv->monitor_event_timeout_id != 0) {
+                        g_source_remove (priv->monitor_event_timeout_id);
+                }
+                priv->monitor_event_timeout_id = g_timeout_add_seconds (EVENT_MERGE_TIMEOUT_SECS,
+                                                                        book_monitor_event_timeout_cb,
+                                                                        book);
+        }
+}
+
 GList *
 dh_book_get_keywords (DhBook *book)
 {
@@ -201,6 +314,18 @@ dh_book_get_title (DhBook *book)
         return priv->title;
 }
 
+const gchar *
+dh_book_get_path (DhBook *book)
+{
+        DhBookPriv *priv;
+
+        g_return_val_if_fail (DH_IS_BOOK (book), NULL);
+
+        priv = GET_PRIVATE (book);
+
+        return priv->path;
+}
+
 gboolean
 dh_book_get_enabled (DhBook *book)
 {
@@ -228,6 +353,15 @@ dh_book_cmp_by_path (const DhBook *a,
 }
 
 gint
+dh_book_cmp_by_path_str (const DhBook *a,
+                         const gchar  *b_path)
+{
+        return ((a && b_path) ?
+                g_strcmp0 (GET_PRIVATE (a)->path, b_path) :
+                -1);
+}
+
+gint
 dh_book_cmp_by_name (const DhBook *a,
                      const DhBook *b)
 {
@@ -237,6 +371,15 @@ dh_book_cmp_by_name (const DhBook *a,
 }
 
 gint
+dh_book_cmp_by_name_str (const DhBook *a,
+                         const gchar  *b_name)
+{
+        return ((a && b_name) ?
+                g_ascii_strcasecmp (GET_PRIVATE (a)->name, b_name) :
+                -1);
+}
+
+gint
 dh_book_cmp_by_title (const DhBook *a,
                       const DhBook *b)
 {
diff --git a/src/dh-book.h b/src/dh-book.h
index 198f2b3..c7ec7e8 100644
--- a/src/dh-book.h
+++ b/src/dh-book.h
@@ -46,21 +46,26 @@ struct _DhBookClass {
         GObjectClass parent_class;
 };
 
-GType        dh_book_get_type     (void) G_GNUC_CONST;
-DhBook      *dh_book_new          (const gchar  *book_path);
-GList       *dh_book_get_keywords (DhBook *book);
-GNode       *dh_book_get_tree     (DhBook *book);
-const gchar *dh_book_get_name     (DhBook *book);
-const gchar *dh_book_get_title    (DhBook *book);
-gboolean     dh_book_get_enabled  (DhBook *book);
-void         dh_book_set_enabled  (DhBook *book,
-                                   gboolean enabled);
-gint         dh_book_cmp_by_path  (const DhBook *a,
-                                   const DhBook *b);
-gint         dh_book_cmp_by_name  (const DhBook *a,
-                                   const DhBook *b);
-gint         dh_book_cmp_by_title (const DhBook *a,
-                                   const DhBook *b);
+GType        dh_book_get_type        (void) G_GNUC_CONST;
+DhBook      *dh_book_new             (const gchar  *book_path);
+GList       *dh_book_get_keywords    (DhBook *book);
+GNode       *dh_book_get_tree        (DhBook *book);
+const gchar *dh_book_get_name        (DhBook *book);
+const gchar *dh_book_get_title       (DhBook *book);
+const gchar *dh_book_get_path        (DhBook *book);
+gboolean     dh_book_get_enabled     (DhBook *book);
+void         dh_book_set_enabled     (DhBook *book,
+                                      gboolean enabled);
+gint         dh_book_cmp_by_path     (const DhBook *a,
+                                      const DhBook *b);
+gint         dh_book_cmp_by_path_str (const DhBook *a,
+                                      const gchar  *b_path);
+gint         dh_book_cmp_by_name     (const DhBook *a,
+                                      const DhBook *b);
+gint         dh_book_cmp_by_name_str (const DhBook *a,
+                                      const gchar  *b_name);
+gint         dh_book_cmp_by_title    (const DhBook *a,
+                                      const DhBook *b);
 
 G_END_DECLS
 



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