Пример #1
0
/** The key press event handler.
 * \param ev The event.
 */
static void
event_handle_key(xcb_key_press_event_t *ev)
{
    lua_State *L = globalconf_get_lua_State();
    globalconf.timestamp = ev->time;

    if(globalconf.keygrabber != LUA_REFNIL)
    {
        if(keygrabber_handlekpress(L, ev))
        {
            lua_rawgeti(L, LUA_REGISTRYINDEX, globalconf.keygrabber);

            if(!luaA_dofunction(L, 3, 0))
            {
                warn("Stopping keygrabber.");
                luaA_keygrabber_stop(L);
            }
        }
    }
    else
    {
        /* get keysym ignoring all modifiers */
        xcb_keysym_t keysym = xcb_key_symbols_get_keysym(globalconf.keysyms, ev->detail, 0);
        client_t *c;
        if((c = client_getbywin(ev->event)) || (c = client_getbynofocuswin(ev->event)))
        {
            luaA_object_push(L, c);
            event_key_callback(ev, &c->keys, L, -1, 1, &keysym);
        }
        else
            event_key_callback(ev, &globalconf.keys, L, 0, 0, &keysym);
    }
}
Пример #2
0
/** Remove a tag from screen. Tag must be on a screen and have no clients.
 * \param tag The tag to remove.
 */
static void
tag_remove_from_screen(tag_t *tag)
{
    int screen = tag->screen;
    int phys_screen = screen_virttophys(tag->screen);
    tag_array_t *tags = &globalconf.screens[tag->screen].tags;

    for(int i = 0; i < tags->len; i++)
        if(tags->tab[i] == tag)
        {
            tag_array_take(tags, i);
            break;
        }
    ewmh_update_net_numbers_of_desktop(phys_screen);
    ewmh_update_net_desktop_names(phys_screen);
    ewmh_update_workarea(phys_screen);
    tag->screen = SCREEN_UNDEF;
    tag_unref(&tag);

    /* resave tag prop of all clients so the number of tag will be the
     * same */
    for(client_t *c = globalconf.clients; c; c = c->next)
        client_saveprops_tags(c);

    /* call hook */
    if(globalconf.hooks.tags != LUA_REFNIL)
    {
        lua_pushnumber(globalconf.L, screen + 1);
        luaA_dofunction(globalconf.L, globalconf.hooks.tags, 1, 0);
    }
}
Пример #3
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, (void *) *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);
        }
    }
    /* remove args */
    lua_pop(L, nargs);
}
Пример #4
0
/** Emit a signal to an object.
 * \param L The Lua VM state.
 * \param oud The object index on the stack.
 * \param name The name of the signal.
 * \param nargs The number of arguments to pass to the called functions.
 */
void
luaA_object_emit_signal(lua_State *L, int oud,
                        const char *name, int nargs)
{
    int oud_abs = luaA_absindex(L, oud);
    lua_object_t *obj = lua_touserdata(L, oud);
    if(!obj)
        luaL_error(L, "trying to emit signal on non-object");
    signal_t *sigfound = signal_array_getbyid(&obj->signals,
                                              a_strhash((const unsigned char *) name));
    if(sigfound)
    {
        int nbfunc = sigfound->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. */
        foreach(func, sigfound->sigfuncs)
            luaA_object_push_item(L, oud_abs, (void *) *func);

        for(int i = 0; i < nbfunc; i++)
        {
            /* push object */
            lua_pushvalue(L, oud_abs);
            /* push all args */
            for(int 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);
            luaA_dofunction(L, nargs + 1, 0);
        }
    }
    lua_pop(L, nargs);
}
Пример #5
0
/** Remove a tag from screen. Tag must be on a screen and have no clients.
 * \param tag The tag to remove.
 */
