Version 2.0.0 — touch input

A second display
you can touch.

TethrLink turns an Android tablet into a real second monitor for Linux — over a USB cable, not your network. Drag a window onto it and the window stays there. Now you can reach out and drive the pointer with your finger.

GNOME on Wayland · GPL v3 · no account, no cloud

LINUX PC ANDROID TABLET
Not a mirror

GNOME treats it like any other monitor.

TethrLink asks Mutter to create a genuine virtual output, so the tablet arrives in Settings → Displays as a real screen. Put it above, below or beside your laptop, drag windows across the boundary, and they stay where you left them.

The transport is the private network USB tethering already gives you. Nothing touches your router, nothing leaves the cable, and there is no account to make.

BUILT-IN · 1920×1080 TETHRLINK · 1730×1080 shared edge — fully traversable
New in 2.0.0

Your finger drives the pointer.

Touch is off until you turn it on in the server window — something that can drive your desktop should be a choice you make. Once it's on, the tablet stops being a screen you look at and becomes one you use.

Tap

Left click, exactly where your finger lands.

Drag

Press, move, release — windows, sliders, selections.

Long press

Right click. Timing comes from Android's own ViewConfiguration.

Two-finger drag

Scroll, in wheel notches the desktop understands.

There is no hover

Every touch clicks. That's inherent to driving a pointer by absolute position, and it means tooltips and hover-triggered menus won't open from touch. Better to say so than to let you discover it.

It can't reach your laptop's screen

Input goes through GNOME's RemoteDesktop API and is scoped to the virtual display by the platform itself — not by our own care in getting the maths right.

Wayland only, and the app says so

Touch needs GNOME on Wayland, like the virtual display does. On X11 you get video only, and the server window tells you that instead of pretending otherwise.

The pipeline

Frames down the cable, intent back up it.

One TCP connection on port 51137 carries both directions. The tablet finds the server on its own by listening for a UDP broadcast — there is no IP address to type in.

LINUX PC Mutter ScreenCast → virtual monitor PipeWire → frame capture GStreamer → H.264 (GPU) / JPEG RemoteDesktop ← pointer injection ANDROID TABLET MediaCodec → decode fullscreen render touch → normalised [0,1] video · TCP 51137 input · same connection UDP :8765 discovery broadcast LINUX PC Mutter ScreenCast → monitor PipeWire → frame capture GStreamer → H.264 / JPEG RemoteDesktop ← injection video · TCP 51137 input · same connection UDP :8765 discovery broadcast ANDROID TABLET MediaCodec → decode fullscreen render touch → normalised [0,1]
video, PC → tablet pointer input, tablet → PC

Frames drop before encoding, never after

Discarding a raw frame lowers the frame rate. Discarding an encoded one breaks the decoder's reference chain and corrupts everything until the next keyframe. So the leaky queue sits upstream of the encoder, and everything after it is lossless.

The encoder is negotiated, not assumed

Candidates are tried hardware-first and accepted only after genuinely encoding a frame at the real capture size — an element can exist, expose the right property, and still fail. The winner is cached against a fingerprint of your GStreamer install, so a driver upgrade re-probes.

A steady frame rate is manufactured

Mutter's capture is damage-driven: a static screen stops producing frames entirely. A compositor element on its own clock supplies a constant rate at no added latency, so motion resumes instantly instead of after a stall.

Display geometry

The size is derived, not picked.

