XFCE: Remote Desktop via X11vnc Through an SSH Tunnel

For the first time in a loooong time I (had to) set up remote desktop sharing, starting from an existing SSH login through a single-port pinhole in an immutable router firewall.

The remote PC runs Xubuntu 20.4 LTS and I verified it already had x11vnc installed. If that’s not the case, make it so.

In order to share / control the desktop of a different user (hereinafter known as kay), I must SSH into that PC as kay. My SSH session uses public key authentication and kay has no need for outbound SSH, so just use my PC’s public key in kay‘s authorized_keys file. On the remote PC, where I am signed in as me:

cd ~
sudo mkdir /home/kay/.ssh        # kay does not have a public key
sudo cp .ssh/authorized_keys /home/kay/.ssh     # so just copy mine
sudo chown -R kay:kay /home/kay/.ssh     # transfer ownership
sudo chmod go-rwx /home/kay/.ssh     # set proper permissions

From my local PC, I can now SSH into the remote PC as kay and start x11vnc through the SSH tunnel:

ssh -v kay@remote.address -L 5900:localhost:5900 "x11vnc -display :0 -noxdamage -ncache 10 -ncache_cr -nopw"

Still on my PC, aim a VNC client at the local end of the tunnel:

novnc localhost:5900

Using novnc presents the remote desktop as a web page in a browser, although you may prefer something more traditional.

Somewhat to my surprise, It Just Worked™.

Clearing the Noto Font Clutter: Again

Installing Atkinson Hyperlegible reminded me to clear out the Noto font clutter in this (relatively nerecentw) Manjaro installation. Of course fonts now appear in slightly different locations with slightly different names, so this remains just a serving suggestion:

cd /usr/share/fonts/noto
sudo chmod a-w NotoSans-*
sudo chmod a-w NotoSansMono*
sudo chmod a-w NotoSansDisplay*
sudo chmod a-w NotoSansMath*
sudo chmod a-w NotoSansSymbol*
sudo chmod a-w NotoSerif-*
sudo chmod a-w NotoSerifDisplay*
sudo chmod a-w NotoMusic*
sudo chmod a-w NotoMath*
sudo find . -perm /u=w -name \*ttf -delete

Get rid of some other clutter:

cd ../TTF
sudo chmod a-w DejaVu*
sudo chmod a-w Inconsolata-*
sudo find . -perm /u=w -name \*ttf -delete
cd ../droid
sudo chmod a-w DroidSans-Bold.ttf 
sudo chmod a-w DroidSans.ttf 
sudo chmod a-w DroidSansFallback*
sudo chmod a-w DroidSansMono.ttf 
sudo chmod a-w DroidSerif-*
cd ../adobe-source-han-sans
sudo rm *otf

For unknown reasons, we now have two font cache updaters:

sudo fc-cache -v -f
sudo fc-cache-32 -v -f

Now font selection in, say, LibreOffice doesn’t involve paging through a myriad fonts in languages I cannot recognize, let alone read. Admittedly, Inconsolata does have more variations than I’ll ever use.

Naming Is Hard

A recent update to the X Windowing System (or whatever it’s called) once again changed the names of its monitors / displays / output devices, so that my startup script no longer confined the tablet to the landscape display.

In mostly reverse chronological order, here are various commands I’ve puzzled out:

#xsetwacom --verbose set "HUION Huion Tablet stylus" MapToOutput "DP1-8"
xsetwacom --verbose set "HUION Huion Tablet stylus" MapToOutput "DP-1-8"
#xsetwacom --verbose set "HUION Huion Tablet Pen stylus" MapToOutput "DP-1"
#xsetwacom --verbose set "Wacom Graphire3 6x8 Pen stylus" MapToOutput "DP-1"
#xsetwacom --verbose set "Wacom Graphire3 6x8 Pen stylus" MapToOutput "HEAD-0"
#xsetwacom --verbose set "Wacom Graphire3 6x8 Pen eraser" MapToOutput "DP-1"
#xsetwacom --verbose set "Wacom Graphire3 6x8 Pen eraser" MapToOutput "HEAD-0"

Over the last two years, the display name changed from DP-1 to DP-1-8 to DP1-8, and back to DP-1-8. I grew accustomed to this with the Wacom tablet (HEAD-0‽)and now know where to look, but I still have no idea of the motivation.

