Skip to content

Instantly share code, notes, and snippets.

@psychon
Created December 5, 2015 10:38
Show Gist options
  • Save psychon/0a9491c61a3f57bd3663 to your computer and use it in GitHub Desktop.
Save psychon/0a9491c61a3f57bd3663 to your computer and use it in GitHub Desktop.
#include <alloca.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <xcb/xcb.h>
#define NEXT_ARG(argc, argv, val) do { \
if (argc <= 0) { \
fprintf(stderr, "Expected more arguments\n"); \
exit(1); \
} \
val = atoi(argv[0]); \
argc--; \
argv++; \
} while (0)
static xcb_connection_t *conn;
static xcb_screen_t *screen;
static xcb_window_t win;
static xcb_atom_t _NET_WM_ICON;
static void connect(void)
{
xcb_intern_atom_reply_t *r;
conn = xcb_connect(NULL, NULL);
if (xcb_connection_has_error(conn))
{
fprintf(stderr, "Could not connect to X11 server, status %d\n",
xcb_connection_has_error(conn));
exit(1);
}
screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
r = xcb_intern_atom_reply(conn,
xcb_intern_atom(conn, 0, 12, "_NET_WM_ICON"),
NULL);
if (!r)
{
fprintf(stderr, "Could not intern the _NET_WM_ICON atom\n");
exit(1);
}
_NET_WM_ICON = r->atom;
free(r);
}
static void append_icon_bad(uint32_t width, uint32_t height, uint32_t length)
{
uint32_t *data;
if (4 * length >= UINT32_MAX - 2) {
fprintf(stderr, "Icon of size %dx%d and length %d is too large\n",
(int) width, (int) height, (int) length);
exit(1);
}
data = alloca(4 * length);
memset(data, 0x80, 4 * length);
if (length >= 1)
data[0] = width;
if (length >= 2)
data[1] = height;
xcb_change_property(conn, XCB_PROP_MODE_APPEND, win, _NET_WM_ICON,
XCB_ATOM_CARDINAL, 32, length, data);
}
static void append_icon_good(uint32_t width, uint32_t height)
{
uint64_t length = width * (uint64_t) height;
if (length >= UINT32_MAX - 2) {
fprintf(stderr, "Icon of size %dx%d is too large\n",
(int) width, (int) height);
exit(1);
}
append_icon_bad(width, height, (uint32_t) length + 2);
}
int main(int argc, char *argv[])
{
uint32_t width, height, length;
connect();
win = xcb_generate_id(conn);
xcb_create_window(conn, screen->root_depth, win, screen->root,
0, 0, 100, 100, 0, XCB_COPY_FROM_PARENT,
screen->root_visual, 0, NULL);
/* argv[0] is the program name, skip that */
argc--;
argv++;
/* Append a number of valid icons */
while (argc > 3) {
NEXT_ARG(argc, argv, width);
NEXT_ARG(argc, argv, height);
append_icon_good(width, height);
}
/* Then comes some invalid one */
NEXT_ARG(argc, argv, width);
NEXT_ARG(argc, argv, height);
NEXT_ARG(argc, argv, length);
append_icon_bad(width, height, length);
/* Now make the window visible and wait */
xcb_map_window(conn, win);
xcb_flush(conn);
while (!xcb_connection_has_error(conn)) {
xcb_generic_event_t *event = xcb_wait_for_event(conn);
if (event != NULL) {
printf("Got event of type %d = 0x%x\n",
event->response_type, event->response_type);
free(event);
}
}
printf("Connection broke, status: %d\n", xcb_connection_has_error(conn));
xcb_disconnect(conn);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment