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)
82 Controller.CECActions.SuppressUpdates = true;
86 #region Power state change window messages
87 private const int WM_POWERBROADCAST = 0x0218;
88 private const int PBT_APMSUSPEND = 0x0004;
89 private const int PBT_APMRESUMESUSPEND = 0x0007;
90 private const int PBT_APMRESUMECRITICAL = 0x0006;
91 private const int PBT_APMRESUMEAUTOMATIC = 0x0012;
92 private const int PBT_POWERSETTINGCHANGE = 0x8013;
93 private static Guid GUID_SYSTEM_AWAYMODE = new Guid("98a7f580-01f7-48aa-9c0f-44352c29e5c0");
95 [StructLayout(LayoutKind.Sequential, Pack = 4)]
96 internal struct POWERBROADCAST_SETTING
98 public Guid PowerSetting;
99 public uint DataLength;
105 /// Check for power state changes, and pass up when it's something we don't care about
107 /// <param name="msg">The incoming window message</param>
108 protected override void WndProc(ref Message msg)
110 if (msg.Msg == WM_POWERBROADCAST)
112 switch (msg.WParam.ToInt32())
118 case PBT_APMRESUMESUSPEND:
119 case PBT_APMRESUMECRITICAL:
120 case PBT_APMRESUMEAUTOMATIC:
124 case PBT_POWERSETTINGCHANGE:
126 POWERBROADCAST_SETTING pwr = (POWERBROADCAST_SETTING)Marshal.PtrToStructure(msg.LParam, typeof(POWERBROADCAST_SETTING));
127 if (pwr.PowerSetting == GUID_SYSTEM_AWAYMODE && pwr.DataLength == Marshal.SizeOf(typeof(Int32)))
132 // do _not_ wake the pc when away mode is deactivated
149 // pass up when not handled
150 base.WndProc(ref msg);
153 private void OnWake()
155 Controller.Initialise();
158 private void OnSleep()
163 public override sealed string Text
165 get { return base.Text; }
166 set { base.Text = value; }
169 public void Initialise()
171 Controller.Initialise();
174 protected override void Dispose(bool disposing)
179 Controller.CECActions.SuppressUpdates = true;
182 if (disposing && (components != null))
184 components.Dispose();
186 base.Dispose(disposing);
189 #region Configuration tab
191 /// Replaces the gui controls by the ones that are bound to the settings.
192 /// 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
194 public void InitialiseSettingsComponent(CECSettings settings)
196 settings.WakeDevices.ReplaceControls(this, Configuration.Controls, lWakeDevices, cbWakeDevices);
197 settings.PowerOffDevices.ReplaceControls(this, Configuration.Controls, lPowerOff, cbPowerOffDevices);
198 settings.OverridePhysicalAddress.ReplaceControls(this, Configuration.Controls, cbOverrideAddress);
199 settings.OverrideTVVendor.ReplaceControls(this, Configuration.Controls, cbVendorOverride);
200 settings.PhysicalAddress.ReplaceControls(this, Configuration.Controls, tbPhysicalAddress);
201 settings.HDMIPort.ReplaceControls(this, Configuration.Controls, lPortNumber, cbPortNumber);
202 settings.ConnectedDevice.ReplaceControls(this, Configuration.Controls, lConnectedDevice, cbConnectedDevice);
203 settings.ActivateSource.ReplaceControls(this, Configuration.Controls, cbActivateSource);
204 settings.DeviceType.ReplaceControls(this, Configuration.Controls, lDeviceType, cbDeviceType);
205 settings.TVVendor.ReplaceControls(this, Configuration.Controls, cbVendorId);
206 settings.StartHidden.ReplaceControls(this, Configuration.Controls, cbStartMinimised);
209 private void BSaveClick(object sender, EventArgs e)
211 Controller.PersistSettings();
214 private void BReloadConfigClick(object sender, EventArgs e)
216 Controller.ResetDefaultSettings();
220 #region CEC Tester tab
221 delegate void SetActiveDevicesCallback(string[] activeDevices);
222 public void SetActiveDevices(string[] activeDevices)
224 if (cbCommandDestination.InvokeRequired)
226 SetActiveDevicesCallback d = SetActiveDevices;
229 Invoke(d, new object[] { activeDevices });
231 catch (Exception) { }
235 cbCommandDestination.Items.Clear();
236 foreach (string item in activeDevices)
237 cbCommandDestination.Items.Add(item);
241 delegate CecLogicalAddress GetTargetDeviceCallback();
242 private CecLogicalAddress GetTargetDevice()
244 if (cbCommandDestination.InvokeRequired)
246 GetTargetDeviceCallback d = GetTargetDevice;
247 CecLogicalAddress retval = CecLogicalAddress.Unknown;
250 retval = (CecLogicalAddress)Invoke(d, new object[] { });
252 catch (Exception) { }
256 return CECSettingLogicalAddresses.GetLogicalAddressFromString(cbCommandDestination.Text);
259 private void BSendImageViewOnClick(object sender, EventArgs e)
261 Controller.CECActions.SendImageViewOn(GetTargetDevice());
264 private void BStandbyClick(object sender, EventArgs e)
266 Controller.CECActions.SendStandby(GetTargetDevice());
269 private void BScanClick(object sender, EventArgs e)
271 Controller.CECActions.ShowDeviceInfo(GetTargetDevice());
274 private void BActivateSourceClick(object sender, EventArgs e)
276 Controller.CECActions.ActivateSource(GetTargetDevice());
279 private void CbCommandDestinationSelectedIndexChanged(object sender, EventArgs e)
281 bool enableVolumeButtons = (GetTargetDevice() == CecLogicalAddress.AudioSystem);
282 bVolUp.Enabled = enableVolumeButtons;
283 bVolDown.Enabled = enableVolumeButtons;
284 bMute.Enabled = enableVolumeButtons;
285 bActivateSource.Enabled = (GetTargetDevice() != CecLogicalAddress.Broadcast);
286 bScan.Enabled = (GetTargetDevice() != CecLogicalAddress.Broadcast);
289 private void BVolUpClick(object sender, EventArgs e)
291 Controller.Lib.VolumeUp(true);
294 private void BVolDownClick(object sender, EventArgs e)
296 Controller.Lib.VolumeDown(true);
299 private void BMuteClick(object sender, EventArgs e)
301 Controller.Lib.MuteAudio(true);
304 private void BRescanDevicesClick(object sender, EventArgs e)
306 Controller.CECActions.RescanDevices();
311 delegate void UpdateLogCallback();
312 private void UpdateLog()
314 if (tbLog.InvokeRequired)
316 UpdateLogCallback d = UpdateLog;
319 Invoke(d, new object[] { });
321 catch (Exception) { }
326 tbLog.Select(tbLog.Text.Length, 0);
327 tbLog.ScrollToCaret();
331 public void AddLogMessage(CecLogMessage message)
333 string strLevel = "";
334 bool display = false;
335 switch (message.Level)
337 case CecLogLevel.Error:
338 strLevel = "ERROR: ";
339 display = cbLogError.Checked;
341 case CecLogLevel.Warning:
342 strLevel = "WARNING: ";
343 display = cbLogWarning.Checked;
345 case CecLogLevel.Notice:
346 strLevel = "NOTICE: ";
347 display = cbLogNotice.Checked;
349 case CecLogLevel.Traffic:
350 strLevel = "TRAFFIC: ";
351 display = cbLogTraffic.Checked;
353 case CecLogLevel.Debug:
354 strLevel = "DEBUG: ";
355 display = cbLogDebug.Checked;
361 string strLog = string.Format("{0} {1,16} {2}", strLevel, message.Time, message.Message) + Environment.NewLine;
362 AddLogMessage(strLog);
366 public void AddLogMessage(string message)
370 if (_selectedTab == ConfigTab.Log)
374 private void BClearLogClick(object sender, EventArgs e)
380 private void BSaveLogClick(object sender, EventArgs e)
382 SaveFileDialog dialog = new SaveFileDialog
384 Title = Resources.where_do_you_want_to_store_the_log,
385 InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
386 FileName = Resources.cec_log_filename,
387 Filter = Resources.cec_log_filter,
391 if (dialog.ShowDialog() == DialogResult.OK)
393 FileStream fs = (FileStream)dialog.OpenFile();
396 MessageBox.Show(string.Format(Resources.cannot_open_for_writing, dialog.FileName), Resources.app_name, MessageBoxButtons.OK, MessageBoxIcon.Error);
400 StreamWriter writer = new StreamWriter(fs);
405 MessageBox.Show(string.Format(Resources.log_stored_as, dialog.FileName), Resources.app_name, MessageBoxButtons.OK, MessageBoxIcon.Information);
411 #region Tray icon and window controls
412 private void HideToolStripMenuItemClick(object sender, EventArgs e)
417 private void CloseToolStripMenuItemClick(object sender, EventArgs e)
422 private void AboutToolStripMenuItemClick(object sender, EventArgs e)
424 (new About(Controller.LibServerVersion, Controller.LibClientVersion, Controller.LibInfo)).ShowDialog();
427 private void AdvancedModeToolStripMenuItemClick(object sender, EventArgs e)
429 Controller.Settings.AdvancedMode.Value = !advancedModeToolStripMenuItem.Checked;
430 ShowHideAdvanced(!advancedModeToolStripMenuItem.Checked);
433 private void BCancelClick(object sender, EventArgs e)
438 private void TrayIconClick(object sender, EventArgs e)
440 if (e is MouseEventArgs && (e as MouseEventArgs).Button == MouseButtons.Left)
446 ShowInTaskbar = false;
448 tsMenuShowHide.Text = Resources.show;
453 ShowInTaskbar = true;
454 WindowState = FormWindowState.Normal;
456 tsMenuShowHide.Text = Resources.hide;
459 private void ShowHideToggle()
461 if (Visible && WindowState != FormWindowState.Minimized)
463 Controller.Settings.StartHidden.Value = true;
468 Controller.Settings.StartHidden.Value = false;
473 private void TsMenuCloseClick(object sender, EventArgs e)
478 private void CECTrayResize(object sender, EventArgs e)
480 if (WindowState == FormWindowState.Minimized)
486 private void TsMenuShowHideClick(object sender, EventArgs e)
491 public void ShowHideAdvanced(bool setTo)
495 tsAdvanced.Checked = true;
496 advancedModeToolStripMenuItem.Checked = true;
498 if (!tabPanel.Controls.Contains(tbTestCommands))
499 TabControls.Add(tbTestCommands);
500 if (!tabPanel.Controls.Contains(LogOutput))
501 TabControls.Add(LogOutput);
506 tsAdvanced.Checked = false;
507 advancedModeToolStripMenuItem.Checked = false;
509 tabPanel.Controls.Remove(tbTestCommands);
510 tabPanel.Controls.Remove(LogOutput);
515 private void TsAdvancedClick(object sender, EventArgs e)
517 Controller.Settings.AdvancedMode.Value = !tsAdvanced.Checked;
518 ShowHideAdvanced(!tsAdvanced.Checked);
521 public void SetStatusText(string status)
523 SetControlText(lStatus, status);
526 public void SetProgressBar(int progress, bool visible)
528 SetControlVisible(pProgress, visible);
529 SetProgressValue(pProgress, progress);
532 public void SetControlsEnabled(bool val)
535 SetControlEnabled(bClose, val);
536 SetControlEnabled(bSaveConfig, val);
537 SetControlEnabled(bReloadConfig, val);
540 SetControlEnabled(bRescanDevices, val);
541 SetControlEnabled(bSendImageViewOn, val);
542 SetControlEnabled(bStandby, val);
543 SetControlEnabled(bActivateSource, val);
544 SetControlEnabled(bScan, val);
546 bool enableVolumeButtons = (GetTargetDevice() == CecLogicalAddress.AudioSystem) && val;
547 SetControlEnabled(bVolUp, enableVolumeButtons);
548 SetControlEnabled(bVolDown, enableVolumeButtons);
549 SetControlEnabled(bMute, enableVolumeButtons);
552 private void TabControl1SelectedIndexChanged(object sender, EventArgs e)
554 switch (tabPanel.TabPages[tabPanel.SelectedIndex].Name)
556 case "tbTestCommands":
557 _selectedTab = ConfigTab.Tester;
560 _selectedTab = ConfigTab.Log;
564 _selectedTab = ConfigTab.Configuration;
570 #region Class members
571 private ConfigTab _selectedTab = ConfigTab.Configuration;
572 private string _log = string.Empty;
573 private CECController _controller;
574 public CECController Controller
578 return _controller ?? (_controller = new CECController(this));
581 public Control.ControlCollection TabControls
583 get { return tabPanel.Controls; }
585 public string SelectedTabName
587 get { return GetSelectedTabName(tabPanel, tabPanel.TabPages); }
591 private void AddNewApplicationToolStripMenuItemClick(object sender, EventArgs e)
593 ConfigureApplication appConfig = new ConfigureApplication(Controller.Settings, Controller);
594 Controller.DisplayDialog(appConfig, false);