Imported Upstream version 2.2.0
[deb_libcec.git] / src / LibCecTray / controller / applications / internal / XBMCController.cs
CommitLineData
cbbe90dd
JB
1/*
2 * This file is part of the libCEC(R) library.
3 *
4 * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited. All rights reserved.
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.Globalization;
35using System.IO;
36using System.Text;
37using System.Windows.Forms;
38using System.Xml;
39using CecSharp;
40using LibCECTray.Properties;
41using LibCECTray.settings;
42
43namespace LibCECTray.controller.applications.@internal
44{
45 internal class XBMCController : ApplicationController
46 {
47 public XBMCController(CECController controller) :
48 base(controller,
49 Resources.application_xbmc,
50 "XBMC",
51 "XBMC.exe",
52 Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + @"\XBMC")
53 {
54 IsInternal = true;
55 AutoStartApplication.Value = false;
56 ControlApplication.Value = false;
57
58 LoadXMLConfiguration();
59
60 ApplicationRunningChanged += RunningChanged;
61 }
62
63 static void RunningChanged(bool running)
64 {
65 if (running)
66 {
67 // XBMC is running, close the application, or we'll block communication
68 Application.Exit();
69 }
70 }
71
72 public override ApplicationAction DefaultValue(CecKeypress key)
73 {
74 return null;
75 }
76
77 public override ControllerTabPage UiControl
78 {
79 get { return UIControlInternal ?? (UIControlInternal = new XBMCControllerUI(this)); }
80 }
81
82 public bool LoadXMLConfiguration()
83 {
84 var xbmcDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\XBMC\userdata\peripheral_data";
85 return LoadXMLConfiguration(xbmcDir + string.Format(@"\usb_{0:X}_{1:X}.xml", Program.Instance.Controller.AdapterVendorId, Program.Instance.Controller.AdapterProductId)) ||
86 LoadXMLConfiguration(xbmcDir + @"\usb_2548_1001.xml") ||
87 LoadXMLConfiguration(xbmcDir + @"\usb_2548_1002.xml");
88 }
89
90 public bool LoadXMLConfiguration(string filename)
91 {
92 bool gotConfig = false;
93 if (File.Exists(filename))
94 {
95 XmlTextReader reader = new XmlTextReader(filename);
96 while (true)
97 {
98 try
99 {
100 if (!reader.Read())
101 break;
102 } catch (XmlException) {}
103 gotConfig = true;
104 switch (reader.NodeType)
105 {
106 case XmlNodeType.Element:
107 if (reader.Name.ToLower() == "setting")
108 {
109 string name = string.Empty;
110 string value = string.Empty;
111
112 while (reader.MoveToNextAttribute())
113 {
114 if (reader.Name.ToLower().Equals("id"))
115 name = reader.Value.ToLower();
116 if (reader.Name.ToLower().Equals("value"))
117 value = reader.Value;
118 }
119
120 switch (name)
121 {
122 case "cec_hdmi_port":
123 {
124 byte iPort;
125 if (byte.TryParse(value, out iPort))
126 Settings.HDMIPort.Value = iPort;
127 }
128 break;
129 case "connected_device":
130 {
131 int iDevice;
132 if (int.TryParse(value, out iDevice))
133 Settings.ConnectedDevice.Value = iDevice == 36038 ? CecLogicalAddress.AudioSystem : CecLogicalAddress.Tv;
134 }
135 break;
136 case "cec_power_on_startup":
137 if (value.Equals("1") || value.ToLower().Equals("true") || value.ToLower().Equals("yes"))
138 {
139 Settings.ActivateSource.Value = true;
140 Settings.WakeDevices.Value.Set(CecLogicalAddress.Tv);
141 }
142 break;
143 case "cec_power_off_shutdown":
144 if (value.Equals("1") || value.ToLower().Equals("true") || value.ToLower().Equals("yes"))
145 Settings.PowerOffDevices.Value.Set(CecLogicalAddress.Broadcast);
146 break;
147 case "cec_standby_screensaver":
148 StandbyScreensaver.Value = value.Equals("1") || value.ToLower().Equals("true") || value.ToLower().Equals("yes");
149 break;
150 case "standby_pc_on_tv_standby":
151 PowerOffOnStandby.Value = value.Equals("1") || value.ToLower().Equals("true") || value.ToLower().Equals("yes");
152 break;
153 case "use_tv_menu_language":
154 UseTVLanguage.Value = value.Equals("1") || value.ToLower().Equals("true") || value.ToLower().Equals("yes");
155 break;
156 // 1.5.0+ settings
157 case "physical_address":
158 {
159 ushort physicalAddress;
160 if (ushort.TryParse(value, NumberStyles.AllowHexSpecifier, null, out physicalAddress))
161 Settings.PhysicalAddress.Value = physicalAddress;
162 }
163 break;
164 case "device_type":
165 {
166 ushort iType;
167 if (ushort.TryParse(value, out iType))
168 Settings.DeviceType.Value = (CecDeviceType)iType;
169 }
170 break;
171 case "tv_vendor":
172 {
173 UInt64 iVendor;
174 if (UInt64.TryParse(value, out iVendor))
175 Settings.TVVendor.Value = (CecVendorId)iVendor;
176 }
177 break;
178 case "wake_device":
179 {
180 int iWakeDevices;
181 if (int.TryParse(value, out iWakeDevices))
182 {
183 Settings.WakeDevices.Value.Clear();
184 switch (iWakeDevices)
185 {
186 case 36037:
187 Settings.WakeDevices.Value.Set(CecLogicalAddress.Tv);
188 break;
189 case 36038:
190 Settings.WakeDevices.Value.Set(CecLogicalAddress.AudioSystem);
191 break;
192 case 36039:
193 Settings.WakeDevices.Value.Set(CecLogicalAddress.Tv);
194 Settings.WakeDevices.Value.Set(CecLogicalAddress.AudioSystem);
195 break;
196 }
197 }
198 }
199 break;
200 case "wake_devices_advanced":
201 {
202 Settings.WakeDevices.Value.Clear();
203 string[] split = value.Split(new[] { ' ' });
204 foreach (string dev in split)
205 {
206 byte iLogicalAddress;
207 if (byte.TryParse(dev, out iLogicalAddress))
208 Settings.WakeDevices.Value.Set((CecLogicalAddress)iLogicalAddress);
209 }
210 }
211 break;
212 case "standby_devices":
213 {
214 int iStandbyDevices;
215 if (int.TryParse(value, out iStandbyDevices))
216 {
217 Settings.PowerOffDevices.Value.Clear();
218 switch (iStandbyDevices)
219 {
220 case 36037:
221 Settings.PowerOffDevices.Value.Set(CecLogicalAddress.Tv);
222 break;
223 case 36038:
224 Settings.PowerOffDevices.Value.Set(CecLogicalAddress.AudioSystem);
225 break;
226 case 36039:
227 Settings.PowerOffDevices.Value.Set(CecLogicalAddress.Tv);
228 Settings.PowerOffDevices.Value.Set(CecLogicalAddress.AudioSystem);
229 break;
230 }
231 }
232 }
233 break;
234 case "standby_devices_advanced":
235 {
236 Settings.PowerOffDevices.Value.Clear();
237 string[] split = value.Split(new[] { ' ' });
238 foreach (string dev in split)
239 {
240 byte iLogicalAddress;
241 if (byte.TryParse(dev, out iLogicalAddress))
242 Settings.PowerOffDevices.Value.Set((CecLogicalAddress)iLogicalAddress);
243 }
244 }
245 break;
246 case "enabled":
247 break;
248 case "port":
249 //TODO
250 break;
251 // 1.5.1 settings
252 case "send_inactive_source":
253 SendInactiveSource.Value = value.Equals("1") || value.ToLower().Equals("true") || value.ToLower().Equals("yes");
254 break;
255 // 1.9.0+ settings
256 case "pause_playback_on_deactivate":
257 PausePlaybackOnDeactivate.Value = value.Equals("1") || value.ToLower().Equals("true") || value.ToLower().Equals("yes");
258 break;
259 }
260 }
261 break;
262 }
263 }
264 }
265 return gotConfig;
266 }
267
268 static bool HasAdvancedDeviceIdSet(CecLogicalAddresses addresses)
269 {
270 foreach (var val in addresses.Addresses)
271 if (val != CecLogicalAddress.Tv && val != CecLogicalAddress.AudioSystem)
272 return true;
273 return false;
274 }
275
276 public void SaveXMLConfiguration()
277 {
278 Settings.Persist();
279
280 var xbmcDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\XBMC\userdata\peripheral_data";
281 if (!Directory.Exists(xbmcDir))
282 Directory.CreateDirectory(xbmcDir);
283
284 if (!Directory.Exists(xbmcDir))
285 {
286 // couldn't create directory
287 MessageBox.Show(string.Format(Resources.could_not_create_directory, xbmcDir), Resources.error,
288 MessageBoxButtons.OK, MessageBoxIcon.Error);
289 return;
290 }
291
292 SaveFileDialog dialog = new SaveFileDialog
293 {
294 Title = Resources.store_settings_where,
295 InitialDirectory = xbmcDir,
296 FileName = string.Format("usb_{0:X}_{1:X}.xml", Program.Instance.Controller.AdapterVendorId, Program.Instance.Controller.AdapterProductId),
297 Filter = Resources.xml_file_filter,
298 FilterIndex = 1
299 };
300 if (dialog.ShowDialog() != DialogResult.OK) return;
301
302 FileStream fs = null;
303 string error = string.Empty;
304 try
305 {
306 fs = (FileStream)dialog.OpenFile();
307 }
308 catch (Exception ex)
309 {
310 error = ex.Message;
311 }
312 if (fs == null)
313 {
314 MessageBox.Show(string.Format(Resources.cannot_open_file, dialog.FileName) + (error.Length > 0 ? ": " + error : string.Empty), Resources.app_name, MessageBoxButtons.OK, MessageBoxIcon.Error);
315 }
316 else
317 {
318 StreamWriter writer = new StreamWriter(fs);
319 StringBuilder output = new StringBuilder();
320 output.AppendLine("<settings>");
321 output.AppendLine("<setting id=\"cec_hdmi_port\" value=\"" + Settings.HDMIPort.Value + "\" />");
322 output.AppendLine("<setting id=\"connected_device\" value=\"" + (Settings.ConnectedDevice.Value == CecLogicalAddress.AudioSystem ? 36038 : 36037) + "\" />");
323 output.AppendLine("<setting id=\"cec_power_on_startup\" value=\"" + (Settings.ActivateSource.Value ? 1 : 0) + "\" />");
324 output.AppendLine("<setting id=\"cec_power_off_shutdown\" value=\"" + (Settings.PowerOffDevices.Value.IsSet(CecLogicalAddress.Broadcast) ? 1 : 0) + "\" />");
325 output.AppendLine("<setting id=\"cec_standby_screensaver\" value=\"" + (StandbyScreensaver.Value ? 1 : 0) + "\" />");
326 output.AppendLine("<setting id=\"standby_pc_on_tv_standby\" value=\"" + (PowerOffOnStandby.Value ? 1 : 0) + "\" />");
327 output.AppendLine("<setting id=\"use_tv_menu_language\" value=\"" + (UseTVLanguage.Value ? 1 : 0) + "\" />");
328 output.AppendLine("<setting id=\"enabled\" value=\"1\" />");
329 output.AppendLine("<setting id=\"port\" value=\"\" />");
330
331 // only supported by 1.5.0+ clients
332 output.AppendLine("<!-- the following lines are only supported by v1.5.0+ clients -->");
333 output.AppendLine("<setting id=\"activate_source\" value=\"" + (Settings.ActivateSource.Value ? 1 : 0) + "\" />");
334 output.AppendLine("<setting id=\"physical_address\" value=\"" + string.Format("{0,4:X}", Settings.OverridePhysicalAddress.Value ? Settings.PhysicalAddress.Value : 0).Trim() + "\" />");
335 output.AppendLine("<setting id=\"device_type\" value=\"" + (int)Settings.DeviceType.Value + "\" />");
336 output.AppendLine("<setting id=\"tv_vendor\" value=\"" + string.Format("{0,6:X}", Settings.OverrideTVVendor.Value ? (int)Settings.TVVendor.Value : 0).Trim() + "\" />");
337
338 if (HasAdvancedDeviceIdSet(Settings.WakeDevices.Value))
339 {
340 output.Append("<setting id=\"wake_devices_advanced\" value=\"");
341 StringBuilder strWakeDevices = new StringBuilder();
342 foreach (CecLogicalAddress addr in Settings.WakeDevices.Value.Addresses)
343 if (addr != CecLogicalAddress.Unknown)
344 strWakeDevices.Append(" " + (int)addr);
345 output.Append(strWakeDevices.ToString().Trim());
346 output.AppendLine("\" />");
347 }
348
349 if (Settings.WakeDevices.Value.IsSet(CecLogicalAddress.Tv) &&
350 Settings.WakeDevices.Value.IsSet(CecLogicalAddress.AudioSystem))
351 output.Append("<setting id=\"wake_devices\" value=\"36039\">");
352 else if (Settings.WakeDevices.Value.IsSet(CecLogicalAddress.Tv))
353 output.Append("<setting id=\"wake_devices\" value=\"36037\">");
354 else if (Settings.WakeDevices.Value.IsSet(CecLogicalAddress.AudioSystem))
355 output.Append("<setting id=\"wake_devices\" value=\"36038\">");
356 else
357 output.Append("<setting id=\"wake_devices\" value=\"231\">");
358
359 if (HasAdvancedDeviceIdSet(Settings.PowerOffDevices.Value))
360 {
361 output.Append("<setting id=\"standby_devices_advanced\" value=\"");
362 StringBuilder strSleepDevices = new StringBuilder();
363 foreach (CecLogicalAddress addr in Settings.PowerOffDevices.Value.Addresses)
364 if (addr != CecLogicalAddress.Unknown)
365 strSleepDevices.Append(" " + (int) addr);
366 output.Append(strSleepDevices.ToString().Trim());
367 output.AppendLine("\" />");
368 }
369
370 if (Settings.PowerOffDevices.Value.IsSet(CecLogicalAddress.Tv) &&
371 Settings.PowerOffDevices.Value.IsSet(CecLogicalAddress.AudioSystem))
372 output.Append("<setting id=\"standby_devices\" value=\"36039\">");
373 else if (Settings.PowerOffDevices.Value.IsSet(CecLogicalAddress.Tv))
374 output.Append("<setting id=\"standby_devices\" value=\"36037\">");
375 else if (Settings.PowerOffDevices.Value.IsSet(CecLogicalAddress.AudioSystem))
376 output.Append("<setting id=\"standby_devices\" value=\"36038\">");
377 else
378 output.Append("<setting id=\"standby_devices\" value=\"231\">");
379
380 // only supported by 1.5.1+ clients
381 output.AppendLine("<!-- the following lines are only supported by v1.5.1+ clients -->");
382 output.AppendLine("<setting id=\"send_inactive_source\" value=\"" + (SendInactiveSource.Value ? 1 : 0) + "\" />");
383
384 // only supported by 1.9.0+ clients
385 output.AppendLine("<setting id=\"pause_playback_on_deactivate\" value=\"" + (PausePlaybackOnDeactivate.Value ? 1 : 0) + "\" />");
386
387 output.AppendLine("</settings>");
388 writer.Write(output.ToString());
389 writer.Close();
390 fs.Close();
391 fs.Dispose();
392 MessageBox.Show(Resources.settings_stored, Resources.app_name, MessageBoxButtons.OK, MessageBoxIcon.Information);
393 }
394 }
395
396 public CECSettingBool UseTVLanguage
397 {
398 get
399 {
400 if (!Settings.ContainsKey(ProcessName + "_use_tv_language"))
401 {
402 CECSettingBool setting = new CECSettingBool(ProcessName + "_use_tv_language", Resources.app_use_tv_language, true, null);
403 Settings.Load(setting);
404 Settings[ProcessName + "_use_tv_language"] = setting;
405 }
406 return Settings[ProcessName + "_use_tv_language"].AsSettingBool;
407 }
408 }
409
410 public CECSettingBool StandbyScreensaver
411 {
412 get
413 {
414 if (!Settings.ContainsKey(ProcessName + "_standby_screensaver"))
415 {
416 CECSettingBool setting = new CECSettingBool(ProcessName + "_standby_screensaver", Resources.app_standby_screensaver, true, null);
417 Settings.Load(setting);
418 Settings[ProcessName + "_standby_screensaver"] = setting;
419 }
420 return Settings[ProcessName + "_standby_screensaver"].AsSettingBool;
421 }
422 }
423
424 public CECSettingBool ActivateSource
425 {
426 get
427 {
428 if (!Settings.ContainsKey(ProcessName + "_activate_source"))
429 {
430 CECSettingBool setting = new CECSettingBool(ProcessName + "_activate_source", Resources.global_activate_source, true, null);
431 Settings.Load(setting);
432 Settings[ProcessName + "_activate_source"] = setting;
433 }
434 return Settings[ProcessName + "_activate_source"].AsSettingBool;
435 }
436 }
437
438 public CECSettingBool PowerOffOnStandby
439 {
440 get
441 {
442 if (!Settings.ContainsKey(ProcessName + "_standby_on_tv_standby"))
443 {
444 CECSettingBool setting = new CECSettingBool(ProcessName + "_standby_on_tv_standby", Resources.app_standby_on_tv_standby, true, null);
445 Settings.Load(setting);
446 Settings[ProcessName + "_standby_on_tv_standby"] = setting;
447 }
448 return Settings[ProcessName + "_standby_on_tv_standby"].AsSettingBool;
449 }
450 }
451
452 public CECSettingBool SendInactiveSource
453 {
454 get
455 {
456 if (!Settings.ContainsKey(ProcessName + "_send_inactive_source"))
457 {
458 CECSettingBool setting = new CECSettingBool(ProcessName + "_send_inactive_source", Resources.app_send_inactive_source, true, null);
459 Settings.Load(setting);
460 Settings[ProcessName + "_send_inactive_source"] = setting;
461 }
462 return Settings[ProcessName + "_send_inactive_source"].AsSettingBool;
463 }
464 }
465
466 public CECSettingBool PausePlaybackOnDeactivate
467 {
468 get
469 {
470 if (!Settings.ContainsKey(ProcessName + "_pause_playback_on_deactivate"))
471 {
472 CECSettingBool setting = new CECSettingBool(ProcessName + "_pause_playback_on_deactivate", Resources.app_pause_playback_on_deactivate, true, null);
473 Settings.Load(setting);
474 Settings[ProcessName + "_pause_playback_on_deactivate"] = setting;
475 }
476 return Settings[ProcessName + "_pause_playback_on_deactivate"].AsSettingBool;
477 }
478 }
479 }
480}