Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qbsdfbscreen.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 The Qt Company Ltd.
2// Copyright (C) 2015-2016 Oleksandr Tymoshenko <gonzo@bluezbox.com>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:significant reason:default
5
6#include "qbsdfbscreen.h"
7#include <QtFbSupport/private/qfbcursor_p.h>
8#include <QtFbSupport/private/qfbwindow_p.h>
9#include <QtCore/QFile>
10#include <QtCore/QRegularExpression>
11#include <QtGui/QPainter>
12
13#include <private/qcore_unix_p.h> // overrides QT_OPEN
14#include <qimage.h>
15#include <qdebug.h>
16
17#include <unistd.h>
18#include <stdlib.h>
19#include <sys/ioctl.h>
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <sys/mman.h>
23#include <fcntl.h>
24#include <errno.h>
25#include <stdio.h>
26#include <limits.h>
27#include <signal.h>
28
29#include <sys/consio.h>
30#include <sys/fbio.h>
31
32QT_BEGIN_NAMESPACE
33
34using namespace Qt::StringLiterals;
35
36enum {
38};
39
40static int openFramebufferDevice(const QString &dev)
41{
42 const QByteArray devPath = QFile::encodeName(dev);
43
44 int fd = QT_OPEN(devPath.constData(), O_RDWR);
45
46 if (fd == -1)
47 fd = QT_OPEN(devPath.constData(), O_RDONLY);
48
49 return fd;
50}
51
52static QRect determineGeometry(const struct fbtype &fb, const QRect &userGeometry)
53{
54 int xoff = 0;
55 int yoff = 0;
56 int w = 0;
57 int h = 0;
58
59 if (userGeometry.isValid()) {
60 w = qMin(userGeometry.width(), fb.fb_width);
61 h = qMin(userGeometry.height(), fb.fb_height);
62
63 int xxoff = userGeometry.x(), yyoff = userGeometry.y();
64 if (xxoff != 0 || yyoff != 0) {
65 if (xxoff < 0 || xxoff + w > fb.fb_width)
66 xxoff = fb.fb_width - w;
67 if (yyoff < 0 || yyoff + h > fb.fb_height)
68 yyoff = fb.fb_height - h;
69 xoff += xxoff;
70 yoff += yyoff;
71 } else {
72 xoff += (fb.fb_width - w)/2;
73 yoff += (fb.fb_height - h)/2;
74 }
75 } else {
76 w = fb.fb_width;
77 h = fb.fb_height;
78 }
79
80 if (w == 0 || h == 0) {
81 qWarning("Unable to find screen geometry, using 320x240");
82 w = 320;
83 h = 240;
84 }
85
86 return QRect(xoff, yoff, w, h);
87}
88
89static QSizeF determinePhysicalSize(const QSize &mmSize, const QSize &res)
90{
91 int mmWidth = mmSize.width();
92 int mmHeight = mmSize.height();
93
94 if (mmWidth <= 0 && mmHeight <= 0) {
95 const int dpi = DefaultDPI;
96 mmWidth = qRound(res.width() * 25.4 / dpi);
97 mmHeight = qRound(res.height() * 25.4 / dpi);
98 } else if (mmWidth > 0 && mmHeight <= 0) {
99 mmHeight = res.height() * mmWidth/res.width();
100 } else if (mmHeight > 0 && mmWidth <= 0) {
101 mmWidth = res.width() * mmHeight/res.height();
102 }
103
104 return QSize(mmWidth, mmHeight);
105}
106
107QBsdFbScreen::QBsdFbScreen(const QStringList &args)
108 : m_arguments(args)
109{
110}
111
113{
114 if (m_framebufferFd != -1) {
115 munmap(m_mmap.data - m_mmap.offset, m_mmap.size);
116 qt_safe_close(m_framebufferFd);
117 }
118}
119
121{
122 QRegularExpression fbRx("fb=(.*)"_L1);
123 QRegularExpression mmSizeRx("mmsize=(\\d+)x(\\d+)"_L1);
124 QRegularExpression sizeRx("size=(\\d+)x(\\d+)"_L1);
125 QRegularExpression offsetRx("offset=(\\d+)x(\\d+)"_L1);
126
127 QString fbDevice;
128 QSize userMmSize;
129 QRect userGeometry;
130
131 // Parse arguments
132 for (const QString &arg : std::as_const(m_arguments)) {
133 QRegularExpressionMatch match;
134 if (arg.contains(mmSizeRx, &match))
135 userMmSize = QSize(match.captured(1).toInt(), match.captured(2).toInt());
136 else if (arg.contains(sizeRx, &match))
137 userGeometry.setSize(QSize(match.captured(1).toInt(), match.captured(2).toInt()));
138 else if (arg.contains(offsetRx, &match))
139 userGeometry.setTopLeft(QPoint(match.captured(1).toInt(), match.captured(2).toInt()));
140 else if (arg.contains(fbRx, &match))
141 fbDevice = match.captured(1);
142 }
143
144 if (!fbDevice.isEmpty()) {
145 // Open the device
146 m_framebufferFd = openFramebufferDevice(fbDevice);
147 } else {
148 m_framebufferFd = STDIN_FILENO;
149 }
150
151 if (m_framebufferFd == -1) {
152 qErrnoWarning(errno, "Failed to open framebuffer %s", qPrintable(fbDevice));
153 return false;
154 }
155
156 struct fbtype fb;
157 if (ioctl(m_framebufferFd, FBIOGTYPE, &fb) != 0) {
158 qErrnoWarning(errno, "Error reading framebuffer information");
159 return false;
160 }
161
162 int line_length = 0;
163 if (ioctl(m_framebufferFd, FBIO_GETLINEWIDTH, &line_length) != 0) {
164 qErrnoWarning(errno, "Error reading line length information");
165 return false;
166 }
167
168 mDepth = fb.fb_depth;
169
170 m_bytesPerLine = line_length;
171 const QRect geometry = determineGeometry(fb, userGeometry);
172 mGeometry = QRect(QPoint(0, 0), geometry.size());
173 switch (mDepth) {
174 case 32:
175 mFormat = QImage::Format_RGB32;
176 break;
177 case 24:
178 mFormat = QImage::Format_RGB888;
179 break;
180 case 16:
181 // falling back
182 default:
183 mFormat = QImage::Format_RGB16;
184 break;
185 }
186 mPhysicalSize = determinePhysicalSize(userMmSize, geometry.size());
187
188 // mmap the framebuffer
189 const size_t pagemask = getpagesize() - 1;
190 m_mmap.size = (m_bytesPerLine * fb.fb_height + pagemask) & ~pagemask;
191 uchar *data = static_cast<uchar*>(mmap(nullptr, m_mmap.size, PROT_READ | PROT_WRITE, MAP_SHARED, m_framebufferFd, 0));
192 if (data == MAP_FAILED) {
193 qErrnoWarning(errno, "Failed to mmap framebuffer");
194 return false;
195 }
196
197 m_mmap.offset = geometry.y() * m_bytesPerLine + geometry.x() * mDepth / 8;
198 m_mmap.data = data + m_mmap.offset;
199
200 QFbScreen::initializeCompositor();
201 m_onscreenImage = QImage(m_mmap.data, geometry.width(), geometry.height(), m_bytesPerLine, mFormat);
202
203 mCursor = new QFbCursor(this);
204
205 return true;
206}
207
209{
210 const QRegion touched = QFbScreen::doRedraw();
211
212 if (touched.isEmpty())
213 return touched;
214
215 if (!m_blitter)
216 m_blitter.reset(new QPainter(&m_onscreenImage));
217
218 for (const QRect &rect : touched)
219 m_blitter->drawImage(rect, mScreenImage, rect);
220 return touched;
221}
222
223// grabWindow() grabs "from the screen" not from the backingstores.
224QPixmap QBsdFbScreen::grabWindow(WId wid, int x, int y, int width, int height) const
225{
226 if (!wid) {
227 if (width < 0)
228 width = m_onscreenImage.width() - x;
229 if (height < 0)
230 height = m_onscreenImage.height() - y;
231 return QPixmap::fromImage(m_onscreenImage).copy(x, y, width, height);
232 }
233
234 const QFbWindow *window = windowForId(wid);
235 if (window) {
236 const QRect geom = window->geometry();
237 if (width < 0)
238 width = geom.width() - x;
239 if (height < 0)
240 height = geom.height() - y;
241 QRect rect(geom.topLeft() + QPoint(x, y), QSize(width, height));
242 rect &= window->geometry();
243 return QPixmap::fromImage(m_onscreenImage).copy(rect);
244 }
245
246 return QPixmap();
247}
248
249QT_END_NAMESPACE
bool initialize() override
~QBsdFbScreen() override
QRegion doRedraw() override
QPixmap grabWindow(WId wid, int x, int y, int width, int height) const override
This function is called when Qt needs to be able to grab the content of a window.
static QRect determineGeometry(const struct fbtype &fb, const QRect &userGeometry)
static int openFramebufferDevice(const QString &dev)
static QSizeF determinePhysicalSize(const QSize &mmSize, const QSize &res)
@ DefaultDPI
#define MAP_FAILED