Fixing X11 Screen Tearing on my Thinkpad P15 w/ Void Linux

15 September 2021

I noticed today I had some screen tearing on my new Thinkpad P15, noticeable mainly when scrolling in Firefox. Since I had the same issue originally on my GhostBSD desktop, and both systems use Nvidia GPUs, my first instinct was to attempt the same fix, however on my laptop, this gave an error: (line breaks added here for formatting)

$ sudo nvidia-settings --assign CurrentMetaMode="nvidia-auto-select +0+0 \
  { ForceFullCompositionPipeline = On }"
ERROR: Error resolving target specification '' (No targets match target
specification), specified in assignment 'CurrentMetaMode=nvidia-auto-select
+0+0 { ForceFullCompositionPipeline = On }'.

A bunch of searching on line found this to be a common problem, but most posts were just pointing around at other posts with similar issues, and not providing useful information. I did find a forum post eventually that pointed out that since on systems such as my laptop, the Nvidia isn’t the primary video card, and is mainly used for offloading more GPU intensive applications, so whatever fix works, it isn’t going to be at the Nvidia level.

Another forum recommended using a compositor, and specifically mentioned picom, Running picom didn’t make any difference, but the man page provided a few options that seemed relevant. What ended up working for me was:

picom --vsync --backend=glx

I’ll have to add this into my startup somewhere, but just leaving this running in a terminal does seem to prevent the screen tearing from occurring.

Remote Terminals in Emacs and Following the Current Directory

5 September 2021

Previously, I wrote about configuring emacs terminals for remote emacsclient usage. Today I want to write about another aspect of configuring ansi-term in emacs which turned out to be suprisingly difficult.

One of the main purposes of running a terminal inside of emacs instead of as a separate process, is for the integration we get between the terminals and our editor. When editing a file, a keybinding can pop up a terminal in a buffer that is already in the same current directory as the file we are editing, without the need to go traversing the filesystem to get there. This works out-of-the-box with local terminals, but by default, once you ssh into another host, this integration is lost. In addition, if we are in a terminal at a certain directory, and run a command like C-x X-f to open a file or C-x C-d to open a Dired buffer, we would like emacs to default to the same directory we are currently at in the terminal.

With TRAMP, emacs can easily open files on the remote server as if they were local, this two-way integration between the terminal and the rest of emacs is lost without special configuration. To make this work, the remote host needs to send information about its current directory, user, and host. This is done by sending text in a special format, generally as part of the prompt. To avoid visual clutter, escape codes are used to make the text visually invisible, though emacs can still parse it.

Though all of this can be configured manually by editing the .bashrc or equivalent on each remote host you want this to work on. Rather than manually set all this up, there is a small package which wraps ansi-term called tramp-term which can be installed with package-install. This package prompts for a host to connect to (or takes it as a parameter), and then connects to the remote host and sets up environment variables on the remote host to send the necessary data back for the session.

This is all a well traveled path, but no matter what I did, I could not get it to work, whenever I had it set up properly to send the necessary data back from the remote host, attempting to use it by opening a file, etc, would return an error about being unable to resolve host where the host it was trying to resolve was a hyphen (-). Messages showed:

Tramp: Opening connection for - using ssh...
Tramp: Sending command ‘exec ssh   -o ControlMaster=auto -o ControlPath='tramp.%C' -o ControlPersist=no -e none -’
Tramp: Waiting for prompts from remote shell...
Tramp failed to connect.  If this happens repeatedly, try
    ‘M-x tramp-cleanup-this-connection’
Tramp: Waiting for prompts from remote shell...failed
Tramp: Opening connection for - using ssh...failed

Clearly something was wrong, but no amount of googling or ducking found anyone else with a similar issue. It seemed like this just worked fine for everyone but me. I did finally find the culprit, when I first set up tramp, I had put a ine in my init.el to make it use “simplified” syntax for Tramp hosts, so I could leave off the /ssh: when typing host names. Apparently this breaks everything. Once I finally found and removed this line this worked ok.

