Beispiel #1
0
/** Grab key on the root windows.
 * \param k The keybinding.
 */
void
window_root_grabkey(keybinding_t *k)
{
    int phys_screen = 0;
    int nscreen = xcb_setup_roots_length(xcb_get_setup(globalconf.connection));
    xcb_screen_t *s;
    xcb_keycode_t kc;

    if((kc = k->keycode)
       || (k->keysym
           && (kc = xcb_key_symbols_get_keycode(globalconf.keysyms, k->keysym))))
        do
        {
            s = xutil_screen_get(globalconf.connection, phys_screen);
            xcb_grab_key(globalconf.connection, true, s->root,
                         k->mod, kc, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
            xcb_grab_key(globalconf.connection, true, s->root,
                         k->mod | XCB_MOD_MASK_LOCK, kc, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
            xcb_grab_key(globalconf.connection, true, s->root,
                         k->mod | globalconf.numlockmask, kc, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
            xcb_grab_key(globalconf.connection, true, s->root,
                         k->mod | globalconf.numlockmask | XCB_MOD_MASK_LOCK, kc, XCB_GRAB_MODE_ASYNC,
                         XCB_GRAB_MODE_ASYNC);
        phys_screen++;
        } while(phys_screen < nscreen);
}
Beispiel #2
0
/** Create a new Pango font.
 * \param fontname Pango fontname (e.g. [FAMILY-LIST] [STYLE-OPTIONS] [SIZE]).
 * \return A new font.
 */
font_t *
draw_font_new(const char *fontname)
{
    cairo_surface_t *surface;
    xcb_screen_t *s = xutil_screen_get(globalconf.connection, globalconf.default_screen);
    cairo_t *cr;
    PangoLayout *layout;
    font_t *font = p_new(font_t, 1);

    /* Create a dummy cairo surface, cairo context and pango layout in
     * order to get font informations */
    surface = cairo_xcb_surface_create(globalconf.connection,
                                       globalconf.default_screen,
                                       globalconf.screens.tab[0].visual,
                                       s->width_in_pixels,
                                       s->height_in_pixels);

    cr = cairo_create(surface);
    layout = pango_cairo_create_layout(cr);

    /* Get the font description used to set text on a PangoLayout */
    font->desc = pango_font_description_from_string(fontname);
    pango_layout_set_font_description(layout, font->desc);

    /* Get height */
    pango_layout_get_pixel_size(layout, NULL, &font->height);

    g_object_unref(layout);
    cairo_destroy(cr);
    cairo_surface_destroy(surface);

    return font;
}
Beispiel #3
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;
}
Beispiel #4
0
/** Initialize systray information in X.
 * \param phys_screen Physical screen.
 */
void
systray_init(int phys_screen)
{
    xcb_client_message_event_t ev;
    xcb_screen_t *xscreen = xutil_screen_get(globalconf.connection, phys_screen);
    char *atom_name;
    xcb_intern_atom_cookie_t atom_systray_q;
    xcb_intern_atom_reply_t *atom_systray_r;
    xcb_atom_t atom_systray;

    /* Send requests */
    if(!(atom_name = xcb_atom_name_by_screen("_NET_SYSTEM_TRAY", phys_screen)))
    {
        warn("error getting systray atom");
        return;
    }

    atom_systray_q = xcb_intern_atom_unchecked(globalconf.connection, false,
                                               a_strlen(atom_name), atom_name);

    p_delete(&atom_name);

    globalconf.screens[phys_screen].systray.window = xcb_generate_id(globalconf.connection);
    xcb_create_window(globalconf.connection, xscreen->root_depth,
                      globalconf.screens[phys_screen].systray.window,
                      xscreen->root,
                      -1, -1, 1, 1, 0,
                      XCB_COPY_FROM_PARENT, xscreen->root_visual, 0, NULL);

    /* Fill event */
    p_clear(&ev, 1);
    ev.response_type = XCB_CLIENT_MESSAGE;
    ev.window = xscreen->root;
    ev.format = 32;
    ev.type = MANAGER;
    ev.data.data32[0] = XCB_CURRENT_TIME;
    ev.data.data32[2] = globalconf.screens[phys_screen].systray.window;
    ev.data.data32[3] = ev.data.data32[4] = 0;

    if(!(atom_systray_r = xcb_intern_atom_reply(globalconf.connection, atom_systray_q, NULL)))
    {
        warn("error getting systray atom");
        return;
    }

    ev.data.data32[1] = atom_systray = atom_systray_r->atom;

    p_delete(&atom_systray_r);

    xcb_set_selection_owner(globalconf.connection,
                            globalconf.screens[phys_screen].systray.window,
                            atom_systray,
                            XCB_CURRENT_TIME);

    xcb_send_event(globalconf.connection, false, xscreen->root, 0xFFFFFF, (char *) &ev);
}
/** Register systray in X.
 * \param phys_screen Physical screen.
 */
void
systray_register(int phys_screen)
{
    xcb_client_message_event_t ev;
    xcb_screen_t *xscreen = xutil_screen_get(globalconf.connection, phys_screen);
    char *atom_name;
    xcb_intern_atom_cookie_t atom_systray_q;
    xcb_intern_atom_reply_t *atom_systray_r;
    xcb_atom_t atom_systray;

    /* Set registered even if it fails to don't try again unless forced */
    if(globalconf.screens.tab[phys_screen].systray.registered)
        return;
    globalconf.screens.tab[phys_screen].systray.registered = true;

    /* Send requests */
    if(!(atom_name = xcb_atom_name_by_screen("_NET_SYSTEM_TRAY", phys_screen)))
    {
        warn("error getting systray atom");
        return;
    }

    atom_systray_q = xcb_intern_atom_unchecked(globalconf.connection, false,
                                               a_strlen(atom_name), atom_name);

    p_delete(&atom_name);

    /* Fill event */
    p_clear(&ev, 1);
    ev.response_type = XCB_CLIENT_MESSAGE;
    ev.window = xscreen->root;
    ev.format = 32;
    ev.type = MANAGER;
    ev.data.data32[0] = XCB_CURRENT_TIME;
    ev.data.data32[2] = globalconf.screens.tab[phys_screen].systray.window;
    ev.data.data32[3] = ev.data.data32[4] = 0;

    if(!(atom_systray_r = xcb_intern_atom_reply(globalconf.connection, atom_systray_q, NULL)))
    {
        warn("error getting systray atom");
        return;
    }

    ev.data.data32[1] = atom_systray = atom_systray_r->atom;

    p_delete(&atom_systray_r);

    xcb_set_selection_owner(globalconf.connection,
                            globalconf.screens.tab[phys_screen].systray.window,
                            atom_systray,
                            XCB_CURRENT_TIME);

    xcb_send_event(globalconf.connection, false, xscreen->root, 0xFFFFFF, (char *) &ev);
}
/** Initialize systray information in X.
 * \param phys_screen Physical screen.
 */
void
systray_init(int phys_screen)
{
    xcb_screen_t *xscreen = xutil_screen_get(globalconf.connection, phys_screen);

    globalconf.screens.tab[phys_screen].systray.window = xcb_generate_id(globalconf.connection);
    xcb_create_window(globalconf.connection, xscreen->root_depth,
                      globalconf.screens.tab[phys_screen].systray.window,
                      xscreen->root,
                      -1, -1, 1, 1, 0,
                      XCB_COPY_FROM_PARENT, xscreen->root_visual, 0, NULL);
}
Beispiel #7
0
/** Set simple window orientation.
 * \param sw The simple window.
 * \param o The new orientation
 */
void
simplewindow_orientation_set(simple_window_t *sw, orientation_t o)
{
    if(o != sw->orientation)
    {
        xcb_screen_t *s = xutil_screen_get(globalconf.connection, sw->ctx.phys_screen);
        sw->orientation = o;
        /* orientation != East */
        if(sw->pixmap != sw->ctx.pixmap)
            xcb_free_pixmap(globalconf.connection, sw->ctx.pixmap);
        simplewindow_draw_context_update(sw, s);
    }
}
Beispiel #8
0
/** Initialize a simple window.
 * \param sw The simple window to initialize.
 * \param phys_screen Physical screen number.
 * \param geometry Window geometry.
 * \param border_width Window border width.
 * \param orientation The rendering orientation.
 * \param bg Default foreground color.
 * \param bg Default background color.
 */
void
simplewindow_init(simple_window_t *sw,
                  int phys_screen,
                  area_t geometry,
                  uint16_t border_width,
                  orientation_t orientation,
                  const xcolor_t *fg, const xcolor_t *bg)
{
    xcb_screen_t *s = xutil_screen_get(globalconf.connection, phys_screen);
    uint32_t create_win_val[3];
    const uint32_t gc_mask = XCB_GC_FOREGROUND | XCB_GC_BACKGROUND;
    const uint32_t gc_values[2] = { s->black_pixel, s->white_pixel };

    sw->geometry.x = geometry.x;
    sw->geometry.y = geometry.y;
    sw->geometry.width = geometry.width;
    sw->geometry.height = geometry.height;
    sw->border.width = border_width;
    sw->orientation = orientation;
    sw->ctx.fg = *fg;
    sw->ctx.bg = *bg;

    create_win_val[0] = XCB_BACK_PIXMAP_PARENT_RELATIVE;
    create_win_val[1] = 1;
    create_win_val[2] = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT
        | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_ENTER_WINDOW
        | XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_STRUCTURE_NOTIFY
        | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE
        | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_EXPOSURE;

    sw->window = xcb_generate_id(globalconf.connection);
    xcb_create_window(globalconf.connection, s->root_depth, sw->window, s->root,
                      geometry.x, geometry.y, geometry.width, geometry.height,
                      border_width, XCB_COPY_FROM_PARENT, s->root_visual,
                      XCB_CW_BACK_PIXMAP | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK,
                      create_win_val);

    sw->pixmap = xcb_generate_id(globalconf.connection);
    xcb_create_pixmap(globalconf.connection, s->root_depth, sw->pixmap, s->root,
                      geometry.width, geometry.height);

    sw->ctx.phys_screen = phys_screen;
    simplewindow_draw_context_update(sw, s);

    /* The default GC is just a newly created associated to the root window */
    sw->gc = xcb_generate_id(globalconf.connection);
    xcb_create_gc(globalconf.connection, sw->gc, s->root, gc_mask, gc_values);
}
Beispiel #9
0
/** Resize a simple window.
 * \param sw The simple_window_t to resize.
 * \param w New width.
 * \param h New height.
 */
void
simplewindow_resize(simple_window_t *sw, int w, int h)
{
    if(w > 0 && h > 0 && (sw->geometry.width != w || sw->geometry.height != h))
    {
        xcb_screen_t *s = xutil_screen_get(globalconf.connection, sw->ctx.phys_screen);
        uint32_t resize_win_vals[2];

        sw->geometry.width = resize_win_vals[0] = w;
        sw->geometry.height = resize_win_vals[1] = h;
        xcb_free_pixmap(globalconf.connection, sw->pixmap);
        /* orientation != East */
        if(sw->pixmap != sw->ctx.pixmap)
            xcb_free_pixmap(globalconf.connection, sw->ctx.pixmap);
        sw->pixmap = xcb_generate_id(globalconf.connection);
        xcb_create_pixmap(globalconf.connection, s->root_depth, sw->pixmap, s->root, w, h);
        xcb_configure_window(globalconf.connection, sw->window,
                             XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
                             resize_win_vals);
        simplewindow_draw_context_update(sw, s);
    }
}
/** Grab the mouse.
 * \param cursor The cursor to use while grabbing.
 * \return True if mouse was grabbed.
 */
static bool
mousegrabber_grab(xcb_cursor_t cursor)
{
    xcb_window_t root = XCB_NONE;

    for(int screen = 0;
        screen < xcb_setup_roots_length(xcb_get_setup(globalconf.connection));
        screen++)
    {
        int16_t x, y;
        uint16_t mask;

        root = xutil_screen_get(globalconf.connection, screen)->root;
        if(mouse_query_pointer(root, &x, &y, NULL, &mask))
            break;
    }

    for(int i = 1000; i; i--)
    {
        xcb_grab_pointer_reply_t *grab_ptr_r;
        xcb_grab_pointer_cookie_t grab_ptr_c =
            xcb_grab_pointer_unchecked(globalconf.connection, false, root,
                                       XCB_EVENT_MASK_BUTTON_PRESS
                                       | XCB_EVENT_MASK_BUTTON_RELEASE
                                       | XCB_EVENT_MASK_POINTER_MOTION,
                                       XCB_GRAB_MODE_ASYNC,
                                       XCB_GRAB_MODE_ASYNC,
                                       root, cursor, XCB_CURRENT_TIME);

        if((grab_ptr_r = xcb_grab_pointer_reply(globalconf.connection, grab_ptr_c, NULL)))
        {
            p_delete(&grab_ptr_r);
            return true;
        }
        usleep(1000);
    }
    return false;
}
Beispiel #11
0
/** Get or set global key bindings.
 * This binding will be available when you'll press keys on root window.
 * \param L The Lua VM state.
 * \return The number of element pushed on stack.
 * \luastack
 * \lparam An array of key bindings objects, or nothing.
 * \lreturn The array of key bindings objects of this client.
 */
static int
luaA_root_keys(lua_State *L)
{
    if(lua_gettop(L) == 1)
    {
        luaA_checktable(L, 1);

        foreach(key, globalconf.keys)
            luaA_object_unref(globalconf.L, *key);

        key_array_wipe(&globalconf.keys);
        key_array_init(&globalconf.keys);

        lua_pushnil(L);
        while(lua_next(L, 1))
            key_array_append(&globalconf.keys, luaA_object_ref_class(L, -1, &key_class));

        int nscreen = xcb_setup_roots_length(xcb_get_setup(globalconf.connection));

        for(int phys_screen = 0; phys_screen < nscreen; phys_screen++)
        {
            xcb_screen_t *s = xutil_screen_get(globalconf.connection, phys_screen);
            xcb_ungrab_key(globalconf.connection, XCB_GRAB_ANY, s->root, XCB_BUTTON_MASK_ANY);
            xwindow_grabkeys(s->root, &globalconf.keys);
        }

        return 1;
    }

    lua_createtable(L, globalconf.keys.len, 0);
    for(int i = 0; i < globalconf.keys.len; i++)
    {
        luaA_object_push(L, globalconf.keys.tab[i]);
        lua_rawseti(L, -2, i + 1);
    }

    return 1;
}
Beispiel #12
0
/** Grab the keyboard.
 * \return True if keyboard was grabbed.
 */
static bool
keygrabber_grab(void)
{
    int i;
    xcb_grab_keyboard_reply_t *xgb;

    for(i = 1000; i; i--)
    {
        if((xgb = xcb_grab_keyboard_reply(globalconf.connection,
                                          xcb_grab_keyboard(globalconf.connection, true,
                                                            xutil_screen_get(globalconf.connection,
                                                                               globalconf.default_screen)->root,
                                                            XCB_CURRENT_TIME, XCB_GRAB_MODE_ASYNC,
                                                            XCB_GRAB_MODE_ASYNC),
                                          NULL)))
        {
            p_delete(&xgb);
            return true;
        }
        usleep(1000);
    }
    return false;
}
Beispiel #13
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;
}
Beispiel #14
0
/** Move and resize a window in one call.
 * \param sw The simple window to move and resize.
 * \param geom The new gometry.
 */
void
simplewindow_moveresize(simple_window_t *sw, area_t geom)
{
    uint32_t moveresize_win_vals[4], mask_vals = 0;
    xcb_screen_t *s = xutil_screen_get(globalconf.connection, sw->ctx.phys_screen);

    if(sw->geometry.x != geom.x || sw->geometry.y != geom.y)
    {
        sw->geometry.x = moveresize_win_vals[0] = geom.x;
        sw->geometry.y = moveresize_win_vals[1] = geom.y;
        mask_vals |= XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y;
    }

    if(sw->geometry.width != geom.width || sw->geometry.height != geom.height)
    {
        if(mask_vals)
        {
            sw->geometry.width = moveresize_win_vals[2] = geom.width;
            sw->geometry.height = moveresize_win_vals[3] = geom.height;
        }
        else
        {
            sw->geometry.width = moveresize_win_vals[0] = geom.width;
            sw->geometry.height = moveresize_win_vals[1] = geom.height;
        }
        mask_vals |= XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
        xcb_free_pixmap(globalconf.connection, sw->pixmap);
        /* orientation != East */
        if(sw->pixmap != sw->ctx.pixmap)
            xcb_free_pixmap(globalconf.connection, sw->ctx.pixmap);
        sw->pixmap = xcb_generate_id(globalconf.connection);
        xcb_create_pixmap(globalconf.connection, s->root_depth, sw->pixmap, s->root, geom.width, geom.height);
        simplewindow_draw_context_update(sw, s);
    }

    xcb_configure_window(globalconf.connection, sw->window, mask_vals, moveresize_win_vals);
}
Beispiel #15
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;

    if(event_handle_mousegrabber(ev->root_x, ev->root_y, 1 << (ev->detail - 1 + 8)))
        return 0;

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

    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->window == ev->child)
        {
            ev->event_x -= wibox->geometry.x;
            ev->event_y -= wibox->geometry.y;
        }

        /* Push the wibox */
        luaA_object_push(globalconf.L, wibox);
        /* Duplicate the wibox */
        lua_pushvalue(globalconf.L, -1);
        /* Handle the button event on it */
        event_button_callback(ev, &wibox->buttons, -1, 1, NULL);

        /* then try to match a widget binding */
        widget_t *w = widget_getbycoords(wibox->orientation, &wibox->widgets,
                                         wibox->geometry.width,
                                         wibox->geometry.height,
                                         &ev->event_x, &ev->event_y);
        if(w)
        {
            /* Push widget (the wibox is already on stack) */
            luaA_object_push_item(globalconf.L, -1, w);
            /* Move widget before wibox */
            lua_insert(globalconf.L, -2);
            event_button_callback(ev, &w->buttons, -2, 2, NULL);
        }
        else
            /* Remove the wibox, we did not use it */
            lua_pop(globalconf.L, 1);

    }
    else if((c = client_getbywin(ev->event)))
    {
        luaA_object_push(globalconf.L, c);
        event_button_callback(ev, &c->buttons, -1, 1, NULL);
        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_button_callback(ev, &globalconf.buttons, 0, 0, NULL);
                return 0;
            }

    return 0;
}
Beispiel #16
0
/** Render a list of widgets.
 * \param wibox The wibox.
 * \todo Remove GC.
 */
