From b77ae46cc7996c2513df24a724b367bfa7475cfc Mon Sep 17 00:00:00 2001 From: Wesley Kerfoot Date: Sat, 29 Jun 2019 15:21:50 -0400 Subject: [PATCH] Move to XCB --- blit.c | 262 +++++++++++++++++++++++++++++++++++++------------------- blit2.c | 225 ------------------------------------------------ 2 files changed, 176 insertions(+), 311 deletions(-) delete mode 100644 blit2.c diff --git a/blit.c b/blit.c index f30b999..6783245 100644 --- a/blit.c +++ b/blit.c @@ -1,16 +1,62 @@ -#include -#include -#include #include #include -#include #include - -Display* +#include +#include + + +/* Macro definition to parse X server events + * The ~0x80 is needed to get the lower 7 bits + * XCB supports exactly the events specified in the protocol (33 events). + * This structure contains the type of event received (including a bit for whether it came from the server or another client), + * as well as the data associated with the event + * (e.g. position on the screen where the event was generated, + * mouse button associated with the event, + * region of the screen associated with a "redraw" event, etc). + * The way to read the event's data depends on the event type. + */ +#define RECEIVE_EVENT(ev) (ev->response_type & ~0x80) + +/* + * Here is the definition of xcb_cw_t + typedef enum { + XCB_CW_BACK_PIXMAP = 1L<<0, + XCB_CW_BACK_PIXEL = 1L<<1, + XCB_CW_BORDER_PIXMAP = 1L<<2, + XCB_CW_BORDER_PIXEL = 1L<<3, + XCB_CW_BIT_GRAVITY = 1L<<4, + XCB_CW_WIN_GRAVITY = 1L<<5, + XCB_CW_BACKING_STORE = 1L<<6, + XCB_CW_BACKING_PLANES = 1L<<7, + XCB_CW_BACKING_PIXEL = 1L<<8, + XCB_CW_OVERRIDE_REDIRECT = 1L<<9, + XCB_CW_SAVE_UNDER = 1L<<10, + XCB_CW_EVENT_MASK = 1L<<11, + XCB_CW_DONT_PROPAGATE = 1L<<12, + XCB_CW_COLORMAP = 1L<<13, + XCB_CW_CURSOR = 1L<<14 + } xcb_cw_t; + * Why does this matter? + * This lets us define what events we want to handle + * See here https://xcb.freedesktop.org/tutorial/events/ + */ + +/* TODO + * + * Figure out what resources need to be free'd and figure out a strategy for allocating things better + * Figure out a better way of managing the event loop than nanosleep? + * Figure out which events we need to actually be handling + * Figure out how to resize dynamically (See handmade hero videos for tips) + * Figure out good strategy for only copying changed pixels to window + * Figure out what allocations can fail and what to do if they fail + */ + +xcb_connection_t* getDisplay() { /* Get a display to use */ /* Currently just uses the default display */ - Display *display = XOpenDisplay(NULL); + + xcb_connection_t *display = xcb_connect (NULL, NULL); if (display == NULL) { fprintf(stderr, "Could not open the display! :(\n"); @@ -20,116 +66,160 @@ getDisplay() { return display; } -XColor* -getColor(Display *display, - int screen, +xcb_screen_t* +getScreen(xcb_connection_t *display) { + const xcb_setup_t *setup = xcb_get_setup(display); + xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup); + xcb_screen_t *screen = iter.data; + + return screen; +} + +xcb_window_t +getWindow(xcb_connection_t *display, + xcb_screen_t *screen) { + /* Create the window */ + xcb_window_t window = xcb_generate_id(display); + + xcb_cw_t mask = XCB_CW_EVENT_MASK; + + /* Define all the events we want to handle with xcb */ + /* XCB_EVENT_MASK_EXPOSURE is the "exposure" event */ + /* I.e. it fires when our window shows up on the screen */ + + uint32_t valwin[1] = { XCB_EVENT_MASK_EXPOSURE }; + + xcb_create_window(display, /* Connection */ + XCB_COPY_FROM_PARENT, /* depth (same as root) */ + window, /* window Id */ + screen->root, /* parent window */ + 0, /* x */ + 0, /* y */ + 150, + 150,/* width, height */ + 10, /* border_width */ + XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */ + screen->root_visual, /* visual */ + mask, /* value mask, used for events */ + valwin); /* masks, used for events */ + + return window; +} + +xcb_alloc_color_reply_t* +getColor(xcb_connection_t *display, + xcb_screen_t *screen, + xcb_window_t window, unsigned short red, unsigned short green, unsigned short blue) { - /* Return a new XColor structure */ + /* Return a new xcb color structure */ /* Initialize it with RGB */ - XColor *xcolor = malloc(sizeof (XColor)); + xcb_colormap_t colormapId = xcb_generate_id(display); - xcolor->red = red; - xcolor->green = green; - xcolor->blue = blue; + xcb_create_colormap(display, + XCB_COLORMAP_ALLOC_NONE, + colormapId, + window, + screen->root_visual); - xcolor->flags = DoRed | DoGreen | DoBlue; - XAllocColor(display, - XDefaultColormap(display, screen), - xcolor); - return xcolor; -} + xcb_alloc_color_reply_t *reply = xcb_alloc_color_reply(display, + xcb_alloc_color(display, + colormapId, + red, + green, + blue), + NULL); -int -main(void) { - Window window; - XEvent event; + return reply; +} - Display *display = getDisplay(); - int screen = DefaultScreen(display); - GC gc = XDefaultGC(display, screen); +static struct timespec +genSleep(time_t sec, + long nanosec) { + struct timespec t; + t.tv_sec = sec; + t.tv_nsec = nanosec; + return t; +} - XColor *xcolor = getColor(display, screen, 0xffff, 0xffff, 0xffff); +static xcb_gcontext_t +getGC(xcb_connection_t *display, + xcb_screen_t *screen) { - window = XCreateSimpleWindow(display, - RootWindow(display, screen), - 10, - 10, - 100, - 100, - 1, - WhitePixel(display, screen), - xcolor->pixel); + xcb_drawable_t window = screen->root; - XSelectInput(display, - window, - ExposureMask | KeyPressMask); + xcb_gcontext_t foreground = xcb_generate_id(display); - XMapWindow(display, window); + uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES; + uint32_t values[2] = {screen->black_pixel, 0}; - int depth = DefaultDepth(display, DefaultScreen(display)); + xcb_create_gc(display, + foreground, + window, + mask, + values); - Pixmap pixmap; - pixmap = XCreatePixmap(display, - window, - 100, - 100, - depth); + return foreground; +} - int factor = 0; +int +main(void) { - struct timespec req; - struct timespec rem; + xcb_connection_t *display = getDisplay(); - req.tv_sec = 0; - req.tv_nsec = 20000000; + xcb_screen_t *screen = getScreen(display); - while (1) { - /* Event loop that handles events from the X server's event queue */ - /* Will actually block if there are no events */ + xcb_window_t window = getWindow(display, screen); - XNextEvent(display, &event); - if (event.type == Expose) { + xcb_map_window(display, window); - XColor *boxcolor = getColor(display, screen, 32000, 0, 32000); + xcb_alloc_color_reply_t *xcolor = getColor(display, + screen, + window, + 0xffff, + 0xffff, + 0xffff); - XSetForeground(display, gc, boxcolor->pixel); + xcb_flush(display); - } + /* Used to handle the event loop */ + struct timespec req = genSleep(0, 20000000); + struct timespec rem = genSleep(0, 0); - //if (event.type == KeyPress) { - //break; - //} + xcb_generic_event_t *event; + xcb_expose_event_t *expose; - for(int x = 0; x < 100; x++) { - for(int y = 0; y < 100; y++) { - XDrawPoint(display, pixmap, gc, x, y); + while (1) { + event = xcb_poll_for_event(display); + + if (event != NULL) { + switch RECEIVE_EVENT(event) { + /* TODO encapsulate event handlers in functions */ + case XCB_EXPOSE: { + expose = (xcb_expose_event_t *)event; + printf("Window %u exposed. Region to be redrawn at location (%u,%u), with dimension (%u,%u)\n", + expose->window, expose->x, + expose->y, + expose->width, + expose->height); + break; + } + + default: { + printf ("Unknown event: %u\n", event->response_type); + break; + } + + free(event); } } - factor++; - - XClearWindow(display, window); - - XCopyArea(display, - pixmap, - window, - gc, - 0, - 0, - 100, - 100, - factor, - factor); - nanosleep(&req, &rem); - } - XCloseDisplay(display); - + xcb_disconnect(display); return 0; } diff --git a/blit2.c b/blit2.c deleted file mode 100644 index 6783245..0000000 --- a/blit2.c +++ /dev/null @@ -1,225 +0,0 @@ -#include -#include -#include -#include -#include - - -/* Macro definition to parse X server events - * The ~0x80 is needed to get the lower 7 bits - * XCB supports exactly the events specified in the protocol (33 events). - * This structure contains the type of event received (including a bit for whether it came from the server or another client), - * as well as the data associated with the event - * (e.g. position on the screen where the event was generated, - * mouse button associated with the event, - * region of the screen associated with a "redraw" event, etc). - * The way to read the event's data depends on the event type. - */ -#define RECEIVE_EVENT(ev) (ev->response_type & ~0x80) - -/* - * Here is the definition of xcb_cw_t - typedef enum { - XCB_CW_BACK_PIXMAP = 1L<<0, - XCB_CW_BACK_PIXEL = 1L<<1, - XCB_CW_BORDER_PIXMAP = 1L<<2, - XCB_CW_BORDER_PIXEL = 1L<<3, - XCB_CW_BIT_GRAVITY = 1L<<4, - XCB_CW_WIN_GRAVITY = 1L<<5, - XCB_CW_BACKING_STORE = 1L<<6, - XCB_CW_BACKING_PLANES = 1L<<7, - XCB_CW_BACKING_PIXEL = 1L<<8, - XCB_CW_OVERRIDE_REDIRECT = 1L<<9, - XCB_CW_SAVE_UNDER = 1L<<10, - XCB_CW_EVENT_MASK = 1L<<11, - XCB_CW_DONT_PROPAGATE = 1L<<12, - XCB_CW_COLORMAP = 1L<<13, - XCB_CW_CURSOR = 1L<<14 - } xcb_cw_t; - * Why does this matter? - * This lets us define what events we want to handle - * See here https://xcb.freedesktop.org/tutorial/events/ - */ - -/* TODO - * - * Figure out what resources need to be free'd and figure out a strategy for allocating things better - * Figure out a better way of managing the event loop than nanosleep? - * Figure out which events we need to actually be handling - * Figure out how to resize dynamically (See handmade hero videos for tips) - * Figure out good strategy for only copying changed pixels to window - * Figure out what allocations can fail and what to do if they fail - */ - -xcb_connection_t* -getDisplay() { - /* Get a display to use */ - /* Currently just uses the default display */ - - xcb_connection_t *display = xcb_connect (NULL, NULL); - - if (display == NULL) { - fprintf(stderr, "Could not open the display! :(\n"); - exit(1); - } - - return display; -} - -xcb_screen_t* -getScreen(xcb_connection_t *display) { - const xcb_setup_t *setup = xcb_get_setup(display); - xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup); - xcb_screen_t *screen = iter.data; - - return screen; -} - -xcb_window_t -getWindow(xcb_connection_t *display, - xcb_screen_t *screen) { - /* Create the window */ - xcb_window_t window = xcb_generate_id(display); - - xcb_cw_t mask = XCB_CW_EVENT_MASK; - - /* Define all the events we want to handle with xcb */ - /* XCB_EVENT_MASK_EXPOSURE is the "exposure" event */ - /* I.e. it fires when our window shows up on the screen */ - - uint32_t valwin[1] = { XCB_EVENT_MASK_EXPOSURE }; - - xcb_create_window(display, /* Connection */ - XCB_COPY_FROM_PARENT, /* depth (same as root) */ - window, /* window Id */ - screen->root, /* parent window */ - 0, /* x */ - 0, /* y */ - 150, - 150,/* width, height */ - 10, /* border_width */ - XCB_WINDOW_CLASS_INPUT_OUTPUT, /* class */ - screen->root_visual, /* visual */ - mask, /* value mask, used for events */ - valwin); /* masks, used for events */ - - return window; -} - -xcb_alloc_color_reply_t* -getColor(xcb_connection_t *display, - xcb_screen_t *screen, - xcb_window_t window, - unsigned short red, - unsigned short green, - unsigned short blue) { - /* Return a new xcb color structure */ - /* Initialize it with RGB */ - - xcb_colormap_t colormapId = xcb_generate_id(display); - - xcb_create_colormap(display, - XCB_COLORMAP_ALLOC_NONE, - colormapId, - window, - screen->root_visual); - - - xcb_alloc_color_reply_t *reply = xcb_alloc_color_reply(display, - xcb_alloc_color(display, - colormapId, - red, - green, - blue), - NULL); - - return reply; -} - -static struct timespec -genSleep(time_t sec, - long nanosec) { - struct timespec t; - t.tv_sec = sec; - t.tv_nsec = nanosec; - return t; -} - -static xcb_gcontext_t -getGC(xcb_connection_t *display, - xcb_screen_t *screen) { - - xcb_drawable_t window = screen->root; - - xcb_gcontext_t foreground = xcb_generate_id(display); - - uint32_t mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES; - uint32_t values[2] = {screen->black_pixel, 0}; - - xcb_create_gc(display, - foreground, - window, - mask, - values); - - return foreground; -} - -int -main(void) { - - xcb_connection_t *display = getDisplay(); - - xcb_screen_t *screen = getScreen(display); - - xcb_window_t window = getWindow(display, screen); - - xcb_map_window(display, window); - - xcb_alloc_color_reply_t *xcolor = getColor(display, - screen, - window, - 0xffff, - 0xffff, - 0xffff); - - xcb_flush(display); - - /* Used to handle the event loop */ - struct timespec req = genSleep(0, 20000000); - struct timespec rem = genSleep(0, 0); - - xcb_generic_event_t *event; - xcb_expose_event_t *expose; - - while (1) { - event = xcb_poll_for_event(display); - - if (event != NULL) { - switch RECEIVE_EVENT(event) { - /* TODO encapsulate event handlers in functions */ - case XCB_EXPOSE: { - expose = (xcb_expose_event_t *)event; - printf("Window %u exposed. Region to be redrawn at location (%u,%u), with dimension (%u,%u)\n", - expose->window, expose->x, - expose->y, - expose->width, - expose->height); - break; - } - - default: { - printf ("Unknown event: %u\n", event->response_type); - break; - } - - free(event); - } - } - - nanosleep(&req, &rem); - } - - xcb_disconnect(display); - return 0; -}