#include #include "demo.h" #include #include #include struct glx_device { struct device base; struct framebuffer fb; Display *display; Window drawable; GLXContext ctx; cairo_device_t *device; int double_buffered; }; static void destroy (struct framebuffer *fb) { } static void show (struct framebuffer *fb) { struct glx_device *device = (struct glx_device *) fb->device; if (device->double_buffered) { cairo_t *cr = cairo_create (device->base.scanout); cairo_set_source_surface (cr, fb->surface, 0, 0); cairo_paint (cr); cairo_destroy (cr); } cairo_gl_surface_swapbuffers (device->base.scanout); } static struct framebuffer * get_fb (struct device *abstract_device) { struct glx_device *device = (struct glx_device *) abstract_device; return &device->fb; } struct device * glx_open (int argc, char **argv) { int rgba_attribs[] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_ALPHA_SIZE, 1, GLX_DOUBLEBUFFER, None }; XVisualInfo *vi; struct glx_device *device; Display *dpy; Screen *scr; int screen; XSetWindowAttributes attr; enum split split; int i, x, y; dpy = XOpenDisplay (NULL); if (dpy == NULL) return NULL; device = malloc(sizeof(struct glx_device)); device->base.name = "glx"; device->base.get_framebuffer = get_fb; device->display = dpy; device->fb.device = &device->base; device->fb.show = show; device->fb.destroy = destroy; device->double_buffered = 0; for (i = 1; i < argc; i++) { if (strcmp (argv[i], "--double") == 0) device->double_buffered = 1; } screen = DefaultScreen (dpy); scr = XScreenOfDisplay (dpy, screen); device->base.width = WidthOfScreen (scr); device->base.height = HeightOfScreen (scr); device_get_size (argc, argv, &device->base.width, &device->base.height); x = y = 0; switch ((split = device_get_split(argc, argv))) { case SPLIT_NONE: break; case SPLIT_LEFT: device->base.width /= 2; break; case SPLIT_RIGHT: x = device->base.width /= 2; break; case SPLIT_TOP: device->base.height /= 2; break; case SPLIT_BOTTOM: y = device->base.height /= 2; break; case SPLIT_BOTTOM_LEFT: device->base.width /= 2; y = device->base.height /= 2; break; case SPLIT_BOTTOM_RIGHT: x = device->base.width /= 2; y = device->base.height /= 2; break; case SPLIT_TOP_LEFT: device->base.width /= 2; device->base.height /= 2; break; case SPLIT_TOP_RIGHT: x = device->base.width /= 2; device->base.height /= 2; break; case SPLIT_1_16...SPLIT_16_16: split -= SPLIT_1_16; x = split & 3; y = (split >> 2) & 3; device->base.width /= 4; device->base.height /= 4; x *= device->base.width; y *= device->base.height; break; } vi = glXChooseVisual (dpy, DefaultScreen (dpy), rgba_attribs); if (vi == NULL) { XCloseDisplay (dpy); free (device); return NULL; } attr.colormap = XCreateColormap (dpy, RootWindow (dpy, vi->screen), vi->visual, AllocNone); attr.border_pixel = 0; attr.override_redirect = True; device->drawable = XCreateWindow (dpy, DefaultRootWindow (dpy), x, y, device->base.width, device->base.height, 0, vi->depth, InputOutput, vi->visual, CWOverrideRedirect | CWBorderPixel | CWColormap, &attr); XMapWindow (dpy, device->drawable); device->ctx = glXCreateContext(dpy, vi, NULL, True); XFree(vi); device->device = cairo_glx_device_create(dpy, device->ctx); device->base.scanout = cairo_gl_surface_create_for_window (device->device, device->drawable, device->base.width, device->base.height); if (device->double_buffered) { device->fb.surface = cairo_surface_create_similar (device->base.scanout, CAIRO_CONTENT_COLOR, device->base.width, device->base.height); } else { device->fb.surface = device->base.scanout; } return &device->base; }