From f2195ba4e3fa66e04c7cc77df90789e2b78f04ac Mon Sep 17 00:00:00 2001
From: Cedric Roux <cedric.roux@eurecom.fr>
Date: Fri, 29 Apr 2016 15:51:44 +0200
Subject: [PATCH] notification system (from user input to application
 basically)

---
 common/utils/T/tracer/gui/Makefile   |   2 +-
 common/utils/T/tracer/gui/gui.h      |  15 ++++
 common/utils/T/tracer/gui/gui_defs.h |  24 ++++++
 common/utils/T/tracer/gui/notify.c   | 120 +++++++++++++++++++++++++++
 4 files changed, 160 insertions(+), 1 deletion(-)
 create mode 100644 common/utils/T/tracer/gui/notify.c

diff --git a/common/utils/T/tracer/gui/Makefile b/common/utils/T/tracer/gui/Makefile
index 13820114dd..cc6a409e75 100644
--- a/common/utils/T/tracer/gui/Makefile
+++ b/common/utils/T/tracer/gui/Makefile
@@ -2,7 +2,7 @@ CC=gcc
 CFLAGS=-Wall -g -pthread
 
 OBJS=init.o loop.o toplevel_window.o x.o container.o widget.o \
-     gui.o label.o event.o xy_plot.o text_list.o
+     gui.o label.o event.o xy_plot.o text_list.o notify.o
 
 gui.a: $(OBJS)
 	ar cr gui.a $(OBJS)
diff --git a/common/utils/T/tracer/gui/gui.h b/common/utils/T/tracer/gui/gui.h
index 7646b0849e..b1321c1e49 100644
--- a/common/utils/T/tracer/gui/gui.h
+++ b/common/utils/T/tracer/gui/gui.h
@@ -36,4 +36,19 @@ void gunlock(gui *gui);
 
 int new_color(gui *gui, char *color);
 
+/* notifications */
+/* known notifications:
+ * - text_list:
+ *      - scrollup   { }
+ *      - scrolldown { }
+ *      //- click      { int line, int button }
+ */
+
+/* same type as in gui_defs.h */
+typedef void (*notifier)(void *private, gui *g,
+    char *notification, widget *w, void *notification_data);
+unsigned long register_notifier(gui *g, char *notification, widget *w,
+    notifier handler, void *private);
+void unregister_notifier(gui *g, unsigned long notifier_id);
+
 #endif /* _GUI_H_ */
diff --git a/common/utils/T/tracer/gui/gui_defs.h b/common/utils/T/tracer/gui/gui_defs.h
index 8f680c9503..9bb22c9daa 100644
--- a/common/utils/T/tracer/gui/gui_defs.h
+++ b/common/utils/T/tracer/gui/gui_defs.h
@@ -143,6 +143,24 @@ struct repack_event {
   int id;
 };
 
+/*************************************************************************/
+/*                           notifications                               */
+/*************************************************************************/
+
+/* same type as in gui.h */
+typedef void (*notifier)(void *private, gui *g,
+    char *notification, widget *w, void *notification_data);
+
+struct notifier {
+  notifier handler;
+  unsigned long id;
+  char *notification;
+  widget *w;
+  void *private;
+  /* done is used bu gui_notify */
+  int done;
+};
+
 /*************************************************************************/
 /*                          main structure                               */
 /*************************************************************************/
@@ -161,6 +179,9 @@ struct gui {
   void                *xwin;           /* set by a toplevel_window when
                                         * it paints itself, to be used
                                         * by its children */
+  struct notifier     *notifiers;
+  int                 notifiers_count;
+  unsigned long       next_notifier_id;
 };
 
 /*************************************************************************/
@@ -178,4 +199,7 @@ void gui_events(gui *gui);
 
 struct widget *find_widget(struct gui *g, int id);
 
+void gui_notify(struct gui *g, char *notification, widget *w,
+    void *notification_data);
+
 #endif /* _GUI_DEFS_H_ */
