diff options
Diffstat (limited to 'connection.c')
| -rw-r--r-- | connection.c | 137 |
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); +} |
