diff --git a/i3-config-wizard/i3-config-wizard.mk b/i3-config-wizard/i3-config-wizard.mk
index 2a761433..9c01cdb6 100644
--- a/i3-config-wizard/i3-config-wizard.mk
+++ b/i3-config-wizard/i3-config-wizard.mk
@@ -4,8 +4,8 @@ CLEAN_TARGETS += clean-i3-config-wizard
 
 i3_config_wizard_SOURCES           := $(wildcard i3-config-wizard/*.c)
 i3_config_wizard_HEADERS           := $(wildcard i3-config-wizard/*.h)
-i3_config_wizard_CFLAGS             = $(XCB_CFLAGS) $(XCB_KBD_CFLAGS) $(PANGO_CFLAGS) $(XKB_COMMON_CFLAGS) $(XKB_COMMON_X11_CFLAGS)
-i3_config_wizard_LIBS               = $(XCB_LIBS) $(XCB_KBD_LIBS) $(PANGO_LIBS) $(XKB_COMMON_LIBS) $(XKB_COMMON_X11_LIBS)
+i3_config_wizard_CFLAGS             = $(XCB_CFLAGS) $(XCB_KBD_CFLAGS) $(PANGO_CFLAGS) $(XCB_XRM_CFLAGS) $(XKB_COMMON_CFLAGS) $(XKB_COMMON_X11_CFLAGS)
+i3_config_wizard_LIBS               = $(XCB_LIBS) $(XCB_KBD_LIBS) $(PANGO_LIBS) $(XCB_XRM_LIBS) $(XKB_COMMON_LIBS) $(XKB_COMMON_X11_LIBS)
 
 i3_config_wizard_OBJECTS := $(i3_config_wizard_SOURCES:.c=.o)
 
diff --git a/i3-input/i3-input.mk b/i3-input/i3-input.mk
index 2b1f451e..ce36f932 100644
--- a/i3-input/i3-input.mk
+++ b/i3-input/i3-input.mk
@@ -4,8 +4,8 @@ CLEAN_TARGETS += clean-i3-input
 
 i3_input_SOURCES := $(wildcard i3-input/*.c)
 i3_input_HEADERS := $(wildcard i3-input/*.h)
-i3_input_CFLAGS   = $(XCB_CFLAGS) $(XCB_KBD_CFLAGS) $(PANGO_CFLAGS)
-i3_input_LIBS     = $(XCB_LIBS) $(XCB_KBD_LIBS) $(PANGO_LIBS)
+i3_input_CFLAGS   = $(XCB_CFLAGS) $(XCB_KBD_CFLAGS) $(PANGO_CFLAGS) $(XCB_XRM_CFLAGS)
+i3_input_LIBS     = $(XCB_LIBS) $(XCB_KBD_LIBS) $(PANGO_LIBS) $(XCB_XRM_LIBS)
 
 i3_input_OBJECTS := $(i3_input_SOURCES:.c=.o)
 
diff --git a/i3-nagbar/i3-nagbar.mk b/i3-nagbar/i3-nagbar.mk
index 564a7bc2..c6c7a2ef 100644
--- a/i3-nagbar/i3-nagbar.mk
+++ b/i3-nagbar/i3-nagbar.mk
@@ -4,8 +4,8 @@ CLEAN_TARGETS += clean-i3-nagbar
 
 i3_nagbar_SOURCES := $(wildcard i3-nagbar/*.c)
 i3_nagbar_HEADERS := $(wildcard i3-nagbar/*.h)
-i3_nagbar_CFLAGS   = $(XCB_CFLAGS) $(XCB_CURSOR_CFLAGS) $(XCB_WM_CFLAGS) $(PANGO_CFLAGS)
-i3_nagbar_LIBS     = $(XCB_LIBS) $(XCB_CURSOR_LIBS) $(XCB_WM_LIBS) $(PANGO_LIBS)
+i3_nagbar_CFLAGS   = $(XCB_CFLAGS) $(XCB_CURSOR_CFLAGS) $(XCB_WM_CFLAGS) $(PANGO_CFLAGS) $(XCB_XRM_CFLAGS)
+i3_nagbar_LIBS     = $(XCB_LIBS) $(XCB_CURSOR_LIBS) $(XCB_WM_LIBS) $(PANGO_LIBS) $(XCB_XRM_LIBS)
 
 i3_nagbar_OBJECTS := $(i3_nagbar_SOURCES:.c=.o)
 
diff --git a/i3bar/i3bar.mk b/i3bar/i3bar.mk
index 114e9314..03c607dd 100644
--- a/i3bar/i3bar.mk
+++ b/i3bar/i3bar.mk
@@ -4,8 +4,8 @@ CLEAN_TARGETS += clean-i3bar
 
 i3bar_SOURCES := $(wildcard i3bar/src/*.c)
 i3bar_HEADERS := $(wildcard i3bar/include/*.h)
-i3bar_CFLAGS   = $(XCB_CFLAGS) $(XCB_CURSOR_CFLAGS) $(PANGO_CFLAGS) $(YAJL_CFLAGS) $(LIBEV_CFLAGS)
-i3bar_LIBS     = $(XCB_LIBS) $(XCB_CURSOR_LIBS) $(PANGO_LIBS) $(YAJL_LIBS) $(LIBEV_LIBS) $(XCB_XKB_LIBS)
+i3bar_CFLAGS   = $(XCB_CFLAGS) $(XCB_CURSOR_CFLAGS) $(PANGO_CFLAGS) $(XCB_XRM_CFLAGS) $(YAJL_CFLAGS) $(LIBEV_CFLAGS)
+i3bar_LIBS     = $(XCB_LIBS) $(XCB_CURSOR_LIBS) $(PANGO_LIBS) $(XCB_XRM_LIBS) $(YAJL_LIBS) $(LIBEV_LIBS) $(XCB_XKB_LIBS)
 
 i3bar_OBJECTS := $(i3bar_SOURCES:.c=.o)
 
diff --git a/include/libi3.h b/include/libi3.h
index da5ad891..c1fe770b 100644
--- a/include/libi3.h
+++ b/include/libi3.h
@@ -470,6 +470,13 @@ char *get_process_filename(const char *prefix);
  */
 char *get_exe_path(const char *argv0);
 
+/**
+ * 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);
+
 /**
  * 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
diff --git a/libi3/dpi.c b/libi3/dpi.c
index 897e6e40..f105ef9a 100644
--- a/libi3/dpi.c
+++ b/libi3/dpi.c
@@ -7,6 +7,61 @@
  */
 #include "libi3.h"
 #include <math.h>
+#include <stdlib.h>
+#include <xcb/xcb_xrm.h>
+
+static long dpi;
+
+static long init_dpi_fallback(void) {
+    return (double)root_screen->height_in_pixels * 25.4 / (double)root_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;
+
+    if (conn == NULL) {
+        goto init_dpi_end;
+    }
+
+    database = xcb_xrm_database_from_default(conn);
+    if (database == NULL) {
+        ELOG("Failed to open the resource database.\n");
+        goto init_dpi_end;
+    }
+
+    char *resource;
+    xcb_xrm_resource_get_string(database, "Xft.dpi", NULL, &resource);
+    if (resource == NULL) {
+        DLOG("Resource Xft.dpi not specified, skipping.\n");
+        goto init_dpi_end;
+    }
+
+    char *endptr;
+    dpi = strtol(resource, &endptr, 10);
+    if (dpi == LONG_MAX || dpi == LONG_MIN || dpi < 0 || *endptr != '\0' || endptr == resource) {
+        ELOG("Xft.dpi = %s is an invalid number and couldn't be parsed.\n", resource);
+        dpi = 0;
+        goto init_dpi_end;
+    }
+
+    DLOG("Found Xft.dpi = %ld.\n", dpi);
+
+init_dpi_end:
+    if (database != NULL) {
+        xcb_xrm_database_free(database);
+    }
+
+    if (dpi == 0) {
+        DLOG("Using fallback for calculating DPI.\n");
+        dpi = init_dpi_fallback();
+        DLOG("Using dpi = %ld\n", dpi);
+    }
+}
 
 /*
  * Convert a logical amount of pixels (e.g. 2 pixels on a “standard” 96 DPI
@@ -21,8 +76,6 @@ int logical_px(const int logical) {
         return logical;
     }
 
-    const int dpi = (double)root_screen->height_in_pixels * 25.4 /
-                    (double)root_screen->height_in_millimeters;
     /* 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
diff --git a/libi3/libi3.mk b/libi3/libi3.mk
index d313a44e..16e1f149 100644
--- a/libi3/libi3.mk
+++ b/libi3/libi3.mk
@@ -2,7 +2,7 @@ CLEAN_TARGETS += clean-libi3
 
 libi3_SOURCES := $(wildcard libi3/*.c)
 libi3_HEADERS := $(wildcard libi3/*.h)
-libi3_CFLAGS   = $(PANGO_CFLAGS)
+libi3_CFLAGS   = $(PANGO_CFLAGS) $(XCB_XRM_CFLAGS)
 libi3_LIBS     =
 
 libi3_OBJECTS := $(libi3_SOURCES:.c=.o)
diff --git a/src/main.c b/src/main.c
index 5362d077..96eab671 100644
--- a/src/main.c
+++ b/src/main.c
@@ -503,10 +503,11 @@ int main(int argc, char *argv[]) {
         visual_type = get_visualtype(root_screen);
     }
 
+    init_dpi();
+
     DLOG("root_depth = %d, visual_id = 0x%08x.\n", root_depth, visual_type->visual_id);
-    DLOG("root_screen->height_in_pixels = %d, root_screen->height_in_millimeters = %d, dpi = %d\n",
-         root_screen->height_in_pixels, root_screen->height_in_millimeters,
-         (int)((double)root_screen->height_in_pixels * 25.4 / (double)root_screen->height_in_millimeters));
+    DLOG("root_screen->height_in_pixels = %d, root_screen->height_in_millimeters = %d\n",
+         root_screen->height_in_pixels, root_screen->height_in_millimeters);
     DLOG("One logical pixel corresponds to %d physical pixels on this display.\n", logical_px(1));
 
     xcb_get_geometry_cookie_t gcookie = xcb_get_geometry(conn, root);
diff --git a/testcases/lib/TestWorker.pm b/testcases/lib/TestWorker.pm
index 140537d4..6371591f 100644
--- a/testcases/lib/TestWorker.pm
+++ b/testcases/lib/TestWorker.pm
@@ -112,8 +112,9 @@ sub worker_wait {
             $test->failure_output(\*STDERR);
             $test->todo_output(\*STDOUT);
 
-            @ENV{qw(DISPLAY TESTNAME OUTDIR VALGRIND STRACE XTRACE COVERAGE RESTART)}
-                = ($self->{display},
+            @ENV{qw(HOME DISPLAY TESTNAME OUTDIR VALGRIND STRACE XTRACE COVERAGE RESTART)}
+                = ($outdir,
+                   $self->{display},
                    basename($file),
                    $outdir,
                    $options->{valgrind},