diff --git a/common/utils/T/tracer/gui/notify.c b/common/utils/T/tracer/gui/notify.c
new file mode 100644
index 0000000000..dc6bc2fd59
--- /dev/null
+++ b/common/utils/T/tracer/gui/notify.c
@@ -0,0 +1,120 @@
+#include "gui.h"
+#include "gui_defs.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+unsigned long register_notifier(gui *_g, char *notification, widget *w,
+    notifier handler, void *private)
+{
+  struct gui *g = _g;
+  unsigned long ret;
+
+  glock(g);
+
+  if (g->next_notifier_id == 2UL * 1024 * 1024 * 1024)
+    { printf("%s:%d: report a bug\n", __FILE__, __LINE__);  abort(); }
+
+  g->notifiers = realloc(g->notifiers,
+      (g->notifiers_count+1) * sizeof(struct notifier));
+  if (g->notifiers == NULL) abort();
+
+  ret = g->next_notifier_id;
+
+  g->notifiers[g->notifiers_count].handler = handler;
+  g->notifiers[g->notifiers_count].id = g->next_notifier_id;
+  g->next_notifier_id++;
+  g->notifiers[g->notifiers_count].notification = strdup(notification);
+  if (g->notifiers[g->notifiers_count].notification == NULL) abort();
+  g->notifiers[g->notifiers_count].w = w;
+  g->notifiers[g->notifiers_count].private = private;
+  /* initialize done to 1 so as not to call the handler if it's created
+   * by the call of another one that is in progress
+   */
+  g->notifiers[g->notifiers_count].done = 1;
+
+  g->notifiers_count++;
+
+  gunlock(g);
+
+  return ret;
+}
+
+void unregister_notifier(gui *_g, unsigned long notifier_id)
+{
+  struct gui *g = _g;
+  int i;
+
+  glock(g);
+
+  for (i = 0; i < g->notifiers_count; i++)
+    if (g->notifiers[i].id == notifier_id) break;
+
+  if (i == g->notifiers_count) {
+    printf("%s:%d: notifier_id %ld not found\n", __FILE__, __LINE__,
+        notifier_id);
+    abort();
+  }
+
+  free(g->notifiers[i].notification);
+
+  memmove(g->notifiers + i, g->notifiers + i + 1,
+      (g->notifiers_count-1 - i) * sizeof(struct notifier));
+
+  g->notifiers_count--;
+  g->notifiers = realloc(g->notifiers,
+      g->notifiers_count * sizeof(struct notifier));
+  if (g->notifiers == NULL) abort();
+
+  gunlock(g);
+}
+
+/* called with lock ON */
+void gui_notify(struct gui *g, char *notification, widget *w,
+    void *notification_data)
+{
+  void *private;
+  notifier handler;
+  int i;
+
+  /* this function is not re-entrant, for the moment keep as is
+   * and if the need is there, we'll make a new thread to handle
+   * notifications (or something)
+   * for now let's crash in case of recursive call
+   */
+  static int inside = 0;
+  if (inside)
+    {printf("%s:%d: BUG! contact the authors\n", __FILE__, __LINE__);abort();}
+  inside = 1;
+
+  /* clear all handlers */
+  /* TODO: speedup */
+  for (i = 0; i < g->notifiers_count; i++) g->notifiers[i].done = 0;
+
+  /* calling the handler may modify the list of notifiers, we
+   * need to be careful here
+   */
+loop:
+  for (i = 0; i < g->notifiers_count; i++) {
+    if (g->notifiers[i].done == 1 ||
+        g->notifiers[i].w != w    ||
+        strcmp(g->notifiers[i].notification, notification) != 0)
+      continue;
+    break;
+  }
+  if (i == g->notifiers_count) goto done;
+
+  g->notifiers[i].done = 1;
+
+  handler = g->notifiers[i].handler;
+  private = g->notifiers[i].private;
+
+  gunlock(g);
+  handler(private, g, notification, w, notification_data);
+  glock(g);
+
+  goto loop;
+
+done:
+  inside = 0;
+}
-- 
GitLab