Initial commit: sway + uwsm desktop dotfiles

Nord-themed Wayland setup on sway (via uwsm), including:

- sway/swayidle/swaylock/swaddle — WM, idle/lock/inhibit
- waybar, rofi — bar and launcher
- dunst — notifications
- foot — terminal
- zsh (+fzf, syntax highlighting, autosuggestions) — shell
- mpd/rmpc/mpc, mpv — music and video
- nvim — editor (lazy.nvim)
- ly — login manager
- rbw + pinentry-rofi wrapper — Bitwarden/Vaultwarden CLI
- per-window-layout, clipvault — helper systemd services
This commit is contained in:
2026-08-11 10:30:07 +04:00
commit a213b10a88
35 changed files with 2775 additions and 0 deletions
+164
View File
@@ -0,0 +1,164 @@
HISTFILE="$HOME/.zsh_history"
HISTSIZE=10000
SAVEHIST=10000
bindkey -v
KEYTIMEOUT=1
setopt APPEND_HISTORY
setopt SHARE_HISTORY
setopt PROMPT_SUBST
autoload -U compinit
compinit
source <(fzf --zsh)
if [[ -f /usr/share/zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh ]]; then
source /usr/share/zsh/plugins/zsh-autosuggestions/zsh-autosuggestions.zsh
fi
if [[ -f /usr/share/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh ]]; then
source /usr/share/zsh/plugins/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh
fi
if [[ -f ~/.zsh/plugins/fzf-tab/fzf-tab.plugin.zsh ]]; then
source ~/.zsh/plugins/fzf-tab/fzf-tab.plugin.zsh
fi
if [[ -f ~/.zsh/plugins/fzf-tab-completion/zsh/fzf-tab-completion.plugin.zsh ]]; then
source ~/.zsh/plugins/fzf-tab-completion/zsh/fzf-tab-completion.plugin.zsh
fi
typeset -A ZSH_HIGHLIGHT_STYLES
ZSH_HIGHLIGHT_STYLES[default]='fg=#eceff4'
ZSH_HIGHLIGHT_STYLES[unknown-token]='fg=#bf616a'
ZSH_HIGHLIGHT_STYLES[command]='fg=#88c0d0'
ZSH_HIGHLIGHT_STYLES[builtin]='fg=#88c0d0'
ZSH_HIGHLIGHT_STYLES[alias]='fg=#8fbcbb'
ZSH_HIGHLIGHT_STYLES[function]='fg=#88c0d0'
ZSH_HIGHLIGHT_STYLES[precommand]='fg=#81a1c1,bold'
ZSH_HIGHLIGHT_STYLES[reserved-word]='fg=#81a1c1'
ZSH_HIGHLIGHT_STYLES[commandseparator]='fg=#d08770'
ZSH_HIGHLIGHT_STYLES[path]='fg=#eceff4,underline'
ZSH_HIGHLIGHT_STYLES[path_prefix]='fg=#eceff4,underline'
ZSH_HIGHLIGHT_STYLES[optstring]='fg=#ebcb8b'
ZSH_HIGHLIGHT_STYLES[argument-base]='fg=#eceff4'
ZSH_HIGHLIGHT_STYLES[dollar-parameter]='fg=#b48ead'
ZSH_HIGHLIGHT_STYLES[dollar-parameter_extension]='fg=#b48ead'
ZSH_HIGHLIGHT_STYLES[single-quoted-argument]='fg=#a3be8c'
ZSH_HIGHLIGHT_STYLES[double-quoted-argument]='fg=#a3be8c'
ZSH_HIGHLIGHT_STYLES[dollar-quoted-argument]='fg=#a3be8c'
ZSH_HIGHLIGHT_STYLES[comment]='fg=#4c566a,italic'
ZSH_HIGHLIGHT_STYLES[globbing]='fg=#ebcb8b'
ZSH_HIGHLIGHT_STYLES[history-expansion]='fg=#d08770'
zstyle ':fzf-tab:*' fzf-flags \
--color=fg:#eceff4,bg:#2e3440,fg+:#eceff4,bg+:#3b4252 \
--color=hl:#88c0d0,hl+:#88c0d0,info:#b48ead,prompt:#81a1c1 \
--color=pointer:#88c0d0,marker:#a3be8c,spinner:#88c0d0,header:#5e81ac \
--color=border:#4c566a,label:#8fbcbb,query:#eceff4 \
--color=preview-fg:#eceff4,preview-bg:#2e3440,preview-border:#4c566a,preview-label:#8fbcbb \
--color=gutter:#3b4252,separator:#434c5e,scrollbar:#5e81ac,preview-scrollbar:#5e81ac \
--color=disabled:#4c566a \
--prompt='❯ '
export FZF_DEFAULT_OPTS="
--color=fg:#eceff4,bg:#2e3440,fg+:#eceff4,bg+:#3b4252
--color=hl:#88c0d0,hl+:#88c0d0,info:#b48ead,prompt:#81a1c1
--color=pointer:#88c0d0,marker:#a3be8c,spinner:#88c0d0,header:#5e81ac
--color=border:#4c566a,label:#8fbcbb,query:#eceff4
--color=preview-fg:#eceff4,preview-bg:#2e3440,preview-border:#4c566a,preview-label:#8fbcbb
--color=gutter:#3b4252,separator:#434c5e,scrollbar:#5e81ac,preview-scrollbar:#5e81ac
--color=disabled:#4c566a
--prompt='❯ '
"
prompt_symbol() {
if [[ "$KEYMAP" == "vicmd" ]]; then
print -r -- "%F{#ebcb8b}❮%f"
else
print -r -- "%F{#88c0d0}❯%f"
fi
}
update_vim_prompt() {
zle reset-prompt
}
zle-keymap-select() {
update_vim_prompt
}
zle-line-init() {
zle -K viins
update_vim_prompt
}
git_prompt_info() {
local branch
local staged
local modified
local untracked
local deleted
local conflicts
local git_state=""
branch=$(git branch --show-current 2>/dev/null)
# Не Git-репозиторий
if [[ -z "$branch" ]]; then
return
fi
staged=$(git diff --cached --name-only 2>/dev/null | wc -l | tr -d ' ')
modified=$(git diff --name-only 2>/dev/null | wc -l | tr -d ' ')
untracked=$(git ls-files --others --exclude-standard 2>/dev/null | wc -l | tr -d ' ')
deleted=$(git diff --name-only --diff-filter=D 2>/dev/null | wc -l | tr -d ' ')
conflicts=$(git diff --name-only --diff-filter=U 2>/dev/null | wc -l | tr -d ' ')
if (( staged > 0 )); then
git_state+=" %F{#b48ead} ${staged}%f"
fi
if (( modified > 0 )); then
git_state+=" %F{#ebcb8b} ${modified}%f"
fi
if (( untracked > 0 )); then
git_state+=" %F{#a3be8c} ${untracked}%f"
fi
if (( deleted > 0 )); then
git_state+=" %F{#d08770} ${deleted}%f"
fi
if (( conflicts > 0 )); then
git_state+=" %F{#bf616a}󱈸 ${conflicts}%f"
fi
if [[ -n "$git_state" ]]; then
git_state=" %F{#88c0d0}❯%f${git_state}"
fi
print -r -- " %F{#88c0d0}❯%f %F{#8fbcbb}󰘬 ${branch}%f${git_state}"
}
precmd() {
local exit_code=$?
if (( exit_code != 0 )); then
PROMPT_EXIT="%F{#941703}✗${exit_code}%f "
else
PROMPT_EXIT=""
fi
}
nvim() {
printf '\033]0;nvim\007'
command nvim "$@"
printf '\033]0;foot\007'
}
zle -N zle-keymap-select
zle -N zle-line-init
PROMPT='%F{#eceff4}%~%f$(git_prompt_info) $(prompt_symbol) '
vi() { nvim "$@"; }
vim() { nvim "$@"; }
alias rmpc='printf "\033]0;rmpc\007"; command rmpc; printf "\033]0;foot\007"'
+153
View File
@@ -0,0 +1,153 @@
# dotfiles-sway
Конфиги для Sway.
## Стек
|Компонент|Технология|Описание|
|---|---|---|
|Тайлинговый менеджер|sway|i3-совместимый Wayland-компоузер. Раскладка окон, workspaces, бинды, запуск через uwsm|
||swayidle|Демон бездействия: блокирует экран, гасит мониторы (dpms off) и уходит в suspend по таймаутам; блокирует перед сном и включает мониторы после пробуждения|
||swaylock|Экран блокировки для Wayland/sway, с Nord-темой и индикатором ввода пароля|
||swaddle|MPRIS-инхибитор автоблокировки/сна — не даёт экрану гаснуть во время прослушивания музыки или просмотра видео|
||waybar|Панель статуса: workspaces, clock, tray, idle-inhibitor, CPU/RAM/temp/disk, аудио-виджеты (wireplumber), кастомный лаунчер rofi|
||rofi|Лаунчер приложений/меню: drun, кастомные моды по категориям (internet/dev/games/system/media), буфер обмена, история уведомлений, Bitwarden (rofi-rbw)|
|Музыка|mpd|Music Player Daemon — бэкенд воспроизведения музыки (вывод через pipewire, replaygain по альбому)|
||mpc|Консольный клиент-обёртка для MPD (control через CLI/скрипты — быстрые команды типа play/pause/next без запуска TUI)|
||rmpc|TUI-клиент для MPD: очередь, браузер библиотеки, поиск, кастомный статус-бар (артист/альбом/трек/битрейт), Nord-тема|
|Видео|mpv|Плеер с рендером через Vulkan (gpu-context=waylandvk, gpu-api=vulkan) и аппаратным декодированием на nvidia (hwdec=nvdec)|
|Редактор|nvim|Neovim на lazy.nvim: цветовая схема nord, colorizer, render-markdown, nvim-tree, treesitter, gitsigns, bufferline|
|Терминал|foot|Лёгкий Wayland-нативный терминал; шрифт Noto Mono, тёмная тема|
|Уведомления|dunst|Демон уведомлений: позиция top-right, прогресс-бары, история (sticky), Nord-цвета по уровню важности|
|Шелл|zsh|Интерактивный shell: vi-режим (bindkey -v), общая история между сессиями (SHARE_HISTORY), автодополнение через compinit, fzf (включая fzf-tab и fzf-tab-completion), подсветка синтаксиса (zsh-syntax-highlighting) и автоподсказки (zsh-autosuggestions) — всё в Nord-палитре. Кастомный promt с vi-режимом (❯/❮ в зависимости от normal/insert), git-статус в промпте (staged/modified/untracked/deleted/conflicts с иконками) и код выхода последней команды. Обёртки nvim/vi/vim и алиас rmpc меняют заголовок окна терминала (\033]0;...\007) на время работы программы|
|Сессия|uwsm|Universal Wayland Session Manager — запускает sway как systemd-managed сессию, пробрасывает переменные окружения (WAYLAND_DISPLAY, SWAYSOCK, Qt-тема, ssh-agent через rbw)|
|Логин-менеджер|ly|TUI display manager: анимация matrix, большие часы (bigclock=en), пустой пароль запрещён (allow_empty_password=false). Хоткеи: F1 shutdown, F2 restart, F3 suspend (systemctl suspend), F7 показать пароль; brightness/hibernate скрыты (*_key = null)|
## Зависимости
```bash
sudo pacman -S \
zsh \
zsh-syntax-highlighting \
zsh-autosuggestions \
pipewire \
wireplumber \
wl-clipboard \
noto-fonts \
noto-fonts-cjk \
noto-fonts-emoji \
ttf-nerd-fonts-symbols-mono \
sway \
swaylock \
swayidle \
swaybg \
slurp \
grim \
rbw \
rofi \
rofi-rbw \
python-systemd \
python-i3ipc \
rmpc \
neovim \
mpv \
mpc \
mpd \
mpd-mpris \
playerctl \
xorg-xwayland \
xdg-utils \
xdg-desktop-portal-gtk \
xdg-desktop-portal-wlr \
xorg-xwayland \
xorg-xrandr \
polkit \
ly \
jq \
git \
qt6ct \
fzf \
foot \
dunst \
uwsm \
mc \
imv
```
```bash
yay -S \
swaddle \
clipvault \
pinentry-rofi
```
## Деплой
```bash
ln -s ./.zsh ~/.config/.zsh
ln -s ./.zshrc ~/.zshrc
ln -s ./dunst ~/.config/dunst
ln -s ./foot ~/.config/foot
ln -s ./uwsm ~/.config/uwsm
ln -s ./systemd/user/* ~/.config/systemd/user/
ln -s ./sway ~/.config/sway
ln -s ./swaylock ~/.config/swaylock
ln -s ./swaddle ~/.config/swaddle
ln -s ./rofi ~/.config/rofi
ln -s ./rmpc ~/.config/rmpc
ln -s ./nvim ~/.config/nvim
ln -s ./mpv ~/.config/mpv
ln -s ./mpd ~/.config/mpd
```
```bash
mkdir -p ~/.zsh/plugins
git clone https://github.com/Aloxaf/fzf-tab ~/.zsh/plugins/fzf-tab
git clone https://github.com/lincheney/fzf-tab-completion ~/.zsh/plugins/fzf-tab-completion
```
```bash
chsh -s /usr/bin/zsh
```
```bash
sudo cp ./other/sway-uwsm.desktop /usr/share/wayland-sessions/
sudo cp ./other/ly.ini /etc/ly/config.ini
```
```bash
mkdir -p ~/.local/bin/
ln -s ./other/pinentry-rofi-wrapper ~/.local/bin/pinentry-rofi-wrapper
```
```bash
rbw config set email $email
rbw config set base_url $url
rbw config set pinentry $pinentry_rofi_wrapper
```
## Скриншоты
<p align="center">
<img src="./assets/photo_2026-08-11_08-01-47.jpg" alt="waybar/rofi/dunst" width="800">
<br>
<sub>waybar / rofi / dunst</sub>
</p>
<p align="center">
<img src="./assets/photo_2026-08-11_08-01-57.jpg" alt="rmpc" width="800">
<br>
<sub>rmpc</sub>
</p>
<p align="center">
<img src="./assets/photo_2026-08-11_08-02-00.jpg" alt="nvim" width="800">
<br>
<sub>nvim</sub>
</p>
<p align="center">
<img src="./assets/photo_2026-08-11_08-02-03.jpg" alt="zsh/fzf" width="800">
<br>
<sub>zsh / fzf</sub>
</p>
Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

