/* 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; }
/* 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; }