Linux桌面系统屏幕信息获取

Linux桌面系统屏幕信息获取(Qt、X11、Xrandr、Xinerma)

​ 最近在项目测试中,发现了关于Qt - UI分辨率自适应的问题。从大小屏幕互相切换的问题。也引发了关于屏幕检测的问题。其中关于字体还有图片的自适应,需要在QApplication,初始化完成之后在进行配置。

在网上查找到的解决方案大概都是这个模式

#define DEFAULE_DPI 96 //1080P默认逻辑DPI值
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QCoreApplication::setAttribute(QT::AA_UseHighDpiPixmaps);
qreal currentDpi = funtion(); //实际显示器DPI
qreal scale=currentDpi/96;
qputenv("QT_SCALE_FACTOR",QString::number(scale).toLatin1());
QApplication a(argc, argv);

以及qt.conf资源文件设置。

[Platforms]
WindowsArguments = fontengine=freetype

附一些相关解决方案链接:

Qt4K高分屏自适应,解决字体没有跟随组件增大的问题

QT控件字体根据系统缩放比例(DPI)自适应

QT 使用全局缩放进行全分辨率适配

注意:在实际使用测试中,从大分辨率切换到小分辨率,DPI不应是按照比例缩放。并不是预想中,小屏幕与大屏幕的DPI值是按照正比例来进行缩放的。不同品牌,不同年代的DPI也可能会发生,小屏幕的DPI大于大屏幕的DPI,所以字体没有如预期一样变小,反而变大了。

如果进行全局设置,也会有其他问题,一些图片还有字体,并不想让它进行缩放,所以全局设置并不是理想的方案,还需要针对不同控件,字符进行单独的控制。而且要考虑到代码量,qss样式设置等一些其他问题,重构的代价太高。

本文主要讨论在调研中在QApplication,初始化前,怎么获取全部屏幕信息。Windows下的获取调用WindowsAPI进行设置,网上大多也给出了解决方案,但是linux在怎么获取,大多都没有提到,所以在这进行讨论。

Qt

Qt自身获取屏幕分辨率,主要还是在 QApp初始化后获取,在这主要提一下DPI值得获取。一些方案中DPI的计算在初始化之后进行。下述代码是在外网上关于Qt屏幕信息获取的一段,忘记是否是Qt官方的Demo了。在实际DPI值获取中只需要,主屏分辨率获取或者当前屏幕分辨率获取还有DPI值得获取,实际参与计算的是逻辑DPI,即 screen->logicalDotsPerInch(),分辨率使用有效分辨率 screen->availableSize().width() x screen->availableGeometry().height()

#include "mainwindow.h"
#include <QApplication>
#include <QScreen>
#include <QDebug>

QString Orientation(Qt::ScreenOrientation orientation)
{
    switch (orientation) {
        case Qt::PrimaryOrientation           : return "Primary";
        case Qt::LandscapeOrientation         : return "Landscape";
        case Qt::PortraitOrientation          : return "Portrait";
        case Qt::InvertedLandscapeOrientation : return "Inverted landscape";
        case Qt::InvertedPortraitOrientation  : return "Inverted portrait";
        default                               : return "Unknown";
    }
}
	
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

//使用 QApplication 类也可以获取。
//获取当前屏幕的相关信息,首先获取App所在屏幕索引,然后根据索引或者当前屏幕的指针。  
/*    int currentIndex = a.desktop()->screenNumber(&w);
      QScreen* currentScreent =  QGuiApplication::screens()[currentIndex];
      qDebug() << currentScreent->name() << currentScreent->geometry().x() << currentScreent->geometry().y();*/    
    
    
    qDebug() << "Number of screens:" << QGuiApplication::screens().size();
    qDebug() << "Primary screen:" << QGuiApplication::primaryScreen()->name();

    foreach (QScreen *screen, QGuiApplication::screens()) {
           qDebug() << "Information for screen:" << screen->name();
           qDebug() << "  Available geometry:" << screen->availableGeometry().x() << screen->availableGeometry().y() << screen->availableGeometry().width() << "x" << screen->availableGeometry().height();
           qDebug() << "  Available size:" << screen->availableSize().width() << "x" << screen->availableSize().height();
           qDebug() << "  Available virtual geometry:" << screen->availableVirtualGeometry().x() << screen->availableVirtualGeometry().y() << screen->availableVirtualGeometry().width() << "x" << screen->availableVirtualGeometry().height();
           qDebug() << "  Available virtual size:" << screen->availableVirtualSize().width() << "x" << screen->availableVirtualSize().height();
           qDebug() << "  Depth:" << screen->depth() << "bits";
           qDebug() << "  Geometry:" << screen->geometry().x() << screen->geometry().y() << screen->geometry().width() << "x" << screen->geometry().height();
           qDebug() << "  Logical DPI:" << screen->logicalDotsPerInch();
           qDebug() << "  Logical DPI X:" << screen->logicalDotsPerInchX();
           qDebug() << "  Logical DPI Y:" << screen->logicalDotsPerInchY();
           qDebug() << "  Orientation:" << Orientation(screen->orientation());
           qDebug() << "  Physical DPI:" << screen->physicalDotsPerInch();
           qDebug() << "  Physical DPI X:" << screen->physicalDotsPerInchX();
           qDebug() << "  Physical DPI Y:" << screen->physicalDotsPerInchY();
           qDebug() << "  Physical size:" << screen->physicalSize().width() << "x" << screen->physicalSize().height() << "mm";
           qDebug() << "  Primary orientation:" << Orientation(screen->primaryOrientation());
           qDebug() << "  Refresh rate:" << screen->refreshRate() << "Hz";
           qDebug() << "  Size:" << screen->size().width() << "x" << screen->size().height();
           qDebug() << "  Virtual geometry:" << screen->virtualGeometry().x() << screen->virtualGeometry().y() << screen->virtualGeometry().width() << "x" << screen->virtualGeometry().height();
           qDebug() << "  Virtual size:" << screen->virtualSize().width() << "x" << screen->virtualSize().height();
       }

    return a.exec();
}

