public Task ResizeTerminalAsync(byte id, TerminalSize size)
 {
     return(_appServiceConnection.SendMessageAsync(CreateMessage(new ResizeTerminalRequest
     {
         TerminalId = id, NewSize = size
     })));
 }
        public void Start(CreateTerminalRequest request, TerminalsManager terminalsManager)
        {
            Id = request.Id;
            _terminalsManager = terminalsManager;
            _terminalSize     = request.Size;

            ShellExecutableName = Path.GetFileNameWithoutExtension(request.Profile.Location);
            var cwd = GetWorkingDirectory(request.Profile);

            var args = string.Empty;

            if (!string.IsNullOrWhiteSpace(request.Profile.Location))
            {
                args = $"\"{request.Profile.Location}\" {request.Profile.Arguments}";
            }
            else
            {
                args = request.Profile.Arguments;
            }

            _terminal              = new Terminal();
            _terminal.OutputReady += _terminal_OutputReady;
            _terminal.Exited      += _terminal_Exited;
            Task.Run(() => _terminal.Start(args, cwd, terminalsManager.GetDefaultEnvironmentVariableString(request.Profile.EnvironmentVariables), request.Size.Columns, request.Size.Rows));
        }
Beispiel #3
0
        public Task ResizeTerminal(int id, TerminalSize size)
        {
            var request = new ResizeTerminalRequest
            {
                TerminalId = id,
                NewSize    = size
            };

            return(_appServiceConnection.SendMessageAsync(CreateMessage(request)));
        }
Beispiel #4
0
        public WinPty(Profile profile, TerminalSize size, bool separateStdErr = false)
        {
            _size = size;

            IntPtr err      = IntPtr.Zero;
            IntPtr cfg      = IntPtr.Zero;
            IntPtr spawnCfg = IntPtr.Zero;

            try
            {
                ulong cfgFlags = WINPTY_FLAG_COLOR_ESCAPES;
                if (separateStdErr)
                {
                    cfgFlags |= WINPTY_FLAG_CONERR;
                }
                cfg = winpty_config_new(cfgFlags, out err);
                winpty_config_set_initial_size(cfg, size.Columns, size.Rows);

                _handle = winpty_open(cfg, out err);
                if (err != IntPtr.Zero)
                {
                    throw new WinPtrException(err);
                }

                string cmdline = null;
                string env     = GetEnvironmentString(profile.EnvironmentVariables);
                if (profile.Arguments != null && profile.Arguments.Length > 0)
                {
                    cmdline = string.Join(" ", profile.Arguments.Select(x => $"\"{x}\""));
                }
                spawnCfg = winpty_spawn_config_new(WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN, profile.Command, cmdline, profile.CurrentWorkingDirectory, env, out err);
                if (err != IntPtr.Zero)
                {
                    throw new WinPtrException(err);
                }

                StandardInput  = CreatePipe(winpty_conin_name(_handle), PipeDirection.Out);
                StandardOutput = CreatePipe(winpty_conout_name(_handle), PipeDirection.In);
                if (separateStdErr)
                {
                    StandardError = CreatePipe(winpty_conerr_name(_handle), PipeDirection.In);
                }

                if (!winpty_spawn(_handle, spawnCfg, out IntPtr process, out IntPtr thread, out int procError, out err))
                {
                    throw new WinPtrException(err);
                }
            }
            finally
            {
                winpty_config_free(cfg);
                winpty_spawn_config_free(spawnCfg);
                winpty_error_free(err);
            }
        }
 public void ResizeTerminal(int id, TerminalSize size)
 {
     if (_terminals.TryGetValue(id, out TerminalSession terminal))
     {
         terminal.Resize(size);
     }
     else
     {
         Debug.WriteLine($"ResizeTerminal: terminal with id '{id}' was not found");
     }
 }
