--- /dev/null
+
+"""Module for high-level communication over the FreeDesktop.org Bus (DBus)
+
+DBus allows you to share and access remote objects between processes
+running on the desktop, and also to access system services (such as
+the print spool).
+
+To use DBus, first get a Bus object, which provides a connection to one
+of a few standard dbus-daemon instances that might be running. From the
+Bus you can get a RemoteService. A service is provided by an application or
+process connected to the Bus, and represents a set of objects. Once you
+have a RemoteService you can get a RemoteObject that implements a specific interface
+(an interface is just a standard group of member functions). Then you can call
+those member functions directly.
+
+You can think of a complete method call as looking something like:
+
+Bus:SESSION -> Service:org.gnome.Evolution -> Object:/org/gnome/Evolution/Inbox -> Interface: org.gnome.Evolution.MailFolder -> Method: Forward('message1', 'seth@gnome.org')
+
+This communicates over the SESSION Bus to the org.gnome.Evolution process to call the
+Forward method of the /org/gnome/Evolution/Inbox object (which provides the
+org.gnome.Evolution.MailFolder interface) with two string arguments.
+
+For example, the dbus-daemon itself provides a service and some objects:
+
+# Get a connection to the desktop-wide SESSION bus
+bus = dbus.Bus(dbus.Bus.TYPE_SESSION)
+
+# Get the service provided by the dbus-daemon named org.freedesktop.DBus
+dbus_service = bus.get_service('org.freedesktop.DBus')
+
+# Get a reference to the desktop bus' standard object, denoted
+# by the path /org/freedesktop/DBus. The object /org/freedesktop/DBus
+# implements the 'org.freedesktop.DBus' interface
+dbus_object = dbus_service.get_object('/org/freedesktop/DBus',
+ 'org.freedesktop.DBus')
+
+# One of the member functions in the org.freedesktop.DBus interface
+# is ListServices(), which provides a list of all the other services
+# registered on this bus. Call it, and print the list.
+print(dbus_object.ListServices())
+"""
+
+import dbus_bindings
+
+class Bus:
+ """A connection to a DBus daemon.
+
+ One of three possible standard buses, the SESSION, SYSTEM,
+ or ACTIVATION bus
+ """
+ TYPE_SESSION = dbus_bindings.BUS_SESSION
+ TYPE_SYSTEM = dbus_bindings.BUS_SYSTEM
+ TYPE_ACTIVATION = dbus_bindings.BUS_ACTIVATION
+
+ def __init__(self, bus_type=TYPE_SESSION, glib_mainloop=True):
+ self._connection = dbus_bindings.bus_get(bus_type)
+
+ if (glib_mainloop):
+ self._connection.setup_with_g_main()
+
+ def get_service(self, service_name="org.freedesktop.Broadcast"):
+ """Get one of the RemoteServices connected to this Bus. service_name
+ is just a string of the form 'com.widgetcorp.MyService'
+ """
+ return RemoteService(self._connection, service_name)
+
+ def get_connection(self):
+ """Get the dbus_bindings.Connection object associated with this Bus"""
+ return self._connection
+
+
+class RemoteObject:
+ """A remote Object.
+
+ A RemoteObject is provided by a RemoteService on a particular Bus. RemoteObjects
+ have member functions, and can be called like normal Python objects.
+ """
+ def __init__(self, connection, service_name, object_path, interface):
+ self._connection = connection
+ self._service_name = service_name
+ self._object_path = object_path
+ self._interface = interface
+
+ def __getattr__(self, member):
+ if member == '__call__':
+ return object.__call__
+ else:
+ return RemoteMethod(self._connection, self._service_name,
+ self._object_path, self._interface, member)
+
+
+class RemoteMethod:
+ """A remote Method.
+
+ Typically a member of a RemoteObject. Calls to the
+ method produce messages that travel over the Bus and are routed
+ to a specific Service.
+ """
+ def __init__(self, connection, service_name, object_path, interface, method_name):
+ self._connection = connection
+ self._service_name = service_name
+ self._object_path = object_path
+ self._interface = interface
+ self._method_name = method_name
+
+ def __call__(self, *args):
+ print ("Going to call object(%s).interface(%s).method(%s)"
+ % (self._object_path, self._interface, self._method_name))
+
+ message = dbus_bindings.MethodCall(self._object_path, self._interface, self._method_name)
+ message.set_destination(self._service_name)
+
+ # Add the arguments to the function
+ iter = message.get_iter()
+ for arg in args:
+ print ("Adding arg %s" % (arg))
+ print ("Append success is %d" % (iter.append(arg)))
+ print ("Args now %s" % (message.get_args_list()))
+
+ reply_message = self._connection.send_with_reply_and_block(message, 5000)
+
+ args_tuple = reply_message.get_args_list()
+ if (len(args_tuple) == 0):
+ return
+ elif (len(args_tuple) == 1):
+ return args_tuple[0]
+ else:
+ return args_tuple
+
+class Service:
+ """A base class for exporting your own Services across the Bus
+
+ Just inherit from Service, providing the name of your service
+ (e.g. org.designfu.SampleService).
+ """
+ def __init__(self, service_name, bus=None):
+ self._service_name = service_name
+
+ if bus == None:
+ # Get the default bus
+ self._bus = Bus()
+ else:
+ self._bus = bus
+
+ dbus_bindings.bus_acquire_service(self._bus.get_connection(), service_name)
+
+ def get_bus(self):
+ """Get the Bus this Service is on"""
+ return self._bus
+
+class Object:
+ """A base class for exporting your own Objects across the Bus.
+
+ Just inherit from Object and provide a list of methods to share
+ across the Bus. These will appear as member functions of your
+ ServiceObject.
+ """
+ def __init__(self, object_path, methods_to_share, service):
+ self._object_path = object_path
+ self._service = service
+ self._object_methods = methods_to_share
+ self._bus = service.get_bus()
+ self._connection = self._bus.get_connection()
+
+ self._connection.register_object_path(object_path, self._unregister_cb, self._message_cb)
+
+ def _unregister_cb(self, connection):
+ print ("Unregister")
+
+ def message_cb(self, connection, message):
+ print ("Message %s received" % (message))
+ print ("MethodCall %s" % (message.get_member()))
+
+class RemoteService:
+ """A remote service providing objects.
+
+ A service is typically a process or application that provides
+ remote objects, but can also be the broadcast service that
+ receives signals from all applications on the Bus.
+ """
+
+ def __init__(self, connection, service_name):
+ self._connection = connection
+ self._service_name = service_name
+
+ def get_object(self, object_path, interface):
+ """Get an object provided by this Service that implements a
+ particular interface. object_path is a string of the form
+ '/com/widgetcorp/MyService/MyObject1'. interface looks a lot
+ like a service_name (they're often the same) and is of the form,
+ 'com.widgetcorp.MyInterface', and mostly just defines the
+ set of member functions that will be present in the object.
+ """
+ return RemoteObject(self._connection, self._service_name, object_path, interface)
+
--- /dev/null
+# -*- Mode: Python -*-
+
+#include "dbus_h_wrapper.h"
+
+cdef extern from "stdlib.h":
+ cdef void *malloc(size_t size)
+ cdef void free(void *ptr)
+
+cdef extern from "dbus-glib.h":
+ ctypedef struct GMainContext
+ cdef void dbus_connection_setup_with_g_main (DBusConnection *connection,
+ GMainContext *context)
+ cdef void dbus_server_setup_with_g_main (DBusServer *server,
+ GMainContext *context)
+
+cdef extern from "Python.h":
+ void Py_XINCREF (object)
+ void Py_XDECREF (object)
+
+
+ctypedef struct DBusError:
+ char *name
+ char *message
+ unsigned int dummy1
+ unsigned int dummy2
+ unsigned int dummy3
+ unsigned int dummy4
+ unsigned int dummy5
+ void *padding1
+
+ctypedef struct DBusMessageIter:
+ void *dummy1
+ void *dummy2
+ dbus_uint32_t dummy3
+ int dummy4
+ int dummy5
+ int dummy6
+ int dummy7
+ int dummy8
+ int dummy9
+ int dummy10
+ int dummy11
+ int pad1
+ int pad2
+ void *pad3
+
+ctypedef struct DBusObjectPathVTable:
+ DBusObjectPathUnregisterFunction unregister_function
+ DBusObjectPathMessageFunction message_function
+ void (* dbus_internal_pad1) (void *)
+ void (* dbus_internal_pad2) (void *)
+ void (* dbus_internal_pad3) (void *)
+ void (* dbus_internal_pad4) (void *)
+
+
+class DBusException(Exception):
+ pass
+
+class ConnectionError(Exception):
+ pass
+
+cdef void cunregister_function_handler (DBusConnection *connection,
+ void *user_data):
+ print ("cunregister_function_handler() called")
+ tup = <object>user_data
+ function = tup[0]
+ args = [Connection(_conn=<object>connection)]
+ function(*args)
+
+cdef DBusHandlerResult cmessage_function_handler (DBusConnection *connection,
+ DBusMessage *msg,
+ void *user_data):
+ print ("cmessage_function_handler() called")
+ tup = <object>user_data
+ print (tup)
+ function = tup[1]
+ message = Message(_create=0)
+ message._set_msg(<object>msg)
+ args = [Connection(_conn=<object>connection),
+ message]
+ retval = function(*args)
+ if (retval == None):
+ retval = DBUS_HANDLER_RESULT_HANDLED
+ return retval
+
+cdef DBusHandlerResult chandle_message_function_handler (DBusConnection *connection,
+ DBusMessage *msg,
+ void *user_data):
+ function = <object>user_data
+ messagein = Message(_create=0)
+ messagein._set_msg(<object>msg)
+ args = [Connection(_conn=<object>connection),
+ messagein]
+ retval = function(*args)
+ if (retval == None):
+ retval = DBUS_HANDLER_RESULT_HANDLED
+ return retval
+
+cdef class Connection:
+ cdef DBusConnection *conn
+
+ # FIXME: this is a major major hack. We use this because casting values to
+ # python objects and returning seemed to be corrupting them. This is a "global variable" :-(
+ cdef char **_parsed_path
+
+ def __init__(self, address=None, _conn=None):
+ cdef DBusError error
+ dbus_error_init(&error)
+ if <DBusConnection*>_conn != NULL:
+ self.conn = <DBusConnection*>_conn
+ dbus_connection_ref(self.conn)
+ else:
+ self.conn = dbus_connection_open(address,
+ &error)
+ if dbus_error_is_set(&error):
+ raise DBusException, error.message
+
+ dbus_connection_ref(self.conn)
+
+ def _set_conn(self, conn):
+ self.conn = <DBusConnection*>conn
+
+ def _get_conn(self):
+ return <object>self.conn
+
+ #FIXME: this is totally busted, don't use a class shared member like parsed_path
+ def _build_parsed_path(self, path_element_list):
+ cdef char **cpatharray
+ size = len(path_element_list)
+ cpatharray = <char **>malloc(sizeof(char*) * (size + 1))
+
+ for i in range(size):
+ path_element = path_element_list[i]
+ cpatharray[i] = path_element
+
+ cpatharray[size] = NULL
+
+ self._parsed_path = cpatharray
+
+ def get_base_service(self):
+ return bus_get_base_service(self)
+
+ def setup_with_g_main(self):
+ dbus_connection_setup_with_g_main(self.conn, NULL)
+
+ def disconnect(self):
+ dbus_connection_disconnect(self.conn)
+
+ def get_is_connected(self):
+ return dbus_connection_get_is_connected(self.conn)
+
+ def get_is_authenticated(self):
+ return dbus_connection_get_is_authenticated(self.conn)
+
+ def flush(self):
+ dbus_connection_flush(self.conn)
+
+ def borrow_message(self):
+ m = Message(_create=0)
+ m._set_msg(<object>dbus_connection_borrow_message(self.conn))
+ return m
+
+ def return_message(self, message):
+ msg = message._get_msg()
+ dbus_connection_return_message(self.conn, <DBusMessage*>msg)
+
+ def steal_borrowed_message(self, message):
+ msg = message._get_msg()
+ dbus_connection_steal_borrowed_message(self.conn,
+ <DBusMessage*>msg)
+
+ def pop_message(self):
+ cdef DBusMessage *msg
+ msg = dbus_connection_pop_message(self.conn)
+ if msg != NULL:
+ m = Message(_create=0)
+ m._set_msg(<object>msg)
+ else:
+ m = None
+ return m
+
+ def get_dispatch_status(self):
+ return dbus_connection_get_dispatch_status(self.conn)
+
+ def dispatch(self):
+ return dbus_connection_dispatch(self.conn)
+
+ def send(self, message):
+ #cdef dbus_uint32_t client_serial
+ #if type(message) != Message:
+ # raise TypeError
+
+ msg = message._get_msg()
+ retval = dbus_connection_send(self.conn,
+ <DBusMessage*>msg,
+ NULL)
+ return retval
+
+ def send_with_reply(self, message, timeout_milliseconds):
+ cdef dbus_bool_t retval
+ cdef DBusPendingCall *cpending_call
+ cdef DBusError error
+ dbus_error_init(&error)
+
+ cpending_call = NULL
+
+ msg = message._get_msg()
+
+ retval = dbus_connection_send_with_reply(self.conn,
+ <DBusMessage*>msg,
+ &cpending_call,
+ timeout_milliseconds)
+
+ if dbus_error_is_set(&error):
+ raise DBusException, error.message
+
+ if (cpending_call != NULL):
+ pending_call = PendingCall(<object>cpending_call)
+ else:
+ pending_call = None
+
+ return (retval, pending_call)
+
+ def send_with_reply_and_block(self, message,
+ timeout_milliseconds=0):
+ cdef DBusMessage * retval
+ cdef DBusError error
+ dbus_error_init(&error)
+
+ msg = message._get_msg()
+
+ print ("About to block")
+
+ retval = dbus_connection_send_with_reply_and_block(
+ <DBusConnection*>self.conn,
+ <DBusMessage*>msg,
+ <int>timeout_milliseconds,
+ &error)
+
+ print ("done")
+
+ if dbus_error_is_set(&error):
+ raise DBusException, error.message
+
+ if retval == NULL:
+ raise AssertionError
+
+ m = Message(_create=0)
+ m._set_msg(<object>retval)
+ return m
+
+ def set_watch_functions(self, add_function, remove_function, data):
+ pass
+
+ def set_timeout_functions(self, add_function, remove_function, data):
+ pass
+
+ def set_wakeup_main_function(self, wakeup_main_function, data):
+ pass
+
+ # FIXME: set_dispatch_status_function, get_unix_user, set_unix_user_function
+
+ def add_filter(self, function):
+ return dbus_connection_add_filter(self.conn,
+ chandle_message_function_handler,
+ <void*>function,
+ NULL)
+
+
+ #FIXME: remove_filter
+ # this is pretty tricky, we want to only remove the filter
+ # if we truly have no more calls to our message_function_handler...ugh
+
+ def set_data(self, slot, data):
+ pass
+
+ def get_data(self, slot):
+ pass
+
+ def set_max_message_size(self, size):
+ dbus_connection_set_max_message_size(self.conn, size)
+
+ def get_max_message_size(self):
+ return dbus_connection_get_max_message_size(self.conn)
+
+ def set_max_received_size(self, size):
+ dbus_connection_set_max_received_size(self.conn, size)
+
+ def get_max_received_size(self):
+ return dbus_connection_get_max_received_size(self.conn)
+
+ def get_outgoing_size(self):
+ return dbus_connection_get_outgoing_size(self.conn)
+
+ # preallocate_send, free_preallocated_send, send_preallocated
+
+ def register_object_path(self, path, unregister_cb, message_cb):
+ cdef DBusObjectPathVTable cvtable
+
+ cvtable.unregister_function = cunregister_function_handler
+ cvtable.message_function = cmessage_function_handler
+
+ user_data = [unregister_cb, message_cb]
+ #Py_XINCREF(user_data)
+
+ path_element_list = path[1:].split('/')
+ self._build_parsed_path(path_element_list)
+
+ return dbus_connection_register_object_path(self.conn, self._parsed_path, &cvtable,
+ <void*>user_data)
+
+ def register_fallback(self, path, unregister_cb, message_cb):
+ cdef DBusObjectPathVTable cvtable
+
+ cvtable.unregister_function = cunregister_function_handler
+ cvtable.message_function = cmessage_function_handler
+
+ user_data = [unregister_cb, message_cb]
+ Py_XINCREF(user_data)
+
+ print ("Ref inced")
+
+ path_element_list = path[1:].split('/')
+ self._build_parsed_path(path_element_list)
+
+ return dbus_connection_register_fallback(self.conn, self._parsed_path, &cvtable,
+ <void*>user_data)
+
+ #FIXME: unregister_object_path , see problems with remove_filter
+
+ def list_registered (self, parent_path):
+ cdef char **cchild_entries
+ cdef dbus_bool_t retval
+
+ path_element_list = parent_path[1:].split('/')
+ self._build_parsed_path(path_element_list)
+
+ retval = dbus_connection_list_registered(self.conn, self._parsed_path, &cchild_entries)
+
+ if (not retval):
+ #FIXME: raise out of memory exception?
+ return None
+
+ i = 0
+ child_entries = []
+ print ("cchild_entries[0] is %d" % (<int>cchild_entries[0]))
+ while (cchild_entries[i] != NULL):
+ child_entries.append(cchild_entries[i])
+ i = i + 1
+
+ dbus_free_string_array(cchild_entries)
+
+ return child_entries
+
+
+cdef class PendingCall:
+ cdef DBusPendingCall *pending_call
+
+ def __init__(self, _pending_call):
+ self.pending_call = <DBusPendingCall*>_pending_call
+ dbus_pending_call_ref(self.pending_call)
+
+ def _get_pending_call(self):
+ return <object>self.pending_call
+
+ def cancel(self):
+ dbus_pending_call_cancel(self.pending_call)
+
+ def get_completed(self):
+ return dbus_pending_call_get_completed(self.pending_call)
+
+ def get_reply(self):
+ message = Message(_create=0)
+ message._set_msg(<object>dbus_pending_call_get_reply(self.pending_call))
+ return message
+
+ def block(self):
+ dbus_pending_call_block(self.pending_call)
+
+cdef class Watch:
+ cdef DBusWatch* watch
+ def __init__(self, cwatch):
+ self.watch = <DBusWatch*>cwatch
+
+ def get_fd(self):
+ return dbus_watch_get_fd(self.watch)
+
+ # FIXME: not picked up correctly by extract.py
+ #def get_flags(self):
+ # return dbus_watch_get_flags(self.watch)
+
+ def handle(self, flags):
+ return dbus_watch_handle(self.watch, flags)
+
+ def get_enabled(self):
+ return dbus_watch_get_enabled(self.watch)
+
+cdef class MessageIter:
+ cdef DBusMessageIter *iter
+ cdef DBusMessageIter real_iter
+
+
+ def __init__(self, message):
+ self.iter = &self.real_iter
+ msg = message._get_msg()
+ dbus_message_iter_init(<DBusMessage*>msg, self.iter)
+
+ def get_iter(self):
+ return <object>self.iter
+
+ def has_next(self):
+ return dbus_message_iter_has_next(self.iter)
+
+ def next(self):
+ return dbus_message_iter_next(self.iter)
+
+ def get(self):
+ arg_type = self.get_arg_type()
+
+ if arg_type == TYPE_INVALID:
+ raise TypeError, 'Invalid arg type in MessageIter'
+ elif arg_type == TYPE_STRING:
+ retval = self.get_string()
+ elif arg_type == TYPE_INT32:
+ retval = self.get_int32()
+ elif arg_type == TYPE_UINT32:
+ retval = self.get_uint32()
+ elif arg_type == TYPE_DOUBLE:
+ retval = self.get_double()
+ elif arg_type == TYPE_BYTE:
+ retval = self.get_byte()
+ elif arg_type == TYPE_BOOLEAN:
+ retval = self.get_boolean()
+ elif arg_type == TYPE_ARRAY:
+ array_type = self.get_array_type()
+
+ if array_type == TYPE_STRING:
+ retval = self.get_string_array()
+ elif array_type == TYPE_BOOLEAN:
+ retval = self.get_boolean_array()
+ else:
+ raise TypeError, "Unknown array type %d in MessageIter" % (array_type)
+ else:
+ raise TypeError, 'Unknown arg type %d in MessageIter' % (argtype)
+
+ return retval
+
+ def get_arg_type(self):
+ return dbus_message_iter_get_arg_type(self.iter)
+
+ def get_array_type(self):
+ return dbus_message_iter_get_array_type(self.iter)
+
+ #FIXME: implement get_byte
+ #def get_byte(self):
+ # return dbus_message_iter_get_byte(self.iter)
+
+ def get_boolean(self):
+ return dbus_message_iter_get_boolean(self.iter)
+
+ def get_int32(self):
+ return dbus_message_iter_get_int32(self.iter)
+
+ def get_uint32(self):
+ return dbus_message_iter_get_uint32(self.iter)
+
+ def get_double(self):
+ return dbus_message_iter_get_double(self.iter)
+
+ def get_string(self):
+ return dbus_message_iter_get_string(self.iter)
+
+ def get_dict_key(self):
+ return dbus_message_iter_get_dict_key(self.iter)
+
+ # FIXME: implement dbus_message_iter_get_named
+ # dbus_message_iter_init_array_iterator
+
+ def get_byte_array(self):
+ cdef int len
+ cdef unsigned char *retval
+ dbus_message_iter_get_byte_array(self.iter, &retval, <int*>&len)
+ list = []
+ for i from 0 <= i < len:
+ list.append(chr(retval[i]))
+ return list
+
+ # FIXME: implement dbus_message_iter_get_boolean_array
+ # dbus_message_iter_get_int32_array
+ # dbus_message_iter_get_uint32_array
+ # dbus_message_iter_get_double_array
+
+ def get_string_array(self):
+ cdef int len
+ cdef char **retval
+
+ dbus_message_iter_get_string_array(self.iter, &retval, <int*>&len)
+ list = []
+ for i from 0 <= i < len:
+ list.append(retval[i])
+ return list
+
+ # dbus_message_append_iter_init included in class Message
+
+ #FIXME: handle all the different types?
+ def append(self, value):
+ value_type = type(value)
+
+ if value_type == bool:
+ retval = self.append_boolean(value)
+ elif value_type == int:
+ retval = self.append_int32(value)
+ elif value_type == float:
+ retval = self.append_double(value)
+ elif value_type == str:
+ retval = self.append_string(value)
+ elif value_type == list:
+ if (len(list) == 1):
+ raise TypeError, "Empty list"
+ list_type = type(list[0])
+ if list_type == str:
+ self.append_string_array(list)
+ else:
+ raise TypeError, "List of unknown type '%s'" % (list_type)
+ else:
+ raise TypeError, "Argument of unknown type '%s'" % (value_type)
+
+ return retval
+
+ def append_nil(self):
+ return dbus_message_iter_append_nil(self.iter)
+
+ def append_boolean(self, value):
+ return dbus_message_iter_append_boolean(self.iter, value)
+
+ def append_byte(self, value):
+ return dbus_message_iter_append_byte(self.iter, value)
+
+ def append_int32(self, value):
+ return dbus_message_iter_append_int32(self.iter, value)
+
+ def append_uint32(self, value):
+ return dbus_message_iter_append_uint32(self.iter, value)
+
+ def append_double(self, value):
+ return dbus_message_iter_append_double(self.iter, value)
+
+ def append_string(self, value):
+ return dbus_message_iter_append_string(self.iter, value)
+
+ # FIXME: dbus_message_iter_append_named
+
+ def append_dict_key(self, value):
+ return dbus_message_iter_append_dict_key(self.iter, value)
+
+ # FIXME: append_array, append_dict_array, append_boolean_array, append_int32_array, append_uint32_array, append_double_array
+
+ def append_byte_array(self, list):
+ cdef unsigned char * value
+ cdef int length
+ length = len(list)
+ value = <unsigned char*>malloc(length)
+ for i from 0 <= i < length:
+ item = list[i]
+ if type(item) != str or len(item) != 1:
+ raise TypeError
+ value[i] = ord(item)
+ return dbus_message_iter_append_byte_array(self.iter, value, length)
+
+ def append_string_array(self, list):
+ cdef char **value
+ cdef int length
+ length = len(list)
+ value = <char**>malloc(length)
+ for i from 0 <= i < length:
+ item = list[i]
+ if type(item) != str:
+ raise TypeError
+ value[i] = item
+ return dbus_message_iter_append_string_array(self.iter, value, length)
+
+
+(MESSAGE_TYPE_INVALID, MESSAGE_TYPE_METHOD_CALL, MESSAGE_TYPE_METHOD_RETURN, MESSAGE_TYPE_ERROR, MESSAGE_TYPE_SIGNAL) = range(5)
+(TYPE_INVALID, TYPE_NIL, TYPE_BYTE, TYPE_BOOLEAN, TYPE_INT32, TYPE_UINT32, TYPE_INT64, TYPE_UINT64, TYPE_DOUBLE, TYPE_STRING, TYPE_NAMED, TYPE_ARRAY, TYPE_DICT, TYPE_OBJECT_PATH) = range(14)
+
+cdef class Message:
+ cdef DBusMessage *msg
+
+ def __init__(self, message_type=MESSAGE_TYPE_INVALID, service=None, path=None, interface=None,
+ method=None, name=None, reply_to=None, error_name=None, error_message=None,
+ _create=1):
+ cdef char *cservice
+ if (service == None):
+ cservice = NULL
+ else:
+ cservice = service
+
+ if not _create:
+ return 0
+
+ if message_type == MESSAGE_TYPE_METHOD_CALL:
+ self.msg = dbus_message_new_method_call(cservice, path, interface, method)
+ elif message_type == MESSAGE_TYPE_METHOD_RETURN:
+ msg = method_call._get_msg()
+ self.msg = dbus_message_new_method_return(<DBusMessage*>msg)
+ elif message_type == MESSAGE_TYPE_SIGNAL:
+ self.msg = dbus_message_new_signal(path, interface, name)
+ elif message_type == MESSAGE_TYPE_ERROR:
+ msg = reply_to._get_msg()
+ self.msg = dbus_message_new_error(<DBusMessage*>msg, error_name, error_message)
+
+ def type_to_name(self, type):
+ if type == MESSAGE_TYPE_SIGNAL:
+ return "signal"
+ elif type == MESSAGE_TYPE_METHOD_CALL:
+ return "method call"
+ elif type == MESSAGE_TYPE_METHOD_RETURN:
+ return "method return"
+ elif type == MESSAGE_TYPE_ERROR:
+ return "error"
+ else:
+ return "(unknown message type)"
+
+ def __str__(self):
+ message_type = self.get_type()
+ sender = self.get_sender()
+
+ if sender == None:
+ sender = "(no sender)"
+
+ if (message_type == MESSAGE_TYPE_METHOD_CALL) or (message_type == MESSAGE_TYPE_SIGNAL):
+ retval = '%s interface=%s; member=%s; sender=%s' % (self.type_to_name(message_type),
+ self.get_interface(),
+ self.get_member(),
+ sender)
+ elif message_type == MESSAGE_TYPE_METHOD_RETURN:
+ retval = '%s sender=%s' % (self.type_to_name(message_type),
+ sender)
+ elif message_type == MESSAGE_TYPE_ERROR:
+ retval = '%s name=%s; sender=%s' % (self.type_to_name(message_type),
+ self.get_error_name(),
+ sender)
+ else:
+ retval = "Message of unknown type %d" % (message_type)
+
+
+ # FIXME: should really use self.convert_to_tuple() here
+
+ iter = self.get_iter()
+ value_at_iter = True
+
+ while (value_at_iter):
+ type = iter.get_arg_type()
+
+ if type == TYPE_INVALID:
+ break
+ elif type == TYPE_STRING:
+ str = iter.get_string()
+ arg = 'string:%s\n' % (str)
+ elif type == TYPE_INT32:
+ num = iter.get_int32()
+ arg = 'int32:%d\n' % (num)
+ elif type == TYPE_UINT32:
+ num = iter.get_uint32()
+ arg = 'uint32:%u\n' % (num)
+ elif type == TYPE_DOUBLE:
+ num = iter.get_double()
+ arg = 'double:%f\n' % (num)
+ elif type == TYPE_BYTE:
+ num = iter.get_byte()
+ arg = 'byte:%d\n' % (num)
+ elif type == TYPE_BOOLEAN:
+ bool = iter.get_boolean()
+ if (bool):
+ str = "true"
+ else:
+ str = "false"
+ arg = 'boolean:%s\n' % (str)
+ else:
+ arg = '(unknown arg type %d)\n' % type
+
+ retval = retval + arg
+ value_at_iter = iter.next()
+
+ return retval
+
+ def _set_msg(self, msg):
+ self.msg = <DBusMessage*>msg
+
+ def _get_msg(self):
+ return <object>self.msg
+
+ def get_iter(self):
+ return MessageIter(self)
+
+ def get_args_list(self):
+ retval = [ ]
+
+ iter = self.get_iter()
+ try:
+ retval.append(iter.get())
+ except TypeError, e:
+ return [ ]
+
+ value_at_iter = iter.next()
+ while (value_at_iter):
+ retval.append(iter.get())
+ value_at_iter = iter.next()
+
+ return retval
+
+ # FIXME: implement dbus_message_copy?
+
+ def get_type(self):
+ return dbus_message_get_type(self.msg)
+
+ def set_path(self, object_path):
+ return dbus_message_set_path(self.msg, object_path)
+
+ def get_path(self):
+ return dbus_message_get_path(self.msg)
+
+ def set_interface(self, interface):
+ return dbus_message_set_interface(self.msg, interface)
+
+ def get_interface(self):
+ return dbus_message_get_interface(self.msg)
+
+ def set_member(self, member):
+ return dbus_message_set_member(self.msg, member)
+
+ def get_member(self):
+ return dbus_message_get_member(self.msg)
+
+ def set_error_name(self, name):
+ return dbus_message_set_error_name(self.msg, name)
+
+ def get_error_name(self):
+ return dbus_message_get_error_name(self.msg)
+
+ def set_destination(self, destination):
+ return dbus_message_set_destination(self.msg, destination)
+
+ def get_destination(self):
+ return dbus_message_get_destination(self.msg)
+
+ def set_sender(self, sender):
+ return dbus_message_set_sender(self.msg, sender)
+
+ def get_sender(self):
+ cdef char *sender
+ sender = dbus_message_get_sender(self.msg)
+ if (sender == NULL):
+ return None
+ else:
+ return sender
+
+ def set_no_reply(self, no_reply):
+ dbus_message_set_no_reply(self.msg, no_reply)
+
+ def get_no_reply(self):
+ return dbus_message_get_no_reply(self.msg)
+
+ def is_method_call(self, interface, method):
+ return dbus_message_is_method_call(self.msg, interface, method)
+
+ def is_signal(self, interface, signal_name):
+ return dbus_message_is_signal(self.msg, interface, signal_name)
+
+ def is_error(self, error_name):
+ return dbus_message_is_error(self.msg, error_name)
+
+ def has_destination(self, service):
+ return dbus_message_has_destination(self.msg, service)
+
+ def has_sender(self, service):
+ return dbus_message_has_sender(self.msg, service)
+
+ def get_serial(self):
+ return dbus_message_get_serial(self.msg)
+
+ def set_reply_serial(self, reply_serial):
+ return dbus_message_set_reply_serial(self.msg, reply_serial)
+
+ def get_reply_serial(self):
+ return dbus_message_get_reply_serial(self.msg)
+
+ #FIXME: dbus_message_get_path_decomposed
+
+ # FIXME: all the different dbus_message_*args* methods
+
+class Signal(Message):
+ def __init__(self, spath, sinterface, sname):
+ Message.__init__(self, MESSAGE_TYPE_SIGNAL, path=spath, interface=sinterface, name=sname)
+
+class MethodCall(Message):
+ def __init__(self, mpath, minterface, mmethod):
+ Message.__init__(self, MESSAGE_TYPE_METHOD_CALL, path=mpath, interface=minterface, method=mmethod)
+
+cdef class Server:
+ cdef DBusServer *server
+ def __init__(self, address):
+ cdef DBusError error
+ dbus_error_init(&error)
+ self.server = dbus_server_listen(address,
+ &error)
+ if dbus_error_is_set(&error):
+ raise DBusException, error.message
+
+ def setup_with_g_main (self):
+ dbus_server_setup_with_g_main(self.server, NULL)
+
+ def disconnect(self):
+ dbus_server_disconnect(self.server)
+
+ def get_is_connected(self):
+ return dbus_server_get_is_connected(self.server)
+
+# def set_new_connection_function(self, function, data):
+# dbus_server_set_new_connection_function(self.conn, function,
+# data, NULL)
+
+# def set_watch_functions(self, add_function, remove_function, data):
+# dbus_server_set_watch_functions(self.server,
+# add_function, remove_function,
+# data, NULL)
+
+# def set_timeout_functions(self, add_function, remove_function, data):
+# dbus_server_set_timeout_functions(self.server,
+# add_function, remove_function,
+# data, NULL)
+
+# def handle_watch(self, watch, condition):
+# dbus_server_handle_watch(self.conn, watch, condition)
+
+BUS_SESSION = DBUS_BUS_SESSION
+BUS_SYSTEM = DBUS_BUS_SYSTEM
+BUS_ACTIVATION = DBUS_BUS_ACTIVATION
+
+def bus_get (bus_type):
+ cdef DBusError error
+ dbus_error_init(&error)
+ cdef DBusConnection *connection
+
+ connection = dbus_bus_get(bus_type,
+ &error)
+
+ if dbus_error_is_set(&error):
+ raise DBusException, error.message
+
+ return Connection(_conn=<object>connection)
+
+def bus_get_base_service(connection):
+ conn = connection._get_conn()
+ return dbus_bus_get_base_service(<DBusConnection*>conn)
+
+def bus_register(connection):
+ cdef DBusError error
+ dbus_error_init(&error)
+ cdef dbus_bool_t retval
+
+ conn = connection._get_conn()
+ retval = dbus_bus_register(<DBusConnection*>conn,
+ &error)
+ if dbus_error_is_set(&error):
+ raise DBusException, error.message
+
+ return retval
+
+SERVICE_FLAG_PROHIBIT_REPLACEMENT = 0x1
+SERVICE_FLAG_REPLACE_EXISTING = 0x2
+
+def bus_acquire_service(connection, service_name, flags=0):
+ cdef DBusError error
+ dbus_error_init(&error)
+ cdef int retval
+
+ conn = connection._get_conn()
+ retval = dbus_bus_acquire_service(<DBusConnection*>conn,
+ service_name,
+ flags,
+ &error)
+ if dbus_error_is_set(&error):
+ raise DBusException, error.message
+ return retval
+
+def bus_service_exists(connection, service_name):
+ cdef DBusError error
+ dbus_error_init(&error)
+ cdef dbus_bool_t retval
+
+ conn = connection._get_conn()
+ retval = dbus_bus_service_exists(<DBusConnection*>conn,
+ service_name,
+ &error)
+ if dbus_error_is_set(&error):
+ raise DBusException, error.message
+ return retval
+
+
--- /dev/null
+import commands
+import glob
+import re
+import os
+import string
+import sys
+
+def clean_func(buf):
+ buf = strip_comments(buf)
+ pat = re.compile(r"""\\\n""", re.MULTILINE)
+ buf = pat.sub('',buf)
+ pat = re.compile(r"""^[#].*?$""", re.MULTILINE)
+ buf = pat.sub('',buf)
+ pat = re.compile(r"""^(typedef|struct|enum)(\s|.|\n)*?;\s*""", re.MULTILINE)
+ buf = pat.sub('',buf)
+ pat = re.compile(r"""\s+""", re.MULTILINE)
+ buf = pat.sub(' ',buf)
+ pat = re.compile(r""";\s*""", re.MULTILINE)
+ buf = pat.sub('\n',buf)
+ buf = buf.lstrip()
+ #pat=re.compile(r'\s+([*|&]+)\s*(\w+)')
+ pat = re.compile(r' \s+ ([*|&]+) \s* (\w+)',re.VERBOSE)
+ buf = pat.sub(r'\1 \2', buf)
+ pat = re.compile(r'\s+ (\w+) \[ \s* \]',re.VERBOSE)
+ buf = pat.sub(r'[] \1', buf)
+# buf = string.replace(buf, 'G_CONST_RETURN ', 'const-')
+ buf = string.replace(buf, 'const ', '')
+ return buf
+
+def strip_comments(buf):
+ parts = []
+ lastpos = 0
+ while 1:
+ pos = string.find(buf, '/*', lastpos)
+ if pos >= 0:
+ parts.append(buf[lastpos:pos])
+ pos = string.find(buf, '*/', pos)
+ if pos >= 0:
+ lastpos = pos + 2
+ else:
+ break
+ else:
+ parts.append(buf[lastpos:])
+ break
+ return string.join(parts, '')
+
+def find_enums(buf):
+ enums = []
+ buf = strip_comments(buf)
+ buf = re.sub('\n', ' ', buf)
+
+ enum_pat = re.compile(r'enum\s*{([^}]*)}\s*([A-Z][A-Za-z]*)(\s|;)')
+ splitter = re.compile(r'\s*,\s', re.MULTILINE)
+ pos = 0
+ while pos < len(buf):
+ m = enum_pat.search(buf, pos)
+ if not m: break
+
+ name = m.group(2)
+ vals = m.group(1)
+ isflags = string.find(vals, '<<') >= 0
+ entries = []
+ for val in splitter.split(vals):
+ if not string.strip(val): continue
+ entries.append(string.split(val)[0])
+ enums.append((name, isflags, entries))
+
+ pos = m.end()
+ return enums
+
+#typedef unsigned int dbus_bool_t;
+#typedef struct {
+#
+# }
+#typedef struct FooStruct FooStruct;
+# typedef void (* DBusAddWatchFunction) (DBusWatch *watch,
+# void *data);
+
+def find_typedefs(buf):
+ typedefs = []
+ buf = re.sub('\n', ' ', strip_comments(buf))
+ typedef_pat = re.compile(
+ r"""typedef\s*(?P<type>\w*)
+ \s*
+ ([(]\s*\*\s*(?P<callback>[\w* ]*)[)]|{([^}]*)}|)
+ \s*
+ (?P<args1>[(](?P<args2>[\s\w*,_]*)[)]|[\w ]*)""",
+ re.MULTILINE | re.VERBOSE)
+ pat = re.compile(r"""\s+""", re.MULTILINE)
+ pos = 0
+ while pos < len(buf):
+ m = typedef_pat.search(buf, pos)
+ if not m:
+ break
+ if m.group('type') == 'enum':
+ pos = m.end()
+ continue
+ if m.group('args2') != None:
+ args = pat.sub(' ', m.group('args2'))
+
+ current = '%s (* %s) (%s)' % (m.group('type'),
+ m.group('callback'),
+ args)
+ else:
+ current = '%s %s' % (m.group('type'), m.group('args1'))
+ typedefs.append(current)
+ pos = m.end()
+ return typedefs
+
+proto_pat = re.compile(r"""
+(?P<ret>(-|\w|\&|\*)+\s*) # return type
+\s+ # skip whitespace
+(?P<func>\w+)\s*[(] # match the function name until the opening (
+(?P<args>.*?)[)] # group the function arguments
+""", re.IGNORECASE|re.VERBOSE)
+arg_split_pat = re.compile("\s*,\s*")
+
+
+def find_functions(buf):
+ functions = []
+ buf = clean_func(buf)
+ buf = string.split(buf,'\n')
+ for p in buf:
+ if len(p) == 0:
+ continue
+
+ m = proto_pat.match(p)
+ if m == None:
+ continue
+
+ func = m.group('func')
+ ret = m.group('ret')
+ args = m.group('args')
+ args = arg_split_pat.split(args)
+# for i in range(len(args)):
+# spaces = string.count(args[i], ' ')
+# if spaces > 1:
+# args[i] = string.replace(args[i], ' ', '-', spaces - 1)
+
+ functions.append((func, ret, args))
+ return functions
+
+class Writer:
+ def __init__(self, filename, enums, typedefs, functions):
+ if not (enums or typedefs or functions):
+ return
+ print 'cdef extern from "%s":' % filename
+
+ self.output_enums(enums)
+ self.output_typedefs(typedefs)
+ self.output_functions(functions)
+
+ print ' pass'
+ print
+
+ def output_enums(self, enums):
+ for enum in enums:
+ print ' ctypedef enum %s:' % enum[0]
+ if enum[1] == 0:
+ for item in enum[2]:
+ print ' %s' % item
+ else:
+ i = 0
+ for item in enum[2]:
+ print ' %s' % item
+# print ' %s = 1 << %d' % (item, i)
+ i += 1
+ print
+ def output_typedefs(self, typedefs):
+ for typedef in typedefs:
+ if typedef.find('va_list') != -1:
+ continue
+
+ parts = typedef.split()
+ if parts[0] == 'struct':
+ if parts[-2] == parts[-1]:
+ parts = parts[:-1]
+ print ' ctypedef %s' % ' '.join(parts)
+ else:
+ print ' ctypedef %s' % typedef
+
+ def output_functions(self, functions):
+ for func, ret, args in functions:
+ if func[0] == '_':
+ continue
+
+ str = ', '.join(args)
+ if str.find('...') != -1:
+ continue
+ if str.find('va_list') != -1:
+ continue
+ if str.strip() == 'void':
+ continue
+ print ' %-20s %s (%s)' % (ret, func, str)
+
+def do_buffer(name, buffer):
+ functions = find_functions(buffer)
+ typedefs = find_typedefs(buffer)
+ enums = find_enums(buffer)
+
+ Writer(name, enums, typedefs, functions)
+
+def do_header(filename, name=None):
+ if name == None:
+ name = filename
+
+ buffer = ""
+ for line in open(filename).readlines():
+ if line[0] == '#':
+ continue
+ buffer += line
+
+ print '# -- %s -- ' % filename
+ do_buffer(name, buffer)
+
+filename = sys.argv[1]
+
+if filename.endswith('.h'):
+ do_header(filename)
+ raise SystemExit
+
+cppflags = ""
+
+for flag in sys.argv[2:]:
+ cppflags = cppflags + " " + flag
+
+fd = open(filename)
+
+for line in fd.readlines():
+ if line.startswith('#include'):
+ filename = line.split(' ')[1][1:-2]
+ command = "echo '%s'|cpp %s" % (line, cppflags)
+ sys.stderr.write('running %s' % (command))
+ output = commands.getoutput(command)
+ do_buffer(filename, output)
+ else:
+ print line[:-1]