Created
December 5, 2015 10:38
-
-
Save psychon/0a9491c61a3f57bd3663 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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