Aaaand the tablet’s stylus name? The Wacom names were stable, but the Huion names apparently come from the Department of Redundancy Department.

KeyboardIO Atreus: LED Diffuser

After staring at the RGB LED I installed in my Atreus keyboard for a while, I converted the stub of a ¼-20 nylon screw into a light diffuser:

Atreus keyboard - LED diffuser
Atreus keyboard – LED diffuser

It stands slightly proud of the surface plate so I can extract it without dismantling the whole keyboard again:

Atreus keyboard - LED diffuser installed
Atreus keyboard – LED diffuser installed

I’ll eventually make a better-looking diffuser from a recently arrived translucent acrylic rod, but this will reduce the accumulation of fuzz inside the keyboard until the matching Round Tuit arrives.

KeyboardIO Atreus: RGB LED Installation

Having scouted out the territory inside the KeyboardIO Atreus, adding an LED requires taking it completely apart to drill a hole in the aluminum faceplate:

Atreus keyboard - panel drilling
Atreus keyboard – panel drilling

Reattaching the plate to the PCB with only three screws allows marking the hole position on the PCB, which is much easier than pretending to derive the position from first principles:

Atreus keyboard - LED marking
Atreus keyboard – LED marking

Despite appearances, I traced the hole with a mechanical pencil: black graphite turns shiny silvery gray against matte black soldermask. Also, the PCB trace is off-center, not the hole.

Overlay the neighborhood with Kapton tape to protect the PCB from what comes next:

Atreus keyboard - Kapton tape

Snip a WS2812 RGB LED from a strip, stick it in place with eyeballometric alignment over the target, and wire it up:

Atreus keyboard - LED wiring
Atreus keyboard – LED wiring

Despite the terrible reliability of WS2812 RGB LEDs mounted on PCB carriers, a different set on a meter of high-density flex tape have worked reasonably well when not thermally stressed, so I’ll assume this one arrived in good order.

Aligning the LED directly under the hole required a few iterations:

Atreus keyboard - LED positioning
Atreus keyboard – LED positioning

The iridescent green patch is a diffraction pattern from the controller chip’s internal circuitry.

The data comes from MOSI, otherwise known as B2, down in the lower left corner:

Atmel 32U4 - JTAG pins
Atmel 32U4 – JTAG pins

Actually lighting the LED now becomes a simple matter of software QMK firmware.

KeyboardIO Atreus Keymapping

Having a customizable keyboard like the KeyboardIO Atreus means one must customize it. As it turns out, I wanted to use some features of the underlying QMK Kaleidoscope firmware that aren’t exposed by Chrysalis, KeyboardIO’s otherwise competent keymap configuration utility, so what you see below runs on hard mode.

Start by installing QMK, compiling the default Atreus layout, and flashing the keyboard just to confirm all the steps work:

Atreus keyboard - overview
Atreus keyboard – overview

With all that working, add (or create) two lines to the rules.mk file in the keymap directory you’re tweaking:

AUTO_SHIFT_ENABLE = yes			# allow automagic shifting
TAP_DANCE_ENABLE = yes			# allow multi-tap keys

Enabling Auto-Shift lets you generate shifted characters (like Z) by briefly holding down the unshifted key (like z). This requires unlearning an entire lifetime of touch typing practice, but is definitely worthwhile; if a thumb still reaches for the shift key, there’s no harm done. There are, of course, a myriad options, all of which I left unchanged.

Complex passwords suffer, as you must blind-type carefully while tapping each key rapidly.

Enabling Tap Dance lets a key generate one character when tapped and another when double-tapped; you can go crazy with more taps. An enum{} in the keymap.c file generates indexes for the keys and an array holds the action definitions:

