【问题标题】:How to get system scale factor in X11如何在 X11 中获取系统比例因子
【发布时间】:2018-03-02 15:10:28
【问题描述】:

我想让我的应用程序(纯粹在 X11 中)具有高 DPI 感知能力。为此,我需要一种方法来找出在显示设置中配置的系统比例因子。有没有什么方法可以从 X11 应用程序中获得这个系统比例因子,而无需求助于 GTK 等更高级别的 API?

FWIW,我检查了 GTK 源代码以了解 gdk_window_get_scale_factor() 是如何做到的,它似乎读取了一个名为 GDK_SCALE 的环境变量。然而,这个环境变量在我的系统上根本不存在,即使我在 4K 显示器上将缩放设置为 1.75。

那么如何以编程方式检索系统缩放因子?

【问题讨论】:

  • 请注意,您的假设是不合逻辑的 -> “无需求助于 GTK 等更高级别的 API”,它必须是可能的,或者否则这样的更高级别的 API 是如何做到的?
  • 好吧,正如我所说,GTK 读取了 GDK_SCALE 环境变量,但我的系统上没有这个变量,所以我认为 gdk_window_get_scale_factor 并不实际工作。
  • 您根本不需要 GTK。 GTK 在其他地方找到了这个值,这就是我想说的。
  • 对不起,我不明白你的意思。根据消息来源,GTK 显示为GDK_SCALE,仅此而已。
  • 你问的是 DPI 对吧?可能与How to get screen DPI (linux,mac) programatically 重复。

标签: c linux gtk x11


【解决方案1】:

为了回答我自己的问题,我现在尝试了三种方法:

  1. XRandR
  2. X11 的DisplayWidth/HeightDisplayWidthMM/HeightMM
  3. 查看xdpyinfo 输出

都不返回正确的 DPI。相反,Xft.dpi Xresource 似乎是解决这个问题的关键。 Xft.dpi 似乎总是带有正确的 DPI,所以我们可以读取它来获取系统比例因子。

这里有一些来自here的源代码:

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/Xresource.h>

double _glfwPlatformGetMonitorDPI(_GLFWmonitor* monitor)
{
    char *resourceString = XResourceManagerString(_glfw.x11.display);
    XrmDatabase db;
    XrmValue value;
    char *type = NULL;
    double dpi = 0.0;

    XrmInitialize(); /* Need to initialize the DB before calling Xrm* functions */

    db = XrmGetStringDatabase(resourceString);

    if (resourceString) {
        printf("Entire DB:\n%s\n", resourceString);
        if (XrmGetResource(db, "Xft.dpi", "String", &type, &value) == True) {
            if (value.addr) {
                dpi = atof(value.addr);
            }
        }
    }

    printf("DPI: %f\n", dpi);
    return dpi;
}

这对我有用。

【讨论】:

  • XResourceManagerString 为我返回 NULL
【解决方案2】:

我不确定有关 Gtk 的答案是否有帮助,这个问题用gtk 标记,作者似乎使用它。使用 GNOME,我可以在 Wayland 上为每个监视器应用不同的缩放因子,X11 对所有监视器使用缩放因子。以下代码报告了比例因子:

#include <gtk/gtk.h>
#include <stdio.h>

static void activate(GtkApplication *app, gpointer user_data) {
    GtkWidget *window;
    window = gtk_application_window_new(app); // creates GtkApplicationWindow, returns a GtkWidget*
    gtk_window_set_title(GTK_WINDOW (window), "Window"); // macro, checks types and does function style cast
    gtk_window_set_default_size(GTK_WINDOW (window), 200, 200);
    gtk_widget_show_all(window);
    
    GdkWindow* gdk_window = gtk_widget_get_window(window);
    GdkDisplay* gdk_display = gdk_display_get_default();

    // prints sadly always '1' on my system
    GdkMonitor* gdk_monitor = gdk_display_get_monitor_at_window(gdk_display, gdk_window);
    int scale = gdk_monitor_get_scale_factor(gdk_monitor);
    printf("scale is %d\n", scale);

    // seems to work fine
    int n = gdk_display_get_n_monitors(gdk_display);
    for (int i = 0; i < n; ++i) {
        GdkMonitor* monitor = gdk_display_get_monitor(gdk_display, i);
        int scale = gdk_monitor_get_scale_factor(monitor);
        printf("monitor %d, scale %d\n", i, scale);
    }
}

int main(int argc, char **argv) {
    GtkApplication *app;
    int status;

    app = gtk_application_new("org.gtk.example", G_APPLICATION_FLAGS_NONE);
    g_signal_connect(app, "activate", G_CALLBACK (activate), NULL);
    status = g_application_run(G_APPLICATION (app), argc, argv);
    g_object_unref(app); // free memory of GtkApplication

    return status;
}

编译

gcc `pkg-config --cflags gtk+-3.0` -o gtk_scale gtk_scale.c `pkg-config --libs gtk+-3.0`

当我在 Wayland 上运行应用程序时,左侧监视器(主)设置为比例因子 1,右侧监视器设置为比例因子 2:

./gtk_scale 
scale is 1         # wrong, application windows resides on right screen with scale factor 2
monitor 0, scale 2 # correct
monitor 1, scale 1 # correct

更方便的函数gdk_display_get_monitor_at_window() 似乎总是返回主监视器的比例因子,而不是应用程序窗口使用的实际比例因子。

获取最大窗口所在的监视器,或者 如果它在所有监视器之外,则监视器靠近窗口。

因此,我现在推荐gdk_monitor_get_scale_factor(),它提供了正确的结果。如果连接了多个显示器 - 就像在我的示例中一样 - 您现在需要弄清楚您的应用程序窗口显示在哪一个上。

获取从监视器坐标映射到的内部比例因子 实际的设备像素。在传统系统上,这是 1,但在 非常高密度的输出,这可能是一个更高的值(通常为 2)。

如果您想为 特定的监视器,但大多数时候您是在窗口中绘制 最好使用 gdk_window_get_scale_factor() 代替。

提到的另一个函数是 Andreas 最初调查的函数,对我来说它总是返回 2。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-10
    • 1970-01-01
    • 1970-01-01
    • 2012-04-06
    • 2013-04-25
    • 1970-01-01
    相关资源
    最近更新 更多