Пример #1
0
void
signal_object_emit(lua_State *L, signal_array_t *arr, const char *name, int nargs)
{
    signal_t *sigfound = signal_array_getbyid(arr,
                                              a_strhash((const unsigned char *) name));

    if(sigfound)
    {
        int nbfunc = sigfound->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. */
        foreach(func, sigfound->sigfuncs)
            luaA_object_push(L, *func);

        for(int i = 0; i < nbfunc; i++)
        {
            /* push all args */
            for(int 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);
            luaA_dofunction(L, nargs, 0);
        }
    } else
        luaA_warn(L, "Trying to emit unknown signal '%s'", name);

    /* remove args */
    lua_pop(L, nargs);
}
Пример #2
0
/** Send fake events. Usually the current focused client will get it.
 * \param L The Lua VM state.
 * \return The number of element pushed on stack.
 * \luastack
 * \lparam The event type: key_press, key_release, button_press, button_release
 * or motion_notify.
 * \lparam The detail: in case of a key event, this is the keycode to send, in
 * case of a button event this is the number of the button. In case of a motion
 * event, this is a boolean value which if true make the coordinates relatives.
 * \lparam In case of a motion event, this is the X coordinate.
 * \lparam In case of a motion event, this is the Y coordinate.
 * If not specified, the current one is used.
 */
static int
luaA_root_fake_input(lua_State *L)
{
    if(!globalconf.have_xtest)
    {
        luaA_warn(L, "XTest extension is not available, cannot fake input.");
        return 0;
    }

    const char *stype = luaL_checkstring(L, 1);
    uint8_t type, detail;
    int x = 0, y = 0;

    if (A_STREQ(stype, "key_press"))
    {
        type = XCB_KEY_PRESS;
        if(lua_type(L, 2) == LUA_TSTRING) {
            detail = _string_to_key_code(lua_tostring(L, 2)); /* keysym */
        } else {
            detail = luaL_checknumber(L, 2); /* keycode */
        }
    }
    else if(A_STREQ(stype, "key_release"))
    {
        type = XCB_KEY_RELEASE;
        if(lua_type(L, 2) == LUA_TSTRING) {
            detail = _string_to_key_code(lua_tostring(L, 2)); /* keysym */
        } else {
            detail = luaL_checknumber(L, 2); /* keycode */
        }
    }
    else if(A_STREQ(stype, "button_press"))
    {
        type = XCB_BUTTON_PRESS;
        detail = luaL_checknumber(L, 2); /* button number */
    }
    else if(A_STREQ(stype, "button_release"))
    {
        type = XCB_BUTTON_RELEASE;
        detail = luaL_checknumber(L, 2); /* button number */
    }
    else if(A_STREQ(stype, "motion_notify"))
    {
        type = XCB_MOTION_NOTIFY;
        detail = luaA_checkboolean(L, 2); /* relative to the current position or not */
        x = luaL_checknumber(L, 3);
        y = luaL_checknumber(L, 4);
    }
    else
        return 0;

    xcb_test_fake_input(globalconf.connection,
                        type,
                        detail,
                        XCB_CURRENT_TIME,
                        XCB_NONE,
                        x, y,
                        0);
    return 0;
}
Пример #3
0
/** Grab the mouse pointer and list motions, calling callback function at each
 * motion. The callback function must return a boolean value: true to
 * continue grabbing, false to stop.
 * The function is called with one argument:
 * a table containing modifiers pointer coordinates.
 *
 * @param func A callback function as described above.
 * @param cursor The name of a X cursor to use while grabbing.
 * @function run
 */
