]> granicus.if.org Git - neomutt/commitdiff
add notify/observer
authorRichard Russon <rich@flatcap.org>
Tue, 21 May 2019 12:52:03 +0000 (13:52 +0100)
committerRichard Russon <rich@flatcap.org>
Mon, 3 Jun 2019 10:54:19 +0000 (11:54 +0100)
Makefile.autosetup
mutt/mutt.h
mutt/notify.c [new file with mode: 0644]
mutt/notify.h [new file with mode: 0644]
mutt/notify_type.h [new file with mode: 0644]
mutt/observer.h [new file with mode: 0644]
neomutt.c

index eb74db36402116bb099b8b317cbcb2004b068d69..d5cf1d73f7bec0cc23b9923973614e648fb6499a 100644 (file)
@@ -260,7 +260,8 @@ LIBMUTT=    libmutt.a
 LIBMUTTOBJS=   mutt/base64.o mutt/buffer.o mutt/charset.o mutt/date.o \
                mutt/envlist.o mutt/exit.o mutt/file.o mutt/hash.o \
                mutt/history.o mutt/list.o mutt/logging.o mutt/mapping.o \
-               mutt/mbyte.o mutt/md5.o mutt/memory.o mutt/path.o mutt/pool.o \
+               mutt/mbyte.o mutt/md5.o mutt/memory.o mutt/notify.o \
+               mutt/path.o mutt/pool.o \
                mutt/regex.o mutt/sha1.o mutt/signal.o mutt/string.o
 CLEANFILES+=   $(LIBMUTT) $(LIBMUTTOBJS)
 MUTTLIBS+=     $(LIBMUTT)
index b64f2e1155472a7f44636a88205af97df2dd517d..ffdfe99c30f4ac81d077f666b31e94e0c79e2823 100644 (file)
@@ -42,6 +42,8 @@
  * | mutt/mbyte.c     | @subpage mbyte     |
  * | mutt/md5.c       | @subpage md5       |
  * | mutt/memory.c    | @subpage memory    |
+ * | mutt/notify.c    | @subpage notify    |
+ * | mutt/observer.h  | @subpage observer  |
  * | mutt/path.c      | @subpage path      |
  * | mutt/pool.c      | @subpage pool      |
  * | mutt/regex.c     | @subpage regex     |
@@ -73,6 +75,9 @@
 #include "memory.h"
 #include "message.h"
 #include "queue.h"
+#include "notify.h"
+#include "notify_type.h"
+#include "observer.h"
 #include "path.h"
 #include "pool.h"
 #include "regex3.h"
