diff --git a/.config/dms/settings.json b/.config/dms/settings.json
index 5dde39b..9f189ea 100644
--- a/.config/dms/settings.json
+++ b/.config/dms/settings.json
@@ -131,7 +131,7 @@
}
],
"configVersion": 42,
- "popupTransparency": 0.86,
+ "popupTransparency": 0.95,
"fontFamily": "JetBrains Mono Medium",
"audioVisualizerEnabled": true,
"scrollTitleEnabled": true,
@@ -267,5 +267,7 @@
}
],
"monoFontFamily": "JetBrains Mono",
- "displayFontFamily": "JetBrains Mono"
+ "displayFontFamily": "JetBrains Mono",
+ "fontWeight": 300,
+ "fontScale": 1
}
\ No newline at end of file
diff --git a/.config/dunst/dunstrc b/.config/dunst/dunstrc
deleted file mode 100644
index 7c95221..0000000
--- a/.config/dunst/dunstrc
+++ /dev/null
@@ -1,37 +0,0 @@
-[global]
- monitor = 0
- follow = mouse
- width = (250, 360)
- origin = top-right
- offset = (12, 48)
- gap_size = 8
- corner_radius = 14
- frame_width = 1
- padding = 12
- horizontal_padding = 14
- font = JetBrains Mono 10
- format = "%s\n%b"
- icon_position = left
- max_icon_size = 48
- transparency = 0
- icon_corner_radius = 8
- progress_bar_corner_radius = 4
- progress_bar_height = 8
-
-[urgency_low]
- background = "#0c0c0c99"
- foreground = "#e8e8e8"
- frame_color = "#e8e8e815"
- timeout = 5
-
-[urgency_normal]
- background = "#0c0c0c99"
- foreground = "#e8e8e8"
- frame_color = "#e8e8e830"
- timeout = 8
-
-[urgency_critical]
- background = "#0c0c0c99"
- foreground = "#e8e8e8"
- frame_color = "#ff5c5c"
- timeout = 0
diff --git a/.config/rofi/catppuccin.rasi b/.config/rofi/catppuccin.rasi
deleted file mode 100644
index 20a8df8..0000000
--- a/.config/rofi/catppuccin.rasi
+++ /dev/null
@@ -1,25 +0,0 @@
-* {
- base: #0c0c0c; surface: #1c1c1c; text: #e8e8e8; mauve: #e8e8e8; subtext: #8c8c8c;
- background-color: transparent;
- text-color: @text;
- font: "JetBrains Mono 12";
-}
-window {
- background-color: rgba(12,12,12,0.60);
- border: 1px; border-color: rgba(232,232,232,0.14); border-radius: 20px;
- padding: 18px;
- width: 600px;
-}
-mainbox { spacing: 10px; }
-inputbar {
- background-color: rgba(255,255,255,0.07); border-radius: 14px; padding: 12px 16px; spacing: 8px;
- children: [ prompt, entry ];
-}
-prompt { text-color: @mauve; }
-entry { placeholder: "Search..."; placeholder-color: @subtext; }
-listview { lines: 8; scrollbar: false; spacing: 4px; fixed-height: true; }
-element { padding: 9px 14px; border-radius: 14px; spacing: 10px; }
-element selected { background-color: rgba(232,232,232,0.92); text-color: #0c0c0c; }
-element-text { text-color: inherit; }
-element selected element-text { text-color: #0c0c0c; }
-element-icon { size: 1.4em; }
diff --git a/.config/rofi/cyberpunk.rasi b/.config/rofi/cyberpunk.rasi
deleted file mode 100644
index f6a13e2..0000000
--- a/.config/rofi/cyberpunk.rasi
+++ /dev/null
@@ -1,23 +0,0 @@
-* {
- background-color: #05050a;
- text-color: #fcee09;
- border-color: #fcee09;
- font: "monospace 11";
-}
-
-window {
- border: 2px;
- padding: 15px;
- width: 500px;
-}
-
-element selected {
- background-color: #fcee09;
- text-color: #000000;
-}
-
-entry {
- placeholder: "OVERRIDE_SYSTEM...";
- placeholder-color:#444444;
- text-color: #ff003c;
-}
diff --git a/.config/rofi/powermenu.sh b/.config/rofi/powermenu.sh
deleted file mode 100755
index 7dd0af6..0000000
--- a/.config/rofi/powermenu.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-# Power menu in rofi
-opts=$' Lock\n Logout\n Suspend\n Reboot\n Shutdown'
-choice=$(printf '%s' "$opts" | rofi -dmenu -i -p "Power" -theme ~/.config/rofi/catppuccin.rasi -theme-str 'window {width: 300px;} listview {lines: 5;} entry {enabled: false;}')
-case "$choice" in
- *Lock) ~/.config/sway/lock.sh ;;
- *Logout) swaymsg exit ;;
- *Suspend) systemctl suspend ;;
- *Reboot) systemctl reboot ;;
- *Shutdown) systemctl poweroff ;;
-esac
diff --git a/.config/rofi/style.css b/.config/rofi/style.css
deleted file mode 100644
index 4efbf70..0000000
--- a/.config/rofi/style.css
+++ /dev/null
@@ -1,17 +0,0 @@
-window {
- background-color: #050B14;
- border: 2px solid #FF0055;
- font-family: "Orbitron", sans-serif;
-}
-
-#input {
- background-color: #0D0F18;
- color: #00F0FF;
- border: 1px solid #FF0055;
- margin: 10px;
-}
-
-#entry:selected {
- background-color: #FF0055;
- color: #050B14;
-}
diff --git a/.config/swappy/config b/.config/swappy/config
new file mode 100644
index 0000000..c3712f3
--- /dev/null
+++ b/.config/swappy/config
@@ -0,0 +1,8 @@
+[Default]
+save_dir=$HOME/Pictures/Screenshots
+save_filename_format=screenshot_%Y-%m-%d_%H-%M-%S_edited.png
+early_exit=true
+auto_save=false
+show_panel=true
+line_size=5
+text_size=20
diff --git a/.config/sway/bt-menu.sh b/.config/sway/bt-menu.sh
deleted file mode 100755
index 6919e13..0000000
--- a/.config/sway/bt-menu.sh
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/usr/bin/env bash
-# Bluetooth menu (rofi): power, connect/disconnect known devices, scan and pair new ones.
-THEME=~/.config/rofi/catppuccin.rasi
-menu() { rofi -dmenu -i -p "$1" -theme "$THEME" "${@:2}"; }
-
-if ! bluetoothctl show | grep -q "Powered: yes"; then
- choice=$(printf '%s\n' "Включить Bluetooth" | menu "Bluetooth") || exit 0
- [[ $choice == "Включить Bluetooth" ]] && bluetoothctl power on >/dev/null && notify-send "Bluetooth" "Включён"
- exit 0
-fi
-
-build() {
- local list="" mac name mark
- while read -r _ mac name; do
- [[ -z $mac ]] && continue
- mark="○"; bluetoothctl info "$mac" | grep -q "Connected: yes" && mark="●"
- list+="$mark $name [$mac]"$'\n'
- done < <(bluetoothctl devices)
- printf '%s' "$list"
-}
-
-choice=$(printf '%s%s\n%s\n' "$(build)" "Найти новые устройства" "Выключить Bluetooth" | sed '/^$/d' | menu "Bluetooth") || exit 0
-[[ -z $choice ]] && exit 0
-
-case $choice in
- "Выключить Bluetooth") bluetoothctl power off >/dev/null; notify-send "Bluetooth" "Выключен"; exit 0 ;;
- "Найти новые устройства")
- notify-send "Bluetooth" "Поиск устройств (8 с)…"
- bluetoothctl --timeout 8 scan on >/dev/null 2>&1
- choice=$(build | menu "Bluetooth: найденные") || exit 0
- [[ -z $choice ]] && exit 0
- mac=${choice##*[}; mac=${mac%]}
- bluetoothctl pair "$mac" >/dev/null 2>&1; bluetoothctl trust "$mac" >/dev/null 2>&1
- bluetoothctl connect "$mac" >/dev/null 2>&1 && notify-send "Bluetooth" "Подключено" || notify-send -u critical "Bluetooth" "Не удалось подключиться"
- exit 0 ;;
-esac
-
-mac=${choice##*[}; mac=${mac%]}
-name=${choice:2}; name=${name% [*}
-if [[ ${choice:0:1} == "●" ]]; then
- bluetoothctl disconnect "$mac" >/dev/null && notify-send "Bluetooth" "Отключено: $name"
-else
- bluetoothctl connect "$mac" >/dev/null 2>&1 && notify-send "Bluetooth" "Подключено: $name" || notify-send -u critical "Bluetooth" "Не удалось подключиться: $name"
-fi
diff --git a/.config/sway/cheatsheet.sh b/.config/sway/cheatsheet.sh
index d6117c4..581fb1c 100755
--- a/.config/sway/cheatsheet.sh
+++ b/.config/sway/cheatsheet.sh
@@ -1,6 +1,5 @@
#!/bin/bash
-# Shows all sway keybindings in rofi
+# Shows all sway keybindings in the DMS picker (type to filter, Esc to close)
cat ~/.config/sway/config ~/.config/sway/config.d/*.conf | grep -E '^\s*bindsym' | grep -v -- '--locked' \
| sed -E 's/^\s*bindsym\s+//; s/(--[a-z-]+(=[^ ]+)?\s+)+//; s/\$mod/Super/g; s/^(\S+)\s+/\1\t→ /' \
- | column -t -s $'\t' | rofi -dmenu -i -p "Keys" -theme ~/.config/rofi/catppuccin.rasi \
- -theme-str 'window {width: 900px;} listview {lines: 14;} entry {placeholder: "Filter...";}' >/dev/null
+ | column -t -s $'\t' | dms dmenu >/dev/null
diff --git a/.config/sway/config b/.config/sway/config
index f7389b8..4a15b57 100644
--- a/.config/sway/config
+++ b/.config/sway/config
@@ -16,22 +16,10 @@ set $right l
# Your preferred terminal emulator
# Recommends: foot
set $term kitty
-# Your preferred application launcher
-# Note: pass the final command to swaymsg so that the resulting window can be opened
-# on the original workspace that the command was run on.
-# Recommends: rofi-wayland
-set $rofi_cmd rofi -theme ~/.config/rofi/catppuccin.rasi \
- -terminal '$term'
-# Shows a combined list of the applications with desktop files and
-# executables from PATH.
-# TODO: add window with the next release of rofi-wayland
-set $menu $rofi_cmd -show combi -combi-modes drun#run -modes combi
### Output configuration
#
-# Default wallpaper (more resolutions are available in /usr/share/backgrounds/sway/)
-# Requires: desktop-backgrounds-compat, swaybg, jxl-pixbuf-loader
-output * bg /usr/share/backgrounds/default.jxl fill
+# Wallpaper is handled by DankMaterialShell (Settings > Wallpaper), not by sway.
#
# Example configuration:
#
diff --git a/.config/sway/config.d/00-session.conf b/.config/sway/config.d/00-session.conf
new file mode 100644
index 0000000..9c9ea89
--- /dev/null
+++ b/.config/sway/config.d/00-session.conf
@@ -0,0 +1,5 @@
+# Session plumbing so portals (screen sharing, file dialogs, dark mode) and D-Bus activated apps work on any distro.
+# Fedora's sway-systemd already does the same; running it twice is harmless.
+exec_always dbus-update-activation-environment --systemd WAYLAND_DISPLAY DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP XDG_SESSION_TYPE
+exec systemctl --user import-environment WAYLAND_DISPLAY DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP XDG_SESSION_TYPE
+exec systemctl --user start sway-session.target
diff --git a/.config/sway/config.d/05-outputs.conf b/.config/sway/config.d/05-outputs.conf.example
similarity index 100%
rename from .config/sway/config.d/05-outputs.conf
rename to .config/sway/config.d/05-outputs.conf.example
diff --git a/.config/sway/config.d/10-appearance.conf b/.config/sway/config.d/10-appearance.conf
index e8eb322..0ce68be 100644
--- a/.config/sway/config.d/10-appearance.conf
+++ b/.config/sway/config.d/10-appearance.conf
@@ -28,7 +28,6 @@ client.placeholder $base $base $text $base $base
client.background $base
# Autostart
-exec_always sh -c 'pkill -x dunst; pkill -x swaync; true'
exec_always sh -c 'pkill -x nm-applet; exec nm-applet --indicator'
bindsym --to-code $mod+Shift+x exec ~/.config/sway/lock.sh
@@ -45,12 +44,10 @@ input type:touchpad {
# Window rules
for_window [app_id="pavucontrol|nm-connection-editor|blueman-manager"] floating enable, resize set 700 500, border pixel 2
for_window [window_role="pop-up"] floating enable
-for_window [app_id="rofi"] border none
titlebar_padding 10 4
focus_follows_mouse no
workspace_auto_back_and_forth yes
bindsym --to-code $mod+Shift+p exec dms ipc call powermenu toggle
-# Wallpaper + idle/lock
-output * bg ~/Pictures/wallpapers/current fill
+# Idle / lock
exec_always ~/.config/sway/idle.sh
diff --git a/.config/sway/config.d/20-swayfx.conf b/.config/sway/config.d/20-swayfx.conf
index 73836f3..9ea199b 100644
--- a/.config/sway/config.d/20-swayfx.conf
+++ b/.config/sway/config.d/20-swayfx.conf
@@ -29,12 +29,7 @@ dim_inactive_colors.urgent #ff5c5c
# Thin outline instead of fat border -> cleaner look
titlebar_separator disable
-# Frosted glass for layers
-layer_effects "waybar" blur enable; blur_ignore_transparent enable; corner_radius 14; shadows enable
-layer_effects "rofi" blur enable; blur_ignore_transparent enable; corner_radius 20; shadows enable
-layer_effects "notifications" blur enable; blur_ignore_transparent enable; corner_radius 14; shadows enable
-layer_effects "swaync-control-center" blur enable; blur_ignore_transparent enable; corner_radius 20; shadows enable
-layer_effects "swaync-notification-window" blur enable; blur_ignore_transparent enable; corner_radius 14; shadows enable
+# Frosted glass for sway's own layers (DMS layers: 21-dms-effects.conf)
layer_effects "swaynag" blur enable; blur_ignore_transparent enable; corner_radius 12
# Translucent terminals, glass shows through
diff --git a/.config/sway/config.d/21-dms-effects.conf b/.config/sway/config.d/21-dms-effects.conf
new file mode 100644
index 0000000..22c57bf
--- /dev/null
+++ b/.config/sway/config.d/21-dms-effects.conf
@@ -0,0 +1,8 @@
+# SwayFX blur for DMS surfaces (layer names: swaymsg -t get_outputs -r | jq '.[].layer_shell_surfaces[].namespace').
+# Only blur: DMS surfaces are bigger than what is drawn, so shadows / corner_radius here would paint
+# a glow and rounded corners around the whole (often full-screen) layer.
+# SwayFX-only: install.sh drops this file when plain sway is used.
+layer_effects "dms:bar" blur enable; blur_ignore_transparent enable
+layer_effects "dms:notification-popup" blur enable; blur_ignore_transparent enable
+layer_effects "dms:osd" blur enable; blur_ignore_transparent enable
+layer_effects "dms:dock" blur enable; blur_ignore_transparent enable
diff --git a/.config/sway/config.d/30-workflow.conf b/.config/sway/config.d/30-workflow.conf
index 3f35cc3..11335e7 100644
--- a/.config/sway/config.d/30-workflow.conf
+++ b/.config/sway/config.d/30-workflow.conf
@@ -15,20 +15,20 @@ bindsym --to-code $mod+Ctrl+Left workspace prev_on_output
bindsym --to-code $mod+Shift+f floating toggle, resize set 1000 600, move position center
bindsym --to-code $mod+c exec swaymsg [con_id=__focused__] move position center
-# Screenshots: area -> clipboard, area -> file
-bindsym --to-code Shift+Print exec ~/.config/sway/screenshot.sh clip
-bindsym --to-code $mod+Print exec ~/.config/sway/screenshot.sh file
+# Screenshots (saved to ~/Pictures/Screenshots and copied to the clipboard)
+bindsym --to-code Print exec ~/.config/sway/screenshot.sh region
+bindsym --to-code $mod+Shift+s exec ~/.config/sway/screenshot.sh region
+bindsym --to-code Shift+Print exec ~/.config/sway/screenshot.sh full
+bindsym --to-code Ctrl+Print exec ~/.config/sway/screenshot.sh window
+bindsym --to-code Alt+Print exec ~/.config/sway/screenshot.sh scroll
+bindsym --to-code $mod+Print exec ~/.config/sway/screenshot.sh last
+bindsym --to-code Ctrl+Shift+Print exec ~/.config/sway/screenshot.sh edit
# Keep video/browser-video windows undimmed
for_window [app_id="firefox"] inhibit_idle fullscreen
for_window [app_id="mpv"] floating enable, dim_inactive 0
-# Mirror internal screen to HDMI/TV on hotplug
-exec_always ~/.config/sway/mirror.sh
-
# Rice helpers
-bindsym --to-code $mod+Shift+w exec ~/.config/sway/wallpaper.sh
-bindsym --to-code $mod+Shift+s exec ~/.config/sway/screenshot-menu.sh
bindsym --to-code $mod+F1 exec ~/.config/sway/cheatsheet.sh
# Performance mode: toggle blur + shadows
bindsym --to-code $mod+Shift+b blur toggle; shadows toggle
diff --git a/.config/sway/config.d/40-bar.conf.off b/.config/sway/config.d/40-bar.conf.off
deleted file mode 100644
index 06e4437..0000000
--- a/.config/sway/config.d/40-bar.conf.off
+++ /dev/null
@@ -1,4 +0,0 @@
-# Waybar (replaces sway-config-fedora's 90-bar.conf, which isn't installed with swayfx)
-bar {
- swaybar_command waybar
-}
diff --git a/.config/sway/config.d/50-dms.conf b/.config/sway/config.d/50-dms.conf
index e93719b..0cd0396 100644
--- a/.config/sway/config.d/50-dms.conf
+++ b/.config/sway/config.d/50-dms.conf
@@ -4,15 +4,6 @@ exec_always sh -c 'pgrep -x dms >/dev/null || exec dms run'
# Hotkeys: $mod+d launcher, $mod+n control center, $mod+Shift+n notifications, $mod+Shift+p power menu (set in config / config.d)
bindsym --to-code $mod+Shift+v exec dms ipc call clipboard toggle
-
-# SwayFX blur for DMS surfaces (layer names: swaymsg -t get_outputs -r | jq '.[].layer_shell_surfaces[].namespace').
-# Only blur: DMS surfaces are bigger than what is drawn, so shadows / corner_radius here would paint
-# a glow and rounded corners around the whole (often full-screen) layer.
-layer_effects "dms:bar" blur enable; blur_ignore_transparent enable
-layer_effects "dms:notification-popup" blur enable; blur_ignore_transparent enable
-layer_effects "dms:osd" blur enable; blur_ignore_transparent enable
-layer_effects "dms:dock" blur enable; blur_ignore_transparent enable
-
# Media keys (work on the lock screen too); DMS shows the OSD
bindsym --locked XF86AudioRaiseVolume exec dms ipc call audio increment 5
bindsym --locked XF86AudioLowerVolume exec dms ipc call audio decrement 5
diff --git a/.config/sway/doctor.sh b/.config/sway/doctor.sh
new file mode 100755
index 0000000..309fe6b
--- /dev/null
+++ b/.config/sway/doctor.sh
@@ -0,0 +1,52 @@
+#!/usr/bin/env bash
+# Health check for the sway-rising setup. Prints OK / WARN / FAIL per item. Exit code = number of FAILs.
+CFG=${XDG_CONFIG_HOME:-$HOME/.config}
+fails=0
+ok() { printf ' \033[32mOK\033[0m %s\n' "$*"; }
+warn() { printf ' \033[33mWARN\033[0m %s\n' "$*"; }
+bad() { printf ' \033[31mFAIL\033[0m %s\n' "$*"; fails=$((fails+1)); }
+have() { command -v "$1" >/dev/null 2>&1; }
+section() { printf '\n\033[1m%s\033[0m\n' "$*"; }
+
+section "Compositor"
+if have sway; then
+ v=$(sway --version 2>/dev/null | head -1); ok "$v"
+ case $v in *swayfx*) ok "SwayFX (blur, shadows, rounded corners available)";; *) warn "plain sway: effects are disabled";; esac
+ sway -C >/dev/null 2>&1 && ok "sway config is valid" || bad "sway -C reports errors"
+else bad "sway / swayfx not installed"; fi
+[ -n "${SWAYSOCK:-}" ] && ok "running inside sway" || warn "not inside a sway session (some checks skipped)"
+
+section "Shell (DMS)"
+if have dms; then
+ ok "dms installed"
+ pgrep -x dms >/dev/null && ok "dms is running" || { [ -n "${SWAYSOCK:-}" ] && bad "dms is not running" || warn "dms not running (not in session)"; }
+else bad "dms not installed"; fi
+[ -f "$CFG/dms/settings.json" ] && ok "DMS settings present" || warn "no DMS settings yet"
+
+section "Session / portals"
+if systemctl --user is-active sway-session.target >/dev/null 2>&1; then ok "sway-session.target active"
+else [ -n "${SWAYSOCK:-}" ] && bad "sway-session.target inactive (portals will not start)" || warn "sway-session.target inactive (not in session)"; fi
+if [ -n "${SWAYSOCK:-}" ] && have gdbus; then
+ timeout 10 gdbus call --session --dest org.freedesktop.portal.Desktop --object-path /org/freedesktop/portal/desktop \
+ --method org.freedesktop.DBus.Properties.Get org.freedesktop.portal.Settings version >/dev/null 2>&1 \
+ && ok "xdg-desktop-portal reachable" || bad "xdg-desktop-portal unreachable"
+fi
+
+section "Fonts and theme"
+fc-list 2>/dev/null | grep -qi "JetBrains Mono" && ok "JetBrains Mono" || bad "JetBrains Mono missing"
+fc-list 2>/dev/null | grep -qiE "Font ?Awesome" && ok "Font Awesome" || warn "Font Awesome missing (some icons)"
+{ [ -d /usr/share/themes/adw-gtk3-dark ] || [ -d "$HOME/.local/share/themes/adw-gtk3-dark" ]; } && ok "adw-gtk3 theme" || warn "adw-gtk3 theme missing (GTK apps will not follow the palette)"
+
+section "Terminal and shell tools"
+for t in kitty zsh tmux git fzf zoxide eza bat fd rg ncdu lazygit; do
+ have "$t" || { [ "$t" = fd ] && have fdfind; } && ok "$t" || warn "$t missing"
+done
+[ -d "$HOME/.oh-my-zsh" ] && ok "oh-my-zsh" || warn "oh-my-zsh missing"
+[ "$(basename "${SHELL:-}")" = zsh ] && ok "login shell is zsh" || warn "login shell is not zsh (run: chsh -s $(command -v zsh || echo /usr/bin/zsh))"
+
+section "Per-machine config"
+[ -f "$CFG/sway/config.d/05-outputs.conf" ] && ok "monitor layout (05-outputs.conf)" || warn "no monitor layout yet: run ~/.config/sway/outputs-setup.sh inside sway"
+for t in grim slurp swaylock swayidle brightnessctl playerctl wl-copy rofi; do have "$t" && ok "$t" || warn "$t missing"; done
+
+printf '\n'; [ "$fails" -eq 0 ] && echo "No failures." || echo "$fails failure(s)."
+exit "$fails"
diff --git a/.config/sway/mirror.sh b/.config/sway/mirror.sh
deleted file mode 100755
index eb37c51..0000000
--- a/.config/sway/mirror.sh
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/bash
-# Mirror the internal display to any external output (sway has no native mirroring).
-# Watches output hotplug events; needs wl-mirror.
-exec 9>"${XDG_RUNTIME_DIR:-/tmp}/sway-mirror.lock"
-flock -n 9 || exit 0
-
-internal=eDP-1
-
-sync() {
- pkill -x wl-mirror
- for ext in $(swaymsg -t get_outputs -r | jq -r --arg i "$internal" '.[] | select(.active and .name != $i) | .name'); do
- wl-mirror --fullscreen-output "$ext" "$internal" &
- done
-}
-
-sync
-swaymsg -t subscribe -m '["output"]' | while read -r _; do
- sleep 1
- sync
-done
diff --git a/.config/sway/outputs-setup.sh b/.config/sway/outputs-setup.sh
new file mode 100755
index 0000000..5ded6ab
--- /dev/null
+++ b/.config/sway/outputs-setup.sh
@@ -0,0 +1,54 @@
+#!/usr/bin/env bash
+# Generate ~/.config/sway/config.d/05-outputs.conf from the monitors sway sees right now.
+# Laptop panel first (left), the rest follow to the right. Run inside a sway session.
+# Usage: outputs-setup.sh [--auto] (--auto: no questions, guess scales)
+set -euo pipefail
+
+AUTO=0; [ "${1:-}" = "--auto" ] && AUTO=1
+OUT=${XDG_CONFIG_HOME:-$HOME/.config}/sway/config.d/05-outputs.conf
+
+command -v swaymsg >/dev/null && [ -n "${SWAYSOCK:-}" ] || { echo "Run this inside a sway session." >&2; exit 1; }
+command -v python3 >/dev/null || { echo "python3 is required." >&2; exit 1; }
+
+mapfile -t ROWS < <(swaymsg -t get_outputs -r | python3 -c '
+import json,sys
+outs=[o for o in json.load(sys.stdin) if o.get("active") or o.get("power", True)]
+# internal panels (eDP/LVDS/DSI) first, then the others by name
+outs.sort(key=lambda o:(0 if o["name"].startswith(("eDP","LVDS","DSI")) else 1, o["name"]))
+for o in outs:
+ m=o.get("current_mode") or {}
+ print(o["name"], m.get("width",0), m.get("height",0), o.get("make","?").replace(" ","_"), o.get("model","?").replace(" ","_"))
+')
+[ "${#ROWS[@]}" -gt 0 ] || { echo "No outputs found." >&2; exit 1; }
+
+guess_scale() { # name width height
+ case $1 in
+ eDP*|LVDS*|DSI*)
+ if [ "$2" -ge 3000 ]; then echo 2
+ elif [ "$2" -ge 2400 ]; then echo 1.5
+ elif [ "$2" -ge 1900 ] && [ "$3" -ge 1200 ]; then echo 1.25
+ else echo 1; fi ;;
+ *) echo 1 ;;
+ esac
+}
+
+x=0; body=""
+for row in "${ROWS[@]}"; do
+ read -r name w h make model <<<"$row"
+ scale=$(guess_scale "$name" "$w" "$h")
+ if [ "$AUTO" = 0 ]; then
+ read -r -p "$name ($make $model, ${w}x${h}) scale [$scale]: " ans || ans=""
+ [ -n "$ans" ] && scale=$ans
+ fi
+ body+="output $name position $x 0 scale $scale"$'\n'
+ x=$(python3 -c "print(int($x + $w / $scale))")
+done
+
+mkdir -p "$(dirname "$OUT")"
+[ -e "$OUT" ] && cp -a "$OUT" "$OUT.bak"
+{
+ echo "# Monitor layout, generated by outputs-setup.sh (edit freely; re-run to regenerate)"
+ printf '%s' "$body"
+} > "$OUT"
+echo "Wrote $OUT:"; cat "$OUT"
+swaymsg reload >/dev/null && echo "sway reloaded."
diff --git a/.config/sway/screenshot-menu.sh b/.config/sway/screenshot-menu.sh
deleted file mode 100755
index 62b1427..0000000
--- a/.config/sway/screenshot-menu.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/bash
-choice=$(printf '%s\n' ' Area → clipboard' ' Area → file' ' Screen → clipboard' ' Screen → file' \
- | rofi -dmenu -i -p "Screenshot" -theme ~/.config/rofi/catppuccin.rasi \
- -theme-str 'window {width: 380px;} listview {lines: 4;} entry {enabled: false;}')
-dir=$HOME/Pictures/Screenshots; mkdir -p "$dir"
-f=$dir/$(date +%F_%H-%M-%S).png
-case "$choice" in
- *"Area → clipboard") ~/.config/sway/screenshot.sh clip ;;
- *"Area → file") ~/.config/sway/screenshot.sh file ;;
- *"Screen → clipboard") sleep 0.3; grim - | wl-copy ;;
- *"Screen → file") sleep 0.3; grim "$f" ;;
- *) exit 0 ;;
-esac
-notify-send -t 2000 "Screenshot" "Saved"
diff --git a/.config/sway/screenshot.sh b/.config/sway/screenshot.sh
index 1e8cf9c..d8a1535 100755
--- a/.config/sway/screenshot.sh
+++ b/.config/sway/screenshot.sh
@@ -1,10 +1,30 @@
#!/bin/sh
-# usage: screenshot.sh clip | file
-geo=$(slurp) || exit 0
-if [ "$1" = file ]; then
- dir=$HOME/Pictures/Screenshots
- mkdir -p "$dir"
- grim -g "$geo" "$dir/$(date +%F_%H-%M-%S).png"
-else
- grim -g "$geo" - | wl-copy
-fi
+# Screenshots. Every capture goes to ~/Pictures/Screenshots AND the clipboard, with a notification.
+# usage: screenshot.sh region | full | all | window | scroll | last | edit
+# region select an area (DMS selector: drag, Enter/Space to confirm, Esc to cancel)
+# full the focused monitor all all monitors in one image
+# window the focused window last repeat the previous area
+# scroll stitch a scrolling area into one tall image (Enter finishes)
+# edit select an area and annotate it in swappy (arrows, text, blur; save/copy from there)
+dir="$HOME/Pictures/Screenshots"
+mkdir -p "$dir"
+mode=${1:-region}
+
+case "$mode" in
+ region|full|all|last|scroll)
+ exec dms screenshot "$mode" --dir "$dir" ;;
+ window)
+ # DMS cannot capture a single window on sway, so use grim on the focused container
+ geo=$(swaymsg -t get_tree | jq -r '.. | select(.focused? == true) | .rect | "\(.x),\(.y) \(.width)x\(.height)"' | head -1)
+ [ -n "$geo" ] || { notify-send -u low "Screenshot" "No focused window"; exit 1; }
+ f="$dir/$(date +%F_%H-%M-%S)_window.png"
+ grim -g "$geo" "$f" && wl-copy < "$f" && notify-send -t 3000 -i "$f" "Screenshot" "Window saved and copied"
+ ;;
+ edit)
+ if ! command -v swappy >/dev/null; then
+ notify-send -u critical "Screenshot" "swappy is not installed: sudo dnf install swappy"; exit 1
+ fi
+ dms screenshot region --stdout --no-file --no-clipboard --no-notify | swappy -f -
+ ;;
+ *) echo "usage: $0 region|full|all|window|scroll|last|edit" >&2; exit 1 ;;
+esac
diff --git a/.config/sway/vpn-menu.sh b/.config/sway/vpn-menu.sh
deleted file mode 100755
index eb1458b..0000000
--- a/.config/sway/vpn-menu.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env bash
-# VPN menu (rofi): lists NetworkManager vpn/wireguard connections, click to connect/disconnect.
-# Secrets are asked by nm-applet (secret agent).
-THEME=~/.config/rofi/catppuccin.rasi
-menu() { rofi -dmenu -i -p "$1" -theme "$THEME" "${@:2}"; }
-
-active=$(nmcli -t -e no -f NAME,TYPE connection show --active)
-list=""
-while IFS= read -r line; do
- type=${line##*:}; name=${line%:*}
- [[ $type == vpn || $type == wireguard ]] || continue
- mark="○"; grep -Fxq "$line" <<<"$active" && mark="●"
- list+="$mark $name ($type)"$'\n'
-done < <(nmcli -t -e no -f NAME,TYPE connection show)
-
-[[ -z $list ]] && { notify-send "VPN" "Нет настроенных VPN"; exit 0; }
-choice=$(printf '%s%s\n' "$list" "Расширенные настройки…" | menu "VPN") || exit 0
-[[ -z $choice ]] && exit 0
-[[ $choice == "Расширенные настройки…" ]] && exec nm-connection-editor
-
-name=${choice:2}; name=${name% (*}
-if [[ ${choice:0:1} == "●" ]]; then
- nmcli connection down id "$name" >/dev/null && notify-send "VPN" "Отключено: $name"
-else
- nmcli connection up id "$name" >/dev/null 2>&1 && notify-send "VPN" "Подключено: $name" || notify-send -u critical "VPN" "Не удалось подключиться: $name"
-fi
diff --git a/.config/sway/wallpaper.sh b/.config/sway/wallpaper.sh
deleted file mode 100755
index cfad776..0000000
--- a/.config/sway/wallpaper.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/bash
-# Wallpaper picker with previews. Also used by sway at start (arg: apply).
-dir=$HOME/Pictures/wallpapers
-cur=$dir/current
-if [ "$1" != apply ]; then
- pick=$(find "$dir" -maxdepth 1 -type f \( -name '*.jpg' -o -name '*.png' \) | sort | while read -r f; do
- printf '%s\0icon\x1f%s\n' "$(basename "$f" | sed 's/\.[^.]*$//')" "$f"
- done | rofi -dmenu -i -p "Wallpaper" -show-icons -theme ~/.config/rofi/catppuccin.rasi \
- -theme-str 'window {width: 760px;} listview {columns: 3; lines: 2;} element {orientation: vertical; padding: 10px;} element-icon {size: 9em;} element-text {horizontal-align: 0.5;} entry {enabled: false;}')
- [ -n "$pick" ] || exit 0
- file=$(find "$dir" -maxdepth 1 -type f -name "$pick.*" | head -1)
- ln -sf "$file" "$cur"
-fi
-swaymsg output '*' bg "$cur" fill >/dev/null
diff --git a/.config/sway/wifi-menu.sh b/.config/sway/wifi-menu.sh
deleted file mode 100755
index 5772f94..0000000
--- a/.config/sway/wifi-menu.sh
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/usr/bin/env bash
-# Wi-Fi menu (rofi): toggle radio, connect/disconnect, prompt for password on new networks.
-THEME=~/.config/rofi/catppuccin.rasi
-menu() { rofi -dmenu -i -p "$1" -theme "$THEME" "${@:2}"; }
-
-radio=$(nmcli radio wifi)
-if [[ $radio != enabled ]]; then
- choice=$(printf '%s\n' "Включить Wi-Fi" | menu "Wi-Fi")
- [[ $choice == "Включить Wi-Fi" ]] && nmcli radio wifi on && notify-send "Wi-Fi" "Включён"
- exit 0
-fi
-
-declare -A seen
-list=""
-while IFS=: read -r use sig sec ssid; do
- [[ -z $ssid || -n ${seen[$ssid]} ]] && continue
- seen[$ssid]=1
- mark="○"; [[ $use == '*' ]] && mark="●"
- lock=""; [[ -n $sec && $sec != "--" ]] && lock=" (защищена)"
- list+="$mark $ssid ${sig}%$lock"$'\n'
-done < <(nmcli -t -e no -f IN-USE,SIGNAL,SECURITY,SSID dev wifi list --rescan auto | sort -t: -k2 -nr)
-
-choice=$(printf '%s%s\n%s\n' "$list" "Выключить Wi-Fi" "Расширенные настройки…" | sed '/^$/d' | menu "Wi-Fi") || exit 0
-[[ -z $choice ]] && exit 0
-
-case $choice in
- "Выключить Wi-Fi") nmcli radio wifi off; notify-send "Wi-Fi" "Выключен"; exit 0 ;;
- "Расширенные настройки…") exec nm-connection-editor ;;
-esac
-
-ssid=${choice:2}; ssid=${ssid%% *}
-if [[ ${choice:0:1} == "●" ]]; then
- nmcli connection down id "$ssid" >/dev/null && notify-send "Wi-Fi" "Отключено от $ssid"
-elif nmcli -t -f NAME connection show | grep -Fxq "$ssid"; then
- nmcli connection up id "$ssid" >/dev/null 2>&1 && notify-send "Wi-Fi" "Подключено к $ssid" || notify-send -u critical "Wi-Fi" "Не удалось подключиться к $ssid"
-else
- if [[ $choice == *"(защищена)"* ]]; then
- pw=$(menu "Пароль для $ssid" -password -lines 0) || exit 0
- out=$(nmcli dev wifi connect "$ssid" password "$pw" 2>&1)
- else
- out=$(nmcli dev wifi connect "$ssid" 2>&1)
- fi
- [[ $? -eq 0 ]] && notify-send "Wi-Fi" "Подключено к $ssid" || notify-send -u critical "Wi-Fi" "Ошибка: $out"
-fi
diff --git a/.config/swaync/config.json b/.config/swaync/config.json
deleted file mode 100644
index 786105c..0000000
--- a/.config/swaync/config.json
+++ /dev/null
@@ -1,98 +0,0 @@
-{
- "$schema": "/etc/xdg/swaync/configSchema.json",
- "ignore-gtk-theme": true,
- "positionX": "right",
- "positionY": "top",
- "layer": "overlay",
- "control-center-layer": "top",
- "layer-shell": true,
- "layer-shell-cover-screen": false,
- "cssPriority": "user",
- "control-center-margin-top": 6,
- "control-center-margin-bottom": 8,
- "control-center-margin-right": 8,
- "control-center-margin-left": 0,
- "control-center-width": 460,
- "control-center-height": 620,
- "fit-to-screen": false,
- "notification-window-width": 380,
- "notification-icon-size": 48,
- "notification-body-image-height": 100,
- "notification-body-image-width": 200,
- "timeout": 8,
- "timeout-low": 5,
- "timeout-critical": 0,
- "transition-time": 180,
- "hide-on-clear": false,
- "hide-on-action": true,
- "keyboard-shortcuts": true,
- "notification-grouping": true,
- "relative-timestamps": true,
- "text-empty": "Нет уведомлений",
- "widgets": [
- "title",
- "buttons-grid",
- "volume",
- "backlight",
- "mpris",
- "dnd",
- "notifications"
- ],
- "widget-config": {
- "title": {
- "text": "Центр управления",
- "clear-all-button": true,
- "button-text": "Очистить"
- },
- "dnd": {
- "text": "Не беспокоить"
- },
- "buttons-grid": {
- "actions": [
- {
- "label": " Wi-Fi",
- "command": "sh -c 'swaync-client -cp -sw; ~/.config/sway/wifi-menu.sh'"
- },
- {
- "label": " Bluetooth",
- "command": "sh -c 'swaync-client -cp -sw; ~/.config/sway/bt-menu.sh'"
- },
- {
- "label": " VPN",
- "command": "sh -c 'swaync-client -cp -sw; ~/.config/sway/vpn-menu.sh'"
- },
- {
- "label": " Микрофон",
- "type": "toggle",
- "active": true,
- "command": "sh -c '[[ $SWAYNC_TOGGLE_STATE == true ]] && wpctl set-mute @DEFAULT_AUDIO_SOURCE@ 0 || wpctl set-mute @DEFAULT_AUDIO_SOURCE@ 1'",
- "update-command": "sh -c 'wpctl get-volume @DEFAULT_AUDIO_SOURCE@ | grep -q MUTED && echo false || echo true'"
- },
- {
- "label": " Блок",
- "command": "sh -c 'swaync-client -cp -sw; ~/.config/sway/lock.sh'"
- },
- {
- "label": " Выкл",
- "command": "sh -c 'swaync-client -cp -sw; ~/.config/rofi/powermenu.sh'"
- }
- ]
- },
- "volume": {
- "label": "",
- "show-per-app": true,
- "show-per-app-icon": true,
- "show-per-app-label": false
- },
- "backlight": {
- "label": "",
- "device": "intel_backlight"
- },
- "mpris": {
- "image-size": 64,
- "image-radius": 12,
- "autohide": true,
- "show-album-art": "when-available"
- }
- }
-}
\ No newline at end of file
diff --git a/.config/swaync/style.css b/.config/swaync/style.css
deleted file mode 100644
index 827af59..0000000
--- a/.config/swaync/style.css
+++ /dev/null
@@ -1,117 +0,0 @@
-/* swaync glass theme: matches rofi/waybar, purple accent from kitty.
- Icons come from FontAwesome (the same glyphs the waybar uses). */
-@define-color text #f2f2f2;
-@define-color sub #b4b4b4;
-@define-color accent #bb9af7;
-@define-color red #f7768e;
-
-* {
- font-family: "JetBrains Mono", "FontAwesome", "Font Awesome 6 Brands", monospace;
- font-size: 14px;
- color: @text;
- text-shadow: none;
- box-shadow: none;
-}
-
-/* ---------- Panel ---------- */
-.control-center {
- background: rgba(14, 14, 18, 0.80);
- border: 1px solid rgba(232, 232, 232, 0.18);
- border-radius: 20px;
- padding: 16px;
-}
-.control-center .widget-title { margin: 2px 2px 12px 2px; }
-.widget-title > label { font-size: 18px; font-weight: bold; }
-.widget-title > button {
- background: rgba(255, 255, 255, 0.10);
- border: none; border-radius: 12px; padding: 6px 16px;
-}
-.widget-title > button label { color: @text; }
-.widget-title > button:hover { background: rgba(255, 255, 255, 0.22); }
-
-/* ---------- Toggle tiles ---------- */
-.widget-buttons-grid { background: transparent; margin: 0 0 10px 0; padding: 0; }
-.widget-buttons-grid > flowbox > flowboxchild > button {
- background: rgba(255, 255, 255, 0.09);
- border: 1px solid rgba(255, 255, 255, 0.06);
- border-radius: 14px;
- min-width: 120px; min-height: 46px; margin: 4px;
- font-size: 14px;
-}
-.widget-buttons-grid > flowbox > flowboxchild > button label { font-weight: bold; }
-.widget-buttons-grid > flowbox > flowboxchild > button:hover { background: rgba(255, 255, 255, 0.20); }
-.widget-buttons-grid > flowbox > flowboxchild > button:checked {
- background: @accent; border-color: @accent;
-}
-.widget-buttons-grid > flowbox > flowboxchild > button:checked label { color: #11111b; }
-
-/* ---------- Sliders ---------- */
-.widget-volume, .widget-backlight {
- background: rgba(255, 255, 255, 0.09);
- border-radius: 14px; padding: 10px 16px; margin: 4px 0;
-}
-.widget-volume label, .widget-backlight label { font-size: 18px; min-width: 26px; }
-scale trough {
- min-height: 8px; border-radius: 6px;
- background: rgba(255, 255, 255, 0.20);
-}
-scale highlight { background: @accent; border-radius: 6px; }
-scale slider {
- min-width: 18px; min-height: 18px; margin: -6px;
- background: @text; border-radius: 50%; border: none;
-}
-.widget-volume button { background: rgba(255, 255, 255, 0.10); border: none; border-radius: 10px; }
-.per-app-volume { background: transparent; padding: 4px 0; }
-
-/* ---------- Player ---------- */
-.widget-mpris {
- background: rgba(255, 255, 255, 0.09);
- border-radius: 14px; padding: 8px; margin: 4px 0;
-}
-.widget-mpris-title { font-weight: bold; font-size: 15px; }
-.widget-mpris-subtitle { color: @sub; font-size: 13px; }
-.widget-mpris button { background: transparent; border: none; border-radius: 12px; }
-.widget-mpris button:hover { background: rgba(255, 255, 255, 0.18); }
-
-/* ---------- Do not disturb ---------- */
-.widget-dnd { margin: 10px 4px; font-size: 14px; }
-.widget-dnd > label { font-weight: bold; }
-.widget-dnd > switch {
- background: rgba(255, 255, 255, 0.20);
- border: none; border-radius: 14px;
-}
-.widget-dnd > switch:checked { background: @accent; }
-.widget-dnd > switch slider { background: @text; border-radius: 12px; }
-
-/* ---------- Notifications (popups + list) ---------- */
-.notification-row { outline: none; }
-.notification {
- background: rgba(14, 14, 18, 0.85);
- border: 1px solid rgba(232, 232, 232, 0.22);
- border-radius: 14px; margin: 6px 8px; padding: 0;
-}
-.control-center .notification { background: rgba(255, 255, 255, 0.09); border: none; }
-.notification-content { background: transparent; padding: 10px; }
-.notification-default-action, .notification-action { background: transparent; border-radius: 14px; }
-.notification-default-action:hover { background: rgba(255, 255, 255, 0.09); }
-.summary { font-weight: bold; font-size: 15px; }
-.body { color: #d8d8d8; font-size: 14px; }
-.time { color: @sub; font-size: 12px; }
-.image { border-radius: 10px; }
-.close-button {
- background: rgba(255, 255, 255, 0.14);
- border: none; border-radius: 50%; margin: 6px; padding: 2px;
-}
-.close-button:hover { background: @red; }
-.critical { border: 1px solid @red; }
-.notification-group-headers label { color: @sub; font-weight: bold; }
-.widget-notifications, .notification-group { background: transparent; }
-
-/* empty state: text only, no broken icon */
-.notifications-placeholder, .control-center-list placeholder { color: @sub; font-size: 14px; }
-.notifications-placeholder image, .control-center-list placeholder image { opacity: 0; min-height: 0; min-width: 0; -gtk-icon-size: 0; }
-.notifications-placeholder > *:first-child,
-.notifications-placeholder picture,
-.notifications-placeholder > box > image,
-.control-center-list-placeholder image,
-.empty-label image { opacity: 0; min-height: 0; min-width: 0; margin: 0; }
diff --git a/.config/waybar/config.jsonc b/.config/waybar/config.jsonc
deleted file mode 100644
index 485686f..0000000
--- a/.config/waybar/config.jsonc
+++ /dev/null
@@ -1,66 +0,0 @@
-{
- "layer": "top",
- "position": "top",
- "height": 34,
- "margin-top": 8,
- "margin-left": 10,
- "margin-right": 10,
- "spacing": 6,
- "modules-left": ["sway/workspaces", "sway/mode", "sway/window"],
- "modules-center": ["clock", "mpris"],
- "modules-right": ["idle_inhibitor", "sway/language", "group/hw", "backlight", "pulseaudio", "network", "battery", "tray", "custom/notification", "custom/power"],
-
- "sway/workspaces": { "disable-scroll": true, "all-outputs": true, "format": "{icon}", "format-icons": {"1": "", "2": "", "3": "", "4": "", "5": "", "urgent": "", "default": ""} },
- "sway/window": { "max-length": 45, "format": "{title}", "rewrite": { "(.*) — Mozilla Firefox": " $1", "(.*) - Chromium": " $1" } },
- "sway/language": { "format": " {short}" },
- "clock": { "format": " {:%H:%M}", "format-alt": " {:%A, %d %B %Y}", "tooltip-format": "{calendar}" },
- "mpris": { "format": "{player_icon} {title}", "format-paused": " {title}", "player-icons": { "default": "" }, "max-length": 36, "tooltip-format": "{artist} — {title}" },
- "group/hw": { "orientation": "inherit", "drawer": { "transition-duration": 350, "transition-left-to-right": false }, "modules": ["custom/hw", "temperature", "cpu", "memory"] },
- "custom/hw": { "format": "\uf085", "tooltip": false },
- "idle_inhibitor": { "format": "{icon}", "format-icons": { "activated": "", "deactivated": "" }, "tooltip-format-activated": "Idle inhibited", "tooltip-format-deactivated": "Idle allowed" },
- "temperature": { "critical-threshold": 85, "format": " {temperatureC}°", "interval": 5 },
- "cpu": { "format": " {usage}%", "interval": 3 },
- "memory": { "format": " {percentage}%", "interval": 5 },
- "backlight": { "format": "{icon} {percent}%", "format-icons": ["", ""], "on-scroll-up": "brightnessctl set 5%+", "on-scroll-down": "brightnessctl set 5%-" },
- "pulseaudio": {
- "format": "{icon} {volume}%",
- "format-muted": " muted",
- "format-icons": { "default": ["", "", ""] },
- "on-click": "pavucontrol",
- "on-click-right": "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"
- },
- "network": {
- "format-wifi": " {essid}",
- "format-ethernet": " {ipaddr}",
- "format-disconnected": " offline",
- "tooltip-format": "{ifname} {signalStrength}%"
- },
- "battery": {
- "states": { "warning": 25, "critical": 12 },
- "format": "{icon} {capacity}%",
- "format-charging": " {capacity}%",
- "format-icons": ["", "", "", "", ""]
- },
- "tray": { "spacing": 8 },
- "custom/notification": {
- "tooltip": false,
- "format": "{icon}",
- "format-icons": {
- "notification": "\uf0f3\uf111",
- "none": "\uf0f3",
- "dnd-notification": "\uf1f6\uf111",
- "dnd-none": "\uf1f6",
- "inhibited-notification": "\uf0f3\uf111",
- "inhibited-none": "\uf0f3",
- "dnd-inhibited-notification": "\uf1f6\uf111",
- "dnd-inhibited-none": "\uf1f6"
- },
- "return-type": "json",
- "exec-if": "which swaync-client",
- "exec": "swaync-client -swb",
- "on-click": "swaync-client -t -sw",
- "on-click-right": "swaync-client -d -sw",
- "escape": true
- },
- "custom/power": { "format": "", "tooltip": false, "on-click": "~/.config/rofi/powermenu.sh" }
-}
diff --git a/.config/waybar/style.css b/.config/waybar/style.css
deleted file mode 100644
index 266bc73..0000000
--- a/.config/waybar/style.css
+++ /dev/null
@@ -1,74 +0,0 @@
-@define-color base #0c0c0c;
-@define-color surface0 #1c1c1c;
-@define-color surface1 #2e2e2e;
-@define-color text #e8e8e8;
-@define-color subtext #8c8c8c;
-@define-color red #ff5c5c;
-@define-color yellow #d9c99a;
-
-* {
- font-family: "JetBrains Mono", "Font Awesome 6 Free";
- font-size: 13px;
- border: none;
- border-radius: 0;
- min-height: 0;
-}
-
-window#waybar { background: transparent; color: @text; }
-
-/* glass pills: translucent so swayfx blur shows through */
-#workspaces, #window, #clock, #language, #cpu, #memory, #pulseaudio, #network, #battery,
-#tray, #mode, #custom-power, #custom-notification, #backlight, #idle_inhibitor, #temperature, #mpris {
- background: alpha(@base, 0.55);
- border: 1px solid alpha(@text, 0.08);
- border-radius: 14px;
- padding: 0 12px;
- margin: 0;
- color: @text;
- transition: all 0.25s ease;
-}
-
-#workspaces { padding: 0 4px; }
-#workspaces button {
- color: @subtext;
- padding: 0 9px;
- margin: 4px 2px;
- border-radius: 10px;
- background: transparent;
- transition: all 0.25s ease;
-}
-#workspaces button:hover { background: alpha(@text, 0.12); color: @text; box-shadow: none; text-shadow: none; }
-#workspaces button.focused { background: alpha(@text, 0.92); color: @base; padding: 0 16px; box-shadow: 0 0 12px alpha(@text, 0.35); }
-#workspaces button.urgent { background: @red; color: @base; }
-
-#mode { background: @text; color: @base; font-weight: bold; }
-#window { color: @subtext; }
-window#waybar.empty #window { background: transparent; border-color: transparent; }
-#clock { font-weight: bold; padding: 0 16px; }
-#mpris { color: @subtext; }
-
-#cpu:hover, #memory:hover, #pulseaudio:hover, #network:hover, #battery:hover,
-#language:hover, #backlight:hover, #idle_inhibitor:hover, #temperature:hover, #mpris:hover {
- background: alpha(@text, 0.14);
- border-color: alpha(@text, 0.25);
-}
-#idle_inhibitor.activated { background: @text; color: @base; }
-#network.disconnected { color: @red; }
-#battery.charging { color: @text; }
-#battery.warning:not(.charging) { color: @yellow; }
-#battery.critical:not(.charging) { color: @red; animation: blink 1s steps(2) infinite; }
-#temperature.critical { color: @red; }
-#custom-notification { padding: 0 14px; }
-#custom-power { padding: 0 14px; }
-#custom-power:hover { background: @red; color: @base; border-color: @red; }
-
-@keyframes blink { to { background: alpha(@red, 0.5); } }
-
-tooltip { background: alpha(@base, 0.85); border: 1px solid alpha(@text, 0.12); border-radius: 12px; }
-tooltip label { color: @text; padding: 2px; }
-
-/* collapsible hardware drawer */
-#hw { background: alpha(@base, 0.55); border: 1px solid alpha(@text, 0.08); border-radius: 14px; padding: 0 4px; transition: all 0.25s ease; }
-#hw:hover { border-color: alpha(@text, 0.25); }
-#hw #custom-hw, #hw #temperature, #hw #cpu, #hw #memory { background: transparent; border: none; box-shadow: none; }
-#custom-hw { color: @subtext; }
diff --git a/README.md b/README.md
index 1882911..c2d85d6 100644
--- a/README.md
+++ b/README.md
@@ -1,44 +1,46 @@
# sway-rising
-Монохромный «стеклянный» райс для **SwayFX 0.6**: матовый blur, скруглённые углы, мягкое свечение у активного окна и **DankMaterialShell** (бар, лаунчер, панель управления с Wi-Fi / Bluetooth / VPN, уведомления) поверх sway.
+Монохромный «стеклянный» райс для **SwayFX** на Fedora: blur, скруглённые углы, мягкое свечение у активного окна и **DankMaterialShell** (бар, лаунчер, панель управления с Wi-Fi / Bluetooth / VPN, уведомления, блокировка, обои) поверх sway.
## Что внутри
| Путь | Что это |
|---|---|
-| `.config/sway/config.d/10-appearance.conf` | цвета, рамки, отступы, обои, swayidle (через `idle.sh`) |
-| `.config/sway/config.d/20-swayfx.conf` | эффекты SwayFX: blur, тени, скругления, прозрачность, layer_effects |
-| `.config/sway/config.d/30-workflow.conf` | хоткеи и помощники (scratchpad, скриншоты, обои, шпаргалка) |
-| `.config/sway/*.sh` | `wallpaper.sh`, `screenshot-menu.sh`, `screenshot.sh`, `cheatsheet.sh`, `idle.sh`, `mirror.sh` |
-| `.config/waybar` | стеклянные плашки, выдвижной блок железа, mpris, яркость, idle-inhibitor |
-| `.config/rofi` | полупрозрачная тема + меню выключения |
-| `.config/swaync` | центр уведомлений и панель управления (`Super+N`): плитки Wi-Fi / Bluetooth / VPN, громкость, яркость, плеер |
-| `.config/sway/{wifi,bt,vpn}-menu.sh` | rofi-меню для плиток панели (подключение, пароль, спаривание) |
-| `.config/dunst` | старые уведомления (не используются, оставлены для отката) |
-| `.config/swaylock` | локскрин с обоями |
-| `.config/kitty/kitty.conf` | прозрачность терминала, чтобы был виден blur |
-| `.config/sway/config.d/50-dms.conf` | запуск DMS, blur для его слоёв, хоткей буфера обмена, медиаклавиши (громкость, яркость, плеер) |
-| `home/.tmux.conf` | tmux: префикс `Ctrl+A`, сплиты `|` и `-`, нумерация с 1, тема Tokyo Night |
-| `home/.oh-my-zsh/custom/sysadmin.zsh` | алиасы сисадмина (`ports`, `jce`, `dnfu`, `tm`) и автоподключение fzf / zoxide / eza, если установлены |
-| `.config/sway/config.d/60-autostart.conf` | автозапуск Nextcloud, Remmina и Geary (xdg-autostart в sway не работает) |
-| `.config/dms/settings.json` | настройки DMS: виджеты бара (раскладка, VPN, температура, приватность), шрифты, панель управления |
-| `.config/sway/config.d/40-bar.conf.off` | старый запуск waybar (отключён; переименуйте в `.conf`, чтобы вернуть waybar вместо DMS) |
-| `.config/sway/config.d/05-outputs.conf` | расположение и масштаб мониторов (ноутбук слева, HDMI справа; подгоните под своё железо) |
+| `.config/sway/config` | базовый конфиг sway (раскладки us/ru, хоткеи, `--to-code`: хоткеи работают и на русской раскладке) |
+| `.config/sway/config.d/00-session.conf` | окружение и `sway-session.target`, чтобы работали порталы (демонстрация экрана, диалоги) |
+| `.config/sway/config.d/05-outputs.conf.example` | пример раскладки мониторов; свой файл создаёт `outputs-setup.sh` |
| `.config/sway/config.d/06-mouse.conf` | чувствительность мыши |
-| `wallpapers/` | `original.jpg` (основные), `mono-glow`, `mono-orb`, `mono-smoke`, `mono-grid`, `mono-dusk` |
+| `.config/sway/config.d/10-appearance.conf` | цвета рамок и вкладок, отступы, тачпад, правила окон, idle |
+| `.config/sway/config.d/20-swayfx.conf`, `21-dms-effects.conf` | эффекты SwayFX: blur, тени, скругления, прозрачность; blur для слоёв DMS |
+| `.config/sway/config.d/30-workflow.conf` | scratchpad-терминал, скриншоты, шпаргалка, режим производительности |
+| `.config/sway/config.d/50-dms.conf` | запуск DMS, буфер обмена, медиаклавиши (громкость, яркость, плеер) |
+| `.config/sway/config.d/60-autostart.conf` | автозапуск Nextcloud, Remmina и Geary (xdg-autostart в sway не работает) |
+| `.config/sway/screenshot.sh` | все режимы скриншотов (см. ниже) |
+| `.config/sway/{lock,idle,cheatsheet}.sh` | блокировка (DMS, запасной swaylock), swayidle, шпаргалка по хоткеям |
+| `.config/sway/outputs-setup.sh`, `doctor.sh` | настройка мониторов под новое железо; проверка здоровья системы |
+| `.config/dms/settings.json` | настройки DMS: виджеты бара (раскладка, VPN, температура, приватность), шрифты, панель управления |
+| `.config/kitty/kitty.conf` | JetBrains Mono, палитра Tokyo Night, прозрачность, вкладки и сплиты |
+| `.config/swappy/config` | редактор скриншотов (стрелки, текст, размытие) |
+| `.config/swaylock/` | запасная блокировка, если DMS не запущен |
+| `home/.tmux.conf`, `home/.zshrc`, `home/.oh-my-zsh/custom/sysadmin.zsh` | tmux, zsh, алиасы сисадмина; fzf / zoxide / eza подключаются сами |
+| `wallpapers/` | любимые обои (кладутся в `~/.local/share/backgrounds`, дальше обоями управляет DMS) |
-### Что было добавлено
-- **Blur 4 прохода** + brightness / contrast / saturation, шум; свечение у фокусного окна, тёмная тень у остальных.
-- **Waybar:** стеклянные плашки, растягивающийся активный воркспейс, модули mpris, backlight, temperature, idle-inhibitor, выдвижной блок `⚙` (температура / CPU / RAM), мигание при низком заряде.
-- **Rofi и swaync** сделаны полупрозрачными, чтобы под ними был виден blur.
-- **Выбор обоев** с превью (rofi), 6 обоев в наборе.
-- **Меню скриншотов** (область / экран, в буфер / в файл).
-- **Шпаргалка по хоткеям** прямо из конфига.
-- **Режим производительности:** переключатель blur и теней.
-- **swayidle:** блокировка через 5 мин, экран гаснет через 10 мин.
-- **Swaylock-effects:** размытый скриншот экрана, виньетка, часы и дата. Запускается через `sway/lock.sh`: сначала экран блокировки DMS, а если DMS не запущен, то swaylock-effects или обычный swaylock.
+Обои, уведомления, панель управления, лаунчер и бар обслуживает DMS. Waybar, swaync, dunst, rofi и сопутствующие скрипты убраны из репозитория.
-## Важные хоткеи (`Super` = Mod4)
+## Скриншоты
+
+Все снимки сохраняются в `~/Pictures/Screenshots` **и** копируются в буфер обмена, DMS показывает уведомление.
+
+| Клавиши | Что снимает |
+|---|---|
+| `Print` или `Super+Shift+S` | область: выделить мышью, `Enter` или пробел подтверждает, `Esc` отменяет |
+| `Shift+Print` | весь текущий монитор |
+| `Ctrl+Print` | активное окно |
+| `Alt+Print` | прокручиваемая область одним длинным снимком (`Enter` завершает) |
+| `Super+Print` | повторить прошлую область |
+| `Ctrl+Shift+Print` | область с редактором swappy (стрелки, текст, размытие) |
+
+## Хоткеи (`Super` = Mod4)
| Клавиши | Действие |
|---|---|
@@ -49,13 +51,9 @@
| `Super+Shift+V` | история буфера обмена |
| `Super+Shift+Q` | закрыть окно |
| `Super+Shift+C` | перезагрузить конфиг |
-| `Super+Shift+E` | выйти из sway |
+| `Super+Shift+E` / `Super+Shift+P` | меню выключения DMS |
| `Super+Shift+X` | заблокировать экран |
-| `Super+Shift+P` | меню выключения |
| `Super+F1` | **шпаргалка по всем хоткеям** |
-| `Super+Shift+W` | выбор обоев |
-| `Super+Shift+S` | меню скриншотов |
-| `Shift+Print` / `Super+Print` | область → буфер / область → файл |
| `Super+Shift+B` | режим производительности (blur + тени) |
| ``Super+` `` | выпадающий терминал (scratchpad) |
| `Super+H/J/K/L` | фокус влево / вниз / вверх / вправо |
@@ -68,23 +66,37 @@
| `Super+C` | центрировать плавающее окно |
| `Super+R` | режим изменения размера (`H/J/K/L`, `Esc`) |
| `Super+S` / `Super+W` / `Super+E` | layout: stacking / tabbed / split |
-| `Alt+Shift` | переключение раскладки (us / ru); все хоткеи работают и на русской раскладке (`bindsym --to-code`, первой в `xkb_layout` должна стоять `us`) |
+| `Alt+Shift` | переключение раскладки (us / ru); первой в `xkb_layout` должна стоять `us` |
-## Установка одной командой (Fedora)
+## Новый ноутбук за одну команду (Fedora)
+
+На свежей Fedora (Workstation или любой вариант с `git`):
```sh
-git clone git@git.ibrash.duckdns.org:aibrash/sway-rising.git && cd sway-rising
-./install.sh
+git clone git@git.ibrash.duckdns.org:aibrash/sway-rising.git && cd sway-rising && ./install.sh
```
-Скрипт:
-1. ставит недостающие пакеты через `dnf` (swayfx берёт из COPR `swayfx/swayfx`, шрифты, waybar, rofi и остальное);
-2. кладёт `swaylock-effects` из COPR `pheeef/swaylock-effects` в `~/.local/bin` рядом с системным swaylock и ничего не заменяет (`dnf swap` не проходит из-за `sway-config-fedora`);
-3. **делает бэкап** ваших текущих конфигов в `~/rice-backup-<дата>`;
-4. копирует конфиги и обои, проверяет конфиг (`sway -C`) и перезагружает sway.
+Репозиторий клонируется по ssh, поэтому на новой машине сначала нужен ваш ключ (`~/.ssh/id_ed25519`) или ключ, добавленный на git-сервер.
-Можно запускать повторно. Перед подключением каждого COPR скрипт спрашивает подтверждение.
+Скрипт спрашивает подтверждение перед каждым COPR и больше ни о чём не спрашивает. Для полностью автоматического режима: `./install.sh --yes`.
-Флаги: `--yes` (не спрашивать), `--no-packages` (только конфиги), `--no-lock-effects`.
+Что он делает:
+1. Ставит пакеты через `dnf`: сессия sway (`sway-systemd`, порталы), kitty, swaylock/swayidle, grim, swappy (аннотации скриншотов), шрифты JetBrains Mono и Font Awesome, тема `adw-gtk3`.
+2. Подключает COPR `swayfx/swayfx` и `avengemedia/dms` и ставит SwayFX и DankMaterialShell.
+3. Ставит CLI: zsh, tmux, fzf, zoxide, eza, bat, fd, ripgrep, ncdu, fastfetch, lazygit (бинарник с проверкой суммы), клонирует oh-my-zsh с плагинами. Опция `--with-tools` добавляет nmap, tcpdump, mtr, jq, btop, ansible.
+4. **Делает бэкап** ваших конфигов в `~/rice-backup-<дата>` и копирует конфиги, обои (в `~/.local/share/backgrounds`), tmux и алиасы. Ваш `~/.zshrc` не трогает (его заменит только `--force-shell`).
+5. Включает тему `adw-gtk3-dark` и проверяет конфиг (`sway -C`).
-DMS запускается из `config.d/50-dms.conf`. Руками его запускать не нужно. Диагностика: `dms doctor`. Waybar, swaync и dunst в репозитории оставлены как запасной вариант и в `install.sh` больше не ставятся.
+После установки: выйти и выбрать на экране входа сессию **Sway**. Внутри сессии один раз выполнить
+
+```sh
+~/.config/sway/outputs-setup.sh # раскладка и масштаб мониторов (ноутбук слева, внешний справа)
+```
+
+Файл раскладки мониторов намеренно не копируется: на другом железе другие имена выходов. В репозитории лежит только пример `05-outputs.conf.example`.
+
+Проверка здоровья в любой момент: `./install.sh --check` (то же самое: `~/.config/sway/doctor.sh`). Показывает, что установлено, что работает, а что нет (DMS, порталы, шрифты, инструменты, раскладка мониторов).
+
+Флаги: `--yes`, `--dry-run` (показать действия, ничего не менять), `--check`, `--no-packages`, `--no-dms`, `--no-shell`, `--with-tools`, `--force-shell`. Можно запускать повторно.
+
+DMS запускается из `config.d/50-dms.conf`, руками его запускать не нужно. Диагностика самого DMS: `dms doctor`.
diff --git a/home/.zshrc b/home/.zshrc
new file mode 100644
index 0000000..7a01832
--- /dev/null
+++ b/home/.zshrc
@@ -0,0 +1,13 @@
+# sway-rising zsh config (installed only when you have no ~/.zshrc)
+export ZSH="$HOME/.oh-my-zsh"
+ZSH_THEME="robbyrussell"
+plugins=(git zsh-autosuggestions zsh-syntax-highlighting)
+source $ZSH/oh-my-zsh.sh
+
+export PATH="$HOME/.local/bin:$PATH"
+
+# Aliases and tool hooks (fzf, zoxide, eza) live in ~/.oh-my-zsh/custom/sysadmin.zsh
+
+# nvm (optional)
+export NVM_DIR="$HOME/.nvm"
+[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
diff --git a/install.sh b/install.sh
index 12738a3..4b8b5b8 100755
--- a/install.sh
+++ b/install.sh
@@ -1,151 +1,239 @@
#!/usr/bin/env bash
-# sway-rising installer: packages + DankMaterialShell + configs + wallpapers + swaylock-effects.
-# Usage: ./install.sh [--yes] [--no-packages] [--no-lock-effects]
+# sway-rising installer (Fedora): turns a fresh Fedora install into the full rice
+# (SwayFX + DankMaterialShell, kitty, zsh/tmux, CLI tools, fonts, wallpapers, configs).
+#
+# Usage: ./install.sh [options]
+# -y, --yes do not ask questions (non-interactive)
+# --dry-run print what would be done, change nothing
+# --check only run the health check and exit
+# --no-packages configs only, skip package installation
+# --no-dms do not install DankMaterialShell
+# --no-shell skip zsh / oh-my-zsh / tmux / CLI tools
+# --with-tools also install sysadmin tools (nmap, tcpdump, mtr, jq, ansible, btop)
+# --force-shell overwrite an existing ~/.zshrc (the old one is backed up)
+# -h, --help
set -euo pipefail
REPO=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
CFG=${XDG_CONFIG_HOME:-$HOME/.config}
-WALLS=$HOME/Pictures/wallpapers
+WALLS=$HOME/.local/share/backgrounds
STAMP=$(date +%F-%H%M%S)
BACKUP=$HOME/rice-backup-$STAMP
-YES=0; PACKAGES=1; LOCKFX=1
+YES=0; DRY=0; CHECK=0; PACKAGES=1; DMS=1; SHELLSETUP=1; TOOLS=0; FORCE_SHELL=0
for a in "$@"; do
case $a in
-y|--yes) YES=1 ;;
+ --dry-run) DRY=1 ;;
+ --check) CHECK=1 ;;
--no-packages) PACKAGES=0 ;;
- --no-lock-effects) LOCKFX=0 ;;
- -h|--help) sed -n '2,3p' "$0"; exit 0 ;;
- *) echo "unknown option: $a" >&2; exit 1 ;;
+ --no-dms) DMS=0 ;;
+ --no-shell) SHELLSETUP=0 ;;
+ --with-tools) TOOLS=1 ;;
+ --force-shell) FORCE_SHELL=1 ;;
+ -h|--help) sed -n '2,15p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
+ *) echo "unknown option: $a (try --help)" >&2; exit 1 ;;
esac
done
say() { printf '\033[1;37m==>\033[0m %s\n' "$*"; }
warn() { printf '\033[1;33m!!\033[0m %s\n' "$*" >&2; }
-ask() { [ "$YES" = 1 ] && return 0; read -r -p "$1 [y/N] " r; [[ $r =~ ^[yYдД] ]]; }
+ask() { [ "$YES" = 1 ] && return 0; read -r -p "$1 [y/N] " r || return 1; [[ $r =~ ^[yYдД] ]]; }
+run() { if [ "$DRY" = 1 ]; then printf ' [dry-run] %s\n' "$*"; else "$@"; fi; }
+have() { command -v "$1" >/dev/null 2>&1; }
-# ---------- 1. packages (Fedora) ----------
-install_packages() {
- if ! command -v dnf >/dev/null; then
- warn "dnf not found. Install manually: swayfx dms rofi swaylock swayidle kitty grim slurp"
- warn "wl-clipboard playerctl brightnessctl ImageMagick libnotify pavucontrol network-manager-applet"
- warn "JetBrains Mono and Font Awesome 6 fonts."
- return
- fi
+FAILED=() # steps that did not work, shown at the end
+NOTES=() # follow-up hints for the user
- local want=(rofi swaylock swayidle kitty grim slurp wl-clipboard playerctl
- brightnessctl ImageMagick libnotify pavucontrol network-manager-applet
- wireplumber fontawesome-6-free-fonts)
- fc-list | grep -qi "JetBrains Mono" || want+=(jetbrains-mono-fonts)
+# ---------------------------------------------------------------- packages (Fedora names, all verified with dnf)
+CORE_PKGS=(
+ sway-systemd # session target + env for portals
+ kitty swaylock swayidle grim swappy jq wl-clipboard brightnessctl libnotify
+ pavucontrol network-manager-applet wireplumber pipewire-pulseaudio
+ xdg-desktop-portal xdg-desktop-portal-wlr xdg-desktop-portal-gtk
+ jetbrains-mono-fonts fontawesome-6-free-fonts adw-gtk3-theme
+)
+SHELL_PKGS=(zsh tmux git curl fzf zoxide eza bat fd-find ripgrep ncdu fastfetch)
+TOOLS_PKGS=(nmap tcpdump mtr jq btop ansible)
- local missing=() p
- for p in "${want[@]}"; do rpm -q "$p" >/dev/null 2>&1 || missing+=("$p"); done
-
- if ! rpm -q swayfx >/dev/null 2>&1; then
- say "swayfx is not installed (it lives in the swayfx/swayfx COPR)"
- if ask "Enable COPR swayfx/swayfx and install swayfx? (replaces nothing, but 'sway' conflicts)"; then
- sudo dnf copr enable -y swayfx/swayfx
- missing+=(swayfx)
- else
- warn "Skipping swayfx: effects will not work on plain sway."
- fi
- fi
-
- if ! rpm -q dms >/dev/null 2>&1; then
- say "DankMaterialShell (bar, launcher, control center, notifications) comes from the avengemedia/dms COPR"
- if ask "Enable COPR avengemedia/dms and install dms?"; then
- sudo dnf copr enable -y avengemedia/dms
- missing+=(dms)
- else
- warn "Skipping dms: no bar / control center / notifications will be started."
- fi
- fi
-
- if [ ${#missing[@]} -gt 0 ]; then
- say "Installing: ${missing[*]}"
- sudo dnf install -y "${missing[@]}"
- else
- say "All packages already installed"
- fi
+check_fedora() {
+ local ID="" ID_LIKE=""
+ [ -r /etc/os-release ] && . /etc/os-release
+ case " $ID $ID_LIKE " in *" fedora "*) return 0 ;; esac
+ return 1
}
-# ---------- 2. swaylock-effects (side by side, system swaylock untouched) ----------
-install_lock_effects() {
- local dest=$HOME/.local/bin/swaylock-effects
- if [ -x "$dest" ]; then say "swaylock-effects already installed"; return; fi
- command -v dnf >/dev/null || { warn "No dnf: put a swaylock-effects binary at $dest yourself"; return; }
- command -v cpio >/dev/null || { warn "cpio missing, skipping swaylock-effects"; return; }
+dnf_install() { [ $# -gt 0 ] || return 0
+ if run sudo dnf install -y "$@"; then return 0; fi
+ warn "Batch install failed, retrying package by package"
+ local p; for p in "$@"; do run sudo dnf install -y "$p" || FAILED+=("package:$p"); done
+}
- say "swaylock-effects: not in Fedora repos, it comes from the third-party COPR pheeef/swaylock-effects"
- ask "Enable that COPR and extract the binary into ~/.local/bin (does not replace system swaylock)?" || { warn "Skipped; plain swaylock will be used"; return; }
-
- sudo dnf copr enable -y pheeef/swaylock-effects
- local tmp; tmp=$(mktemp -d)
- ( cd "$tmp" && dnf download swaylock-effects \
- && rpm2cpio ./swaylock-effects-*.x86_64.rpm 2>/dev/null | cpio -idm 2>/dev/null \
- || bsdtar -xf ./swaylock-effects-*.x86_64.rpm 2>/dev/null )
- if [ -f "$tmp/usr/bin/swaylock" ]; then
- install -Dm755 "$tmp/usr/bin/swaylock" "$dest"
- say "Installed $dest ($("$dest" --version))"
- else
- warn "Could not extract swaylock-effects; plain swaylock will be used"
+install_swayfx() {
+ if have sway && sway --version 2>/dev/null | grep -qi swayfx; then say "SwayFX already installed"; return 0; fi
+ say "SwayFX comes from the swayfx/swayfx COPR (it conflicts with the stock 'sway' package)"
+ if rpm -q sway >/dev/null 2>&1; then
+ warn "Stock 'sway' is installed. Remove it first: sudo dnf remove sway sway-config-fedora then re-run."
+ FAILED+=("swayfx: stock sway is in the way"); return 0
fi
+ if ask "Enable COPR swayfx/swayfx and install swayfx?"; then
+ run sudo dnf copr enable -y swayfx/swayfx && dnf_install swayfx || FAILED+=("swayfx")
+ else warn "Skipping swayfx: the effects (blur, shadows, rounding) need it."; fi
+}
+
+install_dms() {
+ if have dms; then say "DankMaterialShell already installed"; return 0; fi
+ say "DankMaterialShell (bar, launcher, control center, notifications) comes from the avengemedia/dms COPR"
+ if ask "Enable COPR avengemedia/dms and install dms?"; then
+ run sudo dnf copr enable -y avengemedia/dms && dnf_install dms || FAILED+=("dms")
+ else warn "Skipping dms: no bar / control center / notifications will be started."; fi
+}
+
+# lazygit is not in Fedora: official release binary, checksum verified
+install_lazygit() {
+ have lazygit && return 0
+ local arch; case $(uname -m) in x86_64) arch=x86_64 ;; aarch64) arch=arm64 ;; *) warn "lazygit: unsupported arch"; return 0 ;; esac
+ say "Installing lazygit (official release binary)"
+ if [ "$DRY" = 1 ]; then echo " [dry-run] download lazygit_*_linux_$arch.tar.gz, verify sha256, install to ~/.local/bin"; return 0; fi
+ local tmp tag ver; tmp=$(mktemp -d)
+ tag=$(curl -fsSL https://api.github.com/repos/jesseduffield/lazygit/releases/latest | sed -n 's/.*"tag_name": *"\([^"]*\)".*/\1/p' | head -1)
+ if [ -z "$tag" ]; then warn "lazygit: could not get the latest version"; FAILED+=("lazygit"); rm -rf "$tmp"; return 0; fi
+ ver=${tag#v}
+ local base=https://github.com/jesseduffield/lazygit/releases/download/$tag asset=lazygit_${ver}_linux_${arch}.tar.gz
+ if ( cd "$tmp" && curl -fsSLO "$base/$asset" && curl -fsSLO "$base/checksums.txt" \
+ && [ "$(grep " $asset\$" checksums.txt | awk '{print $1}')" = "$(sha256sum "$asset" | awk '{print $1}')" ] \
+ && tar -xzf "$asset" lazygit ); then
+ install -Dm755 "$tmp/lazygit" "$HOME/.local/bin/lazygit"
+ else warn "lazygit: download or checksum failed"; FAILED+=("lazygit"); fi
rm -rf "$tmp"
}
-# ---------- 3. configs ----------
-install_configs() {
+# ---------------------------------------------------------------- zsh / oh-my-zsh
+install_shell_extras() {
+ local zsh_custom=$HOME/.oh-my-zsh/custom p
+ if [ ! -d "$HOME/.oh-my-zsh" ]; then
+ say "Installing oh-my-zsh"
+ run git clone --depth 1 https://github.com/ohmyzsh/ohmyzsh.git "$HOME/.oh-my-zsh" || FAILED+=("oh-my-zsh")
+ fi
+ for p in zsh-autosuggestions zsh-syntax-highlighting; do
+ [ -d "$zsh_custom/plugins/$p" ] || run git clone --depth 1 "https://github.com/zsh-users/$p.git" "$zsh_custom/plugins/$p" || FAILED+=("zsh plugin $p")
+ done
+ if [ "$(basename "${SHELL:-}")" != zsh ] && have zsh; then
+ if ask "Make zsh your login shell (chsh)?"; then run chsh -s "$(command -v zsh)" || NOTES+=("chsh failed; run: chsh -s $(command -v zsh)"); fi
+ fi
+}
+
+# ---------------------------------------------------------------- configs
+backup_and_copy_configs() {
say "Backing up existing configs to $BACKUP"
- mkdir -p "$BACKUP"
+ run mkdir -p "$BACKUP"
local d
- for d in sway waybar rofi dunst swaync swaylock kitty dms; do
- [ -e "$CFG/$d" ] && cp -a "$CFG/$d" "$BACKUP/"
+ for d in sway swaylock kitty dms swappy waybar rofi dunst swaync; do # last four: legacy, only backed up
+ if [ -e "$CFG/$d" ]; then run cp -a "$CFG/$d" "$BACKUP/"; fi
done
say "Copying configs to $CFG"
- mkdir -p "$CFG"
- cp -a "$REPO/.config/." "$CFG/"
+ run mkdir -p "$CFG"
+ # the machine-specific monitor layout ships only as 05-outputs.conf.example (see outputs-setup.sh)
+ if [ "$DRY" = 1 ]; then echo " [dry-run] cp -a $REPO/.config/. $CFG/"; else cp -a "$REPO/.config/." "$CFG/"; fi
+ run rm -f "$CFG/sway/config.d/40-bar.conf" # waybar is replaced by DMS; a stale file would start a second bar
+ run mkdir -p "$HOME/Pictures/Screenshots"
+ if [ "$DRY" = 0 ]; then chmod +x "$CFG"/sway/*.sh 2>/dev/null || true; fi
+
if [ -d "$REPO/home" ]; then
say "Copying shell/tmux files into $HOME (existing ones are backed up)"
local f
while IFS= read -r f; do
- [ -e "$HOME/$f" ] && { mkdir -p "$BACKUP/$(dirname "$f")"; cp -a "$HOME/$f" "$BACKUP/$f"; }
+ if [ "$f" = ".zshrc" ] && [ -e "$HOME/.zshrc" ] && [ "$FORCE_SHELL" = 0 ]; then
+ NOTES+=("Your ~/.zshrc was kept. To use the rice's one: ./install.sh --force-shell (the old one is backed up)"); continue
+ fi
+ if [ -e "$HOME/$f" ]; then run mkdir -p "$BACKUP/$(dirname "$f")"; run cp -a "$HOME/$f" "$BACKUP/$f"; fi
+ run mkdir -p "$HOME/$(dirname "$f")"
+ run cp -a "$REPO/home/$f" "$HOME/$f"
done < <(cd "$REPO/home" && find . -type f | sed 's|^\./||')
- mkdir -p "$HOME/.oh-my-zsh/custom"
- cp -a "$REPO/home/." "$HOME/"
fi
- # waybar is replaced by DMS; a stale 40-bar.conf from an older install would start a second bar
- rm -f "$CFG/sway/config.d/40-bar.conf"
- chmod +x "$CFG"/sway/*.sh "$CFG"/rofi/*.sh 2>/dev/null || true
+ install_wallpapers
+}
+
+# Wallpapers are managed by DMS (Settings > Wallpaper); we only drop the shipped favourites into its folder
+install_wallpapers() {
+ compgen -G "$REPO/wallpapers/*" >/dev/null || return 0
say "Copying wallpapers to $WALLS"
- mkdir -p "$WALLS"
- cp -n "$REPO"/wallpapers/* "$WALLS/"
- [ -e "$WALLS/current" ] || ln -s "$WALLS/original.jpg" "$WALLS/current"
-}
-
-# ---------- 4. apply ----------
-apply() {
- if command -v sway >/dev/null && sway -C >/dev/null 2>&1; then
- say "sway config is valid"
- else
- warn "sway -C reported a problem; check your config"
- fi
- if [ -n "${SWAYSOCK:-}" ] && command -v swaymsg >/dev/null; then
- swaymsg reload >/dev/null && say "sway reloaded (waybar restarts with it)"
- else
- say "Not inside sway: log in to a sway session to see the result"
+ run mkdir -p "$WALLS"
+ if [ "$DRY" = 1 ]; then echo " [dry-run] cp -n wallpapers/* $WALLS/"; else cp -n "$REPO"/wallpapers/* "$WALLS/"; fi
+ local cur=""
+ if [ -n "${SWAYSOCK:-}" ] && have dms && pgrep -x dms >/dev/null; then cur=$(dms ipc call wallpaper get 2>/dev/null | head -1); fi
+ if [ "$DRY" = 0 ] && [ -n "${SWAYSOCK:-}" ] && pgrep -x dms >/dev/null && [ -z "$cur" ] && [ -f "$WALLS/kitty.jpg" ]; then
+ dms ipc call wallpaper set "$WALLS/kitty.jpg" >/dev/null 2>&1 || true # only when no wallpaper is chosen yet
+ elif [ -z "$cur" ]; then
+ NOTES+=("Wallpaper: pick one in DMS (Super+N > settings > Wallpaper); the shipped ones are in $WALLS")
fi
}
-[ "$PACKAGES" = 1 ] && install_packages
-[ "$LOCKFX" = 1 ] && install_lock_effects
-install_configs
-apply
+# GTK theme: adw-gtk3 (DMS recolors it); only when the user has no choice of their own yet
+apply_gtk_theme() {
+ have gsettings || return 0
+ [ -d /usr/share/themes/adw-gtk3-dark ] || return 0
+ run gsettings set org.gnome.desktop.interface gtk-theme 'adw-gtk3-dark' || true
+ run gsettings set org.gnome.desktop.interface color-scheme 'prefer-dark' || true
+}
+setup_outputs() {
+ if [ -e "$CFG/sway/config.d/05-outputs.conf" ]; then say "Monitor layout already configured (05-outputs.conf)"; return 0; fi
+ if [ -n "${SWAYSOCK:-}" ] && [ "$DRY" = 0 ]; then
+ say "Generating the monitor layout"
+ if [ "$YES" = 1 ]; then "$CFG/sway/outputs-setup.sh" --auto || true; else "$CFG/sway/outputs-setup.sh" || true; fi
+ else
+ NOTES+=("Monitors: after logging into sway run ~/.config/sway/outputs-setup.sh (layout and scale for laptop + external screens)")
+ fi
+}
+
+verify() {
+ if have sway && [ "$DRY" = 0 ]; then
+ if sway -C >/dev/null 2>&1; then say "sway config is valid"; else warn "sway -C reported a problem; run: sway -C"; FAILED+=("sway config check"); fi
+ fi
+ if [ -n "${SWAYSOCK:-}" ] && have swaymsg && [ "$DRY" = 0 ]; then
+ swaymsg reload >/dev/null && say "sway reloaded"
+ else
+ NOTES+=("Log out and pick the 'Sway' session on the login screen to see the result.")
+ fi
+}
+
+# ---------------------------------------------------------------- main
+if [ "$CHECK" = 1 ]; then exec "$REPO/.config/sway/doctor.sh"; fi
+if [ "$(id -u)" = 0 ]; then warn "Do not run as root; the script uses sudo where needed."; exit 1; fi
+
+if check_fedora; then say "Fedora detected"; else
+ warn "This installer is for Fedora. Packages are skipped, configs only."; PACKAGES=0
+fi
+[ "$DRY" = 1 ] && say "DRY RUN: nothing will be changed"
+
+if [ "$PACKAGES" = 1 ]; then
+ say "Installing core packages (${#CORE_PKGS[@]})"
+ dnf_install "${CORE_PKGS[@]}"
+ install_swayfx
+ if [ "$DMS" = 1 ]; then install_dms; fi
+ if [ "$SHELLSETUP" = 1 ]; then
+ say "Installing shell packages (${#SHELL_PKGS[@]})"
+ dnf_install "${SHELL_PKGS[@]}"
+ install_lazygit
+ fi
+ if [ "$TOOLS" = 1 ]; then say "Installing sysadmin tools"; dnf_install "${TOOLS_PKGS[@]}"; fi
+fi
+
+backup_and_copy_configs
+if [ "$PACKAGES" = 1 ]; then apply_gtk_theme; fi
+if [ "$SHELLSETUP" = 1 ]; then install_shell_extras; fi
+setup_outputs
+verify
+
+echo
+echo "Backup of your old configs: $BACKUP"
+if [ ${#FAILED[@]} -gt 0 ]; then printf '\033[1;33mDid not work:\033[0m\n'; printf ' - %s\n' "${FAILED[@]}"; fi
+if [ ${#NOTES[@]} -gt 0 ]; then printf '\033[1mNext steps:\033[0m\n'; printf ' - %s\n' "${NOTES[@]}"; fi
cat <