static int internal_prepare_rendering(CustomCellRendererFlexi *cr)
{
    if (cr->rendered_type!=RENDER_NONE) return cr->rendered_type;

    if (cr->is_raw)
    {
        internal_format(cr, cr->raw_value, 65536);
    }
    else
    {
        if (a_strlen(cr->mime_type)>2)
        {
            if (strstr(a_strval(cr->mime_type)+2,"image/")!=NULL)
            {
                internal_load_image(cr,a_strval(cr->raw_value),a_strval(cr->mime_type)+2);
            }
            else
            {
                internal_render_error(cr,"Unrecognized mime-type");
            }
        }
        else
        {
            if (a_strlen(cr->alt_text)>0)
            {
                internal_format(cr, cr->alt_text,65536);
            }
            else if (a_strlen(cr->raw_value)>0)
            {
                internal_format(cr, cr->raw_value,256);
            }
        }
    }
    return cr->rendered_type;
}
/** Register a new xproperty.
 * \param L The Lua VM state.
 * \return The number of elements pushed on stack.
 * \luastack
 * \lparam The name of the X11 property
 * \lparam One of "string", "number" or "boolean"
 */
int
luaA_register_xproperty(lua_State *L)
{
    const char *name;
    struct xproperty property;
    struct xproperty *found;
    const char *const args[] = { "string", "number", "boolean" };
    xcb_intern_atom_reply_t *atom_r;
    int type;

    name = luaL_checkstring(L, 1);
    type = luaL_checkoption(L, 2, NULL, args);
    if (type == 0)
        property.type = PROP_STRING;
    else if (type == 1)
        property.type = PROP_NUMBER;
    else
        property.type = PROP_BOOLEAN;

    atom_r = xcb_intern_atom_reply(globalconf.connection,
                                   xcb_intern_atom_unchecked(globalconf.connection, false,
                                                             a_strlen(name), name),
                                   NULL);
    if(!atom_r)
        return 0;

    property.atom = atom_r->atom;
    p_delete(&atom_r);

    found = xproperty_array_lookup(&globalconf.xproperties, &property);
    if(found)
    {
        /* Property already registered */
        if(found->type != property.type)
            return luaL_error(L, "xproperty '%s' already registered with different type", name);
    }
    else
    {
        buffer_t buf;
        buffer_inita(&buf, a_strlen(name) + a_strlen("xproperty::") + 1);
        buffer_addf(&buf, "xproperty::%s", name);

        property.name = a_strdup(name);
        xproperty_array_insert(&globalconf.xproperties, property);
        signal_add(&window_class.signals, buf.s);
        signal_add(&global_signals, buf.s);
        buffer_wipe(&buf);
    }

    return 0;
}
Beispiel #3
0
/** Remove systray information in X.
 */
void
systray_cleanup(void)
{
    xcb_intern_atom_reply_t *atom_systray_r;
    char *atom_name;

    if(!(atom_name = xcb_atom_name_by_screen("_NET_SYSTEM_TRAY", globalconf.default_screen))
       || !(atom_systray_r = xcb_intern_atom_reply(globalconf.connection,
                                                   xcb_intern_atom_unchecked(globalconf.connection,
                                                                             false,
                                                                             a_strlen(atom_name),
                                                                             atom_name),
                                                   NULL)))
    {
        warn("error getting systray atom");
        p_delete(&atom_name);
        return;
    }

    p_delete(&atom_name);

    xcb_set_selection_owner(globalconf.connection,
                            XCB_NONE,
                            atom_systray_r->atom,
                            XCB_CURRENT_TIME);

    p_delete(&atom_systray_r);

    xcb_unmap_window(globalconf.connection,
                     globalconf.systray.window);
}
Beispiel #4
0
/** Check whether a composite manager is running.
 * \return True if such a manager is running.
 */
