Client: Support running with no screens
[ChangeLog][QPA plugin] The QPA plugin now supports running with no screens attached. This is handled by adding a fake screen when the last screen is disconnected, similarly to what the other QPA plugins do. Fixes: QTBUG-79111 Change-Id: I4a0e023ae784217dd030f0c62f12487fdff4825c Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
This commit is contained in:
parent
058dc12df8
commit
b5f100975d
@ -50,10 +50,11 @@ QWaylandFullScreenShellV1Surface::QWaylandFullScreenShellV1Surface(QtWayland::zw
|
||||
, m_shell(shell)
|
||||
, m_window(window)
|
||||
{
|
||||
auto screen = static_cast<QWaylandScreen *>(m_window->screen());
|
||||
auto *screen = m_window->waylandScreen();
|
||||
auto *output = screen ? screen->output() : nullptr;
|
||||
m_shell->present_surface(m_window->wlSurface(),
|
||||
QtWayland::zwp_fullscreen_shell_v1::present_method_default,
|
||||
screen->output());
|
||||
output);
|
||||
}
|
||||
|
||||
} // namespace QtWaylandClient
|
||||
|
@ -188,6 +188,18 @@ QWaylandDisplay::~QWaylandDisplay(void)
|
||||
wl_display_disconnect(mDisplay);
|
||||
}
|
||||
|
||||
void QWaylandDisplay::ensureScreen()
|
||||
{
|
||||
if (!mScreens.empty() || mPlaceholderScreen)
|
||||
return; // There are real screens or we already have a fake one
|
||||
|
||||
qCInfo(lcQpaWayland) << "Creating a fake screen in order for Qt not to crash";
|
||||
|
||||
mPlaceholderScreen = new QPlatformPlaceholderScreen();
|
||||
QWindowSystemInterface::handleScreenAdded(mPlaceholderScreen);
|
||||
Q_ASSERT(!QGuiApplication::screens().empty());
|
||||
}
|
||||
|
||||
void QWaylandDisplay::checkError() const
|
||||
{
|
||||
int ecode = wl_display_get_error(mDisplay);
|
||||
@ -253,8 +265,7 @@ void QWaylandDisplay::dispatchQueueWhile(wl_event_queue *queue, std::function<bo
|
||||
|
||||
QWaylandScreen *QWaylandDisplay::screenForOutput(struct wl_output *output) const
|
||||
{
|
||||
for (int i = 0; i < mScreens.size(); ++i) {
|
||||
QWaylandScreen *screen = static_cast<QWaylandScreen *>(mScreens.at(i));
|
||||
for (auto screen : qAsConst(mScreens)) {
|
||||
if (screen->output() == output)
|
||||
return screen;
|
||||
}
|
||||
@ -267,6 +278,11 @@ void QWaylandDisplay::handleScreenInitialized(QWaylandScreen *screen)
|
||||
return;
|
||||
mScreens.append(screen);
|
||||
QWindowSystemInterface::handleScreenAdded(screen);
|
||||
if (mPlaceholderScreen) {
|
||||
QWindowSystemInterface::handleScreenRemoved(mPlaceholderScreen);
|
||||
// handleScreenRemoved deletes the platform screen
|
||||
mPlaceholderScreen = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void QWaylandDisplay::waitForScreens()
|
||||
@ -362,6 +378,8 @@ void QWaylandDisplay::registry_global_remove(uint32_t id)
|
||||
for (QWaylandScreen *screen : qAsConst(mScreens)) {
|
||||
if (screen->outputId() == id) {
|
||||
mScreens.removeOne(screen);
|
||||
// If this is the last screen, we have to add a fake screen, or Qt will break.
|
||||
ensureScreen();
|
||||
QWindowSystemInterface::handleScreenRemoved(screen);
|
||||
break;
|
||||
}
|
||||
|
@ -76,6 +76,7 @@ QT_BEGIN_NAMESPACE
|
||||
class QAbstractEventDispatcher;
|
||||
class QSocketNotifier;
|
||||
class QPlatformScreen;
|
||||
class QPlatformPlaceholderScreen;
|
||||
|
||||
namespace QtWayland {
|
||||
class qt_surface_extension;
|
||||
@ -124,6 +125,8 @@ public:
|
||||
#endif
|
||||
|
||||
QList<QWaylandScreen *> screens() const { return mScreens; }
|
||||
QPlatformPlaceholderScreen *placeholderScreen() const { return mPlaceholderScreen; }
|
||||
void ensureScreen();
|
||||
|
||||
QWaylandScreen *screenForOutput(struct wl_output *output) const;
|
||||
void handleScreenInitialized(QWaylandScreen *screen);
|
||||
@ -228,6 +231,7 @@ private:
|
||||
QScopedPointer<QWaylandShm> mShm;
|
||||
QList<QWaylandScreen *> mWaitingScreens;
|
||||
QList<QWaylandScreen *> mScreens;
|
||||
QPlatformPlaceholderScreen *mPlaceholderScreen = nullptr;
|
||||
QList<QWaylandInputDevice *> mInputDevices;
|
||||
QList<Listener> mRegistryListeners;
|
||||
QWaylandIntegration *mWaylandIntegration = nullptr;
|
||||
|
@ -165,10 +165,10 @@ QPlatformWindow *QWaylandIntegration::createPlatformWindow(QWindow *window) cons
|
||||
|
||||
#if QT_CONFIG(vulkan)
|
||||
if (window->surfaceType() == QSurface::VulkanSurface)
|
||||
return new QWaylandVulkanWindow(window);
|
||||
return new QWaylandVulkanWindow(window, mDisplay.data());
|
||||
#endif // QT_CONFIG(vulkan)
|
||||
|
||||
return new QWaylandShmWindow(window);
|
||||
return new QWaylandShmWindow(window, mDisplay.data());
|
||||
}
|
||||
|
||||
#if QT_CONFIG(opengl)
|
||||
@ -182,7 +182,7 @@ QPlatformOpenGLContext *QWaylandIntegration::createPlatformOpenGLContext(QOpenGL
|
||||
|
||||
QPlatformBackingStore *QWaylandIntegration::createPlatformBackingStore(QWindow *window) const
|
||||
{
|
||||
return new QWaylandShmBackingStore(window);
|
||||
return new QWaylandShmBackingStore(window, mDisplay.data());
|
||||
}
|
||||
|
||||
QAbstractEventDispatcher *QWaylandIntegration::createEventDispatcher() const
|
||||
@ -200,10 +200,8 @@ void QWaylandIntegration::initialize()
|
||||
QSocketNotifier *sn = new QSocketNotifier(fd, QSocketNotifier::Read, mDisplay.data());
|
||||
QObject::connect(sn, SIGNAL(activated(int)), mDisplay.data(), SLOT(flushRequests()));
|
||||
|
||||
if (mDisplay->screens().isEmpty()) {
|
||||
qWarning() << "Running on a compositor with no screens is not supported";
|
||||
::exit(EXIT_FAILURE);
|
||||
}
|
||||
// Qt does not support running with no screens
|
||||
mDisplay->ensureScreen();
|
||||
}
|
||||
|
||||
QPlatformFontDatabase *QWaylandIntegration::fontDatabase() const
|
||||
|
@ -165,11 +165,18 @@ QList<QPlatformScreen *> QWaylandScreen::virtualSiblings() const
|
||||
{
|
||||
QList<QPlatformScreen *> list;
|
||||
const QList<QWaylandScreen*> screens = mWaylandDisplay->screens();
|
||||
list.reserve(screens.count());
|
||||
auto *placeholder = mWaylandDisplay->placeholderScreen();
|
||||
|
||||
list.reserve(screens.count() + (placeholder ? 1 : 0));
|
||||
|
||||
for (QWaylandScreen *screen : qAsConst(screens)) {
|
||||
if (screen->screen())
|
||||
list << screen;
|
||||
}
|
||||
|
||||
if (placeholder)
|
||||
list << placeholder;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@ -210,9 +217,11 @@ QPlatformCursor *QWaylandScreen::cursor() const
|
||||
}
|
||||
#endif // QT_CONFIG(cursor)
|
||||
|
||||
QWaylandScreen * QWaylandScreen::waylandScreenFromWindow(QWindow *window)
|
||||
QWaylandScreen *QWaylandScreen::waylandScreenFromWindow(QWindow *window)
|
||||
{
|
||||
QPlatformScreen *platformScreen = QPlatformScreen::platformScreenForWindow(window);
|
||||
if (platformScreen->isPlaceholder())
|
||||
return nullptr;
|
||||
return static_cast<QWaylandScreen *>(platformScreen);
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,6 @@
|
||||
#include <QtWaylandClient/private/qwayland-wayland.h>
|
||||
#include <QtWaylandClient/private/qwayland-xdg-output-unstable-v1.h>
|
||||
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QtWaylandClient {
|
||||
|
@ -151,9 +151,9 @@ QImage *QWaylandShmBuffer::imageInsideMargins(const QMargins &marginsIn)
|
||||
|
||||
}
|
||||
|
||||
QWaylandShmBackingStore::QWaylandShmBackingStore(QWindow *window)
|
||||
QWaylandShmBackingStore::QWaylandShmBackingStore(QWindow *window, QWaylandDisplay *display)
|
||||
: QPlatformBackingStore(window)
|
||||
, mDisplay(QWaylandScreen::waylandScreenFromWindow(window)->display())
|
||||
, mDisplay(display)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ private:
|
||||
class Q_WAYLAND_CLIENT_EXPORT QWaylandShmBackingStore : public QPlatformBackingStore
|
||||
{
|
||||
public:
|
||||
QWaylandShmBackingStore(QWindow *window);
|
||||
QWaylandShmBackingStore(QWindow *window, QWaylandDisplay *display);
|
||||
~QWaylandShmBackingStore() override;
|
||||
|
||||
QPaintDevice *paintDevice() override;
|
||||
|
@ -49,8 +49,8 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QtWaylandClient {
|
||||
|
||||
QWaylandShmWindow::QWaylandShmWindow(QWindow *window)
|
||||
: QWaylandWindow(window)
|
||||
QWaylandShmWindow::QWaylandShmWindow(QWindow *window, QWaylandDisplay *display)
|
||||
: QWaylandWindow(window, display)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ namespace QtWaylandClient {
|
||||
class Q_WAYLAND_CLIENT_EXPORT QWaylandShmWindow : public QWaylandWindow
|
||||
{
|
||||
public:
|
||||
QWaylandShmWindow(QWindow *window);
|
||||
QWaylandShmWindow(QWindow *window, QWaylandDisplay *display);
|
||||
~QWaylandShmWindow() override;
|
||||
|
||||
WindowType windowType() const override;
|
||||
|
@ -72,8 +72,12 @@ QWaylandSurface *QWaylandSurface::fromWlSurface(::wl_surface *surface)
|
||||
|
||||
void QWaylandSurface::handleScreenRemoved(QScreen *qScreen)
|
||||
{
|
||||
auto *screen = static_cast<QWaylandScreen *>(qScreen->handle());
|
||||
if (m_screens.removeOne(screen))
|
||||
auto *platformScreen = qScreen->handle();
|
||||
if (platformScreen->isPlaceholder())
|
||||
return;
|
||||
|
||||
auto *waylandScreen = static_cast<QWaylandScreen *>(qScreen->handle());
|
||||
if (m_screens.removeOne(waylandScreen))
|
||||
emit screensChanged();
|
||||
}
|
||||
|
||||
|
@ -43,8 +43,8 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QtWaylandClient {
|
||||
|
||||
QWaylandVulkanWindow::QWaylandVulkanWindow(QWindow *window)
|
||||
: QWaylandWindow(window)
|
||||
QWaylandVulkanWindow::QWaylandVulkanWindow(QWindow *window, QWaylandDisplay *display)
|
||||
: QWaylandWindow(window, display)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,7 @@ namespace QtWaylandClient {
|
||||
class QWaylandVulkanWindow : public QWaylandWindow
|
||||
{
|
||||
public:
|
||||
explicit QWaylandVulkanWindow(QWindow *window);
|
||||
explicit QWaylandVulkanWindow(QWindow *window, QWaylandDisplay *display);
|
||||
~QWaylandVulkanWindow() override;
|
||||
|
||||
WindowType windowType() const override;
|
||||
|
@ -73,9 +73,9 @@ Q_LOGGING_CATEGORY(lcWaylandBackingstore, "qt.qpa.wayland.backingstore")
|
||||
|
||||
QWaylandWindow *QWaylandWindow::mMouseGrab = nullptr;
|
||||
|
||||
QWaylandWindow::QWaylandWindow(QWindow *window)
|
||||
QWaylandWindow::QWaylandWindow(QWindow *window, QWaylandDisplay *display)
|
||||
: QPlatformWindow(window)
|
||||
, mDisplay(waylandScreen()->display())
|
||||
, mDisplay(display)
|
||||
, mFrameQueue(mDisplay->createEventQueue())
|
||||
, mResizeAfterSwap(qEnvironmentVariableIsSet("QT_WAYLAND_RESIZE_AFTER_SWAP"))
|
||||
{
|
||||
@ -177,7 +177,7 @@ void QWaylandWindow::initWindow()
|
||||
}
|
||||
}
|
||||
|
||||
mScale = waylandScreen()->scale();
|
||||
mScale = waylandScreen() ? waylandScreen()->scale() : 1; // fallback to 1 if we don't have a real screen
|
||||
|
||||
// Enable high-dpi rendering. Scale() returns the screen scale factor and will
|
||||
// typically be integer 1 (normal-dpi) or 2 (high-dpi). Call set_buffer_scale()
|
||||
@ -402,14 +402,14 @@ void QWaylandWindow::closePopups(QWaylandWindow *parent)
|
||||
}
|
||||
}
|
||||
|
||||
QWaylandScreen *QWaylandWindow::calculateScreenFromSurfaceEvents() const
|
||||
QPlatformScreen *QWaylandWindow::calculateScreenFromSurfaceEvents() const
|
||||
{
|
||||
if (mSurface) {
|
||||
if (auto *screen = mSurface->oldestEnteredScreen())
|
||||
return screen;
|
||||
}
|
||||
|
||||
return waylandScreen();
|
||||
return QPlatformWindow::screen();
|
||||
}
|
||||
|
||||
void QWaylandWindow::setVisible(bool visible)
|
||||
@ -690,7 +690,11 @@ QWaylandSubSurface *QWaylandWindow::subSurfaceWindow() const
|
||||
|
||||
QWaylandScreen *QWaylandWindow::waylandScreen() const
|
||||
{
|
||||
return static_cast<QWaylandScreen *>(QPlatformWindow::screen());
|
||||
auto *platformScreen = QPlatformWindow::screen();
|
||||
Q_ASSERT(platformScreen);
|
||||
if (platformScreen->isPlaceholder())
|
||||
return nullptr;
|
||||
return static_cast<QWaylandScreen *>(platformScreen);
|
||||
}
|
||||
|
||||
void QWaylandWindow::handleContentOrientationChange(Qt::ScreenOrientation orientation)
|
||||
@ -962,7 +966,7 @@ void QWaylandWindow::handleMouseEventWithDecoration(QWaylandInputDevice *inputDe
|
||||
|
||||
void QWaylandWindow::handleScreensChanged()
|
||||
{
|
||||
QWaylandScreen *newScreen = calculateScreenFromSurfaceEvents();
|
||||
QPlatformScreen *newScreen = calculateScreenFromSurfaceEvents();
|
||||
|
||||
if (newScreen == mLastReportedScreen)
|
||||
return;
|
||||
@ -970,7 +974,7 @@ void QWaylandWindow::handleScreensChanged()
|
||||
QWindowSystemInterface::handleWindowScreenChanged(window(), newScreen->QPlatformScreen::screen());
|
||||
mLastReportedScreen = newScreen;
|
||||
|
||||
int scale = newScreen->scale();
|
||||
int scale = newScreen->isPlaceholder() ? 1 : static_cast<QWaylandScreen *>(newScreen)->scale();
|
||||
if (scale != mScale) {
|
||||
mScale = scale;
|
||||
if (mSurface && mDisplay->compositorVersion() >= 3)
|
||||
|
@ -93,7 +93,7 @@ public:
|
||||
Vulkan
|
||||
};
|
||||
|
||||
QWaylandWindow(QWindow *window);
|
||||
QWaylandWindow(QWindow *window, QWaylandDisplay *display);
|
||||
~QWaylandWindow() override;
|
||||
|
||||
virtual WindowType windowType() const = 0;
|
||||
@ -241,7 +241,7 @@ protected:
|
||||
bool mSentInitialResize = false;
|
||||
QPoint mOffset;
|
||||
int mScale = 1;
|
||||
QWaylandScreen *mLastReportedScreen = nullptr;
|
||||
QPlatformScreen *mLastReportedScreen = nullptr;
|
||||
|
||||
QIcon mWindowIcon;
|
||||
|
||||
@ -262,7 +262,7 @@ private:
|
||||
void reset(bool sendDestroyEvent = true);
|
||||
void sendExposeEvent(const QRect &rect);
|
||||
static void closePopups(QWaylandWindow *parent);
|
||||
QWaylandScreen *calculateScreenFromSurfaceEvents() const;
|
||||
QPlatformScreen *calculateScreenFromSurfaceEvents() const;
|
||||
|
||||
void handleMouseEventWithDecoration(QWaylandInputDevice *inputDevice, const QWaylandPointerEvent &e);
|
||||
void handleScreensChanged();
|
||||
|
Loading…
x
Reference in New Issue
Block a user