コード例 #1
0
ファイル: luaobject.c プロジェクト: bradparks/luakit
/* 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;
}
コード例 #2
0
ファイル: luaobject.c プロジェクト: aidanholm/luakit
/* 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;
}