void
widget_render(wibox_t *wibox)
{
    lua_State *L = globalconf.L;
    draw_context_t *ctx = &wibox->ctx;
    area_t rectangle = { 0, 0, 0, 0 };
    color_t col;

    rectangle.width = ctx->width;
    rectangle.height = ctx->height;

    if (!widget_geometries(wibox))
        return;

    if(ctx->bg.alpha != 0xffff)
    {
        int x = wibox->geometry.x + wibox->border_width,
            y = wibox->geometry.y + wibox->border_width;
        xcb_get_property_reply_t *prop_r;
        char *data;
        xcb_pixmap_t rootpix;
        xcb_get_property_cookie_t prop_c;
        xcb_screen_t *s = xutil_screen_get(globalconf.connection, ctx->phys_screen);
        prop_c = xcb_get_property_unchecked(globalconf.connection, false, s->root, _XROOTPMAP_ID,
                                            PIXMAP, 0, 1);
        if((prop_r = xcb_get_property_reply(globalconf.connection, prop_c, NULL)))
        {
            if(prop_r->value_len
               && (data = xcb_get_property_value(prop_r))
               && (rootpix = *(xcb_pixmap_t *) data))
               switch(wibox->orientation)
               {
                 case North:
                   draw_rotate(ctx,
                               rootpix, ctx->pixmap,
                               s->width_in_pixels, s->height_in_pixels,
                               ctx->width, ctx->height,
                               M_PI_2,
                               y + ctx->width,
                               - x);
                   break;
                 case South:
                   draw_rotate(ctx,
                               rootpix, ctx->pixmap,
                               s->width_in_pixels, s->height_in_pixels,
                               ctx->width, ctx->height,
                               - M_PI_2,
                               - y,
                               x + ctx->height);
                   break;
                 case East:
                   xcb_copy_area(globalconf.connection, rootpix,
                                 wibox->pixmap, wibox->gc,
                                 x, y,
                                 0, 0,
                                 ctx->width, ctx->height);
                   break;
               }
            p_delete(&prop_r);
        }
    }

    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(L, widgets);

    /* get computed geometries */
    for(unsigned int i = 0; i < lua_objlen(L, -1); i++)
    {
        lua_pushnumber(L, i + 1);
        lua_gettable(L, -2);

        widgets->tab[i].geometry.x = luaA_getopt_number(L, -1, "x", wibox->geometry.x);
        widgets->tab[i].geometry.y = luaA_getopt_number(L, -1, "y", wibox->geometry.y);
        widgets->tab[i].geometry.width = luaA_getopt_number(L, -1, "width", 1);
        widgets->tab[i].geometry.height = luaA_getopt_number(L, -1, "height", 1);

        lua_pop(L, 1);
    }
    lua_pop(L, 1);

    /* draw background image, only if the background color is not opaque */
    if(wibox->bg_image && ctx->bg.alpha != 0xffff)
        draw_image(ctx, 0, 0, 1.0, wibox->bg_image);

    /* draw background color */
    xcolor_to_color(&ctx->bg, &col);
    draw_rectangle(ctx, rectangle, 1.0, true, &col);

    /* draw everything! */
    for(int i = 0; i < widgets->len; i++)
        if(widgets->tab[i].widget->isvisible)
            widgets->tab[i].widget->draw(widgets->tab[i].widget,
                                         ctx, widgets->tab[i].geometry, wibox);

    switch(wibox->orientation)
    {
        case South:
          draw_rotate(ctx, ctx->pixmap, wibox->pixmap,
                      ctx->width, ctx->height,
                      ctx->height, ctx->width,
                      M_PI_2, ctx->height, 0);
          break;
        case North:
          draw_rotate(ctx, ctx->pixmap, wibox->pixmap,
                      ctx->width, ctx->height,
                      ctx->height, ctx->width,
                      - M_PI_2, 0, ctx->width);
          break;
        case East:
          break;
    }
}
Beispiel #17
0
/** Hello, this is main.
 * \param argc Who knows.
 * \param argv Who knows.
 * \return EXIT_SUCCESS I hope.
 */
