A Weird Imagination

Borderless browser window

The problem#

Web browser UIs have a lot more than just displaying the web page, which is useful when using them as a browser, but clutters the screen if all we want is to define what is displayed on part of the screen using HTML. So, can we get Firefox into a mode where it really does show just the website and nothing else? Firefox does have a fullscreen mode that does that, but it covers an entire monitor.

The solution#

To hide all of the Firefox menus and toolbars, put the following in the chrome/userChrome.css file under your Firefox profile directory (you will likely want to create a separate profile from the one you use for web browsing):

#TabsToolbar, #TabsToolbar-customization-target,
#nav-bar, #urlbar-container, #searchbar {
  visibility: collapse !important;
}

To hide the window border and titlebar, compile toggle-decorations.c and run

firefox &
./toggle-decorations $(xdotool selectwindow)

and then click on the Firefox window once it opens. It may be easier to bind it to a hotkey with xdotool getactivewindow or use some other way to identify the window.

The details#

Read more…

Fullscreen mode on part of screen

Posted in

The problem#

Many applications have a fullscreen mode that has a different interface from their windowed mode. For example, many media players will show just the video in fullscreen mode but include media controls in windowed mode. But, especially if you have a large monitor, you may want to use that interface while only having the application take up part of your monitor.

The solution#

I could not find a solution that works on every window manager.

The window manager handles resizing the application when it switches to fullscreen, so the most straightforward way to accomplish this is to not run a window manager. Problem solved! Unfortunately, window managers are really useful, so outside of some niche cases where you're positioning windows with xdotool, that's probably not what you want.

There's a "fakefullscreen" option in some forks of the very configurable window manager dwm: base dwm with the fakefullscreen patch always does fullscreen that way, the instantWM fork has a hotkey Super+Shift+F that toggles fake fullscreen for a window, and awesome can be configured to do the same.

For more common window managers, there is a solution, but more than two virtual monitors requires an xorg-server newer than 21.1.10 (which is the most recent release at time of writing, so you would have to compile it yourself), and in my tests, it only worked on Compiz, and not Mutter, KWin, or Xfwm. Use xrandr 1.5+ to define virtual monitors on sections of your monitors and then maximizing or fullscreening applications should respect those boundaries:

xrandr --setmonitor lefthalf 960/217x1080/132+0+0 LVDS-1
# This is a hack, should be "LVDS-1", not "none".
xrandr --setmonitor righthalf 960/217x1080/132+960+0 none

where the the geometery specification format is w/mmwxh/mmh+x+y (mmw/h="millimeters width/height") and LVDS-1 is the name xrandr gives to my physical monitor. Note that xorg-server 21.1.10 and older have a limit of one virtual monitor per physical monitor which we can circumvent by putting the second virtual monitor on "none".

The details#

Read more…

Status of long-running copy

The problem#

When running an incremental backup with rsync with the --progress flag, it often spends lot of time outputting nothing as it scans through many unchanged files. If you think of it before starting the transfer, --info=progress2 or the name2/skip2 --info flags would give more detail, but once the transfer has been going for a while, you probably don't want to cancel and restart it so you can add those flags.

The solution#

The documentation and this StackExchange answer say you can send a SIGVTALRM signal to rsync version 3.2.0+ and it will output its current progress, but that wasn't working for me.

As a workaround, you can use strace to get a running log of which files rsync is looking at, which includes files it skips without actually opening:

strace --attach="$(pidof rsync)" --trace=openat

(If that's not showing anything, try removing the --trace=openat filter and seeing if there's other syscalls with paths to filter on.)

Alternatively, this StackExchange answer suggests a way to see the currently open files including their sizes (including directories but not unchanged files being inspected):

watch lsof -p"$(pidof rsync | tr ' ' ',')"

(The same should work for a recursive cp/mv/rm.)

Similarly, for getting the status of a transfer of a single large file, this answer attempts to read the files cp is reading/writing to give a running percentage of how much it has copied; a similar approach might work for rsync.

The details#

Read more…

Hardlink identical directory trees

Posted in

The problem#

