Sophie

Sophie

distrib > Fedora > 18 > x86_64 > by-pkgid > d87f6421cea202ad1fc447ea849326ae > files > 7

kde-workspace-4.10.5-3.fc18.src.rpm

--- kde-workspace-4.10.2/libs/kworkspace/kdisplaymanager.cpp.systemd-displaymanager	2013-03-01 07:32:25.116846223 +0100
+++ kde-workspace-4.10.2/libs/kworkspace/kdisplaymanager.cpp	2013-04-29 14:45:05.406859931 +0200
@@ -40,6 +40,166 @@
 #include <errno.h>
 #include <stdio.h>
 
+#define _DBUS_PROPERTIES_IFACE "org.freedesktop.DBus.Properties"
+#define _DBUS_PROPERTIES_GET "Get"
+
+#define DBUS_PROPERTIES_IFACE QLatin1String(_DBUS_PROPERTIES_IFACE)
+#define DBUS_PROPERTIES_GET QLatin1String(_DBUS_PROPERTIES_GET)
+
+#define _SYSTEMD_SERVICE "org.freedesktop.login1"
+#define _SYSTEMD_BASE_PATH "/org/freedesktop/login1"
+#define _SYSTEMD_MANAGER_IFACE _SYSTEMD_SERVICE ".Manager"
+#define _SYSTEMD_SESSION_BASE_PATH _SYSTEMD_BASE_PATH "/Session"
+#define _SYSTEMD_SEAT_IFACE _SYSTEMD_SERVICE ".Seat"
+#define _SYSTEMD_SEAT_BASE_PATH _SYSTEMD_BASE_PATH "/Seat"
+#define _SYSTEMD_SESSION_IFACE _SYSTEMD_SERVICE ".Session"
+#define _SYSTEMD_USER_PROPERTY "User"
+#define _SYSTEMD_SEAT_PROPERTY "Seat"
+#define _SYSTEMD_SESSIONS_PROPERTY "Sessions"
+#define _SYSTEMD_SWITCH_PROPERTY "Activate"
+
+#define SYSTEMD_SERVICE QLatin1String(_SYSTEMD_SERVICE)
+#define SYSTEMD_BASE_PATH QLatin1String(_SYSTEMD_BASE_PATH)
+#define SYSTEMD_MANAGER_IFACE QLatin1String(_SYSTEMD_MANAGER_IFACE)
+#define SYSTEMD_SESSION_BASE_PATH QLatin1String(_SYSTEMD_SESSION_BASE_PATH)
+#define SYSTEMD_SEAT_IFACE QLatin1String(_SYSTEMD_SEAT_IFACE)
+#define SYSTEMD_SEAT_BASE_PATH QLatin1String(_SYSTEMD_SEAT_BASE_PATH)
+#define SYSTEMD_SESSION_IFACE QLatin1String(_SYSTEMD_SESSION_IFACE)
+#define SYSTEMD_USER_PROPERTY QLatin1String(_SYSTEMD_USER_PROPERTY)
+#define SYSTEMD_SEAT_PROPERTY QLatin1String(_SYSTEMD_SEAT_PROPERTY)
+#define SYSTEMD_SESSIONS_PROPERTY QLatin1String(_SYSTEMD_SESSIONS_PROPERTY)
+#define SYSTEMD_SWITCH_CALL QLatin1String(_SYSTEMD_SWITCH_PROPERTY)
+
+struct NamedDBusObjectPath
+{
+    QString name;
+    QDBusObjectPath path;
+};
+Q_DECLARE_METATYPE(NamedDBusObjectPath)
+Q_DECLARE_METATYPE(QList<NamedDBusObjectPath>)
+
+// Marshall the NamedDBusObjectPath data into a D-Bus argument
+QDBusArgument &operator<<(QDBusArgument &argument, const NamedDBusObjectPath &namedPath)
+{
+    argument.beginStructure();
+    argument << namedPath.name << namedPath.path;
+    argument.endStructure();
+    return argument;
+}
+
+// Retrieve the NamedDBusObjectPath data from the D-Bus argument
+const QDBusArgument &operator>>(const QDBusArgument &argument, NamedDBusObjectPath &namedPath)
+{
+    argument.beginStructure();
+    argument >> namedPath.name >> namedPath.path;
+    argument.endStructure();
+    return argument;
+}
+
+struct NumberedDBusObjectPath
+{
+    uint num;
+    QDBusObjectPath path;
+};
+Q_DECLARE_METATYPE(NumberedDBusObjectPath)
+
+// Marshall the NumberedDBusObjectPath data into a D-Bus argument
+QDBusArgument &operator<<(QDBusArgument &argument, const NumberedDBusObjectPath &numberedPath)
+{
+    argument.beginStructure();
+    argument << numberedPath.num << numberedPath.path;
+    argument.endStructure();
+    return argument;
+}
+
+// Retrieve the NumberedDBusObjectPath data from the D-Bus argument
+const QDBusArgument &operator>>(const QDBusArgument &argument, NumberedDBusObjectPath &numberedPath)
+{
+    argument.beginStructure();
+    argument >> numberedPath.num >> numberedPath.path;
+    argument.endStructure();
+    return argument;
+}
+
+class SystemdManager : public QDBusInterface
+{
+public:
+    SystemdManager() :
+        QDBusInterface(
+                SYSTEMD_SERVICE,
+                SYSTEMD_BASE_PATH,
+                SYSTEMD_MANAGER_IFACE,
+                QDBusConnection::systemBus()) {}
+};
+
+class SystemdSeat : public QDBusInterface
+{
+public:
+    SystemdSeat(const QDBusObjectPath &path) :
+        QDBusInterface(
+                SYSTEMD_SERVICE,
+                path.path(),
+                SYSTEMD_SEAT_IFACE,
+                QDBusConnection::systemBus()) {}
+    /* HACK to be able to extract a(so) type from QDBus, property doesn't do the trick */
+    QList<NamedDBusObjectPath> getSessions() {
+        QDBusMessage message = QDBusMessage::createMethodCall(service(), path(), DBUS_PROPERTIES_IFACE, DBUS_PROPERTIES_GET);
+        message <<  interface() << SYSTEMD_SESSIONS_PROPERTY;
+        QDBusMessage reply = QDBusConnection::systemBus().call(message);
+
+        QVariantList args = reply.arguments();
+        if (!args.isEmpty()) {
+            QList<NamedDBusObjectPath> namedPathList = qdbus_cast< QList<NamedDBusObjectPath> >(args.at(0).value<QDBusVariant>().variant().value<QDBusArgument>());
+            return namedPathList;
+        }
+        return QList<NamedDBusObjectPath>();
+    }
+};
+
+class SystemdSession : public QDBusInterface
+{
+public:
+    SystemdSession(const QDBusObjectPath &path) :
+        QDBusInterface(
+                SYSTEMD_SERVICE,
+                path.path(),
+                SYSTEMD_SESSION_IFACE,
+                QDBusConnection::systemBus()) {}
+    /* HACK to be able to extract (so) type from QDBus, property doesn't do the trick */
+    NamedDBusObjectPath getSeat() {
+        QDBusMessage message = QDBusMessage::createMethodCall(service(), path(), DBUS_PROPERTIES_IFACE, DBUS_PROPERTIES_GET);
+        message <<  interface() <<  SYSTEMD_SEAT_PROPERTY;
+        QDBusMessage reply = QDBusConnection::systemBus().call(message);
+
+        QVariantList args = reply.arguments();
+        if (!args.isEmpty()) {
+            NamedDBusObjectPath namedPath;
+            args.at(0).value<QDBusVariant>().variant().value<QDBusArgument>() >> namedPath;
+            return namedPath;
+        }
+        return NamedDBusObjectPath();
+    }
+    NumberedDBusObjectPath getUser() {
+        QDBusMessage message = QDBusMessage::createMethodCall(service(), path(), DBUS_PROPERTIES_IFACE, DBUS_PROPERTIES_GET);
+        message <<  interface() <<  SYSTEMD_USER_PROPERTY;
+        QDBusMessage reply = QDBusConnection::systemBus().call(message);
+
+        QVariantList args = reply.arguments();
+        if (!args.isEmpty()) {
+            NumberedDBusObjectPath numberedPath;
+            args.at(0).value<QDBusVariant>().variant().value<QDBusArgument>() >> numberedPath;
+            return numberedPath;
+        }
+        return NumberedDBusObjectPath();
+    }
+    void getSessionLocation(SessEnt &se)
+    {
+        se.tty = (property("Type").toString() != QLatin1String("x11"));
+        se.display = property(se.tty ? "TTY" : "Display").toString();
+        se.vt = property("VTNr").toInt();
+    }
+};
+
 class CKManager : public QDBusInterface
 {
 public:
@@ -68,9 +228,26 @@
     CKSession(const QDBusObjectPath &path) :
         QDBusInterface(
                 QLatin1String("org.freedesktop.ConsoleKit"),
-            path.path(),
+                path.path(),
                 QLatin1String("org.freedesktop.ConsoleKit.Session"),
                 QDBusConnection::systemBus()) {}
+    void getSessionLocation(SessEnt &se)
+    {
+        QString tty;
+        QDBusReply<QString> r = call(QLatin1String("GetX11Display"));
+        if (r.isValid() && !r.value().isEmpty()) {
+            QDBusReply<QString> r2 = call(QLatin1String("GetX11DisplayDevice"));
+            tty = r2.value();
+            se.display = r.value();
+            se.tty = false;
+        } else {
+            QDBusReply<QString> r2 = call(QLatin1String("GetDisplayDevice"));
+            tty = r2.value();
+            se.display = tty;
+            se.tty = true;
+        }
+        se.vt = tty.mid(strlen("/dev/tty")).toInt();
+    }
 };
 
 class GDMFactory : public QDBusInterface
