/************************************************************************** * Copyright (C) 2006-2007 by Danny Kukawka * * , * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of version 2 of the GNU General Public License * * as published by the Free Software Foundation. * * * * This program 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 General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ /*! * \file dbusInterface.cpp * \brief In this file can be found the functionality to connect to * the D-Bus, to handle D-Bus session management * \author Danny Kukawka, , * \date 2006-2007 */ #ifdef HAVE_CONFIG_H #include #endif // TQt - Header #include // KDE Header #include // DBUS - Header #include "dbus/dbus-shared.h" #include "dbusInterface.h" #include #include #include #include #include // system headers #include #define DBUS_CONN_NAME "TDEPowersave" static void* myInstance = 0; /*! The default constructor of the class dbusInterface. */ dbusInterface::dbusInterface(): dBusConn(), dBusWatch(0), dBusLocal(0), systemdSession(), systemdSeat(0), systemdInhibit(-1), consolekitSession(), consolekitSeat(0) { kdDebugFuncIn(trace); // add pointer to this for filter_function() myInstance=this; // init connection to dbus initDBUS(); kdDebugFuncOut(trace); } /*! This is the default destructor of class dbusPowersaveConnection. */ dbusInterface::~dbusInterface(){ kdDebugFuncIn(trace); close(); myInstance = NULL; kdDebugFuncOut(trace); } /*! * This function return information about connection status to the DBUS daemon. * \return boolean with the state of the connection to D-Bus * \retval true if connected * \retval false if disconnected */ bool dbusInterface::isConnectedToDBUS() { return dBusConn.isConnected(); } /*! * This function try a reconnect to D-Bus. * \return boolean with the result of the operation * \retval true if successful reconnected to D-Bus * \retval false if unsuccessful */ bool dbusInterface::reconnect() { // close D-Bus connection close(); // init D-Bus conntection return (initDBUS()); } /*! * This function close the connection to powersave over the D-Bus daemon. * \return boolean with the result of the operation * \retval true if successful closed the connection * \retval false if any problems */ bool dbusInterface::close() { if( dBusConn.isConnected() ) { if( dBusWatch ) { delete dBusWatch; } if( dBusLocal ) { delete dBusLocal; } if( systemdSeat ) { delete systemdSeat; } if( consolekitSeat ) { delete consolekitSeat; } } dBusConn.closeConnection(DBUS_CONN_NAME); return true; } /*! * This function initialise the connection to the D-Bus daemon. * \return boolean with the result of the operation * \retval true if successful initialised D-Bus connection * \retval false if unsuccessful */ bool dbusInterface::initDBUS(){ kdDebugFuncIn(trace); dBusConn = TQT_DBusConnection::addConnection(TQT_DBusConnection::SystemBus, DBUS_CONN_NAME); if( !dBusConn.isConnected() ) { kdError() << "Failed to open connection to system message bus: " << dBusConn.lastError().message() << endl; TQTimer::singleShot(4000, this, TQ_SLOT(reconnect())); return false; } // watcher for NameOwnerChanged signals dBusWatch = new TQT_DBusProxy(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, dBusConn); TQObject::connect(dBusWatch, TQ_SIGNAL(dbusSignal(const TQT_DBusMessage&)), this, TQ_SLOT(handleDBusSignal(const TQT_DBusMessage&))); // watcher for Disconnect signal dBusLocal = new TQT_DBusProxy(DBUS_SERVICE_DBUS, DBUS_PATH_LOCAL, DBUS_INTERFACE_LOCAL, dBusConn); TQObject::connect(dBusLocal, TQ_SIGNAL(dbusSignal(const TQT_DBusMessage&)), this, TQ_SLOT(handleDBusSignal(const TQT_DBusMessage&))); // find already running SystemD TQT_DBusProxy checkSystemD(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, dBusConn); if( checkSystemD.canSend() ) { TQValueList params; params << TQT_DBusData::fromString(SYSTEMD_LOGIN1_SERVICE); TQT_DBusMessage reply = checkSystemD.sendWithReply("NameHasOwner", params); if (reply.type() == TQT_DBusMessage::ReplyMessage && reply.count() == 1 && reply[0].toBool() ) { onServiceRegistered(SYSTEMD_LOGIN1_SERVICE); } } // find already running ConsoleKit TQT_DBusProxy checkConsoleKit(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, dBusConn); if( checkConsoleKit.canSend() ) { TQValueList params; params << TQT_DBusData::fromString(CK_SERVICE); TQT_DBusMessage reply = checkConsoleKit.sendWithReply("NameHasOwner", params); if (reply.type() == TQT_DBusMessage::ReplyMessage && reply.count() == 1 && reply[0].toBool() ) { onServiceRegistered(CK_SERVICE); } } kdDebugFuncOut(trace); return true; } /*! * This function handles signals from the D-Bus daemon. */ void dbusInterface::handleDBusSignal(const TQT_DBusMessage& msg) { // dbus terminated if( msg.path() == DBUS_PATH_LOCAL && msg.interface() == DBUS_INTERFACE_LOCAL && msg.member() == "Disconnected" ) { close(); TQTimer::singleShot(1000, this, TQ_SLOT(reconnect())); return; } // service registered / unregistered if( msg.path() == DBUS_PATH_DBUS && msg.interface() == DBUS_INTERFACE_DBUS && msg.member() == "NameOwnerChanged" ) { if( msg[1].toString().isEmpty() ) { // old-owner is empty onServiceRegistered(msg[0].toString()); } if( msg[2].toString().isEmpty() ) { // new-owner is empty onServiceUnregistered(msg[0].toString()); } return; } // systemd session changed if( systemdSeat && systemdSeat->canSend() && msg.path() == systemdSeat->path() && msg.interface() == DBUS_INTERFACE_PROPERTIES && msg.member() == "PropertiesChanged" && msg[0].toString() == SYSTEMD_LOGIN1_SEAT_IFACE) { bool activeSessionProperty = false; TQT_DBusDataMap map = msg[1].toStringKeyMap(); TQT_DBusDataMap::const_iterator it = map.begin(); for (; !activeSessionProperty && it != map.end(); ++it) { if( it.key() != "ActiveSession" ) { activeSessionProperty = true; } } TQValueList list = msg[2].toList().toStringList(); TQValueList::const_iterator it1 = list.begin(); for (; !activeSessionProperty && it1 != list.end(); ++it1) { if( (*it1) == "ActiveSession" ) { activeSessionProperty = true; } } if( activeSessionProperty ) { emit activeSessionChanged(checkActiveSession()); } return; } // consolekit session changed if( consolekitSeat && consolekitSeat->canSend() && msg.path() == consolekitSeat->path() && msg.interface() == CK_SEAT_IFACE && msg.member() == "ActiveSessionChanged") { emit activeSessionChanged(msg[0].toString() == TQString(consolekitSession)); return; } } /*! * This function handles dBus service registering */ void dbusInterface::onServiceRegistered(const TQString& service) { if( service == SYSTEMD_LOGIN1_SERVICE ) { // get current session TQT_DBusProxy managerIface(SYSTEMD_LOGIN1_SERVICE, SYSTEMD_LOGIN1_PATH, SYSTEMD_LOGIN1_MANAGER_IFACE, dBusConn); systemdSession = TQT_DBusObjectPath(); if( managerIface.canSend() ) { TQValueList params; params << TQT_DBusData::fromUInt32( getpid() ); TQT_DBusMessage reply = managerIface.sendWithReply("GetSessionByPID", params); if (reply.type() == TQT_DBusMessage::ReplyMessage && reply.count() == 1 ) { systemdSession = reply[0].toObjectPath(); } } if( !systemdSession.isValid() ) { kdWarning() << "The session is not registered with systemd" << endl; return; } // get session seat TQT_DBusProxy sessionProperties(SYSTEMD_LOGIN1_SERVICE, systemdSession, DBUS_INTERFACE_PROPERTIES, dBusConn); TQT_DBusObjectPath seat; if( sessionProperties.canSend() ) { TQValueList params; params << TQT_DBusData::fromString( SYSTEMD_LOGIN1_SESSION_IFACE ) << TQT_DBusData::fromString( "Seat" ); TQT_DBusMessage reply = sessionProperties.sendWithReply("Get", params); if (reply.type() == TQT_DBusMessage::ReplyMessage && reply.count() == 1 ) { seat = reply[0].toVariant().value.toStruct()[1].toObjectPath(); } } if( !seat.isValid() ) { kdWarning() << "Unable to associate systemd session with a seat" << endl; return; } // watch session changes systemdSeat = new TQT_DBusProxy(SYSTEMD_LOGIN1_SERVICE, seat, DBUS_INTERFACE_PROPERTIES, dBusConn); TQObject::connect(systemdSeat, TQ_SIGNAL(dbusSignal(const TQT_DBusMessage&)), this, TQ_SLOT(handleDBusSignal(const TQT_DBusMessage&))); // inhibit systemd handling of power/sleep/hibernate/lid buttons // http://www.freedesktop.org/wiki/Software/systemd/inhibit if( !systemdInhibit.isValid() && managerIface.canSend() ) { TQValueList params; params << TQT_DBusData::fromString("handle-power-key:handle-suspend-key:handle-hibernate-key:handle-lid-switch") // what << TQT_DBusData::fromString("TDEPowersave") // who << TQT_DBusData::fromString("TDE handles power events") // why << TQT_DBusData::fromString("block"); // mode TQT_DBusMessage reply = managerIface.sendWithReply("Inhibit", params); if (reply.type() == TQT_DBusMessage::ReplyMessage && reply.count() == 1 ) { systemdInhibit = reply[0].toUnixFd(); } } return; } if( service == CK_SERVICE ) { // get current session TQT_DBusProxy managerIface(CK_SERVICE, CK_MANAGER_OBJECT, CK_MANAGER_IFACE, dBusConn); consolekitSession = TQT_DBusObjectPath(); if( managerIface.canSend() ) { TQValueList params; params << TQT_DBusData::fromUInt32( getpid() ); TQT_DBusMessage reply = managerIface.sendWithReply("GetSessionForUnixProcess", params); if (reply.type() == TQT_DBusMessage::ReplyMessage && reply.count() == 1 ) { consolekitSession = reply[0].toObjectPath(); } } if( !consolekitSession.isValid() ) { kdWarning() << "The session is not registered with consolekit" << endl; return; } // get session seat TQT_DBusObjectPath seat; if( dBusConn.isConnected() ) { TQT_DBusMessage msg = TQT_DBusMessage::methodCall(CK_SERVICE, consolekitSession, CK_SESSION_IFACE, "GetSeatId"); TQT_DBusMessage reply = dBusConn.sendWithReply(msg); if (reply.type() == TQT_DBusMessage::ReplyMessage && reply.count() == 1 ) { seat = reply[0].toObjectPath(); } } if( !seat.isValid() ) { kdWarning() << "Unable to associate consolekit session with a seat" << endl; return; } // watch session changes consolekitSeat = new TQT_DBusProxy(CK_SERVICE, seat, CK_SEAT_IFACE, dBusConn); TQObject::connect(consolekitSeat, TQ_SIGNAL(dbusSignal(const TQT_DBusMessage&)), this, TQ_SLOT(handleDBusSignal(const TQT_DBusMessage&))); return; } } /*! * This function handles dBus service unregistering */ void dbusInterface::onServiceUnregistered(const TQString& service) { if( service == SYSTEMD_LOGIN1_SERVICE ) { systemdSession = TQT_DBusObjectPath(); if( systemdSeat ) { delete systemdSeat; } return; } if( service == CK_SERVICE ) { consolekitSession = TQT_DBusObjectPath(); if( consolekitSeat ) { delete consolekitSeat; } return; } } /*! * This functions is used to check if session is active */ bool dbusInterface::checkActiveSession() { if( systemdSeat && systemdSeat->canSend() ) { TQT_DBusObjectPath activeSession; TQValueList params; params << TQT_DBusData::fromString( SYSTEMD_LOGIN1_SEAT_IFACE ) << TQT_DBusData::fromString( "ActiveSession" ); TQT_DBusMessage reply = systemdSeat->sendWithReply("Get", params); if (reply.type() == TQT_DBusMessage::ReplyMessage && reply.count() == 1 ) { activeSession = reply[0].toVariant().value.toStruct()[1].toObjectPath(); return (activeSession == systemdSession); } } if( consolekitSeat && consolekitSeat->canSend() ) { TQT_DBusObjectPath activeSession; TQValueList params; TQT_DBusMessage reply = consolekitSeat->sendWithReply("GetActiveSession", params); if (reply.type() == TQT_DBusMessage::ReplyMessage && reply.count() == 1 ) { activeSession = reply[0].toObjectPath(); return (activeSession == consolekitSession); } } return false; } #include "dbusInterface.moc"