GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gnc-hooks.c
1 /*
2  * gnc-hooks.c -- helpers for using Glib hook functions
3  * Copyright (C) 2005 David Hampton <[email protected]>
4  * Derek Atkins <[email protected]>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, contact:
18  *
19  * Free Software Foundation Voice: +1-617-542-5942
20  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
21  * Boston, MA 02110-1301, USA [email protected]
22  */
23 
24 #include "config.h"
25 
26 #include <glib.h>
27 #include <stdio.h>
28 #include <libguile.h>
29 #include <guile-mappings.h>
30 #include "swig-runtime.h"
31 #include "gnc-hooks.h"
32 #include "gnc-hooks-scm.h"
33 #include "gnc-engine.h"
34 
35 static QofLogModule log_module = GNC_MOD_ENGINE;
36 
37 static GHashTable* gnc_hooks_list = NULL;
38 static gboolean gnc_hooks_initialized = FALSE;
39 
40 typedef struct
41 {
42  gchar *desc;
43  GHookList *c_danglers;
44  GHookList *scm_danglers;
45  gint num_args;
46 } GncHook;
47 
48 typedef struct
49 {
50  SCM proc;
52 
53 gchar *
54 gnc_hook_create (const gchar *name, gint num_args, const gchar *desc)
55 {
56  GncHook *hook_list;
57 
58  g_return_val_if_fail(name != NULL, NULL);
59  g_return_val_if_fail(num_args <= 1, NULL);
60  g_return_val_if_fail(desc != NULL, NULL);
61 
62  ENTER("name %s", name);
63  if (gnc_hooks_list == NULL)
64  {
65  gnc_hooks_list = g_hash_table_new(g_str_hash, g_str_equal);
66 
67  /* If we're not initialized then initialize now */
68  if (!gnc_hooks_initialized)
69  gnc_hooks_init();
70  }
71 
72  hook_list = g_hash_table_lookup(gnc_hooks_list, name);
73  if (hook_list)
74  {
75  LEAVE("List %s(%p) already exists", name, hook_list);
76  return((gchar*)name);
77  }
78 
79  hook_list = g_new0(GncHook, 1);
80  hook_list->desc = g_strdup(desc);
81  hook_list->c_danglers = g_malloc(sizeof(GHookList));
82  g_hook_list_init(hook_list->c_danglers, sizeof(GHook));
83  hook_list->scm_danglers = g_malloc(sizeof(GHookList));
84  hook_list->num_args = num_args;
85  g_hook_list_init(hook_list->scm_danglers, sizeof(GHook));
86  g_hash_table_insert(gnc_hooks_list, (gchar *)name, hook_list);
87 
88  LEAVE("created list %s(%p)", name, hook_list);
89  return (gchar *)name;
90 }
91 
92 static GncHook *
93 gnc_hook_lookup (const gchar *name)
94 {
95  GncHook *hook;
96 
97  ENTER("name %s", name);
98  if (gnc_hooks_list == NULL)
99  {
100  PINFO("no hook lists");
101  gnc_hooks_init();
102  }
103 
104  hook = g_hash_table_lookup(gnc_hooks_list, name);
105  LEAVE("hook list %p", hook);
106  return(hook);
107 }
108 
109 void
110 gnc_hook_add_dangler (const gchar *name, GFunc callback, gpointer cb_arg)
111 {
112  GncHook *gnc_hook;
113  GHook *hook;
114 
115  ENTER("list %s, function %p, cbarg %p", name, callback, cb_arg);
116  gnc_hook = gnc_hook_lookup(name);
117  g_return_if_fail(gnc_hook != NULL);
118  hook = g_hook_alloc(gnc_hook->c_danglers);
119  hook->func = callback;
120  hook->data = cb_arg;
121  hook->destroy = NULL;
122  g_hook_append(gnc_hook->c_danglers, hook);
123  LEAVE("");
124 }
125 
126 static gboolean
127 hook_remove_runner (GHook *hook, gpointer data)
128 {
129  return(hook->func == data);
130 }
131 
132 void
133 gnc_hook_remove_dangler (const gchar *name, GFunc callback)
134 {
135  GncHook *gnc_hook;
136  GHook *hook;
137 
138  ENTER("name %s, function %p", name, callback);
139  gnc_hook = gnc_hook_lookup(name);
140  if (gnc_hook == NULL)
141  {
142  LEAVE("Unknown hook list %s", name);
143  return;
144  }
145 
146  hook = g_hook_find(gnc_hook->c_danglers, TRUE, hook_remove_runner, callback);
147  if (hook == NULL)
148  {
149  LEAVE("Hook %p not found in %s", callback, name);
150  return;
151  }
152 
153  g_hook_destroy_link(gnc_hook->c_danglers, hook);
154  LEAVE("Removed %p from %s", hook, name);
155 }
156 
157 static void
158 delete_scm_hook (gpointer data)
159 {
160  GncScmDangler *scm = data;
161  scm_gc_unprotect_object(scm->proc);
162  g_free(scm);
163 }
164 
165 static void
166 call_scm_hook (GHook *hook, gpointer data)
167 {
168  GncScmDangler *scm = hook->data;
169 
170  ENTER("hook %p, data %p, cbarg %p", hook, data, hook->data);
171 
172  scm_call_0 (scm->proc);
173 
174  LEAVE("");
175 }
176 
177 static void
178 call_scm_hook_1 (GHook *hook, gpointer data)
179 {
180  GncScmDangler *scm = hook->data;
181 
182  ENTER("hook %p, data %p, cbarg %p", hook, data, hook->data);
183 
184  // XXX: FIXME: We really should make sure this is a session!!! */
185  scm_call_1 (scm->proc,
186  SWIG_NewPointerObj(data, SWIG_TypeQuery("_p_QofSession"), 0));
187 
188  LEAVE("");
189 }
190 
191 void
192 gnc_hook_add_scm_dangler (const gchar *name, SCM proc)
193 {
194  GncHook *gnc_hook;
195  GHook *hook;
196  GncScmDangler *scm;
197 
198  ENTER("list %s, proc ???", name);
199  gnc_hook = gnc_hook_lookup(name);
200  g_return_if_fail(gnc_hook != NULL);
201  scm = g_new0(GncScmDangler, 1);
202  scm_gc_protect_object(proc);
203  scm->proc = proc;
204  hook = g_hook_alloc(gnc_hook->scm_danglers);
205  hook->func = call_scm_hook;
206  hook->data = scm;
207  hook->destroy = delete_scm_hook;
208  g_hook_append(gnc_hook->scm_danglers, hook);
209  LEAVE("");
210 }
211 
212 static void
213 call_c_hook (GHook *hook, gpointer data)
214 {
215  ENTER("hook %p (func %p), data %p, cbarg %p", hook, hook->func, data,
216  hook->data);
217  ((GFunc)hook->func)(data, hook->data);
218  LEAVE("");
219 }
220 
221 void
222 gnc_hook_run (const gchar *name, gpointer data)
223 {
224  GncHook *hook;
225 
226  ENTER("list %s, data %p", (name == NULL ? "(null)" : name), data);
227  hook = gnc_hook_lookup(name);
228  if (!hook)
229  {
230  LEAVE("No such hook list");
231  return;
232  }
233  g_hook_list_marshal(hook->c_danglers, TRUE, call_c_hook, data);
234  if (hook->num_args == 0)
235  g_hook_list_marshal(hook->scm_danglers, TRUE, call_scm_hook, data);
236  else
237  g_hook_list_marshal(hook->scm_danglers, TRUE, call_scm_hook_1, data);
238  LEAVE("");
239 }
240 
241 void
242 gnc_hooks_init(void)
243 {
244  ENTER("");
245 
246  if (gnc_hooks_initialized)
247  {
248  LEAVE("Hooks already initialized");
249  return;
250  }
251 
252  gnc_hooks_initialized = TRUE;
253 
254  gnc_hook_create(HOOK_STARTUP, 0,
255  "Functions to run at startup. Hook args: ()");
256  gnc_hook_create(HOOK_SHUTDOWN, 0,
257  "Functions to run at guile shutdown. Hook args: ()");
258  gnc_hook_create(HOOK_UI_STARTUP, 0,
259  "Functions to run when the ui comes up. Hook args: ()");
260  gnc_hook_create(HOOK_UI_POST_STARTUP, 0,
261  "Functions to run after the ui comes up. Hook args: ()");
262  gnc_hook_create(HOOK_UI_SHUTDOWN, 0,
263  "Functions to run at ui shutdown. Hook args: ()");
264  gnc_hook_create(HOOK_NEW_BOOK, 0,
265  "Run after a new (empty) book is opened, before the"
266  " book-opened-hook. Hook args: ()");
267  gnc_hook_create(HOOK_REPORT, 0,
268  "Run just before the reports are pushed into the menus."
269  " Hook args: ()");
270  gnc_hook_create(HOOK_CURRENCY_CHANGED, 0,
271  "Functions to run when the user changes currency settings. Hook args: ()");
272  gnc_hook_create(HOOK_SAVE_OPTIONS, 0,
273  "Functions to run when saving options. Hook args: ()");
274  gnc_hook_create(HOOK_ADD_EXTENSION, 0,
275  "Functions to run when the extensions menu is created."
276  " Hook args: ()");
277 
278  gnc_hook_create(HOOK_BOOK_OPENED, 1,
279  "Run after book open. Hook args: <gnc:Session*>.");
280  gnc_hook_create(HOOK_BOOK_CLOSED, 1,
281  "Run before file close. Hook args: <gnc:Session*>");
282  gnc_hook_create(HOOK_BOOK_SAVED, 1,
283  "Run after file saved. Hook args: <gnc:Session*>");
284 
285  LEAVE("");
286 }
#define PINFO(format, args...)
Definition: qoflog.h:249
#define ENTER(format, args...)
Definition: qoflog.h:261
All type declarations for the whole Gnucash engine.
#define LEAVE(format, args...)
Definition: qoflog.h:271
const gchar * QofLogModule
Definition: qofid.h:89