GnuCash 2.4.99
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, handler_id);
00098     return handler_id;
00099 }
00100 
00101 void
00102 qof_event_unregister_handler (gint handler_id)
00103 {
00104     GList *node;
00105 
00106     ENTER ("(handler_id=%d)", handler_id);
00107     for (node = handlers; node; node = node->next)
00108     {
00109         HandlerInfo *hi = node->data;
00110 
00111         if (hi->handler_id != handler_id)
00112             continue;
00113 
00114         /* Normally, we could actually remove the handler's node from the
00115            list, but we may be unregistering the event handler as a result
00116            of a generated event, such as QOF_EVENT_DESTROY.  In that case,
00117            we're in the middle of walking the GList and it is wrong to
00118            modify the list. So, instead, we just NULL the handler. */
00119         if (hi->handler)
00120             LEAVE ("(handler_id=%d) handler=%p data=%p", handler_id,
00121                    hi->handler, hi->user_data);
00122 
00123         /* safety -- clear the handler in case we're running events now */
00124         hi->handler = NULL;
00125 
00126         if (handler_run_level == 0)
00127         {
00128             handlers = g_list_remove_link (handlers, node);
00129             g_list_free_1 (node);
00130             g_free (hi);
00131         }
00132         else
00133         {
00134             pending_deletes++;
00135         }
00136 
00137         return;
00138     }
00139 
00140     PERR ("no such handler: %d", handler_id);
00141 }
00142 
00143 void
00144 qof_event_suspend (void)
00145 {
00146     suspend_counter++;
00147 
00148     if (suspend_counter == 0)
00149     {
00150         PERR ("suspend counter overflow");
00151     }
00152 }
00153 
00154 void
00155 qof_event_resume (void)
00156 {
00157     if (suspend_counter == 0)
00158     {
00159         PERR ("suspend counter underflow");
00160         return;
00161     }
00162 
00163     suspend_counter--;
00164 }
00165 
00166 static void
00167 qof_event_generate_internal (QofInstance *entity, QofEventId event_id,
00168                              gpointer event_data)
00169 {
00170     GList *node;
00171     GList *next_node = NULL;
00172     gboolean use_old_handlers = FALSE;
00173 
00174     g_return_if_fail(entity);
00175 
00176     if (event_id <= QOF_EVENT__LAST)
00177     {
00178         use_old_handlers = TRUE;
00179     }
00180 
00181     switch (event_id)
00182     {
00183     case QOF_EVENT_NONE:
00184     {
00185         /* if none, don't log, just return. */
00186         return;
00187     }
00188     }
00189 
00190     handler_run_level++;
00191     for (node = handlers; node; node = next_node)
00192     {
00193         HandlerInfo *hi = node->data;
00194 
00195         next_node = node->next;
00196         if (hi->handler)
00197         {
00198             PINFO("id=%d hi=%p han=%p data=%p", hi->handler_id, hi,
00199                   hi->handler, event_data);
00200             hi->handler (entity, event_id, hi->user_data, event_data);
00201         }
00202     }
00203     handler_run_level--;
00204 
00205     /* If we're the outermost event runner and we have pending deletes
00206      * then go delete the handlers now.
00207      */
00208     if (handler_run_level == 0 && pending_deletes)
00209     {
00210         for (node = handlers; node; node = next_node)
00211         {
00212             HandlerInfo *hi = node->data;
00213             next_node = node->next;
00214             if (hi->handler == NULL)
00215             {
00216                 /* remove this node from the list, then free this node */
00217                 handlers = g_list_remove_link (handlers, node);
00218                 g_list_free_1 (node);
00219                 g_free (hi);
00220             }
00221         }
00222         pending_deletes = 0;
00223     }
00224 }
00225 
00226 void
00227 qof_event_force (QofInstance *entity, QofEventId event_id, gpointer event_data)
00228 {
00229     if (!entity)
00230         return;
00231 
00232     qof_event_generate_internal (entity, event_id, event_data);
00233 }
00234 
00235 void
00236 qof_event_gen (QofInstance *entity, QofEventId event_id, gpointer event_data)
00237 {
00238     if (!entity)
00239         return;
00240 
00241     if (suspend_counter)
00242         return;
00243 
00244     qof_event_generate_internal (entity, event_id, event_data);
00245 }
00246 
00247 /* =========================== END OF FILE ======================= */
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines