1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the plugins of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qoffscreencommon.h"
41#include "qoffscreenwindow.h"
42
43#include <QtGui/private/qpixmap_raster_p.h>
44#include <QtGui/private/qguiapplication_p.h>
45
46#include <qpa/qplatformcursor.h>
47#include <qpa/qplatformwindow.h>
48
49QT_BEGIN_NAMESPACE
50
51QPlatformWindow *QOffscreenScreen::windowContainingCursor = nullptr;
52
53class QOffscreenCursor : public QPlatformCursor
54{
55public:
56 QOffscreenCursor() : m_pos(10, 10) {}
57
58 QPoint pos() const override { return m_pos; }
59 void setPos(const QPoint &pos) override
60 {
61 m_pos = pos;
62 const QWindowList wl = QGuiApplication::topLevelWindows();
63 QWindow *containing = nullptr;
64 for (QWindow *w : wl) {
65 if (w->type() != Qt::Desktop && w->isExposed() && w->geometry().contains(p: pos)) {
66 containing = w;
67 break;
68 }
69 }
70
71 QPoint local = pos;
72 if (containing)
73 local -= containing->position();
74
75 QWindow *previous = QOffscreenScreen::windowContainingCursor ? QOffscreenScreen::windowContainingCursor->window() : nullptr;
76
77 if (containing != previous)
78 QWindowSystemInterface::handleEnterLeaveEvent(enter: containing, leave: previous, local, global: pos);
79
80 QWindowSystemInterface::handleMouseEvent(window: containing, local, global: pos, state: QGuiApplication::mouseButtons(), button: Qt::NoButton,
81 type: QEvent::MouseMove, mods: QGuiApplication::keyboardModifiers(), source: Qt::MouseEventSynthesizedByQt);
82
83 QOffscreenScreen::windowContainingCursor = containing ? containing->handle() : nullptr;
84 }
85#ifndef QT_NO_CURSOR
86 void changeCursor(QCursor *windowCursor, QWindow *window) override
87 {
88 Q_UNUSED(windowCursor);
89 Q_UNUSED(window);
90 }
91#endif
92private:
93 QPoint m_pos;
94};
95
96QOffscreenScreen::QOffscreenScreen()
97 : m_geometry(0, 0, 800, 600)
98 , m_cursor(new QOffscreenCursor)
99{
100}
101
102QPixmap QOffscreenScreen::grabWindow(WId id, int x, int y, int width, int height) const
103{
104 QRect rect(x, y, width, height);
105
106 QOffscreenWindow *window = QOffscreenWindow::windowForWinId(id);
107 if (!window || window->window()->type() == Qt::Desktop) {
108 const QWindowList wl = QGuiApplication::topLevelWindows();
109 QWindow *containing = nullptr;
110 for (QWindow *w : wl) {
111 if (w->type() != Qt::Desktop && w->isExposed() && w->geometry().contains(r: rect)) {
112 containing = w;
113 break;
114 }
115 }
116
117 if (!containing)
118 return QPixmap();
119
120 id = containing->winId();
121 rect = rect.translated(p: -containing->geometry().topLeft());
122 }
123
124 QOffscreenBackingStore *store = QOffscreenBackingStore::backingStoreForWinId(id);
125 if (store)
126 return store->grabWindow(window: id, rect);
127 return QPixmap();
128}
129
130QOffscreenBackingStore::QOffscreenBackingStore(QWindow *window)
131 : QPlatformBackingStore(window)
132{
133}
134
135QOffscreenBackingStore::~QOffscreenBackingStore()
136{
137 clearHash();
138}
139
140QPaintDevice *QOffscreenBackingStore::paintDevice()
141{
142 return &m_image;
143}
144
145void QOffscreenBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
146{
147 Q_UNUSED(region);
148
149 if (m_image.size().isEmpty())
150 return;
151
152 QSize imageSize = m_image.size();
153
154 QRegion clipped = QRect(0, 0, window->width(), window->height());
155 clipped &= QRect(0, 0, imageSize.width(), imageSize.height()).translated(p: -offset);
156
157 QRect bounds = clipped.boundingRect().translated(p: offset);
158
159 if (bounds.isNull())
160 return;
161
162 WId id = window->winId();
163
164 m_windowAreaHash[id] = bounds;
165 m_backingStoreForWinIdHash[id] = this;
166}
167
168void QOffscreenBackingStore::resize(const QSize &size, const QRegion &)
169{
170 QImage::Format format = QGuiApplication::primaryScreen()->handle()->format();
171 if (m_image.size() != size)
172 m_image = QImage(size, format);
173 clearHash();
174}
175
176extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset);
177
178bool QOffscreenBackingStore::scroll(const QRegion &area, int dx, int dy)
179{
180 if (m_image.isNull())
181 return false;
182
183 for (const QRect &rect : area)
184 qt_scrollRectInImage(img&: m_image, rect, offset: QPoint(dx, dy));
185
186 return true;
187}
188
189QPixmap QOffscreenBackingStore::grabWindow(WId window, const QRect &rect) const
190{
191 QRect area = m_windowAreaHash.value(akey: window, adefaultValue: QRect());
192 if (area.isNull())
193 return QPixmap();
194
195 QRect adjusted = rect;
196 if (adjusted.width() <= 0)
197 adjusted.setWidth(area.width());
198 if (adjusted.height() <= 0)
199 adjusted.setHeight(area.height());
200
201 adjusted = adjusted.translated(p: area.topLeft()) & area;
202
203 if (adjusted.isEmpty())
204 return QPixmap();
205
206 return QPixmap::fromImage(image: m_image.copy(rect: adjusted));
207}
208
209QOffscreenBackingStore *QOffscreenBackingStore::backingStoreForWinId(WId id)
210{
211 return m_backingStoreForWinIdHash.value(akey: id, adefaultValue: 0);
212}
213
214void QOffscreenBackingStore::clearHash()
215{
216 for (auto it = m_windowAreaHash.cbegin(), end = m_windowAreaHash.cend(); it != end; ++it) {
217 const auto it2 = qAsConst(t&: m_backingStoreForWinIdHash).find(akey: it.key());
218 if (it2.value() == this)
219 m_backingStoreForWinIdHash.erase(it: it2);
220 }
221 m_windowAreaHash.clear();
222}
223
224QHash<WId, QOffscreenBackingStore *> QOffscreenBackingStore::m_backingStoreForWinIdHash;
225
226QOffscreenPlatformNativeInterface::~QOffscreenPlatformNativeInterface() = default;
227
228QT_END_NAMESPACE
229

source code of qtbase/src/plugins/platforms/offscreen/qoffscreencommon.cpp