QOF  0.8.7
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 gint
72 qof_event_register_handler (QofEventHandler handler, gpointer user_data)
73 {
74  HandlerInfo *hi;
75  gint handler_id;
76 
77  ENTER ("(handler=%p, data=%p)", handler, user_data);
78 
79  /* sanity check */
80  if (!handler)
81  {
82  PERR ("no handler specified");
83  return 0;
84  }
85 
86  /* look for a free handler id */
87  handler_id = find_next_handler_id ();
88 
89  /* Found one, add the handler */
90  hi = g_new0 (HandlerInfo, 1);
91 
92  hi->handler = handler;
93  hi->user_data = user_data;
94  hi->handler_id = handler_id;
95 
96  handlers = g_list_prepend (handlers, hi);
97  LEAVE ("(handler=%p, data=%p) handler_id=%d", handler, user_data,
98  handler_id);
99  return handler_id;
100 }
101 
102 void
104 {
105  GList *node;
106 
107  ENTER ("(handler_id=%d)", handler_id);
108  for (node = handlers; node; node = node->next)
109  {
110  HandlerInfo *hi = 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 GNC_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 
144 void
146 {
147  suspend_counter++;
148 
149  if (suspend_counter == 0)
150  {
151  PERR ("suspend counter overflow");
152  }
153 }
154 
155 void
157 {
158  if (suspend_counter == 0)
159  {
160  PERR ("suspend counter underflow");
161  return;
162  }
163 
164  suspend_counter--;
165 }
166 
167 static void
168 qof_event_generate_internal (QofEntity * entity, QofEventId event_id,
169  gpointer event_data)
170 {
171  GList *node;
172  GList *next_node = NULL;
173  gboolean G_GNUC_UNUSED use_old_handlers = FALSE;
174 
175  g_return_if_fail (entity);
176 
177  if (event_id <= QOF_EVENT__LAST)
178  use_old_handlers = TRUE;
179 
180  switch (event_id)
181  {
182  case QOF_EVENT_NONE:
183  {
184  /* if none, don't log, just return. */
185  return;
186  }
187  }
188 
189  handler_run_level++;
190  for (node = handlers; node; node = next_node)
191  {
192  HandlerInfo *hi = node->data;
193 
194  next_node = node->next;
195  if (hi->handler)
196  {
197  PINFO ("id=%d type=%s", hi->handler_id, entity->e_type);
198  hi->handler (entity, event_id, hi->user_data, event_data);
199  }
200  }
201  handler_run_level--;
202 
203  /* If we're the outtermost event runner and we have pending deletes
204  * then go delete the handlers now.
205  */
206  if (handler_run_level == 0 && pending_deletes)
207  {
208  for (node = handlers; node; node = next_node)
209  {
210  HandlerInfo *hi = node->data;
211  next_node = node->next;
212  if (hi->handler == NULL)
213  {
214  /* remove this node from the list, then free this node */
215  handlers = g_list_remove_link (handlers, node);
216  g_list_free_1 (node);
217  g_free (hi);
218  }
219  }
220  pending_deletes = 0;
221  }
222 }
223 
224 void
225 qof_event_force (QofEntity * entity, QofEventId event_id,
226  gpointer event_data)
227 {
228  if (!entity)
229  return;
230 
231  qof_event_generate_internal (entity, event_id, event_data);
232 }
233 
234 void
235 qof_event_gen (QofEntity * entity, QofEventId event_id, gpointer event_data)
236 {
237  if (!entity)
238  return;
239 
240  if (suspend_counter)
241  return;
242 
243  qof_event_generate_internal (entity, event_id, event_data);
244 }
245 
246 /* deprecated */
247 void
248 qof_event_generate (const GUID * guid, QofIdType e_type, QofEventId event_id)
249 {
250  QofEntity ent;
251  ent.guid = *guid;
252  ent.e_type = e_type;
253  if (suspend_counter)
254  return;
255  /* caution: this is an incomplete entity! */
256  qof_event_generate_internal (&ent, event_id, NULL);
257 }
258 
259 /* =========================== END OF FILE ======================= */
#define PERR(format, args...)
Definition: qoflog.h:183
const gchar * QofIdType
Definition: qofid.h:81
#define PINFO(format, args...)
Definition: qoflog.h:199
void(* QofEventHandler)(QofEntity *ent, QofEventId event_type, gpointer handler_data, gpointer event_data)
Handler invoked when an event is generated.
Definition: qofevent.h:104
#define LEAVE(format, args...)
Definition: qoflog.h:227
void qof_event_gen(QofEntity *entity, QofEventId event_id, gpointer event_data)
Invoke all registered event handlers using the given arguments.
Definition: qofevent.c:235
gint qof_event_register_handler(QofEventHandler handler, gpointer user_data)
Register a handler for events.
Definition: qofevent.c:72
gint QofEventId
Definition: qofevent.h:40
void qof_event_unregister_handler(gint handler_id)
Unregister an event handler.
Definition: qofevent.c:103
#define QOF_EVENT_NONE
Definition: qofevent.h:69
Definition: guid.h:53
void qof_event_suspend(void)
Suspend all engine events.
Definition: qofevent.c:145
void qof_event_resume(void)
Definition: qofevent.c:156
#define ENTER(format, args...)
Definition: qoflog.h:217
const gchar * QofLogModule
Definition: qofid.h:85