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;
44 using System.Threading;
46 namespace LibCECTray.ui
49 /// Main LibCecTray GUI
51 partial class CECTray : AsyncForm
55 Text = Resources.app_name;
56 InitializeComponent();
58 _sstimer.Interval = 1000;
59 _sstimer.Tick += ScreensaverActiveCheck;
60 _sstimer.Enabled = false;
62 VisibleChanged += delegate
70 SystemEvents.SessionEnding += new SessionEndingEventHandler(OnSessionEnding);
73 public void OnSessionEnding(object sender, SessionEndingEventArgs e)
75 Controller.CECActions.SuppressUpdates = true;
79 #region Power state change window messages
80 private const int WM_POWERBROADCAST = 0x0218;
81 private const int WM_SYSCOMMAND = 0x0112;
83 private const int PBT_APMSUSPEND = 0x0004;
84 private const int PBT_APMRESUMESUSPEND = 0x0007;
85 private const int PBT_APMRESUMECRITICAL = 0x0006;
86 private const int PBT_APMRESUMEAUTOMATIC = 0x0012;
87 private const int PBT_POWERSETTINGCHANGE = 0x8013;
89 private static Guid GUID_SYSTEM_AWAYMODE = new Guid("98a7f580-01f7-48aa-9c0f-44352c29e5c0");
91 private const int SC_SCREENSAVE = 0xF140;
92 private const int SPI_GETSCREENSAVERRUNNING = 0x0072;
94 [DllImport("user32.dll", SetLastError = true)]
95 static extern bool SystemParametersInfo(int action, int param, ref int retval, int updini);
97 [StructLayout(LayoutKind.Sequential, Pack = 4)]
98 internal struct POWERBROADCAST_SETTING
100 public Guid PowerSetting;
101 public uint DataLength;
107 /// Check for power state changes, and pass up when it's something we don't care about
109 /// <param name="msg">The incoming window message</param>
110 protected override void WndProc(ref Message msg)
112 if (msg.Msg == WM_SYSCOMMAND && (msg.WParam.ToInt32() & 0xfff0) == SC_SCREENSAVE)
114 // there's no event for screensaver exit
115 _sstimer.Enabled = true;
119 else if (msg.Msg == WM_POWERBROADCAST)
121 switch (msg.WParam.ToInt32())
127 case PBT_APMRESUMESUSPEND:
128 case PBT_APMRESUMECRITICAL:
129 case PBT_APMRESUMEAUTOMATIC:
133 case PBT_POWERSETTINGCHANGE:
135 POWERBROADCAST_SETTING pwr = (POWERBROADCAST_SETTING)Marshal.PtrToStructure(msg.LParam, typeof(POWERBROADCAST_SETTING));
136 if (pwr.PowerSetting == GUID_SYSTEM_AWAYMODE && pwr.DataLength == Marshal.SizeOf(typeof(Int32)))
141 // do _not_ wake the pc when away mode is deactivated
158 // pass up when not handled
159 base.WndProc(ref msg);
162 private void ScreensaverActiveCheck(object sender, EventArgs e)
164 if (!IsScreensaverActive())
166 _sstimer.Enabled = false;
171 private bool IsScreensaverActive()
174 SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, ref active, 0);
178 private void OnWake()
180 Controller.Initialise();
183 private void OnSleep()
188 public override sealed string Text
190 get { return base.Text; }
191 set { base.Text = value; }
194 public void Initialise()
196 Controller.Initialise();
199 protected override void Dispose(bool disposing)
204 Controller.CECActions.SuppressUpdates = true;
205 AsyncDisconnect dc = new AsyncDisconnect(Controller);
206 (new Thread(dc.Process)).Start();
208 if (disposing && (components != null))
210 components.Dispose();
212 base.Dispose(disposing);
215 #region Configuration tab
217 /// Replaces the gui controls by the ones that are bound to the settings.
218 /// 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
220 public void InitialiseSettingsComponent(CECSettings settings)
222 settings.WakeDevices.ReplaceControls(this, Configuration.Controls, lWakeDevices, cbWakeDevices);
223 settings.PowerOffDevices.ReplaceControls(this, Configuration.Controls, lPowerOff, cbPowerOffDevices);
224 settings.OverridePhysicalAddress.ReplaceControls(this, Configuration.Controls, cbOverrideAddress);
225 settings.OverrideTVVendor.ReplaceControls(this, Configuration.Controls, cbVendorOverride);
226 settings.PhysicalAddress.ReplaceControls(this, Configuration.Controls, tbPhysicalAddress);
227 settings.HDMIPort.ReplaceControls(this, Configuration.Controls, lPortNumber, cbPortNumber);
228 settings.ConnectedDevice.ReplaceControls(this, Configuration.Controls, lConnectedDevice, cbConnectedDevice);
229 settings.ActivateSource.ReplaceControls(this, Configuration.Controls, cbActivateSource);
230 settings.DeviceType.ReplaceControls(this, Configuration.Controls, lDeviceType, cbDeviceType);
231 settings.TVVendor.ReplaceControls(this, Configuration.Controls, cbVendorId);
232 settings.StartHidden.ReplaceControls(this, Configuration.Controls, cbStartMinimised);
235 private void BSaveClick(object sender, EventArgs e)
237 Controller.PersistSettings();
240 private void BReloadConfigClick(object sender, EventArgs e)
242 Controller.ResetDefaultSettings();
246 #region CEC Tester tab
247 delegate void SetActiveDevicesCallback(string[] activeDevices);
248 public void SetActiveDevices(string[] activeDevices)
250 if (cbCommandDestination.InvokeRequired)
252 SetActiveDevicesCallback d = SetActiveDevices;
255 Invoke(d, new object[] { activeDevices });
257 catch (Exception) { }
261 cbCommandDestination.Items.Clear();
262 foreach (string item in activeDevices)
263 cbCommandDestination.Items.Add(item);
267 delegate CecLogicalAddress GetTargetDeviceCallback();
268 private CecLogicalAddress GetTargetDevice()
270 if (cbCommandDestination.InvokeRequired)
272 GetTargetDeviceCallback d = GetTargetDevice;
273 CecLogicalAddress retval = CecLogicalAddress.Unknown;
276 retval = (CecLogicalAddress)Invoke(d, new object[] { });
278 catch (Exception) { }
282 return CECSettingLogicalAddresses.GetLogicalAddressFromString(cbCommandDestination.Text);
285 private void BSendImageViewOnClick(object sender, EventArgs e)
287 Controller.CECActions.SendImageViewOn(GetTargetDevice());
290 private void BStandbyClick(object sender, EventArgs e)
292 Controller.CECActions.SendStandby(GetTargetDevice());
295 private void BScanClick(object sender, EventArgs e)
297 Controller.CECActions.ShowDeviceInfo(GetTargetDevice());
300 private void BActivateSourceClick(object sender, EventArgs e)
302 Controller.CECActions.ActivateSource(GetTargetDevice());
305 private void CbCommandDestinationSelectedIndexChanged(object sender, EventArgs e)
307 bool enableVolumeButtons = (GetTargetDevice() == CecLogicalAddress.AudioSystem);
308 bVolUp.Enabled = enableVolumeButtons;
309 bVolDown.Enabled = enableVolumeButtons;
310 bMute.Enabled = enableVolumeButtons;
311 bActivateSource.Enabled = (GetTargetDevice() != CecLogicalAddress.Broadcast);
312 bScan.Enabled = (GetTargetDevice() != CecLogicalAddress.Broadcast);
315 private void BVolUpClick(object sender, EventArgs e)
317 Controller.Lib.VolumeUp(true);
320 private void BVolDownClick(object sender, EventArgs e)
322 Controller.Lib.VolumeDown(true);
325 private void BMuteClick(object sender, EventArgs e)
327 Controller.Lib.MuteAudio(true);
330 private void BRescanDevicesClick(object sender, EventArgs e)
332 Controller.CECActions.RescanDevices();
337 delegate void UpdateLogCallback();
338 private void UpdateLog()
340 if (tbLog.InvokeRequired)
342 UpdateLogCallback d = UpdateLog;
345 Invoke(d, new object[] { });
347 catch (Exception) { }
352 tbLog.Select(tbLog.Text.Length, 0);
353 tbLog.ScrollToCaret();
357 public void AddLogMessage(CecLogMessage message)
359 string strLevel = "";
360 bool display = false;
361 switch (message.Level)
363 case CecLogLevel.Error:
364 strLevel = "ERROR: ";
365 display = cbLogError.Checked;
367 case CecLogLevel.Warning:
368 strLevel = "WARNING: ";
369 display = cbLogWarning.Checked;
371 case CecLogLevel.Notice:
372 strLevel = "NOTICE: ";
373 display = cbLogNotice.Checked;
375 case CecLogLevel.Traffic:
376 strLevel = "TRAFFIC: ";
377 display = cbLogTraffic.Checked;
379 case CecLogLevel.Debug:
380 strLevel = "DEBUG: ";
381 display = cbLogDebug.Checked;
387 string strLog = string.Format("{0} {1,16} {2}", strLevel, message.Time, message.Message) + Environment.NewLine;
388 AddLogMessage(strLog);
392 public void AddLogMessage(string message)
396 if (_selectedTab == ConfigTab.Log)
400 private void BClearLogClick(object sender, EventArgs e)
406 private void BSaveLogClick(object sender, EventArgs e)
408 SaveFileDialog dialog = new SaveFileDialog
410 Title = Resources.where_do_you_want_to_store_the_log,
411 InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
412 FileName = Resources.cec_log_filename,
413 Filter = Resources.cec_log_filter,
417 if (dialog.ShowDialog() == DialogResult.OK)
419 FileStream fs = (FileStream)dialog.OpenFile();
422 MessageBox.Show(string.Format(Resources.cannot_open_for_writing, dialog.FileName), Resources.app_name, MessageBoxButtons.OK, MessageBoxIcon.Error);
426 StreamWriter writer = new StreamWriter(fs);
431 MessageBox.Show(string.Format(Resources.log_stored_as, dialog.FileName), Resources.app_name, MessageBoxButtons.OK, MessageBoxIcon.Information);
437 #region Tray icon and window controls
438 private void HideToolStripMenuItemClick(object sender, EventArgs e)
443 private void CloseToolStripMenuItemClick(object sender, EventArgs e)
448 private void AboutToolStripMenuItemClick(object sender, EventArgs e)
450 (new About(Controller.LibServerVersion, Controller.LibClientVersion, Controller.LibInfo)).ShowDialog();
453 private void AdvancedModeToolStripMenuItemClick(object sender, EventArgs e)
455 Controller.Settings.AdvancedMode.Value = !advancedModeToolStripMenuItem.Checked;
456 ShowHideAdvanced(!advancedModeToolStripMenuItem.Checked);
459 private void BCancelClick(object sender, EventArgs e)
464 private void TrayIconClick(object sender, EventArgs e)
466 if (e is MouseEventArgs && (e as MouseEventArgs).Button == MouseButtons.Left)
472 ShowInTaskbar = false;
474 tsMenuShowHide.Text = Resources.show;
479 ShowInTaskbar = true;
480 WindowState = FormWindowState.Normal;
482 tsMenuShowHide.Text = Resources.hide;
485 private void ShowHideToggle()
487 if (Visible && WindowState != FormWindowState.Minimized)
489 Controller.Settings.StartHidden.Value = true;
494 Controller.Settings.StartHidden.Value = false;
499 private void TsMenuCloseClick(object sender, EventArgs e)
504 private void CECTrayResize(object sender, EventArgs e)
506 if (WindowState == FormWindowState.Minimized)
512 private void TsMenuShowHideClick(object sender, EventArgs e)
517 public void ShowHideAdvanced(bool setTo)
521 tsAdvanced.Checked = true;
522 advancedModeToolStripMenuItem.Checked = true;
524 if (!tabPanel.Controls.Contains(tbTestCommands))
525 TabControls.Add(tbTestCommands);
526 if (!tabPanel.Controls.Contains(LogOutput))
527 TabControls.Add(LogOutput);
532 tsAdvanced.Checked = false;
533 advancedModeToolStripMenuItem.Checked = false;
535 tabPanel.Controls.Remove(tbTestCommands);
536 tabPanel.Controls.Remove(LogOutput);
541 private void TsAdvancedClick(object sender, EventArgs e)
543 Controller.Settings.AdvancedMode.Value = !tsAdvanced.Checked;
544 ShowHideAdvanced(!tsAdvanced.Checked);
547 public void SetStatusText(string status)
549 SetControlText(lStatus, status);
552 public void SetProgressBar(int progress, bool visible)
554 SetControlVisible(pProgress, visible);
555 SetProgressValue(pProgress, progress);
558 public void SetControlsEnabled(bool val)
561 SetControlEnabled(bClose, val);
562 SetControlEnabled(bSaveConfig, val);
563 SetControlEnabled(bReloadConfig, val);
566 SetControlEnabled(bRescanDevices, val);
567 SetControlEnabled(bSendImageViewOn, val);
568 SetControlEnabled(bStandby, val);
569 SetControlEnabled(bActivateSource, val);
570 SetControlEnabled(bScan, val);
572 bool enableVolumeButtons = (GetTargetDevice() == CecLogicalAddress.AudioSystem) && val;
573 SetControlEnabled(bVolUp, enableVolumeButtons);
574 SetControlEnabled(bVolDown, enableVolumeButtons);
575 SetControlEnabled(bMute, enableVolumeButtons);
578 private void TabControl1SelectedIndexChanged(object sender, EventArgs e)
580 switch (tabPanel.TabPages[tabPanel.SelectedIndex].Name)
582 case "tbTestCommands":
583 _selectedTab = ConfigTab.Tester;
586 _selectedTab = ConfigTab.Log;
590 _selectedTab = ConfigTab.Configuration;
596 #region Class members
597 private ConfigTab _selectedTab = ConfigTab.Configuration;
598 private string _log = string.Empty;
599 private CECController _controller;
600 public CECController Controller
604 return _controller ?? (_controller = new CECController(this));
607 public Control.ControlCollection TabControls
609 get { return tabPanel.Controls; }
611 public string SelectedTabName
613 get { return GetSelectedTabName(tabPanel, tabPanel.TabPages); }
616 private System.Windows.Forms.Timer _sstimer = new System.Windows.Forms.Timer();
619 private void AddNewApplicationToolStripMenuItemClick(object sender, EventArgs e)
621 ConfigureApplication appConfig = new ConfigureApplication(Controller.Settings, Controller);
622 Controller.DisplayDialog(appConfig, false);
627 /// The tab pages in this application
629 internal enum ConfigTab
639 class AsyncDisconnect
641 public AsyncDisconnect(CECController controller)
643 _controller = controller;
646 public void Process()
651 private CECController _controller;