static int
luaA_mousegrabber_run(lua_State *L)
{
    if(globalconf.mousegrabber != LUA_REFNIL)
        luaL_error(L, "mousegrabber already running");

    uint16_t cfont = xcursor_font_fromstr(luaL_checkstring(L, 2));

    if(cfont)
    {
        xcb_cursor_t cursor = xcursor_new(globalconf.cursor_ctx, cfont);

        luaA_registerfct(L, 1, &globalconf.mousegrabber);

        if(!mousegrabber_grab(cursor))
        {
            luaA_unregister(L, &globalconf.mousegrabber);
            luaL_error(L, "unable to grab mouse pointer");
        }
    }
    else
        luaA_warn(L, "invalid cursor");

    return 0;
}
Пример #4
0
/** Send fake events. Usually the current focused client will get it.
 * \param L The Lua VM state.
 * \return The number of element pushed on stack.
 * \luastack
 * \lparam The event type: key_press, key_release, button_press, button_release
 * or motion_notify.
 * \lparam The detail: in case of a key event, this is the keycode to send, in
 * case of a button event this is the number of the button. In case of a motion
 * event, this is a boolean value which if true make the coordinates relatives.
 * \lparam In case of a motion event, this is the X coordinate.
 * \lparam In case of a motion event, this is the Y coordinate.
 * \lparam In case of a motion event, this is the screen number to move on.
 * If not specified, the current one is used.
 */
static int
luaA_root_fake_input(lua_State *L)
{
    if(!globalconf.have_xtest)
    {
        luaA_warn(L, "XTest extension is not available, cannot fake input.");
        return 0;
    }

    size_t tlen;
    const char *stype = luaL_checklstring(L, 1, &tlen);
    uint8_t type, detail;
    int x = 0, y = 0;
    xcb_window_t root = XCB_NONE;

    switch(a_tokenize(stype, tlen))
    {
      case A_TK_KEY_PRESS:
        type = XCB_KEY_PRESS;
        detail = luaL_checknumber(L, 2); /* keycode */
        break;
      case A_TK_KEY_RELEASE:
        type = XCB_KEY_RELEASE;
        detail = luaL_checknumber(L, 2); /* keycode */
        break;
      case A_TK_BUTTON_PRESS:
        type = XCB_BUTTON_PRESS;
        detail = luaL_checknumber(L, 2); /* button number */
        break;
      case A_TK_BUTTON_RELEASE:
        type = XCB_BUTTON_RELEASE;
        detail = luaL_checknumber(L, 2); /* button number */
        break;
      case A_TK_MOTION_NOTIFY:
        type = XCB_MOTION_NOTIFY;
        detail = luaA_checkboolean(L, 2); /* relative to the current position or not */
        x = luaL_checknumber(L, 3);
        y = luaL_checknumber(L, 4);
        if(lua_gettop(L) == 5 && !globalconf.xinerama_is_active)
        {
            int screen = luaL_checknumber(L, 5) - 1;
            luaA_checkscreen(screen);
            root = xutil_screen_get(globalconf.connection, screen)->root;
        }
        break;
      default:
        return 0;
    }

    xcb_test_fake_input(globalconf.connection,
                        type,
                        detail,
                        XCB_CURRENT_TIME,
                        root,
                        x, y,
                        0);
    return 0;
}
Пример #5
0
static int
luaA_timer_stop(lua_State *L)
{
    atimer_t *timer = luaA_checkudata(L, 1, &timer_class);
    if(timer->started)
    {
        g_source_remove(timer->source_id);
        luaA_object_unref(L, timer);
        timer->started = false;
    }
    else
        luaA_warn(L, "timer not started");
    return 0;
}
Пример #6
0
static int
luaA_timer_start(lua_State *L)
{
    atimer_t *timer = luaA_checkudata(L, 1, &timer_class);
    if(timer->started)
        luaA_warn(L, "timer already started");
    else
    {
        luaA_object_ref(L, 1);
        timer->started = true;
        timer->source_id = g_timeout_add(timer->timeout * 1000, timer_emit_signal, timer);
    }
    return 0;
}
Пример #7
0
/** Set the window type.
 * \param L The Lua VM state.
 * \param window The window object.
 * \return The number of elements pushed on stack.
 */
