2 changed files with 314 additions and 37 deletions
@ -0,0 +1,262 @@ |
|||||
|
#include <assert.h> |
||||
|
#include <cairo-xcb.h> |
||||
|
#include <cairo.h> |
||||
|
#include <stdio.h> |
||||
|
#include <stdlib.h> |
||||
|
#include <string.h> |
||||
|
#include <time.h> |
||||
|
#include <unistd.h> |
||||
|
#include <xcb/xcb.h> |
||||
|
|
||||
|
void |
||||
|
print_cairo_format(cairo_format_t format) { |
||||
|
switch (format) { |
||||
|
case CAIRO_FORMAT_INVALID: |
||||
|
printf("Invalid\n"); |
||||
|
break; |
||||
|
case CAIRO_FORMAT_ARGB32: |
||||
|
printf("ARGB32\n"); |
||||
|
break; |
||||
|
case CAIRO_FORMAT_RGB24: |
||||
|
printf("ARGB32\n"); |
||||
|
break; |
||||
|
case CAIRO_FORMAT_A8: |
||||
|
printf("A8\n"); |
||||
|
break; |
||||
|
case CAIRO_FORMAT_A1: |
||||
|
printf("A1\n"); |
||||
|
break; |
||||
|
case CAIRO_FORMAT_RGB16_565: |
||||
|
printf("RGB16_565\n"); |
||||
|
break; |
||||
|
case CAIRO_FORMAT_RGB30: |
||||
|
printf("RGB30\n"); |
||||
|
break; |
||||
|
default: |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static xcb_visualtype_t* |
||||
|
findVisual(xcb_connection_t *display, |
||||
|
xcb_visualid_t visual) { |
||||
|
|
||||
|
/* Taken from here https://cairographics.org/cookbook/xcbsurface.c/ */ |
||||
|
/* This function basically searches for a xcb_visualtype_t given a visual ID */ |
||||
|
|
||||
|
xcb_screen_iterator_t screen_iter = xcb_setup_roots_iterator(xcb_get_setup(display)); |
||||
|
|
||||
|
for(; screen_iter.rem; xcb_screen_next(&screen_iter)) { |
||||
|
/* Iterate over the screens available */ |
||||
|
|
||||
|
xcb_depth_iterator_t depth_iter = xcb_screen_allowed_depths_iterator(screen_iter.data); |
||||
|
|
||||
|
for (; depth_iter.rem; xcb_depth_next(&depth_iter)) { |
||||
|
/* Iterate over the depths allowed on this screen */ |
||||
|
xcb_visualtype_iterator_t visual_iter = xcb_depth_visuals_iterator(depth_iter.data); |
||||
|
/* depth_iter.data = the number of visuals available */ |
||||
|
|
||||
|
for (; visual_iter.rem; xcb_visualtype_next(&visual_iter)) { |
||||
|
/* Iterate over all of the visuals available */ |
||||
|
if (visual == visual_iter.data->visual_id) { |
||||
|
printf("%u bits per rgb value\n", visual_iter.data->bits_per_rgb_value); |
||||
|
return visual_iter.data; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return NULL; |
||||
|
} |
||||
|
|
||||
|
xcb_screen_t* |
||||
|
allocScreen(xcb_connection_t *display) { |
||||
|
/* Gets a screen from the display connection */ |
||||
|
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; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
swapBuffers(cairo_t *front_cr, |
||||
|
cairo_surface_t *backbuffer_surface, |
||||
|
unsigned char v, |
||||
|
int height) { |
||||
|
|
||||
|
int stride = cairo_image_surface_get_stride(backbuffer_surface); |
||||
|
|
||||
|
unsigned char *data = cairo_image_surface_get_data(backbuffer_surface); |
||||
|
|
||||
|
memset(data, v, stride*height); |
||||
|
|
||||
|
cairo_surface_flush(backbuffer_surface); |
||||
|
|
||||
|
cairo_set_source_surface(front_cr, |
||||
|
backbuffer_surface, |
||||
|
0, |
||||
|
0); |
||||
|
|
||||
|
cairo_paint(front_cr); |
||||
|
cairo_surface_flush(backbuffer_surface); |
||||
|
} |
||||
|
|
||||
|
cairo_surface_t* |
||||
|
allocFrontBuf(xcb_connection_t *display, |
||||
|
xcb_drawable_t drawable, |
||||
|
xcb_screen_t *screen, |
||||
|
int width, |
||||
|
int height) { |
||||
|
|
||||
|
cairo_surface_t *surface = cairo_xcb_surface_create(display, |
||||
|
drawable, |
||||
|
findVisual(display, screen->root_visual), |
||||
|
width, |
||||
|
height); |
||||
|
|
||||
|
printf("Stride = %d\n", cairo_image_surface_get_stride(surface)); |
||||
|
|
||||
|
return surface; |
||||
|
} |
||||
|
|
||||
|
cairo_surface_t* |
||||
|
allocBackBuf(int width, |
||||
|
int height) { |
||||
|
|
||||
|
cairo_format_t format = CAIRO_FORMAT_RGB24; |
||||
|
|
||||
|
cairo_surface_t *surface = cairo_image_surface_create(format, |
||||
|
width, |
||||
|
height); |
||||
|
|
||||
|
int stride = cairo_image_surface_get_stride(surface); |
||||
|
|
||||
|
printf("Stride for image = %d\n", stride); |
||||
|
|
||||
|
/* might not be needed */ |
||||
|
cairo_surface_flush(surface); |
||||
|
|
||||
|
return surface; |
||||
|
} |
||||
|
|
||||
|
xcb_connection_t* |
||||
|
allocDisplay() { |
||||
|
/* 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_window_t |
||||
|
allocWindow(xcb_connection_t *display, |
||||
|
xcb_screen_t *screen, |
||||
|
uint16_t width, |
||||
|
uint16_t height) { |
||||
|
/* Create the window */ |
||||
|
xcb_window_t window = xcb_generate_id(display); |
||||
|
|
||||
|
xcb_cw_t mask = XCB_CW_BACK_PIXEL | 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[2] = {screen->white_pixel, XCB_EVENT_MASK_EXPOSURE}; |
||||
|
|
||||
|
xcb_create_window(display, |
||||
|
XCB_COPY_FROM_PARENT, /* depth (same as root) */ |
||||
|
window, |
||||
|
screen->root, /* parent window */ |
||||
|
0, /* x */ |
||||
|
0, /* y */ |
||||
|
width,/* width */ |
||||
|
height,/* 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; |
||||
|
} |
||||
|
|
||||
|
static struct timespec |
||||
|
genSleep(time_t sec, |
||||
|
long nanosec) { |
||||
|
struct timespec t; |
||||
|
t.tv_sec = sec; |
||||
|
t.tv_nsec = nanosec; |
||||
|
return t; |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
main (void) { |
||||
|
|
||||
|
/* Used to handle the event loop */ |
||||
|
struct timespec req = genSleep(0, 20000000); |
||||
|
struct timespec rem = genSleep(0, 0); |
||||
|
|
||||
|
/* Open up the display */ |
||||
|
xcb_connection_t *display = allocDisplay(); |
||||
|
|
||||
|
/* Get a handle to the screen */ |
||||
|
xcb_screen_t *screen = allocScreen(display); |
||||
|
|
||||
|
int window_height = screen->height_in_pixels; |
||||
|
int window_width = screen->width_in_pixels; |
||||
|
|
||||
|
/* Create a window */ |
||||
|
xcb_window_t window = |
||||
|
allocWindow(display, |
||||
|
screen, |
||||
|
window_width, |
||||
|
window_height); |
||||
|
|
||||
|
/* Map the window to the display */ |
||||
|
xcb_map_window(display, window); |
||||
|
|
||||
|
/* Allocate front buffer (X drawable) */ |
||||
|
cairo_surface_t *frontbuffer_surface = |
||||
|
allocFrontBuf(display, |
||||
|
window, |
||||
|
screen, |
||||
|
window_width, |
||||
|
window_height); |
||||
|
|
||||
|
cairo_t *front_cr = cairo_create(frontbuffer_surface); |
||||
|
|
||||
|
/* Allocate backbuffer (raw pixel buffer) */ |
||||
|
cairo_surface_t *backbuffer_surface = |
||||
|
allocBackBuf(window_width, window_height); |
||||
|
|
||||
|
cairo_t *back_cr = cairo_create(backbuffer_surface); |
||||
|
|
||||
|
unsigned char v = 0; |
||||
|
|
||||
|
while (1) { |
||||
|
swapBuffers(front_cr, |
||||
|
backbuffer_surface, |
||||
|
v, |
||||
|
window_height); |
||||
|
xcb_flush(display); |
||||
|
nanosleep(&req, &rem); |
||||
|
v++; |
||||
|
} |
||||
|
|
||||
|
pause(); |
||||
|
|
||||
|
cairo_destroy(back_cr); |
||||
|
cairo_surface_destroy(backbuffer_surface); |
||||
|
|
||||
|
cairo_destroy(front_cr); |
||||
|
cairo_surface_destroy(frontbuffer_surface); |
||||
|
|
||||
|
return 0; |
||||
|
} |
Loading…
Reference in new issue