diffstat for libkscreen-5.4.2 libkscreen-5.12.0 .arcconfig | 4 .mailmap | 1 .reviewboardrc | 3 CMakeLists.txt | 27 - autotests/CMakeLists.txt | 33 + autotests/configs/default.json | 27 - autotests/configs/multipleoutput.json | 1 autotests/testbackendloader.cpp | 109 +++++ autotests/testconfigmonitor.cpp | 41 +- autotests/testconfigserializer.cpp | 2 autotests/testinprocess.cpp | 317 +++++++++++++++ autotests/testkwaylandbackend.cpp | 316 +++++++++++++++ autotests/testkwaylandconfig.cpp | 271 +++++++++++++ autotests/testkwaylanddpms.cpp | 126 ++++++ autotests/testlog.cpp | 140 ++++++ autotests/testmodelistchange.cpp | 179 ++++++++ autotests/testqscreenbackend.cpp | 40 + autotests/testscreenconfig.cpp | 132 +++++- autotests/testxrandr.cpp | 2 backends/CMakeLists.txt | 11 backends/fake/fake.cpp | 29 + backends/fake/fake.h | 15 backends/fake/parser.cpp | 16 backends/kwayland/CMakeLists.txt | 19 backends/kwayland/README.md | 49 ++ backends/kwayland/waylandbackend.cpp | 96 ++++ backends/kwayland/waylandbackend.h | 61 ++ backends/kwayland/waylandconfig.cpp | 346 ++++++++++++++++ backends/kwayland/waylandconfig.h | 120 +++++ backends/kwayland/waylandoutput.cpp | 195 +++++++++ backends/kwayland/waylandoutput.h | 90 ++++ backends/kwayland/waylandscreen.cpp | 65 +++ backends/kwayland/waylandscreen.h | 56 ++ backends/qscreen/qscreenbackend.cpp | 4 backends/qscreen/qscreenbackend.h | 10 backends/qscreen/qscreenconfig.cpp | 5 backends/qscreen/qscreenconfig.h | 2 backends/utils.cpp | 70 +++ backends/utils.h | 30 + backends/xcbeventlistener.cpp | 4 backends/xcbwrapper.cpp | 2 backends/xrandr/CMakeLists.txt | 1 backends/xrandr/xrandr.cpp | 12 backends/xrandr/xrandr.h | 12 backends/xrandr/xrandrconfig.cpp | 29 - backends/xrandr/xrandrcrtc.cpp | 4 backends/xrandr/xrandroutput.cpp | 81 --- backends/xrandr/xrandroutput.h | 1 backends/xrandr/xrandrscreen.cpp | 4 backends/xrandr1.1/xrandr11.cpp | 4 backends/xrandr1.1/xrandr11.h | 10 debian/changelog | 368 +++++++++++++++++ debian/control | 21 - debian/kscreen-doctor.install | 1 debian/libkf5screen6.install | 4 debian/libkf5screen6.symbols | 333 ---------------- debian/libkf5screen7.install | 5 debian/libkf5screen7.symbols | 339 ++++++++++++++++ debian/meta/upstream_scm.json | 4 debian/tests/control | 11 debian/tests/testsuite | 3 debian/upstream/signing-key.asc | 118 +++++ debian/watch | 5 interfaces/org.kde.KScreen.Backend.xml | 1 interfaces/org.kde.KScreen.xml | 16 src/CMakeLists.txt | 6 src/abstractbackend.cpp | 5 src/abstractbackend.h | 10 src/backendlauncher/CMakeLists.txt | 19 src/backendlauncher/backenddbuswrapper.cpp | 16 src/backendlauncher/backenddbuswrapper.h | 4 src/backendlauncher/backendloader.cpp | 131 +++--- src/backendlauncher/backendloader.h | 32 - src/backendlauncher/main.cpp | 60 -- src/backendlauncher/org.kde.kscreen.service.cmake | 3 src/backendmanager.cpp | 447 +++++++++++++-------- src/backendmanager_p.h | 87 +++- src/config-libkscreen.h.cmake | 2 src/config.cpp | 47 +- src/config.h | 38 + src/configmonitor.cpp | 31 + src/configmonitor.h | 6 src/configoperation.cpp | 20 src/configoperation.h | 12 src/configoperation_p.h | 5 src/configserializer.cpp | 13 src/debug_p.cpp | 8 src/doctor/CMakeLists.txt | 4 src/doctor/doctor.cpp | 450 ++++++++++++++++++++++ src/doctor/doctor.h | 76 +++ src/doctor/dpmsclient.cpp | 157 +++++++ src/doctor/dpmsclient.h | 77 +++ src/doctor/main.cpp | 111 +++++ src/edid.h | 4 src/getconfigoperation.cpp | 51 ++ src/getconfigoperation.h | 13 src/log.cpp | 138 ++++++ src/log.h | 117 +++++ src/mode.cpp | 5 src/output.cpp | 83 +++- src/output.h | 30 + src/screen.h | 32 + src/setconfigoperation.cpp | 48 ++ src/setconfigoperation.h | 6 tests/CMakeLists.txt | 2 tests/kwayland/CMakeLists.txt | 6 tests/kwayland/main.cpp | 44 ++ tests/kwayland/waylandconfigreader.cpp | 253 ++++++++++++ tests/kwayland/waylandconfigreader.h | 51 ++ tests/kwayland/waylandtestserver.cpp | 179 ++++++++ tests/kwayland/waylandtestserver.h | 83 ++++ 111 files changed, 6516 insertions(+), 959 deletions(-) diff -Nru libkscreen-5.4.2/.arcconfig libkscreen-5.12.0/.arcconfig --- libkscreen-5.4.2/.arcconfig 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/.arcconfig 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,4 @@ +{ + "phabricator.uri" : "https://phabricator.kde.org/" +} + diff -Nru libkscreen-5.4.2/.mailmap libkscreen-5.12.0/.mailmap --- libkscreen-5.4.2/.mailmap 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/.mailmap 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1 @@ +Sebastian Kügler diff -Nru libkscreen-5.4.2/.reviewboardrc libkscreen-5.12.0/.reviewboardrc --- libkscreen-5.4.2/.reviewboardrc 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/.reviewboardrc 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -REVIEWBOARD_URL = "https://git.reviewboard.kde.org" -REPOSITORY = 'git://anongit.kde.org/libkscreen' -TARGET_GROUPS = 'solid' diff -Nru libkscreen-5.4.2/CMakeLists.txt libkscreen-5.12.0/CMakeLists.txt --- libkscreen-5.4.2/CMakeLists.txt 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/CMakeLists.txt 2018-02-01 13:45:54.000000000 +0000 @@ -1,34 +1,43 @@ -project(libkscreen) -set(PROJECT_VERSION "5.4.2") - cmake_minimum_required(VERSION 2.8.12) -find_package(ECM 1.3.0 REQUIRED NO_MODULE) +project(libkscreen) +set(PROJECT_VERSION "5.12.0") + +find_package(ECM 5.14.0 REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) include(KDEInstallDirs) -include(KDECompilerSettings) +include(KDECompilerSettings NO_POLICY_SCOPE) include(KDECMakeSettings) include(ECMSetupVersion) include(ECMPackageConfigHelpers) include(ECMMarkAsTest) include(ECMGenerateHeaders) +include(ECMQtDeclareLoggingCategory) include(FeatureSummary) include(CheckCXXCompilerFlag) -set(REQUIRED_QT_VERSION 5.2.0) +set(REQUIRED_QT_VERSION 5.4.0) find_package(Qt5 ${REQUIRED_QT_VERSION} CONFIG REQUIRED Core DBus Gui Test X11Extras) +# Wayland backend +find_package(KF5Wayland CONFIG REQUIRED) +add_feature_info("KF5Wayland" KF5Wayland_FOUND "Required for building libkscreen's KWayland backend") + +# xrandr backend + find_package(XCB COMPONENTS XCB RANDR) set_package_properties(XCB PROPERTIES - TYPE REQUIRED + TYPE OPTIONAL PURPOSE "Required for building XRandR backends" ) +# library setup + set(KF5_VERSION ${PROJECT_VERSION}) #When we are happy with the api, we can sync with frameworks ecm_setup_version(${KF5_VERSION} VARIABLE_PREFIX KSCREEN VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kscreen_version.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5ScreenConfigVersion.cmake" - SOVERSION 6) + SOVERSION 7) check_cxx_compiler_flag(-fvisibility=hidden _HAVE_VISIBILITY) if (_HAVE_VISIBILITY AND NOT WIN32) @@ -40,8 +49,6 @@ endif (_HAVE_VISIBILITY_INLINES) endif (_HAVE_VISIBILITY AND NOT WIN32) -# include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}) - add_subdirectory(src) add_subdirectory(backends) add_subdirectory(autotests) diff -Nru libkscreen-5.4.2/autotests/CMakeLists.txt libkscreen-5.12.0/autotests/CMakeLists.txt --- libkscreen-5.4.2/autotests/CMakeLists.txt 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/autotests/CMakeLists.txt 2018-02-01 13:45:54.000000000 +0000 @@ -1,14 +1,16 @@ add_definitions(-DTEST_DATA="${CMAKE_CURRENT_SOURCE_DIR}/configs/") -include_directories(${CMAKE_CURRENT_BINARY_DIR}) +include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}/tests/kwayland/) macro(KSCREEN_ADD_TEST) foreach(_testname ${ARGN}) - set(test_SRCS ${_testname}.cpp) + set(test_SRCS ${_testname}.cpp ${KSCREEN_WAYLAND_SRCS}) qt5_add_dbus_interface(test_SRCS ${CMAKE_SOURCE_DIR}/interfaces/org.kde.KScreen.FakeBackend.xml fakebackendinterface) add_executable(${_testname} ${test_SRCS}) - target_link_libraries(${_testname} Qt5::Core Qt5::Gui Qt5::Test Qt5::DBus KF5::Screen) - add_test(kscreen-${_testname} ${_testname}) + target_link_libraries(${_testname} Qt5::Core Qt5::Gui Qt5::Test Qt5::DBus KF5::Screen ${KSCREEN_WAYLAND_LIBS}) + add_test(NAME kscreen-${_testname} + COMMAND dbus-launch $ + ) ecm_mark_as_test(${_testname}) endforeach(_testname) endmacro(KSCREEN_ADD_TEST) @@ -17,6 +19,29 @@ kscreen_add_test(testqscreenbackend) kscreen_add_test(testconfigserializer) kscreen_add_test(testconfigmonitor) +kscreen_add_test(testinprocess) +kscreen_add_test(testbackendloader) +kscreen_add_test(testlog) +kscreen_add_test(testmodelistchange) + +set(KSCREEN_WAYLAND_LIBS + KF5::WaylandServer KF5::WaylandClient +) + +# For WaylandConfigReader and TestServer +set(KSCREEN_WAYLAND_SRCS + ${CMAKE_SOURCE_DIR}/tests/kwayland/waylandconfigreader.cpp + ${CMAKE_SOURCE_DIR}/tests/kwayland/waylandtestserver.cpp +) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../backends/kwayland) + +kscreen_add_test(testkwaylandbackend) +kscreen_add_test(testkwaylandconfig) +kscreen_add_test(testkwaylanddpms) + +set(KSCREEN_WAYLAND_LIBS "") +set(KSCREEN_WAYLAND_SRCS "") + if (ENABLE_XRANDR_TESTS) kscreen_add_test(textxrandr) diff -Nru libkscreen-5.4.2/autotests/configs/default.json libkscreen-5.12.0/autotests/configs/default.json --- libkscreen-5.4.2/autotests/configs/default.json 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/autotests/configs/default.json 2018-02-01 13:45:54.000000000 +0000 @@ -6,6 +6,8 @@ "connected": true, "currentModeId": "73", "enabled": false, + "manufacturer": "Butterfly Visuals", + "model": "smaragd", "icon": "", "id": 66, "modes": [ @@ -99,6 +101,8 @@ "type": 7 }, { + "manufacturer": "Octopus Graphics", + "model": "rubyled", "clones": [ ], "connected": true, @@ -323,6 +327,8 @@ "type": 0 }, { + "manufacturer": "Gänseei", + "model": "Dotterfleck", "clones": [ ], "connected": false, @@ -342,12 +348,14 @@ "primary": false, "rotation": 1, "sizeMM": { - "height": 0, - "width": 0 + "height": 300, + "width": 200 }, "type": 0 }, { + "manufacturer": "Anarchy Electronics", + "model": "Che", "clones": [ ], "connected": false, @@ -367,12 +375,14 @@ "primary": false, "rotation": 1, "sizeMM": { - "height": 0, - "width": 0 + "height": 300, + "width": 200 }, "type": 0 }, { + "manufacturer": "Bonsai", + "model": "marina", "clones": [ 71 ], @@ -616,6 +626,8 @@ "type": 0 }, { + "manufacturer": "Tuna Pictures", + "model": "52-1337LED", "clones": [ ], "connected": false, @@ -635,10 +647,11 @@ "primary": false, "rotation": 1, "sizeMM": { - "height": 0, - "width": 0 + "height": 400, + "width": 230 }, - "type": 0 + "type": 0, + "edid" : "AP///////wAQrBbwTExLQQ4WAQOANCB46h7Frk80sSYOUFSlSwCBgKlA0QBxTwEBAQEBAQEBKDyAoHCwI0AwIDYABkQhAAAaAAAA/wBGNTI1TTI0NUFLTEwKAAAA/ABERUxMIFUyNDEwCiAgAAAA/QA4TB5REQAKICAgICAgAToCAynxUJAFBAMCBxYBHxITFCAVEQYjCQcHZwMMABAAOC2DAQAA4wUDAQI6gBhxOC1AWCxFAAZEIQAAHgEdgBhxHBYgWCwlAAZEIQAAngEdAHJR0B4gbihVAAZEIQAAHowK0Iog4C0QED6WAAZEIQAAGAAAAAAAAAAAAAAAAAAAPg==" } ], "screen": { diff -Nru libkscreen-5.4.2/autotests/configs/multipleoutput.json libkscreen-5.12.0/autotests/configs/multipleoutput.json --- libkscreen-5.4.2/autotests/configs/multipleoutput.json 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/autotests/configs/multipleoutput.json 2018-02-01 13:45:54.000000000 +0000 @@ -119,6 +119,7 @@ "width" : 1920, "height" : 1080 }, + "scale" : 1.4, "currentModeId" : 4, "preferredModes" : [4], "rotation" : 1, diff -Nru libkscreen-5.4.2/autotests/testbackendloader.cpp libkscreen-5.12.0/autotests/testbackendloader.cpp --- libkscreen-5.4.2/autotests/testbackendloader.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/autotests/testbackendloader.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,109 @@ +/************************************************************************************* + * Copyright 2016 by Sebastian Kügler * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#include +#include +#include +#include + +#include "../src/backendmanager_p.h" + +Q_LOGGING_CATEGORY(KSCREEN, "kscreen") + +using namespace KScreen; + +class TestBackendLoader : public QObject +{ + Q_OBJECT + +public: + explicit TestBackendLoader(QObject *parent = nullptr); + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + + void testPreferredBackend(); + void testEnv(); + void testEnv_data(); + void testFallback(); +}; + +TestBackendLoader::TestBackendLoader(QObject *parent) + : QObject(parent) +{ + qputenv("KSCREEN_LOGGING", "false"); + qputenv("KSCREEN_BACKEND_INPROCESS", QByteArray()); + qputenv("KSCREEN_BACKEND", QByteArray()); +} + +void TestBackendLoader::initTestCase() +{ +} + +void TestBackendLoader::cleanupTestCase() +{ + // set to original value + qputenv("KSCREEN_BACKEND", QByteArray()); +} + +void TestBackendLoader::testPreferredBackend() +{ + auto backends = BackendManager::instance()->listBackends(); + QVERIFY(!backends.isEmpty()); + auto preferred = BackendManager::instance()->preferredBackend(); + QVERIFY(preferred.exists()); + auto fake = BackendManager::instance()->preferredBackend(QStringLiteral("Fake")); + QVERIFY(fake.fileName().startsWith(QLatin1String("KSC_Fake"))); +} + +void TestBackendLoader::testEnv_data() +{ + QTest::addColumn("var"); + QTest::addColumn("backend"); + + QTest::newRow("all lower") << "kwayland" << "KSC_KWayland"; + QTest::newRow("camel case") << "KWayland" << "KSC_KWayland"; + QTest::newRow("all upper") << "KWAYLAND" << "KSC_KWayland"; + QTest::newRow("mixed") << "kwAYlaND" << "KSC_KWayland"; + + QTest::newRow("xrandr 1.1") << "xrandr11" << "KSC_XRandR11"; + QTest::newRow("qscreen") << "qscreen" << "KSC_QScreen"; + QTest::newRow("mixed") << "fake" << "KSC_Fake"; +} + +void TestBackendLoader::testEnv() +{ + // We want to be pretty liberal, so this should work + QFETCH(QString, var); + QFETCH(QString, backend); + qputenv("KSCREEN_BACKEND", var.toLocal8Bit()); + auto preferred = BackendManager::instance()->preferredBackend(); + QVERIFY(preferred.fileName().startsWith(backend)); +} + +void TestBackendLoader::testFallback() +{ + qputenv("KSCREEN_BACKEND", "nonsense"); + auto preferred = BackendManager::instance()->preferredBackend(); + QVERIFY(preferred.fileName().startsWith("KSC_QScreen")); +} + +QTEST_GUILESS_MAIN(TestBackendLoader) + +#include "testbackendloader.moc" diff -Nru libkscreen-5.4.2/autotests/testconfigmonitor.cpp libkscreen-5.12.0/autotests/testconfigmonitor.cpp --- libkscreen-5.4.2/autotests/testconfigmonitor.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/autotests/testconfigmonitor.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -21,10 +21,13 @@ #include #include +#include "../src/backendmanager_p.h" #include "../src/config.h" #include "../src/output.h" #include "../src/configmonitor.h" +#include "../src/configoperation.h" #include "../src/getconfigoperation.h" +#include "../src/setconfigoperation.h" #include "../src/backendmanager_p.h" #include @@ -40,7 +43,7 @@ KScreen::ConfigPtr getConfig() { - KScreen::GetConfigOperation *op = new KScreen::GetConfigOperation(); + auto op = new KScreen::GetConfigOperation(); if (!op->exec()) { qWarning("Failed to retrieve backend: %s", qPrintable(op->errorString())); return KScreen::ConfigPtr(); @@ -52,7 +55,10 @@ private Q_SLOTS: void initTestCase() { - setenv("KSCREEN_BACKEND", "Fake", 1); + qputenv("KSCREEN_LOGGING", "false"); + qputenv("KSCREEN_BACKEND", "Fake"); + // This particular test is only useful for out of process operation, so enforce that + qputenv("KSCREEN_BACKEND_INPROCESS", "0"); KScreen::BackendManager::instance()->shutdownBackend(); } @@ -61,36 +67,41 @@ KScreen::BackendManager::instance()->shutdownBackend(); } - void testChangeNotify() + void testChangeNotifyInProcess() { + qputenv("KSCREEN_BACKEND_INPROCESS", "1"); + KScreen::BackendManager::instance()->shutdownBackend(); + KScreen::BackendManager::instance()->setMethod(KScreen::BackendManager::InProcess); //json file for the fake backend - QByteArray path(TEST_DATA); - path.append("/singleoutput.json"); - setenv("TEST_DATA", path, 1); + qputenv("KSCREEN_BACKEND_ARGS", "TEST_DATA=" TEST_DATA "singleoutput.json"); // Prepare monitor KScreen::ConfigMonitor *monitor = KScreen::ConfigMonitor::instance(); QSignalSpy spy(monitor, SIGNAL(configurationChanged())); - // Get config and let it monitored + // Get config and monitor it for changes KScreen::ConfigPtr config = getConfig(); monitor->addConfig(config); - QSignalSpy enabledSpy(config->output(1).data(), SIGNAL(isEnabledChanged())); - + QSignalSpy enabledSpy(config->outputs().first().data(), SIGNAL(isEnabledChanged())); - auto iface = new org::kde::kscreen::FakeBackend(QLatin1String("org.kde.KScreen.Backend.Fake"), - QLatin1String("/fake"), - QDBusConnection::sessionBus()); - QVERIFY(iface->isValid()); - - iface->setEnabled(1, false).waitForFinished(); + auto output = config->outputs().first(); + output->setEnabled(false); + auto setop = new KScreen::SetConfigOperation(config); + QVERIFY(!setop->hasError()); + setop->exec(); QTRY_VERIFY(!spy.isEmpty()); QCOMPARE(spy.size(), 1); QCOMPARE(enabledSpy.size(), 1); QCOMPARE(config->output(1)->isEnabled(), false); + output->setEnabled(false); + auto setop2 = new KScreen::SetConfigOperation(config); + QVERIFY(!setop2->hasError()); + setop2->exec(); + QTRY_VERIFY(!spy.isEmpty()); + QCOMPARE(spy.size(), 2); } }; diff -Nru libkscreen-5.4.2/autotests/testconfigserializer.cpp libkscreen-5.12.0/autotests/testconfigserializer.cpp --- libkscreen-5.4.2/autotests/testconfigserializer.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/autotests/testconfigserializer.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -168,7 +168,7 @@ const QJsonArray arr = obj[QLatin1String("modes")].toArray(); QCOMPARE(arr.size(), output->modes().count()); - const QJsonObject pos = obj[QLatin1String("pos")].toObject(); + QJsonObject pos = obj[QLatin1String("pos")].toObject(); QCOMPARE(pos[QLatin1String("x")].toInt(), output->pos().x()); QCOMPARE(pos[QLatin1String("y")].toInt(), output->pos().y()); const QJsonObject size = obj[QLatin1String("size")].toObject(); diff -Nru libkscreen-5.4.2/autotests/testinprocess.cpp libkscreen-5.12.0/autotests/testinprocess.cpp --- libkscreen-5.4.2/autotests/testinprocess.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/autotests/testinprocess.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,317 @@ +/************************************************************************************* + * Copyright 2015 by Sebastian Kügler * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#include +#include +#include +#include + +#include "../src/backendmanager_p.h" +#include "../src/getconfigoperation.h" +#include "../src/setconfigoperation.h" +#include "../src/config.h" +#include "../src/configmonitor.h" +#include "../src/output.h" +#include "../src/mode.h" +#include "../src/edid.h" + +Q_LOGGING_CATEGORY(KSCREEN, "kscreen") + +using namespace KScreen; + +class TestInProcess : public QObject +{ + Q_OBJECT + +public: + explicit TestInProcess(QObject *parent = nullptr); + +private Q_SLOTS: + void init(); + void cleanup(); + + void loadConfig(); + + void testCreateJob(); + void testModeSwitching(); + void testBackendCaching(); + + void testConfigApply(); + void testConfigMonitor(); + +private: + + ConfigPtr m_config; + +}; + +TestInProcess::TestInProcess(QObject *parent) + : QObject(parent) + , m_config(nullptr) +{ +} + +void TestInProcess::init() +{ + qputenv("KSCREEN_LOGGING", "false"); + // Make sure we do everything in-process + qputenv("KSCREEN_BACKEND_INPROCESS", "1"); + // Use Fake backend with one of the json configs + qputenv("KSCREEN_BACKEND", "Fake"); + qputenv("KSCREEN_BACKEND_ARGS", "TEST_DATA=" TEST_DATA "multipleoutput.json"); + + KScreen::BackendManager::instance()->shutdownBackend(); +} + +void TestInProcess::cleanup() +{ + KScreen::BackendManager::instance()->shutdownBackend(); +} + +void TestInProcess::loadConfig() +{ + qputenv("KSCREEN_BACKEND_INPROCESS", "1"); + BackendManager::instance()->setMethod(BackendManager::InProcess); + + auto *op = new GetConfigOperation(); + QVERIFY(op->exec()); + m_config = op->config(); + QVERIFY(m_config); + QVERIFY(m_config->isValid()); +} + +void TestInProcess::testModeSwitching() +{ + KScreen::BackendManager::instance()->shutdownBackend(); + BackendManager::instance()->setMethod(BackendManager::InProcess); + // Load QScreen backend in-process + qDebug() << "TT qscreen in-process"; + qputenv("KSCREEN_BACKEND", "QScreen"); + auto op = new GetConfigOperation(); + QVERIFY(op->exec()); + auto oc = op->config(); + QVERIFY(oc != nullptr); + QVERIFY(oc->isValid()); + + qDebug() << "TT fake in-process"; + // Load the Fake backend in-process + qputenv("KSCREEN_BACKEND", "Fake"); + auto ip = new GetConfigOperation(); + QVERIFY(ip->exec()); + auto ic = ip->config(); + QVERIFY(ic != nullptr); + QVERIFY(ic->isValid()); + QVERIFY(ic->outputs().count()); + + qDebug() << "TT xrandr out-of-process"; + // Load the xrandr backend out-of-process + qputenv("KSCREEN_BACKEND", "QScreen"); + qputenv("KSCREEN_BACKEND_INPROCESS", "0"); + BackendManager::instance()->setMethod(BackendManager::OutOfProcess); + auto xp = new GetConfigOperation(); + QCOMPARE(BackendManager::instance()->method(), BackendManager::OutOfProcess); + QVERIFY(xp->exec()); + auto xc = xp->config(); + QVERIFY(xc != nullptr); + QVERIFY(xc->isValid()); + QVERIFY(xc->outputs().count()); + qDebug() << "TT fake in-process"; + + qputenv("KSCREEN_BACKEND_INPROCESS", "1"); + BackendManager::instance()->setMethod(BackendManager::InProcess); + // Load the Fake backend in-process + qputenv("KSCREEN_BACKEND", "Fake"); + auto fp = new GetConfigOperation(); + QCOMPARE(BackendManager::instance()->method(), BackendManager::InProcess); + QVERIFY(fp->exec()); + auto fc = fp->config(); + QVERIFY(fc != nullptr); + QVERIFY(fc->isValid()); + QVERIFY(fc->outputs().count()); + + QVERIFY(oc->isValid()); + QVERIFY(ic->isValid()); + QVERIFY(xc->isValid()); + QVERIFY(fc->isValid()); +} + +void TestInProcess::testBackendCaching() +{ + KScreen::BackendManager::instance()->shutdownBackend(); + qputenv("KSCREEN_BACKEND", "Fake"); + QElapsedTimer t; + BackendManager::instance()->setMethod(BackendManager::InProcess); + QCOMPARE(BackendManager::instance()->method(), BackendManager::InProcess); + int t_cold; + int t_warm; + + { + t.start(); + auto cp = new GetConfigOperation(); + cp->exec(); + auto cc = cp->config(); + t_cold = t.nsecsElapsed(); + QVERIFY(cc != nullptr); + QVERIFY(cc->isValid()); + QVERIFY(cc->outputs().count()); + } + { + //KScreen::BackendManager::instance()->shutdownBackend(); + QCOMPARE(BackendManager::instance()->method(), BackendManager::InProcess); + t.start(); + auto cp = new GetConfigOperation(); + cp->exec(); + auto cc = cp->config(); + t_warm = t.nsecsElapsed(); + QVERIFY(cc != nullptr); + QVERIFY(cc->isValid()); + QVERIFY(cc->outputs().count()); + } + { + auto cp = new GetConfigOperation(); + QCOMPARE(BackendManager::instance()->method(), BackendManager::InProcess); + cp->exec(); + auto cc = cp->config(); + QVERIFY(cc != nullptr); + QVERIFY(cc->isValid()); + QVERIFY(cc->outputs().count()); + } + // Check if all our configs are still valid after the backend is gone + KScreen::BackendManager::instance()->shutdownBackend(); + + //qputenv("KSCREEN_BACKEND", "QScreen"); + qputenv("KSCREEN_BACKEND_INPROCESS", "0"); + BackendManager::instance()->setMethod(BackendManager::OutOfProcess); + QCOMPARE(BackendManager::instance()->method(), BackendManager::OutOfProcess); + int t_x_cold; + + { + t.start(); + auto xp = new GetConfigOperation(); + xp->exec(); + t_x_cold = t.nsecsElapsed(); + auto xc = xp->config(); + QVERIFY(xc != nullptr); + } + t.start(); + auto xp = new GetConfigOperation(); + xp->exec(); + int t_x_warm = t.nsecsElapsed(); + auto xc = xp->config(); + QVERIFY(xc != nullptr); + + // Make sure in-process is faster + QVERIFY(t_cold > t_warm); + QVERIFY(t_x_cold > t_x_warm); + QVERIFY(t_x_cold > t_cold); + return; + qDebug() << "ip speedup for cached access:" << (qreal)((qreal)t_cold / (qreal)t_warm); + qDebug() << "oop speedup for cached access:" << (qreal)((qreal)t_x_cold / (qreal)t_x_warm); + qDebug() << "out-of vs. in-process speedup:" << (qreal)((qreal)t_x_warm / (qreal)t_warm); + qDebug() << "cold oop: " << ((qreal)t_x_cold / 1000000); + qDebug() << "cached oop: " << ((qreal)t_x_warm / 1000000); + qDebug() << "cold in process: " << ((qreal)t_cold / 1000000); + qDebug() << "cached in process: " << ((qreal)t_warm / 1000000); +} + +void TestInProcess::testCreateJob() +{ + KScreen::BackendManager::instance()->shutdownBackend(); + { + BackendManager::instance()->setMethod(BackendManager::InProcess); + auto op = new GetConfigOperation(); + auto _op = qobject_cast(op); + QVERIFY(_op != nullptr); + QCOMPARE(BackendManager::instance()->method(), BackendManager::InProcess); + QVERIFY(op->exec()); + auto cc = op->config(); + QVERIFY(cc != nullptr); + QVERIFY(cc->isValid()); + } + { + BackendManager::instance()->setMethod(BackendManager::OutOfProcess); + auto op = new GetConfigOperation(); + auto _op = qobject_cast(op); + QVERIFY(_op != nullptr); + QCOMPARE(BackendManager::instance()->method(), BackendManager::OutOfProcess); + QVERIFY(op->exec()); + auto cc = op->config(); + QVERIFY(cc != nullptr); + QVERIFY(cc->isValid()); + } + KScreen::BackendManager::instance()->shutdownBackend(); + BackendManager::instance()->setMethod(BackendManager::InProcess); +} + +void TestInProcess::testConfigApply() +{ + qputenv("KSCREEN_BACKEND", "Fake"); + KScreen::BackendManager::instance()->shutdownBackend(); + BackendManager::instance()->setMethod(BackendManager::InProcess); + auto op = new GetConfigOperation(); + op->exec(); + auto config = op->config(); +// qDebug() << "op:" << config->outputs().count(); + auto output = config->outputs().first(); +// qDebug() << "res:" << output->geometry(); +// qDebug() << "modes:" << output->modes(); + auto m0 = output->modes().first(); + //qDebug() << "m0:" << m0->id() << m0; + output->setCurrentModeId(m0->id()); + QVERIFY(Config::canBeApplied(config)); + + // expected to fail, SetConfigOperation is out-of-process only + auto setop = new SetConfigOperation(config); + QVERIFY(!setop->hasError()); + QVERIFY(setop->exec()); + + QVERIFY(!setop->hasError()); +} + +void TestInProcess::testConfigMonitor() +{ + qputenv("KSCREEN_BACKEND", "Fake"); + + KScreen::BackendManager::instance()->shutdownBackend(); + BackendManager::instance()->setMethod(BackendManager::InProcess); + auto op = new GetConfigOperation(); + op->exec(); + auto config = op->config(); + // qDebug() << "op:" << config->outputs().count(); + auto output = config->outputs().first(); + // qDebug() << "res:" << output->geometry(); + // qDebug() << "modes:" << output->modes(); + auto m0 = output->modes().first(); + //qDebug() << "m0:" << m0->id() << m0; + output->setCurrentModeId(m0->id()); + QVERIFY(Config::canBeApplied(config)); + + QSignalSpy monitorSpy(ConfigMonitor::instance(), &ConfigMonitor::configurationChanged); + qDebug() << "MOnitorspy connencted."; + ConfigMonitor::instance()->addConfig(config); + + auto setop = new SetConfigOperation(config); + QVERIFY(!setop->hasError()); + // do not cal setop->exec(), this must not block as the signalspy already blocks + QVERIFY(monitorSpy.wait(500)); +} + + +QTEST_GUILESS_MAIN(TestInProcess) + +#include "testinprocess.moc" diff -Nru libkscreen-5.4.2/autotests/testkwaylandbackend.cpp libkscreen-5.12.0/autotests/testkwaylandbackend.cpp --- libkscreen-5.4.2/autotests/testkwaylandbackend.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/autotests/testkwaylandbackend.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,316 @@ +/************************************************************************************* + * Copyright 2014-2015 Sebastian Kügler * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#include +#include +#include +#include + +#include "../src/backendmanager_p.h" +#include "../src/getconfigoperation.h" +#include "../src/setconfigoperation.h" +#include "../src/config.h" +#include "../src/configmonitor.h" +#include "../src/output.h" +#include "../src/mode.h" +#include "../src/edid.h" + +// KWayland +#include +#include + +#include "waylandtestserver.h" + +Q_LOGGING_CATEGORY(KSCREEN_WAYLAND, "kscreen.kwayland") + +using namespace KScreen; + +class testWaylandBackend : public QObject +{ + Q_OBJECT + +public: + explicit testWaylandBackend(QObject *parent = nullptr); + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void loadConfig(); + + void verifyConfig(); + void verifyOutputs(); + void verifyModes(); + void verifyScreen(); + void verifyIds(); + void verifyFeatures(); + void simpleWrite(); + void addOutput(); + void removeOutput(); + void testEdid(); + + +private: + ConfigPtr m_config; + WaylandTestServer *m_server; + KWayland::Server::OutputDeviceInterface *m_serverOutputDevice; +}; + +testWaylandBackend::testWaylandBackend(QObject *parent) + : QObject(parent) + , m_config(nullptr) +{ + qputenv("KSCREEN_LOGGING", "false"); + m_server = new WaylandTestServer(this); + m_server->setConfig(TEST_DATA + QStringLiteral("multipleoutput.json")); +} + +void testWaylandBackend::initTestCase() +{ + qputenv("KSCREEN_BACKEND", "kwayland"); + KScreen::BackendManager::instance()->shutdownBackend(); + // This is how KWayland will pick up the right socket, + // and thus connect to our internal test server. + setenv("WAYLAND_DISPLAY", s_socketName.toLocal8Bit(), 1); + m_server->start(); + + GetConfigOperation *op = new GetConfigOperation(); + op->exec(); + m_config = op->config(); +} + +void testWaylandBackend::loadConfig() +{ + GetConfigOperation *op = new GetConfigOperation(); + op->exec(); + m_config = op->config(); + QVERIFY(m_config->isValid()); + qCDebug(KSCREEN_WAYLAND) << "ops" << m_config->outputs(); +} + +void testWaylandBackend::verifyConfig() +{ + QVERIFY(m_config != nullptr); + if (!m_config) { + QSKIP("Wayland backend invalid", SkipAll); + } +} + +void testWaylandBackend::verifyScreen() +{ + ScreenPtr screen = m_config->screen(); + + QVERIFY(screen->minSize().width() <= screen->maxSize().width()); + QVERIFY(screen->minSize().height() <= screen->maxSize().height()); + + QVERIFY(screen->minSize().width() <= screen->currentSize().width()); + QVERIFY(screen->minSize().height() <= screen->currentSize().height()); + + QVERIFY(screen->maxSize().width() >= screen->currentSize().width()); + QVERIFY(screen->maxSize().height() >= screen->currentSize().height()); + QVERIFY(m_config->screen()->maxActiveOutputsCount() > 0); +} + +void testWaylandBackend::verifyOutputs() +{ + bool primaryFound = false; + Q_FOREACH (const KScreen::OutputPtr op, m_config->outputs()) { + if (op->isPrimary()) { + primaryFound = true; + } + } + //qCDebug(KSCREEN_WAYLAND) << "Primary found? " << primaryFound << m_config->outputs(); + QVERIFY(primaryFound); + QVERIFY(m_config->outputs().count()); + QCOMPARE(m_server->outputCount(), m_config->outputs().count()); + + KScreen::OutputPtr primary = m_config->primaryOutput(); + QVERIFY(primary->isEnabled()); + QVERIFY(primary->isConnected()); + + QList ids; + Q_FOREACH (const auto &output, m_config->outputs()) { + QVERIFY(!output->name().isEmpty()); + QVERIFY(output->id() > -1); + QVERIFY(output->isConnected()); + QVERIFY(output->geometry() != QRectF(1,1,1,1)); + QVERIFY(output->geometry() != QRectF()); + QVERIFY(output->sizeMm() != QSize()); + QVERIFY(output->edid() != 0); + QVERIFY(output->preferredModes().size() == 1); + QCOMPARE(output->rotation(), Output::None); + QVERIFY(!ids.contains(output->id())); + ids << output->id(); + } +} + +void testWaylandBackend::verifyModes() +{ + KScreen::OutputPtr primary = m_config->primaryOutput(); + QVERIFY(primary); + QVERIFY(primary->modes().count() > 0); + + Q_FOREACH (const auto &output, m_config->outputs()) { + Q_FOREACH (auto mode, output->modes()) { + QVERIFY(!mode->name().isEmpty()); + QVERIFY(mode->refreshRate() > 0); + QVERIFY(mode->size().isValid()); + } + } +} + +void testWaylandBackend::verifyIds() +{ + QList ids; + Q_FOREACH (const auto &output, m_config->outputs()) { + QVERIFY(ids.contains(output->id()) == false); + QVERIFY(output->id() > 0); + ids << output->id(); + } +} + +void testWaylandBackend::simpleWrite() +{ + KScreen::BackendManager::instance()->shutdownBackend(); + GetConfigOperation *op = new GetConfigOperation(); + op->exec(); + m_config = op->config(); + auto output = m_config->output(1); + auto n_mode = QStringLiteral("800x600@60"); + auto o_mode = output->currentModeId(); + output->setCurrentModeId(n_mode); + + auto setop = new SetConfigOperation(m_config); + QVERIFY(setop->exec()); +} + +void testWaylandBackend::cleanupTestCase() +{ + m_config->deleteLater(); + KScreen::BackendManager::instance()->shutdownBackend(); +} + +void testWaylandBackend::addOutput() +{ + KScreen::BackendManager::instance()->shutdownBackend(); + GetConfigOperation *op = new GetConfigOperation(); + op->exec(); + auto config = op->config(); + QCOMPARE(config->outputs().count(), 2); + KScreen::ConfigMonitor *monitor = KScreen::ConfigMonitor::instance(); + monitor->addConfig(config); + QSignalSpy configSpy(monitor, &KScreen::ConfigMonitor::configurationChanged); + + // Now add an outputdevice on the server side + m_serverOutputDevice = m_server->display()->createOutputDevice(this); + m_serverOutputDevice->setUuid("1337"); + + OutputDeviceInterface::Mode m0; + m0.id = 0; + m0.size = QSize(800, 600); + m0.flags = OutputDeviceInterface::ModeFlags(OutputDeviceInterface::ModeFlag::Preferred); + m_serverOutputDevice->addMode(m0); + + OutputDeviceInterface::Mode m1; + m1.id = 1; + m1.size = QSize(1024, 768); + m_serverOutputDevice->addMode(m1); + + OutputDeviceInterface::Mode m2; + m2.id = 2; + m2.size = QSize(1280, 1024); + m2.refreshRate = 90000; + m_serverOutputDevice->addMode(m2); + + m_serverOutputDevice->setCurrentMode(1); + + m_serverOutputDevice->create(); + + QVERIFY(configSpy.wait()); + //QTRY_VERIFY(configSpy.count()); + + GetConfigOperation *op2 = new GetConfigOperation(); + op2->exec(); + auto newconfig = op2->config(); + QCOMPARE(newconfig->outputs().count(), 3); +} + +void testWaylandBackend::removeOutput() +{ + KScreen::BackendManager::instance()->shutdownBackend(); + GetConfigOperation *op = new GetConfigOperation(); + op->exec(); + auto config = op->config(); + QCOMPARE(config->outputs().count(), 3); + KScreen::ConfigMonitor *monitor = KScreen::ConfigMonitor::instance(); + monitor->addConfig(config); + QSignalSpy configSpy(monitor, &KScreen::ConfigMonitor::configurationChanged); + + delete m_serverOutputDevice; + QVERIFY(configSpy.wait()); + GetConfigOperation *op2 = new GetConfigOperation(); + op2->exec(); + auto newconfig = op2->config(); + QCOMPARE(newconfig->outputs().count(), 2); +} + +void testWaylandBackend::testEdid() +{ + m_server->showOutputs(); + + QByteArray data = QByteArray::fromBase64("AP///////wAQrBbwTExLQQ4WAQOANCB46h7Frk80sSYOUFSlSwCBgKlA0QBxTwEBAQEBAQEBKDyAoHCwI0AwIDYABkQhAAAaAAAA/wBGNTI1TTI0NUFLTEwKAAAA/ABERUxMIFUyNDEwCiAgAAAA/QA4TB5REQAKICAgICAgAToCAynxUJAFBAMCBxYBHxITFCAVEQYjCQcHZwMMABAAOC2DAQAA4wUDAQI6gBhxOC1AWCxFAAZEIQAAHgEdgBhxHBYgWCwlAAZEIQAAngEdAHJR0B4gbihVAAZEIQAAHowK0Iog4C0QED6WAAZEIQAAGAAAAAAAAAAAAAAAAAAAPg=="); + + auto edid = new Edid(data); + QVERIFY(edid->isValid()); + + GetConfigOperation *op = new GetConfigOperation(); + op->exec(); + auto config = op->config(); + QVERIFY(config->outputs().count() > 0); + + auto o = config->outputs().last(); + qCDebug(KSCREEN_WAYLAND) << "Edid: " << o->edid()->isValid(); + QVERIFY(o->edid()->isValid()); + QCOMPARE(o->edid()->deviceId(), edid->deviceId()); + QCOMPARE(o->edid()->name(), edid->name()); + QCOMPARE(o->edid()->vendor(), edid->vendor()); + QCOMPARE(o->edid()->eisaId(), edid->eisaId()); + QCOMPARE(o->edid()->serial(), edid->serial()); + QCOMPARE(o->edid()->hash(), edid->hash()); + QCOMPARE(o->edid()->width(), edid->width()); + QCOMPARE(o->edid()->height(), edid->height()); + QCOMPARE(o->edid()->gamma(), edid->gamma()); + QCOMPARE(o->edid()->red(), edid->red()); + QCOMPARE(o->edid()->green(), edid->green()); + QCOMPARE(o->edid()->blue(), edid->blue()); + QCOMPARE(o->edid()->white(), edid->white()); +} + +void testWaylandBackend::verifyFeatures() +{ + GetConfigOperation *op = new GetConfigOperation(); + op->exec(); + auto config = op->config(); + QVERIFY(!config->supportedFeatures().testFlag(Config::Feature::None)); + QVERIFY(config->supportedFeatures().testFlag(Config::Feature::Writable)); + QVERIFY(!config->supportedFeatures().testFlag(Config::Feature::PrimaryDisplay)); +} + + +QTEST_GUILESS_MAIN(testWaylandBackend) + +#include "testkwaylandbackend.moc" diff -Nru libkscreen-5.4.2/autotests/testkwaylandconfig.cpp libkscreen-5.12.0/autotests/testkwaylandconfig.cpp --- libkscreen-5.4.2/autotests/testkwaylandconfig.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/autotests/testkwaylandconfig.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,271 @@ +/************************************************************************************* + * Copyright 2015 by Sebastian Kügler * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#include +#include +#include +#include + +#include "backendmanager_p.h" +#include "getconfigoperation.h" +#include "setconfigoperation.h" +#include "config.h" +#include "configmonitor.h" +#include "output.h" +#include "mode.h" +#include "edid.h" + +#include "waylandtestserver.h" + +Q_LOGGING_CATEGORY(KSCREEN_WAYLAND, "kscreen.kwayland") + +using namespace KScreen; + +class TestKWaylandConfig : public QObject +{ + Q_OBJECT + +public: + explicit TestKWaylandConfig(QObject *parent = nullptr); + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + + void changeConfig(); + void testPositionChange(); + void testRotationChange(); + void testRotationChange_data(); + void testScaleChange(); + void testModeChange(); + +private: + + WaylandTestServer *m_server; + +}; + +TestKWaylandConfig::TestKWaylandConfig(QObject *parent) + : QObject(parent) + , m_server(nullptr) +{ + qputenv("KSCREEN_LOGGING", "false"); +} + +void TestKWaylandConfig::initTestCase() +{ + setenv("KSCREEN_BACKEND", "kwayland", 1); + KScreen::BackendManager::instance()->shutdownBackend(); + + // This is how KWayland will pick up the right socket, + // and thus connect to our internal test server. + setenv("WAYLAND_DISPLAY", s_socketName.toLocal8Bit(), 1); + + m_server = new WaylandTestServer(this); + m_server->start(); +} + +void TestKWaylandConfig::cleanupTestCase() +{ + qDebug() << "Shutting down"; + KScreen::BackendManager::instance()->shutdownBackend(); + delete m_server; +} + +void TestKWaylandConfig::changeConfig() +{ + auto op = new GetConfigOperation(); + QVERIFY(op->exec()); + auto config = op->config(); + QVERIFY(config); + + // Prepare monitor & spy + KScreen::ConfigMonitor *monitor = KScreen::ConfigMonitor::instance(); + monitor->addConfig(config); + QSignalSpy configSpy(monitor, &KScreen::ConfigMonitor::configurationChanged); + + + // The first output is currently disabled, let's try to enable it + auto output = config->outputs().first(); + QVERIFY(output->isEnabled() == false); + output->setEnabled(true); + output->setCurrentModeId("76"); + + auto output2 = config->outputs()[2]; // is this id stable enough? + output2->setPos(QPoint(4000, 1080)); + output2->setRotation(KScreen::Output::Left); + + QSignalSpy serverSpy(m_server, &WaylandTestServer::configChanged); + auto sop = new SetConfigOperation(config, this); + sop->exec(); // fire and forget... + + QVERIFY(configSpy.wait()); + // check if the server changed + QCOMPARE(serverSpy.count(), 1); + + QCOMPARE(configSpy.count(), 1); + + monitor->removeConfig(config); + m_server->showOutputs(); +} + +void TestKWaylandConfig::testPositionChange() +{ + auto op = new GetConfigOperation(); + QVERIFY(op->exec()); + auto config = op->config(); + QVERIFY(config); + + // Prepare monitor & spy + KScreen::ConfigMonitor *monitor = KScreen::ConfigMonitor::instance(); + monitor->addConfig(config); + QSignalSpy configSpy(monitor, &KScreen::ConfigMonitor::configurationChanged); + + auto output = config->outputs()[2]; // is this id stable enough? + auto new_pos = QPoint(3840, 1080); + output->setPos(new_pos); + + QSignalSpy serverSpy(m_server, &WaylandTestServer::configChanged); + auto sop = new SetConfigOperation(config, this); + sop->exec(); // fire and forget... + + QVERIFY(configSpy.wait()); + // check if the server changed + QCOMPARE(serverSpy.count(), 1); + + QCOMPARE(configSpy.count(), 1); +} + +void TestKWaylandConfig::testRotationChange_data() +{ + QTest::addColumn("rotation"); + QTest::newRow("left") << KScreen::Output::Left; + QTest::newRow("inverted") << KScreen::Output::Inverted; + QTest::newRow("right") << KScreen::Output::Right; + QTest::newRow("none") << KScreen::Output::None; +} + +void TestKWaylandConfig::testRotationChange() +{ + QFETCH(KScreen::Output::Rotation, rotation); + + auto op = new GetConfigOperation(); + QVERIFY(op->exec()); + auto config = op->config(); + QVERIFY(config); + + // Prepare monitor & spy + KScreen::ConfigMonitor *monitor = KScreen::ConfigMonitor::instance(); + monitor->addConfig(config); + QSignalSpy configSpy(monitor, &KScreen::ConfigMonitor::configurationChanged); + + auto output = config->outputs().first(); // is this id stable enough? + output->setRotation(rotation); + + QSignalSpy serverSpy(m_server, &WaylandTestServer::configChanged); + auto sop = new SetConfigOperation(config, this); + sop->exec(); // fire and forget... + + QVERIFY(configSpy.wait()); + // check if the server changed + QCOMPARE(serverSpy.count(), 1); + + QCOMPARE(configSpy.count(), 1); + + // Get a new config, then compare the output with the expected new value + auto newop = new GetConfigOperation(); + QVERIFY(newop->exec()); + auto newconfig = newop->config(); + QVERIFY(newconfig); + + auto newoutput = newconfig->outputs().first(); + QCOMPARE(newoutput->rotation(), rotation); + +} + +void TestKWaylandConfig::testScaleChange() +{ + auto op = new GetConfigOperation(); + QVERIFY(op->exec()); + auto config = op->config(); + QVERIFY(config); + + auto op2 = new GetConfigOperation(); + QVERIFY(op2->exec()); + auto config2 = op2->config(); + QVERIFY(config2); + + // Prepare monitor & spy + KScreen::ConfigMonitor *monitor = KScreen::ConfigMonitor::instance(); + monitor->addConfig(config); + monitor->addConfig(config2); + QSignalSpy configSpy(monitor, &KScreen::ConfigMonitor::configurationChanged); + QSignalSpy configSpy2(monitor, &KScreen::ConfigMonitor::configurationChanged); + + auto output2 = config2->outputs()[2]; // is this id stable enough? + QSignalSpy outputSpy(output2.data(), &KScreen::Output::scaleChanged); + QCOMPARE(output2->scale(), 1.0); + + auto output = config->outputs()[2]; // is this id stable enough? + output->setScale(2); + + QSignalSpy serverSpy(m_server, &WaylandTestServer::configChanged); + auto sop = new SetConfigOperation(config, this); + sop->exec(); // fire and forget... + + QVERIFY(configSpy.wait()); + // check if the server changed + QCOMPARE(serverSpy.count(), 1); + + QCOMPARE(configSpy.count(), 1); + QCOMPARE(outputSpy.count(), 1); + QCOMPARE(configSpy2.count(), 1); + QCOMPARE(output2->scale(), 2.0); +} + +void TestKWaylandConfig::testModeChange() +{ + auto op = new GetConfigOperation(); + QVERIFY(op->exec()); + auto config = op->config(); + QVERIFY(config); + + KScreen::ConfigMonitor *monitor = KScreen::ConfigMonitor::instance(); + monitor->addConfig(config); + QSignalSpy configSpy(monitor, &KScreen::ConfigMonitor::configurationChanged); + + auto output = config->outputs()[1]; // is this id stable enough? + + QString new_mode = QStringLiteral("74"); + output->setCurrentModeId(new_mode); + + QSignalSpy serverSpy(m_server, &WaylandTestServer::configChanged); + auto sop = new SetConfigOperation(config, this); + sop->exec(); + + QVERIFY(configSpy.wait()); + // check if the server changed + QCOMPARE(serverSpy.count(), 1); + + QCOMPARE(configSpy.count(), 1); +} + + +QTEST_GUILESS_MAIN(TestKWaylandConfig) + +#include "testkwaylandconfig.moc" diff -Nru libkscreen-5.4.2/autotests/testkwaylanddpms.cpp libkscreen-5.12.0/autotests/testkwaylanddpms.cpp --- libkscreen-5.4.2/autotests/testkwaylanddpms.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/autotests/testkwaylanddpms.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,126 @@ +/************************************************************************************* + * Copyright 2016 by Sebastian Kügler * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#include +#include +#include +#include + +#include +#include +#include + +#include "waylandtestserver.h" + + +static const QString s_socketName = QStringLiteral("libkscreen-test-wayland-backend-0"); +// static const QString s_socketName = QStringLiteral("wayland-0"); + +Q_LOGGING_CATEGORY(KSCREEN, "kscreen") + +using namespace KWayland::Client; + +class TestDpmsClient : public QObject +{ + Q_OBJECT + +public: + explicit TestDpmsClient(QObject *parent = nullptr); + +Q_SIGNALS: + void dpmsAnnounced(); + + +private Q_SLOTS: + + void initTestCase(); + void cleanupTestCase(); + void testDpmsConnect(); + +private: + ConnectionThread *m_connection; + QThread *m_thread; + Registry *m_registry; + + KScreen::WaylandTestServer *m_server; +}; + +TestDpmsClient::TestDpmsClient(QObject *parent) + : QObject(parent) + , m_server(nullptr) +{ + setenv("WAYLAND_DISPLAY", s_socketName.toLocal8Bit(), 1); + m_server = new KScreen::WaylandTestServer(this); + m_server->start(); +} + +void TestDpmsClient::initTestCase() +{ + // setup connection + m_connection = new KWayland::Client::ConnectionThread; + m_connection->setSocketName(s_socketName); + QSignalSpy connectedSpy(m_connection, SIGNAL(connected())); + m_connection->setSocketName(s_socketName); + + m_thread = new QThread(this); + m_connection->moveToThread(m_thread); + m_thread->start(); + + m_connection->initConnection(); + QVERIFY(connectedSpy.wait()); + + QSignalSpy dpmsSpy(this, &TestDpmsClient::dpmsAnnounced); + + m_connection->initConnection(); + QVERIFY(connectedSpy.wait(100)); + + m_registry = new KWayland::Client::Registry; + m_registry->create(m_connection); + QObject::connect(m_registry, &Registry::interfacesAnnounced, this, + [this] { + const bool hasDpms = m_registry->hasInterface(Registry::Interface::Dpms); + if (hasDpms) { + qDebug() << QStringLiteral("Compositor provides a DpmsManager"); + } else { + qDebug() << QStringLiteral("Compositor does not provid a DpmsManager"); + } + emit this->dpmsAnnounced(); + }); + m_registry->setup(); + + QVERIFY(dpmsSpy.wait(100)); +} + +void TestDpmsClient::cleanupTestCase() +{ + m_thread->exit(); + m_thread->wait(); + delete m_registry; + delete m_thread; + delete m_connection; +} + +void TestDpmsClient::testDpmsConnect() +{ + QVERIFY(m_registry->isValid()); +} + + +QTEST_GUILESS_MAIN(TestDpmsClient) + +#include "testkwaylanddpms.moc" diff -Nru libkscreen-5.4.2/autotests/testlog.cpp libkscreen-5.12.0/autotests/testlog.cpp --- libkscreen-5.4.2/autotests/testlog.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/autotests/testlog.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,140 @@ +/************************************************************************************* + * Copyright 2016 by Sebastian Kügler * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#include +#include +#include + +#include "../src/log.h" + +Q_DECLARE_LOGGING_CATEGORY(KSCREEN_TESTLOG) + +Q_LOGGING_CATEGORY(KSCREEN_TESTLOG, "kscreen.testlog") + +using namespace KScreen; + +auto KSCREEN_LOGGING = "KSCREEN_LOGGING"; + +class TestLog : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void init(); + void initTestCase(); + void cleanupTestCase(); + void testContext(); + void testEnabled(); + void testLog(); + +private: + QString m_defaultLogFile; +}; + +void TestLog::init() +{ + QStandardPaths::setTestModeEnabled(true); + m_defaultLogFile = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/kscreen/kscreen.log"; +} + +void TestLog::initTestCase() +{ + + qputenv(KSCREEN_LOGGING, QByteArray("true")); +} + +void TestLog::cleanupTestCase() +{ + qunsetenv(KSCREEN_LOGGING); +} + +void TestLog::testContext() +{ + auto log = Log::instance(); + QString ctx("context text"); + QVERIFY(log != nullptr); + log->setContext(ctx); + QCOMPARE(log->context(), ctx); + + delete log; +} + +void TestLog::testEnabled() +{ + qputenv(KSCREEN_LOGGING, QByteArray("faLSe")); + + auto log = Log::instance(); + QCOMPARE(log->enabled(), false); + QCOMPARE(log->logFile(), QString()); + + delete log; + qunsetenv(KSCREEN_LOGGING); + + log = Log::instance(); + QCOMPARE(log->enabled(), false); + QCOMPARE(log->logFile(), QString()); + + delete log; + qputenv(KSCREEN_LOGGING, QByteArray("truE")); + + log = Log::instance(); + QCOMPARE(log->enabled(), true); + QCOMPARE(log->logFile(), m_defaultLogFile); + + delete log; +} + +void TestLog::testLog() +{ + auto log = Log::instance(); + Q_UNUSED(log); + + QFile lf(m_defaultLogFile); + lf.remove(); + QVERIFY(!lf.exists()); + + QString logmsg("This is a log message. ♥"); + Log::log(logmsg); + + QVERIFY(lf.exists()); + QVERIFY(lf.remove()); + + qCDebug(KSCREEN_TESTLOG) << "qCDebug message from testlog"; + QVERIFY(lf.exists()); + QVERIFY(lf.remove()); + + delete Log::instance(); + + // Make sure on log file gets written when disabled + qputenv(KSCREEN_LOGGING, "false"); + + qCDebug(KSCREEN_TESTLOG) << logmsg; + QCOMPARE(Log::instance()->enabled(), false); + QVERIFY(!lf.exists()); + + Log::log(logmsg); + QVERIFY(!lf.exists()); + + // Make sure we don't crash on cleanup + delete Log::instance(); + delete Log::instance(); +} + +QTEST_MAIN(TestLog) + +#include "testlog.moc" diff -Nru libkscreen-5.4.2/autotests/testmodelistchange.cpp libkscreen-5.12.0/autotests/testmodelistchange.cpp --- libkscreen-5.4.2/autotests/testmodelistchange.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/autotests/testmodelistchange.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,179 @@ +/************************************************************************************* + * Copyright 2016 by Sebastian Kügler * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#include +#include + +#include "../src/config.h" +#include "../src/configmonitor.h" +#include "../src/output.h" +#include "../src/mode.h" +#include "../src/getconfigoperation.h" +#include "../src/setconfigoperation.h" +#include "../src/backendmanager_p.h" + +using namespace KScreen; + + +class TestModeListChange : public QObject +{ + Q_OBJECT + +private: + KScreen::ConfigPtr getConfig(); + KScreen::ModeList createModeList(); + bool compareModeList(KScreen::ModeList before, KScreen::ModeList &after); + + QSize s0 = QSize(1920, 1080); + QSize s1 = QSize(1600, 1200); + QSize s2 = QSize(1280, 1024); + QSize s3 = QSize(800, 600); + QSize snew = QSize(777, 888); + QString idnew = QStringLiteral("666"); + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + + void modeListChange(); +}; + +ConfigPtr TestModeListChange::getConfig() +{ + qputenv("KSCREEN_BACKEND_INPROCESS", "1"); + auto *op = new GetConfigOperation(); + if (!op->exec()) { + qWarning("ConfigOperation error: %s", qPrintable(op->errorString())); + BackendManager::instance()->shutdownBackend(); + return ConfigPtr(); + } + + BackendManager::instance()->shutdownBackend(); + + return op->config(); +} + +KScreen::ModeList TestModeListChange::createModeList() +{ + + KScreen::ModeList newmodes; + { + QString _id = QString::number(11); + KScreen::ModePtr kscreenMode(new KScreen::Mode); + kscreenMode->setId(_id); + kscreenMode->setName(_id); + kscreenMode->setSize(s0); + kscreenMode->setRefreshRate(60); + newmodes.insert(_id, kscreenMode); + } + { + QString _id = QString::number(22); + KScreen::ModePtr kscreenMode(new KScreen::Mode); + kscreenMode->setId(_id); + kscreenMode->setName(_id); + kscreenMode->setSize(s1); + kscreenMode->setRefreshRate(60); + newmodes.insert(_id, kscreenMode); + } + { + QString _id = QString::number(33); + KScreen::ModePtr kscreenMode(new KScreen::Mode); + kscreenMode->setId(_id); + kscreenMode->setName(_id); + kscreenMode->setSize(s2); + kscreenMode->setRefreshRate(60); + newmodes.insert(_id, kscreenMode); + } + return newmodes; +} + + +void TestModeListChange::initTestCase() +{ + qputenv("KSCREEN_LOGGING", "false"); + qputenv("KSCREEN_BACKEND", "Fake"); +} + +void TestModeListChange::cleanupTestCase() +{ + BackendManager::instance()->shutdownBackend(); +} + +void TestModeListChange::modeListChange() +{ + //json file for the fake backend + qputenv("KSCREEN_BACKEND_ARGS", "TEST_DATA=" TEST_DATA "singleoutput.json"); + + const ConfigPtr config = getConfig(); + QVERIFY(!config.isNull()); + + auto output = config->outputs().first(); + QVERIFY(!output.isNull()); + auto modelist = output->modes(); + + auto mode = modelist.first(); + mode->setId(QStringLiteral("44")); + mode->setSize(QSize(880, 440)); + output->setModes(modelist); + + QCOMPARE(output->modes().first()->id(), QStringLiteral("44")); + QCOMPARE(output->modes().first()->size(), QSize(880, 440)); + QVERIFY(!modelist.isEmpty()); + + ConfigMonitor::instance()->addConfig(config); + QSignalSpy outputChangedSpy(output.data(), &Output::outputChanged); + QVERIFY(outputChangedSpy.isValid()); + QSignalSpy modesChangedSpy(output.data(), &Output::modesChanged); + QVERIFY(modesChangedSpy.isValid()); + + auto before = createModeList(); + output->setModes(before); + QCOMPARE(modesChangedSpy.count(), 1); + output->setModes(before); + QCOMPARE(modesChangedSpy.count(), 1); + output->setModes(before); + QCOMPARE(modesChangedSpy.count(), 1); + QCOMPARE(output->modes().first()->size(), s0); + QCOMPARE(output->modes().first()->id(), QStringLiteral("11")); + + auto after = createModeList(); + auto firstmode = after.first(); + QVERIFY(!firstmode.isNull()); + QCOMPARE(firstmode->size(), s0); + QCOMPARE(firstmode->id(), QStringLiteral("11")); + firstmode->setSize(snew); + firstmode->setId(idnew); + output->setModes(after); + QCOMPARE(modesChangedSpy.count(), 2); + + QString _id = QString::number(11); + KScreen::ModePtr kscreenMode(new KScreen::Mode); + kscreenMode->setId(_id); + kscreenMode->setName(_id); + kscreenMode->setSize(s0); + kscreenMode->setRefreshRate(60); + before.insert(_id, kscreenMode); + output->setModes(before); + QCOMPARE(modesChangedSpy.count(), 3); + QCOMPARE(outputChangedSpy.count(), modesChangedSpy.count()); +} + + +QTEST_MAIN(TestModeListChange) + +#include "testmodelistchange.moc" diff -Nru libkscreen-5.4.2/autotests/testqscreenbackend.cpp libkscreen-5.12.0/autotests/testqscreenbackend.cpp --- libkscreen-5.4.2/autotests/testqscreenbackend.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/autotests/testqscreenbackend.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -17,10 +17,9 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *************************************************************************************/ -#define QT_GUI_LIB - #include #include +#include #include "../src/config.h" #include "../src/output.h" @@ -29,7 +28,7 @@ #include "../src/getconfigoperation.h" #include "../src/backendmanager_p.h" -Q_LOGGING_CATEGORY(KSCREEN_QSCREEN, "kscreen.qscreen"); +Q_LOGGING_CATEGORY(KSCREEN_QSCREEN, "kscreen.qscreen") using namespace KScreen; @@ -43,6 +42,7 @@ void verifyScreen(); void verifyOutputs(); void verifyModes(); + void verifyFeatures(); void commonUsagePattern(); void cleanupTestCase(); @@ -54,15 +54,20 @@ void testQScreenBackend::initTestCase() { - setenv("KSCREEN_BACKEND", "qscreen", 1); + qputenv("KSCREEN_LOGGING", "false"); + qputenv("KSCREEN_BACKEND", "qscreen"); + qputenv("KSCREEN_BACKEND_INPROCESS", "1"); KScreen::BackendManager::instance()->shutdownBackend(); -// setenv("KSCREEN_BACKEND", "xrandr", 1); m_backend = qgetenv("KSCREEN_BACKEND").constData(); - GetConfigOperation *op = new GetConfigOperation(); + QElapsedTimer t; + t.start(); + auto *op = new GetConfigOperation(); op->exec(); m_config = op->config(); + const int n = t.nsecsElapsed(); + qDebug() << "Test took: " << n << "ns"; } void testQScreenBackend::verifyConfig() @@ -91,10 +96,8 @@ void testQScreenBackend::verifyOutputs() { - bool primaryFound = false; foreach (const KScreen::OutputPtr &op, m_config->outputs()) { - qDebug() << "CHecking at all"; if (op->isPrimary()) { primaryFound = true; } @@ -106,11 +109,10 @@ } const KScreen::OutputPtr primary = m_config->primaryOutput(); - qDebug() << "ppp" << primary; QVERIFY(primary->isEnabled()); QVERIFY(primary->isConnected()); //qDebug() << "Primary geometry? " << primary->geometry(); - qDebug() << " prim modes: " << primary->modes(); + //qDebug() << " prim modes: " << primary->modes(); QList ids; @@ -127,7 +129,12 @@ QVERIFY(output->isEnabled()); QVERIFY(output->geometry() != QRectF(1,1,1,1)); QVERIFY(output->geometry() != QRectF()); - QVERIFY(output->sizeMm() != QSize()); + + // Pass, but leave a note, when the x server doesn't report physical size + if (!output->sizeMm().isValid()) { + QEXPECT_FAIL("", "The X server doesn't return a sensible physical output size", Continue); + QVERIFY(output->sizeMm() != QSize()); + } QVERIFY(output->edid() != 0); QCOMPARE(output->rotation(), Output::None); QVERIFY(!ids.contains(output->id())); @@ -153,7 +160,7 @@ void testQScreenBackend::commonUsagePattern() { - GetConfigOperation *op = new GetConfigOperation(); + auto *op = new GetConfigOperation(); op->exec(); const KScreen::OutputList outputs = op->config()->outputs(); @@ -204,6 +211,15 @@ qApp->exit(0); } +void testQScreenBackend::verifyFeatures() +{ + GetConfigOperation *op = new GetConfigOperation(); + op->exec(); + auto config = op->config(); + QVERIFY(config->supportedFeatures().testFlag(Config::Feature::None)); + QVERIFY(!config->supportedFeatures().testFlag(Config::Feature::Writable)); + QVERIFY(!config->supportedFeatures().testFlag(Config::Feature::PrimaryDisplay)); +} QTEST_MAIN(testQScreenBackend) diff -Nru libkscreen-5.4.2/autotests/testscreenconfig.cpp libkscreen-5.12.0/autotests/testscreenconfig.cpp --- libkscreen-5.4.2/autotests/testscreenconfig.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/autotests/testscreenconfig.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -24,6 +24,7 @@ #include "../src/output.h" #include "../src/mode.h" #include "../src/getconfigoperation.h" +#include "../src/setconfigoperation.h" #include "../src/backendmanager_p.h" using namespace KScreen; @@ -42,14 +43,19 @@ void multiOutput(); void clonesOutput(); void configCanBeApplied(); + void supportedFeatures(); + void testInvalidMode(); void cleanupTestCase(); + void testOutputPositionNormalization(); }; ConfigPtr testScreenConfig::getConfig() { - GetConfigOperation *op = new GetConfigOperation(); + qputenv("KSCREEN_BACKEND_INPROCESS", "1"); + auto *op = new GetConfigOperation(); if (!op->exec()) { - qWarning("GetConfigOperation error: %s", qPrintable(op->errorString())); + qWarning("ConfigOperation error: %s", qPrintable(op->errorString())); + BackendManager::instance()->shutdownBackend(); return ConfigPtr(); } @@ -61,7 +67,8 @@ void testScreenConfig::initTestCase() { - setenv("KSCREEN_BACKEND", "Fake", 1); + qputenv("KSCREEN_LOGGING", "false"); + qputenv("KSCREEN_BACKEND", "Fake"); } void testScreenConfig::cleanupTestCase() @@ -72,9 +79,7 @@ void testScreenConfig::singleOutput() { //json file for the fake backend - QByteArray path(TEST_DATA); - path.append("/singleoutput.json"); - setenv("TEST_DATA", path, 1); + qputenv("KSCREEN_BACKEND_ARGS", "TEST_DATA=" TEST_DATA "singleoutput.json"); // QVERIFY2(kscreen, KScreen::errorString().toLatin1()); @@ -104,6 +109,7 @@ QCOMPARE(output->currentModeId(), QLatin1String("3")); QCOMPARE(output->preferredModeId(), QLatin1String("3")); QCOMPARE(output->rotation(), Output::None); + QCOMPARE(output->scale(), 1.0); QCOMPARE(output->isConnected(), true); QCOMPARE(output->isEnabled(), true); QCOMPARE(output->isPrimary(), true); @@ -117,9 +123,7 @@ void testScreenConfig::singleOutputWithoutPreferred() { - QByteArray path(TEST_DATA); - path.append("/singleOutputWithoutPreferred.json"); - setenv("TEST_DATA", path, 1); + qputenv("KSCREEN_BACKEND_ARGS", "TEST_DATA=" TEST_DATA "singleOutputWithoutPreferred.json"); const ConfigPtr config = getConfig(); QVERIFY(!config.isNull()); @@ -132,9 +136,7 @@ void testScreenConfig::multiOutput() { - QByteArray path(TEST_DATA); - path.append("/multipleoutput.json"); - setenv("TEST_DATA", path, 1); + qputenv("KSCREEN_BACKEND_ARGS", "TEST_DATA=" TEST_DATA "multipleoutput.json"); const ConfigPtr config = getConfig(); QVERIFY(!config.isNull()); @@ -154,10 +156,11 @@ QCOMPARE(output->type(), Output::HDMI); QCOMPARE(output->modes().count(), 4); QCOMPARE(output->pos(), QPoint(1280, 0)); - QCOMPARE(output->geometry(), QRect(1280, 0, 1920, 1080)); + QCOMPARE(output->geometry(), QRect(1280, 0, 1920 / 1.4, 1080 / 1.4)); QCOMPARE(output->currentModeId(), QLatin1String("4")); QCOMPARE(output->preferredModeId(), QLatin1String("4")); QCOMPARE(output->rotation(), Output::None); + QCOMPARE(output->scale(), 1.4); QCOMPARE(output->isConnected(), true); QCOMPARE(output->isEnabled(), true); QCOMPARE(output->isPrimary(), false); @@ -171,9 +174,7 @@ void testScreenConfig::clonesOutput() { - QByteArray path(TEST_DATA); - path.append("/multipleclone.json"); - setenv("TEST_DATA", path, 1); + qputenv("KSCREEN_BACKEND_ARGS", "TEST_DATA=" TEST_DATA "multipleclone.json"); const ConfigPtr config = getConfig(); QVERIFY(!config.isNull()); @@ -195,14 +196,10 @@ void testScreenConfig::configCanBeApplied() { - QByteArray path(TEST_DATA); - path.append("/singleoutputBroken.json"); - setenv("TEST_DATA", path, 1); + qputenv("KSCREEN_BACKEND_ARGS", "TEST_DATA=" TEST_DATA "singleoutputBroken.json"); const ConfigPtr brokenConfig = getConfig(); - path = TEST_DATA; - path.append("/singleoutput.json"); - setenv("TEST_DATA", path, 1); + qputenv("KSCREEN_BACKEND_ARGS", "TEST_DATA=" TEST_DATA "singleoutput.json"); const ConfigPtr currentConfig = getConfig(); QVERIFY(!currentConfig.isNull()); const OutputPtr primaryBroken = brokenConfig->outputs()[2]; @@ -219,13 +216,13 @@ QVERIFY(!Config::canBeApplied(brokenConfig)); primaryBroken->setCurrentModeId(currentPrimary->currentModeId()); QVERIFY(!Config::canBeApplied(brokenConfig)); + qDebug() << "brokenConfig.modes" << primaryBroken->mode("3"); primaryBroken->mode(QLatin1String("3"))->setSize(QSize(1280, 800)); + qDebug() << "brokenConfig.modes" << primaryBroken->mode("3"); QVERIFY(Config::canBeApplied(brokenConfig)); - path = TEST_DATA; - path.append("/tooManyOutputs.json"); - setenv("TEST_DATA", path, 1); + qputenv("KSCREEN_BACKEND_ARGS", "TEST_DATA=" TEST_DATA "tooManyOutputs.json"); const ConfigPtr brokenConfig2 = getConfig(); QVERIFY(!brokenConfig2.isNull()); @@ -237,8 +234,93 @@ } QVERIFY(brokenConfig2->screen()->maxActiveOutputsCount() < enabledOutputsCount); QVERIFY(!Config::canBeApplied(brokenConfig2)); + + const ConfigPtr nulllConfig; + QVERIFY(!Config::canBeApplied(nulllConfig)); +} + +void testScreenConfig::supportedFeatures() +{ + ConfigPtr config = getConfig(); + + QVERIFY(config->supportedFeatures().testFlag(KScreen::Config::Feature::None)); + QVERIFY(!config->supportedFeatures().testFlag(KScreen::Config::Feature::Writable)); + QVERIFY(!config->supportedFeatures().testFlag(KScreen::Config::Feature::PrimaryDisplay)); + QVERIFY(!config->supportedFeatures().testFlag(KScreen::Config::Feature::PerOutputScaling)); + + config->setSupportedFeatures(KScreen::Config::Feature::Writable | KScreen::Config::Feature::PrimaryDisplay); + QVERIFY(config->supportedFeatures().testFlag(KScreen::Config::Feature::Writable)); + QVERIFY(config->supportedFeatures().testFlag(KScreen::Config::Feature::PrimaryDisplay)); + + config->setSupportedFeatures(KScreen::Config::Feature::None); + QVERIFY(config->supportedFeatures().testFlag(KScreen::Config::Feature::None)); + + config->setSupportedFeatures(KScreen::Config::Feature::PerOutputScaling | KScreen::Config::Feature::Writable); + QVERIFY(!config->supportedFeatures().testFlag(KScreen::Config::Feature::None)); + QVERIFY(config->supportedFeatures().testFlag(KScreen::Config::Feature::Writable)); + QVERIFY(config->supportedFeatures().testFlag(KScreen::Config::Feature::PerOutputScaling)); + + config->setSupportedFeatures(KScreen::Config::Feature::PerOutputScaling | KScreen::Config::Feature::Writable | KScreen::Config::Feature::PrimaryDisplay); + QVERIFY(!config->supportedFeatures().testFlag(KScreen::Config::Feature::None)); + QVERIFY(config->supportedFeatures().testFlag(KScreen::Config::Feature::Writable)); + QVERIFY(config->supportedFeatures().testFlag(KScreen::Config::Feature::PrimaryDisplay)); + QVERIFY(config->supportedFeatures().testFlag(KScreen::Config::Feature::PerOutputScaling)); +} + +void testScreenConfig::testInvalidMode() +{ + ModeList modes; + ModePtr invalidMode = modes.value("99"); + QVERIFY(invalidMode.isNull()); + + auto output = new KScreen::Output(); + auto currentMode = output->currentMode(); + QVERIFY(currentMode.isNull()); + QVERIFY(!currentMode); + delete output; +} + +void testScreenConfig::testOutputPositionNormalization() +{ + qputenv("KSCREEN_BACKEND_ARGS", "TEST_DATA=" TEST_DATA "multipleoutput.json"); + + const ConfigPtr config = getConfig(); + QVERIFY(!config.isNull()); + auto left = config->outputs().first(); + auto right = config->outputs().last(); + QVERIFY(!left.isNull()); + QVERIFY(!right.isNull()); + left->setPos(QPoint(-5000, 700)); + right->setPos(QPoint(-3720, 666)); + QCOMPARE(left->pos(), QPoint(-5000, 700)); + QCOMPARE(right->pos(), QPoint(-3720, 666)); + + // start a set operation to fix up the positions + { + auto setop = new SetConfigOperation(config); + setop->exec(); + } + QCOMPARE(left->pos(), QPoint(0, 34)); + QCOMPARE(right->pos(), QPoint(1280, 0)); + + // make sure it doesn't touch a valid config + { + auto setop = new SetConfigOperation(config); + setop->exec(); + } + QCOMPARE(left->pos(), QPoint(0, 34)); + QCOMPARE(right->pos(), QPoint(1280, 0)); + + // positions of single outputs should be at 0, 0 + left->setEnabled(false); + { + auto setop = new SetConfigOperation(config); + setop->exec(); + } + QCOMPARE(right->pos(), QPoint()); } + QTEST_MAIN(testScreenConfig) #include "testscreenconfig.moc" diff -Nru libkscreen-5.4.2/autotests/testxrandr.cpp libkscreen-5.12.0/autotests/testxrandr.cpp --- libkscreen-5.4.2/autotests/testxrandr.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/autotests/testxrandr.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -46,7 +46,7 @@ void testXRandR::singleOutput() { - setenv("KSCREEN_BACKEND", "XRandR", 1); + qputenv("KSCREEN_BACKEND", "XRandR"); GetConfigOperation *op = new GetConfigOperation(); QVERIFY(op->exec()); diff -Nru libkscreen-5.4.2/backends/CMakeLists.txt libkscreen-5.12.0/backends/CMakeLists.txt --- libkscreen-5.4.2/backends/CMakeLists.txt 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/backends/CMakeLists.txt 2018-02-01 13:45:54.000000000 +0000 @@ -1,4 +1,11 @@ add_subdirectory(fake) add_subdirectory(qscreen) -add_subdirectory(xrandr) -add_subdirectory(xrandr1.1) +add_subdirectory(kwayland) + +if(${XCB_RANDR_FOUND}) + message(STATUS "Will build xrandr backend.") + add_subdirectory(xrandr) + add_subdirectory(xrandr1.1) +else() + message(STATUS "Not building xrandr backend, no XCB_RANDR_FOUND set.") +endif() diff -Nru libkscreen-5.4.2/backends/fake/fake.cpp libkscreen-5.12.0/backends/fake/fake.cpp --- libkscreen-5.4.2/backends/fake/fake.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/backends/fake/fake.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -45,7 +45,21 @@ { QLoggingCategory::setFilterRules(QStringLiteral("kscreen.fake.debug = true")); - QTimer::singleShot(0, this, SLOT(delayedInit())); + + if (qgetenv("KSCREEN_BACKEND_INPROCESS") != QByteArray("1")) { + QTimer::singleShot(0, this, SLOT(delayedInit())); + } +} + +void Fake::init(const QVariantMap &arguments) +{ + if (!mConfig.isNull()) { + mConfig.clear(); + } + + mConfigFile = arguments[QStringLiteral("TEST_DATA")].toString(); + qCDebug(KSCREEN_FAKE) << "Fake profile file:" << mConfigFile; + } void Fake::delayedInit() @@ -65,17 +79,13 @@ QString Fake::serviceName() const { - if (!qgetenv("KSCREEN_TEST_INSTANCE").isEmpty()) { - return QString::fromLatin1("org.kde.KScreen.Backend.Fake.") + QString::fromLatin1(qgetenv("KSCREEN_TEST_INSTANCE")); - } - return QLatin1Literal("org.kde.KScreen.Backend.Fake"); } ConfigPtr Fake::config() const { if (mConfig.isNull()) { - mConfig = Parser::fromJson(QString(qgetenv("TEST_DATA"))); + mConfig = Parser::fromJson(mConfigFile); } return mConfig; @@ -83,7 +93,9 @@ void Fake::setConfig(const ConfigPtr &config) { - Q_UNUSED(config) + qCDebug(KSCREEN_FAKE) << "set config" << config->outputs(); + mConfig = config->clone(); + emit configChanged(mConfig); } bool Fake::isValid() const @@ -94,7 +106,7 @@ QByteArray Fake::edid(int outputId) const { Q_UNUSED(outputId); - QFile file(QString(qgetenv("TEST_DATA"))); + QFile file(mConfigFile); file.open(QIODevice::ReadOnly); const QJsonDocument jsonDoc = QJsonDocument::fromJson(file.readAll()); @@ -120,6 +132,7 @@ } output->setConnected(connected); + qCDebug(KSCREEN_FAKE) << "emitting configChanged in Fake"; Q_EMIT configChanged(mConfig); } diff -Nru libkscreen-5.4.2/backends/fake/fake.h libkscreen-5.12.0/backends/fake/fake.h --- libkscreen-5.4.2/backends/fake/fake.h 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/backends/fake/fake.h 2018-02-01 13:45:54.000000000 +0000 @@ -33,12 +33,14 @@ explicit Fake(); virtual ~Fake(); - QString name() const; - QString serviceName() const; - KScreen::ConfigPtr config() const; - void setConfig(const KScreen::ConfigPtr &config); - QByteArray edid(int outputId) const; - bool isValid() const; + void init(const QVariantMap &arguments) Q_DECL_OVERRIDE; + + QString name() const Q_DECL_OVERRIDE; + QString serviceName() const Q_DECL_OVERRIDE; + KScreen::ConfigPtr config() const Q_DECL_OVERRIDE; + void setConfig(const KScreen::ConfigPtr &config) Q_DECL_OVERRIDE; + QByteArray edid(int outputId) const Q_DECL_OVERRIDE; + bool isValid() const Q_DECL_OVERRIDE; void setConnected(int outputId, bool connected); void setEnabled(int outputId, bool enabled); @@ -53,6 +55,7 @@ private: + QString mConfigFile; mutable KScreen::ConfigPtr mConfig; }; Q_DECLARE_LOGGING_CATEGORY(KSCREEN_FAKE) diff -Nru libkscreen-5.4.2/backends/fake/parser.cpp libkscreen-5.12.0/backends/fake/parser.cpp --- libkscreen-5.4.2/backends/fake/parser.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/backends/fake/parser.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -86,12 +86,12 @@ for (QVariantMap::const_iterator iter = variant.begin(); iter != variant.end(); ++iter) { const int propertyIndex = metaObject->indexOfProperty(qPrintable(iter.key())); if (propertyIndex == -1) { - qWarning() << "Skipping non-existent property" << iter.key(); + //qWarning() << "Skipping non-existent property" << iter.key(); continue; } const QMetaProperty metaProperty = metaObject->property(propertyIndex); if (!metaProperty.isWritable()) { - qWarning() << "Skipping read-only property" << iter.key(); + //qWarning() << "Skipping read-only property" << iter.key(); continue; } @@ -142,7 +142,7 @@ } const QString type = map["type"].toByteArray().toUpper(); - if (type.contains("LVDS") || type.contains("EDP") || type.contains("IDP")) { + if (type.contains("LVDS") || type.contains("EDP") || type.contains("IDP") || type.contains("7")) { output->setType(Output::Panel); } else if (type.contains("VGA")) { output->setType(Output::VGA); @@ -154,7 +154,7 @@ output->setType(Output::DVIA); } else if (type.contains("DVI-D")) { output->setType(Output::DVID); - } else if (type.contains("HDMI")) { + } else if (type.contains("HDMI") || type.contains("6")) { output->setType(Output::HDMI); } else if (type.contains("Panel")) { output->setType(Output::Panel); @@ -170,7 +170,7 @@ output->setType(Output::TVSCART); } else if (type.contains("TV-C4")) { output->setType(Output::TVC4); - } else if (type.contains("DisplayPort")) { + } else if (type.contains("DisplayPort") || type.contains("14")) { output->setType(Output::DisplayPort); } else if (type.contains("Unknown")) { output->setType(Output::Unknown); @@ -189,6 +189,12 @@ map.remove(QLatin1Literal("size")); } + if (map.contains("scale")) { + qDebug() << "Scale found:" << map["scale"].toReal(); + output->setScale(map["scale"].toReal()); + map.remove(QLatin1Literal("size")); + } + //Remove some extra properties that we do not want or need special treatment map.remove(QLatin1Literal("edid")); diff -Nru libkscreen-5.4.2/backends/kwayland/CMakeLists.txt libkscreen-5.12.0/backends/kwayland/CMakeLists.txt --- libkscreen-5.4.2/backends/kwayland/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/backends/kwayland/CMakeLists.txt 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,19 @@ + +set(wayland_SRCS + waylandbackend.cpp + waylandconfig.cpp + waylandoutput.cpp + waylandscreen.cpp + ../utils.cpp +) + +add_library(KSC_KWayland MODULE ${wayland_SRCS}) + +set_target_properties(KSC_KWayland PROPERTIES PREFIX "") +target_link_libraries(KSC_KWayland Qt5::Core + Qt5::Gui + KF5::Screen + KF5::WaylandClient +) + +install(TARGETS KSC_KWayland DESTINATION ${PLUGIN_INSTALL_DIR}/kf5/kscreen/) diff -Nru libkscreen-5.4.2/backends/kwayland/README.md libkscreen-5.12.0/backends/kwayland/README.md --- libkscreen-5.4.2/backends/kwayland/README.md 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/backends/kwayland/README.md 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,49 @@ +# Design of libkscreen's Wayland backend + +This backend uses KWayland's OutputManagement protocol for listing and +configuring devices. This is described here. + +## Listing outputs + +KScreen's outputs are created from KWayland::Client::OutputDevice objects, +they copy the data into kscreen's Outputs, and update these objects. A list +of outputs is requested from the client Registry object. + +## Configuring outputs + +The backend asks the global OutputManagement interface for an OutputConfiguration +object, then sets the changes per outputdevice on this object, and asks the +compositor to apply() this configuration. + +For this to work, the compositor should support the Wayland org_kde_kwin_outputdevice +and org_kde_kwin_outputmanagement protocols, for example through +KWayland::Server classes OutputDevice, OutputManagmenent and OuputConfiguration. + +## General working + +WaylandBackend creates a global static internal config, available through +WaylandBackend::internalConfig(). WaylandConfig binds to the wl_registry +callbacks and catches org_kde_kwin_outputdevice creation and destruction. +It passes org_kde_kwin_outputdevice creation and removal on to +WB::internalConfig() to handle its internal data representation as WaylandOutput. +WaylandOutput binds to org_kde_kwin_outputdevice's callback, and gets notified +of geometry and modes, including changes. WaylandOutput administrates the +internal representation of these objects, and invokes the global notifier, +which then runs the pointers it holds through the updateK* methods in +Wayland{Screen,Output,...}. + +KScreen:{Screen,Output,Edid,Mode} objects are created from the internal +representation as requested (usually triggered by the creation of a +KScreen::Config object through KScreen::Config::current()). As with other +backends, the objects which are handed out to the lib's user are expected +to be deleted by the user, the backend only takes ownership of its internal +data representation objects. + +## Note about scope of output ids + +The ids of the outputdevices are internal to the wayland backend. The id is +generated in the wayland backend, and does not match kwin's output ids. Do +not try to read kwin's config from here. + + + diff -Nru libkscreen-5.4.2/backends/kwayland/waylandbackend.cpp libkscreen-5.12.0/backends/kwayland/waylandbackend.cpp --- libkscreen-5.4.2/backends/kwayland/waylandbackend.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/backends/kwayland/waylandbackend.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,96 @@ +/************************************************************************************* + * Copyright (C) 2012 by Alejandro Fiestas Olivares * + * Copyright (C) 2012, 2013 by Daniel Vrátil * + * Copyright 2014-2015 Sebastian Kügler * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#include "waylandbackend.h" +#include "waylandconfig.h" +#include "waylandoutput.h" + +#include +#include + +#include +#include + +using namespace KScreen; + +Q_LOGGING_CATEGORY(KSCREEN_WAYLAND, "kscreen.kwayland") + + +WaylandBackend::WaylandBackend() + : KScreen::AbstractBackend() + , m_isValid(true) + , m_config(nullptr) + , m_internalConfig(new WaylandConfig(this)) +{ + qCDebug(KSCREEN_WAYLAND) << "Loading Wayland backend."; + m_internalConfig = new WaylandConfig(this); + m_config = m_internalConfig->toKScreenConfig(); + connect(m_internalConfig, &WaylandConfig::configChanged, + this, &WaylandBackend::emitConfigChanged); +} + +QString WaylandBackend::name() const +{ + return QStringLiteral("kwayland"); +} + +QString WaylandBackend::serviceName() const +{ + return QLatin1Literal("org.kde.KScreen.Backend.KWayland"); +} + +ConfigPtr WaylandBackend::config() const +{ + // Note: This should ONLY be called from GetConfigOperation! + return m_internalConfig->toKScreenConfig(); +} + +void WaylandBackend::setConfig(const KScreen::ConfigPtr &newconfig) +{ + if (!newconfig) { + return; + } + m_internalConfig->applyConfig(newconfig); +} + +void WaylandBackend::emitConfigChanged(const KScreen::ConfigPtr &cfg) +{ + Q_EMIT configChanged(cfg); +} + +QByteArray WaylandBackend::edid(int outputId) const +{ + WaylandOutput *output = m_internalConfig->outputMap().value(outputId); + if (!output) { + return QByteArray(); + } + return output->outputDevice()->edid(); +} + +bool WaylandBackend::isValid() const +{ + return m_isValid; +} + +void WaylandBackend::updateConfig(ConfigPtr &config) +{ + Q_ASSERT(config != 0); + m_internalConfig->updateKScreenConfig(config); +} diff -Nru libkscreen-5.4.2/backends/kwayland/waylandbackend.h libkscreen-5.12.0/backends/kwayland/waylandbackend.h --- libkscreen-5.4.2/backends/kwayland/waylandbackend.h 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/backends/kwayland/waylandbackend.h 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,61 @@ +/************************************************************************************* + * Copyright (C) 2012 by Alejandro Fiestas Olivares * + * Copyright (C) 2012, 2013 by Daniel Vrátil * + * Copyright 2014-2015 Sebastian Kügler * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#ifndef KWAYLAND_BACKEND_H +#define KWAYLAND_BACKEND_H + +#include "abstractbackend.h" + +#include + +namespace KScreen +{ +class WaylandConfig; + +class WaylandBackend : public KScreen::AbstractBackend +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.kf5.kscreen.backends.kwayland") + +public: + explicit WaylandBackend(); + virtual ~WaylandBackend() = default; + + QString name() const Q_DECL_OVERRIDE; + QString serviceName() const Q_DECL_OVERRIDE; + KScreen::ConfigPtr config() const Q_DECL_OVERRIDE; + void setConfig(const KScreen::ConfigPtr &config) Q_DECL_OVERRIDE; + bool isValid() const Q_DECL_OVERRIDE; + QByteArray edid(int outputId) const Q_DECL_OVERRIDE; + + void updateConfig(KScreen::ConfigPtr &config); + +private: + bool m_isValid; + KScreen::ConfigPtr m_config; + WaylandConfig *m_internalConfig; + void emitConfigChanged(const KScreen::ConfigPtr &cfg); +}; + +} // namespace + +Q_DECLARE_LOGGING_CATEGORY(KSCREEN_WAYLAND) + +#endif //KWAYLAND_BACKEND_H diff -Nru libkscreen-5.4.2/backends/kwayland/waylandconfig.cpp libkscreen-5.12.0/backends/kwayland/waylandconfig.cpp --- libkscreen-5.4.2/backends/kwayland/waylandconfig.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/backends/kwayland/waylandconfig.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,346 @@ +/************************************************************************************* + * Copyright 2014-2015 Sebastian Kügler * + * Copyright 2013 Martin Gräßlin * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#include "waylandconfig.h" +#include "waylandoutput.h" +#include "waylandscreen.h" +#include "waylandbackend.h" + +// KWayland +#include +#include +#include +#include +#include +#include + + +// Qt +#include + +#include +#include + + +using namespace KScreen; + + +WaylandConfig::WaylandConfig(QObject *parent) + : QObject(parent) + , m_outputManagement(nullptr) + , m_registryInitialized(false) + , m_blockSignals(true) + , m_newOutputId(0) + , m_kscreenConfig(nullptr) + , m_screen(new WaylandScreen(this)) +{ + connect(this, &WaylandConfig::initialized, &m_syncLoop, &QEventLoop::quit); + QTimer::singleShot(1000, this, [this] { + if (m_syncLoop.isRunning()) { + qCWarning(KSCREEN_WAYLAND) << "Connection to Wayland server at socket:" << m_connection->socketName() << "timed out."; + m_syncLoop.quit(); + m_thread->quit(); + m_thread->wait(); + } + }); + initConnection(); + m_syncLoop.exec(); +} + +WaylandConfig::~WaylandConfig() +{ + m_thread->quit(); + m_thread->wait(); + m_syncLoop.quit(); +} + +void WaylandConfig::initConnection() +{ + m_thread = new QThread(this); + //m_queue = new KWayland::Client::EventQueue(this); + m_connection = new KWayland::Client::ConnectionThread; + + connect(m_connection, &KWayland::Client::ConnectionThread::connected, + this, &WaylandConfig::setupRegistry, Qt::QueuedConnection); + + connect(m_connection, &KWayland::Client::ConnectionThread::connectionDied, + this, &WaylandConfig::disconnected, Qt::QueuedConnection); + connect(m_connection, &KWayland::Client::ConnectionThread::failed, this, [this] { + qCWarning(KSCREEN_WAYLAND) << "Failed to connect to Wayland server at socket:" << m_connection->socketName(); + m_syncLoop.quit(); + m_thread->quit(); + m_thread->wait(); + }); + + m_thread->start(); + m_connection->moveToThread(m_thread); + m_connection->initConnection(); + +} + +void WaylandConfig::blockSignals() +{ + Q_ASSERT(m_blockSignals == false); + m_blockSignals = true; +} + +void WaylandConfig::unblockSignals() +{ + Q_ASSERT(m_blockSignals == true); + m_blockSignals = false; +} + +void WaylandConfig::disconnected() +{ + qCWarning(KSCREEN_WAYLAND) << "Wayland disconnected, cleaning up."; + qDeleteAll(m_outputMap); + m_outputMap.clear(); + + // Clean up + if (m_queue) { + delete m_queue; + m_queue = nullptr; + } + + m_connection->deleteLater(); + m_connection = nullptr; + + if (m_thread) { + m_thread->quit(); + if (!m_thread->wait(3000)) { + m_thread->terminate(); + m_thread->wait(); + } + delete m_thread; + m_thread = nullptr; + } + + Q_EMIT configChanged(toKScreenConfig()); + Q_EMIT gone(); +} + +void WaylandConfig::setupRegistry() +{ + m_queue = new KWayland::Client::EventQueue(this); + m_queue->setup(m_connection); + + m_registry = new KWayland::Client::Registry(this); + + connect(m_registry, &KWayland::Client::Registry::outputDeviceAnnounced, + this, &WaylandConfig::addOutput); + connect(m_registry, &KWayland::Client::Registry::outputDeviceRemoved, + this, &WaylandConfig::removeOutput); + + connect(m_registry, &KWayland::Client::Registry::outputManagementAnnounced, + this, [this](quint32 name, quint32 version) { + m_outputManagement = m_registry->createOutputManagement(name, version, m_registry); + checkInitialized(); + } + ); + + connect(m_registry, &KWayland::Client::Registry::interfacesAnnounced, + this, [this] { + m_registryInitialized = true; + unblockSignals(); + checkInitialized(); + } + ); + + m_registry->create(m_connection); + m_registry->setEventQueue(m_queue); + m_registry->setup(); +} + +void WaylandConfig::addOutput(quint32 name, quint32 version) +{ + ++m_newOutputId; + quint32 new_id = m_newOutputId; + m_outputIds[name] = new_id; + if (m_outputMap.contains(new_id)) { + return; + } + if (!m_initializingOutputs.contains(name)) { + m_initializingOutputs << name; + } + + auto op = new KWayland::Client::OutputDevice(this); + WaylandOutput *waylandoutput = new WaylandOutput(new_id, this); + waylandoutput->bindOutputDevice(m_registry, op, name, version); + + // finalize: when the output is done, we put it in the known outputs map, + // remove if from the list of initializing outputs, and emit configChanged() + connect(waylandoutput, &WaylandOutput::complete, this, [this, waylandoutput, name]{ + + m_outputMap.insert(waylandoutput->id(), waylandoutput); + m_initializingOutputs.removeAll(name); + checkInitialized(); + + if (!m_blockSignals && m_initializingOutputs.empty()) { + m_screen->setOutputs(m_outputMap.values()); + Q_EMIT configChanged(toKScreenConfig()); + } + connect(waylandoutput, &WaylandOutput::changed, this, [this]() { + if (!m_blockSignals) { + Q_EMIT configChanged(toKScreenConfig()); + } + }); + }); +} + +void WaylandConfig::checkInitialized() +{ + if (!m_blockSignals && m_registryInitialized && + m_initializingOutputs.isEmpty() && m_outputMap.count() && m_outputManagement != nullptr) { + m_screen->setOutputs(m_outputMap.values()); + Q_EMIT initialized(); + } +} + +KScreen::ConfigPtr WaylandConfig::toKScreenConfig() +{ + if (m_kscreenConfig == nullptr) { + m_kscreenConfig = KScreen::ConfigPtr(new Config); + } + m_kscreenConfig->setScreen(m_screen->toKScreenScreen(m_kscreenConfig)); + + updateKScreenConfig(m_kscreenConfig); + return m_kscreenConfig; +} + +void WaylandConfig::removeOutput(quint32 name) +{ + const int kscreen_id = m_outputIds[name]; + auto output = m_outputMap.take(kscreen_id); + m_screen->setOutputs(m_outputMap.values()); + delete output; + if (!m_blockSignals) { + Q_EMIT configChanged(toKScreenConfig()); + } +} + +void WaylandConfig::updateKScreenConfig(KScreen::ConfigPtr &config) const +{ + auto features = Config::Feature::Writable | Config::Feature::PerOutputScaling; + config->setSupportedFeatures(features); + config->setValid(m_connection->display()); + KScreen::ScreenPtr screen = config->screen(); + m_screen->updateKScreenScreen(screen); + + //Removing removed outputs + const KScreen::OutputList outputs = config->outputs(); + Q_FOREACH (const KScreen::OutputPtr &output, outputs) { + if (!m_outputMap.contains(output->id())) { + config->removeOutput(output->id()); + } + } + + // Add KScreen::Outputs that aren't in the list yet, handle primaryOutput + KScreen::OutputList kscreenOutputs = config->outputs(); + Q_FOREACH (const auto &output, m_outputMap) { + KScreen::OutputPtr kscreenOutput = kscreenOutputs[output->id()]; + if (!kscreenOutput) { + kscreenOutput = output->toKScreenOutput(); + kscreenOutputs.insert(kscreenOutput->id(), kscreenOutput); + } + if (kscreenOutput && m_outputMap.count() == 1) { + kscreenOutput->setPrimary(true); + } else if (m_outputMap.count() > 1) { + // primaryScreen concept doesn't exist in kwayland, so we don't set one + //qCWarning(KSCREEN_WAYLAND) << "Multiple outputs, but no way to figure out the primary one. :/"; + } + output->updateKScreenOutput(kscreenOutput); + } + config->setOutputs(kscreenOutputs); +} + +QMap WaylandConfig::outputMap() const +{ + return m_outputMap; +} + +void WaylandConfig::applyConfig(const KScreen::ConfigPtr &newConfig) +{ + using namespace KWayland::Client; + // Create a new configuration object + auto wlOutputConfiguration = m_outputManagement->createConfiguration(); + bool changed = false; + + Q_FOREACH (auto output, newConfig->outputs()) { + auto o_old = m_outputMap[output->id()]; + auto device = o_old->outputDevice(); + Q_ASSERT(o_old != nullptr); + + // enabled? + bool old_enabled = (o_old->outputDevice()->enabled() == OutputDevice::Enablement::Enabled); + if (old_enabled != output->isEnabled()) { + changed = true; + auto _enablement = output->isEnabled() ? OutputDevice::Enablement::Enabled : OutputDevice::Enablement::Disabled; + wlOutputConfiguration->setEnabled(o_old->outputDevice(), _enablement); + } + + // position + if (device->globalPosition() != output->pos()) { + changed = true; + wlOutputConfiguration->setPosition(o_old->outputDevice(), output->pos()); + } + + if (device->scale() != output->scale()) { + changed = true; + wlOutputConfiguration->setScale(o_old->outputDevice(), output->scale()); + } + + // rotation + auto r_current = o_old->toKScreenRotation(device->transform()); + auto r_new = output->rotation(); + if (r_current != r_new) { + changed = true; + wlOutputConfiguration->setTransform(device, o_old->toKWaylandTransform(r_new)); + } + + // mode + int w_currentmodeid = device->currentMode().id; + QString l_newmodeid = output->currentModeId(); + int w_newmodeid = o_old->toKWaylandModeId(l_newmodeid); + if (w_newmodeid != w_currentmodeid) { + changed = true; + wlOutputConfiguration->setMode(device, w_newmodeid); + } + } + + if (!changed) { + return; + } + + // We now block changes in order to compress events while the compositor is doing its thing + // once it's done or failed, we'll trigger configChanged() only once, and not per individual + // property change. + connect(wlOutputConfiguration, &OutputConfiguration::applied, this, [this, wlOutputConfiguration] { + wlOutputConfiguration->deleteLater(); + unblockSignals(); + Q_EMIT configChanged(toKScreenConfig()); + }); + connect(wlOutputConfiguration, &OutputConfiguration::failed, this, [this, wlOutputConfiguration] { + wlOutputConfiguration->deleteLater(); + unblockSignals(); + Q_EMIT configChanged(toKScreenConfig()); + }); + blockSignals(); + // Now ask the compositor to apply the changes + wlOutputConfiguration->apply(); +} diff -Nru libkscreen-5.4.2/backends/kwayland/waylandconfig.h libkscreen-5.12.0/backends/kwayland/waylandconfig.h --- libkscreen-5.4.2/backends/kwayland/waylandconfig.h 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/backends/kwayland/waylandconfig.h 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,120 @@ +/************************************************************************************* + * Copyright 2014-2015 Sebastian Kügler * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#ifndef KSCREEN_WAYLAND_CONFIG_H +#define KSCREEN_WAYLAND_CONFIG_H + +#include "abstractbackend.h" +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + + +namespace KWayland { + namespace Client { + class ConnectionThread; + class EventQueue; + class OutputDevice; + class Registry; + class OutputManagement; + } +} + +namespace KScreen +{ +class Output; +class WaylandOutput; +class WaylandScreen; + +/** + * @class WaylandConfig + * + * This class holds the basic skeleton of the configuration and takes care of + * fetching the information from the Wayland server and synchronizing the + * configuration out to the "clients" that receive the config from the backend. + * We initialize a wayland connection, using a threaded event queue when + * querying the wayland server for data. + * Initially, the creation of a WaylandConfig blocks until all data has been + * received, signalled by the initialized() signal. This means that the + * wayland client has received information about all interfaces, and that all + * outputs are completely initialized. From then on, we properly notifyUpdate(). +*/ +class WaylandConfig : public QObject +{ + Q_OBJECT + +public: + explicit WaylandConfig(QObject *parent = nullptr); + virtual ~WaylandConfig(); + + KScreen::ConfigPtr toKScreenConfig(); + void updateKScreenConfig(KScreen::ConfigPtr &config) const; + + QMap outputMap() const; + + void addOutput(quint32 name, quint32 version); + void removeOutput(quint32 name); + + void applyConfig(const KScreen::ConfigPtr &newConfig); + +Q_SIGNALS: + void configChanged(const KScreen::ConfigPtr &config); + void initialized(); + void gone(); + +private Q_SLOTS: + void setupRegistry(); + void checkInitialized(); + void disconnected(); + +private: + void initConnection(); + void blockSignals(); + void unblockSignals(); + + KWayland::Client::ConnectionThread *m_connection; + KWayland::Client::EventQueue *m_queue; + QThread *m_thread; + + KWayland::Client::Registry *m_registry; + KWayland::Client::OutputManagement *m_outputManagement; + + QMap m_outputMap; + // Map between kwayland's outputdevice names and kscreen output ids + // key: wayland's name, value: kscreen id + QMap m_outputIds; + QList m_initializingOutputs; + bool m_registryInitialized; + int m_lastOutputId = -1; + bool m_blockSignals; + QEventLoop m_syncLoop; + int m_newOutputId; + KScreen::ConfigPtr m_kscreenConfig; + WaylandScreen *m_screen; + +}; + +} // namespace + +#endif // KSCREEN_WAYLAND_CONFIG_H diff -Nru libkscreen-5.4.2/backends/kwayland/waylandoutput.cpp libkscreen-5.12.0/backends/kwayland/waylandoutput.cpp --- libkscreen-5.4.2/backends/kwayland/waylandoutput.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/backends/kwayland/waylandoutput.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,195 @@ +/************************************************************************************* + * Copyright 2014-2015 Sebastian Kügler * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#include "waylandoutput.h" +#include "waylandbackend.h" +#include "waylandconfig.h" +#include "../utils.h" + +#include +#include + +#include +#include + + +using namespace KScreen; + +WaylandOutput::WaylandOutput(quint32 id, WaylandConfig *parent) + : QObject(parent) + , m_id(id) + , m_output(nullptr) +{ + m_rotationMap = { + {KWayland::Client::OutputDevice::Transform::Normal, KScreen::Output::None}, + {KWayland::Client::OutputDevice::Transform::Rotated90, KScreen::Output::Right}, + {KWayland::Client::OutputDevice::Transform::Rotated180, KScreen::Output::Inverted}, + {KWayland::Client::OutputDevice::Transform::Rotated270, KScreen::Output::Left}, + {KWayland::Client::OutputDevice::Transform::Flipped, KScreen::Output::None}, + {KWayland::Client::OutputDevice::Transform::Flipped90, KScreen::Output::Right}, + {KWayland::Client::OutputDevice::Transform::Flipped180, KScreen::Output::Inverted}, + {KWayland::Client::OutputDevice::Transform::Flipped270, KScreen::Output::Left} + }; +} + +KScreen::Output::Rotation WaylandOutput::toKScreenRotation(const KWayland::Client::OutputDevice::Transform transform) const +{ + auto it = m_rotationMap.constFind(transform); + return it.value(); +} + +KWayland::Client::OutputDevice::Transform WaylandOutput::toKWaylandTransform(const KScreen::Output::Rotation rotation) const +{ + return m_rotationMap.key(rotation); +} + +QString WaylandOutput::toKScreenModeId(int kwaylandmodeid) const +{ + if (!m_modeIdMap.values().contains(kwaylandmodeid)) { + qCWarning(KSCREEN_WAYLAND) << "Invalid kwayland mode id:" << kwaylandmodeid << m_modeIdMap; + } + return m_modeIdMap.key(kwaylandmodeid, QStringLiteral("invalid_mode_id")); +} + +int WaylandOutput::toKWaylandModeId(const QString &kscreenmodeid) const +{ + if (!m_modeIdMap.contains(kscreenmodeid)) { + qCWarning(KSCREEN_WAYLAND) << "Invalid kscreen mode id:" << kscreenmodeid << m_modeIdMap; + } + return m_modeIdMap.value(kscreenmodeid, -1); +} + +WaylandOutput::~WaylandOutput() +{ +} + +quint32 WaylandOutput::id() const +{ + Q_ASSERT(m_output); + return m_id; +} + +bool WaylandOutput::enabled() const +{ + return m_output != nullptr; +} + +KWayland::Client::OutputDevice* WaylandOutput::outputDevice() const +{ + return m_output; +} + +void WaylandOutput::bindOutputDevice(KWayland::Client::Registry* registry, KWayland::Client::OutputDevice* op, quint32 name, quint32 version) +{ + if (m_output == op) { + return; + } + m_output = op; + + connect(m_output, &KWayland::Client::OutputDevice::done, this, [this]() { + Q_EMIT complete(); + connect(m_output, &KWayland::Client::OutputDevice::changed, + this, &WaylandOutput::changed); + + }); + + m_output->setup(registry->bindOutputDevice(name, version)); +} + +KScreen::OutputPtr WaylandOutput::toKScreenOutput() +{ + KScreen::OutputPtr output(new KScreen::Output()); + output->setId(m_id); + updateKScreenOutput(output); + return output; +} + +void WaylandOutput::updateKScreenOutput(KScreen::OutputPtr &output) +{ + // Initialize primary output + output->setId(m_id); + output->setEnabled(m_output->enabled() == KWayland::Client::OutputDevice::Enablement::Enabled); + output->setConnected(true); + output->setPrimary(true); // FIXME: wayland doesn't have the concept of a primary display + output->setName(m_output->model()); + // Physical size + output->setSizeMm(m_output->physicalSize()); + output->setPos(m_output->globalPosition()); + output->setRotation(m_rotationMap[m_output->transform()]); + KScreen::ModeList modeList; + QStringList preferredModeIds; + m_modeIdMap.clear(); + QString currentModeId = QStringLiteral("-1"); + Q_FOREACH (const KWayland::Client::OutputDevice::Mode &m, m_output->modes()) { + KScreen::ModePtr mode(new KScreen::Mode()); + const QString modename = modeName(m); + QString modeid = QString::number(m.id); + if (modeid.isEmpty()) { + qCDebug(KSCREEN_WAYLAND) << "Could not create mode id from" << m.id << ", using" << modename << "instead."; + modeid = modename; + } + if (m_modeIdMap.keys().contains(modeid)) { + qCWarning(KSCREEN_WAYLAND) << "Mode id already in use:" << modeid; + } + + mode->setId(modeid); + mode->setRefreshRate(m.refreshRate); + mode->setSize(m.size); + mode->setName(modename); + if (m.flags.testFlag(KWayland::Client::OutputDevice::Mode::Flag::Current)) { + currentModeId = modeid; + } + if (m.flags.testFlag(KWayland::Client::OutputDevice::Mode::Flag::Preferred)) { + preferredModeIds << modeid; + } + // Update the kscreen => kwayland mode id translation map + m_modeIdMap.insert(modeid, m.id); + // Add to the modelist which gets set on the output + modeList[modeid] = mode; + } + if (currentModeId == QLatin1String("-1")) { + qCWarning(KSCREEN_WAYLAND) << "Could not find the current mode id" << modeList; + } + output->setCurrentModeId(currentModeId); + + output->setPreferredModes(preferredModeIds); + output->setModes(modeList); + output->setScale(m_output->scale()); + output->setType(Utils::guessOutputType(m_output->model(), m_output->model())); +} + +QString WaylandOutput::modeName(const KWayland::Client::OutputDevice::Mode &m) const +{ + return QString::number(m.size.width()) + QLatin1Char('x') + + QString::number(m.size.height()) + QLatin1Char('@') + + QString::number(qRound(m.refreshRate/1000.0)); +} + +QString WaylandOutput::name() const +{ + Q_ASSERT(m_output); + return QStringLiteral("%1 %2").arg(m_output->manufacturer(), m_output->model()); +} + +QDebug operator<<(QDebug dbg, const WaylandOutput *output) +{ + dbg << "WaylandOutput(Id:" << output->id() <<", Name:" << \ + QString(output->outputDevice()->manufacturer() + QStringLiteral(" ") + \ + output->outputDevice()->model()) << ")"; + return dbg; +} diff -Nru libkscreen-5.4.2/backends/kwayland/waylandoutput.h libkscreen-5.12.0/backends/kwayland/waylandoutput.h --- libkscreen-5.4.2/backends/kwayland/waylandoutput.h 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/backends/kwayland/waylandoutput.h 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,90 @@ +/************************************************************************************* + * Copyright 2014-2015 Sebastian Kügler * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#ifndef KSCREEN_WAYLAND_OUTPUT_H +#define KSCREEN_WAYLAND_OUTPUT_H + +// libkscreen +#include "abstractbackend.h" +#include "config.h" +#include "output.h" + +// Own +#include "waylandconfig.h" + +#include +#include +#include +#include +#include + + +namespace KScreen +{ + +class WaylandOutput : public QObject +{ + Q_OBJECT + +public: + virtual ~WaylandOutput(); + + KScreen::OutputPtr toKScreenOutput(); + void updateKScreenOutput(KScreen::OutputPtr &output); + + quint32 id() const; + + bool enabled() const; + + KWayland::Client::OutputDevice* outputDevice() const; + void bindOutputDevice(KWayland::Client::Registry *registry, KWayland::Client::OutputDevice *op, quint32 name, quint32 version); + + QString name() const; + + // translation methods + KScreen::Output::Rotation toKScreenRotation(const KWayland::Client::OutputDevice::Transform transform) const; + KWayland::Client::OutputDevice::Transform toKWaylandTransform(const KScreen::Output::Rotation rotation) const; + + QString toKScreenModeId(int kwaylandmodeid) const; + int toKWaylandModeId(const QString &kscreenmodeid) const; + +Q_SIGNALS: + void complete(); + + // only emitted after complete() + void changed(); + +private: + friend WaylandConfig; + explicit WaylandOutput(quint32 id, WaylandConfig *parent = nullptr); + void showOutput(); + QString modeName(const KWayland::Client::OutputDevice::Mode &m) const; + + quint32 m_id; + KWayland::Client::OutputDevice* m_output; + KWayland::Client::Registry* m_registry; + + QMap m_rotationMap; + QMap m_modeIdMap; // left-hand-side: KScreen::Mode, right-hand-side: kwayland's mode.id +}; + +} // namespace + +KSCREEN_EXPORT QDebug operator<<(QDebug dbg, const KScreen::WaylandOutput *output); + +#endif diff -Nru libkscreen-5.4.2/backends/kwayland/waylandscreen.cpp libkscreen-5.12.0/backends/kwayland/waylandscreen.cpp --- libkscreen-5.4.2/backends/kwayland/waylandscreen.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/backends/kwayland/waylandscreen.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,65 @@ +/************************************************************************************* + * Copyright 2014-2015 Sebastian Kügler * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#include "waylandconfig.h" +#include "waylandscreen.h" +#include "waylandoutput.h" + +#include + + +using namespace KScreen; + +WaylandScreen::WaylandScreen(WaylandConfig *config) + : QObject(config) + , m_outputCount(0) +{ +} + +WaylandScreen::~WaylandScreen() +{ +} + +ScreenPtr WaylandScreen::toKScreenScreen(KScreen::ConfigPtr &parent) const +{ + Q_UNUSED(parent); + KScreen::ScreenPtr kscreenScreen(new KScreen::Screen); + updateKScreenScreen(kscreenScreen); + return kscreenScreen; +} + +void WaylandScreen::setOutputs(const QList outputs) +{ + m_outputCount = outputs.count(); + QRect r; + Q_FOREACH (auto o, outputs) { + if (o->enabled()) { + r |= QRect(o->outputDevice()->globalPosition(), o->outputDevice()->pixelSize() / o->outputDevice()->scale()); + } + } + m_size = r.size(); +} + +void WaylandScreen::updateKScreenScreen(KScreen::ScreenPtr &screen) const +{ + screen->setMinSize(QSize(0, 0)); + screen->setMaxSize(QSize(64000, 64000)); // 64000^2 should be enough for everyone. + screen->setCurrentSize(m_size); + screen->setMaxActiveOutputsCount(m_outputCount); +} + diff -Nru libkscreen-5.4.2/backends/kwayland/waylandscreen.h libkscreen-5.12.0/backends/kwayland/waylandscreen.h --- libkscreen-5.4.2/backends/kwayland/waylandscreen.h 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/backends/kwayland/waylandscreen.h 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,56 @@ +/************************************************************************************* + * Copyright 2014-2015 Sebastian Kügler * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#ifndef KSCREEN_WAYLAND_SCREEN_H +#define KSCREEN_WAYLAND_SCREEN_H + +#include "abstractbackend.h" +#include "config.h" +#include "screen.h" + +#include +#include + +namespace KScreen +{ +class WaylandConfig; +class WaylandOutput; + +class WaylandScreen : public QObject +{ + Q_OBJECT + +public: + explicit WaylandScreen(WaylandConfig *config); + virtual ~WaylandScreen(); + + KScreen::ScreenPtr toKScreenScreen(KScreen::ConfigPtr &parent) const; + void updateKScreenScreen(KScreen::ScreenPtr &screen) const; + void setOutputs(const QList outputs); + + void setSize(const QSize &size); + void setOutputCount(int count); + +private: + QSize m_size; + int m_outputCount; +}; + +} // namespace + +#endif // KSCREEN_WAYLAND_SCREEN_H diff -Nru libkscreen-5.4.2/backends/qscreen/qscreenbackend.cpp libkscreen-5.12.0/backends/qscreen/qscreenbackend.cpp --- libkscreen-5.4.2/backends/qscreen/qscreenbackend.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/backends/qscreen/qscreenbackend.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -24,7 +24,7 @@ using namespace KScreen; -Q_LOGGING_CATEGORY(KSCREEN_QSCREEN, "kscreen.qscreen"); +Q_LOGGING_CATEGORY(KSCREEN_QSCREEN, "kscreen.qscreen") QScreenConfig *QScreenBackend::s_internalConfig = 0; @@ -32,8 +32,6 @@ : KScreen::AbstractBackend() , m_isValid(true) { - QLoggingCategory::setFilterRules(QLatin1Literal("kscreen.qscreen.debug = true")); - if (s_internalConfig == 0) { s_internalConfig = new QScreenConfig(); connect(s_internalConfig, &QScreenConfig::configChanged, diff -Nru libkscreen-5.4.2/backends/qscreen/qscreenbackend.h libkscreen-5.12.0/backends/qscreen/qscreenbackend.h --- libkscreen-5.4.2/backends/qscreen/qscreenbackend.h 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/backends/qscreen/qscreenbackend.h 2018-02-01 13:45:54.000000000 +0000 @@ -39,11 +39,11 @@ explicit QScreenBackend(); virtual ~QScreenBackend(); - virtual QString name() const; - virtual QString serviceName() const; - virtual KScreen::ConfigPtr config() const; - virtual void setConfig(const KScreen::ConfigPtr &config); - virtual bool isValid() const; + QString name() const Q_DECL_OVERRIDE; + QString serviceName() const Q_DECL_OVERRIDE; + KScreen::ConfigPtr config() const Q_DECL_OVERRIDE; + void setConfig(const KScreen::ConfigPtr &config) Q_DECL_OVERRIDE; + bool isValid() const Q_DECL_OVERRIDE; private: bool m_isValid; diff -Nru libkscreen-5.4.2/backends/qscreen/qscreenconfig.cpp libkscreen-5.12.0/backends/qscreen/qscreenconfig.cpp --- libkscreen-5.4.2/backends/qscreen/qscreenconfig.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/backends/qscreen/qscreenconfig.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -39,6 +39,7 @@ } m_blockSignals = false; connect(qApp, &QGuiApplication::screenAdded, this, &QScreenConfig::screenAdded); + connect(qApp, &QGuiApplication::screenRemoved, this, &QScreenConfig::screenRemoved); } QScreenConfig::~QScreenConfig() @@ -75,14 +76,12 @@ qscreenoutput->setId(outputId(qscreen)); m_outputMap.insert(qscreenoutput->id(), qscreenoutput); - connect(qscreen, &QObject::destroyed, this, &QScreenConfig::screenDestroyed); - if (!m_blockSignals) { Q_EMIT configChanged(toKScreenConfig()); } } -void QScreenConfig::screenDestroyed(QObject *qscreen) +void QScreenConfig::screenRemoved(QScreen *qscreen) { qCDebug(KSCREEN_QSCREEN) << "Screen removed" << qscreen << QGuiApplication::screens().count(); // Find output matching the QScreen object and remove it diff -Nru libkscreen-5.4.2/backends/qscreen/qscreenconfig.h libkscreen-5.12.0/backends/qscreen/qscreenconfig.h --- libkscreen-5.4.2/backends/qscreen/qscreenconfig.h 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/backends/qscreen/qscreenconfig.h 2018-02-01 13:45:54.000000000 +0000 @@ -45,7 +45,7 @@ private Q_SLOTS: void screenAdded(const QScreen *qscreen); - void screenDestroyed(QObject *qscreen = 0); + void screenRemoved(QScreen *qscreen); Q_SIGNALS: void configChanged(const KScreen::ConfigPtr &config); diff -Nru libkscreen-5.4.2/backends/utils.cpp libkscreen-5.12.0/backends/utils.cpp --- libkscreen-5.4.2/backends/utils.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/backends/utils.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,70 @@ +/************************************************************************************* + * Copyright 2018 Daniel Vrátil * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#include "utils.h" + +#include + +KScreen::Output::Type Utils::guessOutputType(const QString &type, const QString &name) +{ + static const auto embedded = { QLatin1String("LVDS"), + QLatin1String("IDP"), + QLatin1String("EDP"), + QLatin1String("LCD") }; + + for (const QLatin1String &pre : embedded) { + if (name.toUpper().startsWith(pre)) { + return KScreen::Output::Panel; + } + } + + if (type.contains("VGA")) { + return KScreen::Output::VGA; + } else if (type.contains("DVI")) { + return KScreen::Output::DVI; + } else if (type.contains("DVI-I")) { + return KScreen::Output::DVII; + } else if (type.contains("DVI-A")) { + return KScreen::Output::DVIA; + } else if (type.contains("DVI-D")) { + return KScreen::Output::DVID; + } else if (type.contains("HDMI")) { + return KScreen::Output::HDMI; + } else if (type.contains("Panel")) { + return KScreen::Output::Panel; + } else if (type.contains("TV-Composite")) { + return KScreen::Output::TVComposite; + } else if (type.contains("TV-SVideo")) { + return KScreen::Output::TVSVideo; + } else if (type.contains("TV-Component")) { + return KScreen::Output::TVComponent; + } else if (type.contains("TV-SCART")) { + return KScreen::Output::TVSCART; + } else if (type.contains("TV-C4")) { + return KScreen::Output::TVC4; + } else if (type.contains("TV")) { + return KScreen::Output::TV; + } else if (type.contains("DisplayPort") || type.startsWith("DP")) { + return KScreen::Output::DisplayPort; + } else if (type.contains("unknown")) { + return KScreen::Output::Unknown; + } else { + return KScreen::Output::Unknown; + } +} + diff -Nru libkscreen-5.4.2/backends/utils.h libkscreen-5.12.0/backends/utils.h --- libkscreen-5.4.2/backends/utils.h 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/backends/utils.h 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,30 @@ +/************************************************************************************* + * Copyright 2018 Daniel Vrátil * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#ifndef KSCREEN_BACKEND_UTILS_H_ +#define KSCREEN_BACKEND_UTILS_H_ + +#include + +namespace Utils { + +KScreen::Output::Type guessOutputType(const QString &type, const QString &name); + +} + +#endif diff -Nru libkscreen-5.4.2/backends/xcbeventlistener.cpp libkscreen-5.12.0/backends/xcbeventlistener.cpp --- libkscreen-5.4.2/backends/xcbeventlistener.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/backends/xcbeventlistener.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -36,8 +36,6 @@ m_versionMinor(0), m_window(0) { - QLoggingCategory::setFilterRules(QStringLiteral("kscreen.xcb.helper = true")); - xcb_connection_t* c = QX11Info::connection(); xcb_prefetch_extension_data(c, &xcb_randr_id); auto cookie = xcb_randr_query_version(c, XCB_RANDR_MAJOR_VERSION, XCB_RANDR_MINOR_VERSION); @@ -189,7 +187,7 @@ } else if(randrEvent->subCode == XCB_RANDR_NOTIFY_OUTPUT_CHANGE) { xcb_randr_output_change_t output = randrEvent->u.oc; - qCDebug(KSCREEN_XCB_HELPER) << "RRotify_OutputChange"; + qCDebug(KSCREEN_XCB_HELPER) << "RRNotify_OutputChange"; qCDebug(KSCREEN_XCB_HELPER) << "\tOutput: " << output.output; qCDebug(KSCREEN_XCB_HELPER) << "\tCRTC: " << output.crtc; qCDebug(KSCREEN_XCB_HELPER) << "\tMode: " << output.mode; diff -Nru libkscreen-5.4.2/backends/xcbwrapper.cpp libkscreen-5.12.0/backends/xcbwrapper.cpp --- libkscreen-5.4.2/backends/xcbwrapper.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/backends/xcbwrapper.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -51,7 +51,7 @@ } } - return Q_NULLPTR; + return nullptr; } diff -Nru libkscreen-5.4.2/backends/xrandr/CMakeLists.txt libkscreen-5.12.0/backends/xrandr/CMakeLists.txt --- libkscreen-5.4.2/backends/xrandr/CMakeLists.txt 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/backends/xrandr/CMakeLists.txt 2018-02-01 13:45:54.000000000 +0000 @@ -11,6 +11,7 @@ xrandrscreen.cpp ../xcbwrapper.cpp ../xcbeventlistener.cpp + ../utils.cpp ) add_library(KSC_XRandR MODULE ${xrandr_SRCS}) diff -Nru libkscreen-5.4.2/backends/xrandr/xrandr.cpp libkscreen-5.12.0/backends/xrandr/xrandr.cpp --- libkscreen-5.4.2/backends/xrandr/xrandr.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/backends/xrandr/xrandr.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -48,7 +48,7 @@ using namespace KScreen; -Q_LOGGING_CATEGORY(KSCREEN_XRANDR, "kscreen.xrandr"); +Q_LOGGING_CATEGORY(KSCREEN_XRANDR, "kscreen.xrandr") XRandR::XRandR() : KScreen::AbstractBackend() @@ -56,8 +56,6 @@ , m_isValid(false) , m_configChangeCompressor(0) { - QLoggingCategory::setFilterRules(QLatin1Literal("kscreen.xrandr.debug = true")); - qRegisterMetaType("xcb_randr_output_t"); qRegisterMetaType("xcb_randr_crtc_t"); qRegisterMetaType("xcb_randr_mode_t"); @@ -187,12 +185,16 @@ void XRandR::screenChanged(xcb_randr_rotation_t rotation, const QSize &sizePx, const QSize &sizeMm) { - Q_UNUSED(rotation); Q_UNUSED(sizeMm); + QSize newSizePx = sizePx; + if (rotation == XCB_RANDR_ROTATION_ROTATE_90 || rotation == XCB_RANDR_ROTATION_ROTATE_270) { + newSizePx.transpose(); + } + XRandRScreen *xScreen = s_internalConfig->screen(); Q_ASSERT(xScreen); - xScreen->update(sizePx); + xScreen->update(newSizePx); m_configChangeCompressor->start(); } diff -Nru libkscreen-5.4.2/backends/xrandr/xrandr.h libkscreen-5.12.0/backends/xrandr/xrandr.h --- libkscreen-5.4.2/backends/xrandr/xrandr.h 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/backends/xrandr/xrandr.h 2018-02-01 13:45:54.000000000 +0000 @@ -45,12 +45,12 @@ explicit XRandR(); virtual ~XRandR(); - virtual QString name() const; - virtual QString serviceName() const; - virtual KScreen::ConfigPtr config() const; - virtual void setConfig(const KScreen::ConfigPtr &config); - virtual bool isValid() const; - virtual QByteArray edid(int outputId) const; + QString name() const Q_DECL_OVERRIDE; + QString serviceName() const Q_DECL_OVERRIDE; + KScreen::ConfigPtr config() const Q_DECL_OVERRIDE; + void setConfig(const KScreen::ConfigPtr &config) Q_DECL_OVERRIDE; + bool isValid() const Q_DECL_OVERRIDE; + QByteArray edid(int outputId) const Q_DECL_OVERRIDE; static quint8 *outputEdid(xcb_randr_output_t outputId, size_t &len); static xcb_randr_get_screen_resources_reply_t* screenResources(); diff -Nru libkscreen-5.4.2/backends/xrandr/xrandrconfig.cpp libkscreen-5.12.0/backends/xrandr/xrandrconfig.cpp --- libkscreen-5.4.2/backends/xrandr/xrandrconfig.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/backends/xrandr/xrandrconfig.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -37,7 +37,7 @@ XRandRConfig::XRandRConfig() : QObject() - , m_screen(Q_NULLPTR) + , m_screen(nullptr) { m_screen = new XRandRScreen(this); @@ -105,6 +105,8 @@ KScreen::ConfigPtr XRandRConfig::toKScreenConfig() const { KScreen::ConfigPtr config(new KScreen::Config); + auto features = Config::Feature::Writable | Config::Feature::PrimaryDisplay; + config->setSupportedFeatures(features); KScreen::OutputList kscreenOutputs; for (auto iter = m_outputs.constBegin(); iter != m_outputs.constEnd(); ++iter) { @@ -198,7 +200,7 @@ // qDebug() << kRealBacktrace(256); printConfig(config); printInternalCond(); - return; + continue; } // If the output would not fit into new screen size, we need to disable @@ -493,9 +495,10 @@ { xcb_randr_output_t outputs[1] { static_cast(kscreenOutput->id()) }; - XRandRCrtc *freeCrtc = Q_NULLPTR; + XRandRCrtc *freeCrtc = nullptr; qCDebug(KSCREEN_XRANDR) << m_crtcs; Q_FOREACH (XRandRCrtc *crtc, m_crtcs) { + crtc->update(); qCDebug(KSCREEN_XRANDR) << "Testing CRTC" << crtc->crtc(); qCDebug(KSCREEN_XRANDR) << "\tFree:" << crtc->isFree(); qCDebug(KSCREEN_XRANDR) << "\tMode:" << crtc->mode(); @@ -512,17 +515,19 @@ return false; } + const int modeId = kscreenOutput->currentMode() ? kscreenOutput->currentModeId().toInt() : kscreenOutput->preferredModeId().toInt(); + qCDebug(KSCREEN_XRANDR) << "RRSetCrtcConfig (enable output)"; qCDebug(KSCREEN_XRANDR) << "\tOutput:" << kscreenOutput->id() << "(" << kscreenOutput->name() << ")"; qCDebug(KSCREEN_XRANDR) << "\tNew CRTC:" << freeCrtc->crtc(); qCDebug(KSCREEN_XRANDR) << "\tPos:" << kscreenOutput->pos(); - qCDebug(KSCREEN_XRANDR) << "\tMode:" << kscreenOutput->currentModeId() << "(" << kscreenOutput->currentMode()->size() << ")"; + qCDebug(KSCREEN_XRANDR) << "\tMode:" << kscreenOutput->currentMode() << "Preferred:" << kscreenOutput->preferredModeId(); qCDebug(KSCREEN_XRANDR) << "\tRotation:" << kscreenOutput->rotation(); auto cookie = xcb_randr_set_crtc_config(XCB::connection(), freeCrtc->crtc(), XCB_CURRENT_TIME, XCB_CURRENT_TIME, kscreenOutput->pos().rx(), kscreenOutput->pos().ry(), - kscreenOutput->currentModeId().toInt(), + modeId, kscreenOutput->rotation(), 1, outputs); XCB::ScopedPointer reply(xcb_randr_set_crtc_config_reply(XCB::connection(), cookie, NULL)); @@ -534,7 +539,7 @@ if (reply->status == XCB_RANDR_SET_CONFIG_SUCCESS) { XRandROutput *xOutput = output(kscreenOutput->id()); - xOutput->update(freeCrtc->crtc(), kscreenOutput->currentModeId().toInt(), + xOutput->update(freeCrtc->crtc(), modeId, XCB_RANDR_CONNECTION_CONNECTED, kscreenOutput->isPrimary()); } return (reply->status == XCB_RANDR_SET_CONFIG_SUCCESS); @@ -544,16 +549,18 @@ { XRandROutput *xOutput = output(kscreenOutput->id()); Q_ASSERT(xOutput); - Q_ASSERT(xOutput->crtc()); if (!xOutput->crtc()) { - qCWarning(KSCREEN_XRANDR) << "Attempting to change output without valid CRTC"; + qCDebug(KSCREEN_XRANDR) << "Output" << kscreenOutput->id() << "has no CRTC, falling back to enableOutput()"; + return enableOutput(kscreenOutput); } + int modeId = kscreenOutput->currentMode() ? kscreenOutput->currentModeId().toInt() : kscreenOutput->preferredModeId().toInt(); + qCDebug(KSCREEN_XRANDR) << "RRSetCrtcConfig (change output)"; qCDebug(KSCREEN_XRANDR) << "\tOutput:" << kscreenOutput->id() << "(" << kscreenOutput->name() << ")"; qCDebug(KSCREEN_XRANDR) << "\tCRTC:" << xOutput->crtc()->crtc(); qCDebug(KSCREEN_XRANDR) << "\tPos:" << kscreenOutput->pos(); - qCDebug(KSCREEN_XRANDR) << "\tMode:" << kscreenOutput->currentModeId() << "(" << kscreenOutput->currentMode()->size() << ")"; + qCDebug(KSCREEN_XRANDR) << "\tMode:" << modeId << kscreenOutput->currentMode(); qCDebug(KSCREEN_XRANDR) << "\tRotation:" << kscreenOutput->rotation(); xcb_randr_output_t outputs[1] { static_cast(kscreenOutput->id()) }; @@ -561,7 +568,7 @@ auto cookie = xcb_randr_set_crtc_config(XCB::connection(), xOutput->crtc()->crtc(), XCB_CURRENT_TIME, XCB_CURRENT_TIME, kscreenOutput->pos().rx(), kscreenOutput->pos().ry(), - kscreenOutput->currentModeId().toInt(), + modeId, kscreenOutput->rotation(), 1, outputs); XCB::ScopedPointer reply(xcb_randr_set_crtc_config_reply(XCB::connection(), cookie, NULL)); @@ -572,7 +579,7 @@ qCDebug(KSCREEN_XRANDR) << "\tResult: " << reply->status; if (reply->status == XCB_RANDR_SET_CONFIG_SUCCESS) { - xOutput->update(xOutput->crtc()->crtc(), kscreenOutput->currentModeId().toInt(), + xOutput->update(xOutput->crtc()->crtc(), modeId, XCB_RANDR_CONNECTION_CONNECTED, kscreenOutput->isPrimary()); } return (reply->status == XCB_RANDR_SET_CONFIG_SUCCESS); diff -Nru libkscreen-5.4.2/backends/xrandr/xrandrcrtc.cpp libkscreen-5.12.0/backends/xrandr/xrandrcrtc.cpp --- libkscreen-5.4.2/backends/xrandr/xrandrcrtc.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/backends/xrandr/xrandrcrtc.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -66,6 +66,7 @@ bool XRandRCrtc::connectOutput(xcb_randr_output_t output) { + update(); qCDebug(KSCREEN_XRANDR) << "Connected output" << output << "to CRTC" << m_crtc; if (!m_possibleOutputs.contains(output)) { qCDebug(KSCREEN_XRANDR) << "Output" << output << "is not an allowed output for CRTC" << m_crtc; @@ -80,6 +81,7 @@ void XRandRCrtc::disconectOutput(xcb_randr_output_t output) { + update(); qCDebug(KSCREEN_XRANDR) << "Disconnected output" << output << "from CRTC" << m_crtc; const int index = m_outputs.indexOf(output); if (index > -1) { @@ -104,6 +106,8 @@ for (int i = 0; i < crtcInfo->num_possible_outputs; ++i) { m_possibleOutputs.append(possible[i]); } + + m_outputs.clear(); xcb_randr_output_t *outputs = xcb_randr_get_crtc_info_outputs(crtcInfo); for (int i = 0; i < crtcInfo->num_outputs; ++i) { m_outputs.append(outputs[i]); diff -Nru libkscreen-5.4.2/backends/xrandr/xrandroutput.cpp libkscreen-5.12.0/backends/xrandr/xrandroutput.cpp --- libkscreen-5.4.2/backends/xrandr/xrandroutput.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/backends/xrandr/xrandroutput.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -23,6 +23,7 @@ #include "xrandr.h" #include "output.h" #include "config.h" +#include "../utils.h" #include @@ -55,7 +56,7 @@ bool XRandROutput::isEnabled() const { - return m_crtc != Q_NULLPTR && m_crtc->mode() != XCB_NONE; + return m_crtc != nullptr && m_crtc->mode() != XCB_NONE; } bool XRandROutput::isPrimary() const @@ -86,7 +87,7 @@ XRandRMode* XRandROutput::currentMode() const { if (!m_crtc) { - return Q_NULLPTR; + return nullptr; } int modeId = m_crtc->mode(); if (!m_modes.contains(modeId)) { @@ -141,7 +142,7 @@ if (isConnected() != (conn == XCB_RANDR_CONNECTION_CONNECTED)) { if (conn == XCB_RANDR_CONNECTION_CONNECTED) { // New monitor has been connected, refresh everything - init(); + init(); } else { // Disconnected m_connected = conn; @@ -152,7 +153,16 @@ qDeleteAll(m_modes); m_modes.clear(); m_preferredModes.clear(); + m_edid.clear(); } + } else if (conn == XCB_RANDR_CONNECTION_CONNECTED) { + // the output changed in some way, let's update the internal + // list of modes, as it may have changed + XCB::OutputInfo outputInfo(m_id, XCB_TIME_CURRENT_TIME); + if (outputInfo) { + updateModes(outputInfo); + } + } // A monitor has been enabled or disabled @@ -160,7 +170,7 @@ // crtc->mode may already be unset due to xcb_randr_crtc_tChangeNotify coming before // xcb_randr_output_tChangeNotify and reseting the CRTC mode - if ((m_crtc == Q_NULLPTR) != (crtc == XCB_NONE)) { + if ((m_crtc == nullptr) != (crtc == XCB_NONE)) { if (crtc == XCB_NONE && mode == XCB_NONE) { // Monitor has been disabled m_crtc->disconectOutput(m_id); @@ -213,12 +223,12 @@ void XRandROutput::updateModes(const XCB::OutputInfo &outputInfo) { /* Init modes */ - auto screenResources = XRandR::screenResources(); + XCB::ScopedPointer screenResources(XRandR::screenResources()); Q_ASSERT(screenResources); if (!screenResources) { return; } - xcb_randr_mode_info_t *modes = xcb_randr_get_screen_resources_modes(screenResources); + xcb_randr_mode_info_t *modes = xcb_randr_get_screen_resources_modes(screenResources.data()); xcb_randr_mode_t *outputModes = xcb_randr_get_output_info_modes(outputInfo.data()); m_preferredModes.clear(); @@ -245,63 +255,12 @@ KScreen::Output::Type XRandROutput::fetchOutputType(xcb_randr_output_t outputId, const QString &name) { - const QByteArray type = typeFromProperty(outputId); + QByteArray type = typeFromProperty(outputId); if (type.isEmpty()) { - return typeFromName(name); - } - - if (type.contains("VGA")) { - return KScreen::Output::VGA; - } else if (type.contains("DVI")) { - return KScreen::Output::DVI; - } else if (type.contains("DVI-I")) { - return KScreen::Output::DVII; - } else if (type.contains("DVI-A")) { - return KScreen::Output::DVIA; - } else if (type.contains("DVI-D")) { - return KScreen::Output::DVID; - } else if (type.contains("HDMI")) { - return KScreen::Output::HDMI; - } else if (type.contains("Panel")) { - return KScreen::Output::Panel; - } else if (type.contains("TV")) { - return KScreen::Output::TV; - } else if (type.contains("TV-Composite")) { - return KScreen::Output::TVComposite; - } else if (type.contains("TV-SVideo")) { - return KScreen::Output::TVSVideo; - } else if (type.contains("TV-Component")) { - return KScreen::Output::TVComponent; - } else if (type.contains("TV-SCART")) { - return KScreen::Output::TVSCART; - } else if (type.contains("TV-C4")) { - return KScreen::Output::TVC4; - } else if (type.contains("DisplayPort")) { - return KScreen::Output::DisplayPort; - } else if (type.contains("unknown")) { - return KScreen::Output::Unknown; - } else { -// qCDebug(KSCREEN_XRANDR) << "Output Type not translated:" << type; - } - - return KScreen::Output::Unknown; - -} - -KScreen::Output::Type XRandROutput::typeFromName(const QString &name) -{ - static const QStringList embedded = QStringList() << QLatin1String("LVDS") - << QLatin1String("IDP") - << QLatin1String("EDP") - << QLatin1String("LCD"); - - Q_FOREACH(const QString &pre, embedded) { - if (name.toUpper().startsWith(pre)) { - return KScreen::Output::Panel; - } + type = name.toLocal8Bit(); } - return KScreen::Output::Unknown; + return Utils::guessOutputType(type, name); } QByteArray XRandROutput::typeFromProperty(xcb_randr_output_t outputId) @@ -315,7 +274,7 @@ char *connectorType; - auto cookie = xcb_randr_get_output_property(XCB::connection(), outputId, atomType, + auto cookie = xcb_randr_get_output_property(XCB::connection(), outputId, atomType->atom, XCB_ATOM_ANY, 0, 100, false, false); XCB::ScopedPointer reply(xcb_randr_get_output_property_reply(XCB::connection(), cookie, NULL)); if (!reply) { diff -Nru libkscreen-5.4.2/backends/xrandr/xrandroutput.h libkscreen-5.12.0/backends/xrandr/xrandroutput.h --- libkscreen-5.4.2/backends/xrandr/xrandroutput.h 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/backends/xrandr/xrandroutput.h 2018-02-01 13:45:54.000000000 +0000 @@ -75,7 +75,6 @@ void updateModes(const XCB::OutputInfo &outputInfo); static KScreen::Output::Type fetchOutputType(xcb_randr_output_t outputId, const QString &name); - static KScreen::Output::Type typeFromName(const QString &name); static QByteArray typeFromProperty(xcb_randr_output_t outputId); XRandRConfig *m_config; diff -Nru libkscreen-5.4.2/backends/xrandr/xrandrscreen.cpp libkscreen-5.12.0/backends/xrandr/xrandrscreen.cpp --- libkscreen-5.4.2/backends/xrandr/xrandrscreen.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/backends/xrandr/xrandrscreen.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -62,7 +62,9 @@ kscreenScreen->setMaxSize(m_maxSize); kscreenScreen->setMinSize(m_minSize); kscreenScreen->setCurrentSize(m_currentSize); - kscreenScreen->setMaxActiveOutputsCount(XRandR::screenResources()->num_crtcs); + + XCB::ScopedPointer screenResources(XRandR::screenResources()); + kscreenScreen->setMaxActiveOutputsCount(screenResources->num_crtcs); return kscreenScreen; } diff -Nru libkscreen-5.4.2/backends/xrandr1.1/xrandr11.cpp libkscreen-5.12.0/backends/xrandr1.1/xrandr11.cpp --- libkscreen-5.4.2/backends/xrandr1.1/xrandr11.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/backends/xrandr1.1/xrandr11.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -39,8 +39,6 @@ , m_currentConfig(new KScreen::Config) , m_currentTimestamp(0) { - QLoggingCategory::setFilterRules(QLatin1Literal("kscreen.xrandr11.debug = true")); - xcb_generic_error_t *error = 0; xcb_randr_query_version_reply_t* version; version = xcb_randr_query_version_reply(XCB::connection(), @@ -91,6 +89,8 @@ KScreen::ConfigPtr XRandR11::config() const { KScreen::ConfigPtr config(new KScreen::Config); + auto features = KScreen::Config::Feature::Writable | KScreen::Config::Feature::PrimaryDisplay; + config->setSupportedFeatures(features); const int screenId = QX11Info::appScreen(); xcb_screen_t* xcbScreen = XCB::screenOfDisplay(XCB::connection(), screenId); diff -Nru libkscreen-5.4.2/backends/xrandr1.1/xrandr11.h libkscreen-5.12.0/backends/xrandr1.1/xrandr11.h --- libkscreen-5.4.2/backends/xrandr1.1/xrandr11.h 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/backends/xrandr1.1/xrandr11.h 2018-02-01 13:45:54.000000000 +0000 @@ -36,11 +36,11 @@ explicit XRandR11(); virtual ~XRandR11(); - virtual QString name() const; - virtual QString serviceName() const; - virtual KScreen::ConfigPtr config() const; - virtual void setConfig(const KScreen::ConfigPtr &config); - virtual bool isValid() const; + QString name() const Q_DECL_OVERRIDE; + QString serviceName() const Q_DECL_OVERRIDE; + KScreen::ConfigPtr config() const Q_DECL_OVERRIDE; + void setConfig(const KScreen::ConfigPtr &config) Q_DECL_OVERRIDE; + bool isValid() const Q_DECL_OVERRIDE; private Q_SLOTS: void updateConfig(); diff -Nru libkscreen-5.4.2/debian/changelog libkscreen-5.12.0/debian/changelog --- libkscreen-5.4.2/debian/changelog 2015-10-06 05:52:07.000000000 +0000 +++ libkscreen-5.12.0/debian/changelog 2018-02-07 10:48:45.000000000 +0000 @@ -1,3 +1,304 @@ +libkscreen (4:5.12.0-0neon+neptune1) stretch; urgency=medium + + * New upstream release packaged for Neptune + + -- Leszek Lesner Wed, 07 Feb 2018 10:48:45 +0000 + +libkscreen (4:5.12.0-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Fri, 02 Feb 2018 13:37:39 +0000 + +libkscreen (4:5.11.5-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Tue, 02 Jan 2018 21:42:35 +0000 + +libkscreen (4:5.11.4-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Tue, 28 Nov 2017 17:00:30 +0000 + +libkscreen (4:5.11.3-0neon) bionic; urgency=medium + + * New release + + -- Neon CI Tue, 07 Nov 2017 15:03:13 +0000 + +libkscreen (4:5.11.2-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Tue, 24 Oct 2017 16:32:22 +0000 + +libkscreen (4:5.11.1-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Tue, 17 Oct 2017 13:46:31 +0000 + +libkscreen (4:5.11.0-0neon) UNRELEASED; urgency=medium + + * new release + + -- Jonathan Riddell Fri, 06 Oct 2017 16:31:49 +0100 + +libkscreen (4:5.10.5-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Wed, 23 Aug 2017 09:54:35 +0000 + +libkscreen (4:5.10.4-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Tue, 18 Jul 2017 13:52:03 +0000 + +libkscreen (4:5.10.3-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Tue, 27 Jun 2017 12:10:59 +0000 + +libkscreen (4:5.10.2-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Tue, 13 Jun 2017 22:14:03 +0000 + +libkscreen (4:5.10.1-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Tue, 06 Jun 2017 17:31:45 +0000 + +libkscreen (4:5.10.0-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Fri, 26 May 2017 15:43:59 +0000 + +libkscreen (4:5.9.5-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Tue, 25 Apr 2017 15:43:23 +0000 + +libkscreen (4:5.9.4-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Tue, 21 Mar 2017 15:02:24 +0000 + +libkscreen (4:5.9.3-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Tue, 28 Feb 2017 16:27:39 +0000 + +libkscreen (4:5.9.2-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Tue, 14 Feb 2017 17:37:55 +0000 + +libkscreen (4:5.9.1-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Tue, 07 Feb 2017 15:10:22 +0000 + +libkscreen (4:5.9.0-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Mon, 30 Jan 2017 11:50:46 +0000 + +libkscreen (4:5.8.6-0neon) UNRELEASED; urgency=medium + + * New release + * New Plasma LTS release + * New LTS release + + -- Jonathan Riddell Wed, 25 Oct 2017 14:56:44 +0100 + +libkscreen (4:5.8.6-0neon) xenial; urgency=medium + + * New Plasma LTS release + + -- Jonathan Riddell Tue, 21 Feb 2017 17:16:31 +0000 + +libkscreen (4:5.8.5-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Tue, 27 Dec 2016 12:51:05 +0000 + +libkscreen (4:5.8.4-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Tue, 22 Nov 2016 14:36:25 +0000 + +libkscreen (4:5.8.3-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Tue, 01 Nov 2016 13:27:05 +0000 + +libkscreen (4:5.8.2-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Tue, 18 Oct 2016 15:25:33 +0000 + +libkscreen (4:5.8.1-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Tue, 11 Oct 2016 14:38:23 +0000 + +libkscreen (4:5.8.0-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Fri, 30 Sep 2016 11:29:53 +0000 + +libkscreen (4:5.7.5-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Tue, 13 Sep 2016 13:47:25 +0000 + +libkscreen (4:5.7.4-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Tue, 23 Aug 2016 17:28:52 +0000 + +libkscreen (4:5.7.3-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Tue, 02 Aug 2016 12:04:35 +0000 + +libkscreen (4:5.7.2-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Tue, 19 Jul 2016 13:47:25 +0000 + +libkscreen (4:5.7.1-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Tue, 12 Jul 2016 16:06:27 +0000 + +libkscreen (4:5.7.0-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Mon, 04 Jul 2016 15:07:08 +0000 + +libkscreen (4:5.6.5-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Tue, 14 Jun 2016 14:14:52 +0000 + +libkscreen (4:5.6.4-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Wed, 11 May 2016 09:41:00 +0000 + +libkscreen (4:5.6.3-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Tue, 19 Apr 2016 16:56:01 +0000 + +libkscreen (4:5.6.2-0neon) xenial; urgency=medium + + * New release + + -- Neon CI Fri, 08 Apr 2016 11:43:33 +0000 + +libkscreen (4:5.5.4-0ubuntu1) UNRELEASED; urgency=medium + + [ Scarlett Clark ] + * New upstream release Xenial + * The .so in this tar is version 6. Update all + files to reflect that. + * Add the renamed files in git. + + [ Clive Johnston ] + * new upstream release + + [ Philip Muškovac ] + * Set the SOVERSION back to 6 in the symbols file + + [ Clive Johnston ] + * New upstream release + + [ Scarlett Clark ] + * merge unstable to get debian merge into archive. + Left so verion at 6 for compatibility with release tar. + * Fix control file to reflect so version 6. + * Some more cleanup to fix archive. + * Fix unstable by bumping so to 7 to match master. + * Add the missing files. + + [ Clive Johnston ] + * New upstream release + + -- Clive Johnston Wed, 27 Jan 2016 20:13:39 +0000 + +libkscreen (4:5.5.1-0ubuntu2) UNRELEASED; urgency=medium + + [ Scarlett Clark ] + * Fix unstable build to reflect the .so version of 7. + * Add the new files and fix the install file. + * Fix symbols file merge markers. + * Fix the .so version in the symbols file. + * Refresh symbols. + + [ Bhushan Shah ] + * Add build-dep to kwayland-dev + + -- Scarlett Clark Sat, 19 Dec 2015 08:10:24 -0800 + +libkscreen (4:5.5.1-0ubuntu1) UNRELEASED; urgency=medium + + * New upstream release Xenial + * The .so in this tar is version 6. Update all + files to reflect that. + * Add the renamed files in git. + * Debian merge: No remaining changes. + + -- Scarlett Clark Fri, 18 Dec 2015 07:36:47 -0800 + +libkscreen (4:5.4.3-1~) UNRELEASED; urgency=medium + + * New upstream release (5.4.3). + + -- Maximiliano Curia Thu, 05 Nov 2015 16:57:17 +0100 + +libkscreen (4:5.4.3-0ubuntu1) xenial; urgency=medium + + [ Scarlett Clark ] + * Vivid backport + * New upstream bugfix release + + [ Philip Muškovac ] + * New upstream bugfix release (LP: #1518598) + + -- Philip Muškovac Sun, 22 Nov 2015 16:36:03 +0100 + libkscreen (4:5.4.2-1) unstable; urgency=medium * New upstream release (5.4.2). @@ -5,12 +306,30 @@ -- Maximiliano Curia Tue, 06 Oct 2015 07:52:07 +0200 +libkscreen (4:5.4.2-0ubuntu2) xenial; urgency=medium + + * Fix autopackagetests by adding allow-stderr to the requirements. + + -- Philip Muškovac Tue, 03 Nov 2015 15:34:53 +0100 + +libkscreen (4:5.4.2-0ubuntu1) wily; urgency=medium + + * New upstream release + + -- Scarlett Clark Fri, 02 Oct 2015 15:57:41 +0100 + libkscreen (4:5.4.1-1) unstable; urgency=medium * New upstream release (5.4.1). -- Maximiliano Curia Fri, 11 Sep 2015 18:45:14 +0200 +libkscreen (4:5.4.1-0ubuntu1) wily; urgency=medium + + * new upstream release + + -- Jonathan Riddell Tue, 08 Sep 2015 10:20:02 +0100 + libkscreen (4:5.4.0-1) unstable; urgency=medium * New upstream release (5.4.0). @@ -18,6 +337,18 @@ -- Maximiliano Curia Thu, 03 Sep 2015 17:59:24 +0200 +libkscreen (4:5.4.0-0ubuntu1) wily; urgency=medium + + * new upstream release + + -- Jonathan Riddell Mon, 31 Aug 2015 15:53:03 +0100 + +libkscreen (4:5.3.95-0ubuntu1) wily; urgency=medium + + * new upstream beta release + + -- Jonathan Riddell Mon, 10 Aug 2015 23:17:17 +0200 + libkscreen (4:5.3.2-2) unstable; urgency=medium * Update symbols files for gcc5 compatibility. (Closes: #791728) @@ -31,6 +362,43 @@ -- Maximiliano Curia Tue, 30 Jun 2015 22:29:10 +0200 +libkscreen (4:5.3.2-0ubuntu2) wily; urgency=medium + + * Non-maintainer upload. + * Update symbols files: mark as optional the symbols gone after + building with GCC 5 + + -- José Manuel Santamaría Lema Wed, 22 Jul 2015 20:00:44 +0200 + +libkscreen (4:5.3.2-0ubuntu1) UNRELEASED; urgency=medium + + * Vivid backport + + -- Scarlett Clark Thu, 02 Jul 2015 11:41:59 -0700 + +libkscreen (4:5.3.2-0ubuntu1) wily; urgency=medium + + * New upstream release + + -- Jonathan Riddell Thu, 02 Jul 2015 12:40:13 +0000 + +libkscreen (4:5.3.1-0ubuntu1) wily; urgency=medium + + [ Scarlett Clark ] + * Manual merge kubuntu_stable. + + [ Jonathan Riddell ] + * Plasma 5.3 beta + * new upstream release + + [ Scarlett Clark ] + * Vivid backport + + [ Jonathan Riddell ] + * New upstream release + + -- Jonathan Riddell Fri, 05 Jun 2015 02:35:42 +0200 + libkscreen (4:5.3.1-1) unstable; urgency=medium * New upstream release (5.3.0). diff -Nru libkscreen-5.4.2/debian/control libkscreen-5.12.0/debian/control --- libkscreen-5.4.2/debian/control 2015-10-06 05:52:07.000000000 +0000 +++ libkscreen-5.12.0/debian/control 2018-02-07 10:48:45.000000000 +0000 @@ -6,6 +6,7 @@ Build-Depends: cmake (>= 2.8.12), debhelper (>= 9), extra-cmake-modules (>= 1.3.0~), + kwayland-dev (>= 4:5.5.1~), libqt5x11extras5-dev (>= 5.4), libx11-dev, libx11-xcb-dev, @@ -22,10 +23,17 @@ Vcs-Browser: http://anonscm.debian.org/cgit/pkg-kde/plasma/libkscreen.git Vcs-Git: git://anonscm.debian.org/pkg-kde/plasma/libkscreen.git +Package: kscreen-doctor +Architecture: any +Depends: ${misc:Depends}, ${shlibs:Depends} +Description: testing tool for libkscreen + A testing and debugging tool for KScreen which allows changes to the + screen setup from the command-line. + Package: libkf5screen-dev Section: libdevel Architecture: any -Depends: libkf5screen6 (= ${binary:Version}), +Depends: libkf5screen7 (= ${binary:Version}), qtbase5-dev (>= 5.4), ${misc:Depends} Description: library for screen management - development files @@ -35,11 +43,11 @@ . This package contains the files necessary for development. -Package: libkf5screen6 +Package: libkf5screen7 Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends} -Breaks: libkf5screen5 (<< 4:5.2.0) -Replaces: libkf5screen5 (<< 4:5.2.0) +Breaks: libkf5screen5 (<< 4:5.2.0), libkf5screen6 +Replaces: libkf5screen5 (<< 4:5.2.0), libkf5screen6 Description: library for screen management - shared library The KDE multiple monitor support is trying be as smart as possible adapting the behavior of it to each use case making the configuration @@ -49,13 +57,14 @@ Package: libkscreen-dbg Section: debug -Priority: extra +Priority: optional Architecture: any Recommends: qtbase5-dbg -Depends: libkf5screen6 (= ${binary:Version}), ${misc:Depends} +Depends: libkf5screen7 (= ${binary:Version}), ${misc:Depends} Description: library for screen management - debug info The KDE multiple monitor support is trying be as smart as possible adapting the behavior of it to each use case making the configuration of monitors as simple as plugging them to your computer. . This package contains the debugging symbols. + diff -Nru libkscreen-5.4.2/debian/kscreen-doctor.install libkscreen-5.12.0/debian/kscreen-doctor.install --- libkscreen-5.4.2/debian/kscreen-doctor.install 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/debian/kscreen-doctor.install 2018-02-07 10:48:45.000000000 +0000 @@ -0,0 +1 @@ +usr/bin/kscreen-doctor diff -Nru libkscreen-5.4.2/debian/libkf5screen6.install libkscreen-5.12.0/debian/libkf5screen6.install --- libkscreen-5.4.2/debian/libkf5screen6.install 2015-10-06 05:52:07.000000000 +0000 +++ libkscreen-5.12.0/debian/libkf5screen6.install 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -usr/lib/*/libKF5Screen.so.5.* -usr/lib/*/libKF5Screen.so.6 -usr/lib/*/libexec/kf5/kscreen_backend_launcher -usr/lib/*/qt5/plugins/kf5/kscreen/ diff -Nru libkscreen-5.4.2/debian/libkf5screen6.symbols libkscreen-5.12.0/debian/libkf5screen6.symbols --- libkscreen-5.4.2/debian/libkf5screen6.symbols 2015-10-06 05:52:07.000000000 +0000 +++ libkscreen-5.12.0/debian/libkf5screen6.symbols 1970-01-01 00:00:00.000000000 +0000 @@ -1,333 +0,0 @@ -# SymbolsHelper-Confirmed: 4:5.4.1 alpha arm64 armel armhf hppa hurd-i386 i386 kfreebsd-amd64 kfreebsd-i386 mips mips64el mipsel powerpc ppc64 ppc64el s390x -KSC_Fake.so libkf5screen6 #MINVER# - qt_plugin_instance@Base 5.1.80 - qt_plugin_query_metadata@Base 5.1.80 -KSC_QScreen.so libkf5screen6 #MINVER# - qt_plugin_instance@Base 5.1.80 - qt_plugin_query_metadata@Base 5.1.80 -KSC_XRandR.so libkf5screen6 #MINVER# - qt_plugin_instance@Base 5.1.80 - qt_plugin_query_metadata@Base 5.1.80 -KSC_XRandR11.so libkf5screen6 #MINVER# - qt_plugin_instance@Base 5.1.80 - qt_plugin_query_metadata@Base 5.1.80 -libKF5Screen.so.6 libkf5screen6 #MINVER# - _ZN7KScreen13ConfigMonitor11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.1.1 - _ZN7KScreen13ConfigMonitor11qt_metacastEPKc@Base 5.1.1 - _ZN7KScreen13ConfigMonitor12removeConfigERK14QSharedPointerINS_6ConfigEE@Base 5.1.1 - _ZN7KScreen13ConfigMonitor16staticMetaObjectE@Base 5.1.1 - _ZN7KScreen13ConfigMonitor20configurationChangedEv@Base 5.1.1 - _ZN7KScreen13ConfigMonitor7Private11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.1.1 - _ZN7KScreen13ConfigMonitor7Private11qt_metacastEPKc@Base 5.1.1 - _ZN7KScreen13ConfigMonitor7Private13updateConfigsERK14QSharedPointerINS_6ConfigEE@Base 5.1.1 - _ZN7KScreen13ConfigMonitor7Private14onBackendReadyEP29OrgKdeKscreenBackendInterface@Base 5.1.1 - _ZN7KScreen13ConfigMonitor7Private15configDestroyedEP7QObject@Base 5.1.1 - _ZN7KScreen13ConfigMonitor7Private16staticMetaObjectE@Base 5.1.1 - _ZN7KScreen13ConfigMonitor7Private17getConfigFinishedEPNS_15ConfigOperationE@Base 5.1.1 - _ZN7KScreen13ConfigMonitor7Private20backendConfigChangedERK4QMapI7QString8QVariantE@Base 5.1.1 - _ZN7KScreen13ConfigMonitor7Private9edidReadyEP23QDBusPendingCallWatcher@Base 5.1.1 - _ZN7KScreen13ConfigMonitor7PrivateC1EPS0_@Base 5.1.1 - _ZN7KScreen13ConfigMonitor7PrivateC2EPS0_@Base 5.1.1 - _ZN7KScreen13ConfigMonitor8instanceEv@Base 5.1.1 - _ZN7KScreen13ConfigMonitor9addConfigERK14QSharedPointerINS_6ConfigEE@Base 5.1.1 - _ZN7KScreen13ConfigMonitorC1Ev@Base 5.1.1 - _ZN7KScreen13ConfigMonitorC2Ev@Base 5.1.1 - _ZN7KScreen13ConfigMonitorD0Ev@Base 5.1.1 - _ZN7KScreen13ConfigMonitorD1Ev@Base 5.1.1 - _ZN7KScreen13ConfigMonitorD2Ev@Base 5.1.1 - _ZN7KScreen14BackendManager11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.1.1 - _ZN7KScreen14BackendManager11qt_metacastEPKc@Base 5.1.1 - _ZN7KScreen14BackendManager12backendReadyEP29OrgKdeKscreenBackendInterface@Base 5.1.1 - _ZN7KScreen14BackendManager12startBackendERK7QString@Base 5.1.1 - _ZN7KScreen14BackendManager14requestBackendEv@Base 5.1.1 - _ZN7KScreen14BackendManager14sMaxCrashCountE@Base 5.1.1 - _ZN7KScreen14BackendManager15shutdownBackendEv@Base 5.1.1 - _ZN7KScreen14BackendManager16emitBackendReadyEv@Base 5.1.1 - _ZN7KScreen14BackendManager16launcherFinishedEiN8QProcess10ExitStatusE@Base 5.1.1 - _ZN7KScreen14BackendManager16staticMetaObjectE@Base 5.1.1 - _ZN7KScreen14BackendManager19backendServiceReadyEv@Base 5.1.1 - _ZN7KScreen14BackendManager19invalidateInterfaceEv@Base 5.1.1 - _ZN7KScreen14BackendManager21launcherDataAvailableEv@Base 5.1.1 - _ZN7KScreen14BackendManager26backendServiceUnregisteredERK7QString@Base 5.1.1 - _ZN7KScreen14BackendManager8instanceEv@Base 5.1.1 - _ZN7KScreen14BackendManager9sInstanceE@Base 5.1.1 - _ZN7KScreen14BackendManagerC1Ev@Base 5.1.1 - _ZN7KScreen14BackendManagerC2Ev@Base 5.1.1 - _ZN7KScreen14BackendManagerD0Ev@Base 5.1.1 - _ZN7KScreen14BackendManagerD1Ev@Base 5.1.1 - _ZN7KScreen14BackendManagerD2Ev@Base 5.1.1 - _ZN7KScreen15AbstractBackend11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.1.1 - _ZN7KScreen15AbstractBackend11qt_metacastEPKc@Base 5.1.1 - _ZN7KScreen15AbstractBackend13configChangedERK14QSharedPointerINS_6ConfigEE@Base 5.1.1 - _ZN7KScreen15AbstractBackend16staticMetaObjectE@Base 5.1.1 - _ZN7KScreen15ConfigOperation10emitResultEv@Base 5.1.1 - _ZN7KScreen15ConfigOperation11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.1.1 - _ZN7KScreen15ConfigOperation11qt_metacastEPKc@Base 5.1.1 - _ZN7KScreen15ConfigOperation16staticMetaObjectE@Base 5.1.1 - _ZN7KScreen15ConfigOperation4execEv@Base 5.1.1 - _ZN7KScreen15ConfigOperation8finishedEPS0_@Base 5.1.1 - _ZN7KScreen15ConfigOperation8setErrorERK7QString@Base 5.1.1 - _ZN7KScreen15ConfigOperationC1EPNS_22ConfigOperationPrivateEP7QObject@Base 5.1.1 - _ZN7KScreen15ConfigOperationC2EPNS_22ConfigOperationPrivateEP7QObject@Base 5.1.1 - _ZN7KScreen15ConfigOperationD0Ev@Base 5.1.1 - _ZN7KScreen15ConfigOperationD1Ev@Base 5.1.1 - _ZN7KScreen15ConfigOperationD2Ev@Base 5.1.1 - (optional=templinst)_ZN7KScreen16ConfigSerializer13serializeListI7QStringEE10QJsonArrayRK5QListIT_E@Base 5.1.1 - (optional=templinst)_ZN7KScreen16ConfigSerializer13serializeListIiEE10QJsonArrayRK5QListIT_E@Base 5.1.1 - _ZN7KScreen16ConfigSerializer13serializeModeERK14QSharedPointerINS_4ModeEE@Base 5.1.1 - _ZN7KScreen16ConfigSerializer13serializeSizeERK5QSize@Base 5.1.1 - _ZN7KScreen16ConfigSerializer14serializePointERK6QPoint@Base 5.1.1 - (optional=templinst)_ZN7KScreen16ConfigSerializer15deserializeListI7QStringEE5QListIT_ERK13QDBusArgument@Base 5.1.1 - (optional=templinst)_ZN7KScreen16ConfigSerializer15deserializeListIiEE5QListIT_ERK13QDBusArgument@Base 5.1.1 - _ZN7KScreen16ConfigSerializer15deserializeModeERK13QDBusArgument@Base 5.1.1 - _ZN7KScreen16ConfigSerializer15deserializeSizeERK13QDBusArgument@Base 5.1.1 - _ZN7KScreen16ConfigSerializer15serializeConfigERK14QSharedPointerINS_6ConfigEE@Base 5.1.1 - _ZN7KScreen16ConfigSerializer15serializeOutputERK14QSharedPointerINS_6OutputEE@Base 5.1.1 - _ZN7KScreen16ConfigSerializer15serializeScreenERK14QSharedPointerINS_6ScreenEE@Base 5.1.1 - _ZN7KScreen16ConfigSerializer16deserializePointERK13QDBusArgument@Base 5.1.1 - _ZN7KScreen16ConfigSerializer17deserializeConfigERK4QMapI7QString8QVariantE@Base 5.1.1 - _ZN7KScreen16ConfigSerializer17deserializeOutputERK13QDBusArgument@Base 5.1.1 - _ZN7KScreen16ConfigSerializer17deserializeScreenERK13QDBusArgument@Base 5.1.1 - _ZN7KScreen18GetConfigOperation11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.1.1 - _ZN7KScreen18GetConfigOperation11qt_metacastEPKc@Base 5.1.1 - _ZN7KScreen18GetConfigOperation16staticMetaObjectE@Base 5.1.1 - _ZN7KScreen18GetConfigOperation5startEv@Base 5.1.1 - _ZN7KScreen18GetConfigOperationC1E6QFlagsINS0_6OptionEEP7QObject@Base 5.1.1 - _ZN7KScreen18GetConfigOperationC2E6QFlagsINS0_6OptionEEP7QObject@Base 5.1.1 - _ZN7KScreen18GetConfigOperationD0Ev@Base 5.1.1 - _ZN7KScreen18GetConfigOperationD1Ev@Base 5.1.1 - _ZN7KScreen18GetConfigOperationD2Ev@Base 5.1.1 - _ZN7KScreen18SetConfigOperation11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.1.1 - _ZN7KScreen18SetConfigOperation11qt_metacastEPKc@Base 5.1.1 - _ZN7KScreen18SetConfigOperation16staticMetaObjectE@Base 5.1.1 - _ZN7KScreen18SetConfigOperation5startEv@Base 5.1.1 - _ZN7KScreen18SetConfigOperationC1ERK14QSharedPointerINS_6ConfigEEP7QObject@Base 5.1.1 - _ZN7KScreen18SetConfigOperationC2ERK14QSharedPointerINS_6ConfigEEP7QObject@Base 5.1.1 - _ZN7KScreen18SetConfigOperationD0Ev@Base 5.1.1 - _ZN7KScreen18SetConfigOperationD1Ev@Base 5.1.1 - _ZN7KScreen18SetConfigOperationD2Ev@Base 5.1.1 - _ZN7KScreen4Edid11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.1.1 - _ZN7KScreen4Edid11qt_metacastEPKc@Base 5.1.1 - _ZN7KScreen4Edid16staticMetaObjectE@Base 5.1.1 - _ZN7KScreen4Edid7Private5parseERK10QByteArray@Base 5.1.1 - _ZN7KScreen4EdidC1EPNS0_7PrivateE@Base 5.1.1 - _ZN7KScreen4EdidC1ERK10QByteArrayP7QObject@Base 5.1.1 - _ZN7KScreen4EdidC1Ev@Base 5.1.1 - _ZN7KScreen4EdidC2EPNS0_7PrivateE@Base 5.1.1 - _ZN7KScreen4EdidC2ERK10QByteArrayP7QObject@Base 5.1.1 - _ZN7KScreen4EdidC2Ev@Base 5.1.1 - _ZN7KScreen4EdidD0Ev@Base 5.1.1 - _ZN7KScreen4EdidD1Ev@Base 5.1.1 - _ZN7KScreen4EdidD2Ev@Base 5.1.1 - _ZN7KScreen4Mode11modeChangedEv@Base 5.1.1 - _ZN7KScreen4Mode11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.1.1 - _ZN7KScreen4Mode11qt_metacastEPKc@Base 5.1.1 - _ZN7KScreen4Mode14setRefreshRateEf@Base 5.1.1 - _ZN7KScreen4Mode16staticMetaObjectE@Base 5.1.1 - _ZN7KScreen4Mode5setIdERK7QString@Base 5.1.1 - _ZN7KScreen4Mode7setNameERK7QString@Base 5.1.1 - _ZN7KScreen4Mode7setSizeERK5QSize@Base 5.1.1 - _ZN7KScreen4ModeC1EPNS0_7PrivateE@Base 5.1.1 - _ZN7KScreen4ModeC1Ev@Base 5.1.1 - _ZN7KScreen4ModeC2EPNS0_7PrivateE@Base 5.1.1 - _ZN7KScreen4ModeC2Ev@Base 5.1.1 - _ZN7KScreen4ModeD0Ev@Base 5.1.1 - _ZN7KScreen4ModeD1Ev@Base 5.1.1 - _ZN7KScreen4ModeD2Ev@Base 5.1.1 - _ZN7KScreen6Config10setOutputsE4QMapIi14QSharedPointerINS_6OutputEEE@Base 5.1.1 - _ZN7KScreen6Config11outputAddedERK14QSharedPointerINS_6OutputEE@Base 5.1.1 - _ZN7KScreen6Config11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.1.1 - _ZN7KScreen6Config11qt_metacastEPKc@Base 5.1.1 - _ZN7KScreen6Config12canBeAppliedERK14QSharedPointerIS0_E6QFlagsINS0_12ValidityFlagEE@Base 4:5.3.0 - _ZN7KScreen6Config12canBeAppliedERK14QSharedPointerIS0_E@Base 5.1.1 - _ZN7KScreen6Config12removeOutputEi@Base 5.1.1 - _ZN7KScreen6Config13outputRemovedEi@Base 5.1.1 - _ZN7KScreen6Config16setPrimaryOutputERK14QSharedPointerINS_6OutputEE@Base 5.1.1 - _ZN7KScreen6Config16staticMetaObjectE@Base 5.1.1 - _ZN7KScreen6Config20primaryOutputChangedERK14QSharedPointerINS_6OutputEE@Base 5.1.1 - _ZN7KScreen6Config5applyERK14QSharedPointerIS0_E@Base 5.1.1 - _ZN7KScreen6Config7Private11qt_metacallEN11QMetaObject4CallEiPPv@Base 4:5.3.0 - _ZN7KScreen6Config7Private11qt_metacastEPKc@Base 4:5.3.0 - _ZN7KScreen6Config7Private16staticMetaObjectE@Base 4:5.3.0 - _ZN7KScreen6Config8setValidEb@Base 5.1.1 - _ZN7KScreen6Config9addOutputERK14QSharedPointerINS_6OutputEE@Base 5.1.1 - _ZN7KScreen6Config9setScreenERK14QSharedPointerINS_6ScreenEE@Base 5.1.1 - _ZN7KScreen6ConfigC1Ev@Base 5.1.1 - _ZN7KScreen6ConfigC2Ev@Base 5.1.1 - _ZN7KScreen6ConfigD0Ev@Base 5.1.1 - _ZN7KScreen6ConfigD1Ev@Base 5.1.1 - _ZN7KScreen6ConfigD2Ev@Base 5.1.1 - _ZN7KScreen6Output10posChangedEv@Base 5.1.1 - _ZN7KScreen6Output10setEnabledEb@Base 5.1.1 - _ZN7KScreen6Output10setPrimaryEb@Base 5.1.1 - _ZN7KScreen6Output11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.1.1 - _ZN7KScreen6Output11qt_metacastEPKc@Base 5.1.1 - _ZN7KScreen6Output11setRotationENS0_8RotationE@Base 5.1.1 - _ZN7KScreen6Output11sizeChangedEv@Base 4:5.4.0 - _ZN7KScreen6Output12setConnectedEb@Base 5.1.1 - _ZN7KScreen6Output13clonesChangedEv@Base 5.1.1 - _ZN7KScreen6Output13outputChangedEv@Base 5.1.1 - _ZN7KScreen6Output15rotationChangedEv@Base 5.1.1 - _ZN7KScreen6Output16isEnabledChangedEv@Base 5.1.1 - _ZN7KScreen6Output16isPrimaryChangedEv@Base 5.1.1 - _ZN7KScreen6Output16setCurrentModeIdERK7QString@Base 5.1.1 - _ZN7KScreen6Output16staticMetaObjectE@Base 5.1.1 - _ZN7KScreen6Output17setPreferredModesERK11QStringList@Base 5.1.1 - _ZN7KScreen6Output18isConnectedChangedEv@Base 5.1.1 - _ZN7KScreen6Output20currentModeIdChangedEv@Base 5.1.1 - _ZN7KScreen6Output5applyERK14QSharedPointerIS0_E@Base 5.1.1 - _ZN7KScreen6Output5setIdEi@Base 5.1.1 - _ZN7KScreen6Output6setPosERK6QPoint@Base 5.1.1 - _ZN7KScreen6Output7setEdidERK10QByteArray@Base 5.1.1 - _ZN7KScreen6Output7setIconERK7QString@Base 5.1.1 - _ZN7KScreen6Output7setNameERK7QString@Base 5.1.1 - _ZN7KScreen6Output7setSizeERK5QSize@Base 4:5.4.0 - _ZN7KScreen6Output7setTypeENS0_4TypeE@Base 5.1.1 - _ZN7KScreen6Output8setModesERK4QMapI7QString14QSharedPointerINS_4ModeEEE@Base 5.1.1 - _ZN7KScreen6Output9setClonesE5QListIiE@Base 5.1.1 - _ZN7KScreen6Output9setSizeMmERK5QSize@Base 5.1.1 - _ZN7KScreen6OutputC1EPNS0_7PrivateE@Base 5.1.1 - _ZN7KScreen6OutputC1Ev@Base 5.1.1 - _ZN7KScreen6OutputC2EPNS0_7PrivateE@Base 5.1.1 - _ZN7KScreen6OutputC2Ev@Base 5.1.1 - _ZN7KScreen6OutputD0Ev@Base 5.1.1 - _ZN7KScreen6OutputD1Ev@Base 5.1.1 - _ZN7KScreen6OutputD2Ev@Base 5.1.1 - _ZN7KScreen6Screen10setMaxSizeERK5QSize@Base 5.1.1 - _ZN7KScreen6Screen10setMinSizeERK5QSize@Base 5.1.1 - _ZN7KScreen6Screen11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.1.1 - _ZN7KScreen6Screen11qt_metacastEPKc@Base 5.1.1 - _ZN7KScreen6Screen14setCurrentSizeERK5QSize@Base 5.1.1 - _ZN7KScreen6Screen16staticMetaObjectE@Base 5.1.1 - _ZN7KScreen6Screen18currentSizeChangedEv@Base 5.1.1 - _ZN7KScreen6Screen24setMaxActiveOutputsCountEi@Base 5.1.1 - _ZN7KScreen6Screen5applyERK14QSharedPointerIS0_E@Base 5.1.1 - _ZN7KScreen6Screen5setIdEi@Base 5.1.1 - _ZN7KScreen6ScreenC1EPNS0_7PrivateE@Base 5.1.1 - _ZN7KScreen6ScreenC1Ev@Base 5.1.1 - _ZN7KScreen6ScreenC2EPNS0_7PrivateE@Base 5.1.1 - _ZN7KScreen6ScreenC2Ev@Base 5.1.1 - _ZN7KScreen6ScreenD0Ev@Base 5.1.1 - _ZN7KScreen6ScreenD1Ev@Base 5.1.1 - _ZN7KScreen6ScreenD2Ev@Base 5.1.1 - _ZNK7KScreen13ConfigMonitor10metaObjectEv@Base 5.1.1 - _ZNK7KScreen13ConfigMonitor7Private10metaObjectEv@Base 5.1.1 - _ZNK7KScreen14BackendManager10metaObjectEv@Base 5.1.1 - _ZNK7KScreen14BackendManager6configEv@Base 5.1.1 - _ZNK7KScreen15AbstractBackend10metaObjectEv@Base 5.1.1 - _ZNK7KScreen15AbstractBackend4edidEi@Base 5.1.1 - _ZNK7KScreen15ConfigOperation10metaObjectEv@Base 5.1.1 - _ZNK7KScreen15ConfigOperation11errorStringEv@Base 5.1.1 - _ZNK7KScreen15ConfigOperation8hasErrorEv@Base 5.1.1 - _ZNK7KScreen18GetConfigOperation10metaObjectEv@Base 5.1.1 - _ZNK7KScreen18GetConfigOperation6configEv@Base 5.1.1 - _ZNK7KScreen18SetConfigOperation10metaObjectEv@Base 5.1.1 - _ZNK7KScreen18SetConfigOperation6configEv@Base 5.1.1 - _ZNK7KScreen4Edid10metaObjectEv@Base 5.1.1 - _ZNK7KScreen4Edid3redEv@Base 5.1.1 - _ZNK7KScreen4Edid4blueEv@Base 5.1.1 - _ZNK7KScreen4Edid4hashEv@Base 5.1.1 - _ZNK7KScreen4Edid4nameEv@Base 5.1.1 - _ZNK7KScreen4Edid5cloneEv@Base 5.1.1 - _ZNK7KScreen4Edid5gammaEv@Base 5.1.1 - _ZNK7KScreen4Edid5greenEv@Base 5.1.1 - _ZNK7KScreen4Edid5pnpIdEv@Base 5.1.1 - _ZNK7KScreen4Edid5whiteEv@Base 5.1.1 - _ZNK7KScreen4Edid5widthEv@Base 5.1.1 - _ZNK7KScreen4Edid6eisaIdEv@Base 5.1.1 - _ZNK7KScreen4Edid6heightEv@Base 5.1.1 - _ZNK7KScreen4Edid6serialEv@Base 5.1.1 - _ZNK7KScreen4Edid6vendorEv@Base 5.1.1 - _ZNK7KScreen4Edid7Private10edidGetBitEii@Base 5.1.1 - _ZNK7KScreen4Edid7Private11edidGetBitsEiii@Base 5.1.1 - _ZNK7KScreen4Edid7Private15edidParseStringEPKh@Base 5.1.1 - _ZNK7KScreen4Edid7Private18edidDecodeFractionEii@Base 5.1.1 - _ZNK7KScreen4Edid7isValidEv@Base 5.1.1 - _ZNK7KScreen4Edid8deviceIdERK7QString@Base 5.1.1 - _ZNK7KScreen4Mode10metaObjectEv@Base 5.1.1 - _ZNK7KScreen4Mode11refreshRateEv@Base 5.1.1 - _ZNK7KScreen4Mode2idEv@Base 5.1.1 - _ZNK7KScreen4Mode4nameEv@Base 5.1.1 - _ZNK7KScreen4Mode4sizeEv@Base 5.1.1 - _ZNK7KScreen4Mode5cloneEv@Base 5.1.1 - _ZNK7KScreen6Config10metaObjectEv@Base 5.1.1 - _ZNK7KScreen6Config13primaryOutputEv@Base 5.1.1 - _ZNK7KScreen6Config16connectedOutputsEv@Base 5.1.1 - _ZNK7KScreen6Config5cloneEv@Base 5.1.1 - _ZNK7KScreen6Config6outputEi@Base 5.1.1 - _ZNK7KScreen6Config6screenEv@Base 5.1.1 - _ZNK7KScreen6Config7Private10metaObjectEv@Base 4:5.3.0 - _ZNK7KScreen6Config7isValidEv@Base 5.1.1 - _ZNK7KScreen6Config7outputsEv@Base 5.1.1 - _ZNK7KScreen6Output10metaObjectEv@Base 5.1.1 - _ZNK7KScreen6Output11currentModeEv@Base 5.1.1 - _ZNK7KScreen6Output11isConnectedEv@Base 5.1.1 - _ZNK7KScreen6Output13currentModeIdEv@Base 5.1.1 - _ZNK7KScreen6Output13preferredModeEv@Base 5.1.1 - _ZNK7KScreen6Output14preferredModesEv@Base 5.1.1 - _ZNK7KScreen6Output15preferredModeIdEv@Base 5.1.1 - _ZNK7KScreen6Output2idEv@Base 5.1.1 - _ZNK7KScreen6Output3posEv@Base 5.1.1 - _ZNK7KScreen6Output4edidEv@Base 5.1.1 - _ZNK7KScreen6Output4iconEv@Base 5.1.1 - _ZNK7KScreen6Output4modeERK7QString@Base 5.1.1 - _ZNK7KScreen6Output4nameEv@Base 5.1.1 - _ZNK7KScreen6Output4sizeEv@Base 4:5.4.0 - _ZNK7KScreen6Output4typeEv@Base 5.1.1 - _ZNK7KScreen6Output5cloneEv@Base 5.1.1 - _ZNK7KScreen6Output5modesEv@Base 5.1.1 - _ZNK7KScreen6Output6clonesEv@Base 5.1.1 - _ZNK7KScreen6Output6sizeMmEv@Base 5.1.1 - _ZNK7KScreen6Output7Private11biggestModeERK4QMapI7QString14QSharedPointerINS_4ModeEEE@Base 5.1.1 - _ZNK7KScreen6Output8geometryEv@Base 5.1.1 - _ZNK7KScreen6Output8rotationEv@Base 5.1.1 - _ZNK7KScreen6Output9isEnabledEv@Base 5.1.1 - _ZNK7KScreen6Output9isPrimaryEv@Base 5.1.1 - _ZNK7KScreen6Screen10metaObjectEv@Base 5.1.1 - _ZNK7KScreen6Screen11currentSizeEv@Base 5.1.1 - _ZNK7KScreen6Screen21maxActiveOutputsCountEv@Base 5.1.1 - _ZNK7KScreen6Screen2idEv@Base 5.1.1 - _ZNK7KScreen6Screen5cloneEv@Base 5.1.1 - _ZNK7KScreen6Screen7maxSizeEv@Base 5.1.1 - _ZNK7KScreen6Screen7minSizeEv@Base 5.1.1 - _ZTIN7KScreen13ConfigMonitor7PrivateE@Base 5.1.1 - _ZTIN7KScreen13ConfigMonitorE@Base 5.1.1 - _ZTIN7KScreen14BackendManagerE@Base 5.1.1 - _ZTIN7KScreen15AbstractBackendE@Base 5.1.1 - _ZTIN7KScreen15ConfigOperationE@Base 5.1.1 - _ZTIN7KScreen18GetConfigOperationE@Base 5.1.1 - _ZTIN7KScreen18SetConfigOperationE@Base 5.1.1 - _ZTIN7KScreen4EdidE@Base 5.1.1 - _ZTIN7KScreen4ModeE@Base 5.1.1 - _ZTIN7KScreen6Config7PrivateE@Base 4:5.3.0 - _ZTIN7KScreen6ConfigE@Base 5.1.1 - _ZTIN7KScreen6OutputE@Base 5.1.1 - _ZTIN7KScreen6ScreenE@Base 5.1.1 - _ZTSN7KScreen13ConfigMonitor7PrivateE@Base 5.1.1 - _ZTSN7KScreen13ConfigMonitorE@Base 5.1.1 - _ZTSN7KScreen14BackendManagerE@Base 5.1.1 - _ZTSN7KScreen15AbstractBackendE@Base 5.1.1 - _ZTSN7KScreen15ConfigOperationE@Base 5.1.1 - _ZTSN7KScreen18GetConfigOperationE@Base 5.1.1 - _ZTSN7KScreen18SetConfigOperationE@Base 5.1.1 - _ZTSN7KScreen4EdidE@Base 5.1.1 - _ZTSN7KScreen4ModeE@Base 5.1.1 - _ZTSN7KScreen6Config7PrivateE@Base 4:5.3.0 - _ZTSN7KScreen6ConfigE@Base 5.1.1 - _ZTSN7KScreen6OutputE@Base 5.1.1 - _ZTSN7KScreen6ScreenE@Base 5.1.1 - _ZTVN7KScreen13ConfigMonitor7PrivateE@Base 5.1.1 - _ZTVN7KScreen13ConfigMonitorE@Base 5.1.1 - _ZTVN7KScreen14BackendManagerE@Base 5.1.1 - _ZTVN7KScreen15AbstractBackendE@Base 5.1.1 - _ZTVN7KScreen15ConfigOperationE@Base 5.1.1 - _ZTVN7KScreen18GetConfigOperationE@Base 5.1.1 - _ZTVN7KScreen18SetConfigOperationE@Base 5.1.1 - _ZTVN7KScreen4EdidE@Base 5.1.1 - _ZTVN7KScreen4ModeE@Base 5.1.1 - _ZTVN7KScreen6Config7PrivateE@Base 4:5.3.0 - _ZTVN7KScreen6ConfigE@Base 5.1.1 - _ZTVN7KScreen6OutputE@Base 5.1.1 - _ZTVN7KScreen6ScreenE@Base 5.1.1 - _Zls6QDebugRK14QSharedPointerIN7KScreen4ModeEE@Base 5.1.1 - _Zls6QDebugRK14QSharedPointerIN7KScreen6OutputEE@Base 5.1.1 diff -Nru libkscreen-5.4.2/debian/libkf5screen7.install libkscreen-5.12.0/debian/libkf5screen7.install --- libkscreen-5.4.2/debian/libkf5screen7.install 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/debian/libkf5screen7.install 2018-02-07 10:48:45.000000000 +0000 @@ -0,0 +1,5 @@ +usr/lib/*/libKF5Screen.so.5.* +usr/lib/*/libKF5Screen.so.7 +usr/lib/*/libexec/kf5/kscreen_backend_launcher +usr/lib/*/qt5/plugins/kf5/kscreen/ +usr/share/dbus-1/services/org.kde.kscreen.service diff -Nru libkscreen-5.4.2/debian/libkf5screen7.symbols libkscreen-5.12.0/debian/libkf5screen7.symbols --- libkscreen-5.4.2/debian/libkf5screen7.symbols 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/debian/libkf5screen7.symbols 2018-02-07 10:48:45.000000000 +0000 @@ -0,0 +1,339 @@ +# SymbolsHelper-Confirmed: 4:5.4.3+git20151204.0801+16.04 amd64 i386 +KSC_Fake.so libkf5screen7 #MINVER# + qt_plugin_instance@Base 5.1.80 + qt_plugin_query_metadata@Base 5.1.80 +KSC_QScreen.so libkf5screen6 #MINVER# + qt_plugin_instance@Base 5.1.80 + qt_plugin_query_metadata@Base 5.1.80 +KSC_XRandR.so libkf5screen6 #MINVER# + qt_plugin_instance@Base 5.1.80 + qt_plugin_query_metadata@Base 5.1.80 +KSC_XRandR11.so libkf5screen6 #MINVER# + qt_plugin_instance@Base 5.1.80 + qt_plugin_query_metadata@Base 5.1.80 +libKF5Screen.so.6 libkf5screen6 #MINVER# + _ZN7KScreen13ConfigMonitor11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.1.1 + _ZN7KScreen13ConfigMonitor11qt_metacastEPKc@Base 5.1.1 + _ZN7KScreen13ConfigMonitor12removeConfigERK14QSharedPointerINS_6ConfigEE@Base 5.1.1 + _ZN7KScreen13ConfigMonitor16staticMetaObjectE@Base 5.1.1 + _ZN7KScreen13ConfigMonitor20configurationChangedEv@Base 5.1.1 + _ZN7KScreen13ConfigMonitor23connectInProcessBackendEPNS_15AbstractBackendE@Base 4:5.5.1 + _ZN7KScreen13ConfigMonitor7Private11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.1.1 + _ZN7KScreen13ConfigMonitor7Private11qt_metacastEPKc@Base 5.1.1 + _ZN7KScreen13ConfigMonitor7Private13updateConfigsERK14QSharedPointerINS_6ConfigEE@Base 5.1.1 + _ZN7KScreen13ConfigMonitor7Private14onBackendReadyEP29OrgKdeKscreenBackendInterface@Base 5.1.1 + _ZN7KScreen13ConfigMonitor7Private15configDestroyedEP7QObject@Base 5.1.1 + _ZN7KScreen13ConfigMonitor7Private16staticMetaObjectE@Base 5.1.1 + _ZN7KScreen13ConfigMonitor7Private17getConfigFinishedEPNS_15ConfigOperationE@Base 5.1.1 + _ZN7KScreen13ConfigMonitor7Private20backendConfigChangedERK4QMapI7QString8QVariantE@Base 5.1.1 + _ZN7KScreen13ConfigMonitor7Private9edidReadyEP23QDBusPendingCallWatcher@Base 5.1.1 + _ZN7KScreen13ConfigMonitor7PrivateC1EPS0_@Base 5.1.1 + _ZN7KScreen13ConfigMonitor7PrivateC2EPS0_@Base 5.1.1 + _ZN7KScreen13ConfigMonitor8instanceEv@Base 5.1.1 + _ZN7KScreen13ConfigMonitor9addConfigERK14QSharedPointerINS_6ConfigEE@Base 5.1.1 + _ZN7KScreen13ConfigMonitorC1Ev@Base 5.1.1 + _ZN7KScreen13ConfigMonitorC2Ev@Base 5.1.1 + _ZN7KScreen13ConfigMonitorD0Ev@Base 5.1.1 + _ZN7KScreen13ConfigMonitorD1Ev@Base 5.1.1 + _ZN7KScreen13ConfigMonitorD2Ev@Base 5.1.1 + _ZN7KScreen14BackendManager10initMethodEv@Base 4:5.5.1 + _ZN7KScreen14BackendManager11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.1.1 + _ZN7KScreen14BackendManager11qt_metacastEPKc@Base 5.1.1 + _ZN7KScreen14BackendManager12backendReadyEP29OrgKdeKscreenBackendInterface@Base 5.1.1 + _ZN7KScreen14BackendManager12startBackendERK7QStringRK4QMapIS1_8QVariantE@Base 4:5.4.2+git20151012.1045 + _ZN7KScreen14BackendManager14requestBackendEv@Base 5.1.1 + _ZN7KScreen14BackendManager14sMaxCrashCountE@Base 5.1.1 + _ZN7KScreen14BackendManager15shutdownBackendEv@Base 5.1.1 + _ZN7KScreen14BackendManager16emitBackendReadyEv@Base 5.1.1 + _ZN7KScreen14BackendManager16staticMetaObjectE@Base 5.1.1 + _ZN7KScreen14BackendManager17loadBackendPluginEP13QPluginLoaderRK7QStringRK4QMapIS3_8QVariantE@Base 4:5.5.1 + _ZN7KScreen14BackendManager19invalidateInterfaceEv@Base 5.1.1 + _ZN7KScreen14BackendManager20loadBackendInProcessERK7QString@Base 4:5.5.1 + _ZN7KScreen14BackendManager20onBackendRequestDoneEP23QDBusPendingCallWatcher@Base 4:5.4.2+git20151012.1045 + _ZN7KScreen14BackendManager26backendServiceUnregisteredERK7QString@Base 5.1.1 + _ZN7KScreen14BackendManager8instanceEv@Base 5.1.1 + _ZN7KScreen14BackendManager9sInstanceE@Base 5.1.1 + _ZN7KScreen14BackendManager9setConfigE14QSharedPointerINS_6ConfigEE@Base 4:5.5.1 + _ZN7KScreen14BackendManager9setMethodENS0_6MethodE@Base 4:5.5.1 + _ZN7KScreen14BackendManagerC1Ev@Base 5.1.1 + _ZN7KScreen14BackendManagerC2Ev@Base 5.1.1 + _ZN7KScreen14BackendManagerD0Ev@Base 5.1.1 + _ZN7KScreen14BackendManagerD1Ev@Base 5.1.1 + _ZN7KScreen14BackendManagerD2Ev@Base 5.1.1 + _ZN7KScreen15AbstractBackend11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.1.1 + _ZN7KScreen15AbstractBackend11qt_metacastEPKc@Base 5.1.1 + _ZN7KScreen15AbstractBackend13configChangedERK14QSharedPointerINS_6ConfigEE@Base 5.1.1 + _ZN7KScreen15AbstractBackend16staticMetaObjectE@Base 5.1.1 + _ZN7KScreen15AbstractBackend4initERK4QMapI7QString8QVariantE@Base 4:5.4.2+git20151012.1045 + _ZN7KScreen15ConfigOperation10emitResultEv@Base 5.1.1 + _ZN7KScreen15ConfigOperation11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.1.1 + _ZN7KScreen15ConfigOperation11qt_metacastEPKc@Base 5.1.1 + _ZN7KScreen15ConfigOperation16staticMetaObjectE@Base 5.1.1 + _ZN7KScreen15ConfigOperation4execEv@Base 5.1.1 + _ZN7KScreen15ConfigOperation8finishedEPS0_@Base 5.1.1 + _ZN7KScreen15ConfigOperation8setErrorERK7QString@Base 5.1.1 + _ZN7KScreen15ConfigOperationC1EPNS_22ConfigOperationPrivateEP7QObject@Base 5.1.1 + _ZN7KScreen15ConfigOperationC2EPNS_22ConfigOperationPrivateEP7QObject@Base 5.1.1 + _ZN7KScreen15ConfigOperationD0Ev@Base 5.1.1 + _ZN7KScreen15ConfigOperationD1Ev@Base 5.1.1 + _ZN7KScreen15ConfigOperationD2Ev@Base 5.1.1 + (optional=templinst)_ZN7KScreen16ConfigSerializer13serializeListI7QStringEE10QJsonArrayRK5QListIT_E@Base 5.1.1 + (optional=templinst)_ZN7KScreen16ConfigSerializer13serializeListIiEE10QJsonArrayRK5QListIT_E@Base 5.1.1 + _ZN7KScreen16ConfigSerializer13serializeModeERK14QSharedPointerINS_4ModeEE@Base 5.1.1 + _ZN7KScreen16ConfigSerializer13serializeSizeERK5QSize@Base 5.1.1 + _ZN7KScreen16ConfigSerializer14serializePointERK6QPoint@Base 5.1.1 + (optional=templinst)_ZN7KScreen16ConfigSerializer15deserializeListI7QStringEE5QListIT_ERK13QDBusArgument@Base 5.1.1 + (optional=templinst)_ZN7KScreen16ConfigSerializer15deserializeListIiEE5QListIT_ERK13QDBusArgument@Base 5.1.1 + _ZN7KScreen16ConfigSerializer15deserializeModeERK13QDBusArgument@Base 5.1.1 + _ZN7KScreen16ConfigSerializer15deserializeSizeERK13QDBusArgument@Base 5.1.1 + _ZN7KScreen16ConfigSerializer15serializeConfigERK14QSharedPointerINS_6ConfigEE@Base 5.1.1 + _ZN7KScreen16ConfigSerializer15serializeOutputERK14QSharedPointerINS_6OutputEE@Base 5.1.1 + _ZN7KScreen16ConfigSerializer15serializeScreenERK14QSharedPointerINS_6ScreenEE@Base 5.1.1 + _ZN7KScreen16ConfigSerializer16deserializePointERK13QDBusArgument@Base 5.1.1 + _ZN7KScreen16ConfigSerializer17deserializeConfigERK4QMapI7QString8QVariantE@Base 5.1.1 + _ZN7KScreen16ConfigSerializer17deserializeOutputERK13QDBusArgument@Base 5.1.1 + _ZN7KScreen16ConfigSerializer17deserializeScreenERK13QDBusArgument@Base 5.1.1 + _ZN7KScreen18GetConfigOperation11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.1.1 + _ZN7KScreen18GetConfigOperation11qt_metacastEPKc@Base 5.1.1 + _ZN7KScreen18GetConfigOperation16staticMetaObjectE@Base 5.1.1 + _ZN7KScreen18GetConfigOperation5startEv@Base 5.1.1 + _ZN7KScreen18GetConfigOperationC1E6QFlagsINS_15ConfigOperation6OptionEEP7QObject@Base 4:5.5.1 + _ZN7KScreen18GetConfigOperationC2E6QFlagsINS_15ConfigOperation6OptionEEP7QObject@Base 4:5.5.1 + _ZN7KScreen18GetConfigOperationD0Ev@Base 5.1.1 + _ZN7KScreen18GetConfigOperationD1Ev@Base 5.1.1 + _ZN7KScreen18GetConfigOperationD2Ev@Base 5.1.1 + _ZN7KScreen18SetConfigOperation11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.1.1 + _ZN7KScreen18SetConfigOperation11qt_metacastEPKc@Base 5.1.1 + _ZN7KScreen18SetConfigOperation16staticMetaObjectE@Base 5.1.1 + _ZN7KScreen18SetConfigOperation5startEv@Base 5.1.1 + _ZN7KScreen18SetConfigOperationC1ERK14QSharedPointerINS_6ConfigEEP7QObject@Base 5.1.1 + _ZN7KScreen18SetConfigOperationC2ERK14QSharedPointerINS_6ConfigEEP7QObject@Base 5.1.1 + _ZN7KScreen18SetConfigOperationD0Ev@Base 5.1.1 + _ZN7KScreen18SetConfigOperationD1Ev@Base 5.1.1 + _ZN7KScreen18SetConfigOperationD2Ev@Base 5.1.1 + _ZN7KScreen4Edid11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.1.1 + _ZN7KScreen4Edid11qt_metacastEPKc@Base 5.1.1 + _ZN7KScreen4Edid16staticMetaObjectE@Base 5.1.1 + _ZN7KScreen4Edid7Private5parseERK10QByteArray@Base 5.1.1 + _ZN7KScreen4EdidC1EPNS0_7PrivateE@Base 5.1.1 + _ZN7KScreen4EdidC1ERK10QByteArrayP7QObject@Base 5.1.1 + _ZN7KScreen4EdidC1Ev@Base 5.1.1 + _ZN7KScreen4EdidC2EPNS0_7PrivateE@Base 5.1.1 + _ZN7KScreen4EdidC2ERK10QByteArrayP7QObject@Base 5.1.1 + _ZN7KScreen4EdidC2Ev@Base 5.1.1 + _ZN7KScreen4EdidD0Ev@Base 5.1.1 + _ZN7KScreen4EdidD1Ev@Base 5.1.1 + _ZN7KScreen4EdidD2Ev@Base 5.1.1 + _ZN7KScreen4Mode11modeChangedEv@Base 5.1.1 + _ZN7KScreen4Mode11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.1.1 + _ZN7KScreen4Mode11qt_metacastEPKc@Base 5.1.1 + _ZN7KScreen4Mode14setRefreshRateEf@Base 5.1.1 + _ZN7KScreen4Mode16staticMetaObjectE@Base 5.1.1 + _ZN7KScreen4Mode5setIdERK7QString@Base 5.1.1 + _ZN7KScreen4Mode7setNameERK7QString@Base 5.1.1 + _ZN7KScreen4Mode7setSizeERK5QSize@Base 5.1.1 + _ZN7KScreen4ModeC1EPNS0_7PrivateE@Base 5.1.1 + _ZN7KScreen4ModeC1Ev@Base 5.1.1 + _ZN7KScreen4ModeC2EPNS0_7PrivateE@Base 5.1.1 + _ZN7KScreen4ModeC2Ev@Base 5.1.1 + _ZN7KScreen4ModeD0Ev@Base 5.1.1 + _ZN7KScreen4ModeD1Ev@Base 5.1.1 + _ZN7KScreen4ModeD2Ev@Base 5.1.1 + _ZN7KScreen6Config10setOutputsE4QMapIi14QSharedPointerINS_6OutputEEE@Base 5.1.1 + _ZN7KScreen6Config11outputAddedERK14QSharedPointerINS_6OutputEE@Base 5.1.1 + _ZN7KScreen6Config11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.1.1 + _ZN7KScreen6Config11qt_metacastEPKc@Base 5.1.1 + _ZN7KScreen6Config12canBeAppliedERK14QSharedPointerIS0_E6QFlagsINS0_12ValidityFlagEE@Base 4:5.3.0 + _ZN7KScreen6Config12canBeAppliedERK14QSharedPointerIS0_E@Base 5.1.1 + _ZN7KScreen6Config12removeOutputEi@Base 5.1.1 + _ZN7KScreen6Config13outputRemovedEi@Base 5.1.1 + _ZN7KScreen6Config16setPrimaryOutputERK14QSharedPointerINS_6OutputEE@Base 5.1.1 + _ZN7KScreen6Config16staticMetaObjectE@Base 5.1.1 + _ZN7KScreen6Config20primaryOutputChangedERK14QSharedPointerINS_6OutputEE@Base 5.1.1 + _ZN7KScreen6Config5applyERK14QSharedPointerIS0_E@Base 5.1.1 + _ZN7KScreen6Config7Private11qt_metacallEN11QMetaObject4CallEiPPv@Base 4:5.3.0 + _ZN7KScreen6Config7Private11qt_metacastEPKc@Base 4:5.3.0 + _ZN7KScreen6Config7Private16staticMetaObjectE@Base 4:5.3.0 + _ZN7KScreen6Config8setValidEb@Base 5.1.1 + _ZN7KScreen6Config9addOutputERK14QSharedPointerINS_6OutputEE@Base 5.1.1 + _ZN7KScreen6Config9setScreenERK14QSharedPointerINS_6ScreenEE@Base 5.1.1 + _ZN7KScreen6ConfigC1Ev@Base 5.1.1 + _ZN7KScreen6ConfigC2Ev@Base 5.1.1 + _ZN7KScreen6ConfigD0Ev@Base 5.1.1 + _ZN7KScreen6ConfigD1Ev@Base 5.1.1 + _ZN7KScreen6ConfigD2Ev@Base 5.1.1 + _ZN7KScreen6Output10posChangedEv@Base 5.1.1 + _ZN7KScreen6Output10setEnabledEb@Base 5.1.1 + _ZN7KScreen6Output10setPrimaryEb@Base 5.1.1 + _ZN7KScreen6Output11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.1.1 + _ZN7KScreen6Output11qt_metacastEPKc@Base 5.1.1 + _ZN7KScreen6Output11setRotationENS0_8RotationE@Base 5.1.1 + _ZN7KScreen6Output11sizeChangedEv@Base 4:5.4.0 + _ZN7KScreen6Output12setConnectedEb@Base 5.1.1 + _ZN7KScreen6Output13clonesChangedEv@Base 5.1.1 + _ZN7KScreen6Output13outputChangedEv@Base 5.1.1 + _ZN7KScreen6Output15rotationChangedEv@Base 5.1.1 + _ZN7KScreen6Output16isEnabledChangedEv@Base 5.1.1 + _ZN7KScreen6Output16isPrimaryChangedEv@Base 5.1.1 + _ZN7KScreen6Output16setCurrentModeIdERK7QString@Base 5.1.1 + _ZN7KScreen6Output16staticMetaObjectE@Base 5.1.1 + _ZN7KScreen6Output17setPreferredModesERK11QStringList@Base 5.1.1 + _ZN7KScreen6Output18isConnectedChangedEv@Base 5.1.1 + _ZN7KScreen6Output20currentModeIdChangedEv@Base 5.1.1 + _ZN7KScreen6Output5applyERK14QSharedPointerIS0_E@Base 5.1.1 + _ZN7KScreen6Output5setIdEi@Base 5.1.1 + _ZN7KScreen6Output6setPosERK6QPoint@Base 5.1.1 + _ZN7KScreen6Output7setEdidERK10QByteArray@Base 5.1.1 + _ZN7KScreen6Output7setIconERK7QString@Base 5.1.1 + _ZN7KScreen6Output7setNameERK7QString@Base 5.1.1 + _ZN7KScreen6Output7setSizeERK5QSize@Base 4:5.4.0 + _ZN7KScreen6Output7setTypeENS0_4TypeE@Base 5.1.1 + _ZN7KScreen6Output8setModesERK4QMapI7QString14QSharedPointerINS_4ModeEEE@Base 5.1.1 + _ZN7KScreen6Output9setClonesE5QListIiE@Base 5.1.1 + _ZN7KScreen6Output9setSizeMmERK5QSize@Base 5.1.1 + _ZN7KScreen6OutputC1EPNS0_7PrivateE@Base 5.1.1 + _ZN7KScreen6OutputC1Ev@Base 5.1.1 + _ZN7KScreen6OutputC2EPNS0_7PrivateE@Base 5.1.1 + _ZN7KScreen6OutputC2Ev@Base 5.1.1 + _ZN7KScreen6OutputD0Ev@Base 5.1.1 + _ZN7KScreen6OutputD1Ev@Base 5.1.1 + _ZN7KScreen6OutputD2Ev@Base 5.1.1 + _ZN7KScreen6Screen10setMaxSizeERK5QSize@Base 5.1.1 + _ZN7KScreen6Screen10setMinSizeERK5QSize@Base 5.1.1 + _ZN7KScreen6Screen11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.1.1 + _ZN7KScreen6Screen11qt_metacastEPKc@Base 5.1.1 + _ZN7KScreen6Screen14setCurrentSizeERK5QSize@Base 5.1.1 + _ZN7KScreen6Screen16staticMetaObjectE@Base 5.1.1 + _ZN7KScreen6Screen18currentSizeChangedEv@Base 5.1.1 + _ZN7KScreen6Screen24setMaxActiveOutputsCountEi@Base 5.1.1 + _ZN7KScreen6Screen5applyERK14QSharedPointerIS0_E@Base 5.1.1 + _ZN7KScreen6Screen5setIdEi@Base 5.1.1 + _ZN7KScreen6ScreenC1EPNS0_7PrivateE@Base 5.1.1 + _ZN7KScreen6ScreenC1Ev@Base 5.1.1 + _ZN7KScreen6ScreenC2EPNS0_7PrivateE@Base 5.1.1 + _ZN7KScreen6ScreenC2Ev@Base 5.1.1 + _ZN7KScreen6ScreenD0Ev@Base 5.1.1 + _ZN7KScreen6ScreenD1Ev@Base 5.1.1 + _ZN7KScreen6ScreenD2Ev@Base 5.1.1 + _ZNK7KScreen13ConfigMonitor10metaObjectEv@Base 5.1.1 + _ZNK7KScreen13ConfigMonitor7Private10metaObjectEv@Base 5.1.1 + _ZNK7KScreen14BackendManager10metaObjectEv@Base 5.1.1 + _ZNK7KScreen14BackendManager6configEv@Base 5.1.1 + _ZNK7KScreen14BackendManager6methodEv@Base 4:5.5.1 + _ZNK7KScreen15AbstractBackend10metaObjectEv@Base 5.1.1 + _ZNK7KScreen15AbstractBackend4edidEi@Base 5.1.1 + _ZNK7KScreen15ConfigOperation10metaObjectEv@Base 5.1.1 + _ZNK7KScreen15ConfigOperation11errorStringEv@Base 5.1.1 + _ZNK7KScreen15ConfigOperation8hasErrorEv@Base 5.1.1 + _ZNK7KScreen18GetConfigOperation10metaObjectEv@Base 5.1.1 + _ZNK7KScreen18GetConfigOperation6configEv@Base 5.1.1 + _ZNK7KScreen18SetConfigOperation10metaObjectEv@Base 5.1.1 + _ZNK7KScreen18SetConfigOperation6configEv@Base 5.1.1 + _ZNK7KScreen4Edid10metaObjectEv@Base 5.1.1 + _ZNK7KScreen4Edid3redEv@Base 5.1.1 + _ZNK7KScreen4Edid4blueEv@Base 5.1.1 + _ZNK7KScreen4Edid4hashEv@Base 5.1.1 + _ZNK7KScreen4Edid4nameEv@Base 5.1.1 + _ZNK7KScreen4Edid5cloneEv@Base 5.1.1 + _ZNK7KScreen4Edid5gammaEv@Base 5.1.1 + _ZNK7KScreen4Edid5greenEv@Base 5.1.1 + _ZNK7KScreen4Edid5pnpIdEv@Base 5.1.1 + _ZNK7KScreen4Edid5whiteEv@Base 5.1.1 + _ZNK7KScreen4Edid5widthEv@Base 5.1.1 + _ZNK7KScreen4Edid6eisaIdEv@Base 5.1.1 + _ZNK7KScreen4Edid6heightEv@Base 5.1.1 + _ZNK7KScreen4Edid6serialEv@Base 5.1.1 + _ZNK7KScreen4Edid6vendorEv@Base 5.1.1 + _ZNK7KScreen4Edid7Private10edidGetBitEii@Base 5.1.1 + _ZNK7KScreen4Edid7Private11edidGetBitsEiii@Base 5.1.1 + _ZNK7KScreen4Edid7Private15edidParseStringEPKh@Base 5.1.1 + _ZNK7KScreen4Edid7Private18edidDecodeFractionEii@Base 5.1.1 + _ZNK7KScreen4Edid7isValidEv@Base 5.1.1 + _ZNK7KScreen4Edid8deviceIdERK7QString@Base 5.1.1 + _ZNK7KScreen4Mode10metaObjectEv@Base 5.1.1 + _ZNK7KScreen4Mode11refreshRateEv@Base 5.1.1 + _ZNK7KScreen4Mode2idEv@Base 5.1.1 + _ZNK7KScreen4Mode4nameEv@Base 5.1.1 + _ZNK7KScreen4Mode4sizeEv@Base 5.1.1 + _ZNK7KScreen4Mode5cloneEv@Base 5.1.1 + _ZNK7KScreen6Config10metaObjectEv@Base 5.1.1 + _ZNK7KScreen6Config13primaryOutputEv@Base 5.1.1 + _ZNK7KScreen6Config16connectedOutputsEv@Base 5.1.1 + _ZNK7KScreen6Config5cloneEv@Base 5.1.1 + _ZNK7KScreen6Config6outputEi@Base 5.1.1 + _ZNK7KScreen6Config6screenEv@Base 5.1.1 + _ZNK7KScreen6Config7Private10metaObjectEv@Base 4:5.3.0 + _ZNK7KScreen6Config7isValidEv@Base 5.1.1 + _ZNK7KScreen6Config7outputsEv@Base 5.1.1 + _ZNK7KScreen6Output10metaObjectEv@Base 5.1.1 + _ZNK7KScreen6Output11currentModeEv@Base 5.1.1 + _ZNK7KScreen6Output11isConnectedEv@Base 5.1.1 + _ZNK7KScreen6Output13currentModeIdEv@Base 5.1.1 + _ZNK7KScreen6Output13preferredModeEv@Base 5.1.1 + _ZNK7KScreen6Output14preferredModesEv@Base 5.1.1 + _ZNK7KScreen6Output15preferredModeIdEv@Base 5.1.1 + _ZNK7KScreen6Output2idEv@Base 5.1.1 + _ZNK7KScreen6Output3posEv@Base 5.1.1 + _ZNK7KScreen6Output4edidEv@Base 5.1.1 + _ZNK7KScreen6Output4iconEv@Base 5.1.1 + _ZNK7KScreen6Output4modeERK7QString@Base 5.1.1 + _ZNK7KScreen6Output4nameEv@Base 5.1.1 + _ZNK7KScreen6Output4sizeEv@Base 4:5.4.0 + _ZNK7KScreen6Output4typeEv@Base 5.1.1 + _ZNK7KScreen6Output5cloneEv@Base 5.1.1 + _ZNK7KScreen6Output5modesEv@Base 5.1.1 + _ZNK7KScreen6Output6clonesEv@Base 5.1.1 + _ZNK7KScreen6Output6sizeMmEv@Base 5.1.1 + _ZNK7KScreen6Output7Private11biggestModeERK4QMapI7QString14QSharedPointerINS_4ModeEEE@Base 5.1.1 + _ZNK7KScreen6Output8geometryEv@Base 5.1.1 + _ZNK7KScreen6Output8rotationEv@Base 5.1.1 + _ZNK7KScreen6Output9isEnabledEv@Base 5.1.1 + _ZNK7KScreen6Output9isPrimaryEv@Base 5.1.1 + _ZNK7KScreen6Screen10metaObjectEv@Base 5.1.1 + _ZNK7KScreen6Screen11currentSizeEv@Base 5.1.1 + _ZNK7KScreen6Screen21maxActiveOutputsCountEv@Base 5.1.1 + _ZNK7KScreen6Screen2idEv@Base 5.1.1 + _ZNK7KScreen6Screen5cloneEv@Base 5.1.1 + _ZNK7KScreen6Screen7maxSizeEv@Base 5.1.1 + _ZNK7KScreen6Screen7minSizeEv@Base 5.1.1 + _ZTIN7KScreen13ConfigMonitor7PrivateE@Base 5.1.1 + _ZTIN7KScreen13ConfigMonitorE@Base 5.1.1 + _ZTIN7KScreen14BackendManagerE@Base 5.1.1 + _ZTIN7KScreen15AbstractBackendE@Base 5.1.1 + _ZTIN7KScreen15ConfigOperationE@Base 5.1.1 + _ZTIN7KScreen18GetConfigOperationE@Base 5.1.1 + _ZTIN7KScreen18SetConfigOperationE@Base 5.1.1 + _ZTIN7KScreen4EdidE@Base 5.1.1 + _ZTIN7KScreen4ModeE@Base 5.1.1 + _ZTIN7KScreen6Config7PrivateE@Base 4:5.3.0 + _ZTIN7KScreen6ConfigE@Base 5.1.1 + _ZTIN7KScreen6OutputE@Base 5.1.1 + _ZTIN7KScreen6ScreenE@Base 5.1.1 + _ZTSN7KScreen13ConfigMonitor7PrivateE@Base 5.1.1 + _ZTSN7KScreen13ConfigMonitorE@Base 5.1.1 + _ZTSN7KScreen14BackendManagerE@Base 5.1.1 + _ZTSN7KScreen15AbstractBackendE@Base 5.1.1 + _ZTSN7KScreen15ConfigOperationE@Base 5.1.1 + _ZTSN7KScreen18GetConfigOperationE@Base 5.1.1 + _ZTSN7KScreen18SetConfigOperationE@Base 5.1.1 + _ZTSN7KScreen4EdidE@Base 5.1.1 + _ZTSN7KScreen4ModeE@Base 5.1.1 + _ZTSN7KScreen6Config7PrivateE@Base 4:5.3.0 + _ZTSN7KScreen6ConfigE@Base 5.1.1 + _ZTSN7KScreen6OutputE@Base 5.1.1 + _ZTSN7KScreen6ScreenE@Base 5.1.1 + _ZTVN7KScreen13ConfigMonitor7PrivateE@Base 5.1.1 + _ZTVN7KScreen13ConfigMonitorE@Base 5.1.1 + _ZTVN7KScreen14BackendManagerE@Base 5.1.1 + _ZTVN7KScreen15AbstractBackendE@Base 5.1.1 + _ZTVN7KScreen15ConfigOperationE@Base 5.1.1 + _ZTVN7KScreen18GetConfigOperationE@Base 5.1.1 + _ZTVN7KScreen18SetConfigOperationE@Base 5.1.1 + _ZTVN7KScreen4EdidE@Base 5.1.1 + _ZTVN7KScreen4ModeE@Base 5.1.1 + _ZTVN7KScreen6Config7PrivateE@Base 4:5.3.0 + _ZTVN7KScreen6ConfigE@Base 5.1.1 + _ZTVN7KScreen6OutputE@Base 5.1.1 + _ZTVN7KScreen6ScreenE@Base 5.1.1 + _Zls6QDebugRK14QSharedPointerIN7KScreen4ModeEE@Base 5.1.1 + _Zls6QDebugRK14QSharedPointerIN7KScreen6OutputEE@Base 5.1.1 diff -Nru libkscreen-5.4.2/debian/meta/upstream_scm.json libkscreen-5.12.0/debian/meta/upstream_scm.json --- libkscreen-5.4.2/debian/meta/upstream_scm.json 2015-10-06 05:52:07.000000000 +0000 +++ libkscreen-5.12.0/debian/meta/upstream_scm.json 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -{ - "type" : "git", - "branch" : "frameworks" -} diff -Nru libkscreen-5.4.2/debian/tests/control libkscreen-5.12.0/debian/tests/control --- libkscreen-5.4.2/debian/tests/control 2015-10-06 05:52:07.000000000 +0000 +++ libkscreen-5.12.0/debian/tests/control 2018-02-07 10:48:45.000000000 +0000 @@ -1,7 +1,4 @@ -# Tests: testsuite -# Depends: @, @builddeps@, build-essential -# Restrictions: build-needed - -Tests: acc -Depends: @, dh-acc, exuberant-ctags -Restrictions: allow-stderr +Tests: testsuite +Depends: @, @builddeps@, build-essential, + xvfb, xauth, dbus-x11, xserver-xephyr, libkf5service-bin +Restrictions: build-needed diff -Nru libkscreen-5.4.2/debian/tests/testsuite libkscreen-5.12.0/debian/tests/testsuite --- libkscreen-5.4.2/debian/tests/testsuite 2015-10-06 05:52:07.000000000 +0000 +++ libkscreen-5.12.0/debian/tests/testsuite 2018-02-07 10:48:45.000000000 +0000 @@ -1,3 +1,4 @@ #!/bin/sh -dh_auto_test +xvfb-run -a --server-args="-screen 0 1024x768x24" \ + dbus-launch --exit-with-session debian/tests/testsuite.xsession diff -Nru libkscreen-5.4.2/debian/upstream/signing-key.asc libkscreen-5.12.0/debian/upstream/signing-key.asc --- libkscreen-5.4.2/debian/upstream/signing-key.asc 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/debian/upstream/signing-key.asc 2018-02-07 10:48:45.000000000 +0000 @@ -0,0 +1,118 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1 + +mQENBFG1+bQBCAC3p+fdi9+55LFuKPqW0XrQkQQ2CRfXcM5lqb6B4xQewLorsdX7 +SRDmLzpdDZ9bCpqxMsiFbB+9lxljHNTzx9BIEO9w6aYtVgPsG4L9ZxwBXUTlgtIA +UoOy4lTQnUR0QDFlJQx8c4Cy82htOSCiWO4iaEvMbo+BGe8g4f2/N0tJOrnAc/xl +sdA64GTWId4NB12F+QeRgWWNQs/W/j/kyy37+L0juD06RMKth0uRMN37wEa9KcLa +lOBEUETrImZfx74wagt6WDnJknLf0ceqzfojk82po0C46BJAu49tLehYYKgo0HKZ +fK7CDw53y9SjkI8cU8g48AyUw8Uk/FyJeW1bABEBAAG0N0RhdmlkIEVkbXVuZHNv +biAoRGF2aWQgYXQgS0RFKSA8ZGF2aWRlZG11bmRzb25Aa2RlLm9yZz6JATgEEwEC +ACIFAlG1+bQCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEPVnVgXHTgLP +KD0H/0Cnj1bM6MYV5nKXJhLpd8as2OHFlhdtaU7QG3QcMVqdtP3rdOp1RgjmkYsB +xgwrxvDTLz0L/PH9UTCXjQeZgNR0hG8iy4IBC9ay0PDdkNpjnHoAiUMRstcDODUZ +QdLEOXCbPbRG3q0OlSaOvETL7YkSY8c2N6yqmWaJvudpJ0VVPyIWa2xT53JTXgAD +4m1w8MThAZBZpJi852nQCByCsRC+3cofA7bQd60XLiFWgmnq+rlqryMlWvUmMmat +e7U1NC5UsfH6ToXf/ZNZG+fMGE+ntYiHWRFr2tZMyXfUOrgHsAVMAE8v/xVtwS5e +VCAdM21GNG4d6XiF7T32GDzrEQm5AQ0EUbX5tAEIAL0uLkPxHbg9boIuVdahyy6F +BOcUf8xj3qj8FUGpRkcSSsoyvFTHZRTR+wwTPTaZzzzTFSITRGVv7vdKyl/A+SMw +/nlUVfB9xGvvCgzPGesUk9lmxX2DRVpoq9CyVIw0XXJQtNkC3O1yEws4zuDzHe99 +sfDvXpA1ikfN+Hgn3oLjCHHtWuTyXGKXUimzToDMqWentVkP1rzKPlin9XJ0KDT/ +axrrD9L5s4KCjHdWEQwG3miJDxQnlsAFDBj7Bs8DZZE+xdzx/l8qBKOxmXD9ohFp +4q0wXVV4QJMHtjhvhId9EN965drlYmMfusMCwavklBOWdR1MdSSBIYPS5eISmj0A +EQEAAYkBHwQYAQIACQUCUbX5tAIbDAAKCRD1Z1YFx04Cz4CzCACpN1l39Yzoniqx +laabcOrEbFjhKXlFXPm5TC+nj2iO8BieJLoltTcQL1nbxBHcxMkxUUJAVKBSmlh3 +BPjYJhXBNRvW/gamjaO+LoStXI+0vO4aOhkR0tLqA9/zQFM9uVPu6InS0N98oMaL +azyxnXuqEanCN7yWfKHKxmkKiVMB1RMaE+2TYQBKPfFukiX2vv3qByVez8qYGa98 +80x6fkrqFbPoJ2oDXEGGD0W7fkv1pZV/1XCuXV/qKz3htD3AQDuLijqt6sM9Oe7Y +Lsv5lqTb5DK6g2N9xvhTz64Z+j9bf44fbMReg3ub3GXlf9rFT8eDYfyYLJgWJ/1h +YZximth9mQENBFfOfR0BCAC9W+wYcz5Ha4Hwllb0c8Cqwp4k5d0bsVWjYgMcn+DL +uJmh7VT80oqiHay9Z75sGZ7flLjdB8ZiAgi2qARz+rNMb9p/S+T4MbjVF2L87on9 +/PdgurUgMsof+UmIClCJBOMvod+BK7VBSPu8XUJzOu61QHQxnhRbLgwmcds15giG +3oSK/h9l/6r2FwD543WZtQ6sforBZ/GtUjFDYsgdPC50RQXRuhNP/ow8py253GQD +gKw37Sx1tRGMHjvD4Dk95i0yeQWcjMoY+VWMWCDOQ2swKjl8q3BX2ltKFir5Bu7l +JeC/96ql9vKaWSTgIqnyQD4+8nYSmetkaGU2LROSg8grABEBAAG0IkpvbmF0aGFu +IFJpZGRlbGwgPGpyQGpyaWRkZWxsLm9yZz6JATgEEwECACIFAlfOfR0CGwMGCwkI +BwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEOyU0Y9/BZl+538H/ixizKvWeq5pPi77 +fYMUWQ57bGBeNuEFLJUk0y6Rz2fAnBPDKYCwLdUEBnDxHDffIl6uVRdCtfMGwQZo +1HutE0ZvGgi20EItsle9qzUUiLfuTyz7Dh1tPz7J8NI7VUffq+XTr/mzhqTbCH0p +uY2AflfHOHQbEJL7wdqCQ95wXQw6fg5/1pbhvxxbRojjGILEiiW1L37gyDjfDZKo +/IdT0e30EgL91vTW1Ctn3IXLOmzp46+h5EatWB/22iIrUZm1ubgX4ubBpHmKmZkK +3ou5vN4qi664EMw8xnh4GmnPM1vNRwXTbt7kQakzOFeT6N2C8AeLPM3oYitGxzMS +KSnmRC25AQ0EV859HQEIAM116WD7qM2bwIuMIYFxe2ARaYpLlHvfm4ptgD6QQH4G +FhK00pWwd3pMXB7MXHv2gY6my1Y7hPQyn+clsE7mPzyxm3lswdZLWn1h6QCrMc+T +s+dynz9F46chbpDJ90QXs/hG8BOsA5P0F7D1YAjv1imPqm1Uo8RfsVCgnRSiENvm +hCKi5+TZiQnpy2wXDUyqiDcm4WvJRhr8UM+cZmOJHUJbUXWTw5iVIjlp6UN8Kbib +TXGsxSKjuEKFLIGZmhX1qP3V0ciZvqx8MMUJqtulcrJ8Pop2Vf2wGrTbfnJ9A2qD +i/MPVV9bfOnE3DO+E+cpoUVcdfe94yIbx3+ZXX3B0zcAEQEAAYkBHwQYAQIACQUC +V859HQIbDAAKCRDslNGPfwWZfs3LCACjpcZ3mE4k720A/11+0sYOvuQJqj7Kf+kT +Cy2AvGBwhHkWSJycz6XMxAiGTX9e9auk2Qwo5UiS9aDboipJJgEc9ptU2aDKi1uV +UCles9u0zNdcEPD03rKfGQ4MzGaMip3U+4OIWXtjhl5UsUOPnWSVjv5Ix6HHyY+y +i1y+ZDl7pyuaMzvTY5LuZEPOUpj/RibzfrYGNkH9XfsNVH29c8nS8Auz50ATr21T +qsALdsaeITr5ibhlPv0PGOhlwYk/cSD5647WoSK1NxhIOabzpb0Fl7CseC34PbQ1 +mVpvqmXoL+jeMnUliXxuyVVhf534xqJl0X6wyZXiZsGBApHyJDVzmQENBFaTa+4B +CACxyJ3oTNhz5oJOCu70mrxFqj/uqDfNm2K8Prr0CQ2I7yXijfTZGVIjURIzp+Zh +mc1LhZYlNwwI9ivFFvLoS9kH2rkx9EaIuP3ljtxQskRFrX4BepR9/EvIoi7tUuOE +qCy2pRy/y7Rc7s3Qbu/sPQ17wvRQqzTKsvoh9wxat6990l1MFjlF/xBOD4Qb9LJG +zc6Y8SLEEs7l/vAesL0viOME1hVQk+fG0KFosI32aeNnnLHPZbLiZ2YETvI5nROM +hleSDusqUpVxXzkIBcVLbCyeJooRsZAhJ6AB8qvhOXx2xTBBgMpwaE/DHF6Zkvms +VB6lRNqMLjGeLOkmqx1vjZynABEBAAG0IkJodXNoYW4gU2hhaCAoa2RlKSA8YnNo +YWhAa2RlLm9yZz6JATcEEwEIACEFAld3rtICGwMFCwkIBwIGFQgJCgsCBBYCAwEC +HgECF4AACgkQ/geEEX+84R1tfwf9GSACMGPFi9AArBwFhaYUKB4BJqNgCSRvQJ7g +tG6YAaW+o919AtmpO+nq0JtvrSXQVLbJ1jxEMXsNJnvZByiACm91u8z/LzMoI5C6 +RK13eGTTBr57LAE8lXI0xhkiSwQUAPQWJXumE1evoHExHrAi+z6aLa6QXwyqmP5a +mwked6S6R9GxGI2c+UPm9sVh4Lb1L/pEzeCdt7/1R1baAQ+weI1cVbfd4b9Qc5r/ +baq41CesZKz29UgorqiLyBXlWLUCClAXB/nrbAh7hR4pDhSsIExSTp8gBnBTpKc2 +NAzGZTxopcvi/SOAxkdFlfkBewXuvHOxg0S8s8z7Owaeckbj7bQgQmh1c2hhbiBT +aGFoIDxiaHVzaDk0QGdtYWlsLmNvbT6JATcEEwEIACEFAlaTa+4CGwMFCwkIBwIG +FQgJCgsCBBYCAwECHgECF4AACgkQ/geEEX+84R3CQggAmSPWL+WBizj5WIcSZ2Ox +1jCNnCcZ73K84s7ZSd83mq6fgi4O4/JqoZCMCU2YzMuo7Cs/h1UPXkARgf/bPFi7 +XKvEytQd0lOSUSubn27ederXfUuhUo5FNneiyYBX9Ri1RjOPv5oE3cmYWM34Xvl/ +O6ucRJ28s8Z9GuWG6NChbbHdkDIhulCzWWiMtIQXG7zGWRdjcqRItGVSjEaCdyWE +L6i//5n0TiM+PPidmFO4A56blLCHrIe6MPW/fAiWBzWpTxTUpn66XC3AMBWdLT/5 +ZCNea1qXY+I/TBwIiBl1mKFN1j945j216mnX1IHBSR01yrMxsBnJ+Hx3i32OxhEf +jrkBDQRWk2vuAQgAvA+l8nsDh1/p03OJgUHy5q5jSbukV+5GP3MLwLLJHrzkzT84 +CSbZ1CUCNYgAViO1PPGn4wL1NcM2KwXxH0ON4dXD8OjTGOP3Jh3vGIpgoJPHDWCh +ktLDN/mCfITU0hsSiWu2N0Q8QyyvX0qhtcWulEXHLTU+e62ru8VLVRMRaTdKhnk7 +TADiw6d+sGPo0mAaVWe/2f49Eg0H/UoVNBtjmTCrGb3B9SmnTlVuJE9uyEhzexCW +43TDwpmcrSfuUsYvTxR2Aq/50dagWP49KLiku9bkoc3LLM+VoJ5Jj/O377H6XwkC +ZeUpIj2r3XaHWaAQkUSsKkJ1e57NyRZoe1NvpQARAQABiQEfBBgBCAAJBQJWk2vu +AhsMAAoJEP4HhBF/vOEdONIH/RviPwDNbm+1AITwED2duUnSGkx/ejFeXJlrLnE5 +xlMtVw4fCNIWWhAf5JFhzq5mysqoYPzbYBKl7T/5KiV+a7k7fQDd00pcSfiKwssA +pt95Eu8j0QA4MDbIaAn/xx91bo3HDeCnw4yLooy0mW3yGxunBqNm4Ks+reKfTWma +H3EIRXz8AIH79yC9QzRamb1KIQz8v4+XlOyHQ48rS54RlGU30q84Vl5AmcmykTlt +Oc0nDEXebi92/op/2bvK4HhP5SxfJ5g+NmCdOfJ/u9i40ez+Q6q25WwIS4kIPAgW +6yBSaM0FMlA5088LBkRbkAMe268qbDkqln2HFRKl8YicHay5AQ0EWivdggEIALrl +1fmIdKmDulkGS5xPl9AYrz5UWNbx+Adsw4AwWNKq2yHT5eP6b28EC5P1aNslWah3 +6BoW6pwZF2Rac1fUDDpxHa6zKPLp5v9Nn+27hGeel5JCk6XpbJet0LtKrtvyEqX8 +QsURSxmXY/lSwNEloXtHnMIEfvdWb3ChNW8n8xvfrG1WNL/FkKvWX8dIVKP9CX+/ +hQIlFiIJkulx7gp/g2AUx6xnBhH/glOuPpXx+Qmxs+NgCqrGM2cGFleEWq8DQVQ7 +jOl3apQvZuFnETqLOasldF0ObBP0gcrhztWuWWsxRT2656ogbYNTzkLOLkMOMFNk +bBDPmxlCETUxaCKYx7EAEQEAAYkCbAQYAQgAIBYhBAqsd1u2Q3qNmvejrP4HhBF/ +vOEdBQJaK92CAhsCAUAJEP4HhBF/vOEdwHQgBBkBCAAdFiEEs8s2ZVJUC+Bu6a2X +EZaMRJKMrvwFAlor3YIACgkQEZaMRJKMrvxlSQf/dMHVeQbG+d1/2otR3UnBO3T/ +nJYQ41RIFPO+tNRe3J7c3qPRAErKNmC3ZF5zROBqvEx1KVy5Pzy05bpuc9jqzmG3 +H681lNZC0YLg4FXIqnMiPuHr+T+cHIU6y60Tl+7shBquX0x2Iu8RJqJURlxVBAHL +FkRsEugzqtvLA0m4aPi0S18jwRVROpU5l84yGsOacT4DFxxj429r7hz94XBUt/Ap +GyoBYJ75Qs3gnmt8uq1bPOsVVIv5dQv7QHUxR5MW0EM8qGzVjheebo4ddoljjxap +Wi10iXEoEW+iQbpj0t1+INwxDnliyjl4Kl11nU8/Z/duRtbPWc+RKkRjj4ObVDaa +B/4g4VraKz1/cqbliz5ic6v3v+pe3dWGOadRT/PHxvt9ywzsT+vaQqnyKEuId8bS +AbaumTg/L3lYW+Bl0l96Nf6xxLq9cI/CXSCk4si0HHNGxP6qpFNc9sLTw56QzIkq +fitF87nq6zpE0dzb246tTd3gE+3KfbvrfYyDQXuC9+vg80GXcFBr4u6IzD02Nryj +OlWUhxCg5sNQuCH6faEhFQJUJNgLJZXSwP/IbgN1e+dvgqLFc+JDtIP34tS6pE7J +BX0VTu2NWW7OTeKm/9q3V6eHGBJijXvyCPsvcaAscqGwRGQRAixwmXyHTtrAeJ7e +9mPtPxudnFths9so2z9DGmaduQENBFor3b0BCACzoDyH2gsTKGGDkR3yybCeerjh +j+mHISDX8u8Blb7TT752wuF6eqvFD0oo6LpI2n8OWT2RbgWexN0KuFcf3kU3B6GK +uNAmocRQ5lL7em5wwhZbDFzVwkjlLZ4Xo+XJTIwrZu2sLZDg9uSUK8twJpsQHkL/ +NOywXImMvv4nUZWr9bEMlDoHIYkv57EkF/pZLY8FypLO0I/9zqZbvg/I04oNqhnT +VK3nZG4GYbFbHb4rZribgatyGsNopV+JevYPYqMQYu+PNW5mi1dT9gbR7KlKZhO8 +KcOCXUPjUwYgD7jPjqqNvJlk1aKL+Uh/UBznr4FSSgnzO0XwY/MxlSdx/w3LABEB +AAGJATYEGAEIACAWIQQKrHdbtkN6jZr3o6z+B4QRf7zhHQUCWivdvQIbIAAKCRD+ +B4QRf7zhHd90CACFf1rob/ih2CpCs8MyWKhGRCkXhakpPdVvnrRw3+9pjwdyfiH6 +JDWAkoBJuEf+e9KfbiAQXHMSz8E72yVO7/VLb3NJBXLvbcTVjoHtFtOOqqrkaFiM +BWcWy8HEpfF8JYYra7dUwGT67CEccs18x3hPVUyAFkH7Z470RqfCn3Ql6C4JTJG+ +CkReuaczD3+dYT0kOe29lYZsGaIfWOG+RTOHICnaLoNgof4DxVk3dChlrkkbPMSp +1LoJN19I9PPaaPNY9Q03DHswM/UGW0rNajNT4cZf0miRBMG/0j+j2hkvTD73zKbI +bs8/0reS1nrBgjiRzBunFiJv0ABSLle1liqY +=l3YP +-----END PGP PUBLIC KEY BLOCK----- diff -Nru libkscreen-5.4.2/debian/watch libkscreen-5.12.0/debian/watch --- libkscreen-5.4.2/debian/watch 2015-10-06 05:52:07.000000000 +0000 +++ libkscreen-5.12.0/debian/watch 2018-02-07 10:48:45.000000000 +0000 @@ -1,3 +1,2 @@ -version=3 -http://download.kde.org/unstable/plasma/([\d.]+)/libkscreen-([\d.]+)\.tar\.xz -http://download.kde.org/stable/plasma/([\d.]+)/libkscreen-([\d.]+)\.tar\.xz +version=4 +opts=pgpsigurlmangle=s/$/.sig/ http://download.kde.org/stable/plasma/([\d.]+)/@PACKAGE@@ANY_VERSION@@ARCHIVE_EXT@ diff -Nru libkscreen-5.4.2/interfaces/org.kde.KScreen.Backend.xml libkscreen-5.12.0/interfaces/org.kde.KScreen.Backend.xml --- libkscreen-5.4.2/interfaces/org.kde.KScreen.Backend.xml 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/interfaces/org.kde.KScreen.Backend.xml 2018-02-01 13:45:54.000000000 +0000 @@ -21,6 +21,5 @@ - diff -Nru libkscreen-5.4.2/interfaces/org.kde.KScreen.xml libkscreen-5.12.0/interfaces/org.kde.KScreen.xml --- libkscreen-5.4.2/interfaces/org.kde.KScreen.xml 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/interfaces/org.kde.KScreen.xml 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff -Nru libkscreen-5.4.2/src/CMakeLists.txt libkscreen-5.12.0/src/CMakeLists.txt --- libkscreen-5.4.2/src/CMakeLists.txt 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/CMakeLists.txt 2018-02-01 13:45:54.000000000 +0000 @@ -1,9 +1,7 @@ include_directories(${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${QT_INCLUDES}) -configure_file(config-libkscreen.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-libkscreen.h) - add_subdirectory(backendlauncher) - +add_subdirectory(doctor) set(libkscreen_SRCS abstractbackend.cpp backendmanager.cpp @@ -18,6 +16,7 @@ edid.cpp mode.cpp debug_p.cpp + log.cpp ) qt5_add_dbus_interface(libkscreen_SRCS ${CMAKE_SOURCE_DIR}/interfaces/org.kde.KScreen.Backend.xml backendinterface) @@ -45,6 +44,7 @@ ecm_generate_headers(KScreen_HEADERS HEADER_NAMES + Log Mode Output EDID diff -Nru libkscreen-5.4.2/src/abstractbackend.cpp libkscreen-5.12.0/src/abstractbackend.cpp --- libkscreen-5.4.2/src/abstractbackend.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/abstractbackend.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -19,6 +19,11 @@ #include "abstractbackend.h" +void KScreen::AbstractBackend::init(const QVariantMap &arguments) +{ + Q_UNUSED(arguments); +} + QByteArray KScreen::AbstractBackend::edid(int outputId) const { Q_UNUSED(outputId); diff -Nru libkscreen-5.4.2/src/abstractbackend.h libkscreen-5.12.0/src/abstractbackend.h --- libkscreen-5.4.2/src/abstractbackend.h 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/abstractbackend.h 2018-02-01 13:45:54.000000000 +0000 @@ -41,6 +41,16 @@ virtual ~AbstractBackend() {} /** + * This is where the backend should perform all initialization. This method + * is always called right after the backend is created. + * + * Default implementation does nothing. + * + * @p arguments Optional arguments passed by caller. Used mostly for unit-testing. + */ + virtual void init(const QVariantMap &arguments); + + /** * Returns user-friendly name of the backend */ virtual QString name() const = 0; diff -Nru libkscreen-5.4.2/src/backendlauncher/CMakeLists.txt libkscreen-5.12.0/src/backendlauncher/CMakeLists.txt --- libkscreen-5.4.2/src/backendlauncher/CMakeLists.txt 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/backendlauncher/CMakeLists.txt 2018-02-01 13:45:54.000000000 +0000 @@ -9,8 +9,16 @@ backenddbuswrapper.cpp ) +ecm_qt_declare_logging_category(backendlauncher_SRCS + HEADER debug_p.h + IDENTIFIER KSCREEN_BACKEND_LAUNCHER + CATEGORY_NAME kscreen.backendLauncher +) + qt5_add_dbus_adaptor(backendlauncher_SRCS ${CMAKE_SOURCE_DIR}/interfaces/org.kde.KScreen.Backend.xml backenddbuswrapper.h BackendDBusWrapper backendadaptor BackendAdaptor) +qt5_add_dbus_adaptor(backendlauncher_SRCS ${CMAKE_SOURCE_DIR}/interfaces/org.kde.KScreen.xml + backendloader.h BackendLoader backendloaderadaptor BackendLoaderAdaptor) add_executable(kscreen_backend_launcher ${backendlauncher_SRCS}) @@ -22,4 +30,13 @@ Qt5::DBus ) -install(TARGETS kscreen_backend_launcher DESTINATION ${CMAKE_INSTALL_FULL_LIBEXECDIR_KF5}) +install(TARGETS kscreen_backend_launcher + DESTINATION ${CMAKE_INSTALL_FULL_LIBEXECDIR_KF5} +) + +configure_file(org.kde.kscreen.service.cmake + ${CMAKE_CURRENT_BINARY_DIR}/org.kde.kscreen.service @ONLY +) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/org.kde.kscreen.service + DESTINATION ${KDE_INSTALL_DBUSSERVICEDIR} +) \ No newline at end of file diff -Nru libkscreen-5.4.2/src/backendlauncher/backenddbuswrapper.cpp libkscreen-5.12.0/src/backendlauncher/backenddbuswrapper.cpp --- libkscreen-5.4.2/src/backendlauncher/backenddbuswrapper.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/backendlauncher/backenddbuswrapper.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -20,6 +20,8 @@ #include "backenddbuswrapper.h" #include "backendloader.h" #include "backendadaptor.h" +#include "debug_p.h" + #include "src/configserializer_p.h" #include "src/config.h" #include "src/abstractbackend.h" @@ -48,14 +50,8 @@ bool BackendDBusWrapper::init() { QDBusConnection dbus = QDBusConnection::sessionBus(); - if (!dbus.registerService(mBackend->serviceName())) { - qCWarning(KSCREEN_BACKEND_LAUNCHER) << "Failed to register as DBus service: another launcher already running?"; - qCWarning(KSCREEN_BACKEND_LAUNCHER) << dbus.lastError().message(); - return false; - } - new BackendAdaptor(this); - if (!dbus.registerObject(QLatin1String("/"), this, QDBusConnection::ExportAdaptors)) { + if (!dbus.registerObject(QLatin1String("/backend"), this, QDBusConnection::ExportAdaptors)) { qCWarning(KSCREEN_BACKEND_LAUNCHER) << "Failed to export backend to DBus: another launcher already running?"; qCWarning(KSCREEN_BACKEND_LAUNCHER) << dbus.lastError().message(); return false; @@ -107,12 +103,6 @@ return edidData; } -void BackendDBusWrapper::quit() -{ - qCDebug(KSCREEN_BACKEND_LAUNCHER) << "Launcher termination requested"; - qApp->exit(BackendLoader::LauncherStopped); -} - void BackendDBusWrapper::backendConfigChanged(const KScreen::ConfigPtr &config) { Q_ASSERT(!config.isNull()); diff -Nru libkscreen-5.4.2/src/backendlauncher/backenddbuswrapper.h libkscreen-5.12.0/src/backendlauncher/backenddbuswrapper.h --- libkscreen-5.4.2/src/backendlauncher/backenddbuswrapper.h 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/backendlauncher/backenddbuswrapper.h 2018-02-01 13:45:54.000000000 +0000 @@ -45,7 +45,7 @@ QVariantMap setConfig(const QVariantMap &config); QByteArray getEdid(int output) const; - void quit(); + inline KScreen::AbstractBackend *backend() const { return mBackend; } Q_SIGNALS: void configChanged(const QVariantMap &config); @@ -56,7 +56,7 @@ private: - KScreen::AbstractBackend *mBackend; + KScreen::AbstractBackend *mBackend = nullptr; QTimer mChangeCollector; KScreen::ConfigPtr mCurrentConfig; diff -Nru libkscreen-5.4.2/src/backendlauncher/backendloader.cpp libkscreen-5.12.0/src/backendlauncher/backendloader.cpp --- libkscreen-5.4.2/src/backendlauncher/backendloader.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/backendlauncher/backendloader.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -18,7 +18,11 @@ */ #include "backendloader.h" +#include "backendloaderadaptor.h" +#include "backenddbuswrapper.h" +#include "debug_p.h" #include "src/abstractbackend.h" +#include "src/backendmanager_p.h" #include #include @@ -31,8 +35,6 @@ #include #include -Q_LOGGING_CATEGORY(KSCREEN_BACKEND_LAUNCHER, "kscreen.backendLauncher") - void pluginDeleter(QPluginLoader *p) { if (p) { @@ -44,8 +46,9 @@ BackendLoader::BackendLoader() : QObject() - , mLoader(0) - , mBackend(0) + , QDBusContext() + , mLoader(nullptr) + , mBackend(nullptr) { } @@ -56,78 +59,70 @@ qCDebug(KSCREEN_BACKEND_LAUNCHER) << "Backend loader destroyed"; } -bool BackendLoader::loadBackend(const QString& backend) +bool BackendLoader::init() +{ + QDBusConnection dbus = QDBusConnection::sessionBus(); + new BackendLoaderAdaptor(this); + if (!dbus.registerObject(QLatin1String("/"), this, QDBusConnection::ExportAdaptors)) { + qCWarning(KSCREEN_BACKEND_LAUNCHER) << "Failed to export backend to DBus: another launcher already running?"; + qCWarning(KSCREEN_BACKEND_LAUNCHER) << dbus.lastError().message(); + return false; + } + + return true; +} + +QString BackendLoader::backend() const { - qCDebug(KSCREEN_BACKEND_LAUNCHER) << "Requested backend:" << backend; - const QString backendFilter = QString::fromLatin1("KSC_%1*").arg(backend); - const QStringList paths = QCoreApplication::libraryPaths(); - qCDebug(KSCREEN_BACKEND_LAUNCHER) << "Lookup paths: " << paths; - Q_FOREACH (const QString &path, paths) { - const QDir dir(path + QLatin1String("/kf5/kscreen/"), - backendFilter, - QDir::SortFlags(QDir::QDir::NoSort), - QDir::NoDotAndDotDot | QDir::Files); - const QFileInfoList finfos = dir.entryInfoList(); - Q_FOREACH (const QFileInfo &finfo, finfos) { - // Skip "Fake" backend unless explicitly specified via KSCREEN_BACKEND - if (backend.isEmpty() && (finfo.fileName().contains(QLatin1String("KSC_Fake")) || finfo.fileName().contains(QLatin1String("KSC_FakeUI")))) { - continue; - } - - // When on X11, skip the QScreen backend, instead use the XRandR backend, - // if not specified in KSCREEN_BACKEND - if (backend.isEmpty() && - finfo.fileName().contains(QLatin1String("KSC_QScreen")) && - QX11Info::isPlatformX11()) { - continue; - } - - // When not on X11, skip the XRandR backend, and fall back to QSCreen - // if not specified in KSCREEN_BACKEND - if (backend.isEmpty() && - finfo.fileName().contains(QLatin1String("KSC_XRandR")) && - !QX11Info::isPlatformX11()) { - continue; - } - - qCDebug(KSCREEN_BACKEND_LAUNCHER) << "Trying" << finfo.filePath(); - // Make sure we unload() and delete the loader whenever it goes out of scope here - std::unique_ptr loader(new QPluginLoader(finfo.filePath()), pluginDeleter); - QObject *instance = loader->instance(); - if (!instance) { - qCDebug(KSCREEN_BACKEND_LAUNCHER) << loader->errorString(); - continue; - } - - mBackend = qobject_cast(instance); - if (mBackend) { - if (!mBackend->isValid()) { - qCDebug(KSCREEN_BACKEND_LAUNCHER) << "Skipping" << mBackend->name() << "backend"; - delete mBackend; - mBackend = 0; - continue; - } - - // This is the only case we don't want to unload() and delete the loader, instead - // we store it and unload it when the backendloader terminates. - mLoader = loader.release(); - qCDebug(KSCREEN_BACKEND_LAUNCHER) << "Loading" << mBackend->name() << "backend"; - return true; - } else { - qCDebug(KSCREEN_BACKEND_LAUNCHER) << finfo.fileName() << "does not provide valid KScreen backend"; - } + if (mBackend) { + return mBackend->backend()->name(); + } + + return QString(); +} + +bool BackendLoader::requestBackend(const QString &backendName, const QVariantMap &arguments) +{ + if (mBackend) { + // If an backend is already loaded, but it's not the same as the one + // requested, then it's an error + if (!backendName.isEmpty() && mBackend->backend()->name() != backendName) { + sendErrorReply(QDBusError::Failed, QStringLiteral("Another backend is already active")); + return false; + } else { + // If caller requested the same one as already loaded, or did not + // request a specific backend, hapilly reuse the existing one + return true; } } - return false; + KScreen::AbstractBackend *backend = loadBackend(backendName, arguments); + if (!backend) { + return false; + } + + mBackend = new BackendDBusWrapper(backend); + if (!mBackend->init()) { + delete mBackend; + mBackend = nullptr; + pluginDeleter(mLoader); + mLoader = nullptr; + return false; + } + return true; } -KScreen::AbstractBackend* BackendLoader::backend() const +KScreen::AbstractBackend *BackendLoader::loadBackend(const QString &name, + const QVariantMap &arguments) { - return mBackend; + if (mLoader == nullptr) { + std::unique_ptr loader(new QPluginLoader(), pluginDeleter); + mLoader = loader.release(); + } + return KScreen::BackendManager::loadBackendPlugin(mLoader, name, arguments); } -bool BackendLoader::checkIsAlreadyRunning() +void BackendLoader::quit() { - return QDBusConnection::sessionBus().interface()->isServiceRegistered(mBackend->serviceName()); + qApp->quit(); } diff -Nru libkscreen-5.4.2/src/backendlauncher/backendloader.h libkscreen-5.12.0/src/backendlauncher/backendloader.h --- libkscreen-5.4.2/src/backendlauncher/backendloader.h 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/backendlauncher/backendloader.h 2018-02-01 13:45:54.000000000 +0000 @@ -21,40 +21,38 @@ #define BACKENDLAUNCHER_H #include -#include - -class QPluginLoader; +#include namespace KScreen { class AbstractBackend; } +class QPluginLoader; +class BackendDBusWrapper; + class BackendLoader : public QObject + , protected QDBusContext { Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "org.kde.KScreen") public: - enum State { - BackendLoaded = 0, - BackendAlreadyExists = 1, - BackendFailedToLoad = 2, - LauncherStopped = 3 - }; - explicit BackendLoader(); ~BackendLoader(); - bool loadBackend(const QString &backendName = QString()); - bool checkIsAlreadyRunning(); + bool init(); - KScreen::AbstractBackend* backend() const; + Q_INVOKABLE QString backend() const; + Q_INVOKABLE bool requestBackend(const QString &name, const QVariantMap &arguments); + Q_INVOKABLE void quit(); private: - QPluginLoader *mLoader; - KScreen::AbstractBackend* mBackend; -}; + KScreen::AbstractBackend *loadBackend(const QString &name, const QVariantMap &arguments); -Q_DECLARE_LOGGING_CATEGORY(KSCREEN_BACKEND_LAUNCHER) +private: + QPluginLoader *mLoader = nullptr; + BackendDBusWrapper *mBackend = nullptr; +}; #endif // BACKENDLAUNCHER_H diff -Nru libkscreen-5.4.2/src/backendlauncher/main.cpp libkscreen-5.12.0/src/backendlauncher/main.cpp --- libkscreen-5.4.2/src/backendlauncher/main.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/backendlauncher/main.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -18,68 +18,32 @@ */ #include -#include -#include +#include +#include "debug_p.h" #include "backendloader.h" -#include "backenddbuswrapper.h" - -#include +#include "log.h" int main(int argc, char **argv) { + KScreen::Log::instance(); QGuiApplication::setDesktopSettingsAware(false); QGuiApplication app(argc, argv); - BackendLoader *loader = new BackendLoader; - - QCommandLineOption backendOption(QLatin1String("backend"), - QLatin1String("Backend to load. When not specified, BackendLauncher will " - "try to load the best backend for current platform."), - QLatin1String("backend")); - QCommandLineParser parser; - parser.addOption(backendOption); - parser.addHelpOption(); - - parser.process(app); - - bool success = false; - if (parser.isSet(backendOption)) { - success = loader->loadBackend(parser.value(backendOption)); - } else { - success = loader->loadBackend(); + if (!QDBusConnection::sessionBus().registerService(QStringLiteral("org.kde.KScreen"))) { + qCWarning(KSCREEN_BACKEND_LAUNCHER) << "Cannot register org.kde.KScreen service. Another launcher already running?"; + return -1; } - // We failed to load any backend: abort immediatelly - if (!success) { - return BackendLoader::BackendFailedToLoad; - } - - // Create BackendDBusWrapper that takes implements the DBus interface and translates - // DBus calls to backend implementations. It will also take care of terminating this - // loader when no other KScreen-enabled processes are running - BackendDBusWrapper backendWrapper(loader->backend()); - if (!backendWrapper.init()) { - // Loading failed, maybe it failed because another process is already running; if so we still want to print the path before we exit - // Check if another Backend Launcher with this particular backend is already running - const bool alreadyRunning = loader->checkIsAlreadyRunning(); - if (alreadyRunning) { - // If it is, let caller now it's DBus service name and terminate - printf("%s", qPrintable(loader->backend()->serviceName())); - fflush(stdout); - return BackendLoader::BackendAlreadyExists; - } - return BackendLoader::BackendFailedToLoad; + BackendLoader *loader = new BackendLoader; + if (!loader->init()) { + return -2; } - // Now let caller now what's our DBus service name, so it can connect to us - printf("%s", qPrintable(loader->backend()->serviceName())); - fflush(stdout); - - // And go! const int ret = app.exec(); - // Make sure the backend is destroyed and unloaded before we return + // Make sure the backend is destroyed and unloaded before we return (i.e. + // as long as QApplication object and it's XCB connection still exist delete loader; return ret; diff -Nru libkscreen-5.4.2/src/backendlauncher/org.kde.kscreen.service.cmake libkscreen-5.12.0/src/backendlauncher/org.kde.kscreen.service.cmake --- libkscreen-5.4.2/src/backendlauncher/org.kde.kscreen.service.cmake 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/src/backendlauncher/org.kde.kscreen.service.cmake 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.kde.KScreen +Exec=@CMAKE_INSTALL_FULL_LIBEXECDIR_KF5@/kscreen_backend_launcher \ No newline at end of file diff -Nru libkscreen-5.4.2/src/backendmanager.cpp libkscreen-5.12.0/src/backendmanager.cpp --- libkscreen-5.4.2/src/backendmanager.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/backendmanager.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -1,5 +1,6 @@ /* * Copyright (C) 2014 Daniel Vratil + * Copyright 2015 Sebastian Kügler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,28 +18,30 @@ * */ + #include "backendmanager_p.h" + +#include "abstractbackend.h" +#include "config.h" +#include "configmonitor.h" #include "backendinterface.h" -#include "backendlauncher/backendloader.h" #include "debug_p.h" #include "getconfigoperation.h" #include "configserializer_p.h" +#include "log.h" #include #include #include #include #include +#include #include +#include +#include -#include "config-libkscreen.h" +#include -#include - -#ifdef Q_OS_UNIX -#include -#include -#endif using namespace KScreen; @@ -46,7 +49,7 @@ const int BackendManager::sMaxCrashCount = 4; -BackendManager *BackendManager::sInstance = 0; +BackendManager *BackendManager::sInstance = nullptr; BackendManager *BackendManager::instance() { @@ -61,30 +64,193 @@ : QObject() , mInterface(0) , mCrashCount(0) - , mLauncher(0) , mShuttingDown(false) , mRequestsCounter(0) + , mLoader(0) + , mMethod(OutOfProcess) { - qRegisterMetaType("OrgKdeKscreenBackendInterface"); + Log::instance(); + // Decide wether to run in, or out-of-process - mServiceWatcher.setConnection(QDBusConnection::sessionBus()); - connect(&mServiceWatcher, &QDBusServiceWatcher::serviceUnregistered, - this, &BackendManager::backendServiceUnregistered); - - mResetCrashCountTimer.setSingleShot(true); - mResetCrashCountTimer.setInterval(60000); - connect(&mResetCrashCountTimer, &QTimer::timeout, - this, [=]() { - mCrashCount = 0; - }); + // if KSCREEN_BACKEND_INPROCESS is set explicitely, we respect that + const auto _inprocess = qgetenv("KSCREEN_BACKEND_INPROCESS"); + if (!_inprocess.isEmpty()) { + + const QByteArrayList falses({QByteArray("0"), QByteArray("false")}); + if (!falses.contains(_inprocess.toLower())) { + mMethod = InProcess; + } else { + mMethod = OutOfProcess; + } + } else { + // For XRandR backends, use out of process + if (preferredBackend().fileName().startsWith(QLatin1String("KSC_XRandR"))) { + mMethod = OutOfProcess; + } else { + mMethod = InProcess; + } + } + initMethod(); +} + +void BackendManager::initMethod() +{ + if (mMethod == OutOfProcess) { + qRegisterMetaType("OrgKdeKscreenBackendInterface"); + + mServiceWatcher.setConnection(QDBusConnection::sessionBus()); + connect(&mServiceWatcher, &QDBusServiceWatcher::serviceUnregistered, + this, &BackendManager::backendServiceUnregistered); + + mResetCrashCountTimer.setSingleShot(true); + mResetCrashCountTimer.setInterval(60000); + connect(&mResetCrashCountTimer, &QTimer::timeout, + this, [=]() { + mCrashCount = 0; + }); + } +} + +void BackendManager::setMethod(BackendManager::Method m) +{ + if (mMethod == m) { + return; + } + shutdownBackend(); + mMethod = m; + initMethod(); +} + +BackendManager::Method BackendManager::method() const +{ + return mMethod; } BackendManager::~BackendManager() { + if (mMethod == InProcess) { + shutdownBackend(); + } +} + +QFileInfo BackendManager::preferredBackend(const QString &backend) +{ + /** this is the logic to pick a backend, in order of priority + * + * - backend argument is used if not empty + * - env var KSCREEN_BACKEND is considered + * - if platform is X11, the XRandR backend is picked + * - if platform is wayland, KWayland backend is picked + * - if neither is the case, QScreen backend is picked + * - the QScreen backend is also used as fallback + * + */ + QString backendFilter; + const auto env_kscreen_backend = qgetenv("KSCREEN_BACKEND"); + if (!backend.isEmpty()) { + backendFilter = backend; + } else if (!env_kscreen_backend.isEmpty()) { + backendFilter = env_kscreen_backend; + } else { + if (QX11Info::isPlatformX11()) { + backendFilter = QStringLiteral("XRandR"); + } else if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"))) { + backendFilter = QStringLiteral("KWayland"); + } else { + backendFilter = QStringLiteral("QScreen"); + } + } + QFileInfo fallback; + Q_FOREACH (const QFileInfo &f, listBackends()) { + // Here's the part where we do the match case-insensitive + if (f.baseName().toLower() == QStringLiteral("ksc_%1").arg(backendFilter.toLower())) { + return f; + } + if (f.baseName() == QLatin1String("KSC_QScreen")) { + fallback = f; + } + } +// qCWarning(KSCREEN) << "No preferred backend found. KSCREEN_BACKEND is set to " << env_kscreen_backend; +// qCWarning(KSCREEN) << "falling back to " << fallback.fileName(); + return fallback; +} + +QFileInfoList BackendManager::listBackends() +{ + // Compile a list of installed backends first + const QString backendFilter = QStringLiteral("KSC_*"); + const QStringList paths = QCoreApplication::libraryPaths(); + QFileInfoList finfos; + for (const QString &path : paths) { + const QDir dir(path + QLatin1String("/kf5/kscreen/"), + backendFilter, + QDir::SortFlags(QDir::QDir::Name), + QDir::NoDotAndDotDot | QDir::Files); + finfos.append(dir.entryInfoList()); + } + return finfos; +} + +KScreen::AbstractBackend *BackendManager::loadBackendPlugin(QPluginLoader *loader, const QString &name, + const QVariantMap &arguments) +{ + const auto finfo = preferredBackend(name); + loader->setFileName(finfo.filePath()); + QObject *instance = loader->instance(); + if (!instance) { + qCDebug(KSCREEN) << loader->errorString(); + return nullptr; + } + + auto backend = qobject_cast(instance); + if (backend) { + backend->init(arguments); + if (!backend->isValid()) { + qCDebug(KSCREEN) << "Skipping" << backend->name() << "backend"; + delete backend; + return nullptr; + } + //qCDebug(KSCREEN) << "Loaded" << backend->name() << "backend"; + return backend; + } else { + qCDebug(KSCREEN) << finfo.fileName() << "does not provide valid KScreen backend"; + } + + return nullptr; +} + +KScreen::AbstractBackend *BackendManager::loadBackendInProcess(const QString &name) +{ + Q_ASSERT(mMethod == InProcess); + if (mMethod == OutOfProcess) { + qCWarning(KSCREEN) << "You are trying to load a backend in process, while the BackendManager is set to use OutOfProcess communication. Use loadBackendPlugin() instead."; + return nullptr; + } + if (m_inProcessBackend.first != nullptr && (name.isEmpty() || m_inProcessBackend.first->name() == name)) { + return m_inProcessBackend.first; + } else if (m_inProcessBackend.first != nullptr && m_inProcessBackend.first->name() != name) { + shutdownBackend(); + } + + if (mLoader == nullptr) { + mLoader = new QPluginLoader(this); + } + QVariantMap arguments; + auto beargs = QString::fromLocal8Bit(qgetenv("KSCREEN_BACKEND_ARGS")); + if (beargs.startsWith("TEST_DATA=")) { + arguments["TEST_DATA"] = beargs.remove("TEST_DATA="); + } + auto backend = BackendManager::loadBackendPlugin(mLoader, name, arguments); + //qCDebug(KSCREEN) << "Connecting ConfigMonitor to backend."; + ConfigMonitor::instance()->connectInProcessBackend(backend); + m_inProcessBackend = qMakePair(backend, arguments); + setConfig(backend->config()); + return backend; } void BackendManager::requestBackend() { + Q_ASSERT(mMethod == OutOfProcess); if (mInterface && mInterface->isValid()) { ++mRequestsCounter; QMetaObject::invokeMethod(this, "emitBackendReady", Qt::QueuedConnection); @@ -97,11 +263,25 @@ } ++mRequestsCounter; - startBackend(QString::fromLatin1(qgetenv("KSCREEN_BACKEND"))); + const QByteArray args = qgetenv("KSCREEN_BACKEND_ARGS"); + QVariantMap arguments; + if (!args.isEmpty()) { + QList arglist = args.split(';'); + Q_FOREACH (const QByteArray &arg, arglist) { + const int pos = arg.indexOf('='); + if (pos == -1) { + continue; + } + arguments.insert(arg.left(pos), arg.mid(pos + 1)); + } + } + + startBackend(QString::fromLatin1(qgetenv("KSCREEN_BACKEND")), arguments); } void BackendManager::emitBackendReady() { + Q_ASSERT(mMethod == OutOfProcess); Q_EMIT backendReady(mInterface); --mRequestsCounter; if (mShutdownLoop.isRunning()) { @@ -109,156 +289,84 @@ } } -void BackendManager::startBackend(const QString &backend) +void BackendManager::startBackend(const QString &backend, const QVariantMap &arguments) { - if (mLauncher && mLauncher->state() == QProcess::Running) { - mLauncher->terminate(); - } - - mLauncher = new QProcess(this); - connect(mLauncher, static_cast(&QProcess::finished), - this, &BackendManager::launcherFinished); - connect(mLauncher, &QProcess::readyReadStandardOutput, - this, &BackendManager::launcherDataAvailable); - - QString launcher = QString::fromLatin1(CMAKE_INSTALL_FULL_LIBEXECDIR_KF5 "/kscreen_backend_launcher"); - if (!QFile::exists(launcher)) { - launcher = QStandardPaths::findExecutable("kscreen_backend_launcher"); - if (launcher.isEmpty()) { - qCWarning(KSCREEN) << "Failed to locate kscreen_backend_launcher, KScreen will be useless"; - invalidateInterface(); - delete mLauncher; - mLauncher = 0; - QMetaObject::invokeMethod(this, "emitBackendReady", Qt::QueuedConnection); - return; - } - } - - mLauncher->setProgram(launcher); - if (!backend.isEmpty()) { - mLauncher->setArguments(QStringList() << "--backend" << backend); - } - - mLauncher->start(); - if (!qgetenv("KSCREEN_BACKEND_DEBUG").isEmpty()) { - pid_t pid = mLauncher->pid(); - qCDebug(KSCREEN) << "=================================="; - qCDebug(KSCREEN) << "KScreen BackendManager: Suspending backend launcher"; - qCDebug(KSCREEN) << "'gdb --pid" << pid << "' to debug"; - qCDebug(KSCREEN) << "'kill -SIGCONT" << pid << "' to continue"; - qCDebug(KSCREEN) << "=================================="; - qCDebug(KSCREEN); - kill(pid, SIGSTOP); - } - - mResetCrashCountTimer.start(); -} - -void BackendManager::launcherFinished(int exitCode, QProcess::ExitStatus exitStatus) -{ - qCDebug(KSCREEN) << "Launcher finished with exit code" << exitCode << ", status" << exitStatus; - - // Stop the timer if it's running, otherwise the number would get reset to 0 - // anyway even if we reached the sMaxCrashCount, and then the backend would - // be restarted again anyway. - mResetCrashCountTimer.stop(); - - if (exitStatus == QProcess::CrashExit) { - // Backend has crashed: restart it + // This will autostart the launcher if it's not running already, calling + // requestBackend(backend) will: + // a) if the launcher is started it will force it to load the correct backend, + // b) if the launcher is already running it will make sure it's running with + // the same backend as the one we requested and send an error otherwise + QDBusConnection conn = QDBusConnection::sessionBus(); + QDBusMessage call = QDBusMessage::createMethodCall(QStringLiteral("org.kde.KScreen"), + QStringLiteral("/"), + QStringLiteral("org.kde.KScreen"), + QStringLiteral("requestBackend")); + call.setArguments({ backend, arguments }); + QDBusPendingCall pending = conn.asyncCall(call); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pending); + connect(watcher, &QDBusPendingCallWatcher::finished, + this, &BackendManager::onBackendRequestDone); +} + +void BackendManager::onBackendRequestDone(QDBusPendingCallWatcher *watcher) +{ + Q_ASSERT(mMethod == OutOfProcess); + watcher->deleteLater(); + QDBusPendingReply reply = *watcher; + // Most probably we requested an explicit backend that is different than the + // one already loaded in the launcher + if (reply.isError()) { + qCWarning(KSCREEN) << "Failed to request backend:" << reply.error().name() << ":" << reply.error().message(); invalidateInterface(); - if (!mShuttingDown) { - if (++mCrashCount <= sMaxCrashCount) { - requestBackend(); - } else { - qCWarning(KSCREEN) << "Launcher has crashed too many times: not restarting"; - mLauncher->deleteLater(); - mLauncher = 0; - } - } - mShuttingDown = false; + emitBackendReady(); return; } - switch (exitCode) { - case BackendLoader::BackendLoaded: - // This means that the launcher has terminated successfully after doing - // what it was asked to do, so delete the interface, but don't emit signals - invalidateInterface(); - break; - - case BackendLoader::BackendFailedToLoad: - // Launcher terminated immediatelly because there was no backend, this - // means that we didn't try before and someone is probably waiting for - // the signal - qCWarning(KSCREEN) << "Launcher failed to load any backend: KScreen will be useless"; + // Most probably request and explicit backend which is not available or failed + // to initialize, or the launcher did not find any suitable backend for the + // current platform. + if (!reply.value()) { + qCWarning(KSCREEN) << "Failed to request backend: unknown error"; invalidateInterface(); emitBackendReady(); - break; + return; + } - case BackendLoader::BackendAlreadyExists: - // The launcher wrote service name to stdout, so backendReady() was emitted - // from launcherDataAvailable(), nothing else to do here - qCDebug(KSCREEN) << "Service for requested backend already running"; - break; - - case BackendLoader::LauncherStopped: - // The launcher has been stopped on request, probably by someone calling - // shutdownBackend() - qCDebug(KSCREEN) << "Backend launcher terminated on requested"; + // The launcher has successfully loaded the backend we wanted and registered + // it to DBus (hopefuly), let's try to get an interface for the backend. + if (mInterface) { invalidateInterface(); - break; } - - mShuttingDown = false; - mLauncher->deleteLater(); - mLauncher = 0; -}; - -void BackendManager::launcherDataAvailable() -{ - mLauncher->setReadChannel(QProcess::StandardOutput); - const QByteArray service = mLauncher->readLine(); - qCDebug(KSCREEN) << "launcherDataAvailable:" << service; - mBackendService = QString::fromLatin1(service); - - mInterface = new org::kde::kscreen::Backend(mBackendService, - QLatin1String("/"), - QDBusConnection::sessionBus(), - this); + mInterface = new org::kde::kscreen::Backend(QStringLiteral("org.kde.KScreen"), + QStringLiteral("/backend"), + QDBusConnection::sessionBus()); if (!mInterface->isValid()) { - QDBusServiceWatcher *watcher = new QDBusServiceWatcher(mBackendService, - QDBusConnection::sessionBus()); - connect(watcher, &QDBusServiceWatcher::serviceOwnerChanged, - [&](const QString &service, const QString &oldOwner, const QString &newOwner) { - qDebug() << service << newOwner << oldOwner; - if (newOwner == mBackendService) { - backendServiceReady(); - } - }); + qCWarning(KSCREEN) << "Backend successfully requested, but we failed to obtain a valid DBus interface for it"; + invalidateInterface(); + emitBackendReady(); return; } - backendServiceReady(); -} -void BackendManager::backendServiceReady() -{ + // The backend is GO, so let's watch for it's possible disappearance, so we + // can invalidate the interface mServiceWatcher.addWatchedService(mBackendService); // Immediatelly request config connect(new GetConfigOperation(GetConfigOperation::NoEDID), &GetConfigOperation::finished, [&](ConfigOperation *op) { mConfig = qobject_cast(op)->config(); + emitBackendReady(); }); + // And listen for its change. connect(mInterface, &org::kde::kscreen::Backend::configChanged, [&](const QVariantMap &newConfig) { mConfig = KScreen::ConfigSerializer::deserializeConfig(newConfig); }); - - emitBackendReady(); } void BackendManager::backendServiceUnregistered(const QString &serviceName) { + Q_ASSERT(mMethod == OutOfProcess); mServiceWatcher.removeWatchedService(serviceName); invalidateInterface(); @@ -267,6 +375,7 @@ void BackendManager::invalidateInterface() { + Q_ASSERT(mMethod == OutOfProcess); delete mInterface; mInterface = 0; mBackendService.clear(); @@ -277,29 +386,45 @@ return mConfig; } +void BackendManager::setConfig(ConfigPtr c) +{ + //qCDebug(KSCREEN) << "BackendManager::setConfig, outputs:" << c->outputs().count(); + mConfig = c; +} + void BackendManager::shutdownBackend() { - if (mBackendService.isEmpty() && !mInterface) { - return; - } + if (mMethod == InProcess) { + delete mLoader; + mLoader = nullptr; + m_inProcessBackend.second.clear(); + delete m_inProcessBackend.first; + m_inProcessBackend.first = nullptr; + } else { - while (mRequestsCounter > 0) { - mShutdownLoop.exec(); - } + if (mBackendService.isEmpty() && !mInterface) { + return; + } - mServiceWatcher.removeWatchedService(mBackendService); - mShuttingDown = true; - const QDBusReply reply = QDBusConnection::sessionBus().interface()->servicePid(mInterface->service()); + // If there are some currently pending requests, then wait for them to + // finish before quitting + while (mRequestsCounter > 0) { + mShutdownLoop.exec(); + } - // Call synchronously - mInterface->quit().waitForFinished(); - invalidateInterface(); + mServiceWatcher.removeWatchedService(mBackendService); + mShuttingDown = true; - if (mLauncher) { - mLauncher->waitForFinished(5000); - // This will ensure that launcherFinished() is called, which will take care - // of deleting the QProcess - } else { - // ... ? + QDBusMessage call = QDBusMessage::createMethodCall(QStringLiteral("org.kde.KScreen"), + QStringLiteral("/"), + QStringLiteral("org.kde.KScreen"), + QStringLiteral("quit")); + // Call synchronously + QDBusConnection::sessionBus().call(call); + invalidateInterface(); + + while (QDBusConnection::sessionBus().interface()->isServiceRegistered(QStringLiteral("org.kde.KScreen"))) { + QThread::msleep(100); + } } } diff -Nru libkscreen-5.4.2/src/backendmanager_p.h libkscreen-5.12.0/src/backendmanager_p.h --- libkscreen-5.4.2/src/backendmanager_p.h 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/backendmanager_p.h 2018-02-01 13:45:54.000000000 +0000 @@ -1,5 +1,6 @@ /* * Copyright (C) 2014 Daniel Vratil + * Copyright 2015 Sebastian Kügler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -27,8 +28,10 @@ #define KSCREEN_BACKENDMANAGER_H #include +#include #include #include +#include #include #include @@ -40,57 +43,113 @@ namespace KScreen { +class AbstractBackend; + class KSCREEN_EXPORT BackendManager : public QObject { Q_OBJECT public: + enum Method { + InProcess, + OutOfProcess + }; + static BackendManager *instance(); ~BackendManager(); - void requestBackend(); - KScreen::ConfigPtr config() const; + void setConfig(KScreen::ConfigPtr c); + + /** Choose which backend to use + * + * This method uses a couple of heuristics to pick the backend to be loaded: + * - If the @p backend argument is specified and not empty it's used to filter the + * available backend list + * - If specified, the KSCREEN_BACKEND env var is considered (case insensitive) + * - Otherwise, the wayland backend is picked when the runtime platform is Wayland + * (we assume kwin in this case + * - Otherwise, if the runtime platform is X11, the XRandR backend is picked + * - If neither is the case, we fall back to the QScreen backend, since that is the + * most generally applicable and may work on platforms not explicitely supported + * + * @return the backend plugin to load + * @since 5.7 + */ + static QFileInfo preferredBackend(const QString &backend = QString()); + + /** List installed backends + * @return a list of installed backend plugins + * @since 5.7 + */ + static QFileInfoList listBackends(); + + /** Encapsulates the plugin loading logic. + * + * @param loader a pointer to the QPluginLoader, the caller is + * responsible for its memory management. + * @param name name of the backend plugin + * @param arguments arguments, used for unit tests + * @return a pointer to the backend loaded from the plugin + * @since 5.6 + */ + static KScreen::AbstractBackend *loadBackendPlugin(QPluginLoader *loader, + const QString &name, + const QVariantMap &arguments); + + KScreen::AbstractBackend *loadBackendInProcess(const QString &name); + BackendManager::Method method() const; + void setMethod(BackendManager::Method m); + + // For out-of-process operation + void requestBackend(); void shutdownBackend(); Q_SIGNALS: void backendReady(OrgKdeKscreenBackendInterface *backend); - private Q_SLOTS: void emitBackendReady(); - void startBackend(const QString &backend = QString()); - - void launcherFinished(int existCode, QProcess::ExitStatus exitStatus); - void launcherDataAvailable(); + void startBackend(const QString &backend = QString(), + const QVariantMap &arguments = QVariantMap()); + void onBackendRequestDone(QDBusPendingCallWatcher *watcher); void backendServiceUnregistered(const QString &serviceName); private: - void findBestBackend(); - void invalidateInterface(); - void backendServiceReady(); - + friend class SetInProcessOperation; + friend class InProcessConfigOperationPrivate; + friend class SetConfigOperation; + friend class SetConfigOperationPrivate; explicit BackendManager(); static BackendManager *sInstance; - static const int sMaxCrashCount; + void initMethod(); + + // For out-of-process operation + void invalidateInterface(); + void backendServiceReady(); + + static const int sMaxCrashCount; OrgKdeKscreenBackendInterface *mInterface; int mCrashCount; - QProcess *mLauncher; QString mBackendService; QDBusServiceWatcher mServiceWatcher; KScreen::ConfigPtr mConfig; QTimer mResetCrashCountTimer; bool mShuttingDown; - int mRequestsCounter; QEventLoop mShutdownLoop; + // For in-process operation + QPluginLoader *mLoader; + QPair m_inProcessBackend; + + Method mMethod; }; } diff -Nru libkscreen-5.4.2/src/config-libkscreen.h.cmake libkscreen-5.12.0/src/config-libkscreen.h.cmake --- libkscreen-5.4.2/src/config-libkscreen.h.cmake 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/config-libkscreen.h.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ - -#define CMAKE_INSTALL_FULL_LIBEXECDIR_KF5 "${CMAKE_INSTALL_FULL_LIBEXECDIR_KF5}" \ No newline at end of file diff -Nru libkscreen-5.4.2/src/config.cpp libkscreen-5.12.0/src/config.cpp --- libkscreen-5.4.2/src/config.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/config.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -35,6 +35,7 @@ Private(Config *parent) : QObject(parent) , valid(true) + , supportedFeatures(Config::Feature::None) , q(parent) { } @@ -86,6 +87,7 @@ ScreenPtr screen; OutputPtr primaryOutput; OutputList outputs; + Features supportedFeatures; private: Config *q; @@ -98,6 +100,10 @@ bool Config::canBeApplied(const ConfigPtr &config, ValidityFlags flags) { + if (!config) { + qCDebug(KSCREEN) << "canBeApplied: Config not available, returning false"; + return false; + } ConfigPtr currentConfig = BackendManager::instance()->config(); if (!currentConfig) { qCDebug(KSCREEN) << "canBeApplied: Current config not available, returning false"; @@ -192,12 +198,11 @@ } Config::Config() - : QObject(0) + : QObject(nullptr) , d(new Private(this)) { } - Config::~Config() { delete d; @@ -211,7 +216,7 @@ newConfig->addOutput(ourOutput->clone()); } newConfig->d->primaryOutput = newConfig->d->findPrimaryOutput(); - + newConfig->setSupportedFeatures(supportedFeatures()); return newConfig; } @@ -231,6 +236,16 @@ return d->outputs.value(outputId); } +Config::Features Config::supportedFeatures() const +{ + return d->supportedFeatures; +} + +void Config::setSupportedFeatures(const Config::Features &features) +{ + d->supportedFeatures = features; +} + OutputList Config::outputs() const { return d->outputs; @@ -267,9 +282,9 @@ return; } - qDebug(KSCREEN) << "Primary output changed from" << primaryOutput() - << "(" << (primaryOutput().isNull() ? "none" : primaryOutput()->name()) << ") to" - << newPrimary << "(" << (newPrimary.isNull() ? "none" : newPrimary->name()) << ")"; +// qCDebug(KSCREEN) << "Primary output changed from" << primaryOutput() +// << "(" << (primaryOutput().isNull() ? "none" : primaryOutput()->name()) << ") to" +// << newPrimary << "(" << (newPrimary.isNull() ? "none" : newPrimary->name()) << ")"; for (OutputPtr &output : d->outputs) { disconnect(output.data(), &KScreen::Output::isPrimaryChanged, @@ -348,4 +363,22 @@ setValid(other->isValid()); } -#include "config.moc" \ No newline at end of file + +QDebug operator<<(QDebug dbg, const KScreen::ConfigPtr &config) +{ + if (config) { + dbg << "KScreen::Config("; + for (const auto output : config->outputs()) { + if (output->isConnected()) { + dbg << endl << output; + } + } + dbg << ")"; + } else { + dbg << "KScreen::Config(NULL)"; + } + return dbg; +} + + +#include "config.moc" diff -Nru libkscreen-5.4.2/src/config.h libkscreen-5.12.0/src/config.h --- libkscreen-5.4.2/src/config.h 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/config.h 2018-02-01 13:45:54.000000000 +0000 @@ -56,6 +56,19 @@ }; Q_DECLARE_FLAGS(ValidityFlags, ValidityFlag) + /** This indicates which features the used backend supports. + * + * @see supportedFeatures + * @since 5.7 + */ + enum class Feature { + None = 0, ///< None of the mentioned features are supported. + PrimaryDisplay = 1, ///< The backend knows about the concept of a primary display, this is mostly limited to X11. + Writable = 1 << 1, ///< The backend supports setting the config, it's not read-only. + PerOutputScaling = 1 << 2 ///< The backend supports scaling each output individually. + }; + Q_DECLARE_FLAGS(Features, Feature) + /** * Validates that a config can be applied in the current system * @@ -119,6 +132,26 @@ void apply(const ConfigPtr &other); + /** Indicates features supported by the backend. This exists to allow the user + * to find out which of the features offered by libkscreen are actually supported + * by the backend. Not all backends are writable (QScreen, for example is + * read-only, only XRandR, but not KWayland support the primary display, etc.). + * + * @return Flags for features that are supported for this config, determined by + * the backend. + * @see setSupportedFeatures + * @since 5.7 + */ + Features supportedFeatures() const; + + /** Sets the features supported by this backend. This should not be called by the + * user, but by the backend. + * + * @see supportedFeatures + * @since 5.7 + */ + void setSupportedFeatures(const Features &features); + Q_SIGNALS: void outputAdded(const KScreen::OutputPtr &output); void outputRemoved(int outputId); @@ -133,5 +166,10 @@ } //KScreen namespace +Q_DECLARE_OPERATORS_FOR_FLAGS(KScreen::Config::Features) + +KSCREEN_EXPORT QDebug operator<<(QDebug dbg, const KScreen::ConfigPtr &config); + + #endif //KSCREEN_CONFIG_H diff -Nru libkscreen-5.4.2/src/configmonitor.cpp libkscreen-5.12.0/src/configmonitor.cpp --- libkscreen-5.4.2/src/configmonitor.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/configmonitor.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -64,6 +64,7 @@ void ConfigMonitor::Private::onBackendReady(org::kde::kscreen::Backend *backend) { + Q_ASSERT(BackendManager::instance()->method() == BackendManager::OutOfProcess); if (backend == mBackend) { return; } @@ -95,6 +96,7 @@ void ConfigMonitor::Private::getConfigFinished(ConfigOperation* op) { + Q_ASSERT(BackendManager::instance()->method() == BackendManager::OutOfProcess); if (op->hasError()) { qCWarning(KSCREEN) << "Failed to retrieve current config: " << op->errorString(); return; @@ -104,9 +106,9 @@ updateConfigs(config); } - void ConfigMonitor::Private::backendConfigChanged(const QVariantMap &configMap) { + Q_ASSERT(BackendManager::instance()->method() == BackendManager::OutOfProcess); ConfigPtr newConfig = ConfigSerializer::deserializeConfig(configMap); if (!newConfig) { qCWarning(KSCREEN) << "Failed to deserialize config from DBus change notification"; @@ -134,6 +136,8 @@ void ConfigMonitor::Private::edidReady(QDBusPendingCallWatcher* watcher) { + Q_ASSERT(BackendManager::instance()->method() == BackendManager::OutOfProcess); + const int outputId = watcher->property("outputId").toInt(); const ConfigPtr config = watcher->property("config").value(); Q_ASSERT(mPendingEDIDRequests.contains(config)); @@ -190,9 +194,9 @@ ConfigMonitor *ConfigMonitor::instance() { - static ConfigMonitor *s_instance = Q_NULLPTR; + static ConfigMonitor *s_instance = nullptr; - if (s_instance == 0) { + if (s_instance == nullptr) { s_instance = new ConfigMonitor(); } @@ -203,9 +207,11 @@ QObject(), d(new Private(this)) { - connect(BackendManager::instance(), &BackendManager::backendReady, - d, &ConfigMonitor::Private::onBackendReady); - BackendManager::instance()->requestBackend(); + if (BackendManager::instance()->method() == BackendManager::OutOfProcess) { + connect(BackendManager::instance(), &BackendManager::backendReady, + d, &ConfigMonitor::Private::onBackendReady); + BackendManager::instance()->requestBackend(); + } } ConfigMonitor::~ConfigMonitor() @@ -233,4 +239,17 @@ } } +void ConfigMonitor::connectInProcessBackend(KScreen::AbstractBackend* backend) +{ + Q_ASSERT(BackendManager::instance()->method() == BackendManager::InProcess); + connect(backend, &AbstractBackend::configChanged, [=](KScreen::ConfigPtr config) { + if (config.isNull()) { + return; + } + qCDebug(KSCREEN) << "Backend change!" << config; + d->updateConfigs(config); + }); +} + + #include "configmonitor.moc" diff -Nru libkscreen-5.4.2/src/configmonitor.h libkscreen-5.12.0/src/configmonitor.h --- libkscreen-5.4.2/src/configmonitor.h 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/configmonitor.h 2018-02-01 13:45:54.000000000 +0000 @@ -28,6 +28,9 @@ namespace KScreen { +class AbstractBackend; +class BackendManager; + class KSCREEN_EXPORT ConfigMonitor : public QObject { Q_OBJECT @@ -47,6 +50,9 @@ Q_DISABLE_COPY(ConfigMonitor) + friend BackendManager; + void connectInProcessBackend(KScreen::AbstractBackend *backend); + class Private; Private * const d; diff -Nru libkscreen-5.4.2/src/configoperation.cpp libkscreen-5.12.0/src/configoperation.cpp --- libkscreen-5.4.2/src/configoperation.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/configoperation.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -1,5 +1,6 @@ /* * Copyright (C) 2014 Daniel Vratil + * Copyright 2015 Sebastian Kügler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -21,6 +22,8 @@ #include "configoperation_p.h" #include "backendmanager_p.h" +#include "debug_p.h" + using namespace KScreen; ConfigOperationPrivate::ConfigOperationPrivate(ConfigOperation* qq) @@ -36,6 +39,7 @@ void ConfigOperationPrivate::requestBackend() { + Q_ASSERT(BackendManager::instance()->method() == BackendManager::OutOfProcess); connect(BackendManager::instance(), &BackendManager::backendReady, this, &ConfigOperationPrivate::backendReady); BackendManager::instance()->requestBackend(); @@ -43,6 +47,7 @@ void ConfigOperationPrivate::backendReady(org::kde::kscreen::Backend *backend) { + Q_ASSERT(BackendManager::instance()->method() == BackendManager::OutOfProcess); Q_UNUSED(backend); disconnect(BackendManager::instance(), &BackendManager::backendReady, @@ -124,3 +129,18 @@ deleteLater(); return !hasError(); } + +KScreen::AbstractBackend* ConfigOperationPrivate::loadBackend() +{ + Q_ASSERT(BackendManager::instance()->method() == BackendManager::InProcess); + Q_Q(ConfigOperation); + const QString &name = qgetenv("KSCREEN_BACKEND").constData(); + auto backend = KScreen::BackendManager::instance()->loadBackendInProcess(name); + if (backend == nullptr) { + const QString &e = QStringLiteral("Plugin does not provide valid KScreen backend"); + qCDebug(KSCREEN) << e; + q->setError(e); + q->emitResult(); + } + return backend; +} diff -Nru libkscreen-5.4.2/src/configoperation.h libkscreen-5.12.0/src/configoperation.h --- libkscreen-5.4.2/src/configoperation.h 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/configoperation.h 2018-02-01 13:45:54.000000000 +0000 @@ -24,6 +24,7 @@ #include #include "kscreen_export.h" +#include "types.h" namespace KScreen { @@ -34,12 +35,21 @@ Q_OBJECT public: + enum Option { + NoOptions, + NoEDID + }; + Q_DECLARE_FLAGS(Options, Option) + virtual ~ConfigOperation(); bool hasError() const; QString errorString() const; + virtual KScreen::ConfigPtr config() const = 0; + bool exec(); + Q_SIGNALS: void finished(ConfigOperation *operation); @@ -54,7 +64,7 @@ protected: ConfigOperationPrivate * const d_ptr; - Q_DECLARE_PRIVATE(ConfigOperation); + Q_DECLARE_PRIVATE(ConfigOperation) }; } diff -Nru libkscreen-5.4.2/src/configoperation_p.h libkscreen-5.12.0/src/configoperation_p.h --- libkscreen-5.4.2/src/configoperation_p.h 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/configoperation_p.h 2018-02-01 13:45:54.000000000 +0000 @@ -20,6 +20,7 @@ #include #include "configoperation.h" +#include "abstractbackend.h" #include "backendinterface.h" namespace KScreen @@ -33,9 +34,13 @@ ConfigOperationPrivate(ConfigOperation *qq); virtual ~ConfigOperationPrivate(); + // For out-of-process void requestBackend(); virtual void backendReady(org::kde::kscreen::Backend *backend); + // For in-process + KScreen::AbstractBackend* loadBackend(); + public Q_SLOTS: void doEmitResult(); diff -Nru libkscreen-5.4.2/src/configserializer.cpp libkscreen-5.12.0/src/configserializer.cpp --- libkscreen-5.4.2/src/configserializer.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/configserializer.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -53,6 +53,12 @@ { QJsonObject obj; + if (!config) { + return obj; + } + + obj[QLatin1String("features")] = static_cast(config->supportedFeatures()); + QJsonArray outputs; Q_FOREACH (const OutputPtr &output, config->outputs()) { outputs.append(serializeOutput(output)); @@ -74,6 +80,7 @@ obj[QLatin1String("type")] = static_cast(output->type()); obj[QLatin1String("icon")] = output->icon(); obj[QLatin1String("pos")] = serializePoint(output->pos()); + obj[QLatin1String("scale")] = output->scale(); obj[QLatin1String("size")] = serializeSize(output->size()); obj[QLatin1String("rotation")] = static_cast(output->rotation()); obj[QLatin1String("currentModeId")] = output->currentModeId(); @@ -170,6 +177,10 @@ { ConfigPtr config(new Config); + if (map.contains(QLatin1String("features"))) { + config->setSupportedFeatures(static_cast(map[QLatin1String("features")].toInt())); + } + if (map.contains(QLatin1String("outputs"))) { const QDBusArgument &outputsArg = map[QLatin1String("outputs")].value(); outputsArg.beginArray(); @@ -219,6 +230,8 @@ output->setIcon(value.toString()); } else if (key == QLatin1String("pos")) { output->setPos(deserializePoint(value.value())); + } else if (key == QLatin1String("scale")) { + output->setScale(value.toDouble()); } else if (key == QLatin1String("size")) { output->setSize(deserializeSize(value.value())); } else if (key == QLatin1String("rotation")) { diff -Nru libkscreen-5.4.2/src/debug_p.cpp libkscreen-5.12.0/src/debug_p.cpp --- libkscreen-5.4.2/src/debug_p.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/debug_p.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -22,11 +22,3 @@ Q_LOGGING_CATEGORY(KSCREEN, "kscreen") Q_LOGGING_CATEGORY(KSCREEN_EDID, "kscreen.edid") - -static void enableAllDebug() -{ - QLoggingCategory::setFilterRules(QStringLiteral("kscreen.debug = true")); - QLoggingCategory::setFilterRules(QStringLiteral("kscreen.edid.debug = true")); -} - -Q_COREAPP_STARTUP_FUNCTION(enableAllDebug) \ No newline at end of file diff -Nru libkscreen-5.4.2/src/doctor/CMakeLists.txt libkscreen-5.12.0/src/doctor/CMakeLists.txt --- libkscreen-5.4.2/src/doctor/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/src/doctor/CMakeLists.txt 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,4 @@ + +add_executable(kscreen-doctor main.cpp doctor.cpp dpmsclient.cpp) +target_link_libraries(kscreen-doctor Qt5::DBus KF5::Screen KF5::WaylandClient) +install(TARGETS kscreen-doctor ${INSTALL_TARGETS_DEFAULT_ARGS}) diff -Nru libkscreen-5.4.2/src/doctor/doctor.cpp libkscreen-5.12.0/src/doctor/doctor.cpp --- libkscreen-5.4.2/src/doctor/doctor.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/src/doctor/doctor.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,450 @@ +/************************************************************************************* + * Copyright 2014-2016 Sebastian Kügler * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#include "doctor.h" +#include "dpmsclient.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../backendmanager_p.h" +#include "../config.h" +#include "../configoperation.h" +#include "../getconfigoperation.h" +#include "../setconfigoperation.h" +#include "../edid.h" +#include "../log.h" +#include "../output.h" + +Q_LOGGING_CATEGORY(KSCREEN_DOCTOR, "kscreen.doctor") + + +static QTextStream cout(stdout); +static QTextStream cerr(stderr); + +const static QString green = QStringLiteral("\033[01;32m"); +const static QString red = QStringLiteral("\033[01;31m"); +const static QString yellow = QStringLiteral("\033[01;33m"); +const static QString blue = QStringLiteral("\033[01;34m"); +const static QString bold = QStringLiteral("\033[01;39m"); +const static QString cr = QStringLiteral("\033[0;0m"); + +namespace KScreen +{ +namespace ConfigSerializer +{ +// Exported private symbol in configserializer_p.h in KScreen +extern QJsonObject serializeConfig(const KScreen::ConfigPtr &config); +} +} + +using namespace KScreen; + +Doctor::Doctor(QObject *parent) + : QObject(parent) + , m_config(nullptr) + , m_changed(false) + , m_dpmsClient(nullptr) +{ +} + +Doctor::~Doctor() +{ +} + +void Doctor::start(QCommandLineParser *parser) +{ + m_parser = parser; + if (m_parser->isSet("info")) { + showBackends(); + } + if (parser->isSet("json") || parser->isSet("outputs") || !m_positionalArgs.isEmpty()) { + + KScreen::GetConfigOperation *op = new KScreen::GetConfigOperation(); + connect(op, &KScreen::GetConfigOperation::finished, this, + [this](KScreen::ConfigOperation *op) { + configReceived(op); + }); + return; + } + if (m_parser->isSet("dpms")) { + if (!QGuiApplication::platformName().startsWith(QLatin1String("wayland"))) { + cerr << "DPMS is only supported on Wayland." << endl; + // We need to kick the event loop, otherwise .quit() hangs + QTimer::singleShot(0, qApp->quit); + return; + + } + m_dpmsClient = new DpmsClient(this); + connect(m_dpmsClient, &DpmsClient::finished, qApp, &QCoreApplication::quit); + + const QString dpmsArg = m_parser->value(QStringLiteral("dpms")); + if (dpmsArg == QStringLiteral("show")) { + showDpms(); + } else { + setDpms(dpmsArg); + } + return; + } + + if (m_parser->isSet("log")) { + + const QString logmsg = m_parser->value(QStringLiteral("log")); + if (!Log::instance()->enabled()) { + qCWarning(KSCREEN_DOCTOR) << "Logging is disabled, unset KSCREEN_LOGGING in your environment."; + } else { + Log::log(logmsg); + } + } + // We need to kick the event loop, otherwise .quit() hangs + QTimer::singleShot(0, qApp->quit); +} + +void KScreen::Doctor::setDpms(const QString& dpmsArg) +{ + qDebug() << "SetDpms: " << dpmsArg; + connect(m_dpmsClient, &DpmsClient::ready, this, [this, dpmsArg]() { + cout << "DPMS.ready()"; + if (dpmsArg == QStringLiteral("off")) { + m_dpmsClient->off(); + } else if (dpmsArg == QStringLiteral("on")) { + m_dpmsClient->on(); + } else { + cout << "--dpms argument not understood (" << dpmsArg << ")"; + } + }); + + m_dpmsClient->connect(); +} + + +void Doctor::showDpms() +{ + m_dpmsClient = new DpmsClient(this); + + connect(m_dpmsClient, &DpmsClient::ready, this, []() { + cout << "DPMS.ready()"; + }); + + m_dpmsClient->connect(); +} + +void Doctor::showBackends() const +{ + cout << "Environment: " << endl; + auto env_kscreen_backend = (qgetenv("KSCREEN_BACKEND").isEmpty()) ? QStringLiteral("[not set]") : qgetenv("KSCREEN_BACKEND"); + cout << " * KSCREEN_BACKEND : " << env_kscreen_backend << endl; + auto env_kscreen_backend_inprocess = (qgetenv("KSCREEN_BACKEND_INPROCESS").isEmpty()) ? QStringLiteral("[not set]") : qgetenv("KSCREEN_BACKEND_INPROCESS"); + cout << " * KSCREEN_BACKEND_INPROCESS : " << env_kscreen_backend_inprocess << endl; + auto env_kscreen_logging = (qgetenv("KSCREEN_LOGGING").isEmpty()) ? QStringLiteral("[not set]") : qgetenv("KSCREEN_LOGGING"); + cout << " * KSCREEN_LOGGING : " << env_kscreen_logging << endl; + + cout << "Logging to : " << (Log::instance()->enabled() ? Log::instance()->logFile() : "[logging disabled]") << endl; + auto backends = BackendManager::instance()->listBackends(); + auto preferred = BackendManager::instance()->preferredBackend(); + cout << "Preferred KScreen backend : " << green << preferred.fileName() << cr << endl; + cout << "Available KScreen backends:" << endl; + Q_FOREACH(const QFileInfo f, backends) { + auto c = blue; + if (preferred == f) { + c = green; + } + cout << " * " << c << f.fileName() << cr << ": " << f.absoluteFilePath() << endl; + } + cout << endl; +} + +void Doctor::setOptionList(const QStringList &positionalArgs) +{ + m_positionalArgs = positionalArgs; +} + +void Doctor::parsePositionalArgs() +{ + //qCDebug(KSCREEN_DOCTOR) << "POSARGS" << m_positionalArgs; + Q_FOREACH(const QString &op, m_positionalArgs) { + auto ops = op.split('.'); + if (ops.count() > 2) { + bool ok; + int output_id = -1; + if (ops[0] == QStringLiteral("output")) { + Q_FOREACH (const auto &output, m_config->outputs()) { + if (output->name() == ops[1]) { + output_id = output->id(); + } + } + if (output_id == -1) { + output_id = ops[1].toInt(&ok); + if (!ok) { + cerr << "Unable to parse output id" << ops[1] << endl; + qApp->exit(3); + return; + } + } + if (ops.count() == 3 && ops[2] == QStringLiteral("enable")) { + if (!setEnabled(output_id, true)) { + qApp->exit(1); + return; + }; + } else if (ops.count() == 3 && ops[2] == QStringLiteral("disable")) { + if (!setEnabled(output_id, false)) { + qApp->exit(1); + return; + }; + } else if (ops.count() == 4 && ops[2] == QStringLiteral("mode")) { + QString mode_id = ops[3]; + // set mode + if (!setMode(output_id, mode_id)) { + qApp->exit(9); + return; + } + qCDebug(KSCREEN_DOCTOR) << "Output" << output_id << "set mode" << mode_id; + + } else if (ops.count() == 4 && ops[2] == QStringLiteral("position")) { + QStringList _pos = ops[3].split(','); + if (_pos.count() != 2) { + qCWarning(KSCREEN_DOCTOR) << "Invalid position:" << ops[3]; + qApp->exit(5); + return; + } + int x = _pos[0].toInt(&ok); + int y = _pos[1].toInt(&ok); + if (!ok) { + cerr << "Unable to parse position" << ops[3] << endl; + qApp->exit(5); + return; + } + + QPoint p(x, y); + qCDebug(KSCREEN_DOCTOR) << "Output position" << p; + if (!setPosition(output_id, p)) { + qApp->exit(1); + return; + } + } else if ((ops.count() == 4 || ops.count() == 5) && ops[2] == QStringLiteral("scale")) { + // be lenient about . vs. comma as separator + qreal scale = ops[3].replace(QStringLiteral(","), QStringLiteral(".")).toDouble(&ok); + if (ops.count() == 5) { + const auto dbl = ops[3] + QStringLiteral(".") + ops[4]; + scale = dbl.toDouble(&ok); + }; + // set scale + if (!ok || scale == 0 || !setScale(output_id, scale)) { + qCDebug(KSCREEN_DOCTOR) << "Could not set scale " << scale << " to output " << output_id; + qApp->exit(9); + return; + } + } else { + cerr << "Unable to parse arguments" << op << endl; + qApp->exit(2); + return; + } + } + } + } +} + +void Doctor::configReceived(KScreen::ConfigOperation *op) +{ + m_config = op->config(); + + if (m_parser->isSet("json")) { + showJson(); + qApp->quit(); + } + if (m_parser->isSet("outputs")) { + showOutputs(); + qApp->quit(); + } + + parsePositionalArgs(); + + if (m_changed) { + applyConfig(); + m_changed = false; + } +} + +int Doctor::outputCount() const +{ + if (!m_config) { + qCWarning(KSCREEN_DOCTOR) << "Invalid config."; + return 0; + } + return m_config->outputs().count(); +} + +void Doctor::showOutputs() const +{ + if (!m_config) { + qCWarning(KSCREEN_DOCTOR) << "Invalid config."; + return; + } + + QHash typeString; + typeString[KScreen::Output::Unknown] = QStringLiteral("Unknown"); + typeString[KScreen::Output::VGA] = QStringLiteral("VGA"); + typeString[KScreen::Output::DVI] = QStringLiteral("DVI"); + typeString[KScreen::Output::DVII] = QStringLiteral("DVII"); + typeString[KScreen::Output::DVIA] = QStringLiteral("DVIA"); + typeString[KScreen::Output::DVID] = QStringLiteral("DVID"); + typeString[KScreen::Output::HDMI] = QStringLiteral("HDMI"); + typeString[KScreen::Output::Panel] = QStringLiteral("Panel"); + typeString[KScreen::Output::TV] = QStringLiteral("TV"); + typeString[KScreen::Output::TVComposite] = QStringLiteral("TVComposite"); + typeString[KScreen::Output::TVSVideo] = QStringLiteral("TVSVideo"); + typeString[KScreen::Output::TVComponent] = QStringLiteral("TVComponent"); + typeString[KScreen::Output::TVSCART] = QStringLiteral("TVSCART"); + typeString[KScreen::Output::TVC4] = QStringLiteral("TVC4"); + typeString[KScreen::Output::DisplayPort] = QStringLiteral("DisplayPort"); + + Q_FOREACH (const auto &output, m_config->outputs()) { + cout << green << "Output: " << cr << output->id() << " " << output->name(); + cout << " " << (output->isEnabled() ? green + "enabled" : red + "disabled"); + cout << " " << (output->isConnected() ? green + "connected" : red + "disconnected"); + cout << " " << (output->isPrimary() ? green + "primary" : QString()); + auto _type = typeString[output->type()]; + cout << " " << yellow << (_type.isEmpty() ? "UnmappedOutputType" : _type); + cout << blue << " Modes: " << cr; + Q_FOREACH (auto mode, output->modes()) { + auto name = QString("%1x%2@%3").arg(QString::number(mode->size().width()), + QString::number(mode->size().height()), + QString::number(qRound(mode->refreshRate()))); + if (mode == output->currentMode()) { + name = green + name + "*" + cr; + } + if (mode == output->preferredMode()) { + name = name + "!"; + } + cout << mode->id() << ":" << name << " "; + } + const auto g = output->geometry(); + cout << yellow << "Geometry: " << cr << g.x() << "," << g.y() << " " << g.width() << "x" << g.height(); + cout << endl; + } +} + +void Doctor::showJson() const +{ + QJsonDocument doc(KScreen::ConfigSerializer::serializeConfig(m_config)); + cout << doc.toJson(QJsonDocument::Indented); +} + +bool Doctor::setEnabled(int id, bool enabled = true) +{ + if (!m_config) { + qCWarning(KSCREEN_DOCTOR) << "Invalid config."; + return false; + } + + Q_FOREACH (const auto &output, m_config->outputs()) { + if (output->id() == id) { + cout << (enabled ? "Enabling " : "Disabling ") << "output " << id << endl; + output->setEnabled(enabled); + m_changed = true; + return true; + } + } + cerr << "Output with id " << id << " not found." << endl; + qApp->exit(8); + return false; +} + +bool Doctor::setPosition(int id, const QPoint &pos) +{ + if (!m_config) { + qCWarning(KSCREEN_DOCTOR) << "Invalid config."; + return false; + } + + Q_FOREACH (const auto &output, m_config->outputs()) { + if (output->id() == id) { + qCDebug(KSCREEN_DOCTOR) << "Set output position" << pos; + output->setPos(pos); + m_changed = true; + return true; + } + } + cout << "Output with id " << id << " not found." << endl; + return false; +} + +bool Doctor::setMode(int id, const QString &mode_id) +{ + if (!m_config) { + qCWarning(KSCREEN_DOCTOR) << "Invalid config."; + return false; + } + + Q_FOREACH (const auto &output, m_config->outputs()) { + if (output->id() == id) { + // find mode + Q_FOREACH (const KScreen::ModePtr mode, output->modes()) { + auto name = QString("%1x%2@%3").arg(QString::number(mode->size().width()), + QString::number(mode->size().height()), + QString::number(qRound(mode->refreshRate()))); + if (mode->id() == mode_id || name == mode_id) { + qCDebug(KSCREEN_DOCTOR) << "Taddaaa! Found mode" << mode->id() << name; + output->setCurrentModeId(mode->id()); + m_changed = true; + return true; + } + } + } + } + cout << "Output mode " << mode_id << " not found." << endl; + return false; +} + +bool Doctor::setScale(int id, qreal scale) +{ + if (!m_config) { + qCWarning(KSCREEN_DOCTOR) << "Invalid config."; + return false; + } + + Q_FOREACH (const auto &output, m_config->outputs()) { + if (output->id() == id) { + output->setScale(scale); + m_changed = true; + return true; + } + } + cout << "Output scale " << id << " invalid." << endl; + return false; +} + +void Doctor::applyConfig() +{ + if (!m_changed) { + return; + } + auto setop = new SetConfigOperation(m_config, this); + setop->exec(); + qCDebug(KSCREEN_DOCTOR) << "setop exec returned" << m_config; + qApp->exit(0); +} diff -Nru libkscreen-5.4.2/src/doctor/doctor.h libkscreen-5.12.0/src/doctor/doctor.h --- libkscreen-5.4.2/src/doctor/doctor.h 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/src/doctor/doctor.h 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,76 @@ +/************************************************************************************* + * Copyright 2015 Sebastian Kügler * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#ifndef KSCREEN_DOCTOR_H +#define KSCREEN_DOCTOR_H + +#include +#include +#include "../config.h" + +namespace KScreen +{ +class ConfigOperation; +class DpmsClient; +//static const QString s_socketName = QStringLiteral("libkscreen-test-wayland-backend-0"); + +class Doctor : public QObject +{ + Q_OBJECT + +public: + explicit Doctor(QObject *parent = nullptr); + virtual ~Doctor(); + + void setOptionList(const QStringList &positionalArgs); + void start(QCommandLineParser *m_parser); + void configReceived(KScreen::ConfigOperation *op); + + void showDpms(); + + void showBackends() const; + void showOutputs() const; + void showJson() const; + int outputCount() const; + void setDpms(const QString &dpmsArg); + + bool setEnabled(int id, bool enabled); + bool setPosition(int id, const QPoint &pos); + bool setMode(int id, const QString &mode_id); + bool setScale(int id, qreal scale); + +Q_SIGNALS: + void outputsChanged(); + void started(); + void configChanged(); + +private: + //static QString modeString(KWayland::Server::OutputDeviceInterface* outputdevice, int mid); + void applyConfig(); + void parsePositionalArgs(); + int parseInt(const QString &str, bool &ok) const; + KScreen::ConfigPtr m_config; + QCommandLineParser* m_parser; + bool m_changed; + QStringList m_positionalArgs; + DpmsClient *m_dpmsClient; +}; + +} // namespace + +#endif // KSCREEN_WAYLAND_SCREEN_H diff -Nru libkscreen-5.4.2/src/doctor/dpmsclient.cpp libkscreen-5.12.0/src/doctor/dpmsclient.cpp --- libkscreen-5.4.2/src/doctor/dpmsclient.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/src/doctor/dpmsclient.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,157 @@ +/************************************************************************************* + * Copyright 2016 Sebastian Kügler * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#include "dpmsclient.h" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +//static const QString s_socketName = QStringLiteral("libkscreen-test-wayland-backend-0"); +static const QString s_socketName = QStringLiteral("wayland-0"); + +Q_LOGGING_CATEGORY(KSCREEN_DPMS, "kscreen.dpms") + +using namespace KScreen; + +using namespace KWayland::Client; + +DpmsClient::DpmsClient(QObject *parent) + : QObject(parent) + , m_thread(nullptr) + , m_connection(nullptr) + , m_dpmsManager(nullptr) +{ + +} + +DpmsClient::~DpmsClient() +{ + m_thread->exit(); + m_thread->wait(); + delete m_thread; + delete m_connection; + +} + +void DpmsClient::connect() +{ + // setup connection + m_connection = new ConnectionThread; + m_connection->setSocketName(s_socketName); + QObject::connect(m_connection, &ConnectionThread::connected, this, &DpmsClient::connected); + QObject::connect(m_connection, &ConnectionThread::failed, this, [=]() { + qCDebug(KSCREEN_DPMS) << "Connection failed"; + }); + + m_thread = new QThread(this); + m_connection->moveToThread(m_thread); + m_thread->start(); + + m_connection->initConnection(); + + qDebug() << "init"; +} + +void DpmsClient::connected() +{ + qDebug() << "Connected!"; + m_registry.create(m_connection); + QObject::connect(&m_registry, &Registry::interfacesAnnounced, this, + [this] { + const bool hasDpms = m_registry.hasInterface(Registry::Interface::Dpms); + // QLabel *hasDpmsLabel = new QLabel(&window); + if (hasDpms) { + qDebug() << QStringLiteral("Compositor provides a DpmsManager"); + } else { + qDebug() << QStringLiteral("Compositor does not provid a DpmsManager"); + } + + if (hasDpms) { + const auto dpmsData = m_registry.interface(Registry::Interface::Dpms); + m_dpmsManager = m_registry.createDpmsManager(dpmsData.name, dpmsData.version); + } + + + emit this->ready(); + }); + m_registry.setup(); + + //QVERIFY(dpmsSpy.wait(100)); + +} + +void KScreen::DpmsClient::changeMode(KWayland::Client::Dpms::Mode mode) +{ + const auto outputs = m_registry.interfaces(Registry::Interface::Output); + for (auto outputInterface : outputs) { + + KWayland::Client::Output *output = m_registry.createOutput(outputInterface.name, outputInterface.version, &m_registry); + qDebug() << "OUTPUT!" << output->model() << output->manufacturer() << output->geometry(); + + Dpms *dpms = nullptr; + if (m_dpmsManager) { + dpms = m_dpmsManager->getDpms(output, output); + } + + if (dpms) { + QObject::connect(dpms, &Dpms::supportedChanged, this, + [dpms, mode, this] { + if (dpms->isSupported()) { + QObject::connect(dpms, &Dpms::modeChanged, this, + &DpmsClient::modeChanged, Qt::QueuedConnection); + qDebug() << "Switching " << (mode == Dpms::Mode::On ? "on" : "off"); + m_modeChanges++; + dpms->requestMode(mode); + } + + }, Qt::QueuedConnection + ); + } + + qDebug() << "dpms->isSupported()" << dpms->isSupported(); + } +} + +void DpmsClient::modeChanged() +{ + m_modeChanges = m_modeChanges - 1; + if (m_modeChanges <= 0) { + emit finished(); + m_modeChanges = 0; + } +} + +void DpmsClient::on() +{ + changeMode(Dpms::Mode::On); + //emit finished(); +} + +void KScreen::DpmsClient::off() +{ + changeMode(Dpms::Mode::Off); + //emit finished(); +} diff -Nru libkscreen-5.4.2/src/doctor/dpmsclient.h libkscreen-5.12.0/src/doctor/dpmsclient.h --- libkscreen-5.4.2/src/doctor/dpmsclient.h 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/src/doctor/dpmsclient.h 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,77 @@ +/************************************************************************************* + * Copyright 2016 Sebastian Kügler * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#ifndef KSCREEN_DPMSCLIENT_H +#define KSCREEN_DPMSCLIENT_H + +#include +#include +#include "../config.h" + +#include +#include + +class QThread; + +namespace KWayland +{ + namespace Client { + class ConnectionThread; + } +} + +namespace KScreen +{ +class ConfigOperation; + +class DpmsClient : public QObject +{ + Q_OBJECT + +public: + explicit DpmsClient(QObject *parent = nullptr); + virtual ~DpmsClient(); + + void connect(); + void off(); + void on(); + +Q_SIGNALS: + void ready(); + void finished(); + +private Q_SLOTS: + void connected(); + void modeChanged(); + +private: + void changeMode(KWayland::Client::Dpms::Mode mode); + QThread *m_thread; + KWayland::Client::ConnectionThread *m_connection = nullptr; + KWayland::Client::DpmsManager *m_dpmsManager = nullptr; + KWayland::Client::Registry m_registry; + bool m_setOff = true; + bool m_setOn = false; + + bool m_supportedOututCount = 0; + int m_modeChanges = 0; +}; + +} // namespace + +#endif // KSCREEN_DPSMCLIENT_H diff -Nru libkscreen-5.4.2/src/doctor/main.cpp libkscreen-5.12.0/src/doctor/main.cpp --- libkscreen-5.4.2/src/doctor/main.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/src/doctor/main.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,111 @@ +/************************************************************************************* + * Copyright 2014-2015 by Sebastian Kügler * + * * + * 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, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * + *************************************************************************************/ + +#include "doctor.h" + +#include +#include + +#include + +/** Usage example: + * kscreen-doctor --set output.0.disable output.1.mode.1 output.1.enable" + * + * Error codes: + * 2 : general parse error + * 3 : output id parse error + * 4 : mode id parse error + * 5 : position parse error + * + * 8 : invalid output id + * 9 : invalid mode id + * + */ + +int main(int argc, char **argv) +{ + const QString desc = "kscreen-doctor allows to change the screen setup from the command-line.\n" + "\n" + "Setting the output configuration is done in an atomic fashion, all settings\n" + "are applied in a single command.\n" + "kscreen-doctor can be used to enable and disable outputs, to position screens,\n" + "change resolution (mode setting), etc.. You should put all your options into \n" + "a single invocation of kscreen-doctor, so they can all be applied at once.\n" + "\n" + "Usage examples:\n\n" + " Show output information:\n" + " $ kscreen-doctor -o\n" + " Output: 1 eDP-1 enabled connected Panel Modes: Modes: 1:800x600@60 [...] Geometry: 0,0 1280x800\n" + " Output: 70 HDMI-2 enabled connected HDMI Modes: 1:800x600@60 [...] Geometry: 1280,0 1920x1080\n" + "\n Disable the hdmi output, enable the laptop panel and set it to a specific mode\n" + " $ kscreen-doctor output.HDMI-2.disable output.eDP-1.mode.1 output.eDP-1.enable\n" + "\n Position the hdmi monitor on the right of the laptop panel\n" + " $ kscreen-doctor output.HDMI-2.position.0,1280 output.eDP-1.position.0,0\n" + "\n Set resolution mode\n" + " $ kscreen-doctor output.HDMI-2.mode.1920x1080@60 \n"; +/* + "\nError codes:\n" + " 2 : general parse error\n" + " 3 : output id parse error\n" + " 4 : mode id parse error\n" + " 5 : position parse error\n" + + " 8 : invalid output id\n" + " 9 : invalid mode id\n"; +*/ + const QString syntax = "Specific output settings are separated by spaces, each setting is in the form of\n" + "output..[.]\n" + "For example:\n" + "$ kscreen-doctor output.HDMI-2.enable \\ \n" + " output.eDP-1.mode.4 \\ \n" + " output.eDP-1.position.1280,0\n" + "Multiple settings are passed in order to have kscreen-doctor apply these settings in one go.\n"; + + QGuiApplication app(argc, argv); + + KScreen::Doctor server; + + QCommandLineOption info = QCommandLineOption(QStringList() << QStringLiteral("i") << "info", + QStringLiteral("Show runtime information: backends, logging, etc.")); + QCommandLineOption outputs = QCommandLineOption(QStringList() << QStringLiteral("o") << "outputs", + QStringLiteral("Show outputs")); + QCommandLineOption json = QCommandLineOption(QStringList() << QStringLiteral("j") << "json", + QStringLiteral("Show configuration in JSON format")); + QCommandLineOption dpms = QCommandLineOption(QStringList() << QStringLiteral("d") << "dpms", + QStringLiteral("Display power management (wayland only)"), QStringLiteral("off")); + QCommandLineOption log = QCommandLineOption(QStringList() << QStringLiteral("l") << "log", + QStringLiteral("Write a comment to the log file"), QStringLiteral("comment")); + + QCommandLineParser parser; + parser.setApplicationDescription(desc); + parser.addPositionalArgument("config", syntax, QStringLiteral("[output.. output..setting [...]]")); + parser.addHelpOption(); + parser.addOption(info); + parser.addOption(json); + parser.addOption(outputs); + parser.addOption(dpms); + parser.addOption(log); + parser.process(app); + + if (!parser.positionalArguments().isEmpty()) { + server.setOptionList(parser.positionalArguments()); + } + + server.start(&parser); + return app.exec(); +} diff -Nru libkscreen-5.4.2/src/edid.h libkscreen-5.12.0/src/edid.h --- libkscreen-5.4.2/src/edid.h 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/edid.h 2018-02-01 13:45:54.000000000 +0000 @@ -50,7 +50,7 @@ public: explicit Edid(); - explicit Edid(const QByteArray &data, QObject *parent = 0); + explicit Edid(const QByteArray &data, QObject *parent = nullptr); virtual ~Edid(); Edid* clone() const; @@ -73,7 +73,7 @@ QQuaternion white() const; private: - Q_DISABLE_COPY(Edid); + Q_DISABLE_COPY(Edid) class Private; Private * const d; diff -Nru libkscreen-5.4.2/src/getconfigoperation.cpp libkscreen-5.12.0/src/getconfigoperation.cpp --- libkscreen-5.4.2/src/getconfigoperation.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/getconfigoperation.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -21,6 +21,7 @@ #include "configoperation_p.h" #include "config.h" #include "output.h" +#include "log.h" #include "backendmanager_p.h" #include "configserializer_p.h" #include "backendinterface.h" @@ -37,14 +38,19 @@ public: GetConfigOperationPrivate(GetConfigOperation::Options options, GetConfigOperation *qq); - virtual void backendReady(org::kde::kscreen::Backend* backend); + void backendReady(org::kde::kscreen::Backend* backend) Q_DECL_OVERRIDE; void onConfigReceived(QDBusPendingCallWatcher *watcher); void onEDIDReceived(QDBusPendingCallWatcher *watcher); public: GetConfigOperation::Options options; ConfigPtr config; + // For in-process + void loadEdid(KScreen::AbstractBackend* backend); + + // For out-of-process int pendingEDIDs; + QPointer mBackend; private: Q_DECLARE_PUBLIC(GetConfigOperation) @@ -58,8 +64,9 @@ { } -void GetConfigOperationPrivate::backendReady(org::kde::kscreen::Backend* backend) +void GetConfigOperationPrivate::backendReady(org::kde::kscreen::Backend *backend) { + Q_ASSERT(BackendManager::instance()->method() == BackendManager::OutOfProcess); ConfigOperationPrivate::backendReady(backend); Q_Q(GetConfigOperation); @@ -70,16 +77,15 @@ return; } - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(backend->getConfig(), this); - - const auto backendPointer = QPointer(backend); - watcher->setProperty("backend", QVariant::fromValue(backendPointer)); + mBackend = backend; + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(mBackend->getConfig(), this); connect(watcher, &QDBusPendingCallWatcher::finished, this, &GetConfigOperationPrivate::onConfigReceived); } void GetConfigOperationPrivate::onConfigReceived(QDBusPendingCallWatcher *watcher) { + Q_ASSERT(BackendManager::instance()->method() == BackendManager::OutOfProcess); Q_Q(GetConfigOperation); QDBusPendingReply reply = *watcher; @@ -103,8 +109,7 @@ } pendingEDIDs = 0; - auto backend = watcher->property("backend").value>(); - if (!backend) { + if (!mBackend) { q->setError(tr("Backend invalidated")); q->emitResult(); return; @@ -114,7 +119,7 @@ continue; } - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(backend->getEdid(output->id()), this); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(mBackend->getEdid(output->id()), this); watcher->setProperty("outputId", output->id()); connect(watcher, &QDBusPendingCallWatcher::finished, this, &GetConfigOperationPrivate::onEDIDReceived); @@ -124,6 +129,7 @@ void GetConfigOperationPrivate::onEDIDReceived(QDBusPendingCallWatcher* watcher) { + Q_ASSERT(BackendManager::instance()->method() == BackendManager::OutOfProcess); Q_Q(GetConfigOperation); QDBusPendingReply reply = *watcher; @@ -163,7 +169,32 @@ void GetConfigOperation::start() { Q_D(GetConfigOperation); - d->requestBackend(); + if (BackendManager::instance()->method() == BackendManager::InProcess) { + auto backend = d->loadBackend(); + d->config = backend->config()->clone(); + d->loadEdid(backend); + emitResult(); + } else { + d->requestBackend(); + } +} + +void GetConfigOperationPrivate::loadEdid(KScreen::AbstractBackend* backend) +{ + Q_ASSERT(BackendManager::instance()->method() == BackendManager::InProcess); + Q_Q(GetConfigOperation); + if (options & KScreen::ConfigOperation::NoEDID) { + return; + } + if (!config) { + return; + } + Q_FOREACH (auto output, config->outputs()) { + if (output->edid() == nullptr) { + const QByteArray edidData = backend->edid(output->id()); + output->setEdid(edidData); + } + } } diff -Nru libkscreen-5.4.2/src/getconfigoperation.h libkscreen-5.12.0/src/getconfigoperation.h --- libkscreen-5.4.2/src/getconfigoperation.h 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/getconfigoperation.h 2018-02-01 13:45:54.000000000 +0000 @@ -36,19 +36,14 @@ Q_OBJECT public: - enum Option { - NoOptions, - NoEDID - }; - Q_DECLARE_FLAGS(Options, Option) - explicit GetConfigOperation(Options options = NoOptions, QObject* parent = 0); - ~GetConfigOperation(); + explicit GetConfigOperation(Options options = NoOptions, QObject* parent = nullptr); + virtual ~GetConfigOperation(); - KScreen::ConfigPtr config() const; + virtual KScreen::ConfigPtr config() const Q_DECL_OVERRIDE; protected: - void start(); + void start() Q_DECL_OVERRIDE; private: Q_DECLARE_PRIVATE(GetConfigOperation) diff -Nru libkscreen-5.4.2/src/log.cpp libkscreen-5.12.0/src/log.cpp --- libkscreen-5.4.2/src/log.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/src/log.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,138 @@ +/************************************************************************************* + * Copyright 2016 by Sebastian Kügler * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#include "log.h" + +#include +#include +#include +#include +#include + +namespace KScreen { + +Log* Log::sInstance = nullptr; +QtMessageHandler sDefaultMessageHandler = nullptr; + +void kscreenLogOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) +{ + QByteArray localMsg = msg.toLocal8Bit(); + if (QString::fromLocal8Bit(context.category).startsWith(QLatin1String("kscreen"))) { + Log::log(localMsg.constData(), context.category); + } + sDefaultMessageHandler(type, context, msg); +} + +void log(const QString& msg) +{ + Log::log(msg); +} + +Log* Log::instance() +{ + if (!sInstance) { + sInstance = new Log(); + } + + return sInstance; +} + +using namespace KScreen; +class Log::Private +{ + public: + QString context; + bool enabled = false; + QString logFile; +}; + +Log::Log() : + d(new Private) +{ + const char* logging_env = "KSCREEN_LOGGING"; + + if (qEnvironmentVariableIsSet(logging_env)) { + const QString logging_env_value = qgetenv(logging_env).constData(); + if (logging_env_value != QStringLiteral("0") && logging_env_value.toLower() != QStringLiteral("false")) { + d->enabled = true; + } + } + if (!d->enabled) { + return; + } + d->logFile = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/kscreen/kscreen.log"; + + QLoggingCategory::setFilterRules("kscreen.*=true"); + QFileInfo fi(d->logFile); + if (!QDir().mkpath(fi.absolutePath())) { + qWarning() << "Failed to create logging dir" << fi.absolutePath(); + } + + if (!sDefaultMessageHandler) { + sDefaultMessageHandler = qInstallMessageHandler(kscreenLogOutput); + } +} + +Log::Log(Log::Private *dd) : + d(dd) +{ +} + +Log::~Log() +{ + delete d; + sInstance = nullptr; +} + +QString Log::context() const +{ + return d->context; +} + +void Log::setContext(const QString& context) +{ + d->context = context; +} + +bool Log::enabled() const +{ + return d->enabled; +} + +QString Log::logFile() const +{ + return d->logFile; +} + +void Log::log(const QString &msg, const QString &category) +{ + if (!instance()->enabled()) { + return; + } + auto _cat = category; + _cat.remove("kscreen."); + const QString timestamp = QDateTime::currentDateTime().toString("dd.MM.yyyy hh:mm:ss.zzz"); + QString logMessage = QString("\n%1 ; %2 ; %3 : %4").arg(timestamp, _cat, instance()->context(), msg); + QFile file(instance()->logFile()); + if (!file.open(QIODevice::Append | QIODevice::Text)) { + return; + } + file.write(logMessage.toUtf8()); +} + +} // ns diff -Nru libkscreen-5.4.2/src/log.h libkscreen-5.12.0/src/log.h --- libkscreen-5.4.2/src/log.h 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/src/log.h 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,117 @@ +/************************************************************************************* + * Copyright 2016 by Sebastian Kügler * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#ifndef KSCREEN_LOG_H +#define KSCREEN_LOG_H + +#include "kscreen_export.h" +#include "types.h" + +#include +#include + +namespace KScreen { + +void log(const QString& msg); + +/** KScreen-internal file logging. + * + * The purpose of this class is to allow better debugging of kscreen. QDebug falls short here, since + * we need to debug the concert of kscreen components from different processes. + * + * KScreen::Log manages access to kscreen's log file. + * + * The following environment variables are considered: + * - disable logging by setting + * KSCREEN_LOGGING=false + * - set the log file to a custom path, the default is in ~/.local/share/kscreen/kscreen.log + * + * Please do not translate messages written to the logs, it's developer information and should be + * english, independent from the user's locale preferences. + * + * @code + * + * Log::instance()->setContext("resume"); + * Log::log("Applying detected output configuration."); + * + * @endcode + * + * @since 5.8 + */ +class KSCREEN_EXPORT Log +{ + public: + virtual ~Log(); + + static Log* instance(); + + /** Log a message to a file + * + * Call this static method to add a new line to the log. + * + * @arg msg The log message to write. + */ + static void log(const QString &msg, const QString &category = QString()); + + /** Context for the logs. + * + * The context can be used to indicate what is going on overall, it is used to be able + * to group log entries into subsequential operations. For example the context can be + * "handling resume", which is then added to the log messages. + * + * @arg msg The log message to write to the file. + * + * @see ontext() + */ + QString context() const; + + /** Set the context for the logs. + * + * @see context() + */ + void setContext(const QString &context); + + /** Logging to file is enabled by environmental var, is it? + * + * @arg msg The log message to write to the file. + * @return Whether logging is enabled. + */ + bool enabled() const; + + /** Path to the log file + * + * This is usually ~/.local/share/kscreen/kscreen.log, but can be changed by setting + * KSCREEN_LOGFILE in the environment. + * + * @return The path to the log file. + */ + QString logFile() const; + + private: + explicit Log(); + class Private; + Private * const d; + + static Log* sInstance; + Log(Private *dd); +}; + +} //KSCreen namespace + + +#endif //KSCREEN_LOG_H diff -Nru libkscreen-5.4.2/src/mode.cpp libkscreen-5.12.0/src/mode.cpp --- libkscreen-5.4.2/src/mode.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/mode.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -42,7 +42,7 @@ }; Mode::Mode() - : QObject(0) + : QObject(nullptr) , d(new Private()) { @@ -129,11 +129,10 @@ Q_EMIT modeChanged(); } - QDebug operator<<(QDebug dbg, const KScreen::ModePtr &mode) { if (mode) { - dbg << "KScreen::Mode(Id:" << mode->id() << ", Size:" << mode->size() << ")"; + dbg << "KScreen::Mode(Id:" << mode->id() << ", Size:" << mode->size() << "@" << mode->refreshRate() << ")"; } else { dbg << "KScreen::Mode(NULL)"; } diff -Nru libkscreen-5.4.2/src/output.cpp libkscreen-5.12.0/src/output.cpp --- libkscreen-5.4.2/src/output.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/output.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -37,6 +37,7 @@ id(0), type(Unknown), rotation(None), + scale(1.0), connected(false), enabled(false), primary(false), @@ -56,6 +57,7 @@ pos(other.pos), size(other.size), rotation(other.rotation), + scale(other.scale), connected(other.connected), enabled(other.enabled), primary(other.primary) @@ -69,6 +71,7 @@ } QString biggestMode(const ModeList& modes) const; + bool compareModeList(const ModeList& before, const ModeList& after); int id; QString name; @@ -83,6 +86,7 @@ QPoint pos; QSize size; Rotation rotation; + qreal scale; bool connected; bool enabled; bool primary; @@ -90,6 +94,32 @@ mutable QPointer edid; }; +bool Output::Private::compareModeList(const ModeList& before, const ModeList &after) +{ + if (before.keys() != after.keys()) { + return false; + } + for (const QString &key : before.keys()) { + const auto mb = before.value(key); + const auto ma = after.value(key); + if (mb->id() != ma->id()) { + return false; + } + if (mb->size() != ma->size()) { + return false; + } + if (mb->refreshRate() != ma->refreshRate()) { + return false; + } + if (mb->name() != ma->name()) { + return false; + } + } + // They're the same + return true; +} + + QString Output::Private::biggestMode(const ModeList& modes) const { int area, total = 0; @@ -221,7 +251,12 @@ void Output::setModes(const ModeList &modes) { + bool changed = !d->compareModeList(d->modeList, modes); d->modeList = modes; + if (changed) { + emit modesChanged(); + emit outputChanged(); + } } QString Output::currentModeId() const @@ -286,7 +321,7 @@ biggest = candidateMode; } - Q_ASSERT_X(biggest, "preferredModeId", "biggest mode must exists"); + Q_ASSERT_X(biggest, "preferredModeId", "biggest mode must exist"); d->preferredMode = biggest->id(); return d->preferredMode; @@ -345,6 +380,20 @@ Q_EMIT rotationChanged(); } +qreal Output::scale() const +{ + return d->scale; +} + +void Output::setScale(qreal factor) +{ + if (d->scale == factor) { + return; + } + d->scale = factor; + emit scaleChanged(); +} + bool Output::isConnected() const { return d->connected; @@ -412,7 +461,6 @@ void Output::setEdid(const QByteArray& rawData) { Q_ASSERT(d->edid == 0); - d->edid = new Edid(rawData); } @@ -440,9 +488,13 @@ // We can't use QRect(d->pos, d->size), because d->size does not reflect the // actual rotation() set by caller, it's only updated when we get update from // KScreen, but not when user changes mode or rotation manually - return isHorizontal() - ? QRect(d->pos, currentMode()->size()) - : QRect(d->pos, currentMode()->size().transposed()); + + QSize size = currentMode()->size() / d->scale; + if (!isHorizontal()) { + size = size.transposed(); + } + + return QRect(d->pos, size); } void Output::apply(const OutputPtr& other) @@ -451,7 +503,7 @@ QList changes; // We block all signals, and emit them only after we have set up everything - // This is necessary in order to prevent clients from accessig inconsistent + // This is necessary in order to prevent clients from accessing inconsistent // outputs from intermediate change signals const bool keepBlocked = signalsBlocked(); blockSignals(true); @@ -475,6 +527,10 @@ changes << &Output::rotationChanged; setRotation(other->d->rotation); } + if (d->scale != other->d->scale) { + changes << &Output::scaleChanged; + setScale(other->d->scale); + } if (d->currentMode != other->d->currentMode) { changes << &Output::currentModeIdChanged; setCurrentModeId(other->d->currentMode); @@ -495,8 +551,10 @@ changes << &Output::clonesChanged; setClones(other->d->clones);; } + if (!d->compareModeList(d->modeList, other->d->modeList)) { + changes << &Output::outputChanged; + } - // Non-notifyable changes setPreferredModes(other->d->preferredModes); ModeList modes; Q_FOREACH (const ModePtr &otherMode, other->modes()) { @@ -504,6 +562,7 @@ } setModes(modes); + // Non-notifyable changes if (other->d->edid) { delete d->edid; d->edid = other->d->edid->clone(); @@ -518,11 +577,17 @@ } } - QDebug operator<<(QDebug dbg, const KScreen::OutputPtr &output) { if(output) { - dbg << "KScreen::Output(Id:" << output->id() <<", Name:" << output->name() << ")"; + dbg << "KScreen::Output(" << output->id() << " " + << output->name() + << (output->isConnected() ? "connected" : "disconnected") + << (output->isEnabled() ? "enabled" : "disabled") + << "pos:" << output->pos() << "res:" << output->size() + << "modeId:" << output->currentModeId() + << "scale:" << output->scale() + << ")"; } else { dbg << "KScreen::Output(NULL)"; } diff -Nru libkscreen-5.4.2/src/output.h libkscreen-5.12.0/src/output.h --- libkscreen-5.4.2/src/output.h 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/output.h 2018-02-01 13:45:54.000000000 +0000 @@ -46,7 +46,7 @@ Q_PROPERTY(QString name READ name WRITE setName NOTIFY outputChanged) Q_PROPERTY(Type type READ type WRITE setType NOTIFY outputChanged) Q_PROPERTY(QString icon READ icon WRITE setIcon NOTIFY outputChanged) - Q_PROPERTY(ModeList modes READ modes CONSTANT) + Q_PROPERTY(ModeList modes READ modes NOTIFY modesChanged) Q_PROPERTY(QPoint pos READ pos WRITE setPos NOTIFY posChanged) Q_PROPERTY(QSize size READ size WRITE setSize NOTIFY sizeChanged) Q_PROPERTY(Rotation rotation READ rotation WRITE setRotation NOTIFY rotationChanged) @@ -58,6 +58,8 @@ Q_PROPERTY(QList clones READ clones WRITE setClones NOTIFY clonesChanged) Q_PROPERTY(KScreen::Edid* edid READ edid CONSTANT) Q_PROPERTY(QSize sizeMm READ sizeMm CONSTANT) + Q_PROPERTY(qreal scale READ scale WRITE setScale NOTIFY scaleChanged) + enum Type { Unknown, @@ -192,6 +194,23 @@ */ QRect geometry() const; + /** + * returns the scaling factor to use for this output + * + * @since 5.9 + */ + qreal scale() const; + + /** + * Set the scaling factor for this output. + * + * @arg factor Scale factor to use for this output, the backend may or may not + * be able to deal with non-integer values, in that case, the factor gets rounded. + * + * @since 5.9 + */ + void setScale(qreal factor); + void apply(const OutputPtr &other); Q_SIGNALS: void outputChanged(); @@ -203,6 +222,15 @@ void isEnabledChanged(); void isPrimaryChanged(); void clonesChanged(); + void scaleChanged(); + + /** The mode list changed. + * + * This may happen when a mode is added or changed. + * + * @since 5.8.3 + */ + void modesChanged(); private: Q_DISABLE_COPY(Output) diff -Nru libkscreen-5.4.2/src/screen.h libkscreen-5.12.0/src/screen.h --- libkscreen-5.4.2/src/screen.h 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/screen.h 2018-02-01 13:45:54.000000000 +0000 @@ -43,16 +43,48 @@ ScreenPtr clone() const; + /** + * The id of this screen. + * @return id of this screen + */ int id() const; + /** + * The identifier of this screen. + * @param id id of the screen + */ void setId(int id); + /** + * The current screen size in pixels. + * @return Screen size in pixels + */ QSize currentSize() const; + /** + * Set the current screen size in pixels. + * @param currentSize Screen size in pixels + */ void setCurrentSize(const QSize& currentSize); + /** + * The minimum screen size in pixels. + * @return Minimum screen size in pixels + */ QSize minSize() const; + /** + * Set the minimum screen size in pixels. + * @param minSize Minimum screen size in pixels + */ void setMinSize(const QSize& minSize); + /** + * The maximum screen size in pixels. + * @return Maximum screen size in pixels + */ QSize maxSize() const; + /** + * Set the maximum screen size in pixels. + * @param maxSize Maximum screen size in pixels + */ void setMaxSize(const QSize& maxSize); int maxActiveOutputsCount() const; diff -Nru libkscreen-5.4.2/src/setconfigoperation.cpp libkscreen-5.12.0/src/setconfigoperation.cpp --- libkscreen-5.4.2/src/setconfigoperation.cpp 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/setconfigoperation.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -18,9 +18,14 @@ */ #include "setconfigoperation.h" + +#include "abstractbackend.h" +#include "backendmanager_p.h" #include "configoperation_p.h" #include "config.h" #include "configserializer_p.h" +#include "debug_p.h" +#include "output.h" #include #include @@ -37,8 +42,9 @@ public: explicit SetConfigOperationPrivate(const KScreen::ConfigPtr &config, ConfigOperation* qq); - void backendReady(org::kde::kscreen::Backend* backend); + void backendReady(org::kde::kscreen::Backend* backend) Q_DECL_OVERRIDE; void onConfigSet(QDBusPendingCallWatcher *watcher); + void normalizeOutputPositions(); KScreen::ConfigPtr config; @@ -99,7 +105,6 @@ q->emitResult(); } - SetConfigOperation::SetConfigOperation(const ConfigPtr &config, QObject* parent) : ConfigOperation(new SetConfigOperationPrivate(config, this), parent) { @@ -115,11 +120,46 @@ return d->config; } - void SetConfigOperation::start() { Q_D(SetConfigOperation); - d->requestBackend(); + d->normalizeOutputPositions(); + if (BackendManager::instance()->method() == BackendManager::InProcess) { + auto backend = d->loadBackend(); + backend->setConfig(d->config); + emitResult(); + } else { + d->requestBackend(); + } +} + +void SetConfigOperationPrivate::normalizeOutputPositions() +{ + if (!config) { + return; + } + int offsetX = INT_MAX; + int offsetY = INT_MAX; + Q_FOREACH (const KScreen::OutputPtr &output, config->outputs()) { + if (!output->isConnected() || !output->isEnabled()) { + continue; + } + offsetX = qMin(output->pos().x(), offsetX); + offsetY = qMin(output->pos().y(), offsetY); + } + + if (!offsetX && !offsetY) { + return; + } + qCDebug(KSCREEN) << "Correcting output positions by:" << QPoint(offsetX, offsetY); + Q_FOREACH (const KScreen::OutputPtr &output, config->outputs()) { + if (!output->isConnected() || !output->isEnabled()) { + continue; + } + QPoint newPos = QPoint(output->pos().x() - offsetX, output->pos().y() - offsetY); + qCDebug(KSCREEN) << "Moved output from" << output->pos() << "to" << newPos; + output->setPos(newPos); + } } #include "setconfigoperation.moc" diff -Nru libkscreen-5.4.2/src/setconfigoperation.h libkscreen-5.12.0/src/setconfigoperation.h --- libkscreen-5.4.2/src/setconfigoperation.h 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/src/setconfigoperation.h 2018-02-01 13:45:54.000000000 +0000 @@ -32,13 +32,13 @@ { Q_OBJECT public: - explicit SetConfigOperation(const KScreen::ConfigPtr &config, QObject* parent = 0); + explicit SetConfigOperation(const KScreen::ConfigPtr &config, QObject* parent = nullptr); ~SetConfigOperation(); - KScreen::ConfigPtr config() const; + KScreen::ConfigPtr config() const Q_DECL_OVERRIDE; protected: - void start(); + void start() Q_DECL_OVERRIDE; private: Q_DECLARE_PRIVATE(SetConfigOperation) diff -Nru libkscreen-5.4.2/tests/CMakeLists.txt libkscreen-5.12.0/tests/CMakeLists.txt --- libkscreen-5.4.2/tests/CMakeLists.txt 2015-10-01 09:47:37.000000000 +0000 +++ libkscreen-5.12.0/tests/CMakeLists.txt 2018-02-01 13:45:54.000000000 +0000 @@ -1,4 +1,4 @@ add_executable(printconfig testplugandplay.cpp testpnp.cpp) target_link_libraries(printconfig Qt5::Gui KF5::Screen) - +add_subdirectory(kwayland) diff -Nru libkscreen-5.4.2/tests/kwayland/CMakeLists.txt libkscreen-5.12.0/tests/kwayland/CMakeLists.txt --- libkscreen-5.4.2/tests/kwayland/CMakeLists.txt 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/tests/kwayland/CMakeLists.txt 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,6 @@ + +add_definitions(-DTEST_DATA="${CMAKE_SOURCE_DIR}/autotests/configs/") + +add_executable(waylandtestserver main.cpp waylandtestserver.cpp waylandconfigreader.cpp) +target_link_libraries(waylandtestserver KF5::Screen KF5::WaylandServer) + diff -Nru libkscreen-5.4.2/tests/kwayland/main.cpp libkscreen-5.12.0/tests/kwayland/main.cpp --- libkscreen-5.4.2/tests/kwayland/main.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/tests/kwayland/main.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,44 @@ +/************************************************************************************* + * Copyright 2014-2016 by Sebastian Kügler * + * * + * 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, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * + *************************************************************************************/ + +#include "waylandtestserver.h" + +#include +#include + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + + KScreen::WaylandTestServer server; + + QCommandLineOption config = QCommandLineOption(QStringList() << QStringLiteral("c") << "config", + QStringLiteral("Config file"), "config"); + QCommandLineParser parser; + parser.addHelpOption(); + parser.addOption(config); + parser.process(app); + + if (parser.isSet(config)) { + server.setConfig(parser.value(config)); + } else { + server.setConfig(QString::fromLocal8Bit(TEST_DATA)+"/multipleoutput.json"); + } + server.start(); + return app.exec(); +} diff -Nru libkscreen-5.4.2/tests/kwayland/waylandconfigreader.cpp libkscreen-5.12.0/tests/kwayland/waylandconfigreader.cpp --- libkscreen-5.4.2/tests/kwayland/waylandconfigreader.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/tests/kwayland/waylandconfigreader.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,253 @@ +/************************************************************************************* + * Copyright 2014-2015 Sebastian Kügler * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#include "waylandconfigreader.h" + +#include + +#include +#include +#include +#include +#include + +#include "edid.h" + +using namespace KScreen; + +static QList s_outputIds; + +void WaylandConfigReader::outputsFromConfig(const QString& configfile, KWayland::Server::Display* display, + QList< KWayland::Server::OutputDeviceInterface* >& outputs) +{ + qDebug() << "Loading server from" << configfile; + QFile file(configfile); + file.open(QIODevice::ReadOnly); + + QJsonDocument jsonDoc = QJsonDocument::fromJson(file.readAll()); + QJsonObject json = jsonDoc.object(); + + QJsonArray omap = json["outputs"].toArray(); + Q_FOREACH(const QJsonValue &value, omap) { + const QVariantMap &output = value.toObject().toVariantMap(); + if (output["connected"].toBool()) { + outputs << createOutputDevice(output, display); + //qDebug() << "new Output created: " << output["name"].toString(); + } else { + //qDebug() << "disconnected Output" << output["name"].toString(); + } + } + auto outpus = WaylandConfigReader::createOutputs(display, outputs); + s_outputIds.clear(); +} + +OutputDeviceInterface* WaylandConfigReader::createOutputDevice(const QVariantMap& outputConfig, KWayland::Server::Display *display) +{ + KWayland::Server::OutputDeviceInterface *outputdevice = display->createOutputDevice(display); + + QByteArray data = QByteArray::fromBase64(outputConfig["edid"].toByteArray()); + outputdevice->setEdid(data); + Edid edid(data, display); + +// qDebug() << "EDID Info: "; + if (edid.isValid()) { +// qDebug() << "\tDevice ID: " << edid.deviceId(); +// qDebug() << "\tName: " << edid.name(); +// qDebug() << "\tVendor: " << edid.vendor(); +// qDebug() << "\tSerial: " << edid.serial(); +// qDebug() << "\tEISA ID: " << edid.eisaId(); +// qDebug() << "\tHash: " << edid.hash(); +// qDebug() << "\tWidth (mm): " << edid.width(); +// qDebug() << "\tHeight (mm): " << edid.height(); +// qDebug() << "\tGamma: " << edid.gamma(); +// qDebug() << "\tRed: " << edid.red(); +// qDebug() << "\tGreen: " << edid.green(); +// qDebug() << "\tBlue: " << edid.blue(); +// qDebug() << "\tWhite: " << edid.white(); + outputdevice->setPhysicalSize(QSize(edid.width() * 10, edid.height() * 10)); + outputdevice->setManufacturer(edid.vendor()); + outputdevice->setModel(edid.name()); + } else { + outputdevice->setPhysicalSize(sizeFromJson(outputConfig["sizeMM"])); + outputdevice->setManufacturer(outputConfig["manufacturer"].toString()); + outputdevice->setModel(outputConfig["model"].toString()); + } + auto uuid = QUuid::createUuid().toByteArray(); + auto _id = outputConfig["id"].toInt(); + if (_id) { + uuid = QString::number(_id).toLocal8Bit(); + } + outputdevice->setUuid(uuid); + + const QMap transformMap = { + {0, KWayland::Server::OutputDeviceInterface::Transform::Normal}, + {1, KWayland::Server::OutputDeviceInterface::Transform::Normal}, + {2, KWayland::Server::OutputDeviceInterface::Transform::Rotated270}, + {3, KWayland::Server::OutputDeviceInterface::Transform::Rotated180}, + {4, KWayland::Server::OutputDeviceInterface::Transform::Rotated90} + }; + + outputdevice->setTransform(transformMap[outputConfig["rotation"].toInt()]); + int currentModeId = outputConfig["currentModeId"].toInt(); + QVariantList preferredModes = outputConfig["preferredModes"].toList(); + + int mode_id = 0; + Q_FOREACH (const QVariant &_mode, outputConfig["modes"].toList()) { + mode_id++; + const QVariantMap &mode = _mode.toMap(); + OutputDeviceInterface::Mode m0; + const QSize _size = sizeFromJson(mode["size"]); + + if (mode.keys().contains("refreshRate")) { + m0.refreshRate = qRound(mode["refreshRate"].toReal() * 1000); // config has it in Hz + } + bool isCurrent = currentModeId == mode["id"].toInt(); + bool isPreferred = preferredModes.contains(mode["id"]); + + OutputDeviceInterface::ModeFlags flags; + if (isCurrent && isPreferred) { + flags = OutputDeviceInterface::ModeFlags(OutputDeviceInterface::ModeFlag::Current | OutputDeviceInterface::ModeFlag::Preferred); + } else if (isCurrent) { + flags = OutputDeviceInterface::ModeFlags(OutputDeviceInterface::ModeFlag::Current); + } else if (isPreferred) { + flags = OutputDeviceInterface::ModeFlags(OutputDeviceInterface::ModeFlag::Preferred); + } + + if (mode.keys().contains("id")) { + m0.id = mode["id"].toInt(); + } else { + m0.id = mode_id; + } + m0.size = _size; + m0.flags = flags; + outputdevice->addMode(m0); + + if (isCurrent) { + outputdevice->setCurrentMode(m0.id); + } + } + + outputdevice->setGlobalPosition(pointFromJson(outputConfig["pos"])); + outputdevice->setEnabled(outputConfig["enabled"].toBool() ? OutputDeviceInterface::Enablement::Enabled : OutputDeviceInterface::Enablement::Disabled); + outputdevice->create(); + + return outputdevice; +} + +QList KScreen::WaylandConfigReader::createOutputs(KWayland::Server::Display* display, QList& outputdevices) +{ + const QMap transformMap = { + {KWayland::Server::OutputDeviceInterface::Transform::Normal, + KWayland::Server::OutputInterface::Transform::Normal}, + {KWayland::Server::OutputDeviceInterface::Transform::Rotated270, + KWayland::Server::OutputInterface::Transform::Rotated270}, + {KWayland::Server::OutputDeviceInterface::Transform::Rotated180, + KWayland::Server::OutputInterface::Transform::Rotated180}, + {KWayland::Server::OutputDeviceInterface::Transform::Rotated90, + KWayland::Server::OutputInterface::Transform::Rotated90}, + }; + + + + QList outputs; + Q_FOREACH (const auto outputdevice, outputdevices) { + qDebug() << "New Output!"; + KWayland::Server::OutputInterface *output = display->createOutput(display); + + // Sync properties from outputdevice to the newly created output interface + output->setManufacturer(outputdevice->manufacturer()); + output->setModel(outputdevice->model()); + //output->setUuid(outputdevice->uuid()); + + + Q_FOREACH (const auto mode, outputdevice->modes()) { + + bool isCurrent = mode.flags.testFlag(OutputDeviceInterface::ModeFlag::Current); + bool isPreferred = mode.flags.testFlag(OutputDeviceInterface::ModeFlag::Current); + OutputInterface::ModeFlags flags; + if (isPreferred && isCurrent) { + flags = OutputInterface::ModeFlags(OutputInterface::ModeFlag::Current | OutputInterface::ModeFlag::Preferred); + } else if (isCurrent) { + flags = OutputInterface::ModeFlags(OutputInterface::ModeFlag::Current); + } else if (isPreferred) { + flags = OutputInterface::ModeFlags(OutputInterface::ModeFlag::Preferred); + } + + OutputInterface::Mode m0; + + m0.size = mode.size; + output->addMode(m0.size, m0.flags, m0.refreshRate); + + if (isCurrent) { + output->setCurrentMode(m0.size, m0.refreshRate); + } + //qDebug() << "mode added:" << m0.size << m0.refreshRate << isCurrent; + } + + output->setGlobalPosition(outputdevice->globalPosition()); + output->setPhysicalSize(outputdevice->physicalSize()); + output->setTransform(transformMap.value(outputdevice->transform())); + + output->setDpmsSupported(true); + output->setDpmsMode(OutputInterface::DpmsMode::On); + QObject::connect(output, &OutputInterface::dpmsModeRequested, + [] (KWayland::Server::OutputInterface::DpmsMode requestedMode) { + Q_UNUSED(requestedMode); + // FIXME: make sure this happens in the scope of an object! + qDebug() << "DPMS Mode change requested"; + + }); + output->create(); + outputs << output; + } + return outputs; +} + + +QSize WaylandConfigReader::sizeFromJson(const QVariant& data) +{ + QVariantMap map = data.toMap(); + + QSize size; + size.setWidth(map["width"].toInt()); + size.setHeight(map["height"].toInt()); + + return size; +} + +QPoint WaylandConfigReader::pointFromJson(const QVariant& data) +{ + QVariantMap map = data.toMap(); + + QPoint point; + point.setX(map["x"].toInt()); + point.setY(map["y"].toInt()); + + return point; +} + +QRect WaylandConfigReader::rectFromJson(const QVariant& data) +{ + QRect rect; + rect.setSize(WaylandConfigReader::sizeFromJson(data)); + rect.setBottomLeft(WaylandConfigReader::pointFromJson(data)); + + return rect; +} + diff -Nru libkscreen-5.4.2/tests/kwayland/waylandconfigreader.h libkscreen-5.12.0/tests/kwayland/waylandconfigreader.h --- libkscreen-5.4.2/tests/kwayland/waylandconfigreader.h 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/tests/kwayland/waylandconfigreader.h 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,51 @@ +/************************************************************************************* + * Copyright 2014-2015 Sebastian Kügler * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#ifndef KSCREEN_WAYLAND_CONFIGREADER_H +#define KSCREEN_WAYLAND_CONFIGREADER_H + +#include +#include + +// KWayland +#include +#include +#include + +namespace KScreen +{ + +using namespace KWayland::Server; + +class WaylandConfigReader +{ + +public: + //static QList outputsFromConfig(const QString &configfile, KWayland::Server::Display *display); + static void outputsFromConfig(const QString &configfile, KWayland::Server::Display *display, QList& outputs); + static OutputDeviceInterface* createOutputDevice(const QVariantMap &outputConfig, KWayland::Server::Display *display); + static QList createOutputs(KWayland::Server::Display *display, QList& outputdevices); + + static QSize sizeFromJson(const QVariant &data); + static QRect rectFromJson(const QVariant &data); + static QPoint pointFromJson(const QVariant &data); +}; + +} // namespace + +#endif // KSCREEN_WAYLAND_CONFIGREADER_H diff -Nru libkscreen-5.4.2/tests/kwayland/waylandtestserver.cpp libkscreen-5.12.0/tests/kwayland/waylandtestserver.cpp --- libkscreen-5.4.2/tests/kwayland/waylandtestserver.cpp 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/tests/kwayland/waylandtestserver.cpp 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,179 @@ +/************************************************************************************* + * Copyright 2014-2015 Sebastian Kügler * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#include "waylandtestserver.h" + +#include "waylandconfigreader.h" +#include + +#include +#include +#include +#include +#include +#include + +#include "../src/edid.h" + +Q_LOGGING_CATEGORY(KSCREEN_WAYLAND_TESTSERVER, "kscreen.kwayland.testserver") + +using namespace KScreen; +using namespace KWayland::Server; + +WaylandTestServer::WaylandTestServer(QObject *parent) + : QObject(parent) + , m_configFile(TEST_DATA + QStringLiteral("default.json")) + , m_display(nullptr) + , m_outputManagement(nullptr) + , m_dpmsManager(nullptr) +{ +} + +WaylandTestServer::~WaylandTestServer() +{ + stop(); + qCDebug(KSCREEN_WAYLAND_TESTSERVER) << "Wayland server shut down."; +} + +void WaylandTestServer::start() +{ + using namespace KWayland::Server; + delete m_display; + m_display = new KWayland::Server::Display(this); + if (qgetenv("WAYLAND_DISPLAY").isEmpty()) { + m_display->setSocketName(s_socketName); + } else { + m_display->setSocketName(qgetenv("WAYLAND_DISPLAY").constData()); + } + m_display->start(); + + auto manager = m_display->createDpmsManager(); + manager->create(); + + m_outputManagement = m_display->createOutputManagement(); + m_outputManagement->create(); + connect(m_outputManagement, &OutputManagementInterface::configurationChangeRequested, this, &WaylandTestServer::configurationChangeRequested); + + KScreen::WaylandConfigReader::outputsFromConfig(m_configFile, m_display, m_outputs); + qCDebug(KSCREEN_WAYLAND_TESTSERVER) << QString("export WAYLAND_DISPLAY="+m_display->socketName()); + qCDebug(KSCREEN_WAYLAND_TESTSERVER) << QString("You can specify the WAYLAND_DISPLAY for this server by exporting it in the environment"); + //showOutputs(); +} + +void WaylandTestServer::stop() +{ + Q_FOREACH (const auto &o, m_outputs) { + delete o; + } + m_outputs.clear(); + // actually stop the Wayland server + delete m_display; + m_display = nullptr; +} + +KWayland::Server::Display* WaylandTestServer::display() +{ + return m_display; +} + +void WaylandTestServer::setConfig(const QString& configfile) +{ + qCDebug(KSCREEN_WAYLAND_TESTSERVER) << "Creating Wayland server from " << configfile; + m_configFile = configfile; +} + +int WaylandTestServer::outputCount() const +{ + return m_outputs.count(); +} +QList WaylandTestServer::outputs() const +{ + return m_outputs; +} + +void WaylandTestServer::configurationChangeRequested(KWayland::Server::OutputConfigurationInterface* configurationInterface) +{ + qCDebug(KSCREEN_WAYLAND_TESTSERVER) << "Server received change request, changes:" << configurationInterface->changes().count(); + + auto changes = configurationInterface->changes(); + Q_FOREACH (const auto &outputdevice, changes.keys()) { + auto c = changes[outputdevice]; + if (c->enabledChanged()) { + qCDebug(KSCREEN_WAYLAND_TESTSERVER) << "Setting enabled:"; + outputdevice->setEnabled(c->enabled()); + } + if (c->modeChanged()) { + qCDebug(KSCREEN_WAYLAND_TESTSERVER) << "Setting new mode:" << c->mode() << modeString(outputdevice, c->mode()); + outputdevice->setCurrentMode(c->mode()); + } + if (c->transformChanged()) { + qCDebug(KSCREEN_WAYLAND_TESTSERVER) << "Server setting transform: " << (int)(c->transform()); + outputdevice->setTransform(c->transform()); + } + if (c->positionChanged()) { + qCDebug(KSCREEN_WAYLAND_TESTSERVER) << "Server setting position: " << c->position(); + outputdevice->setGlobalPosition(c->position()); + } + if (c->scaleChanged()) { + qCDebug(KSCREEN_WAYLAND_TESTSERVER) << "Setting scale:" << c->scale(); + outputdevice->setScale(c->scale()); + } + } + + configurationInterface->setApplied(); + //showOutputs(); + Q_EMIT configChanged(); +} + +void WaylandTestServer::showOutputs() +{ + qCDebug(KSCREEN_WAYLAND_TESTSERVER) << "******** Wayland server running: " << m_outputs.count() << " outputs. ********"; + foreach (auto o, m_outputs) { + bool enabled = (o->enabled() == KWayland::Server::OutputDeviceInterface::Enablement::Enabled); + qCDebug(KSCREEN_WAYLAND_TESTSERVER) << " * Output id: " << o->uuid(); + qCDebug(KSCREEN_WAYLAND_TESTSERVER) << " Enabled: " << (enabled ? "enabled" : "disabled"); + qCDebug(KSCREEN_WAYLAND_TESTSERVER) << " Name: " << QString("%2-%3").arg(o->manufacturer(), o->model()); + qCDebug(KSCREEN_WAYLAND_TESTSERVER) << " Mode: " << modeString(o, o->currentModeId()); + qCDebug(KSCREEN_WAYLAND_TESTSERVER) << " Pos: " << o->globalPosition(); + qCDebug(KSCREEN_WAYLAND_TESTSERVER) << " Edid: " << o->edid(); + // << o->currentMode().size(); + + } + qCDebug(KSCREEN_WAYLAND_TESTSERVER) << "******************************************************"; +} + +QString WaylandTestServer::modeString(KWayland::Server::OutputDeviceInterface* outputdevice, int mid) +{ + QString s; + QString ids; + int _i = 0; + Q_FOREACH (const auto &_m, outputdevice->modes()) { + _i++; + if (_i < 6) { + ids.append(QString::number(_m.id) + ", "); + } else { + ids.append("."); + } + if (_m.id == mid) { + s = QString("%1x%2 @%3").arg(QString::number(_m.size.width()), \ + QString::number(_m.size.height()), QString::number(_m.refreshRate)); + } + } + return QString("[%1] %2 (%4 modes: %3)").arg(QString::number(mid), s, ids, QString::number(outputdevice->modes().count())); + +} diff -Nru libkscreen-5.4.2/tests/kwayland/waylandtestserver.h libkscreen-5.12.0/tests/kwayland/waylandtestserver.h --- libkscreen-5.4.2/tests/kwayland/waylandtestserver.h 1970-01-01 00:00:00.000000000 +0000 +++ libkscreen-5.12.0/tests/kwayland/waylandtestserver.h 2018-02-01 13:45:54.000000000 +0000 @@ -0,0 +1,83 @@ +/************************************************************************************* + * Copyright 2014-2015 Sebastian Kügler * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * This library 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 * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with this library; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + *************************************************************************************/ + +#ifndef KSCREEN_WAYLAND_TESTSERVER_H +#define KSCREEN_WAYLAND_TESTSERVER_H + +#include + +// KWayland +#include +#include +#include +#include +#include +#include +#include +#include + +namespace KScreen +{ +class WaylandConfig; +class WaylandOutput; + +static const QString s_socketName = QStringLiteral("libkscreen-test-wayland-backend-0"); + +using namespace KWayland::Server; + +class WaylandTestServer : public QObject +{ + Q_OBJECT + +public: + explicit WaylandTestServer(QObject *parent = 0); + virtual ~WaylandTestServer(); + + void setConfig(const QString &configfile); + void start(); + void stop(); + void pickupConfigFile(const QString &configfile); + + void showOutputs(); + KWayland::Server::Display* display(); + QList outputs() const; + + int outputCount() const; + +Q_SIGNALS: + void outputsChanged(); + + void started(); + + void configChanged(); + +private Q_SLOTS: + void configurationChangeRequested(KWayland::Server::OutputConfigurationInterface *configurationInterface); + +private: + static QString modeString(KWayland::Server::OutputDeviceInterface* outputdevice, int mid); + QString m_configFile; + KWayland::Server::Display *m_display; + QList m_outputs; + KWayland::Server::OutputManagementInterface *m_outputManagement; + KWayland::Server::DpmsManagerInterface *m_dpmsManager; +}; + +} // namespace + +#endif // KSCREEN_WAYLAND_SCREEN_H