fixed - show/hide toggle when hiding the app via the taskbar
[deb_libcec.git] / src / LibCecTray / controller / applications / ApplicationController.cs
CommitLineData
f017f3c4
LOK
1/*
2 * This file is part of the libCEC(R) library.
3 *
4 * libCEC(R) is Copyright (C) 2011-2012 Pulse-Eight Limited. All rights reserved.
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.Diagnostics;
35using System.Drawing;
36using System.IO;
37using System.Windows.Forms;
38using CecSharp;
39using LibCECTray.Properties;
40using LibCECTray.settings;
41using Timer = System.Timers.Timer;
42
43namespace LibCECTray.controller.applications
44{
45 /// <summary>
46 /// Controls an application on the PC: send key presses, open the application, close it, etc.
47 /// </summary>
48 class ApplicationController
49 {
50 public ApplicationController(CECSettings settings, string uiName, string processName, string filename, string workingDirectory)
51 {
52 Settings = settings;
53 UiName = uiName;
54 ProcessName = processName;
55 ApplicationFilename = filename;
56 ApplicationWorkingDirectory = workingDirectory;
57 SuppressApplicationStart = false;
58 IsInternal = false;
59 }
60
61 public static ApplicationController FromString(CECSettings settings, string serialisedConfig)
62 {
63 var splitString = serialisedConfig.Split(';');
64 if (splitString.Length != 4)
65 throw new InvalidDataException("incorrect number of parameters");
66
67 return new ApplicationController(settings, splitString[0], splitString[1], splitString[2], splitString[3]);
68 }
69
70 public string AsString()
71 {
72 return string.Format("{0};{1};{2};{3}", UiName, ProcessName, ApplicationFilename, ApplicationWorkingDirectory);
73 }
74
75 public void BindButtonConfiguration(DataGridView gridView, BindingSource bindingSource)
76 {
77 CecButtonGridView = gridView;
78
79 DataGridViewCell buttonCellTemplate = new DataGridViewTextBoxCell();
80 CecButtonGridView.Columns.Add(new DataGridViewColumn(buttonCellTemplate)
81 {
82 DataPropertyName = "CecButtonName",
83 Name = Resources.config_cec_button,
84 ReadOnly = true,
85 Width = 150
86 });
87
88 DataGridViewButtonCell mappedToCellTemplate = new DataGridViewButtonCell();
89 CecButtonGridView.Columns.Add(new DataGridViewColumn(mappedToCellTemplate)
90 {
91 DataPropertyName = "MappedButtonName",
92 Name = Resources.config_button_mapped_to,
93 ReadOnly = true,
94 Width = 350
95 });
96
97 bindingSource.DataSource = ButtonConfig;
98 CecButtonGridView.DataSource = bindingSource;
99
100 gridView.CellFormatting += delegate(object sender, DataGridViewCellFormattingEventArgs args)
101 {
102 DataGridView grid = sender as DataGridView;
103 var data = grid != null ? grid.Rows[args.RowIndex].DataBoundItem as CecButtonConfigItem : null;
104 if (data == null || !data.Enabled)
105 {
106 args.CellStyle.ForeColor = Color.Gray;
107 }
108 };
109
110 gridView.CellClick += delegate(object sender, DataGridViewCellEventArgs args)
111 {
112 var item = args.RowIndex < ButtonConfig.Count ? ButtonConfig[args.RowIndex] : null;
113 if (item == null)
114 return;
115 (new CecButtonConfigUI(item)).ShowDialog();
116 };
117
118 foreach (var item in _buttonConfig)
119 {
120 item.SettingChanged += delegate
121 {
122 gridView.Refresh();
123 };
124 }
125 }
126
127 #region Start and stop the application
128 /// <summary>
129 /// Check if the application is running
130 /// </summary>
131 /// <returns>True when running, false otherwise</returns>
132 public virtual bool IsRunning()
133 {
134 return FindInstance() != IntPtr.Zero;
135 }
136
137 /// <summary>
138 /// Start the application if it's not running already, and suppress further starts for 5 seconds
139 /// </summary>
140 /// <returns>True when started or suppressed, false otherwise</returns>
141 public virtual bool Start(bool bExitAfterStarting)
142 {
143 if (IsRunning())
144 {
145 SetForeground();
146 return true;
147 }
148
149 if (SuppressApplicationStart)
150 return false;
151
152 SuppressApplicationStart = true;
153 Timer timer = new Timer {Interval = 5000, AutoReset = false};
154 timer.Elapsed += delegate { SuppressApplicationStart = false; };
155 timer.Start();
156
157 try
158 {
159 using (
160 Process runningProcess = new Process
161 {
162 StartInfo =
163 {
164 WorkingDirectory = ApplicationWorkingDirectory,
165 FileName = ApplicationFilename
166 }
167 })
168 {
169 // start maximised if the option is enabled
170 if (StartFullScreen.Value)
171 runningProcess.StartInfo.WindowStyle = ProcessWindowStyle.Maximized;
172
173 runningProcess.Start();
174 }
175 }
176 catch (Exception)
177 {
178 return false;
179 }
180
181 if (bExitAfterStarting)
182 Application.Exit();
183
184 return true;
185 }
186
187 /// <summary>
188 /// Initialise the controller and autostart the application
189 /// </summary>
190 public virtual void Initialise()
191 {
192 Timer timer = new Timer { Interval = 1000, AutoReset = true };
193 timer.Elapsed += delegate { UiControl.SetStartButtonEnabled(true); };
194 timer.Start();
195
196 if (AutoStartApplication.Value)
197 Start(false);
198 }
199 #endregion
200
201 #region Send input to the application
202 /// <summary>
203 /// Send a keypress to the application if it's running
204 /// </summary>
205 /// <param name="key">The keypress to send</param>
206 /// <param name="isSelectedTab">True when this tab is currently selected in the UI</param>
207 /// <returns>True when sent, false otherwise</returns>
208 public virtual bool SendKey(CecKeypress key, bool isSelectedTab)
209 {
210 if (isSelectedTab)
211 UiControl.SelectKeypressRow(UiControl, CecButtonGridView, key);
212
213 if (isSelectedTab && SuppressKeypressWhenSelected.Value)
214 return false;
215
216 if (!ControlApplication.Value)
217 return false;
218
219 var mappedButton = ButtonConfig[key];
220 if (mappedButton == null || mappedButton.Value.Empty())
221 return false;
222
223 var controlWindow = FindInstance();
224 if (controlWindow != IntPtr.Zero && key.Duration == 0)
225 return mappedButton.Value.Transmit(controlWindow);
226
227 return false;
228 }
229 #endregion
230
231 #region Process control
232 /// <summary>
233 /// Make this application the foreground application if it's running
234 /// </summary>
235 public virtual void SetForeground()
236 {
237 var wmcInstance = FindInstance();
238 if (wmcInstance != IntPtr.Zero)
239 WindowsAPI.SetForegroundWindow(wmcInstance);
240 }
241
242 /// <summary>
243 /// The main window handle of the application if it's running.
244 /// </summary>
245 /// <returns>The main window handle, or IntPtr.Zero if it's not found</returns>
246 protected virtual IntPtr FindInstance()
247 {
248 var processes = Process.GetProcessesByName(ProcessName);
249 return processes.Length > 0 ? processes[0].MainWindowHandle : IntPtr.Zero;
250 }
251 #endregion
252
253 #region Members
254 /// <summary>
255 /// The name of the process in the process manager
256 /// </summary>
257 public string ProcessName { set; get; }
258
259 /// <summary>
260 /// The filename of the application
261 /// </summary>
262 public string ApplicationFilename { set; get; }
263
264 /// <summary>
265 /// The working directory of the application
266 /// </summary>
267 public string ApplicationWorkingDirectory { set; get; }
268
269 /// <summary>
270 /// Don't start the application while true
271 /// </summary>
272 public bool SuppressApplicationStart { get; private set; }
273
274 /// <summary>
275 /// The name of the application how it shows up in this application
276 /// </summary>
277 public string UiName { set; get; }
278
279 /// <summary>
280 /// True when this application should be autostarted when this application is activated, or made the active source
281 /// </summary>
282 public CECSettingBool AutoStartApplication
283 {
284 get
285 {
286 if (!Settings.ContainsKey(ProcessName + "_autostart"))
287 {
cf3303fc 288 CECSettingBool setting = new CECSettingBool(ProcessName + "_autostart", "Autostart application", false, null);
f017f3c4
LOK
289 Settings.Load(setting);
290 Settings[ProcessName + "_autostart"] = setting;
291 }
292 return Settings[ProcessName + "_autostart"].AsSettingBool;
293 }
294 }
295
296 /// <summary>
297 /// True when keypresses should be routed to this application
298 /// </summary>
299 public CECSettingBool ControlApplication
300 {
301 get
302 {
303 if (!Settings.ContainsKey(ProcessName + "_control"))
304 {
305 CECSettingBool setting = new CECSettingBool(ProcessName + "_control", "Control application", true, null);
306 Settings.Load(setting);
307 Settings[ProcessName + "_control"] = setting;
308 }
309 return Settings[ProcessName + "_control"].AsSettingBool;
310 }
311 }
312
313 /// <summary>
314 /// True when this application should be autostarted when this application is activated, or made the active source
315 /// </summary>
316 public CECSettingBool SuppressKeypressWhenSelected
317 {
318 get
319 {
320 if (!Settings.ContainsKey(ProcessName + "_suppress_when_selected"))
321 {
322 CECSettingBool setting = new CECSettingBool(ProcessName + "_suppress_when_selected", "Suppress keypress when this tab is selected", true, null);
323 Settings.Load(setting);
324 Settings[ProcessName + "_suppress_when_selected"] = setting;
325 }
326 return Settings[ProcessName + "_suppress_when_selected"].AsSettingBool;
327 }
328 }
329
330 /// <summary>
331 /// True when the application should be started in full screen mode
332 /// </summary>
333 public CECSettingBool StartFullScreen
334 {
335 get
336 {
337 if (!Settings.ContainsKey(ProcessName + "_start_fullscreen"))
338 {
339 CECSettingBool setting = new CECSettingBool(ProcessName + "_start_fullscreen", "Start in full screen mode", true, null);
340 Settings.Load(setting);
341 Settings[ProcessName + "_start_fullscreen"] = setting;
342 }
343 return Settings[ProcessName + "_start_fullscreen"].AsSettingBool;
344 }
345 }
346
347 protected ControllerTabPage UIControlInternal;
348 public virtual ControllerTabPage UiControl
349 {
350 get { return UIControlInternal ?? (UIControlInternal = new ApplicationControllerUI(this)); }
351 }
352
353 private CecButtonConfig _buttonConfig;
354 public CecButtonConfig ButtonConfig
355 {
356 get
357 {
358 if (_buttonConfig == null)
359 {
360 _buttonConfig = new CecButtonConfig(this);
361 foreach (CecUserControlCode key in Enum.GetValues(typeof(CecUserControlCode)))
362 _buttonConfig.Add(new CecButtonConfigItem(this, (new CecKeypress { Keycode = key })));
363
364 _buttonConfig.Load();
365 }
366 return _buttonConfig;
367 }
368 }
369
370 public CECSettings Settings;
371 protected DataGridView CecButtonGridView;
372
373 public virtual ApplicationAction DefaultValue(CecKeypress key)
374 {
375 return null;
376 }
377
378 public virtual bool HasDefaultValue(CecKeypress key)
379 {
380 return DefaultValue(key) != null;
381 }
382
383 public bool IsInternal { protected set; get; }
384 public bool CanConfigureProcess
385 {
386 get
387 {
388 return !IsInternal;
389 }
390 }
391 #endregion
392 }
393}