height = min(your monitor's height, the tablet's height)
width  = height × (the tablet's aspect ratio)

A 1920×1080 PC with a 2960×1848 tablet gives 1730×1080. Matching heights makes the whole shared edge crossable — GNOME only lets the pointer cross where two monitors overlap vertically, so a mismatch leaves an invisible wall partway along it. Taking the aspect ratio from the tablet keeps the upscale uniform; forcing 16:9 onto a 16:10 panel would stretch the picture about 11%.

Override it with TETHRLINK_RES if you would rather trade decode headroom for sharpness.

1920 × 1080 1730 × 1080 edge aligns 1080 reported size is untrusted input — anything outside 64–16384 px is rejected
Measured, on one machine

Numbers we can reproduce.

Encoder throughput over 120 frames of synthetic video, on a GTX 1650 Ti with an Intel UHD iGPU.

Encoder1280×7201920×10802960×1848
nvh264enc (NVENC)320 fps196 fps93 fps
x264enc ultrafast CBR141 fps71 fps39 fps
x264enc veryfast CBR84 fps48 fps30 fps

The link has room to spare

The tablet enumerates at USB 2.0 High Speed — 480 Mbit/s nominal, 200–300 realistic. H.264 at 1730×1080/30 targets about 16 Mbit/s, roughly 6% of that.

Compression isn't optional

Raw NV12 at 2960×1848/30 is about 1.9 Gbit/s — several times what the cable can carry. Encoding is what makes this work at all.

Startup is mostly cached

Probing and verifying an encoder cold takes about 2.06 s. From cache it's 0.44 s.

No end-to-end latency figure is quoted, because none has been measured under controlled conditions. An earlier version of this page cited one; it wasn't reproducible, so it's been withdrawn rather than repeated.

tethrlink :51137 usb0 (tether) wlan0 (Wi-Fi) docker0 (bridge) detected at runtime via /sys/class/net
Who the server talks to

Only the device on the other end of the cable.

The server accepts peers reachable over a USB-attached interface, plus loopback. Wi-Fi and container bridges are refused. That mattered less when reaching the port only meant seeing your screen; with input, it would mean controlling the machine.

The subnet is detected at runtime, not hardcoded. An earlier version assumed 192.168.42.0/24, the AOSP default, and broke for every device that hands out something else. What's actually reliable is which interface the cable created — so TethrLink reads that from the kernel and trusts exactly what it finds.

There is no authentication. Over a cable, that's a reasonable boundary — and any future transport that isn't a cable has to add pairing first.

Setup

Four steps, in order.

01

Start the server

Launch TethrLink on the PC and click Start Server.

02

Turn on USB tethering

On the tablet: Settings → Connections → Mobile Hotspot and Tethering → USB tethering.

03

Open the Android app

It listens for the server's broadcast and connects on its own. Nothing to type.

04

Arrange the display

In GNOME Settings → Displays, place the new monitor where you want it. Enable touch in the server window if you want the tablet to drive the pointer.

Install

Get TethrLink 2.0.0.

You need the Linux server and the Android app — the tablet half doesn't work alone.

Linux · recommended

Snap

Installs and updates itself. The quickest way onto Ubuntu and anything else with snapd.

sudo snap install tethrlink
View on Snapcraft
Linux · Debian/Ubuntu

.deb package

A normal apt package with dependencies declared. Remove it with apt remove tethrlink.

Download .deb
Android · the other half

Android app

Android 5.0 or newer, with USB tethering. Finds the server by itself.

Download .apk

Prefer to build it yourself? Build from source  ·  All releases  ·  GPL v3

Questions

Before you install.

Does this work on KDE, Sway, or X11?

Not fully. The virtual display uses Mutter's ScreenCast D-Bus API, which has no cross-compositor equivalent — there is no standard for creating a virtual output. On X11 you get JPEG at the PC's own resolution and no touch. On other compositors, no virtual display at all.

Is it mirroring my screen?

No. It creates an additional monitor with its own screen space. Windows you drag onto it stay there, and your laptop display is unaffected.

Why does touch need turning on?

Because it can drive your desktop, and that should be a decision you make rather than a default you inherit. The switch is in the server window, it applies while a client is connected, and your choice is remembered across restarts.

Do I need Wi-Fi, or an internet connection?

Neither. Everything runs over the network USB tethering creates between the two devices. The server actively refuses peers that aren't on a USB-attached interface.

Can I connect two tablets?

No. One client at a time — a second device gets a busy signal.

What does it cost me while it's idle?

About half a core. Holding a constant frame rate means running the pipeline even when nothing on screen changes. Worth knowing if you're on battery.

Do I need a particular GPU?

No, but a hardware H.264 encoder helps — NVENC, VA-API or QSV. TethrLink probes for one at startup, verifies it actually encodes a frame, and falls back to software when none works.

Android alpha

Help test the tablet app.

The Android client is heading to Google Play, and closed testing needs real devices — different panels, different ROMs, different ideas of what a tethered subnet looks like. If you have an Android tablet and a Linux machine running GNOME on Wayland, you can help.

Your address is used to grant Play access and nothing else. No list, no forwarding.

What happens next

  • 01I add your Google account to the closed test and email you the opt-in link.
  • 02You accept, install from Play as normal, and it updates like any other app.
  • 03Use it. Tell me what breaks — GitHub issues, or just reply to the email.

Play needs testers to stay opted in for the test to count, so please don't opt out straight after installing. You can leave any time once it ships.

Don't want to wait? The APK is on the release right now — the alpha is about getting the Play build tested, not about early access.

Get in touch

Tell me what breaks.

Release notes

Know when the next one lands

Audio forwarding is next, then keyboard input. One email per release, nothing else.

No account needed. Unsubscribe anytime.

Bug reports and feature requests are best as GitHub issues — they're easier to track and other people can find them. For anything else, email works.