mirror of https://github.com/Qortal/Brooklyn
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
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; |
|
}
|
|
|