QortalOS Brooklyn for Raspberry Pi 4
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

308 lines
10 KiB

/*
ksmserver - the KDE session management server
SPDX-FileCopyrightText: 2000 Matthias Ettrich <[email protected]>
SPDX-License-Identifier: MIT
*/
#include <config-ksmserver.h>
#include <config-workspace.h>
#include <errno.h>
#include <fcntl.h>
#include <fixx11h.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <KMessageBox>
#include "server.h"
#include <KLocalizedString>
#include <KSharedConfig>
#include <QX11Info>
#include <kconfig.h>
#include <kconfiggroup.h>
#include <kdbusservice.h>
#include <kmanagerselection.h>
#include <ksmserver_debug.h>
#include <kwindowsystem.h>
#include <QApplication>
#include <QCommandLineParser>
#include <QQuickWindow>
#include <X11/extensions/Xrender.h>
static const char version[] = "0.4";
static const char description[] = I18N_NOOP("The reliable Plasma session manager that talks the standard X11R6 \nsession management protocol (XSMP).");
Display *dpy = nullptr;
Colormap colormap = 0;
Visual *visual = nullptr;
extern KSMServer *the_server;
void IoErrorHandler(IceConn iceConn)
{
the_server->ioError(iceConn);
}
bool writeTest(QByteArray path)
{
path += "/XXXXXX";
int fd = mkstemp(path.data());
if (fd == -1)
return false;
if (write(fd, "Hello World\n", 12) == -1) {
int save_errno = errno;
close(fd);
unlink(path.data());
errno = save_errno;
return false;
}
close(fd);
unlink(path.data());
return true;
}
void checkComposite()
{
if (qgetenv("KDE_SKIP_ARGB_VISUALS") == "1")
return;
// thanks to zack rusin and frederik for pointing me in the right direction
// for the following bits of X11 code
dpy = XOpenDisplay(nullptr); // open default display
if (!dpy) {
qCCritical(KSMSERVER) << "Cannot connect to the X server";
return;
}
int screen = DefaultScreen(dpy);
int eventBase, errorBase;
if (XRenderQueryExtension(dpy, &eventBase, &errorBase)) {
int nvi;
XVisualInfo templ;
templ.screen = screen;
templ.depth = 32;
templ.c_class = TrueColor;
XVisualInfo *xvi = XGetVisualInfo(dpy, VisualScreenMask | VisualDepthMask | VisualClassMask, &templ, &nvi);
for (int i = 0; i < nvi; ++i) {
XRenderPictFormat *format = XRenderFindVisualFormat(dpy, xvi[i].visual);
if (format->type == PictTypeDirect && format->direct.alphaMask) {
visual = xvi[i].visual;
colormap = XCreateColormap(dpy, RootWindow(dpy, screen), visual, AllocNone);
XFree(xvi);
return;
}
}
XFree(xvi);
}
XCloseDisplay(dpy);
dpy = nullptr;
}
void sanity_check(int argc, char *argv[])
{
QString msg;
QByteArray path = qgetenv("HOME");
const QByteArray readOnly = qgetenv("KDE_HOME_READONLY");
if (path.isEmpty()) {
msg = i18n("$HOME not set!");
}
if (msg.isEmpty() && access(path.data(), W_OK)) {
if (errno == ENOENT)
msg = i18n("$HOME directory (%1) does not exist.", QFile::decodeName(path));
else if (readOnly.isEmpty())
msg = i18n("No write access to $HOME directory (%1).", QFile::decodeName(path));
}
if (msg.isEmpty() && access(path.data(), R_OK)) {
if (errno == ENOENT)
msg = i18n("$HOME directory (%1) does not exist.", QFile::decodeName(path));
else
msg = i18n("No read access to $HOME directory (%1).", QFile::decodeName(path));
}
if (msg.isEmpty() && readOnly.isEmpty() && !writeTest(path)) {
if (errno == ENOSPC)
msg = i18n("$HOME directory (%1) is out of disk space.", QFile::decodeName(path));
else
msg = i18n(
"Writing to the $HOME directory (%2) failed with "
"the error '%1'",
QString::fromLocal8Bit(strerror(errno)),
QFile::decodeName(path));
}
if (msg.isEmpty()) {
path = getenv("ICEAUTHORITY");
if (path.isEmpty()) {
path = qgetenv("HOME");
path += "/.ICEauthority";
}
if (access(path.data(), W_OK) && (errno != ENOENT))
msg = i18n("No write access to '%1'.", QFile::decodeName(path));
else if (access(path.data(), R_OK) && (errno != ENOENT))
msg = i18n("No read access to '%1'.", QFile::decodeName(path));
}
if (msg.isEmpty()) {
path = getenv("KDETMP");
if (path.isEmpty())
path = "/tmp";
if (!writeTest(path)) {
if (errno == ENOSPC)
msg = i18n("Temp directory (%1) is out of disk space.", QFile::decodeName(path));
else
msg = i18n(
"Writing to the temp directory (%2) failed with\n "
"the error '%1'",
QString::fromLocal8Bit(strerror(errno)),
QFile::decodeName(path));
}
}
if (msg.isEmpty() && (path != "/tmp")) {
path = "/tmp";
if (!writeTest(path)) {
if (errno == ENOSPC)
msg = i18n("Temp directory (%1) is out of disk space.", QFile::decodeName(path));
else
msg = i18n(
"Writing to the temp directory (%2) failed with\n "
"the error '%1'",
QString::fromLocal8Bit(strerror(errno)),
QFile::decodeName(path));
}
}
if (msg.isEmpty()) {
path += "/.ICE-unix";
if (access(path.data(), W_OK) && (errno != ENOENT))
msg = i18n("No write access to '%1'.", QFile::decodeName(path));
else if (access(path.data(), R_OK) && (errno != ENOENT))
msg = i18n("No read access to '%1'.", QFile::decodeName(path));
}
if (!msg.isEmpty()) {
const QString msg_pre = i18n(
"The following installation problem was detected\n"
"while trying to start Plasma:")
+ QStringLiteral("\n\n ");
const QString msg_post = i18n("\n\nPlasma is unable to start.\n");
fputs(msg_pre.toUtf8().constData(), stderr);
fprintf(stderr, "%s", msg.toUtf8().constData());
fputs(msg_post.toUtf8().constData(), stderr);
QApplication a(argc, argv);
const QString qmsg = msg_pre + msg + msg_post;
KMessageBox::error(nullptr, qmsg, i18n("Plasma Workspace installation problem!"));
exit(255);
}
}
int main(int argc, char *argv[])
{
sanity_check(argc, argv);
putenv((char *)"SESSION_MANAGER=");
checkComposite();
// force xcb QPA plugin as ksmserver is very X11 specific
const QByteArray origQpaPlatform = qgetenv("QT_QPA_PLATFORM");
qputenv("QT_QPA_PLATFORM", QByteArrayLiteral("xcb"));
QQuickWindow::setDefaultAlphaBuffer(true);
QCoreApplication::setAttribute(Qt::AA_DisableHighDpiScaling);
QApplication *a = new QApplication(argc, argv);
// now the QPA platform is set, unset variable again to not launch apps with incorrect environment
if (origQpaPlatform.isEmpty()) {
qunsetenv("QT_QPA_PLATFORM");
} else {
qputenv("QT_QPA_PLATFORM", origQpaPlatform);
}
QApplication::setApplicationName(QStringLiteral("ksmserver"));
QApplication::setApplicationVersion(QString::fromLatin1(version));
QApplication::setOrganizationDomain(QStringLiteral("kde.org"));
fcntl(ConnectionNumber(QX11Info::display()), F_SETFD, 1);
a->setQuitOnLastWindowClosed(false); // #169486
QCommandLineParser parser;
parser.setApplicationDescription(i18n(description));
parser.addHelpOption();
parser.addVersionOption();
QCommandLineOption restoreOption(QStringList() << QStringLiteral("r") << QStringLiteral("restore"), i18n("Restores the saved user session if available"));
parser.addOption(restoreOption);
QCommandLineOption nolocalOption(QStringLiteral("nolocal"), i18n("Also allow remote connections"));
parser.addOption(nolocalOption);
QCommandLineOption lockscreenOption(QStringLiteral("lockscreen"), i18n("Starts the session in locked mode"));
parser.addOption(lockscreenOption);
QCommandLineOption noLockscreenOption(QStringLiteral("no-lockscreen"),
i18n("Starts without lock screen support. Only needed if other component provides the lock screen."));
parser.addOption(noLockscreenOption);
parser.process(*a);
bool only_local = !parser.isSet(nolocalOption);
#ifndef HAVE__ICETRANSNOLISTEN
/* this seems strange, but the default is only_local, so if !only_local
* the option --nolocal was given, and we warn (the option --nolocal
* does nothing on this platform, as here the default is reversed)
*/
if (!only_local) {
qCWarning(KSMSERVER, "--nolocal is not supported on your platform. Sorry.");
}
only_local = false;
#endif
KSMServer::InitFlags flags = KSMServer::InitFlag::None;
if (only_local) {
flags |= KSMServer::InitFlag::OnlyLocal;
}
if (parser.isSet(lockscreenOption)) {
flags |= KSMServer::InitFlag::ImmediateLockScreen;
}
if (parser.isSet(noLockscreenOption)) {
flags |= KSMServer::InitFlag::NoLockScreen;
}
// we use the session_type here as ksmserver is already forced as X above
// in wayland, kwin manages the lock screen
if (qgetenv("XDG_SESSION_TYPE") == QByteArrayLiteral("wayland")) {
flags |= KSMServer::InitFlag::NoLockScreen;
}
KSMServer *server = new KSMServer(flags);
// for the KDE-already-running check in startkde
KSelectionOwner kde_running("_KDE_RUNNING", 0);
kde_running.claim(false);
IceSetIOErrorHandler(IoErrorHandler);
KConfigGroup config(KSharedConfig::openConfig(), "General");
QString loginMode = config.readEntry("loginMode", "restorePreviousLogout");
if (parser.isSet(restoreOption))
server->restoreSession(QStringLiteral(SESSION_BY_USER));
else if (loginMode == QLatin1String("restorePreviousLogout"))
server->restoreSession(QStringLiteral(SESSION_PREVIOUS_LOGOUT));
else if (loginMode == QLatin1String("restoreSavedSession"))
server->restoreSession(QStringLiteral(SESSION_BY_USER));
else
server->startDefaultSession();
KDBusService service(KDBusService::Unique);
server->setupShortcuts();
int ret = a->exec();
kde_running.release(); // needs to be done before QApplication destruction
delete a;
return ret;
}