2019-05-27 23:28:21 -05:00
|
|
|
#include <stdio.h>
|
2019-05-27 22:33:02 -05:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include <X11/Xlib.h>
|
|
|
|
#include <X11/extensions/Xdbe.h>
|
2019-05-27 23:05:25 -05:00
|
|
|
#include <cairo-xlib.h>
|
2019-05-27 22:33:02 -05:00
|
|
|
|
|
|
|
#include <hexagram/window.h>
|
|
|
|
|
|
|
|
struct _hexagram_window {
|
|
|
|
Display *display;
|
|
|
|
|
2019-05-28 00:25:16 -05:00
|
|
|
int screen,
|
|
|
|
width, height;
|
2019-05-27 22:33:02 -05:00
|
|
|
|
|
|
|
Window root,
|
|
|
|
win;
|
|
|
|
|
|
|
|
Pixmap shape,
|
|
|
|
bg;
|
|
|
|
|
|
|
|
GC gc;
|
|
|
|
|
|
|
|
XGCValues gc_values;
|
|
|
|
|
|
|
|
XdbeBackBuffer buf;
|
|
|
|
XdbeSwapInfo swapinfo;
|
2019-05-27 23:05:25 -05:00
|
|
|
|
|
|
|
cairo_surface_t *surface_bg,
|
|
|
|
*surface_fg;
|
2019-05-27 22:33:02 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
hexagram_window *hexagram_window_new_x11(const char *display,
|
2019-05-28 00:25:16 -05:00
|
|
|
int width,
|
|
|
|
int height) {
|
2019-05-27 22:33:02 -05:00
|
|
|
hexagram_window *window;
|
|
|
|
int major, minor;
|
|
|
|
|
|
|
|
if ((window = malloc(sizeof(*window))) == NULL) {
|
|
|
|
goto error_malloc_window;
|
|
|
|
}
|
|
|
|
|
2019-05-28 00:25:16 -05:00
|
|
|
window->width = width;
|
|
|
|
window->height = height;
|
|
|
|
|
2019-05-27 22:33:02 -05:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
2019-05-27 23:05:25 -05:00
|
|
|
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,
|
2019-05-28 00:25:16 -05:00
|
|
|
width, height);
|
2019-05-27 23:05:25 -05:00
|
|
|
|
|
|
|
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,
|
2019-05-28 00:25:16 -05:00
|
|
|
width,
|
|
|
|
height);
|
2019-05-27 23:05:25 -05:00
|
|
|
|
2019-05-27 22:33:02 -05:00
|
|
|
return window;
|
|
|
|
|
2019-05-27 23:05:25 -05:00
|
|
|
error_cairo_xlib_surface_create_fg:
|
|
|
|
cairo_surface_destroy(window->surface_bg);
|
|
|
|
|
|
|
|
error_cairo_xlib_surface_create_bg:
|
|
|
|
(void)XFreeGC(window->display, window->gc);
|
|
|
|
|
2019-05-27 22:33:02 -05:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-05-27 23:05:25 -05:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-05-28 00:58:18 -05:00
|
|
|
Display *hexagram_window_display(hexagram_window *window) {
|
2019-05-27 23:28:21 -05:00
|
|
|
return window->display;
|
|
|
|
}
|
|
|
|
|
2019-05-28 00:32:22 -05:00
|
|
|
int hexagram_window_display_fd(hexagram_window *window) {
|
2019-05-27 23:28:21 -05:00
|
|
|
return ConnectionNumber(window->display);
|
|
|
|
}
|
|
|
|
|
2019-05-27 22:33:02 -05:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-05-28 00:36:07 -05:00
|
|
|
int hexagram_window_refresh_bg(hexagram_window *window) {
|
2019-05-27 23:28:21 -05:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-05-27 23:05:25 -05:00
|
|
|
cairo_t *hexagram_window_create_bg_context(hexagram_window *window) {
|
|
|
|
return cairo_create(window->surface_bg);
|
|
|
|
}
|
2019-05-27 22:33:02 -05:00
|
|
|
|
2019-05-27 23:05:25 -05:00
|
|
|
cairo_t *hexagram_window_create_fg_context(hexagram_window *window) {
|
|
|
|
return cairo_create(window->surface_fg);
|
2019-05-27 22:33:02 -05:00
|
|
|
}
|