do not wake the system when exiting away mode
[deb_libcec.git] / src / LibCecTray / ui / CECTray.cs
CommitLineData
f017f3c4
LOK
1/*
2 * This file is part of the libCEC(R) library.
3 *
16f47961 4 * libCEC(R) is Copyright (C) 2011-2013 Pulse-Eight Limited. All rights reserved.
f017f3c4
LOK
5 * libCEC(R) is an original work, containing original code.
6 *
7 * libCEC(R) is a trademark of Pulse-Eight Limited.
8 *
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.
13 *
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.
18 *
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.
22 *
23 *
24 * Alternatively, you can license this library under a commercial license,
25 * please contact Pulse-Eight Licensing for more information.
26 *
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/
31 */
32
33using System;
34using System.Windows.Forms;
35using CecSharp;
36using System.IO;
37using LibCECTray.Properties;
38using LibCECTray.controller;
39using LibCECTray.controller.applications;
40using LibCECTray.settings;
fec04a82
LOK
41using Microsoft.Win32;
42using System.Security.Permissions;
07224bf3 43using System.Runtime.InteropServices;
f017f3c4
LOK
44
45namespace LibCECTray.ui
46{
47 /// <summary>
48 /// The tab pages in this application
49 /// </summary>
50 internal enum ConfigTab
51 {
52 Configuration,
53 KeyConfiguration,
54 Tester,
55 Log,
56 WMC,
57 XBMC
58 }
59
60 /// <summary>
61 /// Main LibCecTray GUI
62 /// </summary>
63 partial class CECTray : AsyncForm
64 {
65 public CECTray()
66 {
67 Text = Resources.app_name;
68 InitializeComponent();
f017f3c4
LOK
69 VisibleChanged += delegate
70 {
71 if (!Visible)
72 OnHide();
73 else
74 OnShow();
75 };
07224bf3 76
fec04a82
LOK
77 SystemEvents.SessionEnding += new SessionEndingEventHandler(OnSessionEnding);
78 }
79
80 public void OnSessionEnding(object sender, SessionEndingEventArgs e)
81 {
82 Controller.Close();
83 }
84
07224bf3
LOK
85 #region Power state change window messages
86 private const int WM_POWERBROADCAST = 0x0218;
87 private const int PBT_APMSUSPEND = 0x0004;
88 private const int PBT_APMRESUMESUSPEND = 0x0007;
89 private const int PBT_APMRESUMECRITICAL = 0x0006;
90 private const int PBT_APMRESUMEAUTOMATIC = 0x0012;
91 private const int PBT_POWERSETTINGCHANGE = 0x8013;
92 private static Guid GUID_SYSTEM_AWAYMODE = new Guid("98a7f580-01f7-48aa-9c0f-44352c29e5c0");
93
94 [StructLayout(LayoutKind.Sequential, Pack = 4)]
95 internal struct POWERBROADCAST_SETTING
96 {
97 public Guid PowerSetting;
98 public uint DataLength;
99 public byte Data;
100 }
101 #endregion
102
103 /// <summary>
104 /// Check for power state changes, and pass up when it's something we don't care about
105 /// </summary>
106 /// <param name="msg">The incoming window message</param>
107 protected override void WndProc(ref Message msg)
fec04a82 108 {
07224bf3 109 if (msg.Msg == WM_POWERBROADCAST)
fec04a82 110 {
07224bf3
LOK
111 switch (msg.WParam.ToInt32())
112 {
113 case PBT_APMSUSPEND:
114 OnSleep();
115 return;
116
117 case PBT_APMRESUMESUSPEND:
118 case PBT_APMRESUMECRITICAL:
119 case PBT_APMRESUMEAUTOMATIC:
120 OnWake();
121 return;
122
123 case PBT_POWERSETTINGCHANGE:
124 {
125 POWERBROADCAST_SETTING pwr = (POWERBROADCAST_SETTING)Marshal.PtrToStructure(msg.LParam, typeof(POWERBROADCAST_SETTING));
126 if (pwr.PowerSetting == GUID_SYSTEM_AWAYMODE && pwr.DataLength == Marshal.SizeOf(typeof(Int32)))
127 {
128 switch (pwr.Data)
129 {
130 case 0:
eb9465c9
LOK
131 // do _not_ wake the pc when away mode is deactivated
132 //OnWake();
133 //return;
07224bf3
LOK
134 case 1:
135 OnSleep();
136 return;
137 default:
138 break;
139 }
140 }
141 }
142 break;
143 default:
144 break;
145 }
fec04a82 146 }
07224bf3
LOK
147
148 // pass up when not handled
149 base.WndProc(ref msg);
150 }
151
152 private void OnWake()
153 {
154 Controller.Initialise();
155 }
156
157 private void OnSleep()
158 {
159 Controller.Close();
f017f3c4
LOK
160 }
161
162 public override sealed string Text
163 {
164 get { return base.Text; }
165 set { base.Text = value; }
166 }
167
97401db1 168 public void Initialise()
f017f3c4 169 {
c4bc8944 170 Controller.Initialise();
f017f3c4
LOK
171 }
172
173 protected override void Dispose(bool disposing)
174 {
175 Hide();
176 if (disposing)
177 {
c4bc8944 178 Controller.Close();
f017f3c4
LOK
179 }
180 if (disposing && (components != null))
181 {
182 components.Dispose();
183 }
184 base.Dispose(disposing);
185 }
186
187 #region Configuration tab
188 /// <summary>
189 /// Replaces the gui controls by the ones that are bound to the settings.
190 /// 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
191 /// </summary>
192 public void InitialiseSettingsComponent(CECSettings settings)
193 {
194 settings.WakeDevices.ReplaceControls(this, Configuration.Controls, lWakeDevices, cbWakeDevices);
195 settings.PowerOffDevices.ReplaceControls(this, Configuration.Controls, lPowerOff, cbPowerOffDevices);
196 settings.OverridePhysicalAddress.ReplaceControls(this, Configuration.Controls, cbOverrideAddress);
197 settings.OverrideTVVendor.ReplaceControls(this, Configuration.Controls, cbVendorOverride);
198 settings.PhysicalAddress.ReplaceControls(this, Configuration.Controls, tbPhysicalAddress);
199 settings.HDMIPort.ReplaceControls(this, Configuration.Controls, lPortNumber, cbPortNumber);
200 settings.ConnectedDevice.ReplaceControls(this, Configuration.Controls, lConnectedDevice, cbConnectedDevice);
201 settings.ActivateSource.ReplaceControls(this, Configuration.Controls, cbActivateSource);
202 settings.DeviceType.ReplaceControls(this, Configuration.Controls, lDeviceType, cbDeviceType);
203 settings.TVVendor.ReplaceControls(this, Configuration.Controls, cbVendorId);
204 settings.StartHidden.ReplaceControls(this, Configuration.Controls, cbStartMinimised);
205 }
206
207 private void BSaveClick(object sender, EventArgs e)
208 {
c4bc8944 209 Controller.PersistSettings();
f017f3c4
LOK
210 }
211
212 private void BReloadConfigClick(object sender, EventArgs e)
213 {
c4bc8944 214 Controller.ResetDefaultSettings();
f017f3c4
LOK
215 }
216 #endregion
217
218 #region CEC Tester tab
219 delegate void SetActiveDevicesCallback(string[] activeDevices);
220 public void SetActiveDevices(string[] activeDevices)
221 {
222 if (cbCommandDestination.InvokeRequired)
223 {
224 SetActiveDevicesCallback d = SetActiveDevices;
225 try
226 {
227 Invoke(d, new object[] { activeDevices });
228 }
229 catch (Exception) { }
230 }
231 else
232 {
233 cbCommandDestination.Items.Clear();
234 foreach (string item in activeDevices)
235 cbCommandDestination.Items.Add(item);
236 }
237 }
238
239 delegate CecLogicalAddress GetTargetDeviceCallback();
240 private CecLogicalAddress GetTargetDevice()
241 {
242 if (cbCommandDestination.InvokeRequired)
243 {
244 GetTargetDeviceCallback d = GetTargetDevice;
245 CecLogicalAddress retval = CecLogicalAddress.Unknown;
246 try
247 {
248 retval = (CecLogicalAddress)Invoke(d, new object[] { });
249 }
250 catch (Exception) { }
251 return retval;
252 }
253
254 return CECSettingLogicalAddresses.GetLogicalAddressFromString(cbCommandDestination.Text);
255 }
256
257 private void BSendImageViewOnClick(object sender, EventArgs e)
258 {
c4bc8944 259 Controller.CECActions.SendImageViewOn(GetTargetDevice());
f017f3c4
LOK
260 }
261
262 private void BStandbyClick(object sender, EventArgs e)
263 {
c4bc8944 264 Controller.CECActions.SendStandby(GetTargetDevice());
f017f3c4
LOK
265 }
266
267 private void BScanClick(object sender, EventArgs e)
268 {
c4bc8944 269 Controller.CECActions.ShowDeviceInfo(GetTargetDevice());
f017f3c4
LOK
270 }
271
272 private void BActivateSourceClick(object sender, EventArgs e)
273 {
c4bc8944 274 Controller.CECActions.ActivateSource(GetTargetDevice());
f017f3c4
LOK
275 }
276
277 private void CbCommandDestinationSelectedIndexChanged(object sender, EventArgs e)
278 {
279 bool enableVolumeButtons = (GetTargetDevice() == CecLogicalAddress.AudioSystem);
280 bVolUp.Enabled = enableVolumeButtons;
281 bVolDown.Enabled = enableVolumeButtons;
282 bMute.Enabled = enableVolumeButtons;
283 bActivateSource.Enabled = (GetTargetDevice() != CecLogicalAddress.Broadcast);
284 bScan.Enabled = (GetTargetDevice() != CecLogicalAddress.Broadcast);
285 }
286
287 private void BVolUpClick(object sender, EventArgs e)
288 {
c4bc8944 289 Controller.Lib.VolumeUp(true);
f017f3c4
LOK
290 }
291
292 private void BVolDownClick(object sender, EventArgs e)
293 {
c4bc8944 294 Controller.Lib.VolumeDown(true);
f017f3c4
LOK
295 }
296
297 private void BMuteClick(object sender, EventArgs e)
298 {
c4bc8944 299 Controller.Lib.MuteAudio(true);
f017f3c4
LOK
300 }
301
302 private void BRescanDevicesClick(object sender, EventArgs e)
303 {
c4bc8944 304 Controller.CECActions.RescanDevices();
f017f3c4
LOK
305 }
306 #endregion
307
308 #region Log tab
309 delegate void UpdateLogCallback();
310 private void UpdateLog()
311 {
312 if (tbLog.InvokeRequired)
313 {
314 UpdateLogCallback d = UpdateLog;
315 try
316 {
317 Invoke(d, new object[] { });
318 }
319 catch (Exception) { }
320 }
321 else
322 {
323 tbLog.Text = _log;
324 tbLog.Select(tbLog.Text.Length, 0);
325 tbLog.ScrollToCaret();
326 }
327 }
328
329 public void AddLogMessage(CecLogMessage message)
330 {
331 string strLevel = "";
332 bool display = false;
333 switch (message.Level)
334 {
335 case CecLogLevel.Error:
336 strLevel = "ERROR: ";
337 display = cbLogError.Checked;
338 break;
339 case CecLogLevel.Warning:
340 strLevel = "WARNING: ";
341 display = cbLogWarning.Checked;
342 break;
343 case CecLogLevel.Notice:
344 strLevel = "NOTICE: ";
345 display = cbLogNotice.Checked;
346 break;
347 case CecLogLevel.Traffic:
348 strLevel = "TRAFFIC: ";
349 display = cbLogTraffic.Checked;
350 break;
351 case CecLogLevel.Debug:
352 strLevel = "DEBUG: ";
353 display = cbLogDebug.Checked;
354 break;
355 }
356
357 if (display)
358 {
359 string strLog = string.Format("{0} {1,16} {2}", strLevel, message.Time, message.Message) + Environment.NewLine;
360 AddLogMessage(strLog);
361 }
362 }
363
364 public void AddLogMessage(string message)
365 {
366 _log += message;
367
368 if (_selectedTab == ConfigTab.Log)
369 UpdateLog();
370 }
371
372 private void BClearLogClick(object sender, EventArgs e)
373 {
374 _log = string.Empty;
375 UpdateLog();
376 }
377
378 private void BSaveLogClick(object sender, EventArgs e)
379 {
380 SaveFileDialog dialog = new SaveFileDialog
381 {
382 Title = Resources.where_do_you_want_to_store_the_log,
383 InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
384 FileName = Resources.cec_log_filename,
385 Filter = Resources.cec_log_filter,
386 FilterIndex = 1
387 };
388
389 if (dialog.ShowDialog() == DialogResult.OK)
390 {
391 FileStream fs = (FileStream)dialog.OpenFile();
392 if (!fs.CanWrite)
393 {
394 MessageBox.Show(string.Format(Resources.cannot_open_for_writing, dialog.FileName), Resources.app_name, MessageBoxButtons.OK, MessageBoxIcon.Error);
395 }
396 else
397 {
398 StreamWriter writer = new StreamWriter(fs);
399 writer.Write(_log);
400 writer.Close();
401 fs.Close();
402 fs.Dispose();
403 MessageBox.Show(string.Format(Resources.log_stored_as, dialog.FileName), Resources.app_name, MessageBoxButtons.OK, MessageBoxIcon.Information);
404 }
405 }
406 }
407 #endregion
408
409 #region Tray icon and window controls
410 private void HideToolStripMenuItemClick(object sender, EventArgs e)
411 {
412 ShowHideToggle();
413 }
414
415 private void CloseToolStripMenuItemClick(object sender, EventArgs e)
416 {
417 Dispose();
418 }
419
420 private void AboutToolStripMenuItemClick(object sender, EventArgs e)
421 {
c4bc8944 422 (new About(Controller.LibServerVersion, Controller.LibClientVersion, Controller.LibInfo)).ShowDialog();
f017f3c4
LOK
423 }
424
425 private void AdvancedModeToolStripMenuItemClick(object sender, EventArgs e)
426 {
c4bc8944 427 Controller.Settings.AdvancedMode.Value = !advancedModeToolStripMenuItem.Checked;
f017f3c4
LOK
428 ShowHideAdvanced(!advancedModeToolStripMenuItem.Checked);
429 }
430
431 private void BCancelClick(object sender, EventArgs e)
432 {
433 Dispose();
434 }
435
436 private void TrayIconClick(object sender, EventArgs e)
437 {
438 if (e is MouseEventArgs && (e as MouseEventArgs).Button == MouseButtons.Left)
439 ShowHideToggle();
440 }
441
442 public void OnHide()
443 {
444 ShowInTaskbar = false;
445 Visible = false;
446 tsMenuShowHide.Text = Resources.show;
447 }
448
449 public void OnShow()
450 {
451 ShowInTaskbar = true;
452 WindowState = FormWindowState.Normal;
453 Activate();
454 tsMenuShowHide.Text = Resources.hide;
455 }
456
457 private void ShowHideToggle()
458 {
459 if (Visible && WindowState != FormWindowState.Minimized)
460 {
c4bc8944 461 Controller.Settings.StartHidden.Value = true;
f017f3c4
LOK
462 Hide();
463 }
464 else
465 {
c4bc8944 466 Controller.Settings.StartHidden.Value = false;
f017f3c4
LOK
467 Show();
468 }
469 }
470
471 private void TsMenuCloseClick(object sender, EventArgs e)
472 {
473 Dispose();
474 }
475
476 private void CECTrayResize(object sender, EventArgs e)
477 {
478 if (WindowState == FormWindowState.Minimized)
177e3a7b 479 Hide();
f017f3c4 480 else
177e3a7b 481 Show();
f017f3c4
LOK
482 }
483
484 private void TsMenuShowHideClick(object sender, EventArgs e)
485 {
486 ShowHideToggle();
487 }
488
489 public void ShowHideAdvanced(bool setTo)
490 {
491 if (setTo)
492 {
493 tsAdvanced.Checked = true;
494 advancedModeToolStripMenuItem.Checked = true;
495 SuspendLayout();
496 if (!tabPanel.Controls.Contains(tbTestCommands))
497 TabControls.Add(tbTestCommands);
498 if (!tabPanel.Controls.Contains(LogOutput))
499 TabControls.Add(LogOutput);
500 ResumeLayout();
501 }
502 else
503 {
504 tsAdvanced.Checked = false;
505 advancedModeToolStripMenuItem.Checked = false;
506 SuspendLayout();
507 tabPanel.Controls.Remove(tbTestCommands);
508 tabPanel.Controls.Remove(LogOutput);
509 ResumeLayout();
510 }
511 }
512
513 private void TsAdvancedClick(object sender, EventArgs e)
514 {
c4bc8944 515 Controller.Settings.AdvancedMode.Value = !tsAdvanced.Checked;
f017f3c4
LOK
516 ShowHideAdvanced(!tsAdvanced.Checked);
517 }
518
519 public void SetStatusText(string status)
520 {
521 SetControlText(lStatus, status);
522 }
523
524 public void SetProgressBar(int progress, bool visible)
525 {
526 SetControlVisible(pProgress, visible);
527 SetProgressValue(pProgress, progress);
528 }
529
530 public void SetControlsEnabled(bool val)
531 {
532 //main tab
533 SetControlEnabled(bClose, val);
534 SetControlEnabled(bSaveConfig, val);
535 SetControlEnabled(bReloadConfig, val);
536
537 //tester tab
538 SetControlEnabled(bRescanDevices, val);
539 SetControlEnabled(bSendImageViewOn, val);
540 SetControlEnabled(bStandby, val);
541 SetControlEnabled(bActivateSource, val);
542 SetControlEnabled(bScan, val);
543
544 bool enableVolumeButtons = (GetTargetDevice() == CecLogicalAddress.AudioSystem) && val;
545 SetControlEnabled(bVolUp, enableVolumeButtons);
546 SetControlEnabled(bVolDown, enableVolumeButtons);
547 SetControlEnabled(bMute, enableVolumeButtons);
548 }
549
550 private void TabControl1SelectedIndexChanged(object sender, EventArgs e)
551 {
552 switch (tabPanel.TabPages[tabPanel.SelectedIndex].Name)
553 {
554 case "tbTestCommands":
555 _selectedTab = ConfigTab.Tester;
556 break;
557 case "LogOutput":
558 _selectedTab = ConfigTab.Log;
559 UpdateLog();
560 break;
561 default:
562 _selectedTab = ConfigTab.Configuration;
563 break;
564 }
565 }
566 #endregion
567
568 #region Class members
569 private ConfigTab _selectedTab = ConfigTab.Configuration;
570 private string _log = string.Empty;
c4bc8944 571 private CECController _controller;
49689754
LOK
572 public CECController Controller
573 {
97401db1
LOK
574 get
575 {
576 return _controller ?? (_controller = new CECController(this));
577 }
49689754 578 }
f017f3c4
LOK
579 public Control.ControlCollection TabControls
580 {
581 get { return tabPanel.Controls; }
582 }
583 public string SelectedTabName
584 {
585 get { return GetSelectedTabName(tabPanel, tabPanel.TabPages); }
586 }
587 #endregion
588
589 private void AddNewApplicationToolStripMenuItemClick(object sender, EventArgs e)
590 {
c4bc8944
LOK
591 ConfigureApplication appConfig = new ConfigureApplication(Controller.Settings, Controller);
592 Controller.DisplayDialog(appConfig, false);
f017f3c4
LOK
593 }
594 }
595}