int
luaA_window_set_type(lua_State *L, window_t *w)
{
    window_type_t type;
    const char *buf = luaL_checkstring(L, -1);

    if (A_STREQ(buf, "desktop"))
        type = WINDOW_TYPE_DESKTOP;
    else if(A_STREQ(buf, "dock"))
        type = WINDOW_TYPE_DOCK;
    else if(A_STREQ(buf, "splash"))
        type = WINDOW_TYPE_SPLASH;
    else if(A_STREQ(buf, "dialog"))
        type = WINDOW_TYPE_DIALOG;
    else if(A_STREQ(buf, "menu"))
        type = WINDOW_TYPE_MENU;
    else if(A_STREQ(buf, "toolbar"))
        type = WINDOW_TYPE_TOOLBAR;
    else if(A_STREQ(buf, "utility"))
        type = WINDOW_TYPE_UTILITY;
    else if(A_STREQ(buf, "dropdown_menu"))
        type = WINDOW_TYPE_DROPDOWN_MENU;
    else if(A_STREQ(buf, "popup_menu"))
        type = WINDOW_TYPE_POPUP_MENU;
    else if(A_STREQ(buf, "tooltip"))
        type = WINDOW_TYPE_TOOLTIP;
    else if(A_STREQ(buf, "notification"))
        type = WINDOW_TYPE_NOTIFICATION;
    else if(A_STREQ(buf, "combo"))
        type = WINDOW_TYPE_COMBO;
    else if(A_STREQ(buf, "dnd"))
        type = WINDOW_TYPE_DND;
    else if(A_STREQ(buf, "normal"))
        type = WINDOW_TYPE_NORMAL;
    else
    {
        luaA_warn(L, "Unknown window type '%s'", buf);
        return 0;
    }

    if(w->type != type)
    {
        w->type = type;
        if(w->window != XCB_WINDOW_NONE)
            ewmh_update_window_type(w->window, window_translate_type(w->type));
        luaA_object_emit_signal(L, -3, "property::type", 0);
    }

    return 0;
}
Пример #8
0
/** Set the root cursor.
 * \param L The Lua VM state.
 * \return The number of element pushed on stack.
 * \luastack
 * \lparam A X cursor name.
 */
static int
luaA_root_cursor(lua_State *L)
{
    const char *cursor_name = luaL_checkstring(L, 1);
    uint16_t cursor_font = xcursor_font_fromstr(cursor_name);

    if(cursor_font)
    {
        uint32_t change_win_vals[] = { xcursor_new(globalconf.connection, cursor_font) };

        xcb_change_window_attributes(globalconf.connection,
                                     globalconf.screen->root,
                                     XCB_CW_CURSOR,
                                     change_win_vals);
    }
    else
        luaA_warn(L, "invalid cursor %s", cursor_name);

    return 0;
}
Пример #9
0
/** Set the root cursor.
 * \param L The Lua VM state.
 * \return The number of element pushed on stack.
 * \luastack
 * \lparam A X cursor name.
 */
static int
luaA_root_cursor(lua_State *L)
{
    const char *cursor_name = luaL_checkstring(L, 1);
    uint16_t cursor_font = xcursor_font_fromstr(cursor_name);

    if(cursor_font)
    {
        uint32_t change_win_vals[] = { xcursor_new(globalconf.connection, cursor_font) };

        for(int screen_nbr = 0;
            screen_nbr < xcb_setup_roots_length(xcb_get_setup(globalconf.connection));
            screen_nbr++)
            xcb_change_window_attributes(globalconf.connection,
                                         xutil_screen_get(globalconf.connection, screen_nbr)->root,
                                         XCB_CW_CURSOR,
                                         change_win_vals);
    }
    else
        luaA_warn(L, "invalid cursor %s", cursor_name);

    return 0;
}
Пример #10
0
/** Tag newindex.
 * \param L The Lua VM state.
 * \return The number of elements pushed on stack.
 */
