diff options
Diffstat (limited to 'pysignals.c')
-rw-r--r-- | pysignals.c | 132 |
1 files changed, 104 insertions, 28 deletions
diff --git a/pysignals.c b/pysignals.c index fb4a3d9..58cc6d4 100644 --- a/pysignals.c +++ b/pysignals.c @@ -14,20 +14,20 @@ * scripts can no longer bind to it. */ -//FIXME: does not handle binding of signals with varying <cmd> text - typedef struct _PY_SIGNAL_SPEC_REC { char *name; char *arglist; - int id; int refcount; int dynamic; + int is_var; /* is this entry a prefix for a variable signal? */ } PY_SIGNAL_SPEC_REC; #include "pysigmap.h" +/* hashtable for normal signals, tree for variable signal prefixes. */ static GHashTable *py_sighash = NULL; +static GTree *py_sigtree = NULL; static void py_run_handler(PY_SIGNAL_REC *rec, void **args); static void py_sig_proxy(void *p1, void *p2, void *p3, void *p4, void *p5, void *p6); @@ -39,6 +39,9 @@ static void py_signal_rec_destroy(PY_SIGNAL_REC *sig); static PyObject *py_mkstrlist(void *iobj); static PyObject *py_i2py(char code, void *iobj); static void py_getstrlist(GList **list, PyObject *pylist); +static int precmp(const char *spec, const char *test); +static PY_SIGNAL_SPEC_REC *py_signal_lookup(const char *name); +static void py_signal_remove(PY_SIGNAL_SPEC_REC *sig); PY_SIGNAL_REC *pysignals_command_bind(const char *cmd, PyObject *func, const char *category, int priority) @@ -56,18 +59,21 @@ PY_SIGNAL_REC *pysignals_command_bind(const char *cmd, PyObject *func, PY_SIGNAL_REC *pysignals_signal_add(const char *signal, PyObject *func, int priority) { PY_SIGNAL_REC *rec = py_signal_rec_new(signal, func, NULL); - + char *name; + if (rec == NULL) return NULL; + + name = rec->command? rec->command : rec->signal->name; - signal_add_full_id(MODULE_NAME, priority, rec->signal->id, - (SIGNAL_FUNC)py_sig_proxy, rec); + signal_add_full(MODULE_NAME, priority, name, (SIGNAL_FUNC)py_sig_proxy, rec); return rec; } void pysignals_command_unbind(PY_SIGNAL_REC *rec) { + g_return_if_fail(rec->is_signal == FALSE); g_return_if_fail(rec->command != NULL); command_unbind_full(rec->command, (SIGNAL_FUNC)py_sig_proxy, rec); @@ -76,18 +82,22 @@ void pysignals_command_unbind(PY_SIGNAL_REC *rec) void pysignals_signal_remove(PY_SIGNAL_REC *rec) { - g_return_if_fail(rec->command == NULL); + char *name; - signal_remove_id(rec->signal->id, (SIGNAL_FUNC)py_sig_proxy, rec); + g_return_if_fail(rec->is_signal == TRUE); + + name = rec->command? rec->command : rec->signal->name; + + signal_remove_full(name, (SIGNAL_FUNC)py_sig_proxy, rec); py_signal_rec_destroy(rec); } void pysignals_remove_generic(PY_SIGNAL_REC *rec) { - if (rec->command) - pysignals_command_unbind(rec); - else + if (rec->is_signal) pysignals_signal_remove(rec); + else + pysignals_command_unbind(rec); } static PyObject *py_mkstrlist(void *iobj) @@ -303,16 +313,30 @@ static PY_SIGNAL_REC *py_signal_rec_new(const char *signal, PyObject *func, cons g_return_val_if_fail(func != NULL, NULL); - spec = g_hash_table_lookup(py_sighash, signal); + spec = py_signal_lookup(signal); if (!spec) return NULL; - rec = g_new(PY_SIGNAL_REC, 1); - rec->command = g_strdup(command); + rec = g_new0(PY_SIGNAL_REC, 1); rec->signal = spec; rec->handler = func; Py_INCREF(func); + if (command) + { + rec->is_signal = FALSE; + rec->command = g_strdup(command); + } + else + { + rec->is_signal = TRUE; + /* handle variable signal. requested signal will be longer than spec->name, ie + * signal = "var signal POOOM", spec->name = "var signal " + */ + if (strcmp(signal, spec->name) != 0) + rec->command = g_strdup(signal); + } + py_signal_ref(spec); return rec; @@ -329,7 +353,51 @@ static void py_signal_rec_destroy(PY_SIGNAL_REC *sig) static void py_signal_add(PY_SIGNAL_SPEC_REC *sig) { - g_hash_table_insert(py_sighash, sig->name, sig); + if (sig->is_var) + g_tree_insert(py_sigtree, sig->name, sig); + else + g_hash_table_insert(py_sighash, sig->name, sig); +} + +static void py_signal_remove(PY_SIGNAL_SPEC_REC *sig) +{ + int ret; + + if (sig->is_var) + g_tree_remove(py_sigtree, sig->name); + else + { + ret = g_hash_table_remove(py_sighash, sig->name); + g_return_if_fail(ret != FALSE); + } +} + +static int precmp(const char *spec, const char *test) +{ + //printf("precmp(spec,test) -> '%s', '%s'\n", spec, test); + + while (*spec == *test++) + if (*spec++ == '\0') + return 0; + + /* Variable event prefix matches (spec must never be empty string)*/ + /* precmp("var event ", "var event POOOM") -> 0 */ + if (*spec == '\0' && *(spec-1) == ' ') + return 0; + + return *(const unsigned char *)(test - 1) - *(const unsigned char *)spec; +} + +static PY_SIGNAL_SPEC_REC *py_signal_lookup(const char *name) +{ + PY_SIGNAL_SPEC_REC *ret; + + /* First check the normal signals hash, then check the variable signal prefixes in the tree */ + ret = g_hash_table_lookup(py_sighash, name); + if (!ret) + ret = g_tree_search(py_sigtree, (GCompareFunc)precmp, name); + + return ret; } static void py_signal_ref(PY_SIGNAL_SPEC_REC *sig) @@ -342,6 +410,7 @@ static void py_signal_ref(PY_SIGNAL_SPEC_REC *sig) static int py_signal_unref(PY_SIGNAL_SPEC_REC *sig) { g_return_val_if_fail(sig->refcount >= 1, 0); + g_return_val_if_fail(sig->refcount > 1 || !sig->dynamic, 0); sig->refcount--; @@ -349,7 +418,7 @@ static int py_signal_unref(PY_SIGNAL_SPEC_REC *sig) { if (sig->dynamic) { - g_hash_table_remove(py_sighash, sig->name); + py_signal_remove(sig); /* freeing name also takes care of the key */ g_free(sig->name); @@ -365,22 +434,22 @@ static int py_signal_unref(PY_SIGNAL_SPEC_REC *sig) return 0; } -/* returns 0 when signal already exists, but with different args */ +/* returns 0 when signal already exists, but with different args. */ int pysignals_register(const char *name, const char *arglist) { PY_SIGNAL_SPEC_REC *spec; - spec = g_hash_table_lookup(py_sighash, name); + spec = py_signal_lookup(name); if (!spec) { spec = g_new0(PY_SIGNAL_SPEC_REC, 1); + spec->is_var = name[strlen(name)-1] == ' '; /* trailing space means signal prefix */ spec->dynamic = 1; spec->refcount = 0; spec->name = g_strdup(name); spec->arglist = g_strdup(arglist); - spec->id = signal_get_uniq_id(name); - - g_hash_table_insert(py_sighash, spec->name, spec); + + py_signal_add(spec); } else if (strcmp(spec->arglist, arglist) != 0) return 0; @@ -395,7 +464,7 @@ int pysignals_unregister(const char *name) { PY_SIGNAL_SPEC_REC *spec; - spec = g_hash_table_lookup(py_sighash, name); + spec = py_signal_lookup(name); if (!spec) return 0; @@ -408,14 +477,15 @@ void pysignals_init(void) int i; g_return_if_fail(py_sighash == NULL); + g_return_if_fail(py_sigtree == NULL); - py_sighash = g_hash_table_new((GHashFunc)g_str_hash, (GCompareFunc)g_str_equal); + py_sigtree = g_tree_new((GCompareFunc)strcmp); + py_sighash = g_hash_table_new(g_str_hash, g_str_equal); for (i = 0; i < py_sigmap_len(); i++) { py_sigmap[i].refcount = 1; py_sigmap[i].dynamic = 0; - py_sigmap[i].id = signal_get_uniq_id(py_sigmap[i].name); py_signal_add(&py_sigmap[i]); } } @@ -425,16 +495,22 @@ static int py_check_sig(char *key, PY_SIGNAL_SPEC_REC *value, void *data) /* shouldn't need to deallocate any script recs -- all remaining at this point should not be dynamic. non dynamic signals should have no outstanding references */ - g_return_val_if_fail(value->dynamic == 0, TRUE); - g_return_val_if_fail(value->refcount == 1, TRUE); + g_return_val_if_fail(value->dynamic == 0, FALSE); + g_return_val_if_fail(value->refcount == 1, FALSE); - return TRUE; + return FALSE; } void pysignals_deinit(void) { g_return_if_fail(py_sighash != NULL); - g_hash_table_foreach_remove(py_sighash, (GHRFunc)py_check_sig, NULL); + g_return_if_fail(py_sigtree != NULL); + + g_tree_foreach(py_sigtree, (GTraverseFunc)py_check_sig, NULL); + g_hash_table_foreach_remove(py_sighash, (GHRFunc)py_check_sig, NULL); + + g_tree_destroy(py_sigtree); g_hash_table_destroy(py_sighash); + py_sigtree = NULL; py_sighash = NULL; } |