static bool
composite_manager_running(void)
{
    xcb_intern_atom_reply_t *atom_r;
    xcb_get_selection_owner_reply_t *selection_r;
    char *atom_name;
    bool result;

    if(!(atom_name = xcb_atom_name_by_screen("_NET_WM_CM", globalconf.default_screen)))
    {
        warn("error getting composite manager atom");
        return false;
    }

    atom_r = xcb_intern_atom_reply(globalconf.connection,
                                   xcb_intern_atom_unchecked(globalconf.connection, false,
                                                             a_strlen(atom_name), atom_name),
                                   NULL);
    p_delete(&atom_name);
    if(!atom_r)
        return false;

    selection_r = xcb_get_selection_owner_reply(globalconf.connection,
                                                xcb_get_selection_owner_unchecked(globalconf.connection,
                                                                                  atom_r->atom),
                                                NULL);
    p_delete(&atom_r);

    result = selection_r != NULL && selection_r->owner != XCB_NONE;
    p_delete(&selection_r);

    return result;
}
Beispiel #5
0
void
atoms_init(xcb_connection_t *conn)
{
    unsigned int i;
    xcb_intern_atom_cookie_t cs[countof(ATOM_LIST)];
    xcb_intern_atom_reply_t *r;

    /* Create the atom and get the reply in a XCB way (e.g. send all
     * the requests at the same time and then get the replies) */
    for(i = 0; i < countof(ATOM_LIST); i++)
	cs[i] = xcb_intern_atom_unchecked(conn,
					  false,
					  a_strlen(ATOM_LIST[i].name),
					  ATOM_LIST[i].name);

    for(i = 0; i < countof(ATOM_LIST); i++)
    {
	if(!(r = xcb_intern_atom_reply(conn, cs[i], NULL)))
	    /* An error occured, get reply for next atom */
	    continue;

	*ATOM_LIST[i].atom = r->atom;
        p_delete(&r);
    }
}
Beispiel #6
0
/** Initialize systray information in X.
 */
void
systray_init(void)
{
    xcb_intern_atom_cookie_t atom_systray_q;
    xcb_intern_atom_reply_t *atom_systray_r;
    char *atom_name;
    xcb_screen_t *xscreen = globalconf.screen;

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

    atom_name = xcb_atom_name_by_screen("_NET_SYSTEM_TRAY", globalconf.default_screen);
    if(!atom_name)
        fatal("error getting systray atom name");

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

    p_delete(&atom_name);

    atom_systray_r = xcb_intern_atom_reply(globalconf.connection, atom_systray_q, NULL);
    if(!atom_systray_r)
        fatal("error getting systray atom");

    globalconf.systray.atom = atom_systray_r->atom;
    p_delete(&atom_systray_r);
}
/** Remove systray information in X.
 * \param phys_screen Physical screen.
 */
