nkeynes@678 | 1 | /**
|
nkeynes@1021 | 2 | * $Id$
|
nkeynes@678 | 3 | *
|
nkeynes@678 | 4 | * This file defines some useful generic macros for hooks
|
nkeynes@678 | 5 | *
|
nkeynes@678 | 6 | * Copyright (c) 2008 Nathan Keynes.
|
nkeynes@678 | 7 | *
|
nkeynes@678 | 8 | * This program is free software; you can redistribute it and/or modify
|
nkeynes@678 | 9 | * it under the terms of the GNU General Public License as published by
|
nkeynes@678 | 10 | * the Free Software Foundation; either version 2 of the License, or
|
nkeynes@678 | 11 | * (at your option) any later version.
|
nkeynes@678 | 12 | *
|
nkeynes@678 | 13 | * This program is distributed in the hope that it will be useful,
|
nkeynes@678 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nkeynes@678 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nkeynes@678 | 16 | * GNU General Public License for more details.
|
nkeynes@678 | 17 | */
|
nkeynes@678 | 18 |
|
nkeynes@678 | 19 | #ifndef lxdream_hook_H
|
nkeynes@678 | 20 | #define lxdream_hook_H 1
|
nkeynes@678 | 21 |
|
nkeynes@678 | 22 | #include <assert.h>
|
nkeynes@678 | 23 |
|
nkeynes@678 | 24 | /**
|
nkeynes@678 | 25 | * Hook functions are generally useful, so we'd let to limit the overhead (and
|
nkeynes@678 | 26 | * opportunity for stupid bugs) by minimizing the amount of code involved. Glib
|
nkeynes@678 | 27 | * has GHook (and of course signals), but they don't actually simplify anything
|
nkeynes@678 | 28 | * at this level.
|
nkeynes@678 | 29 | *
|
nkeynes@678 | 30 | * Hence, the gratuitous macro abuse here.
|
nkeynes@678 | 31 | *
|
nkeynes@678 | 32 | * Usage:
|
nkeynes@678 | 33 | *
|
nkeynes@678 | 34 | * In header file:
|
nkeynes@678 | 35 | *
|
nkeynes@678 | 36 | * DECLARE_HOOK( hook_name, hook_fn_type );
|
nkeynes@678 | 37 | *
|
nkeynes@678 | 38 | * In implementation file:
|
nkeynes@678 | 39 | *
|
nkeynes@678 | 40 | * DEFINE_HOOK( hook_name, hook_fn_type );
|
nkeynes@678 | 41 | *
|
nkeynes@678 | 42 | */
|
nkeynes@678 | 43 | #define DECLARE_HOOK( name, fn_type ) \
|
nkeynes@678 | 44 | void register_##name( fn_type fn, void *user_data ); \
|
nkeynes@968 | 45 | void unregister_##name( fn_type fn, void *user_data )
|
nkeynes@678 | 46 |
|
nkeynes@678 | 47 | #define FOREACH_HOOK( h, name ) struct name##_hook_struct *h; for( h = name##_hook_list; h != NULL; h = h->next )
|
nkeynes@678 | 48 |
|
nkeynes@678 | 49 | #define CALL_HOOKS( name, args... ) FOREACH_HOOK(h, name) { h->fn(args, h->user_data); }
|
nkeynes@678 | 50 |
|
nkeynes@678 | 51 | #define DEFINE_HOOK( name, fn_type ) \
|
nkeynes@678 | 52 | struct name##_hook_struct { \
|
nkeynes@678 | 53 | fn_type fn; \
|
nkeynes@678 | 54 | void *user_data; \
|
nkeynes@678 | 55 | struct name##_hook_struct *next; \
|
nkeynes@678 | 56 | } *name##_hook_list = NULL; \
|
nkeynes@678 | 57 | void register_##name( fn_type fn, void *user_data ) { \
|
nkeynes@678 | 58 | struct name##_hook_struct *h = malloc(sizeof(struct name##_hook_struct)); \
|
nkeynes@678 | 59 | assert(h != NULL); \
|
nkeynes@678 | 60 | h->fn = fn; \
|
nkeynes@678 | 61 | h->user_data = user_data; \
|
nkeynes@678 | 62 | h->next = name##_hook_list; \
|
nkeynes@678 | 63 | name##_hook_list = h; \
|
nkeynes@678 | 64 | } \
|
nkeynes@678 | 65 | void unregister_##name( fn_type fn, void *user_data ) { \
|
nkeynes@678 | 66 | struct name##_hook_struct *last = NULL, *h = name##_hook_list; \
|
nkeynes@678 | 67 | while( h != NULL ) { \
|
nkeynes@678 | 68 | if( h->fn == fn && h->user_data == user_data ) { \
|
nkeynes@678 | 69 | if( last == NULL ) { \
|
nkeynes@678 | 70 | name##_hook_list = h->next; \
|
nkeynes@678 | 71 | } else { \
|
nkeynes@678 | 72 | last->next = h->next; \
|
nkeynes@678 | 73 | } \
|
nkeynes@678 | 74 | free( h ); \
|
nkeynes@678 | 75 | } \
|
nkeynes@678 | 76 | last = h; \
|
nkeynes@678 | 77 | h = h->next; \
|
nkeynes@678 | 78 | }\
|
nkeynes@678 | 79 | }
|
nkeynes@678 | 80 |
|
nkeynes@678 | 81 |
|
nkeynes@681 | 82 | #endif /* !lxdream_hook_H */
|