ensure that the tray app only initialises once. bugzid: 2082
[deb_libcec.git] / src / LibCecTray / controller / CECController.cs
CommitLineData
f017f3c4
LOK
1/*
2 * This file is part of the libCEC(R) library.
3 *
16f47961 4 * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited. All rights reserved.
f017f3c4
LOK
5 * libCEC(R) is an original work, containing original code.
6 *
7 * libCEC(R) is a trademark of Pulse-Eight Limited.
8 *
9 * This program is dual-licensed; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 *
23 *
24 * Alternatively, you can license this library under a commercial license,
25 * please contact Pulse-Eight Licensing for more information.
26 *
27 * For more information contact:
28 * Pulse-Eight Licensing <license@pulse-eight.com>
29 * http://www.pulse-eight.com/
30 * http://www.pulse-eight.net/
31 */
32
33using System;
34using System.Collections.Generic;
35using System.Windows.Forms;
36using CecSharp;
37using LibCECTray.Properties;
38using LibCECTray.controller.applications;
39using LibCECTray.settings;
40using LibCECTray.ui;
41
42namespace LibCECTray.controller
43{
44 internal class CECController : CecCallbackMethods
45 {
46 public CECController(CECTray gui)
47 {
48 _gui = gui;
49 CECActions = new Actions(this);
50
51 InitialiseGui();
52
53 Settings.SettingChanged += OnSettingChanged;
54 }
55
56 #region Settings
57 /// <summary>
58 /// Called when a setting changed
59 /// </summary>
60 /// <param name="setting">The setting that changed</param>
61 /// <param name="oldValue">The old value</param>
62 /// <param name="newValue">The new value</param>
63 private void OnSettingChanged(CECSetting setting, object oldValue, object newValue)
64 {
65 if (setting.KeyName == CECSettings.KeyHDMIPort)
66 {
67 CECSettingByte byteSetting = setting as CECSettingByte;
68 if (byteSetting != null)
69 {
70 if (!Settings.OverridePhysicalAddress.Value)
71 Config.HDMIPort = byteSetting.Value;
72 CECActions.SetConnectedDevice(Settings.ConnectedDevice.Value, byteSetting.Value);
73 }
74 }
75 else if (setting.KeyName == CECSettings.KeyConnectedToHDMIDevice)
76 {
77 CECSettingLogicalAddress laSetting = setting as CECSettingLogicalAddress;
78 if (laSetting != null)
79 {
80 if (!Settings.OverridePhysicalAddress.Value)
81 Config.BaseDevice = laSetting.Value;
82 CECActions.SetConnectedDevice(laSetting.Value, Settings.HDMIPort.Value);
83 }
84 }
85 else if (setting.KeyName == CECSettings.KeyPhysicalAddress)
86 {
87 CECSettingUShort ushortSetting = setting as CECSettingUShort;
88 if (ushortSetting != null && Settings.OverridePhysicalAddress.Value && Config.PhysicalAddress != ushortSetting.Value)
89 {
90 Config.PhysicalAddress = ushortSetting.Value;
91 CECActions.SetPhysicalAddress(ushortSetting.Value);
92 }
93 }
94 else if (setting.KeyName == CECSettings.KeyOverridePhysicalAddress)
95 {
96 CECSettingBool boolSetting = setting as CECSettingBool;
97 if (boolSetting != null)
98 {
99 Settings.PhysicalAddress.Enabled = boolSetting.Value;
100 Settings.HDMIPort.Enabled = !boolSetting.Value;
101 Settings.ConnectedDevice.Enabled = !boolSetting.Value;
102 if (boolSetting.Value)
103 {
104 Config.BaseDevice = Settings.ConnectedDevice.Value;
105 Config.HDMIPort = 0;
106 Config.PhysicalAddress = Settings.PhysicalAddress.Value;
107 }
108 else
109 {
110 Config.BaseDevice = Settings.ConnectedDevice.Value;
111 Config.HDMIPort = Settings.HDMIPort.Value;
112 Config.PhysicalAddress = 0xFFFF;
113 }
114 }
115 }
116 else if (setting.KeyName == CECSettings.KeyDeviceType)
117 {
118 CECSettingDeviceType dtSetting = setting as CECSettingDeviceType;
119 if (dtSetting != null)
120 {
121 if (dtSetting.Value != Config.DeviceTypes.Types[0] && Settings.OverrideTVVendor.Value)
122 {
123 Config.DeviceTypes.Types[0] = dtSetting.Value;
124 if (!_deviceChangeWarningDisplayed)
125 {
126 _deviceChangeWarningDisplayed = true;
127 MessageBox.Show(Resources.device_type_changed, Resources.app_name, MessageBoxButtons.OK,
128 MessageBoxIcon.Warning);
129 }
130 }
131 }
132 }
133 else if (setting.KeyName == CECSettings.KeyOverrideTVVendor)
134 {
135 CECSettingBool boolSetting = setting as CECSettingBool;
136 if (boolSetting != null)
137 {
138 Settings.TVVendor.Enabled = boolSetting.Value;
139 Settings.TVVendor.Value = boolSetting.Value ? Lib.GetDeviceVendorId(CecLogicalAddress.Tv) : CecVendorId.Unknown;
140 Config.TvVendor = boolSetting.Value ? Settings.TVVendor.Value : CecVendorId.Unknown;
141 }
142 }
143 else if (setting.KeyName == CECSettings.KeyActivateSource)
144 {
145 CECSettingBool boolSetting = setting as CECSettingBool;
146 if (boolSetting != null)
147 Config.ActivateSource = boolSetting.Value;
148 }
149 else if (setting.KeyName == CECSettings.KeyTVVendor)
150 {
151 CECSettingVendorId vendorSetting = setting as CECSettingVendorId;
152 if (vendorSetting != null && Settings.OverrideTVVendor.Value)
153 Config.TvVendor = vendorSetting.Value;
154 }
155 else if (setting.KeyName == CECSettings.KeyWakeDevices)
156 {
157 CECSettingLogicalAddresses laSetting = setting as CECSettingLogicalAddresses;
158 if (laSetting != null)
159 Config.WakeDevices = laSetting.Value;
160 }
161 else if (setting.KeyName == CECSettings.KeyPowerOffDevices)
162 {
163 CECSettingLogicalAddresses laSetting = setting as CECSettingLogicalAddresses;
164 if (laSetting != null)
165 Config.PowerOffDevices = laSetting.Value;
166 }
167 }
168
169 /// <summary>
170 /// Persist all known settings in the registry
171 /// </summary>
172 public void PersistSettings()
173 {
174 /* save settings in the eeprom */
175 Lib.SetConfiguration(Config);
176 Lib.PersistConfiguration(Config);
177
178 /* and in the registry */
179 Settings.Persist();
180 }
181
182 /// <summary>
183 /// Reset all settings to their default values
184 /// </summary>
185 public void ResetDefaultSettings()
186 {
187 SetControlsEnabled(false);
188 _gui.ShowHideAdvanced(false);
189
190 CECActions.SuppressUpdates = true;
191 Settings.SetDefaultValues();
192 _config = null;
193 Lib.SetConfiguration(Config);
194 CECActions.SuppressUpdates = false;
195
196 _gui.ShowHideAdvanced(Settings.AdvancedMode.Value);
197 SetControlsEnabled(true);
198 }
199 #endregion
200
201 /// <summary>
202 /// Opens a connection to libCEC and register known applications
203 /// </summary>
204 public void Initialise()
205 {
28fbb193
LOK
206 // only load once
207 if (_initialised)
208 return;
209 _initialised = true;
210
f017f3c4
LOK
211 CECActions.ConnectToDevice(Config);
212 Applications.Initialise(this);
213 }
214
215 /// <summary>
216 /// Closes the connection to libCEC
217 /// </summary>
218 public void Close()
219 {
220 Lib.DisableCallbacks();
221 Lib.StandbyDevices(CecLogicalAddress.Broadcast);
222 Lib.Close();
28fbb193 223 _initialised = false;
f017f3c4
LOK
224 }
225
226 /// <summary>
227 /// Register a new application controller, which will add a new tab for the application
228 /// </summary>
229 /// <param name="app">The new application to register</param>
230 /// <returns>True when registered, false otherwise</returns>
231 public bool RegisterApplication(ApplicationController app)
232 {
233 if (_applications.Contains(app)) return false;
234 _applications.Add(app);
235
236 _gui.SuspendLayout();
237 _gui.TabControls.Add(app.UiControl);
238 _gui.ResumeLayout();
239
240 app.Initialise();
241
242 return true;
243 }
244
245 #region GUI controls
246 /// <summary>
247 /// Initialises the UI
248 /// </summary>
249 private void InitialiseGui()
250 {
251 _gui.SuspendLayout();
252 _gui.InitialiseSettingsComponent(Settings);
253
254 // add the controller tabs to the gui
255 foreach (var ui in ApplicationUIs)
256 _gui.TabControls.Add(ui);
257
258 // enable/disable advanced mode
259 _gui.ShowHideAdvanced(Settings.AdvancedMode.Value);
260
261 _gui.ResumeLayout();
262 }
263
264 /// <summary>
265 /// Display a dialog
266 /// </summary>
267 /// <param name="control">The dialog to display</param>
268 /// <param name="modal">True when modal</param>
269 public void DisplayDialog(Form control, bool modal)
270 {
271 _gui.DisplayDialog(control, modal);
272 }
273
274 /// <summary>
275 /// Changes the status text of this window
276 /// </summary>
277 /// <param name="status">The new status text</param>
278 public void SetStatusText(string status)
279 {
280 _gui.SetStatusText(status);
281 }
282
283 /// <summary>
284 /// Changes the progress bar value
285 /// </summary>
286 /// <param name="progress">The new progress percentage</param>
287 /// <param name="visible">True to make the bar visible, false otherwise</param>
288 public void SetProgressBar(int progress, bool visible)
289 {
290 _gui.SetProgressBar(progress, visible);
291 }
292
293 /// <summary>
294 /// Enable/disable all controls
295 /// </summary>
296 /// <param name="val">True to enable, false to disable</param>
297 public void SetControlsEnabled(bool val)
298 {
299 Settings.Enabled = val;
300 foreach (var app in _applications)
301 app.UiControl.SetEnabled(val);
302 _gui.SetControlsEnabled(val);
303 }
304
305 /// <summary>
306 /// (re)check the logical addresses of the active devices on the bus
307 /// </summary>
308 public void CheckActiveDevices()
309 {
310 var activeDevices = Lib.GetActiveDevices();
311 List<string> deviceList = new List<string>();
312 foreach (var activeDevice in activeDevices.Addresses)
313 {
314 if (activeDevice != CecLogicalAddress.Unknown)
315 deviceList.Add(string.Format("{0,1:X} : {1}", (int)activeDevice, Lib.ToString(activeDevice)));
316 }
317 deviceList.Add(string.Format("{0,1:X} : {1}", (int)CecLogicalAddress.Broadcast, Lib.ToString(CecLogicalAddress.Broadcast)));
318
319 _gui.SetActiveDevices(deviceList.ToArray());
320 }
321
322 /// <summary>
323 /// Show/hide the taskbar entry
324 /// </summary>
325 /// <param name="val">True to show, false to hide</param>
326 public void SetShowInTaskbar(bool val)
327 {
328 _gui.SetShowInTaskbar(val);
329 }
330
331 /// <summary>
332 /// Show or hide this window
333 /// </summary>
334 /// <param name="val">True to show, false to hide</param>
335 public void Hide(bool val)
336 {
337 _gui.SafeHide(val);
338 }
339 #endregion
340
341 #region Callbacks called by libCEC
342 public override int ReceiveCommand(CecCommand command)
343 {
344 return 0;
345 }
346
347 public override int ReceiveKeypress(CecKeypress key)
348 {
349 foreach (var app in _applications)
350 {
351 bool keySent = app.SendKey(key, app.UiName == _gui.SelectedTabName);
352
353 if (keySent)
354 {
355 string strLog = string.Format("sent key '{0}' to '{1}'", (int) key.Keycode, app.UiName) + Environment.NewLine;
356 _gui.AddLogMessage(strLog);
357 break;
358 }
359 }
360
361 return 1;
362 }
363
364 public override int ReceiveLogMessage(CecLogMessage message)
365 {
366 _gui.AddLogMessage(message);
367 return 1;
368 }
369
370 public override int ConfigurationChanged(LibCECConfiguration config)
371 {
372 Settings.PhysicalAddress.Value = Config.PhysicalAddress;
373 Settings.ConnectedDevice.Value = Config.BaseDevice == CecLogicalAddress.AudioSystem ? CecLogicalAddress.AudioSystem : CecLogicalAddress.Tv;
374 Settings.HDMIPort.Value = Config.HDMIPort;
375 Settings.WakeDevices.Value = Config.WakeDevices;
376 Settings.PowerOffDevices.Value = Config.PowerOffDevices;
377 Settings.ActivateSource.Value = Config.ActivateSource;
378 Settings.DeviceType.Value = config.DeviceTypes.Types[0];
379
380 if (config.TvVendor != CecVendorId.Unknown)
381 {
382 Settings.OverrideTVVendor.Value = true;
383 Settings.TVVendor.Value = config.TvVendor;
384 }
385 else
386 {
387 Settings.OverrideTVVendor.Value = false;
388 }
389
390 _gui.SetControlText(_gui, Resources.app_name + " - libCEC " + Lib.ToString(Config.ServerVersion));
391
392 CECActions.UpdatePhysicalAddress();
393 return 1;
394 }
395
396 public override void SourceActivated(CecLogicalAddress logicalAddress, bool activated)
397 {
398 if (!activated)
399 return;
400
401 foreach (var app in _applications)
402 {
403 if (app.AutoStartApplication.Value)
404 app.Start(false);
405 }
406 }
407 #endregion
408
409 #region Members
410 /// <summary>
411 /// List of tab pages for each application that the UI supports
412 /// </summary>
413 public List<ControllerTabPage> ApplicationUIs
414 {
415 get
416 {
417 List<ControllerTabPage> retVal = new List<ControllerTabPage>();
418 foreach (var app in _applications)
419 retVal.Add(app.UiControl);
420 return retVal;
421 }
422 }
423
424 /// <summary>
425 /// List of application controllers that the UI supports
426 /// </summary>
427 private readonly List<ApplicationController> _applications = new List<ApplicationController>();
428
429 /// <summary>
430 /// Settings that are persisted in the registry (when not using the default value)
431 /// </summary>
432 public CECSettings Settings
433 {
434 get { return _settings ?? (_settings = new CECSettings(OnSettingChanged)); }
435 }
436 private CECSettings _settings;
437
438 /// <summary>
439 /// libCEC configuration for the application
440 /// </summary>
441 private LibCECConfiguration Config
442 {
443 get
444 {
445 if (_config == null)
446 {
9b56a19a 447 _config = new LibCECConfiguration { DeviceName = "CEC Tray", ClientVersion = CecClientVersion.Version2_1_0 };
f017f3c4
LOK
448 _config.DeviceTypes.Types[0] = CecDeviceType.RecordingDevice;
449 _config.SetCallbacks(this);
450
451 if (Settings.OverridePhysicalAddress.Value)
452 {
453 _config.PhysicalAddress = Settings.PhysicalAddress.Value;
454 _config.HDMIPort = 0;
455 _config.BaseDevice = CecLogicalAddress.Unknown;
456 }
457 else
458 {
459 _config.PhysicalAddress = 0;
460 _config.HDMIPort = Settings.HDMIPort.Value;
461 _config.BaseDevice = Settings.ConnectedDevice.Value;
462 }
463 _config.ActivateSource = Settings.ActivateSource.Value;
464 _config.DeviceTypes.Types[0] = Settings.DeviceType.Value;
465 if (Settings.OverrideTVVendor.Value)
466 _config.TvVendor = Settings.TVVendor.Value;
467 _config.WakeDevices = Settings.WakeDevices.Value;
468 _config.PowerOffDevices = Settings.PowerOffDevices.Value;
469 }
470 return _config;
471 }
472 }
473 private LibCECConfiguration _config;
474
475 /// <summary>
476 /// Get build info from libCEC
477 /// </summary>
478 public string LibInfo
479 {
480 get { return Lib.GetLibInfo(); }
481 }
482
483 /// <summary>
484 /// libCEC API version
485 /// </summary>
486 public string LibServerVersion
487 {
488 get { return Lib.ToString(Config.ServerVersion); }
489 }
490
491 /// <summary>
492 /// libCEC client API version
493 /// </summary>
494 public string LibClientVersion
495 {
496 get { return Lib.ToString(Config.ClientVersion); }
497 }
498
5156a42c
LOK
499 /// <summary>
500 /// Get the usb vendor id
501 /// </summary>
502 public ushort AdapterVendorId
503 {
504 get { return Lib.GetAdapterVendorId(); }
505 }
506
507 /// <summary>
508 /// Get the usb product id
509 /// </summary>
510 public ushort AdapterProductId
511 {
512 get { return Lib.GetAdapterProductId(); }
513 }
514
515
f017f3c4
LOK
516 /// <summary>
517 /// libCEC
518 /// </summary>
519 public LibCecSharp Lib
520 {
521 get { return _lib ?? (_lib = new LibCecSharp(Config)); }
522 }
523 private LibCecSharp _lib;
524
525 private readonly CECTray _gui;
526 public Actions CECActions;
527 private bool _deviceChangeWarningDisplayed;
28fbb193 528 private bool _initialised;
f017f3c4
LOK
529
530 #endregion
531 }
532}