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 /// The tab pages in this application
51 internal enum ConfigTab
63 public AsyncDisconnect(CECController controller)
65 _controller = controller;
73 private CECController _controller;
77 /// Main LibCecTray GUI
79 partial class CECTray : AsyncForm
83 Text = Resources.app_name;
84 InitializeComponent();
85 VisibleChanged += delegate
93 SystemEvents.SessionEnding += new SessionEndingEventHandler(OnSessionEnding);
96 public void OnSessionEnding(object sender, SessionEndingEventArgs e)
98 Controller.CECActions.SuppressUpdates = true;
102 #region Power state change window messages
103 private const int WM_POWERBROADCAST = 0x0218;
104 private const int PBT_APMSUSPEND = 0x0004;
105 private const int PBT_APMRESUMESUSPEND = 0x0007;
106 private const int PBT_APMRESUMECRITICAL = 0x0006;
107 private const int PBT_APMRESUMEAUTOMATIC = 0x0012;
108 private const int PBT_POWERSETTINGCHANGE = 0x8013;
109 private static Guid GUID_SYSTEM_AWAYMODE = new Guid("98a7f580-01f7-48aa-9c0f-44352c29e5c0");
111 [StructLayout(LayoutKind.Sequential, Pack = 4)]
112 internal struct POWERBROADCAST_SETTING
114 public Guid PowerSetting;
115 public uint DataLength;
121 /// Check for power state changes, and pass up when it's something we don't care about
123 /// <param name="msg">The incoming window message</param>
124 protected override void WndProc(ref Message msg)
126 if (msg.Msg == WM_POWERBROADCAST)
128 switch (msg.WParam.ToInt32())
134 case PBT_APMRESUMESUSPEND:
135 case PBT_APMRESUMECRITICAL:
136 case PBT_APMRESUMEAUTOMATIC:
140 case PBT_POWERSETTINGCHANGE:
142 POWERBROADCAST_SETTING pwr = (POWERBROADCAST_SETTING)Marshal.PtrToStructure(msg.LParam, typeof(POWERBROADCAST_SETTING));
143 if (pwr.PowerSetting == GUID_SYSTEM_AWAYMODE && pwr.DataLength == Marshal.SizeOf(typeof(Int32)))
148 // do _not_ wake the pc when away mode is deactivated
165 // pass up when not handled
166 base.WndProc(ref msg);
169 private void OnWake()
171 Controller.Initialise();
174 private void OnSleep()
179 public override sealed string Text
181 get { return base.Text; }
182 set { base.Text = value; }
185 public void Initialise()
187 Controller.Initialise();
190 protected override void Dispose(bool disposing)
195 Controller.CECActions.SuppressUpdates = true;
196 AsyncDisconnect dc = new AsyncDisconnect(Controller);
197 (new Thread(dc.Process)).Start();
199 if (disposing && (components != null))
201 components.Dispose();
203 base.Dispose(disposing);
206 #region Configuration tab
208 /// Replaces the gui controls by the ones that are bound to the settings.
209 /// 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
211 public void InitialiseSettingsComponent(CECSettings settings)
213 settings.WakeDevices.ReplaceControls(this, Configuration.Controls, lWakeDevices, cbWakeDevices);
214 settings.PowerOffDevices.ReplaceControls(this, Configuration.Controls, lPowerOff, cbPowerOffDevices);
215 settings.OverridePhysicalAddress.ReplaceControls(this, Configuration.Controls, cbOverrideAddress);
216 settings.OverrideTVVendor.ReplaceControls(this, Configuration.Controls, cbVendorOverride);
217 settings.PhysicalAddress.ReplaceControls(this, Configuration.Controls, tbPhysicalAddress);
218 settings.HDMIPort.ReplaceControls(this, Configuration.Controls, lPortNumber, cbPortNumber);
219 settings.ConnectedDevice.ReplaceControls(this, Configuration.Controls, lConnectedDevice, cbConnectedDevice);
220 settings.ActivateSource.ReplaceControls(this, Configuration.Controls, cbActivateSource);
221 settings.DeviceType.ReplaceControls(this, Configuration.Controls, lDeviceType, cbDeviceType);
222 settings.TVVendor.ReplaceControls(this, Configuration.Controls, cbVendorId);
223 settings.StartHidden.ReplaceControls(this, Configuration.Controls, cbStartMinimised);
226 private void BSaveClick(object sender, EventArgs e)
228 Controller.PersistSettings();
231 private void BReloadConfigClick(object sender, EventArgs e)
233 Controller.ResetDefaultSettings();
237 #region CEC Tester tab
238 delegate void SetActiveDevicesCallback(string[] activeDevices);
239 public void SetActiveDevices(string[] activeDevices)
241 if (cbCommandDestination.InvokeRequired)
243 SetActiveDevicesCallback d = SetActiveDevices;
246 Invoke(d, new object[] { activeDevices });
248 catch (Exception) { }
252 cbCommandDestination.Items.Clear();
253 foreach (string item in activeDevices)
254 cbCommandDestination.Items.Add(item);
258 delegate CecLogicalAddress GetTargetDeviceCallback();
259 private CecLogicalAddress GetTargetDevice()
261 if (cbCommandDestination.InvokeRequired)
263 GetTargetDeviceCallback d = GetTargetDevice;
264 CecLogicalAddress retval = CecLogicalAddress.Unknown;
267 retval = (CecLogicalAddress)Invoke(d, new object[] { });
269 catch (Exception) { }
273 return CECSettingLogicalAddresses.GetLogicalAddressFromString(cbCommandDestination.Text);
276 private void BSendImageViewOnClick(object sender, EventArgs e)
278 Controller.CECActions.SendImageViewOn(GetTargetDevice());
281 private void BStandbyClick(object sender, EventArgs e)
283 Controller.CECActions.SendStandby(GetTargetDevice());
286 private void BScanClick(object sender, EventArgs e)
288 Controller.CECActions.ShowDeviceInfo(GetTargetDevice());
291 private void BActivateSourceClick(object sender, EventArgs e)
293 Controller.CECActions.ActivateSource(GetTargetDevice());
296 private void CbCommandDestinationSelectedIndexChanged(object sender, EventArgs e)
298 bool enableVolumeButtons = (GetTargetDevice() == CecLogicalAddress.AudioSystem);
299 bVolUp.Enabled = enableVolumeButtons;
300 bVolDown.Enabled = enableVolumeButtons;
301 bMute.Enabled = enableVolumeButtons;
302 bActivateSource.Enabled = (GetTargetDevice() != CecLogicalAddress.Broadcast);
303 bScan.Enabled = (GetTargetDevice() != CecLogicalAddress.Broadcast);
306 private void BVolUpClick(object sender, EventArgs e)
308 Controller.Lib.VolumeUp(true);
311 private void BVolDownClick(object sender, EventArgs e)
313 Controller.Lib.VolumeDown(true);
316 private void BMuteClick(object sender, EventArgs e)
318 Controller.Lib.MuteAudio(true);
321 private void BRescanDevicesClick(object sender, EventArgs e)
323 Controller.CECActions.RescanDevices();
328 delegate void UpdateLogCallback();
329 private void UpdateLog()
331 if (tbLog.InvokeRequired)
333 UpdateLogCallback d = UpdateLog;
336 Invoke(d, new object[] { });
338 catch (Exception) { }
343 tbLog.Select(tbLog.Text.Length, 0);
344 tbLog.ScrollToCaret();
348 public void AddLogMessage(CecLogMessage message)
350 string strLevel = "";
351 bool display = false;
352 switch (message.Level)
354 case CecLogLevel.Error:
355 strLevel = "ERROR: ";
356 display = cbLogError.Checked;
358 case CecLogLevel.Warning:
359 strLevel = "WARNING: ";
360 display = cbLogWarning.Checked;
362 case CecLogLevel.Notice:
363 strLevel = "NOTICE: ";
364 display = cbLogNotice.Checked;
366 case CecLogLevel.Traffic:
367 strLevel = "TRAFFIC: ";
368 display = cbLogTraffic.Checked;
370 case CecLogLevel.Debug:
371 strLevel = "DEBUG: ";
372 display = cbLogDebug.Checked;
378 string strLog = string.Format("{0} {1,16} {2}", strLevel, message.Time, message.Message) + Environment.NewLine;
379 AddLogMessage(strLog);
383 public void AddLogMessage(string message)
387 if (_selectedTab == ConfigTab.Log)
391 private void BClearLogClick(object sender, EventArgs e)
397 private void BSaveLogClick(object sender, EventArgs e)
399 SaveFileDialog dialog = new SaveFileDialog
401 Title = Resources.where_do_you_want_to_store_the_log,
402 InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
403 FileName = Resources.cec_log_filename,
404 Filter = Resources.cec_log_filter,
408 if (dialog.ShowDialog() == DialogResult.OK)
410 FileStream fs = (FileStream)dialog.OpenFile();
413 MessageBox.Show(string.Format(Resources.cannot_open_for_writing, dialog.FileName), Resources.app_name, MessageBoxButtons.OK, MessageBoxIcon.Error);
417 StreamWriter writer = new StreamWriter(fs);
422 MessageBox.Show(string.Format(Resources.log_stored_as, dialog.FileName), Resources.app_name, MessageBoxButtons.OK, MessageBoxIcon.Information);
428 #region Tray icon and window controls
429 private void HideToolStripMenuItemClick(object sender, EventArgs e)
434 private void CloseToolStripMenuItemClick(object sender, EventArgs e)
439 private void AboutToolStripMenuItemClick(object sender, EventArgs e)
441 (new About(Controller.LibServerVersion, Controller.LibClientVersion, Controller.LibInfo)).ShowDialog();
444 private void AdvancedModeToolStripMenuItemClick(object sender, EventArgs e)
446 Controller.Settings.AdvancedMode.Value = !advancedModeToolStripMenuItem.Checked;
447 ShowHideAdvanced(!advancedModeToolStripMenuItem.Checked);
450 private void BCancelClick(object sender, EventArgs e)
455 private void TrayIconClick(object sender, EventArgs e)
457 if (e is MouseEventArgs && (e as MouseEventArgs).Button == MouseButtons.Left)
463 ShowInTaskbar = false;
465 tsMenuShowHide.Text = Resources.show;
470 ShowInTaskbar = true;
471 WindowState = FormWindowState.Normal;
473 tsMenuShowHide.Text = Resources.hide;
476 private void ShowHideToggle()
478 if (Visible && WindowState != FormWindowState.Minimized)
480 Controller.Settings.StartHidden.Value = true;
485 Controller.Settings.StartHidden.Value = false;
490 private void TsMenuCloseClick(object sender, EventArgs e)
495 private void CECTrayResize(object sender, EventArgs e)
497 if (WindowState == FormWindowState.Minimized)
503 private void TsMenuShowHideClick(object sender, EventArgs e)
508 public void ShowHideAdvanced(bool setTo)
512 tsAdvanced.Checked = true;
513 advancedModeToolStripMenuItem.Checked = true;
515 if (!tabPanel.Controls.Contains(tbTestCommands))
516 TabControls.Add(tbTestCommands);
517 if (!tabPanel.Controls.Contains(LogOutput))
518 TabControls.Add(LogOutput);
523 tsAdvanced.Checked = false;
524 advancedModeToolStripMenuItem.Checked = false;
526 tabPanel.Controls.Remove(tbTestCommands);
527 tabPanel.Controls.Remove(LogOutput);
532 private void TsAdvancedClick(object sender, EventArgs e)
534 Controller.Settings.AdvancedMode.Value = !tsAdvanced.Checked;
535 ShowHideAdvanced(!tsAdvanced.Checked);
538 public void SetStatusText(string status)
540 SetControlText(lStatus, status);
543 public void SetProgressBar(int progress, bool visible)
545 SetControlVisible(pProgress, visible);
546 SetProgressValue(pProgress, progress);
549 public void SetControlsEnabled(bool val)
552 SetControlEnabled(bClose, val);
553 SetControlEnabled(bSaveConfig, val);
554 SetControlEnabled(bReloadConfig, val);
557 SetControlEnabled(bRescanDevices, val);
558 SetControlEnabled(bSendImageViewOn, val);
559 SetControlEnabled(bStandby, val);
560 SetControlEnabled(bActivateSource, val);
561 SetControlEnabled(bScan, val);
563 bool enableVolumeButtons = (GetTargetDevice() == CecLogicalAddress.AudioSystem) && val;
564 SetControlEnabled(bVolUp, enableVolumeButtons);
565 SetControlEnabled(bVolDown, enableVolumeButtons);
566 SetControlEnabled(bMute, enableVolumeButtons);
569 private void TabControl1SelectedIndexChanged(object sender, EventArgs e)
571 switch (tabPanel.TabPages[tabPanel.SelectedIndex].Name)
573 case "tbTestCommands":
574 _selectedTab = ConfigTab.Tester;
577 _selectedTab = ConfigTab.Log;
581 _selectedTab = ConfigTab.Configuration;
587 #region Class members
588 private ConfigTab _selectedTab = ConfigTab.Configuration;
589 private string _log = string.Empty;
590 private CECController _controller;
591 public CECController Controller
595 return _controller ?? (_controller = new CECController(this));
598 public Control.ControlCollection TabControls
600 get { return tabPanel.Controls; }
602 public string SelectedTabName
604 get { return GetSelectedTabName(tabPanel, tabPanel.TabPages); }
608 private void AddNewApplicationToolStripMenuItemClick(object sender, EventArgs e)
610 ConfigureApplication appConfig = new ConfigureApplication(Controller.Settings, Controller);
611 Controller.DisplayDialog(appConfig, false);