void
systray_cleanup(int phys_screen)
{
    xcb_intern_atom_reply_t *atom_systray_r;
    char *atom_name;

    if(!globalconf.screens.tab[phys_screen].systray.registered)
        return;
    globalconf.screens.tab[phys_screen].systray.registered = false;

    if(!(atom_name = xcb_atom_name_by_screen("_NET_SYSTEM_TRAY", phys_screen))
       || !(atom_systray_r = xcb_intern_atom_reply(globalconf.connection,
                                                   xcb_intern_atom_unchecked(globalconf.connection,
                                                                             false,
                                                                             a_strlen(atom_name),
                                                                             atom_name),
                                                   NULL)))
    {
        warn("error getting systray atom");
        p_delete(&atom_name);
        return;
    }

    p_delete(&atom_name);

    xcb_set_selection_owner(globalconf.connection,
                            XCB_NONE,
                            atom_systray_r->atom,
                            XCB_CURRENT_TIME);

    p_delete(&atom_systray_r);
}
static gboolean internal_format(CustomCellRendererFlexi *cr, const a_string_t *a_src, int limit)
{
    int len_src 	= a_strlen(a_src);
    const char *src = a_strval(a_src);

    cr->rendered_type = RENDER_TEXT;
    cr->rendered_value = a_strnew(NULL);

    if (src==NULL || len_src<2) return FALSE;

    switch (src[0])
    {
        case '8':
        case '4':
        case '1':
            internal_format_raw(cr->rendered_value,len_src,src,limit);
            break;
        case 't':
            internal_format_alt(cr->rendered_value,len_src,src);
            break;
        default:
            return internal_render_error(cr,"Internal format error.");
    }
    return TRUE;
}
Beispiel #9
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);
}
static gboolean internal_render_error(CustomCellRendererFlexi *cr, const char *msg)
{
    cr->rendered_type = RENDER_TEXT;
    cr->rendered_value = a_strnew("<span foreground='#7F0000'>Error: ");
    a_strcat(cr->rendered_value,msg);
    a_strcat(cr->rendered_value,"</span>");
    if (a_strlen(cr->mime_type)>2)
        log_printf(LOG_WARNING,"Rendering error for '%s' mime-type: %s",a_strval(cr->mime_type)+2,msg);
    else
        log_printf(LOG_WARNING,"Rendering error: %s",msg);
    return FALSE;
}
Beispiel #12
0
/** \brief safe strcpy.
 *
 * Copies at most <tt>n-1</tt> characters from \c src into \c dst, always
 * adding a final \c \\0 in \c dst.
 *
 * \param[in]  dst      destination buffer.
 * \param[in]  n        size of the buffer. Negative sizes are allowed.
 * \param[in]  src      source string.
 * \return \c src \e length. If this value is \>= \c n then the copy was
 *         truncated.
 */
ssize_t
a_strcpy(char *dst, ssize_t n, const char *src)
{
    ssize_t len = a_strlen(src);

    if (n > 0)
    {
        ssize_t dlen = MIN(n - 1, len);
        memcpy(dst, src, dlen);
        dst[dlen] = '\0';
    }

    return len;
}
Beispiel #13
0
/** Load a configuration file.
 * \param xdg An xdg handle to use to get XDG basedir.
 * \param confpatharg The configuration file to load.
 * \param run Run the configuration file.
 */
