[Gnucash-changes] Implement C side hook lists in parallel with the existing Scheme hook

David Hampton hampton at cvs.gnucash.org
Tue Jun 7 11:47:59 EDT 2005


Log Message:
-----------
Implement C side hook lists in parallel with the existing Scheme
hook lists.  Allows hooks to be easily installed from either
Scheme or C code.

Tags:
----
gnucash-gnome2-dev

Modified Files:
--------------
    gnucash:
        ChangeLog
    gnucash/src/app-file:
        gnc-file.c
    gnucash/src/app-utils:
        prefs.scm
    gnucash/src/core-utils:
        Makefile.am
        gw-core-utils-spec.scm
    gnucash/src/gnome:
        dialog-new-user.c
        top-level.c
    gnucash/src/gnome-utils:
        gnc-menu-extensions.scm
    gnucash/src/report/report-gnome:
        report-gnome.scm
    gnucash/src/scm:
        main.scm

Added Files:
-----------
    gnucash/src/core-utils:
        gnc-hooks.c
        gnc-hooks.h

Revision Data
-------------
Index: ChangeLog
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/ChangeLog,v
retrieving revision 1.1487.2.217
retrieving revision 1.1487.2.218
diff -LChangeLog -LChangeLog -u -r1.1487.2.217 -r1.1487.2.218
--- ChangeLog
+++ ChangeLog
@@ -1,3 +1,10 @@
+2005-06-07  David Hampton  <hampton at employees.org>
+
+	* src/core-utils/gnc-hooks.[ch]: Implement C side hook lists.  Will
+	allow hooks to be easily installed from either Scheme or C code.
+
+	* various files: Call the C hooks whenever a Scheme hook is called.
+
 2005-06-06  David Hampton  <hampton at employees.org>
 
 	* src/gnome/gnc-plugin-basic-commands.c: Forgot to change the
