public static void Run(string[] args) { if (args.FirstOrDefault() != MagicArgument) { return; } if (args.Length < 2) { Console.Error.WriteLine("Expected second argument to be the unique identifier for the pipe."); return; } var systemId = SystemGuidLoader.LoadOrCreateOrEmpty(); var sessionId = Guid.NewGuid(); var reporter = ReportFactory.GetReporter(systemId, sessionId, "SimulatorHost"); AppDomain.CurrentDomain.ReportUnhandledExceptions(reporter); var inputPipe = Platform.CreateStream("input"); var outputPipe = Platform.CreateStream("output"); var input = ReadInput(inputPipe); var output = Run(input, SystemInfoFactory.GetBuildVersion(typeof(FuseApi).Assembly)); using (output.WriteOutput(outputPipe)) using (input.Connect()) { input.LastAsync().Wait(); } }
public Client(IMessageConnection client, ISerializer serializer) { _report = ReportFactory.GetReporter(SystemGuidLoader.LoadOrCreateOrEmpty(), Guid.NewGuid(), "FuseProtocol"); _client = client; var messagesOut = client.OutgoingMessages.Serialized(serializer); // TODO: Find a way to either log or do something about parse errors. var messagesIn = client.IncomingMessages.TryDeserialize(serializer, _report); messagesIn.Subscribe(a => { }, () => _connectionLost.OnNext(DateTime.Now)); _requestSender = new RequestSender(_report, messagesIn, messagesOut); _receiver = new RequestReceiver(_report, messagesIn.OfType <IRequestMessage <UnresolvedMessagePayload> >(), messagesOut); _eventBroadcaster = Observer.Create <IEventData>(e => messagesOut.OnNext(Event.Create(e))); _broadcastedEvents = messagesIn.OfType <IEventMessage <UnresolvedMessagePayload> >(); }
static ReportFactory() { FallbackReport = new NullReport(); //Protect against someone indirectly using `FallbackReport` during execution of `GetReporter()` FallbackReport = GetReporter(SystemGuidLoader.LoadOrCreateOrEmpty(), Guid.NewGuid(), "Fuse"); }
public static IFuse Initialize(string programName, List <string> args) { var systemId = SystemGuidLoader.LoadOrCreateOrEmpty(); var sessionId = Guid.NewGuid(); var report = ReportFactory.GetReporter(systemId, sessionId, programName); AppDomain.CurrentDomain.ReportUnhandledExceptions(report); report.Info("Initializing with arguments '" + args.Join(" ") + "'"); // Report running mono version Type type = Type.GetType("Mono.Runtime"); if (type != null) { MethodInfo displayName = type.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static); if (displayName != null) { report.Info("Running with Mono " + displayName.Invoke(null, null)); } } EnsureSpecialFoldersExist(); var fuseExeOverride = args .TryParse("override-fuse-exe") .SelectMany(AbsoluteFilePath.TryParse); var rootDirSetByArgs = Optional.None <AbsoluteDirectoryPath>(); /*args * .FirstOrNone(a => a.StartsWith("fuse-root")) * .Select(a => a.Substring(a.IndexOf("=", StringComparison.InvariantCulture) + 1, a.Length - 1 - a.IndexOf("=", StringComparison.InvariantCulture))) * .Select(AbsoluteDirectoryPath.Parse);*/ var os = Platform.OperatingSystem; var fuseRoot = rootDirSetByArgs .Or(() => GetFuseRoot(os)) .OrThrow(new FuseRootDirectoryWasNotFound()); if (os != OS.Mac && os != OS.Windows) { throw new UnsupportedPlatformException(os); } var isMac = os == OS.Mac; var mono = isMac ? Optional.Some(FindMonoExe(fuseRoot)) : Optional.None(); var codeAssistanceService = new FileName("Fuse.CodeAssistanceService.exe"); var fuseExe = fuseExeOverride.Or(isMac ? fuseRoot / "MacOS" / new FileName("Fuse") : fuseRoot / new FileName("Fuse.exe")); var unoExe = FindUnoExe(fuseRoot); var impl = new FuseImpl { FuseRoot = fuseRoot, Version = SystemInfoFactory.GetBuildVersion(), UnoExe = unoExe, FuseExe = fuseExe, MonoExe = mono, Fuse = ExternalApplication.FromNativeExe(fuseExe), // Tools Designer = isMac ? ExternalApplication.FromAppBundle(fuseRoot / new FileName("Fuse Studio.app")) : ExternalApplication.FromNativeExe(fuseRoot / new FileName("Fuse Studio.exe")), // Services CodeAssistance = isMac ? ExternalApplication.FromMonoExe(fuseRoot / "MonoBundle" / codeAssistanceService, mono) : ExternalApplication.FromNativeExe(fuseRoot / codeAssistanceService), Tray = isMac ? ExternalApplication.FromNativeExe(fuseRoot / "Fuse Tray.app" / "Contents" / "MacOS" / new FileName("Fuse Tray")) : ExternalApplication.FromNativeExe(fuseRoot / new FileName("Fuse-Tray.exe")), LogServer = isMac ? ExternalApplication.FromNativeExe(fuseRoot / new FileName("fuse-logserver")) : null, // Uno Uno = isMac ? ExternalApplication.FromMonoExe(unoExe, mono) : ExternalApplication.FromNativeExe(unoExe), // System paths UserDataDir = isMac ? AbsoluteDirectoryPath.Parse(Environment.GetFolderPath(Environment.SpecialFolder.Personal)) / ".fuse" : AbsoluteDirectoryPath.Parse(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)) / "Fusetools" / "Fuse", ProjectsDir = AbsoluteDirectoryPath.Parse(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)) / "Fuse", SystemId = systemId, SessionId = sessionId, Report = report }; var partial = args.Remove("--partial") | args.Remove("-p"); if (!partial) { impl.CheckCompleteness(); } // Set assembly configuration for .unoconfig, to be able to find correct bin/$(Configuration) directories. #if DEBUG UnoConfigFile.Constants["Configuration"] = "Debug"; #else UnoConfigFile.Constants["Configuration"] = "Release"; #endif return(impl); }
static void Main(string[] argsArray) { var shell = new Shell(); var systemId = SystemGuidLoader.LoadOrCreateOrEmpty(); var sessionId = Guid.NewGuid(); var log = ReportFactory.GetReporter(systemId, sessionId, "UnoHost"); var descriptiveString = "UnoHost (" + argsArray.Select(a => "\"" + a + "\"").Join(" ") + ")"; try { AppDomain.CurrentDomain.ReportUnhandledExceptions(log); var dispatcher = new Dispatcher(Thread.CurrentThread); log.Info("Starting " + descriptiveString, ReportTo.LogAndUser); var argsList = argsArray.ToList(); var args = UnoHostArgs.RemoveFrom(argsList, shell); NSApplication.Init(); NSApplication.SharedApplication.Delegate = new AppDelegate(); AppDelegate.ThrowOnTerminate = false; Action exit = () => { log.Info("Stopping " + descriptiveString); NSApplication.SharedApplication.Terminate(NSApplication.SharedApplication); }; Console.CancelKeyPress += (sender, e) => exit(); NSApplication.CheckForIllegalCrossThreadCalls = false; // Load metadata var unoHostProject = UnoHostProject.Load(args.MetadataPath, shell); Action <Exception> onLostConnection = exception => { if (exception == null) { log.Info("CommunicationProtocol closed"); } else { log.Exception("CommunicationProtocol failed", exception); } exit(); }; var renderTarget = new IOSurfaceRenderTarget(); var glView = new UnoView.UnoView(dispatcher, log, renderTarget) { WantsBestResolutionOpenGLSurface = true }; glView.PrepareOpenGL(); // We have to call this method manually because the view isn't bound to a window var openGlVersion = new Subject <OpenGlVersion>(); var messagesTo = new Subject <IBinaryMessage>(); var output = Observable.Merge( messagesTo, openGlVersion.Select(OpenGlVersionMessage.Compose), renderTarget.SurfaceRendered.Select(NewSurfaceMessage.Compose)); if (!args.IsDebug) { args.OutputPipe.BeginWritingMessages( "Designer", ex => Console.WriteLine("UnoHost failed to write message to designer: " + ex), output.ObserveOn(new QueuedDispatcher())); } glView.Initialize(unoHostProject, openGlVersion); var messagesFrom = args.InputPipe .ReadMessages("Designer") .RefCount() .ObserveOn(dispatcher) .Publish(); messagesFrom.SelectSome(CocoaEventMessage.TryParse) .Subscribe(e => EventProcesser.SendEvent(glView, e), onLostConnection, () => onLostConnection(null)); // Fuselibs fails during construction if we don't get this, and we can't wait for it because we are dispatching responses on our queue glView.Resize(new SizeData(Size.Create <Points>(0, 0), 1.0)); messagesFrom.SelectSome(ResizeMessage.TryParse) .Subscribe(glView.Resize, onLostConnection, () => onLostConnection(null)); var size = glView.Size.Transpose(); // Run the uno entrypoints, this initializes Uno.Application.Current unoHostProject.ExecuteStartupCode(); var app = Uno.Application.Current as dynamic; // Init plugins FusionImplementation.Initialize(dispatcher, args.UserDataPath, app.Reflection); var overlay = PluginManager.Initialize(messagesFrom, messagesTo, dispatcher, glView.PerFrame, size); app.ResetEverything(true, overlay); // Ready to go messagesFrom.Connect(); messagesTo.OnNext(new Ready()); NSApplication.SharedApplication.Run(); } catch (Exception e) { log.Exception("Exception in " + descriptiveString, e); } }
static void Main(string[] argsArray) { var shell = new Shell(); var systemId = SystemGuidLoader.LoadOrCreateOrEmpty(); var sessionId = Guid.NewGuid(); var log = ReportFactory.GetReporter(systemId, sessionId, "UnoHost"); AppDomain.CurrentDomain.ReportUnhandledExceptions(log); DpiAwareness.SetDpiAware(DpiAwareness.ProcessDpiAwareness.SystemAware); NativeResources.Load(); var args = UnoHostArgs.RemoveFrom(argsArray.ToList(), shell); // Load metadata var unoHostProject = UnoHostProject.Load(args.MetadataPath, shell); var form = new DpiAwareForm() { FormBorderStyle = FormBorderStyle.None, ShowInTaskbar = false }; //if (args.IsDebug) // InitDebugMode(form); var unoControl = new UnoControl(form, log); form.Controls.Add(unoControl); form.ShowIcon = false; var openGlVersion = new Subject <OpenGlVersion>(); var backgroundQueue = new QueuedDispatcher(); var lostFocus = Observable.FromEventPattern(unoControl, "LostFocus").ObserveOn(backgroundQueue); var messagesTo = new Subject <IBinaryMessage>(); var output = Observable.Merge( messagesTo.Do(message => Console.WriteLine(message.Type)), openGlVersion.Select(OpenGlVersionMessage.Compose), Observable.FromEventPattern(unoControl, "GotFocus").Select(_ => WindowFocusMessage.Compose(FocusState.Focused)), lostFocus.Select(_ => WindowFocusMessage.Compose(FocusState.Blurred)), lostFocus.Select(_ => WindowContextMenuMessage.Compose(false)), Observable.FromEventPattern <MouseEventArgs>(unoControl, "MouseUp") .Where(m => m.EventArgs.Button == System.Windows.Forms.MouseButtons.Right) .Select(_ => WindowContextMenuMessage.Compose(true)), Observable.FromEventPattern <MouseEventArgs>(unoControl, "MouseDown") .Select(_ => WindowContextMenuMessage.Compose(false)), Observable.FromEventPattern <MouseEventArgs>(unoControl, "MouseWheel") .Select(m => WindowMouseScrollMessage.Compose(m.EventArgs.Delta)), Observable.FromEventPattern <KeyEventArgs>(unoControl, "KeyDown") .Select(m => WindowKeyDown.Compose(m.EventArgs.KeyCode)), Observable.FromEventPattern <KeyEventArgs>(unoControl, "KeyUp") .Select(m => WindowKeyUp.Compose(m.EventArgs.KeyCode))); args.OutputPipe.BeginWritingMessages( "Designer", ex => Console.WriteLine("UnoHost failed to write message to designer: " + ex), output.ObserveOn(new QueuedDispatcher())); unoControl.Initialize(unoHostProject, openGlVersion); // Set hand cursor so we know when we're interacting with the UnoHost and not in the designer unoControl.Cursor = System.Windows.Forms.Cursors.Hand; // notify studio about the window messagesTo.OnNext(WindowCreatedMessage.Compose(form.Handle)); var dispatcher = new PollingDispatcher(Thread.CurrentThread); unoControl.PerFrame.Subscribe(f => dispatcher.DispatchCurrent()); var density = Observable.Return(new Ratio <Points, Pixels>(1)); var size = Observable.FromEventPattern(unoControl, "SizeChanged") .StartWith(new EventPattern <object>(null, null)) .Select(_ => unoControl.Size.ToSize()) .CombineLatest(density, (s, d) => s.Mul(d)) .Transpose(); var messagesFrom = args.InputPipe .ReadMessages("Designer") .RefCount() .ObserveOn(dispatcher) .Publish(); messagesFrom.Subscribe(next => { }, e => form.Exit(1), () => form.Exit(0)); // Run the uno entrypoints, this initializes Uno.Application.Current unoHostProject.ExecuteStartupCode(); var app = Uno.Application.Current as dynamic; // Init plugins FusionImplementation.Initialize(dispatcher, args.UserDataPath, app.Reflection); var overlay = PluginManager.Initialize(messagesFrom, messagesTo, dispatcher, unoControl.PerFrame, size); app.ResetEverything(true, overlay); // Ready to go messagesFrom.Connect(); messagesTo.OnNext(new Ready()); unoControl.Run(); }
public static CustomWindow Create(Window model, Optional <ObservableNSDocument> document) { var dispatcher = Fusion.Application.MainThread; model.Title = model.Title.Select(title => model.HideTitle ? "" : title); var sizeFeedback = model.Size .Or(Property.Create(Optional.None <Size <Points> >())) .Or(Size.Create <Points>(800, 600)) .AutoInvalidate(TimeSpan.FromSeconds(2)); var size = sizeFeedback.PreventFeedback(); var content = new NSDefaultView(); if (model.DragOperation.HasValue) { content.RegisterForDraggedTypes(new string[] { NSPasteboard.NSFilenamesType }); content.AddDropOperation(model.DragOperation.Value); } var window = new CustomWindow(model.Focused) { BackgroundColor = Color.FromBytes(0x31, 0x34, 0x3a).ToNSColor(), ContentView = content, StyleMask = NSWindowStyle.TexturedBackground | /*NSWindowStyle.Utility |*/ NSWindowStyle.Titled | NSWindowStyle.Closable | NSWindowStyle.Miniaturizable | NSWindowStyle.Resizable, HidesOnDeactivate = false, Restorable = false, }; window.IsOpaque = false; content.WantsLayer = true; var fusionContent = model.Content; var desiredTitleBarHeight = new ReplaySubject <IObservable <Points> >(1); switch (model.Style) { case WindowStyle.Regular: // Render window content beneath title bar area window.StyleMask |= NSWindowStyle.FullSizeContentView; // Make title bar transparent window.TitlebarAppearsTransparent = true; // Build custom title bar content and dock it on top of existing fusionContent var titleTextColor = Color.White; var titleBarContent = document.MatchWith(_ => { // If we have a document, we'll create a container to hijack the window's DocumentIconButton later var titleText = Label.Create(text: window.DocumentTitle.AsText(), color: titleTextColor); var documentIconButtonContainer = DocumentIconButtonContainer.Create(window).WithPadding(right: Optional.Some <Points>(4)); return(Layout.StackFromLeft(documentIconButtonContainer, titleText)); }, () => Label.Create(text: model.Title.AsText(), color: titleTextColor)); Action zoom = () => Fusion.Application.MainThread.Schedule(() => window.Zoom(window)); titleBarContent = titleBarContent .WithPadding(top: Optional.Some <Points>(2), bottom: Optional.Some <Points>(3)) .CenterHorizontally(); desiredTitleBarHeight.OnNext(titleBarContent.DesiredSize.Height); fusionContent = Layout.DockTop( titleBarContent, fusionContent ).OnMouse(doubleClicked: Command.Enabled(zoom)); break; case WindowStyle.Fat: // Render window content beneath title bar area window.StyleMask |= NSWindowStyle.FullSizeContentView; //Create a toolbar window.Toolbar = new NSToolbar("toolbar"); // Make title bar transparent window.TitlebarAppearsTransparent = true; window.Toolbar.ShowsBaselineSeparator = false; window.WillUseFullScreenPresentationOptions = (nsWindow, options) => options | NSApplicationPresentationOptions.AutoHideToolbar; // Build custom title bar content and dock it on top of existing fusionContent var titleTextColorFat = model.Foreground; var titleBarContentFat = document.MatchWith(_ => { // If we have a document, we'll create a container to hijack the window's DocumentIconButton later var titleText = Label.Create( text: window.DocumentTitle.AsText(), color: titleTextColorFat, font: Font.SystemDefault(11), lineBreakMode: LineBreakMode.TruncateTail) .WithWidth(140) .Center(); // Ensures the doc name can never run over the controls in compact mode return(titleText); }, () => Label.Create(text: model.Title.AsText(), color: titleTextColorFat)); // For some reason the toolbar sometimes causes double zoom events, this is a workaround bool zoomExpected = false; Action zoomFat = () => Fusion.Application.MainThread.Schedule(() => { try { zoomExpected = true; window.Zoom(window); } finally { zoomExpected = false; } }); window.ShouldZoom = (_, __) => zoomExpected; titleBarContentFat = Layout.StackFromLeft( Control.Empty .WithWidth(80) .HideOnWindows(), Control.Empty .WithWidth(16) .HideOnMac(), titleBarContentFat) .WithPadding(top: Optional.Some <Points>(12)) .DockTopLeft(); desiredTitleBarHeight.OnNext(Observable.Return <Points>(0.0)); fusionContent = fusionContent.OnMouse(doubleClicked: Command.Enabled(zoomFat)).WithOverlay(titleBarContentFat); break; case WindowStyle.None: window.StyleMask = NSWindowStyle.TexturedBackground | NSWindowStyle.Borderless; window.MovableByWindowBackground = true; window.BackgroundColor = NSColor.Clear; desiredTitleBarHeight.OnNext(Observable.Return <Points>(0.0)); content.Layer.Frame = content.Frame; content.Layer.CornerRadius = 5.0f; content.Layer.MasksToBounds = true; break; case WindowStyle.Sheet: desiredTitleBarHeight.OnNext(Observable.Return <Points>(0.0)); break; default: throw new NotImplementedException(); } model.Size.Do(s => s.IsReadOnly.ObserveOn(dispatcher).Subscribe(isReadOnly => { if (isReadOnly) { window.StyleMask &= ~NSWindowStyle.Resizable; } else { window.StyleMask |= NSWindowStyle.Resizable; } })); var sizeFeedbackObservable = sizeFeedback.AsObservable(); var sizeObservable = size.AsObservable(); model.Title.ObserveOn(dispatcher).Subscribe(title => window.Title = title); sizeObservable.CombineLatest( desiredTitleBarHeight.Switch(), (s, h) => new Size <Points>(s.Width, s.Height + h)).ObserveOn(dispatcher).Subscribe(s => window.SetContentSize(s.ToSize())); window.WillClose += (sender, args) => { model.Closed.ExecuteOnce(); }; // Window closed by user var observer = new WindowObserver(); observer.DangerousRetain(); window.AddObserver(observer, new NSString("visible"), NSKeyValueObservingOptions.New, IntPtr.Zero); window.DidResize += (s, a) => desiredTitleBarHeight.Switch() .Subscribe(titleBarHeight => size.Write((content.Frame.Size - new CGSize(0, (float)titleBarHeight)).ToFusion())); var transize = sizeFeedbackObservable.CombineLatest( desiredTitleBarHeight.Switch(), (s, h) => new Size <Points>(s.Width, s.Height + h)).Transpose(); fusionContent.Mount(new MountLocation.Mutable { AvailableSize = transize, NativeFrame = ObservableMath.RectangleWithSize(transize), IsRooted = window.IsShowing }); Fusion.Application.MainThread.Schedule(() => { var nativeContent = fusionContent.NativeHandle as NSView; if (nativeContent != null) { content.AddSubview(nativeContent); } }); var systemId = SystemGuidLoader.LoadOrCreateOrEmpty(); model.Menu.Do(menu => MenuBuilder .CreateMenu(menu, ReportFactory.GetReporter(systemId, Guid.NewGuid(), "Menu")) .ToObservable() .Subscribe(m => window.Menu = m)); window.Center(); var centerposition = new Point <Points>((double)window.Frame.X, (double)window.Frame.Y); var position = model.Position .Or(Property.Create(Optional.None <Point <Points> >())) .Or(centerposition) .AutoInvalidate(TimeSpan.FromSeconds(2)) .PreventFeedback(); model.TopMost.Do(topMost => topMost.Subscribe(t => { window.Level = t ? NSWindowLevel.Floating : NSWindowLevel.Normal; })); position.ObserveOn(dispatcher).Subscribe(p => { window.SetFrameOrigin(new CGPoint(p.X, p.Y)); }); window.DidMove += (s, a) => { position.Write(new Point <Points>((double)window.Frame.Left, (double)window.Frame.Top)); }; window.DidBecomeMain += (s, a) => { if (window.Menu != null) { NSApplication.SharedApplication.MainMenu = window.Menu; } else { NSApplication.SharedApplication.MainMenu = new NSMenu(); } }; return(window); }