+82
View File
@@ -0,0 +1,82 @@
[global]
monitor = 0
follow = mouse
origin = top-right
offset = 5x5
scale = 0
width = 340
height = 300
notification_limit = 5
progress_bar = true
progress_bar_height = 10
progress_bar_frame_width = 0
progress_bar_min_width = 150
progress_bar_max_width = 300
progress_bar_corner_radius = 0
indicate_hidden = yes
separator_height = 0
padding = 10
horizontal_padding = 10
text_icon_padding = 10
frame_width = 0
separator_color = frame
sort = yes
idle_threshold = 120
gap_size = 5
font = Noto Mono 10
line_height = 0
markup = full
format = "<b>%s</b>\n%b"
alignment = left
vertical_alignment = center
show_age_threshold = 60
ellipsize = middle
ignore_newline = no
stack_duplicates = true
hide_duplicate_count = false
show_indicators = yes
icon_position = left
min_icon_size = 32
max_icon_size = 48
sticky_history = yes
history_length = 20
dmenu = rofi -dmenu -p dunst
browser = xdg-open
always_run_script = true
title = Dunst
class = Dunst
corner_radius = 0
ignore_dbusclose = false
force_xwayland = false
force_xinerama = false
mouse_left_click = close_current
mouse_middle_click = do_action, close_current
mouse_right_click = close_all
[experimental]
per_monitor_dpi = false
[urgency_low]
background = "#2e3440"
foreground = "#eceff4"
timeout = 2
[urgency_normal]
background = "#2e3440"
foreground = "#eceff4"
timeout = 8
[urgency_critical]
background = "#2e3440"
foreground = "#bf616a"
timeout = 0
+11
View File
@@ -0,0 +1,11 @@
[main]
font=Noto Mono:size=10
dpi-aware=no
pad=0x0
[colors-dark]
background=2e3440
[key-bindings]
clipboard-copy=Control+Shift+c
clipboard-paste=Control+Shift+v
+16
View File
@@ -0,0 +1,16 @@
music_directory "/mnt/media1/music"
playlist_directory "~/.config/mpd/playlists"
db_file "~/.config/mpd/database"
log_file "~/.config/mpd/log"
pid_file "~/.config/mpd/pid"
state_file "~/.config/mpd/state"
sticker_file "~/.config/mpd/sticker.sql"
bind_to_address "~/.config/mpd/socket"
bind_to_address "127.0.0.1"
port "6600"
auto_update "yes"
audio_output {
type "pipewire"
name "MPD PipeWire Output"
}
replaygain "album"
+3
View File
@@ -0,0 +1,3 @@
gpu-context=waylandvk
gpu-api=vulkan
hwdec=nvdec
+141
View File
@@ -0,0 +1,141 @@
require('core.configs')
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not (vim.uv or vim.loop).fs_stat(lazypath) then
vim.fn.system({
"git",
"clone",
"--filter=blob:none",
"https://github.com/folke/lazy.nvim.git",
"--branch=stable",
lazypath,
})
end
vim.opt.rtp:prepend(lazypath)
require("lazy").setup({
{
"shaunsingh/nord.nvim",
lazy = false,
priority = 1000,
config = function()
vim.cmd("colorscheme nord")
end,
},
{
"NvChad/nvim-colorizer.lua",
opts = {
filetypes = { "*" },
user_default_options = {
RGB = true,
RRGGBB = true,
names = false,
RRGGBBAA = true,
css = true,
mode = "background",
},
},
},
{
"MeanderingProgrammer/render-markdown.nvim",
dependencies = { "nvim-treesitter/nvim-treesitter", "nvim-tree/nvim-web-devicons" },
ft = { "markdown" },
opts = {},
},
{
"nvim-tree/nvim-tree.lua",
version = "*",
dependencies = { "nvim-tree/nvim-web-devicons" },
config = function()
require("nvim-tree").setup({
view = { side = "left", width = 30 },
})
end,
},
{
"nvim-treesitter/nvim-treesitter",
build = ":TSUpdate",
config = function()
local status_ok, configs = pcall(require, "nvim-treesitter.configs")
if not status_ok then
return
end
configs.setup({
ensure_installed = { "python", "bash", "lua", "vim", "markdown" },
highlight = { enable = true },
})
end,
},
{
"lewis6991/gitsigns.nvim",
opts = {},
},
{
"akinsho/bufferline.nvim",
version = "*",
dependencies = "nvim-tree/nvim-web-devicons",
config = function()
require("bufferline").setup({
options = {
mode = "buffers",
separator_style = "thick",
diagnostics = "nvim_lsp",
enforce_regular_tabs = true,
tab_size = 14,
},
highlights = {
fill = {
bg = "#2e3440",
},
background = {
bg = "#2e3440",
fg = "#eceff4",
},
buffer_selected = {
bg = "#3b4252",
fg = "#eceff4",
bold = false,
italic = false,
},
close_button_selected = {
bg = "#3b4252",
fg = "#eceff4",
},
close_button = {
bg = "#2e3440",
fg = "#4c566a",
},
close_button_visible = {
bg = "#2e3440",
fg = "#4c566a",
},
separator = {
bg = "#2e3440",
fg = "#2e3440",
},
separator_selected = {
bg = "#3b4252",
fg = "#3b4252",
},
indicator_selected = {
bg = "#3b4252",
fg = "#88c0d0",
},
modified_selected = {
bg = "#3b4252",
fg = "#a3be8c",
},
modified = {
bg = "#2e3440",
fg = "#4c566a",
},
modified_visible = {
bg = "#2e3440",
fg = "#4c566a",
},
},
})
end,
},
})
+11
View File
@@ -0,0 +1,11 @@
{
"bufferline.nvim": { "branch": "main", "commit": "655133c3b4c3e5e05ec549b9f8cc2894ac6f51b3" },
"gitsigns.nvim": { "branch": "main", "commit": "31d6fb2d618bca1482b9f274751ead5f03461408" },
"lazy.nvim": { "branch": "main", "commit": "306a05526ada86a7b30af95c5cc81ffba93fef97" },
"nord.nvim": { "branch": "master", "commit": "80c1e5321505aeb22b7a9f23eb82f1e193c12470" },
"nvim-colorizer.lua": { "branch": "master", "commit": "72a05f62c52241bc7441c820eb53946f92b2e6a4" },
"nvim-tree.lua": { "branch": "master", "commit": "531b807b8f0d6f75016a0ee1e0cd5ce2086e9d95" },
"nvim-treesitter": { "branch": "main", "commit": "c9f9ed6c1892f629ea399f4ee7905f2686fa13f2" },
"nvim-web-devicons": { "branch": "master", "commit": "2ae6958df7ced50baac5035cec0c15799eedfbf7" },
"render-markdown.nvim": { "branch": "main", "commit": "f422cb5c6855f150e2ddcfaf44e7157b98b34f6a" }
}
+6
View File
@@ -0,0 +1,6 @@
vim.opt.ignorecase = true
vim.opt.smartcase = true
vim.opt.number = true
vim.opt.relativenumber = true
vim.o.termguicolors = true
vim.cmd("syntax enable")
+4
View File
@@ -0,0 +1,4 @@
vim.keymap.set('n', '<leader>e', ':NvimTreeToggle<CR>')
vim.keymap.set('n', '<Tab>', ':BufferLineCycleNext<CR>')
vim.keymap.set('n', '<S-Tab>', ':BufferLineCyclePrev<CR>')
vim.keymap.set('n', '<leader>x', ':bdelete<CR>')
+422
View File
@@ -0,0 +1,422 @@
# Ly supports 24-bit true color with styling, which means each color is a 32-bit value.
# The format is 0xSSRRGGBB, where SS is the styling, RR is red, GG is green, and BB is blue.
# Here are the possible styling options:
# TB_BOLD 0x01000000
# TB_UNDERLINE 0x02000000
# TB_REVERSE 0x04000000
# TB_ITALIC 0x08000000
# TB_BLINK 0x10000000
# TB_HI_BLACK 0x20000000
# TB_BRIGHT 0x40000000
# TB_DIM 0x80000000
# Programmatically, you'd apply them using the bitwise OR operator (|), but because Ly's
# configuration doesn't support using it, you have to manually compute the color value.
# Note that, if you want to use the default color value of the terminal, you can use the
# special value 0x00000000. This means that, if you want to use black, you *must* use
# the styling option TB_HI_BLACK (the RGB values are ignored when using this option).
# Allow empty password or not when authenticating
allow_empty_password = false
# The active animation
# none -> Nothing
# doom -> PSX DOOM fire
# matrix -> CMatrix
# colormix -> Color mixing shader
# gameoflife -> John Conway's Game of Life
# dur_file -> .dur file format (https://github.com/cmang/durdraw/tree/master)
animation = matrix
# Delay between each animation frame in milliseconds
animation_frame_delay = 5
# Stop the animation after some time
# 0 -> Run forever
# 1..2e12 -> Stop the animation after this many seconds
animation_timeout_sec = 0
# The character used to mask the password
# You can either type it directly as a UTF-8 character (like *), or use a UTF-32
# codepoint (for example 0x2022 for a bullet point)
# If null, the password will be hidden
# Note: you can use a # by escaping it like so: \#
asterisk = *
# The number of failed authentications before a special animation is played... ;)
# If set to 0, the animation will never be played
auth_fails = 10
# Identifier for battery whose charge to display at top left
# Primary battery is usually BAT0 or BAT1
# If set to null, battery status won't be shown
battery_id = null
# Automatic login configuration
# This feature allows Ly to automatically log in a user without password prompt.
# IMPORTANT: Both auto_login_user and auto_login_session must be set for this to work.
# Autologin only happens once at startup - it won't re-trigger after logout.
# PAM service name to use for automatic login
# The default service (ly-autologin) uses pam_permit to allow login without password
# The appropriate platform-specific PAM configuration (ly-autologin) will be used automatically
auto_login_service = ly-autologin
# Session name to launch automatically
# To find available session names, check the .desktop files in:
# - /usr/share/xsessions/ (for X11 sessions)
# - /usr/share/wayland-sessions/ (for Wayland sessions)
# Use the filename without .desktop extension, the Name field inside the file or the value of the DesktopNames field
# Examples: "i3", "sway", "gnome", "plasma", "xfce"
# If null, automatic login is disabled
auto_login_session = null
# Username to automatically log in
# Must be a valid user on the system
# If null, automatic login is disabled
auto_login_user = null
# Background color id
bg = 0x00000000
# Change the state and language of the big clock
# none -> Disabled (default)
# en -> English
# fa -> Farsi
bigclock = en
# Set bigclock to 12-hour notation.
bigclock_12hr = false
# Set bigclock to show the seconds.
bigclock_seconds = false
# Blank main box background
# Setting to false will make it transparent
blank_box = true
# Border foreground color id
border_fg = 0x00FFFFFF
# Title to show at the top of the main box
# If set to null, none will be shown
box_title = null
# Brightness decrease command
brightness_down_cmd = /usr/bin/brightnessctl -q -n s 10%-
# Brightness decrease key combination, or null to disable
brightness_down_key = null
# Brightness increase command
brightness_up_cmd = /usr/bin/brightnessctl -q -n s +10%
# Brightness increase key combination, or null to disable
brightness_up_key = null
# Erase password input on failure
clear_password = false
# Format string for clock in top right corner (see strftime specification). Example: %c
# If null, the clock won't be shown
clock = null
# CMatrix animation foreground color id
cmatrix_fg = 0x0000FF00
# CMatrix animation character string head color id
cmatrix_head_col = 0x01FFFFFF
# CMatrix animation minimum codepoint. It uses a 16-bit integer
# For Japanese characters for example, you can use 0x3000 here
cmatrix_min_codepoint = 0x21
# CMatrix animation maximum codepoint. It uses a 16-bit integer
# For Japanese characters for example, you can use 0x30FF here
cmatrix_max_codepoint = 0x7B
# Color mixing animation first color id
colormix_col1 = 0x00FF0000
# Color mixing animation second color id
colormix_col2 = 0x000000FF
# Color mixing animation third color id
colormix_col3 = 0x20000000
# For custom binds: the horizontal limit in characters for each
# line of custom binds before moving on to the next.
# If null, defaults to the width of the terminal instead.
custom_bind_width = null
# Custom sessions directory
# You can specify multiple directories,
# e.g. /etc/ly/custom-sessions:/usr/share/custom-sessions
custom_sessions = /etc/ly/custom-sessions
# Input box active by default on startup
# Available inputs: info_line, session, login, password
default_input = login
# DOOM animation fire height (1 thru 9)
doom_fire_height = 6
# DOOM animation fire spread (0 thru 4)
doom_fire_spread = 2
# DOOM animation custom top color (low intensity flames)
doom_top_color = 0x009F2707
# DOOM animation custom middle color (medium intensity flames)
doom_middle_color = 0x00C78F17
# DOOM animation custom bottom color (high intensity flames)
doom_bottom_color = 0x00FFFFFF
# Dur file path
dur_file_path = /etc/ly/example.dur
# Dur file alignment
# The dur file can be aligned with a direction and centered easily with the flags below
# Available inputs: topleft, topcenter, topright, centerleft, center, centerright, bottomleft, bottomcenter, bottomright
dur_offset_alignment = center
# Dur offset x direction (value is added to the current position determined by alignment, negatives are supported)
dur_x_offset = 0
# Dur offset y direction (value is added to the current position determined by alignment, negatives are supported)
dur_y_offset = 0
# Set margin to the edges of the DM (useful for curved monitors)
edge_margin = 0
# Error background color id
error_bg = 0x00000000
# Error foreground color id
# Default is red and bold
error_fg = 0x01FF0000
# Foreground color id
fg = 0x00FFFFFF
# Render true colors (if supported)
# If false, output will be in eight-color mode
# All eight-color mode color codes:
# TB_DEFAULT 0x0000
# TB_BLACK 0x0001
# TB_RED 0x0002
# TB_GREEN 0x0003
# TB_YELLOW 0x0004
# TB_BLUE 0x0005
# TB_MAGENTA 0x0006
# TB_CYAN 0x0007
# TB_WHITE 0x0008
# If full color is off, the styling options still work. The colors are
# always 32-bit values with the styling in the most significant byte.
# Note: If using the dur_file animation option and the dur file's color range
# is saved as 256 with this option disabled, the file will not be drawn.
full_color = true
# Game of Life entropy interval (0 = disabled, >0 = add entropy every N generations)
# 0 -> Pure Conway's Game of Life (will eventually stabilize)
# 10 -> Add entropy every 10 generations (recommended for continuous activity)
# 50+ -> Less frequent entropy for more natural evolution
gameoflife_entropy_interval = 10
# Game of Life animation foreground color id
gameoflife_fg = 0x0000FF00
# Game of Life frame delay (lower = faster animation, higher = slower)
# 1-3 -> Very fast animation
# 6 -> Default smooth animation speed
# 10+ -> Slower, more contemplative speed
gameoflife_frame_delay = 6
# Game of Life initial cell density (0.0 to 1.0)
# 0.1 -> Sparse, minimal activity
# 0.4 -> Balanced activity (recommended)
# 0.7+ -> Dense, chaotic patterns
gameoflife_initial_density = 0.4
# Command executed when pressing hibernate key (can be null)
hibernate_cmd = null
# Specifies the key combination used for hibernate
hibernate_key = null
# Remove main box borders
hide_borders = false
# Remove power management command hints
hide_key_hints = false
# Remove keyboard lock states from the top right corner
hide_keyboard_locks = false
# Remove version number from the top left corner
hide_version_string = false
# Command executed when no input is detected for a certain time
# If null, no command will be executed
inactivity_cmd = null
# Executes a command after a certain amount of seconds
inactivity_delay = 0
# Initial text to show on the info line
# If set to null, the info line defaults to the hostname
initial_info_text = null
# Input boxes length
input_len = 34
# Active language
# Available languages are found in /etc/ly/lang/
lang = en
# Command executed when logging in
# If null, no command will be executed
# Important: the code itself must end with `exec "$@"` in order to launch the session!
# You can also set environment variables in there, they'll persist until logout
login_cmd = null
# Path for login.defs file (used for listing all local users on the system on
# Linux)
login_defs_path = /etc/login.defs
# Command executed when logging out
# If null, no command will be executed
# Important: the session will already be terminated when this command is executed, so
# no need to add `exec "$@"` at the end
logout_cmd = null
# General log file path
ly_log = /var/log/ly.log
# Main box horizontal margin
margin_box_h = 2
# Main box vertical margin
margin_box_v = 1
# Set numlock on/off at startup
numlock = false
# Default path
# If null, ly doesn't set a path
path = /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# Command executed when pressing restart_key
restart_cmd = /sbin/shutdown -r now
# Specifies the key combination used for restart
restart_key = F2
# Save the current desktop and login as defaults, and load them on startup
save = true
# Service name (set to ly to use the provided pam config file)
service_name = ly
# Session log file path
# This will contain stdout and stderr of Wayland sessions
# By default it's saved in the user's home directory
# Important: due to technical limitations, X11, shell sessions as well as
# launching session via KMSCON aren't supported, which means you won't get any
# logs from those sessions.
# If null, no session log will be created
session_log = .local/state/ly-session.log
# Setup command
setup_cmd = /etc/ly/setup.sh
# Show the shell session in the session list
# If false, the shell session will be hidden
shell = true
# Specifies the key combination used for showing the password
show_password_key = F7
# Display the active TTY number (e.g. tty3) to the right of the clock in the top right corner
# If the clock is disabled, the TTY label occupies the top right corner on its own
# If false, the TTY number will not be shown
show_tty = false
# Command executed when pressing shutdown_key
shutdown_cmd = /sbin/shutdown -a now
# Specifies the key combination used for shutdown
shutdown_key = F1
# Command executed when pressing sleep key (can be null)
sleep_cmd = systemctl suspend
# Specifies the key combination used for sleep
sleep_key = F3
# Command executed when starting Ly (before the TTY is taken control of)
# See file at path below for an example of changing the default TTY colors
start_cmd = /etc/ly/startup.sh
# Center the session name.
text_in_center = false
# Default vi mode
# normal -> normal mode
# insert -> insert mode
vi_default_mode = normal
# Enable vi keybindings
vi_mode = false
# Wayland desktop environments
# You can specify multiple directories,
# e.g. /usr/share/wayland-sessions:/usr/local/share/wayland-sessions
# If null, Wayland sessions will not be shown
waylandsessions = /usr/share/wayland-sessions
# Xorg server command
# Add the -quiet argument to hide startup logs from the server
x_cmd = /usr/bin/X
# Xorg virtual terminal number
# Mostly useful for FreeBSD where choosing the current TTY causes issues
# If null, the current TTY will be chosen
x_vt = null
# Xorg xauthority edition tool
xauth_cmd = /usr/bin/xauth
# xinitrc
# If null, the xinitrc session will be hidden
xinitrc = ~/.xinitrc
# Xorg desktop environments
# You can specify multiple directories,
# e.g. /usr/share/xsessions:/usr/local/share/xsessions
# If null, X11 sessions will not be shown
xsessions = /usr/share/xsessions
# Custom Commands and Labels:
# The following examples below give an outline for setting up custom commands and labels.
# Unless specified as optional, an option is mandatory.
# Comments preceding with '##' are for documentation.
# Comments preceding with '#' comment out the example INI.
## Declare a command with the F8 binding.
#[cmd:F8]
## The name of the command to show up in Ly.
## Note: "$" in "$brightness_up" fetches the appropriate string from the specified locale file
## and is replaced with the value representing "brightness_up".
## You can see the list of keys in any locale file in /etc/ly/lang.
#cmd = touch /tmp/ly.gaming
#name = custom command $brightness_up
## Declare a label with an ID. This ID should be unique across all labels.
#[lbl:kernel]
#cmd = uname -srn
## Optional, defaulting to 0.
## In frames, the time to re-run the command and update the label.
## If 0, only run once and do not refresh afterwards
#refresh = 0
+4
View File
@@ -0,0 +1,4 @@
#!/bin/sh
exec pinentry-rofi -- \
-theme "$HOME/.config/rofi/password.rasi" \
"$@"
+7
View File
@@ -0,0 +1,7 @@
[Desktop Entry]
Name=Sway (uwsm-managed)
Comment=An i3-compatible Wayland compositor
Exec=uwsm start -e -D sway sway.desktop
TryExec=uwsm
DesktopNames=sway
Type=Application
+253
View File
@@ -0,0 +1,253 @@
#![enable(implicit_some)]
#![enable(unwrap_newtypes)]
#![enable(unwrap_variant_newtypes)]
(
address: "127.0.0.1:6600",
password: None,
theme: "def",
cache_dir: None,
on_song_change: None,
volume_step: 5,
max_fps: 30,
scrolloff: 0,
wrap_navigation: false,
enable_mouse: true,
scroll_amount: 1,
enable_config_hot_reload: true,
enable_lyrics_hot_reload: false,
status_update_interval_ms: 1000,
rewind_to_start_sec: None,
keep_state_on_song_change: true,
reflect_changes_to_playlist: false,
select_current_song_on_change: false,
ignore_leading_the: true,
browser_song_sort: [Disc, Track, Artist, Title],
directories_sort: SortFormat(group_by_type: true, reverse: false),
auto_open_downloads: true,
album_art: (
method: Auto,
max_size_px: (width: 1200, height: 1200),
disabled_protocols: ["http://", "https://"],
vertical_align: Center,
horizontal_align: Center,
),
keybinds: (
global: {
"q": Quit,
"?": ShowHelp,
":": CommandMode,
"oI": ShowCurrentSongInfo,
"oo": ShowOutputs,
"op": ShowDecoders,
"od": ShowDownloads,
"oP": Partition(),
"z": ToggleRepeat,
"x": ToggleRandom,
"c": ToggleConsume,
"v": ToggleSingle,
"p": TogglePause,
"s": Stop,
">": NextTrack,
"<": PreviousTrack,
"f": SeekForward,
"b": SeekBack,
".": VolumeUp,
",": VolumeDown,
"<Tab>": NextTab,
"gt": NextTab,
"<S-Tab>": PreviousTab,
"gT": PreviousTab,
"1": SwitchToTab("Queue"),
"2": SwitchToTab("Directories"),
//"3": SwitchToTab("Artists"),
"3": SwitchToTab("Album Artists"),
//"5": SwitchToTab("Albums"),
"4": SwitchToTab("Playlists"),
"5": SwitchToTab("Search"),
"<C-u>": Update,
"<C-U>": Rescan,
"R": AddRandom,
},
navigation: {
"<C-c>": Close,
"<Esc>": Close,
"<CR>": Confirm,
"k": Up,
"<Up>": Up,
"j": Down,
"<Down>": Down,
"h": Left,
"<Left>": Left,
"l": Right,
"<Right>": Right,
"<C-w>k": PaneUp,
"<C-Up>": PaneUp,
"<C-w>j": PaneDown,
"<C-Down>": PaneDown,
"<C-w>h": PaneLeft,
"<C-Left>": PaneLeft,
"<C-w>l": PaneRight,
"<C-Right>": PaneRight,
"K": MoveUp,
"J": MoveDown,
"<C-u>": UpHalf,
"<C-d>": DownHalf,
"<C-b>": PageUp,
"<PageUp>": PageUp,
"<C-f>": PageDown,
"<PageDown>": PageDown,
"gg": Top,
"G": Bottom,
"<Space>": Select,
"<C-Space>": InvertSelection,
"/": EnterSearch,
"n": NextResult,
"N": PreviousResult,
"a": Add,
"A": AddAll,
"D": Delete,
"<C-r>": Rename,
"i": FocusInput,
"oi": ShowInfo,
"<C-z>": ContextMenu(),
"<C-s>s": Save(kind: Modal(all: false, duplicates_strategy: Ask)),
"<C-s>a": Save(kind: Modal(all: true, duplicates_strategy: Ask)),
"r": Rate(),
},
queue: {
"d": Delete,
"D": DeleteAll,
"<CR>": Play,
"C": JumpToCurrent,
"X": Shuffle,
},
),
search: (
case_sensitive: false,
ignore_diacritics: false,
search_button: true,
mode: Contains,
tags: [
(value: "any", label: "any tag"),
(value: "artist", label: "artist"),
(value: "album", label: "album"),
(value: "albumartist", label: "album artist"),
(value: "title", label: "title"),
(value: "filename", label: "filename"),
(value: "genre", label: "genre"),
],
),
artists: (
album_display_mode: SplitByDate,
album_sort_by: Date,
album_date_tags: [Date],
),
tabs: [
(
name: "queue",
pane: Split(
direction: Vertical,
panes: [
(
size: "100%",
pane: Split(
direction: Vertical,
panes: [
(
size: "1",
//borders: "ALL",
//border_symbols: Inherited(parent: Rounded, bottom_left: "├", bottom_right: "┤",),
pane: Split(
direction: Horizontal,
panes: [
/*(
size: "1",
pane: Pane(Empty())
),*/
(
size: "100%",
pane: Pane(QueueHeader())
),
]
)
),
(
size: "100%",
//borders: "LEFT | RIGHT | BOTTOM",
//border_symbols: Rounded,
pane: Split(
direction: Horizontal,
panes: [
/*(
size: "1",
pane: Pane(Empty())
),*/
(
size: "100%",
pane: Pane(Queue)
),
]
)
),
],
)
),
(
size: "8",
pane: Split(
direction: Horizontal,
panes: [
(
size: "19",
//borders: "", //LEFT | RIGHT | TOP",
//border_symbols: Rounded,
pane: Pane(AlbumArt)
),
(
size: "100%",
//borders: "", //ALL",
//border_symbols: Inherited(parent: Rounded, top_left: "├", top_right: "┤",),
//border_title: [(kind: Text(" Lyrics "))],
//border_title_alignment: Right,
pane: Component("column1"),
),
],
),
),
],
),
),
(
name: "directories",
pane: Split(
size: "100%",
direction: Vertical,
panes: [(pane: Pane(Directories), size: "100%")] //, borders: "ALL", border_symbols: Rounded)],
)
),
(
name: "album artists",
pane: Split(
size: "100%",
direction: Vertical,
panes: [(pane: Pane(AlbumArtists), size: "100%")] //, borders: "ALL", border_symbols: Rounded)],
)
),
(
name: "playlists",
pane: Split(
size: "100%",
direction: Vertical,
panes: [(pane: Pane(Playlists), size: "100%")] //, borders: "ALL", border_symbols: Rounded)],
)
),
(
name: "search",
pane: Split(
size: "100%",
direction: Vertical,
panes: [(pane: Pane(Search), size: "100%")] //, borders: "ALL", border_symbols: Rounded)],
)
),
],
)
+311
View File
@@ -0,0 +1,311 @@
#![enable(implicit_some)]
#![enable(unwrap_newtypes)]
#![enable(unwrap_variant_newtypes)]
(
default_album_art_path: None,
format_tag_separator: " | ",
browser_column_widths: [0,30,70],
background_color: None,
text_color: None,
header_background_color: None,
modal_background_color: None,
modal_backdrop: false,
preview_label_style: (fg: "#88c0d0"),
preview_metadata_group_style: (fg: "#88c0d0", modifiers: "Bold"),
highlighted_item_style: (fg: "#88c0d0", modifiers: "Bold"),
current_item_style: (fg: "#2e3440", bg: "#88c0d0", modifiers: "Bold"),
borders_style: (fg: "#88c0d0"),
highlight_border_style: (fg: "#88c0d0"),
symbols: (
song: "S",
dir: "D",
playlist: "P",
marker: "M",
ellipsis: "...",
song_style: (fg: "#88c0d0"),
dir_style: (fg: "#ebcb8b"),
playlist_style: (fg: "#b48ead"),
),
level_styles: (
info: (fg: "blue", bg: "black"),
warn: (fg: "yellow", bg: "black"),
error: (fg: "red", bg: "black"),
debug: (fg: "light_green", bg: "black"),
trace: (fg: "magenta", bg: "black"),
),
progress_bar: (
symbols: ["█", "█", "█", "█", "█"],
track_style: (fg: "#4c566a"),
elapsed_style: (fg: "#88c0d0"),
thumb_style: (fg: "#5e81ac"),
use_track_when_empty: true,
),
scrollbar: (
symbols: ["│", "█", "", ""],
track_style: (),
ends_style: (),
thumb_style: (fg: "#88c0d0"),
),
tab_bar: (
active_style: (fg: "#2e3440", bg: "#88c0d0"),
inactive_style: (fg: "#eceff4", bg: "#2e3440"),),
lyrics: (
timestamp: false
),
browser_song_format: [
(
kind: Group([
(kind: Property(Track)),
(kind: Text(" ")),
])
),
(
kind: Group([
(kind: Property(Artist)),
(kind: Text(" - ")),
(kind: Property(Title)),
]),
default: (kind: Property(Filename))
),
],
song_table_format: [
(
prop: (kind: Property(Artist), style: (fg: "#eceff4"),
default: (kind: Text("unknown"), style: (fg: "#eceff4"))
),
label_prop: (kind: Text("artist"), style: (fg: "#8fbcbb", modifiers: "Bold")),
width: "20%",
),
(
prop: (kind: Property(Title), style: (fg: "#eceff4"),
default: (kind: Text("unknown"), style: (fg: "#eceff4"))
),
label_prop: (kind: Text("title"), style: (fg: "#a3be8c", modifiers: "Bold")),
width: "35%",
),
(
prop: (kind: Property(Album), style: (fg: "#eceff4"),
default: (kind: Text("unknown"), style: (fg: "#eceff4"))
),
label_prop: (kind: Text("album"), style: (fg: "#b48ead", modifiers: "Bold")),
width: "30%",
),
(
prop: (kind: Property(Duration), style: (fg: "#eceff4"),
default: (kind: Text("-"), style: (fg: "#eceff4"))
),
label_prop: (kind: Text("duration"), style: (fg: "#ebcb8b", modifiers: "Bold")),
width: "15%",
alignment: Right,
),
],
layout: Split(
direction: Vertical,
panes: [
(
size: "1",
pane: Split(
direction: Horizontal,
panes: [
( pane: Pane(Tabs), size: "70" ),
( pane: Pane(Empty()), size: "100%" ),
],
),
),
(
pane: Pane(TabContent),
size: "100%",
),
(
size: "1",
pane: Split(
direction: Horizontal,
panes: [
(
size: "8",
pane: Component("input_mode")
),
(
size: "100%",
pane: Component("progress_bar"),
),
(
size: "20",
pane: Component("volume_and_state"),
)
]
),
),
],
),
components: {
"volume_and_state": Split(
direction: Horizontal,
panes: [
(size: "100%", pane: Component("volume")),
(size: "7", pane: Component("states")),
]
),
"column1": Split(
direction: Vertical,
panes: [
(size: "1", pane: Component("state")),
(size: "1", pane: Component("artist")),
(size: "1", pane: Component("album")),
(size: "1", pane: Component("track")),
(size: "1", pane: Component("title")),
(size: "1", pane: Component("date")),
(size: "1", pane: Component("elapsed")),
(size: "1", pane: Component("bitrate")),
]
),
"state": Pane(Property(
content: [
(kind: Text("state: "), style: (fg: "#88c0d0", modifiers: "Bold")),
(kind: Property(Status(StateV2( ))), style: (fg: "#eceff4")),
], align: Left, scroll_speed: 1
)),
"artist": Pane(Property(
content: [
(kind: Text("artist: "), style: (fg: "#88c0d0", modifiers: "Bold")),
(kind: Property(Song(Artist)), style: (fg: "#eceff4"),
default: (kind: Text("unknown"), style: (fg: "#eceff4"))),
], align: Left, scroll_speed: 1
)),
"album": Pane(Property(
content: [
(kind: Text("album: "), style: (fg: "#88c0d0", modifiers: "Bold")),
(kind: Property(Song(Album)), style: (fg: "#eceff4"),
default: (kind: Text("unknown"), style: (fg: "#eceff4"))),
], align: Left, scroll_speed: 1
)),
"track": Pane(Property(
content: [
(kind: Text("track: "), style: (fg: "#88c0d0", modifiers: "Bold")),
(kind: Property(Song(Track)), style: (fg: "#eceff4"),
default: (kind: Text("unknown"), style: (fg: "#eceff4"))),
], align: Left, scroll_speed: 1
)),
"title": Pane(Property(
content: [
(kind: Text("title: "), style: (fg: "#88c0d0", modifiers: "Bold")),
(kind: Property(Song(Title)), style: (fg: "#eceff4"),
default: (kind: Text("unknown"), style: (fg: "#eceff4"))),
], align: Left, scroll_speed: 1
)),
"date": Pane(Property(
content: [
(kind: Text("date: "), style: (fg: "#88c0d0", modifiers: "Bold")),
(kind: Property(Song(Other("date"))), style: (fg: "#eceff4"),
default: (kind: Text("unknown"), style: (fg: "#eceff4"))),
], align: Left, scroll_speed: 1
)),
"elapsed": Pane(Property(
content: [
(kind: Text("elapsed: "), style: (fg: "#88c0d0", modifiers: "Bold")),
(kind: Property(Status(Elapsed)), style: (fg: "#eceff4")),
(kind: Text(" / ")),
(kind: Property(Status(Duration)), style: (fg: "#eceff4")),
],
align: Left, scroll_speed: 1
)),
"bitrate": Pane(Property(
content: [
(kind: Text("bitrate: "), style: (fg: "#88c0d0", modifiers: "Bold")),
(kind: Property(Status(Bitrate)), style: (fg: "#eceff4")),
(kind: Text(" kbps"), style: (fg: "#eceff4")),
],
align: Left, scroll_speed: 1
)),
"volume": Split(
direction: Horizontal,
panes: [
(size: "100%", pane: Pane(Volume(kind: Slider(
symbols: (filled: "█", thumb: "█", track: "█"),
filled_style: (fg: "#d08770"),
track_style: (fg: "#4c566a"),
thumb_style: (fg: "#bf616a"),
)))),
], align: Right
),
"states": Split(
direction: Horizontal,
panes: [
(
size: "1",
pane: Pane(Empty())
),
(
size: "100%",
pane: Pane(Property(content: [(kind: Property(Status(InputBuffer())), style: (fg: "blue"), align: Right)]))
),
(
size: "1",
pane: Pane(Empty())
),
(
size: "6",
pane: Pane(Property(content: [
(kind: Text(" "), style: (bg: "#4c566a")),
(kind: Property(Status(RepeatV2(
on_label: "z",
off_label: "z",
on_style: (fg: "#ebcb8b", bg: "#4c566a", modifiers: "Bold"),
off_style: (fg: "#eceff4", bg: "#4c566a"),
)))),
(kind: Property(Status(RandomV2(
on_label: "x",
off_label: "x",
on_style: (fg: "#ebcb8b", bg: "#4c566a", modifiers: "Bold"),
off_style: (fg: "#eceff4", bg: "#4c566a"),
)))),
(kind: Property(Status(ConsumeV2(
on_label: "c",
off_label: "c",
oneshot_label: "c",
on_style: (fg: "#ebcb8b", bg: "#4c566a", modifiers: "Bold"),
off_style: (fg: "#eceff4", bg: "#4c566a"),
oneshot_style: (fg: "#d08770", bg: "#4c566a", modifiers: "Bold"),
)))),
(kind: Property(Status(SingleV2(
on_label: "v",
off_label: "v",
oneshot_label: "v",
on_style: (fg: "#ebcb8b", bg: "#4c566a", modifiers: "Bold"),
off_style: (fg: "#eceff4", bg: "#4c566a"),
oneshot_style: (fg: "#d08770", bg: "#4c566a", modifiers: "Bold"),
)))),
(kind: Text(" "), style: (bg: "#4c566a")),
],
align: Right
))
),
]
),
"input_mode": Pane(Property(
content: [
(kind: Transform(Replace(content: (kind: Property(Status(InputMode()))), replacements: [
(match: "Normal", replace: (kind: Text(" normal "), style: (fg: "#eceff4", bg: "#4c566a"))),
(match: "Insert", replace: (kind: Text(" insert "), style: (fg: "#2e3440", bg: "#a3be8c"))),
])))
], align: Left
)),
"progress_bar": Split(
direction: Horizontal,
panes: [
(
size: "1",
pane: Pane(Empty())
),
(
size: "100%",
pane: Pane(ProgressBar)
),
(
size: "1",
pane: Pane(Empty())
),
]
)
},
)
+29
View File
@@ -0,0 +1,29 @@
@import "config.rasi"
window {
children: [ mainbox ];
}
mainbox {
background-color: transparent;
children: [ inputbar, listview, message ];
}
element {
children: [ element-icon, element-text ];
}
element-icon {
size: 0px;
margin: 0;
}
message {
background-color: @NORD1;
padding: 6px 0 12px 12px;
}
textbox {
text-color: @NORD6;
background-color: transparent;
}
+166
View File
@@ -0,0 +1,166 @@
configuration {
me-select-entry: "MouseSecondary";
me-accept-entry: "MousePrimary";
scroll-method: 1;
show-icons: true;
sidebar-mode: true;
modi: "drun,internet:~/.config/rofi/rofi-filter internet,dev:~/.config/rofi/rofi-filter dev,games:~/.config/rofi/rofi-filter games,system:~/.config/rofi/rofi-filter system,media:~/.config/rofi/rofi-filter media,notifications:~/.config/rofi/rofi-filter notifications,clipboard:~/.config/rofi/rofi-filter clipboard";
display-drun: "ALL";
display-internet: "NET";
display-dev: "DEV";
display-games: "GMS";
display-system: "SYS";
display-media: "MED";
display-notifications: "NTF";
display-clipboard: "CLP";
kb-remove-to-eol: "";
kb-mode-complete: "";
kb-remove-char-back: "BackSpace,Shift+BackSpace";
kb-row-down: "Down,Control+j";
kb-row-up: "Up,Control+k";
kb-accept-entry: "Control+m,Return,KP_Enter";
}
* {
NORD0: #2e3440;
NORD1: #3b4252;
NORD2: #434c5e;
NORD3: #4c566a;
NORD4: #d8dee9;
NORD5: #e5e9f0;
NORD6: #eceff4;
NORD7: #8fbcbb;
NORD8: #88c0d0;
NORD9: #81a1c1;
NORD10: #5e81ac;
NORD11: #bf616a;
NORD12: #d08770;
NORD13: #ebcb8b;
NORD14: #a3be8c;
NORD15: #b48ead;
font: "Noto Sans Mono 10";
}
window {
background-color: @NORD0;
location: north west;
anchor: north west;
width: 540px;
height: 550px;
x-offset: 5px;
y-offset: 5px;
padding: 0px;
border: 0px;
border-radius: 0px;
children: [ sb-mainbox ];
}
sb-mainbox {
orientation: horizontal;
spacing: 0px;
children: [ left-bar-container, vertibox ];
}
left-bar-container {
background-color: @NORD0;
orientation: vertical;
width: 40px;
expand: false;
children: [ mode-switcher ];
}
mode-switcher {
orientation: vertical;
spacing: 0px;
padding: 0px;
}
button {
text-color: @NORD4;
background-color: transparent;
border-color: transparent;
horizontal-align: 0.5;
vertical-align: 0.5;
padding: 6px 0px;
border: 0px 0px 0px 2px;
font: "Noto Sans Mono Bold 8";
}
button selected {
text-color: @NORD6;
background-color: @NORD1;
border-color: @NORD8;
}
vertibox {
background-color: @NORD0;
orientation: vertical;
spacing: 0px;
padding: 0px;
children: [ inputbar, listview ];
}
inputbar {
background-color: transparent;
children: [ entry ];
}
entry {
text-color: @NORD6;
background-color: transparent;
placeholder-color: @NORD4;
padding: 6px;
placeholder: " [search...]";
}
listview {
background-color: transparent;
margin: 0px;
spacing: 0px;
columns: 1;
lines: 10;
border: 0px;
cycle: false;
dynamic: true;
scrollbar: false;
}
element {
background-color: transparent;
padding: 8px;
children: [ element-icon, element-text ];
}
element normal.normal,
element normal.urgent,
element normal.active {
text-color: @NORD6;
background-color: transparent;
}
element alternate.normal,
element alternate.urgent,
element alternate.active {
text-color: @NORD6;
background-color: transparent;
}
element selected.normal,
element selected.urgent,
element selected.active {
text-color: @NORD4;
background-color: @NORD1;
border: 0px 0px 0px 2px;
border-color: @NORD8;
}
element-icon {
background-color: transparent;
size: 14px;
margin: 0 8px 0 6px;
}
element-text {
text-color: inherit;
background-color: transparent;
}
+28
View File
@@ -0,0 +1,28 @@
@import "config.rasi"
window {
width: 540px;
height: 60px;
children: [ vertibox ];
}
vertibox {
children: [ label-box, inputbar ];
}
label-box {
background-color: @NORD1;
children: [ prompt ];
}
prompt {
text-color: @NORD4;
background-color: @NORD1;
border-color: @NORD8;
padding: 6px;
border: 0px 0px 0px 2px;
}
entry {
placeholder: " [password...]";
}
+75
View File
@@ -0,0 +1,75 @@
#!/usr/bin/env bash
set -uo pipefail
tmp_dir="/tmp/cliphist"
mkdir -p "$tmp_dir"
mode="${1:-}"
selection="${2:-}"
if [[ -n "$selection" ]]; then
if [[ "$mode" == "clipboard" ]]; then
id="${selection%% *}"
printf '%s' "$id" | clipvault get | wl-copy
elif [[ "$mode" == "notifications" ]]; then
body="${selection#*— }"
printf '%s' "$body" | wl-copy
else
target_app=$(grep -rl "^Name=${selection}\$" /usr/share/applications/*.desktop 2>/dev/null | head -n1)
if [[ -n "$target_app" ]]; then
exec_cmd=$(awk -F= '/^Exec=/{print $2; exit}' "$target_app" | sed 's/%[uUfFck]//g')
setsid $exec_cmd >/dev/null 2>&1 &
disown
fi
fi
exit 0
fi
case "$mode" in
clipboard)
find "$tmp_dir" -type f -mmin +30 -delete 2>/dev/null
while IFS=$'\t' read -r id rest; do
[[ "$id" =~ ^[0-9]+$ ]] || continue
[[ "$rest" == *"meta http-equiv"* ]] && continue
if [[ "$rest" == *"binary data"* ]]; then
ext=""
case "$rest" in
*jpeg*|*jpg*) ext="jpg" ;;
*png*) ext="png" ;;
*bmp*) ext="bmp" ;;
*) continue ;;
esac
img="$tmp_dir/$id.$ext"
[[ -s "$img" ]] || printf '%s\n' "$id" | clipvault get > "$img" 2>/dev/null
[[ -s "$img" ]] && printf '%s [IMG]\0icon\x1f%s\n' "$id" "$img"
else
printf '%s %s\n' "$id" "$rest"
fi
done < <(clipvault list)
;;
notifications)
dunstctl history | jq -r '
.data[0][] |
"\(.appname.data): \(.summary.data) — \(.body.data)"
'
;;
internet|dev|media|games|system)
case "$mode" in
internet) category="Network" ;;
dev) category="Development" ;;
media) category="AudioVideo" ;;
games) category="Game" ;;
system) category="System" ;;
esac
awk -v cat="$category" '
BEGINFILE { name=""; icon=""; match_cat=0 }
/^Categories=/ { if (index($0, cat)) match_cat=1 }
/^Name=/ && name=="" { sub(/^Name=/, ""); name=$0 }
/^Icon=/ && icon=="" { sub(/^Icon=/, ""); icon=$0 }
ENDFILE {
if (match_cat && name != "") {
if (icon != "") printf "%s\x00icon\x1f%s\n", name, icon
else printf "%s\n", name
}
}
' /usr/share/applications/*.desktop 2>/dev/null
;;
esac
+5
View File
@@ -0,0 +1,5 @@
debug = false
[server]
inhibit_duration = 25
sleep_duration = 5
+126
View File
@@ -0,0 +1,126 @@
client.focused #88c0d0 #88c0d0 #eceff4 #88c0d0 #88c0d0
client.focused_inactive #00000000 #00000000 #81a1c1 #00000000 #00000000
client.unfocused #00000000 #00000000 #81a1c1 #00000000 #00000000
client.urgent #d08770 #d08770 #eceff4 #d08770 #d08770
font pango:Noto Sans Mono 10
smart_gaps off
smart_borders off
gaps inner 3
gaps outer 1
default_border pixel 1
default_floating_border pixel 1
titlebar_border_thickness 0
default_orientation auto
input type:keyboard {
xkb_layout "us,ru"
xkb_options "grp:win_space_toggle"
}
exec uwsm finalize WAYLAND_DISPLAY SWAYSOCK QT_QPA_PLATFORMTHEME QT_QPA_PLATFORMTHEME_QT6
exec_always xrandr --output HDMI-A-2 --primary
set $mod Mod4
set $left h
set $down j
set $up k
set $right l
set $term foot
set $menu rofi -show drun
set $file foot mc
workspace 1 output HDMI-A-2
workspace 2 output HDMI-A-2
workspace 3 output HDMI-A-2
workspace 4 output HDMI-A-2
workspace 5 output HDMI-A-2
workspace 6 output HDMI-A-2
workspace 7 output DP-1
workspace 8 output DP-1
workspace 9 output DP-2
workspace 0 output DP-2
workspace 1
output DP-1 bg ~/Pictures/wallhaven-43qlkd.jpg fill
output HDMI-A-2 bg ~/Pictures/wallhaven-478kjo.jpg fill
output DP-2 bg ~/Pictures/wallhaven-4gx713.jpg fill
output DP-1 resolution 1280x1024 position 0,220
output HDMI-A-2 resolution 1920x1080 position 1280,0
output DP-2 resolution 1280x102 position 3200,220
floating_modifier $mod normal
bindsym --to-code $mod+$left focus left
bindsym --to-code $mod+$down focus down
bindsym --to-code $mod+$up focus up
bindsym --to-code $mod+$right focus right
bindsym --to-code $mod+Shift+$left move left
bindsym --to-code $mod+Shift+$down move down
bindsym --to-code $mod+Shift+$up move up
bindsym --to-code $mod+Shift+$right move right
bindsym --to-code $mod+1 workspace number 1
bindsym --to-code $mod+2 workspace number 2
bindsym --to-code $mod+3 workspace number 3
bindsym --to-code $mod+4 workspace number 4
bindsym --to-code $mod+5 workspace number 5
bindsym --to-code $mod+6 workspace number 6
bindsym --to-code $mod+7 workspace number 7
bindsym --to-code $mod+8 workspace number 8
bindsym --to-code $mod+9 workspace number 9
bindsym --to-code $mod+0 workspace number 10
bindsym --to-code $mod+Shift+1 move container to workspace number 1
bindsym --to-code $mod+Shift+2 move container to workspace number 2
bindsym --to-code $mod+Shift+3 move container to workspace number 3
bindsym --to-code $mod+Shift+4 move container to workspace number 4
bindsym --to-code $mod+Shift+5 move container to workspace number 5
bindsym --to-code $mod+Shift+6 move container to workspace number 6
bindsym --to-code $mod+Shift+7 move container to workspace number 7
bindsym --to-code $mod+Shift+8 move container to workspace number 8
bindsym --to-code $mod+Shift+9 move container to workspace number 9
bindsym --to-code $mod+Shift+0 move container to workspace number 10
bindsym --to-code $mod+d exec $menu
bindsym --to-code $mod+v exec rofi -show clipboard
bindsym --to-code $mod+e exec $file
bindsym --to-code $mod+Return exec $term
bindsym --to-code $mod+c exec pkill -SIGRTMIN+13 waybar
bindsym --to-code $mod+Shift+q kill
bindsym --to-code $mod+f fullscreen
bindsym --to-code $mod+m focus mode_toggle
bindsym --to-code $mod+Shift+m floating toggle
bindsym --to-code $mod+s scratchpad show
bindsym --to-code $mod+Shift+s move scratchpad
bindsym --to-code --locked XF86AudioRaiseVolume exec wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+
bindsym --to-code --locked XF86AudioLowerVolume exec wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
bindsym --to-code --locked XF86AudioMute exec wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
bindsym --to-code --locked $mod+F12 exec wpctl set-volume -l 1 @DEFAULT_AUDIO_SOURCE@ 5%+
bindsym --to-code --locked $mod+F11 exec wpctl set-volume @DEFAULT_AUDIO_SOURCE@ 5%-
bindsym --to-code --locked $mod+F10 exec wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle
bindsym --to-code --locked XF86AudioNext exec playerctl next
bindsym --to-code --locked XF86AudioPause exec playerctl play-pause
bindsym --to-code --locked XF86AudioPlay exec playerctl play-pause
bindsym --to-code --locked XF86AudioPrev exec playerctl previous
bindsym --to-code Print exec area=$(slurp) && grim -g "$area" - | wl-copy && notify-send -u low "Screenshot" "Captured: $area"
bindsym --to-code $mod+Print exec active_class=$(swaymsg -t get_tree | jq -r '.. | select(.focused? == true) | .app_id // .window_properties.class // "unknown"') && geom=$(swaymsg -t get_tree | jq -r '.. | select(.focused? == true) | "\(.rect.x),\(.rect.y) \(.rect.width)x\(.rect.height)"') && grim -g "$geom" - | wl-copy && notify-send -u low "Screenshot" "Captured: $active_class"
bindsym --to-code ctrl+Print exec monitor=$(swaymsg -t get_outputs | jq -r '.[] | select(.focused==true) | .name') && grim -o "$monitor" - | wl-copy && notify-send -u low "Screenshot" "Captured: $monitor"
bindsym --to-code $mod+u exec sh -c 'rbw get ed-ssh | jq -r ".fields[]? | select(.name==\"privateKey\") | .text" | ssh-add -'
bindsym --to-code $mod+b exec rofi-rbw --selector rofi --selector-args="-theme ~/.config/rofi/bitwarden.rasi -mesg 'alt+1: <span foreground=\\\"#d8dee9\\\">type username/password</span>\nalt+2: <span foreground=\\\"#d8dee9\\\">type username</span>\talt+3: <span foreground=\\\"#d8dee9\\\">type password</span>\talt+4: <span foreground=\\\"#d8dee9\\\">type totp</span>\talt+u: <span foreground=\\\"#d8dee9\\\">copy username</span>\talt+c: <span foreground=\\\"#d8dee9\\\">copy password</span>\talt+t: <span foreground=\\\"#d8dee9\\\">copy totp</span>\talt+m: <span foreground=\\\"#d8dee9\\\">menu</span>\t\talt+s: <span foreground=\\\"#d8dee9\\\">sync logins</span>'"
mode "resize" {
bindsym --to-code $left resize shrink width 10px
bindsym --to-code $down resize grow height 10px
bindsym --to-code $up resize shrink height 10px
bindsym --to-code $right resize grow width 10px
bindsym --to-code Return mode "default"
bindsym --to-code Escape mode "default"
}
mode "reload sway? [y/n]" {
bindsym --to-code y reload; mode "default"
bindsym --to-code n mode "default"
bindsym Escape mode "default"
}
mode "lock sway? [y/n]" {
bindsym --to-code y exec swaylock; mode "default"
bindsym --to-code n mode "default"
bindsym Escape mode "default"
}
mode "exit sway? [y/n]" {
bindsym --to-code y exec swaymsg exit; mode "default"
bindsym --to-code n mode "default"
bindsym Escape mode "default"
}
bindsym --to-code $mod+r mode "resize"
bindsym --to-code $mod+Shift+r mode "reload sway? [y/n]"
bindsym --to-code $mod+x mode "lock sway? [y/n]"
bindsym --to-code $mod+Shift+x mode "exit sway? [y/n]"
+282
View File
@@ -0,0 +1,282 @@
#!/usr/bin/env python3
from __future__ import annotations
import asyncio
import logging
import os
import signal
from dataclasses import dataclass, field
from typing import Dict, Optional
try:
from systemd import daemon
except ImportError:
daemon = None
import i3ipc
from i3ipc.aio import Connection
DEFAULT_MODE = os.getenv("PWL_DEFAULT_MODE", "1") == "1"
DEBUG = os.getenv("PWL_DEBUG", "0") == "1"
INFO = os.getenv("PWL_INFO", "1") == "1"
logging.basicConfig(
level=logging.DEBUG if DEBUG else (logging.INFO if INFO else logging.WARNING),
format="[pwl] %(asctime)s %(message)s",
datefmt="%H:%M:%S",
)
log = logging.getLogger("pwl")
def notify_systemd(msg: str) -> None:
if daemon:
try:
daemon.notify(msg)
except Exception as e:
log.debug("Failed to notify systemd: %s", e)
def notify_ready(status: str) -> None:
notify_systemd(f"READY=1\nSTATUS={status}")
def notify_status(status: str) -> None:
notify_systemd(f"STATUS={status}")
def notify_watchdog() -> None:
notify_systemd("WATCHDOG=1")
@dataclass
class Keyboard:
identifier: str
default_index: int
current_index: int
layout_map: Dict[str, int] = field(default_factory=dict)
class PerWindowLayout:
def __init__(self) -> None:
self.conn: Optional[Connection] = None
self.keyboard: Optional[Keyboard] = None
self.window_layouts: Dict[int, int] = {}
self.current_window: Optional[int] = None
self.stop_event = asyncio.Event()
self._layout_map_built = False
async def connect(self) -> None:
self.conn = await Connection(auto_reconnect=True).connect()
def _find_main_keyboard(self, inputs) -> Optional[object]:
keyboards = [i for i in inputs if i.type == "keyboard"]
if not keyboards:
return None
real = [k for k in keyboards if "virtual" not in (k.identifier or "").lower()]
return (real or keyboards)[0]
async def wait_until_ready(self) -> None:
notify_status("Waiting for sway...")
while not self.stop_event.is_set():
try:
inputs = await self.conn.get_inputs()
except Exception:
await asyncio.sleep(0.2)
continue
main = self._find_main_keyboard(inputs)
if main is None:
await asyncio.sleep(0.2)
continue
idx = main.xkb_active_layout_index or 0
self.keyboard = Keyboard(
identifier=main.identifier,
default_index=idx,
current_index=idx,
)
return
async def build_layout_map(self, force: bool = False) -> None:
assert self.keyboard is not None
inputs = await self.conn.get_inputs()
current = self.keyboard.current_index
kbd = next((i for i in inputs if i.identifier == self.keyboard.identifier), None)
if not kbd:
return
layouts = kbd.xkb_layout_names or []
count = len(layouts)
if self._layout_map_built and not force and len(self.keyboard.layout_map) == count:
return
notify_status("Building layout map...")
self.keyboard.layout_map.clear()
for i in range(count):
await self.conn.command(f'input "{self.keyboard.identifier}" xkb_switch_layout {i}')
inputs = await self.conn.get_inputs()
kbd = next((k for k in inputs if k.identifier == self.keyboard.identifier), kbd)
name = kbd.xkb_active_layout_name or str(i)
self.keyboard.layout_map[name] = i
await self.conn.command(f'input "{self.keyboard.identifier}" xkb_switch_layout {current}')
self.keyboard.current_index = current
self._layout_map_built = True
log.info("Layout map initialized (%d layouts)", len(self.keyboard.layout_map))
async def init_windows(self) -> None:
assert self.keyboard is not None
inputs = await self.conn.get_inputs()
kbd = next((i for i in inputs if i.identifier == self.keyboard.identifier), None)
idx = kbd.xkb_active_layout_index if kbd else self.keyboard.default_index
tree = await self.conn.get_tree()
active_ids = set()
for con in tree.leaves():
active_ids.add(con.id)
if con.id not in self.window_layouts:
self.window_layouts[con.id] = idx
stale = [wid for wid in self.window_layouts if wid not in active_ids]
for wid in stale:
self.window_layouts.pop(wid, None)
notify_status(f"Tracking {len(self.window_layouts)} windows")
async def switch_layout(self, idx: int) -> None:
assert self.keyboard is not None
if idx == self.keyboard.current_index:
return
await self.conn.command(f'input "{self.keyboard.identifier}" xkb_switch_layout {idx}')
self.keyboard.current_index = idx
async def handle_active_window(self, con_id: int) -> None:
assert self.keyboard is not None
self.current_window = con_id
if con_id in self.window_layouts:
idx = self.window_layouts[con_id]
else:
idx = self.keyboard.default_index if DEFAULT_MODE else self.keyboard.current_index
self.window_layouts[con_id] = idx
notify_status(f"Tracking {len(self.window_layouts)} windows")
await self.switch_layout(idx)
def handle_active_layout(self, identifier: str, layout_name: Optional[str]) -> None:
assert self.keyboard is not None
if identifier != self.keyboard.identifier or not layout_name:
return
idx = self.keyboard.layout_map.get(layout_name)
if idx is None:
return
self.keyboard.current_index = idx
if self.current_window is not None:
self.window_layouts[self.current_window] = idx
def handle_close_window(self, con_id: int) -> None:
if self.window_layouts.pop(con_id, None) is not None:
notify_status(f"Tracking {len(self.window_layouts)} windows")
async def handle_device_change(self) -> None:
inputs = await self.conn.get_inputs()
main = self._find_main_keyboard(inputs)
if main and self.keyboard and main.identifier != self.keyboard.identifier:
log.info("Main keyboard changed: %s -> %s", self.keyboard.identifier, main.identifier)
idx = main.xkb_active_layout_index or 0
self.keyboard.identifier = main.identifier
self.keyboard.default_index = idx
self.keyboard.current_index = idx
await self.build_layout_map(force=True)
await self.init_windows()
def _register_handlers(self) -> None:
assert self.conn is not None
async def on_window(_conn, event):
change = event.change
if change == "focus" and event.container is not None:
await self.handle_active_window(event.container.id)
elif change == "close" and event.container is not None:
self.handle_close_window(event.container.id)
async def on_input(_conn, event):
change = event.change
if change == "xkb_layout" and event.input is not None:
self.handle_active_layout(
event.input.identifier, event.input.xkb_active_layout_name
)
elif change in ("added", "removed"):
await self.handle_device_change()
self.conn.on(i3ipc.Event.WINDOW, on_window)
self.conn.on(i3ipc.Event.INPUT, on_input)
async def watchdog_loop(self) -> None:
interval = 10.0
if daemon:
try:
wd = daemon.watchdog_enabled()
if isinstance(wd, (int, float)) and wd > 0:
interval = wd / 2.0
except Exception:
pass
while not self.stop_event.is_set():
notify_watchdog()
await asyncio.sleep(interval)
async def run(self) -> None:
await self.connect()
await self.wait_until_ready()
await self.build_layout_map()
await self.init_windows()
self._register_handlers()
notify_ready(f"Tracking {len(self.window_layouts)} windows")
async with asyncio.TaskGroup() as tg:
tg.create_task(self.conn.main())
tg.create_task(self.watchdog_loop())
await self.stop_event.wait()
await self.conn.main_quit()
async def amain() -> None:
pwl = PerWindowLayout()
loop = asyncio.get_running_loop()
def shutdown_handler() -> None:
pwl.stop_event.set()
for sig in (signal.SIGINT, signal.SIGTERM):
loop.add_signal_handler(sig, shutdown_handler)
try:
await pwl.run()
except asyncio.CancelledError:
raise
except Exception:
log.exception("Fatal error")
raise
def main() -> None:
try:
asyncio.run(amain())
except KeyboardInterrupt:
pass
if __name__ == "__main__":
main()
+39
View File
@@ -0,0 +1,39 @@
ignore-empty-password
show-failed-attempts
daemonize
color=2e3440
indicator-idle-visible
indicator-caps-lock
disable-caps-lock-text
hide-keyboard-layout
indicator-radius=42
indicator-thickness=2
font=Noto Sans Mono
font-size=10
inside-color=00000000
inside-clear-color=00000000
inside-ver-color=00000000
inside-wrong-color=00000000
inside-caps-lock-color=00000000
ring-color=4c566a
ring-clear-color=ebcb8b
ring-ver-color=a3be8c
ring-wrong-color=bf616a
ring-caps-lock-color=d08770
line-color=00000000
line-clear-color=00000000
line-ver-color=00000000
line-wrong-color=00000000
line-caps-lock-color=00000000
text-color=eceff4
text-clear-color=ebcb8bff
text-ver-color=a3be8cff
text-wrong-color=bf616aff
text-caps-lock-color=d08770ff
separator-color=00000000
key-hl-color=88c0d0ff
caps-lock-key-hl-color=88c0d0ff
bs-hl-color=ebcb8bff
layout-bg-color=00000000
layout-border-color=00000000
layout-text-color=d8dee9ff
+12
View File
@@ -0,0 +1,12 @@
[Unit]
Description=clipvault
PartOf=graphical-session.target
After=graphical-session.target
[Service]
ExecStart=/usr/bin/wl-paste --watch clipvault store --max-entries 5000
Restart=on-failure
RestartSec=2
[Install]
WantedBy=graphical-session.target
+12
View File
@@ -0,0 +1,12 @@
[Unit]
Description=GTK dark mode settings
After=graphical-session.target
PartOf=graphical-session.target
[Service]
Type=oneshot
ExecStart=/usr/bin/gsettings set org.gnome.desktop.interface gtk-theme Adwaita-dark
ExecStart=/usr/bin/gsettings set org.gnome.desktop.interface color-scheme prefer-dark
[Install]
WantedBy=graphical-session.target
+24
View File
@@ -0,0 +1,24 @@
[Unit]
Description=Per window keyboard layout (sway)
Documentation=https://github.com/pyrschtjag
PartOf=graphical-session.target
After=graphical-session.target
BindsTo=graphical-session.target
[Service]
Type=notify
NotifyAccess=main
ExecStart=%h/.config/sway/scripts/per-window-layout.py
Environment=PWL_DEFAULT_MODE=1
Environment=PWL_INFO=1
Environment=PWL_DEBUG=0
Restart=always
RestartSec=1
NoNewPrivileges=yes
StandardOutput=journal
StandardError=journal
TimeoutStartSec=30
TimeoutStopSec=5
[Install]
WantedBy=graphical-session.target
+12
View File
@@ -0,0 +1,12 @@
[Unit]
Description=Swaddle
[Service]
Type=simple
ExecStart=/usr/sbin/swaddle
NoNewPrivileges=yes
Restart=on-failure
RestartSec=3
[Install]
WantedBy=graphical-session.target
+21
View File
@@ -0,0 +1,21 @@
[Unit]
Description=Sway idle daemon
PartOf=graphical-session.target
After=graphical-session.target
BindsTo=graphical-session.target
[Service]
Type=simple
ExecStart=/usr/bin/swayidle -w \
timeout 300 'pidof swaylock || swaylock -f' \
timeout 360 'swaymsg "output * dpms off"' \
timeout 420 'systemctl suspend' \
before-sleep 'pidof swaylock || swaylock -f' \
after-resume 'swaymsg "output * dpms on"'
Restart=always
RestartSec=1
StandardOutput=journal
StandardError=journal
[Install]
WantedBy=graphical-session.target
+3
View File
@@ -0,0 +1,3 @@
export QT_QPA_PLATFORMTHEME=qt6ct
export QT_QPA_PLATFORMTHEME_QT6=qt6ct
export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/rbw/ssh-agent-socket"
+197
View File
@@ -0,0 +1,197 @@
{
"layer": "top",
"position": "top",
"margin-top": 5,
"margin-left": 5,
"margin-right": 5,
"height": 34,
"modules-left": [
"custom/rofi",
"sway/workspaces",
"sway/mode"
],
"modules-center": [
"clock#time"
],
"modules-right": [
"tray",
"idle_inhibitor",
"group/keyboard",
"disk" ,
"group/hardware",
"group/temp",
"group/audio"
],
"group/keyboard": {
"orientation": "horizontal",
/*"modules": [
"keyboard-state",
"sway/language"
]*/
"modules": ["sway/language"]
},
"group/hardware": {
"orientation": "horizontal",
"modules": [
"cpu",
"memory"
]
},
"group/temp": {
"orientation": "horizontal",
"modules": [
"temperature#cpu",
"custom/gpu_temperature"
]
},
"group/audio": {
"orientation": "horizontal",
"modules": [
"wireplumber#source",
"wireplumber#sink"
]
},
"custom/rofi": {
"exec-if": "[ \"$USER\" != \"pyrschtjag\" ]",
"exec": "echo '{\"text\": \"\", \"tooltip\": \"\"}'",
"return-type": "json",
"format": "<span color='#88c0d0'>{icon}</span><span rise='1000' font='Symbols Nerd Font Mono 8'>{text}</span>",
"format-icons": ["󰀻"],
"interval": "once",
"on-click": "rofi -show drun",
"tooltip": false
},
"sway/workspaces": {
"format": "<span color='#88c0d0' weight='bold'>{icon}</span><span rise='1000' font='Symbols Nerd Font Mono 8'>{windows}</span>",
"window-rewrite": {
"class<firefox>": " 󰈹",
"class<foot>": " ",
"class<discord>": " 󰙯",
"class<org.telegram.desktop>": " ",
"class<steam>": " 󰓓",
"class<org.gajim.Gajim>": " 󰷕",
"class<Spotify>": " ",
"title<nvim>": " ",
"title<rmpc>": " 󰎈",
"title<mc(.*)>": " ",
"": " "
},
"tooltip": false
},
"sway/mode": {
"format": "<span color='#ebcb8b'>{}</span>",
"max-length": 18,
"tooltip": false
},
"clock#time": {
"format": "{:%H:%M}",
"tooltip": false
},
"tray": {
"icon-size": 12,
"spacing": 10,
"tooltip": false
},
"idle_inhibitor": {
"format": "{icon}",
"format-icons": {
"activated": "<span color='#d08770' rise='1000' font='Symbols Nerd Font Mono 8'></span>",
// "deactivated": ""
"deactivated": "<span color='#ebcb8b' rise='1000' font='Symbols Nerd Font Mono 8'>󱎴</span>"
},
"signal": 13,
"tooltip": false,
"cursor": ""
},
"sway/language": {
// "format": "{}",
"format": "<span color='#8fbcbb' rise='1000' font='Symbols Nerd Font Mono 8'>󰌌</span> {}",
"format-en": "EN",
"format-ru": "RU",
"tooltip": false
},
"keyboard-state": {
"format": "{name}{icon}",
"numlock": true,
"capslock": true,
"scrolllock": false,
"format-icons": {
"numlock": {
"locked": "<span color='#a3be8c' rise='1000' font='Symbols Nerd Font Mono 8'>󰎠</span> ",
"unlocked": ""
},
"capslock": {
"locked": "<span color='##8fbcbb' rise='1000' font='Symbols Nerd Font Mono 8'>󰌌</span> <span color='#bf616a' rise='1000' font='Symbols Nerd Font Mono 8'>󰬴</span> ",
"unlocked": "<span color='##8fbcbb' rise='1000' font='Symbols Nerd Font Mono 8'>󰌌</span> "
}
}
},
"disk": {
// enable when release waybar 0.16+
// "format": "<span color='#a3be8c' rise='1000' font='Symbols Nerd Font Mono 8'></span> {free:5G}G",
"format": "<span color='#a3be8c' rise='1000' font='Symbols Nerd Font Mono 8'></span> {free:7}",
"paths": ["/"],
"interval": 120,
"tooltip": false
},
"cpu": {
"format": "<span color='#5e81ac' rise='1000' font='Symbols Nerd Font Mono 8'></span> {usage:03}%",
"interval": 5,
"tooltip": false
},
"memory": {
"format": "<span color='#81a1c1' rise='1000' font='Symbols Nerd Font Mono 8'></span> {percentage:03}%",
"interval": 5,
"tooltip": false
},
"temperature#cpu": {
"format": "<span color='#ebcb8b' rise='1000' font='Symbols Nerd Font Mono 8'></span> {temperatureC:03}°C",
"hwmon-path": "/sys/class/hwmon/hwmon2/temp1_input",
"interval": 5,
"tooltip": false
},
"custom/gpu_temperature": {
"format": "<span color='#d08770' rise='1000' font='Symbols Nerd Font Mono 8'>󰢮</span> {text}°C",
"exec": "nvidia-smi --query-gpu=temperature.gpu --format=csv,noheader,nounits | xargs printf '%03d'",
"interval": 5,
"tooltip": false
},
"wireplumber#source": {
"format": "<span color='#b48ead' rise='1000' font='Symbols Nerd Font Mono 8'></span> {volume:03}%",
"format-muted": "<span color='#4c566a' rise='1000' font='Symbols Nerd Font Mono 8'></span> 000%",
"node-type": "Audio/Source",
"scroll-step": 5,
"tooltip": false
},
"wireplumber#sink": {
"format": "<span color='#b48ead' rise='1000' font='Symbols Nerd Font Mono 8'>{icon}</span> {volume:03}%",
"format-muted": "<span color='#4c566a' rise='1000' font='Symbols Nerd Font Mono 8'></span> 000%",
"format-icons": ["", "", ""],
"scroll-step": 5,
"tooltip": false
}
}
+156
View File
@@ -0,0 +1,156 @@
@define-color nord0 #2e3440;
@define-color nord1 #3b4252;
@define-color nord2 #434c5e;
@define-color nord3 #4c566a;
@define-color nord4 #d8dee9;
@define-color nord5 #e5e9f0;
@define-color nord6 #eceff4;
@define-color nord7 #8fbcbb;
@define-color nord8 #88c0d0;
@define-color nord9 #81a1c1;
@define-color nord10 #5e81ac;
@define-color nord11 #bf616a;
@define-color nord12 #d08770;
@define-color nord13 #ebcb8b;
@define-color nord14 #a3be8c;
@define-color nord15 #b48ead;
* {
font-family: "Noto Sans Mono";
font-size: 13px;
border: 0px;
border-radius: 0px;
box-shadow: none;
text-shadow: none;
transition: none;
}
window#waybar {
color: @nord6;
background-color: @nord0;
}
#custom-rofi {
margin: 0 10px 0 10px;
}
#workspaces button {
color: @nord4;
padding: 0px 10px;
border-bottom: 2px solid transparent;
}
#workspaces button.visible {
color: @nord5;
background-color: transparent;
border-bottom: 2px solid @nord9;
}
#workspaces button.focused {
color: @nord6;
background-color: @nord1;
border-bottom: 2px solid @nord8;
}
#workspaces button.urgent {
color: @nord8;
}
#workspaces button:hover {
background: transparent;
border-bottom: 2px solid transparent;
}
#workspaces button:hover.active,
#workspaces button:hover.visible {
background-color: @nord1;
border-bottom: 2px solid @nord8;
}
#workspaces button.urgent {
border-bottom: 2px solid @nord12;
}
#mode {
margin: 0 0 0 10px;
}
#tray menu {
background-color: @nord0;
padding: 4px 0;
}
#tray menu menuitem {
color: @nord4;
padding: 4px 0px;
border-left: 2px solid transparent;
}
#tray menu menuitem:hover {
background-color: @nord1;
color: @nord6;
border-left: 2px solid @nord8;
}
#tray menu separator {
background-color: @nord3;
margin: 4px 0;
min-height: 1px;
}
#tray > .passive { opacity: 0.6; }
#tray > .needs-attention { color: @nord8; }
/* delete when release waybar 0.16+ */
#idle_inhibitor {
margin: 0 10px 0 0;
opacity: 1;
}
/* enable when release waybar 0.16+
#idle_inhibitor {
margin: 0;
opacity: 0;
}
#idle_inhibitor.activated {
margin: 0 10px 0 0;
opacity: 1;
}
*/
#tray,
#keyboard,
#disk,
#hardware,
#temp,
#audio {
margin: 0 10px 0 0;
}
#wireplumber.source-muted,
#wireplumber.sink-muted {
color: @nord3;
color: @nord3;
}
#cpu,
#temperature.cpu,
#wireplumber.source {
padding: 0 5px 0 0;
}
#memory,
#custom-gpu_temperature,
#wireplumber.sink {
padding: 0 0 0 5px;
}
tooltip {
background-color: @nord0;
}
tooltip label {
background-color: @nord0;
color: @nord6;
}