PageRenderTime 204ms CodeModel.GetById 145ms app.highlight 13ms RepoModel.GetById 39ms app.codeStats 0ms

/GammaJul.LgLcd/LcdApplet.cs

#
C# | 388 lines | 211 code | 54 blank | 123 comment | 29 complexity | 2cdcce1f7cc111a06a2cdfff77743709 MD5 | raw file
Possible License(s): LGPL-2.1
  1using System;
  2using System.Security.Permissions;
  3using System.Threading;
  4
  5namespace GammaJul.LgLcd {
  6
  7	/// <summary>
  8	/// This class represent a single LCD applet.
  9	/// </summary>
 10	public class LcdApplet : IDisposable {
 11		private static int _initCount;
 12		
 13
 14		#region Properties
 15
 16		private volatile int _connectionNumber = -1;
 17		private volatile bool _isDisposed;
 18		private volatile bool _isEnabled;
 19		private string _friendlyName = String.Empty;
 20		private bool _isAutoStartable;
 21		private LcdAppletCapabilities _capabilities = LcdAppletCapabilities.Monochrome;
 22		
 23		/// <summary>
 24		/// Gets whether the applet is connected.
 25		/// </summary>
 26		public bool IsConnected {
 27			get { return _connectionNumber != -1; }
 28		}
 29
 30		/// <summary>
 31		/// Gets whether the applet has been disposed.
 32		/// </summary>
 33		public bool IsDisposed {
 34			get { return _isDisposed; }
 35		}
 36
 37		/// <summary>
 38		/// Gets whether the applet is enabled.
 39		/// </summary>
 40		public bool IsEnabled {
 41			get { return _isEnabled; }
 42		}
 43
 44		/// <summary>
 45		/// Gets or sets the friendly name of the applet that is displayed in LCD Monitor.
 46		/// Note that changing this property must be done before calling <see cref="Connect"/>.
 47		/// </summary>
 48		public string FriendlyName {
 49			get { return _friendlyName; }
 50			set {
 51				if (value == null)
 52					throw new ArgumentNullException("value");
 53				VerifyNotConnected();
 54				_friendlyName = value;
 55			}
 56		}
 57
 58		/// <summary>
 59		/// Gets or sets whether this applet has the option to be auto-startable.
 60		/// The default is <c>false</c>.
 61		/// Note that changing this property must be done before calling <see cref="Connect"/>.
 62		/// </summary>
 63		public bool IsAutoStartable {
 64			get { return _isAutoStartable; }
 65			set {
 66				VerifyNotConnected();
 67				_isAutoStartable = value;
 68			}
 69		}
 70
 71		/// <summary>
 72		/// Gets or sets the capabilities that this applet supports.
 73		/// The default is <see cref="LcdAppletCapabilities.Monochrome"/>.
 74		/// Note that changing this property must be done before calling <see cref="Connect"/>.
 75		/// </summary>
 76		public LcdAppletCapabilities Capabilities {
 77			get { return _capabilities; }
 78			set {
 79				VerifyNotConnected();
 80				_capabilities = value;
 81			}
 82		}
 83
 84		/// <summary>
 85		/// Gets the internal number of this applet.
 86		/// </summary>
 87		protected internal int ConnectionNumber {
 88			get { return _connectionNumber; }
 89		}
 90
 91		#endregion
 92
 93
 94		#region Events
 95
 96		private EventHandler _configure;
 97		private static SafeNativeMethods.LgLcdOnNotificationCallback _notificationCallback;
 98		private static SafeNativeMethods.LgLcdOnConfigureCallback _configCallback;
 99
100		/// <summary>
101		/// Occurs when the Configure button in the LCD Monitor configuration is clicked.
102		/// Note that suscribing or unsuscribing to this event must be done before calling <see cref="Connect"/>.
103		/// Note that this event is raised in the context of a thread within the library.
104		/// Therefore, take the necessary precautions for thread safety.
105		/// </summary>
106		public event EventHandler Configure {
107			add {
108				VerifyNotConnected();
109				_configure = (EventHandler) Delegate.Combine(_configure, value);
110			}
111			remove {
112				VerifyNotConnected();
113				_configure = (EventHandler) Delegate.Remove(_configure, value);
114			}
115		}
116
117		/// <summary>
118		/// Occurs when at least one device that the applet supports (as indicated by <see cref="Capabilities"/>)
119		/// arrives in the system. A device arrival can also be triggered when the user enables a device that
120		/// was previously disabled.
121		/// Note that this event is raised in the context of a thread within the library.
122		/// Therefore, take the necessary precautions for thread safety.
123		/// </summary>
124		public event EventHandler<LcdDeviceTypeEventArgs> DeviceArrival;
125
126		/// <summary>
127		/// Occurs when the user disables all devices of a given type, or when all physical devices of a given
128		/// type have been unplugged.
129		/// Note that this event is raised in the context of a thread within the library.
130		/// Therefore, take the necessary precautions for thread safety.
131		/// </summary>
132		public event EventHandler<LcdDeviceTypeEventArgs> DeviceRemoval;
133
134		/// <summary>
135		/// Occurs when the applet is enabled or disabled using the Progams configuration panel on the LCD Manager
136		/// (LCDMon) application program. The global enable and disable functions are initiated by the user on this
137		/// configuration screen.
138		/// Note that this event is raised in the context of a thread within the library.
139		/// Therefore, take the necessary precautions for thread safety.
140		/// </summary>
141		public event EventHandler IsEnabledChanged;
142
143		/// <summary>
144		/// Occurs when the appletÂ’s connection to the LCD Manager application is disrupted for any reason.
145		/// Note that this event is raised in the context of a thread within the library.
146		/// Therefore, take the necessary precautions for thread safety.
147		/// </summary>
148		public event EventHandler ConnectionDisrupted;
149
150		/// <summary>
151		/// Raises the <see cref="Configure"/> event.
152		/// </summary>
153		protected virtual void OnConfigure() {
154			EventHandler configure = _configure;
155			if (configure != null)
156				configure(this, EventArgs.Empty);
157		}
158
159		/// <summary>
160		/// Raises the <see cref="DeviceArrival"/> event.
161		/// </summary>
162		/// <param name="deviceType">The device type that has arrived.</param>
163		protected virtual void OnDeviceArrival(LcdDeviceType deviceType) {
164			EventHandler<LcdDeviceTypeEventArgs> handler = DeviceArrival;
165			if (handler != null)
166				handler(this, new LcdDeviceTypeEventArgs(deviceType));
167		}
168
169		/// <summary>
170		/// Raises the <see cref="DeviceRemoval"/> event.
171		/// </summary>
172		/// <param name="deviceType">The device type that was removed.</param>
173		protected virtual void OnDeviceRemoval(LcdDeviceType deviceType) {
174			EventHandler<LcdDeviceTypeEventArgs> handler = DeviceRemoval;
175			if (handler != null)
176				handler(this, new LcdDeviceTypeEventArgs(deviceType));
177		}
178
179		/// <summary>
180		/// Raises the <see cref="IsEnabledChanged"/> event.
181		/// </summary>
182		protected virtual void OnIsEnabledChanged() {
183			EventHandler handler = IsEnabledChanged;
184			if (handler != null)
185				handler(this, EventArgs.Empty);
186		}
187
188		/// <summary>
189		/// Raises the <see cref="ConnectionDisrupted"/> event.
190		/// </summary>
191		protected virtual void OnConnectionDisrupted() {
192			EventHandler handler = ConnectionDisrupted;
193			if (handler != null)
194				handler(this, EventArgs.Empty);
195		}
196
197		#endregion
198        
199
200		#region Verifications
201
202		/// <summary>
203		/// Ensures that we are connected; throw an exception otherwise.
204		/// </summary>
205		private void VerifyConnected() {
206			VerifyValid();
207			if (!IsConnected)
208				throw new InvalidOperationException("The applet must be connected to call this method.");
209		}
210
211		/// <summary>
212		/// Ensures that we are not connected yet; throw an exception otherwise.
213		/// </summary>
214		private void VerifyNotConnected() {
215			VerifyValid();
216			if (IsConnected)
217				throw new InvalidOperationException("You can only change members of this class before Connect() is called.");
218		}
219
220		/// <summary>
221		/// Ensures that the object is not disposed.
222		/// </summary>
223		private void VerifyValid() {
224			if (_isDisposed)
225				throw new InvalidOperationException("This method cannot be called after the applet has been disposed.");
226		}
227
228		#endregion
229
230
231		/// <summary>
232		/// Establishes a connection to the LCD monitor process.
233		/// </summary>
234		public void Connect() {
235			VerifyNotConnected();
236			EventHandler configureHandler = _configure;
237			SafeNativeMethods.LgLcdConnectContextEx context = new SafeNativeMethods.LgLcdConnectContextEx {
238				AppFriendlyName = _friendlyName,
239				IsPersistent = false,
240				IsAutoStartable = _isAutoStartable,
241				ConfigCallback = configureHandler != null ? _configCallback : null,
242				ConfigContext = IntPtr.Zero,
243				Connection = -1,
244				AppletCapabilitiesSupported = _capabilities,
245				Reserved = 0,
246				NotificationCallback = _notificationCallback,
247				NotificationContext = IntPtr.Zero
248			};
249			_connectionNumber = SafeNativeMethods.LgLcdConnectEx(context);
250		}
251
252		/// <summary>
253		/// Close an existing connection to the LCD monitor process.
254		/// </summary>
255		public void Disconnect() {
256			VerifyConnected();
257			Dispose();
258		}
259
260		/// <summary>
261		/// Opens a device of a given type.
262		/// This function is generally called after a <see cref="DeviceArrival" /> event has been received.
263		/// </summary>
264		/// <param name="deviceType">Type of the device to open.</param>
265		public LcdDevice OpenDeviceByType(LcdDeviceType deviceType) {
266			VerifyConnected();
267			switch (deviceType) {
268				case LcdDeviceType.Monochrome:
269					return new LcdDeviceMonochrome(this);
270				case LcdDeviceType.Qvga:
271					return new LcdDeviceQvga(this);
272				default:
273					throw new NotSupportedException(deviceType + " is not a supported device type.");
274			}
275		}
276
277		private int ConfigCallback(int connection, IntPtr context) {
278			OnConfigure();
279			return 0;
280		}
281
282		private int NotificationCallback(int connection, IntPtr context, SafeNativeMethods.NotificationCode notificationCode, int param1, int param2, int param3, int param4) {
283			switch (notificationCode) {
284				case SafeNativeMethods.NotificationCode.DeviceArrival:
285					OnDeviceArrival((LcdDeviceType) param1);
286					break;
287				case SafeNativeMethods.NotificationCode.DeviceRemoval:
288					OnDeviceRemoval((LcdDeviceType) param1);
289					break;
290				case SafeNativeMethods.NotificationCode.AppletEnabled:
291					_isEnabled = true;
292					OnIsEnabledChanged();
293					break;
294				case SafeNativeMethods.NotificationCode.AppletDisabled:
295					_isEnabled = false;
296					OnIsEnabledChanged();
297					break;
298                case SafeNativeMethods.NotificationCode.CloseConnection:
299					_connectionNumber = -1;
300					OnConnectionDisrupted();
301					break;
302			}
303			return 0;
304		}
305
306
307		#region IDisposable
308
309		/// <summary>
310		/// Releases the resources associated with this <see cref="LcdApplet"/>.
311		/// </summary>
312		public void Dispose() {
313			Dispose(true);
314			GC.SuppressFinalize(this);
315		}
316
317		/// <summary>
318		/// Releases the resources associated with this <see cref="LcdApplet"/>.
319		/// </summary>
320		/// <param name="disposing">Whether to also release managed resources along with unmanaged ones.</param>
321		protected virtual void Dispose(bool disposing) {
322			if (disposing && !_isDisposed) {
323				_configure = null;
324				if (_connectionNumber != -1) {
325					SafeNativeMethods.LgLcdDisconnect(_connectionNumber);
326					_connectionNumber = -1;
327				}
328				_isDisposed = true;
329				if (Interlocked.Decrement(ref _initCount) == 0)
330					SafeNativeMethods.LgLcdDeInit();
331			}
332		}
333
334		#endregion
335
336        
337		#region Constructors
338
339		/// <summary>
340		/// Creates a new instance of <see cref="LcdApplet"/> that support both monochrome and QVGA devices.
341		/// </summary>
342		public LcdApplet()
343			: this(String.Empty, LcdAppletCapabilities.Both, false) {
344		}
345
346		/// <summary>
347		/// Creates a new instance of <see cref="LcdApplet"/> that support both monochrome and QVGA devices,
348		/// with the specified friendly name.
349		/// </summary>
350		/// <param name="friendlyName">Friendly name of the applet that is displayed in LCD Monitor.</param>
351		public LcdApplet(string friendlyName)
352			: this(friendlyName, LcdAppletCapabilities.Both, false) {
353		}
354
355		/// <summary>
356		/// Creates a new instance of <see cref="LcdApplet"/> with the specified friendly name and capabilities.
357		/// </summary>
358		/// <param name="friendlyName">Friendly name of the applet that is displayed in LCD Monitor.</param>
359		/// <param name="capabilities">Gets or sets the capabilities that this applet supports.</param>
360		public LcdApplet(string friendlyName, LcdAppletCapabilities capabilities)
361			: this(friendlyName, capabilities, false) {
362		}
363
364		/// <summary>
365		/// Creates a new instance of <see cref="LcdApplet"/> with the specified friendly name, capabilities and auto-startable flag.
366		/// </summary>
367		/// <param name="friendlyName">Friendly name of the applet that is displayed in LCD Monitor.</param>
368		/// <param name="capabilities">Gets or sets the capabilities that this applet supports.</param>
369		/// <param name="isAutoStartable">Whether this applet has the option to be auto-startable.</param>
370		public LcdApplet(string friendlyName, LcdAppletCapabilities capabilities, bool isAutoStartable) {
371			if (friendlyName == null)
372				throw new ArgumentNullException("friendlyName");
373			new LgLcdPermission(PermissionState.Unrestricted).Demand();
374			if (Interlocked.Increment(ref _initCount) == 1)
375				SafeNativeMethods.LgLcdInit();
376			_friendlyName = friendlyName;
377			_isAutoStartable = isAutoStartable;
378			_capabilities = capabilities;
379			_configCallback = ConfigCallback;
380			_notificationCallback = NotificationCallback;
381		}
382
383		#endregion
384
385
386	}
387
388}