The second part of the issue was to be able to open a terminal and have it automatically open at the same host and path as my current emacs directory, so if I was looking at a file on localhost, it would open an ansi-term at that directory, and if the current file was a tramp file on a remote host, it would open a tramp-term, connect to that host over ssh at the same directory as the file. For this I ended up writing some elisp:

(defun my-tramp-term--cd-hook(host)
  (term-send-raw-string (concat "cd " (tramp-file-name-localname ts) ";clear" (kbd "RET")))
)

(defun my-tramp-term-here()
    (interactive)
    (if (tramp-tramp-file-p default-directory)
         (let ((ts (tramp-dissect-file-name default-directory)))
           (if (string= (tramp-file-name-method ts) "ssh")
               (progn
                 (add-hook 'tramp-term-after-initialized-hook 'my-tramp-term--cd-hook)
                 (if (tramp-file-name-user ts)
                     (tramp-term (list (tramp-file-name-user ts) (tramp-file-name-host ts)))
                   (tramp-term (list (tramp-file-name-host ts)))
                   )
                 (remove-hook 'tramp-term-after-initialized-hook 'my-tramp-term--cd-hook)
                 )
             (message "tramp-term-here: Unsupported Tramp method. Only ssh supported"))
           )
      (ansi-term (or explicit-shell-file-name "bash") "localhost")
      )
    )

Now I can just call my-tramp-term-here on an open buffer, and it will do the right thing. Looking at this again, I don’t think I really need the hook, I could just run the term-send-raw-string right in the method body after connecting the tramp-term.

Incidently as I am just now learning elisp, I was surprised that the hook function was able to access the ts variable defined in the my-tramp-term-here function locally. At first I figured it was some sort of automatic closure and had to do with where the hook was defined, but it actually turns out to be due to elisp’s dynamic scoping and the ts variable is only visible because the hook is called from the tramp-term call which is called from my my-tramp-term-here function. If I were to leave that hook in place and tramp-term got called from a different function, this wouldn’t work. I don’t think I’ve ever worked in a language with dynamic scoping before, its kind of different.

Remote emacsclient with tramp-term

3 September 2021

For a long time, my workflow for development at ${WORK} has been to ssh from my workstation into a server and run emacs in a terminal to edit and build my code. Recently, I’ve started experimenting with running emacs locally and accessing resources on the remote server via TRAMP.

My emacs usage as traditionally been very basic, mainly starting emacs to edit a file, then either quitting to the shell to perform other commands, or having another shell already running under GNU Screen and switching to it. As part of my experiment I’ve been working to configure emacs to provide more of what I need so much more is done from inside emacs itself, providing a nicely integrated experience. To that end, I’ve been testing out tramp-term a package which allows a terminal to be opened on a remote host (via ssh), and then tracks as you move between directories. Therefore at any time from the terminal window if you C-x C-f to open a file, or C-x C-d to open a dired buffer, emacs knows the current directory of the terminal and defaults to that directory.

One missing feature, however, is the ability to edit a file from the command line inside the terminal window and have it open the file in a new buffer in the local emacs instance, rather than run a new instance of emacs on the remote server inside the tramp-term. Normally emacsclient would be used for that, but out of the box, it doesn’t work remotely. This would be useful to have working; even though you could just C-x C-f to open the file, because some programs will open an editor automatically, looking at the $VISUAL or $EDITOR environment variables. Setting those to emacsclient allows those files to open in buffers in your existing emacs session.

After much research, I did manage to cobble something together that works:

In ~/.emacs.d/init.el add the following:

(setq server-use-tcp t
      server-port    9999)
(server-start)
(defun my-tramp-term--emacsclient-hook (host)
  (term-send-raw-string (concat "alias emacsclient='emacsclient --tramp /ssh:"
                         host ":'" (kbd "RET")))
  (term-send-raw-string (concat "mkdir -p ~/.emacs.d/server/ ; clear"
                         (kbd "RET")))
  (copy-file "~/.emacs.d/server/server" (concat "/ssh:" host ":.emacs.d/server/server") t)

)

(add-hook 'tramp-term-after-initialized-hook 'my-tramp-term--emacsclient-hook)

In ~/.ssh/config Add the following for all hosts that you want to be able to use remote editing from

 RemoteForward 9999 localhost:9999

