diff --git a/src/window.c b/src/window.c new file mode 100644 index 0000000..b578b3e --- /dev/null +++ b/src/window.c @@ -0,0 +1,142 @@ +#include + +#include +#include + +#include + +struct _hexagram_window { + Display *display; + + int screen; + + unsigned int width, + height; + + Window root, + win; + + Pixmap shape, + bg; + + GC gc; + + XGCValues gc_values; + + XdbeBackBuffer buf; + XdbeSwapInfo swapinfo; +}; + +hexagram_window *hexagram_window_new_x11(const char *display, + unsigned int width, + unsigned int height) { + hexagram_window *window; + int major, minor; + + if ((window = malloc(sizeof(*window))) == NULL) { + goto error_malloc_window; + } + + /* + * Connect to the X display + */ + if ((window->display = XOpenDisplay(display)) == NULL) { + goto error_x_open_display; + } + + window->screen = DefaultScreen(window->display); + window->root = DefaultRootWindow(window->display); + + /* + * Create the X window + */ + if ((window->win = XCreateSimpleWindow(window->display, + window->root, + 0, 0, + width, height, 0, 0, 0)) == 0) { + goto error_x_create_simple_window; + } + + /* + * Create a back buffer, if the Xdbe extension is available. If not, render + * directly to the window, at the cost of flickering. + */ + if (XdbeQueryExtension(window->display, &major, &minor)) { + if ((window->buf = XdbeAllocateBackBufferName(window->display, + window->win, + XdbeBackground)) == 0) { + goto error_x_dbe_allocate_back_buffer_name; + } + + window->swapinfo.swap_window = window->win; + window->swapinfo.swap_action = XdbeBackground; + } else { + window->buf = window->win; + } + + if ((window->bg = XCreatePixmap(window->display, + window->win, width, height, 24)) == 0) { + goto error_x_create_pixmap_bg; + } + + window->gc_values.foreground = 0x000000; + window->gc_values.background = 0xffffff; + window->gc_values.graphics_exposures = 0; + + if ((window->gc = XCreateGC(window->display, + window->win, + HEXAGRAM_WINDOW_GC_FLAGS, + &window->gc_values)) == 0) { + goto error_x_create_gc; + } + + return window; + +error_x_create_gc: + (void)XFreePixmap(window->display, window->bg); + +error_x_create_pixmap_bg: + if (window->buf != window->win) { + (void)XdbeDeallocateBackBufferName(window->display, window->buf); + } + +error_x_dbe_allocate_back_buffer_name: + (void)XDestroyWindow(window->display, window->win); + +error_x_create_simple_window: + (void)XCloseDisplay(window->display); + +error_x_open_display: + free(window); + +error_malloc_window: + return NULL; +} + +int hexagram_window_show(hexagram_window *window) { + if (XSelectInput(window->display, window->win, + ExposureMask | ButtonPressMask | KeyPressMask) == 0) { + goto error_x; + } + + if (XMapWindow(window->display, window->win) == 0) { + goto error_x; + } + + return 0; + +error_x: + return -1; +} + +void hexagram_window_destroy(hexagram_window *window) { + (void)XFreeGC(window->display, window->gc); + + (void)XFreePixmap(window->display, window->bg); + + if (window->buf != window->win) { + (void)XdbeDeallocateBackBufferName(window->display, window->buf); + } + + XUnmapWindow(window->display, window->win); +}