alien-everywhere/shimming/alienkeyboardservice/dbussy.py

7022 lines
267 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

"""
Pure-Python binding for D-Bus <https://www.freedesktop.org/wiki/Software/dbus/>,
built around libdbus <https://dbus.freedesktop.org/doc/api/html/index.html>.
This Python binding supports hooking into event loops via Pythons standard
asyncio module.
"""
#+
# Copyright 2017-2020 Lawrence D'Oliveiro <ldo@geek-central.gen.nz>.
# Licensed under the GNU Lesser General Public License v2.1 or later.
#-
import os
import builtins
import operator
import array
import enum
import ctypes as ct
from weakref import \
ref as weak_ref, \
WeakValueDictionary
import threading
import io
import atexit
import asyncio
import functools
from xml.etree import \
ElementTree as XMLElementTree
from xml.sax.saxutils import \
quoteattr as quote_xml_attr
dbus = ct.cdll.LoadLibrary("libdbus-1.so.3")
class DBUS :
"useful definitions adapted from the D-Bus includes. You will need to use the" \
" constants, but apart from that, see the more Pythonic wrappers defined outside" \
" this class in preference to accessing low-level structures directly."
# General ctypes gotcha: when passing addresses of ctypes-constructed objects
# to routine calls, do not construct the objects directly in the call. Otherwise
# the refcount goes to 0 before the routine is actually entered, and the object
# can get prematurely disposed. Always store the object reference into a local
# variable, and pass the value of the variable instead.
# from dbus-protocol.h:
# Message byte order
LITTLE_ENDIAN = 'l'
BIG_ENDIAN = 'B'
# Protocol version.
MAJOR_PROTOCOL_VERSION = 1
# Type code that is never equal to a legitimate type code
TYPE_INVALID = 0
# Primitive types
TYPE_BYTE = ord('y') # 8-bit unsigned integer
TYPE_BOOLEAN = ord('b') # boolean
TYPE_INT16 = ord('n') # 16-bit signed integer
TYPE_UINT16 = ord('q') # 16-bit unsigned integer
TYPE_INT32 = ord('i') # 32-bit signed integer
TYPE_UINT32 = ord('u') # 32-bit unsigned integer
TYPE_INT64 = ord('x') # 64-bit signed integer
TYPE_UINT64 = ord('t') # 64-bit unsigned integer
TYPE_DOUBLE = ord('d') # 8-byte double in IEEE 754 format
TYPE_STRING = ord('s') # UTF-8 encoded, nul-terminated Unicode string
TYPE_OBJECT_PATH = ord('o') # D-Bus object path
TYPE_SIGNATURE = ord('g') # D-Bus type signature
TYPE_UNIX_FD = ord('h') # unix file descriptor
basic_to_ctypes = \
{ # ctypes objects suitable for holding values of D-Bus types
TYPE_BYTE : ct.c_ubyte,
TYPE_BOOLEAN : ct.c_ubyte,
TYPE_INT16 : ct.c_short,
TYPE_UINT16 : ct.c_ushort,
TYPE_INT32 : ct.c_int,
TYPE_UINT32 : ct.c_uint,
TYPE_INT64 : ct.c_longlong,
TYPE_UINT64 : ct.c_ulonglong,
TYPE_DOUBLE : ct.c_double,
TYPE_STRING : ct.c_char_p,
TYPE_OBJECT_PATH : ct.c_char_p,
TYPE_SIGNATURE : ct.c_char_p,
TYPE_UNIX_FD : ct.c_int,
}
def int_subtype(i, bits, signed) :
"returns integer i after checking that it fits in the given number of bits."
if not isinstance(i, int) :
raise TypeError("value is not int: %s" % repr(i))
#end if
if signed :
lo = - 1 << bits - 1
hi = (1 << bits - 1) - 1
else :
lo = 0
hi = (1 << bits) - 1
#end if
if i < lo or i > hi :
raise ValueError \
(
"%d not in range of %s %d-bit value" % (i, ("unsigned", "signed")[signed], bits)
)
#end if
return \
i
#end int_subtype
subtype_boolean = lambda i : DBUS.int_subtype(i, 1, False)
subtype_byte = lambda i : DBUS.int_subtype(i, 8, False)
subtype_int16 = lambda i : DBUS.int_subtype(i, 16, True)
subtype_uint16 = lambda i : DBUS.int_subtype(i, 16, False)
subtype_int32 = lambda i : DBUS.int_subtype(i, 32, True)
subtype_uint32 = lambda i : DBUS.int_subtype(i, 32, False)
subtype_int64 = lambda i : DBUS.int_subtype(i, 64, True)
subtype_uint64 = lambda i : DBUS.int_subtype(i, 64, False)
int_convert = \
{ # range checks for the various D-Bus integer types
TYPE_BOOLEAN : subtype_boolean,
TYPE_BYTE : subtype_byte,
TYPE_INT16 : subtype_int16,
TYPE_UINT16 : subtype_uint16,
TYPE_INT32 : subtype_int32,
TYPE_UINT32 : subtype_uint32,
TYPE_INT64 : subtype_int64,
TYPE_UINT64 : subtype_uint64,
}
# subclasses for distinguishing various special kinds of D-Bus values:
class ObjectPath(str) :
"an object path string."
def __repr__(self) :
return \
"%s(%s)" % (self.__class__.__name__, super().__repr__())
#end __repr__
#end ObjectPath
class Signature(str) :
"a type-signature string."
def __repr__(self) :
return \
"%s(%s)" % (self.__class__.__name__, super().__repr__())
#end __repr__
#end Signature
class UnixFD(int) :
"a file-descriptor integer."
def __repr__(self) :
return \
"%s(%s)" % (self.__class__.__name__, super().__repr__())
#end __repr__
#end UnixFD
basic_subclasses = \
{
TYPE_BOOLEAN : bool,
TYPE_OBJECT_PATH : ObjectPath,
TYPE_SIGNATURE : Signature,
TYPE_UNIX_FD : UnixFD,
}
# Compound types
TYPE_ARRAY = ord('a') # D-Bus array type
TYPE_VARIANT = ord('v') # D-Bus variant type
TYPE_STRUCT = ord('r') # a struct; however, type signatures use STRUCT_BEGIN/END_CHAR
TYPE_DICT_ENTRY = ord('e') # a dict entry; however, type signatures use DICT_ENTRY_BEGIN/END_CHAR
NUMBER_OF_TYPES = 16 # does not include TYPE_INVALID or STRUCT/DICT_ENTRY_BEGIN/END_CHAR
# characters other than typecodes that appear in type signatures
STRUCT_BEGIN_CHAR = ord('(') # start of a struct type in a type signature
STRUCT_END_CHAR = ord(')') # end of a struct type in a type signature
DICT_ENTRY_BEGIN_CHAR = ord('{') # start of a dict entry type in a type signature
DICT_ENTRY_END_CHAR = ord('}') # end of a dict entry type in a type signature
MAXIMUM_NAME_LENGTH = 255 # max length in bytes of a bus name, interface or member (object paths are unlimited)
MAXIMUM_SIGNATURE_LENGTH = 255 # fits in a byte
MAXIMUM_MATCH_RULE_LENGTH = 1024
MAXIMUM_MATCH_RULE_ARG_NUMBER = 63
MAXIMUM_ARRAY_LENGTH = 67108864 # 2 * 26
MAXIMUM_ARRAY_LENGTH_BITS = 26 # to store the max array size
MAXIMUM_MESSAGE_LENGTH = MAXIMUM_ARRAY_LENGTH * 2
MAXIMUM_MESSAGE_LENGTH_BITS = 27
MAXIMUM_MESSAGE_UNIX_FDS = MAXIMUM_MESSAGE_LENGTH // 4 # FDs are at least 32 bits
MAXIMUM_MESSAGE_UNIX_FDS_BITS = MAXIMUM_MESSAGE_LENGTH_BITS - 2
MAXIMUM_TYPE_RECURSION_DEPTH = 32
# Types of message
MESSAGE_TYPE_INVALID = 0 # never a valid message type
MESSAGE_TYPE_METHOD_CALL = 1
MESSAGE_TYPE_METHOD_RETURN = 2
MESSAGE_TYPE_ERROR = 3
MESSAGE_TYPE_SIGNAL = 4
NUM_MESSAGE_TYPES = 5
# Header flags
HEADER_FLAG_NO_REPLY_EXPECTED = 0x1
HEADER_FLAG_NO_AUTO_START = 0x2
HEADER_FLAG_ALLOW_INTERACTIVE_AUTHORIZATION = 0x4
# Header fields
HEADER_FIELD_INVALID = 0
HEADER_FIELD_PATH = 1
HEADER_FIELD_INTERFACE = 2
HEADER_FIELD_MEMBER = 3
HEADER_FIELD_ERROR_NAME = 4
HEADER_FIELD_REPLY_SERIAL = 5
HEADER_FIELD_DESTINATION = 6
HEADER_FIELD_SENDER = 7
HEADER_FIELD_SIGNATURE = 8
HEADER_FIELD_UNIX_FDS = 9
HEADER_FIELD_LAST = HEADER_FIELD_UNIX_FDS
HEADER_SIGNATURE = bytes \
((
TYPE_BYTE,
TYPE_BYTE,
TYPE_BYTE,
TYPE_BYTE,
TYPE_UINT32,
TYPE_UINT32,
TYPE_ARRAY,
STRUCT_BEGIN_CHAR,
TYPE_BYTE,
TYPE_VARIANT,
STRUCT_END_CHAR,
))
MINIMUM_HEADER_SIZE = 16 # smallest header size that can occur (missing required fields, though)
# Errors
ERROR_FAILED = "org.freedesktop.DBus.Error.Failed" # generic error
ERROR_NO_MEMORY = "org.freedesktop.DBus.Error.NoMemory"
ERROR_SERVICE_UNKNOWN = "org.freedesktop.DBus.Error.ServiceUnknown"
ERROR_NAME_HAS_NO_OWNER = "org.freedesktop.DBus.Error.NameHasNoOwner"
ERROR_NO_REPLY = "org.freedesktop.DBus.Error.NoReply"
ERROR_IO_ERROR = "org.freedesktop.DBus.Error.IOError"
ERROR_BAD_ADDRESS = "org.freedesktop.DBus.Error.BadAddress"
ERROR_NOT_SUPPORTED = "org.freedesktop.DBus.Error.NotSupported"
ERROR_LIMITS_EXCEEDED = "org.freedesktop.DBus.Error.LimitsExceeded"
ERROR_ACCESS_DENIED = "org.freedesktop.DBus.Error.AccessDenied"
ERROR_AUTH_FAILED = "org.freedesktop.DBus.Error.AuthFailed"
ERROR_NO_SERVER = "org.freedesktop.DBus.Error.NoServer"
ERROR_TIMEOUT = "org.freedesktop.DBus.Error.Timeout"
ERROR_NO_NETWORK = "org.freedesktop.DBus.Error.NoNetwork"
ERROR_ADDRESS_IN_USE = "org.freedesktop.DBus.Error.AddressInUse"
ERROR_DISCONNECTED = "org.freedesktop.DBus.Error.Disconnected"
ERROR_INVALID_ARGS = "org.freedesktop.DBus.Error.InvalidArgs"
ERROR_FILE_NOT_FOUND = "org.freedesktop.DBus.Error.FileNotFound"
ERROR_FILE_EXISTS = "org.freedesktop.DBus.Error.FileExists"
ERROR_UNKNOWN_METHOD = "org.freedesktop.DBus.Error.UnknownMethod"
ERROR_UNKNOWN_OBJECT = "org.freedesktop.DBus.Error.UnknownObject"
ERROR_UNKNOWN_INTERFACE = "org.freedesktop.DBus.Error.UnknownInterface"
ERROR_UNKNOWN_PROPERTY = "org.freedesktop.DBus.Error.UnknownProperty"
ERROR_PROPERTY_READ_ONLY = "org.freedesktop.DBus.Error.PropertyReadOnly"
ERROR_TIMED_OUT = "org.freedesktop.DBus.Error.TimedOut"
ERROR_MATCH_RULE_NOT_FOUND = "org.freedesktop.DBus.Error.MatchRuleNotFound"
ERROR_MATCH_RULE_INVALID = "org.freedesktop.DBus.Error.MatchRuleInvalid"
ERROR_SPAWN_EXEC_FAILED = "org.freedesktop.DBus.Error.Spawn.ExecFailed"
ERROR_SPAWN_FORK_FAILED = "org.freedesktop.DBus.Error.Spawn.ForkFailed"
ERROR_SPAWN_CHILD_EXITED = "org.freedesktop.DBus.Error.Spawn.ChildExited"
ERROR_SPAWN_CHILD_SIGNALED = "org.freedesktop.DBus.Error.Spawn.ChildSignaled"
ERROR_SPAWN_FAILED = "org.freedesktop.DBus.Error.Spawn.Failed"
ERROR_SPAWN_SETUP_FAILED = "org.freedesktop.DBus.Error.Spawn.FailedToSetup"
ERROR_SPAWN_CONFIG_INVALID = "org.freedesktop.DBus.Error.Spawn.ConfigInvalid"
ERROR_SPAWN_SERVICE_INVALID = "org.freedesktop.DBus.Error.Spawn.ServiceNotValid"
ERROR_SPAWN_SERVICE_NOT_FOUND = "org.freedesktop.DBus.Error.Spawn.ServiceNotFound"
ERROR_SPAWN_PERMISSIONS_INVALID = "org.freedesktop.DBus.Error.Spawn.PermissionsInvalid"
ERROR_SPAWN_FILE_INVALID = "org.freedesktop.DBus.Error.Spawn.FileInvalid"
ERROR_SPAWN_NO_MEMORY = "org.freedesktop.DBus.Error.Spawn.NoMemory"
ERROR_UNIX_PROCESS_ID_UNKNOWN = "org.freedesktop.DBus.Error.UnixProcessIdUnknown"
ERROR_INVALID_SIGNATURE = "org.freedesktop.DBus.Error.InvalidSignature"
ERROR_INVALID_FILE_CONTENT = "org.freedesktop.DBus.Error.InvalidFileContent"
ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN = "org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown"
ERROR_ADT_AUDIT_DATA_UNKNOWN = "org.freedesktop.DBus.Error.AdtAuditDataUnknown"
ERROR_OBJECT_PATH_IN_USE = "org.freedesktop.DBus.Error.ObjectPathInUse"
ERROR_INCONSISTENT_MESSAGE = "org.freedesktop.DBus.Error.InconsistentMessage"
ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED = "org.freedesktop.DBus.Error.InteractiveAuthorizationRequired"
# XML introspection format
INTROSPECT_1_0_XML_NAMESPACE = "http://www.freedesktop.org/standards/dbus"
INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER = "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER = "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"
INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE = \
(
"<!DOCTYPE node PUBLIC \""
+
INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER
+
"\"\n\"" + INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER
+
"\">\n"
)
# from dbus-shared.h:
# well-known bus types
BusType = ct.c_uint
BUS_SESSION = 0
BUS_SYSTEM = 1
BUS_STARTER = 2
# results that a message handler can return
BusHandlerResult = ct.c_uint
HANDLER_RESULT_HANDLED = 0 # no need to try more handlers
HANDLER_RESULT_NOT_YET_HANDLED = 1 # see if other handlers want it
HANDLER_RESULT_NEED_MEMORY = 2 # try again later with more memory
# Bus names
SERVICE_DBUS = "org.freedesktop.DBus" # used to talk to the bus itself
# Paths
PATH_DBUS = "/org/freedesktop/DBus" # object path used to talk to the bus itself
PATH_LOCAL = "/org/freedesktop/DBus/Local" # path used in local/in-process-generated messages
# Interfaces
INTERFACE_DBUS = "org.freedesktop.DBus" # interface exported by the object with SERVICE_DBUS and PATH_DBUS
INTERFACE_MONITORING = "org.freedesktop.DBus.Monitoring" # monitoring interface exported by the dbus-daemon
INTERFACE_VERBOSE = "org.freedesktop.DBus.Verbose" # verbose interface exported by the dbus-daemon
INTERFACE_INTROSPECTABLE = "org.freedesktop.DBus.Introspectable" # interface supported by introspectable objects
INTERFACE_PROPERTIES = "org.freedesktop.DBus.Properties" # interface supported by objects with properties
INTERFACE_PEER = "org.freedesktop.DBus.Peer" # interface supported by most dbus peers
INTERFACE_LOCAL = "org.freedesktop.DBus.Local" # methods can only be invoked locally
# Owner flags for request_name
NAME_FLAG_ALLOW_REPLACEMENT = 0x1
NAME_FLAG_REPLACE_EXISTING = 0x2
NAME_FLAG_DO_NOT_QUEUE = 0x4
# Replies to request for a name
REQUEST_NAME_REPLY_PRIMARY_OWNER = 1
REQUEST_NAME_REPLY_IN_QUEUE = 2
REQUEST_NAME_REPLY_EXISTS = 3
REQUEST_NAME_REPLY_ALREADY_OWNER = 4
# Replies to releasing a name
RELEASE_NAME_REPLY_RELEASED = 1
RELEASE_NAME_REPLY_NON_EXISTENT = 2
RELEASE_NAME_REPLY_NOT_OWNER = 3
# Replies to service starts
START_REPLY_SUCCESS = 1
START_REPLY_ALREADY_RUNNING = 2
# from dbus-types.h:
bool_t = ct.c_uint
# from dbus-memory.h:
FreeFunction = ct.CFUNCTYPE(None, ct.c_void_p)
# from dbus-connection.h:
HandlerResult = ct.c_uint
class Error(ct.Structure) :
_fields_ = \
[
("name", ct.c_char_p),
("message", ct.c_char_p),
("padding", 2 * ct.c_void_p),
]
#end Error
ErrorPtr = ct.POINTER(Error)
WatchFlags = ct.c_uint
WATCH_READABLE = 1 << 0
WATCH_WRITABLE = 1 << 1
WATCH_ERROR = 1 << 2
WATCH_HANGUP = 1 << 3
DispatchStatus = ct.c_uint
DISPATCH_DATA_REMAINS = 0 # more data available
DISPATCH_COMPLETE = 1 # all available data has been processed
DISPATCH_NEED_MEMORY = 2 # not enough memory to continue
AddWatchFunction = ct.CFUNCTYPE(bool_t, ct.c_void_p, ct.c_void_p)
# add_watch(DBusWatch, user_data) returns success/failure
WatchToggledFunction = ct.CFUNCTYPE(None, ct.c_void_p, ct.c_void_p)
# watch_toggled(DBusWatch, user_data)
RemoveWatchFunction = ct.CFUNCTYPE(None, ct.c_void_p, ct.c_void_p)
# remove_watch(DBusWatch, user_data)
AddTimeoutFunction = ct.CFUNCTYPE(bool_t, ct.c_void_p, ct.c_void_p)
# add_timeout(DBusTimeout, user_data) returns success/failure
TimeoutToggledFunction = ct.CFUNCTYPE(None, ct.c_void_p, ct.c_void_p)
# timeout_toggled(DBusTimeout, user_data)
RemoveTimeoutFunction = ct.CFUNCTYPE(None, ct.c_void_p, ct.c_void_p)
# remove_timeout(DBusTimeout, user_data)
DispatchStatusFunction = ct.CFUNCTYPE(None, ct.c_void_p, ct.POINTER(DispatchStatus), ct.c_void_p)
# dispatch_status(DBusConnection, DBusDispatchStatus, user_data)
WakeupMainFunction = ct.CFUNCTYPE(None, ct.c_void_p)
# wakeup_main(user_data)
AllowUnixUserFunction = ct.CFUNCTYPE(bool_t, ct.c_void_p, ct.c_ulong, ct.c_void_p)
# allow_unix_user(DBusConnection, uid, user_data) returns success/failure
AllowWindowsUserFunction = ct.CFUNCTYPE(bool_t, ct.c_void_p, ct.c_void_p, ct.c_void_p)
# allow_windows_user(DBusConnection, user_sid, user_data)returns success/failure
PendingCallNotifyFunction = ct.CFUNCTYPE(None, ct.c_void_p, ct.c_void_p)
# notify(DBusPendingCall, user_data)
HandleMessageFunction = ct.CFUNCTYPE(HandlerResult, ct.c_void_p, ct.c_void_p, ct.c_void_p)
# handle_message(DBusConnection, DBusMessage, user_data)
ObjectPathUnregisterFunction = ct.CFUNCTYPE(None, ct.c_void_p, ct.c_void_p)
# unregister(DBusConnection, user_data)
ObjectPathMessageFunction = ct.CFUNCTYPE(HandlerResult, ct.c_void_p, ct.c_void_p, ct.c_void_p)
# handle_message(DBusConnection, DBusMessage, user_data)
class ObjectPathVTable(ct.Structure) :
pass
#end ObjectPathVTable
ObjectPathVTable._fields_ = \
[
("unregister_function", ObjectPathUnregisterFunction),
("message_function", ObjectPathMessageFunction),
("internal_pad1", ct.CFUNCTYPE(None, ct.c_void_p)),
("internal_pad2", ct.CFUNCTYPE(None, ct.c_void_p)),
("internal_pad3", ct.CFUNCTYPE(None, ct.c_void_p)),
("internal_pad4", ct.CFUNCTYPE(None, ct.c_void_p)),
]
ObjectPathVTablePtr = ct.POINTER(ObjectPathVTable)
# from dbus-pending-call.h:
TIMEOUT_INFINITE = 0x7fffffff
TIMEOUT_USE_DEFAULT = -1
# from dbus-message.h:
class MessageIter(ct.Structure) :
"contains no public fields."
_fields_ = \
[
("dummy1", ct.c_void_p),
("dummy2", ct.c_void_p),
("dummy3", ct.c_uint),
("dummy4", ct.c_int),
("dummy5", ct.c_int),
("dummy6", ct.c_int),
("dummy7", ct.c_int),
("dummy8", ct.c_int),
("dummy9", ct.c_int),
("dummy10", ct.c_int),
("dummy11", ct.c_int),
("pad1", ct.c_int),
("pad2", ct.c_void_p),
("pad3", ct.c_void_p),
]
#end MessageIter
MessageIterPtr = ct.POINTER(MessageIter)
# from dbus-server.h:
NewConnectionFunction = ct.CFUNCTYPE(None, ct.c_void_p, ct.c_void_p, ct.c_void_p)
# new_connection(DBusServer, DBusConnection, user_data)
# from dbus-signature.h:
class SignatureIter(ct.Structure) :
"contains no public fields."
_fields_ = \
[
("dummy1", ct.c_void_p),
("dummy2", ct.c_void_p),
("dummy8", ct.c_uint),
("dummy12", ct.c_int),
("dummy17", ct.c_int),
]
#end SignatureIter
SignatureIterPtr = ct.POINTER(SignatureIter)
#end DBUS
class DBUSX:
"additional definitions not part of the official interfaces"
DEFAULT_TIMEOUT = 25 # seconds, from dbus-connection-internal.h in libdbus source
# For reference implementation for how to connect to daemon,
# see libdbus sources, dbus/dbus-bus.c (internal_bus_get routine
# and stuff that it calls)
# environment variables used to find addresses of bus daemons
SESSION_BUS_ADDRESS_VAR = "DBUS_SESSION_BUS_ADDRESS"
SYSTEM_BUS_ADDRESS_VAR = "DBUS_SYSTEM_BUS_ADDRESS"
STARTER_BUS_ADDRESS_VAR = "DBUS_STARTER_ADDRESS"
STARTER_BUS_ADDRESS_TYPE = "DBUS_STARTER_BUS_TYPE"
# values for value of STARTER_BUS_ADDRESS_TYPE
# If cannot determine type, then default to session bus
BUS_TYPE_SESSION = "session"
BUS_TYPE_SYSTEM = "system"
SYSTEM_BUS_ADDRESS = "unix:path=/var/run/dbus/system_bus_socket"
# default system bus daemon address if value of SYSTEM_BUS_ADDRESS_VAR is not defined
SESSION_BUS_ADDRESS = "autolaunch:"
# default session bus daemon address if value of SESSION_BUS_ADDRESS_VAR is not defined
INTERFACE_OBJECT_MANAGER = "org.freedesktop.DBus.ObjectManager"
# no symbolic name for this in standard headers as yet
#end DBUSX
#+
# Useful stuff
#-
if hasattr(asyncio, "get_running_loop") :
# new in Python 3.7
get_running_loop = asyncio.get_running_loop
else :
# as long as I want to support pre-3.7...
get_running_loop = asyncio.get_event_loop
#end if
def get_event_loop() :
"Python docs indicate that asyncio.get_event_loop() is going away" \
" in its current form. But I still need to be able to attach objects" \
" to the default event loop from a non-coroutine context. So I" \
" reimplement its original semantics here."
return \
asyncio.get_event_loop_policy().get_event_loop()
#end get_event_loop
def _wderef(w_self, parent) :
self = w_self()
assert self != None, "%s has gone away" % parent
return \
self
#end _wderef
def call_async(func, funcargs = (), timeout = None, abort = None, loop = None) :
"invokes func on a separate temporary thread and returns a Future that" \
" can be used to wait for its completion and obtain its result. If timeout" \
" is not None, then waiters on the Future will get a TimeoutError exception" \
" if the function has not completed execution after that number of seconds." \
" This allows easy invocation of blocking I/O functions in an asyncio-" \
"compatible fashion. But note that the operation cannot be cancelled" \
" if the timeout elapses; instead, you can specify an abort callback" \
" which will be invoked with whatever result is eventually returned from" \
" func."
if loop == None :
loop = get_running_loop()
#end if
timeout_task = None
def func_done(ref_awaiting, result) :
awaiting = ref_awaiting()
if awaiting != None :
if not awaiting.done() :
awaiting.set_result(result)
if timeout_task != None :
timeout_task.cancel()
#end if
else :
if abort != None :
abort(result)
#end if
#end if
#end if
#end func_done
def do_func_timedout(ref_awaiting) :
awaiting = ref_awaiting()
if awaiting != None :
if not awaiting.done() :
awaiting.set_exception(TimeoutError())
# Python doesnt give me any (easy) way to cancel the thread running the
# do_func() call, so just let it run to completion, whereupon func_done()
# will get rid of the result. Even if I could delete the thread, can I be sure
# that would clean up memory and OS/library resources properly?
#end if
#end if
#end do_func_timedout
def do_func(ref_awaiting) :
# makes the blocking call on a separate thread.
result = func(*funcargs)
# A Future is not itself threadsafe, but I can thread-safely
# run a callback on the main thread to set it.
loop.call_soon_threadsafe(func_done, ref_awaiting, result)
#end do_func
#begin call_async
awaiting = loop.create_future()
ref_awaiting = weak_ref(awaiting)
# weak ref to avoid circular refs with loop
subthread = threading.Thread(target = do_func, args = (ref_awaiting,), daemon = True)
subthread.start()
if timeout != None :
timeout_task = loop.call_later(timeout, do_func_timedout, ref_awaiting)
#end if
return \
awaiting
#end call_async
#+
# Higher-level interface to type system
#-
class TYPE(enum.Enum) :
"D-Bus type codes wrapped up in an enumeration."
BYTE = ord('y') # 8-bit unsigned integer
BOOLEAN = ord('b') # boolean
INT16 = ord('n') # 16-bit signed integer
UINT16 = ord('q') # 16-bit unsigned integer
INT32 = ord('i') # 32-bit signed integer
UINT32 = ord('u') # 32-bit unsigned integer
INT64 = ord('x') # 64-bit signed integer
UINT64 = ord('t') # 64-bit unsigned integer
DOUBLE = ord('d') # 8-byte double in IEEE 754 format
STRING = ord('s') # UTF-8 encoded, nul-terminated Unicode string
OBJECT_PATH = ord('o') # D-Bus object path
SIGNATURE = ord('g') # D-Bus type signature
UNIX_FD = ord('h') # unix file descriptor
ARRAY = ord('a') # array of elements all of same type, or possibly dict
STRUCT = ord('r') # sequence of elements of arbitrary types
VARIANT = ord('v') # a single element of dynamic type
@property
def is_basic(self) :
"does this code represent a basic (non-container) type."
return \
self.value in DBUS.basic_to_ctypes
#end is_basic
#end TYPE
class Type :
"base class for all Types. The “signature” property returns the fully-encoded" \
" signature string for the entire Type."
__slots__ = ("code",)
def __init__(self, code) :
if not isinstance(code, TYPE) :
raise TypeError("only TYPE.xxx values allowed")
#end if
self.code = code
#end __init__
@property
def signature(self) :
raise NotImplementedError("subclass forgot to override signature property")
#end signature
def __eq__(t1, t2) :
raise NotImplementedError("subclass forgot to override __eq__ method")
#end __eq__
def validate(self, val) :
"returns val if it is an acceptable value of this Type, else raises" \
" TypeError or ValueError."
raise NotImplementedError("subclass forgot to override validate method")
#end validate
def __repr__(self) :
return \
"%s(sig = %s)" % (type(self).__name__, repr(self.signature))
#end __repr__
#end Type
class BasicType(Type) :
"a basic (non-container) type."
__slots__ = ()
def __init__(self, code) :
if not isinstance(code, TYPE) or not code.is_basic :
raise TypeError("only basic TYPE.xxx values allowed")
#end if
super().__init__(code)
#end __init__
def __repr__(self) :
return \
"%s(%s)" % (type(self).__name__, repr(self.code))
#end __repr__
@property
def signature(self) :
return \
chr(self.code.value)
#end signature
def __eq__(t1, t2) :
return \
isinstance(t2, BasicType) and t1.code == t2.code
#end __eq__
def validate(self, val) :
if self.code.value in DBUS.int_convert :
val = DBUS.int_convert[self.code.value](val)
elif self.code == TYPE.DOUBLE :
if not isinstance(val, float) :
raise TypeError("expecting a float, not %s: %s" % (type(val).__name__, repr(val)))
#end if
elif self.code == TYPE.UNIX_FD :
val = DBUS.subtype_uint32(val)
elif DBUS.basic_to_ctypes[self.code.value] == ct.c_char_p :
if not isinstance(val, str) :
raise TypeError("expecting a string, not %s: %s" % (type(val).__name__, repr(val)))
#end if
else :
raise RuntimeError("unknown basic type %s" % repr(self.code))
#end if
return \
val
#end validate
#end BasicType
class VariantType(Type) :
"the variant type--a single element of a type determined at run-time."
def __init__(self) :
super().__init__(TYPE.VARIANT)
#end __init__
@property
def signature(self) :
return \
chr(TYPE.VARIANT.value)
#end signature
def __repr__(self) :
return \
"%s()" % type(self).__name__
#end __repr__
def __eq__(t1, t2) :
return \
isinstance(t2, VariantType)
#end __eq__
def validate(self, val) :
if not isinstance(val, (tuple, list)) or len(val) != 2 :
raise ValueError("expecting a (type, value) pair")
#end if
valtype, val = val
valtype = parse_single_signature(valtype)
return \
(valtype, valtype.validate(val))
#end validate
#end VariantType
class StructType(Type) :
"a sequence of one or more arbitrary types (empty structs are not allowed)."
__slots__ = ("elttypes",)
def __init__(self, *types) :
if len(types) == 0 :
raise TypeError("must have at least one element type")
#end if
if not all(isinstance(t, Type) for t in types) :
raise TypeError("struct elements must be Types")
#end if
super().__init__(TYPE.STRUCT)
self.elttypes = tuple(types)
#end __init__
def __repr__(self) :
return \
"%s(%s)" % (type(self).__name__, repr(self.elttypes))
#end __repr__
@property
def signature(self) :
return \
"(%s)" % "".join(t.signature for t in self.elttypes)
#end signature
def __eq__(t1, t2) :
return \
(
isinstance(t2, StructType)
and
len(t1.elttypes) == len(t2.elttypes)
and
all(e1 == e2 for e1, e2 in zip(t1.elttypes, t2.elttypes))
)
#end __eq__
def validate(self, val) :
if not isinstance(val, (tuple, list)) or len(val) != len(self.elttypes) :
raise TypeError \
(
"need a list or tuple of %d elements, not %s" % (len(self.elttypes), repr(val))
)
#end if
return \
type(val)(elttype.validate(elt) for elttype, elt in zip(self.elttypes, val))
#end validate
#end StructType
class ArrayType(Type) :
"an array of zero or more elements all of the same type."
__slots__ = ("elttype",)
def __init__(self, elttype) :
if not isinstance(elttype, Type) :
raise TypeError("invalid array element type")
#end if
super().__init__(TYPE.ARRAY)
self.elttype = elttype
#end __init__
def __repr__(self) :
return \
"%s[%s]" % (type(self).__name__, repr(self.elttype))
#end __repr__
@property
def signature(self) :
return \
chr(TYPE.ARRAY.value) + self.elttype.signature
#end signature
def __eq__(t1, t2) :
return \
isinstance(t2, ArrayType) and t1.elttype == t2.elttype
#end __eq__
def validate(self, val) :
if not isinstance(val, (tuple, list)) :
raise TypeError("need a tuple or list, not %s: %s" % (type(val).__name__, repr(val)))
#end if
return \
type(val)(self.elttype.validate(elt) for elt in val)
#end validate
#end ArrayType
class DictType(Type) :
"a dictionary mapping zero or more keys to values."
__slots__ = ("keytype", "valuetype")
def __init__(self, keytype, valuetype) :
if not isinstance(keytype, BasicType) or not isinstance(valuetype, Type) :
raise TypeError("invalid dict key/value type")
#end if
super().__init__(TYPE.ARRAY)
self.keytype = keytype
self.valuetype = valuetype
#end keytype
def __repr__(self) :
return \
"%s[%s : %s]" % (type(self).__name__, repr(self.keytype), repr(self.valuetype))
#end __repr__
@property
def signature(self) :
return \
"%s{%s%s}" % (chr(TYPE.ARRAY.value), self.keytype.signature, self.valuetype.signature)
#end signature
@property
def entry_signature(self) :
"signature for a dict entry."
return \
"{%s%s}" % (self.keytype.signature, self.valuetype.signature)
#end entry_signature
def __eq__(t1, t2) :
return \
isinstance(t2, DictType) and t1.keytype == t2.keytype and t1.valuetype == t2.valuetype
#end __eq__
def validate(self, val) :
if not isinstance(val, dict) :
raise TypeError("need a dict, not %s: %s" % (type(val).__name__, repr(val)))
#end if
return \
type(val) \
(
(self.keytype.validate(key), self.valuetype.validate(val[key]))
for key in val
)
#end validate
#end DictType
def data_key(data) :
"returns a unique value that allows data to be used as a dict/set key."
if isinstance(data, (bytes, float, frozenset, int, str, tuple)) :
result = data
else :
# data itself is non-hashable
result = id(data)
#end if
return \
result
#end data_key
#+
# Library prototypes
#-
# from dbus-connection.h:
dbus.dbus_connection_open.restype = ct.c_void_p
dbus.dbus_connection_open.argtypes = (ct.c_char_p, DBUS.ErrorPtr)
dbus.dbus_connection_open_private.restype = ct.c_void_p
dbus.dbus_connection_open_private.argtypes = (ct.c_char_p, DBUS.ErrorPtr)
dbus.dbus_connection_ref.restype = ct.c_void_p
dbus.dbus_connection_ref.argtypes = (ct.c_void_p,)
dbus.dbus_connection_unref.restype = None
dbus.dbus_connection_unref.argtypes = (ct.c_void_p,)
dbus.dbus_connection_close.restype = None
dbus.dbus_connection_close.argtypes = (ct.c_void_p,)
dbus.dbus_connection_get_is_connected.restype = DBUS.bool_t
dbus.dbus_connection_get_is_connected.argtypes = (ct.c_void_p,)
dbus.dbus_connection_get_is_authenticated.restype = DBUS.bool_t
dbus.dbus_connection_get_is_authenticated.argtypes = (ct.c_void_p,)
dbus.dbus_connection_get_is_anonymous.restype = DBUS.bool_t
dbus.dbus_connection_get_is_anonymous.argtypes = (ct.c_void_p,)
dbus.dbus_connection_get_server_id.restype = ct.c_void_p
dbus.dbus_connection_get_server_id.argtypes = (ct.c_void_p,)
dbus.dbus_connection_can_send_type.restype = DBUS.bool_t
dbus.dbus_connection_can_send_type.argtypes = (ct.c_void_p, ct.c_int)
dbus.dbus_connection_set_exit_on_disconnect.restype = None
dbus.dbus_connection_set_exit_on_disconnect.argtypes = (ct.c_void_p, DBUS.bool_t)
dbus.dbus_connection_preallocate_send.restype = ct.c_void_p
dbus.dbus_connection_preallocate_send.argtypes = (ct.c_void_p,)
dbus.dbus_connection_free_preallocated_send.restype = None
dbus.dbus_connection_free_preallocated_send.argtypes = (ct.c_void_p, ct.c_void_p)
dbus.dbus_connection_send_preallocated.restype = None
dbus.dbus_connection_send_preallocated.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.POINTER(ct.c_uint))
dbus.dbus_connection_has_messages_to_send.restype = DBUS.bool_t
dbus.dbus_connection_has_messages_to_send.argtypes = (ct.c_void_p,)
dbus.dbus_connection_send.restype = DBUS.bool_t
dbus.dbus_connection_send.argtypes = (ct.c_void_p, ct.c_void_p, ct.POINTER(ct.c_uint))
dbus.dbus_connection_send_with_reply.restype = DBUS.bool_t
dbus.dbus_connection_send_with_reply.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_int)
dbus.dbus_connection_send_with_reply_and_block.restype = ct.c_void_p
dbus.dbus_connection_send_with_reply_and_block.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_int, DBUS.ErrorPtr)
dbus.dbus_connection_flush.restype = None
dbus.dbus_connection_flush.argtypes = (ct.c_void_p,)
dbus.dbus_connection_read_write_dispatch.restype = DBUS.bool_t
dbus.dbus_connection_read_write_dispatch.argtypes = (ct.c_void_p, ct.c_int)
dbus.dbus_connection_read_write.restype = DBUS.bool_t
dbus.dbus_connection_read_write.argtypes = (ct.c_void_p, ct.c_int)
dbus.dbus_connection_borrow_message.restype = ct.c_void_p
dbus.dbus_connection_borrow_message.argtypes = (ct.c_void_p,)
dbus.dbus_connection_return_message.restype = None
dbus.dbus_connection_return_message.argtypes = (ct.c_void_p, ct.c_void_p)
dbus.dbus_connection_steal_borrowed_message.restype = None
dbus.dbus_connection_steal_borrowed_message.argtypes = (ct.c_void_p, ct.c_void_p)
dbus.dbus_connection_pop_message.restype = ct.c_void_p
dbus.dbus_connection_pop_message.argtypes = (ct.c_void_p,)
dbus.dbus_connection_get_dispatch_status.restype = ct.c_uint
dbus.dbus_connection_get_dispatch_status.argtypes = (ct.c_void_p,)
dbus.dbus_connection_dispatch.restype = ct.c_uint
dbus.dbus_connection_dispatch.argtypes = (ct.c_void_p,)
dbus.dbus_connection_set_watch_functions.restype = DBUS.bool_t
dbus.dbus_connection_set_watch_functions.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_void_p)
dbus.dbus_connection_set_timeout_functions.restype = DBUS.bool_t
dbus.dbus_connection_set_timeout_functions.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_void_p)
dbus.dbus_connection_set_wakeup_main_function.restype = None
dbus.dbus_connection_set_wakeup_main_function.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_void_p)
dbus.dbus_connection_set_dispatch_status_function.restype = None
dbus.dbus_connection_set_dispatch_status_function.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_void_p)
dbus.dbus_connection_get_unix_user.restype = DBUS.bool_t
dbus.dbus_connection_get_unix_user.argtypes = (ct.c_void_p, ct.POINTER(ct.c_ulong))
dbus.dbus_connection_get_unix_process_id.restype = DBUS.bool_t
dbus.dbus_connection_get_unix_process_id.argtypes = (ct.c_void_p, ct.POINTER(ct.c_ulong))
dbus.dbus_connection_get_adt_audit_session_data.restype = DBUS.bool_t
dbus.dbus_connection_get_adt_audit_session_data.argtypes = (ct.c_void_p, ct.c_void_p, ct.POINTER(ct.c_uint))
dbus.dbus_connection_set_unix_user_function.restype = None
dbus.dbus_connection_set_unix_user_function.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_void_p)
dbus.dbus_connection_get_windows_user.restype = DBUS.bool_t
dbus.dbus_connection_get_windows_user.argtypes = (ct.c_void_p, ct.c_void_p)
dbus.dbus_connection_set_windows_user_function.restype = None
dbus.dbus_connection_set_windows_user_function.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_void_p)
dbus.dbus_connection_set_allow_anonymous.restype = None
dbus.dbus_connection_set_allow_anonymous.argtypes = (ct.c_void_p, DBUS.bool_t)
dbus.dbus_connection_set_route_peer_messages.restype = None
dbus.dbus_connection_set_route_peer_messages.argtypes = (ct.c_void_p, DBUS.bool_t)
dbus.dbus_connection_add_filter.restype = DBUS.bool_t
dbus.dbus_connection_add_filter.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_void_p)
dbus.dbus_connection_remove_filter.restype = None
dbus.dbus_connection_remove_filter.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_void_p)
dbus.dbus_connection_allocate_data_slot.restype = DBUS.bool_t
dbus.dbus_connection_allocate_data_slot.argtypes = (ct.POINTER(ct.c_uint),)
dbus.dbus_connection_free_data_slot.restype = None
dbus.dbus_connection_free_data_slot.argtypes = (ct.c_uint,)
dbus.dbus_connection_set_data.restype = DBUS.bool_t
dbus.dbus_connection_set_data.argtypes = (ct.c_void_p, ct.c_uint, ct.c_void_p, ct.c_void_p)
dbus.dbus_connection_get_data.restype = ct.c_void_p
dbus.dbus_connection_get_data.argtypes = (ct.c_void_p, ct.c_uint)
dbus.dbus_connection_set_change_sigpipe.restype = None
dbus.dbus_connection_set_change_sigpipe.argtypes = (DBUS.bool_t,)
dbus.dbus_connection_set_max_message_size.restype = None
dbus.dbus_connection_set_max_message_size.argtypes = (ct.c_void_p, ct.c_long)
dbus.dbus_connection_get_max_message_size.restype = ct.c_long
dbus.dbus_connection_get_max_message_size.argtypes = (ct.c_void_p,)
dbus.dbus_connection_set_max_received_size.restype = None
dbus.dbus_connection_set_max_received_size.argtypes = (ct.c_void_p, ct.c_long)
dbus.dbus_connection_get_max_received_size.restype = ct.c_long
dbus.dbus_connection_get_max_received_size.argtypes = (ct.c_void_p,)
dbus.dbus_connection_set_max_message_unix_fds.restype = None
dbus.dbus_connection_set_max_message_unix_fds.argtypes = (ct.c_void_p, ct.c_long)
dbus.dbus_connection_get_max_message_unix_fds.restype = ct.c_long
dbus.dbus_connection_get_max_message_unix_fds.argtypes = (ct.c_void_p,)
dbus.dbus_connection_set_max_received_unix_fds.restype = None
dbus.dbus_connection_set_max_received_unix_fds.argtypes = (ct.c_void_p, ct.c_long)
dbus.dbus_connection_get_max_received_unix_fds.restype = ct.c_long
dbus.dbus_connection_get_max_received_unix_fds.argtypes = (ct.c_void_p,)
dbus.dbus_connection_get_outgoing_size.restype = ct.c_long
dbus.dbus_connection_get_outgoing_size.argtypes = (ct.c_void_p,)
dbus.dbus_connection_get_outgoing_unix_fds.restype = ct.c_long
dbus.dbus_connection_get_outgoing_unix_fds.argtypes = (ct.c_void_p,)
dbus.dbus_connection_register_object_path.restype = DBUS.bool_t
dbus.dbus_connection_register_object_path.argtypes = (ct.c_void_p, ct.c_char_p, DBUS.ObjectPathVTablePtr, ct.c_void_p)
dbus.dbus_connection_try_register_object_path.restype = DBUS.bool_t
dbus.dbus_connection_try_register_object_path.argtypes = (ct.c_void_p, ct.c_char_p, DBUS.ObjectPathVTablePtr, ct.c_void_p, DBUS.ErrorPtr)
dbus.dbus_connection_register_fallback.restype = DBUS.bool_t
dbus.dbus_connection_register_fallback.argtypes = (ct.c_void_p, ct.c_char_p, DBUS.ObjectPathVTablePtr, ct.c_void_p)
dbus.dbus_connection_try_register_fallback.restype = DBUS.bool_t
dbus.dbus_connection_try_register_fallback.argtypes = (ct.c_void_p, ct.c_char_p, DBUS.ObjectPathVTablePtr, ct.c_void_p, DBUS.ErrorPtr)
dbus.dbus_connection_get_object_path_data.restype = DBUS.bool_t
dbus.dbus_connection_get_object_path_data.argtypes = (ct.c_void_p, ct.c_char_p, ct.c_void_p)
dbus.dbus_connection_list_registered.restype = DBUS.bool_t
dbus.dbus_connection_list_registered.argtypes = (ct.c_void_p, ct.c_char_p, ct.c_void_p)
dbus.dbus_connection_get_unix_fd.restype = DBUS.bool_t
dbus.dbus_connection_get_unix_fd.argtypes = (ct.c_void_p, ct.POINTER(ct.c_int))
dbus.dbus_connection_get_socket.restype = DBUS.bool_t
dbus.dbus_connection_get_socket.argtypes = (ct.c_void_p, ct.POINTER(ct.c_int))
dbus.dbus_connection_unregister_object_path.restype = DBUS.bool_t
dbus.dbus_connection_unregister_object_path.argtypes = (ct.c_void_p, ct.c_char_p)
dbus.dbus_watch_get_unix_fd.restype = ct.c_int
dbus.dbus_watch_get_unix_fd.argtypes = (ct.c_void_p,)
dbus.dbus_watch_get_socket.restype = ct.c_int
dbus.dbus_watch_get_socket.argtypes = (ct.c_void_p,)
dbus.dbus_watch_get_flags.restype = ct.c_uint
dbus.dbus_watch_get_flags.argtypes = (ct.c_void_p,)
dbus.dbus_watch_get_data.restype = ct.c_void_p
dbus.dbus_watch_get_data.argtypes = (ct.c_void_p,)
dbus.dbus_watch_set_data.restype = None
dbus.dbus_watch_set_data.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_void_p)
dbus.dbus_watch_handle.restype = DBUS.bool_t
dbus.dbus_watch_handle.argtypes = (ct.c_void_p, ct.c_uint)
dbus.dbus_watch_get_enabled.restype = DBUS.bool_t
dbus.dbus_watch_get_enabled.argtypes = (ct.c_void_p,)
dbus.dbus_timeout_get_interval.restype = ct.c_int
dbus.dbus_timeout_get_interval.argtypes = (ct.c_void_p,)
dbus.dbus_timeout_get_data.restype = ct.c_void_p
dbus.dbus_timeout_get_data.argtypes = (ct.c_void_p,)
dbus.dbus_timeout_set_data.restype = None
dbus.dbus_timeout_set_data.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_void_p)
dbus.dbus_timeout_handle.restype = DBUS.bool_t
dbus.dbus_timeout_handle.argtypes = (ct.c_void_p,)
dbus.dbus_timeout_get_enabled.restype = DBUS.bool_t
dbus.dbus_timeout_get_enabled.argtypes = (ct.c_void_p,)
# from dbus-bus.h:
dbus.dbus_bus_get.restype = ct.c_void_p
dbus.dbus_bus_get.argtypes = (ct.c_uint, DBUS.ErrorPtr)
dbus.dbus_bus_get_private.restype = ct.c_void_p
dbus.dbus_bus_get_private.argtypes = (ct.c_uint, DBUS.ErrorPtr)
dbus.dbus_bus_register.restype = DBUS.bool_t
dbus.dbus_bus_register.argtypes = (ct.c_void_p, DBUS.ErrorPtr)
dbus.dbus_bus_set_unique_name.restype = DBUS.bool_t
dbus.dbus_bus_set_unique_name.argtypes = (ct.c_void_p, ct.c_char_p)
dbus.dbus_bus_get_unique_name.restype = ct.c_char_p
dbus.dbus_bus_get_unique_name.argtypes = (ct.c_void_p,)
dbus.dbus_bus_get_unix_user.restype = ct.c_ulong
dbus.dbus_bus_get_unix_user.argtypes = (ct.c_void_p, ct.c_char_p, DBUS.ErrorPtr)
dbus.dbus_bus_get_id.restype = ct.c_void_p
dbus.dbus_bus_get_id.argtypes = (ct.c_void_p, DBUS.ErrorPtr)
dbus.dbus_bus_request_name.restype = ct.c_int
dbus.dbus_bus_request_name.argtypes = (ct.c_void_p, ct.c_char_p, ct.c_uint, DBUS.ErrorPtr)
dbus.dbus_bus_release_name.restype = ct.c_int
dbus.dbus_bus_release_name.argtypes = (ct.c_void_p, ct.c_char_p, DBUS.ErrorPtr)
dbus.dbus_bus_name_has_owner.restype = DBUS.bool_t
dbus.dbus_bus_name_has_owner.argtypes = (ct.c_void_p, ct.c_char_p, DBUS.ErrorPtr)
dbus.dbus_bus_start_service_by_name.restype = DBUS.bool_t
dbus.dbus_bus_start_service_by_name.argtypes = (ct.c_void_p, ct.c_char_p, ct.c_uint, ct.POINTER(ct.c_uint), DBUS.ErrorPtr)
dbus.dbus_bus_add_match.restype = None
dbus.dbus_bus_add_match.argtypes = (ct.c_void_p, ct.c_char_p, DBUS.ErrorPtr)
dbus.dbus_bus_remove_match.restype = None
dbus.dbus_bus_remove_match.argtypes = (ct.c_void_p, ct.c_char_p, DBUS.ErrorPtr)
dbus.dbus_error_init.restype = None
dbus.dbus_error_init.argtypes = (DBUS.ErrorPtr,)
dbus.dbus_error_free.restype = None
dbus.dbus_error_free.argtypes = (DBUS.ErrorPtr,)
dbus.dbus_move_error.restype = None
dbus.dbus_move_error.argtypes = (DBUS.ErrorPtr, DBUS.ErrorPtr)
dbus.dbus_error_has_name.restype = DBUS.bool_t
dbus.dbus_error_has_name.argtypes = (DBUS.ErrorPtr, ct.c_char_p)
dbus.dbus_error_is_set.restype = DBUS.bool_t
dbus.dbus_error_is_set.argtypes = (DBUS.ErrorPtr,)
dbus.dbus_set_error.restype = None
dbus.dbus_set_error.argtypes = (DBUS.ErrorPtr, ct.c_char_p, ct.c_char_p, ct.c_char_p)
# note I cant handle varargs
# from dbus-pending-call.h:
dbus.dbus_pending_call_ref.restype = ct.c_void_p
dbus.dbus_pending_call_ref.argtypes = (ct.c_void_p,)
dbus.dbus_pending_call_unref.restype = None
dbus.dbus_pending_call_unref.argtypes = (ct.c_void_p,)
dbus.dbus_pending_call_set_notify.restype = DBUS.bool_t
dbus.dbus_pending_call_set_notify.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_void_p)
dbus.dbus_pending_call_cancel.restype = None
dbus.dbus_pending_call_cancel.argtypes = (ct.c_void_p,)
dbus.dbus_pending_call_get_completed.restype = DBUS.bool_t
dbus.dbus_pending_call_get_completed.argtypes = (ct.c_void_p,)
dbus.dbus_pending_call_steal_reply.restype = ct.c_void_p
dbus.dbus_pending_call_steal_reply.argtypes = (ct.c_void_p,)
dbus.dbus_pending_call_block.restype = None
dbus.dbus_pending_call_block.argtypes = (ct.c_void_p,)
dbus.dbus_pending_call_allocate_data_slot.restype = DBUS.bool_t
dbus.dbus_pending_call_allocate_data_slot.argtypes = (ct.POINTER(ct.c_int),)
dbus.dbus_pending_call_free_data_slot.restype = None
dbus.dbus_pending_call_free_data_slot.argtypes = (ct.c_int,)
dbus.dbus_pending_call_set_data.restype = DBUS.bool_t
dbus.dbus_pending_call_set_data.argtypes = (ct.c_void_p, ct.c_int, ct.c_void_p, ct.c_void_p)
dbus.dbus_pending_call_get_data.restype = ct.c_void_p
dbus.dbus_pending_call_get_data.argtypes = (ct.c_void_p, ct.c_int)
# from dbus-message.h:
dbus.dbus_message_new.restype = ct.c_void_p
dbus.dbus_message_new.argtypes = (ct.c_int,)
dbus.dbus_message_new_method_call.restype = ct.c_void_p
dbus.dbus_message_new_method_call.argtypes = (ct.c_char_p, ct.c_char_p, ct.c_char_p, ct.c_char_p)
dbus.dbus_message_new_method_return.restype = ct.c_void_p
dbus.dbus_message_new_method_return.argtypes = (ct.c_void_p,)
dbus.dbus_message_new_signal.restype = ct.c_void_p
dbus.dbus_message_new_signal.argtypes = (ct.c_char_p, ct.c_char_p, ct.c_char_p)
dbus.dbus_message_new_error.restype = ct.c_void_p
dbus.dbus_message_new_error.argtypes = (ct.c_void_p, ct.c_char_p, ct.c_char_p)
dbus.dbus_message_new_error_printf.restype = ct.c_void_p
dbus.dbus_message_new_error_printf.argtypes = (ct.c_void_p, ct.c_char_p, ct.c_char_p, ct.c_char_p)
# note I cant handle varargs
dbus.dbus_message_copy.restype = ct.c_void_p
dbus.dbus_message_copy.argtypes = (ct.c_void_p,)
dbus.dbus_message_ref.restype = ct.c_void_p
dbus.dbus_message_ref.argtypes = (ct.c_void_p,)
dbus.dbus_message_unref.restype = None
dbus.dbus_message_unref.argtypes = (ct.c_void_p,)
dbus.dbus_message_get_type.restype = ct.c_int
dbus.dbus_message_get_type.argtypes = (ct.c_void_p,)
dbus.dbus_message_set_path.restype = DBUS.bool_t
dbus.dbus_message_set_path.argtypes = (ct.c_void_p, ct.c_char_p)
dbus.dbus_message_get_path.restype = ct.c_char_p
dbus.dbus_message_get_path.argtypes = (ct.c_void_p,)
dbus.dbus_message_has_path.restype = DBUS.bool_t
dbus.dbus_message_has_path.argtypes = (ct.c_void_p, ct.c_char_p)
dbus.dbus_message_set_interface.restype = DBUS.bool_t
dbus.dbus_message_set_interface.argtypes = (ct.c_void_p, ct.c_char_p)
dbus.dbus_message_get_interface.restype = ct.c_char_p
dbus.dbus_message_get_interface.argtypes = (ct.c_void_p,)
dbus.dbus_message_has_interface.restype = DBUS.bool_t
dbus.dbus_message_has_interface.argtypes = (ct.c_void_p, ct.c_char_p)
dbus.dbus_message_set_member.restype = DBUS.bool_t
dbus.dbus_message_set_member.argtypes = (ct.c_void_p, ct.c_char_p)
dbus.dbus_message_get_member.restype = ct.c_char_p
dbus.dbus_message_get_member.argtypes = (ct.c_void_p,)
dbus.dbus_message_has_member.restype = DBUS.bool_t
dbus.dbus_message_has_member.argtypes = (ct.c_void_p, ct.c_char_p)
dbus.dbus_message_set_error_name.restype = DBUS.bool_t
dbus.dbus_message_set_error_name.argtypes = (ct.c_void_p, ct.c_char_p)
dbus.dbus_message_get_error_name.restype = ct.c_char_p
dbus.dbus_message_get_error_name.argtypes = (ct.c_void_p,)
dbus.dbus_message_set_destination.restype = DBUS.bool_t
dbus.dbus_message_set_destination.argtypes = (ct.c_void_p, ct.c_char_p)
dbus.dbus_message_get_destination.restype = ct.c_char_p
dbus.dbus_message_get_destination.argtypes = (ct.c_void_p,)
dbus.dbus_message_set_sender.restype = DBUS.bool_t
dbus.dbus_message_set_sender.argtypes = (ct.c_void_p, ct.c_char_p)
dbus.dbus_message_get_sender.restype = ct.c_char_p
dbus.dbus_message_get_sender.argtypes = (ct.c_void_p,)
dbus.dbus_message_get_signature.restype = ct.c_char_p
dbus.dbus_message_get_signature.argtypes = (ct.c_void_p,)
dbus.dbus_message_set_no_reply.restype = None
dbus.dbus_message_set_no_reply.argtypes = (ct.c_void_p, DBUS.bool_t)
dbus.dbus_message_get_no_reply.restype = DBUS.bool_t
dbus.dbus_message_get_no_reply.argtypes = (ct.c_void_p,)
dbus.dbus_message_is_method_call.restype = DBUS.bool_t
dbus.dbus_message_is_method_call.argtypes = (ct.c_void_p, ct.c_char_p, ct.c_char_p)
dbus.dbus_message_is_signal.restype = DBUS.bool_t
dbus.dbus_message_is_signal.argtypes = (ct.c_void_p, ct.c_char_p, ct.c_char_p)
dbus.dbus_message_is_error.restype = DBUS.bool_t
dbus.dbus_message_is_error.argtypes = (ct.c_void_p, ct.c_char_p)
dbus.dbus_message_has_destination.restype = DBUS.bool_t
dbus.dbus_message_has_destination.argtypes = (ct.c_void_p, ct.c_char_p)
dbus.dbus_message_has_sender.restype = DBUS.bool_t
dbus.dbus_message_has_sender.argtypes = (ct.c_void_p, ct.c_char_p)
dbus.dbus_message_has_signature.restype = DBUS.bool_t
dbus.dbus_message_has_signature.argtypes = (ct.c_void_p, ct.c_char_p)
dbus.dbus_message_get_serial.restype = ct.c_uint
dbus.dbus_message_get_serial.argtypes = (ct.c_void_p,)
dbus.dbus_message_set_serial.restype = None
dbus.dbus_message_set_serial.argtypes = (ct.c_void_p, ct.c_uint)
dbus.dbus_message_set_reply_serial.restype = DBUS.bool_t
dbus.dbus_message_set_reply_serial.argtypes = (ct.c_void_p, ct.c_uint)
dbus.dbus_message_get_reply_serial.restype = ct.c_uint
dbus.dbus_message_get_reply_serial.argtypes = (ct.c_void_p,)
dbus.dbus_message_set_auto_start.restype = None
dbus.dbus_message_set_auto_start.argtypes = (ct.c_void_p, DBUS.bool_t)
dbus.dbus_message_get_auto_start.restype = DBUS.bool_t
dbus.dbus_message_get_auto_start.argtypes = (ct.c_void_p,)
dbus.dbus_message_get_path_decomposed.restype = DBUS.bool_t
dbus.dbus_message_get_path_decomposed.argtypes = (ct.c_void_p, ct.c_void_p)
dbus.dbus_message_append_args.restype = DBUS.bool_t
dbus.dbus_message_append_args.argtypes = (ct.c_void_p, ct.c_int, ct.c_void_p, ct.c_int)
# note I cant handle varargs
# probably cannot make use of dbus.dbus_message_append_args_valist
dbus.dbus_message_get_args.restype = DBUS.bool_t
dbus.dbus_message_get_args.argtypes = (ct.c_void_p, DBUS.ErrorPtr, ct.c_int, ct.c_void_p, ct.c_int)
# note I cant handle varargs
# probably cannot make use of dbus.dbus_message_get_args_valist
dbus.dbus_message_contains_unix_fds.restype = DBUS.bool_t
dbus.dbus_message_contains_unix_fds.argtypes = (ct.c_void_p,)
dbus.dbus_message_iter_init.restype = DBUS.bool_t
dbus.dbus_message_iter_init.argtypes = (ct.c_void_p, DBUS.MessageIterPtr)
dbus.dbus_message_iter_has_next.restype = DBUS.bool_t
dbus.dbus_message_iter_has_next.argtypes = (DBUS.MessageIterPtr,)
dbus.dbus_message_iter_next.restype = DBUS.bool_t
dbus.dbus_message_iter_next.argtypes = (DBUS.MessageIterPtr,)
dbus.dbus_message_iter_get_signature.restype = ct.c_void_p
dbus.dbus_message_iter_next.argtypes = (DBUS.MessageIterPtr,)
dbus.dbus_message_iter_get_signature.restype = ct.c_void_p
dbus.dbus_message_iter_get_signature.argtypes = (DBUS.MessageIterPtr,)
dbus.dbus_message_iter_get_arg_type.restype = ct.c_int
dbus.dbus_message_iter_get_arg_type.argtypes = (DBUS.MessageIterPtr,)
dbus.dbus_message_iter_get_element_type.restype = ct.c_int
dbus.dbus_message_iter_get_element_type.argtypes = (DBUS.MessageIterPtr,)
dbus.dbus_message_iter_recurse.restype = None
dbus.dbus_message_iter_recurse.argtypes = (DBUS.MessageIterPtr, DBUS.MessageIterPtr)
dbus.dbus_message_iter_get_basic.restype = None
dbus.dbus_message_iter_get_basic.argtypes = (DBUS.MessageIterPtr, ct.c_void_p)
if hasattr(dbus, "dbus_message_iter_get_element_count") :
dbus.dbus_message_iter_get_element_count.restype = ct.c_int
dbus.dbus_message_iter_get_element_count.argtypes = (DBUS.MessageIterPtr,)
#end if
# dbus_message_iter_get_array_len deprecated
dbus.dbus_message_iter_get_fixed_array.restype = None
dbus.dbus_message_iter_get_fixed_array.argtypes = (DBUS.MessageIterPtr, ct.c_void_p, ct.POINTER(ct.c_int))
dbus.dbus_message_iter_init_append.restype = None
dbus.dbus_message_iter_init_append.argtypes = (ct.c_void_p, DBUS.MessageIterPtr)
dbus.dbus_message_iter_append_basic.restype = DBUS.bool_t
dbus.dbus_message_iter_append_basic.argtypes = (DBUS.MessageIterPtr, ct.c_int, ct.c_void_p)
dbus.dbus_message_iter_append_fixed_array.restype = DBUS.bool_t
dbus.dbus_message_iter_append_fixed_array.argtypes = (DBUS.MessageIterPtr, ct.c_int, ct.c_void_p, ct.c_int)
dbus.dbus_message_iter_open_container.restype = DBUS.bool_t
dbus.dbus_message_iter_open_container.argtypes = (DBUS.MessageIterPtr, ct.c_int, ct.c_char_p, DBUS.MessageIterPtr)
dbus.dbus_message_iter_close_container.restype = DBUS.bool_t
dbus.dbus_message_iter_close_container.argtypes = (DBUS.MessageIterPtr, DBUS.MessageIterPtr)
dbus.dbus_message_iter_abandon_container.restype = None
dbus.dbus_message_iter_abandon_container.argtypes = (DBUS.MessageIterPtr, DBUS.MessageIterPtr)
dbus.dbus_message_lock.restype = None
dbus.dbus_message_lock.argtypes = (DBUS.MessageIterPtr,)
dbus.dbus_set_error_from_message.restype = DBUS.bool_t
dbus.dbus_set_error_from_message.argtypes = (DBUS.ErrorPtr, ct.c_void_p)
dbus.dbus_message_allocate_data_slot.restype = DBUS.bool_t
dbus.dbus_message_allocate_data_slot.argtypes = (ct.POINTER(ct.c_int),)
dbus.dbus_message_free_data_slot.restype = None
dbus.dbus_message_free_data_slot.argtypes = (ct.POINTER(ct.c_int),)
dbus.dbus_message_set_data.restype = DBUS.bool_t
dbus.dbus_message_set_data.argtypes = (ct.c_void_p, ct.c_int, ct.c_void_p, ct.c_void_p)
dbus.dbus_message_get_data.restype = ct.c_void_p
dbus.dbus_message_get_data.argtypes = (ct.c_void_p, ct.c_int)
dbus.dbus_message_type_from_string.restype = ct.c_int
dbus.dbus_message_type_from_string.argtypes = (ct.c_char_p,)
dbus.dbus_message_type_to_string.restype = ct.c_char_p
dbus.dbus_message_type_to_string.argtypes = (ct.c_int,)
dbus.dbus_message_marshal.restype = DBUS.bool_t
dbus.dbus_message_marshal.argtypes = (ct.c_void_p, ct.c_void_p, ct.POINTER(ct.c_int))
dbus.dbus_message_demarshal.restype = ct.c_void_p
dbus.dbus_message_demarshal.argtypes = (ct.c_void_p, ct.c_int, DBUS.ErrorPtr)
dbus.dbus_message_demarshal_bytes_needed.restype = ct.c_int
dbus.dbus_message_demarshal_bytes_needed.argtypes = (ct.c_void_p, ct.c_int)
if hasattr(dbus, "dbus_message_set_allow_interactive_authorization") :
dbus.dbus_message_set_allow_interactive_authorization.restype = None
dbus.dbus_message_set_allow_interactive_authorization.argtypes = (ct.c_void_p, DBUS.bool_t)
#end if
if hasattr(dbus, "dbus_message_get_allow_interactive_authorization") :
dbus.dbus_message_get_allow_interactive_authorization.restype = DBUS.bool_t
dbus.dbus_message_get_allow_interactive_authorization.argtypes = (ct.c_void_p,)
#end if
# from dbus-memory.h:
dbus.dbus_malloc.restype = ct.c_void_p
dbus.dbus_malloc.argtypes = (ct.c_size_t,)
dbus.dbus_malloc0.restype = ct.c_void_p
dbus.dbus_malloc0.argtypes = (ct.c_size_t,)
dbus.dbus_realloc.restype = ct.c_void_p
dbus.dbus_realloc.argtypes = (ct.c_void_p, ct.c_size_t)
dbus.dbus_free.restype = None
dbus.dbus_free.argtypes = (ct.c_void_p,)
dbus.dbus_free_string_array.restype = None
dbus.dbus_free_string_array.argtypes = (ct.c_void_p,)
# from dbus-misc.h:
dbus.dbus_get_local_machine_id.restype = ct.c_void_p
dbus.dbus_get_local_machine_id.argtypes = ()
dbus.dbus_get_version.restype = None
dbus.dbus_get_version.argtypes = (ct.POINTER(ct.c_int), ct.POINTER(ct.c_int), ct.POINTER(ct.c_int))
dbus.dbus_setenv.restype = DBUS.bool_t
dbus.dbus_setenv.argtypes = (ct.c_char_p, ct.c_char_p)
# from dbus-address.h:
dbus.dbus_parse_address.restype = DBUS.bool_t
dbus.dbus_parse_address.argtypes = (ct.c_char_p, ct.c_void_p, ct.POINTER(ct.c_int), DBUS.ErrorPtr)
dbus.dbus_address_entry_get_value.restype = ct.c_char_p
dbus.dbus_address_entry_get_value.argtypes = (ct.c_void_p, ct.c_char_p)
dbus.dbus_address_entry_get_method.restype = ct.c_char_p
dbus.dbus_address_entry_get_method.argtypes = (ct.c_void_p,)
dbus.dbus_address_entries_free.restype = None
dbus.dbus_address_entries_free.argtypes = (ct.c_void_p,)
dbus.dbus_address_escape_value.restype = ct.c_void_p
dbus.dbus_address_escape_value.argtypes = (ct.c_char_p,)
dbus.dbus_address_unescape_value.restype = ct.c_void_p
dbus.dbus_address_unescape_value.argtypes = (ct.c_char_p, DBUS.ErrorPtr)
# from dbus-signature.h:
dbus.dbus_signature_iter_init.restype = None
dbus.dbus_signature_iter_init.argtypes = (DBUS.SignatureIterPtr, ct.c_char_p)
dbus.dbus_signature_iter_get_current_type.restype = ct.c_int
dbus.dbus_signature_iter_get_current_type.argtypes = (DBUS.SignatureIterPtr,)
dbus.dbus_signature_iter_get_signature.restype = ct.c_void_p
dbus.dbus_signature_iter_get_signature.argtypes = (DBUS.SignatureIterPtr,)
dbus.dbus_signature_iter_get_element_type.restype = ct.c_int
dbus.dbus_signature_iter_get_element_type.argtypes = (DBUS.SignatureIterPtr,)
dbus.dbus_signature_iter_next.restype = DBUS.bool_t
dbus.dbus_signature_iter_next.argtypes = (DBUS.SignatureIterPtr,)
dbus.dbus_signature_iter_recurse.restype = None
dbus.dbus_signature_iter_recurse.argtypes = (DBUS.SignatureIterPtr, DBUS.SignatureIterPtr)
dbus.dbus_signature_validate.restype = DBUS.bool_t
dbus.dbus_signature_validate.argtypes = (ct.c_char_p, DBUS.ErrorPtr)
dbus.dbus_signature_validate_single.restype = DBUS.bool_t
dbus.dbus_signature_validate_single.argtypes = (ct.c_char_p, DBUS.ErrorPtr)
dbus.dbus_type_is_valid.restype = DBUS.bool_t
dbus.dbus_type_is_valid.argtypes = (ct.c_int,)
dbus.dbus_type_is_basic.restype = DBUS.bool_t
dbus.dbus_type_is_basic.argtypes = (ct.c_int,)
dbus.dbus_type_is_container.restype = DBUS.bool_t
dbus.dbus_type_is_container.argtypes = (ct.c_int,)
dbus.dbus_type_is_fixed.restype = DBUS.bool_t
dbus.dbus_type_is_fixed.argtypes = (ct.c_int,)
# from dbus-syntax.h:
dbus.dbus_validate_path.restype = DBUS.bool_t
dbus.dbus_validate_path.argtypes = (ct.c_char_p, DBUS.ErrorPtr)
dbus.dbus_validate_interface.restype = DBUS.bool_t
dbus.dbus_validate_interface.argtypes = (ct.c_char_p, DBUS.ErrorPtr)
dbus.dbus_validate_member.restype = DBUS.bool_t
dbus.dbus_validate_member.argtypes = (ct.c_char_p, DBUS.ErrorPtr)
dbus.dbus_validate_error_name.restype = DBUS.bool_t
dbus.dbus_validate_error_name.argtypes = (ct.c_char_p, DBUS.ErrorPtr)
dbus.dbus_validate_bus_name.restype = DBUS.bool_t
dbus.dbus_validate_bus_name.argtypes = (ct.c_char_p, DBUS.ErrorPtr)
dbus.dbus_validate_utf8.restype = DBUS.bool_t
dbus.dbus_validate_utf8.argtypes = (ct.c_char_p, DBUS.ErrorPtr)
# from dbus-server.h:
dbus.dbus_server_listen.restype = ct.c_void_p
dbus.dbus_server_listen.argtypes = (ct.c_char_p, DBUS.ErrorPtr)
dbus.dbus_server_ref.restype = ct.c_void_p
dbus.dbus_server_ref.argtypes = (ct.c_void_p,)
dbus.dbus_server_unref.restype = ct.c_void_p
dbus.dbus_server_unref.argtypes = (ct.c_void_p,)
dbus.dbus_server_disconnect.restype = None
dbus.dbus_server_disconnect.argtypes = (ct.c_void_p,)
dbus.dbus_server_get_is_connected.restype = DBUS.bool_t
dbus.dbus_server_get_is_connected.argtypes = (ct.c_void_p,)
dbus.dbus_server_get_address.restype = ct.c_void_p
dbus.dbus_server_get_address.argtypes = (ct.c_void_p,)
dbus.dbus_server_get_id.restype = ct.c_void_p
dbus.dbus_server_get_id.argtypes = (ct.c_void_p,)
dbus.dbus_server_set_new_connection_function.restype = None
dbus.dbus_server_set_new_connection_function.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_void_p)
dbus.dbus_server_set_watch_functions.restype = DBUS.bool_t
dbus.dbus_server_set_watch_functions.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_void_p)
dbus.dbus_server_set_timeout_functions.restype = DBUS.bool_t
dbus.dbus_server_set_timeout_functions.argtypes = (ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_void_p)
dbus.dbus_server_set_auth_mechanisms.restype = DBUS.bool_t
dbus.dbus_server_set_auth_mechanisms.argtypes = (ct.c_void_p, ct.c_void_p)
dbus.dbus_server_allocate_data_slot.restype = DBUS.bool_t
dbus.dbus_server_allocate_data_slot.argtypes = (ct.POINTER(ct.c_int),)
dbus.dbus_server_free_data_slot.restype = DBUS.bool_t
dbus.dbus_server_free_data_slot.argtypes = (ct.POINTER(ct.c_int),)
dbus.dbus_server_set_data.restype = DBUS.bool_t
dbus.dbus_server_set_data.argtypes = (ct.c_void_p, ct.c_int, ct.c_void_p, ct.c_void_p)
dbus.dbus_server_set_data.restype = ct.c_void_p
dbus.dbus_server_set_data.argtypes = (ct.c_void_p, ct.c_int)
# TODO dbus-threads.h <https://dbus.freedesktop.org/doc/api/html/group__DBusThreads.html>
# Seems like the only call worth making is dbus_threads_init_default.
#+
# High-level stuff follows
#-
class DBusError(Exception) :
"for raising an exception that reports a D-Bus error name and accompanying message."
__slots__ = ("name", "message")
def __init__(self, name, message) :
self.args = ("%s -- %s" % (name, message),)
self.name = name
self.message = message
#end __init__
#end DBusError
class CallFailed(Exception) :
"used internally for reporting general failure from calling a libdbus routine."
__slots__ = ("funcname",)
def __init__(self, funcname) :
self.args = ("%s failed" % funcname,)
self.funcname = funcname
#end __init__
#end CallFailed
class _Abort(Exception) :
pass
#end _Abort
class TaskKeeper :
"Base class for classes that need to call EventLoop.create_task() to" \
" schedule caller-created coroutines for execution. asyncio only keeps" \
" weak references to Task objects when they are not being scheduled," \
" so to keep them from disappearing unexpectedly, I maintain a list of" \
" strong references here, and clean them out as they end execution."
__slots__ = ("__weakref__", "loop", "_cur_tasks")
def _init(self) :
# avoid __init__ so I don't get passed spurious args
self.loop = None
self._cur_tasks = set()
#end _init
def create_task(self, coro) :
assert self.loop != None, "no event loop to attach coroutine to"
task = self.loop.create_task(coro)
task.add_done_callback(functools.partial(self._reaper, weak_ref(self)))
self._cur_tasks.add(task)
#end create_task
@staticmethod
def _reaper(self, task) :
self = self() # avoid reference circularity
self._cur_tasks.remove(task)
#end _reaper
if "loop" in asyncio.wait.__kwdefaults__ :
def wait(self, futures, *, timeout = None, return_when = asyncio.ALL_COMPLETED) :
"wrapper around asyncio.wait for compatibility with pre-Python-3.7."
return \
asyncio.wait(futures, loop = self.loop, timeout = timeout, return_when = return_when)
# No default loop in pre-3.7.
#end wait
else :
wait = staticmethod(asyncio.wait)
# no need to pass loop arg in ≥ 3.7, removed in ≥ 3.10.
#end if
#end TaskKeeper
# Misc: <https://dbus.freedesktop.org/doc/api/html/group__DBusMisc.html>
def get_local_machine_id() :
"returns a systemwide unique ID that is supposed to remain constant at least" \
" until the next reboot. Two processes seeing the same value for this can assume" \
" they are on the same machine."
c_result = dbus.dbus_get_local_machine_id()
if c_result == None :
raise CallFailed("dbus_get_local_machine_id")
#end if
result = ct.cast(c_result, ct.c_char_p).value.decode()
dbus.dbus_free(c_result)
return \
result
#end get_local_machine_id
def get_version() :
"returns the libdbus library version as a tuple of integers (major, minor, micro)."
major = ct.c_int()
minor = ct.c_int()
micro = ct.c_int()
dbus.dbus_get_version(ct.byref(major), ct.byref(minor), ct.byref(micro))
return \
(major.value, minor.value, micro.value)
#end get_version
def setenv(key, value) :
key = key.encode()
if value != None :
value = value.encode()
#end if
if not dbus.dbus_setenv(key, value) :
raise CallFailed("dbus_setenv")
#end if
#end setenv
def unsetenv(key) :
setenv(key, None)
#end unsetenv
class Watch :
"wrapper around a DBusWatch object. Do not instantiate directly; they" \
" are created and destroyed by libdbus.\n" \
"\n" \
"A Watch is the basic mechanism for plugging libdbus-created file descriptors" \
" into your event loop. When created, they are passed to your add-watch callback" \
" to manage; and conversely, when deleted, your remove-watch callback is notified." \
" (These callbacks are ones you attach to Server and Connection objects.)\n" \
"\n" \
"Check the enabled property to decide if you need to pay attention to this Watch, and" \
" look at the flags to see if you need to check for pending reads, or writes, or both." \
" Call the handle() method with the appropriate flags when you see that reads or writes" \
" are pending."
# <https://dbus.freedesktop.org/doc/api/html/group__DBusWatch.html>
__slots__ = ("__weakref__", "_dbobj",) # to forestall typos
_instances = WeakValueDictionary()
def __new__(celf, _dbobj) :
self = celf._instances.get(_dbobj)
if self == None :
self = super().__new__(celf)
self._dbobj = _dbobj
celf._instances[_dbobj] = self
#end if
return \
self
#end __new__
# no __del__ method -- no underlying dispose API call
@property
def unix_fd(self) :
"the underlying file descriptor for this Watch."
return \
dbus.dbus_watch_get_unix_fd(self._dbobj)
#end unix_fd
def fileno(self) :
"for use with Pythons “select” functions."
return \
self.unix_fd
#end fileno
@property
def socket(self) :
return \
dbus.dbus_watch_get_socket(self._dbobj)
#end socket
@property
def flags(self) :
"returns WATCH_READABLE and/or WATCH_WRITABLE, indicating what to watch for."
return \
dbus.dbus_watch_get_flags(self._dbobj)
#end flags
# TODO: get/set data
def handle(self, flags) :
"tells libdbus that there is something to be read or written." \
" flags are a combination of WATCH_xxx values."
return \
dbus.dbus_watch_handle(self._dbobj, flags) != 0
#end handle
@property
def enabled(self) :
"does libdbus want you to actually watch this Watch."
return \
dbus.dbus_watch_get_enabled(self._dbobj) != 0
#end enabled
#end Watch
class Timeout :
"wrapper around a DBusTimeout object. Do not instantiate directly; they" \
" are created and destroyed by libdbus.\n" \
"\n" \
" A Timeout is the basic mechanism for plugging libdbus-created timeouts" \
" into your event loop. When created, they are passed to your add-timeout" \
" callback to manage; and conversely, when deleted, your remove-timeout" \
" callback is notified. (These callbacks are ones you attach to Server and" \
" Connection objects.)\n" \
"\n" \
"Check the enabled property to decide if you need to pay attention to this" \
" Timeout. Call the handle() method when the timeout becomes due, as measured" \
" from when it was initially created or most recently enabled, whichever" \
" happened last."
# <https://dbus.freedesktop.org/doc/api/html/group__DBusTimeout.html>
__slots__ = ("__weakref__", "_dbobj",) # to forestall typos
_instances = WeakValueDictionary()
def __new__(celf, _dbobj) :
self = celf._instances.get(_dbobj)
if self == None :
self = super().__new__(celf)
self._dbobj = _dbobj
celf._instances[_dbobj] = self
#end if
return \
self
#end __new__
# no __del__ method -- no underlying dispose API call
@property
def interval(self) :
"how long in float seconds until the timeout should fire."
return \
dbus.dbus_timeout_get_interval(self._dbobj) / 1000
#end interval
# TODO: get/set data
def handle(self) :
"tells libdbus the timeout has fired."
return \
dbus.dbus_timeout_handle(self._dbobj)
#end handle
@property
def enabled(self) :
"does libdbus want you to actually schedule this Timeout."
return \
dbus.dbus_timeout_get_enabled(self._dbobj) != 0
#end enabled
#end Timeout
class ObjectPathVTable(TaskKeeper) :
"wrapper around an ObjectPathVTable struct. You can instantiate directly, or call" \
" the init method. An additional feature beyond the underlying libdbus capabilities" \
" is the option to specify an asyncio event loop. If the message handler returns" \
" a coroutine, then an asyncio task is created to run it, and a result of" \
" DBUS.HANDLER_RESULT_HANDLED is returned on behalf of the message handler;" \
" that way, the message function can do the minimum beyond some initial filtering of" \
" the message, leaving the time-consuming part of the work to the coroutine."
__slots__ = \
(
"_dbobj",
# need to keep references to ctypes-wrapped functions
# so they don't disappear prematurely:
"_wrap_unregister_func",
"_wrap_message_func",
) # to forestall typos
def __init__(self, *, loop = None, unregister = None, message = None) :
super().__init__()
super()._init()
self._dbobj = DBUS.ObjectPathVTable()
self.loop = loop
self._wrap_unregister_func = None
self._wrap_message_func = None
if unregister != None :
self.set_unregister(unregister)
#end if
if message != None :
self.set_message(message)
#end if
#end __init__
@classmethod
def init(celf, *, loop = None, unregister = None, message = None) :
"for consistency with other classes that dont want caller to instantiate directly."
return \
celf \
(
loop = loop,
unregister = unregister,
message = message,
)
#end init
def set_unregister(self, unregister) :
def wrap_unregister(c_conn, c_user_data) :
conn = Connection(dbus.dbus_connection_ref(c_conn))
unregister(conn, conn._user_data.get(c_user_data))
#end wrap_unregister
#begin set_unregister
if unregister != None :
self._wrap_unregister_func = DBUS.ObjectPathUnregisterFunction(wrap_unregister)
else :
self._wrap_unregister_func = None
#end if
self._dbobj.unregister_function = self._wrap_unregister_func
return \
self
#end set_unregister
def set_message(self, message) :
w_self = weak_ref(self)
def wrap_message(c_conn, c_message, c_user_data) :
self = _wderef(w_self, "vtable")
conn = Connection(dbus.dbus_connection_ref(c_conn))
msg = Message(dbus.dbus_message_ref(c_message))
user_data = conn._user_data.get(c_user_data)
result = message(conn, msg, user_data)
if asyncio.iscoroutine(result) :
self.create_task(result)
result = DBUS.HANDLER_RESULT_HANDLED
#end if
return \
result
#end wrap_message
#begin set_message
if message != None :
self._wrap_message_func = DBUS.ObjectPathMessageFunction(wrap_message)
else :
self._wrap_message_func = None
#end if
self._dbobj.message_function = self._wrap_message_func
return \
self
#end set_message
#end ObjectPathVTable
class _DummyError :
# like an Error, but is never set and so will never raise.
@property
def is_set(self) :
return \
False
#end is_set
def raise_if_set(self) :
pass
#end raise_if_set
#end _DummyError
def _get_error(error) :
# Common routine which processes an optional user-supplied Error
# argument, and returns 2 Error-like objects: the first a real
# Error object to be passed to the libdbus call, the second is
# either the same Error object or a separate _DummyError object
# on which to call raise_if_set() afterwards. The procedure for
# using this is
#
# error, my_error = _get_error(error)
# ... call libdbus routine, passing error._dbobj ...
# my_error.raise_if_set()
#
# If the user passes None for error, then an internal Error object
# is created, and returned as both results. That way, if it is
# filled in by the libdbus call, calling raise_if_set() will
# automatically raise the exception.
# But if the user passed their own Error object, then it is
# returned as the first result, and a _DummyError as the second
# result. This means the raise_if_set() call becomes a noop, and
# it is up to the caller to check if their Error object was filled
# in or not.
if error != None and not isinstance(error, Error) :
raise TypeError("error must be an Error")
#end if
if error != None :
my_error = _DummyError()
else :
my_error = Error()
error = my_error
#end if
return \
error, my_error
#end _get_error
def _get_timeout(timeout) :
# accepts a timeout in float seconds and converts it to integer milliseconds
# as expected by libdbus. Special-cases DBUS.TIMEOUT_INFINITE and DBUS.TIMEOUT_USE_DEFAULT,
# allowing these to be passed through unchanged.
if not isinstance(timeout, int) or timeout not in (DBUS.TIMEOUT_INFINITE, DBUS.TIMEOUT_USE_DEFAULT) :
timeout = round(timeout * 1000)
#end if
return \
timeout
#end _get_timeout
def _loop_attach(self, loop, dispatch) :
# attaches a Server or Connection object to a given asyncio event loop.
# If loop is None, then the default asyncio loop is used. The actual loop
# value is also stored as the loop attribute of the object.
if loop == None :
try :
# if running within a task, current loop takes priority
loop = get_running_loop()
except RuntimeError :
# not running within a task, use default loop
loop = get_event_loop()
#end try
#end if
watches = [] # do I need to keep track of Watch objects?
timeouts = []
def call_dispatch() :
status = dispatch()
if status == DBUS.DISPATCH_NEED_MEMORY :
raise DBusError(DBUS.ERROR_NO_MEMORY, "not enough memory for connection dispatch")
#end if
if status == DBUS.DISPATCH_DATA_REMAINS :
loop.call_soon(call_dispatch)
#end if
#end call_dispatch
def add_remove_watch(watch, add) :
def handle_watch_event(flags) :
# seems I need to remove the watch and add it again to
# avoid an endless stream of notifications that cause
# excessive CPU usage -- asyncio bug?
add_remove_watch(watch, False)
watch.handle(flags)
if watch.enabled :
add_remove_watch(watch, True)
#end if
if dispatch != None :
call_dispatch()
#end if
#end handle_watch_event
#end add_remove_watch
if DBUS.WATCH_READABLE & watch.flags != 0 :
if add :
loop.add_reader(watch, handle_watch_event, DBUS.WATCH_READABLE)
else :
loop.remove_reader(watch)
#end if
#end if
if DBUS.WATCH_WRITABLE & watch.flags != 0 :
if add :
loop.add_writer(watch, handle_watch_event, DBUS.WATCH_WRITABLE)
else :
loop.remove_writer(watch)
#end if
#end if
#end add_remove_watch
def handle_add_watch(watch, data) :
if watch not in watches :
watches.append(watch)
add_remove_watch(watch, True)
#end if
return \
True
#end handle_add_watch
def handle_watch_toggled(watch, data) :
add_remove_watch(watch, watch.enabled)
#end handle_watch_toggled
def handle_remove_watch(watch, data) :
try :
pos = watches.index(watch)
except ValueError :
pos = None
#end try
if pos != None :
watches[pos : pos + 1] = []
add_remove_watch(watch, False)
#end if
#end handle_remove_watch
def handle_timeout(timeout) :
if timeout["due"] != None and timeout["due"] <= loop.time() and timeout["timeout"].enabled :
timeout["timeout"].handle()
#end if
#end handle_timeout
def handle_add_timeout(timeout, data) :
if not any(timeout == t["timeout"] for t in timeouts) :
entry = \
{
"timeout" : timeout,
"due" : (lambda : None, lambda : loop.time() + timeout.interval)[timeout.enabled](),
}
timeouts.append(entry)
if timeout.enabled :
loop.call_later(timeout.interval, handle_timeout, entry)
#end if
#end if
return \
True
#end handle_add_timeout
def handle_timeout_toggled(timeout, data) :
# not sure what to do if a Timeout gets toggled from enabled to disabled
# and then to enabled again; effectively I update the due time from
# the time of re-enabling.
search = iter(timeouts)
while True :
entry = next(search, None)
if entry == None :
break
#end if
if entry["timeout"] == timeout :
if timeout.enabled :
entry["due"] = loop.time() + timeout.enterval
loop.call_later(timeout.interval, handle_timeout, entry)
else :
entry["due"] = None
#end if
break
#end if
#end while
#end handle_timeout_toggled
def handle_remove_timeout(timeout, data) :
new_timeouts = []
for entry in timeouts :
if entry["timeout"] == timeout :
entry["due"] = None # in case already queued, avoid segfault in handle_timeout
else :
new_timeouts.append(entry)
#end if
#end for
timeouts[:] = new_timeouts
#end handle_remove_timeout
#begin _loop_attach
self.set_watch_functions \
(
add_function = handle_add_watch,
remove_function = handle_remove_watch,
toggled_function = handle_watch_toggled,
data = None
)
self.set_timeout_functions \
(
add_function = handle_add_timeout,
remove_function = handle_remove_timeout,
toggled_function = handle_timeout_toggled,
data = None
)
self.loop = loop
self = None # avoid circularity
#end _loop_attach
class _MatchActionEntry :
__slots__ = ("rule", "actions")
class _Action :
__slots__ = ("func", "user_data")
def __init__(self, func, user_data) :
self.func = func
self.user_data = user_data
#end __init__
def __eq__(a, b) :
# needed to allow equality comparison of set entries
return \
(
a.func == b.func
and
data_key(a.user_data) == data_key(b.user_data)
)
#end __eq__
def __hash__(self) :
return \
hash((self.func, data_key(self.user_data)))
#end __hash__
#end _Action
def __init__(self, rule) :
self.rule = rule
self.actions = set()
#end __init__
#end _MatchActionEntry
@enum.unique
class STOP_ON(enum.Enum) :
"set of conditions on which to raise StopAsyncIteration:\n" \
"\n" \
" TIMEOUT - timeout has elapsed\n" \
" CLOSED - server/connection has closed.\n" \
"\n" \
"Otherwise None will be returned on timeout, and the usual BrokenPipeError" \
" exception will be raised when the connection is closed."
TIMEOUT = 1
CLOSED = 2
#end STOP_ON
class Connection(TaskKeeper) :
"wrapper around a DBusConnection object. Do not instantiate directly; use the open" \
" or bus_get methods."
# <https://dbus.freedesktop.org/doc/api/html/group__DBusConnection.html>
__slots__ = \
(
"_dbobj",
"_filters",
"_match_actions",
"_receive_queue",
"_receive_queue_enabled",
"_awaiting_receive",
"_user_data",
# need to keep references to ctypes-wrapped functions
# so they don't disappear prematurely:
"_object_paths",
"_add_watch_function",
"_remove_watch_function",
"_toggled_watch_function",
"_free_watch_data",
"_add_timeout_function",
"_remove_timeout_function",
"_toggled_timeout_function",
"_free_timeout_data",
"_wakeup_main",
"_free_wakeup_main_data",
"_dispatch_status",
"_free_dispatch_status_data",
"_allow_unix_user",
"_free_unix_user_data",
) # to forestall typos
_instances = WeakValueDictionary()
_shared_connections = [None, None]
def __new__(celf, _dbobj) :
self = celf._instances.get(_dbobj)
if self == None :
self = super().__new__(celf)
super()._init(self)
self._dbobj = _dbobj
self._user_data = {}
self._filters = {}
self._match_actions = {}
self._receive_queue = None
self._receive_queue_enabled = set()
self._awaiting_receive = []
self._object_paths = {}
celf._instances[_dbobj] = self
else :
dbus.dbus_connection_unref(self._dbobj)
# lose extra reference created by caller
#end if
return \
self
#end __new__
def __del__(self) :
if self._dbobj != None :
if self.loop != None :
# remove via direct low-level libdbus calls
dbus.dbus_connection_set_watch_functions(self._dbobj, None, None, None, None, None)
dbus.dbus_connection_set_timeout_functions(self._dbobj, None, None, None, None, None)
self.loop = None
#end if
# Any entries still in super(TaskKeeper, self)._cur_tasks will be lost
# at this point. I leave it to asyncio to report them as destroyed
# while still pending, and the caller to notice this as a program bug.
dbus.dbus_connection_unref(self._dbobj)
self._dbobj = None
#end if
#end __del__
@classmethod
def open(celf, address, private, error = None) :
"opens a Connection to a specified address, separate from the" \
" system or session buses."
error, my_error = _get_error(error)
result = (dbus.dbus_connection_open, dbus.dbus_connection_open_private)[private](address.encode(), error._dbobj)
my_error.raise_if_set()
if result != None :
result = celf(result)
#end if
return \
result
#end open
@classmethod
async def open_async(celf, address, private, error = None, loop = None, timeout = DBUS.TIMEOUT_INFINITE) :
"opens a Connection to a specified address, separate from the" \
" system or session buses."
# There is no nonblocking version of dbus_connection_open/dbus_connection_open_private,
# so I invoke it in a separate thread.
if loop == None :
loop = get_running_loop()
#end if
error, my_error = _get_error(error)
if timeout == DBUS.TIMEOUT_USE_DEFAULT :
timeout = DBUSX.DEFAULT_TIMEOUT
elif timeout == DBUS.TIMEOUT_INFINITE :
timeout = None
#end if
try :
result = await call_async \
(
func = (dbus.dbus_connection_open, dbus.dbus_connection_open_private)[private],
funcargs = (address.encode(), error._dbobj),
timeout = timeout,
abort = dbus.dbus_connection_unref,
loop = loop
)
except TimeoutError :
result = None
error.set(DBUS.ERROR_TIMEOUT, "connection did not open in time")
#end try
my_error.raise_if_set()
if result != None :
result = celf(result)
result.attach_asyncio(loop)
#end if
return \
result
#end open_async
def _flush_awaiting_receive(self) :
if self._receive_queue != None :
while len(self._awaiting_receive) != 0 :
waiting = self._awaiting_receive.pop(0)
waiting.set_exception(BrokenPipeError("async receives have been disabled"))
#end while
#end if
#end _flush_awaiting_receive
def close(self) :
self._flush_awaiting_receive()
dbus.dbus_connection_close(self._dbobj)
#end close
@property
def is_connected(self) :
return \
dbus.dbus_connection_get_is_connected(self._dbobj) != 0
#end is_connected
@property
def is_authenticated(self) :
return \
dbus.dbus_connection_get_is_authenticated(self._dbobj) != 0
#end is_authenticated
@property
def is_anonymous(self) :
return \
dbus.dbus_connection_get_is_anonymous(self._dbobj) != 0
#end is_anonymous
@property
def server_id(self) :
"asks the server at the other end for its unique id."
c_result = dbus.dbus_connection_get_server_id(self._dbobj)
result = ct.cast(c_result, ct.c_char_p).value.decode()
dbus.dbus_free(c_result)
return \
result
#end server_id
def can_send_type(self, type_code) :
"can this Connection send values of the specified TYPE_XXX code." \
" Mainly useful for checking if we can send TYPE_UNIX_FD values."
return \
dbus.dbus_connection_can_send_type(self._dbobj, type_code) != 0
#end can_send_type
def set_exit_on_disconnect(self, exit_on_disconnect) :
dbus.dbus_connection_set_exit_on_disconnect(self._dbobj, exit_on_disconnect)
#end set_exit_on_disconnect
def preallocate_send(self) :
result = dbus.dbus_connection_preallocate_send(self._dbobj)
if result == None :
raise CallFailed("dbus_connection_preallocate_send")
#end if
return \
PreallocatedSend(result, self)
#end preallocate_send
def send_preallocated(self, preallocated, message) :
if not isinstance(preallocated, PreallocatedSend) or not isinstance(message, Message) :
raise TypeError("preallocated must be a PreallocatedSend and message must be a Message")
#end if
assert not preallocated._sent, "preallocated has already been sent"
serial = ct.c_uint()
dbus.dbus_connection_send_preallocated(self._dbobj, preallocated._dbobj, message._dbobj, ct.byref(serial))
preallocated._sent = True
return \
serial.value
#end send_preallocated
def send(self, message) :
"puts a message in the outgoing queue."
if not isinstance(message, Message) :
raise TypeError("message must be a Message")
#end if
serial = ct.c_uint()
if not dbus.dbus_connection_send(self._dbobj, message._dbobj, ct.byref(serial)) :
raise CallFailed("dbus_connection_send")
#end if
return \
serial.value
#end send
def send_with_reply(self, message, timeout = DBUS.TIMEOUT_USE_DEFAULT) :
"puts a message in the outgoing queue and returns a PendingCall" \
" that you can use to obtain the reply."
if not isinstance(message, Message) :
raise TypeError("message must be a Message")
#end if
pending_call = ct.c_void_p()
if not dbus.dbus_connection_send_with_reply(self._dbobj, message._dbobj, ct.byref(pending_call), _get_timeout(timeout)) :
raise CallFailed("dbus_connection_send_with_reply")
#end if
if pending_call.value != None :
result = PendingCall(pending_call.value, self)
else :
result = None
#end if
return \
result
#end send_with_reply
def send_with_reply_and_block(self, message, timeout = DBUS.TIMEOUT_USE_DEFAULT, error = None) :
"sends a message, blocks the thread until the reply is available, and returns it."
if not isinstance(message, Message) :
raise TypeError("message must be a Message")
#end if
error, my_error = _get_error(error)
reply = dbus.dbus_connection_send_with_reply_and_block(self._dbobj, message._dbobj, _get_timeout(timeout), error._dbobj)
my_error.raise_if_set()
if reply != None :
result = Message(reply)
else :
result = None
#end if
return \
result
#end send_with_reply_and_block
async def send_await_reply(self, message, timeout = DBUS.TIMEOUT_USE_DEFAULT) :
"queues a message, suspends the coroutine (letting the event loop do" \
" other things) until the reply is available, and returns it."
if not isinstance(message, Message) :
raise TypeError("message must be a Message")
#end if
assert self.loop != None, "no event loop to attach coroutine to"
pending_call = ct.c_void_p()
if not dbus.dbus_connection_send_with_reply(self._dbobj, message._dbobj, ct.byref(pending_call), _get_timeout(timeout)) :
raise CallFailed("dbus_connection_send_with_reply")
#end if
if pending_call.value != None :
pending = PendingCall(pending_call.value, self)
else :
pending = None
#end if
reply = None # to begin with
if pending != None :
reply = await pending.await_reply()
#end if
return \
reply
#end send_await_reply
def flush(self) :
"makes sure all queued messages have been sent, blocking" \
" the thread until this is done."
dbus.dbus_connection_flush(self._dbobj)
#end flush
def read_write_dispatch(self, timeout = DBUS.TIMEOUT_USE_DEFAULT) :
"dispatches the first available message, if any. Otherwise blocks the" \
" thread until it can read or write, and does so before returning. Returns" \
" True as long as the Connection remains connected."
return \
dbus.dbus_connection_read_write_dispatch(self._dbobj, _get_timeout(timeout)) != 0
#end read_write_dispatch
def read_write(self, timeout = DBUS.TIMEOUT_USE_DEFAULT) :
"blocks the thread until something can be read or written on the Connection," \
" and does so, returning True. If the Connection has been disconnected," \
" immediately returns False."
return \
dbus.dbus_connection_read_write(self._dbobj, _get_timeout(timeout)) != 0
#end read_write
def borrow_message(self) :
"tries to peek at the next available message waiting to be read, returning" \
" None if these isnt one. Call the Messages return_borrowed() method" \
" to return it to the queue, or steal_borrowed() to confirm that you have" \
" read the message."
msg = dbus.dbus_connection_borrow_message(self._dbobj)
if msg != None :
msg = Message(msg)
msg._conn = self
msg._borrowed = True
#end if
return \
msg
#end borrow_message
# returning/stealing borrowed messages done with
# Message.return_borrowed and Message.steal_borrowed
def pop_message(self) :
"returns the next available incoming Message, if any, otherwise returns None." \
" Note this bypasses all message filtering/dispatching on this Connection."
message = dbus.dbus_connection_pop_message(self._dbobj)
if message != None :
message = Message(message)
#end if
return \
message
#end pop_message
@property
def dispatch_status(self) :
"checks the state of the incoming message queue; returns a DISPATCH_XXX code."
return \
dbus.dbus_connection_get_dispatch_status(self._dbobj)
#end dispatch_status
def dispatch(self) :
"processes any available data, adding messages into the incoming" \
" queue as appropriate. returns a DISPATCH_XXX code."
return \
dbus.dbus_connection_dispatch(self._dbobj)
#end dispatch
def set_watch_functions(self, add_function, remove_function, toggled_function, data, free_data = None) :
"sets the callbacks for libdbus to use to notify you of Watch objects it wants" \
" you to manage."
def wrap_add_function(c_watch, _data) :
return \
add_function(Watch(c_watch), data)
#end wrap_add_function
def wrap_remove_function(c_watch, _data) :
return \
remove_function(Watch(c_watch), data)
#end wrap_remove_function
def wrap_toggled_function(c_watch, _data) :
return \
toggled_function(Watch(c_watch), data)
#end wrap_toggled_function
def wrap_free_data(_data) :
free_data(data)
#end wrap_free_data
#begin set_watch_functions
self._add_watch_function = DBUS.AddWatchFunction(wrap_add_function)
self._remove_watch_function = DBUS.RemoveWatchFunction(wrap_remove_function)
if toggled_function != None :
self._toggled_watch_function = DBUS.WatchToggledFunction(wrap_toggled_function)
else :
self._toggled_watch_function = None
#end if
if free_data != None :
self._free_watch_data = DBUS.FreeFunction(wrap_free_data)
else :
self._free_watch_data = None
#end if
if not dbus.dbus_connection_set_watch_functions(self._dbobj, self._add_watch_function, self._remove_watch_function, self._toggled_watch_function, None, self._free_watch_data) :
raise CallFailed("dbus_connection_set_watch_functions")
#end if
#end set_watch_functions
def set_timeout_functions(self, add_function, remove_function, toggled_function, data, free_data = None) :
"sets the callbacks for libdbus to use to notify you of Timeout objects it wants" \
" you to manage."
def wrap_add_function(c_timeout, _data) :
return \
add_function(Timeout(c_timeout), data)
#end wrap_add_function
def wrap_remove_function(c_timeout, _data) :
return \
remove_function(Timeout(c_timeout), data)
#end wrap_remove_function
def wrap_toggled_function(c_timeout, _data) :
return \
toggled_function(Timeout(c_timeout), data)
#end wrap_toggled_function
def wrap_free_data(_data) :
free_data(data)
#end wrap_free_data
#begin set_timeout_functions
self._add_timeout_function = DBUS.AddTimeoutFunction(wrap_add_function)
self._remove_timeout_function = DBUS.RemoveTimeoutFunction(wrap_remove_function)
if toggled_function != None :
self._toggled_timeout_function = DBUS.TimeoutToggledFunction(wrap_toggled_function)
else :
self._toggled_timeout_function = None
#end if
if free_data != None :
self._free_timeout_data = DBUS.FreeFunction(wrap_free_data)
else :
self._free_timeout_data = None
#end if
if not dbus.dbus_connection_set_timeout_functions(self._dbobj, self._add_timeout_function, self._remove_timeout_function, self._toggled_timeout_function, None, self._free_timeout_data) :
raise CallFailed("dbus_connection_set_timeout_functions")
#end if
#end set_timeout_functions
def set_wakeup_main_function(self, wakeup_main, data, free_data = None) :
"sets the callback to use for libdbus to notify you that something has" \
" happened requiring processing on the Connection."
def wrap_wakeup_main(_data) :
wakeup_main(data)
#end wrap_wakeup_main
def wrap_free_data(_data) :
free_data(data)
#end wrap_free_data
#begin set_wakeup_main_function
if wakeup_main != None :
self._wakeup_main = DBUS.WakeupMainFunction(wrap_wakeup_main)
else :
self._wakeup_main = None
#end if
if free_data != None :
self._free_wakeup_main_data = DBUS.FreeFunction(wrap_free_data)
else :
self._free_wakeup_main_data = None
#end if
dbus.dbus_connection_set_wakeup_main_function(self._dbobj, self._wakeup_main, None, self._free_wakeup_main_data)
#end set_wakeup_main_function
def set_dispatch_status_function(self, function, data, free_data = None) :
"sets the callback to use for libdbus to notify you of a change in the" \
" dispatch status of the Connection."
w_self = weak_ref(self)
def wrap_dispatch_status(_conn, status, _data) :
function(_wderef(w_self, "connection"), status, data)
#end wrap_dispatch_status
def wrap_free_data(_data) :
free_data(data)
#end wrap_free_data
#begin set_dispatch_status_function
self._dispatch_status = DBUS.DispatchStatusFunction(wrap_dispatch_status)
if free_data != None :
self._free_wakeup_main_data = DBUS.FreeFunction(wrap_free_data)
else :
self._free_wakeup_main_data = None
#end if
dbus.dbus_connection_set_dispatch_status_function(self._dbobj, self._dispatch_status, None, self._free_wakeup_main_data)
#end set_dispatch_status_function
@property
def unix_fd(self) :
c_fd = ct.c_int()
if dbus.dbus_connection_get_unix_fd(self._dbobj, ct.byref(c_fd)) :
result = c_fd.value
else :
result = None
#end if
return \
result
#end unix_fd
def fileno(self) :
"for use with Pythons “select” functions."
return \
self.unix_fd
#end fileno
@property
def socket(self) :
c_fd = ct.c_int()
if dbus.dbus_connection_get_socket(self._dbobj, ct.byref(c_fd)) :
result = c_fd.value
else :
result = None
#end if
return \
result
#end socket
@property
def unix_process_id(self) :
c_pid = ct.c_ulong()
if dbus.dbus_connection_get_unix_process_id(self._dbobj, ct.byref(c_pid)) :
result = c_pid.value
else :
result = None
#end if
return \
result
#end unix_process_id
@property
def unix_user(self) :
c_uid = ct.c_ulong()
if dbus.dbus_connection_get_unix_user(self._dbobj, ct.byref(c_uid)) :
result = c_uid.value
else :
result = None
#end if
return \
result
#end unix_user
# TODO: get_adt
def set_unix_user_function(self, allow_unix_user, data, free_data = None) :
w_self = weak_ref(self)
def wrap_allow_unix_user(c_conn, uid, c_data) :
return \
allow_unix_user(_wderef(w_self, "connection"), uid, data)
#end wrap_allow_unix_user
def wrap_free_data(_data) :
free_data(data)
#end wrap_free_data
#begin set_unix_user_function
if allow_unix_user != None :
self._allow_unix_user = DBUS.AllowUnixUserFunction(wrap_allow_unix_user)
else :
self._allow_unix_user = None
#end if
if free_data != None :
self._free_unix_user_data = DBUS.FreeFunction(wrap_free_data)
else :
self._free_unix_user_data = None
#end if
dbus.dbus_connection_set_unix_user_function(self._dbobj, self._allow_unix_user, None, self._free_unix_user_data)
#end set_unix_user_function
def set_allow_anonymous(self, allow) :
dbus.dbus_connection_set_allow_anonymous(self._dbobj, allow)
#end set_allow_anonymous
def set_route_peer_messages(self, enable) :
dbus.dbus_connection_set_route_peer_messages(self._dbobj, enable)
#end set_route_peer_messages
def add_filter(self, function, user_data, free_data = None) :
"adds a filter callback that gets to look at all incoming messages" \
" before they get to the dispatch system. The same function can be added" \
" multiple times as long as the user_data is different."
w_self = weak_ref(self)
def wrap_function(c_conn, c_message, _data) :
self = _wderef(w_self, "connection")
message = Message(dbus.dbus_message_ref(c_message))
result = function(self, message, user_data)
if asyncio.iscoroutine(result) :
self.create_task(result)
result = DBUS.HANDLER_RESULT_HANDLED
#end if
return \
result
#end wrap_function
def wrap_free_data(_data) :
free_data(user_data)
#end wrap_free_data
#begin add_filter
filter_key = (function, data_key(user_data))
filter_value = \
{
"function" : DBUS.HandleMessageFunction(wrap_function),
"free_data" : (lambda : None, lambda : DBUS.FreeFunction(wrap_free_data))[free_data != None](),
}
# pass user_data id because libdbus identifies filter entry by both function address and user data address
if not dbus.dbus_connection_add_filter(self._dbobj, filter_value["function"], filter_key[1], filter_value["free_data"]) :
raise CallFailed("dbus_connection_add_filter")
#end if
self._filters[filter_key] = filter_value
# need to ensure wrapped functions dont disappear prematurely
#end add_filter
def remove_filter(self, function, user_data) :
"removes a message filter added by add_filter. The filter is identified" \
" by both the function object and the user_data that was passed."
filter_key = (function, data_key(user_data))
if filter_key not in self._filters :
raise KeyError("removing nonexistent Connection filter")
#end if
filter_value = self._filters[filter_key]
# pass user_data id because libdbus identifies filter entry by both function address and user data address
dbus.dbus_connection_remove_filter(self._dbobj, filter_value["function"], filter_key[1])
del self._filters[filter_key]
#end remove_filter
def register_object_path(self, path, vtable, user_data, error = None) :
"registers an ObjectPathVTable as a dispatch handler for a specified" \
" path within your object hierarchy."
if not isinstance(vtable, ObjectPathVTable) :
raise TypeError("vtable must be an ObjectPathVTable")
#end if
self._object_paths[path] = {"vtable" : vtable, "user_data" : user_data} # ensure it doesnt disappear prematurely
error, my_error = _get_error(error)
if user_data != None :
c_user_data = id(user_data)
self._user_data[c_user_data] = user_data
else :
c_user_data = None
#end if
dbus.dbus_connection_try_register_object_path(self._dbobj, path.encode(), vtable._dbobj, c_user_data, error._dbobj)
my_error.raise_if_set()
#end register_object_path
def register_fallback(self, path, vtable, user_data, error = None) :
"registers an ObjectPathVTable as a dispatch handler for an entire specified" \
" subtree within your object hierarchy."
if not isinstance(vtable, ObjectPathVTable) :
raise TypeError("vtable must be an ObjectPathVTable")
#end if
self._object_paths[path] = {"vtable" : vtable, "user_data" : user_data} # ensure it doesnt disappear prematurely
error, my_error = _get_error(error)
if user_data != None :
c_user_data = id(user_data)
self._user_data[c_user_data] = user_data
else :
c_user_data = None
#end if
dbus.dbus_connection_try_register_fallback(self._dbobj, path.encode(), vtable._dbobj, c_user_data, error._dbobj)
my_error.raise_if_set()
#end register_fallback
def unregister_object_path(self, path) :
"removes a previously-registered ObjectPathVTable handler at a specified" \
" point (single object or entire subtree) within your object hierarchy."
if path not in self._object_paths :
raise KeyError("unregistering unregistered path")
#end if
if not dbus.dbus_connection_unregister_object_path(self._dbobj, path.encode()) :
raise CallFailed("dbus_connection_unregister_object_path")
#end if
user_data = self._object_paths[path]["user_data"]
c_user_data = id(user_data)
nr_remaining_refs = sum(int(self._object_paths[p]["user_data"] == user_data) for p in self._object_paths if p != path)
if nr_remaining_refs == 0 :
try :
del self._user_data[c_user_data]
except KeyError :
pass
#end try
#end if
del self._object_paths[path]
#end unregister_object_path
def get_object_path_data(self, path) :
"returns the user_data you passed when previously registering an ObjectPathVTable" \
" that covers this path in your object hierarchy, or None if no suitable match" \
" could be found."
c_data_p = ct.c_void_p()
if not dbus.dbus_connection_get_object_path_data(self._dbobj, path.encode(), ct.byref(c_data_p)) :
raise CallFailed("dbus_connection_get_object_path_data")
#end if
return \
self._user_data.get(c_data_p.value)
#end get_object_path_data
def list_registered(self, parent_path) :
"lists all the object paths for which you have ObjectPathVTable handlers registered."
child_entries = ct.POINTER(ct.c_char_p)()
if not dbus.dbus_connection_list_registered(self._dbobj, parent_path.encode(), ct.byref(child_entries)) :
raise CallFailed("dbus_connection_list_registered")
#end if
result = []
i = 0
while True :
entry = child_entries[i]
if entry == None :
break
result.append(entry.decode())
i += 1
#end while
dbus.dbus_free_string_array(child_entries)
return \
result
#end list_registered
@staticmethod
def _queue_received_message(self, message, _) :
# message filter which queues messages as appropriate for receive_message_async.
# Must be static so same function object can be passed to all add_filter/remove_filter
# calls.
queueit = message.type in self._receive_queue_enabled
if queueit :
self._receive_queue.append(message)
while len(self._awaiting_receive) != 0 :
# wake them all up, because I dont know what message types
# each might be waiting for
waiting = self._awaiting_receive.pop(0)
waiting.set_result(True) # result actually ignored
#end while
#end if
return \
(DBUS.HANDLER_RESULT_NOT_YET_HANDLED, DBUS.HANDLER_RESULT_HANDLED)[queueit]
#end _queue_received_message
def enable_receive_message(self, queue_types) :
"enables/disables message types for reception via receive_message_async." \
" queue_types is a set or sequence of DBUS.MESSAGE_TYPE_XXX values for" \
" the types of messages to be put into the receive queue, or None to" \
" disable all message types; this replaces queue_types passed to" \
" any prior enable_receive_message_async call on this Connection."
assert self.loop != None, "no event loop to attach coroutines to"
enable = queue_types != None and len(queue_types) != 0
if (
enable
and
not all
(
m
in
(
DBUS.MESSAGE_TYPE_METHOD_CALL,
DBUS.MESSAGE_TYPE_METHOD_RETURN,
DBUS.MESSAGE_TYPE_ERROR,
DBUS.MESSAGE_TYPE_SIGNAL,
)
for m in queue_types
)
) :
raise TypeError("invalid message type in queue_types: %s" % repr(queue_types))
#end if
if enable :
if self._receive_queue == None :
self.add_filter(self._queue_received_message, None)
self._receive_queue = []
#end if
self._receive_queue_enabled.clear()
self._receive_queue_enabled.update(queue_types)
else :
if self._receive_queue != None :
self._flush_awaiting_receive()
self.remove_filter(self._queue_received_message, None)
self._receive_queue = None
#end if
#end if
#end enable_receive_message
async def receive_message_async(self, want_types = None, timeout = DBUS.TIMEOUT_INFINITE) :
"receives the first available queued message of an appropriate type, blocking" \
" if none is available and timeout is nonzero. Returns None if the timeout" \
" elapses without a suitable message becoming available. want_types can be" \
" None to receive any of the previously-enabled message types, or a set or" \
" sequence of DBUS.MESSAGE_TYPE_XXX values to look only for messages of those" \
" types.\n" \
"\n" \
"You must have previously made a call to enable_receive_message to enable" \
" queueing of one or more message types on this Connection."
assert self._receive_queue != None, "receive_message_async not enabled"
# should I check if want_types contains anything not in self._receive_queue_enabled?
if timeout == DBUS.TIMEOUT_USE_DEFAULT :
timeout = DBUSX.DEFAULT_TIMEOUT
#end if
if timeout != DBUS.TIMEOUT_INFINITE :
finish_time = self.loop.time() + timeout
else :
finish_time = None
#end if
result = ... # indicates “watch this space”
while True :
# keep rescanning queue until got something or timeout
index = 0 # start next queue scan
while True :
if index == len(self._receive_queue) :
# nothing currently suitable on queue
if (
timeout == 0
or
finish_time != None
and
self.loop.time() > finish_time
) :
# waited too long, give up
result = None
break
#end if
if not self.is_connected :
raise BrokenPipeError("Connection has been disconnected")
#end if
# wait and see if something turns up
awaiting = self.loop.create_future()
self._awaiting_receive.append(awaiting)
if finish_time != None :
wait_timeout = finish_time - self.loop.time()
else :
wait_timeout = None
#end if
await self.wait \
(
(awaiting,),
timeout = wait_timeout
)
# ignore done & pending results because they
# dont match up with future Im waiting for
try :
self._awaiting_receive.remove(awaiting)
except ValueError :
pass
#end try
awaiting.cancel()
# just to avoid “Future exception was never retrieved” message
break # start new queue scan
#end if
# check next queue item
msg = self._receive_queue[index]
if want_types == None or msg.type in want_types :
# caller wants this one
result = msg
self._receive_queue.pop(index) # remove msg from queue
break
#end if
index += 1
#end while
if result != ... :
# either got something or given up
break
#end while
return \
result
#end receive_message_async
def iter_messages_async(self, want_types = None, stop_on = None, timeout = DBUS.TIMEOUT_INFINITE) :
"wrapper around receive_message_async() to allow use with an async-for statement." \
" Lets you write\n" \
"\n" \
" async for message in «conn».iter_messages_async(«want_types», «stop_on», «timeout») :" \
" «process message»\n" \
" #end for\n" \
"\n" \
"to receive and process messages in a loop. stop_on is an optional set of" \
" STOP_ON.xxx values indicating the conditions under which the iterator will" \
" raise StopAsyncIteration to terminate the loop."
if stop_on == None :
stop_on = frozenset()
elif (
not isinstance(stop_on, (set, frozenset))
or
not all(isinstance(elt, STOP_ON) for elt in stop_on)
) :
raise TypeError("stop_on must be None or set of STOP_ON")
#end if
assert self._receive_queue != None, "receive_message_async not enabled"
return \
_MsgAiter(self, want_types, stop_on, timeout)
#end iter_messages_async
# TODO: allocate/free data slot -- staticmethods
# TODO: get/set data
def set_change_sigpipe(self, will_modify_sigpipe) :
dbus.dbus_connection_set_change_sigpipe(self._dbobj, will_modify_sigpipe)
#end set_change_sigpipe
@property
def max_message_size(self) :
return \
dbus.dbus_connection_get_max_message_size(self._dbobj)
#end max_message_size
@max_message_size.setter
def max_message_size(self, size) :
dbus.dbus_connection_set_max_message_size(self._dbobj, size)
#end max_message_size
@property
def max_received_size(self) :
return \
dbus.dbus_connection_get_max_received_size(self._dbobj)
#end max_received_size
@max_received_size.setter
def max_received_size(self, size) :
dbus.dbus_connection_set_max_received_size(self._dbobj, size)
#end max_received_size
@property
def max_message_unix_fds(self) :
return \
dbus.dbus_connection_get_max_message_unix_fds(self._dbobj)
#end max_message_unix_fds
@max_message_unix_fds.setter
def max_message_unix_fds(self, size) :
dbus.dbus_connection_set_max_message_unix_fds(self._dbobj, size)
#end max_message_unix_fds
@property
def max_received_unix_fds(self) :
return \
dbus.dbus_connection_get_max_received_unix_fds(self._dbobj)
#end max_received_unix_fds
@max_received_unix_fds.setter
def max_received_unix_fds(self, size) :
dbus.dbus_connection_set_max_received_unix_fds(self._dbobj, size)
#end max_received_unix_fds
@property
def outgoing_size(self) :
return \
dbus.dbus_connection_get_outgoing_size(self._dbobj)
#end outgoing_size
@property
def outgoing_unix_fds(self) :
return \
dbus.dbus_connection_get_outgoing_unix_fds(self._dbobj)
#end outgoing_unix_fds
@property
def has_messages_to_send(self) :
return \
dbus.dbus_connection_has_messages_to_send(self._dbobj) != 0
#end has_messages_to_send
# message bus APIs
# <https://dbus.freedesktop.org/doc/api/html/group__DBusBus.html>
@classmethod
def bus_get(celf, type, private, error = None) :
"returns a Connection to one of the predefined D-Bus buses; type is a BUS_xxx value."
error, my_error = _get_error(error)
result = (dbus.dbus_bus_get, dbus.dbus_bus_get_private)[private](type, error._dbobj)
my_error.raise_if_set()
if result != None :
result = celf(result)
#end if
return \
result
#end bus_get
@classmethod
async def bus_get_async(celf, type, private, error = None, loop = None, timeout = DBUS.TIMEOUT_USE_DEFAULT) :
if loop == None :
loop = get_running_loop()
#end if
assert type in (DBUS.BUS_SESSION, DBUS.BUS_SYSTEM, DBUS.BUS_STARTER), \
"bus type must be BUS_SESSION, BUS_SYSTEM or BUS_STARTER"
if type == DBUS.BUS_STARTER :
starter_type = os.environ.get(DBUSX.STARTER_BUS_ADDRESS_TYPE)
is_system_bus = starter_type != None and starter_type == DBUSX.BUS_TYPE_SYSTEM
addr = os.environ.get(DBUSX.STARTER_BUS_ADDRESS_VAR)
else :
is_system_bus = type == DBUS.BUS_SYSTEM
addr = os.environ.get \
(
(DBUSX.SESSION_BUS_ADDRESS_VAR, DBUSX.SYSTEM_BUS_ADDRESS_VAR)[is_system_bus]
)
#end if
if not private and celf._shared_connections[is_system_bus] != None :
result = celf._shared_connections[is_system_bus]
else :
if addr == None :
addr = (DBUSX.SESSION_BUS_ADDRESS, DBUSX.SYSTEM_BUS_ADDRESS)[is_system_bus]
#end if
try :
result = await celf.open_async(addr, private, error, loop, timeout)
if error != None and error.is_set :
raise _Abort
#end if
await result.bus_register_async(error = error, timeout = timeout)
if error != None and error.is_set :
raise _Abort
#end if
if not private :
celf._shared_connections[is_system_bus] = result
#end if
except _Abort :
result = None
#end try
#end if
return \
result
#end bus_get_async
def bus_register(self, error = None) :
"Only to be used if you created the Connection with open() instead of bus_get();" \
" sends a “Hello” message to the D-Bus daemon to get a unique name assigned." \
" Can only be called once."
error, my_error = _get_error(error)
dbus.dbus_bus_register(self._dbobj, error._dbobj)
my_error.raise_if_set()
#end bus_register
async def bus_register_async(self, error = None, timeout = DBUS.TIMEOUT_USE_DEFAULT) :
"Only to be used if you created the Connection with open() instead of bus_get();" \
" sends a “Hello” message to the D-Bus daemon to get a unique name assigned." \
" Can only be called once."
assert self.loop != None, "no event loop to attach coroutine to"
assert self.bus_unique_name == None, "bus already registered"
message = Message.new_method_call \
(
destination = DBUS.SERVICE_DBUS,
path = DBUS.PATH_DBUS,
iface = DBUS.INTERFACE_DBUS,
method = "Hello"
)
reply = await self.send_await_reply(message, timeout = timeout)
if error != None and reply.type == DBUS.MESSAGE_TYPE_ERROR :
reply.set_error(error)
else :
self.bus_unique_name = reply.expect_return_objects("s")[0]
#end if
#end bus_register_async
@property
def bus_unique_name(self) :
"returns None if the bus connection has not been registered. Note that the" \
" unique_name can only be set once."
result = dbus.dbus_bus_get_unique_name(self._dbobj)
if result != None :
result = result.decode()
#end if
return \
result
#end bus_unique_name
@bus_unique_name.setter
def bus_unique_name(self, unique_name) :
if not dbus.dbus_bus_set_unique_name(self._dbobj, unique_name.encode()) :
raise CallFailed("dbus_bus_set_unique_name")
#end if
#end bus_unique_name
#+
# Calls to D-Bus Daemon
#-
@property
def bus_id(self) :
my_error = Error()
c_result = dbus.dbus_bus_get_id(self._dbobj, my_error._dbobj)
my_error.raise_if_set()
result = ct.cast(c_result, ct.c_char_p).value.decode()
dbus.dbus_free(c_result)
return \
result
#end bus_id
@property
async def bus_id_async(self) :
message = Message.new_method_call \
(
destination = DBUS.SERVICE_DBUS,
path = DBUS.PATH_DBUS,
iface = DBUS.INTERFACE_DBUS,
method = "GetId"
)
reply = await self.send_await_reply(message)
return \
reply.expect_return_objects("s")[0]
#end bus_id_async
def bus_get_unix_user(self, name, error = None) :
error, my_error = _get_error(error)
result = dbus.dbus_bus_get_unix_user(self._dbobj, name.encode(), error._dbobj)
my_error.raise_if_set()
return \
result
#end bus_get_unix_user
async def bus_get_unix_user_async(self, name, error = None, timeout = DBUS.TIMEOUT_USE_DEFAULT) :
message = Message.new_method_call \
(
destination = DBUS.SERVICE_DBUS,
path = DBUS.PATH_DBUS,
iface = DBUS.INTERFACE_DBUS,
method = "GetConnectionUnixUser"
)
message.append_objects("s", name)
reply = await self.send_await_reply(message, timeout = timeout)
if error != None and reply.type == DBUS.MESSAGE_TYPE_ERROR :
reply.set_error(error)
result = None
else :
result = reply.expect_return_objects("u")[0]
#end if
return \
result
#end bus_get_unix_user_async
def bus_request_name(self, name, flags, error = None) :
"asks the D-Bus daemon to register the specified bus name on your behalf," \
" blocking the thread until the reply is received. flags is a combination of" \
" NAME_FLAG_xxx bits. Result will be a REQUEST_NAME_REPLY_xxx value or -1 on error."
error, my_error = _get_error(error)
result = dbus.dbus_bus_request_name(self._dbobj, name.encode(), flags, error._dbobj)
my_error.raise_if_set()
return \
result
#end bus_request_name
async def bus_request_name_async(self, name, flags, error = None, timeout = DBUS.TIMEOUT_USE_DEFAULT) :
"asks the D-Bus daemon to register the specified bus name on your behalf. flags is" \
" a combination of NAME_FLAG_xxx bits. Result will be a REQUEST_NAME_REPLY_xxx value" \
" or None on error."
message = Message.new_method_call \
(
destination = DBUS.SERVICE_DBUS,
path = DBUS.PATH_DBUS,
iface = DBUS.INTERFACE_DBUS,
method = "RequestName"
)
message.append_objects("su", name, flags)
reply = await self.send_await_reply(message, timeout = timeout)
if error != None and reply.type == DBUS.MESSAGE_TYPE_ERROR :
reply.set_error(error)
result = None
else :
result = reply.expect_return_objects("u")[0]
#end if
return \
result
#end bus_request_name_async
def bus_release_name(self, name, error = None) :
"asks the D-Bus daemon to release your registration of the specified bus name," \
" blocking the thread until the reply is received."
error, my_error = _get_error(error)
result = dbus.dbus_bus_release_name(self._dbobj, name.encode(), error._dbobj)
my_error.raise_if_set()
return \
result
#end bus_release_name
async def bus_release_name_async(self, name, error = None, timeout = DBUS.TIMEOUT_USE_DEFAULT) :
"asks the D-Bus daemon to release your registration of the specified bus name."
message = Message.new_method_call \
(
destination = DBUS.SERVICE_DBUS,
path = DBUS.PATH_DBUS,
iface = DBUS.INTERFACE_DBUS,
method = "ReleaseName"
)
message.append_objects("s", name)
reply = await self.send_await_reply(message, timeout = timeout)
if error != None and reply.type == DBUS.MESSAGE_TYPE_ERROR :
reply.set_error(error)
result = None
else :
result = reply.expect_return_objects("u")[0]
#end if
return \
result
#end bus_release_name_async
def bus_name_has_owner(self, name, error = None) :
"asks the D-Bus daemon if anybody has claimed the specified bus name, blocking" \
" the thread until the reply is received."
error, my_error = _get_error(error)
result = dbus.dbus_bus_name_has_owner(self._dbobj, name.encode(), error._dbobj)
my_error.raise_if_set()
return \
result
#end bus_name_has_owner
async def bus_name_has_owner_async(self, name, error = None, timeout = DBUS.TIMEOUT_USE_DEFAULT) :
"asks the D-Bus daemon if anybody has claimed the specified bus name."
message = Message.new_method_call \
(
destination = DBUS.SERVICE_DBUS,
path = DBUS.PATH_DBUS,
iface = DBUS.INTERFACE_DBUS,
method = "NameHasOwner"
)
message.append_objects("s", name)
reply = await self.send_await_reply(message, timeout = timeout)
if error != None and reply.type == DBUS.MESSAGE_TYPE_ERROR :
reply.set_error(error)
result = None
else :
result = reply.expect_return_objects("b")[0]
#end if
return \
result
#end bus_name_has_owner_async
def bus_start_service_by_name(self, name, flags = 0, error = None) :
error, my_error = _get_error(error)
outflags = ct.c_uint()
success = dbus.dbus_bus_start_service_by_name(self._dbobj, name.encode(), flags, ct.byref(outflags), error._dbobj)
my_error.raise_if_set()
return \
outflags.value
#end bus_start_service_by_name
async def bus_start_service_by_name_async(self, name, flags = 0, error = None, timeout = DBUS.TIMEOUT_USE_DEFAULT) :
message = Message.new_method_call \
(
destination = DBUS.SERVICE_DBUS,
path = DBUS.PATH_DBUS,
iface = DBUS.INTERFACE_DBUS,
method = "StartServiceByName"
)
message.append_objects("su", name, flags)
reply = await self.send_await_reply(message, timeout = timeout)
if error != None and reply.type == DBUS.MESSAGE_TYPE_ERROR :
reply.set_error(error)
result = None
else :
result = reply.expect_return_objects("u")[0]
#end if
return \
result
#end bus_start_service_by_name
def bus_add_match(self, rule, error = None) :
"adds a match rule for messages you want to receive. By default you get all" \
" messages addressed to your bus name(s); but you can use this, for example," \
" to request notification of signals indicating useful events on the system."
error, my_error = _get_error(error)
dbus.dbus_bus_add_match(self._dbobj, format_rule(rule).encode(), error._dbobj)
my_error.raise_if_set()
#end bus_add_match
async def bus_add_match_async(self, rule, error = None, timeout = DBUS.TIMEOUT_USE_DEFAULT) :
"adds a match rule for messages you want to receive. By default you get all" \
" messages addressed to your bus name(s); but you can use this, for example," \
" to request notification of signals indicating useful events on the system."
message = Message.new_method_call \
(
destination = DBUS.SERVICE_DBUS,
path = DBUS.PATH_DBUS,
iface = DBUS.INTERFACE_DBUS,
method = "AddMatch"
)
message.append_objects("s", format_rule(rule))
reply = await self.send_await_reply(message, timeout = timeout)
if error != None and reply.type == DBUS.MESSAGE_TYPE_ERROR :
reply.set_error(error)
else :
reply.expect_return_objects("")
#end if
#end bus_add_match_async
def bus_remove_match(self, rule, error = None) :
"removes a previously-added match rule for messages you previously wanted" \
" to receive."
error, my_error = _get_error(error)
dbus.dbus_bus_remove_match(self._dbobj, format_rule(rule).encode(), error._dbobj)
my_error.raise_if_set()
#end bus_remove_match
async def bus_remove_match_async(self, rule, error = None, timeout = DBUS.TIMEOUT_USE_DEFAULT) :
"removes a previously-added match rule for messages you previously wanted" \
" to receive."
message = Message.new_method_call \
(
destination = DBUS.SERVICE_DBUS,
path = DBUS.PATH_DBUS,
iface = DBUS.INTERFACE_DBUS,
method = "RemoveMatch"
)
message.append_objects("s", format_rule(rule))
reply = await self.send_await_reply(message, timeout = timeout)
if error != None and reply.type == DBUS.MESSAGE_TYPE_ERROR :
reply.set_error(error)
else :
reply.expect_return_objects("")
#end if
#end bus_remove_match_async
@staticmethod
def _rule_action_match(self, message, _) :
# installed as a message filter to invoke actions corresponding to rules
# that the message matches. To avoid spurious method-not-handled errors
# from eavesdropping on method calls not addressed to me, this routine
# always returns a “handled” status. That means this same Connection
# object should not be used for both eavesdropping and for normal
# method calls.
handled = False
for entry in self._match_actions.values() :
if matches_rule(message, entry.rule) :
for action in entry.actions :
result = action.func(self, message, action.user_data)
if asyncio.iscoroutine(result) :
self.create_task(result)
#end if
#end for
handled = True # passed to at least one handler
#end if
#end for
return \
(DBUS.HANDLER_RESULT_NOT_YET_HANDLED, DBUS.HANDLER_RESULT_HANDLED)[handled]
#end _rule_action_match
def bus_add_match_action(self, rule, func, user_data, error = None) :
"adds a message filter that invokes func(conn, message, user_data)" \
" for each incoming message that matches the specified rule. Unlike" \
" the underlying add_filter and bus_add_match calls, this allows you" \
" to associate the action with the particular matching rule.\n" \
"\n" \
"Note that the message filter installed to process these rules always" \
" returns a DBUS.HANDLER_RESULT_HANDLED status; so either only use this" \
" to listen for signals, or do not use the same Connection object to" \
" handle normal method calls."
rulekey = format_rule(rule)
rule = unformat_rule(rule)
if rulekey not in self._match_actions :
self.bus_add_match(rulekey, error) # could fail here with bad rule
if error == None or not error.is_set :
if len(self._match_actions) == 0 :
self.add_filter(self._rule_action_match, None)
#end if
self._match_actions[rulekey] = _MatchActionEntry(rule)
#end if
#end if
if error == None or not error.is_set :
self._match_actions[rulekey].actions.add(_MatchActionEntry._Action(func, user_data))
#end if
#end bus_add_match_action
def bus_remove_match_action(self, rule, func, user_data, error = None) :
"removes a message filter previously installed with bus_add_match_action."
rulekey = format_rule(rule)
rule = unformat_rule(rule)
self._match_actions[rulekey].actions.remove(_MatchActionEntry._Action(func, user_data))
if len(self._match_actions[rulekey].actions) == 0 :
self.bus_remove_match(rulekey, error) # shouldnt fail!
del self._match_actions[rulekey]
if len(self._match_actions) == 0 :
self.remove_filter(self._rule_action_match, None)
#end if
#end if
#end bus_remove_match_action
async def bus_add_match_action_async(self, rule, func, user_data, error = None, timeout = DBUS.TIMEOUT_USE_DEFAULT) :
"adds a message filter that invokes func(conn, message, user_data)" \
" for each incoming message that matches the specified rule. Unlike" \
" the underlying add_filter and bus_add_match calls, this allows you" \
" to associate the action with the particular matching rule.\n" \
"\n" \
"Note that the message filter installed to process these rules always" \
" returns a DBUS.HANDLER_RESULT_HANDLED status; so either only use this" \
" to listen for signals, or do not use the same Connection object to" \
" handle normal method calls."
rulekey = format_rule(rule)
rule = unformat_rule(rule)
if rulekey not in self._match_actions :
await self.bus_add_match_async(rulekey, error, timeout) # could fail here with bad rule
if error == None or not error.is_set :
if len(self._match_actions) == 0 :
self.add_filter(self._rule_action_match, None)
#end if
self._match_actions[rulekey] = _MatchActionEntry(rule)
#end if
#end if
if error == None or not error.is_set :
self._match_actions[rulekey].actions.add(_MatchActionEntry._Action(func, user_data))
#end if
#end bus_add_match_action_async
async def bus_remove_match_action_async(self, rule, func, user_data, error = None, timeout = DBUS.TIMEOUT_USE_DEFAULT) :
"removes a message filter previously installed with bus_add_match_action."
rulekey = format_rule(rule)
rule = unformat_rule(rule)
self._match_actions[rulekey].actions.remove(_MatchActionEntry._Action(func, user_data))
if len(self._match_actions[rulekey].actions) == 0 :
await self.bus_remove_match_async(rulekey, error, timeout) # shouldnt fail!
del self._match_actions[rulekey]
if len(self._match_actions) == 0 :
self.remove_filter(self._rule_action_match, None)
#end if
#end if
#end bus_remove_match_action_async
def become_monitor(self, rules) :
"turns the connection into one that can only receive monitoring messages."
message = Message.new_method_call \
(
destination = DBUS.SERVICE_DBUS,
path = DBUS.PATH_DBUS,
iface = DBUS.INTERFACE_MONITORING,
method = "BecomeMonitor"
)
message.append_objects("asu", (list(format_rule(rule) for rule in rules)), 0)
self.send(message)
#end become_monitor
#+
# End calls to D-Bus Daemon
#-
def attach_asyncio(self, loop = None) :
"attaches this Connection object to an asyncio event loop. If none is" \
" specified, the default event loop (as returned from asyncio.get_event_loop()" \
" is used."
w_self = weak_ref(self)
# to avoid a reference cycle
def dispatch() :
return \
_wderef(w_self, "connection").dispatch()
#end dispatch
#begin attach_asyncio
assert self.loop == None, "already attached to an event loop"
_loop_attach(self, loop, dispatch)
#end attach_asyncio
#end Connection
class _MsgAiter :
# internal class for use by Connection.iter_messages_async (above).
def __init__(self, conn, want_types, stop_on, timeout) :
self.conn = conn
self.want_types = want_types
self.stop_on = stop_on
self.timeout = timeout
#end __init__
def __aiter__(self) :
# Im my own iterator.
return \
self
#end __aiter__
async def __anext__(self) :
stop_iter = False
try :
result = await self.conn.receive_message_async(self.want_types, self.timeout)
if result == None and STOP_ON.TIMEOUT in self.stop_on :
stop_iter = True
#end if
except BrokenPipeError :
if STOP_ON.CLOSED not in self.stop_on :
raise
#end if
stop_iter = True
#end try
if stop_iter :
raise StopAsyncIteration("Connection.receive_message_async terminating")
#end if
return \
result
#end __anext__
#end _MsgAiter
class Server(TaskKeeper) :
"wrapper around a DBusServer object. Do not instantiate directly; use" \
" the listen method.\n" \
"\n" \
"You only need this if you want to use D-Bus as a communication mechanism" \
" separate from the system/session buses provided by the D-Bus daemon: you" \
" create a Server object listening on a specified address, and clients can" \
" use Connection.open() to connect to you on that address."
# <https://dbus.freedesktop.org/doc/api/html/group__DBusServer.html>
# Doesnt really need services of TaskKeeper for now, but might be
# useful in future
__slots__ = \
(
"_dbobj",
"_new_connections",
"_await_new_connections",
"max_new_connections",
"autoattach_new_connections",
# need to keep references to ctypes-wrapped functions
# so they don't disappear prematurely:
"_new_connection_function",
"_free_new_connection_data",
"_add_watch_function",
"_remove_watch_function",
"_toggled_watch_function",
"_free_watch_data",
"_add_timeout_function",
"_remove_timeout_function",
"_toggled_timeout_function",
"_free_timeout_data",
) # to forestall typos
_instances = WeakValueDictionary()
def __new__(celf, _dbobj) :
self = celf._instances.get(_dbobj)
if self == None :
self = super().__new__(celf)
super()._init(self)
self._dbobj = _dbobj
self._new_connections = None
self._await_new_connections = None
self.max_new_connections = None
self.autoattach_new_connections = True
self._new_connection_function = None
self._free_new_connection_data = None
self._add_watch_function = None
self._remove_watch_function = None
self._toggled_watch_function = None
self._free_watch_data = None
self._add_timeout_function = None
self._remove_timeout_function = None
self._toggled_timeout_function = None
self._free_timeout_data = None
celf._instances[_dbobj] = self
else :
dbus.dbus_server_unref(self._dbobj)
# lose extra reference created by caller
#end if
return \
self
#end __new__
def __del__(self) :
if self._dbobj != None :
if self.loop != None :
# remove via direct low-level libdbus calls
dbus.dbus_server_set_watch_functions(self._dbobj, None, None, None, None, None)
dbus.dbus_server_set_timeout_functions(self._dbobj, None, None, None, None, None)
self.loop = None
#end if
dbus.dbus_server_unref(self._dbobj)
self._dbobj = None
#end if
#end __del__
@classmethod
def listen(celf, address, error = None) :
error, my_error = _get_error(error)
result = dbus.dbus_server_listen(address.encode(), error._dbobj)
my_error.raise_if_set()
if result != None :
result = celf(result)
#end if
return \
result
#end listen
def _flush_awaiting_connect(self) :
if self._await_new_connections != None :
while len(self._await_new_connections) != 0 :
waiting = self._await_new_connections.pop(0)
waiting.set_exception(BrokenPipeError("async listens have been disabled"))
#end while
#end if
#end _flush_awaiting_connect
def disconnect(self) :
self._flush_awaiting_connect()
dbus.dbus_server_disconnect(self._dbobj)
#end disconnect
@property
def is_connected(self) :
return \
dbus.dbus_server_get_is_connected(self._dbobj) != 0
#end is_connected
@property
def address(self) :
c_result = dbus.dbus_server_get_address(self._dbobj)
if c_result == None :
raise CallFailed("dbus_server_get_address")
#end if
result = ct.cast(c_result, ct.c_char_p).value.decode()
dbus.dbus_free(c_result)
return \
result
#end address
@property
def id(self) :
c_result = dbus.dbus_server_get_id(self._dbobj)
if c_result == None :
raise CallFailed("dbus_server_get_id")
#end if
result = ct.cast(c_result, ct.c_char_p).value.decode()
dbus.dbus_free(c_result)
return \
result
#end id
def set_new_connection_function(self, function, data, free_data = None) :
"sets the callback for libdbus to notify you of a new incoming connection." \
" It is up to you to save the Connection object for later processing of" \
" messages, or close it to reject the connection attempt."
w_self = weak_ref(self)
def wrap_function(c_self, c_conn, _data) :
function(_wderef(w_self, "server"), Connection(dbus.dbus_connection_ref(c_conn)), data)
# even though this is a new connection, I still have to reference it
#end wrap_function
def wrap_free_data(_data) :
free_data(data)
#end wrap_free_data
#begin set_new_connection_function
assert self.loop == None, "new connections are being managed by an event loop"
self._new_connection_function = DBUS.NewConnectionFunction(wrap_function)
if free_data != None :
self._free_new_connection_data = DBUS.FreeFunction(wrap_free_data)
else :
self._free_new_connection_data = None
#end if
dbus.dbus_server_set_new_connection_function(self._dbobj, self._new_connection_function, None, self._free_new_connection_data)
#end set_new_connection_function
def set_watch_functions(self, add_function, remove_function, toggled_function, data, free_data = None) :
"sets the callbacks for libdbus to use to notify you of Watch objects it wants" \
" you to manage."
def wrap_add_function(c_watch, _data) :
return \
add_function(Watch(c_watch), data)
#end wrap_add_function
def wrap_remove_function(c_watch, _data) :
return \
remove_function(Watch(c_watch), data)
#end wrap_remove_function
def wrap_toggled_function(c_watch, _data) :
return \
toggled_function(Watch(c_watch), data)
#end wrap_toggled_function
def wrap_free_data(_data) :
free_data(data)
#end wrap_free_data
#begin set_watch_functions
self._add_watch_function = DBUS.AddWatchFunction(wrap_add_function)
self._remove_watch_function = DBUS.RemoveWatchFunction(wrap_remove_function)
if toggled_function != None :
self._toggled_watch_function = DBUS.WatchToggledFunction(wrap_toggled_function)
else :
self._toggled_watch_function = None
#end if
if free_data != None :
self._free_watch_data = DBUS.FreeFunction(wrap_free_data)
else :
self._free_watch_data = None
#end if
if not dbus.dbus_server_set_watch_functions(self._dbobj, self._add_watch_function, self._remove_watch_function, self._toggled_watch_function, None, self._free_watch_data) :
raise CallFailed("dbus_server_set_watch_functions")
#end if
#end set_watch_functions
def set_timeout_functions(self, add_function, remove_function, toggled_function, data, free_data = None) :
"sets the callbacks for libdbus to use to notify you of Timeout objects it wants" \
" you to manage."
def wrap_add_function(c_timeout, _data) :
return \
add_function(Timeout(c_timeout), data)
#end wrap_add_function
def wrap_remove_function(c_timeout, _data) :
return \
remove_function(Timeout(c_timeout), data)
#end wrap_remove_function
def wrap_toggled_function(c_timeout, _data) :
return \
toggled_function(Timeout(c_timeout), data)
#end wrap_toggled_function
def wrap_free_data(_data) :
free_data(data)
#end wrap_free_data
#begin set_timeout_functions
self._add_timeout_function = DBUS.AddTimeoutFunction(wrap_add_function)
self._remove_timeout_function = DBUS.RemoveTimeoutFunction(wrap_remove_function)
if toggled_function != None :
self._toggled_timeout_function = DBUS.TimeoutToggledFunction(wrap_toggled_function)
else :
self._toggled_timeout_function = None
#end if
if free_data != None :
self._free_timeout_data = DBUS.FreeFunction(wrap_free_data)
else :
self._free_timeout_data = None
#end if
if not dbus.dbus_server_set_timeout_functions(self._dbobj, self._add_timeout_function, self._remove_timeout_function, self._toggled_timeout_function, None, self._free_timeout_data) :
raise CallFailed("dbus_server_set_timeout_functions")
#end if
#end set_timeout_functions
def set_auth_mechanisms(self, mechanisms) :
nr_mechanisms = len(mechanisms)
c_mechanisms = (ct.c_char_p * (nr_mechanisms + 1))()
for i in range(nr_mechanisms) :
c_mechanisms[i] = mechanisms[i].encode()
#end if
c_mechanisms[nr_mechanisms] = None # marks end of array
if not dbus.dbus_server_set_auth_mechanisms(self._dbobj, c_mechanisms) :
raise CallFailed("dbus_server_set_auth_mechanisms")
#end if
#end set_auth_mechanisms
# TODO: allocate/free slot (static methods)
# TODO: get/set/data
def attach_asyncio(self, loop = None) :
"attaches this Server object to an asyncio event loop. If none is" \
" specified, the default event loop (as returned from asyncio.get_event_loop()" \
" is used.\n" \
"\n" \
"This call will also automatically attach a new_connection callback. You then use" \
" the await_new_connection coroutine to obtain new connections. If" \
" self.autoattach_new_connections, then Connection.attach_asyncio() will" \
" automatically be called to handle events for the new connection."
def new_connection(self, conn, user_data) :
if len(self._await_new_connections) != 0 :
awaiting = self._await_new_connections.pop(0)
awaiting.set_result(conn)
else :
# put it in _new_connections queue
if (
self.max_new_connections != None
and
len(self._new_connections) >= self.max_new_connections
) :
# too many connections pending, reject
conn.close()
else :
self._new_connections.append(conn)
#end if
#end if
#end new_connection
#begin attach_asyncio
assert self.loop == None, "already attached to an event loop"
assert self._new_connection_function == None, "already set a new-connection function"
self._new_connections = []
self._await_new_connections = []
self.set_new_connection_function(new_connection, None)
_loop_attach(self, loop, None)
#end attach_asyncio
async def await_new_connection(self, timeout = DBUS.TIMEOUT_INFINITE) :
"retrieves the next new Connection, if there is one available, otherwise" \
" suspends the current coroutine for up to the specified timeout duration" \
" while waiting for one to appear. Returns None if there is no new connection" \
" within that time."
assert self.loop != None, "no event loop to attach coroutine to"
if len(self._new_connections) != 0 :
result = self._new_connections.pop(0)
else :
if not self.is_connected :
raise BrokenPipeError("Server has been disconnected")
#end if
if timeout == 0 :
# might as well short-circuit the whole waiting process
result = None
else :
awaiting = self.loop.create_future()
self._await_new_connections.append(awaiting)
if timeout == DBUS.TIMEOUT_INFINITE :
timeout = None
else :
if timeout == DBUS.TIMEOUT_USE_DEFAULT :
timeout = DBUSX.DEFAULT_TIMEOUT
#end if
#end if
await self.wait \
(
(awaiting,),
timeout = timeout
)
# ignore done & pending results because they
# dont match up with future Im waiting for
if awaiting.done() :
result = awaiting.result()
else :
self._await_new_connections.pop(self._await_new_connections.index(awaiting))
result = None
#end if
#end if
#end if
if result != None and self.autoattach_new_connections :
result.attach_asyncio(self.loop)
#end if
return \
result
#end await_new_connection
def iter_connections_async(self, stop_on = None, timeout = DBUS.TIMEOUT_INFINITE) :
"wrapper around await_new_connection() to allow use with an async-for" \
" statement. Lets you write\n" \
"\n" \
" async for conn in «server».iter_connections_async(«timeout») :" \
" «accept conn»\n" \
" #end for\n" \
"\n" \
"to receive and process incoming connections in a loop. stop_on is an optional set of" \
" STOP_ON.xxx values indicating the conditions under which the iterator will" \
" raise StopAsyncIteration to terminate the loop."
assert self.loop != None, "no event loop to attach coroutine to"
if stop_on == None :
stop_on = frozenset()
elif (
not isinstance(stop_on, (set, frozenset))
or
not all(isinstance(elt, STOP_ON) for elt in stop_on)
) :
raise TypeError("stop_on must be None or set of STOP_ON")
#end if
return \
_SrvAiter(self, stop_on, timeout)
#end iter_connections_async
#end Server
class _SrvAiter :
# internal class for use by Server.iter_connections_async (above).
def __init__(self, srv, stop_on, timeout) :
self.srv = srv
self.stop_on = stop_on
self.timeout = timeout
#end __init__
def __aiter__(self) :
# Im my own iterator.
return \
self
#end __aiter__
async def __anext__(self) :
stop_iter = False
try :
result = await self.srv.await_new_connection(self.timeout)
if result == None and STOP_ON.TIMEOUT in self.stop_on :
stop_iter = True
#end if
except BrokenPipeError :
if STOP_ON.CLOSED not in self.stop_on :
raise
#end if
stop_iter = True
#end try
if stop_iter :
raise StopAsyncIteration("Server.iter_connections_async terminating")
#end if
return \
result
#end __anext__
#end _SrvAiter
class PreallocatedSend :
"wrapper around a DBusPreallocatedSend object. Do not instantiate directly;" \
" get from Connection.preallocate_send method."
# <https://dbus.freedesktop.org/doc/api/html/group__DBusConnection.html>
__slots__ = ("__weakref__", "_dbobj", "_w_parent", "_sent") # to forestall typos
_instances = WeakValueDictionary()
def __new__(celf, _dbobj, _parent) :
self = celf._instances.get(_dbobj)
if self == None :
self = super().__new__(celf)
self._dbobj = _dbobj
self._w_parent = weak_ref(_parent)
self._sent = False
celf._instances[_dbobj] = self
else :
assert self._w_parent() == _parent
#end if
return \
self
#end __new__
def __del__(self) :
if self._dbobj != None :
parent = self._w_parent()
if parent != None and not self._sent :
dbus.dbus_connection_free_preallocated_send(parent._dbobj, self._dbobj)
#end if
self._dbobj = None
#end if
#end __del__
def send(self, message) :
"alternative to Connection.send_preallocated."
if not isinstance(message, Message) :
raise TypeError("message must be a Message")
#end if
assert not self._sent, "preallocated has already been sent"
parent = self._w_parent()
assert parent != None, "parent Connection has gone away"
serial = ct.c_uint()
dbus.dbus_connection_send_preallocated(parent._dbobj, self._dbobj, message._dbobj, ct.byref(serial))
self._sent = True
return \
serial.value
#end send
#end PreallocatedSend
class Message :
"wrapper around a DBusMessage object. Do not instantiate directly; use one of the" \
" new_xxx or copy methods, or Connection.pop_message or Connection.borrow_message."
# <https://dbus.freedesktop.org/doc/api/html/group__DBusMessage.html>
__slots__ = ("__weakref__", "_dbobj", "_conn", "_borrowed") # to forestall typos
_instances = WeakValueDictionary()
def __new__(celf, _dbobj) :
self = celf._instances.get(_dbobj)
if self == None :
self = super().__new__(celf)
self._dbobj = _dbobj
self._conn = None
self._borrowed = False
celf._instances[_dbobj] = self
else :
dbus.dbus_message_unref(self._dbobj)
# lose extra reference created by caller
#end if
return \
self
#end __new__
def __del__(self) :
if self._dbobj != None :
assert not self._borrowed, "trying to dispose of borrowed message"
dbus.dbus_message_unref(self._dbobj)
self._dbobj = None
#end if
#end __del__
@classmethod
def new(celf, type) :
"type is one of the DBUS.MESSAGE_TYPE_xxx codes. Using one of the type-specific" \
" calls--new_error, new_method_call, new_method_return, new_signal--is probably" \
" more convenient."
result = dbus.dbus_message_new(type)
if result == None :
raise CallFailed("dbus_message_new")
#end if
return \
celf(result)
#end new
def new_error(self, name, message) :
"creates a new DBUS.MESSAGE_TYPE_ERROR message that is a reply to this Message."
result = dbus.dbus_message_new_error(self._dbobj, name.encode(), (lambda : None, lambda : message.encode())[message != None]())
if result == None :
raise CallFailed("dbus_message_new_error")
#end if
return \
type(self)(result)
#end new_error
# probably not much point trying to use new_error_printf
@classmethod
def new_method_call(celf, destination, path, iface, method) :
"creates a new DBUS.MESSAGE_TYPE_METHOD_CALL message."
result = dbus.dbus_message_new_method_call \
(
(lambda : None, lambda : destination.encode())[destination != None](),
path.encode(),
(lambda : None, lambda : iface.encode())[iface != None](),
method.encode(),
)
if result == None :
raise CallFailed("dbus_message_new_method_call")
#end if
return \
celf(result)
#end new_method_call
def new_method_return(self) :
"creates a new DBUS.MESSAGE_TYPE_METHOD_RETURN that is a reply to this Message."
result = dbus.dbus_message_new_method_return(self._dbobj)
if result == None :
raise CallFailed("dbus_message_new_method_return")
#end if
return \
type(self)(result)
#end new_method_return
@classmethod
def new_signal(celf, path, iface, name) :
"creates a new DBUS.MESSAGE_TYPE_SIGNAL message."
result = dbus.dbus_message_new_signal(path.encode(), iface.encode(), name.encode())
if result == None :
raise CallFailed("dbus_message_new_signal")
#end if
return \
celf(result)
#end new_signal
def copy(self) :
"creates a copy of this Message."
result = dbus.dbus_message_copy(self._dbobj)
if result == None :
raise CallFailed("dbus_message_copy")
#end if
return \
type(self)(result)
#end copy
@property
def type(self) :
"returns the DBUS.MESSAGE_TYPE_XXX code for this Message."
return \
dbus.dbus_message_get_type(self._dbobj)
#end type
# NYI append_args, get_args -- probably not useful, use my
# objects and append_objects convenience methods (below) instead
class ExtractIter :
"for iterating over the arguments in a Message for reading. Do not" \
" instantiate directly; get from Message.iter_init or ExtractIter.recurse.\n" \
"\n" \
"You can use this as a Python iterator, in a for-loop, passing" \
" it to the next() built-in function etc. Do not mix such usage with calls to" \
" the has_next() and next() methods."
__slots__ = ("_dbobj", "_parent", "_nulliter", "_startiter") # to forestall typos
def __init__(self, _parent) :
self._dbobj = DBUS.MessageIter()
self._parent = _parent
self._nulliter = False
self._startiter = True
#end __init__
@property
def has_next(self) :
return \
dbus.dbus_message_iter_has_next(self._dbobj)
#end has_next
def next(self) :
if self._nulliter or not dbus.dbus_message_iter_next(self._dbobj) :
raise StopIteration("end of message iterator")
#end if
self._startiter = False
return \
self
#end next
def __iter__(self) :
return \
self
#end __iter__
def __next__(self) :
if self._nulliter :
raise StopIteration("empty message iterator")
else :
if self._startiter :
self._startiter = False
else :
self.next()
#end if
#end if
return \
self
#end __next__
@property
def arg_type(self) :
"the type code for this argument."
return \
dbus.dbus_message_iter_get_arg_type(self._dbobj)
#end arg_type
@property
def element_type(self) :
"the contained element type of this argument, assuming it is of a container type."
return \
dbus.dbus_message_iter_get_element_type(self._dbobj)
#end element_type
def recurse(self) :
"creates a sub-iterator for recursing into a container argument."
subiter = type(self)(self)
dbus.dbus_message_iter_recurse(self._dbobj, subiter._dbobj)
return \
subiter
#end recurse
@property
def signature(self) :
c_result = dbus.dbus_message_iter_get_signature(self._dbobj)
if c_result == None :
raise CallFailed("dbus_message_iter_get_signature")
#end if
result = ct.cast(c_result, ct.c_char_p).value.decode()
dbus.dbus_free(c_result)
return \
result
#end signature
@property
def basic(self) :
"returns the argument value, assuming it is of a non-container type."
argtype = self.arg_type
c_result_type = DBUS.basic_to_ctypes[argtype]
c_result = c_result_type()
dbus.dbus_message_iter_get_basic(self._dbobj, ct.byref(c_result))
if c_result_type == ct.c_char_p :
result = c_result.value.decode()
else :
result = c_result.value
#end if
if argtype in DBUS.basic_subclasses :
result = DBUS.basic_subclasses[argtype](result)
#end if
return \
result
#end basic
@property
def object(self) :
"returns the current iterator item as a Python object. Will recursively" \
" process container objects."
argtype = self.arg_type
if argtype in DBUS.basic_to_ctypes :
result = self.basic
elif argtype == DBUS.TYPE_ARRAY :
if self.element_type == DBUS.TYPE_DICT_ENTRY :
result = {}
subiter = self.recurse()
while True :
entry = next(subiter, None)
if entry == None or entry.arg_type == DBUS.TYPE_INVALID :
# TYPE_INVALID can be returned for an empty dict
break
if entry.arg_type != DBUS.TYPE_DICT_ENTRY :
raise RuntimeError("invalid dict entry type %d" % entry.arg_type)
#end if
key, value = tuple(x.object for x in entry.recurse())
result[key] = value
#end while
elif type_is_fixed_array_elttype(self.element_type) :
result = self.fixed_array
else :
result = list(x.object for x in self.recurse())
if len(result) != 0 and result[-1] == None :
# fudge for iterating into an empty array
result = result[:-1]
#end if
#end if
elif argtype == DBUS.TYPE_STRUCT :
result = list(x.object for x in self.recurse())
elif argtype == DBUS.TYPE_VARIANT :
subiter = self.recurse()
subiter = next(subiter)
result = (DBUS.Signature(subiter.signature), subiter.object)
elif argtype == DBUS.TYPE_INVALID :
# fudge for iterating into an empty array
result = None
else :
raise RuntimeError("unrecognized argtype %d" % argtype)
#end if
return \
result
#end object
if hasattr(dbus, "dbus_message_iter_get_element_count") :
@property
def element_count(self) :
"returns the count of contained elements, assuming the current argument" \
" is of a container type."
return \
dbus.dbus_message_iter_get_element_count(self._dbobj)
#end element_count
#end if
@property
def fixed_array(self) :
"returns the array elements, assuming the current argument is an array" \
" with a non-container element type."
c_element_type = DBUS.basic_to_ctypes[self.element_type]
c_result = ct.POINTER(c_element_type)()
c_nr_elts = ct.c_int()
subiter = self.recurse()
dbus.dbus_message_iter_get_fixed_array(subiter._dbobj, ct.byref(c_result), ct.byref(c_nr_elts))
result = []
for i in range(c_nr_elts.value) :
elt = c_result[i]
if c_element_type == ct.c_char_p :
elt = elt.value.decode()
#end if
result.append(elt)
#end for
return \
result
#end fixed_array
#end ExtractIter
class AppendIter :
"for iterating over the arguments in a Message for appending." \
" Do not instantiate directly; get from Message.iter_init_append or" \
" AppendIter.open_container."
__slots__ = ("_dbobj", "_parent") # to forestall typos
def __init__(self, _parent) :
self._dbobj = DBUS.MessageIter()
self._parent = _parent
#end __init__
def append_basic(self, type, value) :
"appends a single value of a non-container type."
if type in DBUS.int_convert :
value = DBUS.int_convert[type](value)
#end if
c_type = DBUS.basic_to_ctypes[type]
if c_type == ct.c_char_p :
if not isinstance(value, str) :
raise TypeError \
(
"expecting type %s, got %s" % (TYPE(type), builtins.type(value).__name__)
)
#end if
value = value.encode()
#end if
c_value = c_type(value)
if not dbus.dbus_message_iter_append_basic(self._dbobj, type, ct.byref(c_value)) :
raise CallFailed("dbus_message_iter_append_basic")
#end if
return \
self
#end append_basic
def append_fixed_array(self, element_type, values) :
"appends an array of elements of a non-container type."
c_elt_type = DBUS.basic_to_ctypes[element_type]
nr_elts = len(values)
c_arr = (nr_elts * c_elt_type)()
for i in range(nr_elts) :
if c_elt_type == ct.c_char_p :
c_arr[i] = values[i].encode()
else :
c_arr[i] = values[i]
#end if
#end for
c_arr_ptr = ct.pointer(c_arr)
if not dbus.dbus_message_iter_append_fixed_array(self._dbobj, element_type, ct.byref(c_arr_ptr), nr_elts) :
raise CallFailed("dbus_message_iter_append_fixed_array")
#end if
return \
self
#end append_fixed_array
def open_container(self, type, contained_signature) :
"starts appending an argument of a container type, returning a sub-iterator" \
" for appending the contents of the argument. Can be called recursively for" \
" containers of containers etc."
if contained_signature != None :
c_sig = contained_signature.encode()
else :
c_sig = None
#end if
subiter = builtins.type(self)(self)
if not dbus.dbus_message_iter_open_container(self._dbobj, type, c_sig, subiter._dbobj) :
raise CallFailed("dbus_message_iter_open_container")
#end if
return \
subiter
#end open_container
def close(self) :
"closes a sub-iterator, indicating the completion of construction" \
" of a container value."
assert self._parent != None, "cannot close top-level iterator"
if not dbus.dbus_message_iter_close_container(self._parent._dbobj, self._dbobj) :
raise CallFailed("dbus_message_iter_close_container")
#end if
return \
self._parent
#end close
def abandon(self) :
"closes a sub-iterator, indicating the abandonment of construction" \
" of a container value. The Message object is effectively unusable" \
" after this point and should be discarded."
assert self._parent != None, "cannot abandon top-level iterator"
dbus.dbus_message_iter_abandon_container(self._parent._dbobj, self._dbobj)
return \
self._parent
#end abandon
#end AppendIter
def iter_init(self) :
"creates an iterator for extracting the arguments of the Message."
iter = self.ExtractIter(None)
if dbus.dbus_message_iter_init(self._dbobj, iter._dbobj) == 0 :
iter._nulliter = True
#end if
return \
iter
#end iter_init
@property
def objects(self) :
"yields the arguments of the Message as Python objects."
for iter in self.iter_init() :
yield iter.object
#end for
#end objects
@property
def all_objects(self) :
"all the arguments of the Message as a list of Python objects."
return \
list(self.objects)
#end all_objects
def expect_objects(self, signature) :
"expects the arguments of the Message to conform to the given signature," \
" raising a TypeError if not. If they match, returns them as a list."
signature = unparse_signature(signature)
if self.signature != signature :
raise TypeError("message args dont match: expected “%s”, got “%s" % (signature, self.signature))
#end if
return \
self.all_objects
#end expect_objects
def expect_return_objects(self, signature) :
"expects the Message to be of type DBUS.MESSAGE_TYPE_METHOD_RETURN and its" \
" arguments to conform to the given signature. Raises the appropriate DBusError" \
" if the Message is of type DBUS.MESSAGE_TYPE_ERROR."
if self.type == DBUS.MESSAGE_TYPE_METHOD_RETURN :
result = self.expect_objects(signature)
elif self.type == DBUS.MESSAGE_TYPE_ERROR :
raise DBusError(self.error_name, self.expect_objects("s")[0])
else :
raise ValueError("unexpected message type %d" % self.type)
#end if
return \
result
#end expect_return_objects
def iter_init_append(self) :
"creates a Message.AppendIter for appending arguments to the Message."
iter = self.AppendIter(None)
dbus.dbus_message_iter_init_append(self._dbobj, iter._dbobj)
return \
iter
#end iter_init_append
def append_objects(self, signature, *args) :
"interprets Python values args according to signature and appends" \
" converted item(s) to the message args."
def append_sub(siglist, eltlist, appenditer) :
if len(siglist) != len(eltlist) :
raise ValueError \
(
"mismatch between signature entries %s and number of sequence elements %s"
%
(repr(siglist), repr(eltlist))
)
#end if
for elttype, elt in zip(siglist, eltlist) :
if isinstance(elttype, BasicType) :
appenditer.append_basic(elttype.code.value, elt)
elif isinstance(elttype, DictType) :
if not isinstance(elt, dict) :
raise TypeError("dict expected for %s" % repr(elttype))
#end if
subiter = appenditer.open_container(DBUS.TYPE_ARRAY, elttype.entry_signature)
for key in sorted(elt) : # might as well insert in some kind of predictable order
value = elt[key]
subsubiter = subiter.open_container(DBUS.TYPE_DICT_ENTRY, None)
append_sub([elttype.keytype, elttype.valuetype], [key, value], subsubiter)
subsubiter.close()
#end for
subiter.close()
elif isinstance(elttype, ArrayType) :
# append 0 or more elements matching elttype.elttype
arrelttype = elttype.elttype
if type_is_fixed_array_elttype(arrelttype.code.value) :
subiter = appenditer.open_container(DBUS.TYPE_ARRAY, arrelttype.signature)
subiter.append_fixed_array(arrelttype.code.value, elt)
subiter.close()
else :
subiter = appenditer.open_container(DBUS.TYPE_ARRAY, arrelttype.signature)
if not isinstance(elt, (tuple, list)) :
raise TypeError("expecting sequence of values for array")
#end if
for subval in elt :
append_sub([arrelttype], [subval], subiter)
#end for
subiter.close()
#end if
elif isinstance(elttype, StructType) :
if not isinstance(elt, (tuple, list)) :
raise TypeError("expecting sequence of values for struct")
#end if
subiter = appenditer.open_container(DBUS.TYPE_STRUCT, None)
append_sub(elttype.elttypes, elt, subiter)
subiter.close()
elif isinstance(elttype, VariantType) :
if not isinstance(elt, (list, tuple)) or len(elt) != 2 :
raise TypeError("sequence of 2 elements expected for variant: %s" % repr(elt))
#end if
actual_type = parse_single_signature(elt[0])
subiter = appenditer.open_container(DBUS.TYPE_VARIANT, actual_type.signature)
append_sub([actual_type], [elt[1]], subiter)
subiter.close()
else :
raise RuntimeError("unrecognized type %s" % repr(elttype))
#end if
#end for
#end append_sub
#begin append_objects
append_sub(parse_signature(signature), args, self.iter_init_append())
return \
self
#end append_objects
@property
def no_reply(self) :
"whether the Message is not expecting a reply."
return \
dbus.dbus_message_get_no_reply(self._dbobj) != 0
#end no_reply
@no_reply.setter
def no_reply(self, no_reply) :
dbus.dbus_message_set_no_reply(self._dbobj, no_reply)
#end no_reply
@property
def auto_start(self) :
return \
dbus.dbus_message_get_auto_start(self._dbobj) != 0
#end auto_start
@auto_start.setter
def auto_start(self, auto_start) :
dbus.dbus_message_set_auto_start(self._dbobj, auto_start)
#end auto_start
@property
def path(self) :
"the object path for a DBUS.MESSAGE_TYPE_METHOD_CALL or DBUS.DBUS.MESSAGE_TYPE_SIGNAL" \
" message."
result = dbus.dbus_message_get_path(self._dbobj)
if result != None :
result = DBUS.ObjectPath(result.decode())
#end if
return \
result
#end path
@path.setter
def path(self, object_path) :
if not dbus.dbus_message_set_path(self._dbobj, (lambda : None, lambda : object_path.encode())[object_path != None]()) :
raise CallFailed("dbus_message_set_path")
#end if
#end path
@property
def path_decomposed(self) :
"the object path for a DBUS.MESSAGE_TYPE_METHOD_CALL or DBUS.DBUS.MESSAGE_TYPE_SIGNAL" \
" message, decomposed into a list of the slash-separated components without the slashes."
path = ct.POINTER(ct.c_char_p)()
if not dbus.dbus_message_get_path_decomposed(self._dbobj, ct.byref(path)) :
raise CallFailed("dbus_message_get_path_decomposed")
#end if
if bool(path) :
result = []
i = 0
while True :
entry = path[i]
if entry == None :
break
result.append(entry.decode())
i += 1
#end while
dbus.dbus_free_string_array(path)
else :
result = None
#end if
return \
result
#end path_decomposed
@property
def interface(self) :
"the interface name for a DBUS.MESSAGE_TYPE_METHOD_CALL or DBUS.MESSAGE_TYPE_SIGNAL" \
" message."
result = dbus.dbus_message_get_interface(self._dbobj)
if result != None :
result = result.decode()
#end if
return \
result
#end interface
@interface.setter
def interface(self, iface) :
if not dbus.dbus_message_set_interface(self._dbobj, (lambda : None, lambda : iface.encode())[iface != None]()) :
raise CallFailed("dbus_message_set_interface")
#end if
#end interface
def has_interface(self, iface) :
return \
dbus.dbus_message_has_interface(self._dbobj, iface.encode()) != 0
#end has_interface
@property
def member(self) :
"the method name for a DBUS.MESSAGE_TYPE_METHOD_CALL message or the signal" \
" name for DBUS.MESSAGE_TYPE_SIGNAL."
result = dbus.dbus_message_get_member(self._dbobj)
if result != None :
result = result.decode()
#end if
return \
result
#end member
@member.setter
def member(self, member) :
if not dbus.dbus_message_set_member(self._dbobj, (lambda : None, lambda : member.encode())[member != None]()) :
raise CallFailed("dbus_message_set_member")
#end if
#end member
def has_member(self, member) :
return \
dbus.dbus_message_has_member(self._dbobj, member.encode()) != 0
#end has_member
@property
def error_name(self) :
"the error name for a DBUS.MESSAGE_TYPE_ERROR message."
result = dbus.dbus_message_get_error_name(self._dbobj)
if result != None :
result = result.decode()
#end if
return \
result
#end error_name
@error_name.setter
def error_name(self, error_name) :
if not dbus.dbus_message_set_error_name(self._dbobj, (lambda : None, lambda : error_name.encode())[error_name != None]()) :
raise CallFailed("dbus_message_set_error_name")
#end if
#end error_name
@property
def destination(self) :
"the bus name that the message is to be sent to."
result = dbus.dbus_message_get_destination(self._dbobj)
if result != None :
result = result.decode()
#end if
return \
result
#end destination
@destination.setter
def destination(self, destination) :
if not dbus.dbus_message_set_destination(self._dbobj, (lambda : None, lambda : destination.encode())[destination != None]()) :
raise CallFailed("dbus_message_set_destination")
#end if
#end destination
@property
def sender(self) :
result = dbus.dbus_message_get_sender(self._dbobj)
if result != None :
result = result.decode()
#end if
return \
result
#end sender
@sender.setter
def sender(self, sender) :
if not dbus.dbus_message_set_sender(self._dbobj, (lambda : None, lambda : sender.encode())[sender != None]()) :
raise CallFailed("dbus_message_set_sender")
#end if
#end sender
@property
def signature(self) :
result = dbus.dbus_message_get_signature(self._dbobj)
if result != None :
result = DBUS.Signature(result.decode())
#end if
return \
result
#end signature
def is_method_call(self, iface, method) :
return \
dbus.dbus_message_is_method_call(self._dbobj, iface.encode(), method.encode()) != 0
#end is_method_call
def is_signal(self, iface, signal_name) :
return \
dbus.dbus_message_is_signal(self._dbobj, iface.encode(), signal_name.encode()) != 0
#end is_signal
def is_error(self, iface, error_name) :
return \
dbus.dbus_message_is_error(self._dbobj, error_name.encode()) != 0
#end is_error
def has_destination(self, iface, destination) :
return \
dbus.dbus_message_has_destination(self._dbobj, destination.encode()) != 0
#end has_destination
def has_sender(self, iface, sender) :
return \
dbus.dbus_message_has_sender(self._dbobj, sender.encode()) != 0
#end has_sender
def has_signature(self, iface, signature) :
return \
dbus.dbus_message_has_signature(self._dbobj, signature.encode()) != 0
#end has_signature
def set_error(self, error) :
"fills in error if this is an error message, else does nothing. Returns" \
" whether it was an error message or not."
if not isinstance(error, Error) :
raise TypeError("error must be an Error")
#end if
return \
dbus.dbus_set_error_from_message(error._dbobj, self._dbobj) != 0
#end set_error
@property
def contains_unix_fds(self) :
return \
dbus.dbus_message_contains_unix_fds(self._dbobj) != 0
#end contains_unix_fds
@property
def serial(self) :
"the serial number of the Message, to be referenced in replies."
return \
dbus.dbus_message_get_serial(self._dbobj)
#end serial
@serial.setter
def serial(self, serial) :
dbus.dbus_message_set_serial(self._dbobj, serial)
#end serial
@property
def reply_serial(self) :
"the serial number of the original Message that that this" \
" DBUS.MESSAGE_TYPE_METHOD_RETURN message is a reply to."
return \
dbus.dbus_message_get_reply_serial(self._dbobj)
#end reply_serial
@reply_serial.setter
def reply_serial(self, serial) :
if not dbus.dbus_message_set_reply_serial(self._dbobj, serial) :
raise CallFailed("dbus_message_set_reply_serial")
#end if
#end serial
def lock(self) :
dbus.dbus_message_lock(self._dbobj)
#end lock
def return_borrowed(self) :
assert self._borrowed and self._conn != None
dbus.dbus_connection_return_message(self._conn._dbobj, self._dbobj)
self._borrowed = False
#end return_borrowed
def steal_borrowed(self) :
assert self._borrowed and self._conn != None
dbus.dbus_connection_steal_borrowed_message(self._conn._dbobj, self._dbobj)
self._borrowed = False
return \
self
#end steal_borrowed
# TODO: allocate/free data slot -- static methods
# (freeing slot can set passed-in var to -1 on actual free; do I care?)
# TODO: set/get data
@staticmethod
def type_from_string(type_str) :
"returns a MESSAGE_TYPE_xxx value."
return \
dbus.dbus_message_type_from_string(type_str.encode())
#end type_from_string
@staticmethod
def type_to_string(type) :
"type is a MESSAGE_TYPE_xxx value."
return \
dbus.dbus_message_type_to_string(type).decode()
#end type_to_string
def marshal(self) :
"serializes this Message into the wire protocol format and returns a bytes object."
buf = ct.POINTER(ct.c_ubyte)()
nr_bytes = ct.c_int()
if not dbus.dbus_message_marshal(self._dbobj, ct.byref(buf), ct.byref(nr_bytes)) :
raise CallFailed("dbus_message_marshal")
#end if
result = bytearray(nr_bytes.value)
ct.memmove \
(
ct.addressof((ct.c_ubyte * nr_bytes.value).from_buffer(result)),
buf,
nr_bytes.value
)
dbus.dbus_free(buf)
return \
result
#end marshal
@classmethod
def demarshal(celf, buf, error = None) :
"deserializes a bytes or array-of-bytes object from the wire protocol" \
" format into a Message object."
error, my_error = _get_error(error)
if isinstance(buf, bytes) :
baseadr = ct.cast(buf, ct.c_void_p).value
elif isinstance(buf, bytearray) :
baseadr = ct.addressof((ct.c_ubyte * len(buf)).from_buffer(buf))
elif isinstance(buf, array.array) and buf.typecode == "B" :
baseadr = buf.buffer_info()[0]
else :
raise TypeError("buf is not bytes, bytearray or array.array of bytes")
#end if
msg = dbus.dbus_message_demarshal(baseadr, len(buf), error._dbobj)
my_error.raise_if_set()
if msg != None :
msg = celf(msg)
#end if
return \
msg
#end demarshal
@classmethod
def demarshal_bytes_needed(celf, buf) :
"the number of bytes needed to deserialize a bytes or array-of-bytes" \
" object from the wire protocol format."
if isinstance(buf, bytes) :
baseadr = ct.cast(buf, ct.c_void_p).value
elif isinstance(buf, bytearray) :
baseadr = ct.addressof((ct.c_ubyte * len(buf)).from_buffer(buf))
elif isinstance(buf, array.array) and buf.typecode == "B" :
baseadr = buf.buffer_info()[0]
else :
raise TypeError("buf is not bytes, bytearray or array.array of bytes")
#end if
return \
dbus.dbus_message_demarshal_bytes_needed(baseadr, len(buf))
#end demarshal_bytes_needed
@property
def interactive_authorization(self) :
return \
dbus.dbus_message_get_interactive_authorization(self._dbobj)
#end interactive_authorization
@interactive_authorization.setter
def interactive_authorization(self, allow) :
dbus.dbus_message_set_interactive_authorization(self._dbobj, allow)
#end interactive_authorization
#end Message
class PendingCall :
"wrapper around a DBusPendingCall object. This represents a pending reply" \
" message that hasnt been received yet. Do not instantiate directly; libdbus" \
" creates these as the result from calling send_with_reply() on a Message."
# <https://dbus.freedesktop.org/doc/api/html/group__DBusPendingCall.html>
__slots__ = \
(
"__weakref__",
"_dbobj",
"_w_conn",
"_wrap_notify",
"_wrap_free",
"_awaiting",
) # to forestall typos
_instances = WeakValueDictionary()
def __new__(celf, _dbobj, _conn) :
self = celf._instances.get(_dbobj)
if self == None :
self = super().__new__(celf)
self._dbobj = _dbobj
self._w_conn = weak_ref(_conn)
self._wrap_notify = None
self._wrap_free = None
self._awaiting = None
celf._instances[_dbobj] = self
else :
dbus.dbus_pending_call_unref(self._dbobj)
# lose extra reference created by caller
#end if
return \
self
#end __new__
def __del__(self) :
if self._dbobj != None :
dbus.dbus_pending_call_unref(self._dbobj)
self._dbobj = None
#end if
#end __del__
def set_notify(self, function, user_data, free_user_data = None) :
"sets the callback for libdbus to notify you that the pending message" \
" has become available. Note: it appears to be possible for your notifier" \
" to be called spuriously before the message is actually available."
w_self = weak_ref(self)
def wrap_notify(c_pending, c_user_data) :
function(_wderef(w_self, "pending call"), user_data)
#end _wrap_notify
def wrap_free(c_user_data) :
free_user_data(user_data)
#end _wrap_free
#begin set_notify
if function != None :
self._wrap_notify = DBUS.PendingCallNotifyFunction(wrap_notify)
else :
self._wrap_notify = None
#end if
if free_user_data != None :
self._wrap_free = DBUS.FreeFunction(wrap_free)
else :
self._wrap_free = None
#end if
if not dbus.dbus_pending_call_set_notify(self._dbobj, self._wrap_notify, None, self._wrap_free) :
raise CallFailed("dbus_pending_call_set_notify")
#end if
#end set_notify
def cancel(self) :
"tells libdbus you no longer care about the pending incoming message."
dbus.dbus_pending_call_cancel(self._dbobj)
if self._awaiting != None :
# This probably shouldnt occur. Looking at the source of libdbus,
# it doesnt keep track of any “cancelled” state for the PendingCall,
# it just detaches it from any notifications about an incoming reply.
self._awaiting.cancel()
#end if
#end cancel
@property
def completed(self) :
"checks whether the pending message is available."
return \
dbus.dbus_pending_call_get_completed(self._dbobj) != 0
#end completed
def steal_reply(self) :
"retrieves the Message, assuming it is actually available." \
" You should check PendingCall.completed returns True first."
result = dbus.dbus_pending_call_steal_reply(self._dbobj)
if result != None :
result = Message(result)
#end if
return \
result
#end steal_reply
async def await_reply(self) :
"retrieves the Message. If it is not yet available, suspends the" \
" coroutine (letting the event loop do other things) until it becomes" \
" available. On a timeout, libdbus will construct and return an error" \
" return message."
conn = self._w_conn()
assert conn != None, "parent Connection has gone away"
assert conn.loop != None, "no event loop on parent Connection to attach coroutine to"
if self._wrap_notify != None or self._awaiting != None :
raise asyncio.InvalidStateError("there is already a notify set on this PendingCall")
#end if
done = conn.loop.create_future()
self._awaiting = done
def pending_done(pending, wself) :
if not done.done() : # just in case of self.cancel() being called
self = wself()
# Note it seems to be possible for callback to be triggered spuriously
if self != None and self.completed :
done.set_result(self.steal_reply())
#end if
#end if
#end pending_done
self.set_notify(pending_done, weak_ref(self))
# avoid reference circularity self → pending_done → self
reply = await done
return \
reply
#end await_reply
def block(self) :
"blocks the current thread until the pending message has become available."
dbus.dbus_pending_call_block(self._dbobj)
#end block
# TODO: data slots (static methods), get/set data
#end PendingCall
class Error :
"wrapper around a DBusError object. You can create one by calling the init method."
# <https://dbus.freedesktop.org/doc/api/html/group__DBusErrors.html>
__slots__ = ("_dbobj",) # to forestall typos
def __init__(self) :
dbobj = DBUS.Error()
dbus.dbus_error_init(dbobj)
self._dbobj = dbobj
#end __init__
def __del__(self) :
if self._dbobj != None :
dbus.dbus_error_free(self._dbobj)
self._dbobj = None
#end if
#end __del__
@classmethod
def init(celf) :
"for consistency with other classes that dont want caller to instantiate directly."
return \
celf()
#end init
def set(self, name, msg) :
"fills in the error name and message."
dbus.dbus_set_error(self._dbobj, name.encode(), b"%s", msg.encode())
#end set
@property
def is_set(self) :
"has the Error been filled in."
return \
dbus.dbus_error_is_set(self._dbobj) != 0
#end is_set
def has_name(self, name) :
"has the Error got the specified name."
return \
dbus.dbus_error_has_name(self._dbobj, name.encode()) != 0
#end has_name
@property
def name(self) :
"the name of the Error, if it has been filled in."
return \
(lambda : None, lambda : self._dbobj.name.decode())[self._dbobj.name != None]()
#end name
@property
def message(self) :
"the message string for the Error, if it has been filled in."
return \
(lambda : None, lambda : self._dbobj.message.decode())[self._dbobj.message != None]()
#end message
def raise_if_set(self) :
"raises a DBusError exception if this Error has been filled in."
if self.is_set :
raise DBusError(self.name, self.message)
#end if
#end raise_if_set
def set_from_message(self, message) :
"fills in this Error object from message if it is an error message." \
" Returns whether it was or not."
if not isinstance(message, Message) :
raise TypeError("message must be a Message")
#end if
return \
dbus.dbus_set_error_from_message(self._dbobj, message._dbobj) != 0
#end set_from_message
#end Error
class AddressEntries :
"wrapper for arrays of DBusAddressEntry values. Do not instantiate directly;" \
" get from AddressEntries.parse. This object behaves like an array; you can obtain" \
" the number of elements with len(), and use array subscripting to access the elements."
# <https://dbus.freedesktop.org/doc/api/html/group__DBusAddress.html>
__slots__ = ("__weakref__", "_dbobj", "_nrelts") # to forestall typos
def __init__(self, _dbobj, _nrelts) :
self._dbobj = _dbobj
self._nrelts = _nrelts
#end __init__
def __del__(self) :
if self._dbobj != None :
dbus.dbus_address_entries_free(self._dbobj)
self._dbobj = None
#end if
#end __del__
class Entry :
"a single AddressEntry. Do not instantiate directly; get from AddressEntries[]." \
" This object behaves like a dictionary in that you can use keys to get values;" \
" however, there is no libdbus API to check what keys are present; unrecognized" \
" keys return a value of None."
__slots__ = ("_dbobj", "_parent", "_index") # to forestall typos
def __init__(self, _parent, _index) :
self._dbobj = _parent._dbobj
self._parent = weak_ref(_parent)
self._index = _index
#end __init__
@property
def method(self) :
assert self._parent() != None, "AddressEntries object has gone"
result = dbus.dbus_address_entry_get_method(self._dbobj[self._index])
if result != None :
result = result.decode()
#end if
return \
result
#end method
def get_value(self, key) :
assert self._parent() != None, "AddressEntries object has gone"
c_result = dbus.dbus_address_entry_get_value(self._dbobj[self._index], key.encode())
if c_result != None :
result = c_result.decode()
else :
result = None
#end if
return \
result
#end get_value
__getitem__ = get_value
#end Entry
@classmethod
def parse(celf, address, error = None) :
error, my_error = _get_error(error)
c_result = ct.POINTER(ct.c_void_p)()
nr_elts = ct.c_int()
if not dbus.dbus_parse_address(address.encode(), ct.byref(c_result), ct.byref(nr_elts), error._dbobj) :
c_result.contents = None
nr_elts.value = 0
#end if
my_error.raise_if_set()
if c_result.contents != None :
result = celf(c_result, nr_elts.value)
else :
result = None
#end if
return \
result
#end parse
def __len__(self) :
return \
self._nrelts
#end __len__
def __getitem__(self, index) :
if not isinstance(index, int) or index < 0 or index >= self._nrelts :
raise IndexError("AddressEntries[%d] out of range" % index)
#end if
return \
type(self).Entry(self, index)
#end __getitem__
#end AddressEntries
def address_escape_value(value) :
c_result = dbus.dbus_address_escape_value(value.encode())
if c_result == None :
raise CallFailed("dbus_address_escape_value")
#end if
result = ct.cast(c_result, ct.c_char_p).value.decode()
dbus.dbus_free(c_result)
return \
result
#end address_escape_value
def address_unescape_value(value, error = None) :
error, my_error = _get_error(error)
c_result = dbus.dbus_address_unescape_value(value.encode(), error._dbobj)
my_error.raise_if_set()
if c_result != None :
result = ct.cast(c_result, ct.c_char_p).value.decode()
dbus.dbus_free(c_result)
elif not error.is_set :
raise CallFailed("dbus_address_unescape_value")
else :
result = None
#end if
return \
result
#end address_unescape_value
def format_rule(rule) :
"convenience routine to allow a match rule to be expressed as either" \
" a dict of {key : value} or the usual string \"key='value'\", automatically" \
" converting the former to the latter."
def escape_val(val) :
if "," in val :
if "'" in val :
out = "'"
in_quotes = True
for ch in val :
if ch == "'" :
if in_quotes :
out += "'"
in_quotes = False
#end if
out += "\\'"
else :
if not in_quotes :
out += "'"
in_quotes = True
#end if
out += ch
#end if
#end for
if in_quotes :
out += "'"
#end if
else :
out = "'" + val + "'"
#end if
else :
out = ""
for ch in val :
if ch in ("\\", "'") :
out += "\\"
#end if
out += ch
#end for
#end if
return \
out
#end escape_val
#begin format_rule
if isinstance(rule, str) :
pass
elif isinstance(rule, dict) :
rule = ",".join("%s=%s" % (k, escape_val(rule[k])) for k in sorted(rule))
# sort to ensure some kind of consistent ordering, just for
# appearances sake
else :
raise TypeError("rule “%s” must be a dict or string" % repr(rule))
#end if
return \
rule
#end format_rule
class _RuleParser :
# internal definitions for rule parsing.
class PARSE(enum.Enum) :
EXPECT_NAME = 1
EXPECT_UNQUOTED_VALUE = 2
EXPECT_ESCAPED = 3
EXPECT_QUOTED_VALUE = 4
#end PARSE
@classmethod
def unformat_rule(celf, rule) :
"converts a match rule string from the standard syntax to a dict of {key : value} entries."
if isinstance(rule, dict) :
pass
elif isinstance(rule, str) :
PARSE = celf.PARSE
parsed = {}
chars = iter(rule)
state = PARSE.EXPECT_NAME
curname = None
curval = None
while True :
ch = next(chars, None)
if ch == None :
if state == PARSE.EXPECT_ESCAPED :
raise SyntaxError("missing character after backslash")
elif state == PARSE.EXPECT_QUOTED_VALUE :
raise SyntaxError("missing closing apostrophe")
else : # state in (PARSE.EXPECT_NAME, PARSE.EXPECT_UNQUOTED_VALUE)
if curname != None :
if curval != None :
if curname in parsed :
raise SyntaxError("duplicated attribute “%s" % curname)
#end if
parsed[curname] = curval
else :
raise SyntaxError("missing value for attribute “%s" % curname)
#end if
#end if
#end if
break
#end if
if state == PARSE.EXPECT_ESCAPED :
if ch == "'" :
usech = ch
nextch = None
else :
usech = "\\"
nextch = ch
#end if
ch = usech
if curval == None :
curval = ch
else :
curval += ch
#end if
ch = nextch # None indicates already processed
state = PARSE.EXPECT_UNQUOTED_VALUE
#end if
if ch != None :
if ch == "," and state != PARSE.EXPECT_QUOTED_VALUE :
if state == PARSE.EXPECT_UNQUOTED_VALUE :
if curname in parsed :
raise SyntaxError("duplicated attribute “%s" % curname)
#end if
if curval == None :
curval = ""
#end if
parsed[curname] = curval
curname = None
curval = None
state = PARSE.EXPECT_NAME
else :
raise SyntaxError("unexpected comma")
#end if
elif ch == "\\" and state != PARSE.EXPECT_QUOTED_VALUE :
if state == PARSE.EXPECT_UNQUOTED_VALUE :
state = PARSE.EXPECT_ESCAPED
else :
raise SyntaxError("unexpected backslash")
#end if
elif ch == "=" and state != PARSE.EXPECT_QUOTED_VALUE :
if curname == None :
raise SyntaxError("empty attribute name")
#end if
if state == PARSE.EXPECT_NAME :
state = PARSE.EXPECT_UNQUOTED_VALUE
else :
raise SyntaxError("unexpected equals sign")
#end if
elif ch == "'" :
if state == PARSE.EXPECT_UNQUOTED_VALUE :
state = PARSE.EXPECT_QUOTED_VALUE
elif state == PARSE.EXPECT_QUOTED_VALUE :
state = PARSE.EXPECT_UNQUOTED_VALUE
else :
raise SyntaxError("unexpected apostrophe")
#end if
else :
if state == PARSE.EXPECT_NAME :
if curname == None :
curname = ch
else :
curname += ch
#end if
elif state in (PARSE.EXPECT_QUOTED_VALUE, PARSE.EXPECT_UNQUOTED_VALUE) :
if curval == None :
curval = ch
else :
curval += ch
#end if
else :
raise AssertionError("shouldnt occur: parse state %s" % repr(state))
#end if
#end if
#end if
#end while
rule = parsed
else :
raise TypeError("rule “%s” must be a dict or string" % repr(rule))
#end if
return \
rule
#end unformat_rule
#end _RuleParser
unformat_rule = _RuleParser.unformat_rule
del _RuleParser
def matches_rule(message, rule, destinations = None) :
"does Message message match against the specified rule."
if not isinstance(message, Message) :
raise TypeError("message must be a Message")
#end if
rule = unformat_rule(rule)
eavesdrop = rule.get("eavesdrop", "false") == "true"
def match_message_type(expect, actual) :
return \
actual == Message.type_from_string(expect)
#end match_message_type
def match_path_namespace(expect, actual) :
return \
(
actual != None
and
(
expect == actual
or
actual.startswith(expect) and (expect == "/" or actual[len(expect)] == "/")
)
)
#end match_path_namespace
def match_dotted_namespace(expect, actual) :
return \
(
actual != None
and
(
expect == actual
or
actual.startswith(expect) and actual[len(expect)] == "."
)
)
#end match_dotted_namespace
def get_nth_arg(msg, n, expect_types) :
msg_signature = parse_signature(msg.signature)
if n >= len(msg_signature) :
raise IndexError("arg nr %d beyond nr args %d" % (n, len(msg_signature)))
#end if
val = msg.all_objects[n]
valtype = msg_signature[n]
if valtype not in expect_types :
if False :
raise TypeError \
(
"expecting one of types %s, not %s for arg %d val %s"
%
((repr(expect_types), repr(valtype), n, repr(val)))
)
#end if
val = None # never match
#end if
return \
val
#end get_nth_arg
def get_arg_0_str(message) :
return \
get_nth_arg(message, 0, [BasicType(TYPE.STRING)])
#end get_arg_0_str
def match_arg_paths(expect, actual) :
return \
(
actual != None
and
(
expect == actual
or
expect.endswith("/") and actual.startswith(expect)
or
actual.endswith("/") and expect.startswith(actual)
)
)
#end match_arg_paths
match_types = \
( # note that message attribute value of None will fail to match
# any expected string value, which is exactly what we want
("type", None, match_message_type, None),
("sender", None, operator.eq, None),
("interface", None, operator.eq, None),
("member", None, operator.eq, None),
("path", None, operator.eq, None),
("destination", None, operator.eq, None),
("path_namespace", "path", match_path_namespace, None),
("arg0namespace", None, match_dotted_namespace, get_arg_0_str),
# “arg«n»path” handled specially below
)
#begin matches_rule
keys_used = set(rule.keys()) - {"eavesdrop"}
matches = \
(
eavesdrop
or
destinations == None
or
message.destination == None
or
message.destination in destinations
)
if matches :
try_matching = iter(match_types)
while True :
try_rule = next(try_matching, None)
if try_rule == None :
break
rulekey, attrname, action, accessor = try_rule
if attrname == None :
attrname = rulekey
#end if
if rulekey in rule :
if accessor != None :
val = accessor(message)
else :
val = getattr(message, attrname)
#end if
keys_used.remove(rulekey)
if not action(rule[rulekey], val) :
matches = False
break
#end if
#end if
#end while
#end if
if matches :
try_matching = iter(rule.keys())
while True :
try_key = next(try_matching, None)
if try_key == None :
break
if try_key.startswith("arg") and not try_key.endswith("namespace") :
argnr = try_key[3:]
is_path = argnr.endswith("path")
if is_path :
argnr = argnr[:-4]
#end if
argnr = int(argnr)
if not (0 <= argnr < 64) :
raise ValueError("argnr %d out of range" % argnr)
#end if
argval = get_nth_arg \
(
message,
argnr,
[BasicType(TYPE.STRING)] + ([], [BasicType(TYPE.OBJECT_PATH)])[is_path]
)
keys_used.remove(try_key)
if not (operator.eq, match_arg_paths)[is_path](rule[try_key], argval) :
matches = False
break
#end if
#end if
#end while
#end if
if matches and len(keys_used) != 0 :
# fixme: not checking for unrecognized rule keys if I didnt try matching them all
raise KeyError("unrecognized rule keywords: %s" % ", ".join(sorted(keys_used)))
#end if
return \
matches
#end matches_rule
class SignatureIter :
"wraps a DBusSignatureIter object. Do not instantiate directly; use the init" \
" and recurse methods."
# <https://dbus.freedesktop.org/doc/api/html/group__DBusSignature.html>
__slots__ = ("_dbobj", "_signature", "_startiter") # to forestall typos
@classmethod
def init(celf, signature) :
self = celf()
self._signature = ct.c_char_p(signature.encode()) # need to ensure storage stays valid
dbus.dbus_signature_iter_init(self._dbobj, self._signature)
return \
self
#end init
def __init__(self) :
self._dbobj = DBUS.SignatureIter()
self._signature = None # caller will set as necessary
self._startiter = True
#end __init__
def __iter__(self) :
return \
self
#end __iter__
def __next__(self) :
if self._startiter :
self._startiter = False
else :
self.next()
#end if
return \
self
#end __next__
def next(self) :
if dbus.dbus_signature_iter_next(self._dbobj) == 0 :
raise StopIteration("end of signature iterator")
#end if
self._startiter = False
return \
self
#end next
def recurse(self) :
subiter = type(self)()
dbus.dbus_signature_iter_recurse(self._dbobj, subiter._dbobj)
return \
subiter
#end recurse
@property
def current_type(self) :
return \
dbus.dbus_signature_iter_get_current_type(self._dbobj)
#end current_type
@property
def signature(self) :
c_result = dbus.dbus_signature_iter_get_signature(self._dbobj)
result = ct.cast(c_result, ct.c_char_p).value.decode()
dbus.dbus_free(c_result)
return \
result
#end signature
@property
def parsed_signature(self) :
return \
parse_single_signature(self.signature)
#end parsed_signature
@property
def element_type(self) :
return \
dbus.dbus_signature_iter_get_element_type(self._dbobj)
#end element_type
#end SignatureIter
def signature_validate(signature, error = None) :
"is signature a valid sequence of zero or more complete types."
error, my_error = _get_error(error)
result = dbus.dbus_signature_validate(signature.encode(), error._dbobj) != 0
my_error.raise_if_set()
return \
result
#end signature_validate
def parse_signature(signature) :
"convenience routine for parsing a signature string into a list of Type()" \
" instances."
def process_subsig(sigelt) :
elttype = sigelt.current_type
if elttype in DBUS.basic_to_ctypes :
result = BasicType(TYPE(elttype))
elif elttype == DBUS.TYPE_ARRAY :
if sigelt.element_type == DBUS.TYPE_DICT_ENTRY :
subsig = sigelt.recurse()
subsubsig = subsig.recurse()
keytype = process_subsig(next(subsubsig))
valuetype = process_subsig(next(subsubsig))
result = DictType(keytype, valuetype)
else :
subsig = sigelt.recurse()
result = ArrayType(process_subsig(next(subsig)))
#end if
elif elttype == DBUS.TYPE_STRUCT :
result = []
subsig = sigelt.recurse()
for subelt in subsig :
result.append(process_subsig(subelt))
#end for
result = StructType(*result)
elif elttype == DBUS.TYPE_VARIANT :
result = VariantType()
else :
raise RuntimeError("unrecognized type %s" % bytes((elttype,)))
#end if
return \
result
#end process_subsig
#begin parse_signature
if isinstance(signature, (tuple, list)) :
if not all(isinstance(t, Type) for t in signature) :
raise TypeError("signature is list containing non-Type objects")
#end if
result = signature
elif isinstance(signature, Type) :
result = [signature]
elif isinstance(signature, str) :
signature_validate(signature)
result = []
if len(signature) != 0 :
sigiter = SignatureIter.init(signature)
for elt in sigiter :
result.append(process_subsig(elt))
#end for
#end if
else :
raise TypeError("signature must be list or str")
#end if
return \
result
#end parse_signature
def parse_single_signature(signature) :
result = parse_signature(signature)
if len(result) != 1 :
raise ValueError("only single type expected")
#end if
return \
result[0]
#end parse_single_signature
def unparse_signature(signature) :
"converts a signature from parsed form to string form."
signature = parse_signature(signature)
if not isinstance(signature, (tuple, list)) :
signature = [signature]
#end if
return \
DBUS.Signature("".join(t.signature for t in signature))
#end unparse_signature
def signature_validate_single(signature, error = None) :
"is signature a single valid type."
error, my_error = _get_error(error)
result = dbus.dbus_signature_validate_single(signature.encode(), error._dbobj) != 0
my_error.raise_if_set()
return \
result
#end signature_validate_single
def type_is_valid(typecode) :
return \
dbus.dbus_type_is_valid(typecode) != 0
#end type_is_valid
def type_is_basic(typecode) :
return \
dbus.dbus_type_is_basic(typecode) != 0
#end type_is_basic
def type_is_container(typecode) :
return \
dbus.dbus_type_is_container(typecode) != 0
#end type_is_container
def type_is_fixed(typecode) :
return \
dbus.dbus_type_is_fixed(typecode) != 0
#end type_is_fixed
def type_is_fixed_array_elttype(typecode) :
"is typecode suitable as the element type of a fixed_array."
return \
type_is_fixed(typecode) and typecode != DBUS.TYPE_UNIX_FD
#end type_is_fixed_array_elttype
# syntax validation <https://dbus.freedesktop.org/doc/api/html/group__DBusSyntax.html>
def validate_path(path, error = None) :
error, my_error = _get_error(error)
result = dbus.dbus_validate_path(path.encode(), error._dbobj) != 0
my_error.raise_if_set()
return \
result
#end validate_path
def valid_path(path) :
"returns path if valid, raising appropriate exception if not."
validate_path(path)
return \
path
#end valid_path
def split_path(path) :
"convenience routine for splitting a path into a list of components."
if isinstance(path, (tuple, list)) :
result = path # assume already split
elif path == "/" :
result = []
else :
if not path.startswith("/") or path.endswith("/") :
raise DBusError(DBUS.ERROR_INVALID_ARGS, "invalid path %s" % repr(path))
#end if
result = path.split("/")[1:]
#end if
return \
result
#end split_path
def unsplit_path(path) :
path = split_path(path)
if len(path) != 0 :
result = DBUS.ObjectPath("".join("/" + component for component in path))
else :
result = "/"
#end if
return \
result
#end unsplit_path
def validate_interface(name, error = None) :
error, my_error = _get_error(error)
result = dbus.dbus_validate_interface(name.encode(), error._dbobj) != 0
my_error.raise_if_set()
return \
result
#end validate_interface
def valid_interface(name) :
"returns name if it is a valid interface name, raising appropriate exception if not."
validate_interface(name)
return \
name
#end valid_interface
def validate_member(name, error = None) :
error, my_error = _get_error(error)
result = dbus.dbus_validate_member(name.encode(), error._dbobj) != 0
my_error.raise_if_set()
return \
result
#end validate_member
def valid_member(name) :
"returns name if it is a valid member name, raising appropriate exception if not."
validate_member(name)
return \
name
#end valid_member
def validate_error_name(name, error = None) :
error, my_error = _get_error(error)
result = dbus.dbus_validate_error_name(name.encode(), error._dbobj) != 0
my_error.raise_if_set()
return \
result
#end validate_error_name
def valid_error_name(name) :
"returns name if it is a valid error name, raising appropriate exception if not."
validate_error_name(name)
return \
name
#end valid_error_name
def validate_bus_name(name, error = None) :
error, my_error = _get_error(error)
result = dbus.dbus_validate_bus_name(name.encode(), error._dbobj) != 0
my_error.raise_if_set()
return \
result
#end validate_bus_name
def valid_bus_name(name) :
"returns name if it is a valid bus name, raising appropriate exception if not."
validate_bus_name(name)
return \
name
#end valid_bus_name
def validate_utf8(alleged_utf8, error = None) :
"alleged_utf8 must be null-terminated bytes."
error, my_error = _get_error(error)
result = dbus.dbus_validate_utf8(alleged_utf8, error._dbobj) != 0
my_error.raise_if_set()
return \
result
#end validate_utf8
def valid_utf8(alleged_utf8) :
"returns alleged_utf8 if it is a valid utf-8 bytes value, raising" \
" appropriate exception if not."
validate_utf8(alleged_utf8)
return \
alleged_utf8
#end valid_utf8
#+
# Introspection representation
#-
class _TagCommon :
def get_annotation(self, name) :
"returns the value of the annotation with the specified name, or None" \
" if none could be found"
annots = iter(self.annotations)
while True :
annot = next(annots, None)
if annot == None :
result = None
break
#end if
if annot.name == name :
result = annot.value
break
#end if
#end while
return \
result
#end get_annotation
@property
def is_deprecated(self) :
"is this interface/method/signal etc deprecated."
return \
self.get_annotation("org.freedesktop.DBus.Deprecated") == "true"
#end is_deprecated
def __repr__(self) :
celf = type(self)
return \
(
"%s(%s)"
%
(
celf.__name__,
", ".join
(
"%s = %s"
%
(name, repr(getattr(self, name)))
for name in celf.__slots__
),
)
)
#end __repr__
#end _TagCommon
class Introspection(_TagCommon) :
"high-level wrapper for the DBUS.INTERFACE_INTROSPECTABLE interface."
__slots__ = ("name", "interfaces", "nodes", "annotations")
tag_name = "node"
tag_attrs = ("name",)
tag_attrs_optional = {"name"}
class DIRECTION(enum.Enum) :
"argument direction."
IN = "in" # client to server
OUT = "out" # server to client
#end DIRECTION
class ACCESS(enum.Enum) :
"property access."
READ = "read"
WRITE = "write"
READWRITE = "readwrite"
#end ACCESS
class PROP_CHANGE_NOTIFICATION(enum.Enum) :
"how/if a changed property emits a notification signal."
NEW_VALUE = "true" # notification includes new value
INVALIDATES = "invalidates" # notification does not include new value
CONST = "const" # property shouldnt change
NONE = "false" # does not notify changes
#end PROP_CHANGE_NOTIFICATION
class Annotation(_TagCommon) :
__slots__ = ("name", "value")
tag_name = "annotation"
tag_attrs = ("name", "value")
tag_elts = {}
def __init__(self, name, value) :
self.name = name
self.value = value
#end __init__
#end Annotation
def _get_annotations(annotations) :
# common validation of annotations arguments.
if not all(isinstance(a, Introspection.Annotation) for a in annotations) :
raise TypeError("annotations must be Annotation instances")
#end if
return \
annotations
#end _get_annotations
class Interface(_TagCommon) :
__slots__ = ("name", "methods", "signals", "properties", "annotations")
tag_name = "interface"
tag_attrs = ("name",)
class Method(_TagCommon) :
__slots__ = ("name", "args", "annotations")
tag_name = "method"
tag_attrs = ("name",)
class Arg(_TagCommon) :
__slots__ = ("name", "type", "direction", "annotations")
tag_name = "arg"
tag_attrs = ("name", "type", "direction")
tag_attrs_optional = {"name"}
tag_elts = {}
attr_convert = {} # {"direction" : Introspection.DIRECTION} assigned below
def __init__(self, *, name = None, type, direction, annotations = ()) :
if not isinstance(direction, Introspection.DIRECTION) :
raise TypeError("direction must be an Introspection.DIRECTION.xxx enum")
#end if
self.name = name
self.type = parse_single_signature(type)
self.direction = direction
self.annotations = Introspection._get_annotations(annotations)
#end __init__
#end Arg
tag_elts = {"args" : Arg}
def __init__(self, name, args = (), annotations = ()) :
if not all(isinstance(a, self.Arg) for a in args) :
raise TypeError("args must be Arg instances")
#end if
self.name = name
self.args = list(args)
self.annotations = Introspection._get_annotations(annotations)
#end __init__
@property
def in_signature(self) :
return \
list(a.type for a in self.args if a.direction == Introspection.DIRECTION.IN)
#end in_signature
@property
def out_signature(self) :
return \
list \
(a.type for a in self.args if a.direction == Introspection.DIRECTION.OUT)
#end out_signature
@property
def expect_reply(self) :
"will there be replies to this request method."
return \
self.get_annotation("org.freedesktop.DBus.Method.NoReply") != "true"
#end expect_reply
#end Method
class Signal(_TagCommon) :
__slots__ = ("name", "args", "annotations")
tag_name = "signal"
tag_attrs = ("name",)
class Arg(_TagCommon) :
__slots__ = ("name", "type", "direction", "annotations")
tag_name = "arg"
tag_attrs = ("name", "type", "direction")
tag_attrs_optional = {"name", "direction"}
tag_elts = {}
attr_convert = {} # {"direction" : Introspection.DIRECTION} assigned below
def __init__(self, *, name = None, type, direction = None, annotations = ()) :
if direction != None and direction != Introspection.DIRECTION.OUT :
raise ValueError("direction can only be Introspection.DIRECTION.OUT")
#end if
self.name = name
self.type = parse_single_signature(type)
self.direction = direction
self.annotations = Introspection._get_annotations(annotations)
#end __init__
#end Arg
tag_elts = {"args" : Arg}
def __init__(self, name, args = (), annotations = ()) :
if not all(isinstance(a, self.Arg) for a in args) :
raise TypeError("args must be Arg instances")
#end if
self.name = name
self.args = list(args)
self.annotations = Introspection._get_annotations(annotations)
#end __init__
@property
def in_signature(self) :
return \
list(a.type for a in self.args)
#end in_signature
#end Signal
class Property(_TagCommon) :
__slots__ = ("name", "type", "access", "annotations")
tag_name = "property"
tag_attrs = ("name", "type", "access")
tag_elts = {}
attr_convert = {} # {"access" : Introspection.ACCESS} assigned below
def __init__(self, name, type, access, annotations = ()) :
if not isinstance(access, Introspection.ACCESS) :
raise TypeError("access must be an Introspection.ACCESS.xxx enum")
#end if
self.name = name
self.type = parse_single_signature(type)
self.access = access
self.annotations = Introspection._get_annotations(annotations)
#end __init__
#end Property
tag_elts = {"methods" : Method, "signals" : Signal, "properties" : Property}
def __init__(self, name, methods = (), signals = (), properties = (), annotations = ()) :
if not all(isinstance(m, self.Method) for m in methods) :
raise TypeError("methods must be Method instances")
#end if
if not all(isinstance(s, self.Signal) for s in signals) :
raise TypeError("signals must be Signal instances")
#end if
if not all(isinstance(p, self.Property) for p in properties) :
raise TypeError("properties must be Property instances")
#end if
self.name = name
self.methods = list(methods)
self.signals = list(signals)
self.properties = list(properties)
self.annotations = Introspection._get_annotations(annotations)
#end __init__
@property
def methods_by_name(self) :
"returns a dict associating all the methods with their names."
return \
dict((method.name, method) for method in self.methods)
#end methods_by_name
@property
def signals_by_name(self) :
"returns a dict associating all the signals with their names."
return \
dict((signal.name, signal) for signal in self.signals)
#end signals_by_name
@property
def properties_by_name(self) :
"returns a dict associating all the properties with their names."
return \
dict((prop.name, prop) for prop in self.properties)
#end properties_by_name
#end Interface
Interface.Method.Arg.attr_convert["direction"] = DIRECTION
Interface.Signal.Arg.attr_convert["direction"] = lambda x : (lambda : None, lambda : Introspection.DIRECTION(x))[x != None]()
Interface.Property.attr_convert["access"] = ACCESS
class StubInterface(_TagCommon) :
"use this as a replacement for an Interface that you dont want" \
" to see expanded, e.g. if it has already been seen."
__slots__ = ("name", "annotations")
tag_name = "interface"
tag_attrs = ("name",)
tag_elts = {}
def __init__(self, name) :
self.name = name
self.annotations = ()
#end __init__
#end StubInterface
class Node(_TagCommon) :
__slots__ = ("name", "interfaces", "nodes", "annotations")
tag_name = "node"
tag_attrs = ("name",)
def __init__(self, name, interfaces = (), nodes = (), annotations = ()) :
if not all(isinstance(i, (Introspection.Interface, Introspection.StubInterface)) for i in interfaces) :
raise TypeError("interfaces must be Interface or StubInterface instances")
#end if
if not all(isinstance(n, Introspection.Node) for n in nodes) :
raise TypeError("nodes must be Node instances")
#end if
self.name = name
self.interfaces = interfaces
self.nodes = nodes
self.annotations = Introspection._get_annotations(annotations)
#end __init__
@property
def interfaces_by_name(self) :
"returns a dict associating all the interfaces with their names."
return \
dict((iface.name, iface) for iface in self.interfaces)
#end interfaces_by_name
@property
def nodes_by_name(self) :
"returns a dict associating all the child nodes with their names."
return \
dict((node.name, node) for node in self.nodes)
#end nodes_by_name
#end Node
Node.tag_elts = {"interfaces" : Interface, "nodes" : Node}
tag_elts = {"interfaces" : Interface, "nodes" : Node}
def __init__(self, name = None, interfaces = (), nodes = (), annotations = ()) :
if not all(isinstance(i, self.Interface) for i in interfaces) :
raise TypeError("interfaces must be Interface instances")
#end if
if not all(isinstance(n, self.Node) for n in nodes) :
raise TypeError("nodes must be Node instances")
#end if
self.name = name
self.interfaces = list(interfaces)
self.nodes = list(nodes)
self.annotations = Introspection._get_annotations(annotations)
#end __init__
@property
def interfaces_by_name(self) :
"returns a dict associating all the interfaces with their names."
return \
dict((iface.name, iface) for iface in self.interfaces)
#end interfaces_by_name
@property
def nodes_by_name(self) :
"returns a dict associating all the nodes with their names."
return \
dict((node.name, node) for node in self.nodes)
#end nodes_by_name
@classmethod
def parse(celf, s) :
"generates an Introspection tree from the given XML string description."
def from_string_elts(celf, attrs, tree) :
elts = dict((k, attrs[k]) for k in attrs)
child_tags = dict \
(
(childclass.tag_name, childclass)
for childclass in tuple(celf.tag_elts.values()) + (Introspection.Annotation,)
)
children = []
for child in tree :
if child.tag not in child_tags :
raise KeyError("unrecognized tag %s" % child.tag)
#end if
childclass = child_tags[child.tag]
childattrs = {}
for attrname in childclass.tag_attrs :
if hasattr(childclass, "tag_attrs_optional") and attrname in childclass.tag_attrs_optional :
childattrs[attrname] = child.attrib.get(attrname, None)
else :
if attrname not in child.attrib :
raise ValueError("missing %s attribute for %s tag" % (attrname, child.tag))
#end if
childattrs[attrname] = child.attrib[attrname]
#end if
#end for
if hasattr(childclass, "attr_convert") :
for attr in childclass.attr_convert :
if attr in childattrs :
childattrs[attr] = childclass.attr_convert[attr](childattrs[attr])
#end if
#end for
#end if
children.append(from_string_elts(childclass, childattrs, child))
#end for
for child_tag, childclass in tuple(celf.tag_elts.items()) + ((), (("annotations", Introspection.Annotation),))[tree.tag != "annotation"] :
for child in children :
if isinstance(child, childclass) :
if child_tag not in elts :
elts[child_tag] = []
#end if
elts[child_tag].append(child)
#end if
#end for
#end for
return \
celf(**elts)
#end from_string_elts
#begin parse
tree = XMLElementTree.fromstring(s)
assert tree.tag == "node", "root of introspection tree must be <node> tag"
return \
from_string_elts(Introspection, {}, tree)
#end parse
def unparse(self, indent_step = 4, max_linelen = 72) :
"returns an XML string description of this Introspection tree."
out = io.StringIO()
def to_string(obj, indent) :
tag_name = obj.tag_name
attrs = []
for attrname in obj.tag_attrs :
attr = getattr(obj, attrname)
if attr != None :
if isinstance(attr, enum.Enum) :
attr = attr.value
elif isinstance(attr, Type) :
attr = unparse_signature(attr)
elif not isinstance(attr, str) :
raise TypeError("unexpected attribute type %s for %s" % (type(attr).__name__, repr(attr)))
#end if
attrs.append("%s=%s" % (attrname, quote_xml_attr(attr)))
#end if
#end for
has_elts = \
(
sum
(
len(getattr(obj, attrname))
for attrname in
tuple(obj.tag_elts.keys())
+
((), ("annotations",))
[not isinstance(obj, Introspection.Annotation)]
)
!=
0
)
out.write(" " * indent + "<" + tag_name)
if (
max_linelen != None
and
indent
+
len(tag_name)
+
sum((len(s) + 1) for s in attrs)
+
2
+
int(has_elts)
>
max_linelen
) :
out.write("\n")
for attr in attrs :
out.write(" " * (indent + indent_step))
out.write(attr)
out.write("\n")
#end for
out.write(" " * indent)
else :
for attr in attrs :
out.write(" ")
out.write(attr)
#end for
#end if
if not has_elts :
out.write("/")
#end if
out.write(">\n")
if has_elts :
for attrname in sorted(obj.tag_elts.keys()) + ["annotations"] :
for elt in getattr(obj, attrname) :
to_string(elt, indent + indent_step)
#end for
#end for
out.write(" " * indent + "</" + tag_name + ">\n")
#end if
#end to_string
#begin unparse
out.write(DBUS.INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE)
out.write("<node")
if self.name != None :
out.write(" name=%s" % quote_xml_attr(self.name))
#end if
out.write(">\n")
for elt in self.interfaces :
to_string(elt, indent_step)
#end for
for elt in self.nodes :
to_string(elt, indent_step)
#end for
out.write("</node>\n")
return \
out.getvalue()
#end unparse
#end Introspection
del _TagCommon
#+
# Standard interfaces
#-
standard_interfaces = \
{
DBUS.INTERFACE_PEER :
# note implementation of this is hard-coded inside libdbus
Introspection.Interface
(
name = DBUS.INTERFACE_PEER,
methods =
[
Introspection.Interface.Method(name = "Ping"),
Introspection.Interface.Method
(
name = "GetMachineId",
args =
[
Introspection.Interface.Method.Arg
(
name = "machine_uuid",
type = BasicType(TYPE.STRING),
direction = Introspection.DIRECTION.OUT,
),
]
),
],
),
DBUS.INTERFACE_LOCAL :
# note implementation of this is hard-coded inside, and specific to, libdbus
Introspection.Interface
(
name = DBUS.INTERFACE_LOCAL,
signals =
[
Introspection.Interface.Signal(name = "Disconnected"),
# auto-generated by libdbus with path = DBUS.PATH_LOCAL
# when connection is closed; cannot be explicitly sent by
# clients. Documented here:
# <https://lists.freedesktop.org/archives/dbus/2018-October/017587.html>
],
),
DBUS.INTERFACE_DBUS :
Introspection.Interface
(
name = DBUS.INTERFACE_DBUS,
methods =
[
Introspection.Interface.Method
(
name = "Hello",
args =
[
Introspection.Interface.Method.Arg
(
type = BasicType(TYPE.STRING),
direction = Introspection.DIRECTION.OUT,
), # returned unique name
]
),
Introspection.Interface.Method
(
name = "RequestName",
args =
[
Introspection.Interface.Method.Arg
(
type = BasicType(TYPE.STRING),
direction = Introspection.DIRECTION.IN,
), # name
Introspection.Interface.Method.Arg
(
type = BasicType(TYPE.UINT32),
direction = Introspection.DIRECTION.IN,
), # flags DBUS.NAME_FLAG_xxx
Introspection.Interface.Method.Arg
(
type = BasicType(TYPE.UINT32),
direction = Introspection.DIRECTION.OUT,
), # result DBUS.REQUEST_NAME_REPLY_xxx
]
),
Introspection.Interface.Method
(
name = "ReleaseName",
args =
[
Introspection.Interface.Method.Arg
(
type = BasicType(TYPE.STRING),
direction = Introspection.DIRECTION.IN,
),
Introspection.Interface.Method.Arg
(
type = BasicType(TYPE.UINT32),
direction = Introspection.DIRECTION.OUT,
), # result DBUS.RELEASE_NAME_REPLY_xxx
]
),
Introspection.Interface.Method
(
name = "StartServiceByName",
args =
[
Introspection.Interface.Method.Arg
(
type = BasicType(TYPE.STRING),
direction = Introspection.DIRECTION.IN,
), # name
Introspection.Interface.Method.Arg
(
type = BasicType(TYPE.UINT32),
direction = Introspection.DIRECTION.IN,
), # flags (currently unused)
Introspection.Interface.Method.Arg
(
type = BasicType(TYPE.UINT32),
direction = Introspection.DIRECTION.OUT,
), # result DBUS.START_REPLY_xxx
]
),
Introspection.Interface.Method
(
name = "UpdateActivationEnvironment",
args =
[
Introspection.Interface.Method.Arg
(
type = DictType
(
keytype = BasicType(TYPE.STRING),
valuetype = BasicType(TYPE.STRING)
),
direction = Introspection.DIRECTION.IN,
), # environment
]
),
Introspection.Interface.Method
(
name = "NameHasOwner",
args =
[
Introspection.Interface.Method.Arg
(
type = BasicType(TYPE.STRING),
direction = Introspection.DIRECTION.IN,
), # name
Introspection.Interface.Method.Arg
(
type = BasicType(TYPE.BOOLEAN),
direction = Introspection.DIRECTION.OUT,
),
]
),
Introspection.Interface.Method
(
name = "ListNames",
args =
[
Introspection.Interface.Method.Arg
(
type = ArrayType(BasicType(TYPE.STRING)),
direction = Introspection.DIRECTION.OUT,
),
]
),
Introspection.Interface.Method
(
name = "ListActivatableNames",
args =
[
Introspection.Interface.Method.Arg
(
type = ArrayType(BasicType(TYPE.STRING)),
direction = Introspection.DIRECTION.OUT,
),
]
),
Introspection.Interface.Method
(
name = "AddMatch",
args =
[
Introspection.Interface.Method.Arg
(
type = BasicType(TYPE.STRING),
direction = Introspection.DIRECTION.IN,
),
]
),
Introspection.Interface.Method
(
name = "RemoveMatch",
args =
[
Introspection.Interface.Method.Arg
(
type = BasicType(TYPE.STRING),
direction = Introspection.DIRECTION.IN,
),
]
),
Introspection.Interface.Method
(
name = "GetNameOwner",
args =
[
Introspection.Interface.Method.Arg
(
type = BasicType(TYPE.STRING),
direction = Introspection.DIRECTION.IN,
),
Introspection.Interface.Method.Arg
(
type = BasicType(TYPE.STRING),
direction = Introspection.DIRECTION.OUT,
),
]
),
Introspection.Interface.Method
(
name = "ListQueuedOwners",
args =
[
Introspection.Interface.Method.Arg
(
type = BasicType(TYPE.STRING),
direction = Introspection.DIRECTION.IN,
),
Introspection.Interface.Method.Arg
(
type = ArrayType(BasicType(TYPE.STRING)),
direction = Introspection.DIRECTION.OUT,
),
]
),
Introspection.Interface.Method
(
name = "GetConnectionUnixUser",
args =
[
Introspection.Interface.Method.Arg
(
type = BasicType(TYPE.STRING),
direction = Introspection.DIRECTION.IN,
),
Introspection.Interface.Method.Arg
(
type = BasicType(TYPE.UINT32),
direction = Introspection.DIRECTION.OUT,
),
]
),
Introspection.Interface.Method
(
name = "GetConnectionUnixProcessID",
args =
[
Introspection.Interface.Method.Arg
(
type = BasicType(TYPE.STRING),
direction = Introspection.DIRECTION.IN,
),
Introspection.Interface.Method.Arg
(
type = BasicType(TYPE.UINT32),
direction = Introspection.DIRECTION.OUT,
),
]
),
Introspection.Interface.Method
(
name = "GetAdtAuditSessionData",
args =
[
Introspection.Interface.Method.Arg
(
type = BasicType(TYPE.STRING),
direction = Introspection.DIRECTION.IN,
),
Introspection.Interface.Method.Arg
(
type = ArrayType(BasicType(TYPE.BYTE)),
direction = Introspection.DIRECTION.OUT,
),
]
),
Introspection.Interface.Method
(
name = "GetConnectionSELinuxSecurityContext",
args =
[
Introspection.Interface.Method.Arg
(
type = BasicType(TYPE.STRING),
direction = Introspection.DIRECTION.IN,
),
Introspection.Interface.Method.Arg
(
type = ArrayType(BasicType(TYPE.BYTE)),
direction = Introspection.DIRECTION.OUT,
),
]
),
Introspection.Interface.Method
(
name = "ReloadConfig",
),
Introspection.Interface.Method
(
name = "GetId",
args =
[
Introspection.Interface.Method.Arg
(
type = BasicType(TYPE.STRING),
direction = Introspection.DIRECTION.OUT,
),
]
),
Introspection.Interface.Method
(
name = "GetConnectionCredentials",
args =
[
Introspection.Interface.Method.Arg
(
type = BasicType(TYPE.STRING),
direction = Introspection.DIRECTION.IN,
),
Introspection.Interface.Method.Arg
(
type = DictType(BasicType(TYPE.STRING), VariantType()),
direction = Introspection.DIRECTION.OUT,
),
]
),
],
signals =
[
Introspection.Interface.Signal
(
name = "NameOwnerChanged",
args =
[
Introspection.Interface.Signal.Arg
(
type = BasicType(TYPE.STRING),
), # bus name
Introspection.Interface.Signal.Arg
(
type = BasicType(TYPE.STRING),
), # old owner, empty if none
Introspection.Interface.Signal.Arg
(
type = BasicType(TYPE.STRING),
), # new owner, empty if none
]
),
Introspection.Interface.Signal
(
name = "NameLost", # sent to previous owner of name
args =
[
Introspection.Interface.Signal.Arg
(
type = BasicType(TYPE.STRING),
),
]
),
Introspection.Interface.Signal
(
name = "NameAcquired", # sent to new owner of name
args =
[
Introspection.Interface.Signal.Arg
(
type = BasicType(TYPE.STRING),
),
]
),
],
),
DBUS.INTERFACE_INTROSPECTABLE :
Introspection.Interface
(
name = DBUS.INTERFACE_INTROSPECTABLE,
methods =
[
Introspection.Interface.Method
(
name = "Introspect",
args =
[
Introspection.Interface.Method.Arg
(
name = "data",
type = BasicType(TYPE.STRING),
direction = Introspection.DIRECTION.OUT,
),
]
),
],
),
DBUS.INTERFACE_PROPERTIES :
Introspection.Interface
(
name = DBUS.INTERFACE_PROPERTIES,
methods =
[
Introspection.Interface.Method
(
name = "Get",
args =
[
Introspection.Interface.Method.Arg
(
name = "interface_name",
type = BasicType(TYPE.STRING),
direction = Introspection.DIRECTION.IN,
),
Introspection.Interface.Method.Arg
(
name = "property_name",
type = BasicType(TYPE.STRING),
direction = Introspection.DIRECTION.IN,
),
Introspection.Interface.Method.Arg
(
name = "value",
type = VariantType(),
direction = Introspection.DIRECTION.OUT,
),
],
),
Introspection.Interface.Method
(
name = "Set",
args =
[
Introspection.Interface.Method.Arg
(
name = "interface_name",
type = BasicType(TYPE.STRING),
direction = Introspection.DIRECTION.IN,
),
Introspection.Interface.Method.Arg
(
name = "property_name",
type = BasicType(TYPE.STRING),
direction = Introspection.DIRECTION.IN,
),
Introspection.Interface.Method.Arg
(
name = "value",
type = VariantType(),
direction = Introspection.DIRECTION.IN,
),
],
),
Introspection.Interface.Method
(
name = "GetAll",
args =
[
Introspection.Interface.Method.Arg
(
name = "interface_name",
type = BasicType(TYPE.STRING),
direction = Introspection.DIRECTION.IN,
),
Introspection.Interface.Method.Arg
(
name = "values",
type = DictType(BasicType(TYPE.STRING), VariantType()),
direction = Introspection.DIRECTION.OUT,
),
],
),
],
signals =
[
Introspection.Interface.Signal
(
name = "PropertiesChanged",
args =
[
Introspection.Interface.Signal.Arg
(
name = "interface_name",
type = BasicType(TYPE.STRING),
),
Introspection.Interface.Signal.Arg
(
name = "changed_properties",
type = DictType(BasicType(TYPE.STRING), VariantType()),
),
Introspection.Interface.Signal.Arg
(
name = "invalidated_properties",
type = ArrayType(BasicType(TYPE.STRING)),
),
],
),
],
),
DBUS.INTERFACE_MONITORING :
Introspection.Interface
(
name = DBUS.INTERFACE_MONITORING,
methods =
[
Introspection.Interface.Method
(
name = "BecomeMonitor",
args =
[
Introspection.Interface.Method.Arg
(
type = ArrayType(BasicType(TYPE.STRING)),
direction = Introspection.DIRECTION.IN,
), # match rules to add to the connection
Introspection.Interface.Method.Arg
(
type = BasicType(TYPE.UINT32),
direction = Introspection.DIRECTION.IN,
), # flags (currently unused)
],
),
],
),
DBUSX.INTERFACE_OBJECT_MANAGER :
Introspection.Interface
(
name = DBUSX.INTERFACE_OBJECT_MANAGER,
methods =
[
Introspection.Interface.Method
(
name = "GetManagedObjects",
args =
[
Introspection.Interface.Method.Arg
(
name = "objpath_interfaces_and_properties",
type = DictType
(
BasicType(TYPE.OBJECT_PATH),
DictType
(
BasicType(TYPE.STRING), # interface
DictType(BasicType(TYPE.STRING), VariantType())
# properties and values
)
),
direction = Introspection.DIRECTION.OUT,
),
],
),
],
signals =
[
Introspection.Interface.Signal
(
name = "InterfacesAdded",
args =
[
Introspection.Interface.Signal.Arg
(
name = "object_path",
type = BasicType(TYPE.OBJECT_PATH),
),
Introspection.Interface.Signal.Arg
(
name = "interfaces_and_properties",
type = DictType
(
BasicType(TYPE.STRING), # interface added/changed
DictType(BasicType(TYPE.STRING), VariantType())
# properties and values added
),
),
],
),
Introspection.Interface.Signal
(
name = "InterfacesRemoved",
args =
[
Introspection.Interface.Signal.Arg
(
name = "object_path",
type = BasicType(TYPE.OBJECT_PATH),
),
Introspection.Interface.Signal.Arg
(
name = "interfaces",
type = ArrayType(BasicType(TYPE.STRING)),
# interfaces removed
),
],
),
],
),
}
#+
# Cleanup
#-
def _atexit() :
# disable all __del__ methods at process termination to avoid segfaults
for cls in Connection, Server, PreallocatedSend, Message, PendingCall, Error, AddressEntries :
delattr(cls, "__del__")
#end for
#end _atexit
atexit.register(_atexit)
del _atexit