QOF  0.7.5
qofevent.c
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 #include "qof.h"
28 #include "qofevent-p.h"
29 
30 /* Static Variables ************************************************/
31 static guint suspend_counter = 0;
32 static gint next_handler_id = 1;
33 static guint handler_run_level = 0;
34 static guint pending_deletes = 0;
35 static GList *handlers = NULL;
36 
37 /* This static indicates the debugging module that this .o belongs to. */
38 static QofLogModule log_module = QOF_MOD_ENGINE;
39 
40 /* Implementations *************************************************/
41 
42 static gint
43 find_next_handler_id (void)
44 {
45  HandlerInfo *hi;
46  gint handler_id;
47  GList *node;
48 
49  /* look for a free handler id */
50  handler_id = next_handler_id;
51  node = handlers;
52 
53  while (node)
54  {
55  hi = node->data;
56 
57  if (hi->handler_id == handler_id)
58  {
59  handler_id++;
60  node = handlers;
61  continue;
62  }
63 
64  node = node->next;
65  }
66  /* Update id for next registration */
67  next_handler_id = handler_id + 1;
68  return handler_id;
69 }
70 
71 /* support deprecated code with a private function*/
72 #ifndef QOF_DISABLE_DEPRECATED
73 gint
75  gpointer user_data)
76 {
77  HandlerInfo *hi;
78  gint handler_id;
79 
80  ENTER ("(handler=%p, data=%p)", handler, user_data);
81 
82  /* sanity check */
83  if (!handler)
84  {
85  PERR ("no handler specified");
86  return 0;
87  }
88  PINFO (" deprecated handler specified");
89 
90  handler_id = find_next_handler_id ();
91  /* Found one, add the handler */
92  hi = g_new0 (HandlerInfo, 1);
93 
94  hi->old_handler = handler;
95  hi->user_data = user_data;
96  hi->handler_id = handler_id;
97 
98  handlers = g_list_prepend (handlers, hi);
99 
100  LEAVE (" (handler=%p, data=%p) handler_id=%d", handler, user_data,
101  handler_id);
102  return handler_id;
103 
104 }
105 #endif /* QOF_DISABLE_DEPRECATED */
106 
107 gint
108 qof_event_register_handler (QofEventHandler handler, gpointer user_data)
109 {
110  HandlerInfo *hi;
111  gint handler_id;
112 
113  ENTER ("(handler=%p, data=%p)", handler, user_data);
114 
115  /* sanity check */
116  if (!handler)
117  {
118  PERR ("no handler specified");
119  return 0;
120  }
121 
122  /* look for a free handler id */
123  handler_id = find_next_handler_id ();
124 
125  /* Found one, add the handler */
126  hi = g_new0 (HandlerInfo, 1);
127 
128  hi->handler = handler;
129  hi->user_data = user_data;
130  hi->handler_id = handler_id;
131 
132  handlers = g_list_prepend (handlers, hi);
133  LEAVE ("(handler=%p, data=%p) handler_id=%d", handler, user_data,
134  handler_id);
135  return handler_id;
136 }
137 
138 void
140 {
141  GList *node;
142 
143  ENTER ("(handler_id=%d)", handler_id);
144  for (node = handlers; node; node = node->next)
145  {
146  HandlerInfo *hi = node->data;
147 
148  if (hi->handler_id != handler_id)
149  continue;
150 
151  /* Normally, we could actually remove the handler's node from the
152  list, but we may be unregistering the event handler as a result
153  of a generated event, such as GNC_EVENT_DESTROY. In that case,
154  we're in the middle of walking the GList and it is wrong to
155  modify the list. So, instead, we just NULL the handler. */
156  if (hi->handler)
157  LEAVE ("(handler_id=%d) handler=%p data=%p", handler_id,
158  hi->handler, hi->user_data);
159 #ifndef QOF_DISABLE_DEPRECATED
160  if (hi->old_handler)
161  LEAVE ("(handler_id=%d) handler=%p data=%p", handler_id,
162  hi->old_handler, hi->user_data);
163 #endif
164 
165  /* safety -- clear the handler in case we're running events now */
166  hi->handler = NULL;
167 #ifndef QOF_DISABLE_DEPRECATED
168  hi->old_handler = NULL;
169 #endif
170 
171  if (handler_run_level == 0)
172  {
173  handlers = g_list_remove_link (handlers, node);
174  g_list_free_1 (node);
175  g_free (hi);
176  }
177  else
178  {
179  pending_deletes++;
180  }
181 
182  return;
183  }
184 
185  PERR ("no such handler: %d", handler_id);
186 }
187 
188 void
190 {
191  suspend_counter++;
192 
193  if (suspend_counter == 0)
194  {
195  PERR ("suspend counter overflow");
196  }
197 }
198 
199 void
201 {
202  if (suspend_counter == 0)
203  {
204  PERR ("suspend counter underflow");
205  return;
206  }
207 
208  suspend_counter--;
209 }
210 
211 static void
212 qof_event_generate_internal (QofEntity * entity, QofEventId event_id,
213  gpointer event_data)
214 {
215  GList *node;
216  GList *next_node = NULL;
217  gboolean use_old_handlers = FALSE;
218 
219  g_return_if_fail (entity);
220 
221  if (event_id <= QOF_EVENT__LAST)
222  use_old_handlers = TRUE;
223 
224  switch (event_id)
225  {
226  case QOF_EVENT_NONE:
227  {
228  /* if none, don't log, just return. */
229  return;
230  }
231  }
232 
233  handler_run_level++;
234  for (node = handlers; node; node = next_node)
235  {
236  HandlerInfo *hi = node->data;
237 
238  next_node = node->next;
239 #ifndef QOF_DISABLE_DEPRECATED
240  if ((hi->old_handler) && (use_old_handlers))
241  {
242  PINFO (" deprecated: id=%d hi=%p han=%p", hi->handler_id, hi,
243  hi->old_handler);
244  hi->old_handler ((GUID *) & entity->guid, entity->e_type,
245  event_id, hi->user_data);
246  }
247 #endif
248  if (hi->handler)
249  {
250  PINFO ("id=%d type=%s", hi->handler_id, entity->e_type);
251  hi->handler (entity, event_id, hi->user_data, event_data);
252  }
253  }
254  handler_run_level--;
255 
256  /* If we're the outtermost event runner and we have pending deletes
257  * then go delete the handlers now.
258  */
259  if (handler_run_level == 0 && pending_deletes)
260  {
261  for (node = handlers; node; node = next_node)
262  {
263  HandlerInfo *hi = node->data;
264  next_node = node->next;
265  if ((hi->handler == NULL)
266 #ifndef QOF_DISABLE_DEPRECATED
267  && (hi->old_handler == NULL)
268 #endif
269  )
270  {
271  /* remove this node from the list, then free this node */
272  handlers = g_list_remove_link (handlers, node);
273  g_list_free_1 (node);
274  g_free (hi);
275  }
276  }
277  pending_deletes = 0;
278  }
279 }
280 
281 void
282 qof_event_force (QofEntity * entity, QofEventId event_id,
283  gpointer event_data)
284 {
285  if (!entity)
286  return;
287 
288  qof_event_generate_internal (entity, event_id, event_data);
289 }
290 
291 void
292 qof_event_gen (QofEntity * entity, QofEventId event_id, gpointer event_data)
293 {
294  if (!entity)
295  return;
296 
297  if (suspend_counter)
298  return;
299 
300  qof_event_generate_internal (entity, event_id, event_data);
301 }
302 
303 /* deprecated */
304 void
305 qof_event_generate (const GUID * guid, QofIdType e_type, QofEventId event_id)
306 {
307  QofEntity ent;
308  ent.guid = *guid;
309  ent.e_type = e_type;
310  if (suspend_counter)
311  return;
312  /* caution: this is an incomplete entity! */
313  qof_event_generate_internal (&ent, event_id, NULL);
314 }
315 
316 /* =========================== END OF FILE ======================= */