1 |
//#define DEV_DEBUG |
2 |
|
3 |
|
4 |
#if DEV_DEBUG |
5 |
#define FORCE_CACHE_REBULD // when defined will force rebuilding of cache |
6 |
#endif |
7 |
//#define DISABLE_PLUGINS // when defined plugin loading an their use will be disabled |
8 |
|
9 |
//#define HAVE_X11_BORDERSTYLE_ERROR // indicates that there is an error with Control.set_InternalBorderStyle resulting in an X11 Error BadWindow (invalid Window parameter) |
10 |
|
11 |
//#define DISABLE_WORKER_PROGRESS_EVENT // when defined will disable worker progress events |
12 |
//#define DISABLE_SPLASH // when defined will not show a splash (e.g. during cache building) |
13 |
|
14 |
//#define DISABLE_CURSOR_HIDE // when this is present, the cursor will not be hidden |
15 |
//#define DISABLE_PROGRESS_PERCENTAGE_MESSASGE // when this is present, no progress percent message will be shown on any progressbar |
16 |
|
17 |
|
18 |
#if DEV_DEBUG |
19 |
#warning DEV_DEBUG is enabled |
20 |
#endif |
21 |
|
22 |
using System; |
23 |
using System.Collections.Generic; |
24 |
using System.ComponentModel; |
25 |
using System.Data; |
26 |
using System.Drawing; |
27 |
using System.Linq; |
28 |
using System.Text; |
29 |
using System.Windows.Forms; |
30 |
using EmuXPortal.Api; |
31 |
using System.Diagnostics; |
32 |
using System.Reflection; |
33 |
using System.Threading; |
34 |
using Utilities.TransparentControls; |
35 |
using Enterprise.Logging; |
36 |
using System.IO; |
37 |
using Enterprise.CrossPlatform; |
38 |
using EmuXPortal.UI; |
39 |
using EmuXPortal.UI.RenderControls; |
40 |
using EmuXPortal.Plugins; |
41 |
using irexec_api; |
42 |
|
43 |
namespace EmuXPortal { |
44 |
public partial class Form1 : Form { |
45 |
static readonly System.Drawing.Color DEFAULT_TEXTFORECOLOR = System.Drawing.Color.Lime; |
46 |
static readonly System.Drawing.Color DEFAULT_TEXTFORECOLOR_ERROR = System.Drawing.Color.Yellow; |
47 |
static readonly System.Drawing.Color DEFAULT_TEXTFORECOLOR_LAUNCH = System.Drawing.Color.Blue; |
48 |
static readonly System.Drawing.Color DEFAULT_TEXTFORECOLOR_MISSING = System.Drawing.Color.Red; |
49 |
|
50 |
//const string irexec = "/usr/bin/irexec"; |
51 |
const string irexec = "irexec"; |
52 |
const string irexec_lircrc = "emuxportal.lircrc"; |
53 |
|
54 |
Thread irexec_thread_monitor = null; |
55 |
|
56 |
static bool bUserAbort = false; |
57 |
|
58 |
private const int WINDOW_MODE_WIDTH = 900; |
59 |
private const int WINDOW_MODE_HEIGHT = 500; |
60 |
private const int INPUT_POLLING_FREQUENCY = 100; |
61 |
|
62 |
|
63 |
#if DEV_DEBUG && FORCE_CACHE_REBULD |
64 |
private const bool bRebuildCache = false; |
65 |
#else |
66 |
private bool bRebuildCache = false; |
67 |
#endif |
68 |
|
69 |
private CustomProgressBar progress_bar; |
70 |
private IPlatformCache cache = null; |
71 |
private bool bConfigLoaded = false; |
72 |
|
73 |
private System.Windows.Forms.Timer input_queue_handler; |
74 |
|
75 |
private bool bInputQueuHandlerRunning = false; |
76 |
private bool bInputQueueDisabled = false; |
77 |
|
78 |
private Queue<KeyArrayArgs> event_queue; |
79 |
private readonly object event_queue_lock = new object (); |
80 |
|
81 |
|
82 |
private void do_irexec_monitor () |
83 |
{ |
84 |
var manager = IRExecManager.CreateManager (); |
85 |
string arguments = Enterprise.CrossPlatform.OSInfo.FormatPath (string.Format ("{0}/{1}", Application.StartupPath, irexec_lircrc)); |
86 |
manager.SetIRExecArguments (arguments); |
87 |
|
88 |
try { |
89 |
while (true) { |
90 |
manager.StartIRExec (); |
91 |
Thread.Sleep (100); |
92 |
} |
93 |
} catch (ThreadAbortException) { |
94 |
//gLog.Verbose.Error.WriteLine (ex.ToString ()); |
95 |
manager.StopIRExec (); |
96 |
} |
97 |
|
98 |
} |
99 |
|
100 |
private void HookIRExec () |
101 |
{ |
102 |
irexec_thread_monitor = new Thread (new ThreadStart (do_irexec_monitor)); |
103 |
irexec_thread_monitor.SetApartmentState (ApartmentState.STA); |
104 |
irexec_thread_monitor.Start (); |
105 |
} |
106 |
private void UnHookIRExec () |
107 |
{ |
108 |
if (irexec_thread_monitor != null && irexec_thread_monitor.IsAlive) { |
109 |
irexec_thread_monitor.Abort (); |
110 |
irexec_thread_monitor = null; |
111 |
} |
112 |
} |
113 |
static bool OnAbort () |
114 |
{ |
115 |
|
116 |
return bUserAbort; |
117 |
} |
118 |
#region unhandled exception support |
119 |
static void Application_Unhandled_ThreadException (object sender, ThreadExceptionEventArgs e) |
120 |
{ |
121 |
UnhandledExceptionEventArgs uea = new UnhandledExceptionEventArgs (e.Exception, false); |
122 |
UnhandledExceptionEventHandler (sender, uea); |
123 |
} |
124 |
static void UnhandledExceptionEventHandler (object sender, UnhandledExceptionEventArgs args) |
125 |
{ |
126 |
Exception ex = (args.ExceptionObject as Exception); |
127 |
if (sender == null) { |
128 |
gLog.Error.WriteLine ("Caught an unhandled exception from an unkown source"); |
129 |
} else { |
130 |
gLog.Error.WriteLine ("Caught an unhandled exception from type: {0}", sender.GetType ().Name); |
131 |
} |
132 |
|
133 |
if (ex == null) { |
134 |
gLog.Error.WriteLine ("The exception object was null -- it probably is not derived from System.Exception"); |
135 |
} else { |
136 |
ex = ex.GetBaseException (); |
137 |
gLog.Error.WriteLine ("{0}:", ex.GetType ().Name); |
138 |
gLog.Verbose.Error.WriteLine (ex.ToString ()); |
139 |
} |
140 |
|
141 |
} |
142 |
#endregion |
143 |
public Form1 () |
144 |
{ |
145 |
InitializeComponent (); |
146 |
this.progress_bar = new CustomProgressBar (); |
147 |
|
148 |
#region logging support |
149 |
string log_path = Application.StartupPath; |
150 |
string log_filename = string.Format ("{0}.log", typeof (Form1).Assembly.GetName ().Name); |
151 |
FileInfo log_file = new FileInfo (OSInfo.FormatPath (string.Format (@"{0}\{1}", log_path, log_filename))); |
152 |
|
153 |
gLog.CreateLog (log_file.Name, true, LogLevel.kLogLevel_All_NoProgress, new EventHandler<LoggerOnFlushEventArgs> (Log_OnFlush)); |
154 |
LogLevel gLevel = gLog.LogLevel; |
155 |
#if DEBUG |
156 |
gLevel |= LogLevel.kLogLevel_Debug; |
157 |
gLevel |= LogLevel.kLogLevel_VerboseDebug; |
158 |
#else |
159 |
gLevel &= ~LogLevel.kLogLevel_Debug; |
160 |
gLevel &= ~LogLevel.kLogLevel_VerboseDebug; |
161 |
#endif |
162 |
|
163 |
gLog.SetLogLevel(gLevel); |
164 |
|
165 |
#endregion |
166 |
|
167 |
#region unhandled exception support |
168 |
// AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledExceptionEventHandler); |
169 |
// Application.ThreadException += Application_Unhandled_ThreadException; |
170 |
#endregion |
171 |
|
172 |
HookIRExec (); |
173 |
#if !DISABLE_PLUGINS |
174 |
event_queue = new Queue<KeyArrayArgs> (); |
175 |
PluginLoader.LoadPlugins (); |
176 |
PluginLoader.InitializeInputSystem (); |
177 |
|
178 |
input_queue_handler = new System.Windows.Forms.Timer (); |
179 |
input_queue_handler.Tick += Input_Queue_Handler_Tick; |
180 |
input_queue_handler.Interval = INPUT_POLLING_FREQUENCY; |
181 |
input_queue_handler.Enabled = true; |
182 |
input_queue_handler.Start (); |
183 |
#endif |
184 |
} |
185 |
|
186 |
#if !DISABLE_PLUGINS |
187 |
void Input_Queue_Handler_Tick (object sender, EventArgs e) |
188 |
{ |
189 |
if (bInputQueueDisabled) { |
190 |
return; |
191 |
} |
192 |
if (bInputQueuHandlerRunning) { return; } |
193 |
if (event_queue.Count > 0) { |
194 |
bInputQueuHandlerRunning = true; |
195 |
KeyArrayArgs key_event = null; |
196 |
lock (event_queue_lock) { |
197 |
key_event = event_queue.Dequeue (); |
198 |
} |
199 |
var keys = key_event.GetKeys (); |
200 |
string key_string = KeyConverter.getSendKeysString (keys); |
201 |
StringBuilder sb = new StringBuilder (); |
202 |
keys.ToList ().ForEach ((Keys obj) => sb.AppendFormat (" {0}", obj)); |
203 |
SendKeys.Send (key_string); |
204 |
bInputQueuHandlerRunning = false; |
205 |
} |
206 |
} |
207 |
|
208 |
|
209 |
void Handle_InputPoll (object sender, KeyArrayArgs e) |
210 |
{ |
211 |
if (!bInputQueueDisabled) { |
212 |
lock (event_queue_lock) { |
213 |
event_queue.Enqueue (e); |
214 |
} |
215 |
} |
216 |
} |
217 |
#endif |
218 |
|
219 |
|
220 |
#region logging support |
221 |
void Log_OnFlush (object sender, LoggerOnFlushEventArgs e) { OnLogFlush (e.Buffer); } |
222 |
|
223 |
|
224 |
|
225 |
|
226 |
void OnLogFlush (string logmessage) |
227 |
{ |
228 |
//if (this.IsDisposed) { return; } |
229 |
////UpdateStatus(logmessage); |
230 |
////UpdateLogOutput(logmessage); |
231 |
//Application.DoEvents(); |
232 |
} |
233 |
#endregion |
234 |
|
235 |
private bool bCachedLoaded = false; |
236 |
private bool OnCacheLoaded () |
237 |
{ |
238 |
return bCachedLoaded; |
239 |
} |
240 |
|
241 |
|
242 |
private void HandleCommandLine () |
243 |
{ |
244 |
var cargs = new List<String> (System.Environment.GetCommandLineArgs ()); |
245 |
if (cargs.Contains ("--rebuild")) { |
246 |
#if !DEV_DEBUG |
247 |
bRebuildCache = true; |
248 |
#endif |
249 |
} |
250 |
} |
251 |
|
252 |
|
253 |
private void Form1_Load (object sender, EventArgs e) |
254 |
{ |
255 |
HandleCommandLine (); |
256 |
Config.InitializePresentationForm (this); |
257 |
this.Activated += Handle_Activated; |
258 |
|
259 |
} |
260 |
|
261 |
|
262 |
void Handle_Activated (object sender, EventArgs e) |
263 |
{ |
264 |
this.Activated -= Handle_Activated; |
265 |
this.cache_worker.RunWorkerAsync (); |
266 |
} |
267 |
|
268 |
void Rom_Flow_RomLaunched (object sender, RomLaunchArgs e) |
269 |
{ |
270 |
var flags = e.RomLaunchFlags; |
271 |
var info = e.RomInfo; |
272 |
string game_name = ""; |
273 |
if (info == null) { |
274 |
gLog.Warn.WriteLine ("recieved null rom info!"); |
275 |
} else { |
276 |
game_name = info.RomTitle; |
277 |
} |
278 |
|
279 |
if (flags == RomLaunchFlags.BEGIN_LAUNCH) { |
280 |
gLog.Debug.WriteLine ("Game '{0}' has been launched, disabling input queue",game_name); |
281 |
bInputQueueDisabled = true; |
282 |
PluginLoader.DisableInputPolling (); |
283 |
} else if (flags == RomLaunchFlags.END_LAUNCH) { |
284 |
gLog.Debug.WriteLine ("Game '{0}' has exited, re-enabling input queue",game_name); |
285 |
bInputQueueDisabled = false; |
286 |
PluginLoader.EnableInputPolling (); |
287 |
} else { |
288 |
if (flags != RomLaunchFlags.NONE) { |
289 |
gLog.Debug.WriteLine ("Unknown rom launch flag: {0}", (int)flags); |
290 |
} |
291 |
} |
292 |
} |
293 |
|
294 |
|
295 |
|
296 |
void ControlsRendered (object sender, EventArgs e) |
297 |
{ |
298 |
|
299 |
} |
300 |
|
301 |
void SwitchControls (object sender, EventArgs e) |
302 |
{ |
303 |
PlatformGridContrainer pc = (sender as PlatformGridContrainer); |
304 |
if (pc != null) { |
305 |
platform_flow.Visible = false; |
306 |
rom_flow.Visible = true; |
307 |
rom_flow.BringToFront (); |
308 |
rom_flow.setCurrentRomPlatform (pc.getCurrentPlatform ()); |
309 |
rom_flow.Focus (); |
310 |
rom_flow.renderControls (); |
311 |
} |
312 |
GameGridContainer gc = (sender as GameGridContainer); |
313 |
if (gc != null) { |
314 |
rom_flow.Visible = false; |
315 |
platform_flow.Visible = true; |
316 |
platform_flow.BringToFront (); |
317 |
platform_flow.Focus (); |
318 |
} |
319 |
} |
320 |
|
321 |
private void platform_flow_VisibleChanged (object sender, EventArgs e) |
322 |
{ |
323 |
if (!platform_flow.Visible) return; |
324 |
platform_flow.Width = this.Width - 10; |
325 |
platform_flow.renderControls (); |
326 |
} |
327 |
|
328 |
private void rom_flow_VisibleChanged (object sender, EventArgs e) |
329 |
{ |
330 |
if (!rom_flow.Visible) return; |
331 |
rom_flow.Width = this.Width - 10; |
332 |
} |
333 |
|
334 |
|
335 |
private void Form1_FormClosing (object sender, FormClosingEventArgs e) |
336 |
{ |
337 |
this.UnHookIRExec (); |
338 |
} |
339 |
private void Form1_FormClosed (object sender, FormClosedEventArgs e) |
340 |
{ |
341 |
Cursor.Show (); |
342 |
PluginLoader.EndInputPolling (); |
343 |
} |
344 |
|
345 |
private void Cache_Worker_DoWork (object sender, DoWorkEventArgs e) |
346 |
{ |
347 |
|
348 |
#if !DISABLE_SPLASH |
349 |
this.Controls.Add (splash); |
350 |
this.splash.Width = this.Width; |
351 |
#endif |
352 |
Stopwatch t = new Stopwatch (); |
353 |
t.Start (); |
354 |
try { |
355 |
cache = PlatformCache.Create (new AbortEvent (OnAbort), bRebuildCache); |
356 |
bCachedLoaded = true; |
357 |
} catch (Exception ex) { |
358 |
gLog.Error.WriteLine (ex.ToString ()); |
359 |
} |
360 |
t.Stop (); |
361 |
|
362 |
if (bCachedLoaded) { |
363 |
gLog.Profiler.WriteLine ("Cache generate/load took: {0}", TimeUtils.getTimeString (t)); |
364 |
} |
365 |
} |
366 |
private void Cache_Worker_RunWorkerCompleted (object sender, RunWorkerCompletedEventArgs e) |
367 |
{ |
368 |
if (!bCachedLoaded) { |
369 |
gLog.Warn.WriteLine ("Failed to generate cache..."); |
370 |
Application.Exit (); |
371 |
return; |
372 |
} |
373 |
#if !DISABLE_SPLASH |
374 |
this.Controls.Remove (splash); |
375 |
#endif |
376 |
config_worker.RunWorkerAsync (); |
377 |
} |
378 |
private void Config_Worker_DoWork (object sender, DoWorkEventArgs e) |
379 |
{ |
380 |
Stopwatch t = new Stopwatch (); |
381 |
t.Start (); |
382 |
try { |
383 |
bConfigLoaded = Config.LoadConfig (cache); |
384 |
} catch (Exception ex) { |
385 |
bConfigLoaded = false; |
386 |
gLog.Error.WriteLine (ex.ToString ()); |
387 |
return; |
388 |
} |
389 |
t.Stop (); |
390 |
gLog.Profiler.WriteLine ("Config load took: {0}", TimeUtils.getTimeString (t)); |
391 |
|
392 |
|
393 |
|
394 |
} |
395 |
private void Config_Worker_RunWorkerCompleted (object sender, RunWorkerCompletedEventArgs e) |
396 |
{ |
397 |
if (!bConfigLoaded) { |
398 |
gLog.Warn.WriteLine ("Failed to load config..."); |
399 |
Application.Exit (); |
400 |
return; |
401 |
} |
402 |
/* set the container control's cache */ |
403 |
platform_flow.setCache (cache); |
404 |
rom_flow.setCache (cache); |
405 |
platform_flow.Visible = true; |
406 |
platform_flow.Focus (); |
407 |
#if !DISABLE_CURSOR_HIDE |
408 |
Cursor.Hide (); |
409 |
#else |
410 |
Cursor.Show(); |
411 |
#endif |
412 |
|
413 |
#if !DISABLE_PLUGINS |
414 |
PluginLoader.StartInputPolling (bInputQueueDisabled, Handle_InputPoll); |
415 |
#endif |
416 |
} |
417 |
} |
418 |
} |