GnuCash c935c2f+
Loading...
Searching...
No Matches
qofevent.cpp
1/********************************************************************
2 * qofevent.c -- QOF event handling implementation *
3 * Copyright 2000 Dave Peticolas <dave@krondo.com> *
4 * Copyright 2006 Neil Williams <linux@codehelp.co.uk> *
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 gnu@gnu.org *
22 * *
23 ********************************************************************/
24
25#include <config.h>
26#include <glib.h>
27
28#include "qof.h"
29#include "qofevent-p.h"
30
31/* Static Variables ************************************************/
32static guint suspend_counter = 0;
33static gint next_handler_id = 1;
34static guint handler_run_level = 0;
35static guint pending_deletes = 0;
36static GList *handlers = NULL;
37
38/* This static indicates the debugging module that this .o belongs to. */
39static QofLogModule log_module = QOF_MOD_ENGINE;
40
41/* Implementations *************************************************/
42
43static gint
44find_next_handler_id(void)
45{
46 HandlerInfo *hi;
47 gint handler_id;
48 GList *node;
49
50 /* look for a free handler id */
51 handler_id = next_handler_id;
52 node = handlers;
53
54 while (node)
55 {
56 hi = static_cast<HandlerInfo*>(node->data);
57
58 if (hi->handler_id == handler_id)
59 {
60 handler_id++;
61 node = handlers;
62 continue;
63 }
64
65 node = node->next;
66 }
67 /* Update id for next registration */
68 next_handler_id = handler_id + 1;
69 return handler_id;
70}
71
72gint
73qof_event_register_handler (QofEventHandler handler, gpointer user_data)
74{
75 HandlerInfo *hi;
76 gint handler_id;
77
78 ENTER ("(handler=%p, data=%p)", handler, user_data);
79
80 /* sanity check */
81 if (!handler)
82 {
83 PERR ("no handler specified");
84 return 0;
85 }
86
87 /* look for a free handler id */
88 handler_id = find_next_handler_id();
89
90 /* Found one, add the handler */
91 hi = g_new0 (HandlerInfo, 1);
92
93 hi->handler = handler;
94 hi->user_data = user_data;
95 hi->handler_id = handler_id;
96
97 handlers = g_list_prepend (handlers, hi);
98 LEAVE ("(handler=%p, data=%p) handler_id=%d", handler, user_data, handler_id);
99 return handler_id;
100}
101
102void
104{
105 GList *node;
106
107 ENTER ("(handler_id=%d)", handler_id);
108 for (node = handlers; node; node = node->next)
109 {
110 HandlerInfo *hi = static_cast<HandlerInfo*>(node->data);
111
112 if (hi->handler_id != handler_id)
113 continue;
114
115 /* Normally, we could actually remove the handler's node from the
116 list, but we may be unregistering the event handler as a result
117 of a generated event, such as QOF_EVENT_DESTROY. In that case,
118 we're in the middle of walking the GList and it is wrong to
119 modify the list. So, instead, we just NULL the handler. */
120 if (hi->handler)
121 LEAVE ("(handler_id=%d) handler=%p data=%p", handler_id,
122 hi->handler, hi->user_data);
123
124 /* safety -- clear the handler in case we're running events now */
125 hi->handler = NULL;
126
127 if (handler_run_level == 0)
128 {
129 handlers = g_list_remove_link (handlers, node);
130 g_list_free_1 (node);
131 g_free (hi);
132 }
133 else
134 {
135 pending_deletes++;
136 }
137
138 return;
139 }
140
141 PERR ("no such handler: %d", handler_id);
142}
143
144void
146{
147 suspend_counter++;
148
149 if (suspend_counter == 0)
150 {
151 PERR ("suspend counter overflow");
152 }
153}
154
155void
157{
158 if (suspend_counter == 0)
159 {
160 PERR ("suspend counter underflow");
161 return;
162 }
163
164 suspend_counter--;
165}
166
167static void
168qof_event_generate_internal (QofInstance *entity, QofEventId event_id,
169 gpointer event_data)
170{
171 GList *node;
172 GList *next_node = NULL;
173
174 g_return_if_fail(entity);
175
176 switch (event_id)
177 {
178 case QOF_EVENT_NONE:
179 {
180 /* if none, don't log, just return. */
181 return;
182 }
183 }
184
185 handler_run_level++;
186 for (node = handlers; node; node = next_node)
187 {
188 HandlerInfo *hi = static_cast<HandlerInfo*>(node->data);
189
190 next_node = node->next;
191 if (hi->handler)
192 {
193 PINFO("id=%d hi=%p han=%p data=%p", hi->handler_id, hi,
194 hi->handler, event_data);
195 hi->handler (entity, event_id, hi->user_data, event_data);
196 }
197 }
198 handler_run_level--;
199
200 /* If we're the outermost event runner and we have pending deletes
201 * then go delete the handlers now.
202 */
203 if (handler_run_level == 0 && pending_deletes)
204 {
205 for (node = handlers; node; node = next_node)
206 {
207 HandlerInfo *hi = static_cast<HandlerInfo*>(node->data);
208 next_node = node->next;
209 if (hi->handler == NULL)
210 {
211 /* remove this node from the list, then free this node */
212 handlers = g_list_remove_link (handlers, node);
213 g_list_free_1 (node);
214 g_free (hi);
215 }
216 }
217 pending_deletes = 0;
218 }
219}
220
221void
222qof_event_force (QofInstance *entity, QofEventId event_id, gpointer event_data)
223{
224 if (!entity)
225 return;
226
227 qof_event_generate_internal (entity, event_id, event_data);
228}
229
230void
231qof_event_gen (QofInstance *entity, QofEventId event_id, gpointer event_data)
232{
233 if (!entity)
234 return;
235
236 if (suspend_counter)
237 return;
238
239 qof_event_generate_internal (entity, event_id, event_data);
240}
241
242/* =========================== END OF FILE ======================= */
void qof_event_unregister_handler(gint handler_id)
Unregister an event handler.
Definition qofevent.cpp:103
void(* QofEventHandler)(QofInstance *ent, QofEventId event_type, gpointer handler_data, gpointer event_data)
Handler invoked when an event is generated.
Definition qofevent.h:89
void qof_event_resume(void)
Resume engine event generation.
Definition qofevent.cpp:156
gint qof_event_register_handler(QofEventHandler handler, gpointer user_data)
Register a handler for events.
Definition qofevent.cpp:73
void qof_event_gen(QofInstance *entity, QofEventId event_id, gpointer event_data)
Invoke all registered event handlers using the given arguments.
Definition qofevent.cpp:231
void qof_event_suspend(void)
Suspend all engine events.
Definition qofevent.cpp:145
gint QofEventId
Define the type of events allowed.
Definition qofevent.h:45
#define QOF_EVENT_NONE
Default events for backwards compatibility.
Definition qofevent.h:72
#define PINFO(format, args...)
Print an informational note.
Definition qoflog.h:256
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition qoflog.h:282
#define PERR(format, args...)
Log a serious error.
Definition qoflog.h:244
#define ENTER(format, args...)
Print a function entry debugging message.
Definition qoflog.h:272