QOF  0.8.0
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 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 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 ======================= */