int
main(int argc, char **argv)
{
    char *confpath = NULL;
    int xfd, i, screen_nbr, opt, colors_nbr;
    xcolor_init_request_t colors_reqs[2];
    ssize_t cmdlen = 1;
    xdgHandle xdg;
    xcb_generic_event_t *event;
    static struct option long_options[] =
    {
        { "help",    0, NULL, 'h' },
        { "version", 0, NULL, 'v' },
        { "config",  1, NULL, 'c' },
        { "check",   0, NULL, 'k' },
        { NULL,      0, NULL, 0 }
    };

    /* event loop watchers */
    ev_io xio    = { .fd = -1 };
    ev_check xcheck;
    ev_prepare a_refresh;
    ev_signal sigint;
    ev_signal sigterm;
    ev_signal sighup;

    /* clear the globalconf structure */
    p_clear(&globalconf, 1);
    globalconf.keygrabber = LUA_REFNIL;
    globalconf.mousegrabber = LUA_REFNIL;
    buffer_init(&globalconf.startup_errors);

    /* save argv */
    for(i = 0; i < argc; i++)
        cmdlen += a_strlen(argv[i]) + 1;

    globalconf.argv = p_new(char, cmdlen);
    a_strcpy(globalconf.argv, cmdlen, argv[0]);

    for(i = 1; i < argc; i++)
    {
        a_strcat(globalconf.argv, cmdlen, " ");
        a_strcat(globalconf.argv, cmdlen, argv[i]);
    }

    /* Text won't be printed correctly otherwise */
    setlocale(LC_CTYPE, "");

    /* Get XDG basedir data */
    xdgInitHandle(&xdg);

    /* init lua */
    luaA_init(&xdg);

    /* check args */
    while((opt = getopt_long(argc, argv, "vhkc:",
                             long_options, NULL)) != -1)
        switch(opt)
        {
          case 'v':
            eprint_version();
            break;
          case 'h':
            exit_help(EXIT_SUCCESS);
            break;
          case 'k':
            if(!luaA_parserc(&xdg, confpath, false))
            {
                fprintf(stderr, "✘ Configuration file syntax error.\n");
                return EXIT_FAILURE;
            }
            else
            {
                fprintf(stderr, "✔ Configuration file syntax OK.\n");
                return EXIT_SUCCESS;
            }
          case 'c':
            if(a_strlen(optarg))
                confpath = a_strdup(optarg);
            else
                fatal("-c option requires a file name");
            break;
        }

    globalconf.loop = ev_default_loop(0);
    ev_timer_init(&globalconf.timer, &luaA_on_timer, 0., 0.);

    /* register function for signals */
    ev_signal_init(&sigint, exit_on_signal, SIGINT);
    ev_signal_init(&sigterm, exit_on_signal, SIGTERM);
    ev_signal_init(&sighup, restart_on_signal, SIGHUP);
    ev_signal_start(globalconf.loop, &sigint);
    ev_signal_start(globalconf.loop, &sigterm);
    ev_signal_start(globalconf.loop, &sighup);
    ev_unref(globalconf.loop);
    ev_unref(globalconf.loop);
    ev_unref(globalconf.loop);

    struct sigaction sa = { .sa_handler = signal_fatal, .sa_flags = 0 };
    sigemptyset(&sa.sa_mask);
    sigaction(SIGSEGV, &sa, 0);

    /* XLib sucks */
    XkbIgnoreExtension(True);

    /* X stuff */
    globalconf.display = XOpenDisplay(NULL);
    if (globalconf.display == NULL)
        fatal("cannot open display");

    globalconf.default_screen = XDefaultScreen(globalconf.display);

    globalconf.connection = XGetXCBConnection(globalconf.display);

    /* Double checking then everything is OK. */
    if(xcb_connection_has_error(globalconf.connection))
        fatal("cannot open display");

    /* Prefetch all the extensions we might need */
    xcb_prefetch_extension_data(globalconf.connection, &xcb_big_requests_id);
    xcb_prefetch_extension_data(globalconf.connection, &xcb_test_id);
    xcb_prefetch_extension_data(globalconf.connection, &xcb_randr_id);
    xcb_prefetch_extension_data(globalconf.connection, &xcb_shape_id);

    /* initialize dbus */
    a_dbus_init();

    /* Get the file descriptor corresponding to the X connection */
    xfd = xcb_get_file_descriptor(globalconf.connection);
    ev_io_init(&xio, &a_xcb_io_cb, xfd, EV_READ);
    ev_io_start(globalconf.loop, &xio);
    ev_check_init(&xcheck, &a_xcb_check_cb);
    ev_check_start(globalconf.loop, &xcheck);
    ev_unref(globalconf.loop);
    ev_prepare_init(&a_refresh, &a_refresh_cb);
    ev_prepare_start(globalconf.loop, &a_refresh);
    ev_unref(globalconf.loop);

    /* Grab server */
    xcb_grab_server(globalconf.connection);

    /* Make sure there are no pending events. Since we didn't really do anything
     * at all yet, we will just discard all events which we received so far.
     * The above GrabServer should make sure no new events are generated. */
    xcb_aux_sync(globalconf.connection);
    while ((event = xcb_poll_for_event(globalconf.connection)) != NULL)
    {
        /* Make sure errors are printed */
        uint8_t response_type = XCB_EVENT_RESPONSE_TYPE(event);
        if(response_type == 0)
            event_handle(event);
        p_delete(&event);
    }

    for(screen_nbr = 0;
        screen_nbr < xcb_setup_roots_length(xcb_get_setup(globalconf.connection));
        screen_nbr++)
    {
        const uint32_t select_input_val = XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT;

        /* This causes an error if some other window manager is running */
        xcb_change_window_attributes(globalconf.connection,
                                     xutil_screen_get(globalconf.connection, screen_nbr)->root,
                                     XCB_CW_EVENT_MASK, &select_input_val);
    }

    /* Need to xcb_flush to validate error handler */
    xcb_aux_sync(globalconf.connection);

    /* Process all errors in the queue if any. There can be no events yet, so if
     * this function returns something, it must be an error. */
    if (xcb_poll_for_event(globalconf.connection) != NULL)
        fatal("another window manager is already running");

    /* Prefetch the maximum request length */
    xcb_prefetch_maximum_request_length(globalconf.connection);

    /* check for xtest extension */
    const xcb_query_extension_reply_t *xtest_query;
    xtest_query = xcb_get_extension_data(globalconf.connection, &xcb_test_id);
    globalconf.have_xtest = xtest_query->present;

    /* Allocate the key symbols */
    globalconf.keysyms = xcb_key_symbols_alloc(globalconf.connection);
    xcb_get_modifier_mapping_cookie_t xmapping_cookie =
        xcb_get_modifier_mapping_unchecked(globalconf.connection);

    /* init atom cache */
    atoms_init(globalconf.connection);

    /* init screens information */
    screen_scan();

    /* init default font and colors */
    colors_reqs[0] = xcolor_init_unchecked(&globalconf.colors.fg,
                                           "black", sizeof("black") - 1);

    colors_reqs[1] = xcolor_init_unchecked(&globalconf.colors.bg,
                                           "white", sizeof("white") - 1);

    globalconf.font = draw_font_new("sans 8");

    for(colors_nbr = 0; colors_nbr < 2; colors_nbr++)
        xcolor_init_reply(colors_reqs[colors_nbr]);

    xutil_lock_mask_get(globalconf.connection, xmapping_cookie,
                        globalconf.keysyms, &globalconf.numlockmask,
                        &globalconf.shiftlockmask, &globalconf.capslockmask,
                        &globalconf.modeswitchmask);

    /* Get the window tree associated to this screen */
    const int screen_max = xcb_setup_roots_length(xcb_get_setup(globalconf.connection));
    xcb_query_tree_cookie_t tree_c[screen_max];

    /* do this only for real screen */
    for(screen_nbr = 0; screen_nbr < screen_max; screen_nbr++)
    {
        /* select for events */
        const uint32_t change_win_vals[] =
        {
            XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY
                | XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW
                | XCB_EVENT_MASK_STRUCTURE_NOTIFY
                | XCB_EVENT_MASK_PROPERTY_CHANGE
                | XCB_EVENT_MASK_BUTTON_PRESS
                | XCB_EVENT_MASK_BUTTON_RELEASE
                | XCB_EVENT_MASK_FOCUS_CHANGE
        };

        tree_c[screen_nbr] = xcb_query_tree_unchecked(globalconf.connection,
                                                      xutil_screen_get(globalconf.connection, screen_nbr)->root);

        xcb_change_window_attributes(globalconf.connection,
                                     xutil_screen_get(globalconf.connection, screen_nbr)->root,
                                     XCB_CW_EVENT_MASK,
                                     change_win_vals);
        ewmh_init(screen_nbr);
        systray_init(screen_nbr);
    }

    /* init spawn (sn) */
    spawn_init();

    /* we will receive events, stop grabbing server */
    xcb_ungrab_server(globalconf.connection);

    /* Parse and run configuration file */
    if (!luaA_parserc(&xdg, confpath, true))
        fatal("couldn't find any rc file");

    scan(tree_c);

    xcb_flush(globalconf.connection);

    /* main event loop */
    ev_loop(globalconf.loop, 0);

    /* cleanup event loop */
    ev_ref(globalconf.loop);
    ev_check_stop(globalconf.loop, &xcheck);
    ev_ref(globalconf.loop);
    ev_prepare_stop(globalconf.loop, &a_refresh);
    ev_ref(globalconf.loop);
    ev_io_stop(globalconf.loop, &xio);

    awesome_atexit(false);

    return EXIT_SUCCESS;
}
Beispiel #18
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;
}
Beispiel #19
0
/** Get the current X selection buffer.
 * \param L The Lua VM state.
 * \return The number of elements pushed on stack.
 * \luastack
 * \lreturn A string with the current X selection buffer.
 */