@@ -115,6 +292,10 @@
     const char *ptr;
     struct sockaddr_un sa;
 
+    qDBusRegisterMetaType<NamedDBusObjectPath>();
+    qDBusRegisterMetaType<QList<NamedDBusObjectPath> >();
+    qDBusRegisterMetaType<NumberedDBusObjectPath>();
+
     if (DMType == Dunno) {
         if (!(dpy = ::getenv("DISPLAY")))
             DMType = NoDM;
@@ -242,17 +423,31 @@
 
 static bool getCurrentSeat(QDBusObjectPath *currentSession, QDBusObjectPath *currentSeat)
 {
-    CKManager man;
-    QDBusReply<QDBusObjectPath> r = man.call(QLatin1String("GetCurrentSession"));
+    SystemdManager man;
+    QDBusReply<QDBusObjectPath> r = man.call(QLatin1String("GetSessionByPID"), (uint) QCoreApplication::applicationPid());
     if (r.isValid()) {
-        CKSession sess(r.value());
+        SystemdSession sess(r.value());
         if (sess.isValid()) {
-            QDBusReply<QDBusObjectPath> r2 = sess.call(QLatin1String("GetSeatId"));
-            if (r2.isValid()) {
-                if (currentSession)
-                    *currentSession = r.value();
-                *currentSeat = r2.value();
-                return true;
+            NamedDBusObjectPath namedPath = sess.getSeat();
+            if (currentSession)
+                *currentSession = r.value();
+            *currentSeat = namedPath.path;
+            return true;
+        }
+    }
+    else {
+        CKManager man;
+        QDBusReply<QDBusObjectPath> r = man.call(QLatin1String("GetCurrentSession"));
+        if (r.isValid()) {
+            CKSession sess(r.value());
+            if (sess.isValid()) {
+                QDBusReply<QDBusObjectPath> r2 = sess.call(QLatin1String("GetSeatId"));
+                if (r2.isValid()) {
+                    if (currentSession)
+                        *currentSession = r.value();
+                    *currentSeat = r2.value();
+                    return true;
+                }
             }
         }
     }
@@ -261,44 +456,44 @@
 
 static QList<QDBusObjectPath> getSessionsForSeat(const QDBusObjectPath &path)
 {
-    CKSeat seat(path);
-    if (seat.isValid()) {
-        QDBusReply<QList<QDBusObjectPath> > r = seat.call(QLatin1String("GetSessions"));
-        if (r.isValid()) {
-            // This will contain only local sessions:
-            // - this is only ever called when isSwitchable() is true => local seat
-            // - remote logins into the machine are assigned to other seats
-            return r.value();
+    if (path.path().startsWith(SYSTEMD_BASE_PATH)) { // systemd path incoming
+        SystemdSeat seat(path);
+        if (seat.isValid()) {
+            QList<NamedDBusObjectPath> r = seat.getSessions();
+            QList<QDBusObjectPath> result;
+            foreach (const NamedDBusObjectPath &namedPath, r)
+                result.append(namedPath.path);
+            // This pretty much can't contain any other than local sessions as the seat is retrieved from the current session
+            return result;
+        }
+    }
+    else if (path.path().startsWith("/org/freedesktop/ConsoleKit")) {
+        CKSeat seat(path);
+        if (seat.isValid()) {
+            QDBusReply<QList<QDBusObjectPath> > r = seat.call(QLatin1String("GetSessions"));
+            if (r.isValid()) {
+                // This will contain only local sessions:
+                // - this is only ever called when isSwitchable() is true => local seat
+                // - remote logins into the machine are assigned to other seats
+                return r.value();
+            }
         }
     }
     return QList<QDBusObjectPath>();
 }
 
-static void getSessionLocation(CKSession &lsess, SessEnt &se)
-{
-    QString tty;
-    QDBusReply<QString> r = lsess.call(QLatin1String("GetX11Display"));
-    if (r.isValid() && !r.value().isEmpty()) {
-        QDBusReply<QString> r2 = lsess.call(QLatin1String("GetX11DisplayDevice"));
-        tty = r2.value();
-        se.display = r.value();
-        se.tty = false;
-    } else {
-        QDBusReply<QString> r2 = lsess.call(QLatin1String("GetDisplayDevice"));
-        tty = r2.value();
-        se.display = tty;
-        se.tty = true;
-    }
-    se.vt = tty.mid(strlen("/dev/tty")).toInt();
-}
-
 #ifndef KDM_NO_SHUTDOWN
 bool
 KDisplayManager::canShutdown()
 {
     if (DMType == NewGDM || DMType == NoDM || DMType == LightDM) {
+        QDBusReply<QString> canPowerOff = SystemdManager().call(QLatin1String("CanPowerOff"));
+        if (canPowerOff.isValid())
+            return canPowerOff.value() != QLatin1String("no");
         QDBusReply<bool> canStop = CKManager().call(QLatin1String("CanStop"));
-        return (canStop.isValid() && canStop.value());
+        if (canStop.isValid())
+            return canStop.value();
+        return false;
     }
 
     if (DMType == OldKDM)
@@ -329,9 +524,21 @@
             return;
 
         if (DMType == NewGDM || DMType == NoDM || DMType == LightDM) {
-            // FIXME: entirely ignoring shutdownMode
-            CKManager().call(QLatin1String(
-                    shutdownType == KWorkSpace::ShutdownTypeReboot ? "Restart" : "Stop"));
+            // systemd supports only 2 modes:
+            // * interactive = true: brings up a PolicyKit prompt if other sessions are active
+            // * interactive = false: rejects the shutdown if other sessions are active
+            // There are no schedule or force modes.
+            // We try to map our 4 shutdown modes in the sanest way.
+            bool interactive = (shutdownMode == KWorkSpace::ShutdownModeInteractive
+                                || shutdownMode == KWorkSpace::ShutdownModeForceNow);
+            QDBusReply<QString> check = SystemdManager().call(QLatin1String(
+                    shutdownType == KWorkSpace::ShutdownTypeReboot ? "Reboot" : "PowerOff"), interactive);
+            if (!check.isValid()) {
+                // FIXME: entirely ignoring shutdownMode
+                CKManager().call(QLatin1String(
+                        shutdownType == KWorkSpace::ShutdownTypeReboot ? "Restart" : "Stop"));
+                // if even CKManager call fails, there is nothing more to be done
+            }
             return;
         }
 
@@ -406,9 +613,15 @@
     if (DMType == NewGDM || DMType == LightDM) {
         QDBusObjectPath currentSeat;
         if (getCurrentSeat(0, &currentSeat)) {
-            CKSeat seat(currentSeat);
-            if (seat.isValid()) {
-                QDBusReply<bool> r = seat.call(QLatin1String("CanActivateSessions"));
+            SystemdSeat SDseat(currentSeat);
+            if (SDseat.isValid()) {
+                QVariant prop = SDseat.property("CanMultiSession");
+                if (prop.isValid())
+                    return prop.toBool();
+            }
+            CKSeat CKseat(currentSeat);
+            if (CKseat.isValid()) {
+                QDBusReply<bool> r = CKseat.call(QLatin1String("CanActivateSessions"));
                 if (r.isValid())
                     return r.value();
             }
@@ -465,26 +678,61 @@
     if (DMType == OldKDM)
         return false;
 
-    if (DMType == NewGDM || DMType == LightDM) {
+    // FIXME TODO WARNING HACK beware of this workaround, will get rid of it in a few days (if it's not spring 2013 and this line is still here, please smack mbriza-at-redhat-dot-com)
+    if (DMType != OldGDM) {
         QDBusObjectPath currentSession, currentSeat;
         if (getCurrentSeat(&currentSession, &currentSeat)) {
-            foreach (const QDBusObjectPath &sp, getSessionsForSeat(currentSeat)) {
-                CKSession lsess(sp);
-                if (lsess.isValid()) {
-                    SessEnt se;
-                    getSessionLocation(lsess, se);
-                    // "Warning: we haven't yet defined the allowed values for this property.
-                    // It is probably best to avoid this until we do."
-                    QDBusReply<QString> r = lsess.call(QLatin1String("GetSessionType"));
-                    if (r.value() != QLatin1String("LoginWindow")) {
-                        QDBusReply<unsigned> r2 = lsess.call(QLatin1String("GetUnixUser"));
-                        se.user = KUser(K_UID(r2.value())).loginName();
-                        se.session = "<unknown>";
+            // we'll divide the code in two branches to reduce the overhead of calls to non-existent services
+            // systemd part // preferred
+            if (QDBusConnection::systemBus().interface()->isServiceRegistered(SYSTEMD_SERVICE)) {
+                foreach (const QDBusObjectPath &sp, getSessionsForSeat(currentSeat)) {
+                    SystemdSession lsess(sp);
+                    if (lsess.isValid()) {
+                        SessEnt se;
+                        lsess.getSessionLocation(se);
+                        if ((lsess.property("Class").toString() != QLatin1String("greeter")) &&
+                             (lsess.property("State").toString() == QLatin1String("online") ||
+                              lsess.property("State").toString() == QLatin1String("active"))) {
+                            NumberedDBusObjectPath numberedPath = lsess.getUser();
+                            se.display = lsess.property("Display").toString();
+                            se.vt = lsess.property("VTNr").toInt();
+                            se.user = KUser(K_UID(numberedPath.num)).loginName();
+                            /* TODO:
+                             * regarding the session name in this, it IS possible to find it out - logind tracks the session leader PID
+                             * the problem is finding out the name of the process, I could come only with reading /proc/PID/comm which
+                             * doesn't seem exactly... right to me --mbriza
+                             */
+                            se.session = "<unknown>";
+                            se.self = lsess.property("Display").toString() == ::getenv("DISPLAY"); /* Bleh once again */
+                            se.tty = !lsess.property("TTY").toString().isEmpty();
+                        }
+                        list.append(se);
+                    }
+                }
+            }
+            // ConsoleKit part
+            else if (QDBusConnection::systemBus().interface()->isServiceRegistered("org.freedesktop.ConsoleKit")) {
+                foreach (const QDBusObjectPath &sp, getSessionsForSeat(currentSeat)) {
+                    CKSession lsess(sp);
+                    if (lsess.isValid()) {
+                        SessEnt se;
+                        lsess.getSessionLocation(se);
+                        // "Warning: we haven't yet defined the allowed values for this property.
+                        // It is probably best to avoid this until we do."
+                        QDBusReply<QString> r = lsess.call(QLatin1String("GetSessionType"));
+                        if (r.value() != QLatin1String("LoginWindow")) {
+                            QDBusReply<unsigned> r2 = lsess.call(QLatin1String("GetUnixUser"));
+                            se.user = KUser(K_UID(r2.value())).loginName();
+                            se.session = "<unknown>";
+                        }
+                        se.self = (sp == currentSession);
+                        list.append(se);
                     }
-                    se.self = (sp == currentSession);
-                    list.append(se);
                 }
             }
+            else {
+                return false;
+            }
             return true;
         }
         return false;
@@ -507,21 +755,6 @@
             se.tty = false;
             list.append(se);
         }
-    } else {
-        if (!exec("list\talllocal\n", re))
-            return false;
-        const QStringList sess = QString(re.data() + 3).split(QChar('\t'), QString::SkipEmptyParts);
-        for (QStringList::ConstIterator it = sess.constBegin(); it != sess.constEnd(); ++it) {
-            QStringList ts = (*it).split(QChar(','));
-            SessEnt se;
-            se.display = ts[0];
-            se.vt = ts[1].mid(2).toInt();
-            se.user = ts[2];
-            se.session = ts[3];
-            se.self = (ts[4].indexOf('*') >= 0);
-            se.tty = (ts[4].indexOf('t') >= 0);
-            list.append(se);
-        }
     }
     return true;
 }
@@ -563,14 +796,35 @@
 bool
 KDisplayManager::switchVT(int vt)
 {
-    if (DMType == NewGDM || DMType == LightDM) {
-        QDBusObjectPath currentSeat;
-        if (getCurrentSeat(0, &currentSeat)) {
+    if (DMType == OldKDM)
+        return exec(QString("activate\tvt%1\n").arg(vt).toLatin1());
+
+    if (DMType == OldGDM)
+        return exec(QString("SET_VT %1\n").arg(vt).toLatin1());
+
+    QDBusObjectPath currentSeat;
+    if (getCurrentSeat(0, &currentSeat)) {
+        // systemd part // preferred
+        if (QDBusConnection::systemBus().interface()->isServiceRegistered(SYSTEMD_SERVICE)) {
+            foreach (const QDBusObjectPath &sp, getSessionsForSeat(currentSeat)) {
+                SystemdSession lsess(sp);
+                if (lsess.isValid()) {
+                    SessEnt se;
+                    lsess.getSessionLocation(se);
+                    if (se.vt == vt) {
+                        lsess.call(SYSTEMD_SWITCH_CALL);
+                        return true;
+                    }
+                }
+            }
+        }
+        // ConsoleKit part
+        else if (QDBusConnection::systemBus().interface()->isServiceRegistered("org.freedesktop.ConsoleKit")) {
             foreach (const QDBusObjectPath &sp, getSessionsForSeat(currentSeat)) {
                 CKSession lsess(sp);
                 if (lsess.isValid()) {
                     SessEnt se;
-                    getSessionLocation(lsess, se);
+                    lsess.getSessionLocation(se);
                     if (se.vt == vt) {
                         if (se.tty) // ConsoleKit simply ignores these
                             return false;
@@ -580,13 +834,8 @@
                 }
             }
         }
-        return false;
     }
-
-    if (DMType == OldGDM)
-        return exec(QString("SET_VT %1\n").arg(vt).toLatin1());
-
-    return exec(QString("activate\tvt%1\n").arg(vt).toLatin1());
+    return false;
 }
 
 void