Esempio n. 1
0
        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();
                }
        }
Esempio n. 2
0
        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> >();
        }
Esempio n. 3
0
 static ReportFactory()
 {
     FallbackReport = new NullReport();             //Protect against someone indirectly using `FallbackReport` during execution of `GetReporter()`
     FallbackReport = GetReporter(SystemGuidLoader.LoadOrCreateOrEmpty(), Guid.NewGuid(), "Fuse");
 }
Esempio n. 4
0
        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);
        }
Esempio n. 5
0
        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);
            }
        }
Esempio n. 6
0
        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();
        }
Esempio n. 7
0
        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);
        }