summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/eglfs/qeglfswindow.cpp
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@digia.com>2013-09-13 13:02:20 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-20 12:05:08 +0200
commitf89f099c55576992b39a8021aace64ff32747624 (patch)
treeedefe8cefb81d63ef60440608112ee67ad837960 /src/plugins/platforms/eglfs/qeglfswindow.cpp
parentcfd52842492d12af26d897e0f893c80b2df5945a (diff)
eglfs: Support multiple raster windows
Allow widget apps with popups and multiple top-level widgets to function on the eglfs platform. GL and Quick2 apps are not affected. Instead of trying to create a native window and EGL surface for each window, do it only for the window that is created first. This first window is forced to fullscreen as usual. Later windows however are treated differently: These will not have a native window, surface or context, and keep their normal size. All the textures belonging to the raster windows are then rendered in one step, using a stacking order maintained based on visibility changes and window activation. Note that this will only help apps that create a main window first and have everything else inside that window or on top of it as menus, dialogs, popups, etc. Change-Id: Ia435458ba81bf3c35cc8f61bcb2d2a50cf17f0e3 Reviewed-by: Gunnar Sletta <gunnar.sletta@digia.com> Reviewed-by: Andy Nichols <andy.nichols@digia.com>
Diffstat (limited to 'src/plugins/platforms/eglfs/qeglfswindow.cpp')
-rw-r--r--src/plugins/platforms/eglfs/qeglfswindow.cpp152
1 files changed, 104 insertions, 48 deletions
diff --git a/src/plugins/platforms/eglfs/qeglfswindow.cpp b/src/plugins/platforms/eglfs/qeglfswindow.cpp
index d66f175920..888de058ad 100644
--- a/src/plugins/platforms/eglfs/qeglfswindow.cpp
+++ b/src/plugins/platforms/eglfs/qeglfswindow.cpp
@@ -41,6 +41,7 @@
#include "qeglfswindow.h"
#include "qeglfshooks.h"
+#include "qeglfscursor.h"
#include <qpa/qwindowsysteminterface.h>
#include <qpa/qplatformintegration.h>
#include <private/qguiapplication_p.h>
@@ -55,12 +56,13 @@ QEglFSWindow::QEglFSWindow(QWindow *w)
: QPlatformWindow(w)
, m_surface(0)
, m_window(0)
- , has_window(false)
+ , m_wid(0)
+ , m_backingStore(0)
+ , m_flags(0)
{
#ifdef QEGL_EXTRA_DEBUG
qWarning("QEglWindow %p: %p 0x%x\n", this, w, uint(m_window));
#endif
- w->setSurfaceType(QSurface::OpenGLSurface);
}
QEglFSWindow::~QEglFSWindow()
@@ -68,17 +70,23 @@ QEglFSWindow::~QEglFSWindow()
destroy();
}
-static inline bool supportsMultipleWindows()
+static WId newWId()
{
- return QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::MultipleWindows);
+ static WId id = 0;
+
+ if (id == std::numeric_limits<WId>::max())
+ qWarning("EGLFS: Out of window IDs");
+
+ return ++id;
}
void QEglFSWindow::create()
{
- if (has_window)
+ if (m_flags.testFlag(Created))
return;
- setWindowState(Qt::WindowFullScreen);
+ m_flags = Created;
+ m_wid = newWId();
if (window()->type() == Qt::Desktop) {
QRect rect(QPoint(), QEglFSHooks::hooks()->screenSize());
@@ -87,94 +95,142 @@ void QEglFSWindow::create()
return;
}
- if (!supportsMultipleWindows() && screen()->primarySurface()) {
- qFatal("EGLFS: Multiple windows are not supported");
- return;
+ // Save the original surface type before changing to OpenGLSurface.
+ if (window()->surfaceType() == QSurface::RasterSurface)
+ m_flags |= IsRaster;
+
+ // Stop if there is already a raster root window backed by a native window and
+ // surface. Other raster windows will not have their own native window, surface and
+ // context. Instead, they will be composited onto the root window's surface.
+ if (screen()->primarySurface() != EGL_NO_SURFACE) {
+ if (m_flags.testFlag(IsRaster) && screen()->rootWindow()->m_flags.testFlag(IsRaster))
+ return;
+
+#ifndef Q_OS_ANDROID
+ // We can have either a single OpenGL window or multiple raster windows.
+ // Other combinations cannot work.
+ qFatal("EGLFS: OpenGL windows cannot be mixed with others.");
+#endif
}
- EGLDisplay display = (static_cast<QEglFSScreen *>(window()->screen()->handle()))->display();
+ window()->setSurfaceType(QSurface::OpenGLSurface);
+ setGeometry(screen()->availableGeometry());
+ QWindowSystemInterface::handleExposeEvent(window(), QRegion(screen()->availableGeometry()));
+
+ EGLDisplay display = static_cast<QEglFSScreen *>(screen())->display();
QSurfaceFormat platformFormat = QEglFSHooks::hooks()->surfaceFormatFor(window()->requestedFormat());
m_config = QEglFSIntegration::chooseConfig(display, platformFormat);
m_format = q_glFormatFromConfig(display, m_config);
+
resetSurface();
+
+ m_flags |= HasNativeWindow;
+ if (screen()->primarySurface() == EGL_NO_SURFACE) {
+ screen()->setPrimarySurface(m_surface);
+ m_flags |= IsRasterRoot;
+ }
+}
+
+void QEglFSWindow::destroy()
+{
+ if (m_flags.testFlag(HasNativeWindow)) {
+ QEglFSCursor *cursor = static_cast<QEglFSCursor *>(screen()->cursor());
+ if (cursor)
+ cursor->resetResources();
+ if (screen()->primarySurface() == m_surface)
+ screen()->setPrimarySurface(EGL_NO_SURFACE);
+ invalidateSurface();
+ }
+ m_flags = 0;
+ screen()->removeWindow(this);
}
+// The virtual functions resetSurface and invalidateSurface may get overridden
+// in derived classes, for example in the Android port, to perform the native
+// window and surface creation differently.
+
void QEglFSWindow::invalidateSurface()
{
- // Native surface has been deleted behind our backs
- has_window = false;
- if (m_surface != 0) {
- EGLDisplay display = (static_cast<QEglFSScreen *>(window()->screen()->handle()))->display();
+ if (m_surface != EGL_NO_SURFACE) {
+ EGLDisplay display = static_cast<QEglFSScreen *>(screen())->display();
eglDestroySurface(display, m_surface);
- m_surface = 0;
+ m_surface = EGL_NO_SURFACE;
}
+ QEglFSHooks::hooks()->destroyNativeWindow(m_window);
+ m_window = 0;
}
void QEglFSWindow::resetSurface()
{
EGLDisplay display = static_cast<QEglFSScreen *>(screen())->display();
-
m_window = QEglFSHooks::hooks()->createNativeWindow(this, QEglFSHooks::hooks()->screenSize(), m_format);
- has_window = true;
m_surface = eglCreateWindowSurface(display, m_config, m_window, NULL);
-
if (m_surface == EGL_NO_SURFACE) {
EGLint error = eglGetError();
eglTerminate(display);
qFatal("EGL Error : Could not create the egl surface: error = 0x%x\n", error);
}
-
- screen()->setPrimarySurface(m_surface);
}
-void QEglFSWindow::destroy()
+void QEglFSWindow::setVisible(bool visible)
{
- if (m_surface) {
- EGLDisplay display = static_cast<QEglFSScreen *>(screen())->display();
- eglDestroySurface(display, m_surface);
-
- if (!supportsMultipleWindows()) {
- // ours must be the primary surface
- screen()->setPrimarySurface(0);
+ QList<QEglFSWindow *> windows = screen()->windows();
+
+ if (window()->type() != Qt::Desktop) {
+ if (visible) {
+ screen()->addWindow(this);
+ } else {
+ screen()->removeWindow(this);
+ windows = screen()->windows();
+ // try activating the window below
+ if (windows.size())
+ windows.last()->requestActivateWindow();
}
-
- m_surface = 0;
}
- if (has_window) {
- QEglFSHooks::hooks()->destroyNativeWindow(m_window);
- has_window = false;
+ // trigger an update
+ QEglFSWindow *rootWin = screen()->rootWindow();
+ if (rootWin) {
+ QWindowSystemInterface::handleExposeEvent(rootWin->window(), rootWin->window()->geometry());
+ QWindowSystemInterface::flushWindowSystemEvents();
}
+
+ QPlatformWindow::setVisible(visible);
}
-void QEglFSWindow::setGeometry(const QRect &)
+void QEglFSWindow::setGeometry(const QRect &r)
{
- // We only support full-screen windows
- QRect rect(screen()->availableGeometry());
+ QRect rect;
+ if (m_flags.testFlag(HasNativeWindow))
+ rect = screen()->availableGeometry();
+ else
+ rect = r;
+
QPlatformWindow::setGeometry(rect);
- QWindowSystemInterface::handleGeometryChange(window(), rect);
- QWindowSystemInterface::handleExposeEvent(window(), QRegion(rect));
+
+ if (rect != r)
+ QWindowSystemInterface::handleGeometryChange(window(), rect);
}
-void QEglFSWindow::setWindowState(Qt::WindowState)
+WId QEglFSWindow::winId() const
{
- setGeometry(QRect());
+ return m_wid;
}
-WId QEglFSWindow::winId() const
+void QEglFSWindow::requestActivateWindow()
{
- // Return a fake WId for desktop windows.
- if (window()->type() == Qt::Desktop)
- return std::numeric_limits<WId>::max();
+ if (window()->type() != Qt::Desktop) {
+ // move to the end of the list, to be on top
+ screen()->removeWindow(this);
+ screen()->addWindow(this);
+ }
- return WId(m_window);
+ QWindowSystemInterface::handleWindowActivated(window());
}
EGLSurface QEglFSWindow::surface() const
{
- if (!supportsMultipleWindows())
- return screen()->primarySurface();
- return m_surface;
+ return m_surface != EGL_NO_SURFACE ? m_surface : screen()->primarySurface();
}
QSurfaceFormat QEglFSWindow::format() const