tabby-rdp 0.2.7 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +72 -2
- package/README.md +182 -21
- package/dist/connectionStatus.js +140 -0
- package/dist/connectionStatus.js.map +1 -0
- package/dist/desk.js +21 -10
- package/dist/desk.js.map +1 -1
- package/dist/deskScript.js +3 -0
- package/dist/deskScript.js.map +1 -1
- package/dist/desktop.service.js +994 -53
- package/dist/desktop.service.js.map +1 -1
- package/dist/desktopForm.js +64 -19
- package/dist/desktopForm.js.map +1 -1
- package/dist/desktops.js +60 -21
- package/dist/desktops.js.map +1 -1
- package/dist/fileTransfer.js +152 -5
- package/dist/fileTransfer.js.map +1 -1
- package/dist/header.js +22 -7
- package/dist/header.js.map +1 -1
- package/dist/help.js +241 -0
- package/dist/help.js.map +1 -0
- package/dist/index.js +16 -1
- package/dist/index.js.map +1 -1
- package/dist/keyboard.js +142 -5
- package/dist/keyboard.js.map +1 -1
- package/dist/microphone.js +295 -0
- package/dist/microphone.js.map +1 -0
- package/dist/osd.js +79 -0
- package/dist/osd.js.map +1 -0
- package/dist/probe.js +33 -0
- package/dist/probe.js.map +1 -0
- package/dist/rdcleanpath.js +132 -7
- package/dist/rdcleanpath.js.map +1 -1
- package/dist/rdpFile.js +47 -0
- package/dist/rdpFile.js.map +1 -0
- package/dist/rdpProfile.js +367 -0
- package/dist/rdpProfile.js.map +1 -0
- package/dist/remoteSetup.js +90 -11
- package/dist/remoteSetup.js.map +1 -1
- package/dist/settingsPage.js +554 -0
- package/dist/settingsPage.js.map +1 -0
- package/dist/signin.js +21 -2
- package/dist/signin.js.map +1 -1
- package/dist/ssh.js +28 -0
- package/dist/ssh.js.map +1 -1
- package/dist/targets.js +148 -8
- package/dist/targets.js.map +1 -1
- package/dist/ui.js +163 -24
- package/dist/ui.js.map +1 -1
- package/dist/updates.js +123 -0
- package/dist/updates.js.map +1 -0
- package/dist/vms.js +90 -0
- package/dist/vms.js.map +1 -0
- package/dist/wake.js +124 -0
- package/dist/wake.js.map +1 -0
- package/package.json +2 -1
- package/vendor/IRONRDP-LICENSE +3 -3
- package/vendor/iron-remote-desktop-rdp.js +698 -451
- package/vendor/iron-remote-desktop.js +87 -81
- package/vendor/ironrdp_web_bg.wasm +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,79 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.1
|
|
4
|
+
|
|
5
|
+
**New**
|
|
6
|
+
- **New versions:** Tabby shows plugin upgrades only while its Plugins page is open, so tabby-rdp now says so itself.
|
|
7
|
+
Once a day it asks npm for the latest version (nothing else is sent); a newer one gets a note once, an **Update
|
|
8
|
+
available** item in the menus and a line on Settings › Remote Desktop, each leading to Tabby's Upgrade button.
|
|
9
|
+
**Tell me about new versions** turns it off.
|
|
10
|
+
|
|
11
|
+
**Docs**
|
|
12
|
+
- The README's demo plays in the page (a GIF), on GitHub and on npm.
|
|
13
|
+
|
|
14
|
+
## 0.3.0
|
|
15
|
+
|
|
16
|
+
**New**
|
|
17
|
+
- **Settings › Remote Desktop:** getting started, every setting with a line on what it does, keys and tips, the
|
|
18
|
+
desktops and certificates the plugin keeps, troubleshooting, and each open desktop's log to copy for a bug report.
|
|
19
|
+
A tip the first time a desktop connects, and **What does this mean?** under a message that ends a connection.
|
|
20
|
+
- **Several desktops in one tab:** **Paste to all desktops in this tab** (text, pictures, or files copied here),
|
|
21
|
+
**Type into all desktops in this tab** (a label on each says so while it's on), and **Make panes even**. As you
|
|
22
|
+
click into a desktop, its name shows in its corner for a moment; when, and its font, size, place and color, are in
|
|
23
|
+
the settings, with a preview.
|
|
24
|
+
- **Files copied in Finder** (Explorer, Files) paste on the desktop with ⌘V (Ctrl+V), and the paste waits until the
|
|
25
|
+
remote has taken them in.
|
|
26
|
+
- **VMs on a host:** the libvirt VMs with a desktop on an SSH host (RDP answering, or Windows and shut off) show up in
|
|
27
|
+
its menu, ready to open, or to start and open. **Find virtual machines on SSH hosts** turns it off.
|
|
28
|
+
- **`ssh` typed in an SSH tab:** **Desktop** and `desk` there open the machine it went to, through the tab's host, and
|
|
29
|
+
Reconnect stays with it.
|
|
30
|
+
- **Remote desktop (RDP) profiles:** desktops as Tabby profiles, in their own tab: connect directly to an RDP server
|
|
31
|
+
this machine reaches (LAN, VPN), or through an SSH profile. They show up in the profile list, quick connect
|
|
32
|
+
(`user@host:port`), recent profiles and tab recovery. **Import an .rdp file…** turns a saved Remote Desktop
|
|
33
|
+
connection into one.
|
|
34
|
+
- **Linux desktops through xrdp** (KDE, XFCE, MATE, …): the SSH host's own desktop is xrdp's when GNOME isn't there,
|
|
35
|
+
and offered next to GNOME when both are; `kind: xrdp` for desktops behind a host. Signs in with the Linux account.
|
|
36
|
+
- **Windows as the SSH host:** an SSH host that is itself Windows (OpenSSH server) opens its own RDP desktop.
|
|
37
|
+
- **H.264 video decoding** (setting **Video decoding**, on by default), hardware-accelerated where Tabby's engine can:
|
|
38
|
+
Windows desktops now use the graphics pipeline with H.264 for what changes like video, instead of bitmaps; GNOME
|
|
39
|
+
uses it when its machine has a hardware encoder.
|
|
40
|
+
- **Microphone** (off by default): an app on the remote desktop that records gets your microphone, only while it
|
|
41
|
+
records, with an indicator.
|
|
42
|
+
- **Send keys:** Ctrl+Alt+Del, Win+R, Win+L, Task Manager and more for Windows; Super, the app grid, Alt+F2 for GNOME.
|
|
43
|
+
From a Mac, ⌃⌘ with a key is the Windows key with it (⌃⌘R for Win+R).
|
|
44
|
+
- **View only**, **Save a screenshot** (to Downloads and the clipboard), and **actual size** with scroll bars for a
|
|
45
|
+
fixed resolution.
|
|
46
|
+
- **Certificates:** GNOME desktops accept only the certificate the plugin made for them; other desktops remember theirs
|
|
47
|
+
on first use and stop to ask, before signing in, if it changes.
|
|
48
|
+
- **Edit a desktop** behind a host from the menus (name, address, account, kind).
|
|
49
|
+
- **Wake before connecting:** `wake: { vm }` starts a libvirt VM on the SSH host, `wake: { mac }` sends Wake-on-LAN,
|
|
50
|
+
when the desktop doesn't answer.
|
|
51
|
+
- **Connection status** (off by default): throughput, frames per second, SSH round trip and how it's connected, in the
|
|
52
|
+
desktop's corner.
|
|
53
|
+
|
|
54
|
+
**Fixed**
|
|
55
|
+
- `desk` run on another machine than the tab's (after `ssh` there, or with a shared home folder) opened a terminal on
|
|
56
|
+
the wrong desktop; it's refused now, with a note that says why.
|
|
57
|
+
- Windows over the graphics pipeline: IronRDP's RemoteFX Progressive decoder rejected Windows' refinement passes and
|
|
58
|
+
ended the session (patch 0010, for upstream).
|
|
59
|
+
|
|
60
|
+
**Package**
|
|
61
|
+
- IronRDP's WebAssembly ships as its own file instead of a 6.6 MB base64 string inside the JavaScript: the package is
|
|
62
|
+
about 2 MB instead of 2.7 MB.
|
|
63
|
+
- Releases are built and staged on npm by GitHub Actions, with provenance.
|
|
64
|
+
|
|
65
|
+
**Changed**
|
|
66
|
+
- Hosts are called by their SSH profile's name (not its address) in messages and the on-screen name.
|
|
67
|
+
- **Remove a desktop** asks first.
|
|
68
|
+
- **Menus:** the plugin's items in a terminal's or tab's menu start with a **Remote Desktop** heading (naming the
|
|
69
|
+
desktop while one is connected), so they read as the plugin's rather than Tabby's. Under it the items are shorter:
|
|
70
|
+
**Send files…**, **Disconnect** and **Settings**, and the host's other desktops (and VMs found there) and
|
|
71
|
+
**Add a desktop behind \<host\>…** are under **Desktops**.
|
|
72
|
+
|
|
3
73
|
## 0.2.7
|
|
4
74
|
|
|
5
|
-
(0.2.6
|
|
6
|
-
|
|
75
|
+
(0.2.6 carries the same change: its staged publish on npm looked like it had failed and only appeared later, so the
|
|
76
|
+
change was released again as 0.2.7.)
|
|
7
77
|
|
|
8
78
|
**Security**
|
|
9
79
|
- Files copied on the remote desktop are saved inside the folder you save them to (Downloads). Their names come from
|
package/README.md
CHANGED
|
@@ -5,13 +5,15 @@
|
|
|
5
5
|
# tabby-rdp
|
|
6
6
|
|
|
7
7
|
**Remote desktops in your Tabby SSH tabs.**<br>
|
|
8
|
-
Linux
|
|
8
|
+
Linux and Windows, side by side, through the SSH connections you already have.
|
|
9
9
|
|
|
10
10
|
[](https://www.npmjs.com/package/tabby-rdp)
|
|
11
11
|
[](LICENSE)
|
|
12
12
|
[](https://tabby.sh)
|
|
13
13
|
|
|
14
|
-
<img src="docs/images/
|
|
14
|
+
<img src="docs/images/demo.gif" width="860" alt="Four desktops in one Tabby tab (GNOME, Windows, xrdp), a file pasted to all of them, a pane switched to its console, and desk">
|
|
15
|
+
|
|
16
|
+
<sub>Sharper: <a href="https://github.com/meanaverage/tabby-rdp/releases/download/v0.3.0/tabby-rdp-demo.mp4">the same demo as an MP4</a> (downloads)</sub>
|
|
15
17
|
|
|
16
18
|
</div>
|
|
17
19
|
|
|
@@ -23,12 +25,24 @@ nothing is opened on the network, and nothing has to be installed on the remote
|
|
|
23
25
|
|
|
24
26
|
- **Linux desktops without a monitor or a login.** The plugin starts a headless GNOME session for your SSH user with
|
|
25
27
|
GNOME Remote Desktop, on the fly, without root. A server in a rack works as well as a workstation.
|
|
26
|
-
- **
|
|
27
|
-
- **
|
|
28
|
-
|
|
28
|
+
- **Other Linux desktops** (KDE, XFCE, MATE, Cinnamon, …) through xrdp, where it runs: the plugin finds it by itself.
|
|
29
|
+
- **Windows desktops** behind any SSH host, such as a VM on your build server, and the desktop of a Windows machine
|
|
30
|
+
you SSH into.
|
|
31
|
+
- **Remote desktop profiles** for machines you reach without SSH (LAN, VPN): in Tabby's profile list, in a tab of their
|
|
32
|
+
own.
|
|
33
|
+
- **Several machines at once:** split a tab into a grid of desktops, then paste to all of them or type into all of them
|
|
34
|
+
at once. A short on-screen name says which one you're in.
|
|
35
|
+
- **VMs found for you:** the libvirt VMs on an SSH host that have a desktop show up in its menu, ready to open, or to
|
|
36
|
+
start and open.
|
|
37
|
+
- **`ssh` on from a host:** in an SSH tab where you typed `ssh` to another machine, the desktop is that machine's.
|
|
38
|
+
- **A proper desktop experience:** clipboard and files both ways, sound and microphone, live resize to the pane,
|
|
39
|
+
sharp Retina rendering, Mac keyboard shortcuts, and automatic reconnects after sleep.
|
|
29
40
|
- **`desk`:** type `desk` in the console and the same shell, with its history and running programs, moves into a
|
|
30
41
|
terminal on the desktop.
|
|
31
42
|
|
|
43
|
+
Everything is in **Settings › Remote Desktop**: getting started, every setting with a line on what it does, the keys,
|
|
44
|
+
the desktops and certificates the plugin keeps, and troubleshooting.
|
|
45
|
+
|
|
32
46
|
The remote desktop itself is [IronRDP](https://github.com/Devolutions/IronRDP)'s web client, running inside Tabby.
|
|
33
47
|
Making it work with GNOME took fixes in IronRDP, which we contribute upstream ([below](#built-on-ironrdp)).
|
|
34
48
|
|
|
@@ -38,6 +52,9 @@ Making it work with GNOME took fixes in IronRDP, which we contribute upstream ([
|
|
|
38
52
|
- [Use](#use)
|
|
39
53
|
- [Features](#features)
|
|
40
54
|
- [Windows and other desktops behind a host](#windows-and-other-desktops-behind-a-host)
|
|
55
|
+
- [Remote desktop profiles](#remote-desktop-profiles)
|
|
56
|
+
- [Several desktops in one tab](#several-desktops-in-one-tab)
|
|
57
|
+
- [VMs on a host](#vms-on-a-host)
|
|
41
58
|
- [desk: the console on the desktop](#desk-the-console-on-the-desktop)
|
|
42
59
|
- [Settings](#settings)
|
|
43
60
|
- [Requirements](#requirements)
|
|
@@ -63,14 +80,24 @@ Open an SSH tab to a Linux machine with GNOME, and:
|
|
|
63
80
|
|
|
64
81
|
- press **⌘⇧G** (Ctrl+Shift+G on Windows and Linux), or
|
|
65
82
|
- click **Desktop** in the SSH tab's toolbar, or the desktop button in Tabby's header, or
|
|
66
|
-
- right-click the terminal or the tab: **Open remote desktop
|
|
83
|
+
- right-click the terminal or the tab: **Open remote desktop**, under the **Remote Desktop** heading.
|
|
84
|
+
|
|
85
|
+
<p align="center"><img src="docs/images/desktop.png" width="760" alt="A GNOME desktop in a Tabby SSH tab"></p>
|
|
67
86
|
|
|
68
87
|
The first connection to a machine takes a few seconds while it prepares GNOME Remote Desktop and a session; later
|
|
69
88
|
ones take well under a second. The same shortcut switches between the desktop and the console, and the desktop keeps
|
|
70
89
|
running in the background until you disconnect or close the tab.
|
|
71
90
|
|
|
91
|
+
A machine without GNOME but with [xrdp](https://github.com/neutrinolabs/xrdp) running (the usual RDP server for KDE,
|
|
92
|
+
XFCE, MATE and the rest) gets xrdp's desktop instead: sign in with your Linux password, which the plugin can remember
|
|
93
|
+
in the system keychain. A machine with both keeps GNOME as the tab's desktop and, once that has been opened, also
|
|
94
|
+
offers **Open \<host\> desktop (xrdp)** in its menus.
|
|
95
|
+
|
|
72
96
|
It also works in a plain local terminal where you typed `ssh host` (macOS and Linux), as long as that host accepts
|
|
73
|
-
your key without a password prompt.
|
|
97
|
+
your key without a password prompt. And in an SSH tab where you typed `ssh` on to another machine: **Desktop** there
|
|
98
|
+
opens that machine's desktop, going through the first, as long as the first can log in to it by itself (a key there,
|
|
99
|
+
or agent forwarding). So one pane of a split can show the first machine's desktop, and the other, after `ssh other`,
|
|
100
|
+
that machine's.
|
|
74
101
|
|
|
75
102
|
One desktop per account: a second tab to the same `user@host` switches to the tab that has it open, rather than
|
|
76
103
|
connecting again.
|
|
@@ -80,22 +107,32 @@ connecting again.
|
|
|
80
107
|
| | |
|
|
81
108
|
|---|---|
|
|
82
109
|
| **Clipboard** | Copy and paste text and images in both directions. |
|
|
83
|
-
| **Files** |
|
|
110
|
+
| **Files** | Copy files or folders in Finder and press ⌘V on the desktop, or drop them onto it, or use **Remote Desktop › Send files…** in the pane's menu; they paste in Files or Explorer. Files copied on the remote offer **Save to Downloads**. |
|
|
111
|
+
| **Several desktops in one tab** | Paste to all of them, type into all of them, and see which is which: [below](#several-desktops-in-one-tab). |
|
|
112
|
+
| **VMs on a host** | The host's VMs with a desktop, ready to open: [below](#vms-on-a-host). |
|
|
84
113
|
| **Sound** | The remote desktop's sound plays locally. |
|
|
85
|
-
| **
|
|
114
|
+
| **Microphone** | Optional (off by default): an app on the remote desktop that records, such as a call, gets your microphone. It is only captured while the app records, with an indicator in the corner of the desktop. |
|
|
115
|
+
| **Resize** | The remote resolution follows the pane as you resize the window or split it. Or reconnect at the new size, or keep a fixed resolution, scaled to fit or at actual size with scroll bars. |
|
|
86
116
|
| **Retina** | Optionally renders at device pixels, with the remote's UI scaled to match (GNOME and Windows alike), for sharp text. For all desktops, or only some. |
|
|
87
|
-
| **Keyboard on macOS** | ⌘C, ⌘V, ⌘Z and the rest work as on a Mac; tapping ⌘ alone is the Windows key. Tabby's own shortcuts stay out of the way while a desktop is showing, except switching tabs and returning to the console. |
|
|
117
|
+
| **Keyboard on macOS** | ⌘C, ⌘V, ⌘Z and the rest work as on a Mac; tapping ⌘ alone is the Windows key, and ⌃⌘ with a key is the Windows key with it (⌃⌘R for Win+R). Tabby's own shortcuts stay out of the way while a desktop is showing, except switching tabs and returning to the console. |
|
|
118
|
+
| **Send keys** | In the desktop's menus: Ctrl+Alt+Del, Win+R, Win+L, Ctrl+Shift+Esc, Print Screen and more for Windows; Super, Super+A, Alt+F2 and more for GNOME. |
|
|
119
|
+
| **View only** | In the desktop's menus: watch a desktop without touching it. No keys or clicks go to it while a "View only" label shows; the picture, clipboard and sound carry on. Kept across reconnects, until the desktop is closed. |
|
|
120
|
+
| **Screenshots** | **Save a screenshot** in the desktop's menus saves the remote screen at its full resolution as a PNG in Downloads, and copies it to the clipboard. |
|
|
121
|
+
| **Connection status** | Optionally, a small line in the corner of the desktop with the throughput each way, frames per second, the SSH round trip, and how it is connected (desktop, host, resolution, graphics mode, sharpness). |
|
|
88
122
|
| **Reconnecting** | After sleep or a network change, the desktop reconnects by itself once the connection is back. |
|
|
89
|
-
| **Sign-in** | GNOME desktops need none: the plugin manages their credentials. Windows desktops ask for the account once and can remember it in the system keychain. |
|
|
123
|
+
| **Sign-in** | GNOME desktops need none: the plugin manages their credentials. Windows and xrdp desktops ask for the account once and can remember it in the system keychain; **Sign in again…** in the menu replaces it. |
|
|
124
|
+
| **Certificates** | GNOME desktops accept only the certificate the plugin made for them. Windows and xrdp desktops remember theirs on first use and ask before accepting a different one. |
|
|
90
125
|
|
|
91
126
|
<p align="center"><img src="docs/images/files.png" width="760" alt="A file copied on the remote desktop, offered for saving"></p>
|
|
92
127
|
|
|
93
128
|
## Windows and other desktops behind a host
|
|
94
129
|
|
|
95
130
|
An SSH host can lead to other desktops it can reach, such as a Windows VM on the same machine. In that host's menu,
|
|
96
|
-
choose **Add a desktop behind \<host\>…** and enter a name, the address as seen from the host, and optionally the
|
|
97
|
-
user name. It opens right away, and from then on appears
|
|
98
|
-
|
|
131
|
+
choose **Desktops › Add a desktop behind \<host\>…** and enter a name, the address as seen from the host, and optionally the
|
|
132
|
+
user name and domain. It opens right away, and from then on appears under **Desktops** in the host's menu.
|
|
133
|
+
**Settings › Edit a desktop** changes one (its saved password, sharpness and remembered certificate
|
|
134
|
+
follow a new address; a new user name forgets the saved password), and **Remove a desktop** removes one, along with
|
|
135
|
+
its saved password and remembered certificate.
|
|
99
136
|
|
|
100
137
|
<p align="center"><img src="docs/images/windows.png" width="760" alt="A Windows 11 desktop, reached through an SSH host, in a Tabby tab"></p>
|
|
101
138
|
|
|
@@ -108,13 +145,108 @@ remoteDesktop:
|
|
|
108
145
|
via: buildhost # the SSH host: alias, hostname, user@hostname or user@hostname:port
|
|
109
146
|
host: 192.168.122.20 # the RDP server as seen from that host
|
|
110
147
|
port: 3389
|
|
111
|
-
kind: windows # or gnome
|
|
148
|
+
kind: windows # or xrdp (a Linux desktop served by xrdp), or gnome
|
|
112
149
|
username: alice # optional; DOMAIN\user works too
|
|
150
|
+
domain: CORP # optional
|
|
151
|
+
wake: { vm: win11 } # optional: start it when it's off (see below)
|
|
113
152
|
```
|
|
114
153
|
|
|
115
154
|
The connection runs through the same SSH connection; the Windows machine needs Remote Desktop turned on, and nothing
|
|
116
155
|
else.
|
|
117
156
|
|
|
157
|
+
The first connection to a desktop remembers its TLS certificate, without asking (in Tabby's config, under
|
|
158
|
+
`remoteDesktop.trustedCertificates`). If a later connection meets a different one, the plugin stops before signing in
|
|
159
|
+
and shows both fingerprints, with **Trust the new certificate** and **Cancel**. Reinstalling Windows or renewing its
|
|
160
|
+
certificate changes it; if neither happened, something else is answering at that address. Automatic reconnects stop at
|
|
161
|
+
the same question.
|
|
162
|
+
|
|
163
|
+
**An SSH host that is itself Windows** (with OpenSSH Server): its own desktop is Windows' Remote Desktop, at
|
|
164
|
+
127.0.0.1:3389 as seen from the host. The plugin finds this out the first time you open the desktop there, and asks
|
|
165
|
+
for the Windows account instead (your SSH user name is filled in), with the same keychain option.
|
|
166
|
+
|
|
167
|
+
### Starting a desktop that is off
|
|
168
|
+
|
|
169
|
+
A VM on the SSH host, or a machine next to it, may be shut down when you want its desktop. With `wake`, the plugin
|
|
170
|
+
checks from the SSH host whether the desktop answers, and if it doesn't, starts it, shows **Starting \<name\>…** with
|
|
171
|
+
the time so far, and connects as soon as it answers (it gives up after 3 minutes):
|
|
172
|
+
|
|
173
|
+
- `wake: { vm: win11 }` starts the libvirt VM `win11` on the SSH host with `virsh start`, as your SSH user: first in
|
|
174
|
+
`qemu:///system` (you need to be in the `libvirt` group, or allowed by polkit), then in your own `qemu:///session`.
|
|
175
|
+
A paused VM is resumed.
|
|
176
|
+
- `wake: { mac: "aa:bb:cc:dd:ee:ff" }` sends a Wake-on-LAN packet from the SSH host (with `python3`, to the broadcast
|
|
177
|
+
address, UDP port 9). Add `broadcast: 192.168.1.255` for a particular network, or `port: 7`.
|
|
178
|
+
|
|
179
|
+
In the add and edit forms, the last field takes a VM name or a MAC address. Automatic reconnects never start a desktop,
|
|
180
|
+
since it may have been shut down on purpose; **Reconnect** does.
|
|
181
|
+
|
|
182
|
+
## Remote desktop profiles
|
|
183
|
+
|
|
184
|
+
For an RDP server this computer reaches by itself (on the LAN, or over a VPN), there is a Tabby profile type:
|
|
185
|
+
**Settings › Profiles & connections › New profile › Remote desktop (RDP)**. Give it the address, the kind (Windows,
|
|
186
|
+
xrdp or GNOME Remote Desktop), and optionally the user name and domain. It then shows up in Tabby's profile list like
|
|
187
|
+
SSH profiles do, and opens in a tab of its own that the desktop fills; there is no console under it. Sign-in, the
|
|
188
|
+
keychain, certificates, resize, sharpness, clipboard, files, sound, microphone, **Send keys**, view only, screenshots
|
|
189
|
+
and reconnecting work as in SSH tabs. After **Disconnect**, the tab offers **Connect**. In the profile selector you can
|
|
190
|
+
also type `user@host:port` and pick **Quick connect (REMOTE DESKTOP (RDP))**.
|
|
191
|
+
|
|
192
|
+
**Import an .rdp file…** (in the menu's **Settings**, or **Remote desktop: import an .rdp file…** in Tabby's
|
|
193
|
+
command palette) makes such a profile from a file saved by Remote Desktop Connection or handed out by an admin: its
|
|
194
|
+
address, port, user name and domain, named after the file. Other settings in the file (screen size, drives, gateway)
|
|
195
|
+
are ignored.
|
|
196
|
+
|
|
197
|
+
Its **Connect** setting can name an SSH profile instead of connecting directly. The address is then as that host sees
|
|
198
|
+
it, and opening the profile opens that SSH tab and shows the desktop over it once SSH is connected. Such a desktop is
|
|
199
|
+
also offered in the menus of that SSH profile's tabs, next to the host's own desktop, so it works like a desktop
|
|
200
|
+
added with **Desktops › Add a desktop behind \<host\>…**, but with a place in the profile list.
|
|
201
|
+
|
|
202
|
+
In Tabby's config file:
|
|
203
|
+
|
|
204
|
+
```yaml
|
|
205
|
+
profiles:
|
|
206
|
+
- type: rdp
|
|
207
|
+
name: Office PC
|
|
208
|
+
options:
|
|
209
|
+
host: 192.168.1.20 # as this computer sees it (or as the SSH host sees it, with via)
|
|
210
|
+
port: 3389
|
|
211
|
+
kind: windows # or xrdp, or gnome
|
|
212
|
+
username: alice # optional
|
|
213
|
+
via: '' # or the id of an SSH profile to go through
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
A direct connection is a plain TCP connection from this computer, encrypted with TLS like any RDP client's. The
|
|
217
|
+
server's certificate is remembered on the first connection and checked on every later one, as for desktops behind a
|
|
218
|
+
host (above).
|
|
219
|
+
|
|
220
|
+
## Several desktops in one tab
|
|
221
|
+
|
|
222
|
+
Split a tab (Tabby's **Split** in the tab's menu, or drag one tab onto another) and each pane can show a desktop: one
|
|
223
|
+
machine's desktop next to another's, or next to its own console. Right-click any of them:
|
|
224
|
+
|
|
225
|
+
- **Paste to all \<n\> desktops in this tab** pastes what's on your clipboard on every desktop in the tab, in whichever
|
|
226
|
+
window is active on each: text, a picture, or files and folders copied in Finder (or Explorer, or Files).
|
|
227
|
+
- **Type into all \<n\> desktops in this tab** sends every key you type on one desktop to the others too, shortcuts and
|
|
228
|
+
**Send keys** included, until you turn it off. An orange label on each desktop says so while it's on. The mouse stays
|
|
229
|
+
per desktop, and desktops in view-only mode are left out.
|
|
230
|
+
- **Make panes even** evens out the split's panes, which Tabby does itself but offers nowhere else.
|
|
231
|
+
|
|
232
|
+
As you click into a desktop, its name shows in its corner for a moment, like a TV naming its input ("BUILDBOX", or "WIN-11 ·
|
|
233
|
+
via buildhost · 1920×1080"). It shows by default where it helps (in a split, and for a desktop other than the tab's own
|
|
234
|
+
connection); **Settings › Remote Desktop › Desktop name overlay** sets when, and its font, size, place and color, with a
|
|
235
|
+
preview. Desktops are named after their SSH profile's name.
|
|
236
|
+
|
|
237
|
+
## VMs on a host
|
|
238
|
+
|
|
239
|
+
When you right-click an SSH host, the plugin looks at the host's libvirt VMs (`virsh`, as your SSH user; read-only, at
|
|
240
|
+
most once a minute) and lists the ones with a desktop under **Desktops**, with nothing to set up:
|
|
241
|
+
|
|
242
|
+
- a running VM whose RDP port answers: Windows, or Linux with xrdp;
|
|
243
|
+
- a Windows VM that's shut off: **Start and open**, which starts it (`virsh start`) and connects as soon as it answers.
|
|
244
|
+
|
|
245
|
+
A Linux VM that runs GNOME is left out: its desktop is reached by SSH-ing to it (its own desktop, or `ssh` typed in a
|
|
246
|
+
console on the host, [above](#use)). A VM found this way asks for its account the first time, like any Windows or xrdp
|
|
247
|
+
desktop; **Save \<name\> to this host's desktops** in its menu keeps it, for a name of your own and other settings.
|
|
248
|
+
**Settings › Remote Desktop › Find virtual machines on SSH hosts** turns this off.
|
|
249
|
+
|
|
118
250
|
## desk: the console on the desktop
|
|
119
251
|
|
|
120
252
|
Type `desk` in an SSH console, and the tab switches to that machine's desktop with a terminal attached to the very same
|
|
@@ -126,24 +258,31 @@ shell: its scrollback, working directory, jobs and running programs. Type on eit
|
|
|
126
258
|
</p>
|
|
127
259
|
|
|
128
260
|
`desk` is off by default, because it makes interactive SSH logins on that machine start inside a shareable session.
|
|
129
|
-
Turn it on in **Remote
|
|
261
|
+
Turn it on in the pane's menu under **Remote Desktop › Settings**, or in Settings › Remote Desktop. The sessions are handled by a small helper, `trd-pty`, rather than tmux, so
|
|
130
262
|
your terminal's scrollback, colors and shortcuts stay as they are. Turning it off removes it again. Details:
|
|
131
263
|
[docs/desk.md](docs/desk.md).
|
|
132
264
|
|
|
133
265
|
## Settings
|
|
134
266
|
|
|
135
|
-
|
|
267
|
+
Open **Settings › Remote Desktop** in Tabby, right-click the desktop button in Tabby's header, or open **Settings** in the Remote Desktop section of a terminal's or tab's menu.
|
|
136
268
|
They are stored in Tabby's config under `remoteDesktop`:
|
|
137
269
|
|
|
138
270
|
| Setting | Default | |
|
|
139
271
|
|---|---|---|
|
|
140
|
-
| When the pane is resized (`resize`) | Resize the remote desktop to fit (`live`) | Or reconnect at the new size (`reconnect`), or keep the resolution
|
|
272
|
+
| When the pane is resized (`resize`) | Resize the remote desktop to fit (`live`) | Or reconnect at the new size (`reconnect`), or keep the resolution (`off`). |
|
|
273
|
+
| Keep the resolution: scale to fit or actual size (`zoom`) | Scale to fit (`fit`) | With `resize: off`: `actual` shows one remote pixel per point, with scroll bars when the desktop is larger than the pane (a Retina-sized desktop shows at twice the size). |
|
|
141
274
|
| Sharpness (`sharpness`) | Standard (`standard`) | Retina (`retina`): device pixels, with the remote's scale set to match. |
|
|
142
|
-
| For *this desktop* only (`desktopSharpness`) | As above | In the menu of a tab with a desktop open: Standard or Retina for that desktop, whatever the default. Kept by desktop (`user@host`,
|
|
275
|
+
| For *this desktop* only (`desktopSharpness`) | As above | In the menu of a tab with a desktop open: Standard or Retina for that desktop, whatever the default. Kept by desktop (`user@host`, `user@host#address` for one behind a host, or `rdp#address` for a remote desktop profile's own tab). |
|
|
143
276
|
| Sound (`sound`) | On | Applies on the next connection. |
|
|
277
|
+
| Video decoding (`h264`) | On | H.264 decoded by Tabby's browser engine (hardware-accelerated where available), for what the remote sends as video; applies on the next connection. |
|
|
278
|
+
| Microphone (`microphone`) | Off | Send your microphone while an app on the remote desktop records. Applies on the next connection. |
|
|
279
|
+
| Show connection status (`connectionStatus`) | Off | The indicator in the desktop's corner; fades when the pointer comes near. |
|
|
144
280
|
| Mac shortcuts (`macShortcuts`) | On | macOS. Off: ⌘ is the Windows key. |
|
|
145
281
|
| Bring the console along with `desk` (`desk`) | Off | Installs `desk` and a login line on each machine you open a desktop on; applies on the next connection there. |
|
|
146
282
|
| Session backend (`sessionBackend`) | `native` | For `desk`: `native` (trd-pty) or `tmux`. Config file only. |
|
|
283
|
+
| Find virtual machines on SSH hosts (`discoverVMs`) | On | Lists a host's libvirt VMs with a desktop in its menu ([VMs on a host](#vms-on-a-host)). |
|
|
284
|
+
| Tell me about new versions (`checkUpdates`) | On | Once a day, asks npm for the latest tabby-rdp (nothing else is sent), and says so in a note, the menus and the settings page when there's a newer one: Tabby itself shows plugin upgrades only on its Plugins page. |
|
|
285
|
+
| Desktop name overlay (`osd`) | When it helps | `show` (`auto`, `always`, `off`), `font`, `size`, `position`, `color` (empty: white) and `seconds`; the settings page previews it. |
|
|
147
286
|
|
|
148
287
|
## Requirements
|
|
149
288
|
|
|
@@ -153,8 +292,12 @@ They are stored in Tabby's config under `remoteDesktop`:
|
|
|
153
292
|
- **Linux desktops:** GNOME Shell and GNOME Remote Desktop 46 or newer (Ubuntu 24.04, for example), a systemd user
|
|
154
293
|
session, and SSH access with a key or agent. `desk` also needs `python3` and GNOME Terminal. No root, no display, no
|
|
155
294
|
login screen.
|
|
295
|
+
- **Other Linux desktops:** xrdp running on the machine, with a desktop for its sessions (on Debian and Ubuntu:
|
|
296
|
+
`sudo apt install xrdp xfce4`, or KDE, MATE, …), and an account with a password. xrdp's default settings work
|
|
297
|
+
(`security_layer=negotiate`, its own certificate); the port is read from `/etc/xrdp/xrdp.ini`. Sound needs
|
|
298
|
+
`pipewire-module-xrdp` or `pulseaudio-module-xrdp`.
|
|
156
299
|
- **Windows desktops:** Windows 10 or 11 Pro, or Windows Server, with Remote Desktop turned on, reachable from an SSH
|
|
157
|
-
host.
|
|
300
|
+
host or running OpenSSH Server itself.
|
|
158
301
|
|
|
159
302
|
Tested with Ubuntu 24.04 (GNOME Remote Desktop 46.3) and Windows 11 (Pro and Enterprise), from Tabby on macOS,
|
|
160
303
|
Windows 11 and Ubuntu 24.04 (arm64).
|
|
@@ -177,6 +320,9 @@ tabby-rdp ships IronRDP with a short series of patches ([ironrdp/](ironrdp)). Th
|
|
|
177
320
|
| Echo the correct size in the sound channel's Training Confirm | [Devolutions/IronRDP#2019](https://github.com/Devolutions/IronRDP/pull/2019) |
|
|
178
321
|
| The graphics pipeline in the web client, following its resets | Covered by [Devolutions/IronRDP#1977](https://github.com/Devolutions/IronRDP/pull/1977) (not ours; [tested with GNOME](https://github.com/Devolutions/IronRDP/pull/1977#issuecomment-5851624036)) |
|
|
179
322
|
| Sound in the web client | [Devolutions/IronRDP#2020](https://github.com/Devolutions/IronRDP/pull/2020) |
|
|
323
|
+
| H.264 in the web client, decoded by the browser (WebCodecs) | Not submitted yet |
|
|
324
|
+
| Decode Windows' RemoteFX Progressive refinements | Not submitted yet |
|
|
325
|
+
| Microphone in the web client | Not submitted yet |
|
|
180
326
|
|
|
181
327
|
The aim is to make IronRDP's browser client work well with both Linux and Windows desktops, for everyone who embeds
|
|
182
328
|
it, not just this plugin.
|
|
@@ -210,7 +356,22 @@ npm run build:ironrdp # rebuild vendor/ from IronRDP and ironrdp/patches:
|
|
|
210
356
|
- **GNOME Remote Desktop listens on all interfaces** (password-protected, TLS); it has no setting to listen on
|
|
211
357
|
loopback only. See [docs/architecture.md](docs/architecture.md#security-notes) to restrict it.
|
|
212
358
|
- **Windows-key combinations** such as Win+R don't come through from macOS. Tapping ⌘ for the Windows key does.
|
|
213
|
-
- **
|
|
359
|
+
- **The microphone** needs the system's permission: macOS asks the first time a remote app records (if it was denied,
|
|
360
|
+
allow Tabby in System Settings › Privacy & Security › Microphone, then restart Tabby), and Windows needs "Let desktop
|
|
361
|
+
apps access your microphone". On GNOME, apps record from GNOME Remote Desktop's "Remoteaudio Source", which is the
|
|
362
|
+
default input on a machine without a microphone of its own; otherwise pick it in Settings › Sound. On Windows, the
|
|
363
|
+
remote machine must allow audio recording redirection (the Remote Desktop Session Host policy "Allow audio recording
|
|
364
|
+
redirection").
|
|
365
|
+
- **xrdp sessions are separate X sessions**, not the machine's screen, and use whatever `~/.xsession` or the system
|
|
366
|
+
default starts. Don't have them start GNOME for a user who also has a GNOME session (the plugin's headless one, or
|
|
367
|
+
a login at the machine): GNOME runs once per user.
|
|
368
|
+
- **xrdp and a wrong password:** xrdp doesn't refuse the connection, it shows its own login window instead, where you
|
|
369
|
+
can sign in. A remembered password that no longer works leads there each time; **Sign in again…** replaces it.
|
|
370
|
+
- **What works on xrdp** depends on its channels: the clipboard through `xrdp-chansrv` (text; images and files as
|
|
371
|
+
far as that xrdp version supports them), sound through the PipeWire or PulseAudio module. Live resize needs xrdp
|
|
372
|
+
0.10 or newer; with 0.9 (Ubuntu 24.04), the desktop keeps its size, scaled to fit, or choose **Reconnect at the new
|
|
373
|
+
size**. xrdp's standard RDP security without TLS (`security_layer=rdp`) isn't supported. `desk` needs GNOME.
|
|
374
|
+
- **Waking a desktop** starts it but never shuts it down again; that is up to you (or the VM's own settings).
|
|
214
375
|
|
|
215
376
|
## License
|
|
216
377
|
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConnectionStatus = exports.STYLE = void 0;
|
|
4
|
+
exports.STYLE = `
|
|
5
|
+
.trd-stats { position: absolute; left: 8px; bottom: 8px; z-index: 2; padding: 3px 7px; border-radius: 4px;
|
|
6
|
+
background: rgba(20, 20, 20, 0.7); color: #ddd; font: 11px/1.45 ui-monospace, Menlo, Consolas, monospace;
|
|
7
|
+
white-space: pre; pointer-events: none; transition: opacity 0.15s; }
|
|
8
|
+
.trd-stats-path { color: #999; }
|
|
9
|
+
.trd-stats.trd-stats-away { opacity: 0.1; }
|
|
10
|
+
`;
|
|
11
|
+
// Rates are per second; the round trip is measured less often, since it opens a channel on the SSH server.
|
|
12
|
+
const TICK_MS = 1000;
|
|
13
|
+
const PING_EVERY_TICKS = 5;
|
|
14
|
+
function rate(bytesPerSecond) {
|
|
15
|
+
if (bytesPerSecond < 1000) {
|
|
16
|
+
return `${Math.round(bytesPerSecond)} B/s`;
|
|
17
|
+
}
|
|
18
|
+
if (bytesPerSecond < 1e6) {
|
|
19
|
+
return `${(bytesPerSecond / 1e3).toFixed(bytesPerSecond < 1e4 ? 1 : 0)} kB/s`;
|
|
20
|
+
}
|
|
21
|
+
return `${(bytesPerSecond / 1e6).toFixed(1)} MB/s`;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The connection-status indicator in a desktop layer: throughput, frames per second, SSH round trip, and the
|
|
25
|
+
* connection path. Runs only while active (the setting is on and the desktop shows and is connected); its timers
|
|
26
|
+
* and listeners stay outside Angular's zone, like everything that runs on its own (see docs/architecture.md).
|
|
27
|
+
*/
|
|
28
|
+
class ConnectionStatus {
|
|
29
|
+
constructor(overlay, zone, info) {
|
|
30
|
+
this.overlay = overlay;
|
|
31
|
+
this.zone = zone;
|
|
32
|
+
this.info = info;
|
|
33
|
+
this.timer = null;
|
|
34
|
+
this.ticks = 0;
|
|
35
|
+
this.last = null;
|
|
36
|
+
this.frames = 0;
|
|
37
|
+
this.hooked = null;
|
|
38
|
+
this.latency = null;
|
|
39
|
+
this.pinging = false;
|
|
40
|
+
this.active = false;
|
|
41
|
+
/** The indicator fades while the pointer is near it, so it never hides what is under it for long. */
|
|
42
|
+
this.onMouseMove = (event) => {
|
|
43
|
+
const r = this.el.getBoundingClientRect();
|
|
44
|
+
const near = event.clientX > r.left - 24 && event.clientX < r.right + 24 && event.clientY > r.top - 24 && event.clientY < r.bottom + 24;
|
|
45
|
+
if (near !== this.el.classList.contains('trd-stats-away')) {
|
|
46
|
+
this.el.classList.toggle('trd-stats-away', near);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
this.el = document.createElement('div');
|
|
50
|
+
this.el.className = 'trd-stats';
|
|
51
|
+
this.el.innerHTML = '<div class="trd-stats-numbers"></div><div class="trd-stats-path"></div>';
|
|
52
|
+
this.numbersEl = this.el.querySelector('.trd-stats-numbers');
|
|
53
|
+
this.pathEl = this.el.querySelector('.trd-stats-path');
|
|
54
|
+
}
|
|
55
|
+
/** Starts or stops the indicator. `canvas`: the remote display, whose updates are counted as frames. */
|
|
56
|
+
setActive(active, canvas) {
|
|
57
|
+
if (active && canvas) {
|
|
58
|
+
this.countFrames(canvas);
|
|
59
|
+
}
|
|
60
|
+
if (active === this.active) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
this.active = active;
|
|
64
|
+
if (!active) {
|
|
65
|
+
clearInterval(this.timer ?? undefined);
|
|
66
|
+
this.timer = null;
|
|
67
|
+
this.overlay.removeEventListener('mousemove', this.onMouseMove, true);
|
|
68
|
+
this.el.remove();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
this.last = null;
|
|
72
|
+
this.ticks = 0;
|
|
73
|
+
this.latency = null;
|
|
74
|
+
this.numbersEl.textContent = '…';
|
|
75
|
+
this.pathEl.textContent = this.info.path();
|
|
76
|
+
this.el.classList.remove('trd-stats-away');
|
|
77
|
+
this.overlay.appendChild(this.el);
|
|
78
|
+
this.zone.runOutsideAngular(() => {
|
|
79
|
+
this.timer = setInterval(() => this.tick(), TICK_MS);
|
|
80
|
+
this.overlay.addEventListener('mousemove', this.onMouseMove, { capture: true, passive: true });
|
|
81
|
+
this.tick();
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
dispose() {
|
|
85
|
+
this.setActive(false);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* IronRDP's web client blits each changed region with putImageData and tells nobody, so the canvas context's
|
|
89
|
+
* putImageData is wrapped (on that one context object). A frame is one synchronous batch of blits.
|
|
90
|
+
*/
|
|
91
|
+
countFrames(canvas) {
|
|
92
|
+
const ctx = canvas.getContext('2d');
|
|
93
|
+
if (!ctx || ctx === this.hooked) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
this.hooked = ctx;
|
|
97
|
+
const original = ctx.putImageData;
|
|
98
|
+
let batch = false;
|
|
99
|
+
ctx.putImageData = ((...args) => {
|
|
100
|
+
if (!batch) {
|
|
101
|
+
batch = true;
|
|
102
|
+
this.frames++;
|
|
103
|
+
queueMicrotask(() => { batch = false; });
|
|
104
|
+
}
|
|
105
|
+
return original.apply(ctx, args);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
tick() {
|
|
109
|
+
const now = performance.now();
|
|
110
|
+
const bytes = this.info.bytes() ?? { bytesIn: 0, bytesOut: 0 };
|
|
111
|
+
const current = { at: now, bytesIn: bytes.bytesIn, bytesOut: bytes.bytesOut, frames: this.frames };
|
|
112
|
+
const parts = [];
|
|
113
|
+
if (this.last && now > this.last.at) {
|
|
114
|
+
const seconds = (now - this.last.at) / 1000;
|
|
115
|
+
parts.push(`↓ ${rate((current.bytesIn - this.last.bytesIn) / seconds)}`, `↑ ${rate((current.bytesOut - this.last.bytesOut) / seconds)}`, `${Math.round((current.frames - this.last.frames) / seconds)} fps`);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
parts.push('↓ …', '↑ …', '… fps');
|
|
119
|
+
}
|
|
120
|
+
if (this.info.ping) {
|
|
121
|
+
parts.push(this.latency === null ? 'ping …' : `ping ${this.latency < 10 ? this.latency.toFixed(1) : Math.round(this.latency)} ms`);
|
|
122
|
+
if (this.ticks++ % PING_EVERY_TICKS === 0) {
|
|
123
|
+
this.measureLatency();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
this.last = current;
|
|
127
|
+
this.numbersEl.textContent = parts.join(' ');
|
|
128
|
+
this.pathEl.textContent = this.info.path();
|
|
129
|
+
}
|
|
130
|
+
measureLatency() {
|
|
131
|
+
// Nothing to show while the window is hidden; and never two at once on a slow link.
|
|
132
|
+
if (this.pinging || document.hidden) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
this.pinging = true;
|
|
136
|
+
this.info.ping().then(ms => { this.latency = ms; }, () => { this.latency = null; }).finally(() => { this.pinging = false; });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
exports.ConnectionStatus = ConnectionStatus;
|
|
140
|
+
//# sourceMappingURL=connectionStatus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connectionStatus.js","sourceRoot":"","sources":["../src/connectionStatus.ts"],"names":[],"mappings":"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"}
|
package/dist/desk.js
CHANGED
|
@@ -15,19 +15,24 @@ const tabby_core_1 = require("tabby-core");
|
|
|
15
15
|
const tabby_terminal_1 = require("tabby-terminal");
|
|
16
16
|
const desktop_service_1 = require("./desktop.service");
|
|
17
17
|
const targets_1 = require("./targets");
|
|
18
|
-
const
|
|
18
|
+
const probe_1 = require("./probe");
|
|
19
|
+
const PREFIX = Buffer.from('\x1b]7777;');
|
|
19
20
|
const BEL = 0x07;
|
|
20
21
|
const ST = Buffer.from('\x1b\\');
|
|
21
22
|
function parse(payload) {
|
|
22
|
-
const [session, socket, cwd, kind] = payload.split(';').map(f => Buffer.from(f ?? '', 'base64').toString('utf8'));
|
|
23
|
-
// Older `desk` scripts sent no kind
|
|
24
|
-
return {
|
|
23
|
+
const [session, socket, cwd, kind, machine, hostname] = payload.split(';').map(f => Buffer.from(f ?? '', 'base64').toString('utf8'));
|
|
24
|
+
// Older `desk` scripts sent no kind (they only knew tmux), and no machine.
|
|
25
|
+
return {
|
|
26
|
+
session: session ?? '', socket: socket ?? '', cwd: cwd ?? '', kind: kind ?? (session ? 'tmux' : ''),
|
|
27
|
+
machine: machine?.trim() ?? '', hostname: hostname?.trim() ?? '',
|
|
28
|
+
};
|
|
25
29
|
}
|
|
26
|
-
/** Strips `desk` requests out of a session's output and reports them. */
|
|
30
|
+
/** Strips `desk` requests (and probes, see probe.ts) out of a session's output and reports them. */
|
|
27
31
|
class DeskTrigger extends tabby_terminal_1.SessionMiddleware {
|
|
28
|
-
constructor(onDesk) {
|
|
32
|
+
constructor(onDesk, onProbe) {
|
|
29
33
|
super();
|
|
30
34
|
this.onDesk = onDesk;
|
|
35
|
+
this.onProbe = onProbe;
|
|
31
36
|
}
|
|
32
37
|
feedFromSession(data) {
|
|
33
38
|
// Tabby's OSC processor runs first and passes unknown OSCs through whole, so each request
|
|
@@ -41,9 +46,15 @@ class DeskTrigger extends tabby_terminal_1.SessionMiddleware {
|
|
|
41
46
|
if (end === -1) {
|
|
42
47
|
break;
|
|
43
48
|
}
|
|
44
|
-
const
|
|
49
|
+
const payload = data.subarray(body, end).toString('utf8');
|
|
45
50
|
data = Buffer.concat([data.subarray(0, start), data.subarray(end + (end === st ? ST.length : 1))]);
|
|
46
|
-
|
|
51
|
+
if (payload.startsWith('desk;')) {
|
|
52
|
+
const request = parse(payload.slice('desk;'.length));
|
|
53
|
+
setTimeout(() => this.onDesk(request));
|
|
54
|
+
}
|
|
55
|
+
else if (payload.startsWith('probe;')) {
|
|
56
|
+
this.onProbe(payload.slice('probe;'.length));
|
|
57
|
+
}
|
|
47
58
|
start = data.indexOf(PREFIX, start);
|
|
48
59
|
}
|
|
49
60
|
if (data.length) {
|
|
@@ -68,11 +79,11 @@ let DeskTriggerDecorator = class DeskTriggerDecorator extends tabby_terminal_1.T
|
|
|
68
79
|
}
|
|
69
80
|
if (!this.desktop.settings().desk) {
|
|
70
81
|
// A hook left from when it was on; it goes away the next time a desktop opens there.
|
|
71
|
-
this.notifications.info('`desk` is off: turn it on in Remote
|
|
82
|
+
this.notifications.info('`desk` is off: turn it on in the menu under Remote Desktop › Settings');
|
|
72
83
|
return;
|
|
73
84
|
}
|
|
74
85
|
this.desktop.openConsole(pane, request);
|
|
75
|
-
})));
|
|
86
|
+
}), id => (0, probe_1.probeArrived)(id, terminal)));
|
|
76
87
|
};
|
|
77
88
|
install();
|
|
78
89
|
this.subscribeUntilDetached(terminal, terminal.sessionChanged$.subscribe(() => install()));
|