Beispiel #6
0
        private Size GetWindowSizeForBufferSize(TerminalSize size)
        {
            Size charSize           = terminalControl.CharSize;
            Size snappedConsoleSize = new Size(size.Columns * charSize.Width,
                                               size.Rows * charSize.Height);

            Size result = new Size(Math.Ceiling(snappedConsoleSize.Width + _consoleSizeDelta.Width) + 2,
                                   Math.Ceiling(snappedConsoleSize.Height + _consoleSizeDelta.Height));

            return(result);
        }
Beispiel #7
0
        /// <summary>
        /// to be called by view when ready
        /// </summary>
        /// <param name="shellProfile"></param>
        /// <param name="size"></param>
        /// <param name="sessionType"></param>
        public async Task StartShellProcess(ShellProfile shellProfile, TerminalSize size, SessionType sessionType)
        {
            _trayProcessCommunicationService.SubscribeForTerminalOutput(Id, t => OutputReceived?.Invoke(this, t));
            var response = await _trayProcessCommunicationService.CreateTerminal(Id, size, shellProfile, sessionType).ConfigureAwait(true);

            if (response.Success)
            {
                FallbackTitle = response.ShellExecutableName;
                SetTitle(FallbackTitle);
            }
        }
Beispiel #8
0
 public void ResizeTerminal(byte id, TerminalSize size)
 {
     if (_terminals.TryGetValue(id, out TerminalSessionInfo sessionInfo))
     {
         sessionInfo.Session.Resize(size);
     }
     else
     {
         Debug.WriteLine($"ResizeTerminal: terminal with id '{id}' was not found");
     }
 }
        public async Task <CreateTerminalResponse> CreateTerminal(TerminalSize size, ShellProfile shellProfile)
        {
            var request = new CreateTerminalRequest
            {
                Size    = size,
                Profile = shellProfile
            };

            var responseMessage = await _appServiceConnection.SendMessageAsync(CreateMessage(request));

            return(JsonConvert.DeserializeObject <CreateTerminalResponse>(responseMessage[MessageKeys.Content]));
        }
Beispiel #10
0
        public NativePty(ExecutionProfile executionProfile, TerminalSize size)
        {
            SafeFileHandle stdin;
            SafeFileHandle stdout;

            CreatePipe(out stdin, out _writeHandle, IntPtr.Zero, 0);
            CreatePipe(out _readHandle, out stdout, IntPtr.Zero, 0);

            W32Throw(CreatePseudoConsole(new COORD {
                X = (short)size.Columns, Y = (short)size.Rows
            },
                                         stdin, stdout, 0, out this._ptyHandle));

            var allocSize = IntPtr.Zero;

            InitializeProcThreadAttributeList(IntPtr.Zero, 1, 0, ref allocSize);
            if (allocSize == IntPtr.Zero)
            {
                W32Throw(0, "allocation granularity whatever.");
            }

            var startupInfo = new STARTUPINFOEX
            {
                StartupInfo     = { cb = Marshal.SizeOf <STARTUPINFOEX>() },
                lpAttributeList = Marshal.AllocHGlobal(allocSize)
            };

            W32Throw(InitializeProcThreadAttributeList(startupInfo.lpAttributeList, 1, 0, ref allocSize));

            W32Throw(UpdateProcThreadAttribute(startupInfo.lpAttributeList, 0,
                                               (IntPtr)PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, _ptyHandle, (IntPtr)IntPtr.Size, IntPtr.Zero,
                                               IntPtr.Zero));

            var processSecurityAttr = new SECURITY_ATTRIBUTES();
            var threadSecurityAttr  = new SECURITY_ATTRIBUTES();

            processSecurityAttr.nLength = threadSecurityAttr.nLength = Marshal.SizeOf <SECURITY_ATTRIBUTES>();

            var args    = executionProfile.Arguments ?? Array.Empty <string>();
            var cmdline = executionProfile.EscapeArguments
                ? string.Join(" ", args.Select(x => $"\"{x}\""))
                : string.Join(" ", args);

            W32Throw(CreateProcess(executionProfile.Command, cmdline, ref processSecurityAttr, ref threadSecurityAttr,
                                   false, EXTENDED_STARTUPINFO_PRESENT, IntPtr.Zero, null, ref startupInfo, out var processInfo));

            DeleteProcThreadAttributeList(startupInfo.lpAttributeList);
            Marshal.FreeHGlobal(startupInfo.lpAttributeList);

            StandardOutput = new FileStream(_readHandle, FileAccess.Read);
            StandardInput  = new FileStream(_writeHandle, FileAccess.Write);
        }
