Audacious $Id:Doxyfile42802007-03-2104:39:00Znenolod$
hook.c
Go to the documentation of this file.
00001 /*  Audacious
00002  *  Copyright (c) 2006-2007 William Pitcock
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; under version 3 of the License.
00007  *
00008  *  This program is distributed in the hope that it will be useful,
00009  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00010  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011  *  GNU General Public License for more details.
00012  *
00013  *  You should have received a copy of the GNU General Public License
00014  *  along with this program.  If not, see <http://www.gnu.org/licenses>.
00015  *
00016  *  The Audacious team does not consider modular code linking to
00017  *  Audacious or using our public API to be a derived work.
00018  */
00019 
00020 #include <stdio.h>
00021 #include <string.h>
00022 
00023 #include <glib.h>
00024 #include "hook.h"
00025 
00026 static GThread * hook_thread;
00027 static GSList *hook_list;
00028 
00029 void hook_init (void)
00030 {
00031     hook_thread = g_thread_self ();
00032 }
00033 
00034 static Hook *
00035 hook_find(const gchar *name)
00036 {
00037     GSList *list;
00038 
00039     for (list = hook_list; list != NULL; list = g_slist_next(list))
00040     {
00041         Hook *hook = (Hook *) list->data;
00042 
00043         if (!g_ascii_strcasecmp(hook->name, name))
00044             return hook;
00045     }
00046 
00047     return NULL;
00048 }
00049 
00050 void
00051 hook_register(const gchar *name)
00052 {
00053     Hook *hook;
00054 
00055     g_return_if_fail(name != NULL);
00056 
00057     if (hook_find(name) != NULL)
00058         return;
00059 
00060     hook = g_new0(Hook, 1);
00061     hook->name = g_strdup(name);
00062     hook->items = NULL;
00063 
00064     hook_list = g_slist_append(hook_list, hook);
00065 }
00066 
00067 gint
00068 hook_associate(const gchar *name, HookFunction func, gpointer user_data)
00069 {
00070     Hook *hook;
00071     HookItem *hookitem;
00072 
00073     g_return_val_if_fail(name != NULL, -1);
00074     g_return_val_if_fail(func != NULL, -1);
00075 
00076     hook = hook_find(name);
00077 
00078     if (hook == NULL)
00079     {
00080         hook_register(name);
00081         hook = hook_find(name);
00082     }
00083 
00084     /* this *cant* happen */
00085     g_return_val_if_fail(hook != NULL, -1);
00086 
00087     hookitem = g_new0(HookItem, 1);
00088     hookitem->func = func;
00089     hookitem->user_data = user_data;
00090 
00091     hook->items = g_slist_append(hook->items, hookitem);
00092     return 0;
00093 }
00094 
00095 gint
00096 hook_dissociate(const gchar *name, HookFunction func)
00097 {
00098     Hook *hook;
00099     GSList *iter;
00100 
00101     g_return_val_if_fail(name != NULL, -1);
00102     g_return_val_if_fail(func != NULL, -1);
00103 
00104     hook = hook_find(name);
00105 
00106     if (hook == NULL)
00107         return -1;
00108 
00109     iter = hook->items;
00110     while (iter != NULL)
00111     {
00112         HookItem *hookitem = (HookItem*)iter->data;
00113         if (hookitem->func == func)
00114         {
00115             hook->items = g_slist_delete_link(hook->items, iter);
00116             g_free( hookitem );
00117             return 0;
00118         }
00119         iter = g_slist_next(iter);
00120     }
00121     return -1;
00122 }
00123 
00124 gint
00125 hook_dissociate_full(const gchar *name, HookFunction func, gpointer user_data)
00126 {
00127     Hook *hook;
00128     GSList *iter;
00129 
00130     g_return_val_if_fail(name != NULL, -1);
00131     g_return_val_if_fail(func != NULL, -1);
00132 
00133     hook = hook_find(name);
00134 
00135     if (hook == NULL)
00136         return -1;
00137 
00138     iter = hook->items;
00139     while (iter != NULL)
00140     {
00141         HookItem *hookitem = (HookItem*)iter->data;
00142         if (hookitem->func == func && hookitem->user_data == user_data)
00143         {
00144             hook->items = g_slist_delete_link(hook->items, iter);
00145             g_free( hookitem );
00146             return 0;
00147         }
00148         iter = g_slist_next(iter);
00149     }
00150     return -1;
00151 }
00152 
00153 void
00154 hook_call(const gchar *name, gpointer hook_data)
00155 {
00156     Hook *hook;
00157     GSList *iter;
00158 
00159     // Some plugins (skins, cdaudio-ng, maybe others) set up hooks that are not
00160     // thread safe. We can disagree about whether that's the way it should be;
00161     // but that's the way it is, so live with it. -jlindgren
00162     if (g_thread_self () != hook_thread)
00163     {
00164         fprintf (stderr, "Warning: Unsafe hook_call of \"%s\" from secondary "
00165          "thread. (Use event_queue instead.)\n", name);
00166         return;
00167     }
00168 
00169     hook = hook_find(name);
00170 
00171     if (hook == NULL)
00172         return;
00173 
00174     for (iter = hook->items; iter != NULL; iter = g_slist_next(iter))
00175     {
00176         HookItem *hookitem = (HookItem*)iter->data;
00177 
00178         g_return_if_fail(hookitem->func != NULL);
00179 
00180         hookitem->func(hook_data, hookitem->user_data);
00181     }
00182 }