I will often make copies of important files onto multiple devices, and then later make backups of all of those devices onto the same drive. At which point, I now have multiple redundant copies of those files within my backup. Tools like rdfind, fdupes, and jdupes exist to deal with the general problem of searching a collection of files for duplicates efficiently, but none of them support only checking if files are identical if their filenames and/or paths match, so they end up doing a lot of extra work in this case.

The solution#

Download the script I wrote, hardlink-dups-by-name.sh and run it as follows:

hardlink-dups-by-name.sh a_backup/ another_backup/

Then all files like a_backup/some/path that are identical to the corresponding file another_backup/some/path will get hard-linked together so there will only be one copy of the data taking up space.

The details#

Read more…

Generating specialized word lists

Posted in

The problem#

I've been playing Codenames online a lot lately (using my fork of codenames.plus), and a friend suggested it might be fun to have themed word lists. Specifically, they suggested Star Trek as a theme as it's a fandom that's fairly widely known. They left it up to me to figure out what should be in a Star Trek themed word list.

The solution#

If you just want to play Codenames with the list, go to my Codenames web app and select one or both of the Star Trek card packs. If you just want the word lists, you can download the Star Trek: The Next Generation words and the Star Trek: Deep Space 9 words.

To generate a word list yourself (I used this source for the Star Trek scripts), you will need a common words list like en_50k.txt which I mentioned in my previous post on anagram games, and then pipe the corpus through the following script (which you will likely have to modify for the idiosyncrasies of your data):

#!/bin/bash
set -euo pipefail

NUM_COMMON=2000 # Filter out the most common 2000 words
COMMON_WORDS="$(mktemp)"
<en_50k.txt head "-$NUM_COMMON" | cut -d' ' -f1 |\
    sort | tr '[:lower:]' '[:upper:]' >"$COMMON_WORDS"

# Select only dialogue lines (in Star Trek scripts)
grep -aP '^\t\t\t[^\t]' |\
    # Split words
    tr ' .,:()\[\]!?;"/\t[:cntrl:]' '[\n*]' |\
    sed 's/--/\n/' |\
    # Strip whitespace
    sed 's/^\s\+//' | sed 's/\s\+$//' |\
    grep -av '^\s*$' |\
    # Strip quotes
    sed "s/^'//" | sed "s/'$//" |\
    # Filter out numbers
    grep -av '^[[:digit:]]*$' |\
    tr '[:lower:]' '[:upper:]' |\
    # Fix for contractions not being in wordlist
    sed "s/'\(S\|RE\|VE\|LL\|M\|D\)$//" |\
    grep -av "'T$" |\
    # Remove some more non-words
    grep -avF '-' |\
    grep -avF '&' |\
    # Count
    sort | uniq -c |\
    # Only keep words with >25 occurrences
    awk '{ if ($1 > 25) { print } }' |\
    # Remove common words
    join -v2 -22 -o 2.1,2.2 "$COMMON_WORDS" - |\
    # Sort most common words first
    sort -rn

rm "$COMMON_WORDS"

The output of the script will require some manual effort to decide which words really belong in the final list, but it's a good start.

The details#

Read more…

Useful global keyboard shortcuts

Most desktop environments provide options for customizing keyboard shortcuts. In XFCE, there's settings panels for both for window manager shortcuts and application shortcuts. While the term "application shortcuts" suggests using them for launching applications, and many keyboards do have special keys for launching a music player or a calculator that I do have set up, I don't find myself using those much. I have buttons on my panel for applications that I launch often; if I'm going to be clicking away into a new application, I don't find clicking on the panel to be an additional inconvenience.

On the other hand, "application shortcuts" can be used for launching arbitrary scripts, including ones don't involve switching contexts.

Keys to use#

Many keyboards have extra keys intended for global commands labeled with various symbols. If you have them, you can be creative about what you want them to mean and even combine them with modifiers (Shift, Ctrl, etc.) to get more inputs. On the other hand, if you have a more traditional keyboard layout (which is likely the case on a laptop), your choices are more limited. To avoid confusion, it's generally best to use the Windows key (usually called the Super key in Linux) for global shortcuts as it is not usually used for anything else.

Shortcut ideas#

Read more…

