#include #include #include #include #include #include struct _hexagram_window { Display *display; int screen, width, height; Window root, win; Pixmap shape, bg; GC gc; XGCValues gc_values; XdbeBackBuffer buf; XdbeSwapInfo swapinfo; cairo_surface_t *surface_bg, *surface_fg; }; hexagram_window *hexagram_window_new_x11(const char *display, int width, int height) { hexagram_window *window; int major, minor; if ((window = malloc(sizeof(*window))) == NULL) { goto error_malloc_window; } window->width = width; window->height = height; /* * 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; } if ((window->surface_bg = cairo_xlib_surface_create(window->display, window->bg, DefaultVisual(window->display, window->screen), width, height)) == NULL) { goto error_cairo_xlib_surface_create_bg; } cairo_xlib_surface_set_size(window->surface_bg, width, height); if ((window->surface_fg = cairo_xlib_surface_create(window->display, window->buf, DefaultVisual(window->display, window->screen), width, height)) == NULL) { goto error_cairo_xlib_surface_create_fg; } cairo_xlib_surface_set_size(window->surface_fg, width, height); return window; error_cairo_xlib_surface_create_fg: cairo_surface_destroy(window->surface_bg); error_cairo_xlib_surface_create_bg: (void)XFreeGC(window->display, window->gc); 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; } void hexagram_window_destroy(hexagram_window *window) { cairo_surface_destroy(window->surface_fg); cairo_surface_destroy(window->surface_bg); (void)XFreeGC(window->display, window->gc); (void)XFreePixmap(window->display, window->bg); if (window->buf != window->win) { (void)XdbeDeallocateBackBufferName(window->display, window->buf); } (void)XUnmapWindow(window->display, window->win); (void)XDestroyWindow(window->display, window->win); } Display *hexagram_window_display(hexagram_window *window) { return window->display; } int hexagram_window_display_fd(hexagram_window *window) { return ConnectionNumber(window->display); } int hexagram_window_show(hexagram_window *window) { if (XSelectInput(window->display, window->win, HEXAGRAM_WINDOW_EVENT_MASK) == 0) { goto error_x; } if (XMapWindow(window->display, window->win) == 0) { goto error_x; } return 0; error_x: return -1; } int hexagram_window_refresh_bg(hexagram_window *window) { return XCopyArea(window->display, window->bg, window->buf, window->gc, 0, 0, window->width, window->height, 0, 0) == 0? -1: 1; } int hexagram_window_swap_buffer(hexagram_window *window) { return XdbeSwapBuffers(window->display, &window->swapinfo, 1) == 0? -1: 1; } cairo_t *hexagram_window_create_bg_context(hexagram_window *window) { return cairo_create(window->surface_bg); } cairo_t *hexagram_window_create_fg_context(hexagram_window *window) { return cairo_create(window->surface_fg); }