Posted on 2011-09-15 21:24
RTY 阅读(866)
评论(0) 编辑 收藏 引用 所属分类:
Qt
上一次关注Qt Lighthouse是在6月初,可是现在都8月底了。时间真快...
Lighthouse 是 QPA(Qt Platform Abstraction) 项目的名字,它使得将Qt移植到新的平台变得比较简单。尽管现在它已经完全融入到了Qt主干代码中,lighthouse作为独立项目已经不复存在了,但本文中,我们继续使用这个名字(虽然已不太恰当)。
QPA 抽象了什么?
不妨看看QPA前后,有何不同:
之前
考虑一下,传统的Qt是如何实现图形界面的夸平台:
Q_WS_X11
Q_WS_MAC
Q_WS_QWS
Q_WS_WIN
Q_WS_S60
#if defined(Q_WS_X11)
...
#elif defined(Q_WS_MAC)
...
#elif defined(Q_WS_WIN)
...
#endif
qapplication_x11.cpp
qapplication_win.cpp
qapplication_s60.cpp
qapplication_mac.mm
qapplication_qws.cpp
...
qwidget_win.cpp
qwidget_qws.cpp
qwidget_mac.cpp
qwidget_x11.cpp
...
- src/gui/kernel.pri 等工程文件内,控制哪些文件参与编译
win32 {
...
}
symbian {
...
}
unix:x11 {
...
}
这一切这意味这什么??
如果我们想在这个基础上支持一个新的窗口系统,比如wayland,需要
总之,需要对Qt的代码进行大量的修改。这一切使得将Qt移植到新的窗口系统中,变得不是那么容易。
之后
QPA 定义了一套接口,而后,将窗口系统相关的代码放到插件中:
- src/plugins/platforms/xlib/*
- src/plugins/platforms/wayland/*
- src/plugins/platforms/cocoa/*
这时,如果我们想支持一个新的窗口系统,怎么办?只需要编写一个新的插件,而Qt自身的代码则不需要任何改变。
(当然,编写插件本身还是很有难度的,哈...)
QPA源码结构
为了使插件能供工作,Qt中需要提供有相应的加载接口,在Qt源码中搜索*_qpa.h、*_qpa.cpp、 *_qpa_p.h 即可找到所有(fixme)和 qpa有关的代码:
- QTDIR/src/opengl
- QTDIR/src/gui
- painting
- qcolormap_qpa.cpp
- qpaintdevice_qpa.cpp
- image
- egl
- kernel
- qplatformintegrationplugin_qpa.cpp
- qplatformcursor_qpa.cpp
- qwidget_qpa.cpp
- ...
- text
- qfontengine_qpa.cpp
- qfontengine_qpa_p.h
- ...
可以看到代码集中在 gui/kernel 部分;除此外,和字体相关gui/text,和绘图相关gui/painting、gui/image、gui/egl,和opengl相关
QPA结构
这个应该算是 QPA 的核心了,
- 它是QApplication(准确地说是QApplicationPrivate)的成员
class Q_GUI_EXPORT QApplicationPrivate : public QCoreApplicationPrivate
{
...
static QPlatformIntegration *platform_integration;
...
QApplication::QApplication()
QApplicationPrivate::construct()
qt_init()
init_platform()
QPlatfromIntegrationFactory::create()
class Q_GUI_EXPORT QPlatformIntegration
{
public:
GraphicsSystem functions |
| virtual QPixmapData *createPixmapData() |
| virtual QPlatformWindow *createPlatformWindow() |
| virtual QWindowSurface *createWindowSurface() |
Window System functions |
| virtual QList<QPlatformScreen *> screens() |
| virtual void moveToScreen() |
| virtual bool isVirtualDesktop() |
| virtual QPixmap grabWindow() |
Deeper window system integrations |
| virtual QPlatformFontDatabase *fontDatabase() |
| virtual QPlatformClipboard *clipboard() |
... |
这样一来:
当你在程序中 | 它会向QPlatformIntegration请求 |
使用QWidget时 | 给我一个窗口(QPlatformWindow)及绘图区域(QWindowSurface) |
使用QPixmap时 | 给我一个位图的后端(QPixmapData) |
使用QFont时 | 给我字体数据信息(QPlatformFontDatabase) |
使用QGLWidget时 | 给我一个窗口 |
... | ... |
QPlatformWindow | 窗口 负责窗口的几何尺寸 可以是另一个窗口的子窗口 |
QWindowSurface | 窗口绘图区域(drawing area of a window) 它来决定使用哪一个paintEngine 将像素Push到屏幕上 |
相对而言,QPlatformWindow 出现的比较晚一点(见Say hello to QPlatformWindow一文)之所以。之所以分离开来,原因见Remodelling the Lighthouse。
- 代表屏幕(显示器)
- 它提供的api对应用程序来说是只读的
- 用来计算分辨率 dpi
class Q_GUI_EXPORT QPlatformScreen : public QObject
{
...
virtual QRect geometry() const = 0;
virtual QRect availableGeometry() const {return geometry();}
virtual int depth() const = 0;
virtual QImage::Format format() const = 0;
virtual QSize physicalSize() const;
QPixmapData
为什么要有这个东西?
通常我们似乎都不怎么区分QImage和QPixmap,尽管在Manual中很大的篇幅在描述这二者的区别。
设计目的和用途(一个是IO和像素操作,一个是屏幕显示):
- QImage is designed and optimized for I/O, and for direct pixel access and manipulation
- while QPixmap is designed and optimized for showing images on screen.
典型的用途:
- Typically, the QImage class is used to load an image file, optionally manipulating the image data, before the QImage object is converted into a QPixmap to be shown on screen.
- Alternatively, if no manipulation is desired, the image file can be loaded directly into a QPixmap.
与QImage不同,QPixmap 是平台相关的
- Note that the pixel data in a pixmap is internal and is managed by the underlying window system.
于是它的后端需要由各个窗口系统来提供也就不足为奇了。
提供字体信息
详见Fonts in Lighthouse一文。
其他
- QPlatformClipboard
- QPlatformCursor
- ...
同前面几个一样,从名字上容易看出是做什么的。
参考