|
// FILE: src/main.cpp |
|
#include <xcb/xcb.h> |
|
#include <iostream> |
|
|
|
#include "cairo_utils.hpp" |
|
|
|
/** |
|
* Draws vector graphics with cairo on a xcb window |
|
* Leave application with <Ctrl-C> as key events not handled yet |
|
*/ |
|
int main() { |
|
// connect to X server identified by `$DISPLAY` |
|
int screen_number; |
|
xcb_connection_t* connection = xcb_connect(NULL, &screen_number); |
|
|
|
// data returned by server after connection |
|
const xcb_setup_t* setup = xcb_get_setup(connection); |
|
|
|
// get screens (monitors) managed by display (i.e. X server) |
|
xcb_screen_iterator_t iter_screens = xcb_setup_roots_iterator(setup); |
|
xcb_screen_t* screen = iter_screens.data; // first screen |
|
uint16_t width_screen = screen->width_in_pixels; |
|
uint16_t height_screen = screen->height_in_pixels; |
|
|
|
std::cout << "# of screen: " << iter_screens.rem << '\n'; |
|
std::cout << "screen width: " << width_screen << '\n'; |
|
std::cout << "screen height: " << height_screen << '\n'; |
|
|
|
// screen supports multiple depths, each depth having multiple visual types (color mapping) |
|
xcb_visualtype_t* visual_type; |
|
|
|
xcb_depth_iterator_t iter_depths = xcb_screen_allowed_depths_iterator(screen); |
|
for (; iter_depths.rem; xcb_depth_next(&iter_depths)) { |
|
xcb_depth_t* depth = iter_depths.data; |
|
|
|
xcb_visualtype_iterator_t iter_visuals = xcb_depth_visuals_iterator(depth); |
|
for (; iter_visuals.rem; xcb_visualtype_next(&iter_visuals)) { |
|
xcb_visualtype_t* visual_type_current = iter_visuals.data; |
|
|
|
if (visual_type_current->visual_id == screen->root_visual) { |
|
visual_type = visual_type_current; |
|
goto endloop; |
|
} |
|
} |
|
} |
|
|
|
endloop: |
|
// allocate an XID to identify object created (e.g. window, pixmap...) |
|
xcb_window_t window = xcb_generate_id(connection); |
|
|
|
// white bg & register for selected events (value_list items respect bit-order in `xcb_cw_t` enum) |
|
uint32_t value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK; |
|
uint32_t value_list[] = { |
|
screen->white_pixel, |
|
XCB_EVENT_MASK_EXPOSURE, |
|
}; |
|
int width = 500, |
|
height = 500; |
|
|
|
// create window identified by created xid |
|
xcb_create_window( |
|
connection, |
|
XCB_COPY_FROM_PARENT, |
|
window, |
|
screen->root, |
|
0, 0, // x & y |
|
width, height, |
|
10, // border size |
|
XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, |
|
value_mask, value_list); |
|
|
|
// set window title |
|
std::string title = "Hello XCB/Cairo worlds"; |
|
xcb_change_property( |
|
connection, |
|
XCB_PROP_MODE_REPLACE, |
|
window, |
|
XCB_ATOM_WM_NAME, |
|
XCB_ATOM_STRING, |
|
8, |
|
title.length(), |
|
title.c_str()); |
|
|
|
// make a window visible |
|
xcb_map_window(connection, window); |
|
|
|
// send commands to server (forces window to show) |
|
xcb_flush(connection); |
|
|
|
// receiving events (blocking way using infinite loop) |
|
xcb_generic_event_t* event; |
|
while ((event = xcb_wait_for_event(connection))) { |
|
// wait for window to render, otherwise white bg overwrites cairo drawing |
|
// https://gitlab.freedesktop.org/cairo/cairo/-/issues/531 |
|
if (event->response_type == XCB_EXPOSE) { |
|
std::cout << "Rendering graphics with Cairo" << '\n'; |
|
CairoUtils::draw(connection, window, visual_type); |
|
|
|
// send commands to server (forces vector to show) |
|
xcb_flush(connection); |
|
} |
|
|
|
delete event; |
|
} |
|
|
|
// close connection to server |
|
xcb_disconnect(connection); |
|
|
|
return 0; |
|
} |