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);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
以及qt.conf资源文件设置。
[Platforms]
WindowsArguments = fontengine=freetype
- 1
- 2
附一些相关解决方案链接:
注意:在实际使用测试中,从大分辨率切换到小分辨率,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();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
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;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
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);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
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);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
对比说明
- 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;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- Xinerma
为什么不使用Xinerma,看屏幕信息结构体就知道了。相比于 Xrandr 少了 是否是主屏的关键信息,根据使用,笔者必须用到 是否为主屏这个关键信息,所以抛弃使用了 Xinerma。
typedef struct { int screen_number; //屏幕索引 short x_org; // left short y_org; // top short width; // 分辨率 宽 short height; // 分辨率 高
} XineramaScreenInfo;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
其他
代码就不上传,上述说明已经是全部关键代码了。如果其他需要补充,或者说错误说明的地方,欢迎指正。不过特意强调,lubuntu18.04中 lxrandr,arandr是真的难用,用的有点难受。有时间自己写一个。
文章来源: blog.csdn.net,作者:何其不顾四月天,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/u011218356/article/details/118854817
- 点赞
- 收藏
- 关注作者
评论(0)