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)
177 SuppressLogUpdates = true;
180 Controller.CECActions.SuppressUpdates = true;
183 if (disposing && (components != null))
185 components.Dispose();
187 base.Dispose(disposing);
190 #region Configuration tab
192 /// Replaces the gui controls by the ones that are bound to the settings.
193 /// 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
195 public void InitialiseSettingsComponent(CECSettings settings)
197 settings.WakeDevices.ReplaceControls(this, Configuration.Controls, lWakeDevices, cbWakeDevices);
198 settings.PowerOffDevices.ReplaceControls(this, Configuration.Controls, lPowerOff, cbPowerOffDevices);
199 settings.OverridePhysicalAddress.ReplaceControls(this, Configuration.Controls, cbOverrideAddress);
200 settings.OverrideTVVendor.ReplaceControls(this, Configuration.Controls, cbVendorOverride);
201 settings.PhysicalAddress.ReplaceControls(this, Configuration.Controls, tbPhysicalAddress);
202 settings.HDMIPort.ReplaceControls(this, Configuration.Controls, lPortNumber, cbPortNumber);
203 settings.ConnectedDevice.ReplaceControls(this, Configuration.Controls, lConnectedDevice, cbConnectedDevice);
204 settings.ActivateSource.ReplaceControls(this, Configuration.Controls, cbActivateSource);
205 settings.DeviceType.ReplaceControls(this, Configuration.Controls, lDeviceType, cbDeviceType);
206 settings.TVVendor.ReplaceControls(this, Configuration.Controls, cbVendorId);
207 settings.StartHidden.ReplaceControls(this, Configuration.Controls, cbStartMinimised);
210 private void BSaveClick(object sender, EventArgs e)
212 Controller.PersistSettings();
215 private void BReloadConfigClick(object sender, EventArgs e)
217 Controller.ResetDefaultSettings();
221 #region CEC Tester tab
222 delegate void SetActiveDevicesCallback(string[] activeDevices);
223 public void SetActiveDevices(string[] activeDevices)
225 if (cbCommandDestination.InvokeRequired)
227 SetActiveDevicesCallback d = SetActiveDevices;
230 Invoke(d, new object[] { activeDevices });
232 catch (Exception) { }
236 cbCommandDestination.Items.Clear();
237 foreach (string item in activeDevices)
238 cbCommandDestination.Items.Add(item);
242 delegate CecLogicalAddress GetTargetDeviceCallback();
243 private CecLogicalAddress GetTargetDevice()
245 if (cbCommandDestination.InvokeRequired)
247 GetTargetDeviceCallback d = GetTargetDevice;
248 CecLogicalAddress retval = CecLogicalAddress.Unknown;
251 retval = (CecLogicalAddress)Invoke(d, new object[] { });
253 catch (Exception) { }
257 return CECSettingLogicalAddresses.GetLogicalAddressFromString(cbCommandDestination.Text);
260 private void BSendImageViewOnClick(object sender, EventArgs e)
262 Controller.CECActions.SendImageViewOn(GetTargetDevice());
265 private void BStandbyClick(object sender, EventArgs e)
267 Controller.CECActions.SendStandby(GetTargetDevice());
270 private void BScanClick(object sender, EventArgs e)
272 Controller.CECActions.ShowDeviceInfo(GetTargetDevice());
275 private void BActivateSourceClick(object sender, EventArgs e)
277 Controller.CECActions.ActivateSource(GetTargetDevice());
280 private void CbCommandDestinationSelectedIndexChanged(object sender, EventArgs e)
282 bool enableVolumeButtons = (GetTargetDevice() == CecLogicalAddress.AudioSystem);
283 bVolUp.Enabled = enableVolumeButtons;
284 bVolDown.Enabled = enableVolumeButtons;
285 bMute.Enabled = enableVolumeButtons;
286 bActivateSource.Enabled = (GetTargetDevice() != CecLogicalAddress.Broadcast);
287 bScan.Enabled = (GetTargetDevice() != CecLogicalAddress.Broadcast);
290 private void BVolUpClick(object sender, EventArgs e)
292 Controller.Lib.VolumeUp(true);
295 private void BVolDownClick(object sender, EventArgs e)
297 Controller.Lib.VolumeDown(true);
300 private void BMuteClick(object sender, EventArgs e)
302 Controller.Lib.MuteAudio(true);
305 private void BRescanDevicesClick(object sender, EventArgs e)
307 Controller.CECActions.RescanDevices();
312 delegate void UpdateLogCallback();
313 private void UpdateLog()
315 if (SuppressLogUpdates)
318 if (tbLog.InvokeRequired)
320 UpdateLogCallback d = UpdateLog;
323 Invoke(d, new object[] { });
325 catch (Exception) { }
330 tbLog.Select(tbLog.Text.Length, 0);
331 tbLog.ScrollToCaret();
335 public void AddLogMessage(CecLogMessage message)
337 string strLevel = "";
338 bool display = false;
339 switch (message.Level)
341 case CecLogLevel.Error:
342 strLevel = "ERROR: ";
343 display = cbLogError.Checked;
345 case CecLogLevel.Warning:
346 strLevel = "WARNING: ";
347 display = cbLogWarning.Checked;
349 case CecLogLevel.Notice:
350 strLevel = "NOTICE: ";
351 display = cbLogNotice.Checked;
353 case CecLogLevel.Traffic:
354 strLevel = "TRAFFIC: ";
355 display = cbLogTraffic.Checked;
357 case CecLogLevel.Debug:
358 strLevel = "DEBUG: ";
359 display = cbLogDebug.Checked;
365 string strLog = string.Format("{0} {1,16} {2}", strLevel, message.Time, message.Message) + Environment.NewLine;
366 AddLogMessage(strLog);
370 public void AddLogMessage(string message)
374 if (_selectedTab == ConfigTab.Log)
378 private void BClearLogClick(object sender, EventArgs e)
384 private void BSaveLogClick(object sender, EventArgs e)
386 SaveFileDialog dialog = new SaveFileDialog
388 Title = Resources.where_do_you_want_to_store_the_log,
389 InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
390 FileName = Resources.cec_log_filename,
391 Filter = Resources.cec_log_filter,
395 if (dialog.ShowDialog() == DialogResult.OK)
397 FileStream fs = (FileStream)dialog.OpenFile();
400 MessageBox.Show(string.Format(Resources.cannot_open_for_writing, dialog.FileName), Resources.app_name, MessageBoxButtons.OK, MessageBoxIcon.Error);
404 StreamWriter writer = new StreamWriter(fs);
409 MessageBox.Show(string.Format(Resources.log_stored_as, dialog.FileName), Resources.app_name, MessageBoxButtons.OK, MessageBoxIcon.Information);
415 #region Tray icon and window controls
416 private void HideToolStripMenuItemClick(object sender, EventArgs e)
421 private void CloseToolStripMenuItemClick(object sender, EventArgs e)
426 private void AboutToolStripMenuItemClick(object sender, EventArgs e)
428 (new About(Controller.LibServerVersion, Controller.LibClientVersion, Controller.LibInfo)).ShowDialog();
431 private void AdvancedModeToolStripMenuItemClick(object sender, EventArgs e)
433 Controller.Settings.AdvancedMode.Value = !advancedModeToolStripMenuItem.Checked;
434 ShowHideAdvanced(!advancedModeToolStripMenuItem.Checked);
437 private void BCancelClick(object sender, EventArgs e)
442 private void TrayIconClick(object sender, EventArgs e)
444 if (e is MouseEventArgs && (e as MouseEventArgs).Button == MouseButtons.Left)
450 ShowInTaskbar = false;
452 tsMenuShowHide.Text = Resources.show;
457 ShowInTaskbar = true;
458 WindowState = FormWindowState.Normal;
460 tsMenuShowHide.Text = Resources.hide;
463 private void ShowHideToggle()
465 if (Visible && WindowState != FormWindowState.Minimized)
467 Controller.Settings.StartHidden.Value = true;
472 Controller.Settings.StartHidden.Value = false;
477 private void TsMenuCloseClick(object sender, EventArgs e)
482 private void CECTrayResize(object sender, EventArgs e)
484 if (WindowState == FormWindowState.Minimized)
490 private void TsMenuShowHideClick(object sender, EventArgs e)
495 public void ShowHideAdvanced(bool setTo)
499 tsAdvanced.Checked = true;
500 advancedModeToolStripMenuItem.Checked = true;
502 if (!tabPanel.Controls.Contains(tbTestCommands))
503 TabControls.Add(tbTestCommands);
504 if (!tabPanel.Controls.Contains(LogOutput))
505 TabControls.Add(LogOutput);
510 tsAdvanced.Checked = false;
511 advancedModeToolStripMenuItem.Checked = false;
513 tabPanel.Controls.Remove(tbTestCommands);
514 tabPanel.Controls.Remove(LogOutput);
519 private void TsAdvancedClick(object sender, EventArgs e)
521 Controller.Settings.AdvancedMode.Value = !tsAdvanced.Checked;
522 ShowHideAdvanced(!tsAdvanced.Checked);
525 public void SetStatusText(string status)
527 SetControlText(lStatus, status);
530 public void SetProgressBar(int progress, bool visible)
532 SetControlVisible(pProgress, visible);
533 SetProgressValue(pProgress, progress);
536 public void SetControlsEnabled(bool val)
539 SetControlEnabled(bClose, val);
540 SetControlEnabled(bSaveConfig, val);
541 SetControlEnabled(bReloadConfig, val);
544 SetControlEnabled(bRescanDevices, val);
545 SetControlEnabled(bSendImageViewOn, val);
546 SetControlEnabled(bStandby, val);
547 SetControlEnabled(bActivateSource, val);
548 SetControlEnabled(bScan, val);
550 bool enableVolumeButtons = (GetTargetDevice() == CecLogicalAddress.AudioSystem) && val;
551 SetControlEnabled(bVolUp, enableVolumeButtons);
552 SetControlEnabled(bVolDown, enableVolumeButtons);
553 SetControlEnabled(bMute, enableVolumeButtons);
556 private void TabControl1SelectedIndexChanged(object sender, EventArgs e)
558 switch (tabPanel.TabPages[tabPanel.SelectedIndex].Name)
560 case "tbTestCommands":
561 _selectedTab = ConfigTab.Tester;
564 _selectedTab = ConfigTab.Log;
568 _selectedTab = ConfigTab.Configuration;
574 #region Class members
575 private bool SuppressLogUpdates = false;
576 private ConfigTab _selectedTab = ConfigTab.Configuration;
577 private string _log = string.Empty;
578 private CECController _controller;
579 public CECController Controller
583 return _controller ?? (_controller = new CECController(this));
586 public Control.ControlCollection TabControls
588 get { return tabPanel.Controls; }
590 public string SelectedTabName
592 get { return GetSelectedTabName(tabPanel, tabPanel.TabPages); }
596 private void AddNewApplicationToolStripMenuItemClick(object sender, EventArgs e)
598 ConfigureApplication appConfig = new ConfigureApplication(Controller.Settings, Controller);
599 Controller.DisplayDialog(appConfig, false);