int
luaA_selection_get(lua_State *L)
{
    if(selection_window == XCB_NONE)
    {
        xcb_screen_t *screen = xutil_screen_get(globalconf.connection, globalconf.default_screen);
        uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK;
        uint32_t values[] = { screen->black_pixel, 1, XCB_EVENT_MASK_PROPERTY_CHANGE };

        selection_window = xcb_generate_id(globalconf.connection);

        xcb_create_window(globalconf.connection, screen->root_depth, selection_window, screen->root,
                          0, 0, 1, 1, 0, XCB_COPY_FROM_PARENT, screen->root_visual,
                          mask, values);
    }

    xcb_convert_selection(globalconf.connection, selection_window,
                          PRIMARY, UTF8_STRING, XSEL_DATA, XCB_CURRENT_TIME);
    xcb_flush(globalconf.connection);

    xcb_generic_event_t *event;

    while(true)
    {
        event = xcb_wait_for_event(globalconf.connection);

        if(!event)
            return 0;

        if(XCB_EVENT_RESPONSE_TYPE(event) != XCB_SELECTION_NOTIFY)
        {
            /* \todo Eventually, this may be rewritten with adding a static
             * buffer, then a event handler for XCB_SELECTION_NOTIFY, then call
             * xcb_event_poll_for_event_loop() and awesome_refresh(),
             * then check if some static buffer has been filled with data.
             * If yes, that'd be the xsel data, otherwise, re-loop.
             * Anyway that's still brokes the socket or D-Bus, so maybe using
             * ev_loop() would be even better.
             */
            xcb_event_handle(&globalconf.evenths, event);
            p_delete(&event);
            awesome_refresh();
            continue;
        }

        xcb_selection_notify_event_t *event_notify =
            (xcb_selection_notify_event_t *) event;

        if(event_notify->selection == PRIMARY
           && event_notify->property != XCB_NONE)
        {
            xcb_get_text_property_reply_t prop;
            xcb_get_property_cookie_t cookie =
                xcb_get_text_property(globalconf.connection,
                                      event_notify->requestor,
                                      event_notify->property);

            if(xcb_get_text_property_reply(globalconf.connection,
                                           cookie, &prop, NULL))
            {
                lua_pushlstring(L, prop.name, prop.name_len);

                xcb_get_text_property_reply_wipe(&prop);

                xcb_delete_property(globalconf.connection,
                                    event_notify->requestor,
                                    event_notify->property);

                p_delete(&event);

                return 1;
            }
            else
                break;
        }
    }

    p_delete(&event);
    return 0;
}