static int
luaA_tag_newindex(lua_State *L)
{
    size_t len;
    tag_t **tag = luaA_checkudata(L, 1, "tag");
    const char *buf, *attr = luaL_checklstring(L, 2, &len);
    double d;
    int i, screen;
    layout_t *l;

    switch(a_tokenize(attr, len))
    {
      case A_TK_NAME:
        buf = luaL_checklstring(L, 3, &len);
        p_delete(&(*tag)->name);
        a_iso2utf8(&(*tag)->name, buf, len);
        break;
      case A_TK_SCREEN:
        if(!lua_isnil(L, 3))
        {
            screen = luaL_checknumber(L, 3) - 1;
            luaA_checkscreen(screen);
        }
        else
            screen = SCREEN_UNDEF;

        if((*tag)->screen != SCREEN_UNDEF)
            tag_remove_from_screen(*tag);

        if(screen != SCREEN_UNDEF)
            tag_append_to_screen(*tag, &globalconf.screens[screen]);
        break;
      case A_TK_LAYOUT:
        buf = luaL_checkstring(L, 3);
        l = name_func_lookup(buf, LayoutList);
        if(l)
            (*tag)->layout = l;
        else
        {
            luaA_warn(L, "unknown layout: %s", buf);
            return 0;
        }
        break;
      case A_TK_SELECTED:
        if((*tag)->screen != SCREEN_UNDEF)
            tag_view(*tag, luaA_checkboolean(L, 3));
        return 0;
      case A_TK_MWFACT:
        d = luaL_checknumber(L, 3);
        if(d > 0 && d < 1)
            (*tag)->mwfact = d;
        else
        {
            luaA_warn(L, "bad value, must be between 0 and 1");
            return 0;
        }
        break;
      case A_TK_NMASTER:
        i = luaL_checknumber(L, 3);
        if(i >= 0)
            (*tag)->nmaster = i;
        else
        {
            luaA_warn(L, "bad value, must be greater than 0");
            return 0;
        }
        break;
      case A_TK_NCOL:
        i = luaL_checknumber(L, 3);
        if(i >= 1)
            (*tag)->ncol = i;
        else
        {
            luaA_warn(L, "bad value, must be greater than 1");
            return 0;
        }
        break;
      default:
        return 0;
    }

    if((*tag)->screen != SCREEN_UNDEF && (*tag)->selected)
        globalconf.screens[(*tag)->screen].need_arrange = true;

    return 0;
}
Пример #11
0
static void
luaA_keystore(lua_State *L, int ud, const char *str, ssize_t len)
{
    if(len <= 0 || !str)
        return;

    keyb_t *key = luaA_checkudata(L, ud, &key_class);

    if(len == 1)
    {
        key->keycode = 0;
        key->keysym = str[0];
    }
    else if(str[0] == '#')
    {
        key->keycode = atoi(str + 1);
        key->keysym = 0;
    }
    else
    {
        key->keycode = 0;

        if((key->keysym = XStringToKeysym(str)) == NoSymbol )
        {
            glong length;
            gunichar unicode;

            if(!g_utf8_validate(str, -1, NULL))
            {
                luaA_warn(L, "failed to convert \"%s\" into keysym (invalid UTF-8 string)", str);
                return;
            }

            length = g_utf8_strlen(str, -1); /* This function counts combining characters. */
            if(length <= 0)
            {
                luaA_warn(L, "failed to convert \"%s\" into keysym (empty UTF-8 string)", str);
                return;
            }
            else if(length > 1)
            {
                gchar *composed = g_utf8_normalize(str, -1, G_NORMALIZE_DEFAULT_COMPOSE);
                if(g_utf8_strlen(composed, -1) != 1)
                {
                    p_delete(&composed);
                    luaA_warn(L, "failed to convert \"%s\" into keysym (failed to compose a single character)", str);
                    return;
                }
                unicode = g_utf8_get_char(composed);
                p_delete(&composed);
            }
            else
                unicode = g_utf8_get_char(str);

            if(unicode == (gunichar)-1 || unicode == (gunichar)-2)
            {
                luaA_warn(L, "failed to convert \"%s\" into keysym (neither keysym nor single unicode)", str);
                return;
            }

            /* Unicode-to-Keysym Conversion
             *
             * http://www.x.org/releases/X11R7.7/doc/xproto/x11protocol.html#keysym_encoding
             */
            if(unicode <= 0x0ff)
                key->keysym = unicode;
            else if(unicode >= 0x100 && unicode <= 0x10ffff)
                key->keysym = unicode | (1 << 24);
            else
            {
                luaA_warn(L, "failed to convert \"%s\" into keysym (unicode out of range): \"%u\"", str, unicode);
                return;
            }
        }
    }

    luaA_object_emit_signal(L, ud, "property::key", 0);
}