Index: prefs.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/app-utils/prefs.scm,v
retrieving revision 1.28.4.4
retrieving revision 1.28.4.5
diff -Lsrc/app-utils/prefs.scm -Lsrc/app-utils/prefs.scm -u -r1.28.4.4 -r1.28.4.5
--- src/app-utils/prefs.scm
+++ src/app-utils/prefs.scm
@@ -19,6 +19,7 @@
 
 (require 'sort)
 (require 'hash-table)
+(use-modules (g-wrapped gw-core-utils))
 
 ;; (define gnc:*double-entry-restriction*
 ;;   (gnc:make-config-var
@@ -80,7 +81,8 @@
 ;; hook should probably revert back to just save-global-options.
 (define (gnc:save-all-options)
   (gnc:save-global-options)
-  (gnc:hook-run-danglers gnc:*save-options-hook*))
+  (gnc:hook-run-danglers gnc:*save-options-hook*)
+  (gnc:run-c-hook "save-options-hook" #f))
 
 (define (gnc:save-global-options)
   (gnc:make-home-dir)
--- /dev/null
+++ src/core-utils/gnc-hooks.h
@@ -0,0 +1,40 @@
+/*
+ * gnc-hooks.h -- helpers for using Glib hook functions
+ * Copyright (C) 2005 David Hampton <hampton at employees.org>
+ *
+ * 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, contact:
+ *
+ * Free Software Foundation           Voice:  +1-617-542-5942
+ * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652
+ * Boston, MA  02111-1307,  USA       gnu at gnu.org
+ *
+ */
+
+void gnc_run_c_hook(const gchar *name, gpointer data);
+void gnc_add_to_c_hook(const gchar *name, GHookFunc callback);
+void gnc_remove_from_c_hook(const gchar *name, GHookFunc callback);
+
+
+/* Common hook name */
+#define HOOK_STARTUP		"hook_startup"
+#define HOOK_SHUTDOWN		"hook_shutdown"
+#define HOOK_UI_STARTUP		"ui-startup-hook"
+#define HOOK_UI_POST_STARTUP	"hook_ui_post_startup"
+#define HOOK_UI_SHUTDOWN	"hook_ui_shutdown"
+#define HOOK_NEW_BOOK		"new-book-hook"
+#define HOOK_REPORT		"report-hook"
+
+/* Common session hook names */
+#define HOOK_BOOK_OPENED	"book-opened-hook"
+#define HOOK_BOOK_CLOSED	"book-closed-hook"
--- /dev/null
+++ src/core-utils/gnc-hooks.c
@@ -0,0 +1,138 @@
+/*
+ * gnc-hooks.c -- helpers for using Glib hook functions
+ * Copyright (C) 2005 David Hampton <hampton at employees.org>
+ *
+ * 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, contact:
+ *
+ * Free Software Foundation           Voice:  +1-617-542-5942
+ * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652
+ * Boston, MA  02111-1307,  USA       gnu at gnu.org
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <stdio.h>
+#include "gnc-hooks.h"
+
+GHashTable* all_hook_lists = NULL;
+
+static GHookList *
+gnc_lookup_hook_list (const gchar *name)
+{
+  GHookList *hook_list;
+
+  //printf("Enter %s: name %s\n", __FUNCTION__, name);
+  if (all_hook_lists == NULL) {
+    //printf("Leave %s: no hook lists\n", __FUNCTION__);
+    return NULL;
+  }
+
+  hook_list = g_hash_table_lookup(all_hook_lists, name);
+  //printf("Leave %s: hook list %p\n", __FUNCTION__, hook_list);
+  return(hook_list);
+}
+
+static GHookList *
+gnc_create_hook_list (const gchar *name)
+{
+  GHookList *hook_list;
+
+  //printf("Enter %s: name %s\n", __FUNCTION__, name);
+  if (all_hook_lists == NULL)
+    all_hook_lists = g_hash_table_new(g_str_hash, g_str_equal);
+
+  hook_list = g_hash_table_lookup(all_hook_lists, name);
+  if (hook_list) {
+    //printf("Leave %s: list %s(%p) already exists\n\n", __FUNCTION__, name, hook_list);
+    return(hook_list);
+  }
+
+  hook_list = g_malloc(sizeof(GHookList));
+  g_hook_list_init(hook_list, sizeof(GHook));
+  g_hash_table_insert(all_hook_lists, (gchar *)name, hook_list);
+  //printf("Leave %s: created list %s(%p)\n", __FUNCTION__, name, hook_list);
+  return(hook_list);
+}
+
+void
+gnc_add_to_c_hook (const gchar *name,
+		   GHookFunc callback)
+{
+  GHookList *hook_list;
+  GHook *hook;
+
+  //printf("Enter %s: list %s, function %p\n\n", __FUNCTION__, name, callback);
+  hook_list = gnc_create_hook_list(name);
+  hook = g_hook_alloc(hook_list);
+  hook->func = callback;
+  g_hook_append(hook_list, hook);
+  //printf("Leave %s:  \n", __FUNCTION__);
+}
+
+static gboolean
+hook_remove_runner (GHook *hook,
+		    gpointer data)
+{
+  return(hook->func == data);
+}
+
+
+void
+gnc_remove_from_c_hook (const gchar *name,
+			GHookFunc callback)
+{
+  GHookList *hook_list;
+  GHook *hook;
+
+  //printf("Enter %s: name %s, function %p\n\n", __FUNCTION__, name, callback);
+  hook_list = gnc_lookup_hook_list(name);
+  if (hook_list == NULL) {
+    //printf("Leave %s: Unknown hook list %s\n", __FUNCTION__, name);
+    return;
+  }
+
+  hook = g_hook_find(hook_list, TRUE, hook_remove_runner, callback);
+  if (hook == NULL) {
+    //printf("Leave %s: Hook %p not found in %s\n", __FUNCTION__, callback, name);
+    return;
+  }
+
+  g_hook_unref(hook_list, hook);
+  //printf("Leave %s: Removed %p from %s\n", __FUNCTION__ , hook, name);
+}
+
+
+static void
+call_hook (GHook *hook, gpointer data)
+{
+  //printf("Enter %s: hook %p (func %p), data %p\n", __FUNCTION__, hook, hook->func, data);
+  ((GHookFunc)hook->func)(data);
+  //printf("Leave %s:  \n", __FUNCTION__);
+}
+
+void
+gnc_run_c_hook (const gchar *name, gpointer data)
+{
+  GHookList *hook_list;
+
+  //printf("Enter %s: list %s, data %p\n", __FUNCTION__, name, data);
+  hook_list = gnc_lookup_hook_list(name);
+  if (!hook_list) {
+    //printf("Leave %s: No such hook list\n", __FUNCTION__);
+    return;
+  }
+  g_hook_list_marshal(hook_list, TRUE, call_hook, data);
+  //printf("Leave %s:  \n", __FUNCTION__);
+}
Index: Makefile.am
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/core-utils/Makefile.am,v
retrieving revision 1.7.4.1
retrieving revision 1.7.4.2
diff -Lsrc/core-utils/Makefile.am -Lsrc/core-utils/Makefile.am -u -r1.7.4.1 -r1.7.4.2
--- src/core-utils/Makefile.am
+++ src/core-utils/Makefile.am
@@ -3,7 +3,8 @@
 
 libcore_utils_la_SOURCES = \
   core-utils.c \
-  gnc-gconf-utils.c
+  gnc-gconf-utils.c \
+  gnc-hooks.c
 
 libcore_utils_la_LDFLAGS = -module
 
@@ -21,6 +22,8 @@
 
 noinst_HEADERS = \
   core-utils.h \
+  gnc-gconf-utils.h \
+  gnc-hooks.h \
   gw-core-utils.h
 
 EXTRA_DIST = .cvsignore ${gwmod_DATA}
Index: gw-core-utils-spec.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/core-utils/gw-core-utils-spec.scm,v
retrieving revision 1.2
retrieving revision 1.2.4.1
diff -Lsrc/core-utils/gw-core-utils-spec.scm -Lsrc/core-utils/gw-core-utils-spec.scm -u -r1.2 -r1.2.4.1
--- src/core-utils/gw-core-utils-spec.scm
+++ src/core-utils/gw-core-utils-spec.scm
@@ -6,16 +6,42 @@
 (define-module (g-wrapped gw-core-utils-spec))
 
 (use-modules (g-wrap))
+(use-modules (g-wrap simple-type))
 
-(display "**** NOTE: this wrapset appears to be empty !?\n")
+(use-modules (g-wrap gw-standard-spec))
+(use-modules (g-wrap gw-wct-spec))
+(use-modules (g-wrap gw-glib-spec))
 
 (let ((ws (gw:new-wrapset "gw-core-utils")))
 
+  (gw:wrapset-depends-on ws "gw-standard")
+  (gw:wrapset-depends-on ws "gw-wct")
+  (gw:wrapset-depends-on ws "gw-glib")
+
   (gw:wrapset-set-guile-module! ws '(g-wrapped gw-core-utils))
 
   (gw:wrapset-add-cs-declarations!
    ws
    (lambda (wrapset client-wrapset)
-     (if client-wrapset
-         '()
-         "#include <core-utils.h>\n"))))
+     (list
+      "#include <core-utils.h>\n"
+      "#include <gnc-gconf-utils.h>\n"
+      "#include <gnc-hooks.h>\n")))
+
+  (gw:wrap-function
+   ws
+   'gnc:gconf-get-bool
+   '<gw:bool>
+   "gnc_gconf_get_bool_no_error"
+   '(((<gw:mchars> caller-owned) section)
+     ((<gw:mchars> caller-owned) name))
+   "Get a boolean value from gconf.")
+
+  (gw:wrap-function
+   ws
+   'gnc:run-c-hook
+   '<gw:void>
+   "gnc_run_c_hook"
+   '(((<gw:mchars> caller-owned) name) (<gw:void*> data))
+   "Run a callback hook in the C domain.")
+)
Index: gnc-menu-extensions.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome-utils/gnc-menu-extensions.scm,v
retrieving revision 1.4.4.2
retrieving revision 1.4.4.3
diff -Lsrc/gnome-utils/gnc-menu-extensions.scm -Lsrc/gnome-utils/gnc-menu-extensions.scm -u -r1.4.4.2 -r1.4.4.3
--- src/gnome-utils/gnc-menu-extensions.scm
+++ src/gnome-utils/gnc-menu-extensions.scm
@@ -62,7 +62,8 @@
 (define (gnc:extensions-menu-setup)
   (define menu (gnc:make-menu (N_ "Extensions") (list "_Tools")))
   (gnc:add-extension menu)
-  (gnc:hook-run-danglers gnc:*add-extension-hook*))
+  (gnc:hook-run-danglers gnc:*add-extension-hook*)
+  (gnc:run-c-hook "add-extension-hook") #f)
 
 (if (gnc:debugging?)
     (gnc:hook-add-dangler gnc:*ui-startup-hook*
Index: report-gnome.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/report/report-gnome/report-gnome.scm,v
retrieving revision 1.9.4.5
retrieving revision 1.9.4.6
diff -Lsrc/report/report-gnome/report-gnome.scm -Lsrc/report/report-gnome/report-gnome.scm -u -r1.9.4.5 -r1.9.4.6
--- src/report/report-gnome/report-gnome.scm
+++ src/report/report-gnome/report-gnome.scm
@@ -12,6 +12,7 @@
 (use-modules (ice-9 slib))
 (require 'printf)
 
+(use-modules (g-wrapped gw-core-utils))
 (use-modules (g-wrapped gw-report-gnome))
 
 (gnc:module-load "gnucash/gnome-utils" 0)
@@ -113,6 +114,7 @@
 
   ;; run report-hook danglers
   (gnc:hook-run-danglers gnc:*report-hook*)
+  (gnc:run-c-hook "report-hook" #f)
 
   ;; push reports (new items added on top of menu)
   (gnc:add-report-template-menu-items))
Index: gnc-file.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/app-file/gnc-file.c,v
retrieving revision 1.25.4.14
retrieving revision 1.25.4.15
diff -Lsrc/app-file/gnc-file.c -Lsrc/app-file/gnc-file.c -u -r1.25.4.14 -r1.25.4.15
--- src/app-file/gnc-file.c
+++ src/app-file/gnc-file.c
@@ -38,6 +38,7 @@
 #include "gnc-file-p.h"
 #include "gnc-filepath-utils.h"
 #include "gnc-gui-query.h"
+#include "gnc-hooks.h"
 #include "gnc-splash.h"
 #include "gnc-ui.h"
 #include "gnc-ui-util.h"
@@ -354,6 +355,7 @@
               (session ? 
                gw_wcp_assimilate_ptr (session, scm_c_eval_string("<gnc:Session*>")) :
                SCM_BOOL_F));
+  gnc_run_c_hook(HOOK_BOOK_OPENED, session);
 }
 
 void
@@ -378,6 +380,7 @@
              (session ?
               gw_wcp_assimilate_ptr (session, scm_c_eval_string("<gnc:Session*>")) :
               SCM_BOOL_F));
+  gnc_run_c_hook(HOOK_BOOK_CLOSED, session);
 
   gnc_close_gui_component_by_session (session);
   xaccLogDisable();
@@ -389,6 +392,7 @@
 
   scm_call_1(scm_c_eval_string("gnc:hook-run-danglers"),
              scm_c_eval_string("gnc:*new-book-hook*"));
+  gnc_run_c_hook(HOOK_NEW_BOOK, NULL);
 
   gnc_book_opened ();
 
@@ -471,6 +475,7 @@
               gw_wcp_assimilate_ptr (current_session,
                                      scm_c_eval_string("<gnc:Session*>")) :
               SCM_BOOL_F));
+  gnc_run_c_hook(HOOK_BOOK_CLOSED, current_session);
   xaccLogDisable();
   qof_session_destroy (current_session);
   xaccLogEnable();
@@ -965,6 +970,7 @@
              (session ?
               gw_wcp_assimilate_ptr (session, scm_c_eval_string("<gnc:Session*>")) :
               SCM_BOOL_F));
+  gnc_run_c_hook(HOOK_BOOK_CLOSED, session);
   
   xaccLogDisable();
   qof_session_destroy (session);
Index: dialog-new-user.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome/dialog-new-user.c,v
retrieving revision 1.4.4.9
retrieving revision 1.4.4.10
diff -Lsrc/gnome/dialog-new-user.c -Lsrc/gnome/dialog-new-user.c -u -r1.4.4.9 -r1.4.4.10
--- src/gnome/dialog-new-user.c
+++ src/gnome/dialog-new-user.c
@@ -31,6 +31,7 @@
 #include "global-options.h"
 #include "gnc-engine-util.h"
 #include "gnc-gconf-utils.h"
+#include "gnc-hooks.h"
 #include "gnc-ui.h"
 
 #define GCONF_SECTION "dialogs/new_user"
@@ -136,4 +137,5 @@
 gncp_new_user_finish (void)
 {
   scm_c_eval_string("(gnc:hook-run-danglers gnc:*book-opened-hook* #f)");
+  gnc_run_c_hook(HOOK_BOOK_OPENED, NULL);
 }
Index: top-level.c
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/gnome/top-level.c,v
retrieving revision 1.140.4.19
retrieving revision 1.140.4.20
diff -Lsrc/gnome/top-level.c -Lsrc/gnome/top-level.c -u -r1.140.4.19 -r1.140.4.20
--- src/gnome/top-level.c
+++ src/gnome/top-level.c
@@ -45,6 +45,7 @@
 #include "gnc-date.h"
 #include "gnc-engine-util.h"
 #include "gnc-file.h"
+#include "gnc-hooks.h"
 #include "gnc-main-window.h"
 #include "gnc-menu-extensions.h"
 #include "gnc-plugin-menu-additions.h" /* FIXME Remove this line*/
@@ -402,6 +403,7 @@
       SCM run_danglers = scm_c_eval_string("gnc:hook-run-danglers");
       SCM hook = scm_c_eval_string("gnc:*ui-startup-hook*");
       scm_call_1(run_danglers, hook); 
+      gnc_run_c_hook(HOOK_UI_STARTUP, NULL);
     }
 
     // return ( main_window . command_line )
Index: main.scm
===================================================================
RCS file: /home/cvs/cvsroot/gnucash/src/scm/main.scm,v
retrieving revision 1.109.2.17
retrieving revision 1.109.2.18
diff -Lsrc/scm/main.scm -Lsrc/scm/main.scm -u -r1.109.2.17 -r1.109.2.18
--- src/scm/main.scm
+++ src/scm/main.scm
@@ -20,7 +20,7 @@
 (use-modules (ice-9 slib))
 
 (use-modules (g-wrap gw-wct))
-
+(use-modules (g-wrapped gw-core-utils))
 (use-modules (g-wrapped gw-gnc))
 
 ;; Load the srfis (eventually, we should see where these are needed
@@ -503,6 +503,7 @@
       (gnc:main-window-open-report (gnc:make-welcome-report) window))))
 
   (gnc:hook-run-danglers gnc:*startup-hook*)
+  (gnc:run-c-hook "startup-hook" #f)
 
   (if (gnc:config-var-value-get gnc:*loglevel*)
       (gnc:set-log-level-global (gnc:config-var-value-get gnc:*loglevel*))))
@@ -516,10 +517,12 @@
              (if (gnc:file-query-save)
                  (begin
                    (gnc:hook-run-danglers gnc:*ui-shutdown-hook*)
+		   (gnc:run-c-hook "ui-shutdown-hook" #f)
                    (gnc:gui-shutdown)))))
         (else
 	 (gnc:gui-destroy)
 	 (gnc:hook-run-danglers gnc:*shutdown-hook*)
+	 (gnc:run-c-hook "shutdown-hook" #f)
          (gnc:engine-shutdown)
 	 (exit exit-status))))
 
@@ -578,8 +581,10 @@
 	(begin
 	  (gnc:update-splash-screen (_ "Loading data..."))
 	  (and (not (gnc:file-open-file file))
-	       (gnc:hook-run-danglers gnc:*book-opened-hook* #f)))
-        (gnc:hook-run-danglers gnc:*book-opened-hook* #f))))
+	       (gnc:hook-run-danglers gnc:*book-opened-hook* #f)
+	       (gnc:run-c-hook "book-opened-hook" #f)))
+        (and (gnc:hook-run-danglers gnc:*book-opened-hook* #f)
+	     (gnc:run-c-hook "book-opened-hook" #f)))))
 
 (define (gnc:main)
 
@@ -641,6 +646,7 @@
           ;; no matter how or what we loaded, ensure the main-window title is valid...
           (gnc:main-window-update-title main-window)
           (gnc:hook-run-danglers gnc:*ui-post-startup-hook*)
+	  (gnc:run-c-hook "ui-post-startup-hook" #f)
           (gnc:start-ui-event-loop)
           (gnc:hook-remove-dangler gnc:*ui-shutdown-hook* gnc:gui-finish)))
         


More information about the gnucash-changes mailing list