Sakura Line: retheme the whole desktop from the wallpaper

Palette sampled from bspwm/wallpaper/wallpaper.jpg and applied per-role
(not per-hex, so terminal green stays green and nvim's LineNr/Comment
stay recessive) across st, kitty, polybar, rofi, dunst, nvim, qt5ct/qt6ct
and GTK 2/3/4.

Also:
- rofi drun centred, icons enabled
- polybar translucent (true ARGB) and rounded; picom corner-radius, with
  the desktop layer and fullscreen windows excluded
- fix qt5ct color_scheme_path pointing at a nonexistent /home/carrie
- export QT_QPA_PLATFORMTHEME so qt6ct is actually consulted
- point GTK at an icon theme that exists on this system
- add .config/rice: one-shot install.sh (--dry-run supported), package
  list, vendored st config.h (gitignored upstream) and the particles
  wallpaper-layer source, so a clone reproduces the rice

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cn3dHfbgNYdbZvzb1b3GQt
This commit is contained in:
Sarthak 2026-09-04 00:19:36 +05:30
parent 45e5fe53d2
commit f341989335
35 changed files with 3300 additions and 124 deletions

61
.config/rice/README.md Normal file
View file

@ -0,0 +1,61 @@
# Sakura Line
bspwm rice. Palette sampled from `~/.config/bspwm/wallpaper/wallpaper.jpg`.
## Replicate on a fresh machine
```sh
bash <(curl -fsSL https://git.srtk.in/sarthak/dotfiles/raw/branch/main/.config/rice/install.sh)
```
Or, if the dotfiles are already cloned:
```sh
~/.config/rice/install.sh # full run
~/.config/rice/install.sh --dry-run # show what it would do, change nothing
```
Arch is the first-class target. Debian/Ubuntu and Fedora are best-effort —
the desktop, build and theming steps work; the AUR extras are skipped.
The script is safe to re-run. Anything in `$HOME` that would be overwritten by
the dotfiles checkout is moved to `~/.rice-backup-<timestamp>/` first.
## What it sets up
| | |
|---|---|
| WM | bspwm + sxhkd |
| Bar | polybar (translucent, rounded) |
| Compositor | picom (rounded corners, vsync) |
| Launcher | rofi, centred, with icons |
| Notifications | dunst |
| Terminal | st, built from `st/config.h` here (upstream gitignores it) |
| Wallpaper layer | `particles`, built from `particles/` here |
| Toolkits | GTK2/3/4 via `gtk.css` overrides, Qt via qt6ct |
## Palette
| role | hex | from |
|---|---|---|
| bg | `#0f0d17` | twilight shadow |
| fg | `#e9eefb` | cool white |
| accent | `#92b9ea` | sky |
| red | `#cf6a80` | blossom |
| green | `#8fae74` | grass |
| yellow | `#d8a87c` | train stripe |
| magenta | `#b483c0` | plum blossom |
| cyan | `#8ab6c4` | station house |
Changing the wallpaper does not re-derive these — they are written into each
app's config.
## Layout
```
.config/rice/
├── install.sh one-shot bootstrap
├── packages.txt package list ("aur:" prefix = needs an AUR helper)
├── st/config.h st build config
└── particles/ wallpaper-layer particle field (source + Makefile)
```

238
.config/rice/install.sh Executable file
View file

