Line data Source code
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 ************************************************/
32 : static guint suspend_counter = 0;
33 : static gint next_handler_id = 1;
34 : static guint handler_run_level = 0;
35 : static guint pending_deletes = 0;
36 : static GList *handlers = NULL;
37 :
38 : /* This static indicates the debugging module that this .o belongs to. */
39 : static QofLogModule log_module = QOF_MOD_ENGINE;
40 :
41 : /* Implementations *************************************************/
42 :
43 : static gint
44 226 : find_next_handler_id(void)
45 : {
46 : HandlerInfo *hi;
47 : gint handler_id;
48 : GList *node;
49 :
50 : /* look for a free handler id */
51 226 : handler_id = next_handler_id;
52 226 : node = handlers;
53 :
54 655 : while (node)
55 : {
56 429 : hi = static_cast<HandlerInfo*>(node->data);
57 :
58 429 : if (hi->handler_id == handler_id)
59 : {
60 0 : handler_id++;
61 0 : node = handlers;
62 0 : continue;
63 : }
64 :
65 429 : node = node->next;
66 : }
67 : /* Update id for next registration */
68 226 : next_handler_id = handler_id + 1;
69 226 : return handler_id;
70 : }
71 :
72 : gint
73 226 : qof_event_register_handler (QofEventHandler handler, gpointer user_data)
74 : {
75 : HandlerInfo *hi;
76 : gint handler_id;
77 :
78 226 : ENTER ("(handler=%p, data=%p)", handler, user_data);
79 :
80 : /* sanity check */
81 226 : if (!handler)
82 : {
83 0 : PERR ("no handler specified");
84 0 : return 0;
85 : }
86 :
87 : /* look for a free handler id */
88 226 : handler_id = find_next_handler_id();
89 :
90 : /* Found one, add the handler */
91 226 : hi = g_new0 (HandlerInfo, 1);
92 :
93 226 : hi->handler = handler;
94 226 : hi->user_data = user_data;
95 226 : hi->handler_id = handler_id;
96 :
97 226 : handlers = g_list_prepend (handlers, hi);
98 226 : LEAVE ("(handler=%p, data=%p) handler_id=%d", handler, user_data, handler_id);
99 226 : return handler_id;
100 : }
101 :
102 : void
103 198 : qof_event_unregister_handler (gint handler_id)
104 : {
105 : GList *node;
106 :
107 198 : ENTER ("(handler_id=%d)", handler_id);
108 243 : for (node = handlers; node; node = node->next)
109 : {
110 237 : HandlerInfo *hi = static_cast<HandlerInfo*>(node->data);
111 :
112 237 : if (hi->handler_id != handler_id)
113 45 : 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 192 : if (hi->handler)
121 192 : 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 192 : hi->handler = NULL;
126 :
127 192 : if (handler_run_level == 0)
128 : {
129 191 : handlers = g_list_remove_link (handlers, node);
130 191 : g_list_free_1 (node);
131 191 : g_free (hi);
132 : }
133 : else
134 : {
135 1 : pending_deletes++;
136 : }
137 :
138 192 : return;
139 : }
140 :
141 6 : PERR ("no such handler: %d", handler_id);
142 : }
143 :
144 : void
145 162 : qof_event_suspend (void)
146 : {
147 162 : suspend_counter++;
148 :
149 162 : if (suspend_counter == 0)
150 : {
151 0 : PERR ("suspend counter overflow");
152 : }
153 162 : }
154 :
155 : void
156 162 : qof_event_resume (void)
157 : {
158 162 : if (suspend_counter == 0)
159 : {
160 0 : PERR ("suspend counter underflow");
161 0 : return;
162 : }
163 :
164 162 : suspend_counter--;
165 : }
166 :
167 : static void
168 839312 : qof_event_generate_internal (QofInstance *entity, QofEventId event_id,
169 : gpointer event_data)
170 : {
171 : GList *node;
172 839312 : GList *next_node = NULL;
173 :
174 839312 : g_return_if_fail(entity);
175 :
176 839312 : switch (event_id)
177 : {
178 1 : case QOF_EVENT_NONE:
179 : {
180 : /* if none, don't log, just return. */
181 1 : return;
182 : }
183 : }
184 :
185 839311 : handler_run_level++;
186 1390865 : for (node = handlers; node; node = next_node)
187 : {
188 551554 : HandlerInfo *hi = static_cast<HandlerInfo*>(node->data);
189 :
190 551554 : next_node = node->next;
191 551554 : if (hi->handler)
192 : {
193 551554 : PINFO("id=%d hi=%p han=%p data=%p", hi->handler_id, hi,
194 : hi->handler, event_data);
195 551554 : hi->handler (entity, event_id, hi->user_data, event_data);
196 : }
197 : }
198 839311 : 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 839311 : if (handler_run_level == 0 && pending_deletes)
204 : {
205 3 : for (node = handlers; node; node = next_node)
206 : {
207 2 : HandlerInfo *hi = static_cast<HandlerInfo*>(node->data);
208 2 : next_node = node->next;
209 2 : if (hi->handler == NULL)
210 : {
211 : /* remove this node from the list, then free this node */
212 1 : handlers = g_list_remove_link (handlers, node);
213 1 : g_list_free_1 (node);
214 1 : g_free (hi);
215 : }
216 : }
217 1 : pending_deletes = 0;
218 : }
219 : }
220 :
221 : void
222 500 : qof_event_force (QofInstance *entity, QofEventId event_id, gpointer event_data)
223 : {
224 500 : if (!entity)
225 0 : return;
226 :
227 500 : qof_event_generate_internal (entity, event_id, event_data);
228 : }
229 :
230 : void
231 838970 : qof_event_gen (QofInstance *entity, QofEventId event_id, gpointer event_data)
232 : {
233 838970 : if (!entity)
234 10 : return;
235 :
236 838960 : if (suspend_counter)
237 148 : return;
238 :
239 838812 : qof_event_generate_internal (entity, event_id, event_data);
240 : }
241 :
242 : /* =========================== END OF FILE ======================= */
|