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
130
131
132
133
134
135
136
137
|
#include <glib.h>
#include <xcb/xcb.h>
#include <xcb/xcb_ewmh.h>
#include <xcb/xcb_xrm.h>
#include <xcb/xcb_errors.h>
#include <xcb/randr.h>
#include "log.h"
#include "connection.h"
struct Connection {
xcb_connection_t *connection;
xcb_screen_t *screen;
xcb_randr_screen_size_t *screen_size;
double screen_dpi;
xcb_visualtype_t *visual_type;
xcb_depth_t *depth;
xcb_xrm_database_t *database;
xcb_errors_context_t *errors;
xcb_ewmh_connection_t ewmh;
};
static bool query_xrm(Connection *con, const char *res, char **value)
{
if (xcb_xrm_resource_get_string(con->database, res, res, value) >= 0) {
log_debug("Xrm query '%s' found '%s'", res, *value);
return true;
}
log_debug("Xrm query '%s' not found", res);
return false;
}
static void update_scale(Connection *con)
{
char *dpi_value;
if (query_xrm(con, "Xft.dpi", &dpi_value)) {
con->screen_dpi = strtod(dpi_value, NULL);
g_free(dpi_value);
} else {
con->screen_dpi = (double)con->screen_size->height * 25.4 / (double)con->screen_size->mheight;
log_debug("Fallback dpi value '%.2lf'", con->screen_dpi);
}
}
Connection *connection_create()
{
Connection *con = g_malloc0(sizeof(Connection));
g_assert_nonnull(con);
int preferred_screen = 0;
con->connection = xcb_connect(NULL, &preferred_screen);
g_assert_true(con->connection != NULL && !xcb_connection_has_error(con->connection));
log_debug("Xcb connection established");
log_debug("Default screen %d", preferred_screen);
xcb_screen_iterator_t iter = xcb_setup_roots_iterator(xcb_get_setup(con->connection));
while (preferred_screen != 0 && iter.rem) {
xcb_screen_next(&iter);
preferred_screen--;
}
con->screen = iter.data;
xcb_generic_error_t *error;
xcb_randr_query_version_cookie_t version_cookie = xcb_randr_query_version(con->connection,
XCB_RANDR_MAJOR_VERSION,
XCB_RANDR_MINOR_VERSION);
xcb_randr_query_version_reply_t *randr_version = xcb_randr_query_version_reply(con->connection,
version_cookie,
&error);
g_assert_null(error);
log_debug("RandR loaded [version=%d.%d]", randr_version->major_version, randr_version->minor_version);
g_assert_cmpint(randr_version->major_version, >=, 1);
xcb_randr_get_screen_info_cookie_t cookie = xcb_randr_get_screen_info(con->connection, con->screen->root);
xcb_randr_get_screen_info_reply_t *info_reply = xcb_randr_get_screen_info_reply(con->connection, cookie, &error);
g_assert_null(error);
con->screen_size = xcb_randr_get_screen_info_sizes(info_reply);
g_assert_nonnull(con->screen_size);
log_debug("Screen size [width=%d, height=%d]", con->screen_size->width, con->screen_size->height);
xcb_randr_select_input(con->connection,
con->screen->root,
XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE |
XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE |
XCB_RANDR_NOTIFY_MASK_OUTPUT_PROPERTY);
con->database = xcb_xrm_database_from_default(con->connection);
g_assert_nonnull(con->database);
g_assert(xcb_errors_context_new(con->connection, &con->errors) == 0);
log_debug("Xcb errors loaded");
xcb_depth_iterator_t depth_iter = xcb_screen_allowed_depths_iterator(con->screen);
while (depth_iter.rem) {
xcb_visualtype_iterator_t visual_iter = xcb_depth_visuals_iterator(depth_iter.data);
while (visual_iter.rem) {
if (con->screen->root_visual == visual_iter.data->visual_id) {
con->visual_type = visual_iter.data;
con->depth = depth_iter.data;
goto found_visual;
}
xcb_visualtype_next(&visual_iter);
}
xcb_depth_next(&depth_iter);
}
found_visual:
log_debug("Xcb visual type found [id=%u]", con->visual_type->visual_id);
xcb_intern_atom_cookie_t *ewmh_cookie = xcb_ewmh_init_atoms(con->connection, &con->ewmh);
g_assert_true(xcb_ewmh_init_atoms_replies(&con->ewmh, ewmh_cookie, &error));
g_assert_null(error);
log_debug("Xcb ewmh initialized");
update_scale(con);
xcb_flush(con->connection);
log_debug("Xcb set up");
return con;
}
void connection_destroy(Connection *con)
{
xcb_ewmh_connection_wipe(&con->ewmh);
xcb_errors_context_free(con->errors);
xcb_xrm_database_free(con->database);
xcb_disconnect(con->connection);
g_free(con);
}
|