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.
tdepowersave/src/dbusInterface.cpp

400 lines
13 KiB

/**************************************************************************
* Copyright (C) 2006-2007 by Danny Kukawka *
* <dkukawka@suse.de>, <danny.kukawka@web.de> *
* *
* 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, <dkukawka@suse.de>, <danny.kukawka@web.de>
* \date 2006-2007
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
// QT - Header
#include <tqtimer.h>
// KDE Header
#include <tdelocale.h>
// DBUS - Header
#include "dbus/dbus-shared.h"
#include "dbusInterface.h"
#include <tqdbusdatalist.h>
#include <tqdbusdatamap.h>
#include <tqdbuserror.h>
#include <tqdbusmessage.h>
#include <tqdbusvariant.h>
// system headers
#include <unistd.h>
#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, TQT_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, TQT_SIGNAL(dbusSignal(const TQT_DBusMessage&)),
this, TQT_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, TQT_SIGNAL(dbusSignal(const TQT_DBusMessage&)),
this, TQT_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<TQT_DBusData> 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<TQT_DBusData> 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, TQT_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<TQString> map = msg[1].toStringKeyMap();
TQT_DBusDataMap<TQString>::const_iterator it = map.begin();
for (; !activeSessionProperty && it != map.end(); ++it) {
if( it.key() != "ActiveSession" ) {
activeSessionProperty = true;
}
}
TQValueList<TQString> list = msg[2].toList().toStringList();
TQValueList<TQString>::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<TQT_DBusData> 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<TQT_DBusData> 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, TQT_SIGNAL(dbusSignal(const TQT_DBusMessage&)),
this, TQT_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<TQT_DBusData> 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<TQT_DBusData> 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, TQT_SIGNAL(dbusSignal(const TQT_DBusMessage&)),
this, TQT_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<TQT_DBusData> 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<TQT_DBusData> 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"