From 15ca798e7f2c8bf877d771822e67ccae45f9156f Mon Sep 17 00:00:00 2001 From: Aaron Bockover Date: Sun, 17 Jul 2005 20:22:11 +0000 Subject: [PATCH] Version 0.2, HAL Callback/Event Support svn path=/trunk/hal-sharp/; revision=47367 --- ChangeLog | 9 ++ Makefile.am | 2 +- NEWS | 1 + README | 6 +- configure.ac | 2 +- hal-sharp.mdp | 5 +- hal-sharp.mds | 4 +- src/HalCallbacks.cs | 94 ++++++++++++++++ src/HalContext.cs | 254 ++++++++++++++++++++++++++++++++++++++++++-- src/HalTest.cs | 73 ++++++++++++- src/HalUnmanaged.cs | 35 ++++++ src/Makefile.am | 3 +- 12 files changed, 465 insertions(+), 23 deletions(-) create mode 100644 src/HalCallbacks.cs diff --git a/ChangeLog b/ChangeLog index 09add0a..7b9c40b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2005-07-17 Aaron Bockover + + * HalTest.cs: GTK test for events using main context + * HalContext.cs: Changed some constructors around, now defaults to + DbusBusType.System, added event system for HAL callbacks + * HalUnmanaged.cs: Added callback set signatures + * HalCallbacks.cs: Contains all callback and event delegates, and + event delegate args classes + 2005-07-16 Aaron Bockover * hal-sharp: Version 0.1 Committed to Mono SVN diff --git a/Makefile.am b/Makefile.am index 38694a4..0f620ed 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,6 +4,6 @@ EXTRA_DIST = hal-sharp.pc.in hal-sharp.mds hal-sharp.mdp pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = hal-sharp.pc -DISTCLEANFILES = config.* configure INSTALL install-sh missing aclocal.m4 Makefile.in +DISTCLEANFILES = config.* configure INSTALL install-sh missing aclocal.m4 Makefile.in *.pidb diff --git a/NEWS b/NEWS index 9f64a76..a550ec5 100644 --- a/NEWS +++ b/NEWS @@ -1,2 +1,3 @@ +2005-07-17: hal-sharp 0.2 Committed to Mono SVN with HAL Callback Support 2005-07-16: hal-sharp 0.1 Committed to Mono SVN diff --git a/README b/README index 06b6006..db63f02 100644 --- a/README +++ b/README @@ -1,7 +1,7 @@ -These bindings aren't complete, but for the most part are functional with -the exception of callback support. Missing pieces are: +These bindings aren't complete, but for the most part are functional. + +Missing pieces are: * Agent Support * PSI Support - * Callback Support diff --git a/configure.ac b/configure.ac index a773b71..809b83e 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ AC_INIT(README) AC_CANONICAL_SYSTEM -AM_INIT_AUTOMAKE(hal-sharp, 0.1) +AM_INIT_AUTOMAKE(hal-sharp, 0.2) AM_MAINTAINER_MODE AC_PROG_INSTALL diff --git a/hal-sharp.mdp b/hal-sharp.mdp index 7946d92..a7313c7 100644 --- a/hal-sharp.mdp +++ b/hal-sharp.mdp @@ -15,6 +15,8 @@ + + @@ -27,5 +29,6 @@ + - + \ No newline at end of file diff --git a/hal-sharp.mds b/hal-sharp.mds index 16e7e0b..a5087ee 100644 --- a/hal-sharp.mds +++ b/hal-sharp.mds @@ -7,10 +7,10 @@ - + - + \ No newline at end of file diff --git a/src/HalCallbacks.cs b/src/HalCallbacks.cs new file mode 100644 index 0000000..171000d --- /dev/null +++ b/src/HalCallbacks.cs @@ -0,0 +1,94 @@ +/*************************************************************************** + * HalCallbacks.cs + * + * Copyright (C) 2005 Novell + * Written by Aaron Bockover (aaron@aaronbock.net) + ****************************************************************************/ + +/* THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW: + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +using System; +using System.Runtime.InteropServices; + +namespace Hal +{ + // Raw HAL Callbacks + public delegate void DeviceAddedCallback(IntPtr ctx, IntPtr udi); + public delegate void DeviceRemovedCallback(IntPtr ctx, IntPtr udi); + public delegate void DeviceNewCapabilityCallback(IntPtr ctx, IntPtr udi, + IntPtr capability); + public delegate void DeviceLostCapabilityCallback(IntPtr ctx, IntPtr udi, + IntPtr capability); + public delegate void DevicePropertyModifiedCallback(IntPtr ctx, IntPtr udi, + IntPtr key, bool is_removed, bool is_added); + public delegate void DeviceConditionCallback(IntPtr ctx, IntPtr udi, + IntPtr condition_name, IntPtr condition_details); + + // Managed Event Handlers + public delegate void DeviceAddedHandler(object o, DeviceAddedArgs args); + public delegate void DeviceRemovedHandler(object o, DeviceRemovedArgs args); + public delegate void DeviceNewCapabilityHandler(object o, + DeviceNewCapabilityArgs args); + public delegate void DeviceLostCapabilityHandler(object o, + DeviceLostCapabilityArgs args); + public delegate void DevicePropertyModifiedHandler(object o, + DevicePropertyModifiedArgs args); + public delegate void DeviceConditionHandler(object o, + DeviceConditionArgs args); + + public class DeviceAddedArgs : EventArgs + { + public Device Device; + } + + public class DeviceRemovedArgs : EventArgs + { + public Device Device; + } + + public class DeviceNewCapabilityArgs : EventArgs + { + public Device Device; + public string Capability; + } + + public class DeviceLostCapabilityArgs : EventArgs + { + public Device Device; + public string Capability; + } + + public class DevicePropertyModifiedArgs : EventArgs + { + public Device Device; + public string Key; + public bool IsRemoved; + public bool IsAdded; + } + + public class DeviceConditionArgs : EventArgs + { + public Device Device; + public string ConditionName; + public string ConditionDetails; + } +} diff --git a/src/HalContext.cs b/src/HalContext.cs index 5013fbf..f37013f 100644 --- a/src/HalContext.cs +++ b/src/HalContext.cs @@ -27,6 +27,7 @@ */ using System; +using System.Collections; using System.Runtime.InteropServices; namespace Hal @@ -36,17 +37,14 @@ namespace Hal private HandleRef ctx_handle; private IntPtr dbus_conn; private bool initialized; + private bool mainLoopIntegrated; - public Context() + public Context() : this(DbusBusType.System) { - IntPtr ctx = Unmanaged.libhal_ctx_init_direct(IntPtr.Zero); - if(ctx == IntPtr.Zero) - throw new HalException("Could not create Direct HAL Context"); - - ctx_handle = new HandleRef(this, ctx); + } - public Context(IntPtr dbus_conn) + protected Context(IntPtr dbus_conn) { IntPtr ctx = Unmanaged.libhal_ctx_new(); if(ctx == IntPtr.Zero) @@ -59,7 +57,7 @@ namespace Hal public Context(DbusBusType type) : this(Unmanaged.dbus_bus_get(type, IntPtr.Zero)) { - + Initialize(); } public Context(DbusBusType type, bool initialize) : this(type) @@ -98,7 +96,16 @@ namespace Hal return Unmanaged.libhal_ctx_free(ctx_handle); } - + + public void IntegrateMainLoop() + { + // would be nice to let user specify an optional GMainContext + Unmanaged.dbus_connection_setup_with_g_main(dbus_conn, + Unmanaged.g_main_context_default()); + + mainLoopIntegrated = true; + } + public void Initialize() { if(!Unmanaged.libhal_ctx_init(ctx_handle, IntPtr.Zero)) @@ -111,8 +118,10 @@ namespace Hal { set { dbus_conn = value; - if(!Unmanaged.libhal_ctx_set_dbus_connection(ctx_handle, dbus_conn)) - throw new HalException("Could not set D-Bus Connection for HAL"); + if(!Unmanaged.libhal_ctx_set_dbus_connection(ctx_handle, + dbus_conn)) + throw new HalException( + "Could not set D-Bus Connection for HAL"); } } @@ -131,5 +140,228 @@ namespace Hal return ctx_handle; } } + + // Events + + private Hashtable EventTable = new Hashtable(); + + private bool AddEvent(Type evType, object ev) + { + if(EventTable[evType] == null) + EventTable[evType] = new ArrayList(); + + (EventTable[evType] as ArrayList).Add(ev); + + if(!mainLoopIntegrated) + IntegrateMainLoop(); + + return (EventTable[evType] as ArrayList).Count == 1; + } + + private void RemoveEvent(Type evType, object ev) + { + if(EventTable[evType] == null) + return; + + (EventTable[evType] as ArrayList).Remove(ev); + } + + private ArrayList GetEvents(Type evType) + { + if(EventTable[evType] == null) + return null; + + return EventTable[evType] as ArrayList; + } + + public event DeviceAddedHandler DeviceAdded + { + add { + if(AddEvent(typeof(DeviceAddedHandler), value)) + Unmanaged.libhal_ctx_set_device_added(ctx_handle, + new DeviceAddedCallback(OnHalDeviceAdded)); + } + + remove { + RemoveEvent(typeof(DeviceAddedHandler), value); + } + } + + public event DeviceRemovedHandler DeviceRemoved + { + add { + if(AddEvent(typeof(DeviceRemovedHandler), value)) + Unmanaged.libhal_ctx_set_device_removed(ctx_handle, + new DeviceRemovedCallback(OnHalDeviceRemoved)); + } + + remove { + RemoveEvent(typeof(DeviceRemovedHandler), value); + } + } + + public event DeviceNewCapabilityHandler DeviceNewCapability + { + add { + if(AddEvent(typeof(DeviceNewCapabilityHandler), value)) + Unmanaged.libhal_ctx_set_device_new_capability(ctx_handle, + new DeviceNewCapabilityCallback( + OnHalDeviceNewCapability)); + } + + remove { + RemoveEvent(typeof(DeviceNewCapabilityHandler), value); + } + } + + public event DeviceLostCapabilityHandler DeviceLostCapability + { + add { + if(AddEvent(typeof(DeviceLostCapabilityHandler), value)) + Unmanaged.libhal_ctx_set_device_lost_capability(ctx_handle, + new DeviceLostCapabilityCallback( + OnHalDeviceLostCapability)); + } + + remove { + RemoveEvent(typeof(DeviceLostCapabilityHandler), value); + } + } + + public event DevicePropertyModifiedHandler DevicePropertyModified + { + add { + if(AddEvent(typeof(DevicePropertyModifiedHandler), value)) + Unmanaged.libhal_ctx_set_device_property_modified( + ctx_handle, new DevicePropertyModifiedCallback( + OnHalDevicePropertyModified)); + } + + remove { + RemoveEvent(typeof(DevicePropertyModifiedHandler), value); + } + } + + public event DeviceConditionHandler DeviceCondition + { + add { + if(AddEvent(typeof(DeviceConditionHandler), value)) + Unmanaged.libhal_ctx_set_device_condition(ctx_handle, + new DeviceConditionCallback(OnHalDeviceCondition)); + } + + remove { + RemoveEvent(typeof(DeviceConditionHandler), value); + } + } + + private void OnHalDeviceAdded(IntPtr ctx, IntPtr udiPtr) + { + foreach(DeviceAddedHandler addedHandler in + GetEvents(typeof(DeviceAddedHandler))) { + DeviceAddedHandler handler = addedHandler; + + if(handler != null) { + string udi = Marshal.PtrToStringAnsi(udiPtr); + DeviceAddedArgs args = new DeviceAddedArgs(); + args.Device = new Device(this, udi); + handler(this, args); + } + } + } + + private void OnHalDeviceRemoved(IntPtr ctx, IntPtr udiPtr) + { + foreach(DeviceRemovedHandler removedHandler in + GetEvents(typeof(DeviceRemovedHandler))) { + DeviceRemovedHandler handler = removedHandler; + + if(handler != null) { + string udi = Marshal.PtrToStringAnsi(udiPtr); + DeviceRemovedArgs args = new DeviceRemovedArgs(); + args.Device = new Device(this, udi); + handler(this, args); + } + } + } + + private void OnHalDeviceNewCapability(IntPtr ctx, IntPtr udiPtr, + IntPtr capPtr) + { + foreach(DeviceNewCapabilityHandler newCapHandler in + GetEvents(typeof(DeviceNewCapabilityHandler))) { + DeviceNewCapabilityHandler handler = newCapHandler; + + if(handler != null) { + string udi = Marshal.PtrToStringAnsi(udiPtr); + string cap = Marshal.PtrToStringAnsi(capPtr); + DeviceNewCapabilityArgs args = + new DeviceNewCapabilityArgs(); + args.Device = new Device(this, udi); + args.Capability = cap; + handler(this, args); + } + } + } + + private void OnHalDeviceLostCapability(IntPtr ctx, IntPtr udiPtr, + IntPtr capPtr) + { + foreach(DeviceLostCapabilityHandler lostCapHandler in + GetEvents(typeof(DeviceLostCapabilityHandler))) { + DeviceLostCapabilityHandler handler = lostCapHandler; + + if(handler != null) { + string udi = Marshal.PtrToStringAnsi(udiPtr); + string cap = Marshal.PtrToStringAnsi(capPtr); + DeviceLostCapabilityArgs args = + new DeviceLostCapabilityArgs(); + args.Device = new Device(this, udi); + args.Capability = cap; + handler(this, args); + } + } + } + + private void OnHalDevicePropertyModified(IntPtr ctx, IntPtr udiPtr, + IntPtr keyPtr, bool isRemoved, bool isAdded) + { + foreach(DevicePropertyModifiedHandler propModHandler in + GetEvents(typeof(DevicePropertyModifiedHandler))) { + DevicePropertyModifiedHandler handler = propModHandler; + + if(handler != null) { + string udi = Marshal.PtrToStringAnsi(udiPtr); + string key = Marshal.PtrToStringAnsi(keyPtr); + DevicePropertyModifiedArgs args = + new DevicePropertyModifiedArgs(); + args.Device = new Device(this, udi); + args.Key = key; + args.IsRemoved = isRemoved; + args.IsAdded = isAdded; + handler(this, args); + } + } + } + + private void OnHalDeviceCondition(IntPtr ctx, IntPtr udiPtr, + IntPtr namePtr, IntPtr detailsPtr) + { + foreach(DeviceConditionHandler condHandler in + GetEvents(typeof(DeviceConditionHandler))) { + DeviceConditionHandler handler = condHandler; + + if(handler != null) { + string udi = Marshal.PtrToStringAnsi(udiPtr); + string name = Marshal.PtrToStringAnsi(namePtr); + string details = Marshal.PtrToStringAnsi(detailsPtr); + DeviceConditionArgs args = new DeviceConditionArgs(); + args.Device = new Device(this, udi); + args.ConditionName = name; + args.ConditionDetails = details; + handler(this, args); + } + } + } } } diff --git a/src/HalTest.cs b/src/HalTest.cs index 6e97836..95eb609 100644 --- a/src/HalTest.cs +++ b/src/HalTest.cs @@ -28,15 +28,20 @@ using System; using Hal; +using Gtk; public class Entry { public static void Main() { - Context ctx = new Context(DbusBusType.System, true); + Application.Init(); + new GtkTest(); + Application.Run(); - foreach(Device device in Device.FindByCapability(ctx, "net")) - device.Print(); + /* Context ctx = new Context(); */ + + /*foreach(Device device in Device.FindByCapability(ctx, "net")) + device.Print();*/ /*foreach(Device device in Device.GetAll(ctx)) device.Print();*/ @@ -50,3 +55,65 @@ public class Entry Console.WriteLine(cap);*/ } } + +public class GtkTest +{ + private Window win; + private Context ctx; + + public GtkTest() + { + ctx = new Context(); + ctx.DeviceAdded += OnHalDeviceAdded; + ctx.DeviceRemoved += OnHalDeviceRemoved; + ctx.DeviceCondition += OnHalDeviceCondition; + ctx.DeviceLostCapability += OnHalDeviceLostCapability; + ctx.DeviceNewCapability += OnHalDeviceNewCapability; + ctx.DevicePropertyModified += OnHalDevicePropertyModified; + + win = new Window("HAL Event Loop Test"); + win.DeleteEvent += OnWindowDeleteEvent; + win.ShowAll(); + } + + public void OnHalDeviceAdded(object o, DeviceAddedArgs args) + { + Console.WriteLine("Device Added: " + args.Device); + args.Device.WatchProperties = true; + } + + public void OnHalDeviceRemoved(object o, DeviceRemovedArgs args) + { + Console.WriteLine("Device Removed: " + args.Device); + } + + public void OnHalDeviceCondition(object o, DeviceConditionArgs args) + { + Console.WriteLine("Device Condition: " + args.Device); + } + + public void OnHalDeviceLostCapability(object o, + DeviceLostCapabilityArgs args) + { + Console.WriteLine("Device Lost Capability: " + args.Device); + } + + public void OnHalDeviceNewCapability(object o, + DeviceNewCapabilityArgs args) + { + Console.WriteLine("Device New Capability: " + args.Device); + } + + public void OnHalDevicePropertyModified(object o, + DevicePropertyModifiedArgs args) + { + Console.WriteLine("Device Property Modified: " + args.Device + + ", Key: " + args.Key + ", Is Removed: " + args.IsRemoved + + ", Is Added: " + args.IsAdded); + } + + public void OnWindowDeleteEvent(object o, EventArgs args) + { + Application.Quit(); + } +} diff --git a/src/HalUnmanaged.cs b/src/HalUnmanaged.cs index b21f528..90bae0d 100644 --- a/src/HalUnmanaged.cs +++ b/src/HalUnmanaged.cs @@ -59,6 +59,32 @@ namespace Hal [DllImport("libhal")] public static extern bool libhal_ctx_free(HandleRef ctx); + // Callback Set Functions + + [DllImport("libhal")] + public static extern bool libhal_ctx_set_device_added(HandleRef ctx, + DeviceAddedCallback cb); + + [DllImport("libhal")] + public static extern bool libhal_ctx_set_device_removed(HandleRef ctx, + DeviceRemovedCallback cb); + + [DllImport("libhal")] + public static extern bool libhal_ctx_set_device_new_capability( + HandleRef ctx, DeviceNewCapabilityCallback cb); + + [DllImport("libhal")] + public static extern bool libhal_ctx_set_device_lost_capability( + HandleRef ctx, DeviceLostCapabilityCallback cb); + + [DllImport("libhal")] + public static extern bool libhal_ctx_set_device_property_modified( + HandleRef ctx, DevicePropertyModifiedCallback cb); + + [DllImport("libhal")] + public static extern bool libhal_ctx_set_device_condition( + HandleRef ctx, DeviceConditionCallback cb); + // String Functions [DllImport("libhal")] @@ -225,5 +251,14 @@ namespace Hal [DllImport("libdbus-1")] public static extern IntPtr dbus_bus_get(DbusBusType bus_typed, IntPtr error); + + [DllImport("libdbus-glib-1")] + public static extern void dbus_connection_setup_with_g_main( + IntPtr dbus_connection, IntPtr g_main_context); + + // ughhh + [DllImport("libglib-2.0.so")] + public static extern IntPtr g_main_context_default(); + } } diff --git a/src/Makefile.am b/src/Makefile.am index a4cd67a..ef53736 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,7 +2,7 @@ halsharpdir=$(pkglibdir) halsharp_SCRIPTS = hal-sharp.dll EXTRA_DIST = $(halsharp_sources) HalTest.cs CLEANFILES = hal-sharp.dll AssemblyInfo.cs -DISTCLEANFILES = Makefile.in +DISTCLEANFILES = Makefile.in *.exe *.mdb halsharp_sources = \ HalContext.cs \ @@ -10,6 +10,7 @@ halsharp_sources = \ HalUnmanaged.cs \ HalDefines.cs \ HalExceptions.cs \ + HalCallbacks.cs \ AssemblyInfo.cs halsharp_build_sources = $(addprefix $(srcdir)/, $(halsharp_sources))