/* BEGIN_COMMON_COPYRIGHT_HEADER * (c)LGPL2+ * Copyright: 2019 Tianjin KYLIN Information Technology Co., Ltd. * 2012 Razor team * Authors: * Christian Surlykke * * This program or library is free software; you can redistribute it * and/or modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General * Public License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA * * END_COMMON_COPYRIGHT_HEADER */ #include "powerprovider.h" #include #include #include #include #include #include #include #include #include #include //#include "loginedusers.h" #define LIGHTDM_SERVICE "org.freedesktop.DisplayManager" #define LIGTHDM_INTERFACE "org.freedesktop.DisplayManager.Seat" #define SYSTEMD_SERVICE "org.freedesktop.login1" #define SYSTEMD_PATH "/org/freedesktop/login1" #define SYSTEMD_INTERFACE "org.freedesktop.login1.Manager" #define UKUI_SERVICE "org.gnome.SessionManager" #define UKUI_PATH "/org/gnome/SessionManager" #define UKUI_INTERFACE "org.gnome.SessionManager" #define PROPERTIES_INTERFACE "org.freedesktop.DBus.Properties" bool messageBoxCheck() { QMessageBox msgBox; // msgBox.setWindowTitle(QObject::tr("conform")); msgBox.setIcon(QMessageBox::Warning); msgBox.setWindowFlags(Qt::WindowStaysOnTopHint); // msgBox.setModal(false); msgBox.setText(QObject::tr("some applications are running and they don't want you to do this.")); QPushButton *stillButton = msgBox.addButton(QObject::tr("Still to do!"), QMessageBox::ActionRole); QPushButton *giveupButton = msgBox.addButton(QObject::tr("give up"), QMessageBox::RejectRole); // QStringList usrlist = getLoginedUsers(); // QList::Iterator it = usrlist.begin(),itend = usrlist.end(); // for(;it != itend;it++){ // qDebug()<<*it; // } msgBox.exec(); if (msgBox.clickedButton() == stillButton) { qDebug() << "Still to do!"; return true; } else if (msgBox.clickedButton() == giveupButton) { qDebug() << "give up"; return false; } else { return false; } } static bool dbusCall(const QString &service, const QString &path, const QString &interface, const QDBusConnection &connection, const QString &method) { QDBusInterface dbus(service, path, interface, connection); if (!dbus.isValid()) { qWarning() << "dbusCall: QDBusInterface is invalid" << service << path << interface << method; return false; } QDBusMessage msg = dbus.call(method); if (!msg.errorName().isEmpty()) { qWarning() << "Dbus error: " << msg; } return msg.arguments().isEmpty() || msg.arguments().constFirst().isNull() || msg.arguments().constFirst().toBool(); } static bool dbusCallSystemd(const QString &service, const QString &path, const QString &interface, const QDBusConnection &connection, const QString &method, bool needBoolArg) { QDBusInterface dbus(service, path, interface, connection); if (!dbus.isValid()) { qWarning() << "dbusCall: QDBusInterface is invalid" << service << path << interface << method; return false; } // QDBusMessage msg = dbus.call(method, needBoolArg ? QVariant(true) : QVariant()); // 在华为相关的机器上,如果调用的method没有参数,但仍传入一个空值,会调用失败 QDBusMessage msg; if (needBoolArg) { msg = dbus.call(method, QVariant(true)); } else { msg = dbus.call(method); } if (!msg.errorName().isEmpty()) { qWarning() << "Debus error: " << msg; } if (msg.arguments().isEmpty() || msg.arguments().constFirst().isNull()) { return false; } QString response = msg.arguments().constFirst().toString(); qDebug() << "systemd:" << method << "=" << response; // this need to be resolved: // while canReboot and canPoweroff return challenge,users click Reboot or shutdown, // we call logout ,then Reboot(true) and Poweroff(true) is called, // if user click cancel in the polkit messagebox,then Reboot or Poweroff is canceled, // but logout has been executed. return response == QLatin1String("yes"); //|| response == QLatin1String("challenge"); } bool dbusGetProperty(const QString &service, const QString &path, const QString &interface, const QDBusConnection &connection, const QString &property) { QDBusInterface dbus(service, path, interface, connection); if (!dbus.isValid()) { qWarning() << "dbusGetProperty: QDBusinterface is invalid" << service << path << interface << property; return false; } // QDBusMessage msg = dbus.call("SwitchToGreeter");//QLatin1String("Get"), dbus.interface(),property // if (!msg.errorName().isEmpty()) { // qWarning() << "Dbus error: " << msg; // } // return !msg.arguments().isEmpty() && // msg.arguments().constFirst().value().variant().toBool(); QVariant canswitch = dbus.property("CanSwitch"); qDebug() << property << "=" << canswitch.toString(); return canswitch.toBool(); } PowerProvider::PowerProvider(QObject *parent) : QObject(parent) { } PowerProvider::~PowerProvider() { } /************************************************ SystemdProvider http://www.freedesktop.org/wiki/Software/systemd/logind ************************************************/ SystemdProvider::SystemdProvider(QObject *parent): PowerProvider(parent) { } SystemdProvider::~SystemdProvider() { } bool SystemdProvider::canSwitchUser() const { QString property = "CanSwitch"; QString xdg_seat_path = qgetenv("XDG_SEAT_PATH"); return dbusGetProperty(QLatin1String(LIGHTDM_SERVICE), xdg_seat_path, QLatin1String(LIGTHDM_INTERFACE), QDBusConnection::systemBus(), property); } bool SystemdProvider::canAction(UkuiPower::Action action) const { QString command; switch (action) { case UkuiPower::PowerSwitchUser: return canSwitchUser(); case UkuiPower::PowerReboot: command = QLatin1String("CanReboot"); break; case UkuiPower::PowerShutdown: command = QLatin1String("CanPowerOff"); break; case UkuiPower::PowerSuspend: command = QLatin1String("CanSuspend"); break; case UkuiPower::PowerHibernate: command = QLatin1String("CanHibernate"); break; default: return false; } // canAction should be always silent because it can freeze // g_main_context_iteration Qt event loop in QMessageBox // on panel startup if there is no DBUS running. return dbusCallSystemd(QLatin1String(SYSTEMD_SERVICE), QLatin1String(SYSTEMD_PATH), QLatin1String(SYSTEMD_INTERFACE), QDBusConnection::systemBus(), command, false); } bool SystemdProvider::doSwitchUser() { bool isinhibited =false; QDBusInterface *interface = new QDBusInterface( "org.gnome.SessionManager", "/org/gnome/SessionManager", "org.gnome.SessionManager", QDBusConnection::sessionBus()); quint32 inhibit_switchuser = 2; QDBusReply reply = interface->call("IsInhibited",inhibit_switchuser); if (reply.isValid()) { // use the returned value qDebug() << "Is inhibit by someone: " << reply.value(); isinhibited = reply.value(); } else { qDebug() << reply.value(); } if (isinhibited == true) { isinhibited = !messageBoxCheck(); } if (isinhibited == false) { // QDBusInterface dbus("org.ukui.KWin", "/Compositor", "org.ukui.kwin.Compositing", QDBusConnection::sessionBus()); // if (!dbus.isValid()) { // qWarning() << "dbusCall: QDBusInterface is invalid"; // return false; // } // dbus.call("suspend"); QString command = "SwitchToGreeter"; QString xdg_seat_path = qgetenv("XDG_SEAT_PATH"); return dbusCall(QLatin1String(LIGHTDM_SERVICE), xdg_seat_path, QLatin1String(LIGTHDM_INTERFACE), QDBusConnection::systemBus(), command); } return false; } bool SystemdProvider::doAction(UkuiPower::Action action) { QString command; switch (action) { case UkuiPower::PowerSwitchUser: return doSwitchUser(); case UkuiPower::PowerReboot: command = QLatin1String("Reboot"); break; case UkuiPower::PowerShutdown: command = QLatin1String("PowerOff"); break; case UkuiPower::PowerSuspend: command = QLatin1String("Suspend"); break; case UkuiPower::PowerHibernate: command = QLatin1String("Hibernate"); break; default: return false; } return dbusCallSystemd(QLatin1String(SYSTEMD_SERVICE), QLatin1String(SYSTEMD_PATH), QLatin1String(SYSTEMD_INTERFACE), QDBusConnection::systemBus(), command, true); } UKUIProvider::UKUIProvider(QObject *parent): PowerProvider (parent) { } UKUIProvider::~UKUIProvider() { } bool UKUIProvider::canAction(UkuiPower::Action action) const { //这里是调用ukui-session注册的d-bus检测是否有inhibitor存在 bool isinhibited = false; QDBusInterface *interface = new QDBusInterface("org.gnome.SessionManager", "/org/gnome/SessionManager", "org.gnome.SessionManager", QDBusConnection::sessionBus()); quint32 inhibit_logout = 1; QDBusReply reply = interface->call("IsInhibited", inhibit_logout); if (reply.isValid()) { // use the returned value qDebug() << "Is inhibit by someone: " << reply.value(); isinhibited = reply.value(); } else { qDebug() << reply.value(); } if (isinhibited == true) { isinhibited = !messageBoxCheck(); } return !isinhibited; } bool UKUIProvider::doAction(UkuiPower::Action action) { QString command; switch (action) { case UkuiPower::PowerLogout: command = QLatin1String("logout"); break; case UkuiPower::PowerReboot: command = QLatin1String("reboot"); break; case UkuiPower::PowerShutdown: command = QLatin1String("powerOff"); break; default: return false; } qDebug() << "ukuipowerprovider call D-Bus session"; return dbusCall(QLatin1String(UKUI_SERVICE), QLatin1String(UKUI_PATH), QLatin1String(UKUI_INTERFACE), QDBusConnection::sessionBus(), command); }