Beispiel #11
0
        private async Task ResizeTask()
        {
            while (true)
            {
                TimeSpan     delay;
                TerminalSize size = null;

                lock (_resizeLock)
                {
                    if (_requestedSize?.EquivalentTo(_setSize) ?? true)
                    {
                        // Resize finished. Unblock output and exit.

                        if (_outputBlockedBuffer != null)
                        {
                            OnOutput?.Invoke(this, _outputBlockedBuffer.ToArray());

                            _outputBlockedBuffer.Dispose();
                            _outputBlockedBuffer = null;
                        }

                        _resizeTask = null;

                        break;
                    }

                    delay = _resizeScheduleTime.Subtract(DateTime.UtcNow);

                    // To avoid sleeping for only few milliseconds we're introducing a threshold of 10 milliseconds
                    if (delay.TotalMilliseconds < 10)
                    {
                        _setSize = size = _requestedSize;

                        if (_outputBlockedBuffer == null)
                        {
                            _outputBlockedBuffer = new MemoryStream();
                        }
                    }
                }

                if (size == null)
                {
                    await Task.Delay(delay).ConfigureAwait(false);
                }
                else
                {
                    await ViewModel.Terminal.SetSizeAsync(_requestedSize).ConfigureAwait(false);
                }
            }
        }
Beispiel #12
0
        // Must be called from a code locked with _resizeLock
        private void ScheduleResize(TerminalSize size, bool scheduleIfEqual)
        {
            if (!scheduleIfEqual && size.EquivalentTo(_requestedSize))
            {
                return;
            }

            _requestedSize      = size;
            _resizeScheduleTime = DateTime.UtcNow.Add(ResizeDelay);

            if (_resizeTask == null)
            {
                _resizeTask = ResizeTask();
            }
        }
        public Task ResizeTerminal(int id, TerminalSize size)
        {
            var request = new ResizeTerminalRequest
            {
                TerminalId = id,
                NewSize    = size
            };

            var message = new ValueSet
            {
                { MessageKeys.Type, MessageTypes.ResizeTerminalRequest },
                { MessageKeys.Content, JsonConvert.SerializeObject(request) }
            };

            return(_appServiceConnection.SendMessageAsync(message).AsTask());
        }
