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 <QtCore/qtextstream.h>
41#include <QtGui/qwindow.h>
42#include <QtGui/private/qguiapplication_p.h>
43#include <qpa/qwindowsysteminterface.h>
44#include <qpa/qplatformcursor.h>
45#ifndef QT_NO_OPENGL
46# include <QtOpenGL/private/qopenglcompositor_p.h>
47#endif
48
49#include "qeglfsscreen_p.h"
50#include "qeglfswindow_p.h"
51#include "qeglfshooks_p.h"
52
53QT_BEGIN_NAMESPACE
54
55QEglFSScreen::QEglFSScreen(EGLDisplay dpy)
56 : m_dpy(dpy),
57 m_surface(EGL_NO_SURFACE),
58 m_cursor(nullptr)
59{
60 m_cursor = qt_egl_device_integration()->createCursor(this);
61}
62
63QEglFSScreen::~QEglFSScreen()
64{
65 delete m_cursor;
66}
67
68QRect QEglFSScreen::geometry() const
69{
70 QRect r = rawGeometry();
71
72 static int rotation = qEnvironmentVariableIntValue("QT_QPA_EGLFS_ROTATION");
73 switch (rotation) {
74 case 0:
75 case 180:
76 case -180:
77 break;
78 case 90:
79 case -90: {
80 int h = r.height();
81 r.setHeight(r.width());
82 r.setWidth(h);
83 break;
84 }
85 default:
86 qWarning("Invalid rotation %d specified in QT_QPA_EGLFS_ROTATION", rotation);
87 break;
88 }
89
90 return r;
91}
92
93QRect QEglFSScreen::rawGeometry() const
94{
95 return QRect(QPoint(0, 0), qt_egl_device_integration()->screenSize());
96}
97
98int QEglFSScreen::depth() const
99{
100 return qt_egl_device_integration()->screenDepth();
101}
102
103QImage::Format QEglFSScreen::format() const
104{
105 return qt_egl_device_integration()->screenFormat();
106}
107
108QSizeF QEglFSScreen::physicalSize() const
109{
110 return qt_egl_device_integration()->physicalScreenSize();
111}
112
113QDpi QEglFSScreen::logicalDpi() const
114{
115 return qt_egl_device_integration()->logicalDpi();
116}
117
118QDpi QEglFSScreen::logicalBaseDpi() const
119{
120 return qt_egl_device_integration()->logicalBaseDpi();
121}
122
123Qt::ScreenOrientation QEglFSScreen::nativeOrientation() const
124{
125 return qt_egl_device_integration()->nativeOrientation();
126}
127
128Qt::ScreenOrientation QEglFSScreen::orientation() const
129{
130 return qt_egl_device_integration()->orientation();
131}
132
133QPlatformCursor *QEglFSScreen::cursor() const
134{
135 return m_cursor;
136}
137
138qreal QEglFSScreen::refreshRate() const
139{
140 return qt_egl_device_integration()->refreshRate();
141}
142
143void QEglFSScreen::setPrimarySurface(EGLSurface surface)
144{
145 m_surface = surface;
146}
147
148void QEglFSScreen::handleCursorMove(const QPoint &pos)
149{
150#ifndef QT_NO_OPENGL
151 const QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
152 const QList<QOpenGLCompositorWindow *> windows = compositor->windows();
153 QEglFSIntegration *platformIntegration = static_cast<QEglFSIntegration *>(QGuiApplicationPrivate::platformIntegration());
154
155 // Generate enter and leave events like a real windowing system would do.
156 if (windows.isEmpty())
157 return;
158
159 // First window is always fullscreen.
160 if (windows.count() == 1) {
161 QWindow *window = windows[0]->sourceWindow();
162 if (platformIntegration->pointerWindow() != window) {
163 platformIntegration->setPointerWindow(window);
164 QWindowSystemInterface::handleEnterEvent(window, window->mapFromGlobal(pos), pos);
165 }
166 return;
167 }
168
169 QWindow *enter = nullptr, *leave = nullptr;
170 for (int i = windows.count() - 1; i >= 0; --i) {
171 QWindow *window = windows[i]->sourceWindow();
172 const QRect geom = window->geometry();
173 if (geom.contains(pos)) {
174 if (platformIntegration->pointerWindow() != window) {
175 leave = platformIntegration->pointerWindow();
176 platformIntegration->setPointerWindow(window);
177 enter = window;
178 }
179 break;
180 }
181 }
182
183 if (enter && leave) {
184 QWindowSystemInterface::handleEnterLeaveEvent(enter, leave, enter->mapFromGlobal(pos), pos);
185 } else if (enter) {
186 QWindowSystemInterface::handleEnterEvent(enter, enter->mapFromGlobal(pos), pos);
187 } else if (leave) {
188 QWindowSystemInterface::handleLeaveEvent(leave);
189 }
190#else
191 Q_UNUSED(pos);
192#endif
193}
194
195QPixmap QEglFSScreen::grabWindow(WId wid, int x, int y, int width, int height) const
196{
197#ifndef QT_NO_OPENGL
198 QOpenGLCompositor *compositor = QOpenGLCompositor::instance();
199 const QList<QOpenGLCompositorWindow *> windows = compositor->windows();
200 Q_ASSERT(!windows.isEmpty());
201
202 QImage img;
203
204 if (static_cast<QEglFSWindow *>(windows.first()->sourceWindow()->handle())->isRaster()) {
205 // Request the compositor to render everything into an FBO and read it back. This
206 // is of course slow, but it's safe and reliable. It will not include the mouse
207 // cursor, which is a plus.
208 img = compositor->grab();
209 } else {
210 // Just a single OpenGL window without compositing. Do not support this case for now. Doing
211 // glReadPixels is not an option since it would read from the back buffer which may have
212 // undefined content when calling right after a swapBuffers (unless preserved swap is
213 // available and enabled, but we have no support for that).
214 qWarning("grabWindow: Not supported for non-composited OpenGL content. Use QQuickWindow::grabWindow() instead.");
215 return QPixmap();
216 }
217
218 if (!wid) {
219 const QSize screenSize = geometry().size();
220 if (width < 0)
221 width = screenSize.width() - x;
222 if (height < 0)
223 height = screenSize.height() - y;
224 return QPixmap::fromImage(img).copy(x, y, width, height);
225 }
226
227 foreach (QOpenGLCompositorWindow *w, windows) {
228 const QWindow *window = w->sourceWindow();
229 if (window->winId() == wid) {
230 const QRect geom = window->geometry();
231 if (width < 0)
232 width = geom.width() - x;
233 if (height < 0)
234 height = geom.height() - y;
235 QRect rect(geom.topLeft() + QPoint(x, y), QSize(width, height));
236 rect &= window->geometry();
237 return QPixmap::fromImage(img).copy(rect);
238 }
239 }
240#else // QT_NO_OPENGL
241 Q_UNUSED(wid);
242 Q_UNUSED(x);
243 Q_UNUSED(y);
244 Q_UNUSED(width);
245 Q_UNUSED(height);
246#endif
247 return QPixmap();
248}
249
250QT_END_NAMESPACE
251