diff --git a/ksmserver/CMakeLists.txt b/ksmserver/CMakeLists.txt --- a/ksmserver/CMakeLists.txt +++ b/ksmserver/CMakeLists.txt @@ -7,6 +7,9 @@ check_library_exists(ICE _IceTransNoListen "" HAVE__ICETRANSNOLISTEN) configure_file(config-ksmserver.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-ksmserver.h) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) +add_subdirectory(logout-greeter) + ########### next target ############### set(ksmserver_KDEINIT_SRCS diff --git a/ksmserver/config-ksmserver.h.cmake b/ksmserver/config-ksmserver.h.cmake --- a/ksmserver/config-ksmserver.h.cmake +++ b/ksmserver/config-ksmserver.h.cmake @@ -1,4 +1,5 @@ /* 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 KWIN_BIN "${KWIN_BIN}" diff --git a/ksmserver/logout-greeter/CMakeLists.txt b/ksmserver/logout-greeter/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/ksmserver/logout-greeter/CMakeLists.txt @@ -0,0 +1,17 @@ +set(KSMSERVER_LOGOUT_GREETER_SRCS main.cpp ../shutdowndlg.cpp) +add_executable(ksmserver-logout-greeter ${KSMSERVER_LOGOUT_GREETER_SRCS}) +target_link_libraries(ksmserver-logout-greeter + PW::KWorkspace + Qt5::Widgets + Qt5::Quick + Qt5::X11Extras + KF5::Declarative + KF5::IconThemes + KF5::I18n + KF5::Package + KF5::KDELibs4Support # Solid/PowerManagement + ${X11_LIBRARIES} +) +install(TARGETS ksmserver-logout-greeter DESTINATION ${KDE_INSTALL_LIBEXECDIR}) + +add_subdirectory(tests) diff --git a/ksmserver/logout-greeter/main.cpp b/ksmserver/logout-greeter/main.cpp new file mode 100644 --- /dev/null +++ b/ksmserver/logout-greeter/main.cpp @@ -0,0 +1,112 @@ +/***************************************************************** +ksmserver - the KDE session management server + +Copyright 2016 Martin Graesslin + +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 +#include +#include +#include "../shutdowndlg.h" + +#include + +int main(int argc, char *argv[]) +{ + // TODO: remove dependency on X11 + qputenv("QT_QPA_PLATFORM", "xcb"); + QApplication app(argc, argv); + + QCommandLineParser parser; + parser.addHelpOption(); + + // TODO: should these things be translated? It's internal after all... + QCommandLineOption shutdownAllowedOption(QStringLiteral("shutdown-allowed"), + QStringLiteral("Whether the user is allowed to shut down the system.")); + parser.addOption(shutdownAllowedOption); + + QCommandLineOption chooseOption(QStringLiteral("choose"), + QStringLiteral("Whether the user is offered the choices between logout, shutdown, etc.")); + parser.addOption(chooseOption); + + QCommandLineOption modeOption(QStringLiteral("mode"), + QStringLiteral("The initial exit mode to offer to the user."), + QStringLiteral("logout|shutdown|reboot"), + QStringLiteral("logout")); + parser.addOption(modeOption); + + QCommandLineOption fdOption(QStringLiteral("mode-fd"), + QStringLiteral("An optional file descriptor the selected mode is written to on accepted"), + QStringLiteral("fd"), QString::number(-1)); + parser.addOption(fdOption); + + parser.process(app); + + KWorkSpace::ShutdownType type = KWorkSpace::ShutdownTypeDefault; + if (parser.isSet(modeOption)) { + const QString modeValue = parser.value(modeOption); + if (QString::compare(QLatin1String("logout"), modeValue, Qt::CaseInsensitive) == 0) { + type = KWorkSpace::ShutdownTypeNone; + } else if (QString::compare(QLatin1String("shutdown"), modeValue, Qt::CaseInsensitive) == 0) { + type = KWorkSpace::ShutdownTypeHalt; + } else if (QString::compare(QLatin1String("reboot"), modeValue, Qt::CaseInsensitive) == 0) { + type = KWorkSpace::ShutdownTypeReboot; + } else { + return 1; + } + } + + int fd = -1; + if (parser.isSet(fdOption)) { + bool ok = false; + const int passedFd = parser.value(fdOption).toInt(&ok); + if (ok) { + fd = dup(passedFd); + } + } + + // TODO: last argument is the theme, maybe add command line option for it? + // TODO: create one dialog per screen, properly handle screen add/remove + KSMShutdownDlg dlg(nullptr, + parser.isSet(shutdownAllowedOption), + parser.isSet(chooseOption), type, QString()); + QObject::connect(&dlg, &KSMShutdownDlg::rejected, &app, + [fd] { + if (fd != -1) { + close(fd); + } + QApplication::exit(1); + } + ); + QObject::connect(&dlg, &KSMShutdownDlg::accepted, &app, + [fd, &dlg] { + if (fd != -1) { + QFile f; + if (f.open(fd, QFile::WriteOnly, QFile::AutoCloseHandle)) { + f.write(QByteArray::number(int(dlg.shutdownType()))); + f.close(); + } + } + QApplication::quit(); + } + ); + + return app.exec(); +} diff --git a/ksmserver/logout-greeter/tests/CMakeLists.txt b/ksmserver/logout-greeter/tests/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/ksmserver/logout-greeter/tests/CMakeLists.txt @@ -0,0 +1,3 @@ +add_executable(logout-greeter-test main.cpp) +target_link_libraries(logout-greeter-test Qt5::Core Qt5::Concurrent) +ecm_mark_as_test(logout-greeter-test) diff --git a/ksmserver/logout-greeter/tests/main.cpp b/ksmserver/logout-greeter/tests/main.cpp new file mode 100644 --- /dev/null +++ b/ksmserver/logout-greeter/tests/main.cpp @@ -0,0 +1,116 @@ +/***************************************************************** +ksmserver - the KDE session management server + +Copyright 2016 Martin Graesslin + +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 +#include +#include +#include +#include +#include +#include + +#include + +#include + +static void readFromPipe(int pipe) +{ + QFile readPipe; + if (!readPipe.open(pipe, QIODevice::ReadOnly)) { + QCoreApplication::exit(1); + return; + } + QByteArray result = readPipe.readLine(); + qDebug() << "!!!! Result from helper process: " << result; + if (result.isEmpty()) { + qDebug() << "!!!! Error"; + QCoreApplication::exit(1); + } +} + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + + QCommandLineParser parser; + parser.addHelpOption(); + + QCommandLineOption shutdownAllowedOption(QStringLiteral("shutdown-allowed"), + QStringLiteral("Whether the user is allowed to shut down the system.")); + parser.addOption(shutdownAllowedOption); + + QCommandLineOption chooseOption(QStringLiteral("choose"), + QStringLiteral("Whether the user is offered the choices between logout, shutdown, etc.")); + parser.addOption(chooseOption); + + QCommandLineOption modeOption(QStringLiteral("mode"), + QStringLiteral("The initial exit mode to offer to the user."), + QStringLiteral("logout|shutdown|reboot"), + QStringLiteral("logout")); + parser.addOption(modeOption); + + parser.process(app); + + int pipeFds[2]; + if (pipe(pipeFds) != 0) { + return 1; + } + + QProcess p; + p.setProgram(QStringLiteral(LOGOUT_GREETER_BIN)); + QStringList arguments; + if (parser.isSet(shutdownAllowedOption)) { + arguments << QStringLiteral("--shutdown-allowed"); + } + if (parser.isSet(chooseOption)) { + arguments << QStringLiteral("--choose"); + } + if (parser.isSet(modeOption)) { + arguments << QStringLiteral("--mode"); + arguments << parser.value(modeOption); + } + arguments << QStringLiteral("--mode-fd"); + arguments << QString::number(pipeFds[1]); + p.setArguments(arguments); + + QObject::connect(&p, static_cast(&QProcess::error), &app, + [] { + QCoreApplication::exit(1); + } + ); + + const int resultPipe = pipeFds[0]; + QObject::connect(&p, &QProcess::started, + [resultPipe] { + QFutureWatcher *watcher = new QFutureWatcher(); + QObject::connect(watcher, &QFutureWatcher::finished, QCoreApplication::instance(), &QCoreApplication::quit, Qt::QueuedConnection); + QObject::connect(watcher, &QFutureWatcher::finished, watcher, &QFutureWatcher::deleteLater, Qt::QueuedConnection); + watcher->setFuture(QtConcurrent::run(readFromPipe, resultPipe)); + } + ); + + p.start(); + close(pipeFds[1]); + + return app.exec(); +} diff --git a/ksmserver/shutdowndlg.h b/ksmserver/shutdowndlg.h --- a/ksmserver/shutdowndlg.h +++ b/ksmserver/shutdowndlg.h @@ -49,12 +49,17 @@ Q_OBJECT public: + KSMShutdownDlg( QWindow* parent, bool maysd, bool choose, KWorkSpace::ShutdownType sdtype, const QString& theme ); static bool confirmShutdown( bool maysd, bool choose, KWorkSpace::ShutdownType& sdtype, QString& bopt, const QString& theme ); bool result() const; bool exec(); + KWorkSpace::ShutdownType shutdownType() const { + return m_shutdownType; + } + public Q_SLOTS: void accept(); void reject(); @@ -74,7 +79,6 @@ void mousePressEvent(QMouseEvent *e) Q_DECL_OVERRIDE; private: - KSMShutdownDlg( QWindow* parent, bool maysd, bool choose, KWorkSpace::ShutdownType sdtype, const QString& theme ); KWorkSpace::ShutdownType m_shutdownType; QString m_bootOption; QStringList rebootOptions; diff --git a/ksmserver/shutdowndlg.cpp b/ksmserver/shutdowndlg.cpp --- a/ksmserver/shutdowndlg.cpp +++ b/ksmserver/shutdowndlg.cpp @@ -97,6 +97,11 @@ XInternAtom( QX11Info::display(), "WM_WINDOW_ROLE", False ), XA_STRING, 8, PropModeReplace, (unsigned char *)"logoutdialog", strlen( "logoutdialog" )); + XClassHint classHint; + classHint.res_name = const_cast("ksmserver"); + classHint.res_class = const_cast("ksmserver"); + XSetClassHint(QX11Info::display(), winId(), &classHint); + //QQuickView *windowContainer = QQuickView::createWindowContainer(m_view, this); //windowContainer->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);