From f9c30db62b61672410f7729d88c85a99679a6f71 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 11 May 2018 13:28:06 +0200 Subject: [PATCH 1/3] =?UTF-8?q?Respect=20Xft.dpi=20for=20determining=20the?= =?UTF-8?q?=20unlock=20indicator=E2=80=99s=20scale=20factor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixes #184 --- Makefile.am | 4 ++ configure.ac | 1 + dpi.c | 109 +++++++++++++++++++++++++++++++++++++++++++++ dpi.h | 22 +++++++++ i3lock.c | 3 ++ unlock_indicator.c | 19 +++----- 6 files changed, 144 insertions(+), 14 deletions(-) create mode 100644 dpi.c create mode 100644 dpi.h diff --git a/Makefile.am b/Makefile.am index aa70ded..3c0d16a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,6 +19,7 @@ i3lock_CFLAGS = \ $(XCB_CFLAGS) \ $(XCB_IMAGE_CFLAGS) \ $(XCB_UTIL_CFLAGS) \ + $(XCB_UTIL_XRM_CFLAGS) \ $(XKBCOMMON_CFLAGS) \ $(CAIRO_CFLAGS) \ $(CODE_COVERAGE_CFLAGS) @@ -31,12 +32,15 @@ i3lock_LDADD = \ $(XCB_LIBS) \ $(XCB_IMAGE_LIBS) \ $(XCB_UTIL_LIBS) \ + $(XCB_UTIL_XRM_LIBS) \ $(XKBCOMMON_LIBS) \ $(CAIRO_LIBS) \ $(CODE_COVERAGE_LDFLAGS) i3lock_SOURCES = \ cursors.h \ + dpi.c \ + dpi.h \ i3lock.c \ i3lock.h \ randr.c \ diff --git a/configure.ac b/configure.ac index 3402736..9171521 100644 --- a/configure.ac +++ b/configure.ac @@ -93,6 +93,7 @@ dnl downloaded in a newer version and would like to overwrite. PKG_CHECK_MODULES([XCB], [xcb xcb-xkb xcb-xinerama xcb-randr]) PKG_CHECK_MODULES([XCB_IMAGE], [xcb-image]) PKG_CHECK_MODULES([XCB_UTIL], [xcb-event xcb-util xcb-atom]) +PKG_CHECK_MODULES([XCB_UTIL_XRM], [xcb-xrm]) PKG_CHECK_MODULES([XKBCOMMON], [xkbcommon xkbcommon-x11]) PKG_CHECK_MODULES([CAIRO], [cairo]) diff --git a/dpi.c b/dpi.c new file mode 100644 index 0000000..3cb08ee --- /dev/null +++ b/dpi.c @@ -0,0 +1,109 @@ +/* + * vim:ts=4:sw=4:expandtab + * + * i3 - an improved dynamic tiling window manager + * © 2009 Michael Stapelberg and contributors (see also: LICENSE) + * + */ +#include "dpi.h" + +#include +#include +#include +#include +#include "xcb.h" +#include "i3lock.h" + +extern bool debug_mode; + +static long dpi; + +extern xcb_screen_t *screen; + +static long init_dpi_fallback(void) { + return (double)screen->height_in_pixels * 25.4 / (double)screen->height_in_millimeters; +} + +/* + * Initialize the DPI setting. + * This will use the 'Xft.dpi' X resource if available and fall back to + * guessing the correct value otherwise. + */ +void init_dpi(void) { + xcb_xrm_database_t *database = NULL; + char *resource = NULL; + + if (conn == NULL) { + goto init_dpi_end; + } + + database = xcb_xrm_database_from_default(conn); + if (database == NULL) { + DEBUG("Failed to open the resource database.\n"); + goto init_dpi_end; + } + + xcb_xrm_resource_get_string(database, "Xft.dpi", NULL, &resource); + if (resource == NULL) { + DEBUG("Resource Xft.dpi not specified, skipping.\n"); + goto init_dpi_end; + } + + char *endptr; + double in_dpi = strtod(resource, &endptr); + if (in_dpi == HUGE_VAL || dpi < 0 || *endptr != '\0' || endptr == resource) { + DEBUG("Xft.dpi = %s is an invalid number and couldn't be parsed.\n", resource); + dpi = 0; + goto init_dpi_end; + } + dpi = (long)round(in_dpi); + + DEBUG("Found Xft.dpi = %ld.\n", dpi); + +init_dpi_end: + if (resource != NULL) { + free(resource); + } + + if (database != NULL) { + xcb_xrm_database_free(database); + } + + if (dpi == 0) { + DEBUG("Using fallback for calculating DPI.\n"); + dpi = init_dpi_fallback(); + DEBUG("Using dpi = %ld\n", dpi); + } +} + +/* + * This function returns the value of the DPI setting. + * + */ +long get_dpi_value(void) { + return dpi; +} + +/* + * Convert a logical amount of pixels (e.g. 2 pixels on a “standard” 96 DPI + * screen) to a corresponding amount of physical pixels on a standard or retina + * screen, e.g. 5 pixels on a 227 DPI MacBook Pro 13" Retina screen. + * + */ +int logical_px(const int logical) { + if (screen == NULL) { + /* Dpi info may not be available when parsing a config without an X + * server, such as for config file validation. */ + return logical; + } + + /* There are many misconfigurations out there, i.e. systems with screens + * whose dpi is in fact higher than 96 dpi, but not significantly higher, + * so software was never adapted. We could tell people to reconfigure their + * systems to 96 dpi in order to get the behavior they expect/are used to, + * but since we can easily detect this case in code, let’s do it for them. + */ + if ((dpi / 96.0) < 1.25) + return logical; + return ceil((dpi / 96.0) * logical); +} diff --git a/dpi.h b/dpi.h new file mode 100644 index 0000000..35840d2 --- /dev/null +++ b/dpi.h @@ -0,0 +1,22 @@ +#pragma once + +/** + * Initialize the DPI setting. + * This will use the 'Xft.dpi' X resource if available and fall back to + * guessing the correct value otherwise. + */ +void init_dpi(void); + +/** + * This function returns the value of the DPI setting. + * + */ +long get_dpi_value(void); + +/** + * Convert a logical amount of pixels (e.g. 2 pixels on a “standard” 96 DPI + * screen) to a corresponding amount of physical pixels on a standard or retina + * screen, e.g. 5 pixels on a 227 DPI MacBook Pro 13" Retina screen. + * + */ +int logical_px(const int logical); diff --git a/i3lock.c b/i3lock.c index 2bf3901..602ccca 100644 --- a/i3lock.c +++ b/i3lock.c @@ -46,6 +46,7 @@ #include "cursors.h" #include "unlock_indicator.h" #include "randr.h" +#include "dpi.h" #define TSTAMP_N_SECS(n) (n * 1.0) #define TSTAMP_N_MINS(n) (60 * TSTAMP_N_SECS(n)) @@ -1033,6 +1034,8 @@ int main(int argc, char *argv[]) { screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data; + init_dpi(); + randr_init(&randr_base, screen->root); randr_query(screen->root); diff --git a/unlock_indicator.c b/unlock_indicator.c index da1a7f2..a6a603f 100644 --- a/unlock_indicator.c +++ b/unlock_indicator.c @@ -20,6 +20,7 @@ #include "xcb.h" #include "unlock_indicator.h" #include "randr.h" +#include "dpi.h" #define BUTTON_RADIUS 90 #define BUTTON_SPACE (BUTTON_RADIUS + 5) @@ -80,17 +81,6 @@ static xcb_visualtype_t *vistype; unlock_state_t unlock_state; auth_state_t auth_state; -/* - * Returns the scaling factor of the current screen. E.g., on a 227 DPI MacBook - * Pro 13" Retina screen, the scaling factor is 227/96 = 2.36. - * - */ -static double scaling_factor(void) { - const int dpi = (double)screen->height_in_pixels * 25.4 / - (double)screen->height_in_millimeters; - return (dpi / 96.0); -} - /* * Draws global image with fill color onto a pixmap with the given * resolution and returns it. @@ -98,9 +88,10 @@ static double scaling_factor(void) { */ xcb_pixmap_t draw_image(uint32_t *resolution) { xcb_pixmap_t bg_pixmap = XCB_NONE; - int button_diameter_physical = ceil(scaling_factor() * BUTTON_DIAMETER); + const double scaling_factor = get_dpi_value() / 96.0; + int button_diameter_physical = ceil(scaling_factor * BUTTON_DIAMETER); DEBUG("scaling_factor is %.f, physical diameter is %d px\n", - scaling_factor(), button_diameter_physical); + scaling_factor, button_diameter_physical); if (!vistype) vistype = get_root_visual_type(screen); @@ -142,7 +133,7 @@ xcb_pixmap_t draw_image(uint32_t *resolution) { if (unlock_indicator && (unlock_state >= STATE_KEY_PRESSED || auth_state > STATE_AUTH_IDLE)) { - cairo_scale(ctx, scaling_factor(), scaling_factor()); + cairo_scale(ctx, scaling_factor, scaling_factor); /* Draw a (centered) circle with transparent background. */ cairo_set_line_width(ctx, 10.0); cairo_arc(ctx, From 28ad24e0ced32cd8733c7e610e63218491ba7068 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 11 May 2018 13:40:18 +0200 Subject: [PATCH 2/3] clang-format-3.5 --- i3lock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i3lock.c b/i3lock.c index 602ccca..13adc2b 100644 --- a/i3lock.c +++ b/i3lock.c @@ -656,7 +656,7 @@ static bool verify_png_image(const char *image_path) { // Check PNG header according to the specification, available at: // https://www.w3.org/TR/2003/REC-PNG-20031110/#5PNG-file-signature - static unsigned char PNG_REFERENCE_HEADER[8] = { 137, 80, 78, 71, 13, 10, 26, 10 }; + static unsigned char PNG_REFERENCE_HEADER[8] = {137, 80, 78, 71, 13, 10, 26, 10}; if (memcmp(PNG_REFERENCE_HEADER, png_header, sizeof(png_header)) != 0) { fprintf(stderr, "File \"%s\" does not start with a PNG header. i3lock currently only supports loading PNG files.\n", image_path); return false; From ec5f21d1f8f62772b10ab6beb1e22be55a7a22e6 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 11 May 2018 15:30:48 +0200 Subject: [PATCH 3/3] travis: build in Debian sid Docker container --- .travis.yml | 22 +++++----------------- travis/Dockerfile | 25 +++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 17 deletions(-) create mode 100644 travis/Dockerfile diff --git a/.travis.yml b/.travis.yml index c9db585..15ad1e4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,8 @@ # Use Ubuntu 14.04 (trusty), as per http://blog.travis-ci.com/2015-10-14-opening-up-ubuntu-trusty-beta/ -sudo: required +sudo: false dist: trusty +services: + - docker language: c compiler: - gcc @@ -9,21 +11,7 @@ addons: apt: packages: - clang-format-3.5 - - pkg-config - - libpam0g-dev - - libcairo2-dev - - libxcb1-dev - - libxcb-dpms0-dev - - libxcb-image0-dev - - libxcb-util0-dev - - libev-dev - - libxcb-xinerama0-dev - - libxcb-xkb-dev -before_install: - - "echo 'APT::Default-Release \"trusty\";' | sudo tee /etc/apt/apt.conf.d/default-release" - - "echo 'deb http://archive.ubuntu.com/ubuntu/ xenial main universe' | sudo tee /etc/apt/sources.list.d/wily.list" - - sudo apt-get update - - sudo apt-get --force-yes -y install -t xenial libxkbcommon-dev libxkbcommon-x11-dev script: - - autoreconf -fi && mkdir -p build && cd build && (../configure || (cat config.log; false)) && make -j CFLAGS="-Wformat -Wformat-security -Wextra -Wno-unused-parameter -Werror" - clang-format-3.5 -i *.[ch] && git diff --exit-code || (echo 'Code was not formatted using clang-format!'; false) + - docker build --pull --no-cache --rm -t=i3lock -f travis/Dockerfile . + - docker run -e CC=$CC -v $PWD:/usr/src:rw i3lock /bin/sh -c 'autoreconf -fi && mkdir -p build && cd build && (../configure || (cat config.log; false)) && make -j V=1 CFLAGS="-Wformat -Wformat-security -Wextra -Wno-unused-parameter -Werror"' diff --git a/travis/Dockerfile b/travis/Dockerfile new file mode 100644 index 0000000..5381276 --- /dev/null +++ b/travis/Dockerfile @@ -0,0 +1,25 @@ +# vim:ft=Dockerfile +FROM debian:sid + +RUN echo force-unsafe-io > /etc/dpkg/dpkg.cfg.d/docker-apt-speedup +# Paper over occasional network flakiness of some mirrors. +RUN echo 'APT::Acquire::Retries "5";' > /etc/apt/apt.conf.d/80retry + +# NOTE: I tried exclusively using gce_debian_mirror.storage.googleapis.com +# instead of httpredir.debian.org, but the results (Fetched 123 MB in 36s (3357 +# kB/s)) are not any better than httpredir.debian.org (Fetched 123 MB in 34s +# (3608 kB/s)). Hence, let’s stick with httpredir.debian.org (default) for now. + +# Install mk-build-deps (for installing the i3 build dependencies), +# clang and clang-format-3.8 (for checking formatting and building with clang), +# lintian (for checking spelling errors), +# test suite dependencies (for running tests) +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + build-essential clang git autoconf automake libxcb-randr0-dev pkg-config libpam0g-dev \ + libcairo2-dev libxcb1-dev libxcb-dpms0-dev libxcb-image0-dev libxcb-util0-dev \ + libxcb-xrm-dev libev-dev libxcb-xinerama0-dev libxcb-xkb-dev libxkbcommon-dev \ + libxkbcommon-x11-dev && \ + rm -rf /var/lib/apt/lists/* + +WORKDIR /usr/src