上一次關注Qt Lighthouse是在6月初,可是現在都8月底了。時間真快...
Lighthouse 是 QPA(Qt Platform Abstraction) 項目的名字,它使得將Qt移植到新的平臺變得比較簡單。盡管現在它已經完全融入到了Qt主干代碼中,lighthouse作為獨立項目已經不復存在了,但本文中,我們繼續使用這個名字(雖然已不太恰當)。
QPA 抽象了什么?
不妨看看QPA前后,有何不同:
之前
考慮一下,傳統的Qt是如何實現圖形界面的夸平臺:
針對不同的窗口系統(WS)定義相應的宏: Q_WS_*
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,需要
添加平臺相關的宏,代碼中針對該窗口再擴充 #if #elif #endif
- 添加平臺相關的文件,擴充 **.pri 文件使其融入Qt
- ...
總之,需要對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
- qgl_qpa.cpp
- QTDIR/src/gui
- painting
- qcolormap_qpa.cpp
- qpaintdevice_qpa.cpp
- image
- qpixmap_qpa.cpp
- egl
- qegl_qpa.cpp
- kernel
- qplatformintegrationplugin_qpa.cpp
- qplatformcursor_qpa.cpp
- qwidget_qpa.cpp
- ...
- text
- qfontengine_qpa.cpp
- qfontengine_qpa_p.h
- ...
- painting
可以看到代碼集中在 gui/kernel 部分;除此外,和字體相關gui/text,和繪圖相關gui/painting、gui/image、gui/egl,和opengl相關
QPA結構
QPlatformIntegration
這個應該算是 QPA 的核心了,
- 它是QApplication(準確地說是QApplicationPrivate)的成員
class Q_GUI_EXPORT QApplicationPrivate : public QCoreApplicationPrivate { ... static QPlatformIntegration *platform_integration; ...
- 在初始化QAppliction時它會被創建
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
QPlatformWindow | 窗口 |
QWindowSurface | 窗口繪圖區域(drawing area of a window) |
相對而言,QPlatformWindow 出現的比較晚一點(見Say hello to QPlatformWindow一文)之所以。之所以分離開來,原因見Remodelling the Lighthouse。
QPlatformScreen
- 代表屏幕(顯示器)
- 它提供的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.
于是它的后端需要由各個窗口系統來提供也就不足為奇了。
QPlatformFontDatabase
提供字體信息
詳見Fonts in Lighthouse一文。
其他
- QPlatformClipboard
- QPlatformCursor
- ...
同前面幾個一樣,從名字上容易看出是做什么的。