diff --git a/mutt/notify.c b/mutt/notify.c
new file mode 100644 (file)
index 0000000..9bed9cc
--- /dev/null
@@ -0,0 +1,203 @@
+/**
+ * @file
+ * Notification API
+ *
+ * @authors
+ * Copyright (C) 2019 Richard Russon <rich@flatcap.org>
+ *
+ * @copyright
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * @page notify Notification API
+ *
+ * Notification API
+ */
+
+#include "config.h"
+#include <stdbool.h>
+#include <stdint.h>
+#include "notify.h"
+
+/**
+ * struct Notify - Notification API
+ */
+struct Notify
+{
+  void *obj;
+  enum NotifyType obj_type;
+  struct Notify *parent;
+  struct ObserverHead observers;
+};
+
+/**
+ * notify_new - Create a new notifications handler
+ * @param object Owner of the object
+ * @param type   Object type, e.g. #NT_ACCOUNT
+ * @retval ptr New notification handler
+ */
+struct Notify *notify_new(void *object, enum NotifyType type)
+{
+  struct Notify *notify = mutt_mem_calloc(1, sizeof(*notify));
+
+  notify->obj = object;
+  notify->obj_type = type;
+  STAILQ_INIT(&notify->observers);
+
+  return notify;
+}
+
+/**
+ * notify_free - Free a notification handler
+ * @param ptr Notification handler to free
+ */
+void notify_free(struct Notify **ptr)
+{
+  if (!ptr || !*ptr)
+    return;
+
+  // struct Notify *notify = *ptr;
+  // NOTIFY observers
+  // FREE observers
+
+  FREE(ptr);
+}
+
+/**
+ * notify_set_parent - Set the parent notification handler
+ * @param notify Notification handler to alter
+ * @param parent Parent notification handler
+ *
+ * Notifications are passed up the tree of handlers.
+ */
+void notify_set_parent(struct Notify *notify, struct Notify *parent)
+{
+  if (!notify || !parent)
+    return;
+
+  notify->parent = parent;
+}
+
+/**
+ * send - Send out a notification message
+ * @param source  Source of the event, e.g. #Account
+ * @param current Current handler, e.g. #NeoMutt
+ * @param type    Type of event, e.g. #NT_ACCOUNT
+ * @param subtype Subtype, e.g. NT_ACCOUNT_NEW
+ * @param data    Private data associated with the event type
+ * @retval true If successfully sent
+ *
+ * Notifications are sent to all matching observers, then propagated up the
+ * handler tree.  For example a "new email" notification would be sent to the
+ * Mailbox that owned it, the Account (owning the Mailbox) and finally the
+ * NeoMutt object.
+ */
+static bool send(struct Notify *source, struct Notify *current, int type,
+                 int subtype, intptr_t data)
+{
+  if (!source || !current)
+    return false;
+
+  // mutt_debug(LL_NOTIFY, "send: %d, %ld\n", type, data);
+  struct ObserverNode *np = NULL;
+  STAILQ_FOREACH(np, &current->observers, entries)
+  {
+    struct Observer *o = np->observer;
+
+    struct NotifyCallback nc = { source->obj, source->obj_type, type,   subtype,
+                                 data,        o->flags,         o->data };
+    o->callback(&nc);
+  }
+
+  if (current->parent)
+    return send(source, current->parent, type, subtype, data);
+  return true;
+}
+
+/**
+ * notify_send - Send out a notification message
+ * @param notify  Notification handler
+ * @param type    Type of event, e.g. #NT_ACCOUNT
+ * @param subtype Subtype, e.g. NT_ACCOUNT_NEW
+ * @param data    Private data associated with the event type
+ * @retval true If successfully sent
+ *
+ * See send() for more details.
+ */
+bool notify_send(struct Notify *notify, int type, int subtype, intptr_t data)
+{
+  return send(notify, notify, type, subtype, data);
+}
+
+/**
+ * notify_observer_add - Add an observer to an object
+ * @param notify   Notification handler
+ * @param type     Type of event to listen for, e.g. #NT_ACCOUNT
+ * @param subtype  Subtype, e.g. NT_ACCOUNT_NEW
+ * @param callback Function to call on a matching event, see ::observer_t
+ * @param data     Private data associated with the event type
+ * @retval true If successful
+ */
+bool notify_observer_add(struct Notify *notify, enum NotifyType type,
+                         int subtype, observer_t callback, intptr_t data)
+{
+  if (!notify || !callback)
+    return false;
+
+  struct ObserverNode *np = NULL;
+  STAILQ_FOREACH(np, &notify->observers, entries)
+  {
+    if (np->observer->callback == callback)
+      return true;
+  }
+
+  struct Observer *o = mutt_mem_calloc(1, sizeof(*o));
+  o->type = type;
+  o->flags = subtype;
+  o->callback = callback;
+  o->data = data;
+
+  np = mutt_mem_calloc(1, sizeof(*np));
+  np->observer = o;
+  STAILQ_INSERT_TAIL(&notify->observers, np, entries);
+
+  return true;
+}
+
+/**
+ * notify_observer_remove - Remove an observer from an object
+ * @param notify   Notification handler
+ * @param callback Function to call on a matching event, see ::observer_t
+ * @retval true If successful
+ */
+bool notify_observer_remove(struct Notify *notify, observer_t callback)
+{
+  if (!notify || !callback)
+    return false;
+
+  struct ObserverNode *np = NULL;
+  STAILQ_FOREACH(np, &notify->observers, entries)
+  {
+    if (np->observer->callback == callback)
+    {
+      STAILQ_REMOVE(&notify->observers, np, ObserverNode, entries);
+      FREE(&np->observer);
+      FREE(&np);
+      return true;
+    }
+  }
+
+  return false;
+}
diff --git a/mutt/notify.h b/mutt/notify.h
new file mode 100644 (file)
index 0000000..30e1030
--- /dev/null
@@ -0,0 +1,41 @@
+/**
+ * @file
+ * Notification API
+ *
+ * @authors
+ * Copyright (C) 2019 Richard Russon <rich@flatcap.org>
+ *
+ * @copyright
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MUTT_LIB_NOTIFY_H
+#define MUTT_LIB_NOTIFY_H
+
+#include <stdbool.h>
+#include "observer.h"
+#include "notify_type.h"
+
+struct Notify;
+
+struct Notify *notify_new(void *object, enum NotifyType type);
+void notify_free(struct Notify **ptr);
+void notify_set_parent(struct Notify *notify, struct Notify *parent);
+
+bool notify_send(struct Notify *notify, int type, int subtype, intptr_t data);
+
+bool notify_observer_add(struct Notify *notify, enum NotifyType type, int subtype, observer_t callback, intptr_t data);
+bool notify_observer_remove(struct Notify *notify, observer_t callback);
+
+#endif /* MUTT_LIB_NOTIFY_H */
diff --git a/mutt/notify_type.h b/mutt/notify_type.h
new file mode 100644 (file)
index 0000000..eaa7a18
--- /dev/null
@@ -0,0 +1,42 @@
+/**
+ * @file
+ * Notification Types
+ *
+ * @authors
+ * Copyright (C) 2019 Richard Russon <rich@flatcap.org>
+ *
+ * @copyright
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MUTT_LIB_NOTIFY_TYPE_H
+#define MUTT_LIB_NOTIFY_TYPE_H
+
+/**
+ * enum NotifyType - Notification Types
+ */
+enum NotifyType
+{
+  NT_NEOMUTT, ///< Container for all notifications
+  NT_GLOBAL,  ///< Not object-related
+  NT_CONFIG,  ///< Config has changed
+  NT_ACCOUNT, ///< Account has changed
+  NT_MAILBOX, ///< Mailbox has changed
+  NT_EMAIL,   ///< Email has changed
+  NT_WINDOW,  ///< Window has changed
+
+  NT_MAX,
+};
+
+#endif /* MUTT_LIB_NOTIFY_TYPE_H */
diff --git a/mutt/observer.h b/mutt/observer.h
new file mode 100644 (file)
index 0000000..8b3f66f
--- /dev/null
@@ -0,0 +1,86 @@
+/**
+ * @file
+ * Observer of notifications
+ *
+ * @authors
+ * Copyright (C) 2019 Richard Russon <rich@flatcap.org>
+ *
+ * @copyright
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * @page observer Observer of notifications
+ *
+ * Observer of notifications
+ */
+
+#ifndef MUTT_LIB_OBSERVER_H
+#define MUTT_LIB_OBSERVER_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "mutt/mutt.h"
+#include "notify_type.h"
+
+struct Notify;
+
+/**
+ * struct NotifyCallback - Data passed to a notification function
+ */
+struct NotifyCallback
+{
+  void *obj;         ///< Notify: Event happened here
+  int obj_type;      ///< Notify: type of object event happened on
+  int event_type;    ///< Send: event type
+  int event_subtype; ///< Send: event subtype
+  intptr_t event;    ///< Send: event data
+  int flags;         ///< Observer: determine event data
+  intptr_t data;     ///< Observer: private to observer
+};
+
+/**
+ * typedef observer_t - Prototype for a notification callback function
+ * @param[in]  flags    Flags, see #MuttFormatFlags
+ * @retval  0 Success
+ * @retval -1 Error
+ */
+typedef int (*observer_t)(struct NotifyCallback *nc);
+
+typedef uint8_t ObserverFlags;     ///< Flags, e.g. #OBSERVE_RECURSIVE
+#define OBSERVE_NO_FLAGS        0  ///< No flags are set
+#define OBSERVE_RECURSIVE (1 << 0) ///< Listen for events of children
+
+/**
+ * struct Observer - An observer of notifications
+ */
+struct Observer
+{
+  enum NotifyType type;  ///< Object to observe to, e.g. #NT_NEOMUTT
+  ObserverFlags flags;   ///< Flags, e.g. #OBSERVE_RECURSIVE
+  observer_t callback;   ///< Callback function for events
+  intptr_t data;         ///< Private data to pass to callback
+};
+
+/**
+ * struct ObserverNode - List of Observers
+ */
+struct ObserverNode
+{
+  struct Observer *observer;
+  STAILQ_ENTRY(ObserverNode) entries;
+};
+STAILQ_HEAD(ObserverHead, ObserverNode);
+
+#endif /* MUTT_LIB_OBSERVER_H */
index 0c34cf8d2474f7052f1e843323b10a3b267cb929..1164906e8a570bf413450977a258f448bd56e18a 100644 (file)
--- a/neomutt.c
+++ b/neomutt.c
@@ -40,6 +40,8 @@ struct NeoMutt *neomutt_new(void)
 {
   struct NeoMutt *n = mutt_mem_calloc(1, sizeof(*NeoMutt));
 
+  n->notify = notify_new(n, NT_NEOMUTT);
+
   return n;
 }
 
@@ -52,7 +54,9 @@ void neomutt_free(struct NeoMutt **ptr)
   if (!ptr || !*ptr)
     return;
 
-  // struct NeoMutt *n = *ptr;
+  struct NeoMutt *n = *ptr;
+
+  notify_free(&n->notify);
 
   FREE(ptr);
 }