#include #include #include #include #include "any_log.h" #include "display.h" void display_init(display_t *display) { memset(display, 0, sizeof(display_t)); int preferred_screen = 0; display->connection = xcb_connect(NULL, &preferred_screen); assert(display->connection != NULL && !xcb_connection_has_error(display->connection)); log_value_debug("Connected to xcb", "i:preferred_screen", preferred_screen); xcb_screen_iterator_t iter = xcb_setup_roots_iterator(xcb_get_setup(display->connection)); while (preferred_screen != 0 && iter.rem) { xcb_screen_next(&iter); preferred_screen--; } display->screen = iter.data; xcb_generic_error_t *error; xcb_randr_query_version_cookie_t version_cookie = xcb_randr_query_version(display->connection, XCB_RANDR_MAJOR_VERSION, XCB_RANDR_MINOR_VERSION); xcb_randr_query_version_reply_t *randr_version = xcb_randr_query_version_reply(display->connection, version_cookie, &error); assert(error == NULL); log_value_trace("Found RandR extension", "i:major", randr_version->major_version, "i:minor", randr_version->minor_version); assert(randr_version->major_version >= 1); free(randr_version); xcb_randr_get_screen_info_cookie_t cookie = xcb_randr_get_screen_info(display->connection, display->screen->root); display->info_reply = xcb_randr_get_screen_info_reply(display->connection, cookie, &error); assert(error == NULL); // TODO: Listen to xrandr notify with select input // and select the monitor by name display->screen_size = xcb_randr_get_screen_info_sizes(display->info_reply); assert(display->screen_size != NULL); log_value_info("Display information", "i:width", display->screen_size->width, "i:height", display->screen_size->height); xcb_randr_select_input(display->connection, display->screen->root, XCB_RANDR_NOTIFY_MASK_SCREEN_CHANGE | XCB_RANDR_NOTIFY_MASK_OUTPUT_CHANGE | XCB_RANDR_NOTIFY_MASK_OUTPUT_PROPERTY); log_trace("Searching 32 bit visual"); display->visual_type = xcb_aux_find_visual_by_attrs(display->screen, XCB_VISUAL_CLASS_TRUE_COLOR, 32); display->screen_depth = 32; if (display->visual_type == NULL) { // NOTE: 24 bit visuals don't have the alpha channel for transparency log_trace("Falling back to 24 bit visual"); display->visual_type = xcb_aux_find_visual_by_attrs(display->screen, XCB_VISUAL_CLASS_TRUE_COLOR, 24); display->screen_depth = 24; } assert(display->visual_type != 0); xcb_intern_atom_cookie_t *ewmh_cookie = xcb_ewmh_init_atoms(display->connection, &display->ewmh); assert(xcb_ewmh_init_atoms_replies(&display->ewmh, ewmh_cookie, &error)); assert(error == NULL); log_trace("Initialized xcb_ewmh"); display->database = xcb_xrm_database_from_default(display->connection); assert(display->database != NULL); display_update_scale(display); assert(xcb_errors_context_new(display->connection, &display->errors) == 0); log_trace("Initialized xcb_errors"); xcb_flush(display->connection); } bool display_query_xrm(display_t *display, const char *resource, char **value) { bool found = xcb_xrm_resource_get_string(display->database, resource, NULL, value) >= 0; log_value_trace("Xrm query", "b:found", found, "s:resource", resource, "s:value", *value ? *value : ""); return found; } void display_update_xrm(display_t *display) { xcb_flush(display->connection); xcb_xrm_database_t *database = xcb_xrm_database_from_default(display->connection); if (database == NULL) { log_warn("Xrm database couldn't be updated"); return; } xcb_xrm_database_free(display->database); display->database = database; log_trace("Xrm database updated"); } void display_update_scale(display_t *display) { char *dpi_value; if (display_query_xrm(display, "Xft.dpi", &dpi_value)) { display->screen_dpi = strtod(dpi_value, NULL); free(dpi_value); // Ignore invalid values if (display->screen_dpi != 0) return; } display->screen_dpi = (double)display->screen_size->height * 25.4 / (double)display->screen_size->mheight; log_debug("Fallback dpi value '%.2lf'", display->screen_dpi); } void display_close(display_t *display) { xcb_ewmh_connection_wipe(&display->ewmh); xcb_errors_context_free(display->errors); xcb_xrm_database_free(display->database); xcb_disconnect(display->connection); free(display->info_reply); }