qofevent.c

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 /* support deprecated code with a private function*/
00072 #ifndef QOF_DISABLE_DEPRECATED
00073 gint
00074 qof_event_register_old_handler (GNCEngineEventHandler handler,
00075     gpointer user_data)
00076 {
00077     HandlerInfo *hi;
00078     gint handler_id;
00079 
00080     ENTER ("(handler=%p, data=%p)", handler, user_data);
00081 
00082     /* sanity check */
00083     if (!handler)
00084     {
00085         PERR ("no handler specified");
00086         return 0;
00087     }
00088     PINFO (" deprecated handler specified");
00089 
00090     handler_id = find_next_handler_id ();
00091     /* Found one, add the handler */
00092     hi = g_new0 (HandlerInfo, 1);
00093 
00094     hi->old_handler = handler;
00095     hi->user_data = user_data;
00096     hi->handler_id = handler_id;
00097 
00098     handlers = g_list_prepend (handlers, hi);
00099 
00100     LEAVE (" (handler=%p, data=%p) handler_id=%d", handler, user_data,
00101         handler_id);
00102     return handler_id;
00103 
00104 }
00105 #endif /* QOF_DISABLE_DEPRECATED */
00106 
00107 gint
00108 qof_event_register_handler (QofEventHandler handler, gpointer user_data)
00109 {
00110     HandlerInfo *hi;
00111     gint handler_id;
00112 
00113     ENTER ("(handler=%p, data=%p)", handler, user_data);
00114 
00115     /* sanity check */
00116     if (!handler)
00117     {
00118         PERR ("no handler specified");
00119         return 0;
00120     }
00121 
00122     /* look for a free handler id */
00123     handler_id = find_next_handler_id ();
00124 
00125     /* Found one, add the handler */
00126     hi = g_new0 (HandlerInfo, 1);
00127 
00128     hi->handler = handler;
00129     hi->user_data = user_data;
00130     hi->handler_id = handler_id;
00131 
00132     handlers = g_list_prepend (handlers, hi);
00133     LEAVE ("(handler=%p, data=%p) handler_id=%d", handler, user_data,
00134         handler_id);
00135     return handler_id;
00136 }
00137 
00138 void
00139 qof_event_unregister_handler (gint handler_id)
00140 {
00141     GList *node;
00142 
00143     ENTER ("(handler_id=%d)", handler_id);
00144     for (node = handlers; node; node = node->next)
00145     {
00146         HandlerInfo *hi = node->data;
00147 
00148         if (hi->handler_id != handler_id)
00149             continue;
00150 
00151         /* Normally, we could actually remove the handler's node from the
00152            list, but we may be unregistering the event handler as a result
00153            of a generated event, such as GNC_EVENT_DESTROY.  In that case,
00154            we're in the middle of walking the GList and it is wrong to
00155            modify the list. So, instead, we just NULL the handler. */
00156         if (hi->handler)
00157             LEAVE ("(handler_id=%d) handler=%p data=%p", handler_id,
00158                 hi->handler, hi->user_data);
00159 #ifndef QOF_DISABLE_DEPRECATED
00160         if (hi->old_handler)
00161             LEAVE ("(handler_id=%d) handler=%p data=%p", handler_id,
00162                 hi->old_handler, hi->user_data);
00163 #endif
00164 
00165         /* safety -- clear the handler in case we're running events now */
00166         hi->handler = NULL;
00167 #ifndef QOF_DISABLE_DEPRECATED
00168         hi->old_handler = NULL;
00169 #endif
00170 
00171         if (handler_run_level == 0)
00172         {
00173             handlers = g_list_remove_link (handlers, node);
00174             g_list_free_1 (node);
00175             g_free (hi);
00176         }
00177         else
00178         {
00179             pending_deletes++;
00180         }
00181 
00182         return;
00183     }
00184 
00185     PERR ("no such handler: %d", handler_id);
00186 }
00187 
00188 void
00189 qof_event_suspend (void)
00190 {
00191     suspend_counter++;
00192 
00193     if (suspend_counter == 0)
00194     {
00195         PERR ("suspend counter overflow");
00196     }
00197 }
00198 
00199 void
00200 qof_event_resume (void)
00201 {
00202     if (suspend_counter == 0)
00203     {
00204         PERR ("suspend counter underflow");
00205         return;
00206     }
00207 
00208     suspend_counter--;
00209 }
00210 
00211 static void
00212 qof_event_generate_internal (QofEntity * entity, QofEventId event_id,
00213     gpointer event_data)
00214 {
00215     GList *node;
00216     GList *next_node = NULL;
00217     gboolean use_old_handlers = FALSE;
00218 
00219     g_return_if_fail (entity);
00220 
00221     if (event_id <= QOF_EVENT__LAST)
00222         use_old_handlers = TRUE;
00223 
00224     switch (event_id)
00225     {
00226     case QOF_EVENT_NONE:
00227         {
00228             /* if none, don't log, just return. */
00229             return;
00230         }
00231     }
00232 
00233     handler_run_level++;
00234     for (node = handlers; node; node = next_node)
00235     {
00236         HandlerInfo *hi = node->data;
00237 
00238         next_node = node->next;
00239 #ifndef QOF_DISABLE_DEPRECATED
00240         if ((hi->old_handler) && (use_old_handlers))
00241         {
00242             PINFO (" deprecated: id=%d hi=%p han=%p", hi->handler_id, hi,
00243                 hi->old_handler);
00244             hi->old_handler ((GUID *) & entity->guid, entity->e_type,
00245                 event_id, hi->user_data);
00246         }
00247 #endif
00248         if (hi->handler)
00249         {
00250             PINFO ("id=%d type=%s", hi->handler_id, entity->e_type);
00251             hi->handler (entity, event_id, hi->user_data, event_data);
00252         }
00253     }
00254     handler_run_level--;
00255 
00256     /* If we're the outtermost event runner and we have pending deletes
00257      * then go delete the handlers now.
00258      */
00259     if (handler_run_level == 0 && pending_deletes)
00260     {
00261         for (node = handlers; node; node = next_node)
00262         {
00263             HandlerInfo *hi = node->data;
00264             next_node = node->next;
00265             if ((hi->handler == NULL)
00266 #ifndef QOF_DISABLE_DEPRECATED
00267                 && (hi->old_handler == NULL)
00268 #endif
00269                 )
00270             {
00271                 /* remove this node from the list, then free this node */
00272                 handlers = g_list_remove_link (handlers, node);
00273                 g_list_free_1 (node);
00274                 g_free (hi);
00275             }
00276         }
00277         pending_deletes = 0;
00278     }
00279 }
00280 
00281 void
00282 qof_event_force (QofEntity * entity, QofEventId event_id,
00283     gpointer event_data)
00284 {
00285     if (!entity)
00286         return;
00287 
00288     qof_event_generate_internal (entity, event_id, event_data);
00289 }
00290 
00291 void
00292 qof_event_gen (QofEntity * entity, QofEventId event_id, gpointer event_data)
00293 {
00294     if (!entity)
00295         return;
00296 
00297     if (suspend_counter)
00298         return;
00299 
00300     qof_event_generate_internal (entity, event_id, event_data);
00301 }
00302 
00303 /* deprecated */
00304 void
00305 qof_event_generate (const GUID * guid, QofIdType e_type, QofEventId event_id)
00306 {
00307     QofEntity ent;
00308     ent.guid = *guid;
00309     ent.e_type = e_type;
00310     if (suspend_counter)
00311         return;
00312     /* caution: this is an incomplete entity! */
00313     qof_event_generate_internal (&ent, event_id, NULL);
00314 }
00315 
00316 /* =========================== END OF FILE ======================= */

Generated on Thu Jan 31 22:50:25 2008 for QOF by  doxygen 1.5.4