summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKai Uwe Broulik <[email protected]>2016-11-24 14:06:01 +0100
committerKai Uwe Broulik <[email protected]>2016-11-24 14:06:01 +0100
commitec1c80326a07c710262b6496873f51e0d3ed7d92 (patch)
tree5c4c768dddd8aecdf29c1b8b642b9610a30e5fff
parentce8327253bccfb4e327b9949bffea3b9148014ce (diff)
[KSMServer] Turn user switcher into a separate binary
This follows the same approach as the logout greeter, albeit a bit simplified. It also creates one window per screen and should fix the problems we had with its positioning in multi-screen setups. Differential Revision: https://phabricator.kde.org/D3204
-rw-r--r--ksmserver/CMakeLists.txt2
-rw-r--r--ksmserver/config-ksmserver.h.cmake1
-rw-r--r--ksmserver/server.cpp15
-rw-r--r--ksmserver/switchuser-greeter/CMakeLists.txt15
-rw-r--r--ksmserver/switchuser-greeter/main.cpp147
-rw-r--r--ksmserver/switchuserdialog.cpp94
-rw-r--r--ksmserver/switchuserdialog.h21
7 files changed, 264 insertions, 31 deletions
diff --git a/ksmserver/CMakeLists.txt b/ksmserver/CMakeLists.txt
index 4f1e0d0..c52a04a 100644
--- a/ksmserver/CMakeLists.txt
+++ b/ksmserver/CMakeLists.txt
@@ -7,6 +7,7 @@ configure_file(config-ksmserver.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-ksmse
include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_subdirectory(logout-greeter)
+add_subdirectory(switchuser-greeter)
########### next target ###############
@@ -14,7 +15,6 @@ set(ksmserver_KDEINIT_SRCS
ksmserver_debug.cpp
main.cpp
server.cpp
- switchuserdialog.cpp
legacy.cpp
startup.cpp
autostart.cpp
diff --git a/ksmserver/config-ksmserver.h.cmake b/ksmserver/config-ksmserver.h.cmake
index d6dd8d3..fa59e01 100644
--- a/ksmserver/config-ksmserver.h.cmake
+++ b/ksmserver/config-ksmserver.h.cmake
@@ -1,5 +1,6 @@
/* Define to 1 if you have the `_IceTransNoListen' function. */
#cmakedefine HAVE__ICETRANSNOLISTEN 1
#define LOGOUT_GREETER_BIN "${CMAKE_INSTALL_FULL_LIBEXECDIR}/ksmserver-logout-greeter"
+#define SWITCHUSER_GREETER_BIN "${CMAKE_INSTALL_FULL_LIBEXECDIR}/ksmserver-switchuser-greeter"
#define KWIN_BIN "${KWIN_BIN}"
diff --git a/ksmserver/server.cpp b/ksmserver/server.cpp
index 98e41db..24c76c9 100644
--- a/ksmserver/server.cpp
+++ b/ksmserver/server.cpp
@@ -1083,13 +1083,20 @@ void KSMServer::rebootWithoutConfirmation()
void KSMServer::openSwitchUserDialog()
{
- KDisplayManager dm;
- if (!dm.isSwitchable()) {
+ if (dialogActive) {
return;
}
- QScopedPointer<KSMSwitchUserDialog> dlg(new KSMSwitchUserDialog(&dm));
- dlg->exec();
+ QProcess *p = new QProcess(this);
+ p->setProgram(QStringLiteral(SWITCHUSER_GREETER_BIN));
+
+ connect(p, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), this, [this, p] {
+ p->deleteLater();
+ dialogActive = false;
+ });
+
+ dialogActive = true;
+ p->start();
}
void KSMServer::runShutdownScripts()
diff --git a/ksmserver/switchuser-greeter/CMakeLists.txt b/ksmserver/switchuser-greeter/CMakeLists.txt
new file mode 100644
index 0000000..a9e33f3
--- /dev/null
+++ b/ksmserver/switchuser-greeter/CMakeLists.txt
@@ -0,0 +1,15 @@
+set(KSMSERVER_SWITCHUSER_GREETER_SRCS main.cpp ../switchuserdialog.cpp ../ksmserver_debug.cpp)
+add_executable(ksmserver-switchuser-greeter ${KSMSERVER_SWITCHUSER_GREETER_SRCS})
+target_link_libraries(ksmserver-switchuser-greeter
+ PW::KWorkspace
+ Qt5::Quick
+ Qt5::X11Extras
+ KF5::Declarative
+ KF5::IconThemes
+ KF5::I18n
+ KF5::Package
+ KF5::WaylandClient
+ KF5::WindowSystem
+ ${X11_LIBRARIES}
+)
+install(TARGETS ksmserver-switchuser-greeter DESTINATION ${KDE_INSTALL_LIBEXECDIR})
diff --git a/ksmserver/switchuser-greeter/main.cpp b/ksmserver/switchuser-greeter/main.cpp
new file mode 100644
index 0000000..f2b768d
--- /dev/null
+++ b/ksmserver/switchuser-greeter/main.cpp
@@ -0,0 +1,147 @@
+/*****************************************************************
+ksmserver - the KDE session management server
+
+Copyright 2016 Martin Graesslin <[email protected]>
+Copyright 2016 Kai Uwe Broulik <[email protected]>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************************************/
+
+#include <QGuiApplication>
+#include <QScreen>
+
+#include "../switchuserdialog.h"
+
+#include <kdisplaymanager.h>
+#include <KWindowSystem>
+
+#include <KWayland/Client/connection_thread.h>
+#include <KWayland/Client/registry.h>
+#include <KWayland/Client/plasmashell.h>
+
+#include <unistd.h>
+
+class Greeter : public QObject
+{
+ Q_OBJECT
+public:
+ Greeter();
+ ~Greeter() override;
+
+ void init();
+
+ bool eventFilter(QObject *watched, QEvent *event) override;
+
+private:
+ void adoptScreen(QScreen *screen);
+ void rejected();
+ void setupWaylandIntegration();
+
+ QVector<KSMSwitchUserDialog *> m_dialogs;
+ KWayland::Client::PlasmaShell *m_waylandPlasmaShell;
+ KDisplayManager m_displayManager;
+};
+
+Greeter::Greeter()
+ : QObject()
+ , m_waylandPlasmaShell(nullptr)
+{
+}
+
+Greeter::~Greeter()
+{
+ qDeleteAll(m_dialogs);
+}
+
+void Greeter::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();
+}
+
+void Greeter::init()
+{
+ setupWaylandIntegration();
+ foreach (QScreen *screen, qApp->screens()) {
+ adoptScreen(screen);
+ }
+ connect(qApp, &QGuiApplication::screenAdded, this, &Greeter::adoptScreen);
+}
+
+void Greeter::adoptScreen(QScreen* screen)
+{
+ KSMSwitchUserDialog *w = new KSMSwitchUserDialog(&m_displayManager, m_waylandPlasmaShell);
+ w->installEventFilter(this);
+ m_dialogs << w;
+
+ QObject::connect(screen, &QObject::destroyed, w, [w, this] {
+ m_dialogs.removeOne(w);
+ w->deleteLater();
+ });
+ connect(w, &KSMSwitchUserDialog::dismissed, qApp, &QCoreApplication::quit);
+ w->setScreen(screen);
+ w->setGeometry(screen->geometry());
+ w->init();
+}
+
+bool Greeter::eventFilter(QObject *watched, QEvent *event)
+{
+ if (qobject_cast<KSMSwitchUserDialog*>(watched)) {
+ if (event->type() == QEvent::MouseButtonPress) {
+ // check that the position is on no window
+ QMouseEvent *me = static_cast<QMouseEvent*>(event);
+ for (auto it = m_dialogs.constBegin(); it != m_dialogs.constEnd(); ++it) {
+ if ((*it)->geometry().contains(me->globalPos())) {
+ return false;
+ }
+ }
+ // click outside, close
+ qApp->quit();
+ }
+ }
+ return false;
+}
+
+int main(int argc, char *argv[])
+{
+ QQuickWindow::setDefaultAlphaBuffer(true);
+ QGuiApplication app(argc, argv);
+
+ Greeter greeter;
+ greeter.init();
+
+ return app.exec();
+}
+
+#include "main.moc"
diff --git a/ksmserver/switchuserdialog.cpp b/ksmserver/switchuserdialog.cpp
index f4f6436..e7e4003 100644
--- a/ksmserver/switchuserdialog.cpp
+++ b/ksmserver/switchuserdialog.cpp
@@ -19,20 +19,17 @@
*/
#include "switchuserdialog.h"
+#include "ksmserver_debug.h"
#include <kdisplaymanager.h>
-#include <ksmserver_debug.h>
-#include <QApplication>
#include <QDebug>
-#include <QDesktopWidget>
-#include <QEventLoop>
+#include <QGuiApplication>
#include <QQuickItem>
#include <QQmlContext>
#include <QQmlEngine>
#include <QX11Info>
#include <QScreen>
-#include <QStandardItemModel>
#include <QStandardPaths>
#include <KPackage/Package>
@@ -41,21 +38,28 @@
#include <KConfigGroup>
#include <KLocalizedString>
#include <KSharedConfig>
+#include <KWindowEffects>
#include <KWindowSystem>
#include <KUser>
#include <KDeclarative/KDeclarative>
+#include <KWayland/Client/surface.h>
+#include <KWayland/Client/plasmashell.h>
+
#include <X11/Xutil.h>
#include <X11/Xatom.h>
-KSMSwitchUserDialog::KSMSwitchUserDialog(KDisplayManager *dm, QWindow *parent)
+KSMSwitchUserDialog::KSMSwitchUserDialog(KDisplayManager *dm, KWayland::Client::PlasmaShell *plasmaShell, QWindow *parent)
: QQuickView(parent)
, m_displayManager(dm)
+ , m_waylandPlasmaShell(plasmaShell)
{
setClearBeforeRendering(true);
setColor(QColor(Qt::transparent));
setFlags(Qt::FramelessWindowHint | Qt::BypassWindowManagerHint);
+ setResizeMode(QQuickView::SizeRootObjectToView);
+
QPoint globalPosition(QCursor::pos());
foreach (QScreen *s, QGuiApplication::screens()) {
if (s->geometry().contains(globalPosition)) {
@@ -66,19 +70,26 @@ KSMSwitchUserDialog::KSMSwitchUserDialog(KDisplayManager *dm, QWindow *parent)
// Qt doesn't set this on unmanaged windows
//FIXME: or does it?
- XChangeProperty( QX11Info::display(), winId(),
- XInternAtom( QX11Info::display(), "WM_WINDOW_ROLE", False ), XA_STRING, 8, PropModeReplace,
- (unsigned char *)"logoutdialog", strlen( "logoutdialog" ));
-
-
- rootContext()->setContextProperty(QStringLiteral("screenGeometry"), screen()->geometry());
-
- setModality(Qt::ApplicationModal);
+ if (KWindowSystem::isPlatformX11()) {
+ XChangeProperty( QX11Info::display(), winId(),
+ XInternAtom( QX11Info::display(), "WM_WINDOW_ROLE", False ), XA_STRING, 8, PropModeReplace,
+ (unsigned char *)"logoutdialog", strlen( "logoutdialog" ));
+
+ XClassHint classHint;
+ classHint.res_name = const_cast<char*>("ksmserver");
+ classHint.res_class = const_cast<char*>("ksmserver");
+ XSetClassHint(QX11Info::display(), winId(), &classHint);
+ }
KDeclarative::KDeclarative kdeclarative;
kdeclarative.setDeclarativeEngine(engine());
- //kdeclarative.initialize();
+ kdeclarative.initialize();
kdeclarative.setupBindings();
+}
+
+void KSMSwitchUserDialog::init()
+{
+ rootContext()->setContextProperty(QStringLiteral("screenGeometry"), screen()->geometry());
KPackage::Package package = KPackage::PackageLoader::self()->loadPackage("Plasma/LookAndFeel");
KConfigGroup cg(KSharedConfig::openConfig("kdeglobals"), "KDE");
@@ -96,24 +107,59 @@ KSMSwitchUserDialog::KSMSwitchUserDialog(KDisplayManager *dm, QWindow *parent)
return;
}
- setPosition(screen()->virtualGeometry().center().x() - width() / 2,
- screen()->virtualGeometry().center().y() - height() / 2);
-
if (!errors().isEmpty()) {
qCWarning(KSMSERVER) << errors();
}
connect(rootObject(), SIGNAL(dismissed()), this, SIGNAL(dismissed()));
- show();
+ connect(screen(), &QScreen::geometryChanged, this, [this] {
+ setGeometry(screen()->geometry());
+ });
+
+ QQuickView::show();
requestActivate();
- KWindowSystem::setState(winId(), NET::SkipTaskbar | NET::SkipPager);
+ KWindowSystem::setState(winId(), NET::SkipTaskbar|NET::SkipPager);
+
+ setKeyboardGrabEnabled(true);
+}
+
+bool KSMSwitchUserDialog::event(QEvent *e)
+{
+ if (e->type() == QEvent::PlatformSurface) {
+ if (auto pe = dynamic_cast<QPlatformSurfaceEvent*>(e)) {
+ switch (pe->surfaceEventType()) {
+ case QPlatformSurfaceEvent::SurfaceCreated:
+ setupWaylandIntegration();
+ KWindowEffects::enableBlurBehind(winId(), true);
+ break;
+ case QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed:
+ delete m_shellSurface;
+ m_shellSurface = nullptr;
+ break;
+ }
+ }
+ }
+ return QQuickView::event(e);
}
-void KSMSwitchUserDialog::exec()
+void KSMSwitchUserDialog::setupWaylandIntegration()
{
- QEventLoop loop;
- connect(this, &KSMSwitchUserDialog::dismissed, &loop, &QEventLoop::quit);
- loop.exec();
+ if (m_shellSurface) {
+ // already setup
+ return;
+ }
+ using namespace KWayland::Client;
+ if (!m_waylandPlasmaShell) {
+ return;
+ }
+ Surface *s = Surface::fromWindow(this);
+ if (!s) {
+ return;
+ }
+ m_shellSurface = m_waylandPlasmaShell->createSurface(s, this);
+ // TODO: set a proper window type to indicate to KWin that this is the logout dialog
+ // maybe we need a dedicated type for it?
+ m_shellSurface->setPosition(geometry().topLeft());
}
diff --git a/ksmserver/switchuserdialog.h b/ksmserver/switchuserdialog.h
index 66d9d88..958cdd7 100644
--- a/ksmserver/switchuserdialog.h
+++ b/ksmserver/switchuserdialog.h
@@ -25,22 +25,39 @@
class KDisplayManager;
+namespace KWayland
+{
+namespace Client
+{
+class PlasmaShell;
+class PlasmaShellSurface;
+}
+}
+
class KSMSwitchUserDialog : public QQuickView
{
Q_OBJECT
public:
- explicit KSMSwitchUserDialog(KDisplayManager *dm, QWindow *parent = nullptr);
+ explicit KSMSwitchUserDialog(KDisplayManager *dm, KWayland::Client::PlasmaShell *plasmaShell = nullptr, QWindow *parent = nullptr);
~KSMSwitchUserDialog() override = default;
- void exec();
+ void init();
signals:
void dismissed();
+protected:
+ bool event(QEvent *e) override;
+
private:
+ void setupWaylandIntegration();
+
KDisplayManager *m_displayManager = nullptr;
+ KWayland::Client::PlasmaShell *m_waylandPlasmaShell;
+ KWayland::Client::PlasmaShellSurface *m_shellSurface = nullptr;
+
};
#endif // SWITCHUSERDIALOG_H