bool
luaA_parserc(xdgHandle* xdg, const char *confpatharg, bool run)
{
    char *confpath = NULL;
    bool ret = false;

    /* try to load, return if it's ok */
    if(confpatharg)
    {
        if(luaA_loadrc(confpatharg, run))
        {
            ret = true;
            goto bailout;
        }
        else if(!run)
            goto bailout;
    }

    confpath = xdgConfigFind("awesome/rc.lua", xdg);

    char *tmp = confpath;

    /* confpath is "string1\0string2\0string3\0\0" */
    while(*tmp)
    {
        if(luaA_loadrc(tmp, run))
        {
            ret = true;
            goto bailout;
        }
        else if(!run)
            goto bailout;
        tmp += a_strlen(tmp) + 1;
    }

bailout:

    p_delete(&confpath);

    return ret;
}
Beispiel #14
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, opt;
    ssize_t cmdlen = 1;
    xdgHandle xdg;
    bool no_argb = false;
    xcb_generic_event_t *event;
    xcb_query_tree_cookie_t tree_c;
    static struct option long_options[] =
    {
        { "help",    0, NULL, 'h' },
        { "version", 0, NULL, 'v' },
        { "config",  1, NULL, 'c' },
        { "check",   0, NULL, 'k' },
        { "no-argb", 0, NULL, 'a' },
        { 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;

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

    for(i = 1; i < argc; i++)
    {
        a_strcat(awesome_argv, cmdlen, " ");
        a_strcat(awesome_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:a",
                             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;
        case 'a':
            no_argb = true;
            break;
        }

    globalconf.loop = ev_default_loop(EVFLAG_NOSIGFD);

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

    /* X stuff */
    globalconf.connection = xcb_connect(NULL, &globalconf.default_screen);
    if(xcb_connection_has_error(globalconf.connection))
        fatal("cannot open display");

    globalconf.screen = xcb_aux_get_screen(globalconf.connection, globalconf.default_screen);
    /* FIXME The following two assignments were swapped on purpose */
    if(!no_argb)
        globalconf.visual = a_default_visual(globalconf.screen);
    if(!globalconf.visual)
        globalconf.visual = a_argb_visual(globalconf.screen);
    globalconf.default_depth = a_visual_depth(globalconf.screen, globalconf.visual->visual_id);
    globalconf.default_cmap = globalconf.screen->default_colormap;
    if(globalconf.default_depth != globalconf.screen->root_depth)
    {
        // We need our own color map if we aren't using the default depth
        globalconf.default_cmap = xcb_generate_id(globalconf.connection);
        xcb_create_colormap(globalconf.connection, XCB_COLORMAP_ALLOC_NONE,
                            globalconf.default_cmap, globalconf.screen->root,
                            globalconf.visual->visual_id);
    }

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

    {
        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,
                                     globalconf.screen->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();

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

    /* do this only for real screen */
    ewmh_init();
    systray_init();

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

    /* The default GC is just a newly created associated with a window with
     * depth globalconf.default_depth */
    xcb_window_t tmp_win = xcb_generate_id(globalconf.connection);
    globalconf.gc = xcb_generate_id(globalconf.connection);
    xcb_create_window(globalconf.connection, globalconf.default_depth,
                      tmp_win, globalconf.screen->root,
                      -1, -1, 1, 1, 0,
                      XCB_COPY_FROM_PARENT, globalconf.visual->visual_id,
                      XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_COLORMAP,
                      (const uint32_t [])
    {
        globalconf.screen->black_pixel,
                          globalconf.screen->black_pixel,
                          globalconf.default_cmap
    });
    xcb_create_gc(globalconf.connection, globalconf.gc, tmp_win, XCB_GC_FOREGROUND | XCB_GC_BACKGROUND,
    (const uint32_t[]) {
        globalconf.screen->black_pixel, globalconf.screen->white_pixel
    });
    xcb_destroy_window(globalconf.connection, tmp_win);

    /* Get the window tree associated to this screen */
    tree_c = xcb_query_tree_unchecked(globalconf.connection,
                                      globalconf.screen->root);

    xcb_change_window_attributes(globalconf.connection,
                                 globalconf.screen->root,
                                 XCB_CW_EVENT_MASK,
                                 ROOT_WINDOW_EVENT_MASK);

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

    p_delete(&confpath);

    xdgWipeHandle(&xdg);

    /* scan existing windows */
    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 #15
0
/** Initialize the Lua VM
 * \param xdg An xdg handle to use to get XDG basedir.
 */
void
luaA_init(xdgHandle* xdg)
{
    lua_State *L;
    static const struct luaL_reg awesome_lib[] =
    {
        { "quit", luaA_quit },
        { "exec", luaA_exec },
        { "spawn", luaA_spawn },
        { "restart", luaA_restart },
        { "add_signal", luaA_awesome_add_signal },
        { "remove_signal", luaA_awesome_remove_signal },
        { "emit_signal", luaA_awesome_emit_signal },
        { "__index", luaA_awesome_index },
        { "__newindex", luaA_awesome_newindex },
        { NULL, NULL }
    };

    L = globalconf.L = luaL_newstate();

    /* Set panic function */
    lua_atpanic(L, luaA_panic);

    /* Set error handling function */
    lualib_dofunction_on_error = luaA_dofunction_on_error;

    luaL_openlibs(L);

    luaA_fixups(L);

    luaA_object_setup(L);

    /* Export awesome lib */
    luaA_openlib(L, "awesome", awesome_lib, awesome_lib);

    /* Export root lib */
    luaL_register(L, "root", awesome_root_lib);
    lua_pop(L, 1); /* luaL_register() leaves the table on stack */

    /* Export hooks lib */
    luaL_register(L, "hooks", awesome_hooks_lib);
    lua_pop(L, 1); /* luaL_register() leaves the table on stack */

#ifdef WITH_DBUS
    /* Export D-Bus lib */
    luaL_register(L, "dbus", awesome_dbus_lib);
    lua_pop(L, 1); /* luaL_register() leaves the table on stack */
#endif

    /* Export keygrabber lib */
    luaL_register(L, "keygrabber", awesome_keygrabber_lib);
    lua_pop(L, 1); /* luaL_register() leaves the table on stack */

    /* Export mousegrabber lib */
    luaL_register(L, "mousegrabber", awesome_mousegrabber_lib);
    lua_pop(L, 1); /* luaL_register() leaves the table on stack */

    /* Export screen */
    luaA_openlib(L, "screen", awesome_screen_methods, awesome_screen_meta);

    /* Export mouse */
    luaA_openlib(L, "mouse", awesome_mouse_methods, awesome_mouse_meta);

    /* Export button */
    button_class_setup(L);

    /* Export image */
    image_class_setup(L);

    /* Export tag */
    tag_class_setup(L);

    /* Export wibox */
    wibox_class_setup(L);

    /* Export widget */
    widget_class_setup(L);

    /* Export client */
    client_class_setup(L);

    /* Export keys */
    key_class_setup(L);

    /* Export timer */
    timer_class_setup(L);

    /* init hooks */
    globalconf.hooks.manage = LUA_REFNIL;
    globalconf.hooks.unmanage = LUA_REFNIL;
    globalconf.hooks.focus = LUA_REFNIL;
    globalconf.hooks.unfocus = LUA_REFNIL;
    globalconf.hooks.mouse_enter = LUA_REFNIL;
    globalconf.hooks.mouse_leave = LUA_REFNIL;
    globalconf.hooks.clients = LUA_REFNIL;
    globalconf.hooks.tags = LUA_REFNIL;
    globalconf.hooks.tagged = LUA_REFNIL;
    globalconf.hooks.property = LUA_REFNIL;
    globalconf.hooks.timer = LUA_REFNIL;
    globalconf.hooks.exit = LUA_REFNIL;

    /* add Lua search paths */
    lua_getglobal(L, "package");
    if (LUA_TTABLE != lua_type(L, 1))
    {
        warn("package is not a table");
        return;
    }
    lua_getfield(L, 1, "path");
    if (LUA_TSTRING != lua_type(L, 2))
    {
        warn("package.path is not a string");
        lua_pop(L, 1);
        return;
    }

    /* add XDG_CONFIG_DIR as include path */
    const char * const *xdgconfigdirs = xdgSearchableConfigDirectories(xdg);
    for(; *xdgconfigdirs; xdgconfigdirs++)
    {
        size_t len = a_strlen(*xdgconfigdirs);
        lua_pushliteral(L, ";");
        lua_pushlstring(L, *xdgconfigdirs, len);
        lua_pushliteral(L, "/awesome/?.lua");
        lua_concat(L, 3);

        lua_pushliteral(L, ";");
        lua_pushlstring(L, *xdgconfigdirs, len);
        lua_pushliteral(L, "/awesome/?/init.lua");
        lua_concat(L, 3);

        lua_concat(L, 3); /* concatenate with package.path */
    }

    /* add Lua lib path (/usr/share/awesome/lib by default) */
    lua_pushliteral(L, ";" AWESOME_LUA_LIB_PATH "/?.lua");
    lua_pushliteral(L, ";" AWESOME_LUA_LIB_PATH "/?/init.lua");
    lua_concat(L, 3); /* concatenate with package.path */
    lua_setfield(L, 1, "path"); /* package.path = "concatenated string" */
}
Beispiel #16
0
/** Initialize the Lua VM
 * \param xdg An xdg handle to use to get XDG basedir.
 */
void
luaA_init(xdgHandle* xdg)
{
    lua_State *L;
    static const struct luaL_Reg awesome_lib[] =
    {
        { "quit", luaA_quit },
        { "exec", luaA_exec },
        { "spawn", luaA_spawn },
        { "restart", luaA_restart },
        { "connect_signal", luaA_awesome_connect_signal },
        { "disconnect_signal", luaA_awesome_disconnect_signal },
        { "emit_signal", luaA_awesome_emit_signal },
        { "systray", luaA_systray },
        { "load_image", luaA_load_image },
        { "__index", luaA_awesome_index },
        { NULL, NULL }
    };

    L = globalconf.L = luaL_newstate();

    /* Set panic function */
    lua_atpanic(L, luaA_panic);

    /* Set error handling function */
    lualib_dofunction_on_error = luaA_dofunction_on_error;

    luaL_openlibs(L);

    luaA_fixups(L);

    luaA_object_setup(L);

    /* Export awesome lib */
    luaA_openlib(L, "awesome", awesome_lib, awesome_lib);

    /* Export root lib */
    luaA_registerlib(L, "root", awesome_root_lib);
    lua_pop(L, 1); /* luaA_registerlib() leaves the table on stack */

#ifdef WITH_DBUS
    /* Export D-Bus lib */
    luaA_registerlib(L, "dbus", awesome_dbus_lib);
    lua_pop(L, 1); /* luaA_registerlib() leaves the table on stack */
#endif

    /* Export keygrabber lib */
    luaA_registerlib(L, "keygrabber", awesome_keygrabber_lib);
    lua_pop(L, 1); /* luaA_registerlib() leaves the table on stack */

    /* Export mousegrabber lib */
    luaA_registerlib(L, "mousegrabber", awesome_mousegrabber_lib);
    lua_pop(L, 1); /* luaA_registerlib() leaves the table on stack */

    /* Export screen */
    luaA_openlib(L, "screen", awesome_screen_methods, awesome_screen_meta);

    /* Export mouse */
    luaA_openlib(L, "mouse", awesome_mouse_methods, awesome_mouse_meta);

    /* Export button */
    button_class_setup(L);

    /* Export tag */
    tag_class_setup(L);

    /* Export window */
    window_class_setup(L);

    /* Export drawable */
    drawable_class_setup(L);

    /* Export drawin */
    drawin_class_setup(L);

    /* Export client */
    client_class_setup(L);

    /* Export keys */
    key_class_setup(L);

    /* Export timer */
    timer_class_setup(L);

    /* add Lua search paths */
    lua_getglobal(L, "package");
    if (LUA_TTABLE != lua_type(L, 1))
    {
        warn("package is not a table");
        return;
    }
    lua_getfield(L, 1, "path");
    if (LUA_TSTRING != lua_type(L, 2))
    {
        warn("package.path is not a string");
        lua_pop(L, 1);
        return;
    }

    /* add XDG_CONFIG_DIR as include path */
    const char * const *xdgconfigdirs = xdgSearchableConfigDirectories(xdg);
    for(; *xdgconfigdirs; xdgconfigdirs++)
    {
        size_t len = a_strlen(*xdgconfigdirs);
        lua_pushliteral(L, ";");
        lua_pushlstring(L, *xdgconfigdirs, len);
        lua_pushliteral(L, "/awesome/?.lua");
        lua_concat(L, 3);

        lua_pushliteral(L, ";");
        lua_pushlstring(L, *xdgconfigdirs, len);
        lua_pushliteral(L, "/awesome/?/init.lua");
        lua_concat(L, 3);

        lua_concat(L, 3); /* concatenate with package.path */
    }

    /* add Lua lib path (/usr/share/awesome/lib by default) */
    lua_pushliteral(L, ";" AWESOME_LUA_LIB_PATH "/?.lua");
    lua_pushliteral(L, ";" AWESOME_LUA_LIB_PATH "/?/init.lua");
    lua_concat(L, 3); /* concatenate with package.path */
    lua_setfield(L, 1, "path"); /* package.path = "concatenated string" */

    lua_getfield(L, 1, "loaded");

    lua_pop(L, 2); /* pop "package" and "package.loaded" */

    signal_add(&global_signals, "debug::error");
    signal_add(&global_signals, "debug::deprecation");
    signal_add(&global_signals, "debug::index::miss");
    signal_add(&global_signals, "debug::newindex::miss");
    signal_add(&global_signals, "systray::update");
    signal_add(&global_signals, "wallpaper_changed");
    signal_add(&global_signals, "refresh");
    signal_add(&global_signals, "exit");
}
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;
}
int cardpeek_update_perform(void)
{
    const char* cardpeek_update_file = path_config_get_string(PATH_CONFIG_FILE_CARDPEEK_UPDATE);
    a_string_t *contents;
    update_t *update;
    int remove;
    update_item_t *item;
    time_t now = time(NULL);
    int updated = 0;
    char *url = NULL;
    char *local_file;
    char *local_dnld;
    unsigned char digest[SHA256_DIGEST_LENGTH];
    a_string_t *url_request;
    unsigned first_update;

    first_update = (unsigned)luax_variable_get_integer("cardpeek.updates.first_update");
    
    /* STEP 1: get cardpeek.update file */

    url=luax_variable_get_strdup("cardpeek.updates.url");

    if (url==NULL)
        url = g_strdup(DEFAULT_UPDATE_URL);

    log_printf(LOG_INFO,"Fetching '%s'",url);

    url_request = a_strnew(NULL);
    a_sprintf(url_request,"%s?u=%x&v=%s",url,first_update,VERSION);

    if (http_download(a_strval(url_request),cardpeek_update_file)==0)
    {
        g_free(url);
        return 0;
    }
    g_free(url);
    a_strfree(url_request);


    /* STEP 2: parse file */

    if ((contents=file_get_contents(cardpeek_update_file))==NULL)
    {
        log_printf(LOG_ERROR,"failed to read update file information.");
        unlink(cardpeek_update_file);
        return 0;
    }

    update = update_new();

    if ((update_load(update,a_strval(contents),a_strlen(contents)))==0)
    {
        unlink(cardpeek_update_file);
        a_strfree(contents);
        update_free(update);
        return 0;
    }
    a_strfree(contents);

    /* log_printf(LOG_DEBUG,"Updates correctly loaded from '%s'",cardpeek_update_file); */
    if ((remove = update_filter_version(update,VERSION))>0)
        log_printf(LOG_WARNING,"%d updates will not be installed because they require a newer version of Cardpeek.");
    
    remove = update_filter_files(update);

    if (update->item_count)
        log_printf(LOG_INFO,"A total of %d files will be updated, %d files are kept unchanged.",update->item_count,remove);
    else
        log_printf(LOG_INFO,"No files will be updated, %d files are kept unchanged.",remove);

    item = update->items;

    while (item)
    {
        local_dnld = new_path(PATH_CONFIG_FOLDER_CARDPEEK,item->file,".download");
        local_file = new_path(PATH_CONFIG_FOLDER_CARDPEEK,item->file,NULL);

        if (http_download(item->url,local_dnld)!=0)
        {        
            if (sha256sum(local_dnld,digest))
            {
                if (memcmp(digest,bytestring_get_data(&item->digest),SHA256_DIGEST_LENGTH)==0)
                {
                    unlink(local_file);

                    if (rename(local_dnld,local_file)==0)
                    {
                        log_printf(LOG_INFO,"Successfuly updated %s", local_file);
                        updated++;
                    }
                    else
                    {
                        log_printf(LOG_ERROR,"Failed to copy %s to %s: %s", 
                                local_dnld,
                                local_file, 
                                strerror(errno));
                    }
                }
                else
                {
                    log_printf(LOG_WARNING,"File %s was not updated: authentication failed.",local_file);
                }
            }
            unlink(local_dnld);
        }
        g_free(local_dnld);
        g_free(local_file);
        item =  item->next; 
    }

    if (updated == update->item_count)
    {    
        luax_variable_set_integer("cardpeek.updates.next_update",(int)(now+7*(24*3600)));  
        luax_config_table_save();
    }

    unlink(cardpeek_update_file);
    update_free(update);

    /* STEP 3: finish */

    return 1;

}
/** The property notify event handler handling xproperties.
 * \param ev The event.
 */
static void
property_handle_propertynotify_xproperty(xcb_property_notify_event_t *ev)
{
    xproperty_t *prop;
    xproperty_t lookup = { .atom = ev->atom };
    buffer_t buf;
    void *obj;

    prop = xproperty_array_lookup(&globalconf.xproperties, &lookup);
    if(!prop)
        /* Property is not registered */
        return;

    if (ev->window != globalconf.screen->root)
    {
        obj = client_getbywin(ev->window);
        if(!obj)
            obj = drawin_getbywin(ev->window);
        if(!obj)
            return;
    } else
        obj = NULL;

    /* Get us the name of the property */
    buffer_inita(&buf, a_strlen(prop->name) + a_strlen("xproperty::") + 1);
    buffer_addf(&buf, "xproperty::%s", prop->name);

    /* And emit the right signal */
    if (obj)
    {
        luaA_object_push(globalconf.L, obj);
        luaA_object_emit_signal(globalconf.L, -1, buf.s, 0);
        lua_pop(globalconf.L, 1);
    } else
        signal_object_emit(globalconf.L, &global_signals, buf.s, 0);
    buffer_wipe(&buf);
}

/** The property notify event handler.
 * \param ev The event.
 */
void
property_handle_propertynotify(xcb_property_notify_event_t *ev)
{
    int (*handler)(uint8_t state,
                   xcb_window_t window) = NULL;

    globalconf.timestamp = ev->time;

    property_handle_propertynotify_xproperty(ev);

    /* Find the correct event handler */
#define HANDLE(atom_, cb) \
    if (ev->atom == atom_) \
    { \
        handler = cb; \
    } else
#define END return

    /* Xembed stuff */
    HANDLE(_XEMBED_INFO, property_handle_xembed_info)

    /* ICCCM stuff */
    HANDLE(XCB_ATOM_WM_TRANSIENT_FOR, property_handle_wm_transient_for)
    HANDLE(WM_CLIENT_LEADER, property_handle_wm_client_leader)
    HANDLE(XCB_ATOM_WM_NORMAL_HINTS, property_handle_wm_normal_hints)
    HANDLE(XCB_ATOM_WM_HINTS, property_handle_wm_hints)
    HANDLE(XCB_ATOM_WM_NAME, property_handle_wm_name)
    HANDLE(XCB_ATOM_WM_ICON_NAME, property_handle_wm_icon_name)
    HANDLE(XCB_ATOM_WM_CLASS, property_handle_wm_class)
    HANDLE(WM_PROTOCOLS, property_handle_wm_protocols)
    HANDLE(XCB_ATOM_WM_CLIENT_MACHINE, property_handle_wm_client_machine)
    HANDLE(WM_WINDOW_ROLE, property_handle_wm_window_role)

    /* EWMH stuff */
    HANDLE(_NET_WM_NAME, property_handle_net_wm_name)
    HANDLE(_NET_WM_ICON_NAME, property_handle_net_wm_icon_name)
    HANDLE(_NET_WM_STRUT_PARTIAL, property_handle_net_wm_strut_partial)
    HANDLE(_NET_WM_ICON, property_handle_net_wm_icon)
    HANDLE(_NET_WM_PID, property_handle_net_wm_pid)
    HANDLE(_NET_WM_WINDOW_OPACITY, property_handle_net_wm_opacity)

    /* background change */
    HANDLE(_XROOTPMAP_ID, property_handle_xrootpmap_id)

    /* If nothing was found, return */
    END;

#undef HANDLE
#undef END

    (*handler)(ev->state, ev->window);
}