Then when you log in to one of these remote servers inside tramp-term you can use emacsclient on the remote to open a file locally.

Caveats

  • You must have emacsclient installed on the remote host and it needs to be a new enough version to support the --tramp option
  • Since on the host we are binding emacs server to port 9999, if you run more than one copy of emacs at a time, susequent copies will give an error here on startup. This could probably be improved to first check if an emacs-server is already running before starting the server
  • This will only work if only one remote emacs is used to edit on the remote host at a time. If you log in from multiple emacs instances to the same remote, this solution will always try to use the most recently connected instance.
  • TCP Port 9999 must be free for binding on both the local and remote systems.

Inspired by This Solution, though modified to create and use an alias instead of needing a bash script on the remote and altered to work with tramp-term.

I’ve also posted these instruction as a comment on the relevant ticket on the Tramp-term.el Github since if anyone else is searching for a solution, people are more likely to end up there than this blog.

Skype Web on FreeBSD Finally

26 August 2021

I’ve written before about various work-arounds I’ve used to access Skype from FreeBSD and GhostBSD. Adequate Skype connectivity is necessary for me to be able to use these as my daily driver, since thats what we use at ${WORK} to stay in touch.

Running Skype under a headless Debian VM and fowarding the screen via X and the audio via Pulseaudio to the host machine has proven pretty reliable, though high CPU utilization is the norm, and I didn’t have the ability to share my screen. I’ve tried a couple of times to get the Skype Web client working, both in Firefox and Chromium as well as in Google Chrome running with FreeBSD’s Linux Emulation with limited success.

Recently, however, when I gave it another shot in Chromium on my GhostBSD workstation, everything suddenly works! I’m not sure if its related to a recent Chromium update (I currently have 91.0.4472.164), or to something that Microsoft recently changed on the servers, but either way, I’ll take it.

Not only do inbound and outbound calls work, but so does screen sharing! I can even use my webcam and show my face at work, though its a little glitchy from time to time. My webcam works fine under pwcview but it has some glitchy frames on all web sites under Chromium.

One odd thing with the Skype Web client is that periodically, perhaps once a day, it “Deactivates” my Skype session and pops up a notification that I need to activate it again. If I get a call while its not activated, it doesn’t ring, but does pop up another notification telling me to reactivate it because a call is coming in. This is pretty weird– its obviously still connected to the servers since it knows a call is coming in, so why do I need to ‘Reactivate’? I’ve been meaning to look into a chromium plugin that will automatically refresh the page every twelve hours or whatever.

I’ve closed down my Debian VM on my desktop and have been using the Web Client now for the past two weeks with good results . I’ve also verified it works on my FreeBSD Laptop (Currently on 12.2), so its not just a FreeBSD 13 thing, though I don’t have much mileage on it there.

Zoom has also been working pretty well for me under Chromium on GhostBSD for me lately, though I did have one meeting where incoming video died and I couldn’t get it to re-enable.

Trying out Void Linux on a Thinkpad P15

19 August 2021

Since moving to full work-from-home eighteen months ago, I’ve mainly been working from my GhostBSD Desktop, and, when I need to be more mobile, my Thinkpad T450 running FreeBSD (recently upgraded to 12.2). I do have a work provided laptop as well–but as a seven year old Windows machine, I prefer my T450 for most things. As the Windows laptop has started getting unreasonably warm at times, and after a few unexplained lockups, I was approved for a new work laptop, which I could pick out and get reimbursed for. Though I considered a Dell XPS and several different Thinkpads, I ended up purchasing a Thinkpad P15 Gen1 with the following specs:

Lenovo Thinkpad P15 Gen1

  • Intel i7-10875H Processor
  • 64 GB RAM
  • 2TB NVMe SSD
  • 15.6” 1920 x 1080 Display

At over six pounds its a bit of a beast, and feels almost as large my 17” Toshiba its replacing. I considered a P15s or P15v for better portability, but the reviews I read showed the P15v having heat issues, and the display on the P15s I was looking at wasn’t as bright. I still have my 14” T450 for when I want to grab something more portable.

