diff --git a/ksplash/ksplashqml/CMakeLists.txt b/ksplash/ksplashqml/CMakeLists.txt index f7e431d3..105cd022 100644 --- a/ksplash/ksplashqml/CMakeLists.txt +++ b/ksplash/ksplashqml/CMakeLists.txt @@ -1,21 +1,23 @@ add_subdirectory(themes) set(ksplashqml_SRCS main.cpp splashapp.cpp splashwindow.cpp ) add_executable(ksplashqml ${ksplashqml_SRCS}) target_link_libraries(ksplashqml Qt5::Quick Qt5::DBus KF5::ConfigCore KF5::Package KF5::QuickAddons + KF5::WaylandClient + KF5::WindowSystem ) install(TARGETS ksplashqml ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES org.kde.KSplash.xml DESTINATION ${KDE_INSTALL_DBUSINTERFACEDIR}) diff --git a/ksplash/ksplashqml/splashapp.cpp b/ksplash/ksplashqml/splashapp.cpp index d66c4afb..1495ce31 100644 --- a/ksplash/ksplashqml/splashapp.cpp +++ b/ksplash/ksplashqml/splashapp.cpp @@ -1,145 +1,173 @@ /* * Copyright (C) 2010 Ivan Cukic * Copyright (C) 2013 Martin Klapetek * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, * or (at your option) any later version, as published by the Free * Software Foundation * * 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 "splashwindow.h" #include "splashapp.h" #include #include #include #include #include #include #include #include +#include +#include +#include +#include + #define TEST_STEP_INTERVAL 2000 /** * There are 6 used stages in ksplash * - initial * - kinit * - ksmserver * - wm * - ready * - desktop */ SplashApp::SplashApp(int &argc, char ** argv) : QGuiApplication(argc, argv), m_stage(0), m_testing(false), m_window(false), m_startTime(QDateTime::currentDateTime()) { QCommandLineParser parser; parser.addOption(QCommandLineOption(QStringLiteral("test"), QStringLiteral("Run in test mode"))); parser.addOption(QCommandLineOption(QStringLiteral("window"), QStringLiteral("Run in windowed mode"))); parser.addOption(QCommandLineOption(QStringLiteral("nofork"), QStringLiteral("Don't fork"))); parser.addOption(QCommandLineOption(QStringLiteral("pid"), QStringLiteral("Print the pid of the child process"))); parser.addHelpOption(); parser.process(*this); m_testing = parser.isSet(QStringLiteral("test")); m_window = parser.isSet(QStringLiteral("window")); + setupWaylandIntegration(); + foreach(QScreen* screen, screens()) adoptScreen(screen); setStage(QStringLiteral("initial")); if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive)) { setStage(QStringLiteral("wm")); } QPixmap cursor(32, 32); cursor.fill(Qt::transparent); setOverrideCursor(QCursor(cursor)); if (m_testing) { m_timer.start(TEST_STEP_INTERVAL, this); } connect(this, &QGuiApplication::screenAdded, this, &SplashApp::adoptScreen); QDBusConnection dbus = QDBusConnection::sessionBus(); dbus.registerObject(QStringLiteral("/KSplash"), this, QDBusConnection::ExportScriptableSlots); dbus.registerService(QStringLiteral("org.kde.KSplash")); } SplashApp::~SplashApp() { qDeleteAll(m_windows); } void SplashApp::timerEvent(QTimerEvent * event) { if (event->timerId() == m_timer.timerId()) { m_timer.stop(); setStage(m_stage + 1); m_timer.start(TEST_STEP_INTERVAL, this); } } void SplashApp::setStage(const QString &stage) { //filter out startup events from KDED as they will be removed in a future release if (stage == QLatin1String("kded") || stage == QLatin1String("confupdate")) { return; } qDebug() << "Loading stage " << stage << m_startTime.msecsTo(QDateTime::currentDateTime()); if (m_stages.contains(stage)) { return; } m_stages.append(stage); setStage(m_stages.count()); } void SplashApp::setStage(int stage) { if (m_stage == 6) { QGuiApplication::exit(EXIT_SUCCESS); } m_stage = stage; foreach (SplashWindow *w, m_windows) { w->setStage(stage); } } void SplashApp::adoptScreen(QScreen* screen) { SplashWindow *w = new SplashWindow(m_testing, m_window); w->setGeometry(screen->geometry()); w->setStage(m_stage); w->setVisible(true); m_windows << w; connect(screen, &QScreen::geometryChanged, w, &SplashWindow::setGeometry); connect(screen, &QObject::destroyed, w, [this, w](){ m_windows.removeAll(w); w->deleteLater(); }); } + +void SplashApp::setupWaylandIntegration() +{ + if (!KWindowSystem::isPlatformWayland()) { + return; + } + using namespace KWayland::Client; + ConnectionThread *connection = ConnectionThread::fromApplication(this); + if (!connection) { + return; + } + Registry *registry = new Registry(this); + registry->create(connection); + connect(registry, &Registry::plasmaShellAnnounced, this, + [this, registry] (quint32 name, quint32 version) { + m_waylandPlasmaShell = registry->createPlasmaShell(name, version, this); + } + ); + registry->setup(); + connection->roundtrip(); +} diff --git a/ksplash/ksplashqml/splashapp.h b/ksplash/ksplashqml/splashapp.h index 9477b10e..9e4e159b 100644 --- a/ksplash/ksplashqml/splashapp.h +++ b/ksplash/ksplashqml/splashapp.h @@ -1,60 +1,76 @@ /* * Copyright (C) 2010 Ivan Cukic * Copyright (C) 2013 Martin Klapetek * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, * or (at your option) any later version, as published by the Free * Software Foundation * * 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. */ #ifndef SPLASH_APP_H_ #define SPLASH_APP_H_ #include #include #include #include class SplashWindow; +namespace KWayland +{ +namespace Client +{ +class PlasmaShell; +} +} + class SplashApp: public QGuiApplication { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.KSplash") public: explicit SplashApp(int &argc, char ** argv); ~SplashApp() override; + + KWayland::Client::PlasmaShell *waylandPlasmaShellInterface() const { + return m_waylandPlasmaShell; + } + public Q_SLOTS: Q_SCRIPTABLE void setStage(const QString &messgae); protected: void timerEvent(QTimerEvent *event) override; void setStage(int stage); private: + void setupWaylandIntegration(); int m_stage; QList m_windows; bool m_testing; bool m_window; QStringList m_stages; QBasicTimer m_timer; QDateTime m_startTime; + KWayland::Client::PlasmaShell *m_waylandPlasmaShell = nullptr; + private Q_SLOTS: void adoptScreen(QScreen*); }; #endif // SPLASH_APP_H_ diff --git a/ksplash/ksplashqml/splashwindow.cpp b/ksplash/ksplashqml/splashwindow.cpp index 205eedf9..5df357b8 100644 --- a/ksplash/ksplashqml/splashwindow.cpp +++ b/ksplash/ksplashqml/splashwindow.cpp @@ -1,114 +1,166 @@ /* * Copyright (C) 2010 Ivan Cukic * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, * or (at your option) any later version, as published by the Free * Software Foundation * * 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 "splashwindow.h" +#include "splashapp.h" #include #include #include #include #include #include #include #include #include #include #include #include +#include +#include +#include + SplashWindow::SplashWindow(bool testing, bool window) : KQuickAddons::QuickViewSharedEngine(), m_stage(0), m_testing(testing), m_window(window) { setColor(Qt::transparent); setDefaultAlphaBuffer(true); setClearBeforeRendering(true); setResizeMode(KQuickAddons::QuickViewSharedEngine::SizeRootObjectToView); if (!m_window) { setFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); } if (!m_testing && !m_window) { - if (QGuiApplication::platformName().compare(QLatin1String("xcb"), Qt::CaseInsensitive) == 0) { + if (KWindowSystem::isPlatformX11()) { // X11 specific hint only on X11 setFlags(Qt::BypassWindowManagerHint); - } else { + } else if (!KWindowSystem::isPlatformWayland()) { // on other platforms go fullscreen + // on Wayland we cannot go fullscreen due to QTBUG 54883 setWindowState(Qt::WindowFullScreen); } } - if (m_testing && !m_window) { + if (m_testing && !m_window && !KWindowSystem::isPlatformWayland()) { setWindowState(Qt::WindowFullScreen); } //be sure it will be eventually closed //FIXME: should never be stuck QTimer::singleShot(30000, this, &QWindow::close); } void SplashWindow::setStage(int stage) { m_stage = stage; rootObject()->setProperty("stage", stage); } +bool SplashWindow::event(QEvent *e) +{ + if (e->type() == QEvent::PlatformSurface) { + if (auto pe = dynamic_cast(e)) { + switch (pe->surfaceEventType()) { + case QPlatformSurfaceEvent::SurfaceCreated: + setupWaylandIntegration(); + break; + case QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed: + delete m_shellSurface; + m_shellSurface = nullptr; + break; + } + } + } + return KQuickAddons::QuickViewSharedEngine::event(e); +} + void SplashWindow::keyPressEvent(QKeyEvent *event) { KQuickAddons::QuickViewSharedEngine::keyPressEvent(event); if (m_testing && !event->isAccepted() && event->key() == Qt::Key_Escape) { close(); } } void SplashWindow::mousePressEvent(QMouseEvent *event) { KQuickAddons::QuickViewSharedEngine::mousePressEvent(event); if (m_testing && !event->isAccepted()) { close(); } } void SplashWindow::setGeometry(const QRect& rect) { bool oldGeometryEmpty = geometry().isNull(); KQuickAddons::QuickViewSharedEngine::setGeometry(rect); if (oldGeometryEmpty) { KPackage::Package package = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Plasma/LookAndFeel")); KConfigGroup cg(KSharedConfig::openConfig(QStringLiteral("kdeglobals")), "KDE"); const QString packageName = cg.readEntry("LookAndFeelPackage", QString()); if (!packageName.isEmpty()) { package.setPath(packageName); }; const QString theme = QGuiApplication::arguments().at(1); if (!theme.startsWith(QLatin1String("--"))) { package.setPath(theme); } setSource(QUrl::fromLocalFile(package.filePath("splashmainscript"))); } + + if (m_shellSurface) { + m_shellSurface->setPosition(geometry().topLeft()); + } +} + +void SplashWindow::setupWaylandIntegration() +{ + if (m_shellSurface) { + // already setup + return; + } + if (SplashApp *a = qobject_cast(qApp)) { + using namespace KWayland::Client; + PlasmaShell *interface = a->waylandPlasmaShellInterface(); + if (!interface) { + return; + } + Surface *s = Surface::fromWindow(this); + if (!s) { + return; + } + m_shellSurface = interface->createSurface(s, this); + // Use OSD to make it go above all other windows + // that's the closest we have to the X11 unmanged layer we have on Wayland + m_shellSurface->setRole(PlasmaShellSurface::Role::OnScreenDisplay); + m_shellSurface->setPosition(geometry().topLeft()); + } } diff --git a/ksplash/ksplashqml/splashwindow.h b/ksplash/ksplashqml/splashwindow.h index ef817fb6..25367642 100644 --- a/ksplash/ksplashqml/splashwindow.h +++ b/ksplash/ksplashqml/splashwindow.h @@ -1,47 +1,58 @@ /* * Copyright (C) 2010 Ivan Cukic * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, * or (at your option) any later version, as published by the Free * Software Foundation * * 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. */ #ifndef SPLASH_WINDOW_H_ #define SPLASH_WINDOW_H_ #include class QResizeEvent; class QMouseEvent; class QKeyEvent; +namespace KWayland +{ +namespace Client +{ +class PlasmaShellSurface; +} +} + class SplashWindow: public KQuickAddons::QuickViewSharedEngine { public: SplashWindow(bool testing = false, bool window = false); void setStage(int stage); virtual void setGeometry(const QRect &rect); protected: + bool event(QEvent *e) override; void keyPressEvent(QKeyEvent *event) override; void mousePressEvent(QMouseEvent *event) override; private: + void setupWaylandIntegration(); int m_stage; bool m_testing; bool m_window; + KWayland::Client::PlasmaShellSurface *m_shellSurface = nullptr; }; #endif // SPLASH_WINDOW_H_