source: roaraudio/libroar/notify.c @ 4320:024275201dee

Last change on this file since 4320:024275201dee was 4320:024275201dee, checked in by phi, 14 years ago

support global notify core

File size: 7.8 KB
Line 
1//notify.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010
5 *
6 *  This file is part of libroar a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  libroar is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 *  NOTE for everyone want's to change something and send patches:
25 *  read README and HACKING! There a addition information on
26 *  the license of this document you need to read before you send
27 *  any patches.
28 *
29 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
30 *  or libpulse*:
31 *  The libs libroaresd, libroararts and libroarpulse link this lib
32 *  and are therefore GPL. Because of this it may be illigal to use
33 *  them with any software that uses libesd, libartsc or libpulse*.
34 */
35
36#include "libroar.h"
37
38struct roar_subscriber {
39 uint32_t flags;
40 uint32_t event;
41 int emitter;
42 int target;
43 int target_type;
44 void (*cb)(struct roar_notify_core * core, struct roar_event * event, void * userdata);
45 void * userdata;
46 size_t refc;
47 unsigned int hash;
48// struct roar_subscriber * prev;
49 struct roar_subscriber * next;
50};
51
52struct roar_notify_core {
53 size_t refc;
54 size_t listc;
55 struct roar_subscriber ** lists;
56 void (*proxy)(struct roar_notify_core * core, struct roar_event * event, void * userdata);
57 void * proxy_userdata;
58};
59
60static struct roar_notify_core * _libroar_notify_core = NULL;
61
62#define _CKRCORE(ret) if ( core == NULL ) { if ( _libroar_notify_core == NULL ) { roar_errno = ROAR_ERROR_INVAL; return (ret); } else { core = _libroar_notify_core; } }
63#define _CKICORE() _CKRCORE(-1)
64
65static unsigned int _hash_event (struct roar_notify_core * core, struct roar_event * event) {
66 unsigned int hash = 0;
67 unsigned int mask = core->listc - 1;
68
69 hash ^= event->event >>  0;
70 hash ^= event->event >>  8;
71 hash ^= event->event >> 16;
72 hash ^= event->event >> 24;
73
74 return hash & mask;
75}
76
77struct roar_notify_core * roar_notify_core_new(ssize_t lists) {
78 struct roar_notify_core * core = NULL;
79
80 switch (lists) {
81  case    1:
82  case    2:
83  case    4:
84  case    8:
85  case   16:
86  case   32:
87  case   64:
88  case  128:
89  case  256:
90  case  512:
91  case 1024:
92    // they all are ok.
93   break;
94  case  -1:
95    // handle defult:
96    lists = 16;
97   break;
98  default:
99    roar_errno = ROAR_ERROR_INVAL;
100    return NULL;
101   break;
102 }
103
104 if ( (core = roar_mm_malloc(sizeof(struct roar_notify_core))) == NULL ) {
105  return NULL;
106 }
107
108 memset(core, 0, sizeof(struct roar_notify_core));
109
110 core->refc  = 1;
111 core->listc = lists;
112 core->lists = roar_mm_malloc(lists*sizeof(struct roar_subscriber *));
113 core->proxy = NULL;
114 core->proxy_userdata = NULL;
115
116 if ( core->lists == NULL ) {
117  roar_mm_free(core);
118  return NULL;
119 }
120
121 memset(core->lists, 0, lists*sizeof(struct roar_subscriber *));
122
123 return core;
124}
125
126int roar_notify_core_ref(struct roar_notify_core * core) {
127 _CKICORE();
128
129 core->refc++;
130
131 return 0;
132}
133
134int roar_notify_core_unref(struct roar_notify_core * core) {
135 struct roar_subscriber * cur, * next;
136 size_t i;
137
138 _CKICORE();
139
140 if ( core->refc == 0 ) {
141  ROAR_ERR("roar_notify_core_unref(core=%p): refc is zero, must be greater zero. resolving by setting to one.", core);
142  core->refc = 1;
143 }
144
145 core->refc--;
146
147 if ( core->refc > 0 ) {
148  return 0;
149 }
150
151 for (i = 0; i < core->listc; i++) {
152  cur = core->lists[i];
153  while (cur != NULL) {
154   next = cur->next;
155
156   roar_mm_free(cur);
157
158   cur = next;
159  }
160 }
161
162 roar_mm_free(core->lists);
163 roar_mm_free(core);
164 return 0;
165}
166
167int roar_notify_core_new_global(ssize_t lists) {
168 if ( _libroar_notify_core != NULL ) {
169  roar_errno = ROAR_ERROR_INVAL;
170  return -1;
171 }
172
173 if ( (_libroar_notify_core = roar_notify_core_new(lists)) == NULL )
174  return -1;
175
176 return 0;
177}
178
179int roar_notify_core_register_proxy(struct roar_notify_core * core, void (*cb)(struct roar_notify_core * core, struct roar_event * event, void * userdata), void * userdata) {
180 _CKICORE();
181
182 core->proxy = cb;
183 core->proxy_userdata = userdata;
184
185 return 0;
186}
187
188
189struct roar_subscriber * roar_notify_core_subscribe(struct roar_notify_core * core, struct roar_event * event, void (*cb)(struct roar_notify_core * core, struct roar_event * event, void * userdata), void * userdata) {
190 struct roar_subscriber * subs = NULL;
191 struct roar_subscriber * cur, * old;
192
193 ROAR_DBG("roar_notify_core_subscribe(core=%p, event=%p, cb=%p, userdata=%p) = ?", core, event, cb, userdata);
194
195 _CKRCORE(NULL);
196
197 if ( event == NULL || cb == NULL ) {
198  ROAR_DBG("roar_notify_core_subscribe(core=%p, event=%p, cb=%p, userdata=%p) = NULL // errno = EINVAL", core, event, cb, userdata);
199  roar_errno = ROAR_ERROR_INVAL;
200  return NULL;
201 }
202
203 if ( (subs = roar_mm_malloc(sizeof(struct roar_subscriber))) == NULL ) {
204  ROAR_DBG("roar_notify_core_subscribe(core=%p, event=%p, cb=%p, userdata=%p) = NULL // errno = ENOMEM?", core, event, cb, userdata);
205  return NULL;
206 }
207
208 memset(subs, 0, sizeof(struct roar_subscriber));
209
210 subs->flags       = 0;
211 subs->event       = event->event;
212 subs->emitter     = event->emitter;
213 subs->target      = event->target;
214 subs->target_type = event->target_type;
215 subs->cb          = cb;
216 subs->userdata    = userdata;
217 subs->refc        = 1;
218 subs->hash        = _hash_event(core, event);
219 subs->next        = NULL;
220
221 if ( (cur = core->lists[subs->hash]) == NULL ) {
222  core->lists[subs->hash] = subs;
223 } else {
224  old = cur;
225  while (cur != NULL) {
226   old = cur;
227   cur = cur->next;
228  }
229
230  old->next = subs;
231 }
232
233 ROAR_DBG("roar_notify_core_subscribe(core=%p, event=%p, cb=%p, userdata=%p) = %p", core, event, cb, userdata, subs);
234 return subs;
235}
236
237int roar_notify_core_unsubscribe(struct roar_notify_core * core, struct roar_subscriber * subscriber) {
238 struct roar_subscriber * cur, * old;
239
240 _CKICORE();
241
242 if ( subscriber == NULL ) {
243  roar_errno = ROAR_ERROR_INVAL;
244  return -1;
245 }
246
247 if ( (cur = core->lists[subscriber->hash]) == subscriber ) {
248  core->lists[subscriber->hash] = core->lists[subscriber->hash]->next;
249 } else {
250  old = NULL;
251  while (cur != NULL && cur != subscriber ) {
252   old = cur;
253   cur = cur->next;
254  }
255
256  if ( cur != subscriber )
257   return -1;
258
259  old->next = cur->next;
260  roar_mm_free(cur);
261 }
262
263 return 0;
264}
265
266int roar_notify_core_emit(struct roar_notify_core * core, struct roar_event * event) {
267 struct roar_subscriber * cur;
268
269 _CKICORE();
270
271 if ( event == NULL ) {
272  roar_errno = ROAR_ERROR_INVAL;
273  return -1;
274 }
275
276 if ( core->proxy != NULL && !(event->flags & ROAR_EVENT_FLAG_PROXYEVENT) ) {
277  core->proxy(core, event, core->proxy_userdata);
278 }
279
280 cur = core->lists[_hash_event(core, event)];
281 ROAR_DBG("roar_notify_core_emit(core=%p, event=%p): cur=%p", core, event, cur);
282
283 while (cur != NULL) {
284  ROAR_DBG("roar_notify_core_emit(core=%p, event=%p): cur=%p", core, event, cur);
285
286  // test if we can skip this one:
287  if ( !( (cur->event       == ROAR_NOTIFY_SPECIAL || cur->event       == event->event)   &&
288          (cur->emitter     == -1                  || cur->emitter     == event->emitter) &&
289          (cur->target      == -1                  || cur->target      == event->target)  &&
290          (cur->target_type == -1                  || cur->target_type == event->target_type)
291        ) ) {
292   cur = cur->next;
293   continue;
294  }
295
296  if ( cur->cb == NULL ) {
297   ROAR_ERR("roar_notify_core_emit(core=%p, event=%p): cur=%p, cb is set NULL, bad.", core, event, cur);
298  } else {
299   cur->cb(core, event, cur->userdata);
300  }
301  cur = cur->next;
302 }
303
304 return 0;
305}
306
307//ll
Note: See TracBrowser for help on using the repository browser.