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();
|
||||
|
||||
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);
|
||||
|
||||
|
112
src/x11/screen.c
112
src/x11/screen.c
@ -25,8 +25,6 @@ int screens_len;
|
||||
|
||||
bool dunst_follow_errored = false;
|
||||
|
||||
int randr_event_base = 0;
|
||||
|
||||
static int randr_major_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 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;
|
||||
//Only run this once, we don't expect dpi changes during runtime
|
||||
if (dpi <= -1) {
|
||||
XrmInitialize();
|
||||
char *xRMS = XResourceManagerString(xctx.dpy);
|
||||
screen_dpi_xft_cache = -DBL_MAX;
|
||||
}
|
||||
|
||||
if (!xRMS) {
|
||||
dpi = 0;
|
||||
return 0;
|
||||
}
|
||||
static double screen_dpi_get_from_xft(void)
|
||||
{
|
||||
if (screen_dpi_xft_cache == -DBL_MAX) {
|
||||
screen_dpi_xft_cache = 0;
|
||||
|
||||
XrmDatabase xDB = XrmGetStringDatabase(xRMS);
|
||||
char *xrmType;
|
||||
XrmValue xrmValue;
|
||||
|
||||
if (XrmGetResource(xDB, "Xft.dpi", "Xft.dpi", &xrmType, &xrmValue)) {
|
||||
dpi = strtod(xrmValue.addr, NULL);
|
||||
} else {
|
||||
dpi = 0;
|
||||
}
|
||||
XrmDestroyDatabase(xDB);
|
||||
XrmDatabase db = XrmGetDatabase(xctx.dpy);
|
||||
ASSERT_OR_RET(db, screen_dpi_xft_cache);
|
||||
if (XrmGetResource(db, "Xft.dpi", "Xft.dpi", &xrmType, &xrmValue))
|
||||
screen_dpi_xft_cache = strtod(xrmValue.addr, NULL);
|
||||
}
|
||||
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)
|
||||
{
|
||||
if (!settings.force_xinerama) {
|
||||
if (settings.force_xinerama) {
|
||||
xinerama_update();
|
||||
} else {
|
||||
randr_init();
|
||||
randr_update();
|
||||
} else {
|
||||
xinerama_update();
|
||||
}
|
||||
}
|
||||
|
||||
void alloc_screen_ar(int n)
|
||||
{
|
||||
assert(n > 0);
|
||||
if (n <= screens_len) return;
|
||||
|
||||
screens = g_realloc(screens, n * sizeof(struct screen_info));
|
||||
|
||||
memset(screens, 0, n * sizeof(struct screen_info));
|
||||
|
||||
g_free(screens);
|
||||
screens = g_malloc0(n * sizeof(struct screen_info));
|
||||
screens_len = n;
|
||||
}
|
||||
|
||||
void randr_init(void)
|
||||
{
|
||||
int randr_error_base = 0;
|
||||
if (!XRRQueryExtension(xctx.dpy, &randr_event_base, &randr_error_base)) {
|
||||
int ignored;
|
||||
if (!XRRQueryExtension(xctx.dpy, &ignored, &ignored)) {
|
||||
LOG_W("Could not initialize the RandR extension. "
|
||||
"Falling back to single monitor mode.");
|
||||
return;
|
||||
@ -138,20 +161,15 @@ void randr_update(void)
|
||||
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;
|
||||
}
|
||||
|
||||
void screen_check_event(XEvent event)
|
||||
{
|
||||
if (event.type == randr_event_base + RRScreenChangeNotify) {
|
||||
if (XRRUpdateConfiguration(ev)) {
|
||||
LOG_D("XEvent: processing 'RRScreenChangeNotify'");
|
||||
randr_update();
|
||||
|
||||
} else {
|
||||
LOG_D("XEvent: Ignoring '%d'", event.type);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void xinerama_update(void)
|
||||
@ -355,18 +373,6 @@ sc_cleanup:
|
||||
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
|
||||
* the keyboard focus.
|
||||
|
@ -17,10 +17,11 @@ struct screen_info {
|
||||
};
|
||||
|
||||
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);
|
||||
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
|
||||
|
74
src/x11/x.c
74
src/x11/x.c
@ -17,6 +17,7 @@
|
||||
#include <X11/X.h>
|
||||
#include <X11/XKBlib.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xresource.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
#include "../dbus.h"
|
||||
@ -55,6 +56,8 @@ bool dunst_grab_errored = false;
|
||||
|
||||
static bool fullscreen_last = false;
|
||||
|
||||
static void XRM_update_db(void);
|
||||
|
||||
static void x_shortcut_init(struct keyboard_shortcut *ks);
|
||||
static int x_shortcut_grab(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)
|
||||
XRaiseWindow(xctx.dpy, win->xwin);
|
||||
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 FocusOut:
|
||||
case PropertyNotify:
|
||||
LOG_D("XEvent: Checking for active screen changes");
|
||||
fullscreen_now = have_fullscreen_window();
|
||||
scr = get_active_screen();
|
||||
@ -355,7 +367,10 @@ gboolean x_mainloop_fd_dispatch(GSource *source, GSourceFunc callback, gpointer
|
||||
}
|
||||
break;
|
||||
default:
|
||||
screen_check_event(ev);
|
||||
if (!screen_check_event(&ev)) {
|
||||
LOG_D("XEvent: Ignoring '%d'", ev.type);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -437,6 +452,47 @@ void x_free(void)
|
||||
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
|
||||
*/
|
||||
@ -468,6 +524,8 @@ void x_setup(void)
|
||||
|
||||
init_screens();
|
||||
x_shortcut_grab(&settings.history_ks);
|
||||
|
||||
XrmInitialize();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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) {
|
||||
root_event_mask |= FocusChangeMask | PropertyChangeMask;
|
||||
root_event_mask |= FocusChangeMask;
|
||||
}
|
||||
XSelectInput(xctx.dpy, root, root_event_mask);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user