Beispiel #14
0
        public void Resize(TerminalSize size)
        {
            var errorHandle = IntPtr.Zero;

            try
            {
                winpty_set_size(_handle, size.Columns, size.Rows, out errorHandle);
                if (errorHandle != IntPtr.Zero)
                {
                    throw new Exception(winpty_error_msg(errorHandle).ToString());
                }
            }
            finally
            {
                winpty_error_free(errorHandle);
            }
        }
        public async Task <CreateTerminalResponse> CreateTerminal(TerminalSize size, ShellProfile shellProfile)
        {
            var request = new CreateTerminalRequest
            {
                Size    = size,
                Profile = shellProfile
            };

            var message = new ValueSet
            {
                { MessageKeys.Type, MessageTypes.CreateTerminalRequest },
                { MessageKeys.Content, JsonConvert.SerializeObject(request) }
            };

            var responseMessage = await _appServiceConnection.SendMessageAsync(message);

            return(JsonConvert.DeserializeObject <CreateTerminalResponse>((string)responseMessage.Message[MessageKeys.Content]));
        }
 public void ResizeTerminal(byte id, TerminalSize size)
 {
     if (_terminals.TryGetValue(id, out TerminalSessionInfo sessionInfo))
     {
         try
         {
             sessionInfo.Session.Resize(size);
         }
         catch (Exception e)
         {
             Logger.Instance.Error($"ResizeTerminal: resizing of terminal with id '{id}' failed with exception: {e}");
         }
     }
     else
     {
         Debug.WriteLine($"ResizeTerminal: terminal with id '{id}' was not found");
     }
 }
        public async Task <CreateTerminalResponse> CreateTerminalAsync(byte id, TerminalSize size, ShellProfile shellProfile,
                                                                       SessionType sessionType)
        {
            var request = new CreateTerminalRequest
            {
                Id          = id,
                Size        = size,
                Profile     = shellProfile,
                SessionType = sessionType
            };

            Logger.Instance.Debug("Sending CreateTerminalRequest: {@request}", request);

            var response = await GetResponseAsync <CreateTerminalResponse>(request).ConfigureAwait(false);

            Logger.Instance.Debug("Received CreateTerminalResponse: {@response}", response);

            return(response);
        }
Beispiel #18
0
        private async Task <bool> StartShellProcessAsync(TerminalSize size)
        {
            var sessionType = ViewModel.ShellProfile.UseConPty &&
                              ViewModel.ApplicationView.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 7)
                    ? SessionType.ConPty
                    : SessionType.WinPty;

            var response = await ViewModel.Terminal.StartShellProcessAsync(ViewModel.ShellProfile, size, sessionType, ViewModel.XtermBufferState).ConfigureAwait(false);

            if (!response.Success)
            {
                await Dispatcher.ExecuteAsync(async() =>
                                              await ViewModel.DialogService.ShowMessageDialogAsync("Error", response.Error, DialogButton.OK))
                .ConfigureAwait(false);

                ViewModel.Terminal.ReportLauchFailed();
                return(false);
            }
            return(true);
        }
        public async Task <CreateTerminalResponse> CreateTerminal(byte id, TerminalSize size, ShellProfile shellProfile, SessionType sessionType)
        {
            var request = new CreateTerminalRequest
            {
                Id          = id,
                Size        = size,
                Profile     = shellProfile,
                SessionType = sessionType
            };

            Logger.Instance.Debug("Sending CreateTerminalRequest: {@request}", request);

            var responseMessage = await _appServiceConnection.SendMessageAsync(CreateMessage(request));

            var response = JsonConvert.DeserializeObject <CreateTerminalResponse>((string)responseMessage[MessageKeys.Content]);

            Logger.Instance.Debug("Received CreateTerminalResponse: {@response}", response);

            return(response);
        }
Beispiel #20
0
        protected override void OnSourceInitialized(EventArgs e)
        {
            base.OnSourceInitialized(e);

            var config = _configService.Config;

            int columns = Math.Max(config.Columns, MinColumns);
            int rows    = Math.Max(config.Rows, MinRows);

            _terminalSize = new TerminalSize(columns, rows);
            FixWindowSize();

            Profile profile = config.Profile;

            if (profile == null)
            {
                profile = DefaultProfile.Get();
            }
            _defaultProfile = ExpandVariables(profile);
            CreateSession(_defaultProfile);
        }
Beispiel #21
0
        void IxtermEventListener.OnTerminalResized(int columns, int rows)
        {
            if (_terminalClosed)
            {
                return;
            }

            var size = new TerminalSize {
                Columns = columns, Rows = rows
            };

            lock (_resizeLock)
            {
                if (_setSize == null)
                {
                    // Initialization not finished yet
                    _requestedSize = size;
                }
                else
                {
                    ScheduleResize(size, false);
                }
            }
        }