X11_Xlib

关于Xlib 获取所有屏幕信息,并没有成功,只是获取到了总的屏幕大小,并没有做更细致的研究。XScreenCount获取到的屏幕数量为1.等到随后有兴趣的时候在进行深入研究吧。

Display *display = XOpenDisplay(NULL);
Window window = DefaultRootWindow(display);
int screenCount = XScreenCount(display);
for(int i = 0 ; i < screenCount; i++)
{
    Screen* screent =  XScreenOfDisplay(display, i);
    //        XDisplayHeight(display, i);
    int width = screent->mwidth;
    int height = screent->mheight;
    std::cout << width << " " << height << std::endl;
}

Xrandr

XRandr目前通用的屏幕信息获取工具了。并不想直接调用命令,在这里调用了 libXrandr-dev ,开发库的API。调用X11通用的方法,获取Display,window等信息,然后获取 XRRMonitorInfo 列表。

#include <X11/extensions/Xrandr.h>

Display *display = XOpenDisplay(NULL);
Window window = DefaultRootWindow(display);
int monitors = 0;
XRRMonitorInfo* info = XRRGetMonitors(display, window, True, &monitors);
for(int i = 0; i < monitors; i++)
{
    XID id;
    RROutput* out = info[i].outputs;
    memcpy(&id, out, sizeof(RROutput));
    std::cout << "XRRMonitorInfo: " << "index:" << i << " primary:"  << info[i].primary  << " noutput:" << info[i].noutput << " width:" << info[i].width << " height:" << info[i].height \
        << " widthmm:" << info[i].mwidth << " heightm:" << info[i].mheight << " outputs:"<< id << std::endl;
}
XRRFreeMonitors(info);
XFree(display);

Xinerma

Xinerma,主要是负责多屏显示的。一些基础信息资料不做说明,只说明简单使用,通用X11调用方法,

#include <X11/extensions/Xinerama.h>

Display *display = XOpenDisplay(NULL);
int screenSize = 0;
XineramaScreenInfo * screenXi = XineramaQueryScreens(display, &screenSize);
for(int i = 0; i < screenSize; i++)
{
    std::cout << "XineramaScreenInfo:" << " x_org:" << screenXi[i].x_org << " y_org:" <<  screenXi[i].y_org \
        << " width:" << screenXi[i].width << " height:" << screenXi[i].height << std::endl;
}

XFree(display);

对比说明

  • Qt

在日常使用,Qt获取屏幕分辨率,设置全屏之类的属性,理论来说并不会出问题,但在实际使用中,笔者发现了Qt获取桌面有效分辨率并不正确,大多数情况下是准确的,但是偶尔也会出现获取错误,所有全屏属性的打破,导致整个界面布局失败。即在后来的项目放弃了这一方法。

错误情况猜测,Qt毕竟属于C++接口,属于上层应用接口。并不如X11这些C接口直接调用来的准确。以后劲量避免使用Qt接口来设置屏幕相关属性了。

  • Xrandr

笔者目前使用的获取屏幕信息方法,xrandr。下面是 XRRMonitorInfo,xrandr获取到的屏幕信息结构体,

typedef struct _XRRMonitorInfo {
    Atom name;
    Bool primary; 		//是否是主屏
    Bool automatic;
    int noutput;
    int x;				// left
    int y;				//top
    int width;			//像素 宽度 分辨率的宽
    int height;			//像素 高度 分辨率的高
    int mwidth;			//物理 宽度
    int mheight;		//物理 高度 
    RROutput *outputs;
} XRRMonitorInfo;
  • Xinerma

