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