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