1 //
2 // Copyright (c) 2010-2018 Antmicro
3 // Copyright (c) 2011-2015 Realtime Embedded
4 //
5 // This file is licensed under the MIT License.
6 // Full license text is available in 'licenses/MIT.txt'.
7 //
8 using System;
9 using Xwt;
10 #if !PLATFORM_WINDOWS && !GUI_DISABLED
11 using Xwt.GtkBackend;
12 // for DllMap replacement
13 using System.Reflection;
14 using System.IO;
15 #endif
16 using System.Threading;
17 using Antmicro.Renode.UserInterface;
18 
19 namespace Antmicro.Renode.UI
20 {
21     public class XwtProvider : IDisposable
22     {
XwtProvider()23         static XwtProvider()
24         {
25             internalLock = new object();
26             UiThreadId = -1;
27         }
28 
Create(IUserInterfaceProvider uiProvider)29         public static XwtProvider Create(IUserInterfaceProvider uiProvider)
30         {
31 #if GUI_DISABLED
32             return null;
33 #else
34             Emulator.UserInterfaceProvider = uiProvider;
35             var xwtProvider = new XwtProvider();
36             return (xwtProvider.StartXwtThreadOnMainThread())
37                 ? xwtProvider
38                 : null;
39 #endif
40         }
41 
Dispose()42         public void Dispose()
43         {
44             StopXwtThread();
45         }
46 
Initialize()47         public bool Initialize()
48         {
49             try
50             {
51 #if !GUI_DISABLED
52 #if PLATFORM_WINDOWS
53                 Application.Initialize(ToolkitType.Wpf);
54 #elif NET
55                 var assemblyLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
56                 var assembly = Assembly.LoadFrom(Path.Combine(assemblyLocation, "Xwt.Gtk3.dll"));
57                 DllMap.Register(assembly);
58 
59                 Application.Initialize(ToolkitType.Gtk3);
60 #else
61                 Application.Initialize(ToolkitType.Gtk);
62 #endif
63 #endif
64                 return true;
65             }
66             catch(Exception)
67             {
68                 return false;
69             }
70         }
71 
RunMainLoopInCurrentThread()72         public void RunMainLoopInCurrentThread()
73         {
74             lock(internalLock)
75             {
76                 if(UiThreadId != -1)
77                 {
78                     throw new ArgumentException(string.Format("UI thread is already running: {0}", UiThreadId));
79                 }
80                 UiThreadId = Thread.CurrentThread.ManagedThreadId;
81             }
82 
83             Application.UnhandledException += (sender, arg) => CrashHandler.HandleCrash(arg.ErrorException);
84 #if !PLATFORM_WINDOWS && !GUI_DISABLED
85             GLib.ExceptionManager.UnhandledException += arg => CrashHandler.HandleCrash((Exception)arg.ExceptionObject);
86 #endif
87             Application.Run();
88 
89 #if !PLATFORM_WINDOWS && !GUI_DISABLED
90             GtkTextLayoutBackendHandler.DisposeResources();
91 #endif
92             lock(internalLock)
93             {
94                 UiThreadId = -1;
95             }
96         }
97 
98         public static int UiThreadId { get; private set; }
99 
XwtProvider()100         private XwtProvider()
101         {
102         }
103 
StartXwtThreadOnMainThread()104         private bool StartXwtThreadOnMainThread()
105         {
106             var initialized = false;
107             var manualResetEvent = new ManualResetEventSlim();
108             Emulator.ExecuteOnMainThread(() =>
109             {
110                 // XWT thread has to be initialized on the first thread at OSX
111                 initialized = Initialize();
112                 manualResetEvent.Set();
113                 if(initialized)
114                 {
115                     RunMainLoopInCurrentThread();
116                 }
117             });
118             // we should wait here for the initalization of XWT
119             // as further code might want to use it
120             manualResetEvent.Wait();
121             return initialized;
122         }
123 
StopXwtThread()124         private void StopXwtThread()
125         {
126             lock(internalLock)
127             {
128                 if(UiThreadId == -1)
129                 {
130                     return;
131                 }
132                 ApplicationExtensions.InvokeInUIThread(Application.Exit);
133             }
134         }
135 
136         private static object internalLock;
137     }
138 }
139 
140