7#include "kdisplaymanager.h"
11#include <KLocalizedString>
13#include <QDBusArgument>
14#include <QDBusConnectionInterface>
15#include <QDBusInterface>
16#include <QDBusMetaType>
17#include <QDBusObjectPath>
19#include <QGuiApplication>
21#include "config-X11.h"
31#include <sys/socket.h>
36#define _DBUS_PROPERTIES_IFACE "org.freedesktop.DBus.Properties"
37#define _DBUS_PROPERTIES_GET "Get"
39#define DBUS_PROPERTIES_IFACE QLatin1String(_DBUS_PROPERTIES_IFACE)
40#define DBUS_PROPERTIES_GET QLatin1String(_DBUS_PROPERTIES_GET)
42#define _SYSTEMD_SERVICE "org.freedesktop.login1"
43#define _SYSTEMD_BASE_PATH "/org/freedesktop/login1"
44#define _SYSTEMD_MANAGER_IFACE _SYSTEMD_SERVICE ".Manager"
45#define _SYSTEMD_SESSION_BASE_PATH _SYSTEMD_BASE_PATH "/session"
46#define _SYSTEMD_SEAT_IFACE _SYSTEMD_SERVICE ".Seat"
47#define _SYSTEMD_SEAT_BASE_PATH _SYSTEMD_BASE_PATH "/seat"
48#define _SYSTEMD_SESSION_IFACE _SYSTEMD_SERVICE ".Session"
49#define _SYSTEMD_USER_PROPERTY "User"
50#define _SYSTEMD_SEAT_PROPERTY "Seat"
51#define _SYSTEMD_SESSIONS_PROPERTY "Sessions"
52#define _SYSTEMD_SWITCH_PROPERTY "Activate"
54#define SYSTEMD_SERVICE QLatin1String(_SYSTEMD_SERVICE)
55#define SYSTEMD_BASE_PATH QLatin1String(_SYSTEMD_BASE_PATH)
56#define SYSTEMD_MANAGER_IFACE QLatin1String(_SYSTEMD_MANAGER_IFACE)
57#define SYSTEMD_SESSION_BASE_PATH QLatin1String(_SYSTEMD_SESSION_BASE_PATH)
58#define SYSTEMD_SEAT_IFACE QLatin1String(_SYSTEMD_SEAT_IFACE)
59#define SYSTEMD_SEAT_BASE_PATH QLatin1String(_SYSTEMD_SEAT_BASE_PATH)
60#define SYSTEMD_SESSION_IFACE QLatin1String(_SYSTEMD_SESSION_IFACE)
61#define SYSTEMD_USER_PROPERTY QLatin1String(_SYSTEMD_USER_PROPERTY)
62#define SYSTEMD_SEAT_PROPERTY QLatin1String(_SYSTEMD_SEAT_PROPERTY)
63#define SYSTEMD_SESSIONS_PROPERTY QLatin1String(_SYSTEMD_SESSIONS_PROPERTY)
64#define SYSTEMD_SWITCH_CALL QLatin1String(_SYSTEMD_SWITCH_PROPERTY)
66struct NamedDBusObjectPath {
75 argument << namedPath.name << namedPath.path;
84 argument >> namedPath.name >> namedPath.path;
89struct NumberedDBusObjectPath {
98 argument << numberedPath.num << numberedPath.path;
107 argument >> numberedPath.num >> numberedPath.path;
132 message <<
interface() << SYSTEMD_SESSIONS_PROPERTY;
136 if (!args.isEmpty()) {
138 qdbus_cast<QList<NamedDBusObjectPath>>(args.at(0).value<QDBusVariant>().variant().value<QDBusArgument>());
139 return namedPathList;
153 NamedDBusObjectPath getSeat()
156 message <<
interface() << SYSTEMD_SEAT_PROPERTY;
160 if (!args.isEmpty()) {
161 NamedDBusObjectPath namedPath;
165 return NamedDBusObjectPath();
167 NumberedDBusObjectPath getUser()
170 message <<
interface() << SYSTEMD_USER_PROPERTY;
174 if (!args.isEmpty()) {
175 NumberedDBusObjectPath numberedPath;
179 return NumberedDBusObjectPath();
181 void getSessionLocation(SessEnt &se)
194 QStringLiteral(
"/org/freedesktop/ConsoleKit/Manager"),
195 QStringLiteral(
"org.freedesktop.ConsoleKit.Manager"),
207 QStringLiteral(
"org.freedesktop.ConsoleKit.Seat"),
219 QStringLiteral(
"org.freedesktop.ConsoleKit.Session"),
223 void getSessionLocation(SessEnt &se)
227 if (r.
isValid() && !r.value().isEmpty()) {
230 se.display = r.value();
247 QStringLiteral(
"/org/gnome/DisplayManager/LocalDisplayFactory"),
248 QStringLiteral(
"org.gnome.DisplayManager.LocalDisplayFactory"),
258 :
QDBusInterface(QStringLiteral(
"org.freedesktop.DisplayManager"),
259 qEnvironmentVariable(
"XDG_SEAT_PATH"),
260 QStringLiteral(
"org.freedesktop.DisplayManager.Seat"),
275static const char *ctl, *dpy;
277class KDisplayManager::Private
293KDisplayManager::KDisplayManager()
297 struct sockaddr_un sa;
299 qDBusRegisterMetaType<NamedDBusObjectPath>();
300 qDBusRegisterMetaType<QList<NamedDBusObjectPath>>();
301 qDBusRegisterMetaType<NumberedDBusObjectPath>();
303 if (DMType == Dunno) {
304 dpy = ::getenv(
"DISPLAY");
305 if (dpy && (ctl = ::getenv(
"DM_CONTROL")))
307 else if (dpy && (ctl = ::getenv(
"XDM_MANAGED")) && ctl[0] ==
'/')
309 else if (::getenv(
"XDG_SEAT_PATH") && LightDMDBus().
isValid())
311 else if (::getenv(
"GDMSESSION"))
312 DMType = GDMFactory().isValid() ? NewGDM : OldGDM;
321 if ((d->fd = ::socket(PF_UNIX, SOCK_STREAM, 0)) < 0)
323 sa.sun_family = AF_UNIX;
324 if (DMType == OldGDM) {
325 strcpy(sa.sun_path,
"/var/run/gdm_socket");
326 if (::connect(d->fd, (
struct sockaddr *)&sa,
sizeof(sa))) {
327 strcpy(sa.sun_path,
"/tmp/.gdm_socket");
328 if (::connect(d->fd, (
struct sockaddr *)&sa,
sizeof(sa))) {
336 if ((ptr = strchr(dpy,
':')))
337 ptr = strchr(ptr,
'.');
338 snprintf(sa.sun_path,
sizeof(sa.sun_path),
"%s/dmctl-%.*s/socket", ctl, ptr ?
int(ptr - dpy) : 512, dpy);
339 if (::connect(d->fd, (
struct sockaddr *)&sa,
sizeof(sa))) {
347 tf.truncate(tf.indexOf(
','));
348 d->fd = ::open(tf.constData(), O_WRONLY);
353KDisplayManager::~KDisplayManager()
358bool KDisplayManager::exec(
const char *cmd)
362 return exec(cmd, buf);
377bool KDisplayManager::exec(
const char *cmd,
QByteArray &buf)
387 if (::write(d->fd, cmd, tl) != tl) {
395 if (DMType == OldKDM) {
400 if (buf.
size() < 128)
402 else if (buf.
size() < len * 2)
404 if ((tl = ::read(d->fd, buf.
data() + len, buf.
size() - len)) <= 0) {
405 if (tl < 0 && errno == EINTR)
410 if (buf[len - 1] ==
'\n') {
412 if (len > 2 && (buf[0] ==
'o' || buf[0] ==
'O') && (buf[1] ==
'k' || buf[1] ==
'K') && buf[2] <=
' ')
425 SystemdSeat seat(*currentSeat);
426 if (seat.property(
"Id").isValid()) {
434 SystemdSession sess(r.value());
435 if (sess.isValid()) {
436 NamedDBusObjectPath namedPath = sess.getSeat();
437 *currentSeat = namedPath.path;
445 CKSession sess(r.value());
446 if (sess.isValid()) {
450 *currentSession = r.value();
451 *currentSeat = r2.value();
463 SystemdSeat seat(path);
464 if (seat.isValid()) {
467 for (
const NamedDBusObjectPath &namedPath : r)
468 result.
append(namedPath.path);
474 if (seat.isValid()) {
487#ifndef KDM_NO_SHUTDOWN
488bool KDisplayManager::canShutdown()
490 if (DMType == NewGDM || DMType == NoDM || DMType == LightDM) {
496 return canStop.value();
500 if (DMType == OldKDM)
501 return strstr(ctl,
",maysd") !=
nullptr;
505 if (DMType == OldGDM)
506 return exec(
"QUERY_LOGOUT_ACTION\n", re) && re.
indexOf(
"HALT") >= 0;
508 return exec(
"caps\n", re) && re.
indexOf(
"\tshutdown") >= 0;
511void KDisplayManager::shutdown(KWorkSpace::ShutdownType shutdownType,
512 KWorkSpace::ShutdownMode shutdownMode,
515 if (shutdownType == KWorkSpace::ShutdownTypeNone || shutdownType == KWorkSpace::ShutdownTypeLogout)
519 if (DMType == NewKDM) {
521 cap_ask = exec(
"caps\n", re) && re.
indexOf(
"\tshutdown ask") >= 0;
526 if (DMType == NewGDM || DMType == NoDM || DMType == LightDM) {
532 bool interactive = (shutdownMode == KWorkSpace::ShutdownModeInteractive || shutdownMode == KWorkSpace::ShutdownModeForceNow);
534 SystemdManager().call(
QLatin1String(shutdownType == KWorkSpace::ShutdownTypeReboot ?
"Reboot" :
"PowerOff"), interactive);
537 CKManager().call(
QLatin1String(shutdownType == KWorkSpace::ShutdownTypeReboot ?
"Restart" :
"Stop"));
545 if (!cap_ask && shutdownMode == KWorkSpace::ShutdownModeInteractive)
546 shutdownMode = KWorkSpace::ShutdownModeForceNow;
549 if (DMType == OldGDM) {
550 cmd.
append(shutdownMode == KWorkSpace::ShutdownModeForceNow ?
"SET_LOGOUT_ACTION " :
"SET_SAFE_LOGOUT_ACTION ");
551 cmd.
append(shutdownType == KWorkSpace::ShutdownTypeReboot ?
"REBOOT\n" :
"HALT\n");
554 cmd.
append(shutdownType == KWorkSpace::ShutdownTypeReboot ?
"reboot\t" :
"halt\t");
557 cmd.
append(shutdownMode == KWorkSpace::ShutdownModeInteractive ?
"ask\n"
558 : shutdownMode == KWorkSpace::ShutdownModeForceNow ?
"forcenow\n"
559 : shutdownMode == KWorkSpace::ShutdownModeTryNow ?
"trynow\n"
565bool KDisplayManager::bootOptions(
QStringList &opts,
int &defopt,
int ¤t)
567 if (DMType != NewKDM)
571 if (!exec(
"listbootoptions\n", re))
579 defopt = opts[2].toInt(&ok);
582 current = opts[3].toInt(&ok);
594bool KDisplayManager::isSwitchable()
596 if (DMType == NewGDM || DMType == LightDM) {
598 if (getCurrentSeat(
nullptr, ¤tSeat)) {
599 SystemdSeat SDseat(currentSeat);
600 if (SDseat.isValid()) {
601 QVariant prop = SDseat.property(
"CanMultiSession");
613 CKSeat CKseat(currentSeat);
614 if (CKseat.isValid()) {
623 if (DMType == OldKDM)
624 return dpy[0] ==
':';
626 if (DMType == OldGDM)
627 return exec(
"QUERY_VT\n");
631 return exec(
"caps\n", re) && re.
indexOf(
"\tlocal") >= 0;
634int KDisplayManager::numReserve()
636 if (DMType == NewGDM || DMType == OldGDM || DMType == LightDM)
639 if (DMType == OldKDM)
640 return strstr(ctl,
",rsvd") ? 1 : -1;
645 if (!(exec(
"caps\n", re) && (p = re.
indexOf(
"\treserve ")) >= 0))
647 return atoi(re.
data() + p + 9);
650void KDisplayManager::startReserve()
652 if (DMType == NewGDM)
653 GDMFactory().call(QStringLiteral(
"CreateTransientDisplay"));
654 else if (DMType == OldGDM)
655 exec(
"FLEXI_XSERVER\n");
656 else if (DMType == LightDM) {
658 lightDM.
call(QStringLiteral(
"SwitchToGreeter"));
663bool KDisplayManager::localSessions(
SessList &list)
665 if (DMType == OldKDM)
668 if (DMType == NewGDM || DMType == LightDM) {
670 if (getCurrentSeat(¤tSession, ¤tSeat)) {
674 const auto sessionsForSeat = getSessionsForSeat(currentSeat);
676 SystemdSession lsess(sp);
677 if (lsess.isValid()) {
679 lsess.getSessionLocation(se);
680 if ((lsess.property(
"Class").toString() !=
QLatin1String(
"greeter"))
681 && (lsess.property(
"State").toString() ==
QLatin1String(
"online")
682 || lsess.property(
"State").toString() ==
QLatin1String(
"active"))) {
683 NumberedDBusObjectPath numberedPath = lsess.getUser();
684 se.display = lsess.property(
"Display").toString();
685 se.vt = lsess.property(
"VTNr").toInt();
692 se.session = QStringLiteral(
"<unknown>");
694 se.self = lsess.property(
"Id").toString() == qEnvironmentVariable(
"XDG_SESSION_ID");
695 se.tty = !lsess.property(
"TTY").toString().isEmpty();
703 const auto sessionsForSeat = getSessionsForSeat(currentSeat);
706 if (lsess.isValid()) {
708 lsess.getSessionLocation(se);
715 se.session = QStringLiteral(
"<unknown>");
717 se.self = (sp == currentSession);
731 if (DMType == OldGDM) {
732 if (!exec(
"CONSOLE_SERVERS\n", re))
740 se.vt = ts[2].toInt();
741 se.session = QStringLiteral(
"<unknown>");
747 if (!exec(
"list\talllocal\n", re))
757 se.self = (ts[4].
indexOf(u
'*') >= 0);
758 se.tty = (ts[4].
indexOf(u
't') >= 0);
765void KDisplayManager::sess2Str2(
const SessEnt &se,
QString &user,
QString &loc)
768 user =
i18nc(
"user: …",
"%1: TTY login", se.user);
769 loc = se.vt ? QStringLiteral(
"vt%1").arg(se.vt) : se.display;
773 ?
i18nc(
"… location (TTY or X display)",
"Unused") : se.session ==
QLatin1String(
"<remote>")
774 ?
i18n(
"X login on remote host") :
i18nc(
"… host",
"X login on %1", se.session)
776 ? se.user :
i18nc(
"user: session type",
"%1: %2", se.user, se.session);
778 loc = se.vt ? QStringLiteral(
"%1, vt%2").arg(se.display).arg(se.vt) : se.display;
782QString KDisplayManager::sess2Str(
const SessEnt &se)
786 sess2Str2(se, user, loc);
787 return i18nc(
"session (location)",
"%1 (%2)", user, loc);
790bool KDisplayManager::switchVT(
int vt)
792 if (DMType == NewGDM || DMType == LightDM) {
794 if (getCurrentSeat(
nullptr, ¤tSeat)) {
797 const auto sessionsForSeat = getSessionsForSeat(currentSeat);
799 SystemdSession lsess(sp);
800 if (lsess.isValid()) {
802 lsess.getSessionLocation(se);
804 lsess.call(SYSTEMD_SWITCH_CALL);
812 const auto sessionsForSeat = getSessionsForSeat(currentSeat);
815 if (lsess.isValid()) {
817 lsess.getSessionLocation(se);
821 lsess.call(QStringLiteral(
"Activate"));
831 if (DMType == OldGDM)
832 return exec(QStringLiteral(
"SET_VT %1\n").arg(vt).toLatin1().constData());
834 return exec(QStringLiteral(
"activate\tvt%1\n").arg(vt).toLatin1().constData());
837void KDisplayManager::lockSwitchVT(
int vt)
840 QDBusInterface screensaver(QStringLiteral(
"org.freedesktop.ScreenSaver"), QStringLiteral(
"/ScreenSaver"), QStringLiteral(
"org.freedesktop.ScreenSaver"));
841 screensaver.call(QStringLiteral(
"Lock"));
846void KDisplayManager::GDMAuthenticate()
850 const char *dpy =
nullptr, *dnum, *dne;
856 dpy = DisplayString(nativeInterface->display());
861 dpy = ::getenv(
"DISPLAY");
865 dnum = strchr(dpy,
':') + 1;
866 dne = strchr(dpy,
'.');
867 dnl = dne ? dne - dnum : strlen(dnum);
870 if (!(fp = fopen(XauFileName(),
"r")))
873 while ((xau = XauReadAuth(fp))) {
874 if (xau->family == FamilyLocal && xau->number_length == dnl && !memcmp(xau->number, dnum, dnl) && xau->data_length == 16 && xau->name_length == 18
875 && !memcmp(xau->name,
"MIT-MAGIC-COOKIE-1", 18)) {
876 QString cmd(QStringLiteral(
"AUTH_LOCAL "));
877 for (
int i = 0; i < 16; i++)
QString loginName() const
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
KCALENDARCORE_EXPORT QDataStream & operator>>(QDataStream &in, const KCalendarCore::Alarm::Ptr &)
QString path(const QString &relativePath)
bool isValid(QStringView ifopt)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
KTEXTEDITOR_EXPORT QDebug operator<<(QDebug s, const MovingCursor &cursor)
QByteArray & append(QByteArrayView data)
const char * constData() const const
qsizetype indexOf(QByteArrayView bv, qsizetype from) const const
void resize(qsizetype newSize, char c)
qsizetype size() const const
QCoreApplication * instance()
QDBusMessage call(QDBus::CallMode mode, const QString &method, Args &&... args)
QString interface() const const
bool isValid() const const
QString path() const const
QString service() const const
QDBusMessage call(const QDBusMessage &message, QDBus::CallMode mode, int timeout) const const
QDBusConnection systemBus()
QList< QVariant > arguments() const const
QDBusMessage createMethodCall(const QString &service, const QString &path, const QString &interface, const QString &method)
bool isValid() const const
void append(QList< T > &&value)
const_iterator constBegin() const const
const_iterator constEnd() const const
void replace(qsizetype i, parameter_type value)
qsizetype size() const const
QVariant property(const char *name) const const
QString fromLocal8Bit(QByteArrayView str)
bool isEmpty() const const
QString number(double n, char format, int precision)
QString rightJustified(qsizetype width, QChar fill, bool truncate) const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QByteArray toLocal8Bit() const const
qsizetype indexOf(const QRegularExpression &re, qsizetype from) const const
QStringView mid(qsizetype start, qsizetype length) const const
int toInt(bool *ok, int base) const const
bool isValid() const const
bool toBool() const const
int toInt(bool *ok) const const
QString toString() const const