Merge pull request #608 from bebehei/xrandr-dpi
XRandR DPI Online Changes
This commit is contained in:
commit
591c6f91f3
@ -237,7 +237,7 @@ static PangoLayout *layout_create(cairo_t *c)
|
|||||||
struct screen_info *screen = get_active_screen();
|
struct screen_info *screen = get_active_screen();
|
||||||
|
|
||||||
PangoContext *context = pango_cairo_create_context(c);
|
PangoContext *context = pango_cairo_create_context(c);
|
||||||
pango_cairo_context_set_resolution(context, get_dpi_for_screen(screen));
|
pango_cairo_context_set_resolution(context, screen_dpi_get(screen));
|
||||||
|
|
||||||
PangoLayout *layout = pango_layout_new(context);
|
PangoLayout *layout = pango_layout_new(context);
|
||||||
|
|
||||||
|
112
src/x11/screen.c
112
src/x11/screen.c
@ -25,8 +25,6 @@ int screens_len;
|
|||||||
|
|
||||||
bool dunst_follow_errored = false;
|
bool dunst_follow_errored = false;
|
||||||
|
|
||||||
int randr_event_base = 0;
|
|
||||||
|
|
||||||
static int randr_major_version = 0;
|
static int randr_major_version = 0;
|
||||||
static int randr_minor_version = 0;
|
static int randr_minor_version = 0;
|
||||||
|
|
||||||
@ -39,59 +37,84 @@ static int x_follow_tear_down_error_handler(void);
|
|||||||
static int FollowXErrorHandler(Display *display, XErrorEvent *e);
|
static int FollowXErrorHandler(Display *display, XErrorEvent *e);
|
||||||
static Window get_focused_window(void);
|
static Window get_focused_window(void);
|
||||||
|
|
||||||
static double get_xft_dpi_value(void)
|
|
||||||
|
/**
|
||||||
|
* A cache variable to cache the Xft.dpi xrdb values.
|
||||||
|
* We do not expect to change xrdb often, but there's much
|
||||||
|
* overhead to query it once.
|
||||||
|
*
|
||||||
|
* @retval -DBL_MAX: uncached
|
||||||
|
* @retval <=0: Invalid and unusable value
|
||||||
|
* @retval >0: valid
|
||||||
|
*/
|
||||||
|
double screen_dpi_xft_cache = -DBL_MAX;
|
||||||
|
|
||||||
|
void screen_dpi_xft_cache_purge(void)
|
||||||
{
|
{
|
||||||
static double dpi = -1;
|
screen_dpi_xft_cache = -DBL_MAX;
|
||||||
//Only run this once, we don't expect dpi changes during runtime
|
}
|
||||||
if (dpi <= -1) {
|
|
||||||
XrmInitialize();
|
|
||||||
char *xRMS = XResourceManagerString(xctx.dpy);
|
|
||||||
|
|
||||||
if (!xRMS) {
|
static double screen_dpi_get_from_xft(void)
|
||||||
dpi = 0;
|
{
|
||||||
return 0;
|
if (screen_dpi_xft_cache == -DBL_MAX) {
|
||||||
}
|
screen_dpi_xft_cache = 0;
|
||||||
|
|
||||||
XrmDatabase xDB = XrmGetStringDatabase(xRMS);
|
|
||||||
char *xrmType;
|
char *xrmType;
|
||||||
XrmValue xrmValue;
|
XrmValue xrmValue;
|
||||||
|
XrmDatabase db = XrmGetDatabase(xctx.dpy);
|
||||||
if (XrmGetResource(xDB, "Xft.dpi", "Xft.dpi", &xrmType, &xrmValue)) {
|
ASSERT_OR_RET(db, screen_dpi_xft_cache);
|
||||||
dpi = strtod(xrmValue.addr, NULL);
|
if (XrmGetResource(db, "Xft.dpi", "Xft.dpi", &xrmType, &xrmValue))
|
||||||
} else {
|
screen_dpi_xft_cache = strtod(xrmValue.addr, NULL);
|
||||||
dpi = 0;
|
|
||||||
}
|
|
||||||
XrmDestroyDatabase(xDB);
|
|
||||||
}
|
}
|
||||||
return dpi;
|
return screen_dpi_xft_cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double screen_dpi_get_from_monitor(struct screen_info *scr)
|
||||||
|
{
|
||||||
|
return (double)scr->h * 25.4 / (double)scr->mmh;
|
||||||
|
}
|
||||||
|
|
||||||
|
double screen_dpi_get(struct screen_info *scr)
|
||||||
|
{
|
||||||
|
if ( ! settings.force_xinerama
|
||||||
|
&& settings.per_monitor_dpi)
|
||||||
|
return screen_dpi_get_from_monitor(scr);
|
||||||
|
|
||||||
|
if (screen_dpi_get_from_xft() > 0)
|
||||||
|
return screen_dpi_get_from_xft();
|
||||||
|
|
||||||
|
// Calculate the DPI on the overall screen size.
|
||||||
|
// xrandr --dpi <DPI> does only change the overall screen's millimeters,
|
||||||
|
// but not the physical screen's sizes.
|
||||||
|
//
|
||||||
|
// The screen parameter is XDefaultScreen(), as our scr->id references
|
||||||
|
// the xrandr monitor and not the xrandr screen
|
||||||
|
return ((((double)DisplayWidth (xctx.dpy, XDefaultScreen(xctx.dpy))) * 25.4) /
|
||||||
|
((double)DisplayWidthMM(xctx.dpy, XDefaultScreen(xctx.dpy))));
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_screens(void)
|
void init_screens(void)
|
||||||
{
|
{
|
||||||
if (!settings.force_xinerama) {
|
if (settings.force_xinerama) {
|
||||||
|
xinerama_update();
|
||||||
|
} else {
|
||||||
randr_init();
|
randr_init();
|
||||||
randr_update();
|
randr_update();
|
||||||
} else {
|
|
||||||
xinerama_update();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void alloc_screen_ar(int n)
|
void alloc_screen_ar(int n)
|
||||||
{
|
{
|
||||||
assert(n > 0);
|
assert(n > 0);
|
||||||
if (n <= screens_len) return;
|
g_free(screens);
|
||||||
|
screens = g_malloc0(n * sizeof(struct screen_info));
|
||||||
screens = g_realloc(screens, n * sizeof(struct screen_info));
|
|
||||||
|
|
||||||
memset(screens, 0, n * sizeof(struct screen_info));
|
|
||||||
|
|
||||||
screens_len = n;
|
screens_len = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
void randr_init(void)
|
void randr_init(void)
|
||||||
{
|
{
|
||||||
int randr_error_base = 0;
|
int ignored;
|
||||||
if (!XRRQueryExtension(xctx.dpy, &randr_event_base, &randr_error_base)) {
|
if (!XRRQueryExtension(xctx.dpy, &ignored, &ignored)) {
|
||||||
LOG_W("Could not initialize the RandR extension. "
|
LOG_W("Could not initialize the RandR extension. "
|
||||||
"Falling back to single monitor mode.");
|
"Falling back to single monitor mode.");
|
||||||
return;
|
return;
|
||||||
@ -138,20 +161,15 @@ void randr_update(void)
|
|||||||
XRRFreeMonitors(m);
|
XRRFreeMonitors(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int autodetect_dpi(struct screen_info *scr)
|
bool screen_check_event(XEvent *ev)
|
||||||
{
|
{
|
||||||
return (double)scr->h * 25.4 / (double)scr->mmh;
|
if (XRRUpdateConfiguration(ev)) {
|
||||||
}
|
|
||||||
|
|
||||||
void screen_check_event(XEvent event)
|
|
||||||
{
|
|
||||||
if (event.type == randr_event_base + RRScreenChangeNotify) {
|
|
||||||
LOG_D("XEvent: processing 'RRScreenChangeNotify'");
|
LOG_D("XEvent: processing 'RRScreenChangeNotify'");
|
||||||
randr_update();
|
randr_update();
|
||||||
|
|
||||||
} else {
|
return true;
|
||||||
LOG_D("XEvent: Ignoring '%d'", event.type);
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void xinerama_update(void)
|
void xinerama_update(void)
|
||||||
@ -355,18 +373,6 @@ sc_cleanup:
|
|||||||
return &screens[ret];
|
return &screens[ret];
|
||||||
}
|
}
|
||||||
|
|
||||||
double get_dpi_for_screen(struct screen_info *scr)
|
|
||||||
{
|
|
||||||
double dpi = 0;
|
|
||||||
if ((!settings.force_xinerama && settings.per_monitor_dpi &&
|
|
||||||
(dpi = autodetect_dpi(scr))))
|
|
||||||
return dpi;
|
|
||||||
else if ((dpi = get_xft_dpi_value()))
|
|
||||||
return dpi;
|
|
||||||
else
|
|
||||||
return 96;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return the window that currently has
|
* Return the window that currently has
|
||||||
* the keyboard focus.
|
* the keyboard focus.
|
||||||
|
@ -17,10 +17,11 @@ struct screen_info {
|
|||||||
};
|
};
|
||||||
|
|
||||||
void init_screens(void);
|
void init_screens(void);
|
||||||
void screen_check_event(XEvent event);
|
void screen_dpi_xft_cache_purge(void);
|
||||||
|
bool screen_check_event(XEvent *ev);
|
||||||
|
|
||||||
struct screen_info *get_active_screen(void);
|
struct screen_info *get_active_screen(void);
|
||||||
double get_dpi_for_screen(struct screen_info *scr);
|
double screen_dpi_get(struct screen_info *scr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the currently focused window and check if it's in
|
* Find the currently focused window and check if it's in
|
||||||
|
74
src/x11/x.c
74
src/x11/x.c
@ -17,6 +17,7 @@
|
|||||||
#include <X11/X.h>
|
#include <X11/X.h>
|
||||||
#include <X11/XKBlib.h>
|
#include <X11/XKBlib.h>
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/Xresource.h>
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
|
|
||||||
#include "../dbus.h"
|
#include "../dbus.h"
|
||||||
@ -55,6 +56,8 @@ bool dunst_grab_errored = false;
|
|||||||
|
|
||||||
static bool fullscreen_last = false;
|
static bool fullscreen_last = false;
|
||||||
|
|
||||||
|
static void XRM_update_db(void);
|
||||||
|
|
||||||
static void x_shortcut_init(struct keyboard_shortcut *ks);
|
static void x_shortcut_init(struct keyboard_shortcut *ks);
|
||||||
static int x_shortcut_grab(struct keyboard_shortcut *ks);
|
static int x_shortcut_grab(struct keyboard_shortcut *ks);
|
||||||
static void x_shortcut_ungrab(struct keyboard_shortcut *ks);
|
static void x_shortcut_ungrab(struct keyboard_shortcut *ks);
|
||||||
@ -333,9 +336,18 @@ gboolean x_mainloop_fd_dispatch(GSource *source, GSourceFunc callback, gpointer
|
|||||||
ev.xcreatewindow.override_redirect == 0)
|
ev.xcreatewindow.override_redirect == 0)
|
||||||
XRaiseWindow(xctx.dpy, win->xwin);
|
XRaiseWindow(xctx.dpy, win->xwin);
|
||||||
break;
|
break;
|
||||||
|
case PropertyNotify:
|
||||||
|
if (ev.xproperty.atom == XA_RESOURCE_MANAGER) {
|
||||||
|
LOG_D("XEvent: processing PropertyNotify for Resource manager");
|
||||||
|
XRM_update_db();
|
||||||
|
screen_dpi_xft_cache_purge();
|
||||||
|
draw();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Explicitly fallthrough. Other PropertyNotify events, e.g. catching
|
||||||
|
* _NET_WM get handled in the Focus(In|Out) section */
|
||||||
case FocusIn:
|
case FocusIn:
|
||||||
case FocusOut:
|
case FocusOut:
|
||||||
case PropertyNotify:
|
|
||||||
LOG_D("XEvent: Checking for active screen changes");
|
LOG_D("XEvent: Checking for active screen changes");
|
||||||
fullscreen_now = have_fullscreen_window();
|
fullscreen_now = have_fullscreen_window();
|
||||||
scr = get_active_screen();
|
scr = get_active_screen();
|
||||||
@ -355,7 +367,10 @@ gboolean x_mainloop_fd_dispatch(GSource *source, GSourceFunc callback, gpointer
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
screen_check_event(ev);
|
if (!screen_check_event(&ev)) {
|
||||||
|
LOG_D("XEvent: Ignoring '%d'", ev.type);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -437,6 +452,47 @@ void x_free(void)
|
|||||||
XCloseDisplay(xctx.dpy);
|
XCloseDisplay(xctx.dpy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int XErrorHandlerDB(Display *display, XErrorEvent *e)
|
||||||
|
{
|
||||||
|
char err_buf[BUFSIZ];
|
||||||
|
XGetErrorText(display, e->error_code, err_buf, BUFSIZ);
|
||||||
|
LOG_W("%s", err_buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void XRM_update_db(void)
|
||||||
|
{
|
||||||
|
XrmDatabase db;
|
||||||
|
XTextProperty prop;
|
||||||
|
Window root;
|
||||||
|
// We shouldn't destroy the first DB coming
|
||||||
|
// from the display object itself
|
||||||
|
static bool runonce = false;
|
||||||
|
|
||||||
|
XFlush(xctx.dpy);
|
||||||
|
XSetErrorHandler(XErrorHandlerDB);
|
||||||
|
|
||||||
|
root = RootWindow(xctx.dpy, DefaultScreen(xctx.dpy));
|
||||||
|
|
||||||
|
XLockDisplay(xctx.dpy);
|
||||||
|
if (XGetTextProperty(xctx.dpy, root, &prop, XA_RESOURCE_MANAGER)) {
|
||||||
|
if (runonce) {
|
||||||
|
db = XrmGetDatabase(xctx.dpy);
|
||||||
|
XrmDestroyDatabase(db);
|
||||||
|
}
|
||||||
|
|
||||||
|
db = XrmGetStringDatabase((const char*)prop.value);
|
||||||
|
XrmSetDatabase(xctx.dpy, db);
|
||||||
|
}
|
||||||
|
XUnlockDisplay(xctx.dpy);
|
||||||
|
|
||||||
|
runonce = true;
|
||||||
|
|
||||||
|
XFlush(xctx.dpy);
|
||||||
|
XSync(xctx.dpy, false);
|
||||||
|
XSetErrorHandler(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup X11 stuff
|
* Setup X11 stuff
|
||||||
*/
|
*/
|
||||||
@ -468,6 +524,8 @@ void x_setup(void)
|
|||||||
|
|
||||||
init_screens();
|
init_screens();
|
||||||
x_shortcut_grab(&settings.history_ks);
|
x_shortcut_grab(&settings.history_ks);
|
||||||
|
|
||||||
|
XrmInitialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct geometry x_parse_geometry(const char *geom_str)
|
struct geometry x_parse_geometry(const char *geom_str)
|
||||||
@ -616,9 +674,17 @@ struct window_x11 *x_win_create(void)
|
|||||||
|
|
||||||
win->esrc = x_win_reg_source(win);
|
win->esrc = x_win_reg_source(win);
|
||||||
|
|
||||||
long root_event_mask = SubstructureNotifyMask;
|
/* SubstructureNotifyMask is required for receiving CreateNotify events
|
||||||
|
* in order to raise the window when something covers us. See #160
|
||||||
|
*
|
||||||
|
* PropertyChangeMask is requred for getting screen change events when follow_mode != none
|
||||||
|
* and it's also needed to receive
|
||||||
|
* XA_RESOURCE_MANAGER events to update the dpi when
|
||||||
|
* the xresource value is updated
|
||||||
|
*/
|
||||||
|
long root_event_mask = SubstructureNotifyMask | PropertyChangeMask;
|
||||||
if (settings.f_mode != FOLLOW_NONE) {
|
if (settings.f_mode != FOLLOW_NONE) {
|
||||||
root_event_mask |= FocusChangeMask | PropertyChangeMask;
|
root_event_mask |= FocusChangeMask;
|
||||||
}
|
}
|
||||||
XSelectInput(xctx.dpy, root, root_event_mask);
|
XSelectInput(xctx.dpy, root, root_event_mask);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user