Beispiel #22
0
        private void SetTermialSize(TerminalSize size)
        {
            if (_terminalSize != size)
            {
                _terminalSize = size;
                if (_currentSession != null)
                {
                    _currentSession.Size = size;
                }

                if (Ready)
                {
                    // Save configuration
                    _configService.Config.Columns = size.Columns;
                    _configService.Config.Rows    = size.Rows;
                    _configService.Save();

                    // Update hint overlay
                    resizeHint.Hint      = size;
                    resizeHint.IsShowing = true;
                    resizeHint.IsShowing = IsResizing;
                }
            }
        }
Beispiel #23
0
        /// <summary>
        /// To be called by view
        /// </summary>
        public async Task SetSizeAsync(TerminalSize size)
        {
            await _trayProcessCommunicationService.ResizeTerminalAsync(Id, size).ConfigureAwait(false);

            SizeChanged?.Invoke(this, size);
        }
Beispiel #24
0
        public async Task InitializeAsync(TerminalViewModel viewModel)
        {
            ViewModel = viewModel;
            ViewModel.Terminal.OutputReceived += Terminal_OutputReceived;
            ViewModel.Terminal.RegisterSelectedTextCallback(() => ExecuteScriptAsync("term.getSelection()"));
            ViewModel.Terminal.Closed += Terminal_Closed;

            _webView.SetBinding(ContextFlyoutProperty, new Binding
            {
                Converter = (IValueConverter)Application.Current.Resources["MenuViewModelToFlyoutMenuConverter"],
                Mode      = BindingMode.OneWay,
                Source    = ViewModel,
                Path      = new PropertyPath(nameof(TerminalViewModel.ContextMenu))
            });

            var options     = ViewModel.SettingsService.GetTerminalOptions();
            var keyBindings = ViewModel.SettingsService.GetCommandKeyBindings();
            var profiles    = ViewModel.SettingsService.GetShellProfiles();
            var sshprofiles = ViewModel.SettingsService.GetSshProfiles();
            var theme       = ViewModel.TerminalTheme;

            // Waiting for WebView.NavigationCompleted event to happen
            await _tcsNavigationCompleted.Task.ConfigureAwait(false);

            var size = await CreateXtermViewAsync(options, theme.Colors,
                                                  FlattenKeyBindings(keyBindings, profiles, sshprofiles)).ConfigureAwait(false);

            // Waiting for IxtermEventListener.OnInitialized() call to happen
            await _tcsConnected.Task;

            lock (_resizeLock)
            {
                // Check to see if some resizing has happened meanwhile
                if (_requestedSize != null)
                {
                    size = _requestedSize;
                }
                else
                {
                    _requestedSize = size;
                }
            }

            if (false == await StartShellProcessAsync(size).ConfigureAwait(false))
            {
                return;
            }

            lock (_resizeLock)
            {
                // Check to see if some resizing has happened meanwhile
                if (!size.EquivalentTo(_requestedSize))
                {
                    ScheduleResize(_requestedSize, true);
                }
                else
                {
                    _setSize = size;
                }
            }

            if (ViewModel.ShellProfile?.Tag is ISessionSuccessTracker tracker)
            {
                tracker.SetSuccessfulSessionStart();
            }

            await Dispatcher.ExecuteAsync(() => _webView.Focus(FocusState.Programmatic)).ConfigureAwait(false);
        }
 public void Resize(TerminalSize size)
 {
     _terminal.Resize(size.Columns, size.Rows);
 }
 public bool EquivalentTo(TerminalSize other) => ReferenceEquals(this, other) ||
 other != null && Columns.Equals(other.Columns) &&
 Rows.Equals(other.Rows);
