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

source code of qtbase/src/plugins/platforms/eglfs/api/qeglfsscreen.cpp