static void
tag_remove_from_screen(tag_t *tag)
{
    int screen = tag->screen;
    int phys_screen = screen_virttophys(tag->screen);
    tag_array_t *tags = &globalconf.screens[tag->screen].tags;

    for(int i = 0; i < tags->len; i++)
        if(tags->tab[i] == tag)
        {
            tag_array_take(tags, i);
            break;
        }
    ewmh_update_net_numbers_of_desktop(phys_screen);
    ewmh_update_net_desktop_names(phys_screen);
    ewmh_update_workarea(phys_screen);
    tag->screen = SCREEN_UNDEF;

    /* call hook */
    if(globalconf.hooks.tags != LUA_REFNIL)
    {
        lua_pushnumber(globalconf.L, screen + 1);
        tag_push(globalconf.L, tag);
        lua_pushliteral(globalconf.L, "remove");
        luaA_dofunction(globalconf.L, globalconf.hooks.tags, 3, 0);
    }

    tag_unref(globalconf.L, tag);
}
Пример #6
0
/** Handle mouse button events.
 * \param c The client on which the event happened or NULL.
 * \param type Event type, press or release.
 * \param button Button number.
 * \param state Modkeys state.
 * \param buttons Buttons array to check for.
 */
static void
event_handle_mouse_button(client_t *c,
                          uint8_t type,
                          xcb_button_t button,
                          uint16_t state,
                          button_array_t *buttons)
{
    for(int i = 0; i < buttons->len; i++)
        if(button == buttons->tab[i]->button
           && state == buttons->tab[i]->mod)
            switch(type)
            {
              case XCB_BUTTON_PRESS:
                if(buttons->tab[i]->press != LUA_REFNIL)
                {
                    if(c)
                    {
                        client_push(globalconf.L, c);
                        luaA_dofunction(globalconf.L, buttons->tab[i]->press, 1, 0);
                    }
                    else
                        luaA_dofunction(globalconf.L, buttons->tab[i]->press, 0, 0);
                }
                break;
              case XCB_BUTTON_RELEASE:
                if(buttons->tab[i]->release != LUA_REFNIL)
                {
                    if(c)
                    {
                        client_push(globalconf.L, c);
                        luaA_dofunction(globalconf.L, buttons->tab[i]->release, 1, 0);
                    }
                    else
                        luaA_dofunction(globalconf.L, buttons->tab[i]->release, 0, 0);
                }
                break;
            }
}
Пример #7
0
/** Emit a signal.
 * @tparam string name A signal name.
 * @param[opt] ... Various arguments.
 * @function emit_signal
 */
