diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -453,6 +453,7 @@ decorations/decorationrenderer.cpp decorations/decorations_logging.cpp platform.cpp + output.cpp shell_client.cpp wayland_server.cpp wayland_cursor_theme.cpp diff --git a/abstract_opengl_context_attribute_builder.h b/abstract_opengl_context_attribute_builder.h --- a/abstract_opengl_context_attribute_builder.h +++ b/abstract_opengl_context_attribute_builder.h @@ -94,6 +94,14 @@ return m_resetOnVideoMemoryPurge; } + void setHighPriority(bool highPriority) { + m_highPriority = highPriority; + } + + bool isHighPriority() const { + return m_highPriority; + } + virtual std::vector build() const = 0; QDebug operator<<(QDebug dbg) const; @@ -107,6 +115,7 @@ bool m_coreProfile = false; bool m_compatibilityProfile = false; bool m_resetOnVideoMemoryPurge = false; + bool m_highPriority = false; }; inline QDebug operator<<(QDebug dbg, const AbstractOpenGLContextAttributeBuilder *attribs) diff --git a/abstract_opengl_context_attribute_builder.cpp b/abstract_opengl_context_attribute_builder.cpp --- a/abstract_opengl_context_attribute_builder.cpp +++ b/abstract_opengl_context_attribute_builder.cpp @@ -32,7 +32,8 @@ dbg.nospace() << "Robust:\t" << isRobust() << "\n"; dbg.nospace() << "Forward compatible:\t" << isForwardCompatible() << "\n"; dbg.nospace() << "Core profile:\t" << isCoreProfile() << "\n"; - dbg.nospace() << "Compatibility profile:\t" << isCompatibilityProfile(); + dbg.nospace() << "Compatibility profile:\t" << isCompatibilityProfile() << "\n"; + dbg.nospace() << "High priority:\t" << isHighPriority(); return dbg; } diff --git a/autotests/integration/screen_changes_test.cpp b/autotests/integration/screen_changes_test.cpp --- a/autotests/integration/screen_changes_test.cpp +++ b/autotests/integration/screen_changes_test.cpp @@ -125,15 +125,15 @@ QCOMPARE(outputRemovedSpy.count(), 1); // let's create the output objects to ensure they are correct - QScopedPointer o1(registry.createOutput(outputAnnouncedSpy.first().first().value(), outputAnnouncedSpy.first().last().value())); + QScopedPointer o1(registry.createOutput(outputAnnouncedSpy.first().first().value(), outputAnnouncedSpy.first().last().value())); QVERIFY(o1->isValid()); - QSignalSpy o1ChangedSpy(o1.data(), &Output::changed); + QSignalSpy o1ChangedSpy(o1.data(), &KWayland::Client::Output::changed); QVERIFY(o1ChangedSpy.isValid()); QVERIFY(o1ChangedSpy.wait()); QCOMPARE(o1->geometry(), geometries.at(0)); - QScopedPointer o2(registry.createOutput(outputAnnouncedSpy.last().first().value(), outputAnnouncedSpy.last().last().value())); + QScopedPointer o2(registry.createOutput(outputAnnouncedSpy.last().first().value(), outputAnnouncedSpy.last().last().value())); QVERIFY(o2->isValid()); - QSignalSpy o2ChangedSpy(o2.data(), &Output::changed); + QSignalSpy o2ChangedSpy(o2.data(), &KWayland::Client::Output::changed); QVERIFY(o2ChangedSpy.isValid()); QVERIFY(o2ChangedSpy.wait()); QCOMPARE(o2->geometry(), geometries.at(1)); @@ -143,9 +143,9 @@ outputRemovedSpy.clear(); screensChangedSpy.clear(); - QSignalSpy o1RemovedSpy(o1.data(), &Output::removed); + QSignalSpy o1RemovedSpy(o1.data(), &KWayland::Client::Output::removed); QVERIFY(o1RemovedSpy.isValid()); - QSignalSpy o2RemovedSpy(o2.data(), &Output::removed); + QSignalSpy o2RemovedSpy(o2.data(), &KWayland::Client::Output::removed); QVERIFY(o2RemovedSpy.isValid()); const QVector geometries2{QRect(0, 0, 1280, 1024)}; diff --git a/autotests/integration/virtual_desktop_test.cpp b/autotests/integration/virtual_desktop_test.cpp --- a/autotests/integration/virtual_desktop_test.cpp +++ b/autotests/integration/virtual_desktop_test.cpp @@ -40,6 +40,7 @@ void init(); void cleanup(); + void testNetCurrentDesktop(); void testLastDesktopRemoved_data(); void testLastDesktopRemoved(); }; @@ -60,6 +61,16 @@ kwinApp()->start(); QVERIFY(workspaceCreatedSpy.wait()); waylandServer()->initWorkspace(); + + if (kwinApp()->x11Connection()) { + // verify the current desktop x11 property on startup, see BUG: 391034 + Xcb::Atom currentDesktopAtom("_NET_CURRENT_DESKTOP"); + QVERIFY(currentDesktopAtom.isValid()); + Xcb::Property currentDesktop(0, kwinApp()->x11RootWindow(), currentDesktopAtom, XCB_ATOM_CARDINAL, 0, 1); + bool ok = true; + QCOMPARE(currentDesktop.value(0, &ok), 0); + QVERIFY(ok); + } } void VirtualDesktopTest::init() @@ -74,6 +85,47 @@ Test::destroyWaylandConnection(); } +void VirtualDesktopTest::testNetCurrentDesktop() +{ + if (!kwinApp()->x11Connection()) { + QSKIP("Skipped on Wayland only"); + } + QCOMPARE(VirtualDesktopManager::self()->count(), 1u); + VirtualDesktopManager::self()->setCount(4); + QCOMPARE(VirtualDesktopManager::self()->count(), 4u); + + Xcb::Atom currentDesktopAtom("_NET_CURRENT_DESKTOP"); + QVERIFY(currentDesktopAtom.isValid()); + Xcb::Property currentDesktop(0, kwinApp()->x11RootWindow(), currentDesktopAtom, XCB_ATOM_CARDINAL, 0, 1); + bool ok = true; + QCOMPARE(currentDesktop.value(0, &ok), 0); + QVERIFY(ok); + + // go to desktop 2 + VirtualDesktopManager::self()->setCurrent(2); + currentDesktop = Xcb::Property(0, kwinApp()->x11RootWindow(), currentDesktopAtom, XCB_ATOM_CARDINAL, 0, 1); + QCOMPARE(currentDesktop.value(0, &ok), 1); + QVERIFY(ok); + + // go to desktop 3 + VirtualDesktopManager::self()->setCurrent(3); + currentDesktop = Xcb::Property(0, kwinApp()->x11RootWindow(), currentDesktopAtom, XCB_ATOM_CARDINAL, 0, 1); + QCOMPARE(currentDesktop.value(0, &ok), 2); + QVERIFY(ok); + + // go to desktop 4 + VirtualDesktopManager::self()->setCurrent(4); + currentDesktop = Xcb::Property(0, kwinApp()->x11RootWindow(), currentDesktopAtom, XCB_ATOM_CARDINAL, 0, 1); + QCOMPARE(currentDesktop.value(0, &ok), 3); + QVERIFY(ok); + + // and back to first + VirtualDesktopManager::self()->setCurrent(1); + currentDesktop = Xcb::Property(0, kwinApp()->x11RootWindow(), currentDesktopAtom, XCB_ATOM_CARDINAL, 0, 1); + QCOMPARE(currentDesktop.value(0, &ok), 0); + QVERIFY(ok); +} + void VirtualDesktopTest::testLastDesktopRemoved_data() { QTest::addColumn("type"); diff --git a/autotests/opengl_context_attribute_builder_test.cpp b/autotests/opengl_context_attribute_builder_test.cpp --- a/autotests/opengl_context_attribute_builder_test.cpp +++ b/autotests/opengl_context_attribute_builder_test.cpp @@ -45,6 +45,7 @@ void testResetOnVideoMemoryPurge(); void testVersionMajor(); void testVersionMajorAndMinor(); + void testHighPriority(); void testEgl_data(); void testEgl(); void testGles_data(); @@ -75,6 +76,7 @@ QCOMPARE(builder.isCoreProfile(), false); QCOMPARE(builder.isCompatibilityProfile(), false); QCOMPARE(builder.isResetOnVideoMemoryPurge(), false); + QCOMPARE(builder.isHighPriority(), false); } void OpenGLContextAttributeBuilderTest::testRobust() @@ -123,6 +125,16 @@ QCOMPARE(builder.isResetOnVideoMemoryPurge(), false); } +void OpenGLContextAttributeBuilderTest::testHighPriority() +{ + MockOpenGLContextAttributeBuilder builder; + QCOMPARE(builder.isHighPriority(), false); + builder.setHighPriority(true); + QCOMPARE(builder.isHighPriority(), true); + builder.setHighPriority(false); + QCOMPARE(builder.isHighPriority(), false); +} + void OpenGLContextAttributeBuilderTest::testVersionMajor() { MockOpenGLContextAttributeBuilder builder; @@ -158,69 +170,139 @@ QTest::addColumn("forwardCompatible"); QTest::addColumn("coreProfile"); QTest::addColumn("compatibilityProfile"); + QTest::addColumn("highPriority"); QTest::addColumn>("expectedAttribs"); - QTest::newRow("fallback") << false << 0 << 0 << false << false << false << false << std::vector{EGL_NONE}; - QTest::newRow("legacy/robust") << false << 0 << 0 << true << false << false << false << + QTest::newRow("fallback") << false << 0 << 0 << false << false << false << false << false << std::vector{EGL_NONE}; + QTest::newRow("legacy/robust") << false << 0 << 0 << true << false << false << false << false << + std::vector{ + EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, EGL_LOSE_CONTEXT_ON_RESET_KHR, + EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR, + EGL_NONE}; + QTest::newRow("legacy/robust/high priority") << false << 0 << 0 << true << false << false << false << true << std::vector{ EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, EGL_LOSE_CONTEXT_ON_RESET_KHR, EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR, + EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG, EGL_NONE}; - QTest::newRow("core") << true << 3 << 1 << false << false << false << false << + QTest::newRow("core") << true << 3 << 1 << false << false << false << false << false << std::vector{ EGL_CONTEXT_MAJOR_VERSION_KHR, 3, EGL_CONTEXT_MINOR_VERSION_KHR, 1, EGL_NONE}; - QTest::newRow("core/robust") << true << 3 << 1 << true << false << false << false << + QTest::newRow("core/high priority") << true << 3 << 1 << false << false << false << false << true << + std::vector{ + EGL_CONTEXT_MAJOR_VERSION_KHR, 3, + EGL_CONTEXT_MINOR_VERSION_KHR, 1, + EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG, + EGL_NONE}; + QTest::newRow("core/robust") << true << 3 << 1 << true << false << false << false << false << std::vector{ EGL_CONTEXT_MAJOR_VERSION_KHR, 3, EGL_CONTEXT_MINOR_VERSION_KHR, 1, EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, EGL_LOSE_CONTEXT_ON_RESET_KHR, EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR, EGL_NONE}; - QTest::newRow("core/robust/forward compatible") << true << 3 << 1 << true << true << false << false << + QTest::newRow("core/robust/high priority") << true << 3 << 1 << true << false << false << false << true << + std::vector{ + EGL_CONTEXT_MAJOR_VERSION_KHR, 3, + EGL_CONTEXT_MINOR_VERSION_KHR, 1, + EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, EGL_LOSE_CONTEXT_ON_RESET_KHR, + EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR, + EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG, + EGL_NONE}; + QTest::newRow("core/robust/forward compatible") << true << 3 << 1 << true << true << false << false << false << + std::vector{ + EGL_CONTEXT_MAJOR_VERSION_KHR, 3, + EGL_CONTEXT_MINOR_VERSION_KHR, 1, + EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, EGL_LOSE_CONTEXT_ON_RESET_KHR, + EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR | EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR, + EGL_NONE}; + QTest::newRow("core/robust/forward compatible/high priority") << true << 3 << 1 << true << true << false << false << true << std::vector{ EGL_CONTEXT_MAJOR_VERSION_KHR, 3, EGL_CONTEXT_MINOR_VERSION_KHR, 1, EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, EGL_LOSE_CONTEXT_ON_RESET_KHR, EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR | EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR, + EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG, EGL_NONE}; - QTest::newRow("core/forward compatible") << true << 3 << 1 << false << true << false << false << + QTest::newRow("core/forward compatible") << true << 3 << 1 << false << true << false << false << false << std::vector{ EGL_CONTEXT_MAJOR_VERSION_KHR, 3, EGL_CONTEXT_MINOR_VERSION_KHR, 1, EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR, EGL_NONE}; - QTest::newRow("core profile/forward compatible") << true << 3 << 2 << false << true << true << false << + QTest::newRow("core/forward compatible/high priority") << true << 3 << 1 << false << true << false << false << true << + std::vector{ + EGL_CONTEXT_MAJOR_VERSION_KHR, 3, + EGL_CONTEXT_MINOR_VERSION_KHR, 1, + EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR, + EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG, + EGL_NONE}; + QTest::newRow("core profile/forward compatible") << true << 3 << 2 << false << true << true << false << false << std::vector{ EGL_CONTEXT_MAJOR_VERSION_KHR, 3, EGL_CONTEXT_MINOR_VERSION_KHR, 2, EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR, EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR, EGL_NONE}; - QTest::newRow("compatibility profile/forward compatible") << true << 3 << 2 << false << true << false << true << + QTest::newRow("core profile/forward compatible/high priority") << true << 3 << 2 << false << true << true << false << true << + std::vector{ + EGL_CONTEXT_MAJOR_VERSION_KHR, 3, + EGL_CONTEXT_MINOR_VERSION_KHR, 2, + EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR, + EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR, + EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG, + EGL_NONE}; + QTest::newRow("compatibility profile/forward compatible") << true << 3 << 2 << false << true << false << true << false << std::vector{ EGL_CONTEXT_MAJOR_VERSION_KHR, 3, EGL_CONTEXT_MINOR_VERSION_KHR, 2, EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR, EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR, EGL_NONE}; - QTest::newRow("core profile/robust/forward compatible") << true << 3 << 2 << true << true << true << false << + QTest::newRow("compatibility profile/forward compatible/high priority") << true << 3 << 2 << false << true << false << true << true << + std::vector{ + EGL_CONTEXT_MAJOR_VERSION_KHR, 3, + EGL_CONTEXT_MINOR_VERSION_KHR, 2, + EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR, + EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR, + EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG, + EGL_NONE}; + QTest::newRow("core profile/robust/forward compatible") << true << 3 << 2 << true << true << true << false << false << + std::vector{ + EGL_CONTEXT_MAJOR_VERSION_KHR, 3, + EGL_CONTEXT_MINOR_VERSION_KHR, 2, + EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, EGL_LOSE_CONTEXT_ON_RESET_KHR, + EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR | EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR, + EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR, + EGL_NONE}; + QTest::newRow("core profile/robust/forward compatible/high priority") << true << 3 << 2 << true << true << true << false << true << std::vector{ EGL_CONTEXT_MAJOR_VERSION_KHR, 3, EGL_CONTEXT_MINOR_VERSION_KHR, 2, EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, EGL_LOSE_CONTEXT_ON_RESET_KHR, EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR | EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR, EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR, + EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG, EGL_NONE}; - QTest::newRow("compatibility profile/robust/forward compatible") << true << 3 << 2 << true << true << false << true << + QTest::newRow("compatibility profile/robust/forward compatible") << true << 3 << 2 << true << true << false << true << false << std::vector{ EGL_CONTEXT_MAJOR_VERSION_KHR, 3, EGL_CONTEXT_MINOR_VERSION_KHR, 2, EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, EGL_LOSE_CONTEXT_ON_RESET_KHR, EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR | EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR, EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR, EGL_NONE}; + QTest::newRow("compatibility profile/robust/forward compatible/high priority") << true << 3 << 2 << true << true << false << true << true << + std::vector{ + EGL_CONTEXT_MAJOR_VERSION_KHR, 3, + EGL_CONTEXT_MINOR_VERSION_KHR, 2, + EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, EGL_LOSE_CONTEXT_ON_RESET_KHR, + EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR | EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR, + EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR, + EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG, + EGL_NONE}; } void OpenGLContextAttributeBuilderTest::testEgl() @@ -232,6 +314,7 @@ QFETCH(bool, forwardCompatible); QFETCH(bool, coreProfile); QFETCH(bool, compatibilityProfile); + QFETCH(bool, highPriority); EglContextAttributeBuilder builder; if (requestVersion) { @@ -241,33 +324,47 @@ builder.setForwardCompatible(forwardCompatible); builder.setCoreProfile(coreProfile); builder.setCompatibilityProfile(compatibilityProfile); + builder.setHighPriority(highPriority); auto attribs = builder.build(); QTEST(attribs, "expectedAttribs"); } void OpenGLContextAttributeBuilderTest::testGles_data() { QTest::addColumn("robust"); + QTest::addColumn("highPriority"); QTest::addColumn>("expectedAttribs"); - QTest::newRow("robust") << true << std::vector{ + QTest::newRow("robust") << true << false << std::vector{ EGL_CONTEXT_CLIENT_VERSION, 2, EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_TRUE, EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, EGL_LOSE_CONTEXT_ON_RESET_EXT, EGL_NONE}; - QTest::newRow("normal") << false << std::vector{ + QTest::newRow("robust/high priority") << true << true << std::vector{ + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_TRUE, + EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, EGL_LOSE_CONTEXT_ON_RESET_EXT, + EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG, + EGL_NONE}; + QTest::newRow("normal") << false << false << std::vector{ + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE}; + QTest::newRow("normal/high priority") << false << true << std::vector{ EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG, EGL_NONE}; } void OpenGLContextAttributeBuilderTest::testGles() { QFETCH(bool, robust); + QFETCH(bool, highPriority); EglOpenGLESContextAttributeBuilder builder; builder.setVersion(2); builder.setRobust(robust); + builder.setHighPriority(highPriority); auto attribs = builder.build(); QTEST(attribs, "expectedAttribs"); diff --git a/effects/blur/blur_config.desktop b/effects/blur/blur_config.desktop --- a/effects/blur/blur_config.desktop +++ b/effects/blur/blur_config.desktop @@ -39,7 +39,7 @@ Name[hsb]=Młowojty Name[hu]=Elmosódás Name[ia]=Obscura (Blur) -Name[id]=Samar +Name[id]=Buram Name[is]=Móða Name[it]=Sfocatura Name[ja]=ぼかし diff --git a/egl_context_attribute_builder.cpp b/egl_context_attribute_builder.cpp --- a/egl_context_attribute_builder.cpp +++ b/egl_context_attribute_builder.cpp @@ -52,6 +52,10 @@ attribs.emplace_back(EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR); } } + if (isHighPriority()) { + attribs.emplace_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG); + attribs.emplace_back(EGL_CONTEXT_PRIORITY_HIGH_IMG); + } attribs.emplace_back(EGL_NONE); return attribs; } @@ -67,6 +71,10 @@ attribs.emplace_back(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT); attribs.emplace_back(EGL_LOSE_CONTEXT_ON_RESET_EXT); } + if (isHighPriority()) { + attribs.emplace_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG); + attribs.emplace_back(EGL_CONTEXT_PRIORITY_HIGH_IMG); + } attribs.emplace_back(EGL_NONE); return attribs; } diff --git a/keyboard_layout.cpp b/keyboard_layout.cpp --- a/keyboard_layout.cpp +++ b/keyboard_layout.cpp @@ -272,7 +272,7 @@ p->setProgram(QStringLiteral("kcmshell5")); connect(p, static_cast(&QProcess::finished), p, &QProcess::deleteLater); connect(p, static_cast(&QProcess::error), this, - [p] (QProcess::ProcessError e) { + [] (QProcess::ProcessError e) { if (e == QProcess::FailedToStart) { qCDebug(KWIN_CORE) << "Failed to start kcmshell5"; } diff --git a/libinput/connection.cpp b/libinput/connection.cpp --- a/libinput/connection.cpp +++ b/libinput/connection.cpp @@ -28,8 +28,6 @@ #include "../udev.h" #include "libinput_logging.h" -#include - #include #include #include @@ -603,23 +601,6 @@ // pass configuration to Device device->setConfig(m_config->group("Libinput").group(QString::number(device->vendor())).group(QString::number(device->product())).group(device->name())); device->loadConfiguration(); - - if (device->isPointer() && !device->isTouchpad()) { - const KConfigGroup group = m_config->group("Mouse"); - device->setLeftHanded(group.readEntry("MouseButtonMapping", "RightHanded") == QLatin1String("LeftHanded")); - qreal accel = group.readEntry("Acceleration", -1.0); - if (qFuzzyCompare(accel, -1.0) || qFuzzyCompare(accel, 1.0)) { - // default value - device->setPointerAcceleration(0.0); - } else { - // the X11-based config is mapped in [0.1,20.0] with 1.0 being the "normal" setting - we assume that's the default - if (accel < 1.0) { - device->setPointerAcceleration(-1.0 + ((accel * 10.0) - 1.0) / 9.0); - } else { - device->setPointerAcceleration((accel -1.0)/19.0); - } - } - } } void Connection::slotKGlobalSettingsNotifyChange(int type, int arg) diff --git a/output.h b/output.h new file mode 100644 --- /dev/null +++ b/output.h @@ -0,0 +1,138 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright 2018 Roman Gilg + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#ifndef KWIN_OUTPUT_H +#define KWIN_OUTPUT_H + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace KWayland +{ +namespace Server +{ +class OutputInterface; +class OutputDeviceInterface; +class OutputChangeSet; +class OutputManagementInterface; +} +} + +namespace KWin +{ + +/** + * Generic output representation in a Wayland session + **/ +class KWIN_EXPORT Output : public QObject +{ + Q_OBJECT +public: + virtual ~Output() {} + + QString name() const; + bool isEnabled() const { + return !m_waylandOutput.isNull(); + } + + virtual QSize pixelSize() const = 0; + qreal scale() const { + return m_scale; + } + /* + * The geometry of this output in global compositor co-ordinates (i.e scaled) + */ + QRect geometry() const; + QSize physicalSize() const; + Qt::ScreenOrientation orientation() const { + return m_orientation; + } + + bool isInternal() const { + return m_internal; + } + + void setGlobalPos(const QPoint &pos); + void setScale(qreal scale); + + /** + * This sets the changes and tests them against the specific output + */ + void setChanges(KWayland::Server::OutputChangeSet *changeset); + virtual bool commitChanges() { return false; } + + const QPointer getWaylandInterface() const { + return m_waylandOutput; + } + +protected: + QPointer getChangeset() const { + return m_changeset; + } + QPointer getWaylandOutput() const { + return m_waylandOutput; + } + void setWaylandOutput(KWayland::Server::OutputInterface *set); + QPointer getWaylandOutputDevice() const { + return m_waylandOutputDevice; + } + void setWaylandOutputDevice(KWayland::Server::OutputDeviceInterface *set); + QPoint globalPos() const { + return m_globalPos; + } + + QSize rawPhysicalSize() const { + return m_physicalSize; + } + void setRawPhysicalSize(const QSize &set) { + m_physicalSize = set; + } + + void setOrientation(Qt::ScreenOrientation set) { + m_orientation = set; + } + bool internal() const { + return m_internal; + } + void setInternal(bool set) { + m_internal = set; + } + +private: + QPointer m_changeset; + QPointer m_waylandOutput; + QPointer m_waylandOutputDevice; + + QPoint m_globalPos; + qreal m_scale = 1; + QSize m_physicalSize; + Qt::ScreenOrientation m_orientation = Qt::PrimaryOrientation; + bool m_internal = false; +}; + +} + +#endif // KWIN_OUTPUT_H diff --git a/output.cpp b/output.cpp new file mode 100644 --- /dev/null +++ b/output.cpp @@ -0,0 +1,92 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright 2018 Roman Gilg + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +#include "output.h" + +// KWayland +#include +#include +#include +// KF5 +#include + +namespace KWin +{ + +QString Output::name() const +{ + if (!m_waylandOutput) { + return i18n("unknown"); + } + return QStringLiteral("%1 %2").arg(m_waylandOutput->manufacturer()).arg(m_waylandOutput->model()); +} + +QRect Output::geometry() const +{ + return QRect(m_globalPos, pixelSize() / scale()); +} + +QSize Output::physicalSize() const +{ + if (m_orientation == Qt::PortraitOrientation || m_orientation == Qt::InvertedPortraitOrientation) { + return QSize(m_physicalSize.height(), m_physicalSize.width()); + } + return m_physicalSize; +} + +void Output::setGlobalPos(const QPoint &pos) +{ + m_globalPos = pos; + if (m_waylandOutput) { + m_waylandOutput->setGlobalPosition(pos); + } + if (m_waylandOutputDevice) { + m_waylandOutputDevice->setGlobalPosition(pos); + } +} + +void Output::setScale(qreal scale) +{ + m_scale = scale; + if (m_waylandOutput) { + m_waylandOutput->setScale(scale); + } + if (m_waylandOutputDevice) { + m_waylandOutputDevice->setScale(scale); + } +} + +void Output::setChanges(KWayland::Server::OutputChangeSet *changes) +{ + m_changeset = changes; + qCDebug(KWIN_CORE) << "set changes in Output"; + commitChanges(); +} + +void Output::setWaylandOutput(KWayland::Server::OutputInterface *set) +{ + m_waylandOutput = set; +} + +void Output::setWaylandOutputDevice(KWayland::Server::OutputDeviceInterface *set) +{ + m_waylandOutputDevice = set; +} + +} diff --git a/platform.h b/platform.h --- a/platform.h +++ b/platform.h @@ -45,6 +45,7 @@ struct GammaRamp; } +class Output; class Edge; class Compositor; class OverlayWindow; @@ -411,6 +412,15 @@ return false; } + // outputs with connections (org_kde_kwin_outputdevice) + QVector outputs() const { + return m_outputs; + } + // actively compositing outputs (wl_output) + QVector enabledOutputs() const { + return m_enabledOutputs; + } + /* * A string of information to include in kwin debug output * It should not be translated. @@ -500,6 +510,9 @@ **/ virtual void doShowCursor(); + QVector m_outputs; + QVector m_enabledOutputs; + private: void triggerCursorRepaint(); bool m_softWareCursor = false; diff --git a/platform.cpp b/platform.cpp --- a/platform.cpp +++ b/platform.cpp @@ -46,6 +46,7 @@ Platform::~Platform() { + qDeleteAll(m_outputs); if (m_eglDisplay != EGL_NO_DISPLAY) { eglTerminate(m_eglDisplay); } diff --git a/platformsupport/scenes/opengl/abstract_egl_backend.cpp b/platformsupport/scenes/opengl/abstract_egl_backend.cpp --- a/platformsupport/scenes/opengl/abstract_egl_backend.cpp +++ b/platformsupport/scenes/opengl/abstract_egl_backend.cpp @@ -217,30 +217,63 @@ { const bool haveRobustness = hasExtension(QByteArrayLiteral("EGL_EXT_create_context_robustness")); const bool haveCreateContext = hasExtension(QByteArrayLiteral("EGL_KHR_create_context")); + const bool haveContextPriority = hasExtension(QByteArrayLiteral("EGL_IMG_context_priority")); std::vector> candidates; if (isOpenGLES()) { + if (haveCreateContext && haveRobustness && haveContextPriority) { + auto glesRobustPriority = std::unique_ptr(new EglOpenGLESContextAttributeBuilder); + glesRobustPriority->setVersion(2); + glesRobustPriority->setRobust(true); + glesRobustPriority->setHighPriority(true); + candidates.push_back(std::move(glesRobustPriority)); + } if (haveCreateContext && haveRobustness) { auto glesRobust = std::unique_ptr(new EglOpenGLESContextAttributeBuilder); glesRobust->setVersion(2); glesRobust->setRobust(true); candidates.push_back(std::move(glesRobust)); } + if (haveContextPriority) { + auto glesPriority = std::unique_ptr(new EglOpenGLESContextAttributeBuilder); + glesPriority->setVersion(2); + glesPriority->setHighPriority(true); + candidates.push_back(std::move(glesPriority)); + } auto gles = std::unique_ptr(new EglOpenGLESContextAttributeBuilder); gles->setVersion(2); candidates.push_back(std::move(gles)); } else { if (options->glCoreProfile() && haveCreateContext) { + if (haveRobustness && haveContextPriority) { + auto robustCorePriority = std::unique_ptr(new EglContextAttributeBuilder); + robustCorePriority->setVersion(3, 1); + robustCorePriority->setRobust(true); + robustCorePriority->setHighPriority(true); + candidates.push_back(std::move(robustCorePriority)); + } if (haveRobustness) { auto robustCore = std::unique_ptr(new EglContextAttributeBuilder); robustCore->setVersion(3, 1); robustCore->setRobust(true); candidates.push_back(std::move(robustCore)); } + if (haveContextPriority) { + auto corePriority = std::unique_ptr(new EglContextAttributeBuilder); + corePriority->setVersion(3, 1); + corePriority->setHighPriority(true); + candidates.push_back(std::move(corePriority)); + } auto core = std::unique_ptr(new EglContextAttributeBuilder); core->setVersion(3, 1); candidates.push_back(std::move(core)); } + if (haveRobustness && haveCreateContext && haveContextPriority) { + auto robustPriority = std::unique_ptr(new EglContextAttributeBuilder); + robustPriority->setRobust(true); + robustPriority->setHighPriority(true); + candidates.push_back(std::move(robustPriority)); + } if (haveRobustness && haveCreateContext) { auto robust = std::unique_ptr(new EglContextAttributeBuilder); robust->setRobust(true); diff --git a/plugins/platforms/drm/drm_backend.h b/plugins/platforms/drm/drm_backend.h --- a/plugins/platforms/drm/drm_backend.h +++ b/plugins/platforms/drm/drm_backend.h @@ -93,12 +93,6 @@ int fd() const { return m_fd; } - QVector outputs() const { - return m_outputs; - } - QVector enabledOutputs() const { - return m_enabledOutputs; - } QVector planes() const { return m_planes; } @@ -173,10 +167,6 @@ QVector m_crtcs; // all connectors QVector m_connectors; - // active output pipelines (planes + crtc + encoder + connector) - QVector m_outputs; - // active and enabled pipelines (above + wl_output) - QVector m_enabledOutputs; bool m_deleteBufferAfterPageFlip; bool m_atomicModeSetting = false; diff --git a/plugins/platforms/drm/drm_backend.cpp b/plugins/platforms/drm/drm_backend.cpp --- a/plugins/platforms/drm/drm_backend.cpp +++ b/plugins/platforms/drm/drm_backend.cpp @@ -90,7 +90,10 @@ while (m_pageFlipsPending != 0) { QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents); } + // we need to first remove all outputs qDeleteAll(m_outputs); + m_outputs.clear(); + qDeleteAll(m_planes); qDeleteAll(m_crtcs); qDeleteAll(m_connectors); @@ -130,7 +133,8 @@ { m_dpmsFilter.reset(); for (auto it = m_enabledOutputs.constBegin(), end = m_enabledOutputs.constEnd(); it != end; it++) { - (*it)->setDpms(DrmOutput::DpmsMode::On); + auto *o = qobject_cast(*it); + o->setDpms(DrmOutput::DpmsMode::On); } } @@ -141,7 +145,8 @@ return; } for (auto it = m_enabledOutputs.constBegin(), end = m_enabledOutputs.constEnd(); it != end; it++) { - if (!(*it)->isDpmsEnabled()) { + auto *o = qobject_cast(*it); + if (!o->isDpmsEnabled()) { // dpms still disabled, need to keep the filter return; } @@ -170,7 +175,7 @@ if (!usesSoftwareCursor()) { const QPoint cp = Cursor::pos() - softwareCursorHotspot(); for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { - DrmOutput *o = *it; + auto *o = qobject_cast(*it); // only relevant in atomic mode o->m_modesetRequested = true; o->pageFlipped(); // TODO: Do we really need this? @@ -198,7 +203,7 @@ } // hide cursor and disable for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { - DrmOutput *o = *it; + auto *o = qobject_cast(*it); o->hideCursor(); } m_active = false; @@ -373,7 +378,7 @@ return; } - QVector connectedOutputs; + QVector connectedOutputs; QVector pendingConnectors; // split up connected connectors in already or not yet assigned ones @@ -392,15 +397,15 @@ // check for outputs which got removed auto it = m_outputs.begin(); while (it != m_outputs.end()) { - if (connectedOutputs.contains(*it)) { + Output *o = *it; + if (connectedOutputs.contains(o)) { it++; continue; } - DrmOutput *removed = *it; it = m_outputs.erase(it); - m_enabledOutputs.removeOne(removed); - emit outputRemoved(removed); - delete removed; + m_enabledOutputs.removeOne(o); + emit outputRemoved(qobject_cast(o)); + delete o; } // now check new connections @@ -427,8 +432,8 @@ // check if crtc isn't used yet -- currently we don't allow multiple outputs on one crtc (cloned mode) auto it = std::find_if(connectedOutputs.constBegin(), connectedOutputs.constEnd(), - [crtc] (DrmOutput *o) { - return o->m_crtc == crtc; + [crtc] (Output *o) { + return qobject_cast(o)->m_crtc == crtc; } ); if (it != connectedOutputs.constEnd()) { @@ -476,7 +481,9 @@ } } } - std::sort(connectedOutputs.begin(), connectedOutputs.end(), [] (DrmOutput *a, DrmOutput *b) { return a->m_conn->id() < b->m_conn->id(); }); + std::sort(connectedOutputs.begin(), connectedOutputs.end(), [] (Output *a, Output *b) { + return qobject_cast(a)->m_conn->id() < qobject_cast(b)->m_conn->id(); + }); m_outputs = connectedOutputs; m_enabledOutputs = connectedOutputs; readOutputsConfiguration(); @@ -496,25 +503,27 @@ // default position goes from left to right QPoint pos(0, 0); for (auto it = m_outputs.begin(); it != m_outputs.end(); ++it) { - qCDebug(KWIN_DRM) << "Reading output configuration for [" << uuid << "] ["<< (*it)->uuid() << "]"; - const auto outputConfig = configGroup.group((*it)->uuid()); - (*it)->setGlobalPos(outputConfig.readEntry("Position", pos)); + auto *o = qobject_cast(*it); + qCDebug(KWIN_DRM) << "Reading output configuration for [" << uuid << "] ["<< o->uuid() << "]"; + const auto outputConfig = configGroup.group(o->uuid()); + o->setGlobalPos(outputConfig.readEntry("Position", pos)); // TODO: add mode - (*it)->setScale(outputConfig.readEntry("Scale", 1.0)); - pos.setX(pos.x() + (*it)->geometry().width()); + o->setScale(outputConfig.readEntry("Scale", 1.0)); + pos.setX(pos.x() + o->geometry().width()); } } QByteArray DrmBackend::generateOutputConfigurationUuid() const { auto it = m_outputs.constBegin(); if (m_outputs.size() == 1) { // special case: one output - return (*it)->uuid(); + return qobject_cast(*it)->uuid(); } QCryptographicHash hash(QCryptographicHash::Md5); for (; it != m_outputs.constEnd(); ++it) { - hash.addData((*it)->uuid()); + auto *o = qobject_cast(*it); + hash.addData(o->uuid()); } return hash.result().toHex().left(10); } @@ -574,22 +583,22 @@ DrmOutput *DrmBackend::findOutput(quint32 connector) { - auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(), [connector] (DrmOutput *o) { - return o->m_conn->id() == connector; + auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(), [connector] (Output *o) { + return qobject_cast(o)->m_conn->id() == connector; }); if (it != m_outputs.constEnd()) { - return *it; + return qobject_cast(*it); } return nullptr; } DrmOutput *DrmBackend::findOutput(const QByteArray &uuid) { - auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(), [uuid] (DrmOutput *o) { - return o->m_uuid == uuid; + auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(), [uuid] (Output *o) { + return qobject_cast(o)->m_uuid == uuid; }); if (it != m_outputs.constEnd()) { - return *it; + return qobject_cast(*it); } return nullptr; } @@ -623,10 +632,11 @@ return; } for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { + auto *o = qobject_cast(*it); if (m_cursorEnabled) { - (*it)->showCursor(); + o->showCursor(); } else { - (*it)->hideCursor(); + o->hideCursor(); } } } @@ -653,7 +663,8 @@ { if (m_cursorEnabled) { for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { - (*it)->showCursor(); + auto *o = qobject_cast(*it); + o->showCursor(); } } markCursorAsRendered(); @@ -673,7 +684,8 @@ return; } for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { - (*it)->updateCursor(); + auto *o = qobject_cast(*it); + o->updateCursor(); } setCursor(); @@ -691,7 +703,8 @@ return; } for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { - (*it)->hideCursor(); + auto *o = qobject_cast(*it); + o->hideCursor(); } } @@ -701,7 +714,8 @@ return; } for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { - (*it)->moveCursor(Cursor::pos()); + auto *o = qobject_cast(*it); + o->moveCursor(Cursor::pos()); } } @@ -747,7 +761,8 @@ } bool enabled = false; for (auto it = m_enabledOutputs.constBegin(); it != m_enabledOutputs.constEnd(); ++it) { - enabled = enabled || (*it)->isDpmsEnabled(); + auto *o = qobject_cast(*it); + enabled = enabled || o->isDpmsEnabled(); } setOutputsEnabled(enabled); } @@ -766,15 +781,17 @@ if (m_outputs.size() <= screen) { return 0; } - return m_outputs.at(screen)->m_crtc->getGammaRampSize(); + auto *o = qobject_cast(m_outputs.at(screen)); + return o->m_crtc->getGammaRampSize(); } bool DrmBackend::setGammaRamp(int screen, ColorCorrect::GammaRamp &gamma) { if (m_outputs.size() <= screen) { return false; } - return m_outputs.at(screen)->m_crtc->setGammaRamp(gamma); + auto *o = qobject_cast(m_outputs.at(screen)); + return o->m_crtc->setGammaRamp(gamma); } QString DrmBackend::supportInformation() const diff --git a/plugins/platforms/drm/drm_output.h b/plugins/platforms/drm/drm_output.h --- a/plugins/platforms/drm/drm_output.h +++ b/plugins/platforms/drm/drm_output.h @@ -20,30 +20,19 @@ #ifndef KWIN_DRM_OUTPUT_H #define KWIN_DRM_OUTPUT_H +#include "output.h" #include "drm_pointer.h" #include "drm_object.h" #include "drm_object_plane.h" #include #include -#include #include #include #include #include -namespace KWayland -{ -namespace Server -{ -class OutputInterface; -class OutputDeviceInterface; -class OutputChangeSet; -class OutputManagementInterface; -} -} - namespace KWin { @@ -54,7 +43,7 @@ class DrmConnector; class DrmCrtc; -class DrmOutput : public QObject +class KWIN_EXPORT DrmOutput : public Output { Q_OBJECT public: @@ -82,23 +71,11 @@ * The default is on */ void setEnabled(bool enabled); - bool isEnabled() const; - - /** - * This sets the changes and tests them against the DRM output - */ - void setChanges(KWayland::Server::OutputChangeSet *changeset); - bool commitChanges(); - QSize pixelSize() const; - qreal scale() const; + virtual bool commitChanges() override; - /* - * The geometry of this output in global compositor co-ordinates (i.e scaled) - */ - QRect geometry() const; + QSize pixelSize() const override; - QString name() const; int currentRefreshRate() const; // These values are defined by the kernel enum class DpmsMode { @@ -117,24 +94,10 @@ return m_uuid; } - QSize physicalSize() const; - bool initCursor(const QSize &cursorSize); bool supportsTransformations() const; - bool isInternal() const { - return m_internal; - } - - Qt::ScreenOrientation orientation() const { - return m_orientation; - } - - const QPointer getWaylandInterface() const { - return m_waylandOutput; - } - Q_SIGNALS: void dpmsChanged(); void modeChanged(); @@ -160,8 +123,6 @@ bool isCurrentMode(const drmModeModeInfo *mode) const; void initUuid(); - void setGlobalPos(const QPoint &pos); - void setScale(qreal scale); void initOutput(); bool initPrimaryPlane(); bool initCursorPlane(); @@ -178,14 +139,9 @@ DrmBackend *m_backend; DrmConnector *m_conn = nullptr; DrmCrtc *m_crtc = nullptr; - QPoint m_globalPos; - qreal m_scale = 1; bool m_lastGbm = false; drmModeModeInfo m_mode; Edid m_edid; - QPointer m_waylandOutput; - QPointer m_waylandOutputDevice; - QPointer m_changeset; KWin::ScopedDrmPointer<_drmModeProperty, &drmModeFreeProperty> m_dpms; DpmsMode m_dpmsMode = DpmsMode::On; DpmsMode m_dpmsModePending = DpmsMode::On; @@ -198,8 +154,6 @@ bool m_pageFlipPending = false; bool m_dpmsAtomicOffPending = false; bool m_modesetRequested = true; - QSize m_physicalSize; - Qt::ScreenOrientation m_orientation = Qt::PrimaryOrientation; struct { Qt::ScreenOrientation orientation; @@ -211,7 +165,6 @@ DrmDumbBuffer *m_cursor[2] = {nullptr, nullptr}; int m_cursorIndex = 0; bool m_hasNewCursor = false; - bool m_internal = false; }; } diff --git a/plugins/platforms/drm/drm_output.cpp b/plugins/platforms/drm/drm_output.cpp --- a/plugins/platforms/drm/drm_output.cpp +++ b/plugins/platforms/drm/drm_output.cpp @@ -36,7 +36,6 @@ #include #include #include -#include #include #include // KF5 @@ -57,7 +56,7 @@ { DrmOutput::DrmOutput(DrmBackend *backend) - : QObject() + : Output() , m_backend(backend) { } @@ -80,8 +79,8 @@ m_crtc->setOutput(nullptr); m_conn->setOutput(nullptr); - delete m_waylandOutput.data(); - delete m_waylandOutputDevice.data(); + delete getWaylandOutput().data(); + delete getWaylandOutputDevice().data(); delete m_cursor[0]; delete m_cursor[1]; } @@ -127,7 +126,7 @@ c->fill(Qt::transparent); QPainter p; p.begin(c); - if (m_orientation == Qt::InvertedLandscapeOrientation) { + if (orientation() == Qt::InvertedLandscapeOrientation) { QMatrix4x4 matrix; matrix.translate(cursorImage.width() / 2.0, cursorImage.height() / 2.0); matrix.rotate(180.0f, 0.0f, 0.0f, 1.0f); @@ -142,47 +141,31 @@ { QMatrix4x4 matrix; QMatrix4x4 hotspotMatrix; - if (m_orientation == Qt::InvertedLandscapeOrientation) { + if (orientation() == Qt::InvertedLandscapeOrientation) { matrix.translate(pixelSize().width() /2.0, pixelSize().height() / 2.0); matrix.rotate(180.0f, 0.0f, 0.0f, 1.0f); matrix.translate(-pixelSize().width() /2.0, -pixelSize().height() / 2.0); const auto cursorSize = m_backend->softwareCursor().size(); hotspotMatrix.translate(cursorSize.width()/2.0, cursorSize.height()/2.0); hotspotMatrix.rotate(180.0f, 0.0f, 0.0f, 1.0f); hotspotMatrix.translate(-cursorSize.width()/2.0, -cursorSize.height()/2.0); } - matrix.scale(m_scale); - matrix.translate(-m_globalPos.x(), -m_globalPos.y()); + matrix.scale(scale()); + auto outputGlobalPos = Output::globalPos(); + matrix.translate(-outputGlobalPos.x(), -outputGlobalPos.y()); const QPoint p = matrix.map(globalPos) - hotspotMatrix.map(m_backend->softwareCursorHotspot()); drmModeMoveCursor(m_backend->fd(), m_crtc->id(), p.x(), p.y()); } QSize DrmOutput::pixelSize() const { - if (m_orientation == Qt::PortraitOrientation || m_orientation == Qt::InvertedPortraitOrientation) { + auto orient = orientation(); + if (orient == Qt::PortraitOrientation || orient == Qt::InvertedPortraitOrientation) { return QSize(m_mode.vdisplay, m_mode.hdisplay); } return QSize(m_mode.hdisplay, m_mode.vdisplay); } -QSize DrmOutput::physicalSize() const -{ - if (m_orientation == Qt::PortraitOrientation || m_orientation == Qt::InvertedPortraitOrientation) { - return QSize(m_physicalSize.height(), m_physicalSize.width()); - } - return m_physicalSize; -} - -QRect DrmOutput::geometry() const -{ - return QRect(m_globalPos, pixelSize() / scale()); -} - -qreal DrmOutput::scale() const -{ - return m_scale; -} - void DrmOutput::setEnabled(bool enabled) { if (enabled == isEnabled()) { @@ -193,17 +176,12 @@ initOutput(); } else { setDpms(DpmsMode::Off); - delete m_waylandOutput.data(); + delete getWaylandOutput().data(); } - m_waylandOutputDevice->setEnabled(enabled ? + getWaylandOutputDevice()->setEnabled(enabled ? KWayland::Server::OutputDeviceInterface::Enablement::Enabled : KWayland::Server::OutputDeviceInterface::Enablement::Disabled); } -bool DrmOutput::isEnabled() const -{ - return !m_waylandOutput.isNull(); -} - static KWayland::Server::OutputInterface::DpmsMode toWaylandDpmsMode(DrmOutput::DpmsMode mode) { using namespace KWayland::Server; @@ -290,9 +268,10 @@ return false; } - m_internal = connector->connector_type == DRM_MODE_CONNECTOR_LVDS || connector->connector_type == DRM_MODE_CONNECTOR_eDP; + setInternal(connector->connector_type == DRM_MODE_CONNECTOR_LVDS || + connector->connector_type == DRM_MODE_CONNECTOR_eDP); - if (m_internal) { + if (internal()) { connect(kwinApp(), &Application::screensCreated, this, [this] { connect(screens()->orientationSensor(), &OrientationSensor::orientationChanged, this, &DrmOutput::automaticRotation); @@ -312,7 +291,7 @@ qCWarning(KWIN_DRM) << "Overwriting monitor physical size for" << m_edid.eisaId << "/" << m_edid.monitorName << "/" << m_edid.serialNumber << " from " << physicalSize << "to " << overwriteSize; physicalSize = overwriteSize; } - m_physicalSize = physicalSize; + setRawPhysicalSize(physicalSize); initOutputDevice(connector); @@ -332,62 +311,69 @@ void DrmOutput::initOutput() { - Q_ASSERT(m_waylandOutputDevice); - if (!m_waylandOutput.isNull()) { - delete m_waylandOutput.data(); - m_waylandOutput.clear(); + auto waylandOutputDevice = getWaylandOutputDevice(); + Q_ASSERT(waylandOutputDevice); + + auto waylandOutput = getWaylandOutput(); + if (!waylandOutput.isNull()) { + delete waylandOutput.data(); + waylandOutput.clear(); } - m_waylandOutput = waylandServer()->display()->createOutput(); + waylandOutput = waylandServer()->display()->createOutput(); connect(this, &DrmOutput::modeChanged, this, [this] { - if (m_waylandOutput.isNull()) { + auto waylandOutput = getWaylandOutput(); + if (waylandOutput.isNull()) { return; } - m_waylandOutput->setCurrentMode(QSize(m_mode.hdisplay, m_mode.vdisplay), refreshRateForMode(&m_mode)); + waylandOutput->setCurrentMode(QSize(m_mode.hdisplay, m_mode.vdisplay), + refreshRateForMode(&m_mode)); } ); - m_waylandOutput->setManufacturer(m_waylandOutputDevice->manufacturer()); - m_waylandOutput->setModel(m_waylandOutputDevice->model()); - m_waylandOutput->setPhysicalSize(m_physicalSize); + waylandOutput->setManufacturer(waylandOutputDevice->manufacturer()); + waylandOutput->setModel(waylandOutputDevice->model()); + waylandOutput->setPhysicalSize(rawPhysicalSize()); // set dpms if (!m_dpms.isNull()) { - m_waylandOutput->setDpmsSupported(true); - m_waylandOutput->setDpmsMode(toWaylandDpmsMode(m_dpmsMode)); - connect(m_waylandOutput.data(), &KWayland::Server::OutputInterface::dpmsModeRequested, this, + waylandOutput->setDpmsSupported(true); + waylandOutput->setDpmsMode(toWaylandDpmsMode(m_dpmsMode)); + connect(waylandOutput.data(), &KWayland::Server::OutputInterface::dpmsModeRequested, this, [this] (KWayland::Server::OutputInterface::DpmsMode mode) { setDpms(fromWaylandDpmsMode(mode)); }, Qt::QueuedConnection ); } - for(const auto &mode: m_waylandOutputDevice->modes()) { + for(const auto &mode: waylandOutputDevice->modes()) { KWayland::Server::OutputInterface::ModeFlags flags; if (mode.flags & KWayland::Server::OutputDeviceInterface::ModeFlag::Current) { flags |= KWayland::Server::OutputInterface::ModeFlag::Current; } if (mode.flags & KWayland::Server::OutputDeviceInterface::ModeFlag::Preferred) { flags |= KWayland::Server::OutputInterface::ModeFlag::Preferred; } - m_waylandOutput->addMode(mode.size, flags, mode.refreshRate); + waylandOutput->addMode(mode.size, flags, mode.refreshRate); } - m_waylandOutput->create(); + waylandOutput->create(); + setWaylandOutput(waylandOutput.data()); } void DrmOutput::initOutputDevice(drmModeConnector *connector) { - if (!m_waylandOutputDevice.isNull()) { - delete m_waylandOutputDevice.data(); - m_waylandOutputDevice.clear(); + auto waylandOutputDevice = getWaylandOutputDevice(); + if (!waylandOutputDevice.isNull()) { + delete waylandOutputDevice.data(); + waylandOutputDevice.clear(); } - m_waylandOutputDevice = waylandServer()->display()->createOutputDevice(); - m_waylandOutputDevice->setUuid(m_uuid); + waylandOutputDevice = waylandServer()->display()->createOutputDevice(); + waylandOutputDevice->setUuid(m_uuid); if (!m_edid.eisaId.isEmpty()) { - m_waylandOutputDevice->setManufacturer(QString::fromLatin1(m_edid.eisaId)); + waylandOutputDevice->setManufacturer(QString::fromLatin1(m_edid.eisaId)); } else { - m_waylandOutputDevice->setManufacturer(i18n("unknown")); + waylandOutputDevice->setManufacturer(i18n("unknown")); } QString connectorName = s_connectorNames.value(connector->connector_type, QByteArrayLiteral("Unknown")); @@ -406,9 +392,9 @@ modelName = i18n("unknown"); } - m_waylandOutputDevice->setModel(connectorName + QStringLiteral("-") + QString::number(connector->connector_type_id) + QStringLiteral("-") + modelName); + waylandOutputDevice->setModel(connectorName + QStringLiteral("-") + QString::number(connector->connector_type_id) + QStringLiteral("-") + modelName); - m_waylandOutputDevice->setPhysicalSize(m_physicalSize); + waylandOutputDevice->setPhysicalSize(rawPhysicalSize()); // read in mode information for (int i = 0; i < connector->count_modes; ++i) { @@ -431,9 +417,10 @@ mode.flags = deviceflags; mode.refreshRate = refreshRate; qCDebug(KWIN_DRM) << "Adding mode: " << i << mode.size; - m_waylandOutputDevice->addMode(mode); + waylandOutputDevice->addMode(mode); } - m_waylandOutputDevice->create(); + waylandOutputDevice->create(); + setWaylandOutputDevice(waylandOutputDevice.data()); } bool DrmOutput::isCurrentMode(const drmModeModeInfo *mode) const @@ -728,8 +715,9 @@ { qCDebug(KWIN_DRM) << "DPMS mode set for output" << m_crtc->id() << "to On."; - if (m_waylandOutput) { - m_waylandOutput->setDpmsMode(toWaylandDpmsMode(m_dpmsModePending)); + auto waylandOutput = getWaylandOutput(); + if (waylandOutput) { + waylandOutput->setDpmsMode(toWaylandDpmsMode(m_dpmsModePending)); } emit dpmsChanged(); @@ -746,154 +734,124 @@ { qCDebug(KWIN_DRM) << "DPMS mode set for output" << m_crtc->id() << "to Off."; - if (m_waylandOutput) { - m_waylandOutput->setDpmsMode(toWaylandDpmsMode(m_dpmsModePending)); + auto waylandOutput = getWaylandOutput(); + if (waylandOutput) { + waylandOutput->setDpmsMode(toWaylandDpmsMode(m_dpmsModePending)); } emit dpmsChanged(); m_backend->outputWentOff(); } -QString DrmOutput::name() const -{ - if (!m_waylandOutput) { - return i18n("unknown"); - } - return QStringLiteral("%1 %2").arg(m_waylandOutput->manufacturer()).arg(m_waylandOutput->model()); -} - int DrmOutput::currentRefreshRate() const { - if (!m_waylandOutput) { + auto waylandOutput = getWaylandOutput(); + if (!waylandOutput) { return 60000; } - return m_waylandOutput->refreshRate(); -} - -void DrmOutput::setGlobalPos(const QPoint &pos) -{ - m_globalPos = pos; - if (m_waylandOutput) { - m_waylandOutput->setGlobalPosition(pos); - } - if (m_waylandOutputDevice) { - m_waylandOutputDevice->setGlobalPosition(pos); - } -} - -void DrmOutput::setScale(qreal scale) -{ - m_scale = scale; - if (m_waylandOutput) { - m_waylandOutput->setScale(scale); - } - if (m_waylandOutputDevice) { - m_waylandOutputDevice->setScale(scale); - } -} - -void DrmOutput::setChanges(KWayland::Server::OutputChangeSet *changes) -{ - m_changeset = changes; - qCDebug(KWIN_DRM) << "set changes in DrmOutput"; - commitChanges(); + return waylandOutput->refreshRate(); } bool DrmOutput::commitChanges() { - Q_ASSERT(!m_waylandOutputDevice.isNull()); + auto waylandOutputDevice = getWaylandOutputDevice(); + Q_ASSERT(!waylandOutputDevice.isNull()); - if (m_changeset.isNull()) { + auto changeset = getChangeset(); + + if (changeset.isNull()) { qCDebug(KWIN_DRM) << "no changes"; // No changes to an output is an entirely valid thing return true; } //enabledChanged is handled by drmbackend - if (m_changeset->modeChanged()) { - qCDebug(KWIN_DRM) << "Setting new mode:" << m_changeset->mode(); - m_waylandOutputDevice->setCurrentMode(m_changeset->mode()); - updateMode(m_changeset->mode()); - } - if (m_changeset->transformChanged()) { - qCDebug(KWIN_DRM) << "Server setting transform: " << (int)(m_changeset->transform()); - transform(m_changeset->transform()); - } - if (m_changeset->positionChanged()) { - qCDebug(KWIN_DRM) << "Server setting position: " << m_changeset->position(); - setGlobalPos(m_changeset->position()); + if (changeset->modeChanged()) { + qCDebug(KWIN_DRM) << "Setting new mode:" << changeset->mode(); + waylandOutputDevice->setCurrentMode(changeset->mode()); + updateMode(changeset->mode()); + } + if (changeset->transformChanged()) { + qCDebug(KWIN_DRM) << "Server setting transform: " << (int)(changeset->transform()); + transform(changeset->transform()); + } + if (changeset->positionChanged()) { + qCDebug(KWIN_DRM) << "Server setting position: " << changeset->position(); + setGlobalPos(changeset->position()); // may just work already! } - if (m_changeset->scaleChanged()) { - qCDebug(KWIN_DRM) << "Setting scale:" << m_changeset->scale(); - setScale(m_changeset->scale()); + if (changeset->scaleChanged()) { + qCDebug(KWIN_DRM) << "Setting scale:" << changeset->scale(); + setScale(changeset->scale()); } return true; } void DrmOutput::transform(KWayland::Server::OutputDeviceInterface::Transform transform) { - m_waylandOutputDevice->setTransform(transform); + getWaylandOutputDevice()->setTransform(transform); using KWayland::Server::OutputDeviceInterface; using KWayland::Server::OutputInterface; + auto waylandOutput = getWaylandOutput(); + switch (transform) { case OutputDeviceInterface::Transform::Normal: if (m_primaryPlane) { m_primaryPlane->setTransformation(DrmPlane::Transformation::Rotate0); } - if (m_waylandOutput) { - m_waylandOutput->setTransform(OutputInterface::Transform::Normal); + if (waylandOutput) { + waylandOutput->setTransform(OutputInterface::Transform::Normal); } - m_orientation = Qt::PrimaryOrientation; + setOrientation(Qt::PrimaryOrientation); break; case OutputDeviceInterface::Transform::Rotated90: if (m_primaryPlane) { m_primaryPlane->setTransformation(DrmPlane::Transformation::Rotate90); } - if (m_waylandOutput) { - m_waylandOutput->setTransform(OutputInterface::Transform::Rotated90); + if (waylandOutput) { + waylandOutput->setTransform(OutputInterface::Transform::Rotated90); } - m_orientation = Qt::PortraitOrientation; + setOrientation(Qt::PortraitOrientation); break; case OutputDeviceInterface::Transform::Rotated180: if (m_primaryPlane) { m_primaryPlane->setTransformation(DrmPlane::Transformation::Rotate180); } - if (m_waylandOutput) { - m_waylandOutput->setTransform(OutputInterface::Transform::Rotated180); + if (waylandOutput) { + waylandOutput->setTransform(OutputInterface::Transform::Rotated180); } - m_orientation = Qt::InvertedLandscapeOrientation; + setOrientation(Qt::InvertedLandscapeOrientation); break; case OutputDeviceInterface::Transform::Rotated270: if (m_primaryPlane) { m_primaryPlane->setTransformation(DrmPlane::Transformation::Rotate270); } - if (m_waylandOutput) { - m_waylandOutput->setTransform(OutputInterface::Transform::Rotated270); + if (waylandOutput) { + waylandOutput->setTransform(OutputInterface::Transform::Rotated270); } - m_orientation = Qt::InvertedPortraitOrientation; + setOrientation(Qt::InvertedPortraitOrientation); break; case OutputDeviceInterface::Transform::Flipped: // TODO: what is this exactly? - if (m_waylandOutput) { - m_waylandOutput->setTransform(OutputInterface::Transform::Flipped); + if (waylandOutput) { + waylandOutput->setTransform(OutputInterface::Transform::Flipped); } break; case OutputDeviceInterface::Transform::Flipped90: // TODO: what is this exactly? - if (m_waylandOutput) { - m_waylandOutput->setTransform(OutputInterface::Transform::Flipped90); + if (waylandOutput) { + waylandOutput->setTransform(OutputInterface::Transform::Flipped90); } break; case OutputDeviceInterface::Transform::Flipped180: // TODO: what is this exactly? - if (m_waylandOutput) { - m_waylandOutput->setTransform(OutputInterface::Transform::Flipped180); + if (waylandOutput) { + waylandOutput->setTransform(OutputInterface::Transform::Flipped180); } break; case OutputDeviceInterface::Transform::Flipped270: // TODO: what is this exactly? - if (m_waylandOutput) { - m_waylandOutput->setTransform(OutputInterface::Transform::Flipped270); + if (waylandOutput) { + waylandOutput->setTransform(OutputInterface::Transform::Flipped270); } break; } @@ -1023,7 +981,7 @@ // go back to previous state if (m_lastWorkingState.valid) { m_mode = m_lastWorkingState.mode; - m_orientation = m_lastWorkingState.orientation; + setOrientation(m_lastWorkingState.orientation); setGlobalPos(m_lastWorkingState.globalPos); if (m_primaryPlane) { m_primaryPlane->setTransformation(m_lastWorkingState.planeTransformations); @@ -1047,8 +1005,8 @@ if (wasModeset) { // store current mode set as new good state m_lastWorkingState.mode = m_mode; - m_lastWorkingState.orientation = m_orientation; - m_lastWorkingState.globalPos = m_globalPos; + m_lastWorkingState.orientation = orientation(); + m_lastWorkingState.globalPos = globalPos(); if (m_primaryPlane) { m_lastWorkingState.planeTransformations = m_primaryPlane->transformation(); } diff --git a/plugins/platforms/drm/egl_gbm_backend.h b/plugins/platforms/drm/egl_gbm_backend.h --- a/plugins/platforms/drm/egl_gbm_backend.h +++ b/plugins/platforms/drm/egl_gbm_backend.h @@ -61,7 +61,7 @@ bool initBufferConfigs(); bool initRenderingContext(); void initRemotePresent(); - struct Output { + struct EglGbmOutput { DrmOutput *output = nullptr; DrmBuffer *buffer = nullptr; std::shared_ptr gbmSurface; @@ -72,13 +72,13 @@ */ QList damageHistory; }; - bool resetOutput(Output &output, DrmOutput *drmOutput); - bool makeContextCurrent(const Output &output); - void presentOnOutput(Output &output); - void cleanupOutput(const Output &output); + bool resetOutput(EglGbmOutput &output, DrmOutput *drmOutput); + bool makeContextCurrent(const EglGbmOutput &output); + void presentOnOutput(EglGbmOutput &output); + void cleanupOutput(const EglGbmOutput &output); void createOutput(DrmOutput *output); DrmBackend *m_backend; - QVector m_outputs; + QVector m_outputs; QScopedPointer m_remoteaccessManager; friend class EglGbmTexture; }; diff --git a/plugins/platforms/drm/egl_gbm_backend.cpp b/plugins/platforms/drm/egl_gbm_backend.cpp --- a/plugins/platforms/drm/egl_gbm_backend.cpp +++ b/plugins/platforms/drm/egl_gbm_backend.cpp @@ -47,7 +47,7 @@ connect(m_backend, &DrmBackend::outputRemoved, this, [this] (DrmOutput *output) { auto it = std::find_if(m_outputs.begin(), m_outputs.end(), - [output] (const Output &o) { + [output] (const EglGbmOutput &o) { return o.output == output; } ); @@ -73,7 +73,7 @@ m_outputs.clear(); } -void EglGbmBackend::cleanupOutput(const Output &o) +void EglGbmBackend::cleanupOutput(const EglGbmOutput &o) { o.output->releaseGbm(); @@ -142,8 +142,8 @@ } const auto outputs = m_backend->outputs(); - for (DrmOutput *drmOutput: outputs) { - createOutput(drmOutput); + for (Output *drmOutput: outputs) { + createOutput(qobject_cast(drmOutput)); } if (m_outputs.isEmpty()) { qCCritical(KWIN_DRM) << "Create Window Surfaces failed"; @@ -165,7 +165,7 @@ m_remoteaccessManager.reset(new RemoteAccessManager); } -bool EglGbmBackend::resetOutput(Output &o, DrmOutput *drmOutput) +bool EglGbmBackend::resetOutput(EglGbmOutput &o, DrmOutput *drmOutput) { o.output = drmOutput; auto size = drmOutput->pixelSize(); @@ -196,7 +196,7 @@ void EglGbmBackend::createOutput(DrmOutput *drmOutput) { - Output o; + EglGbmOutput o; if (resetOutput(o, drmOutput)) { connect(drmOutput, &DrmOutput::modeChanged, this, [drmOutput, this] { @@ -215,7 +215,7 @@ } } -bool EglGbmBackend::makeContextCurrent(const Output &output) +bool EglGbmBackend::makeContextCurrent(const EglGbmOutput &output) { const EGLSurface surface = output.eglSurface; if (surface == EGL_NO_SURFACE) { @@ -258,17 +258,41 @@ EGLint count; EGLConfig configs[1024]; - if (eglChooseConfig(eglDisplay(), config_attribs, configs, 1, &count) == EGL_FALSE) { + if (!eglChooseConfig(eglDisplay(), config_attribs, configs, sizeof(configs)/sizeof(EGLConfig), &count)) { qCCritical(KWIN_DRM) << "choose config failed"; return false; } - if (count != 1) { - qCCritical(KWIN_DRM) << "choose config did not return a config" << count; - return false; + + qCDebug(KWIN_DRM) << "EGL buffer configs count:" << count; + + // loop through all configs, chosing the first one that has suitable format + for (EGLint i = 0; i < count; i++) { + EGLint gbmFormat; + // query some configuration parameters, to show in debug log + eglGetConfigAttrib(eglDisplay(), configs[i], EGL_NATIVE_VISUAL_ID, &gbmFormat); + + if (KWIN_DRM().isDebugEnabled()) { + // GBM formats are declared as FOURCC code (integer from ASCII chars, so use this fact) + char gbmFormatStr[sizeof(EGLint) + 1] = {0}; + memcpy(gbmFormatStr, &gbmFormat, sizeof(EGLint)); + // query number of bits for color channel + EGLint blueSize, redSize, greenSize, alphaSize; + eglGetConfigAttrib(eglDisplay(), configs[i], EGL_RED_SIZE, &redSize); + eglGetConfigAttrib(eglDisplay(), configs[i], EGL_GREEN_SIZE, &greenSize); + eglGetConfigAttrib(eglDisplay(), configs[i], EGL_BLUE_SIZE, &blueSize); + eglGetConfigAttrib(eglDisplay(), configs[i], EGL_ALPHA_SIZE, &alphaSize); + qCDebug(KWIN_DRM) << " EGL config #" << i << " has GBM FOURCC format:" << gbmFormatStr + << "; color sizes (RGBA order):" << redSize << greenSize << blueSize << alphaSize; + } + + if ((gbmFormat == GBM_FORMAT_XRGB8888) || (gbmFormat == GBM_FORMAT_ARGB8888)) { + setConfig(configs[i]); + return true; + } } - setConfig(configs[0]); - return true; + qCCritical(KWIN_DRM) << "choose EGL config did not return a suitable config" << count; + return false; } void EglGbmBackend::present() @@ -279,7 +303,7 @@ } } -void EglGbmBackend::presentOnOutput(EglGbmBackend::Output &o) +void EglGbmBackend::presentOnOutput(EglGbmBackend::EglGbmOutput &o) { eglSwapBuffers(eglDisplay(), o.eglSurface); o.buffer = m_backend->createBuffer(o.gbmSurface); @@ -315,7 +339,7 @@ QRegion EglGbmBackend::prepareRenderingForScreen(int screenId) { - const Output &o = m_outputs.at(screenId); + const EglGbmOutput &o = m_outputs.at(screenId); makeContextCurrent(o); if (supportsBufferAge()) { QRegion region; @@ -341,7 +365,7 @@ void EglGbmBackend::endRenderingFrameForScreen(int screenId, const QRegion &renderedRegion, const QRegion &damagedRegion) { - Output &o = m_outputs[screenId]; + EglGbmOutput &o = m_outputs[screenId]; if (damagedRegion.intersected(o.output->geometry()).isEmpty() && screenId == 0) { // If the damaged region of a window is fully occluded, the only diff --git a/plugins/platforms/drm/scene_qpainter_drm_backend.h b/plugins/platforms/drm/scene_qpainter_drm_backend.h --- a/plugins/platforms/drm/scene_qpainter_drm_backend.h +++ b/plugins/platforms/drm/scene_qpainter_drm_backend.h @@ -47,12 +47,12 @@ private: void initOutput(DrmOutput *output); - struct Output { + struct QPainterOutput { DrmDumbBuffer *buffer[2]; DrmOutput *output; int index = 0; }; - QVector m_outputs; + QVector m_outputs; DrmBackend *m_backend; }; } diff --git a/plugins/platforms/drm/scene_qpainter_drm_backend.cpp b/plugins/platforms/drm/scene_qpainter_drm_backend.cpp --- a/plugins/platforms/drm/scene_qpainter_drm_backend.cpp +++ b/plugins/platforms/drm/scene_qpainter_drm_backend.cpp @@ -32,13 +32,13 @@ { const auto outputs = m_backend->outputs(); for (auto output: outputs) { - initOutput(output); + initOutput(qobject_cast(output)); } connect(m_backend, &DrmBackend::outputAdded, this, &DrmQPainterBackend::initOutput); connect(m_backend, &DrmBackend::outputRemoved, this, [this] (DrmOutput *o) { auto it = std::find_if(m_outputs.begin(), m_outputs.end(), - [o] (const Output &output) { + [o] (const QPainterOutput &output) { return output.output == o; } ); @@ -62,7 +62,7 @@ void DrmQPainterBackend::initOutput(DrmOutput *output) { - Output o; + QPainterOutput o; auto initBuffer = [&o, output, this] (int index) { o.buffer[index] = m_backend->createBuffer(output->pixelSize()); o.buffer[index]->map(); @@ -102,7 +102,7 @@ QImage *DrmQPainterBackend::bufferForScreen(int screenId) { - const Output &o = m_outputs.at(screenId); + const QPainterOutput &o = m_outputs.at(screenId); return o.buffer[o.index]->image(); } @@ -126,7 +126,7 @@ return; } for (auto it = m_outputs.begin(); it != m_outputs.end(); ++it) { - const Output &o = *it; + const QPainterOutput &o = *it; m_backend->present(o.buffer[o.index], o.output); } } diff --git a/plugins/platforms/drm/screens_drm.cpp b/plugins/platforms/drm/screens_drm.cpp --- a/plugins/platforms/drm/screens_drm.cpp +++ b/plugins/platforms/drm/screens_drm.cpp @@ -79,7 +79,8 @@ int minDistance = INT_MAX; const auto outputs = m_backend->enabledOutputs(); for (int i = 0; i < outputs.size(); ++i) { - const QRect &geo = outputs.at(i)->geometry(); + auto o = qobject_cast(outputs.at(i)); + const QRect &geo = o->geometry(); if (geo.contains(pos)) { return i; } @@ -110,16 +111,18 @@ if (screen >= outputs.size()) { return Screens::refreshRate(screen); } - return outputs.at(screen)->currentRefreshRate() / 1000.0f; + auto *o = qobject_cast(outputs.at(screen)); + return o->currentRefreshRate() / 1000.0f; } QSizeF DrmScreens::physicalSize(int screen) const { const auto outputs = m_backend->enabledOutputs(); if (screen >= outputs.size()) { return Screens::physicalSize(screen); } - return outputs.at(screen)->physicalSize(); + auto *o = qobject_cast(outputs.at(screen)); + return o->physicalSize(); } bool DrmScreens::isInternal(int screen) const @@ -137,16 +140,18 @@ if (screen >= outputs.size()) { return false; } - return outputs.at(screen)->supportsTransformations(); + auto *o = qobject_cast(outputs.at(screen)); + return o->supportsTransformations(); } Qt::ScreenOrientation DrmScreens::orientation(int screen) const { const auto outputs = m_backend->outputs(); if (screen >= outputs.size()) { return Qt::PrimaryOrientation; } - return outputs.at(screen)->orientation(); + auto *o = qobject_cast(outputs.at(screen)); + return o->orientation(); } } diff --git a/plugins/platforms/virtual/virtual_output.h b/plugins/platforms/virtual/virtual_output.h --- a/plugins/platforms/virtual/virtual_output.h +++ b/plugins/platforms/virtual/virtual_output.h @@ -33,14 +33,14 @@ public: VirtualOutput(QObject *parent = nullptr); - VirtualOutput(const VirtualOutput &o); virtual ~VirtualOutput(); QRect geometry() const { return m_geo; } private: + Q_DISABLE_COPY(VirtualOutput); friend class VirtualBackend; QRect m_geo; diff --git a/plugins/platforms/virtual/virtual_output.cpp b/plugins/platforms/virtual/virtual_output.cpp --- a/plugins/platforms/virtual/virtual_output.cpp +++ b/plugins/platforms/virtual/virtual_output.cpp @@ -27,14 +27,6 @@ { } -VirtualOutput::VirtualOutput(const VirtualOutput &o) - : m_geo(o.m_geo), - m_outputScale(o.m_outputScale), - m_gammaSize(o.m_gammaSize), - m_gammaResult(o.m_gammaResult) -{ -} - VirtualOutput::~VirtualOutput() { } diff --git a/plugins/qpa/abstractplatformcontext.cpp b/plugins/qpa/abstractplatformcontext.cpp --- a/plugins/qpa/abstractplatformcontext.cpp +++ b/plugins/qpa/abstractplatformcontext.cpp @@ -146,21 +146,48 @@ const QList extensions = eglExtensions.split(' '); const bool haveRobustness = extensions.contains(QByteArrayLiteral("EGL_EXT_create_context_robustness")); const bool haveCreateContext = extensions.contains(QByteArrayLiteral("EGL_KHR_create_context")); + const bool haveContextPriority = extensions.contains(QByteArrayLiteral("EGL_IMG_context_priority")); std::vector> candidates; if (isOpenGLES()) { + if (haveCreateContext && haveRobustness && haveContextPriority) { + auto glesRobustPriority = std::unique_ptr(new EglOpenGLESContextAttributeBuilder); + glesRobustPriority->setVersion(2); + glesRobustPriority->setRobust(true); + glesRobustPriority->setHighPriority(true); + candidates.push_back(std::move(glesRobustPriority)); + } if (haveCreateContext && haveRobustness) { auto glesRobust = std::unique_ptr(new EglOpenGLESContextAttributeBuilder); glesRobust->setVersion(2); glesRobust->setRobust(true); candidates.push_back(std::move(glesRobust)); } + if (haveContextPriority) { + auto glesPriority = std::unique_ptr(new EglOpenGLESContextAttributeBuilder); + glesPriority->setVersion(2); + glesPriority->setHighPriority(true); + candidates.push_back(std::move(glesPriority)); + } auto gles = std::unique_ptr(new EglOpenGLESContextAttributeBuilder); gles->setVersion(2); candidates.push_back(std::move(gles)); } else { // Try to create a 3.1 core context if (m_format.majorVersion() >= 3 && haveCreateContext) { + if (haveRobustness && haveContextPriority) { + auto robustCorePriority = std::unique_ptr(new EglContextAttributeBuilder); + robustCorePriority->setVersion(m_format.majorVersion(), m_format.minorVersion()); + robustCorePriority->setRobust(true); + robustCorePriority->setForwardCompatible(true); + if (m_format.profile() == QSurfaceFormat::CoreProfile) { + robustCorePriority->setCoreProfile(true); + } else if (m_format.profile() == QSurfaceFormat::CompatibilityProfile) { + robustCorePriority->setCompatibilityProfile(true); + } + robustCorePriority->setHighPriority(true); + candidates.push_back(std::move(robustCorePriority)); + } if (haveRobustness) { auto robustCore = std::unique_ptr(new EglContextAttributeBuilder); robustCore->setVersion(m_format.majorVersion(), m_format.minorVersion()); @@ -173,6 +200,18 @@ } candidates.push_back(std::move(robustCore)); } + if (haveContextPriority) { + auto corePriority = std::unique_ptr(new EglContextAttributeBuilder); + corePriority->setVersion(m_format.majorVersion(), m_format.minorVersion()); + corePriority->setForwardCompatible(true); + if (m_format.profile() == QSurfaceFormat::CoreProfile) { + corePriority->setCoreProfile(true); + } else if (m_format.profile() == QSurfaceFormat::CompatibilityProfile) { + corePriority->setCompatibilityProfile(true); + } + corePriority->setHighPriority(true); + candidates.push_back(std::move(corePriority)); + } auto core = std::unique_ptr(new EglContextAttributeBuilder); core->setVersion(m_format.majorVersion(), m_format.minorVersion()); core->setForwardCompatible(true); @@ -183,7 +222,12 @@ } candidates.push_back(std::move(core)); } - + if (haveRobustness && haveCreateContext && haveContextPriority) { + auto robustPriority = std::unique_ptr(new EglContextAttributeBuilder); + robustPriority->setRobust(true); + robustPriority->setHighPriority(true); + candidates.push_back(std::move(robustPriority)); + } if (haveRobustness && haveCreateContext) { auto robust = std::unique_ptr(new EglContextAttributeBuilder); robust->setRobust(true); diff --git a/scripts/minimizeall/metadata.desktop b/scripts/minimizeall/metadata.desktop --- a/scripts/minimizeall/metadata.desktop +++ b/scripts/minimizeall/metadata.desktop @@ -42,6 +42,7 @@ Comment=Adds a shortcut to minimize and restore all windows Comment[ca]=Afegeix una drecera per a minimitzar i restaurar totes les finestres Comment[ca@valencia]=Afig una drecera per a minimitzar i restaurar totes les finestres +Comment[cs]=Přidá zkratku k minimalizaci a obnovení všech oken. Comment[da]=Tilføjer en genvej til at minimere og gendanne alle vinduer Comment[de]=Fügt einen Kurzbefehl hinzu, um alle Fenster zu minimieren oder wieder anzuzeigen Comment[en_GB]=Adds a shortcut to minimise and restore all windows diff --git a/udev.h b/udev.h --- a/udev.h +++ b/udev.h @@ -82,6 +82,7 @@ return m_udev != nullptr; } UdevDevice::Ptr primaryGpu(); + UdevDevice::Ptr primaryFramebuffer(); UdevDevice::Ptr virtualGpu(); UdevDevice::Ptr renderNode(); UdevDevice::Ptr deviceFromSyspath(const char *syspath); diff --git a/udev.cpp b/udev.cpp --- a/udev.cpp +++ b/udev.cpp @@ -18,6 +18,7 @@ along with this program. If not, see . *********************************************************************/ #include "udev.h" +#include "logind.h" // Qt #include #include @@ -106,6 +107,7 @@ if (m_enumerate.isNull()) { return UdevDevice::Ptr(); } + QString defaultSeat = QStringLiteral("seat0"); udev_list_entry *it = udev_enumerate_get_list_entry(m_enumerate.data()); UdevDevice::Ptr firstFound; while (it) { @@ -115,6 +117,13 @@ if (!device) { continue; } + QString deviceSeat = device->property("ID_SEAT"); + if (deviceSeat.isEmpty()) { + deviceSeat = defaultSeat; + } + if (deviceSeat != LogindIntegration::self()->seat()) { + continue; + } if (test(device)) { return device; } @@ -135,7 +144,6 @@ enumerate.addMatch(UdevEnumerate::Match::SysName, "card[0-9]*"); enumerate.scan(); return enumerate.find([](const UdevDevice::Ptr &device) { - // TODO: check seat auto pci = device->getParentWithSubsystemDevType("pci"); if (!pci) { return false; @@ -178,6 +186,28 @@ }); } +UdevDevice::Ptr Udev::primaryFramebuffer() +{ + if (!m_udev) { + return UdevDevice::Ptr(); + } + UdevEnumerate enumerate(this); + enumerate.addMatch(UdevEnumerate::Match::SubSystem, "graphics"); + enumerate.addMatch(UdevEnumerate::Match::SysName, "fb[0-9]*"); + enumerate.scan(); + return enumerate.find([](const UdevDevice::Ptr &device) { + auto pci = device->getParentWithSubsystemDevType("pci"); + if (!pci) { + return false; + } + const char *systAttrValue = udev_device_get_sysattr_value(pci, "boot_vga"); + if (systAttrValue && qstrcmp(systAttrValue, "1") == 0) { + return true; + } + return false; + }); +} + UdevDevice::Ptr Udev::deviceFromSyspath(const char *syspath) { return UdevDevice::Ptr(new UdevDevice(udev_device_new_from_syspath(m_udev, syspath))); diff --git a/workspace.cpp b/workspace.cpp --- a/workspace.cpp +++ b/workspace.cpp @@ -393,6 +393,7 @@ // load again to sync to RootInfo, see BUG 385260 vds->load(); vds->updateRootInfo(); + rootInfo->setCurrentDesktop(vds->currentDesktop()->x11DesktopNumber()); // TODO: only in X11 mode // Extra NETRootInfo instance in Client mode is needed to get the values of the properties