Beispiel #27
0
        /// <summary>
        /// To be called by view when ready
        /// </summary>
        public async Task <TerminalResponse> StartShellProcessAsync(ShellProfile shellProfile, TerminalSize size, SessionType sessionType, string termState)
        {
            if (!_requireShellProcessStart && !string.IsNullOrEmpty(termState))
            {
                OutputReceived?.Invoke(this, Encoding.UTF8.GetBytes(termState));
            }

            _trayProcessCommunicationService.SubscribeForTerminalOutput(Id, t => OutputReceived?.Invoke(this, t));

            if (_requireShellProcessStart)
            {
                var response = await _trayProcessCommunicationService
                               .CreateTerminalAsync(Id, size, shellProfile, sessionType).ConfigureAwait(false);

                if (response.Success)
                {
                    _fallbackTitle = response.Name;
                    SetTitle(_fallbackTitle);
                }
                return(response);
            }
            else
            {
                return(await _trayProcessCommunicationService.PauseTerminalOutputAsync(Id, false));
            }
        }
Beispiel #28
0
 internal TerminalResizeEventArgs(TerminalSize size)
 {
     Size = size;
 }
Beispiel #29
0
        public void Start(CreateTerminalRequest request, TerminalsManager terminalsManager)
        {
            Id = request.Id;
            _terminalsManager = terminalsManager;
            _terminalSize     = request.Size;

            var configHandle      = IntPtr.Zero;
            var spawnConfigHandle = IntPtr.Zero;
            var errorHandle       = IntPtr.Zero;

            try
            {
                configHandle = winpty_config_new(WINPTY_FLAG_COLOR_ESCAPES, out errorHandle);
                winpty_config_set_initial_size(configHandle, request.Size.Columns, request.Size.Rows);

                _handle = winpty_open(configHandle, out errorHandle);
                if (errorHandle != IntPtr.Zero)
                {
                    throw new Exception(winpty_error_msg(errorHandle));
                }

                var cwd  = GetWorkingDirectory(request.Profile);
                var args = request.Profile.Arguments;

                if (!string.IsNullOrWhiteSpace(request.Profile.Location))
                {
                    args = $"\"{request.Profile.Location}\" {args}";
                }

                spawnConfigHandle = winpty_spawn_config_new(WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN, request.Profile.Location, args, cwd, terminalsManager.GetDefaultEnvironmentVariableString(request.Profile.EnvironmentVariables), out errorHandle);
                if (errorHandle != IntPtr.Zero)
                {
                    throw new Exception(winpty_error_msg(errorHandle));
                }

                _stdin  = CreatePipe(winpty_conin_name(_handle), PipeDirection.Out);
                _stdout = CreatePipe(winpty_conout_name(_handle), PipeDirection.In);

                if (!winpty_spawn(_handle, spawnConfigHandle, out IntPtr process, out IntPtr thread, out int procError, out errorHandle))
                {
                    throw new Exception($@"Failed to start the shell process. Please check your shell settings.{Environment.NewLine}Tried to start: {request.Profile.Location} ""{request.Profile.Arguments}""");
                }

                var shellProcessId = ProcessApi.GetProcessId(process);
                _shellProcess = Process.GetProcessById(shellProcessId);
                _shellProcess.EnableRaisingEvents = true;
                _shellProcess.Exited += _shellProcess_Exited;

                if (!string.IsNullOrWhiteSpace(request.Profile.Location))
                {
                    ShellExecutableName = Path.GetFileNameWithoutExtension(request.Profile.Location);
                }
                else
                {
                    ShellExecutableName = request.Profile.Arguments.Split(' ')[0];
                }
            }
            finally
            {
                winpty_config_free(configHandle);
                winpty_spawn_config_free(spawnConfigHandle);
                winpty_error_free(errorHandle);
            }

            ListenToStdOut();
        }
Beispiel #30
0
        /// <summary>
        /// To be called by view
        /// </summary>
        public async Task SetSize(TerminalSize size)
        {
            await _trayProcessCommunicationService.ResizeTerminal(Id, size);

            SizeChanged?.Invoke(this, size);
        }