2

我正在尝试创建一个 DPI 感知应用程序,该应用程序通过调整窗口大小来响应用户请求的 DPI 更改事件。

有问题的程序是用 C 语言创建的并使用 SDL2,但是为了检索系统 DPI 信息,我直接使用 xlib,因为 X11 中缺乏 SDL DPI 支持。

我找到了两种在程序启动时获取正确DPI信息的方法,都涉及从Xresource获取Xft.dpi信息:一种是使用XGetDefault(display, "Xft", "dpi"),另一种是使用XResourceManagerString, XrmGetStringDatabase和 XrmGetResource。创建程序时,它们都返回正确的 DPI 值。

问题是,如果用户在程序运行时更改系统规模,即使当我运行“xrdb -query | grep Xft.dpi”时,XGetDefault abd XrmGetResource 仍然返回旧的 DPI 值,该值确实发生了变化。

有谁知道获取更新的 Xft.dpi 值的方法?

4

3 回答 3

1

我找到了一种方法来做我想做的事,尽管它相当老套。

解决方案(使用)是使用andXLib创建到 X 服务器的新临时连接,并从该新连接轮询资源信息。XOpenDisplayXCloseDisplay

需要这样做的原因是因为 X 在每个新连接中只获取一次资源信息,并且从不更新它。因此,通过打开一个新连接,X 将获得更新的xresource数据,然后可以将其用于旧的主连接。

请注意,不断打开和关闭新的 X 连接可能对性能没有好处,因此仅在绝对需要时才这样做。在我的例子中,由于窗口有边框,我只在标题高度发生变化时检查 DPI 变化,因为 DPI 变化会由于字体大小差异而改变标题边框的大小。

于 2019-02-04T06:36:30.383 回答
0

您可以尝试使用 xdpyinfo(1); 在我的系统上,它会输出很多其他内容:

  dimensions:    1280x1024 pixels (332x250 millimeters)
  resolution:    98x104 dots per inch
  depths (7):    24, 1, 4, 8, 15, 16, 32

我不知道它是否可以帮助您,因为我不知道您如何更改屏幕的 DPI,但它可能会起作用。祝你好运!

---评论后更新---在OP下面的评论中,据说“有一个更改DPI的设置”......我仍然不知道是哪个。无论如何,我尝试使用 Ctrl+Alt+Plus 和 Ctrl+Alt+Minus 来即时更改 X 服务器的分辨率。在更改了分辨率并看到比以前更大的所有内容后,我再次运行了 xdpyinfo。它不起作用:仍然是相同的输出。但可能是您使用的方法(哪个?)而不是工作......

于 2019-01-26T09:47:00.230 回答
0

首先必须注意,Xft.dpi资源的值不一定准确——这取决于系统和/或用户登录脚本是否正确设置了它。

同样重要的是要记住该Xft.dpi资源旨在供Xft库使用,而不是由寻找屏幕分辨率的任意程序使用。

Xft.dpi资源可以如下设置。此示例有效地仅处理具有单个屏幕的显示,并注意它使用xdpyinfo. 这也表明它可能不精确,但可以四舍五入。最后这个例子显示了水平和垂直分辨率的计算,但Xft真的只想要水平分辨率:

SCREENDPI=$(xdpyinfo | sed -n 's/^[ ]*resolution:[ ]*\([^ ][^ ]*\) .*$/\1/p;//q')
SCREENDPI_X=$(expr "$SCREENDPI" : '\([0-9]*\)x')
SCREENDPI_Y=$(expr "$SCREENDPI" : '[0-9]*x\([0-9]*\)')
# N.B.:  If true screen resolution is within 10% of 100DPI it makes the most
# sense to claim 100DPI to avoid font-scaling artifacts for bitmap fonts.
if expr \( $SCREENDPI_X / 100 = 1 \) \& \( $SCREENDPI_X % 100 \<= 10 \) >/dev/null; then
    FontXDPI=100
fi
if expr \( $SCREENDPI_Y / 100 = 1 \) \& \( $SCREENDPI_Y % 100 \<= 10 \) >/dev/null; then
    FontYDPI=100
