namespace DBus { using System; using System.Runtime.InteropServices; using System.Diagnostics; using System.Reflection; using System.IO; using System.Collections; public delegate int DBusHandleMessageFunction (IntPtr rawConnection, IntPtr rawMessage, IntPtr userData); internal delegate void DBusObjectPathUnregisterFunction(IntPtr rawConnection, IntPtr userData); internal delegate int DBusObjectPathMessageFunction(IntPtr rawConnection, IntPtr rawMessage, IntPtr userData); [StructLayout (LayoutKind.Sequential)] internal struct DBusObjectPathVTable { public DBusObjectPathUnregisterFunction unregisterFunction; public DBusObjectPathMessageFunction messageFunction; public IntPtr padding1; public IntPtr padding2; public IntPtr padding3; public IntPtr padding4; public DBusObjectPathVTable(DBusObjectPathUnregisterFunction unregisterFunction, DBusObjectPathMessageFunction messageFunction) { this.unregisterFunction = unregisterFunction; this.messageFunction = messageFunction; this.padding1 = IntPtr.Zero; this.padding2 = IntPtr.Zero; this.padding3 = IntPtr.Zero; this.padding4 = IntPtr.Zero; } } public class Connection : IDisposable { /// /// A pointer to the underlying Connection structure /// private IntPtr rawConnection; /// /// The current slot number /// private static int slot = -1; private int timeout = -1; private ArrayList filters = new ArrayList (); // of DBusHandleMessageFunction private ArrayList matches = new ArrayList (); // of string private Hashtable object_paths = new Hashtable (); // key: string value: DBusObjectPathVTable internal Connection(IntPtr rawConnection) { RawConnection = rawConnection; } public Connection(string address) { // the assignment bumps the refcount Error error = new Error(); error.Init(); RawConnection = dbus_connection_open(address, ref error); if (RawConnection != IntPtr.Zero) { dbus_connection_unref(RawConnection); } else { throw new DBusException(error); } SetupWithMain(); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } public void Dispose (bool disposing) { if (disposing && RawConnection != IntPtr.Zero) { dbus_connection_disconnect(rawConnection); RawConnection = IntPtr.Zero; // free the native object } } public void Flush() { dbus_connection_flush(RawConnection); } public void SetupWithMain() { dbus_connection_setup_with_g_main(RawConnection, IntPtr.Zero); } ~Connection () { Dispose (false); } internal static Connection Wrap(IntPtr rawConnection) { if (slot > -1) { // Maybe we already have a Connection object associated with // this rawConnection then return it IntPtr rawThis = dbus_connection_get_data (rawConnection, slot); if (rawThis != IntPtr.Zero) { return (DBus.Connection) ((GCHandle)rawThis).Target; } } // If it doesn't exist then create a new connection around it return new Connection(rawConnection); } public void AddFilter (DBusHandleMessageFunction func) { if (!dbus_connection_add_filter (RawConnection, func, IntPtr.Zero, IntPtr.Zero)) throw new OutOfMemoryException (); this.filters.Add (func); } public void RemoveFilter (DBusHandleMessageFunction func) { dbus_connection_remove_filter (RawConnection, func, IntPtr.Zero); this.filters.Remove (func); } public void AddMatch (string match_rule) { dbus_bus_add_match (RawConnection, match_rule, IntPtr.Zero); this.matches.Add (match_rule); } public void RemoveMatch (string match_rule) { dbus_bus_remove_match (RawConnection, match_rule, IntPtr.Zero); this.matches.Remove (match_rule); } internal void RegisterObjectPath (string path, DBusObjectPathVTable vtable) { if (!dbus_connection_register_object_path (RawConnection, path, ref vtable, IntPtr.Zero)) throw new OutOfMemoryException (); this.object_paths[path] = vtable; } internal void UnregisterObjectPath (string path) { dbus_connection_unregister_object_path (RawConnection, path); this.object_paths.Remove (path); } public string UniqueName { get { return Marshal.PtrToStringAnsi (dbus_bus_get_unique_name (RawConnection)); } } public int Timeout { get { return this.timeout; } set { this.timeout = value; } } private int Slot { get { if (slot == -1) { // We need to initialize the slot if (!dbus_connection_allocate_data_slot (ref slot)) throw new OutOfMemoryException (); Debug.Assert (slot >= 0); } return slot; } } internal IntPtr RawConnection { get { return rawConnection; } set { if (value == rawConnection) return; if (rawConnection != IntPtr.Zero) { // Remove our callbacks from this connection foreach (DBusHandleMessageFunction func in this.filters) dbus_connection_remove_filter (rawConnection, func, IntPtr.Zero); foreach (string match_rule in this.matches) dbus_bus_remove_match (rawConnection, match_rule, IntPtr.Zero); foreach (string path in this.object_paths.Keys) dbus_connection_unregister_object_path (rawConnection, path); // Get the reference to this IntPtr rawThis = dbus_connection_get_data (rawConnection, Slot); Debug.Assert (rawThis != IntPtr.Zero); // Blank over the reference dbus_connection_set_data (rawConnection, Slot, IntPtr.Zero, IntPtr.Zero); // Free the reference ((GCHandle) rawThis).Free(); // Unref the connection dbus_connection_unref(rawConnection); } this.rawConnection = value; if (rawConnection != IntPtr.Zero) { GCHandle rawThis; dbus_connection_ref (rawConnection); // We store a weak reference to the C# object on the C object rawThis = GCHandle.Alloc (this, GCHandleType.WeakTrackResurrection); dbus_connection_set_data(rawConnection, Slot, (IntPtr) rawThis, IntPtr.Zero); // Add the callbacks to this new connection foreach (DBusHandleMessageFunction func in this.filters) dbus_connection_add_filter (rawConnection, func, IntPtr.Zero, IntPtr.Zero); foreach (string match_rule in this.matches) dbus_bus_add_match (rawConnection, match_rule, IntPtr.Zero); foreach (string path in this.object_paths.Keys) { DBusObjectPathVTable vtable = (DBusObjectPathVTable) this.object_paths[path]; dbus_connection_register_object_path (rawConnection, path, ref vtable, IntPtr.Zero); } } else { this.filters.Clear (); this.matches.Clear (); this.object_paths.Clear (); } } } [DllImport("dbus-glib-1")] private extern static void dbus_connection_setup_with_g_main(IntPtr rawConnection, IntPtr rawContext); [DllImport ("dbus-1")] private extern static IntPtr dbus_connection_open (string address, ref Error error); [DllImport ("dbus-1")] private extern static void dbus_connection_unref (IntPtr ptr); [DllImport ("dbus-1")] private extern static void dbus_connection_ref (IntPtr ptr); [DllImport ("dbus-1")] private extern static bool dbus_connection_allocate_data_slot (ref int slot); [DllImport ("dbus-1")] private extern static void dbus_connection_free_data_slot (ref int slot); [DllImport ("dbus-1")] private extern static bool dbus_connection_set_data (IntPtr ptr, int slot, IntPtr data, IntPtr free_data_func); [DllImport ("dbus-1")] private extern static void dbus_connection_flush (IntPtr ptr); [DllImport ("dbus-1")] private extern static IntPtr dbus_connection_get_data (IntPtr ptr, int slot); [DllImport ("dbus-1")] private extern static void dbus_connection_disconnect (IntPtr ptr); [DllImport ("dbus-1")] private extern static IntPtr dbus_bus_get_unique_name (IntPtr ptr); [DllImport("dbus-1")] private extern static bool dbus_connection_add_filter(IntPtr rawConnection, DBusHandleMessageFunction filter, IntPtr userData, IntPtr freeData); [DllImport("dbus-1")] private extern static void dbus_connection_remove_filter(IntPtr rawConnection, DBusHandleMessageFunction filter, IntPtr userData); [DllImport("dbus-1")] private extern static void dbus_bus_add_match(IntPtr rawConnection, string rule, IntPtr erro); [DllImport("dbus-1")] private extern static void dbus_bus_remove_match(IntPtr rawConnection, string rule, IntPtr erro); [DllImport ("dbus-1")] private extern static bool dbus_connection_register_object_path (IntPtr rawConnection, string path, ref DBusObjectPathVTable vTable, IntPtr userData); [DllImport ("dbus-1")] private extern static void dbus_connection_unregister_object_path (IntPtr rawConnection, string path); } }