void signal_object_emit(lua_State *L, signal_t *signals, const gchar *name, gint nargs) { signal_array_t *sigfuncs = signal_lookup(signals, name, FALSE); if(sigfuncs) { gint nbfunc = sigfuncs->len; luaL_checkstack(L, lua_gettop(L) + nbfunc + nargs + 1, "too much signal"); /* Push all functions and then execute, because this list can change * while executing funcs. */ for(gint i = 0; i < nbfunc; i++) { luaH_object_push(L, sigfuncs->pdata[i]); } for(gint i = 0; i < nbfunc; i++) { /* push all args */ for(gint j = 0; j < nargs; j++) lua_pushvalue(L, - nargs - nbfunc + i); /* push first function */ lua_pushvalue(L, - nargs - nbfunc + i); /* remove this first function */ lua_remove(L, - nargs - nbfunc - 1 + i); luaH_dofunction(L, nargs, 0); } } /* remove args */ lua_pop(L, nargs); }
/* Emit a signal to an object. * `oud` is the object index on the stack. * `name` is the name of the signal. * `nargs` is the number of arguments to pass to the called functions. */ gint luaH_object_emit_signal(lua_State *L, gint oud, const gchar *name, gint nargs, gint nret) { gint ret, top, bot = lua_gettop(L) - nargs + 1; gint oud_abs = luaH_absindex(L, oud); lua_object_t *obj = lua_touserdata(L, oud); if(!obj) luaL_error(L, "trying to emit signal on non-object"); debug("emitting \"%s\" on %p with %d args and %d nret", name, obj, nargs, nret); signal_array_t *sigfuncs = signal_lookup(obj->signals, name, FALSE); if(sigfuncs) { guint nbfunc = sigfuncs->len; luaL_checkstack(L, lua_gettop(L) + nbfunc + nargs + 2, "too much signal"); /* Push all functions and then execute, because this list can change * while executing funcs. */ for(guint i = 0; i < nbfunc; i++) luaH_object_push_item(L, oud_abs, sigfuncs->pdata[i]); for(guint i = 0; i < nbfunc; i++) { /* push object */ lua_pushvalue(L, oud_abs); /* push all args */ for(gint j = 0; j < nargs; j++) lua_pushvalue(L, - nargs - nbfunc - 1 + i); /* push first function */ lua_pushvalue(L, - nargs - nbfunc - 1 + i); /* remove this first function */ lua_remove(L, - nargs - nbfunc - 2 + i); top = lua_gettop(L) - 2 - nargs; luaH_dofunction(L, nargs + 1, LUA_MULTRET); ret = lua_gettop(L) - top; /* Note that only if nret && ret will the signal execution stop */ if (ret) { /* Adjust the number of results to match nret (including 0) */ if (nret != LUA_MULTRET && ret != nret) { /* Pad with nils */ for (; ret < nret; ret++) lua_pushnil(L); /* Or truncate stack */ if (ret > nret) { lua_pop(L, ret - nret); ret = nret; } } /* Remove all signal functions and args from the stack */ for (gint i = bot; i < top; i++) lua_remove(L, bot); /* Return the number of returned arguments */ return ret; } } } lua_pop(L, nargs); return 0; }
/* Remove all signals of a given name to an object. * `oud` is the object index on the stack. * `name` is the name of the signal. */ void luaH_object_remove_signals(lua_State *L, gint oud, const gchar *name) { lua_object_t *obj = lua_touserdata(L, oud); signal_array_t *sigfuncs = signal_lookup(obj->signals, name); if (!sigfuncs) return; for (guint i = 0; i < sigfuncs->len; i++) { gpointer ref = g_ptr_array_index(sigfuncs, i); luaH_object_unref_item(L, oud, ref); } signals_remove(obj->signals, name); }
/* Emit a signal to an object. * `oud` is the object index on the stack. * `name` is the name of the signal. * `nargs` is the number of arguments to pass to the called functions. * `nret` is the number of return values this function pushes onto the stack. * A positive number means that any missing values will be padded with nil * and any superfluous values will be removed. * LUA_MULTRET means that any number of values is returned without any * adjustment. * 0 means that all return values are removed and that ALL handler functions are * executed. * Returns the number of return values pushed onto the stack. */ gint luaH_object_emit_signal(lua_State *L, gint oud, const gchar *name, gint nargs, gint nret) { gint ret, top, bot = lua_gettop(L) - nargs + 1; gint oud_abs = luaH_absindex(L, oud); lua_object_t *obj = lua_touserdata(L, oud); gchar *origin = luaH_callerinfo(L); debug("emit " ANSI_COLOR_BLUE "\"%s\"" ANSI_COLOR_RESET " on %p from " ANSI_COLOR_GREEN "%s" ANSI_COLOR_RESET " (%d args, %d nret)", name, obj, origin ? origin : "<GTK>", nargs, nret); g_free(origin); if(!obj) return luaL_error(L, "trying to emit " ANSI_COLOR_BLUE "\"%s\"" ANSI_COLOR_RESET " on non-object", name); signal_array_t *sigfuncs = signal_lookup(obj->signals, name); if (sigfuncs) { guint nbfunc = sigfuncs->len; luaL_checkstack(L, lua_gettop(L) + nbfunc + nargs + 2, "too many signal handlers; need a new implementation!"); /* Push all functions and then execute, because this list can change * while executing funcs. */ for (guint i = 0; i < nbfunc; i++) luaH_object_push_item(L, oud_abs, sigfuncs->pdata[i]); for (guint i = 0; i < nbfunc; i++) { /* push object */ lua_pushvalue(L, oud_abs); /* push all args */ for (gint j = 0; j < nargs; j++) lua_pushvalue(L, - nargs - nbfunc - 1 + i); /* push first function */ lua_pushvalue(L, - nargs - nbfunc - 1 + i); /* remove this first function */ lua_remove(L, - nargs - nbfunc - 2 + i); top = lua_gettop(L) - 2 - nargs; luaH_dofunction(L, nargs + 1, LUA_MULTRET); ret = lua_gettop(L) - top; /* Signal execution stops when: * - there's an expected number of return values (>0 or LUA_MULTRET) * - at least one return value (ret) * - the first return value is non-nil */ if (nret && ret && !lua_isnil(L, -ret)) { /* Adjust the number of results to match nret (including 0) */ if (nret != LUA_MULTRET && ret != nret) { /* Pad with nils */ for (; ret < nret; ret++) lua_pushnil(L); /* Or truncate stack */ if (ret > nret) { lua_pop(L, ret - nret); ret = nret; } } /* Remove all signal functions and args from the stack */ for (gint i = bot; i <= top; i++) lua_remove(L, bot); /* Return the number of returned arguments */ return ret; } else if (nret == 0) { /* ignore all return values */ lua_pop(L, ret); } } } lua_pop(L, nargs); return 0; }
/* Similar to signal_object_emit(), but allows you to choose the signal array * by name. */ gint signal_array_emit(lua_State *L, signal_t *signals, const gchar *array_name, const gchar *name, gint nargs, gint nret) { signal_array_t *sigfuncs = signal_lookup(signals, array_name); gchar *origin = luaH_callerinfo(L); debug("emit " ANSI_COLOR_BLUE "\"%s\"" ANSI_COLOR_RESET " on %p from " ANSI_COLOR_GREEN "%s" ANSI_COLOR_RESET " (%d args, %d nret)", name, signals, origin ? origin : "<GTK>", nargs, nret); g_free(origin); if (sigfuncs) { gint nbfunc = sigfuncs->len; luaL_checkstack(L, lua_gettop(L) + nbfunc + nargs + 1, "too many signal handlers; need a new implementation!"); /* Push all functions and then execute, because this list can change * while executing funcs. */ for (gint i = 0; i < nbfunc; i++) { luaH_object_push(L, sigfuncs->pdata[i]); } for (gint i = 0; i < nbfunc; i++) { gint stacksize = lua_gettop(L); /* push all args */ for (gint j = 0; j < nargs; j++) lua_pushvalue(L, - nargs - nbfunc + i); /* push first function */ lua_pushvalue(L, - nargs - nbfunc + i); /* remove this first function */ lua_remove(L, - nargs - nbfunc - 1 + i); luaH_dofunction(L, nargs, LUA_MULTRET); gint ret = lua_gettop(L) - stacksize + 1; /* Signal execution stops when: * - there's an expected number of return values (>0 or LUA_MULTRET) * - at least one return value (ret) * - the first return value is non-nil */ if (nret && ret && !lua_isnil(L, -ret)) { /* remove all args and functions */ for (gint j = 0; j < nargs + nbfunc - i - 1; j++) { lua_remove(L, - ret - 1); } /* Adjust the number of results to match nret */ if (nret != LUA_MULTRET && ret != nret) { /* Pad with nils */ for (; ret < nret; ret++) lua_pushnil(L); /* Or truncate stack */ if (ret > nret) { lua_pop(L, ret - nret); ret = nret; } } /* Return the number of returned arguments */ return ret; } else if (nret == 0) { /* ignore all return values */ lua_pop(L, ret); } } } /* remove args */ lua_pop(L, nargs); return 0; }