7 from gi.repository import GObject
9 logger = logging.getLogger("onoff.dbusutils")
11 object_prefix = "/de/subdivi/onoff0"
12 default_busname = "de.subdivi.onoff0"
14 dbus_options = argparse.ArgumentParser(add_help=False)
15 dbus_options.add_argument("--bus", default="session",
16 choices=("system", "session"),
17 help="which bus to use (default: %(default)s)")
18 dbus_options.add_argument("--busname", type=str, default=default_busname,
19 help="which busname (i.e. client) to use " +
20 "(default: %(default)s)")
21 dbus_options.add_argument("--device", type=str,
22 help="which device to control")
24 def get_dbus(namespace):
26 @param namespace: a namespace returned from a dbus_options argument parser
28 @returns: the requested bus
30 if namespace.bus == "session":
31 return dbus.SessionBus()
32 elif namespace.bus == "system":
33 return dbus.SystemBus()
35 raise AssertionError("namespace.bus %r is neither session nor system",
38 def get_dbus_proxy(namespace):
40 @param namespace: a namespace returned from a dbus_options argument parser
41 @returns: a dbus object proxy
43 bus = get_dbus(namespace)
44 if not namespace.device:
45 raise ValueError("no --device given")
46 objname = "%s/%s" % (object_prefix, namespace.device)
47 return bus.get_object(namespace.busname, objname)
50 """Create a socket pair where the latter end is already wrapped for
51 transmission over dbus.
53 @rtype: (socket, dbus.types.UnixFd)
55 s1, s2 = socket.socketpair()
56 s3 = dbus.types.UnixFd(s2)
60 class OnoffControl(dbus.service.Object):
61 domain = default_busname
64 def __init__(self, bus, name, device):
68 @type device: OnoffDevice
70 busname = dbus.service.BusName(self.domain, bus=bus)
71 dbus.service.Object.__init__(self, busname, "%s/%s" % (self.path, name))
74 device.notify.add(self.changestate)
76 @dbus.service.signal(domain, signature="q")
77 def changestate(self, state):
78 logger.debug("emitting state %d", state)
80 @dbus.service.method(domain, out_signature="q")
82 return self.device.state
84 @dbus.service.method(domain, in_signature="q", out_signature="q")
85 def activatetime(self, duration):
86 """Activate the device for a given number of seconds."""
87 logger.info("activatetime %d", duration)
88 GObject.timeout_add(duration * 1000, self.unuse)
91 @dbus.service.method(domain, in_signature="", out_signature="qh")
93 """Activate a device until the returned file descriptor is closed."""
94 logger.info("activatefd")
95 notifyfd, retfd = socketpair()
97 logger.info("fd %d completed", fd.fileno())
101 GObject.io_add_watch(notifyfd, GObject.IO_HUP|GObject.IO_ERR, callback)
102 return (self.use(), retfd)
106 if self.usecount <= 1:
107 self.device.activate()
108 return self.device.state
112 if not self.usecount:
113 self.device.deactivate()
115 logger.debug("%d users left", self.usecount)