void
luaA_object_emit_signal(lua_State *L, int oud,
                        const char *name, int nargs)
{
    int oud_abs = luaA_absindex(L, oud);
    lua_class_t *lua_class = luaA_class_get(L, oud);
    lua_object_t *obj = luaA_toudata(L, oud, lua_class);
    if(!obj) {
        luaA_warn(L, "Trying to emit signal '%s' on non-object", name);
        return;
    }
    else if(lua_class->checker && !lua_class->checker(obj)) {
        luaA_warn(L, "Trying to emit signal '%s' on invalid object", name);
        return;
    }
    signal_t *sigfound = signal_array_getbyid(&obj->signals,
                                              a_strhash((const unsigned char *) name));
    if(sigfound)
    {
        int nbfunc = sigfound->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. */
        foreach(func, sigfound->sigfuncs)
            luaA_object_push_item(L, oud_abs, *func);

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

    /* Then emit signal on the class */
    lua_pushvalue(L, oud);
    lua_insert(L, - nargs - 1);
    luaA_class_emit_signal(L, luaA_class_get(L, - nargs - 1), name, nargs + 1);
}
Пример #8
0
/** Tag a client with specified tag.
 * \param c the client to tag
 * \param t the tag to tag the client with
 */
void
tag_client(client_t *c, tag_t *t)
{
    /* don't tag twice */
    if(is_client_tagged(c, t))
        return;

    tag_ref(&t);
    client_array_append(&t->clients, c);
    client_saveprops_tags(c);
    client_need_arrange(c);
    /* call hook */
    if(globalconf.hooks.tagged != LUA_REFNIL)
    {
        luaA_client_userdata_new(globalconf.L, c);
        luaA_tag_userdata_new(globalconf.L, t);
        luaA_dofunction(globalconf.L, globalconf.hooks.tagged, 2, 0);
    }
}
Пример #9
0
/** Untag a client with specified tag.
 * \param c the client to tag
 * \param t the tag to tag the client with
 */
void
untag_client(client_t *c, tag_t *t)
{
    for(int i = 0; i < t->clients.len; i++)
        if(t->clients.tab[i] == c)
        {
            client_need_arrange(c);
            client_array_take(&t->clients, i);
            client_saveprops_tags(c);
            /* call hook */
            if(globalconf.hooks.tagged != LUA_REFNIL)
            {
                luaA_client_userdata_new(globalconf.L, c);
                luaA_tag_userdata_new(globalconf.L, t);
                luaA_dofunction(globalconf.L, globalconf.hooks.tagged, 2, 0);
            }
            tag_unref(&t);
            return;
        }
}
Пример #10
0
/** Untag a client with specified tag.
 * \param c the client to tag
 * \param t the tag to tag the client with
 */
void
untag_client(client_t *c, tag_t *t)
{
    for(int i = 0; i < t->clients.len; i++)
        if(t->clients.tab[i] == c)
        {
            client_need_arrange(c);
            client_array_take(&t->clients, i);
            ewmh_client_update_desktop(c);
            /* call hook */
            if(globalconf.hooks.tagged != LUA_REFNIL)
            {
                client_push(globalconf.L, c);
                tag_push(globalconf.L, t);
                luaA_dofunction(globalconf.L, globalconf.hooks.tagged, 2, 0);
            }
            tag_unref(globalconf.L, t);
            return;
        }
}
Пример #11
0
/** Tag a client with the tag on top of the stack.
 * \param c the client to tag
 */
void
tag_client(client_t *c)
{
    tag_t *t = tag_ref(globalconf.L);

    /* don't tag twice */
    if(is_client_tagged(c, t))
        return;

    client_array_append(&t->clients, c);
    ewmh_client_update_desktop(c);
    client_need_arrange(c);
    /* call hook */
    if(globalconf.hooks.tagged != LUA_REFNIL)
    {
        client_push(globalconf.L, c);
        tag_push(globalconf.L, t);
        luaA_dofunction(globalconf.L, globalconf.hooks.tagged, 2, 0);
    }
}
Пример #12
0
/** Handle an event with mouse grabber if needed
 * \param x The x coordinate.
 * \param y The y coordinate.
 * \param mask The mask buttons.
 * \return True if the event was handled.
 */
static bool
event_handle_mousegrabber(int x, int y, uint16_t mask)
{
    if(globalconf.mousegrabber != LUA_REFNIL)
    {
        lua_State *L = globalconf_get_lua_State();
        mousegrabber_handleevent(L, x, y, mask);
        lua_rawgeti(L, LUA_REGISTRYINDEX, globalconf.mousegrabber);
        if(!luaA_dofunction(L, 1, 1))
        {
            warn("Stopping mousegrabber.");
            luaA_mousegrabber_stop(L);
        } else {
            if(!lua_isboolean(L, -1) || !lua_toboolean(L, -1))
                luaA_mousegrabber_stop(L);
            lua_pop(L, 1);  /* pop returned value */
        }
        return true;
    }
    return false;
}
Пример #13
0
/** Append a tag which on top of the stack to a screen.
 * \param screen the screen id
 */
void
tag_append_to_screen(screen_t *s)
{
    int phys_screen = screen_virttophys(s->index);
    tag_t *tag = tag_ref(globalconf.L);

    tag->screen = s->index;
    tag_array_append(&s->tags, tag);
    ewmh_update_net_numbers_of_desktop(phys_screen);
    ewmh_update_net_desktop_names(phys_screen);
    ewmh_update_workarea(phys_screen);

    /* call hook */
    if(globalconf.hooks.tags != LUA_REFNIL)
    {
        lua_pushnumber(globalconf.L, s->index + 1);
        tag_push(globalconf.L, tag);
        lua_pushliteral(globalconf.L, "add");
        luaA_dofunction(globalconf.L, globalconf.hooks.tags, 3, 0);
    }
}
Пример #14
0
/** Append a tag to a screen.
 * \param tag the tag to append
 * \param screen the screen id
 */
void
tag_append_to_screen(tag_t *tag, screen_t *s)
{
    int phys_screen = screen_virttophys(s->index);

    tag->screen = s->index;
    tag_array_append(&s->tags, tag_ref(&tag));
    ewmh_update_net_numbers_of_desktop(phys_screen);
    ewmh_update_net_desktop_names(phys_screen);
    ewmh_update_workarea(phys_screen);

    /* resave tag prop of all clients so the number of tag will be the
     * same */
    for(client_t *c = globalconf.clients; c; c = c->next)
        client_saveprops_tags(c);

    /* call hook */
    if(globalconf.hooks.tags != LUA_REFNIL)
    {
        lua_pushnumber(globalconf.L, s->index + 1);
        luaA_dofunction(globalconf.L, globalconf.hooks.tags, 1, 0);
    }
}
Пример #15
0
/** Retrieve a list of widget geometries using a Lua layout function.
 * a table which contains the geometries is then pushed onto the stack
 * \param wibox The wibox.
 * \return True is everything is ok, false otherwise.
 */
static bool
widget_geometries(wibox_t *wibox)
{
    /* get the layout field of the widget table */
    if(wibox->widgets_table)
    {
        /* push wibox */
        luaA_object_push(globalconf.L, wibox);
        /* push widgets table */
        luaA_object_push_item(globalconf.L, -1, wibox->widgets_table);
        /* remove wibox */
        lua_remove(globalconf.L, -2);
        /* get layout field from the table */
        lua_getfield(globalconf.L, -1, "layout");
        /* remove the widget table */
        lua_remove(globalconf.L, -2);
    }
    else
        lua_pushnil(globalconf.L);

    /* if the layout field is a function */
    if(lua_isfunction(globalconf.L, -1))
    {
        /* Push 1st argument: wibox geometry */
        area_t geometry = wibox->geometry;
        geometry.x = 0;
        geometry.y = 0;
        /* we need to exchange the width and height of the wibox window if it
         * it is rotated, so the layout function doesn't need to care about that
         */
        if(wibox->orientation != East)
        {
            int i = geometry.height;
            geometry.height = geometry.width;
            geometry.width = i;
        }
        luaA_pusharea(globalconf.L, geometry);
        /* Push 2nd argument: widget table */
        luaA_object_push(globalconf.L, wibox);
        luaA_object_push_item(globalconf.L, -1, wibox->widgets_table);
        lua_remove(globalconf.L, -2);
        /* Push 3rd argument: wibox screen */
        lua_pushnumber(globalconf.L, screen_array_indexof(&globalconf.screens, wibox->screen));
        /* Re-push the layout function */
        lua_pushvalue(globalconf.L, -4);
        /* call the layout function with 3 arguments (wibox geometry, widget
         * table, screen) and wait for one result */
        if(!luaA_dofunction(globalconf.L, 3, 1))
            return false;

        /* Remove the left over layout function */
        lua_remove(globalconf.L, -2);
    }
    else
    {
        /* Remove the "nil function" */
        lua_pop(globalconf.L, 1);

        /* If no layout function has been specified, we just push a table with
         * geometries onto the stack. These geometries are nothing fancy, they
         * have x = y = 0 and their height and width set to the widgets demands
         * or the wibox size, depending on which is less.
         */

        widget_node_array_t *widgets = &wibox->widgets;
        widget_node_array_wipe(widgets);
        widget_node_array_init(widgets);

        /* push wibox */
        luaA_object_push(globalconf.L, wibox);
        /* push widgets table */
        luaA_object_push_item(globalconf.L, -1, wibox->widgets_table);
        /* remove wibox */
        lua_remove(globalconf.L, -2);
        luaA_table2widgets(globalconf.L, widgets);

        lua_newtable(globalconf.L);
        for(int i = 0; i < widgets->len; i++)
        {
            lua_pushnumber(globalconf.L, i + 1);
            widget_t *widget = widgets->tab[i].widget;
            lua_pushnumber(globalconf.L, screen_array_indexof(&globalconf.screens, wibox->screen));
            area_t geometry = widget->extents(globalconf.L, widget);
            lua_pop(globalconf.L, 1);
            geometry.x = geometry.y = 0;
            geometry.width = MIN(wibox->geometry.width, geometry.width);
            geometry.height = MIN(wibox->geometry.height, geometry.height);

            luaA_pusharea(globalconf.L, geometry);

            lua_settable(globalconf.L, -3);
        }
    }
    return true;
}
Пример #16
0
/** The button press event handler.
 * \param data The type of mouse event.
 * \param connection The connection to the X server.
 * \param ev The event.
 */
static int
event_handle_button(void *data, xcb_connection_t *connection, xcb_button_press_event_t *ev)
{
    int screen;
    const int nb_screen = xcb_setup_roots_length(xcb_get_setup(connection));
    client_t *c;
    wibox_t *wibox;

    /* ev->state is
     * button status (8 bits) + modifiers status (8 bits)
     * we don't care for button status that we get, especially on release, so
     * drop them */
    ev->state &= 0x00ff;

    event_handle_mousegrabber(ev->root_x, ev->root_y, ev->state);

    if((wibox = wibox_getbywin(ev->event))
       || (wibox = wibox_getbywin(ev->child)))
    {
        /* If the wibox is child, then x,y are
         * relative to root window */
        if(wibox->sw.window == ev->child)
        {
            ev->event_x -= wibox->sw.geometry.x;
            ev->event_y -= wibox->sw.geometry.y;
        }

        /* check if we match a binding on the wibox */
        button_array_t *b = &wibox->buttons;

        for(int i = 0; i < b->len; i++)
            if(ev->detail == b->tab[i]->button
               && ev->state == b->tab[i]->mod)
                switch(ev->response_type)
                {
                  case XCB_BUTTON_PRESS:
                    if(b->tab[i]->press != LUA_REFNIL)
                    {
                        wibox_push(globalconf.L, wibox);
                        luaA_dofunction(globalconf.L, b->tab[i]->press, 1, 0);
                    }
                    break;
                  case XCB_BUTTON_RELEASE:
                    if(b->tab[i]->release != LUA_REFNIL)
                    {
                        wibox_push(globalconf.L, wibox);
                        luaA_dofunction(globalconf.L, b->tab[i]->release, 1, 0);
                    }
                    break;
                }

        /* then try to match a widget binding */
        widget_t *w = widget_getbycoords(wibox->position, &wibox->widgets,
                                         wibox->sw.geometry.width,
                                         wibox->sw.geometry.height,
                                         &ev->event_x, &ev->event_y);
        if(w)
        {
            b = &w->buttons;

            for(int i = 0; i < b->len; i++)
                if(ev->detail == b->tab[i]->button
                   && ev->state == b->tab[i]->mod)
                    switch(ev->response_type)
                    {
                      case XCB_BUTTON_PRESS:
                        if(b->tab[i]->press != LUA_REFNIL)
                        {
                            wibox_push(globalconf.L, wibox);
                            luaA_dofunction(globalconf.L, b->tab[i]->press, 1, 0);
                        }
                        break;
                      case XCB_BUTTON_RELEASE:
                        if(b->tab[i]->release != LUA_REFNIL)
                        {
                            wibox_push(globalconf.L, wibox);
                            luaA_dofunction(globalconf.L, b->tab[i]->release, 1, 0);
                        }
                        break;
                    }
        }
        /* return even if no widget match */
        return 0;
    }
    else if((c = client_getbywin(ev->event)))
    {
        event_handle_mouse_button(c, ev->response_type, ev->detail, ev->state, &c->buttons);
        xcb_allow_events(globalconf.connection,
                         XCB_ALLOW_REPLAY_POINTER,
                         XCB_CURRENT_TIME);
    }
    else if(ev->child == XCB_NONE)
    {
        for(screen = 0; screen < nb_screen; screen++)
            if(xutil_screen_get(connection, screen)->root == ev->event)
            {
                event_handle_mouse_button(NULL, ev->response_type, ev->detail, ev->state, &globalconf.buttons);
                return 0;
            }
    }

    return 0;
}