Reacting to screensaver starting/stopping

Posted in

The problem#

I want my computer to act differently when I'm actively using it as opposed to away from. I almost always lock the screen when I step away from my computer, so I want to have the same signal do more than just start the screensaver.

The solution#

Save the follow script which is slightly modified from the example in the man page for xscreensaver-command as watch-xscreensaver.pl:

#!/usr/bin/perl

my $blanked = 0;
open (IN, "xscreensaver-command -watch |");
while (<IN>) {
    print;
    if (m/^(BLANK|LOCK)/) {
        if (!$blanked) {
            system "on-xscreensaver-lock";
            $blanked = 1;
        }
    } elsif (m/^UNBLANK/) {
        system "on-xscreensaver-unlock";
        $blanked = 0;
    }
}
if ($blanked) {
    system "on-xscreensaver-unlock";
}

Either call it from your ~/.xsessionrc file or just manually run from a terminal in your X session. I run it from a screen session so I can reattach to it and see the output:

screen -d -m -S xscreensaver-watch watch-xscreensaver.pl

My on-xscreensaver-lock and on-xscreensaver-unlock scripts are below and may be a good starting place, but yours will probably be different depending on your needs.

The details#

Read more…

Reacting to active window

Posted in

The problem#

Which window I have focused is a signal to the computer for the state I want it to be in. For instance, I normally leave my speaker muted so, for example, I don't accidentally play sound from a website with unexpected videos. But this means that when I do want sound, I need to manually unmute the sound, even though I've already told the computer that I want to watch Netflix, which always involves turning on the sound.

Of course, for the particular problem of unmuting the sound, adding a keyboard shortcut and rereading xkcd 1205: Is It Worth the Time? probably would have been a more appropriate solution. But I wanted a general solution to the problem.

The solution#

Download x11_watch_active_window.py. Then the following script will unmute the speakers if Netflix is focused:

#!/bin/sh
x11_watch_active_window.py | while read -r FocusApp
do
    if [ "Netflix - Google Chrome" = "$FocusApp" ]
    then
        echo Netflix is focused, unmuting.
        pactl set-sink-mute 0 0
    fi
done

The details#

Read more…

1 comment

Limit processor usage of multiple processes

Posted in

The problem#

In last week's post, I discussed using cpulimit on multiple processes in the special case of web browsers, but I wanted a more general solution.

The solution#

cpulimit-all.sh is a wrapper around cpulimit which will call cpulimit many times to cover multiple processes of the same name and subprocesses.

Using that script, the follow is the equivalent of the script from last week to limit all browser processes to 10% CPU:

cpulimit-all.sh --limit=10 --max-depth=1 \
    -e firefox -e firefox-esr -e chromium -e chrome

But also, we can add a couple options to include any grandchild processes and check for new processes to limit every minute:

cpulimit-all.sh --limit=10 --max-depth=2 \
    -e firefox -e firefox-esr -e chromium -e chrome \
    --watch-interval=1m

The details#

Read more…

Limit web browser processor usage

Posted in

The problem#

cpulimit is a useful utility for stopping a program from wasting CPU, but it only limits a single process. As all modern web browsers use process isolation, limiting just a single process doesn't do very much, we actually want to limit all of the browser processes.

The solution#

The following script will limit the CPU usage of all browser processes to $LIMIT percent CPU. Note that the limit is per process not total over all processes, so you may want to set it quite low to actually have an effect.

LIMIT=10 # Hard-code a limit of 10% CPU as an example.

# Kill child processes (stop limiting CPU) on script exit.
for sig in INT QUIT HUP TERM; do
  trap "
    pkill -P $$
    trap - $sig EXIT
    kill -s $sig "'"$$"' "$sig"
done
trap cleanup EXIT

# Find and limit all child processes of all browsers.
for name in firefox firefox-esr chromium chrome
do
    for ppid in $(pgrep "$name")
    do
        cpulimit --pid="$ppid" --limit="$LIMIT" &
        for pid in "$ppid" $(pgrep --parent "$ppid")
        do
            cpulimit --pid="$pid" --limit="$LIMIT" &
        done
    done
done

The details#

Read more…