QOF
0.8.7
|
00001 /******************************************************************** 00002 * qofevent.c -- QOF event handling implementation * 00003 * Copyright 2000 Dave Peticolas <dave@krondo.com> * 00004 * Copyright 2006 Neil Williams <linux@codehelp.co.uk> * 00005 * * 00006 * This program is free software; you can redistribute it and/or * 00007 * modify it under the terms of the GNU General Public License as * 00008 * published by the Free Software Foundation; either version 2 of * 00009 * the License, or (at your option) any later version. * 00010 * * 00011 * This program is distributed in the hope that it will be useful, * 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00014 * GNU General Public License for more details. * 00015 * * 00016 * You should have received a copy of the GNU General Public License* 00017 * along with this program; if not, contact: * 00018 * * 00019 * Free Software Foundation Voice: +1-617-542-5942 * 00020 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * 00021 * Boston, MA 02110-1301, USA gnu@gnu.org * 00022 * * 00023 ********************************************************************/ 00024 00025 #include "config.h" 00026 #include <glib.h> 00027 #include "qof.h" 00028 #include "qofevent-p.h" 00029 00030 /* Static Variables ************************************************/ 00031 static guint suspend_counter = 0; 00032 static gint next_handler_id = 1; 00033 static guint handler_run_level = 0; 00034 static guint pending_deletes = 0; 00035 static GList *handlers = NULL; 00036 00037 /* This static indicates the debugging module that this .o belongs to. */ 00038 static QofLogModule log_module = QOF_MOD_ENGINE; 00039 00040 /* Implementations *************************************************/ 00041 00042 static gint 00043 find_next_handler_id (void) 00044 { 00045 HandlerInfo *hi; 00046 gint handler_id; 00047 GList *node; 00048 00049 /* look for a free handler id */ 00050 handler_id = next_handler_id; 00051 node = handlers; 00052 00053 while (node) 00054 { 00055 hi = node->data; 00056 00057 if (hi->handler_id == handler_id) 00058 { 00059 handler_id++; 00060 node = handlers; 00061 continue; 00062 } 00063 00064 node = node->next; 00065 } 00066 /* Update id for next registration */ 00067 next_handler_id = handler_id + 1; 00068 return handler_id; 00069 } 00070 00071 gint 00072 qof_event_register_handler (QofEventHandler handler, gpointer user_data) 00073 { 00074 HandlerInfo *hi; 00075 gint handler_id; 00076 00077 ENTER ("(handler=%p, data=%p)", handler, user_data); 00078 00079 /* sanity check */ 00080 if (!handler) 00081 { 00082 PERR ("no handler specified"); 00083 return 0; 00084 } 00085 00086 /* look for a free handler id */ 00087 handler_id = find_next_handler_id (); 00088 00089 /* Found one, add the handler */ 00090 hi = g_new0 (HandlerInfo, 1); 00091 00092 hi->handler = handler; 00093 hi->user_data = user_data; 00094 hi->handler_id = handler_id; 00095 00096 handlers = g_list_prepend (handlers, hi); 00097 LEAVE ("(handler=%p, data=%p) handler_id=%d", handler, user_data, 00098 handler_id); 00099 return handler_id; 00100 } 00101 00102 void 00103 qof_event_unregister_handler (gint handler_id) 00104 { 00105 GList *node; 00106 00107 ENTER ("(handler_id=%d)", handler_id); 00108 for (node = handlers; node; node = node->next) 00109 { 00110 HandlerInfo *hi = node->data; 00111 00112 if (hi->handler_id != handler_id) 00113 continue; 00114 00115 /* Normally, we could actually remove the handler's node from the 00116 list, but we may be unregistering the event handler as a result 00117 of a generated event, such as GNC_EVENT_DESTROY. In that case, 00118 we're in the middle of walking the GList and it is wrong to 00119 modify the list. So, instead, we just NULL the handler. */ 00120 if (hi->handler) 00121 LEAVE ("(handler_id=%d) handler=%p data=%p", handler_id, 00122 hi->handler, hi->user_data); 00123 00124 /* safety -- clear the handler in case we're running events now */ 00125 hi->handler = NULL; 00126 00127 if (handler_run_level == 0) 00128 { 00129 handlers = g_list_remove_link (handlers, node); 00130 g_list_free_1 (node); 00131 g_free (hi); 00132 } 00133 else 00134 { 00135 pending_deletes++; 00136 } 00137 00138 return; 00139 } 00140 00141 PERR ("no such handler: %d", handler_id); 00142 } 00143 00144 void 00145 qof_event_suspend (void) 00146 { 00147 suspend_counter++; 00148 00149 if (suspend_counter == 0) 00150 { 00151 PERR ("suspend counter overflow"); 00152 } 00153 } 00154 00155 void 00156 qof_event_resume (void) 00157 { 00158 if (suspend_counter == 0) 00159 { 00160 PERR ("suspend counter underflow"); 00161 return; 00162 } 00163 00164 suspend_counter--; 00165 } 00166 00167 static void 00168 qof_event_generate_internal (QofEntity * entity, QofEventId event_id, 00169 gpointer event_data) 00170 { 00171 GList *node; 00172 GList *next_node = NULL; 00173 gboolean G_GNUC_UNUSED use_old_handlers = FALSE; 00174 00175 g_return_if_fail (entity); 00176 00177 if (event_id <= QOF_EVENT__LAST) 00178 use_old_handlers = TRUE; 00179 00180 switch (event_id) 00181 { 00182 case QOF_EVENT_NONE: 00183 { 00184 /* if none, don't log, just return. */ 00185 return; 00186 } 00187 } 00188 00189 handler_run_level++; 00190 for (node = handlers; node; node = next_node) 00191 { 00192 HandlerInfo *hi = node->data; 00193 00194 next_node = node->next; 00195 if (hi->handler) 00196 { 00197 PINFO ("id=%d type=%s", hi->handler_id, entity->e_type); 00198 hi->handler (entity, event_id, hi->user_data, event_data); 00199 } 00200 } 00201 handler_run_level--; 00202 00203 /* If we're the outtermost event runner and we have pending deletes 00204 * then go delete the handlers now. 00205 */ 00206 if (handler_run_level == 0 && pending_deletes) 00207 { 00208 for (node = handlers; node; node = next_node) 00209 { 00210 HandlerInfo *hi = node->data; 00211 next_node = node->next; 00212 if (hi->handler == NULL) 00213 { 00214 /* remove this node from the list, then free this node */ 00215 handlers = g_list_remove_link (handlers, node); 00216 g_list_free_1 (node); 00217 g_free (hi); 00218 } 00219 } 00220 pending_deletes = 0; 00221 } 00222 } 00223 00224 void 00225 qof_event_force (QofEntity * entity, QofEventId event_id, 00226 gpointer event_data) 00227 { 00228 if (!entity) 00229 return; 00230 00231 qof_event_generate_internal (entity, event_id, event_data); 00232 } 00233 00234 void 00235 qof_event_gen (QofEntity * entity, QofEventId event_id, gpointer event_data) 00236 { 00237 if (!entity) 00238 return; 00239 00240 if (suspend_counter) 00241 return; 00242 00243 qof_event_generate_internal (entity, event_id, event_data); 00244 } 00245 00246 /* deprecated */ 00247 void 00248 qof_event_generate (const GUID * guid, QofIdType e_type, QofEventId event_id) 00249 { 00250 QofEntity ent; 00251 ent.guid = *guid; 00252 ent.e_type = e_type; 00253 if (suspend_counter) 00254 return; 00255 /* caution: this is an incomplete entity! */ 00256 qof_event_generate_internal (&ent, event_id, NULL); 00257 } 00258 00259 /* =========================== END OF FILE ======================= */