fi
echo "Xft.dpi: ${FontYDPI}" | xrdb -merge

我真的希望我知道为什么Xft至少没有尝试找出屏幕的分辨率本身,而不是一直依赖其设置的“dpi”资源,但我发现当前的实现只使用资源设置,所以实际上总是需要像上面这样的东西来正确设置资源(而且还必须确保 X 服务器本身已经正确配置了正确的物理屏幕尺寸)。

从 C 程序中,您只想做xdpyinfo它本身所做的事情,并跳过所有关于Xft资源的废话。这是xdpyinfo解释的代码:

Display *dpy;
dpy = XOpenDisplay(displayname);
for (scr = 0; scr < ScreenCount(dpy); scr++) {
    int xres, yres;

    /*
     * there are 2.54 centimeters to an inch; so there are 25.4 millimeters.
     *
     *     dpi = N pixels / (M millimeters / (25.4 millimeters / 1 inch))
     *         = N pixels / (M inch / 25.4)
     *         = N * 25.4 pixels / M inch
     */
    xres = ((((double) DisplayWidth(dpy, scr)) * 25.4) /
        ((double) DisplayWidthMM(dpy, scr))) + 0.5;
    yres = ((((double) DisplayHeight(dpy, scr)) * 25.4) /
        ((double) DisplayHeightMM(dpy, scr))) + 0.5;
}
XCloseDisplay(dpy);

另请注意,如果您出于某种奇怪的原因缩放整个显示器(例如使用xrandr),那么您应该希望字体与其他所有字体一样缩放。使用全屏缩放来缩放字体只是一个可怕的坏技巧,尤其是在大多数情况下,告诉应用程序使用正确缩放的字体会更简单,这些字体将以恒定的屏幕点大小显示(这正是Xft使用“dpi”资源来做什么)。我猜 Ubuntu 做了一些愚蠢的事情来改变屏幕分辨率,例如使用xrandr来扩大图标和其他屏幕小部件的外观尺寸,而应用程序不必知道屏幕尺寸和分辨率,然后它必须通过重写来欺骗XftXft.dpi资源。

请注意,如果您避免全屏缩放,那么不使用Xft的应用程序仍然可以通过正确请求正确缩放的字体来获得正确的字体缩放,即即使使用位图字体,您也可以通过以下方式将它们缩放到正确的物理屏幕尺寸在字体规范中使用屏幕的实际分辨率。例如,从上面的 shell 片段继续:

# For pre-Xft applications we can specify physical font text sizes IFF we also tell
# it the screen's actual resolution when requesting a font.  Note the use of the
# rounded values here.
#
DecentDeciPt="80"
DecentPt="8"
export DecentDeciPt DecentPt
#
# Best is to arrange one's font-path to get the desired one first, but....
# If you know the name of a font family that you like and you can be sure
# it is installed and in the font-path somewhere....
#
DefaultFontSpec='-*-liberation mono-medium-r-*-*-*-${DecentDeciPt}-${FontXDPI}-${FontYDPI}-m-*-iso10646-1'
export DefaultFontSpec
#
# For Xft we have set the Xft.dpi resource so this allows the physical font size to
# be specified (e.g. with Xterm's "-fs" option) and for a decent scalable font
# to be chosen:
#
DefaultFTFontSpec="-*-*-medium-r-*-*-*-*-0-0-m-*-iso10646-1"
DefaultFTFontSpecL1="-*-*-medium-r-*-*-*-*-0-0-m-*-iso8859-1"
export DefaultFTFontSpec DefaultFTFontSpecL1

# Set a default font that should work for everything
#
eval echo "*font: ${DefaultFontSpec}" | xrdb -merge

最后,这是一个使用上述设置(即上面的资源和 shell 变量)启动xterm(已编译为使用XftXft.dpi )以在屏幕上以 10.0 点的物理大小显示文本的示例:

xterm -fs 10 -fa $DefaultFTFontSpec
于 2022-01-24T00:19:10.903 回答