Unlike my T450 where I removed Windows and installed FreeBSD upon first powerup, I wanted to leave this one as a Dual Boot with Windows and Linux. I decided to go with Linux instead of FreeBSD on this one for a few reasons: Hardware support seems iffy for hardware this new on FreeBSD, especially the WiFi card, and WiFi in general is slow on FreeBSD. I’ve also been wanting to try out Void Linux for a while, so this gives me the opportunity to do so.

The Void Linux install was more or less painless. I burned the ISO that included the Xfce desktop onto a USB Dongle from my GhostBSD machine, booted up Windows and shrank its partition from 2TB down to about 1.2TB, and disabled secure boot. On bootup I used F12 for the boot menu in order to tell it to boot from the USB Dongle, and ran the Void Linux live/install image. I was pleasantly reassured when everything came up and ran fine right out of the box, including WiFi. The install process was also fairly straight forward, though a little more guidance would have been appreciated– it was a bit scary needing to tell the installer to write the boot loader to /dev/sda, worried it would mess up Windows, but this turned out to be the right thing to do. It makes sense with how EFI works, it just writes the boot loader to the same EFI FAT32 partition where the Windows boot loader lives without needing to overwrite anything, but I still have bad memories of trying to set up multi OS boot in the pre EFI days so this was still a little scary. I also was very paranoid to make sure I didn’t tell it to format the EFI or Windows partitions.

After the install and a reboot, the laptop booted right up to grub and booted Void Linux. I was a little worried I had messed up the Windows Boot after all, as there was no sign of it in the boot process, but another boot, and F12 to bring up the boot menu shows both a Windows and a ‘void grub’ option both of which work fine, the void grub one was just set as the default by the installer. (This can be changed with the efibootmgr command line program)

Booting into Void I was pleasantly surprised by how much just worked out of the box and was set up nicely. Not only was WiFi working, but I could easily connect to WiFi Networks right from the Xfce Panel plugin. The Thinkpad brightness keys worked right out of the box, the trackpad and trackbutton had reasonable sensitivity and even two finger scroll worked right out of the box. Maybe I’m just too easily impressed– I haven’t run Linux on a laptop in quite some time, and it was never this smooth to set up before. I’m not sure how much of the credit goes to Void, to the Linux Kernel, or to Xfce, but everything fits together so much more smoothly then ever before.

I did soon run into my first issue however, when I tested suspends resume and ended up with a black blinky screen with just a mouse cursor. Switching to a terminal was fine however, the problem was limited to X, and after using xbps-install to install the proprietary nvidia driver (it was defaulting to noveau) and updating all the packages, this worked fine. I made one mistake however, I first installed just the nvidia driver, which sucked down a bunch of other required packages like gcc to build the kernel driver. Upon reboot I couldn’t run any programs from X, though again a console still worked. I realized my mistake and ran xbps-install -S to update everything, rebooted, and all was well. I’m guessing the nvidia driver install caused my system to end up with incompatible library versions or something. Since then I’ve always been running xbps-install with the -S option always and it doesn’t seem to have caused any problems.

In addition to suspend / resume working, I’ve been very happy with the hibernation support. It hibernates and wakes up pretty quickly, and it feels like magic to have youtube playing some music in a background window, hibernate the OS to disk, boot into Windows for a while, boot back into Linux, and hear the song continue from the point where it left off as if nothing had happened.

One kind of weird thing with Void Linux is that the default configuration (at least the Xfce variant) comes with pulseaudio set up for audio, but with the audio muted, and doesn’t come with the command line tool you need to run in order to unmute it. Luckily a quick web search names the tool and I was able to install it and unmute my audio, but why include pulseaudio but not a tool you would need to be able to make use of it?

So far I’ve really been liking Void, but I haven’t been using it long enough to develop an informed opinion of it. I used to hate all the ‘Distro Reviews’ I’d read in the late 1990’s that were really installer reviews. The reviewer would install the Distro, use it for ten minutes and then write a review– not particularly useful. The real test of a distro is whether or not it keeps running smooth over months as packages update, or if it craps out with weird issues. Only time will tell.