aboutsummaryrefslogtreecommitdiff
path: root/connection.c
diff options
context:
space:
mode:
authorFederico Angelilli <code@fedang.net>2023-11-15 22:35:41 +0100
committerFederico Angelilli <code@fedang.net>2023-11-15 22:35:41 +0100
commit22086e50382b99de092899a203e520c30f50b618 (patch)
tree90ca79a7e9fedd52b21d458cf91f1fbd8a56bd06 /connection.c
parent7d795eede96e08bf7673a3264648b33693adea21 (diff)
Add `Connection` to separate xcb setup from window logic
Diffstat (limited to 'connection.c')
-rw-r--r--connection.c137
1 files changed, 137 insertions, 0 deletions
diff --git a/connection.c b/connection.c
new file mode 100644
index 0000000..20c1e6d
--- /dev/null
+++ b/connection.c
@@ -0,0 +1,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);
+}