1 // Copyright 2006 Alp Toker <alp@atoker.com>
2 // This software is made available under the MIT License
3 // See COPYING for details
4 
5 using System;
6 using System.Collections;
7 using System.Runtime.InteropServices;
8 
9 namespace DBus.GLib
10 {
11 	/*
12 	Specifies the type of function which is called when a data element is destroyed. It is passed the pointer to the data element and should free any memory and resources allocated for it.
13 
14 	@data: the data element.
15 	*/
16 	[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
DestroyNotify(IntPtr data)17 	delegate void DestroyNotify (IntPtr data);
18 
19 	/*
20 	Specifies the type of function passed to g_io_add_watch() or g_io_add_watch_full(), which is called when the requested condition on a GIOChannel is satisfied.
21 
22 	@source: the GIOChannel event source.
23 	@condition: the condition which has been satisfied.
24 	@data: user data set in g_io_add_watch() or g_io_add_watch_full().
25 
26 	Returns: the function should return FALSE if the event source should be removed.
27 	*/
28 	[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
IOFunc(IntPtr source, IOCondition condition, IntPtr data)29 	delegate bool IOFunc (IntPtr source, IOCondition condition, IntPtr data);
30 
31 	struct IOChannel
32 	{
33 		const string GLIB = "libglib-2.0-0.dll";
34 
35 		public IntPtr Handle;
36 
37 		[DllImport(GLIB)]
g_io_channel_unix_newDBus.GLib.IOChannel38 			static extern IntPtr g_io_channel_unix_new (int fd);
39 
IOChannelDBus.GLib.IOChannel40 		public IOChannel (int fd)
41 		{
42 			try {
43 				Handle = g_io_channel_win32_new_socket (fd);
44 			} catch {
45 				Handle = IntPtr.Zero;
46 			}
47 
48 			if (Handle == IntPtr.Zero)
49 				Handle = g_io_channel_unix_new (fd);
50 
51 			if (Handle == IntPtr.Zero)
52 				throw new Exception ("Failed to create GLib IO channel for fd " + fd);
53 
54 			//Buffered = false;
55 		}
56 
57 		[DllImport(GLIB)]
g_io_channel_unix_get_fdDBus.GLib.IOChannel58 			static extern int g_io_channel_unix_get_fd (IntPtr channel);
59 
60 		public int UnixFd
61 		{
62 			get {
63 				return g_io_channel_unix_get_fd (Handle);
64 			}
65 		}
66 
67 		[DllImport(GLIB)]
g_io_channel_win32_new_fdDBus.GLib.IOChannel68 			public static extern IntPtr g_io_channel_win32_new_fd (int fd);
69 
70 		[DllImport(GLIB)]
g_io_channel_win32_new_socketDBus.GLib.IOChannel71 			public static extern IntPtr g_io_channel_win32_new_socket (int socket);
72 
73 		[DllImport(GLIB)]
g_io_channel_win32_new_messagesDBus.GLib.IOChannel74 			public static extern IntPtr g_io_channel_win32_new_messages (uint hwnd);
75 
76 
77 		[DllImport(GLIB)]
g_io_channel_get_buffer_sizeDBus.GLib.IOChannel78 			public static extern uint g_io_channel_get_buffer_size (IntPtr channel);
79 
80 		[DllImport(GLIB)]
g_io_channel_set_buffer_sizeDBus.GLib.IOChannel81 			public static extern void g_io_channel_set_buffer_size (IntPtr channel, uint size);
82 
83 		public uint BufferSize
84 		{
85 			get {
86 				return g_io_channel_get_buffer_size (Handle);
87 			} set {
88 				g_io_channel_set_buffer_size (Handle, value);
89 			}
90 		}
91 
92 		[DllImport(GLIB)]
g_io_channel_get_bufferedDBus.GLib.IOChannel93 		public static extern bool g_io_channel_get_buffered (IntPtr channel);
94 
95 		[DllImport(GLIB)]
g_io_channel_set_bufferedDBus.GLib.IOChannel96 		public static extern void g_io_channel_set_buffered (IntPtr channel, bool value);
97 
98 		public bool Buffered
99 		{
100 			get
101 			{
102 				return g_io_channel_get_buffered (Handle);
103 			}
104 			set
105 			{
106 				g_io_channel_set_buffered (Handle, value);
107 			}
108 		}
109 
110 		[DllImport(GLIB)]
g_io_channel_get_buffer_conditionDBus.GLib.IOChannel111 			public static extern IOCondition g_io_channel_get_buffer_condition (IntPtr channel);
112 
113 		public IOCondition BufferCondition
114 		{
115 			get {
116 				return g_io_channel_get_buffer_condition (Handle);
117 			}
118 		}
119 
120 		[DllImport(GLIB)]
g_io_channel_get_flagsDBus.GLib.IOChannel121 			public static extern IOFlags g_io_channel_get_flags (IntPtr channel);
122 
123 		[DllImport(GLIB)]
g_io_channel_set_flagsDBus.GLib.IOChannel124 			static extern short g_io_channel_set_flags (IntPtr channel, IOFlags flags, IntPtr error);
125 
126 		public IOFlags Flags
127 		{
128 			get {
129 				return g_io_channel_get_flags (Handle);
130 			} set {
131 				//TODO: fix return and error
132 				g_io_channel_set_flags (Handle, value, IntPtr.Zero);
133 			}
134 		}
135 	}
136 
137 	class IO
138 	{
139 		const string GLIB = "libglib-2.0-0.dll";
140 
141 		//TODO: better memory management
142 		public static ArrayList objs = new ArrayList ();
143 
144 		/*
145 		Adds the GIOChannel into the main event loop with the default priority.
146 
147 		@channel: a GIOChannel.
148 		@condition: the condition to watch for.
149 		@func: the function to call when the condition is satisfied.
150 		@user_data: user data to pass to func.
151 
152 		Returns: the event source id.
153 		*/
154 		[DllImport(GLIB)]
g_io_add_watch(IntPtr channel, IOCondition condition, IOFunc func, IntPtr user_data)155 			protected static extern uint g_io_add_watch (IntPtr channel, IOCondition condition, IOFunc func, IntPtr user_data);
156 
AddWatch(IOChannel channel, IOCondition condition, IOFunc func)157 		public static uint AddWatch (IOChannel channel, IOCondition condition, IOFunc func)
158 		{
159 			objs.Add (func);
160 
161 			return g_io_add_watch (channel.Handle, condition, func, IntPtr.Zero);
162 		}
163 
164 		/*
165 		Adds the GIOChannel into the main event loop with the given priority.
166 
167 		@channel: a GIOChannel.
168 		@priority: the priority of the GIOChannel source.
169 		@condition: the condition to watch for.
170 		@func: the function to call when the condition is satisfied.
171 		@user_data: user data to pass to func.
172 		@notify: the function to call when the source is removed.
173 
174 		Returns: the event source id.
175 		*/
176 		[DllImport(GLIB)]
g_io_add_watch_full(IntPtr channel, int priority, IOCondition condition, IOFunc func, IntPtr user_data, DestroyNotify notify)177 			protected static extern uint g_io_add_watch_full (IntPtr channel, int priority, IOCondition condition, IOFunc func, IntPtr user_data, DestroyNotify notify);
178 
AddWatch(IOChannel channel, int priority, IOCondition condition, IOFunc func, DestroyNotify notify)179 		public static uint AddWatch (IOChannel channel, int priority, IOCondition condition, IOFunc func, DestroyNotify notify)
180 		{
181 			objs.Add (func);
182 			objs.Add (notify);
183 
184 			return g_io_add_watch_full (channel.Handle, priority, condition, func, IntPtr.Zero, notify);
185 		}
186 
187 		[DllImport(GLIB)]
g_main_context_default()188 			protected static extern IntPtr g_main_context_default ();
189 
MainContextDefault()190 		public static IntPtr MainContextDefault ()
191 		{
192 			return g_main_context_default ();
193 		}
194 
195 		[DllImport(GLIB)]
g_main_context_wakeup(IntPtr context)196 			protected static extern void g_main_context_wakeup (IntPtr context);
197 
MainContextWakeup(IntPtr context)198 		public static void MainContextWakeup (IntPtr context)
199 		{
200 			g_main_context_wakeup (context);
201 		}
202 	}
203 
204 	//From Mono.Unix and poll(2)
205 	[Flags]
206 	enum PollEvents : short {
207 		POLLIN      = 0x0001, // There is data to read
208 		POLLPRI     = 0x0002, // There is urgent data to read
209 		POLLOUT     = 0x0004, // Writing now will not block
210 		POLLERR     = 0x0008, // Error condition
211 		POLLHUP     = 0x0010, // Hung up
212 		POLLNVAL    = 0x0020, // Invalid request; fd not open
213 		// XPG4.2 definitions (via _XOPEN_SOURCE)
214 		POLLRDNORM  = 0x0040, // Normal data may be read
215 		POLLRDBAND  = 0x0080, // Priority data may be read
216 		POLLWRNORM  = 0x0100, // Writing now will not block
217 		POLLWRBAND  = 0x0200, // Priority data may be written
218 	}
219 
220 	//A bitwise combination representing a condition to watch for on an event source.
221 	[Flags]
222 	enum IOCondition : short
223 	{
224 		//There is data to read.
225 		In = PollEvents.POLLIN,
226 		//Data can be written (without blocking).
227 		Out = PollEvents.POLLOUT,
228 		//There is urgent data to read.
229 		Pri = PollEvents.POLLPRI,
230 		//Error condition.
231 		Err = PollEvents.POLLERR,
232 		//Hung up (the connection has been broken, usually for pipes and sockets).
233 		Hup = PollEvents.POLLHUP,
234 		//Invalid request. The file descriptor is not open.
235 		Nval = PollEvents.POLLNVAL,
236 	}
237 
238 	[Flags]
239 	enum IOFlags : short
240 	{
241 		Append = 1 << 0,
242 		Nonblock = 1 << 1,
243 		//Read only flag
244 		IsReadable = 1 << 2,
245 		//Read only flag
246 		isWriteable = 1 << 3,
247 		//Read only flag
248 		IsSeekable = 1 << 4,
249 		//?
250 		Mask = (1 << 5) - 1,
251 		GetMask = Mask,
252 		SetMask = Append | Nonblock,
253 	}
254 }
255