initial commit
This commit is contained in:
+10
@@ -0,0 +1,10 @@
|
||||
# generated wallpapers should not be committed back
|
||||
wallpapers/*.png
|
||||
wallpapers/*.jpg
|
||||
wallpapers/*.jpeg
|
||||
wallpapers/*.webp
|
||||
!wallpapers/.gitkeep
|
||||
|
||||
*.log
|
||||
*.swp
|
||||
.DS_Store
|
||||
@@ -0,0 +1,273 @@
|
||||
# arch-i3
|
||||
|
||||
A one-shot bootstrap for a complete i3 desktop on a **fresh Arch Linux install** —
|
||||
starting from a system with no X server at all.
|
||||
|
||||
Everything is themed with **Catppuccin Macchiato** and typeset in **Inconsolata Nerd Font**.
|
||||
|
||||
```
|
||||
i3-wm · polybar · rofi · dunst · polkit-gnome · thunar · kitty
|
||||
i3lock-color + betterlockscreen · feh · picom
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick start
|
||||
|
||||
From a TTY on a fresh install, as your **normal user** (not root — the scripts
|
||||
call `sudo` where they need to):
|
||||
|
||||
```sh
|
||||
sudo pacman -S --needed git
|
||||
git clone <this-repo> ~/arch-i3
|
||||
cd ~/arch-i3
|
||||
./install.sh
|
||||
```
|
||||
|
||||
Then log out, log back in (so the new group memberships apply) and:
|
||||
|
||||
```sh
|
||||
startx
|
||||
```
|
||||
|
||||
### Look before you leap
|
||||
|
||||
```sh
|
||||
./install.sh --dry-run # print every action, change nothing
|
||||
./install.sh --list # show the stages
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## What the installer does
|
||||
|
||||
| Stage | Name | What happens |
|
||||
|-------|------|--------------|
|
||||
| `00` | preflight | Verifies Arch + network, enables pacman colour and parallel downloads, refreshes mirrors with `reflector`, runs a full `pacman -Syu` |
|
||||
| `10` | packages | Installs everything in `packages/pacman.txt`; detects your GPU and adds the matching Vulkan/VA-API driver |
|
||||
| `20` | aur | Builds `yay-bin`, swaps `i3lock` → `i3lock-color`, installs `packages/aur.txt` |
|
||||
| `30` | dotfiles | Copies configs into `~`, helper scripts into `~/.local/bin`, generates wallpapers |
|
||||
| `40` | services | Enables NetworkManager/bluetooth/pipewire, adds you to `video input audio storage`, rebuilds the font cache, primes the betterlockscreen cache |
|
||||
| `50` | theme | Applies the GTK/Qt/cursor/icon theme and reloads a running session |
|
||||
|
||||
Run a subset with `--only` / `--skip`, by number or by name:
|
||||
|
||||
```sh
|
||||
./install.sh --only dotfiles,theme
|
||||
./install.sh --skip 00,10 # configs only, no package churn
|
||||
./install.sh -y # never prompt
|
||||
./install.sh --multilib # also enable the [multilib] repo
|
||||
```
|
||||
|
||||
**Re-running is safe.** Package installs use `--needed`, and any config file the
|
||||
installer would overwrite is first *moved* — never deleted — into
|
||||
`~/.config-backup-<timestamp>/`.
|
||||
|
||||
```sh
|
||||
scripts/restore-backup.sh --list # see what's been backed up
|
||||
scripts/restore-backup.sh # put the most recent backup back
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Keybindings
|
||||
|
||||
`$mod` is the **Super** (Windows) key.
|
||||
|
||||
### Launching
|
||||
| Keys | Action |
|
||||
|------|--------|
|
||||
| `$mod + Return` | kitty |
|
||||
| `$mod + Shift + Return` | kitty, floating and centred |
|
||||
| `$mod + e` | Thunar |
|
||||
| `$mod + d` | rofi — application launcher |
|
||||
| `$mod + Shift + d` | rofi — run a binary |
|
||||
| `$mod + Tab` | rofi — window switcher |
|
||||
| `$mod + Shift + e` | power menu (lock / logout / suspend / reboot / shutdown) |
|
||||
| `$mod + q` | close window |
|
||||
| `$mod + Shift + q` | `xkill` — click a window to kill it |
|
||||
|
||||
### Session
|
||||
| Keys | Action |
|
||||
|------|--------|
|
||||
| `$mod + Shift + x` | lock the screen |
|
||||
| `$mod + Shift + c` | reload the i3 config |
|
||||
| `$mod + Shift + r` | restart i3 in place |
|
||||
|
||||
### Focus and movement
|
||||
| Keys | Action |
|
||||
|------|--------|
|
||||
| `$mod + h/j/k/l` or arrows | move focus |
|
||||
| `$mod + Shift + h/j/k/l` | move the window |
|
||||
| `$mod + 1…0` | switch workspace |
|
||||
| `$mod + Shift + 1…0` | send window to workspace |
|
||||
| `Alt + Tab` | last workspace |
|
||||
| `$mod + Ctrl + ←/→` | previous / next workspace |
|
||||
| `$mod + Ctrl + Shift + ←/→` | move the workspace to another monitor |
|
||||
|
||||
### Layout
|
||||
| Keys | Action |
|
||||
|------|--------|
|
||||
| `$mod + b` / `$mod + v` | split horizontally / vertically |
|
||||
| `$mod + f` | fullscreen |
|
||||
| `$mod + s` / `$mod + w` / `$mod + g` | stacking / tabbed / toggle split |
|
||||
| `$mod + Shift + space` | float this window |
|
||||
| `$mod + space` | focus tiling ↔ floating |
|
||||
| `$mod + r` | resize mode (`h/j/k/l`, `Escape` to leave) |
|
||||
| `$mod + minus` / `$mod + Shift + minus` | show / send to scratchpad |
|
||||
| `$mod + plus` / `$mod + Shift + plus` | grow / shrink gaps |
|
||||
|
||||
### Hardware and utilities
|
||||
| Keys | Action |
|
||||
|------|--------|
|
||||
| Volume / brightness / media keys | handled, with a dunst OSD |
|
||||
| `Print` | full-screen screenshot |
|
||||
| `Shift + Print` | select a region |
|
||||
| `$mod + Print` | active window |
|
||||
| `$mod + p` | display mode: `a`uto / `d`uplicate / `e`xtend / `l`aptop-only |
|
||||
| `$mod + n` | pop the last notification back up |
|
||||
| `$mod + Shift + n` | dismiss all notifications |
|
||||
| `$mod + Ctrl + n` | pause/resume notifications |
|
||||
| `$mod + Shift + w` | random wallpaper |
|
||||
|
||||
---
|
||||
|
||||
## Layout of this repo
|
||||
|
||||
```
|
||||
install.sh orchestrator — stage runner, flags, summary
|
||||
packages/
|
||||
pacman.txt official repo packages
|
||||
aur.txt AUR packages
|
||||
scripts/
|
||||
lib.sh logging, dry-run, backup-aware file installer
|
||||
00-preflight.sh … 50-theme.sh
|
||||
make-wallpaper.sh synthesises the Catppuccin wallpapers
|
||||
restore-backup.sh undo
|
||||
dotfiles/
|
||||
xinitrc, xprofile, Xresources, gtkrc-2.0
|
||||
config/ → ~/.config/…
|
||||
i3/config window manager
|
||||
polybar/config.ini bar; launch.sh detects your hardware
|
||||
rofi/ config.rasi + Macchiato themes + powermenu.sh
|
||||
dunst/dunstrc notifications
|
||||
kitty/ kitty.conf + Macchiato colours
|
||||
picom/picom.conf compositor
|
||||
betterlockscreen/ lock screen colours
|
||||
gtk-3.0/, gtk-4.0/, qt5ct/, xfce4/ toolkit theming
|
||||
local/bin/ → ~/.local/bin/…
|
||||
set-wallpaper volume brightness screenshot display restart-daemon
|
||||
wallpapers/ drop your own images here; they win over generated ones
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Things worth knowing
|
||||
|
||||
### `i3lock` becomes `i3lock-color`
|
||||
|
||||
`betterlockscreen` depends on **i3lock-color**, an AUR fork that adds the
|
||||
`--*-color` flags the Macchiato lock screen needs. It *conflicts with* and
|
||||
*provides* the repo `i3lock`, so stage 20 removes the repo package first. You
|
||||
still get an `i3lock` binary at the usual path — it just understands more flags.
|
||||
|
||||
### The lock screen needs a cached image
|
||||
|
||||
`betterlockscreen` pre-renders blurred wallpapers instead of blurring at lock
|
||||
time (that's why it's instant). Stage 40 builds that cache. After changing your
|
||||
wallpaper, refresh it:
|
||||
|
||||
```sh
|
||||
betterlockscreen -u ~/.local/share/wallpapers/your-image.png --blur 0.5
|
||||
```
|
||||
|
||||
`set-wallpaper <path>` does this for you automatically.
|
||||
|
||||
Locking is wired up three ways: `$mod+Shift+x`, `xss-lock` (10-minute idle timer
|
||||
and lid close, started from the i3 config), and a `betterlockscreen@.service`
|
||||
sleep hook for suspends that happen outside the X session.
|
||||
|
||||
### polybar adapts to the machine
|
||||
|
||||
`~/.config/polybar/launch.sh` detects your battery, AC adapter, backlight device
|
||||
and network interfaces at launch and passes them in as environment variables, so
|
||||
`config.ini` has nothing machine-specific in it. Modules with no matching
|
||||
hardware (battery and backlight on a desktop) are dropped from the bar rather
|
||||
than left to log errors. One bar spawns per monitor; the system tray goes on the
|
||||
primary one. Logs land in `~/.cache/polybar.log`.
|
||||
|
||||
### NVIDIA
|
||||
|
||||
Stage 10 installs Mesa and, for Intel/AMD, the matching Vulkan driver. NVIDIA is
|
||||
left to you deliberately — the right package depends on your card's generation
|
||||
and kernel:
|
||||
|
||||
```sh
|
||||
sudo pacman -S nvidia nvidia-utils # current cards, linux kernel
|
||||
sudo pacman -S nvidia-lts nvidia-utils # linux-lts kernel
|
||||
```
|
||||
|
||||
If you get tearing, uncomment nothing — `picom.conf` already sets
|
||||
`backend = "glx"` and `vsync = true`. On a weak GPU, delete the `blur` block.
|
||||
|
||||
### No display manager
|
||||
|
||||
The setup logs in from a TTY with `startx`, which keeps the boot lean. If you'd
|
||||
rather have a greeter:
|
||||
|
||||
```sh
|
||||
sudo pacman -S ly && sudo systemctl enable ly.service # minimal, TUI
|
||||
# or
|
||||
sudo pacman -S lightdm lightdm-gtk-greeter && sudo systemctl enable lightdm
|
||||
```
|
||||
|
||||
Both read `~/.xprofile`, so the environment stays identical either way.
|
||||
|
||||
### Making it yours
|
||||
|
||||
Put personal i3 tweaks in `~/.config/i3/config.d/*.conf`. They're included at the
|
||||
end of the main config, so they override anything above them, and the installer
|
||||
never touches that directory.
|
||||
|
||||
For everything else, edit the files in `dotfiles/` and re-run:
|
||||
|
||||
```sh
|
||||
./install.sh --only dotfiles
|
||||
```
|
||||
|
||||
### Changing the accent colour
|
||||
|
||||
The Catppuccin accent is **mauve** (`#c6a0f6`) throughout. To switch to, say,
|
||||
teal, change it in five places:
|
||||
|
||||
```
|
||||
dotfiles/config/i3/config client.focused
|
||||
dotfiles/config/polybar/config.ini primary = / label-focused-*
|
||||
dotfiles/config/rofi/themes/… selected:
|
||||
dotfiles/config/dunst/dunstrc frame_color / [urgency_normal]
|
||||
dotfiles/config/*/settings.ini catppuccin-macchiato-<accent>-standard+default
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**The bar is missing.** `cat ~/.cache/polybar.log`. The most common cause is a
|
||||
font that didn't install — check with `fc-list | grep -i inconsolata`.
|
||||
|
||||
**Boxes instead of icons.** The Nerd Font glyphs aren't being found. Run
|
||||
`fc-cache -fv`, then confirm `ttf-inconsolata-nerd` and `ttf-nerd-fonts-symbols-mono`
|
||||
are installed.
|
||||
|
||||
**GTK apps look light/wrong.** The AUR theme package may name its accent
|
||||
directory differently. `ls /usr/share/themes | grep -i catppuccin`, then put the
|
||||
exact name into `~/.config/gtk-3.0/settings.ini`. Stage 50 tries to detect and
|
||||
patch this automatically.
|
||||
|
||||
**No sound.** `systemctl --user status pipewire wireplumber`. A reboot after the
|
||||
first install is usually what's missing.
|
||||
|
||||
**Lock screen shows a plain grey box.** The betterlockscreen cache isn't built —
|
||||
run `betterlockscreen -u <image>`.
|
||||
|
||||
**i3 won't start.** `i3 -C` validates the config and prints the offending line.
|
||||
@@ -0,0 +1,64 @@
|
||||
! ==========================================================================
|
||||
! ~/.Xresources — Catppuccin Macchiato for legacy X clients
|
||||
! (xterm, i3lock's fallback rendering, dmenu, urxvt …)
|
||||
! ==========================================================================
|
||||
|
||||
! --- DPI: uncomment and set for HiDPI panels ------------------------------
|
||||
! Xft.dpi: 144
|
||||
|
||||
Xft.antialias: 1
|
||||
Xft.hinting: 1
|
||||
Xft.hintstyle: hintslight
|
||||
Xft.rgba: rgb
|
||||
Xft.lcdfilter: lcddefault
|
||||
Xft.autohint: 0
|
||||
|
||||
! --- cursor ----------------------------------------------------------------
|
||||
Xcursor.theme: catppuccin-macchiato-dark-cursors
|
||||
Xcursor.size: 24
|
||||
|
||||
! --- Catppuccin Macchiato palette -----------------------------------------
|
||||
#define base #24273a
|
||||
#define mantle #1e2030
|
||||
#define crust #181926
|
||||
#define text #cad3f5
|
||||
#define rosewater #f4dbd6
|
||||
#define surface1 #494d64
|
||||
#define surface2 #5b6078
|
||||
#define red #ed8796
|
||||
#define green #a6da95
|
||||
#define yellow #eed49f
|
||||
#define blue #8aadf4
|
||||
#define pink #f5bde6
|
||||
#define teal #8bd5ca
|
||||
#define subtext1 #b8c0e0
|
||||
#define subtext0 #a5adcb
|
||||
|
||||
*.foreground: text
|
||||
*.background: base
|
||||
*.cursorColor: rosewater
|
||||
|
||||
*.color0: surface1
|
||||
*.color8: surface2
|
||||
*.color1: red
|
||||
*.color9: red
|
||||
*.color2: green
|
||||
*.color10: green
|
||||
*.color3: yellow
|
||||
*.color11: yellow
|
||||
*.color4: blue
|
||||
*.color12: blue
|
||||
*.color5: pink
|
||||
*.color13: pink
|
||||
*.color6: teal
|
||||
*.color14: teal
|
||||
*.color7: subtext1
|
||||
*.color15: subtext0
|
||||
|
||||
! --- xterm -----------------------------------------------------------------
|
||||
XTerm*faceName: Inconsolata Nerd Font
|
||||
XTerm*faceSize: 12
|
||||
XTerm*termName: xterm-256color
|
||||
XTerm*selectToClipboard: true
|
||||
XTerm*saveLines: 10000
|
||||
XTerm*scrollBar: false
|
||||
@@ -0,0 +1,50 @@
|
||||
# ===========================================================================
|
||||
# betterlockscreen — Catppuccin Macchiato
|
||||
# All colours are RRGGBBAA (i3lock-color format, no leading '#').
|
||||
# Docs: https://github.com/betterlockscreen/betterlockscreen
|
||||
# ===========================================================================
|
||||
|
||||
# Which cached image variant `betterlockscreen -l` uses when given no argument
|
||||
display_on=0
|
||||
span_image=false
|
||||
|
||||
# --- ring ------------------------------------------------------------------
|
||||
insidecolor=24273a00
|
||||
ringcolor=c6a0f6ff
|
||||
insidevercolor=8aadf41c
|
||||
insidewrongcolor=ed879633
|
||||
ringvercolor=8aadf4ff
|
||||
ringwrongcolor=ed8796ff
|
||||
|
||||
# --- keypress highlight ----------------------------------------------------
|
||||
keyhlcolor=a6da95ff
|
||||
bshlcolor=f5a97fff
|
||||
separatorcolor=00000000
|
||||
|
||||
# --- text ------------------------------------------------------------------
|
||||
verifcolor=cad3f5ff
|
||||
timecolor=cad3f5ff
|
||||
datecolor=a5adcbff
|
||||
layoutcolor=a5adcbff
|
||||
loginbox=24273aaa
|
||||
locktext="Type password to unlock"
|
||||
font="Inconsolata Nerd Font"
|
||||
|
||||
time_format="%H:%M"
|
||||
date_format="%A, %d %B"
|
||||
|
||||
# --- ring geometry ---------------------------------------------------------
|
||||
ring_width=6
|
||||
radius=120
|
||||
|
||||
# --- greeter ---------------------------------------------------------------
|
||||
greetercolor=c6a0f6ff
|
||||
greeter_text="Welcome back, $USER"
|
||||
|
||||
# --- blur strength used by `betterlockscreen -u <img> --blur <n>` ----------
|
||||
blur_level=1
|
||||
|
||||
# --- behaviour -------------------------------------------------------------
|
||||
# Show the failed-attempt count and blank the screen after 60s of lock idle
|
||||
lock_timeout=60
|
||||
quiet=true
|
||||
@@ -0,0 +1,127 @@
|
||||
# ===========================================================================
|
||||
# dunst — Catppuccin Macchiato
|
||||
# Font: Inconsolata Nerd Font
|
||||
# Docs: man 5 dunst
|
||||
# ===========================================================================
|
||||
|
||||
[global]
|
||||
monitor = 0
|
||||
follow = mouse
|
||||
|
||||
# --- geometry ---------------------------------------------------------
|
||||
width = (280, 440)
|
||||
height = (0, 300)
|
||||
origin = top-right
|
||||
offset = (12, 42) # 42 clears the 30pt polybar
|
||||
scale = 0
|
||||
notification_limit = 6
|
||||
|
||||
progress_bar = true
|
||||
progress_bar_height = 8
|
||||
progress_bar_frame_width = 0
|
||||
progress_bar_min_width = 150
|
||||
progress_bar_max_width = 400
|
||||
progress_bar_corner_radius = 4
|
||||
|
||||
indicate_hidden = yes
|
||||
transparency = 5
|
||||
separator_height = 4
|
||||
padding = 12
|
||||
horizontal_padding = 14
|
||||
text_icon_padding = 10
|
||||
frame_width = 2
|
||||
frame_color = "#c6a0f6"
|
||||
gap_size = 6
|
||||
separator_color = frame
|
||||
sort = yes
|
||||
corner_radius = 10
|
||||
|
||||
# --- text -------------------------------------------------------------
|
||||
font = Inconsolata Nerd Font 11
|
||||
line_height = 0
|
||||
markup = full
|
||||
format = "<b>%s</b>\n%b"
|
||||
alignment = left
|
||||
vertical_alignment = center
|
||||
show_age_threshold = 60
|
||||
ellipsize = middle
|
||||
ignore_newline = no
|
||||
stack_duplicates = true
|
||||
hide_duplicate_count = false
|
||||
show_indicators = yes
|
||||
|
||||
# --- icons ------------------------------------------------------------
|
||||
enable_recursive_icon_lookup = true
|
||||
icon_theme = "Papirus-Dark, Adwaita"
|
||||
icon_position = left
|
||||
min_icon_size = 32
|
||||
max_icon_size = 64
|
||||
|
||||
# --- history ----------------------------------------------------------
|
||||
sticky_history = yes
|
||||
history_length = 25
|
||||
|
||||
# --- misc -------------------------------------------------------------
|
||||
dmenu = /usr/bin/rofi -dmenu -p dunst
|
||||
browser = /usr/bin/xdg-open
|
||||
always_run_script = true
|
||||
title = Dunst
|
||||
class = Dunst
|
||||
ignore_dbusclose = false
|
||||
|
||||
# --- wayland (unused under i3, harmless) -------------------------------
|
||||
force_xwayland = false
|
||||
|
||||
# --- mouse ------------------------------------------------------------
|
||||
mouse_left_click = do_action, close_current
|
||||
mouse_middle_click = close_all
|
||||
mouse_right_click = close_current
|
||||
|
||||
[experimental]
|
||||
per_monitor_dpi = false
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Urgency styling
|
||||
# ---------------------------------------------------------------------------
|
||||
[urgency_low]
|
||||
background = "#24273a"
|
||||
foreground = "#a5adcb"
|
||||
frame_color = "#8bd5ca"
|
||||
highlight = "#8bd5ca"
|
||||
timeout = 5
|
||||
|
||||
[urgency_normal]
|
||||
background = "#24273a"
|
||||
foreground = "#cad3f5"
|
||||
frame_color = "#c6a0f6"
|
||||
highlight = "#c6a0f6"
|
||||
timeout = 8
|
||||
|
||||
[urgency_critical]
|
||||
background = "#24273a"
|
||||
foreground = "#cad3f5"
|
||||
frame_color = "#ed8796"
|
||||
highlight = "#ed8796"
|
||||
timeout = 0
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Rules
|
||||
# ---------------------------------------------------------------------------
|
||||
# Volume / brightness OSD: replace in place instead of stacking up.
|
||||
[osd]
|
||||
appname = "osd"
|
||||
format = "<b>%s</b>\n%b"
|
||||
timeout = 2
|
||||
history_ignore = yes
|
||||
urgency = low
|
||||
|
||||
# Screenshot notifications get a longer read and a click-to-open action.
|
||||
[screenshot]
|
||||
appname = "screenshot"
|
||||
timeout = 6
|
||||
urgency = normal
|
||||
|
||||
# Battery warnings should never disappear on their own.
|
||||
[battery-critical]
|
||||
appname = "battery"
|
||||
urgency = critical
|
||||
@@ -0,0 +1,17 @@
|
||||
[Settings]
|
||||
gtk-theme-name=catppuccin-macchiato-mauve-standard+default
|
||||
gtk-icon-theme-name=Papirus-Dark
|
||||
gtk-cursor-theme-name=catppuccin-macchiato-dark-cursors
|
||||
gtk-cursor-theme-size=24
|
||||
gtk-font-name=Inconsolata Nerd Font 11
|
||||
gtk-application-prefer-dark-theme=1
|
||||
gtk-enable-animations=1
|
||||
gtk-primary-button-warps-slider=1
|
||||
gtk-toolbar-style=GTK_TOOLBAR_ICONS
|
||||
gtk-menu-images=1
|
||||
gtk-button-images=1
|
||||
gtk-decoration-layout=appmenu:none
|
||||
gtk-xft-antialias=1
|
||||
gtk-xft-hinting=1
|
||||
gtk-xft-hintstyle=hintslight
|
||||
gtk-xft-rgba=rgb
|
||||
@@ -0,0 +1,11 @@
|
||||
[Settings]
|
||||
gtk-theme-name=catppuccin-macchiato-mauve-standard+default
|
||||
gtk-icon-theme-name=Papirus-Dark
|
||||
gtk-cursor-theme-name=catppuccin-macchiato-dark-cursors
|
||||
gtk-cursor-theme-size=24
|
||||
gtk-font-name=Inconsolata Nerd Font 11
|
||||
gtk-application-prefer-dark-theme=1
|
||||
gtk-xft-antialias=1
|
||||
gtk-xft-hinting=1
|
||||
gtk-xft-hintstyle=hintslight
|
||||
gtk-xft-rgba=rgb
|
||||
@@ -0,0 +1,333 @@
|
||||
# ===========================================================================
|
||||
# i3 window manager — Catppuccin Macchiato
|
||||
# Font: Inconsolata Nerd Font
|
||||
# Docs: https://i3wm.org/docs/userguide.html
|
||||
# ===========================================================================
|
||||
|
||||
set $mod Mod4
|
||||
set $alt Mod1
|
||||
|
||||
# --- Catppuccin Macchiato palette -----------------------------------------
|
||||
set $rosewater #f4dbd6
|
||||
set $flamingo #f0c6c6
|
||||
set $pink #f5bde6
|
||||
set $mauve #c6a0f6
|
||||
set $red #ed8796
|
||||
set $maroon #ee99a0
|
||||
set $peach #f5a97f
|
||||
set $yellow #eed49f
|
||||
set $green #a6da95
|
||||
set $teal #8bd5ca
|
||||
set $sky #91d7e3
|
||||
set $sapphire #7dc4e4
|
||||
set $blue #8aadf4
|
||||
set $lavender #b7bdf8
|
||||
set $text #cad3f5
|
||||
set $subtext1 #b8c0e0
|
||||
set $subtext0 #a5adcb
|
||||
set $overlay2 #939ab7
|
||||
set $overlay1 #8087a2
|
||||
set $overlay0 #6e738d
|
||||
set $surface2 #5b6078
|
||||
set $surface1 #494d64
|
||||
set $surface0 #363a4f
|
||||
set $base #24273a
|
||||
set $mantle #1e2030
|
||||
set $crust #181926
|
||||
|
||||
# --- fonts -----------------------------------------------------------------
|
||||
font pango:Inconsolata Nerd Font 11
|
||||
|
||||
# --- applications ----------------------------------------------------------
|
||||
set $term kitty
|
||||
set $filemanager thunar
|
||||
set $menu rofi -show drun
|
||||
set $window_menu rofi -show window
|
||||
set $runner rofi -show run
|
||||
set $powermenu ~/.config/rofi/scripts/powermenu.sh
|
||||
set $lock betterlockscreen --lock dimblur
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Appearance
|
||||
# ---------------------------------------------------------------------------
|
||||
# class border backgr. text indicator child_border
|
||||
client.focused $mauve $mauve $crust $lavender $mauve
|
||||
client.focused_inactive $surface0 $surface0 $text $surface0 $surface0
|
||||
client.unfocused $surface0 $base $subtext0 $surface0 $surface0
|
||||
client.urgent $red $red $crust $red $red
|
||||
client.placeholder $base $base $text $base $base
|
||||
client.background $base
|
||||
|
||||
# Gaps + borders (i3 >= 4.22 has gaps built in)
|
||||
default_border pixel 2
|
||||
default_floating_border pixel 2
|
||||
hide_edge_borders smart
|
||||
gaps inner 8
|
||||
gaps outer 4
|
||||
smart_gaps on
|
||||
smart_borders on
|
||||
|
||||
# Focus behaviour
|
||||
focus_follows_mouse no
|
||||
mouse_warping none
|
||||
focus_on_window_activation smart
|
||||
popup_during_fullscreen smart
|
||||
workspace_auto_back_and_forth yes
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Autostart
|
||||
# ---------------------------------------------------------------------------
|
||||
# exec_always => re-run on config reload; exec => only on i3 start.
|
||||
|
||||
# Wallpaper (feh restores whatever set-wallpaper.sh last applied)
|
||||
exec_always --no-startup-id ~/.local/bin/set-wallpaper
|
||||
|
||||
# Compositor
|
||||
exec_always --no-startup-id ~/.local/bin/restart-daemon picom
|
||||
|
||||
# Status bar
|
||||
exec_always --no-startup-id ~/.config/polybar/launch.sh
|
||||
|
||||
# Notification daemon
|
||||
exec_always --no-startup-id ~/.local/bin/restart-daemon dunst
|
||||
|
||||
# XDG autostart entries (nm-applet etc. that ship .desktop files)
|
||||
exec --no-startup-id dex --autostart --environment i3
|
||||
|
||||
# PolicyKit authentication agent (GUI password prompts for gparted, etc.)
|
||||
exec --no-startup-id /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1
|
||||
|
||||
# Tray applets
|
||||
exec --no-startup-id nm-applet
|
||||
exec --no-startup-id blueman-applet
|
||||
exec --no-startup-id udiskie --tray --no-automount --notify
|
||||
|
||||
# Auto-lock: lock on suspend and after 10 min of idle time
|
||||
exec --no-startup-id xss-lock --transfer-sleep-lock -- $lock --nofork
|
||||
exec --no-startup-id xset s 600 600
|
||||
exec --no-startup-id numlockx on
|
||||
|
||||
# Cursor theme for the root window
|
||||
exec_always --no-startup-id xsetroot -cursor_name left_ptr
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Key bindings — launching
|
||||
# ---------------------------------------------------------------------------
|
||||
bindsym $mod+Return exec --no-startup-id $term
|
||||
bindsym $mod+Shift+Return exec --no-startup-id $term --class kitty-float
|
||||
bindsym $mod+e exec --no-startup-id $filemanager
|
||||
bindsym $mod+d exec --no-startup-id $menu
|
||||
bindsym $mod+Shift+d exec --no-startup-id $runner
|
||||
bindsym $mod+Tab exec --no-startup-id $window_menu
|
||||
bindsym $mod+Shift+e exec --no-startup-id $powermenu
|
||||
bindsym $mod+q kill
|
||||
bindsym $mod+Shift+q exec --no-startup-id xkill
|
||||
|
||||
# Lock / session
|
||||
bindsym $mod+Shift+x exec --no-startup-id $lock
|
||||
bindsym $mod+Shift+c reload
|
||||
bindsym $mod+Shift+r restart
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Key bindings — focus & movement
|
||||
# ---------------------------------------------------------------------------
|
||||
# vim keys …
|
||||
bindsym $mod+h focus left
|
||||
bindsym $mod+j focus down
|
||||
bindsym $mod+k focus up
|
||||
bindsym $mod+l focus right
|
||||
# … and arrows
|
||||
bindsym $mod+Left focus left
|
||||
bindsym $mod+Down focus down
|
||||
bindsym $mod+Up focus up
|
||||
bindsym $mod+Right focus right
|
||||
|
||||
bindsym $mod+Shift+h move left
|
||||
bindsym $mod+Shift+j move down
|
||||
bindsym $mod+Shift+k move up
|
||||
bindsym $mod+Shift+l move right
|
||||
bindsym $mod+Shift+Left move left
|
||||
bindsym $mod+Shift+Down move down
|
||||
bindsym $mod+Shift+Up move up
|
||||
bindsym $mod+Shift+Right move right
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Key bindings — layout
|
||||
# ---------------------------------------------------------------------------
|
||||
bindsym $mod+b split h
|
||||
bindsym $mod+v split v
|
||||
bindsym $mod+f fullscreen toggle
|
||||
bindsym $mod+s layout stacking
|
||||
bindsym $mod+w layout tabbed
|
||||
bindsym $mod+g layout toggle split
|
||||
bindsym $mod+Shift+space floating toggle
|
||||
bindsym $mod+space focus mode_toggle
|
||||
bindsym $mod+a focus parent
|
||||
bindsym $mod+Shift+a focus child
|
||||
bindsym $mod+minus scratchpad show
|
||||
bindsym $mod+Shift+minus move scratchpad
|
||||
|
||||
# Gap tweaks on the fly
|
||||
bindsym $mod+plus gaps inner current plus 4
|
||||
bindsym $mod+Shift+plus gaps inner current minus 4
|
||||
bindsym $mod+Shift+g gaps inner current set 8; gaps outer current set 4
|
||||
|
||||
# Drag floating windows with the modifier held
|
||||
floating_modifier $mod
|
||||
tiling_drag modifier titlebar
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Workspaces
|
||||
# ---------------------------------------------------------------------------
|
||||
set $ws1 "1: "
|
||||
set $ws2 "2: "
|
||||
set $ws3 "3: "
|
||||
set $ws4 "4: "
|
||||
set $ws5 "5: "
|
||||
set $ws6 "6: "
|
||||
set $ws7 "7: "
|
||||
set $ws8 "8: "
|
||||
set $ws9 "9: "
|
||||
set $ws10 "10: "
|
||||
|
||||
bindsym $mod+1 workspace number $ws1
|
||||
bindsym $mod+2 workspace number $ws2
|
||||
bindsym $mod+3 workspace number $ws3
|
||||
bindsym $mod+4 workspace number $ws4
|
||||
bindsym $mod+5 workspace number $ws5
|
||||
bindsym $mod+6 workspace number $ws6
|
||||
bindsym $mod+7 workspace number $ws7
|
||||
bindsym $mod+8 workspace number $ws8
|
||||
bindsym $mod+9 workspace number $ws9
|
||||
bindsym $mod+0 workspace number $ws10
|
||||
|
||||
bindsym $mod+Shift+1 move container to workspace number $ws1
|
||||
bindsym $mod+Shift+2 move container to workspace number $ws2
|
||||
bindsym $mod+Shift+3 move container to workspace number $ws3
|
||||
bindsym $mod+Shift+4 move container to workspace number $ws4
|
||||
bindsym $mod+Shift+5 move container to workspace number $ws5
|
||||
bindsym $mod+Shift+6 move container to workspace number $ws6
|
||||
bindsym $mod+Shift+7 move container to workspace number $ws7
|
||||
bindsym $mod+Shift+8 move container to workspace number $ws8
|
||||
bindsym $mod+Shift+9 move container to workspace number $ws9
|
||||
bindsym $mod+Shift+0 move container to workspace number $ws10
|
||||
|
||||
# Cycle workspaces
|
||||
bindsym $mod+Ctrl+Right workspace next
|
||||
bindsym $mod+Ctrl+Left workspace prev
|
||||
bindsym $alt+Tab workspace back_and_forth
|
||||
|
||||
# Move workspace between monitors
|
||||
bindsym $mod+Ctrl+Shift+Right move workspace to output right
|
||||
bindsym $mod+Ctrl+Shift+Left move workspace to output left
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Media / hardware keys
|
||||
# ---------------------------------------------------------------------------
|
||||
bindsym XF86AudioRaiseVolume exec --no-startup-id ~/.local/bin/volume up
|
||||
bindsym XF86AudioLowerVolume exec --no-startup-id ~/.local/bin/volume down
|
||||
bindsym XF86AudioMute exec --no-startup-id ~/.local/bin/volume mute
|
||||
bindsym XF86AudioMicMute exec --no-startup-id ~/.local/bin/volume micmute
|
||||
bindsym XF86AudioPlay exec --no-startup-id playerctl play-pause
|
||||
bindsym XF86AudioNext exec --no-startup-id playerctl next
|
||||
bindsym XF86AudioPrev exec --no-startup-id playerctl previous
|
||||
bindsym XF86MonBrightnessUp exec --no-startup-id ~/.local/bin/brightness up
|
||||
bindsym XF86MonBrightnessDown exec --no-startup-id ~/.local/bin/brightness down
|
||||
|
||||
# Screenshots (maim)
|
||||
bindsym Print exec --no-startup-id ~/.local/bin/screenshot full
|
||||
bindsym Shift+Print exec --no-startup-id ~/.local/bin/screenshot area
|
||||
bindsym $mod+Print exec --no-startup-id ~/.local/bin/screenshot window
|
||||
|
||||
# Notification control
|
||||
bindsym $mod+n exec --no-startup-id dunstctl history-pop
|
||||
bindsym $mod+Shift+n exec --no-startup-id dunstctl close-all
|
||||
bindsym $mod+Ctrl+n exec --no-startup-id dunstctl set-paused toggle
|
||||
|
||||
# Wallpaper shuffle
|
||||
bindsym $mod+Shift+w exec --no-startup-id ~/.local/bin/set-wallpaper --random
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Modes
|
||||
# ---------------------------------------------------------------------------
|
||||
mode "resize" {
|
||||
bindsym h resize shrink width 4 px or 4 ppt
|
||||
bindsym j resize grow height 4 px or 4 ppt
|
||||
bindsym k resize shrink height 4 px or 4 ppt
|
||||
bindsym l resize grow width 4 px or 4 ppt
|
||||
|
||||
bindsym Left resize shrink width 4 px or 4 ppt
|
||||
bindsym Down resize grow height 4 px or 4 ppt
|
||||
bindsym Up resize shrink height 4 px or 4 ppt
|
||||
bindsym Right resize grow width 4 px or 4 ppt
|
||||
|
||||
bindsym Return mode "default"
|
||||
bindsym Escape mode "default"
|
||||
bindsym $mod+r mode "default"
|
||||
}
|
||||
bindsym $mod+r mode "resize"
|
||||
|
||||
set $mode_display Display: [a]uto [d]uplicate [e]xtend-right [l]aptop-only
|
||||
mode "$mode_display" {
|
||||
bindsym a exec --no-startup-id "~/.local/bin/display auto", mode "default"
|
||||
bindsym d exec --no-startup-id "~/.local/bin/display duplicate", mode "default"
|
||||
bindsym e exec --no-startup-id "~/.local/bin/display extend", mode "default"
|
||||
bindsym l exec --no-startup-id "~/.local/bin/display internal", mode "default"
|
||||
bindsym Return mode "default"
|
||||
bindsym Escape mode "default"
|
||||
}
|
||||
bindsym $mod+p mode "$mode_display"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Window rules
|
||||
# ---------------------------------------------------------------------------
|
||||
for_window [class="^.*"] title_format "<span foreground='#cad3f5'>%title</span>"
|
||||
|
||||
# Float dialogs and small utilities
|
||||
for_window [window_role="pop-up"] floating enable
|
||||
for_window [window_role="bubble"] floating enable
|
||||
for_window [window_role="dialog"] floating enable
|
||||
for_window [window_type="dialog"] floating enable
|
||||
for_window [window_type="menu"] floating enable
|
||||
for_window [window_type="utility"] floating enable
|
||||
for_window [window_type="toolbar"] floating enable
|
||||
for_window [window_type="splash"] floating enable
|
||||
|
||||
for_window [class="Pavucontrol"] floating enable, resize set 900 600, move position center
|
||||
for_window [class="Blueman-manager"] floating enable, resize set 800 560, move position center
|
||||
for_window [class="Nm-connection-editor"] floating enable, resize set 800 560, move position center
|
||||
for_window [class="Lxappearance"] floating enable, move position center
|
||||
for_window [class="Thunar" instance="^dialog$"] floating enable
|
||||
for_window [class="File-roller"] floating enable, move position center
|
||||
for_window [class="Xarchiver"] floating enable, move position center
|
||||
for_window [class="kitty-float"] floating enable, resize set 1000 620, move position center
|
||||
for_window [title="^Picture-in-Picture$"] floating enable, sticky enable, resize set 640 360, move position 1250 700
|
||||
|
||||
# Assign apps to workspaces
|
||||
assign [class="(?i)firefox|chromium|Brave-browser"] $ws2
|
||||
assign [class="Thunar"] $ws4
|
||||
|
||||
# No focus stealing from these
|
||||
no_focus [class="Steam"]
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# i3bar — disabled; polybar handles the status bar.
|
||||
# Kept as a commented fallback in case polybar ever fails to start.
|
||||
# ---------------------------------------------------------------------------
|
||||
# bar {
|
||||
# status_command i3status
|
||||
# colors {
|
||||
# background $base
|
||||
# statusline $text
|
||||
# focused_workspace $mauve $mauve $crust
|
||||
# active_workspace $surface0 $surface0 $text
|
||||
# inactive_workspace $base $base $subtext0
|
||||
# urgent_workspace $red $red $crust
|
||||
# }
|
||||
# }
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Local overrides — anything in this directory wins, and it is never
|
||||
# overwritten by the bootstrap script.
|
||||
# ---------------------------------------------------------------------------
|
||||
include ~/.config/i3/config.d/*.conf
|
||||
@@ -0,0 +1,117 @@
|
||||
# ===========================================================================
|
||||
# kitty — Catppuccin Macchiato
|
||||
# Font: Inconsolata Nerd Font
|
||||
# Docs: https://sw.kovidgoyal.net/kitty/conf/
|
||||
# ===========================================================================
|
||||
|
||||
# --- font ------------------------------------------------------------------
|
||||
font_family Inconsolata Nerd Font
|
||||
bold_font Inconsolata Nerd Font Bold
|
||||
italic_font auto
|
||||
bold_italic_font auto
|
||||
font_size 12.0
|
||||
|
||||
# Inconsolata is a touch tight vertically; give the lines a little air.
|
||||
adjust_line_height 110%
|
||||
adjust_column_width 0
|
||||
disable_ligatures never
|
||||
|
||||
# Fall back to the symbol font for glyphs Inconsolata Nerd Font lacks
|
||||
symbol_map U+E000-U+E00A,U+EA60-U+EBEB,U+E0A0-U+E0C8,U+E0CA,U+E0CC-U+E0D7,U+E200-U+E2A9,U+E300-U+E3E3,U+E5FA-U+E6B1,U+E700-U+E7C5,U+F000-U+F2FF,U+F300-U+F375,U+F400-U+F533,U+F0001-U+F1AF0 Symbols Nerd Font Mono
|
||||
|
||||
# --- cursor ----------------------------------------------------------------
|
||||
cursor_shape beam
|
||||
cursor_beam_thickness 1.6
|
||||
cursor_blink_interval -1
|
||||
cursor_stop_blinking_after 15.0
|
||||
|
||||
# --- scrollback ------------------------------------------------------------
|
||||
scrollback_lines 10000
|
||||
scrollback_pager less --chop-long-lines --RAW-CONTROL-CHARS +INPUT_LINE_NUMBER
|
||||
wheel_scroll_multiplier 3.0
|
||||
|
||||
# --- mouse -----------------------------------------------------------------
|
||||
mouse_hide_wait 2.0
|
||||
url_color #8aadf4
|
||||
url_style curly
|
||||
open_url_with default
|
||||
detect_urls yes
|
||||
copy_on_select no
|
||||
strip_trailing_spaces smart
|
||||
focus_follows_mouse no
|
||||
|
||||
# --- performance -----------------------------------------------------------
|
||||
repaint_delay 8
|
||||
input_delay 2
|
||||
sync_to_monitor yes
|
||||
|
||||
# --- bell ------------------------------------------------------------------
|
||||
enable_audio_bell no
|
||||
visual_bell_duration 0.0
|
||||
window_alert_on_bell yes
|
||||
bell_on_tab " "
|
||||
|
||||
# --- window ----------------------------------------------------------------
|
||||
remember_window_size no
|
||||
initial_window_width 110c
|
||||
initial_window_height 30c
|
||||
window_padding_width 10
|
||||
window_margin_width 0
|
||||
placement_strategy center
|
||||
hide_window_decorations yes
|
||||
confirm_os_window_close 0
|
||||
|
||||
# --- tabs ------------------------------------------------------------------
|
||||
tab_bar_edge bottom
|
||||
tab_bar_style powerline
|
||||
tab_powerline_style slanted
|
||||
tab_bar_min_tabs 2
|
||||
tab_title_template "{index}: {title}"
|
||||
active_tab_font_style bold
|
||||
inactive_tab_font_style normal
|
||||
|
||||
# --- layouts ---------------------------------------------------------------
|
||||
enabled_layouts splits,stack,tall,fat,grid
|
||||
# i3 does the tiling; kitty splits are here for the occasional full-screen use.
|
||||
|
||||
# --- misc ------------------------------------------------------------------
|
||||
shell .
|
||||
editor .
|
||||
allow_remote_control yes
|
||||
listen_on unix:@kitty
|
||||
term xterm-kitty
|
||||
update_check_interval 0
|
||||
clipboard_control write-clipboard write-primary read-clipboard read-primary
|
||||
|
||||
# ===========================================================================
|
||||
# Keybindings
|
||||
# ===========================================================================
|
||||
kitty_mod ctrl+shift
|
||||
|
||||
map kitty_mod+c copy_to_clipboard
|
||||
map kitty_mod+v paste_from_clipboard
|
||||
map kitty_mod+t new_tab_with_cwd
|
||||
map kitty_mod+w close_tab
|
||||
map kitty_mod+right next_tab
|
||||
map kitty_mod+left previous_tab
|
||||
map kitty_mod+n new_os_window_with_cwd
|
||||
|
||||
map kitty_mod+enter launch --location=split --cwd=current
|
||||
map kitty_mod+h neighboring_window left
|
||||
map kitty_mod+j neighboring_window down
|
||||
map kitty_mod+k neighboring_window up
|
||||
map kitty_mod+l neighboring_window right
|
||||
|
||||
map kitty_mod+equal change_font_size all +1.0
|
||||
map kitty_mod+minus change_font_size all -1.0
|
||||
map kitty_mod+backspace change_font_size all 0
|
||||
|
||||
map kitty_mod+f show_scrollback
|
||||
map kitty_mod+u scroll_page_up
|
||||
map kitty_mod+d scroll_page_down
|
||||
map kitty_mod+e open_url_with_hints
|
||||
|
||||
# ===========================================================================
|
||||
# Colours
|
||||
# ===========================================================================
|
||||
include themes/catppuccin-macchiato.conf
|
||||
@@ -0,0 +1,76 @@
|
||||
# vim:ft=kitty
|
||||
## name: Catppuccin Kitty Macchiato
|
||||
## author: Catppuccin Org
|
||||
## license: MIT
|
||||
## upstream: https://github.com/catppuccin/kitty
|
||||
|
||||
# The basic colors
|
||||
foreground #CAD3F5
|
||||
background #24273A
|
||||
selection_foreground #24273A
|
||||
selection_background #F4DBD6
|
||||
|
||||
# Cursor colors
|
||||
cursor #F4DBD6
|
||||
cursor_text_color #24273A
|
||||
|
||||
# URL underline color when hovering with mouse
|
||||
url_color #F4DBD6
|
||||
|
||||
# Kitty window border colors
|
||||
active_border_color #B7BDF8
|
||||
inactive_border_color #6E738D
|
||||
bell_border_color #EED49F
|
||||
|
||||
# OS Window titlebar colors
|
||||
wayland_titlebar_color system
|
||||
macos_titlebar_color system
|
||||
|
||||
# Tab bar colors
|
||||
active_tab_foreground #181926
|
||||
active_tab_background #C6A0F6
|
||||
inactive_tab_foreground #CAD3F5
|
||||
inactive_tab_background #1E2030
|
||||
tab_bar_background #181926
|
||||
|
||||
# Colors for marks (marked text in the terminal)
|
||||
mark1_foreground #24273A
|
||||
mark1_background #B7BDF8
|
||||
mark2_foreground #24273A
|
||||
mark2_background #C6A0F6
|
||||
mark3_foreground #24273A
|
||||
mark3_background #7DC4E4
|
||||
|
||||
# The 16 terminal colors
|
||||
|
||||
# black
|
||||
color0 #494D64
|
||||
color8 #5B6078
|
||||
|
||||
# red
|
||||
color1 #ED8796
|
||||
color9 #ED8796
|
||||
|
||||
# green
|
||||
color2 #A6DA95
|
||||
color10 #A6DA95
|
||||
|
||||
# yellow
|
||||
color3 #EED49F
|
||||
color11 #EED49F
|
||||
|
||||
# blue
|
||||
color4 #8AADF4
|
||||
color12 #8AADF4
|
||||
|
||||
# magenta
|
||||
color5 #F5BDE6
|
||||
color13 #F5BDE6
|
||||
|
||||
# cyan
|
||||
color6 #8BD5CA
|
||||
color14 #8BD5CA
|
||||
|
||||
# white
|
||||
color7 #B8C0E0
|
||||
color15 #A5ADCB
|
||||
@@ -0,0 +1,108 @@
|
||||
# ===========================================================================
|
||||
# picom — compositor
|
||||
# Tuned to be subtle: no wobbly nonsense, just tear-free rendering,
|
||||
# soft shadows and a hint of transparency on unfocused terminals.
|
||||
# Docs: man 5 picom
|
||||
# ===========================================================================
|
||||
|
||||
# --- backend ---------------------------------------------------------------
|
||||
backend = "glx";
|
||||
vsync = true;
|
||||
use-damage = true;
|
||||
|
||||
glx-no-stencil = true;
|
||||
glx-no-rebind-pixmap = false;
|
||||
|
||||
# --- shadows ---------------------------------------------------------------
|
||||
shadow = true;
|
||||
shadow-radius = 14;
|
||||
shadow-opacity = 0.45;
|
||||
shadow-offset-x = -14;
|
||||
shadow-offset-y = -12;
|
||||
shadow-color = "#181926";
|
||||
|
||||
shadow-exclude = [
|
||||
"name = 'Notification'",
|
||||
"class_g = 'Conky'",
|
||||
"class_g ?= 'Notify-osd'",
|
||||
"class_g = 'Cairo-clock'",
|
||||
"class_g = 'Polybar'",
|
||||
"class_g = 'i3-frame'",
|
||||
"_GTK_FRAME_EXTENTS@:c",
|
||||
"window_type = 'dock'",
|
||||
"window_type = 'desktop'"
|
||||
];
|
||||
|
||||
# --- fading ----------------------------------------------------------------
|
||||
fading = true;
|
||||
fade-in-step = 0.06;
|
||||
fade-out-step = 0.06;
|
||||
fade-delta = 6;
|
||||
fade-exclude = [];
|
||||
|
||||
# --- transparency ----------------------------------------------------------
|
||||
inactive-opacity = 0.94;
|
||||
active-opacity = 1.0;
|
||||
frame-opacity = 1.0;
|
||||
inactive-opacity-override = false;
|
||||
inactive-dim = 0.0;
|
||||
|
||||
opacity-rule = [
|
||||
"100:class_g = 'firefox'",
|
||||
"100:class_g = 'Chromium'",
|
||||
"100:class_g = 'mpv'",
|
||||
"100:fullscreen",
|
||||
"95:class_g = 'kitty' && focused",
|
||||
"88:class_g = 'kitty' && !focused",
|
||||
"95:class_g = 'Rofi'",
|
||||
"100:class_g = 'Polybar'",
|
||||
"100:class_g = 'Dunst'"
|
||||
];
|
||||
|
||||
# --- corners (picom 9+) ----------------------------------------------------
|
||||
corner-radius = 10;
|
||||
rounded-corners-exclude = [
|
||||
"window_type = 'dock'",
|
||||
"window_type = 'desktop'",
|
||||
"class_g = 'Polybar'",
|
||||
"class_g = 'i3-frame'"
|
||||
];
|
||||
|
||||
# --- blur (comment out on weak GPUs) ---------------------------------------
|
||||
blur: {
|
||||
method = "dual_kawase";
|
||||
strength = 4;
|
||||
background = false;
|
||||
background-frame = false;
|
||||
background-fixed = false;
|
||||
}
|
||||
|
||||
blur-background-exclude = [
|
||||
"window_type = 'dock'",
|
||||
"window_type = 'desktop'",
|
||||
"class_g = 'Polybar'",
|
||||
"_GTK_FRAME_EXTENTS@:c"
|
||||
];
|
||||
|
||||
# --- general ---------------------------------------------------------------
|
||||
mark-wmwin-focused = true;
|
||||
mark-ovredir-focused = true;
|
||||
detect-rounded-corners = true;
|
||||
detect-client-opacity = true;
|
||||
detect-transient = true;
|
||||
detect-client-leader = true;
|
||||
use-ewmh-active-win = true;
|
||||
unredir-if-possible = false;
|
||||
dbe = false;
|
||||
log-level = "warn";
|
||||
|
||||
wintypes:
|
||||
{
|
||||
tooltip = { fade = true; shadow = true; opacity = 0.95; focus = true; full-shadow = false; };
|
||||
dock = { shadow = false; clip-shadow-above = true; };
|
||||
dnd = { shadow = false; };
|
||||
popup_menu = { opacity = 0.98; shadow = true; };
|
||||
dropdown_menu= { opacity = 0.98; shadow = true; };
|
||||
utility = { shadow = false; };
|
||||
notification = { shadow = true; };
|
||||
};
|
||||
@@ -0,0 +1,318 @@
|
||||
; ==========================================================================
|
||||
; polybar — Catppuccin Macchiato
|
||||
; Font: Inconsolata Nerd Font
|
||||
; Docs: https://github.com/polybar/polybar/wiki
|
||||
;
|
||||
; Hardware-specific values (battery, adapter, network interfaces, backlight)
|
||||
; are injected as environment variables by launch.sh, with sane fallbacks.
|
||||
; ==========================================================================
|
||||
|
||||
[colors]
|
||||
rosewater = #f4dbd6
|
||||
flamingo = #f0c6c6
|
||||
pink = #f5bde6
|
||||
mauve = #c6a0f6
|
||||
red = #ed8796
|
||||
maroon = #ee99a0
|
||||
peach = #f5a97f
|
||||
yellow = #eed49f
|
||||
green = #a6da95
|
||||
teal = #8bd5ca
|
||||
sky = #91d7e3
|
||||
sapphire = #7dc4e4
|
||||
blue = #8aadf4
|
||||
lavender = #b7bdf8
|
||||
text = #cad3f5
|
||||
subtext1 = #b8c0e0
|
||||
subtext0 = #a5adcb
|
||||
overlay2 = #939ab7
|
||||
overlay1 = #8087a2
|
||||
overlay0 = #6e738d
|
||||
surface2 = #5b6078
|
||||
surface1 = #494d64
|
||||
surface0 = #363a4f
|
||||
base = #24273a
|
||||
mantle = #1e2030
|
||||
crust = #181926
|
||||
|
||||
background = ${colors.base}
|
||||
background-alt = ${colors.surface0}
|
||||
foreground = ${colors.text}
|
||||
primary = ${colors.mauve}
|
||||
secondary = ${colors.lavender}
|
||||
alert = ${colors.red}
|
||||
disabled = ${colors.overlay0}
|
||||
transparent = #00000000
|
||||
|
||||
; --------------------------------------------------------------------------
|
||||
; Bar
|
||||
; --------------------------------------------------------------------------
|
||||
[bar/main]
|
||||
monitor = ${env:MONITOR:}
|
||||
monitor-strict = false
|
||||
override-redirect = false
|
||||
|
||||
width = 100%
|
||||
height = 30pt
|
||||
radius = 0
|
||||
|
||||
background = ${colors.background}
|
||||
foreground = ${colors.foreground}
|
||||
|
||||
line-size = 3pt
|
||||
border-size = 0pt
|
||||
border-color = ${colors.transparent}
|
||||
|
||||
padding-left = 1
|
||||
padding-right = 1
|
||||
module-margin = 1
|
||||
separator = "│"
|
||||
separator-foreground = ${colors.surface2}
|
||||
|
||||
font-0 = Inconsolata Nerd Font:style=Regular:size=11;2
|
||||
font-1 = Inconsolata Nerd Font:style=Bold:size=11;2
|
||||
font-2 = Symbols Nerd Font Mono:size=13;3
|
||||
font-3 = Noto Color Emoji:scale=10;2
|
||||
|
||||
modules-left = i3 xwindow
|
||||
modules-center = date
|
||||
modules-right = ${env:MODULES_RIGHT:filesystem memory cpu temperature pulseaudio systray}
|
||||
|
||||
cursor-click = pointer
|
||||
cursor-scroll = ns-resize
|
||||
|
||||
enable-ipc = true
|
||||
wm-restack = i3
|
||||
|
||||
; --------------------------------------------------------------------------
|
||||
; Modules
|
||||
; --------------------------------------------------------------------------
|
||||
[module/i3]
|
||||
type = internal/i3
|
||||
pin-workspaces = true
|
||||
show-urgent = true
|
||||
strip-wsnumbers = true
|
||||
index-sort = true
|
||||
enable-click = true
|
||||
enable-scroll = true
|
||||
wrapping-scroll = false
|
||||
reverse-scroll = false
|
||||
fuzzy-match = true
|
||||
|
||||
format = <label-state> <label-mode>
|
||||
|
||||
label-mode = %mode%
|
||||
label-mode-padding = 1
|
||||
label-mode-background = ${colors.peach}
|
||||
label-mode-foreground = ${colors.crust}
|
||||
|
||||
label-focused = %name%
|
||||
label-focused-background = ${colors.surface0}
|
||||
label-focused-foreground = ${colors.mauve}
|
||||
label-focused-underline = ${colors.mauve}
|
||||
label-focused-padding = 1
|
||||
|
||||
label-unfocused = %name%
|
||||
label-unfocused-foreground = ${colors.overlay1}
|
||||
label-unfocused-padding = 1
|
||||
|
||||
label-visible = %name%
|
||||
label-visible-foreground = ${colors.lavender}
|
||||
label-visible-padding = 1
|
||||
|
||||
label-urgent = %name%
|
||||
label-urgent-background = ${colors.red}
|
||||
label-urgent-foreground = ${colors.crust}
|
||||
label-urgent-padding = 1
|
||||
|
||||
[module/xwindow]
|
||||
type = internal/xwindow
|
||||
label = %title:0:80:...%
|
||||
label-foreground = ${colors.subtext0}
|
||||
label-empty =
|
||||
|
||||
[module/date]
|
||||
type = internal/date
|
||||
interval = 1
|
||||
date = %a %d %b
|
||||
time = %H:%M
|
||||
date-alt = %A, %d %B %Y
|
||||
time-alt = %H:%M:%S
|
||||
format-prefix = " "
|
||||
format-prefix-foreground = ${colors.lavender}
|
||||
label = %date% %time%
|
||||
label-foreground = ${colors.text}
|
||||
|
||||
[module/filesystem]
|
||||
type = internal/fs
|
||||
interval = 60
|
||||
mount-0 = /
|
||||
warn-percentage = 85
|
||||
format-mounted-prefix = " "
|
||||
format-mounted-prefix-foreground = ${colors.green}
|
||||
format-warn-prefix = " "
|
||||
format-warn-prefix-foreground = ${colors.peach}
|
||||
label-mounted = %percentage_used%%
|
||||
label-warn = %percentage_used%%
|
||||
label-unmounted =
|
||||
click-left = kitty --class kitty-float -e btop
|
||||
|
||||
[module/memory]
|
||||
type = internal/memory
|
||||
interval = 3
|
||||
warn-percentage = 90
|
||||
format-prefix = " "
|
||||
format-prefix-foreground = ${colors.yellow}
|
||||
format-warn-prefix = " "
|
||||
format-warn-prefix-foreground = ${colors.red}
|
||||
label = %percentage_used%%
|
||||
label-warn = %percentage_used%%
|
||||
label-warn-foreground = ${colors.red}
|
||||
|
||||
[module/cpu]
|
||||
type = internal/cpu
|
||||
interval = 3
|
||||
warn-percentage = 90
|
||||
format-prefix = " "
|
||||
format-prefix-foreground = ${colors.blue}
|
||||
format-warn-prefix = " "
|
||||
format-warn-prefix-foreground = ${colors.red}
|
||||
label = %percentage:2%%
|
||||
label-warn = %percentage:2%%
|
||||
label-warn-foreground = ${colors.red}
|
||||
|
||||
[module/temperature]
|
||||
type = internal/temperature
|
||||
interval = 5
|
||||
thermal-zone = 0
|
||||
base-temperature = 20
|
||||
warn-temperature = 80
|
||||
units = true
|
||||
format = <ramp> <label>
|
||||
format-warn = <ramp> <label-warn>
|
||||
label = %temperature-c%
|
||||
label-warn = %temperature-c%
|
||||
label-warn-foreground = ${colors.red}
|
||||
ramp-0 =
|
||||
ramp-1 =
|
||||
ramp-2 =
|
||||
ramp-3 =
|
||||
ramp-0-foreground = ${colors.sky}
|
||||
ramp-1-foreground = ${colors.green}
|
||||
ramp-2-foreground = ${colors.yellow}
|
||||
ramp-3-foreground = ${colors.peach}
|
||||
|
||||
[module/backlight]
|
||||
type = internal/backlight
|
||||
card = ${env:BACKLIGHT:intel_backlight}
|
||||
use-actual-brightness = true
|
||||
enable-scroll = true
|
||||
format = <ramp> <label>
|
||||
label = %percentage%%
|
||||
ramp-0 =
|
||||
ramp-1 =
|
||||
ramp-2 =
|
||||
ramp-3 =
|
||||
ramp-foreground = ${colors.yellow}
|
||||
|
||||
[module/pulseaudio]
|
||||
type = internal/pulseaudio
|
||||
use-ui-max = false
|
||||
interval = 5
|
||||
format-volume = <ramp-volume> <label-volume>
|
||||
label-volume = %percentage%%
|
||||
label-muted = " muted"
|
||||
label-muted-foreground = ${colors.overlay0}
|
||||
ramp-volume-0 =
|
||||
ramp-volume-1 =
|
||||
ramp-volume-2 =
|
||||
ramp-volume-foreground = ${colors.teal}
|
||||
click-right = pavucontrol
|
||||
scroll-up = ~/.local/bin/volume up
|
||||
scroll-down = ~/.local/bin/volume down
|
||||
|
||||
[module/wlan]
|
||||
type = internal/network
|
||||
interface = ${env:WLAN_IFACE:}
|
||||
interface-type = wireless
|
||||
interval = 5
|
||||
format-connected = <ramp-signal> <label-connected>
|
||||
format-disconnected = <label-disconnected>
|
||||
label-connected = %essid:0:14%
|
||||
label-connected-foreground = ${colors.text}
|
||||
label-disconnected = " offline"
|
||||
label-disconnected-foreground = ${colors.overlay0}
|
||||
ramp-signal-0 =
|
||||
ramp-signal-1 =
|
||||
ramp-signal-2 =
|
||||
ramp-signal-3 =
|
||||
ramp-signal-foreground = ${colors.sapphire}
|
||||
click-left = kitty --class kitty-float -e nmtui
|
||||
|
||||
[module/eth]
|
||||
type = internal/network
|
||||
interface = ${env:ETH_IFACE:}
|
||||
interface-type = wired
|
||||
interval = 5
|
||||
format-connected = <label-connected>
|
||||
format-connected-prefix = " "
|
||||
format-connected-prefix-foreground = ${colors.green}
|
||||
format-disconnected =
|
||||
label-connected = %local_ip%
|
||||
|
||||
[module/battery]
|
||||
type = internal/battery
|
||||
full-at = 98
|
||||
low-at = 15
|
||||
battery = ${env:BATTERY:BAT0}
|
||||
adapter = ${env:ADAPTER:AC}
|
||||
poll-interval = 5
|
||||
|
||||
format-charging = <animation-charging> <label-charging>
|
||||
format-discharging = <ramp-capacity> <label-discharging>
|
||||
format-full = <label-full>
|
||||
format-low = <animation-low> <label-low>
|
||||
|
||||
label-charging = %percentage%%
|
||||
label-discharging = %percentage%%
|
||||
label-full = " full"
|
||||
label-full-foreground = ${colors.green}
|
||||
label-low = %percentage%%
|
||||
label-low-foreground = ${colors.red}
|
||||
|
||||
ramp-capacity-0 =
|
||||
ramp-capacity-1 =
|
||||
ramp-capacity-2 =
|
||||
ramp-capacity-3 =
|
||||
ramp-capacity-4 =
|
||||
ramp-capacity-0-foreground = ${colors.red}
|
||||
ramp-capacity-1-foreground = ${colors.peach}
|
||||
ramp-capacity-2-foreground = ${colors.yellow}
|
||||
ramp-capacity-3-foreground = ${colors.green}
|
||||
ramp-capacity-4-foreground = ${colors.green}
|
||||
|
||||
animation-charging-0 =
|
||||
animation-charging-1 =
|
||||
animation-charging-2 =
|
||||
animation-charging-3 =
|
||||
animation-charging-4 =
|
||||
animation-charging-foreground = ${colors.green}
|
||||
animation-charging-framerate = 750
|
||||
|
||||
animation-low-0 =
|
||||
animation-low-1 =
|
||||
animation-low-foreground = ${colors.red}
|
||||
animation-low-framerate = 500
|
||||
|
||||
[module/systray]
|
||||
type = internal/tray
|
||||
format-margin = 6pt
|
||||
tray-spacing = 8pt
|
||||
tray-background = ${colors.background}
|
||||
|
||||
; --------------------------------------------------------------------------
|
||||
; Global settings
|
||||
; --------------------------------------------------------------------------
|
||||
[settings]
|
||||
screenchange-reload = true
|
||||
pseudo-transparency = false
|
||||
Executable
+85
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env bash
|
||||
# ---------------------------------------------------------------------------
|
||||
# Launch one polybar instance per connected monitor.
|
||||
# Hardware-specific values are detected here and passed to polybar as
|
||||
# environment variables, so config.ini stays machine-independent.
|
||||
# ---------------------------------------------------------------------------
|
||||
set -uo pipefail
|
||||
|
||||
CONFIG="$HOME/.config/polybar/config.ini"
|
||||
LOG="${XDG_CACHE_HOME:-$HOME/.cache}/polybar.log"
|
||||
|
||||
mkdir -p "$(dirname "$LOG")"
|
||||
|
||||
# --- stop any running instances and wait for them to die -------------------
|
||||
pkill -x polybar >/dev/null 2>&1 || true
|
||||
for _ in {1..20}; do
|
||||
pgrep -x polybar >/dev/null || break
|
||||
sleep 0.1
|
||||
done
|
||||
# Anything still alive gets the hammer.
|
||||
pgrep -x polybar >/dev/null && pkill -9 -x polybar
|
||||
|
||||
# --- hardware detection ----------------------------------------------------
|
||||
# Battery + AC adapter
|
||||
BATTERY="$(ls -1 /sys/class/power_supply 2>/dev/null | grep -m1 '^BAT' || true)"
|
||||
ADAPTER="$(ls -1 /sys/class/power_supply 2>/dev/null | grep -m1 -E '^(AC|ADP|ACAD)' || true)"
|
||||
export BATTERY="${BATTERY:-BAT0}"
|
||||
export ADAPTER="${ADAPTER:-AC}"
|
||||
|
||||
# Backlight device (intel_backlight, amdgpu_bl0, nvidia_0, …)
|
||||
BACKLIGHT="$(ls -1 /sys/class/backlight 2>/dev/null | head -n1 || true)"
|
||||
export BACKLIGHT="${BACKLIGHT:-intel_backlight}"
|
||||
|
||||
# Network interfaces: wireless ones have a /sys/class/net/*/wireless dir
|
||||
WLAN_IFACE=""
|
||||
ETH_IFACE=""
|
||||
for iface in /sys/class/net/*; do
|
||||
name="$(basename "$iface")"
|
||||
[[ "$name" == "lo" ]] && continue
|
||||
if [[ -d "$iface/wireless" ]]; then
|
||||
[[ -z "$WLAN_IFACE" ]] && WLAN_IFACE="$name"
|
||||
else
|
||||
[[ -z "$ETH_IFACE" ]] && ETH_IFACE="$name"
|
||||
fi
|
||||
done
|
||||
export WLAN_IFACE ETH_IFACE
|
||||
|
||||
# --- module pruning --------------------------------------------------------
|
||||
# Desktops have no battery/backlight; leaving those modules enabled makes
|
||||
# polybar spam the log, so build the right-hand module list dynamically.
|
||||
MODULES_RIGHT="filesystem memory cpu temperature"
|
||||
[[ -d "/sys/class/backlight/$BACKLIGHT" ]] && MODULES_RIGHT+=" backlight"
|
||||
MODULES_RIGHT+=" pulseaudio"
|
||||
[[ -n "$WLAN_IFACE" ]] && MODULES_RIGHT+=" wlan"
|
||||
[[ -n "$ETH_IFACE" ]] && MODULES_RIGHT+=" eth"
|
||||
[[ -d "/sys/class/power_supply/$BATTERY" ]] && MODULES_RIGHT+=" battery"
|
||||
MODULES_RIGHT+=" systray"
|
||||
export MODULES_RIGHT
|
||||
|
||||
# --- launch ----------------------------------------------------------------
|
||||
{
|
||||
echo
|
||||
echo "=== polybar launch $(date -Is) ==="
|
||||
echo "battery=$BATTERY adapter=$ADAPTER backlight=$BACKLIGHT wlan=${WLAN_IFACE:-none} eth=${ETH_IFACE:-none}"
|
||||
echo "modules-right=$MODULES_RIGHT"
|
||||
} >>"$LOG"
|
||||
|
||||
if command -v polybar >/dev/null && polybar --list-monitors >/dev/null 2>&1; then
|
||||
# The tray can only live on one bar; give it to the primary monitor.
|
||||
primary="$(polybar --list-monitors | grep -m1 '(primary)' | cut -d: -f1)"
|
||||
while IFS= read -r line; do
|
||||
m="${line%%:*}"
|
||||
[[ -z "$m" ]] && continue
|
||||
if [[ -n "$primary" && "$m" != "$primary" ]]; then
|
||||
MONITOR="$m" MODULES_RIGHT="${MODULES_RIGHT/ systray/}" \
|
||||
polybar --reload main --config="$CONFIG" >>"$LOG" 2>&1 &
|
||||
else
|
||||
MONITOR="$m" polybar --reload main --config="$CONFIG" >>"$LOG" 2>&1 &
|
||||
fi
|
||||
done < <(polybar --list-monitors)
|
||||
else
|
||||
polybar --reload main --config="$CONFIG" >>"$LOG" 2>&1 &
|
||||
fi
|
||||
|
||||
echo "polybar launched" >>"$LOG"
|
||||
@@ -0,0 +1,22 @@
|
||||
[Appearance]
|
||||
custom_palette=false
|
||||
icon_theme=Papirus-Dark
|
||||
standard_dialogs=default
|
||||
style=Fusion
|
||||
|
||||
[Fonts]
|
||||
fixed="Inconsolata Nerd Font,11,-1,5,50,0,0,0,0,0"
|
||||
general="Inconsolata Nerd Font,11,-1,5,50,0,0,0,0,0"
|
||||
|
||||
[Interface]
|
||||
activate_item_on_single_click=1
|
||||
buttonbox_layout=0
|
||||
cursor_flash_time=1000
|
||||
dialog_buttons_have_icons=1
|
||||
double_click_interval=400
|
||||
keyboard_scheme=2
|
||||
menus_have_icons=true
|
||||
show_shortcuts_in_context_menus=true
|
||||
toolbutton_style=4
|
||||
underline_shortcut=1
|
||||
wheel_scroll_lines=3
|
||||
@@ -0,0 +1,41 @@
|
||||
/* =========================================================================
|
||||
* rofi — Catppuccin Macchiato
|
||||
* Font: Inconsolata Nerd Font
|
||||
* Docs: man 5 rofi-theme
|
||||
* ========================================================================= */
|
||||
|
||||
configuration {
|
||||
modes: "drun,run,window,ssh";
|
||||
font: "Inconsolata Nerd Font 12";
|
||||
|
||||
show-icons: true;
|
||||
icon-theme: "Papirus-Dark";
|
||||
display-drun: " Apps";
|
||||
display-run: " Run";
|
||||
display-window: " Window";
|
||||
display-ssh: " SSH";
|
||||
drun-display-format: "{name}";
|
||||
window-format: "{w} · {c} · {t}";
|
||||
|
||||
terminal: "kitty";
|
||||
ssh-client: "ssh";
|
||||
ssh-command: "{terminal} -e {ssh-client} {host}";
|
||||
|
||||
matching: "fuzzy";
|
||||
sort: true;
|
||||
sorting-method: "fzf";
|
||||
drun-match-fields: "name,generic,exec,categories,keywords";
|
||||
drun-use-desktop-cache: false;
|
||||
|
||||
hover-select: true;
|
||||
me-select-entry: "";
|
||||
me-accept-entry: "MousePrimary";
|
||||
|
||||
kb-mode-next: "Shift+Right,Control+Tab";
|
||||
kb-mode-previous: "Shift+Left,Control+ISO_Left_Tab";
|
||||
kb-row-up: "Up,Control+k";
|
||||
kb-row-down: "Down,Control+j";
|
||||
kb-remove-to-eol: "";
|
||||
}
|
||||
|
||||
@theme "~/.config/rofi/themes/catppuccin-macchiato.rasi"
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
# ---------------------------------------------------------------------------
|
||||
# rofi power menu — lock / logout / suspend / hibernate / reboot / shutdown
|
||||
# Destructive entries ask for confirmation before firing.
|
||||
# ---------------------------------------------------------------------------
|
||||
set -euo pipefail
|
||||
|
||||
THEME="$HOME/.config/rofi/themes/powermenu.rasi"
|
||||
LOCK_CMD=(betterlockscreen --lock dimblur)
|
||||
|
||||
lock=" Lock"
|
||||
logout=" Log out"
|
||||
suspend=" Suspend"
|
||||
hibernate=" Hibernate"
|
||||
reboot=" Reboot"
|
||||
shutdown=" Shut down"
|
||||
|
||||
menu() {
|
||||
printf '%s\n' "$lock" "$logout" "$suspend" "$hibernate" "$reboot" "$shutdown" |
|
||||
rofi -dmenu -i \
|
||||
-theme "$THEME" \
|
||||
-p " $(whoami)@$(hostname)" \
|
||||
-select "$lock"
|
||||
}
|
||||
|
||||
confirm() {
|
||||
local answer
|
||||
answer=$(printf ' No\n Yes\n' |
|
||||
rofi -dmenu -i -theme "$THEME" -p "$1" -select " No")
|
||||
[[ "$answer" == *Yes* ]]
|
||||
}
|
||||
|
||||
case "$(menu)" in
|
||||
"$lock") "${LOCK_CMD[@]}" ;;
|
||||
"$logout") confirm "Log out?" && i3-msg exit ;;
|
||||
"$suspend") "${LOCK_CMD[@]}" & sleep 0.3; systemctl suspend ;;
|
||||
"$hibernate") confirm "Hibernate?" && { "${LOCK_CMD[@]}" & sleep 0.3; systemctl hibernate; } ;;
|
||||
"$reboot") confirm "Reboot?" && systemctl reboot ;;
|
||||
"$shutdown") confirm "Shut down?" && systemctl poweroff ;;
|
||||
*) exit 0 ;;
|
||||
esac
|
||||
@@ -0,0 +1,195 @@
|
||||
/* =========================================================================
|
||||
* Catppuccin Macchiato theme for rofi
|
||||
* ========================================================================= */
|
||||
|
||||
* {
|
||||
rosewater: #f4dbd6ff;
|
||||
flamingo: #f0c6c6ff;
|
||||
pink: #f5bde6ff;
|
||||
mauve: #c6a0f6ff;
|
||||
red: #ed8796ff;
|
||||
maroon: #ee99a0ff;
|
||||
peach: #f5a97fff;
|
||||
yellow: #eed49fff;
|
||||
green: #a6da95ff;
|
||||
teal: #8bd5caff;
|
||||
sky: #91d7e3ff;
|
||||
sapphire: #7dc4e4ff;
|
||||
blue: #8aadf4ff;
|
||||
lavender: #b7bdf8ff;
|
||||
text: #cad3f5ff;
|
||||
subtext1: #b8c0e0ff;
|
||||
subtext0: #a5adcbff;
|
||||
overlay2: #939ab7ff;
|
||||
overlay1: #8087a2ff;
|
||||
overlay0: #6e738dff;
|
||||
surface2: #5b6078ff;
|
||||
surface1: #494d64ff;
|
||||
surface0: #363a4fff;
|
||||
base: #24273aff;
|
||||
mantle: #1e2030ff;
|
||||
crust: #181926ff;
|
||||
|
||||
background: @base;
|
||||
background-alt: @surface0;
|
||||
foreground: @text;
|
||||
selected: @mauve;
|
||||
active: @green;
|
||||
urgent: @red;
|
||||
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
spacing: 0;
|
||||
}
|
||||
|
||||
window {
|
||||
transparency: "real";
|
||||
location: center;
|
||||
anchor: center;
|
||||
fullscreen: false;
|
||||
width: 640px;
|
||||
x-offset: 0px;
|
||||
y-offset: 0px;
|
||||
|
||||
enabled: true;
|
||||
border-radius: 12px;
|
||||
border: 2px solid;
|
||||
border-color: @mauve;
|
||||
background-color: @background;
|
||||
cursor: "default";
|
||||
}
|
||||
|
||||
mainbox {
|
||||
enabled: true;
|
||||
spacing: 0px;
|
||||
padding: 0px;
|
||||
background-color: transparent;
|
||||
children: [ "inputbar", "message", "listview" ];
|
||||
}
|
||||
|
||||
inputbar {
|
||||
enabled: true;
|
||||
spacing: 10px;
|
||||
padding: 14px 16px;
|
||||
background-color: @mantle;
|
||||
text-color: @foreground;
|
||||
children: [ "prompt", "entry" ];
|
||||
}
|
||||
|
||||
prompt {
|
||||
enabled: true;
|
||||
background-color: transparent;
|
||||
text-color: @mauve;
|
||||
}
|
||||
|
||||
entry {
|
||||
enabled: true;
|
||||
background-color: transparent;
|
||||
text-color: @foreground;
|
||||
cursor: text;
|
||||
placeholder: "Search…";
|
||||
placeholder-color: @overlay0;
|
||||
}
|
||||
|
||||
message {
|
||||
enabled: true;
|
||||
margin: 0px;
|
||||
padding: 10px 16px;
|
||||
background-color: @surface0;
|
||||
text-color: @foreground;
|
||||
}
|
||||
|
||||
textbox {
|
||||
background-color: transparent;
|
||||
text-color: @foreground;
|
||||
vertical-align: 0.5;
|
||||
horizontal-align: 0.0;
|
||||
}
|
||||
|
||||
listview {
|
||||
enabled: true;
|
||||
columns: 1;
|
||||
lines: 10;
|
||||
cycle: true;
|
||||
dynamic: true;
|
||||
scrollbar: true;
|
||||
layout: vertical;
|
||||
reverse: false;
|
||||
fixed-height: true;
|
||||
fixed-columns: true;
|
||||
|
||||
spacing: 2px;
|
||||
padding: 10px;
|
||||
background-color: transparent;
|
||||
cursor: "default";
|
||||
}
|
||||
|
||||
scrollbar {
|
||||
handle-width: 4px;
|
||||
handle-color: @surface2;
|
||||
border-radius: 8px;
|
||||
background-color: @mantle;
|
||||
}
|
||||
|
||||
element {
|
||||
enabled: true;
|
||||
spacing: 10px;
|
||||
padding: 8px 12px;
|
||||
border-radius: 8px;
|
||||
background-color: transparent;
|
||||
text-color: @foreground;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
element normal.normal { background-color: transparent; text-color: @foreground; }
|
||||
element normal.urgent { background-color: transparent; text-color: @urgent; }
|
||||
element normal.active { background-color: transparent; text-color: @active; }
|
||||
|
||||
element selected.normal { background-color: @selected; text-color: @crust; }
|
||||
element selected.urgent { background-color: @urgent; text-color: @crust; }
|
||||
element selected.active { background-color: @active; text-color: @crust; }
|
||||
|
||||
element alternate.normal { background-color: transparent; text-color: @foreground; }
|
||||
element alternate.urgent { background-color: transparent; text-color: @urgent; }
|
||||
element alternate.active { background-color: transparent; text-color: @active; }
|
||||
|
||||
element-icon {
|
||||
background-color: transparent;
|
||||
text-color: inherit;
|
||||
size: 24px;
|
||||
cursor: inherit;
|
||||
}
|
||||
|
||||
element-text {
|
||||
background-color: transparent;
|
||||
text-color: inherit;
|
||||
highlight: inherit;
|
||||
cursor: inherit;
|
||||
vertical-align: 0.5;
|
||||
horizontal-align: 0.0;
|
||||
}
|
||||
|
||||
mode-switcher {
|
||||
enabled: true;
|
||||
spacing: 0px;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 8px;
|
||||
background-color: @surface0;
|
||||
text-color: @overlay1;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button selected {
|
||||
background-color: @mauve;
|
||||
text-color: @crust;
|
||||
}
|
||||
|
||||
error-message {
|
||||
padding: 16px;
|
||||
border-radius: 12px;
|
||||
background-color: @base;
|
||||
text-color: @red;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/* Compact variant of the Macchiato theme, used by powermenu.sh */
|
||||
@import "catppuccin-macchiato.rasi"
|
||||
|
||||
window {
|
||||
width: 360px;
|
||||
border-color: @red;
|
||||
}
|
||||
|
||||
listview {
|
||||
lines: 6;
|
||||
columns: 1;
|
||||
}
|
||||
|
||||
element {
|
||||
padding: 10px 14px;
|
||||
}
|
||||
|
||||
element selected.normal {
|
||||
background-color: @red;
|
||||
text-color: @crust;
|
||||
}
|
||||
|
||||
prompt {
|
||||
text-color: @red;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
TerminalEmulator=kitty
|
||||
FileManager=thunar
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<channel name="thunar" version="1.0">
|
||||
<property name="last-view" type="string" value="ThunarDetailsView"/>
|
||||
<property name="last-icon-view-zoom-level" type="string" value="THUNAR_ZOOM_LEVEL_100_PERCENT"/>
|
||||
<property name="last-details-view-zoom-level" type="string" value="THUNAR_ZOOM_LEVEL_38_PERCENT"/>
|
||||
<property name="last-window-width" type="int" value="1100"/>
|
||||
<property name="last-window-height" type="int" value="700"/>
|
||||
<property name="last-window-maximized" type="bool" value="false"/>
|
||||
<property name="last-separator-position" type="int" value="180"/>
|
||||
<property name="last-show-hidden" type="bool" value="false"/>
|
||||
<property name="misc-single-click" type="bool" value="false"/>
|
||||
<property name="misc-date-style" type="string" value="THUNAR_DATE_STYLE_YYYYMMDD"/>
|
||||
<property name="misc-thumbnail-mode" type="string" value="THUNAR_THUMBNAIL_MODE_ONLY_LOCAL"/>
|
||||
<property name="misc-folders-first" type="bool" value="true"/>
|
||||
<property name="misc-text-beside-icons" type="bool" value="false"/>
|
||||
<property name="misc-middle-click-in-tab" type="bool" value="true"/>
|
||||
<property name="misc-open-new-window-as-tab" type="bool" value="true"/>
|
||||
<property name="misc-full-path-in-title" type="bool" value="false"/>
|
||||
<property name="shortcuts-icon-emblems" type="bool" value="true"/>
|
||||
<property name="tree-icon-emblems" type="bool" value="true"/>
|
||||
<property name="last-location-bar" type="string" value="ThunarLocationButtons"/>
|
||||
<property name="last-side-pane" type="string" value="ThunarShortcutsPane"/>
|
||||
</channel>
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<channel name="xsettings" version="1.0">
|
||||
<property name="Net" type="empty">
|
||||
<property name="ThemeName" type="string" value="catppuccin-macchiato-mauve-standard+default"/>
|
||||
<property name="IconThemeName" type="string" value="Papirus-Dark"/>
|
||||
<property name="EnableEventSounds" type="bool" value="false"/>
|
||||
<property name="EnableInputFeedbackSounds" type="bool" value="false"/>
|
||||
</property>
|
||||
<property name="Xft" type="empty">
|
||||
<property name="DPI" type="int" value="-1"/>
|
||||
<property name="Antialias" type="int" value="1"/>
|
||||
<property name="Hinting" type="int" value="1"/>
|
||||
<property name="HintStyle" type="string" value="hintslight"/>
|
||||
<property name="RGBA" type="string" value="rgb"/>
|
||||
</property>
|
||||
<property name="Gtk" type="empty">
|
||||
<property name="FontName" type="string" value="Inconsolata Nerd Font 11"/>
|
||||
<property name="MonospaceFontName" type="string" value="Inconsolata Nerd Font 11"/>
|
||||
<property name="CursorThemeName" type="string" value="catppuccin-macchiato-dark-cursors"/>
|
||||
<property name="CursorThemeSize" type="int" value="24"/>
|
||||
<property name="DecorationLayout" type="string" value="menu:minimize,maximize,close"/>
|
||||
</property>
|
||||
</channel>
|
||||
@@ -0,0 +1,13 @@
|
||||
# ~/.gtkrc-2.0 — GTK2 apps (lxappearance, some older utilities)
|
||||
gtk-theme-name="catppuccin-macchiato-mauve-standard+default"
|
||||
gtk-icon-theme-name="Papirus-Dark"
|
||||
gtk-cursor-theme-name="catppuccin-macchiato-dark-cursors"
|
||||
gtk-cursor-theme-size=24
|
||||
gtk-font-name="Inconsolata Nerd Font 11"
|
||||
gtk-toolbar-style=GTK_TOOLBAR_ICONS
|
||||
gtk-menu-images=1
|
||||
gtk-button-images=1
|
||||
gtk-xft-antialias=1
|
||||
gtk-xft-hinting=1
|
||||
gtk-xft-hintstyle="hintslight"
|
||||
gtk-xft-rgba="rgb"
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env bash
|
||||
# Backlight control with a dunst OSD. usage: brightness up|down|set <n>
|
||||
set -uo pipefail
|
||||
|
||||
STEP="${BRIGHTNESS_STEP:-5}"
|
||||
MIN=1 # never go fully dark — that looks like a crash
|
||||
ID=2594
|
||||
|
||||
command -v brightnessctl >/dev/null || { echo "brightnessctl not found" >&2; exit 1; }
|
||||
|
||||
pct() { brightnessctl -m | awk -F, '{gsub(/%/,"",$4); print $4}'; }
|
||||
|
||||
case "${1:-}" in
|
||||
up) brightnessctl -q set "${STEP}%+" ;;
|
||||
down) brightnessctl -q set "${STEP}%-" ;;
|
||||
set) brightnessctl -q set "${2:?need a percentage}%" ;;
|
||||
""|-h|--help) echo "usage: brightness up|down|set <percent>"; exit 0 ;;
|
||||
*) echo "unknown action: $1" >&2; exit 2 ;;
|
||||
esac
|
||||
|
||||
# Enforce the floor
|
||||
current="$(pct)"
|
||||
if (( current < MIN )); then
|
||||
brightnessctl -q set "${MIN}%"
|
||||
current="$MIN"
|
||||
fi
|
||||
|
||||
command -v dunstify >/dev/null && \
|
||||
dunstify -a osd -u low -r "$ID" -h "int:value:$current" \
|
||||
-i display-brightness "Brightness ${current}%"
|
||||
Executable
+60
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env bash
|
||||
# ---------------------------------------------------------------------------
|
||||
# Minimal xrandr multi-monitor switcher.
|
||||
# display auto | duplicate | extend | internal | external | list
|
||||
# "internal" is whichever output name looks like a laptop panel.
|
||||
# ---------------------------------------------------------------------------
|
||||
set -uo pipefail
|
||||
|
||||
command -v xrandr >/dev/null || { echo "xrandr not installed" >&2; exit 1; }
|
||||
|
||||
mapfile -t CONNECTED < <(xrandr --query | awk '/ connected/{print $1}')
|
||||
INTERNAL="$(printf '%s\n' "${CONNECTED[@]}" | grep -m1 -E '^(eDP|LVDS|DSI)' || true)"
|
||||
[[ -z "$INTERNAL" ]] && INTERNAL="${CONNECTED[0]:-}"
|
||||
mapfile -t EXTERNALS < <(printf '%s\n' "${CONNECTED[@]}" | grep -v "^${INTERNAL}$" || true)
|
||||
|
||||
reload_bar() { "$HOME/.config/polybar/launch.sh" >/dev/null 2>&1 & }
|
||||
restore_bg() { "$HOME/.local/bin/set-wallpaper" >/dev/null 2>&1 & }
|
||||
|
||||
case "${1:-auto}" in
|
||||
list)
|
||||
xrandr --query | grep -E ' connected|disconnected' ; exit 0 ;;
|
||||
|
||||
internal)
|
||||
args=(--output "$INTERNAL" --auto --primary)
|
||||
for e in "${EXTERNALS[@]}"; do args+=(--output "$e" --off); done
|
||||
xrandr "${args[@]}" ;;
|
||||
|
||||
external)
|
||||
if [[ ${#EXTERNALS[@]} -eq 0 ]]; then echo "no external display connected" >&2; exit 1; fi
|
||||
args=(--output "${EXTERNALS[0]}" --auto --primary --output "$INTERNAL" --off)
|
||||
for e in "${EXTERNALS[@]:1}"; do args+=(--output "$e" --off); done
|
||||
xrandr "${args[@]}" ;;
|
||||
|
||||
duplicate)
|
||||
if [[ ${#EXTERNALS[@]} -eq 0 ]]; then echo "no external display connected" >&2; exit 1; fi
|
||||
args=(--output "$INTERNAL" --auto --primary)
|
||||
for e in "${EXTERNALS[@]}"; do args+=(--output "$e" --auto --same-as "$INTERNAL"); done
|
||||
xrandr "${args[@]}" ;;
|
||||
|
||||
extend)
|
||||
if [[ ${#EXTERNALS[@]} -eq 0 ]]; then echo "no external display connected" >&2; exit 1; fi
|
||||
args=(--output "$INTERNAL" --auto --primary)
|
||||
prev="$INTERNAL"
|
||||
for e in "${EXTERNALS[@]}"; do
|
||||
args+=(--output "$e" --auto --right-of "$prev")
|
||||
prev="$e"
|
||||
done
|
||||
xrandr "${args[@]}" ;;
|
||||
|
||||
auto)
|
||||
# Extend if something external is plugged in, otherwise laptop panel only.
|
||||
if [[ ${#EXTERNALS[@]} -gt 0 ]]; then exec "$0" extend; else exec "$0" internal; fi ;;
|
||||
|
||||
*)
|
||||
echo "usage: display auto|duplicate|extend|internal|external|list" >&2; exit 2 ;;
|
||||
esac
|
||||
|
||||
sleep 0.5
|
||||
restore_bg
|
||||
reload_bar
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env bash
|
||||
# Restart a daemon idempotently — safe to call from i3's exec_always.
|
||||
# usage: restart-daemon <name> [args…]
|
||||
set -uo pipefail
|
||||
|
||||
name="${1:?usage: restart-daemon <name> [args...]}"
|
||||
shift || true
|
||||
|
||||
command -v "$name" >/dev/null 2>&1 || { echo "restart-daemon: $name not installed" >&2; exit 0; }
|
||||
|
||||
pkill -x "$name" >/dev/null 2>&1 || true
|
||||
for _ in {1..20}; do
|
||||
pgrep -x "$name" >/dev/null || break
|
||||
sleep 0.1
|
||||
done
|
||||
pgrep -x "$name" >/dev/null && pkill -9 -x "$name"
|
||||
|
||||
log="${XDG_CACHE_HOME:-$HOME/.cache}/$name.log"
|
||||
mkdir -p "$(dirname "$log")"
|
||||
exec "$name" "$@" >>"$log" 2>&1 &
|
||||
Executable
+49
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
# ---------------------------------------------------------------------------
|
||||
# Screenshots with maim. usage: screenshot full|area|window [--clip-only]
|
||||
# Images land in ~/Pictures/Screenshots and are copied to the clipboard.
|
||||
# ---------------------------------------------------------------------------
|
||||
set -uo pipefail
|
||||
|
||||
DIR="${SCREENSHOT_DIR:-$(xdg-user-dir PICTURES 2>/dev/null || echo "$HOME/Pictures")/Screenshots}"
|
||||
STAMP="$(date +%Y-%m-%d_%H-%M-%S)"
|
||||
FILE="$DIR/screenshot_$STAMP.png"
|
||||
MODE="${1:-full}"
|
||||
CLIP_ONLY=0
|
||||
[[ "${2:-}" == "--clip-only" ]] && CLIP_ONLY=1
|
||||
|
||||
command -v maim >/dev/null || { echo "maim not installed" >&2; exit 1; }
|
||||
mkdir -p "$DIR"
|
||||
|
||||
# Selection colour = Catppuccin mauve (maim wants floats 0-1)
|
||||
SELECT_COLOR="0.776,0.627,0.965,0.5"
|
||||
|
||||
case "$MODE" in
|
||||
full)
|
||||
maim --hidecursor --quality 10 "$FILE" ;;
|
||||
area)
|
||||
maim --select --hidecursor --quality 10 --color="$SELECT_COLOR" \
|
||||
--bordersize=2 --nodrag "$FILE" ;;
|
||||
window)
|
||||
maim --window "$(xdotool getactivewindow)" --hidecursor --quality 10 "$FILE" ;;
|
||||
*)
|
||||
echo "usage: screenshot full|area|window [--clip-only]" >&2; exit 2 ;;
|
||||
esac
|
||||
|
||||
# maim exits non-zero when the user cancels an area selection with Escape.
|
||||
if [[ ! -s "$FILE" ]]; then
|
||||
rm -f "$FILE"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
command -v xclip >/dev/null && xclip -selection clipboard -t image/png -i "$FILE"
|
||||
|
||||
if [[ "$CLIP_ONLY" == "1" ]]; then
|
||||
rm -f "$FILE"
|
||||
command -v dunstify >/dev/null && \
|
||||
dunstify -a screenshot -i camera-photo "Screenshot" "Copied to clipboard"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
command -v dunstify >/dev/null && \
|
||||
dunstify -a screenshot -i "$FILE" "Screenshot saved" "$(basename "$FILE")\nCopied to clipboard"
|
||||
Executable
+65
@@ -0,0 +1,65 @@
|
||||
#!/usr/bin/env bash
|
||||
# ---------------------------------------------------------------------------
|
||||
# Apply a wallpaper with feh and remember the choice.
|
||||
#
|
||||
# set-wallpaper # restore the remembered wallpaper
|
||||
# set-wallpaper /path/img.png # set a specific image
|
||||
# set-wallpaper --random # pick a random one from the wallpaper dir
|
||||
# set-wallpaper --cache # (re)build the betterlockscreen cache
|
||||
#
|
||||
# The current selection is stored in $XDG_STATE_HOME/current-wallpaper.
|
||||
# ---------------------------------------------------------------------------
|
||||
set -uo pipefail
|
||||
|
||||
WALLPAPER_DIR="${WALLPAPER_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/wallpapers}"
|
||||
STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}"
|
||||
STATE_FILE="$STATE_DIR/current-wallpaper"
|
||||
MODE="${FEH_MODE:---bg-fill}"
|
||||
|
||||
mkdir -p "$STATE_DIR" "$WALLPAPER_DIR"
|
||||
|
||||
pick_random() {
|
||||
find -L "$WALLPAPER_DIR" -type f \
|
||||
\( -iname '*.png' -o -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.webp' \) \
|
||||
| shuf -n1
|
||||
}
|
||||
|
||||
first_available() {
|
||||
find -L "$WALLPAPER_DIR" -type f \
|
||||
\( -iname '*.png' -o -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.webp' \) \
|
||||
| sort | head -n1
|
||||
}
|
||||
|
||||
cache_lockscreen=0
|
||||
target=""
|
||||
|
||||
case "${1:-}" in
|
||||
--random) target="$(pick_random)" ;;
|
||||
--cache) cache_lockscreen=1 ;;
|
||||
"") target="$(cat "$STATE_FILE" 2>/dev/null || true)" ;;
|
||||
-*) echo "unknown option: $1" >&2; exit 2 ;;
|
||||
*) target="$1"; cache_lockscreen=1 ;;
|
||||
esac
|
||||
|
||||
# Fall back through: remembered -> anything in the dir -> a flat Macchiato base
|
||||
if [[ -z "$target" || ! -f "$target" ]]; then
|
||||
target="$(first_available)"
|
||||
fi
|
||||
|
||||
if [[ -z "$target" || ! -f "$target" ]]; then
|
||||
echo "set-wallpaper: no image found in $WALLPAPER_DIR — using a flat colour" >&2
|
||||
command -v xsetroot >/dev/null && xsetroot -solid "#24273a"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
command -v feh >/dev/null || { echo "set-wallpaper: feh is not installed" >&2; exit 1; }
|
||||
|
||||
feh --no-fehbg "$MODE" "$target"
|
||||
printf '%s\n' "$target" > "$STATE_FILE"
|
||||
|
||||
# Keep the lock screen in sync with the desktop. Caching is slow (imagemagick
|
||||
# blurs the image at every resolution), so only do it when the image changed.
|
||||
if [[ "$cache_lockscreen" == "1" ]] && command -v betterlockscreen >/dev/null; then
|
||||
( betterlockscreen --update "$target" --blur 0.5 >/dev/null 2>&1 &
|
||||
disown ) 2>/dev/null || true
|
||||
fi
|
||||
Executable
+66
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env bash
|
||||
# Volume / mic control with a dunst OSD. usage: volume up|down|mute|micmute|set <n>
|
||||
set -uo pipefail
|
||||
|
||||
STEP="${VOLUME_STEP:-5}"
|
||||
MAX="${VOLUME_MAX:-100}"
|
||||
SINK="@DEFAULT_AUDIO_SINK@"
|
||||
SOURCE="@DEFAULT_AUDIO_SOURCE@"
|
||||
ID=2593 # fixed notification id => the OSD replaces itself instead of stacking
|
||||
|
||||
have() { command -v "$1" >/dev/null 2>&1; }
|
||||
have wpctl || { echo "wpctl (wireplumber) not found" >&2; exit 1; }
|
||||
|
||||
get_volume() {
|
||||
wpctl get-volume "$SINK" | awk '{printf "%d", $2 * 100}'
|
||||
}
|
||||
is_muted() {
|
||||
wpctl get-volume "$SINK" | grep -q MUTED
|
||||
}
|
||||
|
||||
osd() {
|
||||
have dunstify || return 0
|
||||
local icon="$1" text="$2" value="$3"
|
||||
dunstify -a osd -u low -r "$ID" -h "int:value:$value" -i "$icon" "$text"
|
||||
}
|
||||
|
||||
case "${1:-}" in
|
||||
up)
|
||||
wpctl set-mute "$SINK" 0
|
||||
wpctl set-volume -l "$(awk "BEGIN{print $MAX/100}")" "$SINK" "${STEP}%+"
|
||||
;;
|
||||
down)
|
||||
wpctl set-mute "$SINK" 0
|
||||
wpctl set-volume "$SINK" "${STEP}%-"
|
||||
;;
|
||||
set)
|
||||
wpctl set-volume -l "$(awk "BEGIN{print $MAX/100}")" "$SINK" "${2:?need a percentage}%"
|
||||
;;
|
||||
mute)
|
||||
wpctl set-mute "$SINK" toggle
|
||||
;;
|
||||
micmute)
|
||||
wpctl set-mute "$SOURCE" toggle
|
||||
if wpctl get-volume "$SOURCE" | grep -q MUTED; then
|
||||
osd microphone-sensitivity-muted "Microphone muted" 0
|
||||
else
|
||||
osd microphone-sensitivity-high "Microphone live" 100
|
||||
fi
|
||||
exit 0
|
||||
;;
|
||||
""|-h|--help)
|
||||
echo "usage: volume up|down|mute|micmute|set <percent>"; exit 0 ;;
|
||||
*)
|
||||
echo "unknown action: $1" >&2; exit 2 ;;
|
||||
esac
|
||||
|
||||
vol="$(get_volume)"
|
||||
if is_muted; then
|
||||
osd audio-volume-muted "Muted" 0
|
||||
elif (( vol >= 66 )); then osd audio-volume-high "Volume ${vol}%" "$vol"
|
||||
elif (( vol >= 33 )); then osd audio-volume-medium "Volume ${vol}%" "$vol"
|
||||
else osd audio-volume-low "Volume ${vol}%" "$vol"
|
||||
fi
|
||||
|
||||
# Nudge polybar so the bar updates instantly rather than on its 5s poll
|
||||
pkill -RTMIN+1 polybar 2>/dev/null || true
|
||||
@@ -0,0 +1,27 @@
|
||||
#!/bin/sh
|
||||
# ---------------------------------------------------------------------------
|
||||
# ~/.xinitrc — executed by startx / xinit
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
userresources=$HOME/.Xresources
|
||||
usermodmap=$HOME/.Xmodmap
|
||||
sysresources=/etc/X11/xinit/.Xresources
|
||||
sysmodmap=/etc/X11/xinit/.Xmodmap
|
||||
|
||||
[ -f "$sysresources" ] && xrdb -merge "$sysresources"
|
||||
[ -f "$sysmodmap" ] && xmodmap "$sysmodmap"
|
||||
[ -f "$userresources" ] && xrdb -merge "$userresources"
|
||||
[ -f "$usermodmap" ] && xmodmap "$usermodmap"
|
||||
|
||||
# Run everything in /etc/X11/xinit/xinitrc.d (dbus, gnome-keyring, …)
|
||||
if [ -d /etc/X11/xinit/xinitrc.d ]; then
|
||||
for f in /etc/X11/xinit/xinitrc.d/?*.sh; do
|
||||
[ -x "$f" ] && . "$f"
|
||||
done
|
||||
unset f
|
||||
fi
|
||||
|
||||
# Shared environment for both startx and display-manager logins
|
||||
[ -f "$HOME/.xprofile" ] && . "$HOME/.xprofile"
|
||||
|
||||
exec i3
|
||||
@@ -0,0 +1,48 @@
|
||||
# ---------------------------------------------------------------------------
|
||||
# ~/.xprofile — sourced by .xinitrc and by most display managers.
|
||||
# Put environment variables here, not in .xinitrc, so both login paths agree.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# --- XDG -------------------------------------------------------------------
|
||||
export XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
|
||||
export XDG_DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
|
||||
export XDG_CACHE_HOME="${XDG_CACHE_HOME:-$HOME/.cache}"
|
||||
export XDG_STATE_HOME="${XDG_STATE_HOME:-$HOME/.local/state}"
|
||||
export XDG_CURRENT_DESKTOP=i3
|
||||
export XDG_SESSION_DESKTOP=i3
|
||||
export XDG_SESSION_TYPE=x11
|
||||
|
||||
# --- PATH ------------------------------------------------------------------
|
||||
case ":$PATH:" in
|
||||
*":$HOME/.local/bin:"*) ;;
|
||||
*) export PATH="$HOME/.local/bin:$PATH" ;;
|
||||
esac
|
||||
|
||||
# --- defaults --------------------------------------------------------------
|
||||
export TERMINAL=kitty
|
||||
export EDITOR=nvim
|
||||
export VISUAL=nvim
|
||||
export PAGER=less
|
||||
export BROWSER=xdg-open
|
||||
|
||||
# --- toolkit theming -------------------------------------------------------
|
||||
export GTK_THEME="catppuccin-macchiato-mauve-standard+default"
|
||||
export QT_QPA_PLATFORMTHEME=qt5ct
|
||||
export QT_AUTO_SCREEN_SCALE_FACTOR=1
|
||||
export QT_WAYLAND_DISABLE_WINDOWDECORATION=1
|
||||
export XCURSOR_THEME="catppuccin-macchiato-dark-cursors"
|
||||
export XCURSOR_SIZE=24
|
||||
|
||||
# --- Java apps need this to render under a non-reparenting WM --------------
|
||||
export _JAVA_AWT_WM_NONREPARENTING=1
|
||||
export AWT_TOOLKIT=MToolkit
|
||||
|
||||
# --- Firefox / Electron: touchpad smooth scrolling + wayland off -----------
|
||||
export MOZ_USE_XINPUT2=1
|
||||
|
||||
# --- keyboard --------------------------------------------------------------
|
||||
# Uncomment and adapt if you want caps-lock as an extra escape:
|
||||
# setxkbmap -option caps:escape
|
||||
|
||||
# --- create the standard user directories the first time round ------------
|
||||
command -v xdg-user-dirs-update >/dev/null 2>&1 && xdg-user-dirs-update
|
||||
Executable
+135
@@ -0,0 +1,135 @@
|
||||
#!/usr/bin/env bash
|
||||
# ===========================================================================
|
||||
# arch-i3 — bootstrap a complete i3 desktop on a fresh Arch Linux install
|
||||
#
|
||||
# ./install.sh run every stage
|
||||
# ./install.sh --dry-run print what would happen, change nothing
|
||||
# ./install.sh --only 30,50 run just those stages
|
||||
# ./install.sh --skip 20 run everything except that stage
|
||||
# ./install.sh --list show the stages and exit
|
||||
# ./install.sh -y never prompt
|
||||
#
|
||||
# Safe to re-run: package installs use --needed, and every config file that
|
||||
# would be overwritten is first moved into ~/.config-backup-<timestamp>/.
|
||||
# ===========================================================================
|
||||
set -Eeuo pipefail
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
export DRY_RUN=0 ASSUME_YES=0 ENABLE_MULTILIB=0
|
||||
ONLY="" SKIP=""
|
||||
|
||||
usage() { sed -n '2,20p' "$0" | sed 's/^# \{0,1\}//'; exit 0; }
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-n|--dry-run) DRY_RUN=1 ;;
|
||||
-y|--yes) ASSUME_YES=1 ;;
|
||||
--multilib) ENABLE_MULTILIB=1 ;;
|
||||
--only) ONLY="${2:?--only needs a stage list}"; shift ;;
|
||||
--skip) SKIP="${2:?--skip needs a stage list}"; shift ;;
|
||||
--list) LIST=1 ;;
|
||||
-h|--help) usage ;;
|
||||
*) echo "unknown option: $1 (try --help)" >&2; exit 2 ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
source "$REPO_ROOT/scripts/lib.sh"
|
||||
|
||||
STAGES=(
|
||||
"00:preflight:00-preflight.sh:sanity checks, mirrors, pacman -Syu"
|
||||
"10:packages:10-packages.sh:install everything from the official repos"
|
||||
"20:aur:20-aur.sh:bootstrap yay, install i3lock-color + betterlockscreen"
|
||||
"30:dotfiles:30-dotfiles.sh:deploy configs, scripts and wallpapers"
|
||||
"40:services:40-services.sh:enable services, groups, font + lock cache"
|
||||
"50:theme:50-theme.sh:apply the Catppuccin Macchiato theme"
|
||||
)
|
||||
|
||||
if [[ -n "${LIST:-}" ]]; then
|
||||
printf '%sStages%s\n' "$C_BOLD" "$C_RESET"
|
||||
for s in "${STAGES[@]}"; do
|
||||
IFS=: read -r num name _ desc <<<"$s"
|
||||
printf ' %s%-4s%s %-10s %s\n' "$C_MAUVE" "$num" "$C_RESET" "$name" "$desc"
|
||||
done
|
||||
exit 0
|
||||
fi
|
||||
|
||||
selected() {
|
||||
local num="$1" name="$2"
|
||||
if [[ -n "$ONLY" ]]; then
|
||||
[[ ",$ONLY," == *",$num,"* || ",$ONLY," == *",$name,"* ]] || return 1
|
||||
fi
|
||||
if [[ -n "$SKIP" ]]; then
|
||||
[[ ",$SKIP," == *",$num,"* || ",$SKIP," == *",$name,"* ]] && return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# --- banner ----------------------------------------------------------------
|
||||
cat <<'BANNER'
|
||||
___ _ _ ____
|
||||
/ _ | ________ / / (_) __/
|
||||
/ __ |/ __/ __/ / _ \ / /_ |
|
||||
/_/ |_|_/ \__/ /_//_/ /_/____/ i3 · polybar · rofi · dunst · kitty
|
||||
Catppuccin Macchiato · Inconsolata Nerd Font
|
||||
BANNER
|
||||
|
||||
[[ "$DRY_RUN" == "1" ]] && warn "DRY RUN — nothing will be changed"
|
||||
|
||||
require_arch
|
||||
require_not_root
|
||||
|
||||
# --- confirmation ----------------------------------------------------------
|
||||
echo
|
||||
log "This will install $(read_pkg_list "$PACKAGES_DIR/pacman.txt" | wc -l | tr -d ' ') repo packages and"
|
||||
log "$(read_pkg_list "$PACKAGES_DIR/aur.txt" | wc -l | tr -d ' ') AUR packages, then write configs into ~/.config."
|
||||
log "Existing configs are backed up, never deleted."
|
||||
echo
|
||||
confirm "Proceed?" || die "aborted by user"
|
||||
|
||||
# --- run stages ------------------------------------------------------------
|
||||
START="$SECONDS"
|
||||
FAILED=()
|
||||
|
||||
for s in "${STAGES[@]}"; do
|
||||
IFS=: read -r num name script desc <<<"$s"
|
||||
if ! selected "$num" "$name"; then
|
||||
skip "stage $num ($name) — skipped"
|
||||
continue
|
||||
fi
|
||||
echo
|
||||
printf '%s┌─ stage %s · %s %s%s\n' "$C_BOLD$C_MAUVE" "$num" "$name" "─────────────────────" "$C_RESET"
|
||||
if ! bash "$REPO_ROOT/scripts/$script"; then
|
||||
warn "stage $num ($name) failed"
|
||||
FAILED+=("$num:$name")
|
||||
confirm "continue with the remaining stages?" || die "aborted after stage $num"
|
||||
fi
|
||||
done
|
||||
|
||||
# --- summary ---------------------------------------------------------------
|
||||
echo
|
||||
ELAPSED=$(( SECONDS - START ))
|
||||
if [[ ${#FAILED[@]} -eq 0 ]]; then
|
||||
log "${C_GREEN}Done${C_RESET} in ${ELAPSED}s."
|
||||
else
|
||||
warn "finished in ${ELAPSED}s with ${#FAILED[@]} failed stage(s): ${FAILED[*]}"
|
||||
fi
|
||||
|
||||
cat <<'NEXT'
|
||||
|
||||
Next steps
|
||||
──────────
|
||||
1. Log out of the TTY and back in so the new groups take effect.
|
||||
2. Start the session with: startx
|
||||
(or install a display manager — see the README)
|
||||
3. First keys to try:
|
||||
Super + Return kitty
|
||||
Super + d rofi app launcher
|
||||
Super + e thunar
|
||||
Super + Shift + e power menu
|
||||
Super + Shift + x lock the screen
|
||||
Super + Shift + r restart i3 after editing the config
|
||||
4. Personal tweaks belong in ~/.config/i3/config.d/*.conf — that
|
||||
directory is never overwritten by this installer.
|
||||
|
||||
NEXT
|
||||
@@ -0,0 +1,17 @@
|
||||
# ---------------------------------------------------------------------------
|
||||
# AUR packages (installed with yay)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# i3lock-color provides & conflicts with i3lock — it is the fork that
|
||||
# betterlockscreen depends on. Installing it gives you the `i3lock` binary
|
||||
# with all the extra --*-color flags.
|
||||
i3lock-color
|
||||
betterlockscreen
|
||||
|
||||
# Catppuccin Macchiato theming for GTK apps, cursors and folder icons
|
||||
catppuccin-gtk-theme-macchiato
|
||||
catppuccin-cursors-macchiato
|
||||
papirus-folders-catppuccin-git
|
||||
|
||||
# Nice-to-haves
|
||||
xcursor-themes
|
||||
@@ -0,0 +1,123 @@
|
||||
# ---------------------------------------------------------------------------
|
||||
# Official repository packages (pacman)
|
||||
# Lines starting with '#' and blank lines are ignored.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# --- build tooling (needed for the AUR helper) -----------------------------
|
||||
base-devel
|
||||
git
|
||||
|
||||
# --- X server & friends ----------------------------------------------------
|
||||
xorg-server
|
||||
xorg-xinit
|
||||
xorg-xrandr
|
||||
xorg-xrdb
|
||||
xorg-xset
|
||||
xorg-xsetroot
|
||||
xorg-xprop
|
||||
xorg-xkill
|
||||
xorg-xinput
|
||||
xclip
|
||||
xdotool
|
||||
xsettingsd
|
||||
|
||||
# --- graphics drivers (mesa covers intel/amd; nvidia users: see README) ----
|
||||
mesa
|
||||
xf86-video-vesa
|
||||
|
||||
# --- window manager & core desktop ----------------------------------------
|
||||
i3-wm
|
||||
polybar
|
||||
rofi
|
||||
dunst
|
||||
libnotify
|
||||
polkit
|
||||
polkit-gnome
|
||||
picom
|
||||
feh
|
||||
xss-lock
|
||||
numlockx
|
||||
|
||||
# NOTE: i3lock is intentionally NOT listed here.
|
||||
# betterlockscreen needs i3lock-color (AUR), which provides/replaces i3lock.
|
||||
# See packages/aur.txt.
|
||||
|
||||
# --- terminal --------------------------------------------------------------
|
||||
kitty
|
||||
|
||||
# --- file manager stack ----------------------------------------------------
|
||||
thunar
|
||||
thunar-volman
|
||||
thunar-archive-plugin
|
||||
tumbler
|
||||
ffmpegthumbnailer
|
||||
gvfs
|
||||
gvfs-mtp
|
||||
gvfs-afc
|
||||
gvfs-smb
|
||||
udisks2
|
||||
udiskie
|
||||
file-roller
|
||||
xarchiver
|
||||
|
||||
# --- audio (pipewire) ------------------------------------------------------
|
||||
pipewire
|
||||
pipewire-alsa
|
||||
pipewire-pulse
|
||||
pipewire-jack
|
||||
wireplumber
|
||||
pavucontrol
|
||||
alsa-utils
|
||||
playerctl
|
||||
|
||||
# --- networking ------------------------------------------------------------
|
||||
networkmanager
|
||||
network-manager-applet
|
||||
nm-connection-editor
|
||||
|
||||
# --- bluetooth (harmless if the machine has no radio) ----------------------
|
||||
bluez
|
||||
bluez-utils
|
||||
blueman
|
||||
|
||||
# --- theming / fonts -------------------------------------------------------
|
||||
ttf-inconsolata-nerd
|
||||
ttf-nerd-fonts-symbols
|
||||
ttf-nerd-fonts-symbols-mono
|
||||
noto-fonts
|
||||
noto-fonts-emoji
|
||||
noto-fonts-cjk
|
||||
ttf-liberation
|
||||
papirus-icon-theme
|
||||
lxappearance
|
||||
qt5ct
|
||||
gtk-engine-murrine
|
||||
|
||||
# --- utilities you will miss on day one ------------------------------------
|
||||
imagemagick
|
||||
maim
|
||||
brightnessctl
|
||||
lm_sensors
|
||||
htop
|
||||
btop
|
||||
neovim
|
||||
man-db
|
||||
man-pages
|
||||
less
|
||||
tree
|
||||
unzip
|
||||
zip
|
||||
p7zip
|
||||
unrar
|
||||
wget
|
||||
curl
|
||||
jq
|
||||
rsync
|
||||
fastfetch
|
||||
xdg-user-dirs
|
||||
xdg-utils
|
||||
ntfs-3g
|
||||
reflector
|
||||
zsh
|
||||
zsh-completions
|
||||
starship
|
||||
Executable
+50
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env bash
|
||||
# Stage 00 — sanity checks, mirror refresh, pacman quality-of-life.
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
|
||||
|
||||
log "Preflight"
|
||||
|
||||
require_arch
|
||||
require_not_root
|
||||
require_sudo
|
||||
|
||||
step "checking network connectivity"
|
||||
if ! ping -c1 -W3 archlinux.org >/dev/null 2>&1; then
|
||||
warn "cannot reach archlinux.org — package installation will fail"
|
||||
confirm "continue anyway?" || die "aborted"
|
||||
else
|
||||
ok "network reachable"
|
||||
fi
|
||||
|
||||
# --- pacman.conf niceties --------------------------------------------------
|
||||
step "enabling pacman colour output + parallel downloads"
|
||||
if [[ "$DRY_RUN" != "1" ]]; then
|
||||
sudo sed -i \
|
||||
-e 's/^#\(Color\)$/\1/' \
|
||||
-e 's/^#\(VerbosePkgLists\)$/\1/' \
|
||||
-e 's/^#\?ParallelDownloads.*/ParallelDownloads = 8/' \
|
||||
/etc/pacman.conf
|
||||
grep -q '^ParallelDownloads' /etc/pacman.conf || \
|
||||
sudo sed -i '/^\[options\]/a ParallelDownloads = 8' /etc/pacman.conf
|
||||
fi
|
||||
ok "pacman.conf tuned"
|
||||
|
||||
# --- multilib (optional, off by default) ----------------------------------
|
||||
if [[ "${ENABLE_MULTILIB:-0}" == "1" ]]; then
|
||||
step "enabling [multilib]"
|
||||
run sudo sed -i '/^#\[multilib\]$/,+1 s/^#//' /etc/pacman.conf
|
||||
fi
|
||||
|
||||
# --- mirrors ---------------------------------------------------------------
|
||||
if have reflector; then
|
||||
step "refreshing mirrorlist with reflector (this can take a minute)"
|
||||
run sudo reflector --protocol https --latest 20 --sort rate \
|
||||
--save /etc/pacman.d/mirrorlist || warn "reflector failed; keeping existing mirrorlist"
|
||||
else
|
||||
skip "reflector not installed yet — mirrors will be refreshed on the next run"
|
||||
fi
|
||||
|
||||
step "synchronising package databases"
|
||||
run sudo pacman -Syu --noconfirm
|
||||
|
||||
ok "preflight complete"
|
||||
Executable
+49
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env bash
|
||||
# Stage 10 — install everything available from the official repositories.
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
|
||||
|
||||
log "Installing official packages"
|
||||
|
||||
require_arch
|
||||
require_not_root
|
||||
require_sudo
|
||||
|
||||
mapfile -t PKGS < <(read_pkg_list "$PACKAGES_DIR/pacman.txt")
|
||||
[[ ${#PKGS[@]} -gt 0 ]] || die "pacman.txt yielded no packages"
|
||||
|
||||
# Split into "already installed" and "to install" so re-runs are quiet.
|
||||
TO_INSTALL=()
|
||||
for p in "${PKGS[@]}"; do
|
||||
if pacman -Qq "$p" >/dev/null 2>&1; then
|
||||
continue
|
||||
fi
|
||||
TO_INSTALL+=("$p")
|
||||
done
|
||||
|
||||
if [[ ${#TO_INSTALL[@]} -eq 0 ]]; then
|
||||
ok "all ${#PKGS[@]} packages already installed"
|
||||
else
|
||||
step "installing ${#TO_INSTALL[@]} of ${#PKGS[@]} packages"
|
||||
printf '%s %s%s\n' "$C_DIM" "${TO_INSTALL[*]}" "$C_RESET"
|
||||
# --needed keeps reinstalls off the table; failures on a single package
|
||||
# should not nuke the whole run, so retry one-by-one if the batch fails.
|
||||
if ! run sudo pacman -S --needed --noconfirm "${TO_INSTALL[@]}"; then
|
||||
warn "batch install failed — retrying package by package"
|
||||
for p in "${TO_INSTALL[@]}"; do
|
||||
run sudo pacman -S --needed --noconfirm "$p" || warn "could not install: $p"
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- GPU driver hint -------------------------------------------------------
|
||||
if lspci 2>/dev/null | grep -qi 'vga.*intel'; then
|
||||
step "Intel GPU detected — installing vulkan-intel"
|
||||
run sudo pacman -S --needed --noconfirm vulkan-intel intel-media-driver || true
|
||||
elif lspci 2>/dev/null | grep -qi 'vga.*amd\|vga.*ati'; then
|
||||
step "AMD GPU detected — installing vulkan-radeon"
|
||||
run sudo pacman -S --needed --noconfirm vulkan-radeon libva-mesa-driver || true
|
||||
elif lspci 2>/dev/null | grep -qi 'vga.*nvidia'; then
|
||||
warn "NVIDIA GPU detected — install 'nvidia' or 'nvidia-open' yourself; see README"
|
||||
fi
|
||||
|
||||
ok "official packages done"
|
||||
Executable
+51
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
# Stage 20 — bootstrap the yay AUR helper and install AUR packages.
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
|
||||
|
||||
log "AUR packages"
|
||||
|
||||
require_arch
|
||||
require_not_root
|
||||
require_sudo
|
||||
|
||||
# --- yay -------------------------------------------------------------------
|
||||
if have yay; then
|
||||
ok "yay already installed"
|
||||
else
|
||||
step "building yay-bin from the AUR"
|
||||
build_dir="$(mktemp -d)"
|
||||
if [[ "$DRY_RUN" == "1" ]]; then
|
||||
skip "would clone + makepkg yay-bin in $build_dir"
|
||||
else
|
||||
git clone --depth 1 https://aur.archlinux.org/yay-bin.git "$build_dir/yay-bin"
|
||||
( cd "$build_dir/yay-bin" && makepkg -si --noconfirm )
|
||||
rm -rf "$build_dir"
|
||||
fi
|
||||
ok "yay installed"
|
||||
fi
|
||||
|
||||
# --- i3lock -> i3lock-color swap ------------------------------------------
|
||||
# betterlockscreen needs i3lock-color; it conflicts with plain i3lock.
|
||||
if pacman -Qq i3lock >/dev/null 2>&1 && ! pacman -Qq i3lock-color >/dev/null 2>&1; then
|
||||
step "removing repo i3lock so i3lock-color can take over"
|
||||
run sudo pacman -Rdd --noconfirm i3lock || warn "could not remove i3lock; yay will prompt about the conflict"
|
||||
fi
|
||||
|
||||
mapfile -t AUR_PKGS < <(read_pkg_list "$PACKAGES_DIR/aur.txt")
|
||||
|
||||
TO_INSTALL=()
|
||||
for p in "${AUR_PKGS[@]}"; do
|
||||
pacman -Qq "$p" >/dev/null 2>&1 || TO_INSTALL+=("$p")
|
||||
done
|
||||
|
||||
if [[ ${#TO_INSTALL[@]} -eq 0 ]]; then
|
||||
ok "all AUR packages already installed"
|
||||
else
|
||||
step "installing: ${TO_INSTALL[*]}"
|
||||
for p in "${TO_INSTALL[@]}"; do
|
||||
run yay -S --needed --noconfirm --answerclean None --answerdiff None "$p" \
|
||||
|| warn "AUR package failed to build: $p (continuing)"
|
||||
done
|
||||
fi
|
||||
|
||||
ok "AUR stage done"
|
||||
Executable
+98
@@ -0,0 +1,98 @@
|
||||
#!/usr/bin/env bash
|
||||
# Stage 30 — deploy dotfiles into $HOME (backing up whatever was there).
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
|
||||
|
||||
log "Deploying dotfiles"
|
||||
|
||||
require_not_root
|
||||
|
||||
CFG="${XDG_CONFIG_HOME:-$HOME/.config}"
|
||||
|
||||
# --- home-level files ------------------------------------------------------
|
||||
install_file "$DOTFILES_DIR/xinitrc" "$HOME/.xinitrc" 755
|
||||
install_file "$DOTFILES_DIR/xprofile" "$HOME/.xprofile" 644
|
||||
install_file "$DOTFILES_DIR/Xresources" "$HOME/.Xresources" 644
|
||||
install_file "$DOTFILES_DIR/gtkrc-2.0" "$HOME/.gtkrc-2.0" 644
|
||||
|
||||
# --- ~/.config/* -----------------------------------------------------------
|
||||
# Copy each tracked file individually so untracked files the user added
|
||||
# (e.g. their own polybar module) survive a re-run.
|
||||
while IFS= read -r -d '' src; do
|
||||
rel="${src#"$DOTFILES_DIR"/config/}"
|
||||
install_file "$src" "$CFG/$rel" 644
|
||||
done < <(find "$DOTFILES_DIR/config" -type f -print0)
|
||||
|
||||
# --- executables -----------------------------------------------------------
|
||||
step "installing helper scripts to ~/.local/bin"
|
||||
run mkdir -p "$HOME/.local/bin"
|
||||
while IFS= read -r -d '' src; do
|
||||
install_file "$src" "$HOME/.local/bin/$(basename "$src")" 755
|
||||
done < <(find "$DOTFILES_DIR/local/bin" -type f -print0)
|
||||
|
||||
# Scripts inside ~/.config need the exec bit too
|
||||
for s in "$CFG/polybar/launch.sh" "$CFG/rofi/scripts/powermenu.sh"; do
|
||||
[[ -f "$s" ]] && run chmod 755 "$s"
|
||||
done
|
||||
if [[ -d "$CFG/i3/scripts" ]]; then
|
||||
run find "$CFG/i3/scripts" -type f -name '*.sh' -exec chmod 755 {} +
|
||||
fi
|
||||
|
||||
# --- user-owned override directories (never overwritten) -------------------
|
||||
run mkdir -p "$CFG/i3/config.d"
|
||||
# The include glob in the main config must match at least one file, otherwise
|
||||
# i3 complains on every reload — so ship a comment-only placeholder.
|
||||
if [[ ! -f "$CFG/i3/config.d/00-local.conf" && "$DRY_RUN" != "1" ]]; then
|
||||
cat > "$CFG/i3/config.d/00-local.conf" <<'TXT'
|
||||
# Personal i3 overrides.
|
||||
#
|
||||
# Every *.conf in this directory is included at the very END of
|
||||
# ~/.config/i3/config, so anything you put here wins over the defaults:
|
||||
# re-binding a key here silently replaces the earlier bindsym.
|
||||
#
|
||||
# This directory is never overwritten by the arch-i3 installer.
|
||||
#
|
||||
# Examples:
|
||||
# bindsym $mod+Shift+b exec --no-startup-id firefox
|
||||
# gaps inner 12
|
||||
# for_window [class="Spotify"] move to workspace $ws9
|
||||
TXT
|
||||
fi
|
||||
|
||||
# --- wallpapers ------------------------------------------------------------
|
||||
step "generating wallpapers"
|
||||
if [[ "$DRY_RUN" == "1" ]]; then
|
||||
skip "would generate wallpapers into $WALLPAPER_DIR"
|
||||
else
|
||||
mkdir -p "$WALLPAPER_DIR"
|
||||
# Prefer any images the user dropped into the repo's wallpapers/ dir
|
||||
shopt -s nullglob
|
||||
repo_walls=("$REPO_ROOT"/wallpapers/*.{png,jpg,jpeg,webp})
|
||||
shopt -u nullglob
|
||||
if [[ ${#repo_walls[@]} -gt 0 ]]; then
|
||||
cp -n "${repo_walls[@]}" "$WALLPAPER_DIR/" || true
|
||||
ok "copied ${#repo_walls[@]} wallpaper(s) from the repo"
|
||||
fi
|
||||
# Generate the Catppuccin set if the directory is still (nearly) empty
|
||||
if [[ $(find "$WALLPAPER_DIR" -maxdepth 1 -type f | wc -l) -lt 2 ]]; then
|
||||
# pipefail would turn a missing/failing xrandr into a stage abort
|
||||
geom=""
|
||||
if have xrandr; then
|
||||
geom="$(xrandr --query 2>/dev/null | awk '/\*/{print $1; exit}' || true)"
|
||||
fi
|
||||
"$REPO_ROOT/scripts/make-wallpaper.sh" "$WALLPAPER_DIR" "${geom:-2560x1440}" \
|
||||
|| warn "wallpaper generation failed (ImageMagick missing?)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- default applications --------------------------------------------------
|
||||
step "setting default applications"
|
||||
if [[ "$DRY_RUN" != "1" ]] && have xdg-mime; then
|
||||
xdg-mime default thunar.desktop inode/directory 2>/dev/null || true
|
||||
xdg-settings set default-web-browser firefox.desktop 2>/dev/null || true
|
||||
fi
|
||||
|
||||
if [[ -d "$BACKUP_DIR" ]]; then
|
||||
warn "previous configs were moved to: $(tildify "$BACKUP_DIR")"
|
||||
fi
|
||||
|
||||
ok "dotfiles deployed"
|
||||
Executable
+106
@@ -0,0 +1,106 @@
|
||||
#!/usr/bin/env bash
|
||||
# Stage 40 — enable system services, user services and groups.
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
|
||||
|
||||
log "Services & system integration"
|
||||
|
||||
require_arch
|
||||
require_not_root
|
||||
require_sudo
|
||||
|
||||
enable_system() {
|
||||
local unit="$1"
|
||||
if ! systemctl list-unit-files --no-legend | grep -q "^${unit}"; then
|
||||
skip "$unit not present"
|
||||
return 0
|
||||
fi
|
||||
if systemctl is-enabled --quiet "$unit" 2>/dev/null; then
|
||||
skip "$unit already enabled"
|
||||
else
|
||||
step "enabling $unit"
|
||||
run sudo systemctl enable --now "$unit"
|
||||
fi
|
||||
}
|
||||
|
||||
enable_user() {
|
||||
local unit="$1"
|
||||
if ! systemctl --user list-unit-files | grep -q "^${unit}"; then
|
||||
skip "user unit $unit not present"
|
||||
return 0
|
||||
fi
|
||||
if systemctl --user is-enabled --quiet "$unit" 2>/dev/null; then
|
||||
skip "user unit $unit already enabled"
|
||||
else
|
||||
step "enabling user unit $unit"
|
||||
run systemctl --user enable "$unit"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- system services -------------------------------------------------------
|
||||
enable_system NetworkManager.service
|
||||
enable_system bluetooth.service
|
||||
enable_system systemd-timesyncd.service
|
||||
|
||||
# --- user services ---------------------------------------------------------
|
||||
# pipewire is socket-activated; enabling the sockets is enough.
|
||||
enable_user pipewire.socket
|
||||
enable_user pipewire-pulse.socket
|
||||
enable_user wireplumber.service
|
||||
|
||||
# --- betterlockscreen on suspend ------------------------------------------
|
||||
# xss-lock (started from the i3 config) already handles lid-close and suspend.
|
||||
# The systemd unit below is the belt-and-braces version for logind-initiated
|
||||
# sleeps that happen outside the X session.
|
||||
if have betterlockscreen; then
|
||||
step "installing betterlockscreen@.service hook"
|
||||
if [[ "$DRY_RUN" != "1" ]]; then
|
||||
sudo tee /etc/systemd/system/betterlockscreen@.service >/dev/null <<UNIT
|
||||
[Unit]
|
||||
Description=Lock the screen with betterlockscreen before sleep
|
||||
Before=sleep.target
|
||||
[Service]
|
||||
User=%i
|
||||
Type=forking
|
||||
Environment=DISPLAY=:0
|
||||
ExecStart=/usr/bin/betterlockscreen --lock dimblur
|
||||
TimeoutSec=infinity
|
||||
[Install]
|
||||
WantedBy=sleep.target
|
||||
UNIT
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable "betterlockscreen@${USER}.service"
|
||||
fi
|
||||
ok "betterlockscreen sleep hook enabled"
|
||||
fi
|
||||
|
||||
# --- groups ----------------------------------------------------------------
|
||||
for grp in video input audio storage; do
|
||||
if getent group "$grp" >/dev/null && ! id -nG "$USER" | tr ' ' '\n' | grep -qx "$grp"; then
|
||||
step "adding $USER to group '$grp'"
|
||||
run sudo usermod -aG "$grp" "$USER"
|
||||
fi
|
||||
done
|
||||
|
||||
# --- font cache ------------------------------------------------------------
|
||||
step "rebuilding the font cache"
|
||||
run fc-cache -f >/dev/null
|
||||
if fc-list | grep -qi 'inconsolata.*nerd'; then
|
||||
ok "Inconsolata Nerd Font is available to X clients"
|
||||
else
|
||||
warn "Inconsolata Nerd Font not found by fontconfig — check that ttf-inconsolata-nerd installed"
|
||||
fi
|
||||
|
||||
# --- lock screen cache -----------------------------------------------------
|
||||
if have betterlockscreen; then
|
||||
wall="$(cat "${XDG_STATE_HOME:-$HOME/.local/state}/current-wallpaper" 2>/dev/null || true)"
|
||||
[[ -z "$wall" ]] && wall="$(find "$WALLPAPER_DIR" -maxdepth 1 -type f 2>/dev/null | sort | head -n1 || true)"
|
||||
if [[ -n "$wall" && -f "$wall" ]]; then
|
||||
step "building the betterlockscreen image cache (this takes a moment)"
|
||||
run betterlockscreen --update "$wall" --blur 0.5 >/dev/null 2>&1 \
|
||||
|| warn "betterlockscreen cache build failed; run 'betterlockscreen -u <image>' by hand"
|
||||
else
|
||||
skip "no wallpaper available yet — run 'betterlockscreen -u <image>' after first login"
|
||||
fi
|
||||
fi
|
||||
|
||||
ok "services configured"
|
||||
Executable
+83
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env bash
|
||||
# Stage 50 — apply the Catppuccin Macchiato theme to everything that needs
|
||||
# a runtime nudge rather than a config file.
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
|
||||
|
||||
log "Theming"
|
||||
|
||||
require_not_root
|
||||
|
||||
GTK_THEME_NAME="catppuccin-macchiato-mauve-standard+default"
|
||||
ICON_THEME="Papirus-Dark"
|
||||
CURSOR_THEME="catppuccin-macchiato-dark-cursors"
|
||||
|
||||
# --- verify the themes actually landed ------------------------------------
|
||||
theme_exists() {
|
||||
local name="$1" kind="$2" # kind: themes | icons
|
||||
[[ -d "/usr/share/$kind/$name" || -d "$HOME/.local/share/$kind/$name" || -d "$HOME/.$kind/$name" ]]
|
||||
}
|
||||
|
||||
if theme_exists "$GTK_THEME_NAME" themes; then
|
||||
ok "GTK theme found: $GTK_THEME_NAME"
|
||||
else
|
||||
warn "GTK theme '$GTK_THEME_NAME' not installed"
|
||||
# The AUR package name for the accent may differ; fall back to whatever
|
||||
# catppuccin-macchiato theme is present so apps are not left on Adwaita.
|
||||
found="$(find /usr/share/themes "$HOME/.local/share/themes" -maxdepth 1 \
|
||||
-iname 'catppuccin-macchiato*' -printf '%f\n' 2>/dev/null | sort | head -n1 || true)"
|
||||
if [[ -n "$found" ]]; then
|
||||
warn "using '$found' instead — updating the GTK settings files"
|
||||
GTK_THEME_NAME="$found"
|
||||
if [[ "$DRY_RUN" != "1" ]]; then
|
||||
sed -i "s/^gtk-theme-name=.*/gtk-theme-name=$GTK_THEME_NAME/" \
|
||||
"$HOME/.config/gtk-3.0/settings.ini" "$HOME/.config/gtk-4.0/settings.ini" 2>/dev/null || true
|
||||
sed -i "s/^gtk-theme-name=.*/gtk-theme-name=\"$GTK_THEME_NAME\"/" \
|
||||
"$HOME/.gtkrc-2.0" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
theme_exists "$ICON_THEME" icons || warn "icon theme '$ICON_THEME' not installed"
|
||||
theme_exists "$CURSOR_THEME" icons || warn "cursor theme '$CURSOR_THEME' not installed"
|
||||
|
||||
# --- Papirus folders in Catppuccin colours --------------------------------
|
||||
if have papirus-folders; then
|
||||
step "recolouring Papirus folders (mauve)"
|
||||
run sudo papirus-folders -C cat-macchiato-mauve --theme Papirus-Dark >/dev/null 2>&1 \
|
||||
|| warn "papirus-folders failed; folders keep the stock colour"
|
||||
fi
|
||||
|
||||
# --- default cursor theme (used by the root window and non-GTK apps) ------
|
||||
step "setting the default X cursor theme"
|
||||
if [[ "$DRY_RUN" != "1" ]]; then
|
||||
mkdir -p "$HOME/.icons/default"
|
||||
cat > "$HOME/.icons/default/index.theme" <<INI
|
||||
[Icon Theme]
|
||||
Name=Default
|
||||
Comment=Default cursor theme
|
||||
Inherits=$CURSOR_THEME
|
||||
INI
|
||||
fi
|
||||
ok "cursor theme set to $CURSOR_THEME"
|
||||
|
||||
# --- dconf/gsettings, for the handful of apps that ignore settings.ini ----
|
||||
if have gsettings; then
|
||||
step "applying gsettings desktop preferences"
|
||||
run gsettings set org.gnome.desktop.interface gtk-theme "$GTK_THEME_NAME" 2>/dev/null || true
|
||||
run gsettings set org.gnome.desktop.interface icon-theme "$ICON_THEME" 2>/dev/null || true
|
||||
run gsettings set org.gnome.desktop.interface cursor-theme "$CURSOR_THEME" 2>/dev/null || true
|
||||
run gsettings set org.gnome.desktop.interface font-name "Inconsolata Nerd Font 11" 2>/dev/null || true
|
||||
run gsettings set org.gnome.desktop.interface monospace-font-name "Inconsolata Nerd Font 11" 2>/dev/null || true
|
||||
run gsettings set org.gnome.desktop.interface color-scheme "prefer-dark" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# --- reload anything already running --------------------------------------
|
||||
if [[ -n "${DISPLAY:-}" && "$DRY_RUN" != "1" ]]; then
|
||||
step "reloading the live session"
|
||||
xrdb -merge "$HOME/.Xresources" 2>/dev/null || true
|
||||
have i3-msg && i3-msg reload >/dev/null 2>&1 || true
|
||||
have dunstctl && dunstctl reload >/dev/null 2>&1 || true
|
||||
[[ -x "$HOME/.config/polybar/launch.sh" ]] && "$HOME/.config/polybar/launch.sh" || true
|
||||
fi
|
||||
|
||||
ok "theming applied"
|
||||
Executable
+117
@@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env bash
|
||||
# Shared helpers for the arch-i3 bootstrap scripts.
|
||||
# Sourced, never executed directly.
|
||||
|
||||
set -Eeuo pipefail
|
||||
|
||||
# --- paths -----------------------------------------------------------------
|
||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
DOTFILES_DIR="$REPO_ROOT/dotfiles"
|
||||
PACKAGES_DIR="$REPO_ROOT/packages"
|
||||
WALLPAPER_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/wallpapers"
|
||||
BACKUP_DIR="$HOME/.config-backup-$(date +%Y%m%d-%H%M%S)"
|
||||
|
||||
# --- flags (exported by install.sh) ---------------------------------------
|
||||
: "${DRY_RUN:=0}"
|
||||
: "${ASSUME_YES:=0}"
|
||||
|
||||
# --- colours ---------------------------------------------------------------
|
||||
if [[ -t 1 ]]; then
|
||||
C_RESET=$'\e[0m'; C_BOLD=$'\e[1m'; C_DIM=$'\e[2m'
|
||||
C_BLUE=$'\e[38;5;111m'; C_GREEN=$'\e[38;5;115m'
|
||||
C_YELLOW=$'\e[38;5;222m'; C_RED=$'\e[38;5;210m'; C_MAUVE=$'\e[38;5;140m'
|
||||
else
|
||||
C_RESET=''; C_BOLD=''; C_DIM=''
|
||||
C_BLUE=''; C_GREEN=''; C_YELLOW=''; C_RED=''; C_MAUVE=''
|
||||
fi
|
||||
|
||||
log() { printf '%s==>%s %s\n' "$C_BLUE$C_BOLD" "$C_RESET" "$*"; }
|
||||
step() { printf '%s ->%s %s\n' "$C_MAUVE" "$C_RESET" "$*"; }
|
||||
ok() { printf '%s ok%s %s\n' "$C_GREEN" "$C_RESET" "$*"; }
|
||||
warn() { printf '%s !!%s %s\n' "$C_YELLOW" "$C_RESET" "$*" >&2; }
|
||||
die() { printf '%serror%s %s\n' "$C_RED$C_BOLD" "$C_RESET" "$*" >&2; exit 1; }
|
||||
skip() { printf '%s --%s %s\n' "$C_DIM" "$C_RESET" "$*"; }
|
||||
|
||||
# Run a command, honouring DRY_RUN.
|
||||
run() {
|
||||
if [[ "$DRY_RUN" == "1" ]]; then
|
||||
printf '%s dry%s %s\n' "$C_DIM" "$C_RESET" "$*"
|
||||
return 0
|
||||
fi
|
||||
"$@"
|
||||
}
|
||||
|
||||
confirm() {
|
||||
[[ "$ASSUME_YES" == "1" ]] && return 0
|
||||
[[ "$DRY_RUN" == "1" ]] && return 0
|
||||
local reply
|
||||
read -rp "$(printf '%s ??%s %s [y/N] ' "$C_YELLOW" "$C_RESET" "$1")" reply
|
||||
[[ "$reply" =~ ^[Yy]$ ]]
|
||||
}
|
||||
|
||||
have() { command -v "$1" >/dev/null 2>&1; }
|
||||
|
||||
# Print a path with $HOME collapsed to '~'. Done as a function because the
|
||||
# obvious ${path/#$HOME/~} keeps a literal backslash in the replacement.
|
||||
tildify() {
|
||||
local p="$1"
|
||||
if [[ "$p" == "$HOME"/* ]]; then
|
||||
printf '~/%s' "${p#"$HOME"/}"
|
||||
elif [[ "$p" == "$HOME" ]]; then
|
||||
printf '~'
|
||||
else
|
||||
printf '%s' "$p"
|
||||
fi
|
||||
}
|
||||
|
||||
# Read a package list file, dropping comments and blanks.
|
||||
read_pkg_list() {
|
||||
local file="$1"
|
||||
[[ -f "$file" ]] || die "package list not found: $file"
|
||||
sed -e 's/#.*$//' -e 's/[[:space:]]\+$//' "$file" | grep -v '^[[:space:]]*$' || true
|
||||
}
|
||||
|
||||
# Guard rails common to every stage.
|
||||
require_arch() {
|
||||
[[ -f /etc/arch-release ]] || die "this bootstrap targets Arch Linux (no /etc/arch-release found)"
|
||||
}
|
||||
|
||||
require_not_root() {
|
||||
[[ "$(id -u)" -ne 0 ]] || die "run this as your normal user, not root — sudo is invoked where needed"
|
||||
}
|
||||
|
||||
require_sudo() {
|
||||
have sudo || die "sudo is not installed; install it and add your user to the wheel group first"
|
||||
if [[ "$DRY_RUN" != "1" ]]; then
|
||||
sudo -v || die "sudo authentication failed"
|
||||
# Keep the sudo timestamp alive for the length of the run.
|
||||
( while true; do sudo -n true; sleep 50; kill -0 "$$" 2>/dev/null || exit; done ) &
|
||||
SUDO_KEEPALIVE_PID=$!
|
||||
trap 'kill "$SUDO_KEEPALIVE_PID" 2>/dev/null || true' EXIT
|
||||
fi
|
||||
}
|
||||
|
||||
# Back up a path (file, dir or symlink) into $BACKUP_DIR, preserving structure.
|
||||
backup_path() {
|
||||
local target="$1"
|
||||
[[ -e "$target" || -L "$target" ]] || return 0
|
||||
local rel="${target#"$HOME"/}"
|
||||
local dest="$BACKUP_DIR/$rel"
|
||||
step "backing up $(tildify "$target") -> $(tildify "$dest")"
|
||||
run mkdir -p "$(dirname "$dest")"
|
||||
run mv "$target" "$dest"
|
||||
}
|
||||
|
||||
# Copy a file from the repo into place, backing up whatever was there.
|
||||
install_file() {
|
||||
local src="$1" dest="$2" mode="${3:-644}"
|
||||
[[ -f "$src" ]] || die "missing source file: $src"
|
||||
if [[ -f "$dest" ]] && cmp -s "$src" "$dest"; then
|
||||
skip "$(tildify "$dest") already up to date"
|
||||
return 0
|
||||
fi
|
||||
backup_path "$dest"
|
||||
run mkdir -p "$(dirname "$dest")"
|
||||
run install -m "$mode" "$src" "$dest"
|
||||
ok "installed $(tildify "$dest")"
|
||||
}
|
||||
Executable
+70
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env bash
|
||||
# ---------------------------------------------------------------------------
|
||||
# Generate Catppuccin Macchiato wallpapers with ImageMagick.
|
||||
# Shipping binary images in a config repo is rude, so we synthesise them.
|
||||
# usage: make-wallpaper.sh [output-dir] [WIDTHxHEIGHT]
|
||||
# ---------------------------------------------------------------------------
|
||||
set -euo pipefail
|
||||
|
||||
OUT_DIR="${1:-${XDG_DATA_HOME:-$HOME/.local/share}/wallpapers}"
|
||||
GEOM="${2:-3840x2160}"
|
||||
W="${GEOM%x*}"
|
||||
H="${GEOM#*x}"
|
||||
|
||||
# ImageMagick 7 uses `magick`; 6 uses `convert`.
|
||||
if command -v magick >/dev/null 2>&1; then IM=(magick)
|
||||
elif command -v convert >/dev/null 2>&1; then IM=(convert)
|
||||
else
|
||||
echo "make-wallpaper: ImageMagick not found — skipping wallpaper generation" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mkdir -p "$OUT_DIR"
|
||||
|
||||
base="#24273a"
|
||||
mantle="#1e2030"
|
||||
crust="#181926"
|
||||
mauve="#c6a0f6"
|
||||
blue="#8aadf4"
|
||||
teal="#8bd5ca"
|
||||
pink="#f5bde6"
|
||||
|
||||
# --- 1. soft diagonal gradient --------------------------------------------
|
||||
"${IM[@]}" -size "${W}x${H}" \
|
||||
"gradient:${mantle}-${crust}" \
|
||||
-rotate 45 -gravity center -extent "${W}x${H}" \
|
||||
-blur 0x24 \
|
||||
"$OUT_DIR/macchiato-gradient.png"
|
||||
|
||||
# --- 2. radial glow over the base colour ----------------------------------
|
||||
"${IM[@]}" -size "${W}x${H}" "xc:${base}" \
|
||||
\( -size "${W}x${H}" "radial-gradient:${mauve}-${base}" -alpha set -channel A -evaluate multiply 0.22 +channel \) \
|
||||
-compose over -composite \
|
||||
\( -size "${W}x${H}" "radial-gradient:${teal}-${base}" -alpha set -channel A -evaluate multiply 0.12 +channel -roll +$((W/3))+$((H/3)) \) \
|
||||
-compose over -composite \
|
||||
-blur 0x40 \
|
||||
"$OUT_DIR/macchiato-glow.png"
|
||||
|
||||
# --- 3. subtle triangle/mosaic texture ------------------------------------
|
||||
"${IM[@]}" -size "$((W/12))x$((H/12))" "xc:${base}" \
|
||||
+noise Gaussian -blur 0x2 -normalize \
|
||||
-level 40%,60% \
|
||||
-fill "${base}" -colorize 82% \
|
||||
-resize "${W}x${H}!" -blur 0x3 \
|
||||
"$OUT_DIR/macchiato-texture.png"
|
||||
|
||||
# --- 4. flat base, for people who want zero distraction -------------------
|
||||
"${IM[@]}" -size "${W}x${H}" "xc:${base}" "$OUT_DIR/macchiato-flat.png"
|
||||
|
||||
# --- 5. logo-ish centred mark on the gradient -----------------------------
|
||||
"${IM[@]}" "$OUT_DIR/macchiato-gradient.png" \
|
||||
-gravity center \
|
||||
-fill "${mauve}" -stroke none \
|
||||
-draw "circle $((W/2)),$((H/2)) $((W/2)),$((H/2 - H/9))" \
|
||||
-fill "${base}" \
|
||||
-draw "circle $((W/2)),$((H/2)) $((W/2)),$((H/2 - H/9 + H/90))" \
|
||||
-blur 0x1 \
|
||||
"$OUT_DIR/macchiato-ring.png"
|
||||
|
||||
echo "wallpapers written to $OUT_DIR:"
|
||||
ls -1 "$OUT_DIR"
|
||||
Executable
+33
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
# ---------------------------------------------------------------------------
|
||||
# Put back the configs that install.sh moved aside.
|
||||
# scripts/restore-backup.sh # restore the most recent backup
|
||||
# scripts/restore-backup.sh <dir> # restore a specific backup
|
||||
# scripts/restore-backup.sh --list # show available backups
|
||||
# ---------------------------------------------------------------------------
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
|
||||
|
||||
mapfile -t BACKUPS < <(find "$HOME" -maxdepth 1 -type d -name '.config-backup-*' | sort -r)
|
||||
|
||||
if [[ "${1:-}" == "--list" ]]; then
|
||||
if [[ ${#BACKUPS[@]} -eq 0 ]]; then
|
||||
echo "no backups found in $HOME"
|
||||
else
|
||||
printf '%s\n' "${BACKUPS[@]}"
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
SRC="${1:-${BACKUPS[0]:-}}"
|
||||
[[ -n "$SRC" ]] || die "no backup directories found (looked for ~/.config-backup-*)"
|
||||
[[ -d "$SRC" ]] || die "not a directory: $SRC"
|
||||
|
||||
log "Restoring from ${SRC/#$HOME/\~}"
|
||||
step "the following files will be copied back over your current configs:"
|
||||
(cd "$SRC" && find . -type f | sed 's|^\./| ~/|')
|
||||
|
||||
confirm "Restore these files?" || die "aborted"
|
||||
|
||||
# -a preserves modes; the trailing /. copies the contents, not the directory.
|
||||
run cp -a "$SRC/." "$HOME/"
|
||||
ok "restored — restart i3 (Super+Shift+R) or log out and back in"
|
||||
@@ -0,0 +1,21 @@
|
||||
# wallpapers
|
||||
|
||||
Drop your own images here (`.png`, `.jpg`, `.jpeg`, `.webp`).
|
||||
|
||||
Stage `30-dotfiles` copies everything in this directory into
|
||||
`~/.local/share/wallpapers/`. If the directory is empty, the installer
|
||||
synthesises a small set of Catppuccin Macchiato wallpapers instead, via
|
||||
`scripts/make-wallpaper.sh` and ImageMagick — sized to your primary display.
|
||||
|
||||
Generate them by hand at any time:
|
||||
|
||||
```sh
|
||||
scripts/make-wallpaper.sh ~/.local/share/wallpapers 3840x2160
|
||||
```
|
||||
|
||||
Apply one, which also refreshes the betterlockscreen cache:
|
||||
|
||||
```sh
|
||||
set-wallpaper ~/.local/share/wallpapers/macchiato-glow.png
|
||||
set-wallpaper --random # or Super+Shift+W
|
||||
```
|
||||
Reference in New Issue
Block a user