2 * This file is part of the libCEC(R) library.
4 * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited. All rights reserved.
5 * libCEC(R) is an original work, containing original code.
7 * libCEC(R) is a trademark of Pulse-Eight Limited.
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.
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.
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.
24 * Alternatively, you can license this library under a commercial license,
25 * please contact Pulse-Eight Licensing for more information.
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/
34 using System.Windows.Forms;
37 using LibCECTray.Properties;
38 using LibCECTray.controller;
39 using LibCECTray.controller.applications;
40 using LibCECTray.settings;
41 using Microsoft.Win32;
42 using System.Security.Permissions;
43 using System.Runtime.InteropServices;
45 namespace LibCECTray.ui
48 /// The tab pages in this application
50 internal enum ConfigTab
61 /// Main LibCecTray GUI
63 partial class CECTray : AsyncForm
67 Text = Resources.app_name;
68 InitializeComponent();
69 VisibleChanged += delegate
77 SystemEvents.SessionEnding += new SessionEndingEventHandler(OnSessionEnding);
80 public void OnSessionEnding(object sender, SessionEndingEventArgs e)
85 #region Power state change window messages
86 private const int WM_POWERBROADCAST = 0x0218;
87 private const int PBT_APMSUSPEND = 0x0004;
88 private const int PBT_APMRESUMESUSPEND = 0x0007;
89 private const int PBT_APMRESUMECRITICAL = 0x0006;
90 private const int PBT_APMRESUMEAUTOMATIC = 0x0012;
91 private const int PBT_POWERSETTINGCHANGE = 0x8013;
92 private static Guid GUID_SYSTEM_AWAYMODE = new Guid("98a7f580-01f7-48aa-9c0f-44352c29e5c0");
94 [StructLayout(LayoutKind.Sequential, Pack = 4)]
95 internal struct POWERBROADCAST_SETTING
97 public Guid PowerSetting;
98 public uint DataLength;
104 /// Check for power state changes, and pass up when it's something we don't care about
106 /// <param name="msg">The incoming window message</param>
107 protected override void WndProc(ref Message msg)
109 if (msg.Msg == WM_POWERBROADCAST)
111 switch (msg.WParam.ToInt32())
117 case PBT_APMRESUMESUSPEND:
118 case PBT_APMRESUMECRITICAL:
119 case PBT_APMRESUMEAUTOMATIC:
123 case PBT_POWERSETTINGCHANGE:
125 POWERBROADCAST_SETTING pwr = (POWERBROADCAST_SETTING)Marshal.PtrToStructure(msg.LParam, typeof(POWERBROADCAST_SETTING));
126 if (pwr.PowerSetting == GUID_SYSTEM_AWAYMODE && pwr.DataLength == Marshal.SizeOf(typeof(Int32)))
147 // pass up when not handled
148 base.WndProc(ref msg);
151 private void OnWake()
153 Controller.Initialise();
156 private void OnSleep()
161 public override sealed string Text
163 get { return base.Text; }
164 set { base.Text = value; }
167 public void Initialise()
169 Controller.Initialise();
172 protected override void Dispose(bool disposing)
179 if (disposing && (components != null))
181 components.Dispose();
183 base.Dispose(disposing);
186 #region Configuration tab
188 /// Replaces the gui controls by the ones that are bound to the settings.
189 /// this is a fugly way to do it, but the gui designer doesn't allow us to ref CECSettings, since it uses symbols from LibCecSharp
191 public void InitialiseSettingsComponent(CECSettings settings)
193 settings.WakeDevices.ReplaceControls(this, Configuration.Controls, lWakeDevices, cbWakeDevices);
194 settings.PowerOffDevices.ReplaceControls(this, Configuration.Controls, lPowerOff, cbPowerOffDevices);
195 settings.OverridePhysicalAddress.ReplaceControls(this, Configuration.Controls, cbOverrideAddress);
196 settings.OverrideTVVendor.ReplaceControls(this, Configuration.Controls, cbVendorOverride);
197 settings.PhysicalAddress.ReplaceControls(this, Configuration.Controls, tbPhysicalAddress);
198 settings.HDMIPort.ReplaceControls(this, Configuration.Controls, lPortNumber, cbPortNumber);
199 settings.ConnectedDevice.ReplaceControls(this, Configuration.Controls, lConnectedDevice, cbConnectedDevice);
200 settings.ActivateSource.ReplaceControls(this, Configuration.Controls, cbActivateSource);
201 settings.DeviceType.ReplaceControls(this, Configuration.Controls, lDeviceType, cbDeviceType);
202 settings.TVVendor.ReplaceControls(this, Configuration.Controls, cbVendorId);
203 settings.StartHidden.ReplaceControls(this, Configuration.Controls, cbStartMinimised);
206 private void BSaveClick(object sender, EventArgs e)
208 Controller.PersistSettings();
211 private void BReloadConfigClick(object sender, EventArgs e)
213 Controller.ResetDefaultSettings();
217 #region CEC Tester tab
218 delegate void SetActiveDevicesCallback(string[] activeDevices);
219 public void SetActiveDevices(string[] activeDevices)
221 if (cbCommandDestination.InvokeRequired)
223 SetActiveDevicesCallback d = SetActiveDevices;
226 Invoke(d, new object[] { activeDevices });
228 catch (Exception) { }
232 cbCommandDestination.Items.Clear();
233 foreach (string item in activeDevices)
234 cbCommandDestination.Items.Add(item);
238 delegate CecLogicalAddress GetTargetDeviceCallback();
239 private CecLogicalAddress GetTargetDevice()
241 if (cbCommandDestination.InvokeRequired)
243 GetTargetDeviceCallback d = GetTargetDevice;
244 CecLogicalAddress retval = CecLogicalAddress.Unknown;
247 retval = (CecLogicalAddress)Invoke(d, new object[] { });
249 catch (Exception) { }
253 return CECSettingLogicalAddresses.GetLogicalAddressFromString(cbCommandDestination.Text);
256 private void BSendImageViewOnClick(object sender, EventArgs e)
258 Controller.CECActions.SendImageViewOn(GetTargetDevice());
261 private void BStandbyClick(object sender, EventArgs e)
263 Controller.CECActions.SendStandby(GetTargetDevice());
266 private void BScanClick(object sender, EventArgs e)
268 Controller.CECActions.ShowDeviceInfo(GetTargetDevice());
271 private void BActivateSourceClick(object sender, EventArgs e)
273 Controller.CECActions.ActivateSource(GetTargetDevice());
276 private void CbCommandDestinationSelectedIndexChanged(object sender, EventArgs e)
278 bool enableVolumeButtons = (GetTargetDevice() == CecLogicalAddress.AudioSystem);
279 bVolUp.Enabled = enableVolumeButtons;
280 bVolDown.Enabled = enableVolumeButtons;
281 bMute.Enabled = enableVolumeButtons;
282 bActivateSource.Enabled = (GetTargetDevice() != CecLogicalAddress.Broadcast);
283 bScan.Enabled = (GetTargetDevice() != CecLogicalAddress.Broadcast);
286 private void BVolUpClick(object sender, EventArgs e)
288 Controller.Lib.VolumeUp(true);
291 private void BVolDownClick(object sender, EventArgs e)
293 Controller.Lib.VolumeDown(true);
296 private void BMuteClick(object sender, EventArgs e)
298 Controller.Lib.MuteAudio(true);
301 private void BRescanDevicesClick(object sender, EventArgs e)
303 Controller.CECActions.RescanDevices();
308 delegate void UpdateLogCallback();
309 private void UpdateLog()
311 if (tbLog.InvokeRequired)
313 UpdateLogCallback d = UpdateLog;
316 Invoke(d, new object[] { });
318 catch (Exception) { }
323 tbLog.Select(tbLog.Text.Length, 0);
324 tbLog.ScrollToCaret();
328 public void AddLogMessage(CecLogMessage message)
330 string strLevel = "";
331 bool display = false;
332 switch (message.Level)
334 case CecLogLevel.Error:
335 strLevel = "ERROR: ";
336 display = cbLogError.Checked;
338 case CecLogLevel.Warning:
339 strLevel = "WARNING: ";
340 display = cbLogWarning.Checked;
342 case CecLogLevel.Notice:
343 strLevel = "NOTICE: ";
344 display = cbLogNotice.Checked;
346 case CecLogLevel.Traffic:
347 strLevel = "TRAFFIC: ";
348 display = cbLogTraffic.Checked;
350 case CecLogLevel.Debug:
351 strLevel = "DEBUG: ";
352 display = cbLogDebug.Checked;
358 string strLog = string.Format("{0} {1,16} {2}", strLevel, message.Time, message.Message) + Environment.NewLine;
359 AddLogMessage(strLog);
363 public void AddLogMessage(string message)
367 if (_selectedTab == ConfigTab.Log)
371 private void BClearLogClick(object sender, EventArgs e)
377 private void BSaveLogClick(object sender, EventArgs e)
379 SaveFileDialog dialog = new SaveFileDialog
381 Title = Resources.where_do_you_want_to_store_the_log,
382 InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
383 FileName = Resources.cec_log_filename,
384 Filter = Resources.cec_log_filter,
388 if (dialog.ShowDialog() == DialogResult.OK)
390 FileStream fs = (FileStream)dialog.OpenFile();
393 MessageBox.Show(string.Format(Resources.cannot_open_for_writing, dialog.FileName), Resources.app_name, MessageBoxButtons.OK, MessageBoxIcon.Error);
397 StreamWriter writer = new StreamWriter(fs);
402 MessageBox.Show(string.Format(Resources.log_stored_as, dialog.FileName), Resources.app_name, MessageBoxButtons.OK, MessageBoxIcon.Information);
408 #region Tray icon and window controls
409 private void HideToolStripMenuItemClick(object sender, EventArgs e)
414 private void CloseToolStripMenuItemClick(object sender, EventArgs e)
419 private void AboutToolStripMenuItemClick(object sender, EventArgs e)
421 (new About(Controller.LibServerVersion, Controller.LibClientVersion, Controller.LibInfo)).ShowDialog();
424 private void AdvancedModeToolStripMenuItemClick(object sender, EventArgs e)
426 Controller.Settings.AdvancedMode.Value = !advancedModeToolStripMenuItem.Checked;
427 ShowHideAdvanced(!advancedModeToolStripMenuItem.Checked);
430 private void BCancelClick(object sender, EventArgs e)
435 private void TrayIconClick(object sender, EventArgs e)
437 if (e is MouseEventArgs && (e as MouseEventArgs).Button == MouseButtons.Left)
443 ShowInTaskbar = false;
445 tsMenuShowHide.Text = Resources.show;
450 ShowInTaskbar = true;
451 WindowState = FormWindowState.Normal;
453 tsMenuShowHide.Text = Resources.hide;
456 private void ShowHideToggle()
458 if (Visible && WindowState != FormWindowState.Minimized)
460 Controller.Settings.StartHidden.Value = true;
465 Controller.Settings.StartHidden.Value = false;
470 private void TsMenuCloseClick(object sender, EventArgs e)
475 private void CECTrayResize(object sender, EventArgs e)
477 if (WindowState == FormWindowState.Minimized)
483 private void TsMenuShowHideClick(object sender, EventArgs e)
488 public void ShowHideAdvanced(bool setTo)
492 tsAdvanced.Checked = true;
493 advancedModeToolStripMenuItem.Checked = true;
495 if (!tabPanel.Controls.Contains(tbTestCommands))
496 TabControls.Add(tbTestCommands);
497 if (!tabPanel.Controls.Contains(LogOutput))
498 TabControls.Add(LogOutput);
503 tsAdvanced.Checked = false;
504 advancedModeToolStripMenuItem.Checked = false;
506 tabPanel.Controls.Remove(tbTestCommands);
507 tabPanel.Controls.Remove(LogOutput);
512 private void TsAdvancedClick(object sender, EventArgs e)
514 Controller.Settings.AdvancedMode.Value = !tsAdvanced.Checked;
515 ShowHideAdvanced(!tsAdvanced.Checked);
518 public void SetStatusText(string status)
520 SetControlText(lStatus, status);
523 public void SetProgressBar(int progress, bool visible)
525 SetControlVisible(pProgress, visible);
526 SetProgressValue(pProgress, progress);
529 public void SetControlsEnabled(bool val)
532 SetControlEnabled(bClose, val);
533 SetControlEnabled(bSaveConfig, val);
534 SetControlEnabled(bReloadConfig, val);
537 SetControlEnabled(bRescanDevices, val);
538 SetControlEnabled(bSendImageViewOn, val);
539 SetControlEnabled(bStandby, val);
540 SetControlEnabled(bActivateSource, val);
541 SetControlEnabled(bScan, val);
543 bool enableVolumeButtons = (GetTargetDevice() == CecLogicalAddress.AudioSystem) && val;
544 SetControlEnabled(bVolUp, enableVolumeButtons);
545 SetControlEnabled(bVolDown, enableVolumeButtons);
546 SetControlEnabled(bMute, enableVolumeButtons);
549 private void TabControl1SelectedIndexChanged(object sender, EventArgs e)
551 switch (tabPanel.TabPages[tabPanel.SelectedIndex].Name)
553 case "tbTestCommands":
554 _selectedTab = ConfigTab.Tester;
557 _selectedTab = ConfigTab.Log;
561 _selectedTab = ConfigTab.Configuration;
567 #region Class members
568 private ConfigTab _selectedTab = ConfigTab.Configuration;
569 private string _log = string.Empty;
570 private CECController _controller;
571 public CECController Controller
575 return _controller ?? (_controller = new CECController(this));
578 public Control.ControlCollection TabControls
580 get { return tabPanel.Controls; }
582 public string SelectedTabName
584 get { return GetSelectedTabName(tabPanel, tabPanel.TabPages); }
588 private void AddNewApplicationToolStripMenuItemClick(object sender, EventArgs e)
590 ConfigureApplication appConfig = new ConfigureApplication(Controller.Settings, Controller);
591 Controller.DisplayDialog(appConfig, false);