@ -0,0 +1,238 @@
#!/usr/bin/env bash
#
# Sakura Line - one-shot rice bootstrap.
#
# bash <(curl -fsSL https://git.srtk.in/sarthak/dotfiles/raw/branch/main/.config/rice/install.sh)
#
# or, from a clone: ~/.config/rice/install.sh
#
# Arch is the first-class target. Debian/Ubuntu and Fedora are best-effort:
# the desktop and build steps work, the AUR extras are skipped.
#
# Safe to re-run. Nothing in $HOME is overwritten without a backup first.
set -uo pipefail
DOTS_REMOTE="${DOTS_REMOTE:-https://git.srtk.in/sarthak/dotfiles.git}"
ST_REMOTE="${ST_REMOTE:-https://github.com/siduck/st}"
DOTS_DIR="$HOME/.dotfiles"
RICE_DIR="$HOME/.config/rice"
SRC_DIR="${SRC_DIR:-$HOME/gitclone}"
BACKUP="$HOME/.rice-backup-$(date +%Y%m%d-%H%M%S)"
STEPS_FAILED=()
DRY=0
for a in "$@"; do
case "$a" in
-n|--dry-run) DRY=1 ;;
-h|--help)
sed -n '2,14p' "$0" | sed 's/^#\s\?//'
printf '\nOptions:\n -n, --dry-run show what would happen, change nothing\n -h, --help this text\n\n'
exit 0 ;;
*) printf 'unknown option: %s (try --help)\n' "$a"; exit 2 ;;
esac
done
c_hd=$'\e[1;38;5;111m'; c_ok=$'\e[38;5;108m'; c_wa=$'\e[38;5;179m'
c_er=$'\e[38;5;168m'; c_dim=$'\e[38;5;103m'; c_off=$'\e[0m'
say() { printf '%s==>%s %s\n' "$c_hd" "$c_off" "$*"; }
# every mutating command goes through this so --dry-run is honest
run() { if [ "$DRY" = 1 ]; then printf ' %s$ %s%s\n' "$c_dim" "$*" "$c_off"; else "$@"; fi; }
ok() { printf ' %s+%s %s\n' "$c_ok" "$c_off" "$*"; }
warn() { printf ' %s!%s %s\n' "$c_wa" "$c_off" "$*"; }
die() { printf ' %sx%s %s\n' "$c_er" "$c_off" "$*"; exit 1; }
note() { printf ' %s%s%s\n' "$c_dim" "$*" "$c_off"; }
fail_step() { STEPS_FAILED+=("$1"); printf ' %sx%s %s\n' "$c_er" "$c_off" "$1"; }
[ "$(id -u)" -eq 0 ] && die "run this as your normal user, not root (it uses sudo where needed)"
# ---------------------------------------------------------------- distro
PM=""; AUR=""
if command -v pacman >/dev/null 2>&1; then PM=pacman
elif command -v apt-get >/dev/null 2>&1; then PM=apt
elif command -v dnf >/dev/null 2>&1; then PM=dnf
else warn "no supported package manager found; skipping installs"; PM=none
fi
PM_LINE="package manager: ${PM}"
# Package names differ per distro; this maps the ones that actually differ.
map_pkg() {
local p="$1"
case "$PM" in
apt) case "$p" in
base-devel) echo "build-essential" ;;
pkgconf) echo "pkg-config" ;;
libx11) echo "libx11-dev" ;;
libxext) echo "libxext-dev" ;;
libxft) echo "libxft-dev" ;;
libxrandr) echo "libxrandr-dev" ;;
libxfixes) echo "libxfixes-dev" ;;
libxinerama) echo "libxinerama-dev" ;;
cairo) echo "libcairo2-dev" ;;
harfbuzz) echo "libharfbuzz-dev" ;;
fontconfig) echo "libfontconfig1-dev" ;;
freetype2) echo "libfreetype6-dev" ;;
gd) echo "libgd-dev" ;;
xorg-xrandr) echo "x11-xserver-utils" ;;
xorg-xprop) echo "x11-utils" ;;
ttf-jetbrains-mono-nerd) echo "fonts-jetbrains-mono" ;;
noto-fonts) echo "fonts-noto" ;;
noto-fonts-emoji) echo "fonts-noto-color-emoji" ;;
papirus-icon-theme) echo "papirus-icon-theme" ;;
qt6ct) echo "qt6ct" ;;
*) echo "$p" ;;
esac ;;
dnf) case "$p" in
base-devel) echo "@development-tools" ;;
pkgconf) echo "pkgconf-pkg-config" ;;
libx11) echo "libX11-devel" ;;
libxext) echo "libXext-devel" ;;
libxft) echo "libXft-devel" ;;
libxrandr) echo "libXrandr-devel" ;;
libxfixes) echo "libXfixes-devel" ;;
libxinerama) echo "libXinerama-devel" ;;
cairo) echo "cairo-devel" ;;
harfbuzz) echo "harfbuzz-devel" ;;
fontconfig) echo "fontconfig-devel" ;;
freetype2) echo "freetype-devel" ;;
gd) echo "gd-devel" ;;
xorg-xrandr) echo "xrandr" ;;
xorg-xprop) echo "xprop" ;;
ttf-jetbrains-mono-nerd) echo "jetbrains-mono-fonts" ;;
noto-fonts) echo "google-noto-sans-fonts" ;;
noto-fonts-emoji) echo "google-noto-emoji-fonts" ;;
*) echo "$p" ;;
esac ;;
*) echo "$p" ;;
esac
}
install_packages() {
[ "$PM" = none ] && { warn "skipping package install"; return 0; }
local list="$RICE_DIR/packages.txt" repo=() aur=() line pkg
[ -f "$list" ] || { warn "packages.txt not found, skipping"; return 0; }
while IFS= read -r line; do
line="${line%%#*}"; line="$(echo "$line" | tr -d '[:space:]')"
[ -z "$line" ] && continue
if [[ "$line" == aur:* ]]; then aur+=("${line#aur:}")
else repo+=("$(map_pkg "$line")"); fi
done < "$list"
say "installing ${#repo[@]} packages"
case "$PM" in
pacman) run sudo pacman -S --needed --noconfirm "${repo[@]}" || fail_step "some packages failed" ;;
apt) run sudo apt-get update -qq && run sudo apt-get install -y "${repo[@]}" || fail_step "some packages failed" ;;
dnf) run sudo dnf install -y "${repo[@]}" || fail_step "some packages failed" ;;
esac
if [ "$PM" = pacman ] && [ "${#aur[@]}" -gt 0 ]; then
local helper=""
for h in paru yay pikaur; do command -v "$h" >/dev/null 2>&1 && { helper="$h"; break; }; done
if [ -z "$helper" ]; then
warn "no AUR helper; skipping: ${aur[*]}"
note "install paru, then re-run to get them"
else
say "installing ${#aur[@]} AUR packages with $helper"
run "$helper" -S --needed --noconfirm "${aur[@]}" || fail_step "some AUR packages failed"
fi
elif [ "${#aur[@]}" -gt 0 ]; then
warn "not Arch; skipping AUR extras: ${aur[*]}"
fi
}
# ------------------------------------------------------------- dotfiles
dot() { git --git-dir="$DOTS_DIR" --work-tree="$HOME" "$@"; }
deploy_dotfiles() {
if [ -d "$DOTS_DIR" ]; then
ok "dotfiles repo already present"
else
say "cloning dotfiles"
run git clone --bare "$DOTS_REMOTE" "$DOTS_DIR" || { fail_step "dotfiles clone"; return 1; }
fi
run dot config status.showUntrackedFiles no
if [ "$DRY" = 1 ]; then note "would checkout main into \$HOME (backing up conflicts)"; return 0; fi
# Move anything that would be clobbered into a backup instead of losing it.
mkdir -p "$BACKUP"
local conflicts
conflicts="$(dot checkout main 2>&1 | grep -oP '^\s+\K\S+\.\S+$' || true)"
if [ -n "$conflicts" ]; then
say "backing up files that would be overwritten -> $BACKUP"
while IFS= read -r f; do
[ -z "$f" ] && continue
[ -e "$HOME/$f" ] || continue
mkdir -p "$BACKUP/$(dirname "$f")"
mv "$HOME/$f" "$BACKUP/$f" && note "$f"
done <<< "$conflicts"
dot checkout main || { fail_step "dotfiles checkout"; return 1; }
fi
rmdir "$BACKUP" 2>/dev/null
ok "dotfiles deployed"
}
# --------------------------------------------------------------- builds
build_st() {
command -v gcc >/dev/null 2>&1 || { warn "no compiler; skipping st"; return 0; }
mkdir -p "$SRC_DIR"
if [ ! -d "$SRC_DIR/st/.git" ]; then
say "cloning st"
run git clone --depth 1 "$ST_REMOTE" "$SRC_DIR/st" || { fail_step "st clone"; return 1; }
fi
# config.h is gitignored upstream, so the rice bundle carries ours
run cp "$RICE_DIR/st/config.h" "$SRC_DIR/st/config.h" || { fail_step "st config"; return 1; }
say "building st"
run bash -c 'cd "$1" && make clean >/dev/null 2>&1; make' _ "$SRC_DIR/st" || { fail_step "st build"; return 1; }
run bash -c 'cd "$1" && sudo make install' _ "$SRC_DIR/st" || { fail_step "st install"; return 1; }
ok "st installed"
}
build_particles() {
command -v gcc >/dev/null 2>&1 || { warn "no compiler; skipping particles"; return 0; }
pkg-config --exists cairo x11 xext xfixes xrandr 2>/dev/null || {
warn "cairo/X11 dev headers missing; skipping particles"; return 0; }
say "building particles"
run bash -c 'cd "$1" && make clean >/dev/null 2>&1; make' _ "$RICE_DIR/particles" || { fail_step "particles build"; return 1; }
run bash -c 'cd "$1" && sudo make install' _ "$RICE_DIR/particles" || { fail_step "particles install"; return 1; }
ok "particles installed (run 'particles' to toggle)"
}
# ---------------------------------------------------------------- setup
post_setup() {
say "post-setup"
chmod +x "$HOME"/.config/bspwm/bspwmrc 2>/dev/null
chmod +x "$HOME"/.config/polybar/launch.sh 2>/dev/null
chmod +x "$HOME"/.config/scripts/*.sh 2>/dev/null
chmod +x "$HOME"/.config/scripts/rofi-menus/*.sh 2>/dev/null
chmod +x "$HOME"/.config/rice/install.sh 2>/dev/null
[ "$DRY" = 1 ] && { note "would fix permissions, rebuild fonts, set wallpaper"; return 0; }
command -v fc-cache >/dev/null 2>&1 && fc-cache -f >/dev/null 2>&1 && ok "font cache rebuilt"
if command -v papirus-folders >/dev/null 2>&1; then
papirus-folders -C blue --theme Papirus-Dark >/dev/null 2>&1 && ok "papirus folders set to blue"
fi
if [ -f "$HOME/.config/bspwm/wallpaper/wallpaper.jpg" ] && command -v feh >/dev/null 2>&1; then
feh --bg-fill "$HOME/.config/bspwm/wallpaper/wallpaper.jpg" >/dev/null 2>&1 && ok "wallpaper set"
fi
ok "post-setup done"
}
# ----------------------------------------------------------------- main
printf '\n%s Sakura Line%s - bspwm rice bootstrap\n\n' "$c_hd" "$c_off"
say "$PM_LINE"
[ "$DRY" = 1 ] && say "dry run - nothing will be changed"
install_packages
deploy_dotfiles
build_st
build_particles
post_setup
printf '\n'
if [ "${#STEPS_FAILED[@]}" -eq 0 ]; then
say "done - log out and back into bspwm to pick everything up"
else
say "finished with ${#STEPS_FAILED[@]} problem(s):"
for s in "${STEPS_FAILED[@]}"; do printf ' %s- %s%s\n' "$c_er" "$s" "$c_off"; done
fi
printf '\n %sst%s must be reopened to show new colours; %sparticles%s toggles the wallpaper layer.\n\n' \
"$c_hd" "$c_off" "$c_hd" "$c_off"

54
.config/rice/packages.txt Normal file
View file

@ -0,0 +1,54 @@
# Sakura Line rice - Arch package list.
# Lines starting with # are ignored. "aur:" prefix needs an AUR helper.
# --- window manager / desktop ---
bspwm
sxhkd
polybar
picom
rofi
dunst
feh
xdotool
xorg-xrandr
xorg-xprop
# --- build toolchain (st + particles) ---
base-devel
git
pkgconf
libx11
libxext
libxft
libxrandr
libxfixes
libxinerama
cairo
harfbuzz
fontconfig
freetype2
gd
# --- fonts ---
ttf-jetbrains-mono-nerd
noto-fonts
noto-fonts-emoji
# --- theming ---
qt6ct
papirus-icon-theme
aur:bibata-cursor-theme
# --- apps ---
thunar
fastfetch
# --- showcase toys ---
cava
btop
cmatrix
asciiquarium
onefetch
aur:cbonsai
aur:pipes.sh
aur:tty-clock

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,23 @@
PREFIX ?= /usr/local
BINDIR ?= $(PREFIX)/bin
PKGS := cairo x11 xext xfixes xrender xrandr
CFLAGS ?= -O2 -Wall -Wextra
CFLAGS += $(shell pkg-config --cflags $(PKGS))
LDLIBS := $(shell pkg-config --libs $(PKGS)) -lm
all: particles
particles: particles_wall.c
$(CC) $(CFLAGS) -o $@ $< $(LDLIBS)
install: particles
install -Dm755 particles $(DESTDIR)$(BINDIR)/particles
uninstall:
rm -f $(DESTDIR)$(BINDIR)/particles
clean:
rm -f particles
.PHONY: all install uninstall clean

File diff suppressed because it is too large Load diff

575
.config/rice/st/config.h Normal file
View file

@ -0,0 +1,575 @@
/* See LICENSE file for copyright and license details. */
/*
* appearance
*
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
*/
static char *font = "JetBrainsMono Nerd Font :pixelsize=14:antialias=true:autohint=true";
static char *font2[] = { "JetBrainsMono Nerd Font :pixelsize=14:antialias=true:autohint=true" };
static int borderpx = 15;
/*
* What program is execed by st depends of these precedence rules:
* 1: program passed with -e
* 2: utmp option
* 3: SHELL environment variable
* 4: value of shell in /etc/passwd
* 5: value of shell in config.h
*/
static char *shell = "/bin/sh";
char *utmp = NULL;
char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400";
/* identification sequence returned in DA and DECID */
char *vtiden = "\033[?6c";
/* Kerning / character bounding-box multipliers */
static float cwscale = 1.0;
static float chscale = 1.0;
/*
* word delimiter string
*
* More advanced example: L" `'\"()[]{}"
*/
wchar_t *worddelimiters = L" ";
/* selection timeouts (in milliseconds) */
static unsigned int doubleclicktimeout = 300;
static unsigned int tripleclicktimeout = 600;
/* alt screens */
int allowaltscreen = 1;
/*
* draw latency range in ms - from new content/keypress/etc until drawing.
* within this range, st draws when content stops arriving (idle). mostly it's
* near minlatency, but it waits longer for slow updates to avoid partial draw.
* low minlatency will tear/flicker more, as it can "detect" idle too early.
*/
static double minlatency = 8;
static double maxlatency = 33;
/*
* Synchronized-Update timeout in ms
* https://gitlab.com/gnachman/iterm2/-/wikis/synchronized-updates-spec
*/
static uint su_timeout = 200;
/*
* blinking timeout (set to 0 to disable blinking) for the terminal blinking
* attribute.
*/
static unsigned int blinktimeout = 800;
/*
* interval (in milliseconds) between each successive call to ximspot. This
* improves terminal performance while not reducing functionality to those
* whom need XIM support.
*/
int ximspot_update_interval = 1000;
/*
* thickness of underline and bar cursors
*/
static unsigned int cursorthickness = 2;
/*
* 1: render most of the lines/blocks characters without using the font for
* perfect alignment between cells (U2500 - U259F except dashes/diagonals).
* Bold affects lines thickness if boxdraw_bold is not 0. Italic is ignored.
* 0: disable (render all U25XX glyphs normally from the font).
*/
const int boxdraw = 1;
const int boxdraw_bold = 1;
/* braille (U28XX): 1: render as adjacent "pixels", 0: use font */
const int boxdraw_braille = 1;
/*
* bell volume. It must be a value between -100 and 100. Use 0 for disabling
* it
*/
static int bellvolume = 0;
/* default TERM value */
char *termname = "st-256color";
/*
* spaces per tab
*
* When you are changing this value, don't forget to adapt the »it« value in
* the st.info and appropriately install the st.info in the environment where
* you use this st version.
*
* it#$tabspaces,
*
* Secondly make sure your kernel is not expanding tabs. When running `stty
* -a` »tab0« should appear. You can tell the terminal to not expand tabs by
* running following command:
*
* stty tabs
*/
unsigned int tabspaces = 8;
/* bg opacity */
float alpha = 0.72;
/* Terminal colors (16 first used in escape sequence) */
static const char *colorname[] = {
/* Sakura Line - sampled from bspwm/wallpaper/wallpaper.jpg */
/* 8 normal colors */
"#0f0d17", /* black */
"#cf6a80", /* red */
"#8fae74", /* green */
"#d8a87c", /* yellow */
"#7c9ede", /* blue */
"#b483c0", /* magenta */
"#8ab6c4", /* cyan */
"#c9d1e2", /* white */
/* 8 bright colors */
"#3a3350", /* black */
"#e0798f", /* red */
"#a8c68d", /* green */
"#e9c79b", /* yellow */
"#92b9ea", /* blue */
"#d0a4d8", /* magenta */
"#a3c0cb", /* cyan */
"#e9eefb", /* white */
};
/*
* Default colors (colorname index)
* foreground, background, cursor, reverse cursor
*/
unsigned int defaultfg = 15; // #e9eefb
unsigned int defaultbg = 0; // #0f0d17
unsigned int defaultcs = 12; // cursor: #92b9ea (sky)
unsigned int defaultrcs = 0;
/*
* https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h4-Functions-using-CSI-_-ordered-by-the-final-character-lparen-s-rparen:CSI-Ps-SP-q.1D81
* Default style of cursor
* 0: Blinking block
* 1: Blinking block (default)
* 2: Steady block ("")
* 3: Blinking underline
* 4: Steady underline ("_")
* 5: Blinking bar
* 6: Steady bar ("|")
* 7: Blinking st cursor
* 8: Steady st cursor
*/
static unsigned int cursorshape = 1;
/*
* Default columns and rows numbers
*/
static unsigned int cols = 80;
static unsigned int rows = 24;
/*
* Default colour and shape of the mouse cursor
*/
static unsigned int mouseshape = XC_xterm;
static unsigned int mousefg = 7;
static unsigned int mousebg = 0;
/*
* Color used to display font attributes when fontconfig selected a font which
* doesn't match the ones requested.
*/
static unsigned int defaultattr = 11;
/*
* Xresources preferences to load at startup
*/
ResourcePref resources[] = {
{ "font", STRING, &font },
{ "fontalt0", STRING, &font2[0] },
{ "color0", STRING, &colorname[0] },
{ "color1", STRING, &colorname[1] },
{ "color2", STRING, &colorname[2] },
{ "color3", STRING, &colorname[3] },
{ "color4", STRING, &colorname[4] },
{ "color5", STRING, &colorname[5] },
{ "color6", STRING, &colorname[6] },
{ "color7", STRING, &colorname[7] },
{ "color8", STRING, &colorname[8] },
{ "color9", STRING, &colorname[9] },
{ "color10", STRING, &colorname[10] },
{ "color11", STRING, &colorname[11] },
{ "color12", STRING, &colorname[12] },
{ "color13", STRING, &colorname[13] },
{ "color14", STRING, &colorname[14] },
{ "color15", STRING, &colorname[15] },
{ "background", STRING, &colorname[258] },
{ "foreground", STRING, &colorname[259] },
{ "cursorColor", STRING, &colorname[256] },
{ "termname", STRING, &termname },
{ "shell", STRING, &shell },
{ "blinktimeout", INTEGER, &blinktimeout },
{ "bellvolume", INTEGER, &bellvolume },
{ "tabspaces", INTEGER, &tabspaces },
{ "borderpx", INTEGER, &borderpx },
{ "cwscale", FLOAT, &cwscale },
{ "chscale", FLOAT, &chscale },
{ "alpha", FLOAT, &alpha },
{ "ximspot_update_interval", INTEGER, &ximspot_update_interval },
};
/*
* Internal mouse shortcuts.
* Beware that overloading Button1 will disable the selection.
*/
const unsigned int mousescrollincrement = 3;
static MouseShortcut mshortcuts[] = {
/* button mask string */
{ Button4, XK_NO_MOD, "\031" },
{ Button5, XK_NO_MOD, "\005" },
};
/* Internal keyboard shortcuts. */
#define MODKEY Mod1Mask
#define TERMMOD (Mod4Mask|ShiftMask)
MouseKey mkeys[] = {
/* button mask function argument */
{ Button4, XK_NO_MOD, kscrollup, {.i = mousescrollincrement} },
{ Button5, XK_NO_MOD, kscrolldown, {.i = mousescrollincrement} },
{ Button4, Mod4Mask, zoom, {.f = +1} },
{ Button5, Mod4Mask, zoom, {.f = -1} },
};
static char *openurlcmd[] = { "/bin/sh", "-c", "st-urlhandler", "externalpipe", NULL };
static char *copyurlcmd[] = { "/bin/sh", "-c",
"tmp=$(sed 's/.*│//g' | tr -d '\n' | grep -aEo '(((http|https|gopher|gemini|ftp|ftps|git)://|www\\.)[a-zA-Z0-9.]*[:]?[a-zA-Z0-9./@$&%?$#=_-~]*)|((magnet:\\?xt=urn:btih:)[a-zA-Z0-9]*)' | uniq | sed 's/^www./http:\\/\\/www\\./g' ); IFS=; [ ! -z $tmp ] && echo $tmp | dmenu -i -p 'Copy which url?' -l 10 | tr -d '\n' | xclip -selection clipboard",
"externalpipe", NULL };
static char *copyoutput[] = { "/bin/sh", "-c", "st-copyout", "externalpipe", NULL };
static Shortcut shortcuts[] = {
/* mask keysym function argument */
{ XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} },
{ ControlMask, XK_Print, toggleprinter, {.i = 0} },
{ ShiftMask, XK_Print, printscreen, {.i = 0} },
{ XK_ANY_MOD, XK_Print, printsel, {.i = 0} },
{ MODKEY, XK_comma, zoom, {.f = +1} },
{ MODKEY, XK_period, zoom, {.f = -1} },
{ MODKEY, XK_g, zoomreset, {.f = 0} },
{ ControlMask | ShiftMask, XK_C, clipcopy, {.i = 0} },
{ ShiftMask, XK_Insert, clippaste, {.i = 0} },
{ ControlMask | ShiftMask, XK_V, clippaste, {.i = 0} },
{ XK_ANY_MOD, Button2, selpaste, {.i = 0} },
{ MODKEY, XK_Num_Lock, numlock, {.i = 0} },
{ ControlMask | ShiftMask, XK_U, iso14755, {.i = 0} },
{ ShiftMask, XK_Page_Up, kscrollup, {.i = -1} },
{ ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} },
{ MODKEY, XK_Page_Up, kscrollup, {.i = -1} },
{ MODKEY, XK_Page_Down, kscrolldown, {.i = -1} },
{ MODKEY, XK_k, kscrollup, {.i = 1} },
{ MODKEY, XK_j, kscrolldown, {.i = 1} },
{ MODKEY, XK_Up, kscrollup, {.i = 1} },
{ MODKEY, XK_Down, kscrolldown, {.i = 1} },
{ MODKEY, XK_u, kscrollup, {.i = -1} },
{ MODKEY, XK_d, kscrolldown, {.i = -1} },
{ MODKEY, XK_s, changealpha, {.f = -0.05} },
{ MODKEY, XK_a, changealpha, {.f = +0.05} },
{ MODKEY, XK_m, changealpha, {.f = +2.00} },
{ TERMMOD, XK_Up, zoom, {.f = +1} },
{ TERMMOD, XK_Down, zoom, {.f = -1} },
{ TERMMOD, XK_K, zoom, {.f = +1} },
{ TERMMOD, XK_J, zoom, {.f = -1} },
{ TERMMOD, XK_U, zoom, {.f = +2} },
{ TERMMOD, XK_D, zoom, {.f = -2} },
{ MODKEY, XK_l, externalpipe, {.v = openurlcmd } },
{ MODKEY, XK_y, externalpipe, {.v = copyurlcmd } },
{ MODKEY, XK_o, externalpipe, {.v = copyoutput } },
{ TERMMOD, XK_Return, newterm, {.i = 0} },
};
/*
* Special keys (change & recompile st.info accordingly)
*
* Mask value:
* * Use XK_ANY_MOD to match the key no matter modifiers state
* * Use XK_NO_MOD to match the key alone (no modifiers)
* appkey value:
* * 0: no value
* * > 0: keypad application mode enabled
* * = 2: term.numlock = 1
* * < 0: keypad application mode disabled
* appcursor value:
* * 0: no value
* * > 0: cursor application mode enabled
* * < 0: cursor application mode disabled
* crlf value
* * 0: no value
* * > 0: crlf mode is enabled
* * < 0: crlf mode is disabled
*
* Be careful with the order of the definitions because st searches in
* this table sequentially, so any XK_ANY_MOD must be in the last
* position for a key.
*/
/*
* If you want keys other than the X11 function keys (0xFD00 - 0xFFFF)
* to be mapped below, add them to this array.
*/
static KeySym mappedkeys[] = { -1 };
/*
* State bits to ignore when matching key or button events. By default,
* numlock (Mod2Mask) and keyboard layout (XK_SWITCH_MOD) are ignored.
*/
static uint ignoremod = Mod2Mask|XK_SWITCH_MOD;
/*
* Override mouse-select while mask is active (when MODE_MOUSE is set).
* Note that if you want to use ShiftMask with selmasks, set this to an other
* modifier, set to 0 to not use it.
*/
static uint forceselmod = ShiftMask;
/*
* This is the huge key array which defines all compatibility to the Linux
* world. Please decide about changes wisely.
*/
static Key key[] = {
/* keysym mask string appkey appcursor */
{ XK_KP_Home, ShiftMask, "\033[2J", 0, -1},
{ XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1},
{ XK_KP_Home, XK_ANY_MOD, "\033[H", 0, -1},
{ XK_KP_Home, XK_ANY_MOD, "\033[1~", 0, +1},
{ XK_KP_Up, XK_ANY_MOD, "\033Ox", +1, 0},
{ XK_KP_Up, XK_ANY_MOD, "\033[A", 0, -1},
{ XK_KP_Up, XK_ANY_MOD, "\033OA", 0, +1},
{ XK_KP_Down, XK_ANY_MOD, "\033Or", +1, 0},
{ XK_KP_Down, XK_ANY_MOD, "\033[B", 0, -1},
{ XK_KP_Down, XK_ANY_MOD, "\033OB", 0, +1},
{ XK_KP_Left, XK_ANY_MOD, "\033Ot", +1, 0},
{ XK_KP_Left, XK_ANY_MOD, "\033[D", 0, -1},
{ XK_KP_Left, XK_ANY_MOD, "\033OD", 0, +1},
{ XK_KP_Right, XK_ANY_MOD, "\033Ov", +1, 0},
{ XK_KP_Right, XK_ANY_MOD, "\033[C", 0, -1},
{ XK_KP_Right, XK_ANY_MOD, "\033OC", 0, +1},
{ XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0},
{ XK_KP_Prior, XK_ANY_MOD, "\033[5~", 0, 0},
{ XK_KP_Begin, XK_ANY_MOD, "\033[E", 0, 0},
{ XK_KP_End, ControlMask, "\033[J", -1, 0},
{ XK_KP_End, ControlMask, "\033[1;5F", +1, 0},
{ XK_KP_End, ShiftMask, "\033[K", -1, 0},
{ XK_KP_End, ShiftMask, "\033[1;2F", +1, 0},
{ XK_KP_End, XK_ANY_MOD, "\033[4~", 0, 0},
{ XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0},
{ XK_KP_Next, XK_ANY_MOD, "\033[6~", 0, 0},
{ XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0},
{ XK_KP_Insert, ShiftMask, "\033[4l", -1, 0},
{ XK_KP_Insert, ControlMask, "\033[L", -1, 0},
{ XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0},
{ XK_KP_Insert, XK_ANY_MOD, "\033[4h", -1, 0},
{ XK_KP_Insert, XK_ANY_MOD, "\033[2~", +1, 0},
{ XK_KP_Delete, ControlMask, "\033[M", -1, 0},
{ XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0},
{ XK_KP_Delete, ShiftMask, "\033[2K", -1, 0},
{ XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0},
{ XK_KP_Delete, XK_ANY_MOD, "\033[3~", -1, 0},
{ XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0},
{ XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0},
{ XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0},
{ XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0},
{ XK_KP_Enter, XK_ANY_MOD, "\r", -1, 0},
{ XK_KP_Subtract, XK_ANY_MOD, "\033Om", +2, 0},
{ XK_KP_Decimal, XK_ANY_MOD, "\033On", +2, 0},
{ XK_KP_Divide, XK_ANY_MOD, "\033Oo", +2, 0},
{ XK_KP_0, XK_ANY_MOD, "\033Op", +2, 0},
{ XK_KP_1, XK_ANY_MOD, "\033Oq", +2, 0},
{ XK_KP_2, XK_ANY_MOD, "\033Or", +2, 0},
{ XK_KP_3, XK_ANY_MOD, "\033Os", +2, 0},
{ XK_KP_4, XK_ANY_MOD, "\033Ot", +2, 0},
{ XK_KP_5, XK_ANY_MOD, "\033Ou", +2, 0},
{ XK_KP_6, XK_ANY_MOD, "\033Ov", +2, 0},
{ XK_KP_7, XK_ANY_MOD, "\033Ow", +2, 0},
{ XK_KP_8, XK_ANY_MOD, "\033Ox", +2, 0},
{ XK_KP_9, XK_ANY_MOD, "\033Oy", +2, 0},
{ XK_Up, ShiftMask, "\033[1;2A", 0, 0},
{ XK_Up, Mod1Mask, "\033[1;3A", 0, 0},
{ XK_Up, ShiftMask|Mod1Mask,"\033[1;4A", 0, 0},
{ XK_Up, ControlMask, "\033[1;5A", 0, 0},
{ XK_Up, ShiftMask|ControlMask,"\033[1;6A", 0, 0},
{ XK_Up, ControlMask|Mod1Mask,"\033[1;7A", 0, 0},
{ XK_Up,ShiftMask|ControlMask|Mod1Mask,"\033[1;8A", 0, 0},
{ XK_Up, XK_ANY_MOD, "\033[A", 0, -1},
{ XK_Up, XK_ANY_MOD, "\033OA", 0, +1},
{ XK_Down, ShiftMask, "\033[1;2B", 0, 0},
{ XK_Down, Mod1Mask, "\033[1;3B", 0, 0},
{ XK_Down, ShiftMask|Mod1Mask,"\033[1;4B", 0, 0},
{ XK_Down, ControlMask, "\033[1;5B", 0, 0},
{ XK_Down, ShiftMask|ControlMask,"\033[1;6B", 0, 0},
{ XK_Down, ControlMask|Mod1Mask,"\033[1;7B", 0, 0},
{ XK_Down,ShiftMask|ControlMask|Mod1Mask,"\033[1;8B",0, 0},
{ XK_Down, XK_ANY_MOD, "\033[B", 0, -1},
{ XK_Down, XK_ANY_MOD, "\033OB", 0, +1},
{ XK_Left, ShiftMask, "\033[1;2D", 0, 0},
{ XK_Left, Mod1Mask, "\033[1;3D", 0, 0},
{ XK_Left, ShiftMask|Mod1Mask,"\033[1;4D", 0, 0},
{ XK_Left, ControlMask, "\033[1;5D", 0, 0},
{ XK_Left, ShiftMask|ControlMask,"\033[1;6D", 0, 0},
{ XK_Left, ControlMask|Mod1Mask,"\033[1;7D", 0, 0},
{ XK_Left,ShiftMask|ControlMask|Mod1Mask,"\033[1;8D",0, 0},
{ XK_Left, XK_ANY_MOD, "\033[D", 0, -1},
{ XK_Left, XK_ANY_MOD, "\033OD", 0, +1},
{ XK_Right, ShiftMask, "\033[1;2C", 0, 0},
{ XK_Right, Mod1Mask, "\033[1;3C", 0, 0},
{ XK_Right, ShiftMask|Mod1Mask,"\033[1;4C", 0, 0},
{ XK_Right, ControlMask, "\033[1;5C", 0, 0},
{ XK_Right, ShiftMask|ControlMask,"\033[1;6C", 0, 0},
{ XK_Right, ControlMask|Mod1Mask,"\033[1;7C", 0, 0},
{ XK_Right,ShiftMask|ControlMask|Mod1Mask,"\033[1;8C",0, 0},
{ XK_Right, XK_ANY_MOD, "\033[C", 0, -1},
{ XK_Right, XK_ANY_MOD, "\033OC", 0, +1},
{ XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0},
{ XK_Return, Mod1Mask, "\033\r", 0, 0},
{ XK_Return, XK_ANY_MOD, "\r", 0, 0},
{ XK_Insert, ShiftMask, "\033[4l", -1, 0},
{ XK_Insert, ShiftMask, "\033[2;2~", +1, 0},
{ XK_Insert, ControlMask, "\033[L", -1, 0},
{ XK_Insert, ControlMask, "\033[2;5~", +1, 0},
{ XK_Insert, XK_ANY_MOD, "\033[4h", -1, 0},
{ XK_Insert, XK_ANY_MOD, "\033[2~", +1, 0},
{ XK_Delete, ControlMask, "\033[M", -1, 0},
{ XK_Delete, ControlMask, "\033[3;5~", +1, 0},
{ XK_Delete, ShiftMask, "\033[2K", -1, 0},
{ XK_Delete, ShiftMask, "\033[3;2~", +1, 0},
{ XK_Delete, XK_ANY_MOD, "\033[3~", -1, 0},
{ XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0},
{ XK_BackSpace, XK_NO_MOD, "\177", 0, 0},
{ XK_BackSpace, Mod1Mask, "\033\177", 0, 0},
{ XK_Home, ShiftMask, "\033[2J", 0, -1},
{ XK_Home, ShiftMask, "\033[1;2H", 0, +1},
{ XK_Home, XK_ANY_MOD, "\033[H", 0, -1},
{ XK_Home, XK_ANY_MOD, "\033[1~", 0, +1},
{ XK_End, ControlMask, "\033[J", -1, 0},
{ XK_End, ControlMask, "\033[1;5F", +1, 0},
{ XK_End, ShiftMask, "\033[K", -1, 0},
{ XK_End, ShiftMask, "\033[1;2F", +1, 0},
{ XK_End, XK_ANY_MOD, "\033[4~", 0, 0},
{ XK_Prior, ControlMask, "\033[5;5~", 0, 0},
{ XK_Prior, ShiftMask, "\033[5;2~", 0, 0},
{ XK_Prior, XK_ANY_MOD, "\033[5~", 0, 0},
{ XK_Next, ControlMask, "\033[6;5~", 0, 0},
{ XK_Next, ShiftMask, "\033[6;2~", 0, 0},
{ XK_Next, XK_ANY_MOD, "\033[6~", 0, 0},
{ XK_F1, XK_NO_MOD, "\033OP" , 0, 0},
{ XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0},
{ XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0},
{ XK_F1, /* F37 */ Mod4Mask, "\033[1;6P", 0, 0},
{ XK_F1, /* F49 */ Mod1Mask, "\033[1;3P", 0, 0},
{ XK_F1, /* F61 */ Mod3Mask, "\033[1;4P", 0, 0},
{ XK_F2, XK_NO_MOD, "\033OQ" , 0, 0},
{ XK_F2, /* F14 */ ShiftMask, "\033[1;2Q", 0, 0},
{ XK_F2, /* F26 */ ControlMask, "\033[1;5Q", 0, 0},
{ XK_F2, /* F38 */ Mod4Mask, "\033[1;6Q", 0, 0},
{ XK_F2, /* F50 */ Mod1Mask, "\033[1;3Q", 0, 0},
{ XK_F2, /* F62 */ Mod3Mask, "\033[1;4Q", 0, 0},
{ XK_F3, XK_NO_MOD, "\033OR" , 0, 0},
{ XK_F3, /* F15 */ ShiftMask, "\033[1;2R", 0, 0},
{ XK_F3, /* F27 */ ControlMask, "\033[1;5R", 0, 0},
{ XK_F3, /* F39 */ Mod4Mask, "\033[1;6R", 0, 0},
{ XK_F3, /* F51 */ Mod1Mask, "\033[1;3R", 0, 0},
{ XK_F3, /* F63 */ Mod3Mask, "\033[1;4R", 0, 0},
{ XK_F4, XK_NO_MOD, "\033OS" , 0, 0},
{ XK_F4, /* F16 */ ShiftMask, "\033[1;2S", 0, 0},
{ XK_F4, /* F28 */ ControlMask, "\033[1;5S", 0, 0},
{ XK_F4, /* F40 */ Mod4Mask, "\033[1;6S", 0, 0},
{ XK_F4, /* F52 */ Mod1Mask, "\033[1;3S", 0, 0},
{ XK_F5, XK_NO_MOD, "\033[15~", 0, 0},
{ XK_F5, /* F17 */ ShiftMask, "\033[15;2~", 0, 0},
{ XK_F5, /* F29 */ ControlMask, "\033[15;5~", 0, 0},
{ XK_F5, /* F41 */ Mod4Mask, "\033[15;6~", 0, 0},
{ XK_F5, /* F53 */ Mod1Mask, "\033[15;3~", 0, 0},
{ XK_F6, XK_NO_MOD, "\033[17~", 0, 0},
{ XK_F6, /* F18 */ ShiftMask, "\033[17;2~", 0, 0},
{ XK_F6, /* F30 */ ControlMask, "\033[17;5~", 0, 0},
{ XK_F6, /* F42 */ Mod4Mask, "\033[17;6~", 0, 0},
{ XK_F6, /* F54 */ Mod1Mask, "\033[17;3~", 0, 0},
{ XK_F7, XK_NO_MOD, "\033[18~", 0, 0},
{ XK_F7, /* F19 */ ShiftMask, "\033[18;2~", 0, 0},
{ XK_F7, /* F31 */ ControlMask, "\033[18;5~", 0, 0},
{ XK_F7, /* F43 */ Mod4Mask, "\033[18;6~", 0, 0},
{ XK_F7, /* F55 */ Mod1Mask, "\033[18;3~", 0, 0},
{ XK_F8, XK_NO_MOD, "\033[19~", 0, 0},
{ XK_F8, /* F20 */ ShiftMask, "\033[19;2~", 0, 0},
{ XK_F8, /* F32 */ ControlMask, "\033[19;5~", 0, 0},
{ XK_F8, /* F44 */ Mod4Mask, "\033[19;6~", 0, 0},
{ XK_F8, /* F56 */ Mod1Mask, "\033[19;3~", 0, 0},
{ XK_F9, XK_NO_MOD, "\033[20~", 0, 0},
{ XK_F9, /* F21 */ ShiftMask, "\033[20;2~", 0, 0},
{ XK_F9, /* F33 */ ControlMask, "\033[20;5~", 0, 0},
{ XK_F9, /* F45 */ Mod4Mask, "\033[20;6~", 0, 0},
{ XK_F9, /* F57 */ Mod1Mask, "\033[20;3~", 0, 0},
{ XK_F10, XK_NO_MOD, "\033[21~", 0, 0},
{ XK_F10, /* F22 */ ShiftMask, "\033[21;2~", 0, 0},
{ XK_F10, /* F34 */ ControlMask, "\033[21;5~", 0, 0},
{ XK_F10, /* F46 */ Mod4Mask, "\033[21;6~", 0, 0},
{ XK_F10, /* F58 */ Mod1Mask, "\033[21;3~", 0, 0},
{ XK_F11, XK_NO_MOD, "\033[23~", 0, 0},
{ XK_F11, /* F23 */ ShiftMask, "\033[23;2~", 0, 0},
{ XK_F11, /* F35 */ ControlMask, "\033[23;5~", 0, 0},
{ XK_F11, /* F47 */ Mod4Mask, "\033[23;6~", 0, 0},
{ XK_F11, /* F59 */ Mod1Mask, "\033[23;3~", 0, 0},
{ XK_F12, XK_NO_MOD, "\033[24~", 0, 0},
{ XK_F12, /* F24 */ ShiftMask, "\033[24;2~", 0, 0},
{ XK_F12, /* F36 */ ControlMask, "\033[24;5~", 0, 0},
{ XK_F12, /* F48 */ Mod4Mask, "\033[24;6~", 0, 0},
{ XK_F12, /* F60 */ Mod1Mask, "\033[24;3~", 0, 0},
{ XK_F13, XK_NO_MOD, "\033[1;2P", 0, 0},
{ XK_F14, XK_NO_MOD, "\033[1;2Q", 0, 0},
{ XK_F15, XK_NO_MOD, "\033[1;2R", 0, 0},
{ XK_F16, XK_NO_MOD, "\033[1;2S", 0, 0},
{ XK_F17, XK_NO_MOD, "\033[15;2~", 0, 0},
{ XK_F18, XK_NO_MOD, "\033[17;2~", 0, 0},
{ XK_F19, XK_NO_MOD, "\033[18;2~", 0, 0},
{ XK_F20, XK_NO_MOD, "\033[19;2~", 0, 0},
{ XK_F21, XK_NO_MOD, "\033[20;2~", 0, 0},
{ XK_F22, XK_NO_MOD, "\033[21;2~", 0, 0},
{ XK_F23, XK_NO_MOD, "\033[23;2~", 0, 0},
{ XK_F24, XK_NO_MOD, "\033[24;2~", 0, 0},
{ XK_F25, XK_NO_MOD, "\033[1;5P", 0, 0},
{ XK_F26, XK_NO_MOD, "\033[1;5Q", 0, 0},
{ XK_F27, XK_NO_MOD, "\033[1;5R", 0, 0},
{ XK_F28, XK_NO_MOD, "\033[1;5S", 0, 0},
{ XK_F29, XK_NO_MOD, "\033[15;5~", 0, 0},
{ XK_F30, XK_NO_MOD, "\033[17;5~", 0, 0},
{ XK_F31, XK_NO_MOD, "\033[18;5~", 0, 0},
{ XK_F32, XK_NO_MOD, "\033[19;5~", 0, 0},
{ XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0},
{ XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0},
{ XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0},
};
/*
* Selection types' masks.
* Use the same masks as usual.
* Button1Mask is always unset, to make masks match between ButtonPress.
* ButtonRelease and MotionNotify.
* If no match is found, regular selection is used.
*/
static uint selmasks[] = {
[SEL_RECTANGULAR] = Mod1Mask,
};
/*
* Printable characters in ASCII, used to estimate the advance width
* of single wide characters.
*/
static char ascii_printable[] =
" !\"#$%&'()*+,-./0123456789:;<=>?"
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
"`abcdefghijklmnopqrstuvwxyz{|}~";