1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qfbscreen_p.h"
5#include "qfbcursor_p.h"
6#include "qfbwindow_p.h"
7#include "qfbbackingstore_p.h"
8
9#include <QtGui/QPainter>
10#include <QtCore/QCoreApplication>
11#include <qpa/qwindowsysteminterface.h>
12
13#include <QtCore/QDebug>
14#include <QtCore/QElapsedTimer>
15
16QT_BEGIN_NAMESPACE
17
18QFbScreen::QFbScreen()
19 : mUpdatePending(false),
20 mCursor(0),
21 mDepth(16),
22 mFormat(QImage::Format_RGB16),
23 mPainter(nullptr)
24{
25}
26
27QFbScreen::~QFbScreen()
28{
29 delete mPainter;
30}
31
32void QFbScreen::initializeCompositor()
33{
34 mScreenImage = QImage(mGeometry.size(), mFormat);
35 scheduleUpdate();
36}
37
38bool QFbScreen::event(QEvent *event)
39{
40 if (event->type() == QEvent::UpdateRequest) {
41 doRedraw();
42 mUpdatePending = false;
43 return true;
44 }
45 return QObject::event(event);
46}
47
48void QFbScreen::addWindow(QFbWindow *window)
49{
50 mWindowStack.prepend(t: window);
51 if (!mPendingBackingStores.isEmpty()) {
52 //check if we have a backing store for this window
53 for (int i = 0; i < mPendingBackingStores.size(); ++i) {
54 QFbBackingStore *bs = mPendingBackingStores.at(i);
55 // this gets called during QWindow::create() at a point where the
56 // invariant (window->handle()->window() == window) is broken
57 if (bs->window() == window->window()) {
58 window->setBackingStore(bs);
59 mPendingBackingStores.removeAt(i);
60 break;
61 }
62 }
63 }
64 setDirty(window->geometry());
65 QWindow *w = topWindow();
66 QWindowSystemInterface::handleWindowActivated(window: w);
67 topWindowChanged(w);
68}
69
70void QFbScreen::removeWindow(QFbWindow *window)
71{
72 mWindowStack.removeOne(t: window);
73 setDirty(window->geometry());
74 QWindow *w = topWindow();
75 QWindowSystemInterface::handleWindowActivated(window: w);
76 topWindowChanged(w);
77}
78
79void QFbScreen::raise(QFbWindow *window)
80{
81 int index = mWindowStack.indexOf(t: window);
82 if (index <= 0)
83 return;
84 mWindowStack.move(from: index, to: 0);
85 setDirty(window->geometry());
86 QWindow *w = topWindow();
87 QWindowSystemInterface::handleWindowActivated(window: w);
88 topWindowChanged(w);
89}
90
91void QFbScreen::lower(QFbWindow *window)
92{
93 int index = mWindowStack.indexOf(t: window);
94 if (index == -1 || index == (mWindowStack.size() - 1))
95 return;
96 mWindowStack.move(from: index, to: mWindowStack.size() - 1);
97 setDirty(window->geometry());
98 QWindow *w = topWindow();
99 QWindowSystemInterface::handleWindowActivated(window: w);
100 topWindowChanged(w);
101}
102
103QWindow *QFbScreen::topWindow() const
104{
105 for (QFbWindow *fbw : mWindowStack) {
106 if (fbw->window()->type() == Qt::Window || fbw->window()->type() == Qt::Dialog)
107 return fbw->window();
108 }
109 return nullptr;
110}
111
112QWindow *QFbScreen::topLevelAt(const QPoint & p) const
113{
114 for (QFbWindow *fbw : mWindowStack) {
115 if (fbw->geometry().contains(p, proper: false) && fbw->window()->isVisible())
116 return fbw->window();
117 }
118 return nullptr;
119}
120
121int QFbScreen::windowCount() const
122{
123 return mWindowStack.size();
124}
125
126void QFbScreen::setDirty(const QRect &rect)
127{
128 const QRect intersection = rect.intersected(other: mGeometry);
129 const QPoint screenOffset = mGeometry.topLeft();
130 mRepaintRegion += intersection.translated(p: -screenOffset); // global to local translation
131 scheduleUpdate();
132}
133
134void QFbScreen::scheduleUpdate()
135{
136 if (!mUpdatePending) {
137 mUpdatePending = true;
138 QCoreApplication::postEvent(receiver: this, event: new QEvent(QEvent::UpdateRequest));
139 }
140}
141
142void QFbScreen::setPhysicalSize(const QSize &size)
143{
144 mPhysicalSize = size;
145}
146
147void QFbScreen::setGeometry(const QRect &rect)
148{
149 delete mPainter;
150 mPainter = nullptr;
151 mGeometry = rect;
152 mScreenImage = QImage(mGeometry.size(), mFormat);
153 QWindowSystemInterface::handleScreenGeometryChange(screen: QPlatformScreen::screen(), newGeometry: geometry(), newAvailableGeometry: availableGeometry());
154 resizeMaximizedWindows();
155}
156
157bool QFbScreen::initialize()
158{
159 return true;
160}
161
162QRegion QFbScreen::doRedraw()
163{
164 const QPoint screenOffset = mGeometry.topLeft();
165
166 QRegion touchedRegion;
167 if (mCursor && mCursor->isDirty() && mCursor->isOnScreen()) {
168 const QRect lastCursor = mCursor->dirtyRect();
169 mRepaintRegion += lastCursor;
170 }
171 if (mRepaintRegion.isEmpty() && (!mCursor || !mCursor->isDirty()))
172 return touchedRegion;
173
174 if (!mPainter)
175 mPainter = new QPainter(&mScreenImage);
176
177 const QRect screenRect = mGeometry.translated(p: -screenOffset);
178 for (QRect rect : mRepaintRegion) {
179 rect = rect.intersected(other: screenRect);
180 if (rect.isEmpty())
181 continue;
182
183 mPainter->setCompositionMode(QPainter::CompositionMode_Source);
184 mPainter->fillRect(r: rect, c: mScreenImage.hasAlphaChannel() ? Qt::transparent : Qt::black);
185
186 for (int layerIndex = mWindowStack.size() - 1; layerIndex != -1; layerIndex--) {
187 if (!mWindowStack[layerIndex]->window()->isVisible())
188 continue;
189
190 const QRect windowRect = mWindowStack[layerIndex]->geometry().translated(p: -screenOffset);
191 const QRect windowIntersect = rect.translated(dx: -windowRect.left(), dy: -windowRect.top());
192 QFbBackingStore *backingStore = mWindowStack[layerIndex]->backingStore();
193 if (backingStore) {
194 backingStore->lock();
195 mPainter->drawImage(targetRect: rect, image: backingStore->image(), sourceRect: windowIntersect);
196 backingStore->unlock();
197 }
198 }
199 }
200
201 if (mCursor && (mCursor->isDirty() || mRepaintRegion.intersects(r: mCursor->lastPainted()))) {
202 mPainter->setCompositionMode(QPainter::CompositionMode_SourceOver);
203 touchedRegion += mCursor->drawCursor(painter&: *mPainter);
204 }
205 touchedRegion += mRepaintRegion;
206 mRepaintRegion = QRegion();
207
208 return touchedRegion;
209}
210
211QFbWindow *QFbScreen::windowForId(WId wid) const
212{
213 for (int i = 0; i < mWindowStack.size(); ++i) {
214 if (mWindowStack[i]->winId() == wid)
215 return mWindowStack[i];
216 }
217 return nullptr;
218}
219
220QFbScreen::Flags QFbScreen::flags() const
221{
222 return { };
223}
224
225QT_END_NAMESPACE
226
227#include "moc_qfbscreen_p.cpp"
228

source code of qtbase/src/platformsupport/fbconvenience/qfbscreen.cpp