enum {

qk_tap_dance_action_t tap_dance_actions[] = {

Then each key uses a TD() macro in the keymap.c file:


In contrast, layer shifting uses straightforward built-in macros. The Fun key produces a momentary shift to Layer 1 (known as _RS) when held down:

… MO(_RS), …

The ESC key in the lower left corner emits the expected Escape key code when tapped and switches to Layer 2 (a.k.a. _LW) when held:


For reference, the current state of the keymap.c file:

// Modified from the KeyboardIO layout
// Ed Nisley - KE4ZNU
// Enable Auto Shift and Tap Dance in rules.mk


enum layer_names {

enum {

qk_tap_dance_action_t tap_dance_actions[] = {

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
  [_QW] = LAYOUT( /* Qwerty */
    KC_Q,    KC_W,    KC_E,    KC_R,    KC_T,                      KC_Y,    KC_U,    KC_I,    KC_O,    KC_P    ,
    KC_A,    KC_S,    KC_D,    KC_F,    KC_G,                      KC_H,    KC_J,    KC_K,    KC_L,    KC_SCLN ,
    KC_Z,    KC_X,    KC_C,    KC_V,    KC_B,    KC_GRV,  KC_LALT, KC_N,    KC_M,    KC_COMM, KC_DOT,  KC_SLSH ,

  [_RS] = LAYOUT( /* [> RAISE <] */
    KC_EXLM, KC_AT,   KC_UP,   KC_DLR,  KC_PERC,                  KC_PGUP, KC_7,    KC_8,   KC_9, KC_HOME,
    KC_LPRN, KC_LEFT, KC_DOWN, KC_RGHT, KC_RPRN,                  KC_PGDN, KC_4,    KC_5,   KC_6, KC_END,

  [_LW] = LAYOUT( /* [> LOWER <] */
    KC_INS,  KC_HOME, KC_UP,   KC_END,  KC_PGUP,                   KC_UP,   KC_F7,   KC_F8,   KC_F9,   KC_F10  ,
    KC_DEL,  KC_LEFT, KC_DOWN, KC_RGHT, KC_PGDN,                   KC_DOWN, KC_F4,   KC_F5,   KC_F6,   KC_F11  ,
    KC_NO,   KC_VOLU, KC_NO,   KC_NO,   RESET,   _______, _______, KC_NO,   KC_F1,   KC_F2,   KC_F3,   KC_F12  ,

With all that set up, It Just Works and I can contemplate grafting a status LED into the thing.

USB Memory: Premature Deaths

After about a year of streaming music, the music died over the course of a month, producing progressively bizarre symptoms on all the local Icecast stations. Killing the streaming server and yanking all the USB memory sticks produced this tableau:

USB Memory - streamer failures
USB Memory – streamer failures

The USB 2.0 32 GB SanDisk Cruzer Fit (tiny, black, upper left) holds images from various network cameras and is not involved with music. It’s nigh onto seven years old and, apparently, still going strong.

The USB 2.0 Centron (gray-and-retroreflective, upper right) was forgotten from the last time I set up a drive for our Forester’s player. There’s another one just like it in the car; they’re impossibly old, as you’d expect from their minuscule size.

The USB 3.0 64 GB Samsung Fit (small, white, lower left) is totally dead, to the extent it doesn’t even announce its presence when plugged into a USB socket. It’s 2.5 years into a five year warranty, but their new USB 3.1 version is twelve bucks; Samsung wins. It formerly contained an extensive selection of public-domain music.

The 64 GB Sandisk Cruzer (huge, black, lower right) suffered some serious damage:

sudo mount -o ro /dev/sdg1 /mnt/part
ll /mnt/part
 ls: cannot access '/mnt/part/PILZ': Input/output error
 total 384K
 drwxr-xr-x   6 ed   users 4.0K Nov 28  2019 ./
 drwxr-xr-x  17 root root  4.0K Jun  7  2019 ../
 -rw-r--r--   1 ed   ed    215K Mar  9  2019 CDClassical.m3u
 drwxrwxr-x  56 ed   ed    4.0K Mar  9  2019 Classical/
 drwx------   2 root root   16K Mar  9  2019 lost+found/
 d?????????   ? ?    ?        ?            ? PILZ/
 drwxrwxr-x 116 ed   ed     12K Mar  9  2019 Pop/
 -rw-r--r--   1 ed   ed    117K Nov 28  2019 Pop.m3u

It still contains a fair amount of music ripped from the CDs we’ve collected over the decades, but it’s obviously unusable. Just for fun, I tried reformatting and copying some files to it, but it eventually hard-crashed with I/O errors:

[37787.872410] usb 2-1: new high-speed USB device number 2 using xhci_hcd
 [37788.013027] usb 2-1: New USB device found, idVendor=0781, idProduct=5530, bcdDevice= 1.00
 [37788.013030] usb 2-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
 [37788.013032] usb 2-1: Product: Cruzer
 [37788.013034] usb 2-1: Manufacturer: SanDisk
 [37788.013036] usb 2-1: SerialNumber: 4C530001151215101233
 [37788.013604] usb-storage 2-1:1.0: USB Mass Storage device detected
 [37788.014778] scsi host9: usb-storage 2-1:1.0
 [37789.033409] scsi 9:0:0:0: Direct-Access     SanDisk  Cruzer           1.00 PQ: 0 ANSI: 6
 [37789.034569] sd 9:0:0:0: [sdf] 120225792 512-byte logical blocks: (61.6 GB/57.3 GiB)
 [37789.035820] sd 9:0:0:0: [sdf] Write Protect is off
 [37789.035825] sd 9:0:0:0: [sdf] Mode Sense: 43 00 00 00
 [37789.036137] sd 9:0:0:0: [sdf] Write cache: disabled, read cache: enabled, doesn't support DPO or FUA
 [37789.086533]  sdf: sdf1
 [37789.089418] sd 9:0:0:0: [sdf] Attached SCSI removable disk
 [38035.071013] EXT4-fs (sdf1): mounting ext3 file system using the ext4 subsystem
 [38035.183172] EXT4-fs (sdf1): mounted filesystem with ordered data mode. Opts: (null)
 [38485.302549] usb 2-1: reset high-speed USB device number 2 using xhci_hcd
 [38490.622285] usb 2-1: device descriptor read/64, error -110
 [38506.195617] usb 2-1: device descriptor read/64, error -110
 [38506.425616] usb 2-1: reset high-speed USB device number 2 using xhci_hcd
 [38511.742339] usb 2-1: device descriptor read/64, error -110
 <<< snippage >>>
 [38548.845743] usb 2-1: USB disconnect, device number 2
 [38548.858925] blk_update_request: I/O error, dev sdf, sector 99556320 op 0x1:(WRITE) flags 0x4800 phys_seg 30 prio class 0
 [38548.858933] EXT4-fs warning (device sdf1): ext4_end_bio:309: I/O error 10 writing to inode 1531939 (offset 0 size 0 starting block 12444541
 [38548.858937] Buffer I/O error on device sdf1, logical block 12444284
 [38548.858944] EXT4-fs warning (device sdf1): ext4_end_bio:309: I/O error 10 writing to inode 1531939 (offset 0 size 0 starting block 12444542
 <<< snippage >>>
 [38548.858984] Buffer I/O error on device sdf1, logical block 12444293
 [38548.859034] blk_update_request: I/O error, dev sdf, sector 99017520 op 0x1:(WRITE) flags 0x4000 phys_seg 3 prio class 0
 [38548.859158] blk_update_request: I/O error, dev sdf, sector 99556560 op 0x1:(WRITE) flags 0x4800 phys_seg 30 prio class 0
 [38548.859224] blk_update_request: I/O error, dev sdf, sector 99017760 op 0x1:(WRITE) flags 0x4000 phys_seg 2 prio class 0
 [38548.859237] blk_update_request: I/O error, dev sdf, sector 99018000 op 0x1:(WRITE) flags 0x4000 phys_seg 2 prio class 0
 [38549.230765] JBD2: Detected IO errors while flushing file data on sdf1-8
 [38549.230920] Aborting journal on device sdf1-8.
 [38549.231008] Buffer I/O error on dev sdf1, logical block 1545, lost sync page write
 [38549.231011] JBD2: Error -5 detected when updating journal superblock for sdf1-8.
 [38549.231325] Buffer I/O error on dev sdf1, logical block 0, lost sync page write
 [38549.231332] EXT4-fs (sdf1): I/O error while writing superblock
 [38549.231333] EXT4-fs error (device sdf1): ext4_journal_check_start:61: Detected aborted journal
 [38549.231334] EXT4-fs (sdf1): Remounting filesystem read-only
 <<< and so forth and so on >>>

So, yeah, it’s dead, Jim.

The Icecast streaming server reads data continuously from the USB sticks and, given that I set up half a dozen “stations”, there’s plenty of reading going on. The drives are formatted as ext3 and mounted with the noatime option, so there shouldn’t be any writing going on, but it seems a year of constant reading can kill a USB drive.

Fortunately, the original data lives elsewhere, with scripts to copy the appropriate files to the right places, so rebuilding the drives on a pair of new USB sticks wasn’t a big deal.