为什么不使用Xinerma,看屏幕信息结构体就知道了。相比于 Xrandr 少了 是否是主屏的关键信息,根据使用,笔者必须用到 是否为主屏这个关键信息,所以抛弃使用了 Xinerma。

typedef struct {
   int   screen_number;	//屏幕索引
   short x_org;			// left
   short y_org;			// top
   short width;			// 分辨率 宽
   short height;		// 分辨率 高
} XineramaScreenInfo;

其他

代码就不上传,上述说明已经是全部关键代码了。如果其他需要补充,或者说错误说明的地方,欢迎指正。不过特意强调,lubuntu18.04中 lxrandr,arandr是真的难用,用的有点难受。有时间自己写一个。

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
### 回答1: 要调整Linux屏幕大小,可以使用以下方法: 1. 使用xrandr命令:在终端中输入xrandr命令,可以列出所有可用的分辨率和屏幕大小选项。然后使用xrandr命令设置所需的分辨率和屏幕大小。 2. 使用系统设置:在Linux桌面环境中,可以通过系统设置来调整屏幕大小。打开系统设置,找到显示选项,然后选择所需的分辨率和屏幕大小。 3. 编辑xorg.conf文件:xorg.conf文件是Linux系统的X Window配置文件,可以手动编辑该文件来调整屏幕大小。打开xorg.conf文件,找到屏幕部分,然后修改所需的分辨率和屏幕大小。 无论使用哪种方法,都需要注意选择适合自己的分辨率和屏幕大小,以获得最佳的显示效果。 ### 回答2: 要在Linux上调整屏幕大小,可以使用以下方法: 1. 使用xrandr命令: xrandr(X Resize and Rotate)是一个用于控制和设置屏幕分辨率、旋转以及镜像等属性的命令。要查看当前屏幕的分辨率,可以直接在终端中输入xrandr。要调整分辨率,可以使用xrandr -s命令,后跟所需的分辨率,例如:xrandr -s 1024x768。 2. 在系统设置中更改分辨率:图形用户界面下,可以通过“设置”或“显示设置”等工具来更改屏幕分辨率。大多数Linux发行版都提供这样的软件,为用户提供更友好的方式来进行设置。 3. 使用xorg.conf文件:xorg.conf文件是X Window系统的配置文件,可以用于配置显示驱动程序和显示设置。要调整屏幕大小,可以手动编辑此文件,以指定所需的分辨率和其他属性。该文件通常位于/etc/X11目录下,并需要root权限才能编辑。 需要注意的是,当更改屏幕分辨率时,可能需要重新启动X Window系统或重新登录才能生效。此外,如果新的设置导致显示不正常,则可以使用备选驱动程序或还原之前的设置来恢复系统。 总之,在Linux上调整屏幕大小需要通过命令行或图形界面进行设置,并根据具体情况进行调试和优化。掌握以上方法将有助于用户更好地管理和使用Linux系统。 ### 回答3: 对于Linux系统来说,调整屏幕大小通常需要使用命令行进行操作。以下是几种不同的方法: 1. 使用xrandr命令 xrandr是一个命令行工具,可以用来调整Linux系统上的显示器分辨率。首先,可以使用xrandr命令来查看系统中所有的屏幕以及它们的分辨率: $ xrandr 然后,可以使用以下命令来更改当前屏幕的分辨率: $ xrandr --output <屏幕名称> --mode <分辨率> 例如,如果要将屏幕名称为“eDP-1”的屏幕设置为分辨率为1920x1080,则可以使用以下命令: $ xrandr --output eDP-1 --mode 1920x1080 2. 使用命令行工具cvt和xrandr 如果您想要调整一个自定义的分辨率,可以使用命令行工具cvt来生成一个Modeline字符串,然后再使用xrandr来设置该分辨率。首先,使用cvt命令来生成一个Modeline字符串。以下是一个例子: $ cvt 1920 1080 60 上述命令中,1920和1080分别是您想要设置的分辨率的宽度和高度,60是刷新率。 生成的Modeline字符串类似于以下内容: "1920x1080_60.00" 173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync +vsync 然后,将这个Modeline字符串添加到xrandr命令中,设置屏幕分辨率: $ xrandr --newmode "1920x1080_60.00" 173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync +vsync $ xrandr --addmode <屏幕名称> 1920x1080_60.00 $ xrandr --output <屏幕名称> --mode 1920x1080_60.00 3. 使用GUI工具 除了使用命令行工具外,Linux系统上还有许多GUI工具可以帮助您更轻松地调整屏幕分辨率。例如,Ubuntu系统上的“Displays”应用程序提供了一个直观的界面,其中您可以更改分辨率以及旋转和翻转屏幕。其他流行的GUI工具还包括arandr、lxrandr和xvidtune等。 综上所述,在Linux系统中,您可以使用命令行工具xrandr和cvt来调整屏幕分辨率,也可以使用各种可用的GUI工具来实现更简单的调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值