handle windows away mode in cectray. treated like standby
[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:
131 OnWake();
132 return;
133 case 1:
134 OnSleep();
135 return;
136 default:
137 break;
138 }
139 }
140 }
141 break;
142 default:
143 break;
144 }
fec04a82 145 }
07224bf3
LOK
146
147 // pass up when not handled
148 base.WndProc(ref msg);
149 }
150
151 private void OnWake()
152 {
153 Controller.Initialise();
154 }
155
156 private void OnSleep()
157 {
158 Controller.Close();
f017f3c4
LOK
159 }
160
161 public override sealed string Text
162 {
163 get { return base.Text; }
164 set { base.Text = value; }
165 }
166
97401db1 167 public void Initialise()
f017f3c4 168 {
c4bc8944 169 Controller.Initialise();
f017f3c4
LOK
170 }
171
172 protected override void Dispose(bool disposing)
173 {
174 Hide();
175 if (disposing)
176 {
c4bc8944 177 Controller.Close();
f017f3c4
LOK
178 }
179 if (disposing && (components != null))
180 {
181 components.Dispose();
182 }
183 base.Dispose(disposing);
184 }
185
186 #region Configuration tab
187 /// <summary>
188 /// Replaces the gui controls by the ones that are bound to the settings.
189 /// 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
190 /// </summary>
191 public void InitialiseSettingsComponent(CECSettings settings)
192 {
193 settings.WakeDevices.ReplaceControls(this, Configuration.Controls, lWakeDevices, cbWakeDevices);
194 settings.PowerOffDevices.ReplaceControls(this, Configuration.Controls, lPowerOff, cbPowerOffDevices);
195 settings.OverridePhysicalAddress.ReplaceControls(this, Configuration.Controls, cbOverrideAddress);
196 settings.OverrideTVVendor.ReplaceControls(this, Configuration.Controls, cbVendorOverride);
197 settings.PhysicalAddress.ReplaceControls(this, Configuration.Controls, tbPhysicalAddress);
198 settings.HDMIPort.ReplaceControls(this, Configuration.Controls, lPortNumber, cbPortNumber);
199 settings.ConnectedDevice.ReplaceControls(this, Configuration.Controls, lConnectedDevice, cbConnectedDevice);
200 settings.ActivateSource.ReplaceControls(this, Configuration.Controls, cbActivateSource);
201 settings.DeviceType.ReplaceControls(this, Configuration.Controls, lDeviceType, cbDeviceType);
202 settings.TVVendor.ReplaceControls(this, Configuration.Controls, cbVendorId);
203 settings.StartHidden.ReplaceControls(this, Configuration.Controls, cbStartMinimised);
204 }
205
206 private void BSaveClick(object sender, EventArgs e)
207 {
c4bc8944 208 Controller.PersistSettings();
f017f3c4
LOK
209 }
210
211 private void BReloadConfigClick(object sender, EventArgs e)
212 {
c4bc8944 213 Controller.ResetDefaultSettings();
f017f3c4
LOK
214 }
215 #endregion
216
217 #region CEC Tester tab
218 delegate void SetActiveDevicesCallback(string[] activeDevices);
219 public void SetActiveDevices(string[] activeDevices)
220 {
221 if (cbCommandDestination.InvokeRequired)
222 {
223 SetActiveDevicesCallback d = SetActiveDevices;
224 try
225 {
226 Invoke(d, new object[] { activeDevices });
227 }
228 catch (Exception) { }
229 }
230 else
231 {
232 cbCommandDestination.Items.Clear();
233 foreach (string item in activeDevices)
234 cbCommandDestination.Items.Add(item);
235 }
236 }
237
238 delegate CecLogicalAddress GetTargetDeviceCallback();
239 private CecLogicalAddress GetTargetDevice()
240 {
241 if (cbCommandDestination.InvokeRequired)
242 {
243 GetTargetDeviceCallback d = GetTargetDevice;
244 CecLogicalAddress retval = CecLogicalAddress.Unknown;
245 try
246 {
247 retval = (CecLogicalAddress)Invoke(d, new object[] { });
248 }
249 catch (Exception) { }
250 return retval;
251 }
252
253 return CECSettingLogicalAddresses.GetLogicalAddressFromString(cbCommandDestination.Text);
254 }
255
256 private void BSendImageViewOnClick(object sender, EventArgs e)
257 {
c4bc8944 258 Controller.CECActions.SendImageViewOn(GetTargetDevice());
f017f3c4
LOK
259 }
260
261 private void BStandbyClick(object sender, EventArgs e)
262 {
c4bc8944 263 Controller.CECActions.SendStandby(GetTargetDevice());
f017f3c4
LOK
264 }
265
266 private void BScanClick(object sender, EventArgs e)
267 {
c4bc8944 268 Controller.CECActions.ShowDeviceInfo(GetTargetDevice());
f017f3c4
LOK
269 }
270
271 private void BActivateSourceClick(object sender, EventArgs e)
272 {
c4bc8944 273 Controller.CECActions.ActivateSource(GetTargetDevice());
f017f3c4
LOK
274 }
275
276 private void CbCommandDestinationSelectedIndexChanged(object sender, EventArgs e)
277 {
278 bool enableVolumeButtons = (GetTargetDevice() == CecLogicalAddress.AudioSystem);
279 bVolUp.Enabled = enableVolumeButtons;
280 bVolDown.Enabled = enableVolumeButtons;
281 bMute.Enabled = enableVolumeButtons;
282 bActivateSource.Enabled = (GetTargetDevice() != CecLogicalAddress.Broadcast);
283 bScan.Enabled = (GetTargetDevice() != CecLogicalAddress.Broadcast);
284 }
285
286 private void BVolUpClick(object sender, EventArgs e)
287 {
c4bc8944 288 Controller.Lib.VolumeUp(true);
f017f3c4
LOK
289 }
290
291 private void BVolDownClick(object sender, EventArgs e)
292 {
c4bc8944 293 Controller.Lib.VolumeDown(true);
f017f3c4
LOK
294 }
295
296 private void BMuteClick(object sender, EventArgs e)
297 {
c4bc8944 298 Controller.Lib.MuteAudio(true);
f017f3c4
LOK
299 }
300
301 private void BRescanDevicesClick(object sender, EventArgs e)
302 {
c4bc8944 303 Controller.CECActions.RescanDevices();
f017f3c4
LOK
304 }
305 #endregion
306
307 #region Log tab
308 delegate void UpdateLogCallback();
309 private void UpdateLog()
310 {
311 if (tbLog.InvokeRequired)
312 {
313 UpdateLogCallback d = UpdateLog;
314 try
315 {
316 Invoke(d, new object[] { });
317 }
318 catch (Exception) { }
319 }
320 else
321 {
322 tbLog.Text = _log;
323 tbLog.Select(tbLog.Text.Length, 0);
324 tbLog.ScrollToCaret();
325 }
326 }
327
328 public void AddLogMessage(CecLogMessage message)
329 {
330 string strLevel = "";
331 bool display = false;
332 switch (message.Level)
333 {
334 case CecLogLevel.Error:
335 strLevel = "ERROR: ";
336 display = cbLogError.Checked;
337 break;
338 case CecLogLevel.Warning:
339 strLevel = "WARNING: ";
340 display = cbLogWarning.Checked;
341 break;
342 case CecLogLevel.Notice:
343 strLevel = "NOTICE: ";
344 display = cbLogNotice.Checked;
345 break;
346 case CecLogLevel.Traffic:
347 strLevel = "TRAFFIC: ";
348 display = cbLogTraffic.Checked;
349 break;
350 case CecLogLevel.Debug:
351 strLevel = "DEBUG: ";
352 display = cbLogDebug.Checked;
353 break;
354 }
355
356 if (display)
357 {
358 string strLog = string.Format("{0} {1,16} {2}", strLevel, message.Time, message.Message) + Environment.NewLine;
359 AddLogMessage(strLog);
360 }
361 }
362
363 public void AddLogMessage(string message)
364 {
365 _log += message;
366
367 if (_selectedTab == ConfigTab.Log)
368 UpdateLog();
369 }
370
371 private void BClearLogClick(object sender, EventArgs e)
372 {
373 _log = string.Empty;
374 UpdateLog();
375 }
376
377 private void BSaveLogClick(object sender, EventArgs e)
378 {
379 SaveFileDialog dialog = new SaveFileDialog
380 {
381 Title = Resources.where_do_you_want_to_store_the_log,
382 InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
383 FileName = Resources.cec_log_filename,
384 Filter = Resources.cec_log_filter,
385 FilterIndex = 1
386 };
387
388 if (dialog.ShowDialog() == DialogResult.OK)
389 {
390 FileStream fs = (FileStream)dialog.OpenFile();
391 if (!fs.CanWrite)
392 {
393 MessageBox.Show(string.Format(Resources.cannot_open_for_writing, dialog.FileName), Resources.app_name, MessageBoxButtons.OK, MessageBoxIcon.Error);
394 }
395 else
396 {
397 StreamWriter writer = new StreamWriter(fs);
398 writer.Write(_log);
399 writer.Close();
400 fs.Close();
401 fs.Dispose();
402 MessageBox.Show(string.Format(Resources.log_stored_as, dialog.FileName), Resources.app_name, MessageBoxButtons.OK, MessageBoxIcon.Information);
403 }
404 }
405 }
406 #endregion
407
408 #region Tray icon and window controls
409 private void HideToolStripMenuItemClick(object sender, EventArgs e)
410 {
411 ShowHideToggle();
412 }
413
414 private void CloseToolStripMenuItemClick(object sender, EventArgs e)
415 {
416 Dispose();
417 }
418
419 private void AboutToolStripMenuItemClick(object sender, EventArgs e)
420 {
c4bc8944 421 (new About(Controller.LibServerVersion, Controller.LibClientVersion, Controller.LibInfo)).ShowDialog();
f017f3c4
LOK
422 }
423
424 private void AdvancedModeToolStripMenuItemClick(object sender, EventArgs e)
425 {
c4bc8944 426 Controller.Settings.AdvancedMode.Value = !advancedModeToolStripMenuItem.Checked;
f017f3c4
LOK
427 ShowHideAdvanced(!advancedModeToolStripMenuItem.Checked);
428 }
429
430 private void BCancelClick(object sender, EventArgs e)
431 {
432 Dispose();
433 }
434
435 private void TrayIconClick(object sender, EventArgs e)
436 {
437 if (e is MouseEventArgs && (e as MouseEventArgs).Button == MouseButtons.Left)
438 ShowHideToggle();
439 }
440
441 public void OnHide()
442 {
443 ShowInTaskbar = false;
444 Visible = false;
445 tsMenuShowHide.Text = Resources.show;
446 }
447
448 public void OnShow()
449 {
450 ShowInTaskbar = true;
451 WindowState = FormWindowState.Normal;
452 Activate();
453 tsMenuShowHide.Text = Resources.hide;
454 }
455
456 private void ShowHideToggle()
457 {
458 if (Visible && WindowState != FormWindowState.Minimized)
459 {
c4bc8944 460 Controller.Settings.StartHidden.Value = true;
f017f3c4
LOK
461 Hide();
462 }
463 else
464 {
c4bc8944 465 Controller.Settings.StartHidden.Value = false;
f017f3c4
LOK
466 Show();
467 }
468 }
469
470 private void TsMenuCloseClick(object sender, EventArgs e)
471 {
472 Dispose();
473 }
474
475 private void CECTrayResize(object sender, EventArgs e)
476 {
477 if (WindowState == FormWindowState.Minimized)
177e3a7b 478 Hide();
f017f3c4 479 else
177e3a7b 480 Show();
f017f3c4
LOK
481 }
482
483 private void TsMenuShowHideClick(object sender, EventArgs e)
484 {
485 ShowHideToggle();
486 }
487
488 public void ShowHideAdvanced(bool setTo)
489 {
490 if (setTo)
491 {
492 tsAdvanced.Checked = true;
493 advancedModeToolStripMenuItem.Checked = true;
494 SuspendLayout();
495 if (!tabPanel.Controls.Contains(tbTestCommands))
496 TabControls.Add(tbTestCommands);
497 if (!tabPanel.Controls.Contains(LogOutput))
498 TabControls.Add(LogOutput);
499 ResumeLayout();
500 }
501 else
502 {
503 tsAdvanced.Checked = false;
504 advancedModeToolStripMenuItem.Checked = false;
505 SuspendLayout();
506 tabPanel.Controls.Remove(tbTestCommands);
507 tabPanel.Controls.Remove(LogOutput);
508 ResumeLayout();
509 }
510 }
511
512 private void TsAdvancedClick(object sender, EventArgs e)
513 {
c4bc8944 514 Controller.Settings.AdvancedMode.Value = !tsAdvanced.Checked;
f017f3c4
LOK
515 ShowHideAdvanced(!tsAdvanced.Checked);
516 }
517
518 public void SetStatusText(string status)
519 {
520 SetControlText(lStatus, status);
521 }
522
523 public void SetProgressBar(int progress, bool visible)
524 {
525 SetControlVisible(pProgress, visible);
526 SetProgressValue(pProgress, progress);
527 }
528
529 public void SetControlsEnabled(bool val)
530 {
531 //main tab
532 SetControlEnabled(bClose, val);
533 SetControlEnabled(bSaveConfig, val);
534 SetControlEnabled(bReloadConfig, val);
535
536 //tester tab
537 SetControlEnabled(bRescanDevices, val);
538 SetControlEnabled(bSendImageViewOn, val);
539 SetControlEnabled(bStandby, val);
540 SetControlEnabled(bActivateSource, val);
541 SetControlEnabled(bScan, val);
542
543 bool enableVolumeButtons = (GetTargetDevice() == CecLogicalAddress.AudioSystem) && val;
544 SetControlEnabled(bVolUp, enableVolumeButtons);
545 SetControlEnabled(bVolDown, enableVolumeButtons);
546 SetControlEnabled(bMute, enableVolumeButtons);
547 }
548
549 private void TabControl1SelectedIndexChanged(object sender, EventArgs e)
550 {
551 switch (tabPanel.TabPages[tabPanel.SelectedIndex].Name)
552 {
553 case "tbTestCommands":
554 _selectedTab = ConfigTab.Tester;
555 break;
556 case "LogOutput":
557 _selectedTab = ConfigTab.Log;
558 UpdateLog();
559 break;
560 default:
561 _selectedTab = ConfigTab.Configuration;
562 break;
563 }
564 }
565 #endregion
566
567 #region Class members
568 private ConfigTab _selectedTab = ConfigTab.Configuration;
569 private string _log = string.Empty;
c4bc8944 570 private CECController _controller;
49689754
LOK
571 public CECController Controller
572 {
97401db1
LOK
573 get
574 {
575 return _controller ?? (_controller = new CECController(this));
576 }
49689754 577 }
f017f3c4
LOK
578 public Control.ControlCollection TabControls
579 {
580 get { return tabPanel.Controls; }
581 }
582 public string SelectedTabName
583 {
584 get { return GetSelectedTabName(tabPanel, tabPanel.TabPages); }
585 }
586 #endregion
587
588 private void AddNewApplicationToolStripMenuItemClick(object sender, EventArgs e)
589 {
c4bc8944
LOK
590 ConfigureApplication appConfig = new ConfigureApplication(Controller.Settings, Controller);
591 Controller.DisplayDialog(appConfig, false);
f017f3c4
LOK
592 }
593 }
594}