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();
57 VisibleChanged += delegate
65 SystemEvents.SessionEnding += new SessionEndingEventHandler(OnSessionEnding);
68 public void OnSessionEnding(object sender, SessionEndingEventArgs e)
70 Controller.CECActions.SuppressUpdates = true;
74 #region Power state change window messages
75 private const int WM_POWERBROADCAST = 0x0218;
76 private const int PBT_APMSUSPEND = 0x0004;
77 private const int PBT_APMRESUMESUSPEND = 0x0007;
78 private const int PBT_APMRESUMECRITICAL = 0x0006;
79 private const int PBT_APMRESUMEAUTOMATIC = 0x0012;
80 private const int PBT_POWERSETTINGCHANGE = 0x8013;
81 private static Guid GUID_SYSTEM_AWAYMODE = new Guid("98a7f580-01f7-48aa-9c0f-44352c29e5c0");
83 [StructLayout(LayoutKind.Sequential, Pack = 4)]
84 internal struct POWERBROADCAST_SETTING
86 public Guid PowerSetting;
87 public uint DataLength;
93 /// Check for power state changes, and pass up when it's something we don't care about
95 /// <param name="msg">The incoming window message</param>
96 protected override void WndProc(ref Message msg)
98 if (msg.Msg == WM_POWERBROADCAST)
100 switch (msg.WParam.ToInt32())
106 case PBT_APMRESUMESUSPEND:
107 case PBT_APMRESUMECRITICAL:
108 case PBT_APMRESUMEAUTOMATIC:
112 case PBT_POWERSETTINGCHANGE:
114 POWERBROADCAST_SETTING pwr = (POWERBROADCAST_SETTING)Marshal.PtrToStructure(msg.LParam, typeof(POWERBROADCAST_SETTING));
115 if (pwr.PowerSetting == GUID_SYSTEM_AWAYMODE && pwr.DataLength == Marshal.SizeOf(typeof(Int32)))
120 // do _not_ wake the pc when away mode is deactivated
137 // pass up when not handled
138 base.WndProc(ref msg);
141 private void OnWake()
143 Controller.Initialise();
146 private void OnSleep()
151 public override sealed string Text
153 get { return base.Text; }
154 set { base.Text = value; }
157 public void Initialise()
159 Controller.Initialise();
162 protected override void Dispose(bool disposing)
167 Controller.CECActions.SuppressUpdates = true;
168 AsyncDisconnect dc = new AsyncDisconnect(Controller);
169 (new Thread(dc.Process)).Start();
171 if (disposing && (components != null))
173 components.Dispose();
175 base.Dispose(disposing);
178 #region Configuration tab
180 /// Replaces the gui controls by the ones that are bound to the settings.
181 /// 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
183 public void InitialiseSettingsComponent(CECSettings settings)
185 settings.WakeDevices.ReplaceControls(this, Configuration.Controls, lWakeDevices, cbWakeDevices);
186 settings.PowerOffDevices.ReplaceControls(this, Configuration.Controls, lPowerOff, cbPowerOffDevices);
187 settings.OverridePhysicalAddress.ReplaceControls(this, Configuration.Controls, cbOverrideAddress);
188 settings.OverrideTVVendor.ReplaceControls(this, Configuration.Controls, cbVendorOverride);
189 settings.PhysicalAddress.ReplaceControls(this, Configuration.Controls, tbPhysicalAddress);
190 settings.HDMIPort.ReplaceControls(this, Configuration.Controls, lPortNumber, cbPortNumber);
191 settings.ConnectedDevice.ReplaceControls(this, Configuration.Controls, lConnectedDevice, cbConnectedDevice);
192 settings.ActivateSource.ReplaceControls(this, Configuration.Controls, cbActivateSource);
193 settings.DeviceType.ReplaceControls(this, Configuration.Controls, lDeviceType, cbDeviceType);
194 settings.TVVendor.ReplaceControls(this, Configuration.Controls, cbVendorId);
195 settings.StartHidden.ReplaceControls(this, Configuration.Controls, cbStartMinimised);
198 private void BSaveClick(object sender, EventArgs e)
200 Controller.PersistSettings();
203 private void BReloadConfigClick(object sender, EventArgs e)
205 Controller.ResetDefaultSettings();
209 #region CEC Tester tab
210 delegate void SetActiveDevicesCallback(string[] activeDevices);
211 public void SetActiveDevices(string[] activeDevices)
213 if (cbCommandDestination.InvokeRequired)
215 SetActiveDevicesCallback d = SetActiveDevices;
218 Invoke(d, new object[] { activeDevices });
220 catch (Exception) { }
224 cbCommandDestination.Items.Clear();
225 foreach (string item in activeDevices)
226 cbCommandDestination.Items.Add(item);
230 delegate CecLogicalAddress GetTargetDeviceCallback();
231 private CecLogicalAddress GetTargetDevice()
233 if (cbCommandDestination.InvokeRequired)
235 GetTargetDeviceCallback d = GetTargetDevice;
236 CecLogicalAddress retval = CecLogicalAddress.Unknown;
239 retval = (CecLogicalAddress)Invoke(d, new object[] { });
241 catch (Exception) { }
245 return CECSettingLogicalAddresses.GetLogicalAddressFromString(cbCommandDestination.Text);
248 private void BSendImageViewOnClick(object sender, EventArgs e)
250 Controller.CECActions.SendImageViewOn(GetTargetDevice());
253 private void BStandbyClick(object sender, EventArgs e)
255 Controller.CECActions.SendStandby(GetTargetDevice());
258 private void BScanClick(object sender, EventArgs e)
260 Controller.CECActions.ShowDeviceInfo(GetTargetDevice());
263 private void BActivateSourceClick(object sender, EventArgs e)
265 Controller.CECActions.ActivateSource(GetTargetDevice());
268 private void CbCommandDestinationSelectedIndexChanged(object sender, EventArgs e)
270 bool enableVolumeButtons = (GetTargetDevice() == CecLogicalAddress.AudioSystem);
271 bVolUp.Enabled = enableVolumeButtons;
272 bVolDown.Enabled = enableVolumeButtons;
273 bMute.Enabled = enableVolumeButtons;
274 bActivateSource.Enabled = (GetTargetDevice() != CecLogicalAddress.Broadcast);
275 bScan.Enabled = (GetTargetDevice() != CecLogicalAddress.Broadcast);
278 private void BVolUpClick(object sender, EventArgs e)
280 Controller.Lib.VolumeUp(true);
283 private void BVolDownClick(object sender, EventArgs e)
285 Controller.Lib.VolumeDown(true);
288 private void BMuteClick(object sender, EventArgs e)
290 Controller.Lib.MuteAudio(true);
293 private void BRescanDevicesClick(object sender, EventArgs e)
295 Controller.CECActions.RescanDevices();
300 delegate void UpdateLogCallback();
301 private void UpdateLog()
303 if (tbLog.InvokeRequired)
305 UpdateLogCallback d = UpdateLog;
308 Invoke(d, new object[] { });
310 catch (Exception) { }
315 tbLog.Select(tbLog.Text.Length, 0);
316 tbLog.ScrollToCaret();
320 public void AddLogMessage(CecLogMessage message)
322 string strLevel = "";
323 bool display = false;
324 switch (message.Level)
326 case CecLogLevel.Error:
327 strLevel = "ERROR: ";
328 display = cbLogError.Checked;
330 case CecLogLevel.Warning:
331 strLevel = "WARNING: ";
332 display = cbLogWarning.Checked;
334 case CecLogLevel.Notice:
335 strLevel = "NOTICE: ";
336 display = cbLogNotice.Checked;
338 case CecLogLevel.Traffic:
339 strLevel = "TRAFFIC: ";
340 display = cbLogTraffic.Checked;
342 case CecLogLevel.Debug:
343 strLevel = "DEBUG: ";
344 display = cbLogDebug.Checked;
350 string strLog = string.Format("{0} {1,16} {2}", strLevel, message.Time, message.Message) + Environment.NewLine;
351 AddLogMessage(strLog);
355 public void AddLogMessage(string message)
359 if (_selectedTab == ConfigTab.Log)
363 private void BClearLogClick(object sender, EventArgs e)
369 private void BSaveLogClick(object sender, EventArgs e)
371 SaveFileDialog dialog = new SaveFileDialog
373 Title = Resources.where_do_you_want_to_store_the_log,
374 InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
375 FileName = Resources.cec_log_filename,
376 Filter = Resources.cec_log_filter,
380 if (dialog.ShowDialog() == DialogResult.OK)
382 FileStream fs = (FileStream)dialog.OpenFile();
385 MessageBox.Show(string.Format(Resources.cannot_open_for_writing, dialog.FileName), Resources.app_name, MessageBoxButtons.OK, MessageBoxIcon.Error);
389 StreamWriter writer = new StreamWriter(fs);
394 MessageBox.Show(string.Format(Resources.log_stored_as, dialog.FileName), Resources.app_name, MessageBoxButtons.OK, MessageBoxIcon.Information);
400 #region Tray icon and window controls
401 private void HideToolStripMenuItemClick(object sender, EventArgs e)
406 private void CloseToolStripMenuItemClick(object sender, EventArgs e)
411 private void AboutToolStripMenuItemClick(object sender, EventArgs e)
413 (new About(Controller.LibServerVersion, Controller.LibClientVersion, Controller.LibInfo)).ShowDialog();
416 private void AdvancedModeToolStripMenuItemClick(object sender, EventArgs e)
418 Controller.Settings.AdvancedMode.Value = !advancedModeToolStripMenuItem.Checked;
419 ShowHideAdvanced(!advancedModeToolStripMenuItem.Checked);
422 private void BCancelClick(object sender, EventArgs e)
427 private void TrayIconClick(object sender, EventArgs e)
429 if (e is MouseEventArgs && (e as MouseEventArgs).Button == MouseButtons.Left)
435 ShowInTaskbar = false;
437 tsMenuShowHide.Text = Resources.show;
442 ShowInTaskbar = true;
443 WindowState = FormWindowState.Normal;
445 tsMenuShowHide.Text = Resources.hide;
448 private void ShowHideToggle()
450 if (Visible && WindowState != FormWindowState.Minimized)
452 Controller.Settings.StartHidden.Value = true;
457 Controller.Settings.StartHidden.Value = false;
462 private void TsMenuCloseClick(object sender, EventArgs e)
467 private void CECTrayResize(object sender, EventArgs e)
469 if (WindowState == FormWindowState.Minimized)
475 private void TsMenuShowHideClick(object sender, EventArgs e)
480 public void ShowHideAdvanced(bool setTo)
484 tsAdvanced.Checked = true;
485 advancedModeToolStripMenuItem.Checked = true;
487 if (!tabPanel.Controls.Contains(tbTestCommands))
488 TabControls.Add(tbTestCommands);
489 if (!tabPanel.Controls.Contains(LogOutput))
490 TabControls.Add(LogOutput);
495 tsAdvanced.Checked = false;
496 advancedModeToolStripMenuItem.Checked = false;
498 tabPanel.Controls.Remove(tbTestCommands);
499 tabPanel.Controls.Remove(LogOutput);
504 private void TsAdvancedClick(object sender, EventArgs e)
506 Controller.Settings.AdvancedMode.Value = !tsAdvanced.Checked;
507 ShowHideAdvanced(!tsAdvanced.Checked);
510 public void SetStatusText(string status)
512 SetControlText(lStatus, status);
515 public void SetProgressBar(int progress, bool visible)
517 SetControlVisible(pProgress, visible);
518 SetProgressValue(pProgress, progress);
521 public void SetControlsEnabled(bool val)
524 SetControlEnabled(bClose, val);
525 SetControlEnabled(bSaveConfig, val);
526 SetControlEnabled(bReloadConfig, val);
529 SetControlEnabled(bRescanDevices, val);
530 SetControlEnabled(bSendImageViewOn, val);
531 SetControlEnabled(bStandby, val);
532 SetControlEnabled(bActivateSource, val);
533 SetControlEnabled(bScan, val);
535 bool enableVolumeButtons = (GetTargetDevice() == CecLogicalAddress.AudioSystem) && val;
536 SetControlEnabled(bVolUp, enableVolumeButtons);
537 SetControlEnabled(bVolDown, enableVolumeButtons);
538 SetControlEnabled(bMute, enableVolumeButtons);
541 private void TabControl1SelectedIndexChanged(object sender, EventArgs e)
543 switch (tabPanel.TabPages[tabPanel.SelectedIndex].Name)
545 case "tbTestCommands":
546 _selectedTab = ConfigTab.Tester;
549 _selectedTab = ConfigTab.Log;
553 _selectedTab = ConfigTab.Configuration;
559 #region Class members
560 private ConfigTab _selectedTab = ConfigTab.Configuration;
561 private string _log = string.Empty;
562 private CECController _controller;
563 public CECController Controller
567 return _controller ?? (_controller = new CECController(this));
570 public Control.ControlCollection TabControls
572 get { return tabPanel.Controls; }
574 public string SelectedTabName
576 get { return GetSelectedTabName(tabPanel, tabPanel.TabPages); }
580 private void AddNewApplicationToolStripMenuItemClick(object sender, EventArgs e)
582 ConfigureApplication appConfig = new ConfigureApplication(Controller.Settings, Controller);
583 Controller.DisplayDialog(appConfig, false);
588 /// The tab pages in this application
590 internal enum ConfigTab
600 class AsyncDisconnect
602 public AsyncDisconnect(CECController controller)
604 _controller = controller;
607 public void Process()
612 private CECController _controller;