1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
#include <stdbool.h>
#include <assert.h>
#include <glib.h>
#include <math.h>
#include <cairo.h>
#include <cairo-xcb.h>
#include <xcb/xcb.h>
#include <xcb/xcb_aux.h>
#include <xcb/xproto.h>
#include <xcb/xcb_icccm.h>
#include <xcb/xcb_xrm.h>
#include "x11.h"
struct Window {
xcb_screen_t *screen;
xcb_connection_t *connection;
xcb_xrm_database_t *database;
xcb_drawable_t window;
xcb_visualtype_t *visual_type;
cairo_surface_t *surface;
cairo_t *cr;
double dpi;
};
Window *window_create(void)
{
Window *win = g_malloc0(sizeof(Window));
int preferred_screen = 0;
win->connection = xcb_connect(NULL, &preferred_screen);
assert(win->connection != NULL && !xcb_connection_has_error(win->connection));
win->database = xcb_xrm_database_from_default(win->connection);
assert(win->database != NULL);
char *dpi_value;
if (xcb_xrm_resource_get_string(win->database, "Xft.dpi", "Xft.dpi", &dpi_value) >= 0) {
win->dpi = strtod(dpi_value, NULL);
g_free(dpi_value);
} else {
// TODO: Calculate automatically somehow
win->dpi = 96.0;
}
xcb_screen_iterator_t iter = xcb_setup_roots_iterator(xcb_get_setup(win->connection));
while (preferred_screen != 0 && iter.rem) {
xcb_screen_next(&iter);
preferred_screen--;
}
win->screen = iter.data;
win->window = xcb_generate_id(win->connection);
int y = 0, x = 0, h = 300, w = 400;
xcb_create_window(win->connection,
XCB_COPY_FROM_PARENT,
win->window, win->screen->root,
y, x, h, w, 0,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
win->screen->root_visual,
XCB_CW_BACK_PIXEL,
//XCB_CW_BACK_PIXEL | XCB_CW_BACK_PIXMAP | XCB_CW_OVERRIDE_REDIRECT |
// XCB_CW_BORDER_PIXEL | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP,
&win->screen->white_pixel);
xcb_icccm_set_wm_name(win->connection, win->window, XCB_ATOM_STRING, 8, strlen("comet"), "comet");
xcb_map_window(win->connection, win->window);
xcb_flush(win->connection);
xcb_depth_iterator_t depth_iter = xcb_screen_allowed_depths_iterator(win->screen);
while (depth_iter.rem) {
xcb_visualtype_iterator_t visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
while (visual_iter.rem) {
if (win->screen->root_visual == visual_iter.data->visual_id) {
win->visual_type = visual_iter.data;
goto done;
}
xcb_visualtype_next(&visual_iter);
}
xcb_depth_next(&depth_iter);
}
done:
win->surface = cairo_xcb_surface_create(win->connection, win->window, win->visual_type, w, h);
win->cr = cairo_create(win->surface);
return win;
}
cairo_t *window_get_context(Window *win)
{
return win->cr;
}
double window_get_scale(Window *win)
{
return MAX(1, win->dpi/96.);
}
void window_paint_surface(Window *win, cairo_surface_t *surface, int width, int height)
{
double scale = window_get_scale(win);
cairo_xcb_surface_set_size(win->surface, round(width * scale), round(height * scale));
xcb_clear_area(win->connection, false, win->window, 0, 0, 0, 0);
cairo_set_source_surface(win->cr, surface, 0, 0);
cairo_paint(win->cr);
cairo_show_page(win->cr);
xcb_flush(win->connection);
}
void window_destroy(Window *win)
{
cairo_destroy(win->cr);
cairo_surface_destroy(win->surface);
xcb_xrm_database_free(win->database);
xcb_disconnect(win->connection);
g_free(win);
}
// vim: ts=4 sw=4 et
|