diff --git a/.config/nvim/lazy-lock.json b/.config/nvim/lazy-lock.json
index ec559f8..01bb543 100644
--- a/.config/nvim/lazy-lock.json
+++ b/.config/nvim/lazy-lock.json
@@ -1,6 +1,6 @@
{
"LazyVim": { "branch": "main", "commit": "c10948c50b18fae7f256433afdef09e432410480" },
- "avante.nvim": { "branch": "main", "commit": "dee2402ed0b7c1d3710c0c8eed3d26aa055e118e" },
+ "avante.nvim": { "branch": "main", "commit": "d9c33ebe1e7205f416796b5b383d6894abe47495" },
"blink.cmp": { "branch": "main", "commit": "78336bc89ee5365633bcf754d93df01678b5c08f" },
"bufferline.nvim": { "branch": "main", "commit": "655133c3b4c3e5e05ec549b9f8cc2894ac6f51b3" },
"catppuccin": { "branch": "main", "commit": "49a926655a2f5579e9c276470fc300baaa49e524" },
@@ -10,8 +10,9 @@
"dressing.nvim": { "branch": "master", "commit": "2d7c2db2507fa3c4956142ee607431ddb2828639" },
"flash.nvim": { "branch": "main", "commit": "fcea7ff883235d9024dc41e638f164a450c14ca2" },
"friendly-snippets": { "branch": "main", "commit": "6cd7280adead7f586db6fccbd15d2cac7e2188b9" },
- "gitsigns.nvim": { "branch": "main", "commit": "25050e4ed39e628282831d4cbecb1850454ce915" },
+ "gitsigns.nvim": { "branch": "main", "commit": "2038c666bd9d8a0b7349a0b6ee00dc83104b9ecf" },
"grug-far.nvim": { "branch": "main", "commit": "c995bbacf8229dc096ec1c3d60f8531059c86c1b" },
+ "hybrid-theme": { "branch": "main", "commit": "6ae348938376f345e02eea4e6c27c0874b05f33a" },
"indent-blankline.nvim": { "branch": "master", "commit": "d28a3f70721c79e3c5f6693057ae929f3d9c0a03" },
"just-runner.nvim": { "branch": "main", "commit": "f29d405aa828900df242600720a2b0e57261489f" },
"lazy.nvim": { "branch": "main", "commit": "85c7ff3711b730b4030d03144f6db6375044ae82" },
@@ -19,20 +20,20 @@
"lualine.nvim": { "branch": "master", "commit": "221ce6b2d999187044529f49da6554a92f740a96" },
"mason-lspconfig.nvim": { "branch": "main", "commit": "21c5b3ebeaa0412e28096bb0701434c51c1fbf76" },
"mason.nvim": { "branch": "main", "commit": "2a6940af80375532e5e9e7c1f2fc6319a1b7a69d" },
- "mini.ai": { "branch": "main", "commit": "4511b3481707c1d021485475d34f2ed2a50bf47b" },
- "mini.files": { "branch": "main", "commit": "02874bc653fbecf2bee2c65441d0ebd09110f011" },
- "mini.icons": { "branch": "main", "commit": "ac38c983aed0a2bd32a65ca3e2348e12e58ca292" },
- "mini.pairs": { "branch": "main", "commit": "30cf2f01c4aaa2033db67376b9924fa2442c05d6" },
+ "mini.ai": { "branch": "main", "commit": "d73c36349aa7b0bab5f77ad71701a1d42211a1df" },
+ "mini.files": { "branch": "main", "commit": "a5689dae6b732955e33eec225b798d6815063179" },
+ "mini.icons": { "branch": "main", "commit": "e56797f90192d81f1fda02e662fc3e8e3d775027" },
+ "mini.pairs": { "branch": "main", "commit": "4a014143fcb4e9df26198ccb3ecff3b9e77a048c" },
"noice.nvim": { "branch": "main", "commit": "7bfd942445fb63089b59f97ca487d605e715f155" },
"nui.nvim": { "branch": "main", "commit": "de740991c12411b663994b2860f1a4fd0937c130" },
- "nvim-lint": { "branch": "master", "commit": "1ba49820a3c29ba6ab1b2dd441a63b3822c4e39b" },
- "nvim-lspconfig": { "branch": "master", "commit": "a683e0ddf0cf64c6cd689e18ffb480ade3c162b7" },
+ "nvim-lint": { "branch": "master", "commit": "01c9842c089069ab497430159312b2c8868a4590" },
+ "nvim-lspconfig": { "branch": "master", "commit": "bfcc0171a43f22afa61d927ffe9fcb6cb85dc99e" },
"nvim-treesitter": { "branch": "main", "commit": "4916d6592ede8c07973490d9322f187e07dfefac" },
"nvim-treesitter-textobjects": { "branch": "main", "commit": "851e865342e5a4cb1ae23d31caf6e991e1c99f1e" },
"nvim-ts-autotag": { "branch": "main", "commit": "88c1453db4ba7dd24131086fe51fdf74e587d275" },
"persistence.nvim": { "branch": "main", "commit": "b20b2a7887bd39c1a356980b45e03250f3dce49c" },
"plenary.nvim": { "branch": "master", "commit": "74b06c6c75e4eeb3108ec01852001636d85a932b" },
- "render-markdown.nvim": { "branch": "main", "commit": "5adf0895310c1904e5abfaad40a2baad7fe44a07" },
+ "render-markdown.nvim": { "branch": "main", "commit": "f422cb5c6855f150e2ddcfaf44e7157b98b34f6a" },
"snacks.nvim": { "branch": "main", "commit": "882c996cf28183f4d63640de0b4c02ec886d01f2" },
"todo-comments.nvim": { "branch": "main", "commit": "31e3c38ce9b29781e4422fc0322eb0a21f4e8668" },
"tokyonight.nvim": { "branch": "main", "commit": "cdc07ac78467a233fd62c493de29a17e0cf2b2b6" },
diff --git a/.config/nvim/lua/plugins/colorscheme.lua b/.config/nvim/lua/plugins/colorscheme.lua
index f81ac04..8394a72 100644
--- a/.config/nvim/lua/plugins/colorscheme.lua
+++ b/.config/nvim/lua/plugins/colorscheme.lua
@@ -13,39 +13,39 @@
-- }
-- Local development:
-return {
- dir = "/home/chodak/src/git/nvim-hybrid-theme",
- name = "hybrid-theme",
- lazy = false,
- priority = 1000,
- config = function()
- require("hybrid-theme").setup({
- theme = "dark",
- transparent = false,
- background_variant = "flat",
- italics = {
- comments = true,
- keywords = false,
- functions = false,
- strings = false,
- variables = false,
- },
- })
- require("hybrid-theme").colorscheme()
- end,
-}
-
-- return {
--- {
--- "chodak166/nvim-hybrid-theme",
--- name = "hybrid-theme",
--- lazy = false,
--- priority = 1000,
--- config = function()
--- require("hybrid-theme").setup({
--- background_variant = "semi_flat",
--- })
--- require("hybrid-theme").colorscheme()
--- end,
--- },
+-- dir = "/home/chodak/src/git/nvim-hybrid-theme",
+-- name = "hybrid-theme",
+-- lazy = false,
+-- priority = 1000,
+-- config = function()
+-- require("hybrid-theme").setup({
+-- theme = "dark",
+-- transparent = false,
+-- background_variant = "flat",
+-- italics = {
+-- comments = true,
+-- keywords = false,
+-- functions = false,
+-- strings = false,
+-- variables = false,
+-- },
+-- })
+-- require("hybrid-theme").colorscheme()
+-- end,
-- }
+
+return {
+ {
+ "chodak166/nvim-hybrid-theme",
+ name = "hybrid-theme",
+ lazy = false,
+ priority = 1000,
+ config = function()
+ require("hybrid-theme").setup({
+ background_variant = "semi_flat",
+ })
+ require("hybrid-theme").colorscheme()
+ end,
+ },
+}
diff --git a/.config/sway/config b/.config/sway/config
new file mode 100644
index 0000000..fd901c1
--- /dev/null
+++ b/.config/sway/config
@@ -0,0 +1,610 @@
+#----------------------------------------------------------------
+# Sway Config — Arch + Wayland
+#
+# Migrated from i3/X11 config. All X11-specific tools have been
+# replaced with Wayland-native equivalents (see migration notes
+# throughout this file).
+#
+# Install script: arch-init.sh
+#----------------------------------------------------------------
+
+
+#################################################################
+# Variables
+#################################################################
+
+# Mod key: Mod4 = Super/Windows key, Mod1 = Alt
+set $mod Mod4
+
+# Helper scripts directory (Wayland replacements for ratflow scripts)
+set $scriptsDir ~/.config/sway/scripts
+
+# Config directory
+set $configDir ~/.config/sway
+
+
+#################################################################
+# Workspaces
+#################################################################
+
+set $workspace1 1: >_
+set $workspace2 2: dev
+set $workspace3 3: www
+set $workspace4 4: files
+set $workspace5 5: e-mail
+set $workspace6 6: IM
+set $workspace7 7: video
+set $workspace8 8: workspace
+set $workspace9 9: workspace
+set $workspace10 10: Music
+set $workspace11 V: VM
+
+# Switch to workspace
+bindsym $mod+1 workspace $workspace1
+bindsym $mod+2 workspace $workspace2
+bindsym $mod+3 workspace $workspace3
+bindsym $mod+4 workspace $workspace4
+bindsym $mod+5 workspace $workspace5
+bindsym $mod+6 workspace $workspace6
+bindsym $mod+7 workspace $workspace7
+bindsym $mod+8 workspace $workspace8
+bindsym $mod+9 workspace $workspace9
+bindsym $mod+0 workspace $workspace10
+
+# Move focused container to workspace
+bindsym $mod+Shift+1 move container to workspace $workspace1
+bindsym $mod+Shift+2 move container to workspace $workspace2
+bindsym $mod+Shift+3 move container to workspace $workspace3
+bindsym $mod+Shift+4 move container to workspace $workspace4
+bindsym $mod+Shift+5 move container to workspace $workspace5
+bindsym $mod+Shift+6 move container to workspace $workspace6
+bindsym $mod+Shift+7 move container to workspace $workspace7
+bindsym $mod+Shift+8 move container to workspace $workspace8
+bindsym $mod+Shift+9 move container to workspace $workspace9
+bindsym $mod+Shift+0 move container to workspace $workspace10
+
+# Next/prev workspace
+bindsym $mod+x workspace next
+bindsym $mod+Shift+x move container to workspace next
+bindsym $mod+z workspace prev
+bindsym $mod+Shift+z move container to workspace prev
+
+# Moving workspace across monitors
+# MIGRATION: xrandr replaced by swaymsg output commands
+bindsym $mod+Control+Left move workspace to output left
+bindsym $mod+Control+Right move workspace to output right
+
+
+#################################################################
+# Output / Monitor Management
+# MIGRATION: xrandr → swaymsg output / kanshi for auto profiles
+#################################################################
+
+# Define your outputs — run `swaymsg -t get_outputs` to get names
+set $leftOutput eDP-1
+set $rightOutput HDMI-A-1
+
+# Default monitor setup
+# sway handles output layout natively, no xrandr needed
+output $rightOutput pos 1920 0
+output $leftOutput pos 0 0
+
+# Mode for toggling outputs (replaces i3 "outputs" mode)
+mode "outputs" {
+ # $mod+Shift+1: turn off left monitor; $mod+1: turn it on
+ bindsym $mod+Shift+1 output $leftOutput disable; mode "default"
+ bindsym $mod+1 output $leftOutput enable; mode "default"
+
+ # $mod+Shift+2: turn off right monitor; $mod+2: turn it on
+ bindsym $mod+Shift+2 output $rightOutput disable; mode "default"
+ bindsym $mod+2 output $rightOutput enable; mode "default"
+
+ bindsym Return mode "default"
+ bindsym Escape mode "default"
+}
+
+bindsym $mod+m mode "outputs"
+
+
+#################################################################
+# Wallpaper
+# MIGRATION: feh → swaybg (Wayland-native wallpaper setter)
+# Omarchy also uses swaybg for this purpose.
+#################################################################
+
+set $wallpaper1 /usr/share/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png
+set $wallpaper2 /usr/share/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png
+
+# swaybg is a native Wayland wallpaper setter
+output $leftOutput bg $wallpaper1 fill
+output $rightOutput bg $wallpaper2 fill
+
+
+#################################################################
+# Input Device Configuration
+# MIGRATION: synclient → sway input {} blocks
+# X11 touchpad/synaptics config replaced by libinput via sway.
+#################################################################
+
+input "type:touchpad" {
+ tap enabled
+ click_method button_areas
+ scroll_method two_finger
+ dwt enabled
+ # natural_scroll enabled # uncomment if you prefer macOS-style scrolling
+}
+
+input "type:keyboard" {
+ xkb_layout pl
+ # xkb_variant ...
+ # xkb_options caps:escape # uncomment to remap Caps Lock to Escape
+}
+
+
+#################################################################
+# Application Launchers
+# MIGRATION: ulauncher works on Wayland but is GTK-based.
+# Alternatives: wofi (native), rofi-wayland, tofi.
+# dmenu_run replaced by wofi (or keep as dmenu_path | wofi -d).
+# Omarchy uses Walker — a modern Wayland-native launcher.
+#################################################################
+
+# Terminal
+bindsym $mod+Return exec kitty
+
+# App launcher: wofi (lightweight, Wayland-native)
+# Alternatives: rofi -show drun (rofi-wayland package), tofi
+bindsym $mod+d exec fuzzel
+bindsym Mod1+F2 exec wofi --show run
+
+# Clipboard manager — show history (Ctrl+Alt+H)
+# bindsym Control+Mod1+h exec copyq toggle
+bindsym Control+Mod1+h exec cliphist list | fuzzel --width 80 --dmenu | cliphist decode | wl-copy
+
+# Run app assigned to current workspace
+bindsym $mod+Shift+a exec $scriptsDir/autoapp
+
+
+#################################################################
+# Window Navigation
+# MIGRATION: i3-msg workspace back_and_forth → same in sway
+#################################################################
+
+bindsym $mod+Tab workspace back_and_forth
+
+
+#################################################################
+# Window Management
+# MIGRATION: nearly identical to i3 — sway is i3-compatible
+#################################################################
+
+# Use Mouse+$mod to drag floating windows
+floating_modifier $mod
+
+# Kill focused window
+bindsym $mod+Shift+q kill
+
+# Change focus (vim keys)
+bindsym $mod+j focus left
+bindsym $mod+k focus down
+bindsym $mod+l focus up
+bindsym $mod+semicolon focus right
+
+# Change focus (arrow keys)
+bindsym $mod+Left focus left
+bindsym $mod+Down focus down
+bindsym $mod+Up focus up
+bindsym $mod+Right focus right
+
+# Move focused window (vim keys)
+bindsym $mod+Shift+j move left
+bindsym $mod+Shift+k move down
+bindsym $mod+Shift+l move up
+bindsym $mod+Shift+semicolon move right
+
+# Move focused window (arrow keys)
+bindsym $mod+Shift+Left move left
+bindsym $mod+Shift+Down move down
+bindsym $mod+Shift+Up move up
+bindsym $mod+Shift+Right move right
+
+# Split orientation
+bindsym $mod+h split h
+bindsym $mod+v split v
+
+# Fullscreen
+bindsym $mod+f fullscreen
+
+# Layout modes
+bindsym $mod+s layout stacking
+bindsym $mod+w layout tabbed
+bindsym $mod+e layout toggle split
+
+# Toggle tiling / floating
+bindsym $mod+Shift+space floating toggle
+bindsym $mod+button2 floating toggle
+
+# Focus tiling/floating toggle
+bindsym $mod+space focus mode_toggle
+
+# Focus parent container
+bindsym $mod+a focus parent
+
+# Always-float toggle (custom script)
+bindsym $mod+Shift+f exec $scriptsDir/always-float
+
+
+#################################################################
+# Resize Mode
+#################################################################
+
+mode "resize" {
+ bindsym j resize shrink width 10 px or 10 ppt
+ bindsym k resize grow height 10 px or 10 ppt
+ bindsym l resize shrink height 10 px or 10 ppt
+ bindsym semicolon resize grow width 10 px or 10 ppt
+
+ bindsym Left resize shrink width 10 px or 10 ppt
+ bindsym Down resize grow height 10 px or 10 ppt
+ bindsym Up resize shrink height 10 px or 10 ppt
+ bindsym Right resize grow width 10 px or 10 ppt
+
+ bindsym Return mode "default"
+ bindsym Escape mode "default"
+}
+
+bindsym $mod+r mode "resize"
+
+
+#################################################################
+# Screenshots
+# MIGRATION: screengrab (X11) → grim + slurp (Wayland-native)
+# grim = screen capture (replaces scrot/import/screengrab)
+# slurp = region selector (Wayland-native)
+# wl-copy copies to Wayland clipboard
+# Omarchy also uses grim + slurp (+ satty for annotation).
+#################################################################
+
+# Fullscreen screenshot → save to ~/Pictures and copy to clipboard
+bindsym Print exec grim -t png ~/Pictures/screenshot_$(date +%Y%m%d_%H%M%S).png && grim -t png - | wl-copy -t image/png
+
+# Region screenshot → select area with slurp
+bindsym Shift+Print exec grim -t png -g "$(slurp)" ~/Pictures/screenshot_$(date +%Y%m%d_%H%M%S).png && grim -t png -g "$(slurp)" - | wl-copy -t image/png
+
+# Active window screenshot (sway-specific: get focused window geometry)
+bindsym Control+Print exec grim -t png -g "$(swaymsg -t get_tree | jq -j '.. | select(.type?) | select(.focused) | .rect | "\(.x),\(.y) \(.width)x\(.height)"')" ~/Pictures/screenshot_$(date +%Y%m%d_%H%M%S).png
+
+
+#################################################################
+# Calendar
+# MIGRATION: osmo/gsimplecal (X11) → keep osmo if desired,
+# or use waybar clock module + rofi/wofi calendar script.
+# Omarchy uses waybar clock module only (no standalone calendar app).
+#################################################################
+
+bindsym $mod+c exec osmo -c
+# Alternative: wofi-based calendar popup
+# bindsym $mod+c exec $scriptsDir/calendar-popup
+
+
+#################################################################
+# Screen Color Temperature
+# MIGRATION: redshift (X11) → gammastep (Wayland fork of redshift)
+# or wlsunset (lighter alternative).
+# Omarchy uses hyprsunset (Hyprland-specific), but for sway
+# gammastep is the standard choice.
+# $scriptsDir/gammastep-adjust replaces redshift-adjust.
+#################################################################
+
+bindsym $mod+Control+KP_Next exec $scriptsDir/gammastep-adjust "-500"
+bindsym $mod+Control+KP_Prior exec $scriptsDir/gammastep-adjust "+500"
+bindsym $mod+Control+l exec gammastep -x
+
+
+#################################################################
+# Translation of Selected Text
+# MIGRATION: trans-xsel (X11 xsel) → translate-shell + wl-clipboard
+# Uses wl-paste / wl-copy instead of xsel/xclip.
+#################################################################
+
+bindsym $mod+t exec bash -c "$scriptsDir/translate-wl en:pl &"
+bindsym $mod+Shift+t exec bash -c "$scriptsDir/translate-wl pl:en &"
+
+
+#################################################################
+# Multimedia Keys & Audio
+# MIGRATION: PulseAudio volctl → PipeWire + wpctl (or pamixer)
+# Arch + Wayland standard is PipeWire with WirePlumber.
+# Volume OSD: SwayOSD (Omarchy approach) or swayosd-server.
+# The $scriptsDir/volctl wrapper uses wpctl/pamixer underneath.
+#################################################################
+
+# Volume controls (primary sink)
+bindsym XF86AudioRaiseVolume exec --no-startup-id $scriptsDir/volctl up
+bindsym XF86AudioLowerVolume exec --no-startup-id $scriptsDir/volctl down
+bindsym XF86AudioMute exec --no-startup-id $scriptsDir/volctl toggle
+
+# Volume controls (secondary sink, e.g. HDMI)
+bindsym Shift+XF86AudioRaiseVolume exec --no-startup-id SINK_NUM=1 $scriptsDir/volctl up
+bindsym Shift+XF86AudioLowerVolume exec --no-startup-id SINK_NUM=1 $scriptsDir/volctl down
+bindsym Shift+XF86AudioMute exec --no-startup-id SINK_NUM=1 $scriptsDir/volctl toggle
+
+# Screen brightness
+# MIGRATION: xbacklight / ratflow-backlight → brightnessctl
+bindsym XF86MonBrightnessUp exec --no-startup-id $scriptsDir/backlight up
+bindsym XF86MonBrightnessDown exec --no-startup-id $scriptsDir/backlight down
+
+# Media player controls
+# MIGRATION: clementine-specific → playerctl (agnostic MPRIS controller)
+# playerctl works with any MPRIS2-compatible player (Spotify, mpv, etc.)
+bindsym XF86AudioPlay exec playerctl play-pause
+bindsym XF86AudioPause exec playerctl pause
+bindsym XF86AudioNext exec playerctl next
+bindsym XF86AudioPrev exec playerctl previous
+
+
+#################################################################
+# Projector / Screen Layout
+# MIGRATION: xrandr shell scripts → swaymsg output commands
+# kanshi can auto-switch profiles on hotplug.
+#################################################################
+
+bindsym $mod+p exec $scriptsDir/output-profile projector
+bindsym $mod+Shift+p exec $scriptsDir/output-profile edp-only
+
+
+#################################################################
+# Session / Power Management
+# MIGRATION: i3-nagbar → swaynag, i3exit → loginctl-based script
+# swayidle handles DPMS/idle (replaces xset dpms).
+# swaylock replaces i3lock.
+# Omarchy uses hyprlock+hypridle, sway equivalents are swaylock+swayidle.
+#################################################################
+
+# Reload sway config
+bindsym $mod+Shift+c exec swaymsg reload
+
+# Suspend
+bindsym $mod+Escape exec systemctl suspend
+
+# Restart sway
+bindsym $mod+Shift+r exec swaymsg reload
+
+# Exit sway
+bindsym $mod+Shift+e exec swaynag -t warning -m 'Exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'
+
+# Session management mode (replaces i3exit)
+set $exitScript $scriptsDir/swayexit
+
+mode "session_management" {
+ bindsym l exec --no-startup-id $exitScript lock, mode "default"
+ bindsym e exec --no-startup-id $exitScript logout, mode "default"
+ bindsym s exec --no-startup-id $exitScript suspend, mode "default"
+ bindsym h exec --no-startup-id $exitScript hibernate, mode "default"
+ bindsym r exec --no-startup-id $exitScript reboot, mode "default"
+ bindsym Shift+s exec --no-startup-id $exitScript shutdown, mode "default"
+
+ bindsym Return mode "default"
+ bindsym Escape mode "default"
+}
+
+bindsym $mod+Pause mode "session_management"
+
+
+#################################################################
+# New Workspace
+# MIGRATION: yad → zenity (or rofi/wofi)
+# yad has some Wayland issues; zenity is GTK and works.
+# Alternatively, use wofi for a pure Wayland input dialog.
+#################################################################
+
+bindsym $mod+n exec name=$(wofi --dmenu --prompt "Workspace name") && swaymsg workspace "$name"
+
+
+#################################################################
+# Theme / Appearance
+# MIGRATION: No i3 client colors — sway has the same syntax.
+# compton → not needed (sway has built-in compositor with
+# basic effects). For blur/shadows, use swayfx (fork of sway).
+# Omarchy uses Hyprland which has built-in blur/animation;
+# for sway, swayfx adds these features.
+#################################################################
+
+# Font
+set $fontName "Source Sans 3 Semi-Bold"
+set $fontSize 10
+set $barFontSize 9
+
+font pango: $fontName $fontSize
+
+# Window colors
+# border background text indicator
+client.focused #252525 #252525 #D9D9D9 #101010
+client.focused_inactive #101010 #101010 #606060 #101010
+client.unfocused #101010 #000000 #606060 #101010
+client.urgent #F05000 #F05000 #F0F0F0 #101010
+
+# Default border style
+default_border pixel 2
+default_floating_border normal 2
+
+# Gaps (optional — sway supports gaps natively, unlike stock i3)
+# gaps inner 5
+# gaps outer 2
+
+# Window opacity (requires swayfx for per-window opacity, or use
+# sway's built-in opacity for all windows)
+# for_window [app_id="kitty"] opacity 0.95
+
+
+#################################################################
+# Bar — Waybar
+# MIGRATION: i3bar + py3status → waybar
+# waybar is the standard bar for wlroots-based compositors.
+# Omarchy uses waybar with extensive modules.
+# Config files: ~/.config/waybar/config.jsonc + style.css
+#################################################################
+
+bar {
+ swaybar_command waybar
+}
+
+
+#################################################################
+# Window Assignments
+# MIGRATION: class= → app_id= for native Wayland apps.
+# XWayland apps still use class=. Use `swaymsg -t get_tree`
+# to find the correct app_id for native Wayland apps.
+# Note: some apps may need both rules.
+#################################################################
+
+# Development
+assign [app_id="qtcreator"] $workspace2
+assign [class="Qtcreator"] $workspace2
+assign [app_id="eclipse"] $workspace2
+assign [class="Eclipse"] $workspace2
+
+# Browser
+assign [app_id="firefox"] $workspace3
+assign [class="Firefox"] $workspace3
+assign [app_id="chromium"] $workspace3
+assign [class="Chromium-browser"] $workspace3
+assign [class="Chrome"] $workspace3
+
+# File managers
+assign [app_id="pcmanfm-qt"] $workspace4
+assign [class="Pcmanfm"] $workspace4
+assign [app_id="dolphin"] $workspace4
+assign [class="Dolphin"] $workspace4
+assign [app_id="nautilus"] $workspace4
+assign [class="Nautilus"] $workspace4
+assign [app_id="thunar"] $workspace4
+assign [class="Thunar"] $workspace4
+
+# E-mail
+assign [app_id="thunderbird"] $workspace5
+assign [class="Thunderbird"] $workspace5
+
+# IM
+assign [app_id="telegram-desktop"] $workspace6
+assign [class="Telegram"] $workspace6
+assign [class="Skype"] $workspace6
+
+# Video
+assign [app_id="kodi"] $workspace7
+assign [class="Kodi"] $workspace7
+
+# Music
+assign [app_id="spotify"] $workspace10
+assign [class="Spotify"] $workspace10
+assign [class="Clementine"] $workspace10
+
+# VM
+assign [class="VirtualBox"] $workspace11
+assign [app_id="virt-manager"] $workspace11
+
+
+#################################################################
+# Floating Windows
+#################################################################
+
+for_window [app_id="screengrab"] floating enable
+for_window [app_id="osmo"] floating enable
+for_window [app_id="gsimplecal"] floating enable
+for_window [class="Osmo"] floating enable
+for_window [class="Skype"] floating enable
+for_window [app_id="yad"] floating enable
+for_window [class="Yad"] floating enable
+for_window [app_id="wofi"] floating enable
+for_window [app_id="swaync"] floating enable
+
+
+#################################################################
+# Idle Management
+# MIGRATION: xset dpms → swayidle
+# Locks screen after timeout, turns off display.
+# Omarchy uses hypridle; sway equivalent is swayidle.
+#################################################################
+
+set $lockCommand swaylock -f -c 000000
+
+exec swayidle -w \
+ timeout 600 '$lockCommand' \
+ timeout 900 'swaymsg "output * dpms off"' \
+ resume 'swaymsg "output * dpms on"' \
+ before-sleep '$lockCommand'
+
+
+#################################################################
+# Autostart
+# MIGRATION NOTES:
+# dunst → mako (Wayland-native notifier, used by Omarchy)
+# or swaync (Sway Notification Center, more feature-rich)
+# compton → NOT NEEDED (sway has built-in compositor)
+# For blur/rounded corners, use swayfx
+# synclient → sway input {} block (see above)
+# redshift → gammastep or wlsunset
+# nm-applet → nm-applet still works on Wayland, or use
+# waybar network module + impala TUI (Omarchy approach)
+# parcellite → cliphist + wl-clipboard (Wayland clipboard manager)
+# cliphist stores history, wl-copy/wl-paste for access
+# xset dpms → swayidle (see above)
+#################################################################
+
+# Notification daemon — mako (Omarchy uses mako)
+exec --no-startup-id mako
+
+# Alternative: swaync (Sway Notification Center) — more feature-rich
+# exec --no-startup-id swaync
+
+# Screen color temperature
+exec --no-startup-id gammastep -l 52.43:15.15 -m wayland
+
+# Network manager applet (still works on Wayland)
+exec --no-startup-id nm-applet --indicator
+
+# Clipboard manager
+# Use Ctrl+Alt+H to toggle the clipboard history window
+# exec --no-startup-id wl-paste --watch --type image cliphist store
+exec --no-startup-id wl-paste --type text --watch cliphist store
+exec --no-startup-id wl-paste --type image --watch cliphist store
+
+# Bluetooth manager (waybar module can handle this, or use blueman-applet)
+# exec --no-startup-id blueman-applet
+
+# Polkit authentication agent (needed for GUI apps that need root)
+exec --no-startup-id /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1
+
+# Background services for XDG desktop portals (screen sharing, file picker)
+exec --no-startup-id dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP=sway
+
+
+#################################################################
+# Key repeat rate
+#################################################################
+
+# input "type:keyboard" {
+# xkb_layout pl
+# # xkb_variant "programmer"
+# xkb_options "grp:alt_shift_toggle, compose:ralt"
+# repeat_delay 300
+# repeat_rate 40
+# }
+# input type:keyboard { xkb_layout pl xkb_options grp:win_space_toggle }
+
+# input type:keyboard {
+# xkb_layout pl
+# xkb_options level3:ralt_switch
+# }
+
+# input type:keyboard {
+# xkb_layout pl
+# xkb_options grp:alt_shift_toggle
+# }
+
+input type:keyboard {
+ xkb_layout pl,us
+ # lv3:ralt_switch keeps Right Alt working for Polish chars
+ # grp:alt_shift_toggle allows Alt+Shift to switch layouts
+ xkb_options lv3:ralt_switch,grp:alt_shift_toggle
+}
diff --git a/.config/sway/scripts/always-float b/.config/sway/scripts/always-float
new file mode 100755
index 0000000..5a01c8a
--- /dev/null
+++ b/.config/sway/scripts/always-float
@@ -0,0 +1,11 @@
+#!/bin/bash
+#----------------------------------------------------------------
+# always-float — Toggle floating on the currently focused window
+#
+# Adapted from the ratflow always-float script.
+# Uses swaymsg instead of i3-msg.
+#
+# Dependencies: sway
+#----------------------------------------------------------------
+
+swaymsg floating toggle
diff --git a/.config/sway/scripts/autoapp b/.config/sway/scripts/autoapp
new file mode 100755
index 0000000..f760fe4
--- /dev/null
+++ b/.config/sway/scripts/autoapp
@@ -0,0 +1,28 @@
+#!/bin/bash
+#----------------------------------------------------------------
+# autoapp — Launch the application assigned to current workspace
+#
+# Adapted from the ratflow autoapp script.
+# Reads workspace assignments and launches the matching app.
+# Uses swaymsg instead of i3-msg.
+#
+# Dependencies: sway, jq
+#----------------------------------------------------------------
+
+# Get current workspace name
+WORKSPACE=$(swaymsg -t get_workspaces | jq -r '.[] | select(.focused) | .name')
+
+# Map workspace names to applications
+# Customize these to match your workflow
+case "$WORKSPACE" in
+ *">_"*) kitty ;;
+ *"dev"*) kitty ;;
+ *"www"*) firefox ;;
+ *"files"*) thunar ;;
+ *"e-mail"*) thunderbird ;;
+ *"IM"*) telegram-desktop ;;
+ *"video"*) mpv ;;
+ *"Music"*) spotify ;;
+ *"VM"*) virt-manager ;;
+ *) echo "No app assigned to workspace: $WORKSPACE" ;;
+esac
diff --git a/.config/sway/scripts/backlight b/.config/sway/scripts/backlight
new file mode 100755
index 0000000..5c9279d
--- /dev/null
+++ b/.config/sway/scripts/backlight
@@ -0,0 +1,36 @@
+#!/bin/bash
+#----------------------------------------------------------------
+# backlight — Screen brightness control using brightnessctl
+#
+# Replaces the old ratflow backlight script (xbacklight-based).
+# brightnessctl works on Wayland without X11 dependencies.
+#
+# Usage:
+# backlight up — increase brightness by 5%
+# backlight down — decrease brightness by 5%
+# backlight set N — set brightness to N percent
+# backlight get — print current brightness percentage
+#
+# Dependencies: brightnessctl
+#----------------------------------------------------------------
+
+STEP=5
+
+case "$1" in
+ up)
+ brightnessctl set "${STEP}%+" -q
+ ;;
+ down)
+ brightnessctl set "${STEP}%-" -q
+ ;;
+ set)
+ brightnessctl set "${2}%" -q
+ ;;
+ get)
+ brightnessctl info | grep -oP '\d+%' | head -1 | tr -d '%'
+ ;;
+ *)
+ echo "Usage: backlight {up|down|set N|get}"
+ exit 1
+ ;;
+esac
diff --git a/.config/sway/scripts/gammastep-adjust b/.config/sway/scripts/gammastep-adjust
new file mode 100755
index 0000000..eddd412
--- /dev/null
+++ b/.config/sway/scripts/gammastep-adjust
@@ -0,0 +1,101 @@
+#!/bin/bash
+#----------------------------------------------------------------
+# gammastep-adjust — Adjust gammastep color temperature
+#
+# Replaces the old ratflow redshift-adjust script.
+# gammastep is the Wayland fork of redshift; it uses the same
+# temperature range (1000K–25000K, default 6500K = daylight).
+#
+# Usage:
+# gammastep-adjust -100 — make screen warmer (lower temperature by 100K)
+# gammastep-adjust +100 — make screen cooler (raise temperature by 100K)
+#
+# How it works:
+# gammastep doesn't support runtime temperature changes directly.
+# This script writes the current temperature to a state file,
+# kills any running gammastep, and launches a new one in one-shot
+# mode (-O) with the new temperature.
+#
+# State file: /tmp/gammastep-current-temp
+# PID file: /tmp/gammastep-pid
+# Default: 6500 (neutral/daylight)
+#
+# Dependencies: gammastep
+#----------------------------------------------------------------
+set -x
+
+STATE_FILE="/tmp/gammastep-current-temp"
+PID_FILE="/tmp/gammastep-pid"
+DEFAULT_TEMP=6500
+MIN_TEMP=1000
+MAX_TEMP=25000
+
+# Read current temperature or use default
+if [ -f "$STATE_FILE" ]; then
+ CURRENT=$(cat "$STATE_FILE")
+else
+ CURRENT=$DEFAULT_TEMP
+fi
+
+# Parse argument
+DELTA="${1:-0}"
+# Strip the sign to get the absolute value
+ABS_DELTA="${DELTA#+}"
+ABS_DELTA="${ABS_DELTA#-}"
+
+if [ -z "$ABS_DELTA" ]; then
+ echo "Usage: gammastep-adjust <+/-N>"
+ echo " Example: gammastep-adjust -100 (warmer)"
+ echo " Example: gammastep-adjust +100 (cooler)"
+ exit 1
+fi
+
+# Calculate new temperature
+NEW_TEMP=$((CURRENT + DELTA))
+
+# Clamp to valid range
+if [ "$NEW_TEMP" -lt "$MIN_TEMP" ]; then
+ NEW_TEMP=$MIN_TEMP
+fi
+if [ "$NEW_TEMP" -gt "$MAX_TEMP" ]; then
+ NEW_TEMP=$MAX_TEMP
+fi
+
+# Save new state
+echo "$NEW_TEMP" >"$STATE_FILE"
+
+# Kill existing gammastep instance(s)
+# Priority 1: use PID file if available (most precise)
+if [ -f "$PID_FILE" ]; then
+ OLD_PID=$(cat "$PID_FILE")
+ if kill -0 "$OLD_PID" 2>/dev/null; then
+ kill "$OLD_PID" 2>/dev/null
+ # Give gammastep a moment to release the display and exit
+ sleep 0.2
+ fi
+ rm -f "$PID_FILE"
+fi
+
+# Priority 2: kill any stray gammastep processes
+# -x (exact match) ensures we don't kill this script (gammastep-adjust)
+pkill -x gammastep 2>/dev/null
+sleep 0.1
+
+# Launch gammastep with the new temperature.
+#
+# IMPORTANT: We use "setsid" (create a new session) so that gammastep is
+# completely detached from the shell that Sway spawns for this keybinding.
+# Without setsid, Sway kills gammastep when the keybinding shell exits,
+# even with "&" — because the process is still in the same process group.
+# setsid makes gammastep its own session leader, immune to cleanup.
+# if [ "$NEW_TEMP" -ge "$DEFAULT_TEMP" ]; then
+# # At or above neutral — reset to no tint
+# setsid gammastep -x 2>/dev/null &
+# echo $! >"$PID_FILE"
+# echo "Temperature reset to neutral ($DEFAULT_TEMP K)"
+# else
+# Below neutral — apply one-shot manual temperature
+setsid gammastep -O "$NEW_TEMP" 2>/dev/null &
+echo $! >"$PID_FILE"
+echo "Temperature set to $NEW_TEMP K"
+# fi
diff --git a/.config/sway/scripts/output-profile b/.config/sway/scripts/output-profile
new file mode 100755
index 0000000..9bebb94
--- /dev/null
+++ b/.config/sway/scripts/output-profile
@@ -0,0 +1,44 @@
+#!/bin/bash
+#----------------------------------------------------------------
+# output-profile — Switch sway output profiles
+#
+# Replaces xrandr shell scripts used in the old i3 config.
+# Uses swaymsg output commands to configure displays.
+#
+# Usage:
+# output-profile projector — enable HDMI output (mirror or extend)
+# output-profile edp-only — disable all external outputs
+# output-profile dual — dual monitor setup
+#
+# Dependencies: sway
+#
+# NOTE: Edit the output names to match your hardware.
+# Run `swaymsg -t get_outputs` to list connected outputs.
+#----------------------------------------------------------------
+
+# Output names — adjust to match your hardware
+LAPTOP="eDP-1"
+EXTERNAL="HDMI-A-1"
+
+case "$1" in
+ projector)
+ # Enable external output, mirror the laptop display
+ swaymsg output "$EXTERNAL" enable pos 0 0
+ swaymsg output "$LAPTOP" pos 0 0
+ ;;
+ edp-only)
+ # Disable external output, laptop only
+ swaymsg output "$EXTERNAL" disable
+ ;;
+ dual)
+ # Dual monitor: laptop left, external right
+ swaymsg output "$LAPTOP" pos 0 0
+ swaymsg output "$EXTERNAL" pos 1920 0
+ ;;
+ *)
+ echo "Usage: output-profile {projector|edp-only|dual}"
+ echo " Edit this script to match your output names."
+ echo " Run 'swaymsg -t get_outputs' to list connected outputs."
+ exit 1
+ ;;
+esac
diff --git a/.config/sway/scripts/swayexit b/.config/sway/scripts/swayexit
new file mode 100755
index 0000000..ad2237b
--- /dev/null
+++ b/.config/sway/scripts/swayexit
@@ -0,0 +1,46 @@
+#!/bin/bash
+#----------------------------------------------------------------
+# swayexit — Session management for sway on Wayland
+#
+# Replaces the old i3exit script (i3/X11-based).
+# Uses loginctl for session management (systemd-logind).
+#
+# Usage:
+# swayexit lock — lock the screen (swaylock)
+# swayexit logout — exit sway
+# swayexit suspend — suspend to RAM
+# swayexit hibernate — suspend to disk
+# swayexit reboot — reboot the system
+# swayexit shutdown — power off the system
+#
+# Dependencies: swaylock, systemd (loginctl)
+#----------------------------------------------------------------
+
+case "$1" in
+ lock)
+ swaylock -f -c 000000
+ ;;
+ logout)
+ swaymsg exit
+ ;;
+ suspend)
+ swaylock -f -c 000000 &
+ sleep 0.5
+ systemctl suspend
+ ;;
+ hibernate)
+ swaylock -f -c 000000 &
+ sleep 0.5
+ systemctl hibernate
+ ;;
+ reboot)
+ systemctl reboot
+ ;;
+ shutdown)
+ systemctl poweroff
+ ;;
+ *)
+ echo "Usage: swayexit {lock|logout|suspend|hibernate|reboot|shutdown}"
+ exit 1
+ ;;
+esac
diff --git a/.config/sway/scripts/translate-wl b/.config/sway/scripts/translate-wl
new file mode 100755
index 0000000..527bf43
--- /dev/null
+++ b/.config/sway/scripts/translate-wl
@@ -0,0 +1,48 @@
+#!/bin/bash
+#----------------------------------------------------------------
+# translate-wl — Translate selected text using translate-shell
+# with Wayland clipboard (wl-clipboard)
+#
+# Replaces the old ratflow trans-xsel script (X11 xsel-based).
+# Uses wl-paste to get clipboard content and wl-copy to write
+# the translation back, plus a notification via notify-send
+# (which works with mako/swaync on Wayland).
+#
+# Usage:
+# translate-wl en:pl — translate English to Polish
+# translate-wl pl:en — translate Polish to English
+# translate-wl de:en — translate German to English, etc.
+#
+# Workflow:
+# 1. Select text (it goes to Wayland primary/clipboard)
+# 2. Press the bound key (e.g. $mod+t)
+# 3. Script reads selection via wl-paste, translates,
+# shows notification, and copies result to clipboard
+#
+# Dependencies: translate-shell (trans), wl-clipboard, libnotify
+#----------------------------------------------------------------
+
+LANG_PAIR="${1:-en:pl}"
+
+# Get clipboard content (user should select text first)
+# wl-paste gets the clipboard content; for primary selection use wl-paste -p
+TEXT=$(wl-paste -p 2>/dev/null || wl-paste 2>/dev/null)
+
+if [ -z "$TEXT" ]; then
+ notify-send -t 3000 "Translation" "No text in clipboard/selection"
+ exit 1
+fi
+
+# Translate using translate-shell
+RESULT=$(trans -b "$LANG_PAIR" "$TEXT" 2>/dev/null)
+
+if [ -z "$RESULT" ]; then
+ notify-send -t 3000 "Translation" "Translation failed"
+ exit 1
+fi
+
+# Copy result to clipboard
+echo -n "$RESULT" | wl-copy
+
+# Show notification
+notify-send -t 5000 "Translation ($LANG_PAIR)" "$RESULT"
diff --git a/.config/sway/scripts/volctl b/.config/sway/scripts/volctl
new file mode 100755
index 0000000..39a1a03
--- /dev/null
+++ b/.config/sway/scripts/volctl
@@ -0,0 +1,68 @@
+#!/bin/bash
+#----------------------------------------------------------------
+# volctl — Volume control wrapper for PipeWire + WirePlumber
+#
+# Replaces the old ratflow volctl (PulseAudio-based).
+# Uses wpctl (WirePlumber CLI) for volume management.
+#
+# Usage:
+# volctl up — increase volume by 5%
+# volctl down — decrease volume by 5%
+# volctl toggle — toggle mute on default sink
+# volctl mute — mute default sink
+# volctl unmute — unmute default sink
+#
+# Environment:
+# SINK_NUM — if set, selects Nth sink (0=default, 1=next, etc.)
+# mirrors the old VOLCTL_SINK_NUM behavior
+#
+# Dependencies: wireplumber, wpctl, pipewire, pipewire-pulse
+#----------------------------------------------------------------
+
+STEP=5
+
+# Resolve which sink to use based on SINK_NUM (like old VOLCTL_SINK_NUM)
+# SINK_NUM=0 or unset → default sink, SINK_NUM=1 → second sink, etc.
+get_sink_id() {
+ local num="${SINK_NUM:-0}"
+ if [ "$num" = "0" ]; then
+ echo "@DEFAULT_AUDIO_SINK@"
+ else
+ # List sinks and pick the Nth one (1-indexed in SINK_NUM)
+ local sinks
+ sinks=$(wpctl status | grep -A 100 'Audio' | grep -A 100 'Sinks:' | grep -oP '\d+\.' | head -n $((num + 1)) | tail -1 | tr -d '.')
+ if [ -z "$sinks" ]; then
+ echo "@DEFAULT_AUDIO_SINK@"
+ else
+ echo "$sinks"
+ fi
+ fi
+}
+
+SINK=$(get_sink_id)
+
+case "$1" in
+ up)
+ wpctl set-volume -l 1.5 "$SINK" "${STEP}%+"
+ ;;
+ down)
+ wpctl set-volume "$SINK" "${STEP}%-"
+ ;;
+ toggle)
+ wpctl set-mute "$SINK" toggle
+ ;;
+ mute)
+ wpctl set-mute "$SINK" 1
+ ;;
+ unmute)
+ wpctl set-mute "$SINK" 0
+ ;;
+ *)
+ echo "Usage: volctl {up|down|toggle|mute|unmute}"
+ echo " Set SINK_NUM env var to select sink (0=default, 1=second, etc.)"
+ exit 1
+ ;;
+esac
+
+# Optional: send signal to waybar to update volume display
+# pkill -SIGRTMIN+1 waybar
diff --git a/.config/waybar/config.jsonc b/.config/waybar/config.jsonc
index 2ff3b9d..4de92dc 100644
--- a/.config/waybar/config.jsonc
+++ b/.config/waybar/config.jsonc
@@ -31,20 +31,20 @@
},
"custom/network": {
- "exec": "/home/chodak/.config/waybar/network.py",
+ "exec": "/home/chodak/.config/waybar/network.py --icon-size 12pt",
"interval": 10,
"return-type": "json",
"tooltip": true
},
"clock#0": {
- "format": "{:%H:%M %d/%m/%y}",
+ "format": "{:%d/%m/%y %H:%M}",
"tooltip": false
},
"pulseaudio": {
- "format": "{icon} {volume:2}%",
- "format-bluetooth": "{icon} {volume}%",
+ "format": "{icon} {volume:2}%",
+ "format-bluetooth": "{icon} {volume}%",
"format-muted": "MUTE",
"format-icons": {
"headphones": "",
@@ -59,7 +59,7 @@
},
"memory": {
"interval": 5,
- "format": " {}%"
+ "format": " {}%"
},
"custom/top": {
"exec": "~/.config/waybar/top.sh",
@@ -73,7 +73,7 @@
"warning": 30,
"critical": 15
},
- "format": "{icon} {capacity}%",
+ "format": "{icon} {capacity}%",
"format-icons": [
"",
"",
@@ -83,7 +83,7 @@
]
},
"custom/disk": {
- "exec": "/home/chodak/.config/waybar/disk.py",
+ "exec": "/home/chodak/.config/waybar/disk.py --icon-size 10pt",
"interval": 30,
"return-type": "json",
"tooltip": true,
diff --git a/.config/waybar/disk.py b/.config/waybar/disk.py
index dab4761..d58347c 100755
--- a/.config/waybar/disk.py
+++ b/.config/waybar/disk.py
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
"""Waybar disk module: shows disk usage across all mounted partitions."""
+import argparse
import json
import os
@@ -17,6 +18,15 @@ COLOR_LOW = "#a6e3a1" # green — < 70%
COLOR_MID = "#f9e2af" # yellow — 70–89%
COLOR_HIGH = "#f38ba8" # red — ≥ 90%
+DEFAULT_ICON_SIZE = "24pt"
+
+
+def parse_args():
+ p = argparse.ArgumentParser()
+ p.add_argument("--icon-size", default=DEFAULT_ICON_SIZE,
+ help="Icon size (Pango size, e.g. 24pt)")
+ return p.parse_args()
+
def _pct_color(pct: float) -> str:
"""Return a Pango color string for the given usage percentage."""
@@ -87,6 +97,8 @@ def fmt_size(bytes_val):
def main():
+ args = parse_args()
+ isize = args.icon_size
partitions = get_partitions()
if not partitions:
@@ -137,11 +149,11 @@ def main():
bar_icon = "⚠" if root_pct >= 90 else ""
bar_color = _pct_color(root_pct)
bar_text = (
- f"{bar_icon}"
+ f"{bar_icon}"
f" {_span(bar_color, f'{root_pct:.0f}%')}"
)
elif tooltip_lines:
- bar_text = f" —"
+ bar_text = f" —"
else:
bar_text = " —"
diff --git a/.config/waybar/network.py b/.config/waybar/network.py
index dc67b1a..2d96771 100755
--- a/.config/waybar/network.py
+++ b/.config/waybar/network.py
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
"""Waybar network module: shows interface, IP, and up/down transfer rate."""
+import argparse
import json
import os
import re
@@ -10,6 +11,7 @@ import time
STATE_FILE_TMPL = "/tmp/waybar-network-stats-{}"
ICON = "" # nerd font network icon
NO_NET_ICON = ""
+DEFAULT_ICON_SIZE = "24pt"
def run(cmd: list[str]) -> str:
@@ -62,7 +64,16 @@ def format_rate(bps: float) -> str:
return f"{bps:.1f}B"
+def parse_args():
+ p = argparse.ArgumentParser()
+ p.add_argument("--icon-size", default=DEFAULT_ICON_SIZE,
+ help="Icon size (Pango size, e.g. 24pt)")
+ return p.parse_args()
+
+
def main() -> None:
+ args = parse_args()
+ isize = args.icon_size
iface = get_default_interface()
if iface is None:
print(json.dumps(
@@ -127,7 +138,7 @@ def main() -> None:
tooltip_rate = "↓ ?/s ↑ ?/s"
text = (
- f"{ICON}"
+ f"{ICON}"
f" {iface} {ip}{rate_str}"
)
tooltip = f"{itype}: {iface} — {ip} | {tooltip_rate}"
diff --git a/.config/waybar/style.css b/.config/waybar/style.css
index 022196d..c1fca7b 100644
--- a/.config/waybar/style.css
+++ b/.config/waybar/style.css
@@ -30,6 +30,10 @@ window#waybar {
padding: 0 6px;
}
+#pulseaudio.bluetooth {
+ color: #89b4fa;
+}
+
/* Workspaces: dimmed inactive, bold yellow active */
#workspaces button {
padding: 0 6px;
diff --git a/.local/bin/btswitch b/.local/bin/btswitch
new file mode 100755
index 0000000..f4a11f8
--- /dev/null
+++ b/.local/bin/btswitch
@@ -0,0 +1,447 @@
+#!/usr/bin/env bash
+set -u
+
+# -------------------------------------------------
+# CONFIGURATION
+# -------------------------------------------------
+WIFI_5G="cintra-5g"
+WIFI_24G="cintra-5g"
+
+declare -A BT_DEVICES
+BT_DEVICES[TAH8506]="00:1E:7C:CA:77:00"
+BT_DEVICES[SHB7150]="00:1E:7C:30:F3:69"
+BT_DEVICES[HD450BT]="00:16:94:33:91:51"
+BT_DEVICES[XTREME]="41:42:5D:FA:26:0A" # BT Speaker
+BT_DEVICES[EM03]="F1:5A:D5:16:57:9D" # BT Speaker/powerbank
+BT_DEVICES[X5]="47:0D:FF:C9:62:E1" # Bone Headphones thinkplus-X5
+
+BT_AUTO_DEVICES=("TAH8506" "SHB7150")
+
+BT_SERVICE="bluetooth"
+BT_RETRIES=6
+BT_DELAY=3
+
+# Polkit rule that lets the current user start/stop bluetooth.service
+# without a password, so this script runs sudo-free. Installed on first
+# run via ensure_polkit_rule().
+BT_POLKIT_RULE_FILE="/etc/polkit-1/rules.d/49-btswitch.rules"
+# Sentinel file to track that the rule was installed, since the user
+# may not have read/execute access to the polkit rules directory.
+BT_POLKIT_SENTINEL="$HOME/.config/btswitch/.polkit_rule_installed"
+
+# -------------------------------------------------
+# HELPERS
+# -------------------------------------------------
+
+wifi_switch_needed() {
+ [[ -n "$1" && -n "$2" && "$1" != "$2" ]]
+}
+
+ensure_polkit_rule() {
+ if [[ -f "$BT_POLKIT_SENTINEL" ]]; then
+ return 0
+ fi
+
+ cat >&2 << EOF
+
+NOTE: This script needs to start/stop the bluetooth service, which normally
+requires root. A one-time polkit rule can be installed so "$USER" can do this
+without sudo. You will be prompted for your password once to write:
+
+ $BT_POLKIT_RULE_FILE
+
+EOF
+ read -r -p "Install the polkit rule now? [y/N] " answer
+ case "$answer" in
+ y | Y | yes | YES) ;;
+ *)
+ echo "Skipping. The script cannot control bluetooth.service without it." >&2
+ return 1
+ ;;
+ esac
+
+ local tmpfile
+ tmpfile=$(mktemp) || return 1
+
+ cat > "$tmpfile" << POLKIT
+// Allow user "$USER" to start/stop bluetooth.service without a password.
+// Generated by btswitch on $(date -Is).
+polkit.addRule(function(action, subject) {
+ if (action.id === "org.freedesktop.systemd1.manage-units" &&
+ subject.user === "$USER") {
+ try {
+ var unit = action.lookup("unit");
+ if (unit === "$BT_SERVICE.service") {
+ return polkit.Result.YES;
+ }
+ } catch (e) {}
+ }
+});
+POLKIT
+
+ sudo cp "$tmpfile" "$BT_POLKIT_RULE_FILE" || {
+ echo "ERROR: Failed to write $BT_POLKIT_RULE_FILE." >&2
+ rm -f "$tmpfile"
+ return 1
+ }
+ rm -f "$tmpfile"
+
+ sudo chown root:polkitd "$BT_POLKIT_RULE_FILE" 2>/dev/null \
+ || sudo chown root:root "$BT_POLKIT_RULE_FILE"
+ sudo chmod 644 "$BT_POLKIT_RULE_FILE"
+
+ mkdir -p "$(dirname "$BT_POLKIT_SENTINEL")"
+ touch "$BT_POLKIT_SENTINEL"
+
+ echo "✔ Installed polkit rule: $BT_POLKIT_RULE_FILE" >&2
+ echo " (polkitd picks it up automatically; no restart needed.)" >&2
+ return 0
+}
+
+systemctl_bt() {
+ ensure_polkit_rule || {
+ echo "ERROR: Cannot control bluetooth.service without the polkit rule." >&2
+ echo "Run 'sudo systemctl $* $BT_SERVICE' manually, or re-run this script and install the rule." >&2
+ exit 1
+ }
+ if ! systemctl "$@" "$BT_SERVICE"; then
+ echo "ERROR: systemctl $* $BT_SERVICE failed." >&2
+ echo "If polkit prompted for a password, the rule file may be missing." >&2
+ echo "Remove $BT_POLKIT_SENTINEL and re-run to reinstall it." >&2
+ exit 1
+ fi
+}
+
+bt_info() {
+ bluetoothctl info "$1" 2> /dev/null
+}
+
+bt_is_paired() {
+ bt_info "$1" | grep -q "Paired: yes"
+}
+
+bt_is_trusted() {
+ bt_info "$1" | grep -q "Trusted: yes"
+}
+
+bt_is_connected() {
+ bt_info "$1" | grep -q "Connected: yes"
+}
+
+bt_is_mac_address() {
+ [[ "$1" =~ ^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$ ]]
+}
+
+bt_resolve_device() {
+ local device="$1"
+ if bt_is_mac_address "$device"; then
+ echo "$device"
+ else
+ echo "${BT_DEVICES[$device]:-}"
+ fi
+}
+
+bt_get_all_macs() {
+ local devices=("${!1}")
+ for dev in "${devices[@]}"; do
+ local mac
+ mac=$(bt_resolve_device "$dev")
+ [[ -n "$mac" ]] && echo "$mac"
+ done
+}
+
+# -------------------------------------------------
+# BLUETOOTH CONTROL
+# -------------------------------------------------
+
+start_bluetooth() {
+ echo "Starting Bluetooth service..."
+ systemctl_bt start
+
+ echo "Waiting for bluetoothd to become ready..."
+ for i in {1..10}; do
+ if bluetoothctl show | grep -q "Powered: yes"; then
+ bluetoothctl pairable on > /dev/null 2>&1
+ return 0
+ fi
+ bluetoothctl power on > /dev/null 2>&1
+ sleep 1
+ done
+
+ echo "ERROR: Bluetooth adapter not found or could not be powered on."
+ return 1
+}
+
+bt_pair_device() {
+ local mac="$1"
+
+ if bt_is_paired "$mac"; then
+ return 0
+ fi
+
+ echo "✖ Device $mac is not paired. Automatic pairing is not supported."
+ echo " Please pair it manually, then re-run this command:"
+ echo ""
+ echo " bluetoothctl"
+ echo " [bluetoothctl]# pair $mac"
+ echo " [bluetoothctl]# trust $mac"
+ echo " [bluetoothctl]# connect $mac"
+ echo " [bluetoothctl]# quit"
+ echo ""
+ echo " (Put the device in pairing mode first, if needed.)"
+ return 1
+}
+
+bt_ensure_connected() {
+ local mac="$1"
+ echo "----------------------------------------"
+ echo "Checking device: $mac"
+
+ if ! bt_is_trusted "$mac"; then
+ echo "→ Trusting $mac"
+ bluetoothctl trust "$mac" > /dev/null
+ fi
+
+ for ((i = 1; i <= BT_RETRIES; i++)); do
+ if bt_is_connected "$mac"; then
+ echo "✔ Connected: $mac"
+ return 0
+ fi
+
+ echo "→ Attempt $i/$BT_RETRIES: Connecting to $mac..."
+
+ if ! bt_is_paired "$mac"; then
+ bt_pair_device "$mac" || return 1
+ fi
+
+ bluetoothctl connect "$mac" > /dev/null 2>&1
+ sleep "$BT_DELAY"
+
+ if bt_is_connected "$mac"; then
+ echo "✔ Success!"
+ return 0
+ fi
+ done
+
+ echo "✖ Failed to connect $mac after $BT_RETRIES attempts"
+ return 1
+}
+
+bt_safe_disconnect() {
+ local mac="$1"
+ if bt_is_connected "$mac"; then
+ echo "Disconnecting $mac..."
+ bluetoothctl disconnect "$mac" > /dev/null 2>&1
+ else
+ echo "$mac is already offline."
+ fi
+}
+
+bt_stop_all() {
+ local devices=("${!1}")
+ for dev in "${devices[@]}"; do
+ local mac
+ mac=$(bt_resolve_device "$dev")
+ [[ -n "$mac" ]] && bt_safe_disconnect "$mac"
+ done
+}
+
+bt_start_all() {
+ local devices=("${!1}")
+ for dev in "${devices[@]}"; do
+ local mac
+ mac=$(bt_resolve_device "$dev")
+ [[ -n "$mac" ]] && bt_ensure_connected "$mac"
+ done
+}
+
+bt_status_all() {
+ local devices=("${!1}")
+ for dev in "${devices[@]}"; do
+ local mac
+ mac=$(bt_resolve_device "$dev")
+ if [[ -n "$mac" ]]; then
+ echo "--- $dev ($mac) ---"
+ if bt_is_connected "$mac"; then
+ echo "Status: CONNECTED"
+ elif bt_is_paired "$mac"; then
+ echo "Status: Paired (Offline)"
+ else
+ echo "Status: Not Paired / Unknown"
+ fi
+ fi
+ done
+}
+
+bt_scan() {
+ local scan_duration=30
+ declare -A seen_devices
+ local device_count=0
+
+ echo "Scanning for Bluetooth devices for $scan_duration seconds..."
+ echo "Press Ctrl+C to stop early"
+ echo "----------------------------------------"
+
+ trap 'echo ""; echo "Scan stopped"; exit 0' INT TERM
+
+ local start_time=$(date +%s)
+ local end_time=$((start_time + scan_duration))
+
+ while true; do
+ local current_time=$(date +%s)
+ if ((current_time >= end_time)); then
+ break
+ fi
+
+ while IFS= read -r line; do
+ if [[ $line =~ ^[[:space:]]*([0-9A-F:]{17})[[:space:]]+(.+)$ ]]; then
+ local mac="${BASH_REMATCH[1]}"
+ local name="${BASH_REMATCH[2]}"
+
+ if [[ -z "${seen_devices[$mac]:-}" ]]; then
+ seen_devices[$mac]="$name"
+ ((device_count++))
+ echo "[$device_count] $mac - $name"
+ fi
+ fi
+ done < <(hcitool scan 2> /dev/null | tail -n +2)
+
+ sleep 1
+ done
+
+ echo "----------------------------------------"
+ echo "Scan complete. Found $device_count unique device(s):"
+ for mac in "${!seen_devices[@]}"; do
+ echo " $mac - ${seen_devices[$mac]}"
+ done
+
+ trap - INT TERM
+}
+
+bt_list() {
+ echo "=== BT_DEVICES ==="
+ for name in "${!BT_DEVICES[@]}"; do
+ echo " $name: ${BT_DEVICES[$name]}"
+ done
+ echo ""
+ echo "=== BT_AUTO_DEVICES ==="
+ for name in "${BT_AUTO_DEVICES[@]}"; do
+ echo " $name: ${BT_DEVICES[$name]}"
+ done
+}
+
+# -------------------------------------------------
+# MAIN
+# -------------------------------------------------
+
+DEVICES=()
+TIMED_MINUTES=0
+
+parse_args() {
+ while [[ $# -gt 0 ]]; do
+ case "$1" in
+ -d | --device)
+ DEVICES+=("$2")
+ shift 2
+ ;;
+ -t | --timed)
+ TIMED_MINUTES="$2"
+ shift 2
+ ;;
+ start | stop | status | scan | list)
+ COMMAND="$1"
+ shift
+ ;;
+ *)
+ echo "Unknown option: $1"
+ echo "Usage: $0 [-d|--device DEVICE] [-t|--timed MINUTES] {start|stop|status|scan|list}"
+ exit 1
+ ;;
+ esac
+ done
+}
+
+parse_args "$@"
+
+if [[ -z "${COMMAND:-}" ]]; then
+ echo "Usage: $0 [-d|--device DEVICE] [-t|--timed MINUTES] {start|stop|status|scan|list}"
+ exit 1
+fi
+
+if [[ ${#DEVICES[@]} -gt 0 ]]; then
+ for dev in "${DEVICES[@]}"; do
+ mac=$(bt_resolve_device "$dev")
+ if [[ -z "$mac" ]]; then
+ echo "ERROR: Unknown device '$dev'. Valid aliases: ${!BT_DEVICES[@]}"
+ exit 1
+ fi
+ done
+fi
+
+case "$COMMAND" in
+ start)
+ if wifi_switch_needed "$WIFI_5G" "$WIFI_24G"; then
+ nmcli connection up "$WIFI_5G"
+ fi
+
+ start_bluetooth || exit 1
+
+ if [[ ${#DEVICES[@]} -gt 0 ]]; then
+ bt_start_all DEVICES[@]
+ else
+ bt_start_all BT_AUTO_DEVICES[@]
+ fi
+
+ if [[ "$TIMED_MINUTES" -gt 0 ]]; then
+ echo "Will disconnect after $TIMED_MINUTES minute(s)..."
+ sleep $((TIMED_MINUTES * 60))
+ echo "Time elapsed. Disconnecting..."
+
+ if [[ ${#DEVICES[@]} -gt 0 ]]; then
+ bt_stop_all DEVICES[@]
+ else
+ bt_stop_all BT_AUTO_DEVICES[@]
+ fi
+
+ echo "Stopping Bluetooth service..."
+ systemctl_bt stop
+
+ if wifi_switch_needed "$WIFI_5G" "$WIFI_24G"; then
+ nmcli connection up "$WIFI_24G"
+ fi
+ fi
+ ;;
+
+ stop)
+ if [[ ${#DEVICES[@]} -gt 0 ]]; then
+ bt_stop_all DEVICES[@]
+ else
+ bt_stop_all BT_AUTO_DEVICES[@]
+ fi
+
+ echo "Stopping Bluetooth service..."
+ systemctl_bt stop
+
+ if wifi_switch_needed "$WIFI_5G" "$WIFI_24G"; then
+ nmcli connection up "$WIFI_24G"
+ fi
+ ;;
+
+ status)
+ bluetoothctl show | grep -E "Name|Powered|Discoverable"
+
+ if [[ ${#DEVICES[@]} -gt 0 ]]; then
+ bt_status_all DEVICES[@]
+ else
+ bt_status_all BT_AUTO_DEVICES[@]
+ fi
+ ;;
+
+ scan)
+ bt_scan
+ ;;
+
+ list)
+ bt_list
+ ;;
+esac
diff --git a/.tmux.d/tmux-gruvbox b/.tmux.d/tmux-gruvbox
new file mode 160000
index 0000000..aeb30c7
--- /dev/null
+++ b/.tmux.d/tmux-gruvbox
@@ -0,0 +1 @@
+Subproject commit aeb30c7172a8ed8663409207814cf47d9df10d15