Compare commits
26
Commits
c29abb3e6a
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8509f2ad1c | ||
|
|
92308d3147 | ||
|
|
6903aeec29 | ||
|
|
706a602e33 | ||
|
|
77c616227e | ||
|
|
a42b741022 | ||
|
|
8df49bd750 | ||
|
|
cdc751cae8 | ||
|
|
2d2b176b85 | ||
|
|
9344f1243d | ||
|
|
014f6f165c | ||
|
|
aed8cf9dd3 | ||
|
|
2e546e1ebb | ||
|
|
ab66fe9fca | ||
|
|
5c904d8a7a | ||
|
|
634aa211f4 | ||
|
|
3c53dc30b5 | ||
|
|
974858253b | ||
|
|
b0b2e04b7f | ||
|
|
64e22b0c46 | ||
|
|
65e610507e | ||
|
|
46ca87b6c1 | ||
|
|
0d6d3c094b | ||
|
|
d519d0d187 | ||
|
|
fb4f54e9fa | ||
|
|
2c88f4932e |
+11
-7
@@ -1,7 +1,9 @@
|
|||||||
{{- $git_email := promptStringOnce . "git.email" "Git Email Address" -}}
|
{{- $git_email := promptStringOnce . "git.email" "Git Email Address" -}}
|
||||||
{{- $git_user := promptStringOnce . "git.user" "Git User Name" -}}
|
{{- $git_user := promptStringOnce . "git.user" "Git User Name" -}}
|
||||||
|
{{- $git_signingkey := promptStringOnce . "git.signingkey" "Git Signing Key" -}}
|
||||||
{{- $gpg_recipient := promptStringOnce . "gpg.recipient" "GPG Recipient Address" -}}
|
{{- $gpg_recipient := promptStringOnce . "gpg.recipient" "GPG Recipient Address" -}}
|
||||||
{{- $is_intel_cpu := promptBoolOnce . "cpu.intel" "Is this a Intel CPU?" -}}
|
{{- $is_intel_cpu := promptBoolOnce . "cpu.intel" "Is this a Intel CPU?" -}}
|
||||||
|
{{- $is_amd_cpu := promptBoolOnce . "cpu.amd" "Is this a AMD CPU?" -}}
|
||||||
{{- $is_intel_i915_gpu := promptBoolOnce . "gpu.intel_i915" "Is this a Intel i915 GPU?" -}}
|
{{- $is_intel_i915_gpu := promptBoolOnce . "gpu.intel_i915" "Is this a Intel i915 GPU?" -}}
|
||||||
{{- $is_work_env := promptBoolOnce . "work_env" "Install work environment?" -}}
|
{{- $is_work_env := promptBoolOnce . "work_env" "Install work environment?" -}}
|
||||||
|
|
||||||
@@ -9,10 +11,12 @@ data:
|
|||||||
git:
|
git:
|
||||||
email: {{ $git_email | quote }}
|
email: {{ $git_email | quote }}
|
||||||
user: {{ $git_user | quote }}
|
user: {{ $git_user | quote }}
|
||||||
|
signingkey: {{ $git_signingkey | quote }}
|
||||||
gpg:
|
gpg:
|
||||||
recipient: {{ $gpg_recipient | quote }}
|
recipient: {{ $gpg_recipient | quote }}
|
||||||
cpu:
|
cpu:
|
||||||
intel: {{ $is_intel_cpu }}
|
intel: {{ $is_intel_cpu }}
|
||||||
|
amd: {{ $is_amd_cpu }}
|
||||||
gpu:
|
gpu:
|
||||||
intel_i915: {{ $is_intel_i915_gpu }}
|
intel_i915: {{ $is_intel_i915_gpu }}
|
||||||
work_env: {{ $is_work_env }}
|
work_env: {{ $is_work_env }}
|
||||||
@@ -21,21 +25,21 @@ edit:
|
|||||||
command: nvim
|
command: nvim
|
||||||
|
|
||||||
merge:
|
merge:
|
||||||
|
pager: ""
|
||||||
command: meld
|
command: meld
|
||||||
args:
|
args:
|
||||||
- {{ printf "%q" "{{ .Target }}" }}
|
- "{{`{{ .Source }}`}}"
|
||||||
- {{ printf "%q" "{{ .Source }}" }}
|
- "{{`{{ .Destination }}`}}"
|
||||||
- {{ printf "%q" "{{ .Destination }}" }}
|
|
||||||
|
|
||||||
diff:
|
diff:
|
||||||
command: meld
|
command: sh
|
||||||
args:
|
args:
|
||||||
- --diff
|
- -c
|
||||||
- {{ printf "%q" "{{ .Destination }}" }}
|
- 'echo "Using meld"; meld --diff "{{`{{ .Destination }}`}}" "{{`{{ .Target }}`}}"'
|
||||||
- {{ printf "%q" "{{ .Target }}" }}
|
|
||||||
|
|
||||||
encryption: gpg
|
encryption: gpg
|
||||||
gpg:
|
gpg:
|
||||||
recipient: {{ $gpg_recipient | quote }}
|
recipient: {{ $gpg_recipient | quote }}
|
||||||
|
|
||||||
# vim: ft=template syntax=yaml
|
# vim: ft=template syntax=yaml
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ packages:
|
|||||||
- texinfo
|
- texinfo
|
||||||
- unzip
|
- unzip
|
||||||
- usbutils
|
- usbutils
|
||||||
|
- cups
|
||||||
|
- cups-pk-helper
|
||||||
# Display
|
# Display
|
||||||
- brightnessctl
|
- brightnessctl
|
||||||
- ddcutil
|
- ddcutil
|
||||||
@@ -100,21 +102,27 @@ packages:
|
|||||||
- papirus-icon-theme
|
- papirus-icon-theme
|
||||||
# Themes
|
# Themes
|
||||||
- colloid-catppuccin-gtk-theme-git
|
- colloid-catppuccin-gtk-theme-git
|
||||||
|
- darkly-bin
|
||||||
# Software
|
# Software
|
||||||
- bat
|
- bat
|
||||||
- btop
|
- btop
|
||||||
- bitwarden
|
- bitwarden
|
||||||
- chezmoi
|
- chezmoi
|
||||||
- chromium
|
- ungoogled-chromium-bin
|
||||||
|
- evince
|
||||||
- fastfetch
|
- fastfetch
|
||||||
- figlet
|
- figlet
|
||||||
- firefox
|
- firefox
|
||||||
- fzf
|
- fzf
|
||||||
|
- github-cli
|
||||||
- go
|
- go
|
||||||
- grim
|
- grim
|
||||||
|
- jdk-openjdk
|
||||||
- jq
|
- jq
|
||||||
|
- yq
|
||||||
|
- kdeconnect
|
||||||
- kitty
|
- kitty
|
||||||
- librewolf-bin
|
- librewolf
|
||||||
- meld
|
- meld
|
||||||
- nemo
|
- nemo
|
||||||
- nemo-fileroller
|
- nemo-fileroller
|
||||||
@@ -143,6 +151,7 @@ packages:
|
|||||||
- hunspell-en_gb
|
- hunspell-en_gb
|
||||||
- hunspell-en_us
|
- hunspell-en_us
|
||||||
- qalculate-gtk
|
- qalculate-gtk
|
||||||
|
- wofi
|
||||||
# VIM
|
# VIM
|
||||||
- lua-language-server
|
- lua-language-server
|
||||||
intel_graphics_i915:
|
intel_graphics_i915:
|
||||||
@@ -157,6 +166,19 @@ packages:
|
|||||||
intel_cpu:
|
intel_cpu:
|
||||||
yay:
|
yay:
|
||||||
- intel-ucode
|
- intel-ucode
|
||||||
|
amd_cpu:
|
||||||
|
yay:
|
||||||
|
- amd-ucode
|
||||||
work_env:
|
work_env:
|
||||||
yay:
|
yay:
|
||||||
- teams-for-linux-bin
|
- teams-for-linux-bin
|
||||||
|
- docker
|
||||||
|
- docker-credential-secretservice-bin
|
||||||
|
- docker-compose
|
||||||
|
- claude
|
||||||
|
- claude-code
|
||||||
|
- webstorm
|
||||||
|
- webstorm-jre
|
||||||
|
- azure-cli
|
||||||
|
- terraform
|
||||||
|
- postgresql-libs
|
||||||
|
|||||||
@@ -16,6 +16,11 @@
|
|||||||
url: https://raw.githubusercontent.com/catppuccin/btop/refs/heads/main/themes/catppuccin_macchiato.theme
|
url: https://raw.githubusercontent.com/catppuccin/btop/refs/heads/main/themes/catppuccin_macchiato.theme
|
||||||
refreshPeriod: 168h
|
refreshPeriod: 168h
|
||||||
|
|
||||||
|
.config/btop/themes/catppuccin_mocha.theme:
|
||||||
|
type: file
|
||||||
|
url: https://raw.githubusercontent.com/catppuccin/btop/refs/heads/main/themes/catppuccin_mocha.theme
|
||||||
|
refreshPeriod: 168h
|
||||||
|
|
||||||
# Theme for DankMateiralShell
|
# Theme for DankMateiralShell
|
||||||
.config/DankMaterialShell/catppuccin.json:
|
.config/DankMaterialShell/catppuccin.json:
|
||||||
type: file
|
type: file
|
||||||
@@ -27,3 +32,13 @@
|
|||||||
type: git-repo
|
type: git-repo
|
||||||
url: https://github.com/catppuccin/spicetify.git
|
url: https://github.com/catppuccin/spicetify.git
|
||||||
refreshPeriod: 168h
|
refreshPeriod: 168h
|
||||||
|
|
||||||
|
# Theme for QT
|
||||||
|
.config/qt5ct/colors/catppuccin-mocha-blue.conf:
|
||||||
|
type: file
|
||||||
|
url: https://raw.githubusercontent.com/catppuccin/qt5ct/refs/heads/main/themes/catppuccin-mocha-blue.conf
|
||||||
|
refreshPeriod: 168h
|
||||||
|
.config/qt6ct/colors/catppuccin-mocha-blue.conf:
|
||||||
|
type: file
|
||||||
|
url: https://raw.githubusercontent.com/catppuccin/qt5ct/refs/heads/main/themes/catppuccin-mocha-blue.conf
|
||||||
|
refreshPeriod: 168h
|
||||||
|
|||||||
+88
-28
@@ -1,36 +1,91 @@
|
|||||||
Desktop
|
.azure
|
||||||
Documents
|
|
||||||
Downloads
|
|
||||||
Music
|
|
||||||
Pictures
|
|
||||||
Projects
|
|
||||||
Public
|
|
||||||
Templates
|
|
||||||
Videos
|
|
||||||
thunderbird
|
|
||||||
.cache
|
|
||||||
.lesshst
|
|
||||||
.thunderbird
|
|
||||||
.bash_history
|
.bash_history
|
||||||
|
.cache
|
||||||
|
.camera_driver
|
||||||
|
.cargo
|
||||||
|
.claude
|
||||||
|
.claude.json
|
||||||
|
.claude.json.backup
|
||||||
|
.gradle
|
||||||
|
.ideavimrc
|
||||||
|
.java
|
||||||
|
.jbr
|
||||||
|
.jdks
|
||||||
|
.junie
|
||||||
|
.lesshst
|
||||||
|
.librewolf
|
||||||
|
.local
|
||||||
|
.local/share/*
|
||||||
|
.local/share/**
|
||||||
|
.local/state/**
|
||||||
|
.local/state/**
|
||||||
|
.mozilla
|
||||||
|
.MakeMKV
|
||||||
|
.node_repl_history
|
||||||
|
.npm
|
||||||
|
.nvm
|
||||||
|
.pki
|
||||||
|
.python_history
|
||||||
|
.rustup
|
||||||
|
.ssh
|
||||||
|
.thunderbird
|
||||||
|
|
||||||
.config/Signal
|
.config/autostart
|
||||||
|
.config/Bitwarden
|
||||||
|
.config/bruno
|
||||||
.config/chezmoi
|
.config/chezmoi
|
||||||
|
.config/chromium
|
||||||
|
.config/Claude
|
||||||
|
.config/cura
|
||||||
.config/dconf
|
.config/dconf
|
||||||
|
.config/draw.io
|
||||||
|
.config/filezilla
|
||||||
.config/fontforge
|
.config/fontforge
|
||||||
|
.config/FreeCAD
|
||||||
|
.config/gh
|
||||||
|
.config/GIMP
|
||||||
.config/go
|
.config/go
|
||||||
|
.config/google-chrome
|
||||||
|
.config/icedtea-web
|
||||||
|
.config/inkscape
|
||||||
|
.config/isyncrc
|
||||||
|
.config/JetBrains
|
||||||
|
.config/kdeconnect
|
||||||
|
.config/lftp
|
||||||
|
.config/libaccounts-glib
|
||||||
|
.config/libreoffice
|
||||||
.config/librewolf
|
.config/librewolf
|
||||||
.config/mozilla
|
.config/mozilla
|
||||||
.config/nemo
|
.config/nemo
|
||||||
|
.config/Nextcloud
|
||||||
|
.config/nvim/lazy-lock.json
|
||||||
.config/nvm
|
.config/nvm
|
||||||
|
.config/nvtop
|
||||||
|
.config/okularpartrc
|
||||||
|
.config/okularrc
|
||||||
|
.config/OpenSCAD
|
||||||
|
.config/openttd
|
||||||
.config/pavucontrol.ini
|
.config/pavucontrol.ini
|
||||||
.config/pulse
|
.config/pulse
|
||||||
|
.config/qalculate
|
||||||
|
.config/qt5ct/qss
|
||||||
|
.config/qt6ct/qss
|
||||||
|
.config/QtProject.conf
|
||||||
|
.config/rustdesk
|
||||||
|
.config/Signal
|
||||||
|
.config/spicetify
|
||||||
.config/spotify
|
.config/spotify
|
||||||
.config/systemd
|
.config/spotify-launcher.conf
|
||||||
.config/yay
|
# Ignore only the symlink farms generated by `systemctl --user enable`,
|
||||||
.config/Bitwarden
|
# so that real unit files can still be managed.
|
||||||
.config/autostart
|
.config/systemd/user/*.wants
|
||||||
.config/teams-for-linux
|
.config/teams-for-linux
|
||||||
|
.config/yay
|
||||||
|
|
||||||
|
# Ignore only the keyring and runtime state that GnuPG generates itself,
|
||||||
|
# so that the real config files can still be managed. Do not ignore
|
||||||
|
# `.gnupg` wholesale: chezmoi never descends into an ignored directory, so
|
||||||
|
# a `!` negation for a file inside it can never re-include that file.
|
||||||
.gnupg/crls.d
|
.gnupg/crls.d
|
||||||
.gnupg/openpgp-revocs.d
|
.gnupg/openpgp-revocs.d
|
||||||
.gnupg/private-keys-v1.d
|
.gnupg/private-keys-v1.d
|
||||||
@@ -38,13 +93,18 @@ thunderbird
|
|||||||
.gnupg/sshcontrol
|
.gnupg/sshcontrol
|
||||||
.gnupg/trustdb.gpg
|
.gnupg/trustdb.gpg
|
||||||
|
|
||||||
.local
|
Desktop
|
||||||
.local/state/**
|
Documents
|
||||||
.local/share/**
|
dotfiles
|
||||||
|
Downloads
|
||||||
|
isyncrc
|
||||||
.npm
|
maildir
|
||||||
.nvm
|
maintenance
|
||||||
.ssh
|
Music
|
||||||
.pki
|
nextcloud
|
||||||
.python_history
|
Pictures
|
||||||
|
Projects
|
||||||
|
Public
|
||||||
|
Templates
|
||||||
|
thunderbird
|
||||||
|
Videos
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{{- if eq .chezmoi.os "linux" -}}
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
[ "${CHEZMOI}" -eq 1 ] || exit 1
|
||||||
|
|
||||||
|
|
||||||
|
systemctl --user enable --now dms
|
||||||
|
|
||||||
|
# vim: syntax=bash ft=template
|
||||||
|
{{- end -}}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
{{- if eq .chezmoi.os "linux" -}}
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Enable the battery charge-controller watchdog.
|
||||||
|
#
|
||||||
|
# Re-runs whenever the unit or the watchdog script changes, so that an
|
||||||
|
# already-running instance picks up the new version.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
[ "${CHEZMOI}" -eq 1 ] || exit 1
|
||||||
|
|
||||||
|
# unit hash: {{ include (joinPath .chezmoi.sourceDir "dot_config/systemd/user/battery-charge-watchdog.service") | sha256sum }}
|
||||||
|
# script hash: {{ include (joinPath .chezmoi.sourceDir "dot_config/scripts/executable_battery-charge-watchdog.sh") | sha256sum }}
|
||||||
|
|
||||||
|
# Applying from a TTY or a container has no user bus; skip rather than
|
||||||
|
# aborting the whole apply.
|
||||||
|
if ! systemctl --user show-environment > /dev/null 2>&1; then
|
||||||
|
echo "No systemd user session, skipping battery-charge-watchdog activation"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
systemctl --user daemon-reload
|
||||||
|
|
||||||
|
# The unit carries ConditionPathExists on the battery, so enabling it on a
|
||||||
|
# machine without one is harmless: it simply never starts.
|
||||||
|
systemctl --user enable --now battery-charge-watchdog.service
|
||||||
|
|
||||||
|
# enable --now will not restart an instance that is already running, so an
|
||||||
|
# updated script or unit would otherwise not take effect until next login.
|
||||||
|
systemctl --user try-restart battery-charge-watchdog.service
|
||||||
|
|
||||||
|
# vim: syntax=bash ft=template
|
||||||
|
{{- end -}}
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
#!/usr/bin/bash
|
|
||||||
|
|
||||||
# This script is skipped if no spicetify-cli is available or no spotify is installed
|
|
||||||
|
|
||||||
if ! command -v spicetify > /dev/null; then
|
|
||||||
echo "Skipping Spotify Theming, no spicetify-cli available"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -d "/opt/spotify" ]; then
|
|
||||||
echo "Skipping Spotify Theming, no spotify found at /opt/spotify"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Apply theme to spotify if either the spotify binary has changed, or the theme was updated in github
|
|
||||||
# spotify hash: {{ include "/opt/spotify/spotify" | sha256sum }}
|
|
||||||
# catppuccin hash: {{ joinPath .chezmoi.homeDir ".config/spicetify-catppuccin-theme/catppuccin/app.scss" | include | sha256sum }}
|
|
||||||
|
|
||||||
mkdir -p ~/.config/spicetify/Themes
|
|
||||||
cp -r ~/.config/spicetify-catppuccin-theme/catppuccin ~/.config/spicetify/Themes/
|
|
||||||
|
|
||||||
getent group spotify > /dev/null || {
|
|
||||||
echo "System group spotify is missing"
|
|
||||||
echo "Please create it with groupadd -r spotify"
|
|
||||||
echo "Then re-login and try again"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
sudo chgrp spotify /opt/spotify
|
|
||||||
sudo chgrp -R spotify /opt/spotify/Apps
|
|
||||||
sudo chmod 775 /opt/spotify
|
|
||||||
sudo chmod 775 -R /opt/spotify/Apps
|
|
||||||
|
|
||||||
spicetify backup
|
|
||||||
spicetify config current_theme catppuccin
|
|
||||||
spicetify config color_scheme mocha
|
|
||||||
spicetify config inject_css 1 inject_theme_js 1 replace_colors 1 overwrite_assets 1
|
|
||||||
spicetify apply
|
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
#!/usr/bin/bash
|
||||||
|
|
||||||
|
# This script is skipped if no spicetify-cli is available or no spotify is installed
|
||||||
|
|
||||||
|
if ! command -v spicetify > /dev/null; then
|
||||||
|
echo "Skipping Spotify Theming, no spicetify-cli available"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d "/opt/spotify" ]; then
|
||||||
|
echo "Skipping Spotify Theming, no spotify found at /opt/spotify"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Apply theme to spotify if either the spotify binary has changed, or the theme was updated in github
|
||||||
|
|
||||||
|
{{ $spotifyPath := "/opt/spotify/spotify" }}
|
||||||
|
{{ $s := stat $spotifyPath }}
|
||||||
|
{{ if and $s (hasKey $s "Exists") $s.Exists }}
|
||||||
|
# spotify hash: {{ include $spotifyPath | sha256sum }}
|
||||||
|
{{ else }}
|
||||||
|
# spotify hash: <not installed>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
|
||||||
|
{{ $spotifyPath := "/usr/bin/spotify" }}
|
||||||
|
{{ $s := stat $spotifyPath }}
|
||||||
|
{{ if and $s (hasKey $s "Exists") $s.Exists }}
|
||||||
|
# spotify hash: {{ include $spotifyPath | sha256sum }}
|
||||||
|
{{ else }}
|
||||||
|
# spotify hash: <not installed>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ $catppuccinPath := joinPath .chezmoi.homeDir ".config/spicetify-catppuccin-theme/catppuccin/app.scss" }}
|
||||||
|
{{ $c := stat $catppuccinPath }}
|
||||||
|
{{ if and $c (hasKey $c "Exists") $c.Exists }}
|
||||||
|
# catppuccin hash: {{ include $catppuccinPath | sha256sum }}
|
||||||
|
{{ else }}
|
||||||
|
# catppuccin hash: <theme not installed>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
|
||||||
|
mkdir -p ~/.config/spicetify/Themes
|
||||||
|
cp -r ~/.config/spicetify-catppuccin-theme/catppuccin ~/.config/spicetify/Themes/
|
||||||
|
|
||||||
|
getent group spotify > /dev/null || {
|
||||||
|
echo "System group spotify is missing"
|
||||||
|
echo "Please create it with groupadd -r spotify"
|
||||||
|
echo "Then re-login and try again"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
sudo chgrp spotify /opt/spotify
|
||||||
|
sudo chgrp -R spotify /opt/spotify/Apps
|
||||||
|
sudo chmod 775 /opt/spotify
|
||||||
|
sudo chmod 775 -R /opt/spotify/Apps
|
||||||
|
|
||||||
|
spicetify backup
|
||||||
|
spicetify config current_theme catppuccin
|
||||||
|
spicetify config color_scheme mocha
|
||||||
|
spicetify config inject_css 1 inject_theme_js 1 replace_colors 1 overwrite_assets 1
|
||||||
|
spicetify apply
|
||||||
|
|
||||||
+5
@@ -25,6 +25,11 @@ declare -a yay_packages
|
|||||||
yay_packages+=({{ . | quote}})
|
yay_packages+=({{ . | quote}})
|
||||||
{{ end -}}
|
{{ end -}}
|
||||||
{{ end -}}
|
{{ end -}}
|
||||||
|
{{ if eq .cpu.amd true -}}
|
||||||
|
{{ range .packages.arch.amd_cpu.yay -}}
|
||||||
|
yay_packages+=({{ . | quote}})
|
||||||
|
{{ end -}}
|
||||||
|
{{ end -}}
|
||||||
{{ if eq .gpu.intel_i915 true -}}
|
{{ if eq .gpu.intel_i915 true -}}
|
||||||
{{ range .packages.arch.intel_graphics_i915.yay -}}
|
{{ range .packages.arch.intel_graphics_i915.yay -}}
|
||||||
yay_packages+=({{ . | quote}})
|
yay_packages+=({{ . | quote}})
|
||||||
@@ -10,3 +10,8 @@ if [ "${XDG_VTNR}" -eq 1 ]; then
|
|||||||
exec uwsm start hyprland.desktop
|
exec uwsm start hyprland.desktop
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Added by Toolbox App
|
||||||
|
export PATH="$PATH:/home/frank/.local/share/JetBrains/Toolbox/scripts"
|
||||||
|
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ HISTTIMEFORMAT="[%F %T] "
|
|||||||
HISTCONTROL="ignoredups"
|
HISTCONTROL="ignoredups"
|
||||||
HISTSIZE="200"
|
HISTSIZE="200"
|
||||||
HISTFILESIZE="2000"
|
HISTFILESIZE="2000"
|
||||||
shopt -s histappend
|
shopt -s histappend # append new entries to the histry instead of overwriting
|
||||||
|
|
||||||
# --- Bash Options ---
|
# --- Bash Options ---
|
||||||
set -o vi
|
set -o vi # mandated by POSIX
|
||||||
shopt -s checkwinsize
|
shopt -s checkwinsize
|
||||||
|
|
||||||
# --- Pager ---
|
# --- Pager ---
|
||||||
@@ -27,7 +27,7 @@ export LESS_TERMCAP_se=$'\E[0m'
|
|||||||
export LESS_TERMCAP_so=$'\E[01;44;33m'
|
export LESS_TERMCAP_so=$'\E[01;44;33m'
|
||||||
export LESS_TERMCAP_ue=$'\E[0m'
|
export LESS_TERMCAP_ue=$'\E[0m'
|
||||||
export LESS_TERMCAP_us=$'\E[01;32m'
|
export LESS_TERMCAP_us=$'\E[01;32m'
|
||||||
export BAT_THEME="Catppuccin Macchiato"
|
export BAT_THEME="Catppuccin Mocha"
|
||||||
# for man pages
|
# for man pages
|
||||||
export MANPAGER="sh -c 'sed -u -e \"s/\\x1B\[[0-9;]*m//g; s/.\\x08//g\" | bat -p -lman'"
|
export MANPAGER="sh -c 'sed -u -e \"s/\\x1B\[[0-9;]*m//g; s/.\\x08//g\" | bat -p -lman'"
|
||||||
|
|
||||||
@@ -72,6 +72,8 @@ alias pcat='bat -pp'
|
|||||||
# top / htop
|
# top / htop
|
||||||
alias top='btop'
|
alias top='btop'
|
||||||
alias htop='btop'
|
alias htop='btop'
|
||||||
|
# work
|
||||||
|
alias ia='cd ~/Projects/inso-automation'
|
||||||
# ssh
|
# ssh
|
||||||
[ "$TERM" = "xterm-kitty" ] && alias kssh="kitty +kitten ssh"
|
[ "$TERM" = "xterm-kitty" ] && alias kssh="kitty +kitten ssh"
|
||||||
|
|
||||||
|
|||||||
@@ -360,34 +360,34 @@
|
|||||||
"soundVolumeChanged": true,
|
"soundVolumeChanged": true,
|
||||||
"soundPluggedIn": true,
|
"soundPluggedIn": true,
|
||||||
"muteSoundsWhenMediaPlaying": true,
|
"muteSoundsWhenMediaPlaying": true,
|
||||||
"acMonitorTimeout": 1800,
|
"acMonitorTimeout": 10800,
|
||||||
"acLockTimeout": 300,
|
"acLockTimeout": 1800,
|
||||||
"acSuspendTimeout": 0,
|
"acSuspendTimeout": 0,
|
||||||
"acSuspendBehavior": 0,
|
"acSuspendBehavior": 0,
|
||||||
"acProfileName": "",
|
"acProfileName": "2",
|
||||||
"acPostLockMonitorTimeout": 30,
|
"acPostLockMonitorTimeout": 3600,
|
||||||
"batteryMonitorTimeout": 600,
|
"batteryMonitorTimeout": 600,
|
||||||
"batteryLockTimeout": 300,
|
"batteryLockTimeout": 300,
|
||||||
"batterySuspendTimeout": 7200,
|
"batterySuspendTimeout": 3600,
|
||||||
"batterySuspendBehavior": 2,
|
"batterySuspendBehavior": 2,
|
||||||
"batteryProfileName": "",
|
"batteryProfileName": "0",
|
||||||
"batteryPostLockMonitorTimeout": 60,
|
"batteryPostLockMonitorTimeout": 300,
|
||||||
"batteryChargeLimit": 100,
|
"batteryChargeLimit": 100,
|
||||||
"batteryNotifyChargeLimit": false,
|
"batteryNotifyChargeLimit": true,
|
||||||
"batteryCriticalThreshold": 5,
|
"batteryCriticalThreshold": 10,
|
||||||
"batteryNotifyCritical": true,
|
"batteryNotifyCritical": true,
|
||||||
"batteryLowThreshold": 15,
|
"batteryLowThreshold": 15,
|
||||||
"batteryNotifyLow": true,
|
"batteryNotifyLow": true,
|
||||||
"batteryChargeLimitNotificationType": 0,
|
"batteryChargeLimitNotificationType": 1,
|
||||||
"batteryLowNotificationType": 1,
|
"batteryLowNotificationType": 1,
|
||||||
"batteryCriticalNotificationType": 1,
|
"batteryCriticalNotificationType": 1,
|
||||||
"batteryAutoPowerSaver": false,
|
"batteryAutoPowerSaver": true,
|
||||||
"lockBeforeSuspend": true,
|
"lockBeforeSuspend": true,
|
||||||
"loginctlLockIntegration": true,
|
"loginctlLockIntegration": true,
|
||||||
"fadeToLockEnabled": true,
|
"fadeToLockEnabled": true,
|
||||||
"fadeToLockGracePeriod": 5,
|
"fadeToLockGracePeriod": 30,
|
||||||
"fadeToDpmsEnabled": true,
|
"fadeToDpmsEnabled": true,
|
||||||
"fadeToDpmsGracePeriod": 5,
|
"fadeToDpmsGracePeriod": 30,
|
||||||
"launchPrefix": "uwsm-app -- ",
|
"launchPrefix": "uwsm-app -- ",
|
||||||
"gtkThemingEnabled": false,
|
"gtkThemingEnabled": false,
|
||||||
"qtThemingEnabled": false,
|
"qtThemingEnabled": false,
|
||||||
@@ -614,13 +614,13 @@
|
|||||||
"enabled": true,
|
"enabled": true,
|
||||||
"clockCompactMode": false
|
"clockCompactMode": false
|
||||||
},
|
},
|
||||||
"weather"
|
"weather",
|
||||||
],
|
|
||||||
"rightWidgets": [
|
|
||||||
{
|
{
|
||||||
"id": "privacyIndicator",
|
"id": "privacyIndicator",
|
||||||
"enabled": true
|
"enabled": true
|
||||||
},
|
}
|
||||||
|
],
|
||||||
|
"rightWidgets": [
|
||||||
{
|
{
|
||||||
"id": "capsLockIndicator",
|
"id": "capsLockIndicator",
|
||||||
"enabled": true
|
"enabled": true
|
||||||
@@ -661,10 +661,10 @@
|
|||||||
"enabled": true
|
"enabled": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"spacing": 4,
|
"spacing": 0,
|
||||||
"innerPadding": 6,
|
"innerPadding": 6,
|
||||||
"barInsetPadding": 4,
|
"barInsetPadding": 4,
|
||||||
"bottomGap": 0,
|
"bottomGap": -16,
|
||||||
"transparency": 0,
|
"transparency": 0,
|
||||||
"widgetTransparency": 1,
|
"widgetTransparency": 1,
|
||||||
"squareCorners": false,
|
"squareCorners": false,
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
(gtk_accel_path "<Actions>/DirViewActions/OpenInTerminal" "F4")
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
#* Name of a btop++/bpytop/bashtop formatted ".theme" file, "Default" and "TTY" for builtin themes.
|
#* Name of a btop++/bpytop/bashtop formatted ".theme" file, "Default" and "TTY" for builtin themes.
|
||||||
#* Themes should be placed in "../share/btop/themes" relative to binary or "$HOME/.config/btop/themes"
|
#* Themes should be placed in "../share/btop/themes" relative to binary or "$HOME/.config/btop/themes"
|
||||||
color_theme = "/home/frank/.config/btop/themes/catppuccin_macchiato.theme"
|
color_theme = "/home/frank/.config/btop/themes/catppuccin_mocha.theme"
|
||||||
|
|
||||||
#* If the theme set background should be shown, set to False if you want terminal background transparency.
|
#* If the theme set background should be shown, set to False if you want terminal background transparency.
|
||||||
theme_background = true
|
theme_background = false
|
||||||
|
|
||||||
#* Sets if 24-bit truecolor should be used, will convert 24-bit colors to 256 color (6x6x6 color cube) if false.
|
#* Sets if 24-bit truecolor should be used, will convert 24-bit colors to 256 color (6x6x6 color cube) if false.
|
||||||
truecolor = true
|
truecolor = true
|
||||||
@@ -27,13 +27,13 @@ presets = "cpu:1:default,proc:0:default cpu:0:default,mem:0:default,net:0:defaul
|
|||||||
|
|
||||||
#* Set to True to enable "h,j,k,l,g,G" keys for directional control in lists.
|
#* Set to True to enable "h,j,k,l,g,G" keys for directional control in lists.
|
||||||
#* Conflicting keys for h:"help" and k:"kill" is accessible while holding shift.
|
#* Conflicting keys for h:"help" and k:"kill" is accessible while holding shift.
|
||||||
vim_keys = false
|
vim_keys = true
|
||||||
|
|
||||||
#* Disable all mouse events.
|
#* Disable all mouse events.
|
||||||
disable_mouse = false
|
disable_mouse = false
|
||||||
|
|
||||||
#* Rounded corners on boxes, is ignored if TTY mode is ON.
|
#* Rounded corners on boxes, is ignored if TTY mode is ON.
|
||||||
rounded_corners = true
|
rounded_corners = false
|
||||||
|
|
||||||
#* Use terminal synchronized output sequences to reduce flickering on supported terminals.
|
#* Use terminal synchronized output sequences to reduce flickering on supported terminals.
|
||||||
terminal_sync = true
|
terminal_sync = true
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
**/.claude/settings.local.json
|
||||||
@@ -2,4 +2,7 @@ file:///home/frank/Documents Documents
|
|||||||
file:///home/frank/Downloads Downloads
|
file:///home/frank/Downloads Downloads
|
||||||
file:///home/frank/Pictures Pictures
|
file:///home/frank/Pictures Pictures
|
||||||
file:///home/frank/Projects Projects
|
file:///home/frank/Projects Projects
|
||||||
|
file:///home/frank/Projects/inso-automation inso-automation
|
||||||
|
file:///home/frank/Documents/3d-printing 3d-printing
|
||||||
|
file:///home/frank/nextcloud nextcloud
|
||||||
smb://10.10.10.5/ HOMESERVER
|
smb://10.10.10.5/ HOMESERVER
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
|
|
||||||
-- See https://wiki.hypr.land/Configuring/Basics/Autostart/
|
|
||||||
|
|
||||||
-- Autostart necessary processes (like notifications daemons, status bars, etc.)
|
|
||||||
-- Or execute your favorite apps at launch like this:
|
|
||||||
--
|
|
||||||
-- hl.on("hyprland.start", function ()
|
|
||||||
-- hl.exec_cmd(terminal)
|
|
||||||
-- hl.exec_cmd("nm-applet")
|
|
||||||
-- hl.exec_cmd("waybar & hyprpaper & firefox")
|
|
||||||
-- end)
|
|
||||||
|
|
||||||
hl.on("hyprland.start", function()
|
|
||||||
hl.exec_cmd("librewolf", { workspace = 9 })
|
|
||||||
|
|
||||||
hl.exec_cmd("thunderbird", { workspace = 10 })
|
|
||||||
hl.timer(function()
|
|
||||||
hl.exec_cmd("signal-desktop", { workspace = 10 })
|
|
||||||
hl.exec_cmd("Telegram", { workspace = 10 })
|
|
||||||
end, { timeout = 1000, type = "oneshot" })
|
|
||||||
end)
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
-- See https://wiki.hypr.land/Configuring/Basics/Autostart/
|
||||||
|
|
||||||
|
-- Autostart necessary processes (like notifications daemons, status bars, etc.)
|
||||||
|
-- Or execute your favorite apps at launch like this:
|
||||||
|
--
|
||||||
|
-- Most applications are started by systemd. Others are wrapped by uwsm app -- (by create_launcher() function)
|
||||||
|
hl.on("hyprland.start", function()
|
||||||
|
hl.exec_cmd("~/.config/hypr/scripts/autostart.sh")
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- old stuff, probably not needed anymore
|
||||||
|
-- exec-once = gnome-keyring-daemon --start --components=secrets
|
||||||
|
-- exec-once = systemctl --user start gcr-ssh-agent.socket
|
||||||
|
--
|
||||||
|
-- Polkit Daemon
|
||||||
|
-- exec-once = /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1
|
||||||
|
--
|
||||||
@@ -1,23 +1,5 @@
|
|||||||
local launchPrefix = "uwsm app -- "
|
|
||||||
|
|
||||||
local function is_ipc_call(command)
|
|
||||||
-- check if this is an ipc call to a running programm
|
|
||||||
is_dms_ipc = starts_with(command, "dms ipc")
|
|
||||||
is_hyprctl = starts_with(command, "hyprctl")
|
|
||||||
is_ipc = any({is_dms_ipc, is_hyprctl}, function(v) return v end)
|
|
||||||
return is_ipc
|
|
||||||
end
|
|
||||||
|
|
||||||
function create_launcher(command)
|
|
||||||
if is_ipc_call(command) then
|
|
||||||
return command
|
|
||||||
end
|
|
||||||
return launchPrefix .. command
|
|
||||||
end
|
|
||||||
|
|
||||||
function execute(command)
|
|
||||||
return hl.dsp.exec_cmd(create_launcher(command))
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Program Launchers
|
-- Program Launchers
|
||||||
hl.bind("SUPER + Return", execute(programs.terminal), { description = "Open Terminal" })
|
hl.bind("SUPER + Return", execute(programs.terminal), { description = "Open Terminal" })
|
||||||
@@ -30,6 +12,7 @@ hl.bind("SUPER + Escape", execute("dms ipc call powermenu toggle"), { descriptio
|
|||||||
hl.bind("SUPER + Plus", execute(programs.calculator), { description = "Open Calculator" })
|
hl.bind("SUPER + Plus", execute(programs.calculator), { description = "Open Calculator" })
|
||||||
hl.bind("SUPER + B", execute("dms ipc call night toggle"), { description = "Toggle Night Mode" })
|
hl.bind("SUPER + B", execute("dms ipc call night toggle"), { description = "Toggle Night Mode" })
|
||||||
hl.bind("SUPER + SHIFT + I", execute("dms ipc call inhibit toggle"), { description = "Toggle Idle Inhibitor" })
|
hl.bind("SUPER + SHIFT + I", execute("dms ipc call inhibit toggle"), { description = "Toggle Idle Inhibitor" })
|
||||||
|
hl.bind("SUPER + A", execute("~/.config/scripts/action_menu.sh"), { description = "Open Wofi Action Menu" })
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -62,6 +45,11 @@ hl.bind("SUPER + S", hl.dsp.window.pin({action="toggle"}), { description = "Pin
|
|||||||
hl.bind("SUPER + mouse:272", hl.dsp.window.drag(), { description = "Move Window", mouse = true })
|
hl.bind("SUPER + mouse:272", hl.dsp.window.drag(), { description = "Move Window", mouse = true })
|
||||||
hl.bind("SUPER + mouse:273", hl.dsp.window.resize(), { description = "Resize Window", mouse = true })
|
hl.bind("SUPER + mouse:273", hl.dsp.window.resize(), { description = "Resize Window", mouse = true })
|
||||||
|
|
||||||
|
hl.bind("SUPER + asciicircum", hl.dsp.focus({urgent_or_last = true }), { description = "Focus Last or Urgent Window" })
|
||||||
|
hl.bind("SUPER + Tab", hl.dsp.focus({last = true }), { description = "Focus Last Window" })
|
||||||
|
hl.bind("ALT + Tab", hl.dsp.window.cycle_next({next = true, tiled = true, floating = true}), { description = "Cycle Focus" })
|
||||||
|
hl.bind("ALT + SHIFT + Tab", hl.dsp.window.cycle_next({next = false, tiled = true, floating = true}), { description = "Cycle Focus" })
|
||||||
|
|
||||||
local function smart_focus(direction)
|
local function smart_focus(direction)
|
||||||
local window = hl.get_active_window()
|
local window = hl.get_active_window()
|
||||||
if not window then return end
|
if not window then return end
|
||||||
|
|||||||
@@ -1,267 +0,0 @@
|
|||||||
-- Monitor configuration and automatic and manual switching--
|
|
||||||
|
|
||||||
------------------
|
|
||||||
---- PROFILES ----
|
|
||||||
------------------
|
|
||||||
|
|
||||||
-- Profiles:
|
|
||||||
-- Key of the profile is the name of the profile
|
|
||||||
-- Profiles are ordered by priority, higher number takes precedence over smaller number
|
|
||||||
-- First (by priority) profile that matches will be applied, all others will be ignored
|
|
||||||
--
|
|
||||||
-- A profile matches the current setup if _ALL_ of its match criteria are fulfilled
|
|
||||||
-- If there are no match criteria, it will match always
|
|
||||||
local PROFILES = {
|
|
||||||
-- The most basic fallback if nothing else ever works
|
|
||||||
fallback = {
|
|
||||||
priority = -999,
|
|
||||||
matches = {},
|
|
||||||
monitors = {
|
|
||||||
{
|
|
||||||
output = "",
|
|
||||||
mode = "preferred",
|
|
||||||
position = "auto",
|
|
||||||
scale = 1,
|
|
||||||
disabled = false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
laptop = {
|
|
||||||
priority = 0,
|
|
||||||
matches = {{ output = "eDP-1" }},
|
|
||||||
monitors = {
|
|
||||||
{
|
|
||||||
output = "eDP-1",
|
|
||||||
mode = "1920x1200@120",
|
|
||||||
position = "0x0",
|
|
||||||
scale = 1,
|
|
||||||
disabled = false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
home_docked = {
|
|
||||||
priority = 10,
|
|
||||||
matches = {
|
|
||||||
{ output = "desc:GIGA-BYTE TECHNOLOGY CO. LTD. M34WQ 0x00000B52" },
|
|
||||||
{ output = "desc:Dell Inc. DELL U2414H 292K475V26JL" },
|
|
||||||
{ output = "desc:Dell Inc. DELL U2724D DL7R834" },
|
|
||||||
},
|
|
||||||
monitors = {
|
|
||||||
{
|
|
||||||
output = "eDP-1",
|
|
||||||
mode = "preferred",
|
|
||||||
position = "0x0",
|
|
||||||
scale = 1,
|
|
||||||
disabled = true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
output = "desc:GIGA-BYTE TECHNOLOGY CO. LTD. M34WQ 0x00000B52",
|
|
||||||
mode = "3440x1440@60",
|
|
||||||
position = "0x0",
|
|
||||||
scale = 1,
|
|
||||||
disabled = false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
output = "desc:Dell Inc. DELL U2414H 292K475V26JL",
|
|
||||||
mode = "1920x1080@60",
|
|
||||||
position = "760x-1080",
|
|
||||||
scale = 1,
|
|
||||||
disabled = false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
output = "desc:Dell Inc. DELL U2724D DL7R834",
|
|
||||||
mode = "2560x1440@60",
|
|
||||||
position = "3440x0",
|
|
||||||
scale = 1,
|
|
||||||
disabled = false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
postprocess = function()
|
|
||||||
debug_notify("now applying workspace rules")
|
|
||||||
for i = 1,5 do
|
|
||||||
hl.workspace_rule({ workspace = string.format("%d", i), monitor = "desc:GIGA-BYTE TECHNOLOGY CO. LTD. M34WQ 0x00000B52"})
|
|
||||||
end
|
|
||||||
hl.workspace_rule({ workspace = "1", default = true, persistent = true})
|
|
||||||
for i = 6,9 do
|
|
||||||
hl.workspace_rule({ workspace = string.format("%d", i), monitor = "desc:Dell Inc. DELL U2724D DL7R834"})
|
|
||||||
end
|
|
||||||
hl.workspace_rule({ workspace = "9", default = true, persistent = true})
|
|
||||||
hl.workspace_rule({ workspace = "10", monitor = "desc:Dell Inc. DELL U2414H 292K475V26JL", default = true, persistent = true})
|
|
||||||
|
|
||||||
hl.dispatch(hl.dsp.focus({workspace = 10}))
|
|
||||||
hl.dispatch(hl.dsp.focus({workspace = 9}))
|
|
||||||
hl.dispatch(hl.dsp.focus({workspace = 1}))
|
|
||||||
end
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
local function refresh_monitors()
|
|
||||||
hl.exec_cmd("hyprctl monitors all -j | jq -r '.[] | [.name, .description] | @tsv' > /tmp/hypr_monitors.tsv")
|
|
||||||
end
|
|
||||||
local function get_monitors()
|
|
||||||
-- FIXME: Use hl.get_monitors({all=true}) as soon as it is released
|
|
||||||
local handle = io.open("/tmp/hypr_monitors.tsv", "r")
|
|
||||||
if handle ~= nil then
|
|
||||||
local out = handle:read("*a")
|
|
||||||
handle:close()
|
|
||||||
|
|
||||||
local result = {}
|
|
||||||
for line in out:gmatch("[^\n]+") do
|
|
||||||
local name, desc = line:match("([^\t]+)\t(.+)")
|
|
||||||
table.insert(result, { name = name, description = desc })
|
|
||||||
end
|
|
||||||
return result
|
|
||||||
end
|
|
||||||
return {}
|
|
||||||
end
|
|
||||||
|
|
||||||
local function get_matching_profile()
|
|
||||||
local monitors = get_monitors()
|
|
||||||
local profiles = {} or {}
|
|
||||||
|
|
||||||
local monitor_debug = map(monitors, function(monitor)
|
|
||||||
return monitor.name .. ": "..monitor.description
|
|
||||||
end)
|
|
||||||
debug_notify("Currently " .. #monitors .. " connected: " .. table.concat(monitor_debug, "; "))
|
|
||||||
|
|
||||||
for profile_name, profile in pairs(PROFILES) do
|
|
||||||
profile.name = profile_name or "unknown"
|
|
||||||
table.insert(profiles, profile)
|
|
||||||
end
|
|
||||||
table.sort(profiles, function(a, b) return (a.priority or 0) > (b.priority or 0) end)
|
|
||||||
|
|
||||||
for _, profile in ipairs(profiles) do
|
|
||||||
local matches = profile.matches or {}
|
|
||||||
local has_matched = {}
|
|
||||||
for _, match in ipairs(matches) do
|
|
||||||
if starts_with(match.output, "desc:") then
|
|
||||||
table.insert(has_matched, any(monitors, function(m) return "desc:" .. m.description == match.output end))
|
|
||||||
else
|
|
||||||
table.insert(has_matched, any(monitors, function(m) return m.name == match.output end))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if #has_matched == 0 then
|
|
||||||
debug_notify("Monitor profile " .. profile.name .. " is active because it does not require any matches (fallback)")
|
|
||||||
return profile
|
|
||||||
elseif all(has_matched, function(v) return v end) then
|
|
||||||
return profile
|
|
||||||
else
|
|
||||||
local failed = map(has_matched, function(v, i)
|
|
||||||
if not v then
|
|
||||||
return matches[i].output
|
|
||||||
else
|
|
||||||
return ""
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
local failedmsg = table.concat(failed, " ")
|
|
||||||
debug_notify("Monitor profile " .. profile.name .. " does not match, could not match " .. failedmsg)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
local PROFILE_CHANGE_ONGOING = false
|
|
||||||
local PROFILE_CHANGE_RESET_TIMER = nil
|
|
||||||
local PROFILE_CHANGE_START_TIMER = nil
|
|
||||||
local POSTPROCESS_TIMER = nil
|
|
||||||
|
|
||||||
local function apply_profile(profile)
|
|
||||||
if PROFILE_CHANGE_ONGOING then
|
|
||||||
debug_notify("Monitor profile change is inprogress (debounce)")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if profile == nil then
|
|
||||||
debug_notify("No monitor profile available")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
debug_notify("Applying monitor profile " .. profile.name)
|
|
||||||
PROFILE_CHANGE_ONGOING = true
|
|
||||||
|
|
||||||
-- delay application of the profile for some time, as other monitor change events might still be arriving
|
|
||||||
PROFILE_CHANGE_START_TIMER = hl.timer(function()
|
|
||||||
|
|
||||||
-- after we have started applying our profile, we will generate monitor change events that we do not
|
|
||||||
-- want to process. Assume 5 seconds of non-interesting monitor events that we do not want to process
|
|
||||||
-- afterwards, reset the PROFILE_CHANGE_ONGOING flag for the next time we actually want to change
|
|
||||||
-- monitor profiles
|
|
||||||
PROFILE_CHANGE_RESET_TIMER = hl.timer(function()
|
|
||||||
PROFILE_CHANGE_ONGOING = false
|
|
||||||
debug_notify("Monitor Profile Change Debounce Finished")
|
|
||||||
PROFILE_CHANGE_RESET_TIMER = nil
|
|
||||||
end, { timeout = 5000, type = "oneshot" })
|
|
||||||
|
|
||||||
local monitors = profile.monitors
|
|
||||||
for _, monitor in ipairs(monitors) do
|
|
||||||
hl.monitor(monitor)
|
|
||||||
end
|
|
||||||
|
|
||||||
debug_notify("Monitor Profile " .. profile.name .. " successfully applied")
|
|
||||||
|
|
||||||
-- start any post processing
|
|
||||||
if profile.postprocess ~= nil then
|
|
||||||
POSTPROCESS_TIMER = hl.timer(function()
|
|
||||||
if profile.postprocess ~= nil then
|
|
||||||
profile.postprocess()
|
|
||||||
end
|
|
||||||
|
|
||||||
PROFILE_CHANGE_START_TIMER = nil
|
|
||||||
POSTPROCESS_TIMER = nil
|
|
||||||
end, { timeout = 200, type = "oneshot" })
|
|
||||||
else
|
|
||||||
PROFILE_CHANGE_START_TIMER = nil
|
|
||||||
end
|
|
||||||
end, { timeout = 500, type = "oneshot" })
|
|
||||||
end
|
|
||||||
|
|
||||||
local function apply_current_profile()
|
|
||||||
apply_profile(get_matching_profile())
|
|
||||||
end
|
|
||||||
|
|
||||||
local function force_refresh_profile()
|
|
||||||
if PROFILE_CHANGE_RESET_TIMER ~= nil then PROFILE_CHANGE_RESET_TIMER:set_enabled(false) end
|
|
||||||
if POSTPROCESS_TIMER ~= nil then POSTPROCESS_TIMER:set_enabled(false) end
|
|
||||||
if PROFILE_CHANGE_START_TIMER ~= nil then PROFILE_CHANGE_START_TIMER:set_enabled(false) end
|
|
||||||
|
|
||||||
PROFILE_CHANGE_RESET_TIMER = nil
|
|
||||||
POSTPROCESS_TIMER = nil
|
|
||||||
PROFILE_CHANGE_START_TIMER = nil
|
|
||||||
PROFILE_CHANGE_ONGOING = false
|
|
||||||
|
|
||||||
debug_notify("Force applying monitor profile")
|
|
||||||
refresh_monitors()
|
|
||||||
apply_current_profile()
|
|
||||||
end
|
|
||||||
|
|
||||||
local function on_lid_close()
|
|
||||||
debug_notify("Lid was closed")
|
|
||||||
refresh_monitors()
|
|
||||||
hl.monitor({ output = "eDP-1", disabled = true })
|
|
||||||
end
|
|
||||||
|
|
||||||
local function on_lid_open()
|
|
||||||
debug_notify("Lid was opened")
|
|
||||||
refresh_monitors()
|
|
||||||
apply_current_profile()
|
|
||||||
end
|
|
||||||
|
|
||||||
local function on_monitor_added(_event)
|
|
||||||
debug_notify("A monitor was added")
|
|
||||||
refresh_monitors()
|
|
||||||
apply_current_profile()
|
|
||||||
end
|
|
||||||
|
|
||||||
local function on_monitor_removed(_event)
|
|
||||||
debug_notify("A monitor was removed")
|
|
||||||
refresh_monitors()
|
|
||||||
apply_current_profile()
|
|
||||||
end
|
|
||||||
|
|
||||||
hl.bind("switch:on:Lid Switch", on_lid_close, { locked = true })
|
|
||||||
hl.bind("switch:off:Lid Switch", on_lid_open, { locked = true })
|
|
||||||
hl.bind("SUPER + P", function() force_refresh_profile() end, { locked = true, description = "Force Refresh Monitor Profile" })
|
|
||||||
hl.on("monitor.added", on_monitor_added)
|
|
||||||
hl.on("monitor.removed", on_monitor_removed)
|
|
||||||
hl.on("hyprland.start", function() refresh_monitors() end)
|
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
local workspace_rules = {}
|
||||||
|
|
||||||
|
{{ if eq .chezmoi.hostname "ia-frank-xps13" -}}
|
||||||
|
hl.monitor({
|
||||||
|
output = "eDP-1",
|
||||||
|
scale = 1,
|
||||||
|
position = "0x0",
|
||||||
|
mode = "1920x1200@120"
|
||||||
|
})
|
||||||
|
|
||||||
|
hl.monitor({
|
||||||
|
output = "desc:Dell Inc. DELL U2724DE BD19MF4",
|
||||||
|
scale = 1,
|
||||||
|
position = "-2560x0",
|
||||||
|
mode = "2560x1440@120"
|
||||||
|
})
|
||||||
|
|
||||||
|
hl.monitor({
|
||||||
|
output = "desc:Dell Inc. DELL U2724D 1CQFMF4",
|
||||||
|
scale = 1,
|
||||||
|
position = "-5120x0",
|
||||||
|
mode = "2560x1440@120"
|
||||||
|
})
|
||||||
|
local workspace_rules = {
|
||||||
|
{ workspace = "6", monitor = "desc:Dell Inc. DELL U2724D 1CQFMF4", default = true, persistent = true },
|
||||||
|
{ workspace = "7", monitor = "desc:Dell Inc. DELL U2724D 1CQFMF4", persistent = true },
|
||||||
|
{ workspace = "8", monitor = "desc:Dell Inc. DELL U2724D 1CQFMF4", persistent = true },
|
||||||
|
{ workspace = "1", monitor = "desc:Dell Inc. DELL U2724DE BD19MF4", default = true, persistent = true },
|
||||||
|
{ workspace = "2", monitor = "desc:Dell Inc. DELL U2724DE BD19MF4", persistent = true },
|
||||||
|
{ workspace = "3", monitor = "desc:Dell Inc. DELL U2724DE BD19MF4", persistent = true },
|
||||||
|
{ workspace = "4", monitor = "desc:Dell Inc. DELL U2724DE BD19MF4", persistent = true },
|
||||||
|
{ workspace = "5", monitor = "desc:Dell Inc. DELL U2724DE BD19MF4", persistent = true },
|
||||||
|
{ workspace = "9", monitor = "eDP-1", default = true, persistent = true },
|
||||||
|
{ workspace = "10", monitor = "eDP-1", persistent = true },
|
||||||
|
}
|
||||||
|
{{- else if eq .chezmoi.hostname "arch-next" -}}
|
||||||
|
hl.monitor({
|
||||||
|
output = "desc:GIGA-BYTE TECHNOLOGY CO. LTD. M34WQ 0x00000B52",
|
||||||
|
scale = 1,
|
||||||
|
position = "0x0",
|
||||||
|
mode = "3440x1440@120",
|
||||||
|
})
|
||||||
|
|
||||||
|
hl.monitor({
|
||||||
|
output = "desc:Dell Inc. DELL U2724D DL7R834",
|
||||||
|
scale = 1,
|
||||||
|
position = "3440x0",
|
||||||
|
mode = "2560x1440@120",
|
||||||
|
})
|
||||||
|
|
||||||
|
hl.monitor({
|
||||||
|
output = "desc:Dell Inc. DELL U2414H 292K475V26JL",
|
||||||
|
scale = 1,
|
||||||
|
position = "760x-1080",
|
||||||
|
mode = "1920x1080@60",
|
||||||
|
})
|
||||||
|
local workspace_rules = {
|
||||||
|
{ workspace = "1", monitor = "desc:GIGA-BYTE TECHNOLOGY CO. LTD. M34WQ 0x00000B52", default = true, persistent = true},
|
||||||
|
{ workspace = "9", monitor = "desc:Dell Inc. DELL U2724D DL7R834", default = true, persistent = true},
|
||||||
|
{ workspace = "10", monitor = "desc:Dell Inc. DELL U2414H 292K475V26JL", default = true, persistent = true},
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for _, rule in ipairs(workspace_rules) do
|
||||||
|
hl.workspace_rule(rule)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- if multiple profiles match, profile with highest priority wins.
|
||||||
|
-- if no profile match at all, the fallback_profile will be applied anyways.
|
||||||
|
local fallback_profile="laptop"
|
||||||
|
local profiles = {
|
||||||
|
home_docked = {
|
||||||
|
priority = 10,
|
||||||
|
monitors = {
|
||||||
|
"desc:GIGA-BYTE TECHNOLOGY CO. LTD. M34WQ 0x00000B52",
|
||||||
|
"desc:Dell Inc. DELL U2724D DL7R834",
|
||||||
|
"desc:Dell Inc. DELL U2414H 292K475V26JL",
|
||||||
|
},
|
||||||
|
disable_other_monitors = true,
|
||||||
|
monitor_config = {
|
||||||
|
["desc:GIGA-BYTE TECHNOLOGY CO. LTD. M34WQ 0x00000B52"] = {disabled=false, scale=1, position="0x0", mode="3440x1440@60"},
|
||||||
|
["desc:Dell Inc. DELL U2724D DL7R834"] = {disabled=false, scale=1, position="3440x0", mode="2556x1440@60"},
|
||||||
|
["desc:Dell Inc. DELL U2414H 292K475V26JL"] = {disabled=false, scale=1, position="760x-1080", mode="1920x1080@60"},
|
||||||
|
},
|
||||||
|
workspace_rules = {
|
||||||
|
},
|
||||||
|
},
|
||||||
|
home_pc = {
|
||||||
|
priority = 20,
|
||||||
|
monitors = {
|
||||||
|
"desc:GIGA-BYTE TECHNOLOGY CO. LTD. M34WQ 0x00000B52",
|
||||||
|
"desc:Dell Inc. DELL U2724D DL7R834",
|
||||||
|
"desc:Dell Inc. DELL U2414H 292K475V26JL",
|
||||||
|
},
|
||||||
|
disable_other_monitors = true,
|
||||||
|
monitor_config = {
|
||||||
|
["desc:GIGA-BYTE TECHNOLOGY CO. LTD. M34WQ 0x00000B52"] = {disabled=false, scale=1, position="0x0", mode="3440x1440@120"},
|
||||||
|
["desc:Dell Inc. DELL U2414H 292K475V26JL"] = {disabled=false, scale=1, position="760x-1080", mode="1920x1080@60"},
|
||||||
|
["desc:Dell Inc. DELL U2724D DL7R834"] = {disabled=false, scale=1, position="3440x0", mode="2560x1440@120"},
|
||||||
|
},
|
||||||
|
workspace_rules = {
|
||||||
|
{ workspace = "1", monitor = "desc:GIGA-BYTE TECHNOLOGY CO. LTD. M34WQ 0x00000B52", default = true, persistent = true},
|
||||||
|
{ workspace = "9", monitor = "desc:Dell Inc. DELL U2724D DL7R834", default = true, persistent = true},
|
||||||
|
{ workspace = "10", monitor = "desc:Dell Inc. DELL U2414H 292K475V26JL", default = true, persistent = true},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
work = {
|
||||||
|
priority = 10,
|
||||||
|
monitors = {
|
||||||
|
"desc:Dell Inc. DELL U2724D 1CQFMF4",
|
||||||
|
"desc:Dell Inc. DELL U2724DE BD19MF4",
|
||||||
|
"eDP-1",
|
||||||
|
},
|
||||||
|
disable_other_monitors = false,
|
||||||
|
monitor_config = {
|
||||||
|
["desc:Dell Inc. DELL U2724D 1CQFMF4"] = {disabled=false, scale=1, position="-5120x0", mode="2560x1440@120"},
|
||||||
|
["desc:Dell Inc. DELL U2724DE BD19MF4"] = {disabled=false, scale=1, position="-2560x0", mode="2560x1440@120"},
|
||||||
|
["eDP-1"] = {disabled=false, scale=1, position="0x0", mode="1920x1200@120"},
|
||||||
|
},
|
||||||
|
workspace_rules = {
|
||||||
|
{ workspace = "6", monitor = "desc:Dell Inc. DELL U2724D 1CQFMF4", default = true, persistent = true },
|
||||||
|
{ workspace = "7", monitor = "desc:Dell Inc. DELL U2724D 1CQFMF4", persistent = true },
|
||||||
|
{ workspace = "8", monitor = "desc:Dell Inc. DELL U2724D 1CQFMF4", persistent = true },
|
||||||
|
{ workspace = "1", monitor = "desc:Dell Inc. DELL U2724DE BD19MF4", default = true, persistent = true },
|
||||||
|
{ workspace = "2", monitor = "desc:Dell Inc. DELL U2724DE BD19MF4", persistent = true },
|
||||||
|
{ workspace = "3", monitor = "desc:Dell Inc. DELL U2724DE BD19MF4", persistent = true },
|
||||||
|
{ workspace = "4", monitor = "desc:Dell Inc. DELL U2724DE BD19MF4", persistent = true },
|
||||||
|
{ workspace = "5", monitor = "desc:Dell Inc. DELL U2724DE BD19MF4", persistent = true },
|
||||||
|
{ workspace = "9", monitor = "eDP-1", default = true, persistent = true },
|
||||||
|
{ workspace = "10", monitor = "eDP-1", persistent = true },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
laptop = {
|
||||||
|
priority = 0,
|
||||||
|
monitors = {
|
||||||
|
"eDP-1",
|
||||||
|
},
|
||||||
|
disable_other_monitors = false,
|
||||||
|
monitor_config = {
|
||||||
|
["eDP-1"] = {disabled=false, scale=1, position="0x0", mode="1920x1200@60"},
|
||||||
|
},
|
||||||
|
workspace_rules = {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
local apply_monitor_request_queue = {}
|
||||||
|
|
||||||
|
local function apply_workspace_rules(workspace_rules)
|
||||||
|
if #workspace_rules < 1 then return end
|
||||||
|
for _, rules in ipairs(workspace_rules) do
|
||||||
|
hl.workspace_rule(rules)
|
||||||
|
end
|
||||||
|
debug_notify("Workspace Rules Applied")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function apply_selected_profile(profile_name, profile)
|
||||||
|
-- do we want to disable other monitors that are not used in this profile?
|
||||||
|
if profile.disable_other_monitors then
|
||||||
|
local monitors = hl.get_monitors()
|
||||||
|
table.insert(monitors, hl.get_monitor("eDP-1"))
|
||||||
|
|
||||||
|
for _, monitor in ipairs(monitors) do
|
||||||
|
if monitor ~= nil then
|
||||||
|
local name = monitor.name
|
||||||
|
local description = monitor.description
|
||||||
|
if not any(
|
||||||
|
profile.monitors,
|
||||||
|
function(wanted)
|
||||||
|
return
|
||||||
|
wanted == name or
|
||||||
|
wanted == "desc:"..description
|
||||||
|
end
|
||||||
|
) then
|
||||||
|
debug_notify("Disabling output "..name.." ("..description..")")
|
||||||
|
hl.monitor({output = name, disabled = true})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- use the configuration in the profile and apply it to hyprland
|
||||||
|
for _, monitor_selector in ipairs(profile.monitors) do
|
||||||
|
local config = profile.monitor_config[monitor_selector] or {}
|
||||||
|
config.output = monitor_selector
|
||||||
|
hl.monitor(config)
|
||||||
|
end
|
||||||
|
debug_notify("Profile " .. profile_name .. " was applied")
|
||||||
|
|
||||||
|
apply_workspace_rules(profile.workspace_rules)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function apply_monitor_profile()
|
||||||
|
if #apply_monitor_request_queue < 1 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
table.remove(apply_monitor_request_queue)
|
||||||
|
-- make sure we know the up-to-date state of the system
|
||||||
|
hl.exec_scheduled_prop_refresh_immediately()
|
||||||
|
|
||||||
|
-- try to find all profiles that match current monitors
|
||||||
|
local matching_profiles = {}
|
||||||
|
for profile_name, profile in pairs(profiles) do
|
||||||
|
if all(
|
||||||
|
profile.monitors,
|
||||||
|
function(monitor_selector)
|
||||||
|
local found =
|
||||||
|
-- if the monitor exists, hyprland should be able to return this monitor
|
||||||
|
hl.get_monitor(monitor_selector) ~= nil
|
||||||
|
if not found then
|
||||||
|
debug_notify("not able to find monitor "..monitor_selector.." for profile "..profile_name)
|
||||||
|
end
|
||||||
|
return found
|
||||||
|
end
|
||||||
|
)
|
||||||
|
then
|
||||||
|
table.insert(matching_profiles, {name = profile_name, profile = profile})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- if no profile was found, do nothing
|
||||||
|
if #matching_profiles < 1 then
|
||||||
|
local profile = profiles[fallback_profile] or nil
|
||||||
|
if profile == nil then
|
||||||
|
debug_notify("No profiles are matching the current monitors and no fallback with name '"..fallback_profile.."' available!")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
debug_notify("No profiles are matching the current monitors, applying fallback")
|
||||||
|
apply_selected_profile("fallback", profile)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- if multiple profiles are matching, select the correct one by priority
|
||||||
|
table.sort(matching_profiles, function(a, b) return a.profile.priority > b.profile.priority end)
|
||||||
|
local matching_profile = matching_profiles[1]
|
||||||
|
local profile_name, profile = matching_profile.name, matching_profile.profile
|
||||||
|
debug_notify("Matching monitor profile found: " .. profile_name)
|
||||||
|
apply_selected_profile(profile_name, profile)
|
||||||
|
end
|
||||||
|
|
||||||
|
local monitor_profile_timer = nil
|
||||||
|
function request_apply_monitor_profile(data)
|
||||||
|
debug_notify("requested monitor profile update")
|
||||||
|
table.insert(apply_monitor_request_queue, data or {})
|
||||||
|
if monitor_profile_timer == nil or not monitor_profile_timer:is_enabled() then
|
||||||
|
monitor_profile_timer = hl.timer(apply_monitor_profile, { timeout = 3000, type = "repeat" })
|
||||||
|
debug_notify("monitor profile apply timer has been restarted")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
hl.on("hyprland.start", function()
|
||||||
|
debug_notify("hyprland start :)")
|
||||||
|
hl.dispatch(function()
|
||||||
|
hl.monitor({output = "eDP-1", disabled = false})
|
||||||
|
hl.dispatch(function() request_apply_monitor_profile() end)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
hl.on("monitor.layout_changed", request_apply_monitor_profile)
|
||||||
|
hl.bind("SUPER + P", function()
|
||||||
|
hl.monitor({output = "eDP-1", disabled = true})
|
||||||
|
request_apply_monitor_profile()
|
||||||
|
end, {locked=true, description="Detect & Apply Monitor Profile"})
|
||||||
|
hl.bind("SUPER + SHIFT + P", function()
|
||||||
|
hl.monitor({output = "eDP-1", disabled = false})
|
||||||
|
hl.dispatch(function() request_apply_monitor_profile() end)
|
||||||
|
end, {locked=true, description="Detect & Apply Monitor Profile"})
|
||||||
@@ -108,7 +108,7 @@ return {
|
|||||||
border_size = 3,
|
border_size = 3,
|
||||||
gaps_in = 10,
|
gaps_in = 10,
|
||||||
gaps_out = 20,
|
gaps_out = 20,
|
||||||
float_gaps = 10,
|
float_gaps = 0,
|
||||||
gaps_workspaces = 0,
|
gaps_workspaces = 0,
|
||||||
col = {
|
col = {
|
||||||
inactive_border = color_overlay0,
|
inactive_border = color_overlay0,
|
||||||
@@ -120,7 +120,7 @@ return {
|
|||||||
snap = {
|
snap = {
|
||||||
enabled = true, -- floating windows should snap to each other
|
enabled = true, -- floating windows should snap to each other
|
||||||
respect_gaps = true, -- respect gaps_in when snapping
|
respect_gaps = true, -- respect gaps_in when snapping
|
||||||
window_gap = 20, -- distance between windows before snapping
|
window_gap = 0, -- distance between windows before snapping
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
decoration = {
|
decoration = {
|
||||||
@@ -158,7 +158,7 @@ return {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
master = {
|
master = {
|
||||||
mfact = 0.65,
|
mfact = 0.6,
|
||||||
new_status = "slave",
|
new_status = "slave",
|
||||||
new_on_top = false,
|
new_on_top = false,
|
||||||
new_on_active = "none",
|
new_on_active = "none",
|
||||||
|
|||||||
@@ -217,6 +217,14 @@ rule(
|
|||||||
{ matches_class("^(org.gnome.seahorse.Application)$") },
|
{ matches_class("^(org.gnome.seahorse.Application)$") },
|
||||||
{ float(), center(), size(800, 600) }
|
{ float(), center(), size(800, 600) }
|
||||||
)
|
)
|
||||||
|
rule(
|
||||||
|
{ matches_class("^(hyprland-share-picker)$") },
|
||||||
|
{ float(), center(), pin() }
|
||||||
|
)
|
||||||
|
rule(
|
||||||
|
{ matches_class("^(gcr-prompter)$") },
|
||||||
|
{ float(), center(), pin() }
|
||||||
|
)
|
||||||
|
|
||||||
-- Nemo
|
-- Nemo
|
||||||
rule(
|
rule(
|
||||||
@@ -225,6 +233,8 @@ rule(
|
|||||||
)
|
)
|
||||||
|
|
||||||
-- Librewolf and Firefox
|
-- Librewolf and Firefox
|
||||||
|
-- FIXME: Title is evaluated only once at start of application and then never again
|
||||||
|
-- So these rules will not apply. But i have not found a fix for it yet
|
||||||
rule(
|
rule(
|
||||||
{ matches_class("^(firefox|librewolf)$"), matches_title("^(Picture-in-Picture)$") },
|
{ matches_class("^(firefox|librewolf)$"), matches_title("^(Picture-in-Picture)$") },
|
||||||
{ float() }
|
{ float() }
|
||||||
@@ -255,12 +265,12 @@ rule(
|
|||||||
{ tile() }
|
{ tile() }
|
||||||
)
|
)
|
||||||
rule(
|
rule(
|
||||||
{ matches_class("^(java-lang-Thread|net-sourceforge-jnlp-runtime-Boot)$"), matches_title("^(BÜ Zeiten|Elementname|Verspätungsmeldung.*)$") },
|
{ matches_class("^(java-lang-Thread|net-sourceforge-jnlp-runtime-Boot)$"), matches_title("^(BÜ Zeiten|Elementname)$") },
|
||||||
{ float(), pin() }
|
{ float(), pin(), no_initial_focus() }
|
||||||
)
|
)
|
||||||
rule(
|
rule(
|
||||||
{ matches_class("^(java-lang-Thread|net-sourceforge-jnlp-runtime-Boot)$"), matches_title("^(Verspätungsmeldung.*)$") },
|
{ matches_class("^(java-lang-Thread|net-sourceforge-jnlp-runtime-Boot)$"), matches_title("^(Verspätungsmeldung.*)$") },
|
||||||
{ stay_focused() }
|
{ float(), center() }
|
||||||
)
|
)
|
||||||
rule(
|
rule(
|
||||||
{ matches_title("^(.*StellwerkSim.*)$") },
|
{ matches_title("^(.*StellwerkSim.*)$") },
|
||||||
@@ -277,3 +287,14 @@ rule(
|
|||||||
{ float(), size(700, 600), center(), pin() }
|
{ float(), size(700, 600), center(), pin() }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
-- Teams
|
||||||
|
rule(
|
||||||
|
{ matches_title("^(Teams for Linux - Screen is being shared)$") },
|
||||||
|
{ float(), size(600, 300), pin() }
|
||||||
|
)
|
||||||
|
-- Jetbrains Toolbox
|
||||||
|
rule(
|
||||||
|
{ matches_initial_class("^(jetbrains-toolbox)$") },
|
||||||
|
{ float(), center(), pin() }
|
||||||
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ debug_flag = true
|
|||||||
-------------------
|
-------------------
|
||||||
function debug_notify(message)
|
function debug_notify(message)
|
||||||
if debug_flag and message ~= nil then
|
if debug_flag and message ~= nil then
|
||||||
hl.notification.create({text = message, timeout = 30000})
|
hl.notification.create({text = message, timeout = 10000})
|
||||||
hl.exec_cmd("echo '" .. message .. "' >> /tmp/hyprland-notify.log")
|
hl.exec_cmd("echo '" .. message .. "' >> /tmp/hyprland-notify.log")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -81,6 +81,25 @@ programs = {
|
|||||||
browser = "librewolf",
|
browser = "librewolf",
|
||||||
calculator = "qalculate-gtk",
|
calculator = "qalculate-gtk",
|
||||||
}
|
}
|
||||||
|
launchPrefix = "uwsm app -- "
|
||||||
|
function is_ipc_call(command)
|
||||||
|
-- check if this is an ipc call to a running programm
|
||||||
|
is_dms_ipc = starts_with(command, "dms ipc")
|
||||||
|
is_hyprctl = starts_with(command, "hyprctl")
|
||||||
|
is_ipc = any({is_dms_ipc, is_hyprctl}, function(v) return v end)
|
||||||
|
return is_ipc
|
||||||
|
end
|
||||||
|
|
||||||
|
function create_launcher(command)
|
||||||
|
if is_ipc_call(command) then
|
||||||
|
return command
|
||||||
|
end
|
||||||
|
return launchPrefix .. command
|
||||||
|
end
|
||||||
|
|
||||||
|
function execute(command)
|
||||||
|
return hl.dsp.exec_cmd(create_launcher(command))
|
||||||
|
end
|
||||||
|
|
||||||
-------------------
|
-------------------
|
||||||
---- Variables ----
|
---- Variables ----
|
||||||
@@ -118,6 +137,10 @@ require("hyprland-binds")
|
|||||||
---- WINDOW RULES ----
|
---- WINDOW RULES ----
|
||||||
----------------------
|
----------------------
|
||||||
require("hyprland-windowrules")
|
require("hyprland-windowrules")
|
||||||
|
|
||||||
|
---------------------
|
||||||
|
---- LAYER RULES ----
|
||||||
|
---------------------
|
||||||
hl.layer_rule({ match = { namespace = "^(quickshell)$" }, no_anim = true })
|
hl.layer_rule({ match = { namespace = "^(quickshell)$" }, no_anim = true })
|
||||||
hl.layer_rule({ match = { namespace = "^dms:.*" }, no_anim = true })
|
hl.layer_rule({ match = { namespace = "^dms:.*" }, no_anim = true })
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
(sleep 1 ; hyprctl eval 'request_apply_monitor_profile()') &
|
||||||
|
(sleep 2 ; hyprctl eval 'request_apply_monitor_profile()') &
|
||||||
|
(sleep 3 ; hyprctl eval 'request_apply_monitor_profile()') &
|
||||||
|
|
||||||
|
hyprctl dispatch 'hl.dsp.exec_cmd("uwsm app -- thunderbird", {workspace = 10})'
|
||||||
|
{{ if eq .work_env true -}}
|
||||||
|
# outlook
|
||||||
|
hyprctl dispatch 'hl.dsp.exec_cmd("uwsm app -- /home/frank/.local/share/applications/librewolf.webapp-e7db0a1c-02e9-42cc-a5da-8fdc222e89dc.desktop", {workspace = 9})'
|
||||||
|
{{ end -}}
|
||||||
|
hyprctl dispatch 'hl.dsp.exec_cmd("uwsm app -- nextcloud")'
|
||||||
|
sleep 3
|
||||||
|
hyprctl dispatch 'hl.dsp.exec_cmd("uwsm app -- Telegram --ozone-platform=wayland", {workspace = 10})'
|
||||||
|
hyprctl dispatch 'hl.dsp.exec_cmd("uwsm app -- signal-desktop --ozone-platform=wayland", {workspace = 10})'
|
||||||
|
{{ if eq .work_env true -}}
|
||||||
|
hyprctl dispatch 'hl.dsp.exec_cmd("uwsm app -- teams-for-linux.desktop", {workspace = 9})'
|
||||||
|
{{ end -}}
|
||||||
|
sleep 2
|
||||||
|
hyprctl dispatch 'hl.dsp.focus({workspace = 10})'
|
||||||
|
hyprctl dispatch 'hl.dsp.focus({workspace = 9})'
|
||||||
|
hyprctl dispatch 'hl.dsp.focus({workspace = 1})'
|
||||||
@@ -1177,7 +1177,7 @@ hide_window_decorations yes
|
|||||||
|
|
||||||
#: The foreground and background colors.
|
#: The foreground and background colors.
|
||||||
|
|
||||||
background_opacity 1.0
|
background_opacity 0.7
|
||||||
|
|
||||||
#: The opacity of the background. A number between zero and one, where
|
#: The opacity of the background. A number between zero and one, where
|
||||||
#: one is opaque and zero is fully transparent. This will only work if
|
#: one is opaque and zero is fully transparent. This will only work if
|
||||||
|
|||||||
@@ -1,70 +0,0 @@
|
|||||||
[Default Applications]
|
|
||||||
application/pdf=librewolf.desktop
|
|
||||||
application/rss+xml=userapp-Thunderbird-WTV1S3.desktop
|
|
||||||
application/vnd.comicbook+zip=librewolf.desktop
|
|
||||||
application/vnd.comicbook-rar=librewolf.desktop
|
|
||||||
application/x-bzpdf=librewolf.desktop
|
|
||||||
application/x-ext-pdf=librewolf.desktop
|
|
||||||
application/x-extension-ics=userapp-Thunderbird-X7G9S3.desktop
|
|
||||||
application/x-extension-rss=userapp-Thunderbird-WTV1S3.desktop
|
|
||||||
application/x-gzpdf=librewolf.desktop
|
|
||||||
image/avif=dms-open.desktop
|
|
||||||
image/bmp=dms-open.desktop
|
|
||||||
image/gif=dms-open.desktop
|
|
||||||
image/jpeg=dms-open.desktop
|
|
||||||
image/png=dms-open.desktop
|
|
||||||
image/svg+xml=dms-open.desktop
|
|
||||||
image/webp=dms-open.desktop
|
|
||||||
inode/directory=nemo.desktop
|
|
||||||
message/rfc822=userapp-Thunderbird-3QI0S3.desktop
|
|
||||||
text/calendar=userapp-Thunderbird-X7G9S3.desktop
|
|
||||||
text/html=librewolf.desktop
|
|
||||||
text/plain=nvim.desktop
|
|
||||||
x-directory/normal=nemo.desktop
|
|
||||||
x-scheme-handler/about=librewolf.desktop
|
|
||||||
x-scheme-handler/calendar=dms-open.desktop
|
|
||||||
x-scheme-handler/feed=userapp-Thunderbird-WTV1S3.desktop
|
|
||||||
x-scheme-handler/http=librewolf.desktop
|
|
||||||
x-scheme-handler/https=librewolf.desktop
|
|
||||||
x-scheme-handler/mailto=userapp-Thunderbird-3QI0S3.desktop
|
|
||||||
x-scheme-handler/mid=userapp-Thunderbird-3QI0S3.desktop
|
|
||||||
x-scheme-handler/net.thunderbird=userapp-Thunderbird-U229S3.desktop
|
|
||||||
x-scheme-handler/news=userapp-Thunderbird-AH40S3.desktop
|
|
||||||
x-scheme-handler/nntp=userapp-Thunderbird-AH40S3.desktop
|
|
||||||
x-scheme-handler/snews=userapp-Thunderbird-AH40S3.desktop
|
|
||||||
x-scheme-handler/unknown=librewolf.desktop
|
|
||||||
x-scheme-handler/webcal=userapp-Thunderbird-X7G9S3.desktop
|
|
||||||
x-scheme-handler/webcals=userapp-Thunderbird-X7G9S3.desktop
|
|
||||||
|
|
||||||
[Added Associations]
|
|
||||||
application/pdf=librewolf.desktop;
|
|
||||||
application/rss+xml=userapp-Thunderbird-WTV1S3.desktop;
|
|
||||||
application/vnd.comicbook+zip=librewolf.desktop;
|
|
||||||
application/vnd.comicbook-rar=librewolf.desktop;
|
|
||||||
application/x-bzpdf=librewolf.desktop;
|
|
||||||
application/x-ext-pdf=librewolf.desktop;
|
|
||||||
application/x-extension-ics=userapp-Thunderbird-X7G9S3.desktop;
|
|
||||||
application/x-extension-rss=userapp-Thunderbird-WTV1S3.desktop;
|
|
||||||
application/x-gzpdf=librewolf.desktop;
|
|
||||||
image/avif=dms-open.desktop;
|
|
||||||
image/bmp=dms-open.desktop;
|
|
||||||
image/gif=dms-open.desktop;
|
|
||||||
image/jpeg=dms-open.desktop;
|
|
||||||
image/png=dms-open.desktop;
|
|
||||||
image/svg+xml=dms-open.desktop;
|
|
||||||
image/webp=dms-open.desktop;
|
|
||||||
message/rfc822=userapp-Thunderbird-3QI0S3.desktop;
|
|
||||||
text/calendar=userapp-Thunderbird-X7G9S3.desktop;
|
|
||||||
x-scheme-handler/calendar=dms-open.desktop;
|
|
||||||
x-scheme-handler/feed=userapp-Thunderbird-WTV1S3.desktop;
|
|
||||||
x-scheme-handler/mailto=userapp-Thunderbird-3QI0S3.desktop;
|
|
||||||
x-scheme-handler/mid=userapp-Thunderbird-3QI0S3.desktop;
|
|
||||||
x-scheme-handler/net.thunderbird=userapp-Thunderbird-U229S3.desktop;
|
|
||||||
x-scheme-handler/news=userapp-Thunderbird-AH40S3.desktop;
|
|
||||||
x-scheme-handler/nntp=userapp-Thunderbird-AH40S3.desktop;
|
|
||||||
x-scheme-handler/snews=userapp-Thunderbird-AH40S3.desktop;
|
|
||||||
x-scheme-handler/webcal=userapp-Thunderbird-X7G9S3.desktop;
|
|
||||||
x-scheme-handler/webcals=userapp-Thunderbird-X7G9S3.desktop;
|
|
||||||
|
|
||||||
[Removed Associations]
|
|
||||||
|
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
{{- $rss := "x" -}}
|
||||||
|
{{- $cal := "x" -}}
|
||||||
|
{{- $mail := "x" -}}
|
||||||
|
{{- $tb := "x" -}}
|
||||||
|
{{- $news := "x" -}}
|
||||||
|
{{- if eq .chezmoi.hostname "arch-next" -}}
|
||||||
|
{{- $rss = "userapp-Thunderbird-Y886T3.desktop" -}}
|
||||||
|
{{- $cal = "userapp-Thunderbird-NA25T3.desktop" -}}
|
||||||
|
{{- $mail = "userapp-Thunderbird-Q3N5T3.desktop" -}}
|
||||||
|
{{- $tb = "userapp-Thunderbird-SIG6T3.desktop" -}}
|
||||||
|
{{- $news = "userapp-Thunderbird-A0Q6T3.desktop" -}}
|
||||||
|
{{- else if eq .chezmoi.hostname "ia-frank-xps13" -}}
|
||||||
|
{{- $rss = "userapp-Thunderbird-WTV1S3.desktop" -}}
|
||||||
|
{{- $cal = "userapp-Thunderbird-X7G9S3.desktop" -}}
|
||||||
|
{{- $mail = "userapp-Thunderbird-3QI0S3.desktop" -}}
|
||||||
|
{{- $tb = "userapp-Thunderbird-U229S3.desktop" -}}
|
||||||
|
{{- $news = "userapp-Thunderbird-AH40S3.desktop" -}}
|
||||||
|
{{- end -}}
|
||||||
|
[Default Applications]
|
||||||
|
application/pdf=librewolf.desktop
|
||||||
|
application/rss+xml={{ $rss }}
|
||||||
|
application/vnd.comicbook+zip=librewolf.desktop
|
||||||
|
application/vnd.comicbook-rar=librewolf.desktop
|
||||||
|
application/x-bzpdf=librewolf.desktop
|
||||||
|
application/x-ext-pdf=librewolf.desktop
|
||||||
|
application/x-extension-ics={{ $cal}}
|
||||||
|
application/x-extension-rss={{ $rss }}
|
||||||
|
application/x-gzpdf=librewolf.desktop
|
||||||
|
image/avif=dms-open.desktop
|
||||||
|
image/bmp=dms-open.desktop
|
||||||
|
image/gif=dms-open.desktop
|
||||||
|
image/jpeg=dms-open.desktop
|
||||||
|
image/png=dms-open.desktop
|
||||||
|
image/svg+xml=dms-open.desktop
|
||||||
|
image/webp=dms-open.desktop
|
||||||
|
inode/directory=nemo.desktop
|
||||||
|
message/rfc822={{ $mail }}
|
||||||
|
text/calendar={{ $cal }}
|
||||||
|
text/html=librewolf.desktop
|
||||||
|
text/plain=nvim.desktop
|
||||||
|
x-directory/normal=nemo.desktop
|
||||||
|
x-scheme-handler/about=librewolf.desktop
|
||||||
|
x-scheme-handler/calendar=dms-open.desktop
|
||||||
|
x-scheme-handler/feed={{ $rss }}
|
||||||
|
x-scheme-handler/http=librewolf.desktop
|
||||||
|
x-scheme-handler/https=librewolf.desktop
|
||||||
|
x-scheme-handler/mailto={{ $mail }}
|
||||||
|
x-scheme-handler/mid={{ $mail }}
|
||||||
|
x-scheme-handler/net.thunderbird={{ $tb }}
|
||||||
|
x-scheme-handler/news={{ $news }}
|
||||||
|
x-scheme-handler/nntp={{ $news }}
|
||||||
|
x-scheme-handler/snews={{ $news }}
|
||||||
|
x-scheme-handler/unknown=librewolf.desktop
|
||||||
|
x-scheme-handler/webcal={{ $cal }}
|
||||||
|
x-scheme-handler/webcals={{ $cal }}
|
||||||
|
x-scheme-handler/claude=claude-desktop.desktop
|
||||||
|
x-scheme-handler/jetbrains=jetbrainsd.desktop
|
||||||
|
x-scheme-handler/claude-cli=claude-code-url-handler.desktop
|
||||||
|
application/xhtml+xml=librewolf.desktop
|
||||||
|
x-scheme-handler/bruno=bruno.desktop
|
||||||
|
|
||||||
|
[Added Associations]
|
||||||
|
application/pdf=librewolf.desktop;
|
||||||
|
application/rss+xml={{ $rss }};
|
||||||
|
application/vnd.comicbook+zip=librewolf.desktop;
|
||||||
|
application/vnd.comicbook-rar=librewolf.desktop;
|
||||||
|
application/x-bzpdf=librewolf.desktop;
|
||||||
|
application/x-ext-pdf=librewolf.desktop;
|
||||||
|
application/x-extension-ics={{ $cal }};
|
||||||
|
application/x-extension-rss={{ $rss }};
|
||||||
|
application/x-gzpdf=librewolf.desktop;
|
||||||
|
image/avif=dms-open.desktop;
|
||||||
|
image/bmp=dms-open.desktop;
|
||||||
|
image/gif=dms-open.desktop;
|
||||||
|
image/jpeg=dms-open.desktop;
|
||||||
|
image/png=dms-open.desktop;
|
||||||
|
image/svg+xml=dms-open.desktop;
|
||||||
|
image/webp=dms-open.desktop;
|
||||||
|
message/rfc822={{ $mail }};
|
||||||
|
text/calendar={{ $cal }};
|
||||||
|
x-scheme-handler/calendar=dms-open.desktop;
|
||||||
|
x-scheme-handler/feed={{ $rss }};
|
||||||
|
x-scheme-handler/mailto={{ $mail }};
|
||||||
|
x-scheme-handler/mid={{ $mail }};
|
||||||
|
x-scheme-handler/net.thunderbird={{ $tb }};
|
||||||
|
x-scheme-handler/news={{ $news }};
|
||||||
|
x-scheme-handler/nntp={{ $news }};
|
||||||
|
x-scheme-handler/snews={{ $news }};
|
||||||
|
x-scheme-handler/webcal={{ $cal }};
|
||||||
|
x-scheme-handler/webcals={{ $cal }};
|
||||||
|
application/xhtml+xml=librewolf.desktop;
|
||||||
|
|
||||||
|
[Removed Associations]
|
||||||
@@ -0,0 +1,155 @@
|
|||||||
|
General usage
|
||||||
|
=============
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
mpv infile --o=outfile [--of=outfileformat] [--ofopts=formatoptions] [--orawts] \
|
||||||
|
[(any other mpv options)] \
|
||||||
|
--ovc=outvideocodec [--ovcopts=outvideocodecoptions] \
|
||||||
|
--oac=outaudiocodec [--oacopts=outaudiocodecoptions]
|
||||||
|
|
||||||
|
Help for these options is provided if giving help as parameter, as in::
|
||||||
|
|
||||||
|
mpv --ovc=help
|
||||||
|
|
||||||
|
The suboptions of these generally are identical to ffmpeg's (as option parsing
|
||||||
|
is simply delegated to ffmpeg). The option --ocopyts enables copying timestamps
|
||||||
|
from the source as-is, instead of fixing them to match audio playback time
|
||||||
|
(note: this doesn't work with all output container formats); --orawts even turns
|
||||||
|
off discontinuity fixing.
|
||||||
|
|
||||||
|
Note that if neither --ofps nor --oautofps is specified, VFR encoding is assumed
|
||||||
|
and the time base is 24000fps. --oautofps sets --ofps to a guessed fps number
|
||||||
|
from the input video. Note that not all codecs and not all formats support VFR
|
||||||
|
encoding, and some which do have bugs when a target bitrate is specified - use
|
||||||
|
--ofps or --oautofps to force CFR encoding in these cases.
|
||||||
|
|
||||||
|
Of course, the options can be stored in a profile, like this .config/mpv/mpv.conf
|
||||||
|
section::
|
||||||
|
|
||||||
|
[myencprofile]
|
||||||
|
vf-add = scale=480:-2
|
||||||
|
ovc = libx264
|
||||||
|
ovcopts-add = preset=medium
|
||||||
|
ovcopts-add = tune=fastdecode
|
||||||
|
ovcopts-add = crf=23
|
||||||
|
ovcopts-add = maxrate=1500k
|
||||||
|
ovcopts-add = bufsize=1000k
|
||||||
|
ovcopts-add = rc_init_occupancy=900k
|
||||||
|
ovcopts-add = refs=2
|
||||||
|
ovcopts-add = profile=baseline
|
||||||
|
oac = aac
|
||||||
|
oacopts-add = b=96k
|
||||||
|
|
||||||
|
It's also possible to define default encoding options by putting them into
|
||||||
|
the section named ``[encoding]``. (This behavior changed after mpv 0.3.x. In
|
||||||
|
mpv 0.3.x, config options in the default section / no section were applied
|
||||||
|
to encoding. This is not the case anymore.)
|
||||||
|
|
||||||
|
One can then encode using this profile using the command::
|
||||||
|
|
||||||
|
mpv infile --o=outfile.mp4 --profile=myencprofile
|
||||||
|
|
||||||
|
Some example profiles are provided in a file
|
||||||
|
etc/encoding-profiles.conf; as for this, see below.
|
||||||
|
|
||||||
|
|
||||||
|
Encoding examples
|
||||||
|
=================
|
||||||
|
|
||||||
|
These are some examples of encoding targets this code has been used and tested
|
||||||
|
for.
|
||||||
|
|
||||||
|
Typical MPEG-4 Part 2 ("ASP", "DivX") encoding, AVI container::
|
||||||
|
|
||||||
|
mpv infile --o=outfile.avi \
|
||||||
|
--vf=fps=25 \
|
||||||
|
--ovc=mpeg4 --ovcopts=qscale=4 \
|
||||||
|
--oac=libmp3lame --oacopts=b=128k
|
||||||
|
|
||||||
|
Note: AVI does not support variable frame rate, so the fps filter must be used.
|
||||||
|
The frame rate should ideally match the input (25 for PAL, 24000/1001 or
|
||||||
|
30000/1001 for NTSC)
|
||||||
|
|
||||||
|
Typical MPEG-4 Part 10 ("AVC", "H.264") encoding, Matroska (MKV) container::
|
||||||
|
|
||||||
|
mpv infile --o=outfile.mkv \
|
||||||
|
--ovc=libx264 --ovcopts=preset=medium,crf=23,profile=baseline \
|
||||||
|
--oac=libopus --oacopts=qscale=3
|
||||||
|
|
||||||
|
Typical MPEG-4 Part 10 ("AVC", "H.264") encoding, MPEG-4 (MP4) container::
|
||||||
|
|
||||||
|
mpv infile --o=outfile.mp4 \
|
||||||
|
--ovc=libx264 --ovcopts=preset=medium,crf=23,profile=baseline \
|
||||||
|
--oac=aac --oacopts=b=128k
|
||||||
|
|
||||||
|
Typical VP8 encoding, WebM (restricted Matroska) container::
|
||||||
|
|
||||||
|
mpv infile -o outfile.mkv \
|
||||||
|
--of=webm \
|
||||||
|
--ovc=libvpx --ovcopts=qmin=6,b=1000000k \
|
||||||
|
--oac=libopus --oacopts=qscale=3
|
||||||
|
|
||||||
|
|
||||||
|
Device targets
|
||||||
|
==============
|
||||||
|
|
||||||
|
As the options for various devices can get complex, profiles can be used.
|
||||||
|
|
||||||
|
An example profile file for encoding is provided in
|
||||||
|
etc/encoding-profiles.conf in the source tree. This file is installed and loaded
|
||||||
|
by default. If you want to modify it, you can replace and it with your own copy
|
||||||
|
by doing::
|
||||||
|
|
||||||
|
mkdir -p ~/.mpv
|
||||||
|
cp /etc/mpv/encoding-profiles.conf ~/.mpv/encoding-profiles.conf
|
||||||
|
|
||||||
|
Keep in mind that the default profile is the playback one. If you want to add
|
||||||
|
options that apply only in encoding mode, put them into a ``[encoding]``
|
||||||
|
section.
|
||||||
|
|
||||||
|
Refer to the top of that file for more comments - in a nutshell, the following
|
||||||
|
options are added by it::
|
||||||
|
|
||||||
|
--profile=enc-to-dvdpal # DVD-Video PAL, use dvdauthor -v pal+4:3 -a ac3+en
|
||||||
|
--profile=enc-to-dvdntsc # DVD-Video NTSC, use dvdauthor -v ntsc+4:3 -a ac3+en
|
||||||
|
--profile=enc-to-bb-9000 # MP4 for Blackberry Bold 9000
|
||||||
|
--profile=enc-to-nok-6300 # 3GP for Nokia 6300
|
||||||
|
--profile=enc-to-psp # MP4 for PlayStation Portable
|
||||||
|
--profile=enc-to-iphone # MP4 for iPhone
|
||||||
|
--profile=enc-to-iphone-4 # MP4 for iPhone 4 (double res)
|
||||||
|
--profile=enc-to-iphone-5 # MP4 for iPhone 5 (even larger res)
|
||||||
|
|
||||||
|
You can encode using these with a command line like::
|
||||||
|
|
||||||
|
mpv infile --o=outfile.mp4 --profile=enc-to-bb-9000
|
||||||
|
|
||||||
|
Of course, you are free to override options set by these profiles by specifying
|
||||||
|
them after the -profile option.
|
||||||
|
|
||||||
|
|
||||||
|
What works
|
||||||
|
==========
|
||||||
|
|
||||||
|
* Encoding at variable frame rate (default)
|
||||||
|
* Encoding at constant frame rate using --vf=fps=RATE
|
||||||
|
* 2-pass encoding (specify flags=+pass1 in the first pass's --ovcopts, specify
|
||||||
|
flags=+pass2 in the second pass)
|
||||||
|
* Hardcoding subtitles using vobsub, ass or srt subtitle rendering (just
|
||||||
|
configure mpv for the subtitles as usual)
|
||||||
|
* Hardcoding any other mpv OSD (e.g. time codes, using --osdlevel=3 and
|
||||||
|
--vf=expand=::::1)
|
||||||
|
* Encoding directly from a DVD, network stream, webcam, or any other source
|
||||||
|
mpv supports
|
||||||
|
* Using x264 presets/tunings/profiles (by using profile=, tune=, preset= in the
|
||||||
|
--ovcopts)
|
||||||
|
* Deinterlacing/Inverse Telecine with any of mpv's filters for that
|
||||||
|
* Audio file converting: mpv --o=outfile.m4a infile.flac --no-video
|
||||||
|
--oac=aac --oacopts=b=320k
|
||||||
|
|
||||||
|
What does not work yet
|
||||||
|
======================
|
||||||
|
|
||||||
|
* 3-pass encoding (ensuring constant total size and bitrate constraints while
|
||||||
|
having VBR audio; mencoder calls this "frameno")
|
||||||
|
* Direct stream copy
|
||||||
@@ -0,0 +1,246 @@
|
|||||||
|
# mpv keybindings
|
||||||
|
#
|
||||||
|
# Location of user-defined bindings: ~/.config/mpv/input.conf
|
||||||
|
#
|
||||||
|
# Lines starting with # are comments. Use SHARP to assign the # key.
|
||||||
|
# Copy this file and uncomment and edit the bindings you want to change.
|
||||||
|
#
|
||||||
|
# List of commands and further details: DOCS/man/input.rst
|
||||||
|
# List of special keys: --input-keylist
|
||||||
|
# Keybindings testing mode: mpv --input-test --force-window --idle
|
||||||
|
#
|
||||||
|
# Use 'ignore' to unbind a key fully (e.g. 'ctrl+a ignore').
|
||||||
|
#
|
||||||
|
# Strings need to be quoted and escaped:
|
||||||
|
# KEY show-text "This is a single backslash: \\ and a quote: \" !"
|
||||||
|
#
|
||||||
|
# You can use modifier-key combinations like Shift+Left or Ctrl+Alt+x with
|
||||||
|
# the modifiers Shift, Ctrl, Alt and Meta (may not work on the terminal).
|
||||||
|
#
|
||||||
|
# The default keybindings are hardcoded into the mpv binary.
|
||||||
|
# You can disable them completely with: --no-input-default-bindings
|
||||||
|
|
||||||
|
# Developer note:
|
||||||
|
# On compilation, this file is baked into the mpv binary, and all lines are
|
||||||
|
# uncommented (unless '#' is followed by a space) - thus this file defines the
|
||||||
|
# default key bindings.
|
||||||
|
|
||||||
|
# If this is enabled, treat all the following bindings as default.
|
||||||
|
#default-bindings start
|
||||||
|
|
||||||
|
#MBTN_LEFT ignore # don't do anything
|
||||||
|
#MBTN_LEFT_DBL cycle fullscreen # toggle fullscreen
|
||||||
|
#MBTN_RIGHT cycle pause # toggle pause/playback mode
|
||||||
|
#MBTN_BACK playlist-prev # skip to the previous file
|
||||||
|
#MBTN_FORWARD playlist-next # skip to the next file
|
||||||
|
#Ctrl+MBTN_LEFT script-binding positioning/drag-to-pan # pan around the clicked point
|
||||||
|
|
||||||
|
# Mouse wheels, touchpad or other input devices that have axes
|
||||||
|
# if the input devices supports precise scrolling it will also scale the
|
||||||
|
# numeric value accordingly
|
||||||
|
#WHEEL_UP add volume 2
|
||||||
|
#WHEEL_DOWN add volume -2
|
||||||
|
#WHEEL_LEFT seek -10 # seek 10 seconds backward
|
||||||
|
#WHEEL_RIGHT seek 10 # seek 10 seconds forward
|
||||||
|
|
||||||
|
## Seek units are in seconds, but note that these are limited by keyframes
|
||||||
|
#RIGHT seek 5 # seek 5 seconds forward
|
||||||
|
#LEFT seek -5 # seek 5 seconds backward
|
||||||
|
#UP seek 60 # seek 1 minute forward
|
||||||
|
#DOWN seek -60 # seek 1 minute backward
|
||||||
|
# Do smaller, always exact (non-keyframe-limited), seeks with shift.
|
||||||
|
# Don't show them on the OSD (no-osd).
|
||||||
|
#Shift+RIGHT no-osd seek 1 exact # seek exactly 1 second forward
|
||||||
|
#Shift+LEFT no-osd seek -1 exact # seek exactly 1 second backward
|
||||||
|
#Shift+UP no-osd seek 5 exact # seek exactly 5 seconds forward
|
||||||
|
#Shift+DOWN no-osd seek -5 exact # seek exactly 5 seconds backward
|
||||||
|
#Ctrl+LEFT no-osd sub-seek -1 # seek to the previous subtitle
|
||||||
|
#Ctrl+RIGHT no-osd sub-seek 1 # seek to the next subtitle
|
||||||
|
#Ctrl+Shift+LEFT sub-step -1 # change subtitle timing such that the previous subtitle is displayed
|
||||||
|
#Ctrl+Shift+RIGHT sub-step 1 # change subtitle timing such that the next subtitle is displayed
|
||||||
|
#Alt+left add video-pan-x 0.1 # move the video right
|
||||||
|
#Alt+right add video-pan-x -0.1 # move the video left
|
||||||
|
#Alt+up add video-pan-y 0.1 # move the video down
|
||||||
|
#Alt+down add video-pan-y -0.1 # move the video up
|
||||||
|
#Alt++ add video-zoom 0.1 # zoom in
|
||||||
|
#ZOOMIN add video-zoom 0.1 # zoom in
|
||||||
|
#Alt+- add video-zoom -0.1 # zoom out
|
||||||
|
#ZOOMOUT add video-zoom -0.1 # zoom out
|
||||||
|
#Alt+KP_ADD add video-zoom 0.1 # zoom in
|
||||||
|
#Alt+KP_SUBTRACT add video-zoom -0.1 # zoom out
|
||||||
|
#Ctrl+WHEEL_UP script-binding positioning/cursor-centric-zoom 0.1 # zoom in towards the cursor
|
||||||
|
#Ctrl+WHEEL_DOWN script-binding positioning/cursor-centric-zoom -0.1 # zoom out towards the cursor
|
||||||
|
#Alt+BS set video-zoom 0; no-osd set panscan 0; no-osd set video-pan-x 0; no-osd set video-pan-y 0; no-osd set video-align-x 0; no-osd set video-align-y 0 # reset zoom and pan settings
|
||||||
|
#HOME seek 0 absolute # seek to the start
|
||||||
|
#PGUP add chapter 1 # seek to the next chapter
|
||||||
|
#PGDWN add chapter -1 # seek to the previous chapter
|
||||||
|
#Shift+PGUP seek 600 # seek 10 minutes forward
|
||||||
|
#Shift+PGDWN seek -600 # seek 10 minutes backward
|
||||||
|
#[ multiply speed 1/1.1 # decrease the playback speed
|
||||||
|
#] multiply speed 1.1 # increase the playback speed
|
||||||
|
#{ multiply speed 0.5 # halve the playback speed
|
||||||
|
#} multiply speed 2.0 # double the playback speed
|
||||||
|
#BS set speed 1.0 # reset the speed to normal
|
||||||
|
#Shift+BS revert-seek # undo the previous (or marked) seek
|
||||||
|
#Shift+Ctrl+BS revert-seek mark # mark the position for revert-seek
|
||||||
|
#q quit
|
||||||
|
#Q quit-watch-later # exit and remember the playback position
|
||||||
|
#q {encode} quit 4
|
||||||
|
#ESC set fullscreen no # leave fullscreen
|
||||||
|
#ESC {encode} quit 4
|
||||||
|
#p cycle pause # toggle pause/playback mode
|
||||||
|
#. frame-step # advance one frame and pause
|
||||||
|
#, frame-back-step # go back by one frame and pause
|
||||||
|
#SPACE cycle pause # toggle pause/playback mode
|
||||||
|
#> playlist-next # skip to the next file
|
||||||
|
#ENTER playlist-next # skip to the next file
|
||||||
|
#< playlist-prev # skip to the previous file
|
||||||
|
#Shift+HOME no-osd set playlist-pos 0 # skip to the first file
|
||||||
|
#Shift+END no-osd set playlist-pos-1 ${playlist-count} # skip to the last file
|
||||||
|
#O no-osd cycle-values osd-level 3 1 # toggle displaying the OSD on user interaction or always
|
||||||
|
#o show-progress # show playback progress
|
||||||
|
#P show-progress # show playback progress
|
||||||
|
#i script-binding stats/display-stats # display information and statistics
|
||||||
|
#I script-binding stats/display-stats-toggle # toggle displaying information and statistics
|
||||||
|
#? script-binding stats/display-page-4-toggle # toggle displaying key bindings
|
||||||
|
#` script-binding commands/open # open the console
|
||||||
|
#z add sub-delay -0.1 # shift subtitles 100 ms earlier
|
||||||
|
#Z add sub-delay +0.1 # delay subtitles by 100 ms
|
||||||
|
#x add sub-delay +0.1 # delay subtitles by 100 ms
|
||||||
|
#ctrl++ add audio-delay 0.100 # change audio/video sync by delaying the audio
|
||||||
|
#ctrl+- add audio-delay -0.100 # change audio/video sync by shifting the audio earlier
|
||||||
|
#ctrl+KP_ADD add audio-delay 0.100 # change audio/video sync by delaying the audio
|
||||||
|
#ctrl+KP_SUBTRACT add audio-delay -0.100 # change audio/video sync by shifting the audio earlier
|
||||||
|
#G add sub-scale +0.1 # increase the subtitle font size
|
||||||
|
#F add sub-scale -0.1 # decrease the subtitle font size
|
||||||
|
#9 add volume -2
|
||||||
|
#/ add volume -2
|
||||||
|
#KP_DIVIDE add volume -2
|
||||||
|
#0 add volume 2
|
||||||
|
#* add volume 2
|
||||||
|
#KP_MULTIPLY add volume 2
|
||||||
|
#m cycle mute # toggle mute
|
||||||
|
#1 add contrast -1
|
||||||
|
#2 add contrast 1
|
||||||
|
#3 add brightness -1
|
||||||
|
#4 add brightness 1
|
||||||
|
#5 add gamma -1
|
||||||
|
#6 add gamma 1
|
||||||
|
#7 add saturation -1
|
||||||
|
#8 add saturation 1
|
||||||
|
#Alt+0 set window-scale 0.5 # halve the window size
|
||||||
|
#Alt+1 set window-scale 1.0 # reset the window size
|
||||||
|
#Alt+2 set window-scale 2.0 # double the window size
|
||||||
|
#b cycle deband # toggle the debanding filter
|
||||||
|
#d cycle deinterlace # cycle the deinterlacing filter
|
||||||
|
#r add sub-pos -1 # move subtitles up
|
||||||
|
#R add sub-pos +1 # move subtitles down
|
||||||
|
#t add sub-pos +1 # move subtitles down
|
||||||
|
#v cycle sub-visibility # hide or show the subtitles
|
||||||
|
#Alt+v cycle secondary-sub-visibility # hide or show the secondary subtitles
|
||||||
|
#V cycle sub-ass-use-video-data # cycle which video data gets used in ASS rendering to fix broken files
|
||||||
|
#u cycle-values sub-ass-override "force" "scale" # toggle overriding SSA/ASS subtitle styles with the normal styles
|
||||||
|
#j cycle sub # switch subtitle track
|
||||||
|
#J cycle sub down # switch subtitle track backwards
|
||||||
|
#SHARP cycle audio # switch audio track
|
||||||
|
#_ cycle video # switch video track
|
||||||
|
#T cycle ontop # toggle placing the video on top of other windows
|
||||||
|
#f cycle fullscreen # toggle fullscreen
|
||||||
|
#s screenshot # take a screenshot of the video in its original resolution with subtitles
|
||||||
|
#S screenshot video # take a screenshot of the video in its original resolution without subtitles
|
||||||
|
#Ctrl+s screenshot window # take a screenshot of the window with OSD and subtitles
|
||||||
|
#Alt+s screenshot each-frame # automatically screenshot every frame; issue this command again to stop taking screenshots
|
||||||
|
#w add panscan -0.1 # decrease panscan
|
||||||
|
#W add panscan +0.1 # shrink black bars by cropping the video
|
||||||
|
#e add panscan +0.1 # shrink black bars by cropping the video
|
||||||
|
#A cycle-values video-aspect-override "16:9" "4:3" "2.35:1" "no" # cycle the video aspect ratio
|
||||||
|
#POWER quit
|
||||||
|
#PLAY cycle pause # toggle pause/playback mode
|
||||||
|
#PAUSE cycle pause # toggle pause/playback mode
|
||||||
|
#PLAYPAUSE cycle pause # toggle pause/playback mode
|
||||||
|
#PLAYONLY set pause no # unpause
|
||||||
|
#PAUSEONLY set pause yes # pause
|
||||||
|
#STOP quit
|
||||||
|
#FORWARD seek 60 # seek 1 minute forward
|
||||||
|
#REWIND seek -60 # seek 1 minute backward
|
||||||
|
#NEXT playlist-next # skip to the next file
|
||||||
|
#PREV playlist-prev # skip to the previous file
|
||||||
|
#VOLUME_UP add volume 2
|
||||||
|
#VOLUME_DOWN add volume -2
|
||||||
|
#MUTE cycle mute # toggle mute
|
||||||
|
#CLOSE_WIN quit
|
||||||
|
#CLOSE_WIN {encode} quit 4
|
||||||
|
#ctrl+w quit
|
||||||
|
#E cycle edition # switch edition
|
||||||
|
#l ab-loop # set/clear A-B loop points
|
||||||
|
#L cycle-values loop-file "inf" "no" # toggle infinite looping
|
||||||
|
#ctrl+c quit 4
|
||||||
|
#Ctrl+v loadfile ${clipboard/text} append-play; show-text '+ ${clipboard/text}' # append the copied path
|
||||||
|
#DEL script-binding osc/visibility # cycle OSC visibility between never, auto (mouse-move) and always
|
||||||
|
#ctrl+h cycle-values hwdec "no" "auto" # toggle hardware decoding
|
||||||
|
#F8 show-text ${playlist} # show the playlist
|
||||||
|
#F9 show-text ${track-list} # show the list of video, audio and sub tracks
|
||||||
|
#g ignore
|
||||||
|
#g-p script-binding select/select-playlist
|
||||||
|
#g-s script-binding select/select-sid
|
||||||
|
#g-S script-binding select/select-secondary-sid
|
||||||
|
#g-a script-binding select/select-aid
|
||||||
|
#g-v script-binding select/select-vid
|
||||||
|
#g-t script-binding select/select-track
|
||||||
|
#g-c script-binding select/select-chapter
|
||||||
|
#g-e script-binding select/select-edition
|
||||||
|
#g-l script-binding select/select-subtitle-line
|
||||||
|
#g-d script-binding select/select-audio-device
|
||||||
|
#g-h script-binding select/select-watch-history
|
||||||
|
#g-w script-binding select/select-watch-later
|
||||||
|
#g-b script-binding select/select-binding
|
||||||
|
#g-r script-binding select/show-properties
|
||||||
|
#g-m script-binding select/menu
|
||||||
|
#MENU script-binding select/menu
|
||||||
|
#ctrl+p script-binding select/menu
|
||||||
|
|
||||||
|
#Alt+KP1 add video-rotate -1 # rotate video counterclockwise by 1 degree
|
||||||
|
#Alt+KP5 set video-rotate 0 # reset rotation
|
||||||
|
#Alt+KP3 add video-rotate 1 # rotate video clockwise by 1 degree
|
||||||
|
|
||||||
|
#KP1 add video-zoom -0.01 # zoom out video
|
||||||
|
#KP2 add video-scale-y -0.01 # scale down video vertically
|
||||||
|
#KP4 add video-scale-x -0.01 # scale down video horizontally
|
||||||
|
#KP5 set video-scale-x 1.00; set video-scale-y 1; set video-zoom 0 # reset video scale
|
||||||
|
#KP6 add video-scale-x 0.01 # scale up video horizontally
|
||||||
|
#KP8 add video-scale-y 0.01 # scale up video vertically
|
||||||
|
#KP9 add video-zoom 0.01 # zoom in video
|
||||||
|
|
||||||
|
#Ctrl+KP1 add video-pan-x -0.01; add video-pan-y 0.01 # move video left and down
|
||||||
|
#Ctrl+KP2 add video-pan-y 0.01 # move video down
|
||||||
|
#Ctrl+KP3 add video-pan-x 0.01; add video-pan-y 0.01 # move video right and down
|
||||||
|
#Ctrl+KP4 add video-pan-x -0.01 # move video left
|
||||||
|
#Ctrl+KP5 set video-pan-x 0.00; set video-pan-y 0.00 # reset video position
|
||||||
|
#Ctrl+KP6 add video-pan-x 0.01 # move video right
|
||||||
|
#Ctrl+KP7 add video-pan-x -0.01; add video-pan-y -0.01 # move video left and up
|
||||||
|
#Ctrl+KP8 add video-pan-y -0.01 # move video up
|
||||||
|
#Ctrl+KP9 add video-pan-x 0.01; add video-pan-y -0.01 # move video right and up
|
||||||
|
|
||||||
|
#Ctrl+KP_END add video-align-x -0.01; add video-align-y 0.01 # align video left and down
|
||||||
|
#Ctrl+KP_DOWN add video-align-y 0.01 # align video down
|
||||||
|
#Ctrl+KP_PGDWN add video-align-x 0.01; add video-align-y 0.01 # align video right and down
|
||||||
|
#Ctrl+KP_LEFT add video-align-x -0.01 # align video left
|
||||||
|
#Ctrl+KP_BEGIN set video-align-x 0.00; set video-align-y 0.00 # reset video alignment
|
||||||
|
#Ctrl+KP_RIGHT add video-align-x 0.01 # align video right
|
||||||
|
#Ctrl+KP_HOME add video-align-x -0.01; add video-align-y -0.01 # align video left and up
|
||||||
|
#Ctrl+KP_UP add video-align-y -0.01 # align video up
|
||||||
|
#Ctrl+KP_PGUP add video-align-x 0.01; add video-align-y -0.01 # align video right and up
|
||||||
|
|
||||||
|
#
|
||||||
|
# Legacy bindings (may or may not be removed in the future)
|
||||||
|
#
|
||||||
|
#! add chapter -1 # seek to the previous chapter
|
||||||
|
#@ add chapter 1 # seek to the next chapter
|
||||||
|
|
||||||
|
#
|
||||||
|
# Not assigned by default
|
||||||
|
# (not an exhaustive list of unbound commands)
|
||||||
|
#
|
||||||
|
|
||||||
|
# ? cycle sub-forced-events-only # display only DVD/PGS forced subtitle events
|
||||||
|
# ? stop # stop playback (quit or enter idle mode)
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
##
|
||||||
|
## MPlayer-style key bindings
|
||||||
|
##
|
||||||
|
## Save it as ~/.config/mpv/input.conf to use it.
|
||||||
|
##
|
||||||
|
## Generally, it's recommended to use this as reference-only.
|
||||||
|
##
|
||||||
|
|
||||||
|
RIGHT seek +10
|
||||||
|
LEFT seek -10
|
||||||
|
DOWN seek -60
|
||||||
|
UP seek +60
|
||||||
|
PGUP seek 600
|
||||||
|
PGDWN seek -600
|
||||||
|
m cycle mute
|
||||||
|
SHARP cycle audio # switch audio streams
|
||||||
|
+ add audio-delay 0.100
|
||||||
|
= add audio-delay 0.100
|
||||||
|
- add audio-delay -0.100
|
||||||
|
[ multiply speed 0.9091 # scale playback speed
|
||||||
|
] multiply speed 1.1
|
||||||
|
{ multiply speed 0.5
|
||||||
|
} multiply speed 2.0
|
||||||
|
BS set speed 1.0 # reset speed to normal
|
||||||
|
q quit
|
||||||
|
ESC quit
|
||||||
|
ENTER playlist-next force # skip to next file
|
||||||
|
p cycle pause
|
||||||
|
. frame-step # advance one frame and pause
|
||||||
|
SPACE cycle pause
|
||||||
|
HOME set playlist-pos 0 # not the same as MPlayer
|
||||||
|
#END pt_up_step -1
|
||||||
|
> playlist-next # skip to next file
|
||||||
|
< playlist-prev # previous
|
||||||
|
#INS alt_src_step 1
|
||||||
|
#DEL alt_src_step -1
|
||||||
|
o osd
|
||||||
|
I show-text "${filename}" # display filename in osd
|
||||||
|
P show-progress
|
||||||
|
z add sub-delay -0.1 # subtract 100 ms delay from subs
|
||||||
|
x add sub-delay +0.1 # add
|
||||||
|
9 add volume -1
|
||||||
|
/ add volume -1
|
||||||
|
0 add volume 1
|
||||||
|
* add volume 1
|
||||||
|
1 add contrast -1
|
||||||
|
2 add contrast 1
|
||||||
|
3 add brightness -1
|
||||||
|
4 add brightness 1
|
||||||
|
5 add hue -1
|
||||||
|
6 add hue 1
|
||||||
|
7 add saturation -1
|
||||||
|
8 add saturation 1
|
||||||
|
( add balance -0.1 # adjust audio balance in favor of left
|
||||||
|
) add balance +0.1 # right
|
||||||
|
d cycle framedrop
|
||||||
|
D cycle deinterlace # toggle deinterlacer (auto-inserted filter)
|
||||||
|
r add sub-pos -1 # move subtitles up
|
||||||
|
t add sub-pos +1 # down
|
||||||
|
#? sub-step +1 # immediately display next subtitle
|
||||||
|
#? sub-step -1 # previous
|
||||||
|
#? add sub-scale +0.1 # increase subtitle font size
|
||||||
|
#? add sub-scale -0.1 # decrease subtitle font size
|
||||||
|
f cycle fullscreen
|
||||||
|
T cycle ontop # toggle video window ontop of other windows
|
||||||
|
w add panscan -0.1 # zoom out with -panscan 0 -fs
|
||||||
|
e add panscan +0.1 # in
|
||||||
|
c cycle stream-capture # save (and append) file/stream to stream.dump with -capture
|
||||||
|
s screenshot # take a screenshot (if you want PNG, use "--screenshot-format=png")
|
||||||
|
S screenshot - each-frame # S will take a png screenshot of every frame
|
||||||
|
|
||||||
|
h cycle tv-channel 1
|
||||||
|
l cycle tv-channel -1
|
||||||
|
n cycle tv-norm
|
||||||
|
#b tv_step_chanlist
|
||||||
|
|
||||||
|
#? add chapter -1 # skip to previous dvd chapter
|
||||||
|
#? add chapter +1 # next
|
||||||
|
|
||||||
|
##
|
||||||
|
## Advanced seek
|
||||||
|
## Uncomment the following lines to be able to seek to n% of the media with
|
||||||
|
## the Fx keys.
|
||||||
|
##
|
||||||
|
#F1 seek 10 absolute-percent
|
||||||
|
#F2 seek 20 absolute-percent
|
||||||
|
#F3 seek 30 absolute-percent
|
||||||
|
#F4 seek 40 absolute-percent
|
||||||
|
#F5 seek 50 absolute-percent
|
||||||
|
#F6 seek 60 absolute-percent
|
||||||
|
#F7 seek 70 absolute-percent
|
||||||
|
#F8 seek 80 absolute-percent
|
||||||
|
#F9 seek 90 absolute-percent
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
##################
|
||||||
|
# video settings #
|
||||||
|
##################
|
||||||
|
|
||||||
|
# Start in fullscreen mode by default.
|
||||||
|
fs=yes
|
||||||
|
profile=high-quality
|
||||||
|
video-sync=display-resample
|
||||||
|
interpolation
|
||||||
|
hwdec=auto
|
||||||
|
|
||||||
|
##################
|
||||||
|
# audio settings #
|
||||||
|
##################
|
||||||
|
|
||||||
|
audio-channels=auto
|
||||||
|
|
||||||
|
##################
|
||||||
|
# other settings #
|
||||||
|
##################
|
||||||
|
|
||||||
|
cache=yes
|
||||||
|
demuxer-max-bytes=500M
|
||||||
|
demuxer-max-back-bytes=100M
|
||||||
|
cache-pause=no
|
||||||
|
cache-on-disk=no
|
||||||
|
|
||||||
|
# Display English subtitles if available.
|
||||||
|
slang=de,en
|
||||||
|
|
||||||
|
# Play Finnish audio if available, fall back to English otherwise.
|
||||||
|
alang=de,en
|
||||||
|
|
||||||
|
sub-auto=fuzzy
|
||||||
|
sub-font="Inter"
|
||||||
|
sub-bold=yes
|
||||||
|
|
||||||
|
|
||||||
|
############
|
||||||
|
# Profiles #
|
||||||
|
############
|
||||||
|
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
# This file contains all bindings that were removed or changed
|
||||||
|
# after a certain release.
|
||||||
|
# If you want MPlayer bindings, use mplayer-input.conf
|
||||||
|
|
||||||
|
# Pick the bindings you want back and add them to your own input.conf. Append
|
||||||
|
# this file to your input.conf if you want them all back:
|
||||||
|
#
|
||||||
|
# cat restore-old-bindings.conf >> ~/.config/mpv/input.conf
|
||||||
|
#
|
||||||
|
# Older installations use ~/.mpv/input.conf instead.
|
||||||
|
|
||||||
|
# changed in mpv 0.37.0
|
||||||
|
|
||||||
|
WHEEL_UP seek 10 # seek 10 seconds forward
|
||||||
|
WHEEL_DOWN seek -10 # seek 10 seconds backward
|
||||||
|
WHEEL_LEFT add volume -2
|
||||||
|
WHEEL_RIGHT add volume 2
|
||||||
|
|
||||||
|
# changed in mpv 0.27.0 (macOS and Wayland only)
|
||||||
|
|
||||||
|
# WHEEL_LEFT seek 5
|
||||||
|
# WHEEL_RIGHT seek -5
|
||||||
|
|
||||||
|
# changed in mpv 0.26.0
|
||||||
|
|
||||||
|
H cycle dvbin-channel-switch-offset up
|
||||||
|
K cycle dvbin-channel-switch-offset down
|
||||||
|
|
||||||
|
I show-text "${filename}" # display filename in osd
|
||||||
|
|
||||||
|
# changed in mpv 0.24.0
|
||||||
|
|
||||||
|
L cycle-values loop-playlist "inf" "no"
|
||||||
|
|
||||||
|
# changed in mpv 0.10.0
|
||||||
|
|
||||||
|
O osd
|
||||||
|
D cycle deinterlace
|
||||||
|
d cycle framedrop
|
||||||
|
|
||||||
|
# changed in mpv 0.7.0
|
||||||
|
|
||||||
|
ENTER playlist-next force
|
||||||
|
|
||||||
|
# changed in mpv 0.6.0
|
||||||
|
|
||||||
|
ESC quit
|
||||||
|
|
||||||
|
# changed in mpv 0.5.0
|
||||||
|
|
||||||
|
PGUP seek 600
|
||||||
|
PGDWN seek -600
|
||||||
|
RIGHT seek 10
|
||||||
|
LEFT seek -10
|
||||||
|
+ add audio-delay 0.100
|
||||||
|
- add audio-delay -0.100
|
||||||
|
F cycle sub-forced-events-only
|
||||||
|
U stop
|
||||||
|
o cycle-values osd-level
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# This file contains all bindings that were removed or changed
|
||||||
|
# after a certain release.
|
||||||
|
|
||||||
|
# Pick the bindings you want back and add them to your own osc.conf. Append
|
||||||
|
# this file to your osc.conf if you want them all back:
|
||||||
|
#
|
||||||
|
# cat restore-osc-bindings.conf >> ~/.config/mpv/script-opts/osc.conf
|
||||||
|
|
||||||
|
# changed in mpv 0.40.0
|
||||||
|
|
||||||
|
# previously unbound
|
||||||
|
title_mbtn_mid_command=
|
||||||
|
play_pause_mbtn_mid_command=
|
||||||
|
play_pause_mbtn_right_command=
|
||||||
|
fullscreen_mbtn_right_command=
|
||||||
|
volume_mbtn_right_command=
|
||||||
|
|
||||||
|
# restore playlist_osd=yes behavior
|
||||||
|
playlist_prev_mbtn_left_command=playlist-prev; show-text ${playlist} 3000
|
||||||
|
playlist_next_mbtn_left_command=playlist-next; show-text ${playlist} 3000
|
||||||
|
|
||||||
|
# restore chapter_osd=yes behavior
|
||||||
|
chapter_prev_mbtn_left_command=no-osd add chapter -1; show-text ${chapter-list} 3000
|
||||||
|
chapter_next_mbtn_left_command=no-osd add chapter 1; show-text ${chapter-list} 3000
|
||||||
|
|
||||||
|
# restore behavior before select.lua usage
|
||||||
|
playlist_prev_mbtn_right_command=show-text ${playlist} 3000
|
||||||
|
playlist_next_mbtn_right_command=show-text ${playlist} 3000
|
||||||
|
|
||||||
|
title=${media-title}
|
||||||
|
title_mbtn_left_command=show-text "${!playlist-count==1:[${playlist-pos-1}/${playlist-count}] }${media-title}"
|
||||||
|
title_mbtn_right_command=show-text ${filename}
|
||||||
|
|
||||||
|
chapter_prev_mbtn_right_command=show-text ${chapter-list} 3000
|
||||||
|
chapter_next_mbtn_right_command=show-text ${chapter-list} 3000
|
||||||
|
|
||||||
|
audio_track_mbtn_right_command=cycle audio down
|
||||||
|
audio_track_mbtn_mid_command=show-text ${track-list/audio} 3000
|
||||||
|
|
||||||
|
sub_track_mbtn_right_command=cycle sub down
|
||||||
|
sub_track_mbtn_mid_command=show-text ${track-list/sub} 3000
|
||||||
@@ -0,0 +1,656 @@
|
|||||||
|
This file intends to give a big picture overview of how mpv is structured.
|
||||||
|
|
||||||
|
player/*.c:
|
||||||
|
Essentially makes up the player applications, including the main() function
|
||||||
|
and the playback loop.
|
||||||
|
|
||||||
|
Generally, it accesses all other subsystems, initializes them, and pushes
|
||||||
|
data between them during playback.
|
||||||
|
|
||||||
|
The structure is as follows (as of commit e13c05366557cb):
|
||||||
|
* main():
|
||||||
|
* basic initializations (e.g. init_libav() and more)
|
||||||
|
* pre-parse command line (verbosity level, config file locations)
|
||||||
|
* load config files (mp_parse_cfgfiles())
|
||||||
|
* parse command line, add files from the command line to playlist
|
||||||
|
(m_config_parse_mp_command_line())
|
||||||
|
* check help options etc. (call handle_help_options()), possibly exit
|
||||||
|
* call mp_play_files() function that works down the playlist:
|
||||||
|
* run idle loop (idle_loop()), until there are files in the
|
||||||
|
playlist or an exit command was given (only if --idle it set)
|
||||||
|
* actually load and play a file in play_current_file():
|
||||||
|
* run all the dozens of functions to load the file and
|
||||||
|
initialize playback
|
||||||
|
* run a small loop that does normal playback, until the file is
|
||||||
|
done or a command terminates playback
|
||||||
|
(on each iteration, run_playloop() is called, which is rather
|
||||||
|
big and complicated - it decodes some audio and video on
|
||||||
|
each frame, waits for input, etc.)
|
||||||
|
* uninitialize playback
|
||||||
|
* determine next entry on the playlist to play
|
||||||
|
* loop, or exit if no next file or quit is requested
|
||||||
|
(see enum stop_play_reason)
|
||||||
|
* call mp_destroy()
|
||||||
|
* run_playloop():
|
||||||
|
* calls fill_audio_out_buffers()
|
||||||
|
This checks whether new audio needs to be decoded, and pushes it
|
||||||
|
to the AO.
|
||||||
|
* calls write_video()
|
||||||
|
Decode new video, and push it to the VO.
|
||||||
|
* determines whether playback of the current file has ended
|
||||||
|
* determines when to start playback after seeks
|
||||||
|
* and calls a whole lot of other stuff
|
||||||
|
(Really, this function does everything.)
|
||||||
|
|
||||||
|
Things worth saying about the playback core:
|
||||||
|
- most state is in MPContext (core.h), which is not available to the
|
||||||
|
subsystems (and should not be made available)
|
||||||
|
- the currently played tracks are in mpctx->current_track, and decoder
|
||||||
|
state in track.dec/d_sub
|
||||||
|
- the other subsystems rarely call back into the frontend, and the frontend
|
||||||
|
polls them instead (probably a good thing)
|
||||||
|
- one exceptions are wakeup callbacks, which notify a "higher" component
|
||||||
|
of a changed situation in a subsystem
|
||||||
|
|
||||||
|
I like to call the player/*.c files the "frontend".
|
||||||
|
|
||||||
|
ta.h & ta.c:
|
||||||
|
Hierarchical memory manager inspired by talloc from Samba. It's like a
|
||||||
|
malloc() with more features. Most importantly, each talloc allocation can
|
||||||
|
have a parent, and if the parent is free'd, all children will be free'd as
|
||||||
|
well. The parent is an arbitrary talloc allocation. It's either set by the
|
||||||
|
allocation call by passing a talloc parent, usually as first argument to the
|
||||||
|
allocation function. It can also be set or reset later by other calls (at
|
||||||
|
least talloc_steal()). A talloc allocation that is used as parent is often
|
||||||
|
called a talloc context.
|
||||||
|
|
||||||
|
One very useful feature of talloc is fast tracking of memory leaks. ("Fast"
|
||||||
|
as in it doesn't require valgrind.) You can enable it by setting the
|
||||||
|
MPV_LEAK_REPORT environment variable to "1":
|
||||||
|
export MPV_LEAK_REPORT=1
|
||||||
|
This will list all unfree'd allocations on exit.
|
||||||
|
|
||||||
|
Documentation can be found here:
|
||||||
|
http://git.samba.org/?p=samba.git;a=blob;f=lib/talloc/talloc.h;hb=HEAD
|
||||||
|
|
||||||
|
For some reason, we're still using API-compatible wrappers instead of TA
|
||||||
|
directly. The talloc wrapper has only a subset of the functionality, and
|
||||||
|
in particular the wrappers abort() on memory allocation failure.
|
||||||
|
|
||||||
|
Note: unlike tcmalloc, jemalloc, etc., talloc() is not actually a malloc
|
||||||
|
replacement. It works on top of system malloc and provides additional
|
||||||
|
features that are supposed to make memory management easier.
|
||||||
|
|
||||||
|
player/command.c:
|
||||||
|
This contains the implementation for client API commands and properties.
|
||||||
|
Properties are essentially dynamic variables changed by certain commands.
|
||||||
|
This is basically responsible for all user commands, like initiating
|
||||||
|
seeking, switching tracks, etc. It calls into other player/*.c files,
|
||||||
|
where most of the work is done, but also calls other parts of mpv.
|
||||||
|
|
||||||
|
player/core.h:
|
||||||
|
Data structures and function prototypes for most of player/*.c. They are
|
||||||
|
usually not accessed by other parts of mpv for the sake of modularization.
|
||||||
|
|
||||||
|
player/client.c:
|
||||||
|
This implements the client API (mpv/client.h). For the most part, this
|
||||||
|
just calls into other parts of the player. This also manages a ringbuffer
|
||||||
|
of events from player to clients.
|
||||||
|
|
||||||
|
options/options.h, options/options.c
|
||||||
|
options.h contains the global option struct MPOpts. The option declarations
|
||||||
|
(option names, types, and MPOpts offsets for the option parser) are in
|
||||||
|
options.c. Most default values for options and MPOpts are in
|
||||||
|
mp_default_opts at the end of options.c.
|
||||||
|
|
||||||
|
MPOpts is unfortunately quite monolithic, but is being incrementally broken
|
||||||
|
up into sub-structs. Many components have their own sub-option structs
|
||||||
|
separate from MPOpts. New options should be bound to the component that uses
|
||||||
|
them. Add a new option table/struct if needed.
|
||||||
|
|
||||||
|
The global MPOpts still contains the sub-structs as fields, which serves to
|
||||||
|
link them to the option parser. For example, an entry like this may be
|
||||||
|
typical:
|
||||||
|
|
||||||
|
{"", OPT_SUBSTRUCT(demux_opts, demux_conf)},
|
||||||
|
|
||||||
|
This directs the option access code to include all options in demux_conf
|
||||||
|
into the global option list, with no prefix (""), and as part of the
|
||||||
|
MPOpts.demux_opts field. The MPOpts.demux_opts field is actually not
|
||||||
|
accessed anywhere, and instead demux.c does this:
|
||||||
|
|
||||||
|
struct m_config_cache *opts_cache =
|
||||||
|
m_config_cache_alloc(demuxer, global, &demux_conf);
|
||||||
|
struct demux_opts *opts = opts_cache->opts;
|
||||||
|
|
||||||
|
... to get a copy of its options.
|
||||||
|
|
||||||
|
See m_config_core.h (below) how to access options.
|
||||||
|
|
||||||
|
The actual option parser is spread over m_option.c, m_config_frontend.c,
|
||||||
|
and parse_commandline.c, and uses the option table in options.c.
|
||||||
|
|
||||||
|
options/m_config_*.h & m_config_*.c:
|
||||||
|
Code for querying and managing options. m_config_frontend.h contains
|
||||||
|
declarations for the "legacy-ish" global m_config struct, while
|
||||||
|
m_config_core.h provides ways to access options in a threads-safe way
|
||||||
|
anywhere, like m_config_cache_alloc().
|
||||||
|
|
||||||
|
m_config_cache_alloc() lets anyone read, observe, and write options in any
|
||||||
|
thread. The only state it needs is struct mpv_global, which is an opaque
|
||||||
|
type that can be passed "down" the component hierarchy. For safety reasons,
|
||||||
|
you should not pass down any pointers to option structs (like MPOpts), but
|
||||||
|
instead pass down mpv_global, and use m_config_cache_alloc() (or similar)
|
||||||
|
to get a synchronized copy of the options.
|
||||||
|
|
||||||
|
input/input.c:
|
||||||
|
This translates keyboard input coming from VOs and other sources (such
|
||||||
|
as remote control devices like Apple IR or client API commands) to the
|
||||||
|
key bindings listed in the user's (or the builtin) input.conf and turns
|
||||||
|
them into items of type struct mp_cmd. These commands are queued, and read
|
||||||
|
by playloop.c. They get pushed with run_command() to command.c.
|
||||||
|
|
||||||
|
Note that keyboard input and commands used by the client API are the same.
|
||||||
|
The client API only uses the command parser though, and has its own queue
|
||||||
|
of input commands somewhere else.
|
||||||
|
|
||||||
|
common/msg.h:
|
||||||
|
All terminal output must go through mp_msg().
|
||||||
|
|
||||||
|
stream/*:
|
||||||
|
File input is implemented here. stream.h/.c provides a simple stream based
|
||||||
|
interface (like reading a number of bytes at a given offset). mpv can
|
||||||
|
also play from http streams and such, which is implemented here.
|
||||||
|
|
||||||
|
E.g. if mpv sees "http://something" on the command line, it will pick
|
||||||
|
stream_lavf.c based on the prefix, and pass the rest of the filename to it.
|
||||||
|
|
||||||
|
Some stream inputs are quite special: stream_dvdnav.c turns DVDs into mpeg
|
||||||
|
streams (DVDs are actually a bunch of vob files etc. on a filesystem),
|
||||||
|
|
||||||
|
Some stream inputs are just there to invoke special demuxers, like
|
||||||
|
stream_mf.c. (Basically to make the prefix "mf://" do something special.)
|
||||||
|
|
||||||
|
demux/:
|
||||||
|
Demuxers split data streams into audio/video/sub streams, which in turn
|
||||||
|
are split in packets. Packets (see packet.h) are mostly byte chunks
|
||||||
|
tagged with a playback time (PTS). These packets are passed to the decoders.
|
||||||
|
|
||||||
|
Most demuxers have been removed from this fork, and the only important and
|
||||||
|
"actual" demuxers left are demux_mkv.c and demux_lavf.c (uses libavformat).
|
||||||
|
There are some pseudo demuxers like demux_cue.c.
|
||||||
|
|
||||||
|
The main interface is in demux.h. The stream headers are in stheader.h.
|
||||||
|
There is a stream header for each audio/video/sub stream, and each of them
|
||||||
|
holds codec information about the stream and other information.
|
||||||
|
|
||||||
|
demux.c is a bit big, the main reason being that it contains the demuxer
|
||||||
|
cache, which is implemented as a list of packets. The cache is complex
|
||||||
|
because it support seeking, multiple ranges, prefetching, and so on.
|
||||||
|
|
||||||
|
filters/:
|
||||||
|
Filter related code. filter.c contains the generic filtering framework
|
||||||
|
which converts input frames to output frames (audio, video, or demux
|
||||||
|
packet data). f_decoder_wrapper.c is a source filter which connects the
|
||||||
|
frontend with the actual audio and video decoders. f_output_chain.c handles
|
||||||
|
VO/AO output conversions. f_autoconvert.c automatically inserts the
|
||||||
|
appropriate conversion filters if format conversion is needed.
|
||||||
|
|
||||||
|
video/:
|
||||||
|
This contains several things related to audio/video decoding, as well as
|
||||||
|
video filters.
|
||||||
|
|
||||||
|
mp_image.h and img_format.h define how mpv stores decoded video frames
|
||||||
|
internally.
|
||||||
|
|
||||||
|
video/decode/:
|
||||||
|
vd_*.c are video decoders. (There's only vd_lavc.c left.)
|
||||||
|
|
||||||
|
video/filter/:
|
||||||
|
vf_*.c are video filters. They are fed by the video decoder, and output the
|
||||||
|
filtered images to the VOs. By default, no video filters are used.
|
||||||
|
|
||||||
|
video/out/:
|
||||||
|
Video output. They also create GUI windows and handle user input. In most
|
||||||
|
cases, the windowing code is shared among VOs, like x11_common.c for X11 and
|
||||||
|
w32_common.c for Windows. The VOs stand between frontend and windowing code.
|
||||||
|
vo_gpu and vo_gpu_next can pick a windowing system at runtime, e.g. the same
|
||||||
|
binary can provide both X11 and Cocoa support on macOS.
|
||||||
|
|
||||||
|
VOs can be reconfigured at runtime. A vo_reconfig() call can change the video
|
||||||
|
resolution and format, without destroying the window.
|
||||||
|
|
||||||
|
vo_gpu should be taken as reference.
|
||||||
|
|
||||||
|
audio/:
|
||||||
|
format.h/format.c define the uncompressed audio formats. (As well as some
|
||||||
|
compressed formats used for spdif.)
|
||||||
|
|
||||||
|
audio/decode/:
|
||||||
|
ad_*.c handle audio decoding. ad_lavc.c is the decoder using ffmpeg.
|
||||||
|
ad_spdif.c is not really a decoder, but is used for compressed audio
|
||||||
|
passthrough.
|
||||||
|
|
||||||
|
audio/filter/:
|
||||||
|
Audio filters. af_scaletempo2 is inserted by default if playback is different
|
||||||
|
from normal speed.
|
||||||
|
|
||||||
|
audio/out/:
|
||||||
|
Audio outputs.
|
||||||
|
|
||||||
|
Unlike VOs, AOs can't be reconfigured on a format change. On audio format
|
||||||
|
changes, the AO will simply be closed and re-opened.
|
||||||
|
|
||||||
|
buffer.c is the wrapper to support for two types of audio APIs: push and
|
||||||
|
pull. ao.c calls into that. It contains generic code to deal with the data
|
||||||
|
flow these APIs impose.
|
||||||
|
|
||||||
|
Note that mpv synchronizes the video to the audio. That's the reason
|
||||||
|
why buggy audio drivers can have a bad influence on playback quality.
|
||||||
|
|
||||||
|
sub/:
|
||||||
|
Contains subtitle and OSD rendering.
|
||||||
|
|
||||||
|
osd.c/.h is actually the OSD code. It queries dec_sub.c to retrieve
|
||||||
|
decoded/rendered subtitles. osd_libass.c is the actual implementation of
|
||||||
|
the OSD text renderer (which uses libass, and takes care of all the tricky
|
||||||
|
fontconfig/freetype API usage and text layouting).
|
||||||
|
|
||||||
|
The VOs call osd.c to render OSD and subtitle (via e.g. osd_draw()). osd.c
|
||||||
|
in turn asks dec_sub.c for subtitle overlay bitmaps, which relays the
|
||||||
|
request to one of the sd_*.c subtitle decoders/renderers.
|
||||||
|
|
||||||
|
Subtitle loading is in demux/. Normally, subtitles are loaded via demux_lavf.c.
|
||||||
|
|
||||||
|
The subtitles are passed to dec_sub.c and the subtitle decoders in sd_*.c
|
||||||
|
as they are demuxed. All text subtitles are rendered by sd_ass.c. If text
|
||||||
|
subtitles are not in the ASS format, the libavcodec subtitle converters are
|
||||||
|
used (lavc_conv.c).
|
||||||
|
|
||||||
|
Text subtitles can be preloaded, in which case they are read fully as soon
|
||||||
|
as the subtitle is selected. In this case, they are effectively stored in
|
||||||
|
sd_ass.c's internal state.
|
||||||
|
|
||||||
|
etc/:
|
||||||
|
The files input.conf and builtin.conf are actually integrated into the mpv
|
||||||
|
binary by the build system. They contain the default configs and keybindings.
|
||||||
|
|
||||||
|
Best practices and Concepts within mpv
|
||||||
|
======================================
|
||||||
|
|
||||||
|
General contribution etc.
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
See: DOCS/contribute.md
|
||||||
|
|
||||||
|
Error checking
|
||||||
|
--------------
|
||||||
|
|
||||||
|
If an error is relevant, it should be handled. If it's interesting, log the
|
||||||
|
error. However, mpv often keeps errors silent and reports failures somewhat
|
||||||
|
coarsely by propagating them upwards the caller chain. This is OK, as long as
|
||||||
|
the errors are not very interesting, or would require a developer to debug it
|
||||||
|
anyway (in which case using a debugger would be more convenient, and the
|
||||||
|
developer would need to add temporary debug printfs to get extremely detailed
|
||||||
|
information which would not be appropriate during normal operation).
|
||||||
|
|
||||||
|
Basically, keep a balance on error reporting. But always check them, unless you
|
||||||
|
have a good argument not to.
|
||||||
|
|
||||||
|
Memory allocation errors (OOM) are a special class of errors. Normally such
|
||||||
|
allocation failures are not handled "properly". Instead, abort() is called.
|
||||||
|
(New code should use MP_HANDLE_OOM() for this.) This is done out of laziness and
|
||||||
|
for convenience, and due to the fact that MPlayer/mplayer2 never handled it
|
||||||
|
correctly. (MPlayer varied between handling it correctly, trying to do so but
|
||||||
|
failing, and just not caring, while mplayer2 started using abort() for it.)
|
||||||
|
|
||||||
|
This is justifiable in a number of ways. Error handling paths are notoriously
|
||||||
|
untested and buggy, so merely having them won't make your program more reliable.
|
||||||
|
Having these error handling paths also complicates non-error code, due to the
|
||||||
|
need to roll back state at any point after a memory allocation.
|
||||||
|
|
||||||
|
Take any larger body of code, that is supposed to handle OOM, and test whether
|
||||||
|
the error paths actually work, for example by overriding malloc with a version
|
||||||
|
that randomly fails. You will find bugs quickly, and often they will be very
|
||||||
|
annoying to fix (if you can even reproduce them).
|
||||||
|
|
||||||
|
In addition, a clear indication that something went wrong may be missing. On
|
||||||
|
error your program may exhibit "degraded" behavior by design. Consider a video
|
||||||
|
encoder dropping frames somewhere in the middle of a video due to temporary
|
||||||
|
allocation failures, instead of just exiting with an errors. In other cases, it
|
||||||
|
may open conceptual security holes. Failing fast may be better.
|
||||||
|
|
||||||
|
mpv uses GPU APIs, which may be break on allocation errors (because driver
|
||||||
|
authors will have the same issues as described here), or don't even have a real
|
||||||
|
concept for dealing with OOM (OpenGL).
|
||||||
|
|
||||||
|
libmpv is often used by GUIs, which I predict always break if OOM happens.
|
||||||
|
|
||||||
|
Last but not least, OSes like Linux use "overcommit", which basically means that
|
||||||
|
your program may crash any time OOM happens, even if it doesn't use malloc() at
|
||||||
|
all!
|
||||||
|
|
||||||
|
But still, don't just assume malloc() always succeeds. Use MP_HANDLE_OOM(). The
|
||||||
|
ta* APIs do this for you. The reason for this is that dereferencing a NULL
|
||||||
|
pointer can have security relevant consequences if large offsets are involved.
|
||||||
|
Also, a clear error message is better than a random segfault.
|
||||||
|
|
||||||
|
Some big memory allocations are checked anyway. For example, all code must
|
||||||
|
assume that allocating video frames or packets can fail. (The above example
|
||||||
|
of dropping video frames during encoding is entirely possible in mpv.)
|
||||||
|
|
||||||
|
Undefined behavior
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Undefined behavior (UB) is a concept in the C language. C is famous for being a
|
||||||
|
language that makes it almost impossible to write working code, because
|
||||||
|
undefined behavior is so easily triggered, compilers will happily abuse it to
|
||||||
|
generate "faster" code, debugging tools will shout at you, and sometimes it
|
||||||
|
even means your code doesn't work.
|
||||||
|
|
||||||
|
There is a lot of literature on this topic. Read it.
|
||||||
|
|
||||||
|
(In C's defense, UB exists in other languages too, but since they're not used
|
||||||
|
for low level infrastructure, and/or these languages are at times not rigorously
|
||||||
|
defined, simply nobody cares. However, the C standard committee is still guilty
|
||||||
|
for not addressing this. I'll admit that I can't even tell from the standard's
|
||||||
|
gibberish whether some specific behavior is UB or not. It's written like tax
|
||||||
|
law.)
|
||||||
|
|
||||||
|
In mpv, we generally try to avoid undefined behavior. For one, we want portable
|
||||||
|
and reliable operation. But more importantly, we want clean output from
|
||||||
|
debugging tools, in order to find real bugs more quickly and effectively.
|
||||||
|
|
||||||
|
Avoid the "works in practice" argument. Once debugging tools come into play, or
|
||||||
|
simply when "in practice" stops being true, this will all get back to you in a
|
||||||
|
bad way.
|
||||||
|
|
||||||
|
Global state, library safety
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Mutable global state is when code uses global variables that are not read-only.
|
||||||
|
This must be avoided in mpv. Always use context structs that the caller of
|
||||||
|
your code needs to allocate, and whose pointers are passed to your functions.
|
||||||
|
|
||||||
|
Library safety means that your code (or library) can be used by a library
|
||||||
|
without causing conflicts with other library users in the same process. To any
|
||||||
|
piece of code, a "safe" library's API can simply be used, without having to
|
||||||
|
worry about other API users that may be around somewhere.
|
||||||
|
|
||||||
|
Libraries are often not library safe, because they use global mutable state
|
||||||
|
or other "global" resources. Typical examples include use of signals, simple
|
||||||
|
global variables (like hsearch() in libc), or internal caches not protected by
|
||||||
|
locks.
|
||||||
|
|
||||||
|
A surprisingly high number of libraries are not library safe because they need
|
||||||
|
global initialization. Typically they provide an API function, which
|
||||||
|
"initializes" the library, and which must be called before calling any other
|
||||||
|
API functions. Often, you are to provide global configuration parameters, which
|
||||||
|
can change the behavior of the library. If two libraries A and B use library C,
|
||||||
|
but A and B initialize C with different parameters, something "bad" may happen.
|
||||||
|
In addition, these global initialization functions are often not thread-safe. So
|
||||||
|
if A and B try to initialize C at the same time (from different threads and
|
||||||
|
without knowing about each other), it may cause undefined behavior. (libcurl is
|
||||||
|
a good example of both of these issues. FFmpeg and some TLS libraries used to be
|
||||||
|
affected, but improved.)
|
||||||
|
|
||||||
|
This is so bad because library A and B from the previous example most likely
|
||||||
|
have no way to cooperate, because they're from different authors and have no
|
||||||
|
business knowing each others. They'd need a library D, which wraps library C
|
||||||
|
in a safe way. Unfortunately, typically something worse happens: libraries get
|
||||||
|
"infected" by the unsafeness of its sub-libraries, and export a global init API
|
||||||
|
just to initialize the sub-libraries. In the previous example, libraries A and B
|
||||||
|
would export global init APIs just to init library C, even though the rest of
|
||||||
|
A/B are clean and library safe. (Again, libcurl is an example of this, if you
|
||||||
|
subtract other historic anti-features.)
|
||||||
|
|
||||||
|
The main problem with library safety is that its lack propagates to all
|
||||||
|
libraries using the library.
|
||||||
|
|
||||||
|
We require libmpv to be library safe. This is not really possible, because some
|
||||||
|
libraries are not library safe (FFmpeg, Xlib, partially ALSA). However, for
|
||||||
|
ideological reasons, there is no global init API, and best effort is made to try
|
||||||
|
to avoid problems.
|
||||||
|
|
||||||
|
libmpv has some features that are not library safe, but which are disabled by
|
||||||
|
default (such as terminal usage aka stdout, or JSON IPC blocking SIGPIPE for
|
||||||
|
internal convenience).
|
||||||
|
|
||||||
|
A notable, very disgustingly library unsafe behavior of libmpv is calling
|
||||||
|
abort() on some memory allocation failure. See error checking section.
|
||||||
|
|
||||||
|
Logging
|
||||||
|
-------
|
||||||
|
|
||||||
|
All logging and terminal output in mpv goes through the functions and macros
|
||||||
|
provided in common/msg.h. This is in part for library safety, and in part to
|
||||||
|
make sure users can silence all output, or to redirect the output elsewhere,
|
||||||
|
like a log file or the internal console.lua script.
|
||||||
|
|
||||||
|
Locking
|
||||||
|
-------
|
||||||
|
|
||||||
|
See generally available literature. In mpv, we use mp_thread for this.
|
||||||
|
|
||||||
|
Always keep locking clean. Don't skip locking just because it will work "in
|
||||||
|
practice". (See undefined behavior section.) If your use case is simple, you may
|
||||||
|
use C11 atomics, but most likely you will only hurt yourself and others.
|
||||||
|
|
||||||
|
Always make clear which fields in a struct are protected by which lock. If a
|
||||||
|
field is immutable, or simply not thread-safe (e.g. state for a single worker
|
||||||
|
thread), document it as well.
|
||||||
|
|
||||||
|
Internal mpv APIs are assumed to be not thread-safe by default. If they have
|
||||||
|
special guarantees (such as being usable by more than one thread at a time),
|
||||||
|
these should be explicitly documented.
|
||||||
|
|
||||||
|
All internal mpv APIs must be free of global state. Even if a component is not
|
||||||
|
thread-safe, multiple threads can use _different_ instances of it without any
|
||||||
|
locking.
|
||||||
|
|
||||||
|
On a side note, recursive locks may seem convenient at first, but introduce
|
||||||
|
additional problems with condition variables and locking hierarchies. They
|
||||||
|
should be avoided.
|
||||||
|
|
||||||
|
Locking hierarchy
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
A simple way to avoid deadlocks with classic locking is to define a locking
|
||||||
|
hierarchy or lock order. If all threads acquire locks in the same order, no
|
||||||
|
deadlocks will happen.
|
||||||
|
|
||||||
|
For example, a "leaf" lock is a lock that is below all other locks in the
|
||||||
|
hierarchy. You can acquire it any time, as long as you don't acquire other
|
||||||
|
locks while holding it.
|
||||||
|
|
||||||
|
Unfortunately, C has no way to declare or check the lock order, so you should at
|
||||||
|
least document it.
|
||||||
|
|
||||||
|
In addition, try to avoid exposing locks to the outside. Making the declaration
|
||||||
|
of a lock private to a specific .c file (and _not_ exporting accessors or
|
||||||
|
lock/unlock functions that manipulate the lock) is a good idea. Your component's
|
||||||
|
API may acquire internal locks, but should release them when returning. Keeping
|
||||||
|
the entire locking in a single file makes it easy to check it.
|
||||||
|
|
||||||
|
Avoiding callback hell
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
mpv code is separated in components, like the "frontend" (i.e. MPContext mpctx),
|
||||||
|
VOs, AOs, demuxers, and more. The frontend usually calls "down" the usage
|
||||||
|
hierarchy: mpctx almost on top, then things like vo/ao, and utility code on the
|
||||||
|
very bottom.
|
||||||
|
|
||||||
|
"Callback hell" is when components call both up and down the hierarchy,
|
||||||
|
which for example leads to accidentally recursion, reentrancy problems, or
|
||||||
|
locking nightmares. This is avoided by (mostly) calling only down the hierarchy.
|
||||||
|
Basically the call graph forms a DAG. The other direction is handled by event
|
||||||
|
queues, wakeup callbacks, and similar mechanisms.
|
||||||
|
|
||||||
|
Typically, a component provides an API, and does not know anything about its
|
||||||
|
user. The API user (component higher in the hierarchy) polls the state of the
|
||||||
|
lower component when needed.
|
||||||
|
|
||||||
|
This also enforces some level of modularization, and with some luck the locking
|
||||||
|
hierarchy. (Basically, locks of lower components automatically become leaf
|
||||||
|
locks.) Another positive effect is simpler memory management.
|
||||||
|
|
||||||
|
(Also see e.g.: http://250bpm.com/blog:24)
|
||||||
|
|
||||||
|
Wakeup callbacks
|
||||||
|
----------------
|
||||||
|
|
||||||
|
This is a common concept in mpv. Even the public API uses it. It's used when an
|
||||||
|
API has internal threads (or otherwise triggers asynchronous events), but the
|
||||||
|
component call hierarchy needs to be kept. The wakeup callback is the only
|
||||||
|
exception to the call hierarchy, and always calls up.
|
||||||
|
|
||||||
|
For example, vo spawns a thread that the API user (the mpv frontend) does not
|
||||||
|
need to know about. vo simply provides a single-threaded API (or that looks like
|
||||||
|
one). This API needs a way to notify the API user of new events. But the vo
|
||||||
|
event producer is on the vo thread - it can't simply invoke a callback back into
|
||||||
|
the API user, because then the API user has to deal with locking, despite not
|
||||||
|
using threads. In addition, this will probably cause problems like mentioned in
|
||||||
|
the "callback hell" section, especially lock order issues.
|
||||||
|
|
||||||
|
The solution is the wakeup callback. It merely unblocks the API user from
|
||||||
|
waiting, and the API user then uses the normal vo API to examine whether or
|
||||||
|
which state changed. As a concept, it documents what a wakeup callback is
|
||||||
|
allowed to do and what not, to avoid the aforementioned problems.
|
||||||
|
|
||||||
|
Generally, you are not allowed to call any API from the wakeup callback. You
|
||||||
|
just do whatever is needed to unblock your thread. For example, if it's waiting
|
||||||
|
on a mutex/condition variable, acquire the mutex, set a change flag, signal
|
||||||
|
the condition variable, unlock, return. (This mutex must not be held when
|
||||||
|
calling the API. It must be a leaf lock.)
|
||||||
|
|
||||||
|
Restricting the wakeup callback like this sidesteps any reentrancy issues and
|
||||||
|
other complexities. The API implementation can simply hold internal (and
|
||||||
|
non-recursive) locks while invoking the wakeup callback.
|
||||||
|
|
||||||
|
The API user still needs to deal with locking (probably), but there's only the
|
||||||
|
need to implement a single "receiver", that can handle the entire API of the
|
||||||
|
used component. (Or multiple APIs - MPContext for example has only 1 wakeup
|
||||||
|
callback that handles all AOs, VOs, input, demuxers, and more. It simple re-runs
|
||||||
|
the playloop.)
|
||||||
|
|
||||||
|
You could get something more advanced by turning this into a message queue. The
|
||||||
|
API would append a message to the queue, and the API user can read it. But then
|
||||||
|
you still need a way to "wakeup" the API user (unless you force the API user
|
||||||
|
to block on your API, which will make things inconvenient for the API user). You
|
||||||
|
also need to worry about what happens if the message queue overruns (you either
|
||||||
|
lose messages or have unbounded memory usage). In the mpv public API, the
|
||||||
|
distinction between message queue and wakeup callback is sort of blurry, because
|
||||||
|
it does provide a message queue, but an additional wakeup callback, so API
|
||||||
|
users are not required to call mpv_wait_event() with a high timeout.
|
||||||
|
|
||||||
|
mpv itself prefers using wakeup callbacks over a generic event queue, because
|
||||||
|
most times an event queue is not needed (or complicates things), and it is
|
||||||
|
better to do it manually.
|
||||||
|
|
||||||
|
(You could still abstract the API user side of wakeup callback handling, and
|
||||||
|
avoid reimplementing it all the time. Although mp_dispatch_queue already
|
||||||
|
provides mechanisms for this.)
|
||||||
|
|
||||||
|
Condition variables
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
They're used whenever a thread needs to wait for something, without nonsense
|
||||||
|
like sleep calls or busy waiting. mpv uses the mp_thread API for this.
|
||||||
|
There's a lot of literature on condition variables, threading in general. Read it.
|
||||||
|
|
||||||
|
For initial understanding, it may be helpful to know that condition variables
|
||||||
|
are not variables that signal a condition. mp_cond does not have any
|
||||||
|
state per-se. Maybe mp_cond would better be named mp_interrupt,
|
||||||
|
because its sole purpose is to interrupt a thread waiting via mp_cond_wait()
|
||||||
|
(or similar). The "something" in "waiting for something" can be called
|
||||||
|
predicate (to avoid confusing it with "condition"). Consult literature for the
|
||||||
|
proper terms.
|
||||||
|
|
||||||
|
The very short version is...
|
||||||
|
|
||||||
|
Shared declarations:
|
||||||
|
|
||||||
|
mp_mutex lock;
|
||||||
|
mp_cond cond_var;
|
||||||
|
struct something state_var; // protected by lock, changes signaled by cond_var
|
||||||
|
|
||||||
|
Waiter thread:
|
||||||
|
|
||||||
|
mp_mutex_lock(&lock);
|
||||||
|
|
||||||
|
// Wait for a change in state_var. We want to wait until predicate_fulfilled()
|
||||||
|
// returns true.
|
||||||
|
// Must be a loop for 2 reasons:
|
||||||
|
// 1. cond_var may be associated with other conditions too
|
||||||
|
// 2. mp_cond_wait() can have sporadic wakeups
|
||||||
|
while (!predicate_fulfilled(&state_var)) {
|
||||||
|
// This unlocks, waits for cond_var to be signaled, and then locks again.
|
||||||
|
// The _whole_ point of cond_var is that unlocking and waiting for the
|
||||||
|
// signal happens atomically.
|
||||||
|
mp_cond_wait(&cond_var, &lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Here you may react to the state change. The state cannot change
|
||||||
|
// asynchronously as long as you still hold the lock (and didn't release
|
||||||
|
// and reacquire it).
|
||||||
|
// ...
|
||||||
|
|
||||||
|
mp_mutex_unlock(&lock);
|
||||||
|
|
||||||
|
Signaler thread:
|
||||||
|
|
||||||
|
mp_mutex_lock(&lock);
|
||||||
|
|
||||||
|
// Something changed. Update the shared variable with the new state.
|
||||||
|
update_state(&state_var);
|
||||||
|
|
||||||
|
// Notify that something changed. This will wake up the waiter thread if
|
||||||
|
// it's blocked in mp_cond_wait(). If not, nothing happens.
|
||||||
|
mp_cond_broadcast(&cond_var);
|
||||||
|
|
||||||
|
// Fun fact: good implementations wake up the waiter only when the lock is
|
||||||
|
// released, to reduce kernel scheduling overhead.
|
||||||
|
mp_mutex_unlock(&lock);
|
||||||
|
|
||||||
|
Some basic rules:
|
||||||
|
1. Always access your state under proper locking
|
||||||
|
2. Always check your predicate before every call to mp_cond_wait()
|
||||||
|
(And don't call mp_cond_wait() if the predicate is fulfilled.)
|
||||||
|
3. Always call mp_cond_wait() in a loop
|
||||||
|
(And only if your predicate failed without releasing the lock..)
|
||||||
|
4. Always call mp_cond_broadcast()/_signal() inside of its associated
|
||||||
|
lock
|
||||||
|
|
||||||
|
mpv sometimes violates rule 3, and leaves "retrying" (i.e. looping) to the
|
||||||
|
caller.
|
||||||
|
|
||||||
|
Common pitfalls:
|
||||||
|
- Thinking that mp_cond is some kind of semaphore, or holds any
|
||||||
|
application state or the user predicate (it _only_ wakes up threads
|
||||||
|
that are at the same time blocking on mp_cond_wait() and friends,
|
||||||
|
nothing else)
|
||||||
|
- Changing the predicate, but not updating all mp_cond_broadcast()/
|
||||||
|
_signal() calls correctly
|
||||||
|
- Forgetting that mp_cond_wait() unlocks the lock (other threads can
|
||||||
|
and must acquire the lock)
|
||||||
|
- Holding multiple nested locks while trying to wait (=> deadlock, violates
|
||||||
|
the lock order anyway)
|
||||||
|
- Waiting for a predicate correctly, but unlocking/relocking before acting
|
||||||
|
on it (unlocking allows arbitrary state changes)
|
||||||
|
- Confusing which lock/condition var. is used to manage a bit of state
|
||||||
|
|
||||||
|
Generally available literature probably has better examples and explanations.
|
||||||
|
|
||||||
|
Using condition variables the proper way is generally preferred over using more
|
||||||
|
messy variants of them. (Just saying because on win32, "SetEvent" exists, and
|
||||||
|
it's inferior to condition variables. Try to avoid the win32 primitives, even if
|
||||||
|
you're dealing with Windows-only code.)
|
||||||
|
|
||||||
|
Threads
|
||||||
|
-------
|
||||||
|
|
||||||
|
Threading should be conservatively used. Normally, mpv code pretends to be
|
||||||
|
single-threaded, and provides thread-unsafe APIs. Threads are used coarsely,
|
||||||
|
and if you can avoid messing with threads, you should. For example, VOs and AOs
|
||||||
|
do not need to deal with threads normally, even though they run on separate
|
||||||
|
threads. The glue code "isolates" them from any threading issues.
|
||||||
@@ -1,149 +0,0 @@
|
|||||||
|
|
||||||
[General]
|
|
||||||
version=5.12.0
|
|
||||||
allow_multiple_instances=0
|
|
||||||
width=718
|
|
||||||
always_on_top=0
|
|
||||||
enable_tooltips=1
|
|
||||||
error_info_shown=0
|
|
||||||
save_mode_on_exit=1
|
|
||||||
save_definitions_on_exit=1
|
|
||||||
save_history_separately=0
|
|
||||||
auto_update_exchange_rates=-1
|
|
||||||
clear_history_on_exit=0
|
|
||||||
history_expression_type=2
|
|
||||||
use_custom_history_font=0
|
|
||||||
use_custom_expression_font=0
|
|
||||||
replace_expression=0
|
|
||||||
enable_completion=1
|
|
||||||
enable_completion2=1
|
|
||||||
completion_min=1
|
|
||||||
completion_min2=1
|
|
||||||
completion_delay=0
|
|
||||||
use_custom_status_font=0
|
|
||||||
vertical_button_padding=-1
|
|
||||||
horizontal_button_padding=-1
|
|
||||||
use_custom_keypad_font=0
|
|
||||||
latest_button_currency=EUR
|
|
||||||
use_custom_result_font=0
|
|
||||||
continuous_conversion=1
|
|
||||||
set_missing_prefixes=0
|
|
||||||
show_bases_keypad=1
|
|
||||||
keep_function_dialog_open=0
|
|
||||||
ignore_locale=0
|
|
||||||
load_global_definitions=1
|
|
||||||
local_currency_conversion=1
|
|
||||||
use_binary_prefixes=0
|
|
||||||
check_version=0
|
|
||||||
show_keypad=1
|
|
||||||
show_history=0
|
|
||||||
history_height=0
|
|
||||||
minimal_width=500
|
|
||||||
show_stack=1
|
|
||||||
show_convert=0
|
|
||||||
persistent_keypad=0
|
|
||||||
minimal_mode=0
|
|
||||||
rpn_keys=1
|
|
||||||
display_expression_status=1
|
|
||||||
parsed_expression_in_resultview=0
|
|
||||||
calculate_as_you_type_history_delay=2000
|
|
||||||
use_unicode_signs=1
|
|
||||||
lower_case_numbers=0
|
|
||||||
duodecimal_symbols=0
|
|
||||||
exp_display=3
|
|
||||||
imaginary_j=0
|
|
||||||
base_display=1
|
|
||||||
twos_complement=1
|
|
||||||
hexadecimal_twos_complement=0
|
|
||||||
twos_complement_input=0
|
|
||||||
hexadecimal_twos_complement_input=0
|
|
||||||
spell_out_logical_operators=1
|
|
||||||
caret_as_xor=0
|
|
||||||
close_with_esc=-1
|
|
||||||
digit_grouping=1
|
|
||||||
copy_ascii=0
|
|
||||||
copy_ascii_without_units=0
|
|
||||||
decimal_comma=-1
|
|
||||||
dot_as_separator=-1
|
|
||||||
comma_as_separator=0
|
|
||||||
use_custom_application_font=0
|
|
||||||
multiplication_sign=2
|
|
||||||
division_sign=1
|
|
||||||
recent_functions=
|
|
||||||
recent_variables=
|
|
||||||
recent_units=
|
|
||||||
|
|
||||||
[Mode]
|
|
||||||
min_deci=0
|
|
||||||
use_min_deci=0
|
|
||||||
max_deci=2
|
|
||||||
use_max_deci=0
|
|
||||||
precision=10
|
|
||||||
interval_arithmetic=1
|
|
||||||
interval_display=0
|
|
||||||
min_exp=-1
|
|
||||||
negative_exponents=0
|
|
||||||
sort_minus_last=1
|
|
||||||
number_fraction_format=0
|
|
||||||
complex_number_form=0
|
|
||||||
use_prefixes=1
|
|
||||||
use_prefixes_for_all_units=0
|
|
||||||
use_prefixes_for_currencies=0
|
|
||||||
abbreviate_names=1
|
|
||||||
all_prefixes_enabled=0
|
|
||||||
denominator_prefix_enabled=1
|
|
||||||
place_units_separately=1
|
|
||||||
auto_post_conversion=3
|
|
||||||
mixed_units_conversion=3
|
|
||||||
number_base=10
|
|
||||||
number_base_expression=10
|
|
||||||
read_precision=0
|
|
||||||
assume_denominators_nonzero=1
|
|
||||||
warn_about_denominators_assumed_nonzero=1
|
|
||||||
structuring=1
|
|
||||||
angle_unit=1
|
|
||||||
functions_enabled=1
|
|
||||||
variables_enabled=1
|
|
||||||
calculate_functions=1
|
|
||||||
calculate_variables=1
|
|
||||||
variable_units_enabled=1
|
|
||||||
sync_units=1
|
|
||||||
unknownvariables_enabled=0
|
|
||||||
units_enabled=1
|
|
||||||
allow_complex=1
|
|
||||||
allow_infinite=1
|
|
||||||
indicate_infinite_series=0
|
|
||||||
show_ending_zeroes=1
|
|
||||||
rounding_mode=0
|
|
||||||
approximation=1
|
|
||||||
interval_calculation=1
|
|
||||||
concise_uncertainty_input=0
|
|
||||||
calculate_as_you_type=1
|
|
||||||
in_rpn_mode=0
|
|
||||||
chain_mode=0
|
|
||||||
limit_implicit_multiplication=0
|
|
||||||
parsing_mode=0
|
|
||||||
simplified_percentage=-1
|
|
||||||
spacious=1
|
|
||||||
excessive_parenthesis=0
|
|
||||||
visible_keypad=0
|
|
||||||
short_multiplication=1
|
|
||||||
default_assumption_type=4
|
|
||||||
default_assumption_sign=0
|
|
||||||
|
|
||||||
[Plotting]
|
|
||||||
plot_legend_placement=2
|
|
||||||
plot_style=0
|
|
||||||
plot_smoothing=0
|
|
||||||
plot_display_grid=1
|
|
||||||
plot_full_border=0
|
|
||||||
plot_min=0
|
|
||||||
plot_max=10
|
|
||||||
plot_step=1
|
|
||||||
plot_sampling_rate=1001
|
|
||||||
plot_use_sampling_rate=1
|
|
||||||
plot_variable=x
|
|
||||||
plot_rows=0
|
|
||||||
plot_type=0
|
|
||||||
plot_color=1
|
|
||||||
plot_linewidth=2
|
|
||||||
@@ -1,2 +1,32 @@
|
|||||||
[Appearance]
|
[Appearance]
|
||||||
|
color_scheme_path=/home/frank/.config/qt5ct/colors/catppuccin-mocha-blue.conf
|
||||||
|
custom_palette=true
|
||||||
icon_theme=Papirus-Dark
|
icon_theme=Papirus-Dark
|
||||||
|
standard_dialogs=xdgdesktopportal
|
||||||
|
style=Darkly
|
||||||
|
|
||||||
|
[Fonts]
|
||||||
|
fixed="FiraMono Nerd Font,13,-1,5,50,0,0,0,0,0,Regular"
|
||||||
|
general="Inter,13,-1,5,50,0,0,0,0,0,Regular"
|
||||||
|
|
||||||
|
[Interface]
|
||||||
|
activate_item_on_single_click=1
|
||||||
|
buttonbox_layout=0
|
||||||
|
cursor_flash_time=1000
|
||||||
|
dialog_buttons_have_icons=2
|
||||||
|
double_click_interval=400
|
||||||
|
gui_effects=@Invalid()
|
||||||
|
keyboard_scheme=2
|
||||||
|
menus_have_icons=true
|
||||||
|
show_shortcuts_in_context_menus=true
|
||||||
|
stylesheets=@Invalid()
|
||||||
|
toolbutton_style=4
|
||||||
|
underline_shortcut=2
|
||||||
|
wheel_scroll_lines=3
|
||||||
|
|
||||||
|
[SettingsWindow]
|
||||||
|
geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\0\0\0\0\0\0\0\0\x5?\0\0\x5\x43\0\0\0\0\0\0\0\0\0\0\x6\xb7\0\0\x5\x9f\0\0\0\0\x2\0\0\0\rp\0\0\0\0\0\0\0\0\0\0\x5?\0\0\x5\x43)
|
||||||
|
|
||||||
|
[Troubleshooting]
|
||||||
|
force_raster_widgets=1
|
||||||
|
ignored_applications=@Invalid()
|
||||||
|
|||||||
@@ -1,5 +1,32 @@
|
|||||||
[SettingsWindow]
|
|
||||||
geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\0\0\0\0\0\0\0\0\x4\x13\0\0\x2l\0\0\0\0\0\0\0\0\0\0\x4\x13\0\0\x2l\0\0\0\x1\x2\0\0\0\rp\0\0\0\0\0\0\0\0\0\0\x4\x13\0\0\x2l)
|
|
||||||
|
|
||||||
[Appearance]
|
[Appearance]
|
||||||
|
color_scheme_path=/home/frank/.config/qt6ct/colors/catppuccin-mocha-blue.conf
|
||||||
|
custom_palette=true
|
||||||
icon_theme=Papirus-Dark
|
icon_theme=Papirus-Dark
|
||||||
|
standard_dialogs=xdgdesktopportal
|
||||||
|
style=Darkly
|
||||||
|
|
||||||
|
[Fonts]
|
||||||
|
fixed="FiraMono Nerd Font,13,-1,5,400,0,0,0,0,0,0,0,0,0,0,1,,0,0"
|
||||||
|
general="Inter,13,-1,5,400,0,0,0,0,0,0,0,0,0,0,1,,0,0"
|
||||||
|
|
||||||
|
[Interface]
|
||||||
|
activate_item_on_single_click=1
|
||||||
|
buttonbox_layout=2
|
||||||
|
cursor_flash_time=1200
|
||||||
|
dialog_buttons_have_icons=2
|
||||||
|
double_click_interval=400
|
||||||
|
gui_effects=@Invalid()
|
||||||
|
keyboard_scheme=2
|
||||||
|
menus_have_icons=true
|
||||||
|
show_shortcuts_in_context_menus=true
|
||||||
|
stylesheets=@Invalid()
|
||||||
|
toolbutton_style=4
|
||||||
|
underline_shortcut=2
|
||||||
|
wheel_scroll_lines=3
|
||||||
|
|
||||||
|
[SettingsWindow]
|
||||||
|
geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\0\0\0\0\0\0\0\0\x5?\0\0\x5\x43\0\0\0\0\0\0\0\0\0\0\x5?\0\0\x5\x43\0\0\0\0\x2\0\0\0\rp\0\0\0\0\0\0\0\0\0\0\x5?\0\0\x5\x43)
|
||||||
|
|
||||||
|
[Troubleshooting]
|
||||||
|
force_raster_widgets=1
|
||||||
|
ignored_applications=@Invalid()
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
action=$(wofi --cache-file=/dev/null --dmenu << EOF
|
||||||
|
Restart Network
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
|
||||||
|
case "$action" in
|
||||||
|
" Restart Network")
|
||||||
|
~/.config/scripts/restart_network.sh
|
||||||
|
;;
|
||||||
|
esac
|
||||||
@@ -0,0 +1,206 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# battery-charge-watchdog
|
||||||
|
#
|
||||||
|
# Detects the Dell/UCSI fault where the battery reports a non-discharging
|
||||||
|
# status (Charging / Full / Not charging) while charge_now is actually
|
||||||
|
# falling. In that state UPower never fires CriticalPowerAction, so the
|
||||||
|
# machine runs to 0% and dies with no warning and no clean shutdown.
|
||||||
|
#
|
||||||
|
# The only trustworthy signal is the charge_now trend: current_now is
|
||||||
|
# reported unsigned on this hardware, so its sign says nothing about
|
||||||
|
# direction, and `status` is precisely what lies during the fault.
|
||||||
|
#
|
||||||
|
# Raises a critical desktop notification and keeps re-raising it until
|
||||||
|
# charging genuinely resumes or the status turns honest (Discharging,
|
||||||
|
# where UPower's own safety net takes over again).
|
||||||
|
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
BAT=${BAT:-/sys/class/power_supply/BAT0}
|
||||||
|
AC=${AC:-/sys/class/power_supply/AC}
|
||||||
|
|
||||||
|
# How often to sample.
|
||||||
|
POLL_INTERVAL=${POLL_INTERVAL:-20}
|
||||||
|
# How often to re-raise the alert while the fault persists.
|
||||||
|
REPEAT_INTERVAL=${REPEAT_INTERVAL:-60}
|
||||||
|
# Drop below the running peak, in 1/1000ths of full charge, before we
|
||||||
|
# call it a fault. 15 = 1.5% of full charge, comfortably above gauge jitter.
|
||||||
|
DROP_PERMILLE=${DROP_PERMILLE:-15}
|
||||||
|
# Emergency hibernate floor, in percent. 0 disables it (default: notify only).
|
||||||
|
HIBERNATE_AT=${HIBERNATE_AT:-0}
|
||||||
|
|
||||||
|
# Statuses that mean "UPower will not treat this as discharging", and so
|
||||||
|
# will not act on PercentageAction no matter how low the battery gets.
|
||||||
|
is_lying_status() {
|
||||||
|
case "$1" in
|
||||||
|
Charging | Full | "Not charging" | Unknown) return 0 ;;
|
||||||
|
*) return 1 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# sysfs reads can block for minutes when the UCSI/PD controller wedges,
|
||||||
|
# which is the very condition we are watching for. Never read unguarded.
|
||||||
|
read_attr() {
|
||||||
|
local v
|
||||||
|
v=$(timeout 5 cat "$1" 2>/dev/null) || return 1
|
||||||
|
[[ -n $v ]] || return 1
|
||||||
|
printf '%s' "$v"
|
||||||
|
}
|
||||||
|
|
||||||
|
read_int() {
|
||||||
|
local v
|
||||||
|
v=$(read_attr "$1") || return 1
|
||||||
|
[[ $v =~ ^-?[0-9]+$ ]] || return 1
|
||||||
|
printf '%s' "$v"
|
||||||
|
}
|
||||||
|
|
||||||
|
log() { printf '%s %s\n' "$(date '+%F %T')" "$*"; }
|
||||||
|
|
||||||
|
notify_id=0
|
||||||
|
notify() {
|
||||||
|
local urgency=$1 timeout_ms=$2 title=$3 body=$4 fresh=${5:-0}
|
||||||
|
local args=(-a "Battery Watchdog" -u "$urgency" -t "$timeout_ms"
|
||||||
|
-h string:category:device -i battery-caution)
|
||||||
|
# Reuse one notification so the alert updates in place instead of
|
||||||
|
# stacking, except when we deliberately want a new one to pop.
|
||||||
|
if [[ $fresh -eq 0 && $notify_id -gt 0 ]]; then
|
||||||
|
notify-send "${args[@]}" -r "$notify_id" "$title" "$body" >/dev/null 2>&1
|
||||||
|
else
|
||||||
|
local id
|
||||||
|
id=$(notify-send "${args[@]}" -p "$title" "$body" 2>/dev/null) && notify_id=$id
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt_duration() {
|
||||||
|
local s=$1
|
||||||
|
((s < 0)) && s=0
|
||||||
|
if ((s < 3600)); then
|
||||||
|
printf '%dm' $(((s + 30) / 60))
|
||||||
|
else
|
||||||
|
printf '%dh%02dm' $((s / 3600)) $(((s % 3600) / 60))
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
charge_full=$(read_int "$BAT/charge_full") || {
|
||||||
|
log "FATAL: cannot read $BAT/charge_full"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
((charge_full > 0)) || {
|
||||||
|
log "FATAL: charge_full is $charge_full"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
drop_threshold=$((charge_full * DROP_PERMILLE / 1000))
|
||||||
|
# Clearing the alert needs less movement than raising it: real charging
|
||||||
|
# adds roughly 1%/min here, so this confirms recovery within a minute.
|
||||||
|
recover_threshold=$((drop_threshold / 3))
|
||||||
|
((recover_threshold > 0)) || recover_threshold=1
|
||||||
|
|
||||||
|
log "started: charge_full=${charge_full}uAh threshold=${drop_threshold}uAh" \
|
||||||
|
"poll=${POLL_INTERVAL}s repeat=${REPEAT_INTERVAL}s hibernate_at=${HIBERNATE_AT}%"
|
||||||
|
|
||||||
|
peak=0 # highest charge_now seen in the current non-discharging run
|
||||||
|
trough=0 # low-water mark within the current fault, for recovery
|
||||||
|
alerting=0 # are we currently in the fault state
|
||||||
|
alert_start_t=0 # when the fault was first detected
|
||||||
|
alert_start_c=0 # charge_now at that moment
|
||||||
|
last_notify=0
|
||||||
|
last_escalation=100
|
||||||
|
|
||||||
|
while :; do
|
||||||
|
now=$(date +%s)
|
||||||
|
status=$(read_attr "$BAT/status") || status="Unreadable"
|
||||||
|
charge=$(read_int "$BAT/charge_now") || charge=""
|
||||||
|
capacity=$(read_int "$BAT/capacity") || capacity=""
|
||||||
|
ac=$(read_int "$AC/online") || ac="?"
|
||||||
|
|
||||||
|
if [[ -z $charge ]]; then
|
||||||
|
# A hung or unreadable gauge is itself a symptom worth surfacing.
|
||||||
|
log "WARN: charge_now unreadable (status=$status)"
|
||||||
|
sleep "$POLL_INTERVAL"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
if is_lying_status "$status"; then
|
||||||
|
if ((alerting)); then
|
||||||
|
# Recovery is measured against the low-water mark of this fault,
|
||||||
|
# not the pre-fault peak: after draining 90%->50%, real charging
|
||||||
|
# must clear the alert promptly, not on the way back up to 90%.
|
||||||
|
((charge < trough)) && trough=$charge
|
||||||
|
if ((charge - trough >= recover_threshold)); then
|
||||||
|
log "RESOLVED: charging resumed (status=$status capacity=${capacity}%)"
|
||||||
|
notify normal 10000 "Battery charging restored" \
|
||||||
|
"Charge is rising again at ${capacity}%. Status: ${status}." 1
|
||||||
|
alerting=0
|
||||||
|
peak=$charge
|
||||||
|
last_escalation=100
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
((charge > peak)) && peak=$charge
|
||||||
|
deficit=$((peak - charge))
|
||||||
|
if ((deficit >= drop_threshold)); then
|
||||||
|
alerting=1
|
||||||
|
trough=$charge
|
||||||
|
alert_start_t=$now
|
||||||
|
alert_start_c=$charge
|
||||||
|
last_notify=0
|
||||||
|
log "FAULT: status=$status but charge fell ${deficit}uAh from peak" \
|
||||||
|
"(capacity=${capacity}% ac_online=${ac})"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ((alerting)); then
|
||||||
|
deficit=$((peak - charge))
|
||||||
|
if ((now - last_notify >= REPEAT_INTERVAL)); then
|
||||||
|
elapsed=$((now - alert_start_t))
|
||||||
|
drained=$((alert_start_c - charge))
|
||||||
|
eta=""
|
||||||
|
# Need a wide enough window for the rate to mean anything;
|
||||||
|
# over a few seconds the gauge quantisation dominates.
|
||||||
|
if ((elapsed >= 60 && drained > 0)); then
|
||||||
|
# seconds until charge_now hits zero at the observed rate
|
||||||
|
eta=$(fmt_duration $((charge * elapsed / drained)))
|
||||||
|
eta=" Est. ${eta} to empty."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Pop a brand-new notification when crossing a danger step,
|
||||||
|
# so it is not silently folded into the existing one.
|
||||||
|
fresh=0
|
||||||
|
for step in 20 10 5; do
|
||||||
|
if [[ -n $capacity ]] && ((capacity <= step && last_escalation > step)); then
|
||||||
|
last_escalation=$step
|
||||||
|
fresh=1
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
notify critical 0 "⚠ Battery draining while reporting \"${status}\"" \
|
||||||
|
"Charge controller fault: ${capacity}% and falling, but status reads \"${status}\" and AC online=${ac}.${eta}
|
||||||
|
UPower will NOT hibernate in this state. Reseat the USB-C/dock cable or save your work now." \
|
||||||
|
"$fresh"
|
||||||
|
|
||||||
|
log "ALERT: capacity=${capacity}% status=$status deficit=${deficit}uAh${eta}"
|
||||||
|
last_notify=$now
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ((HIBERNATE_AT > 0)) && [[ -n $capacity ]] && ((capacity <= HIBERNATE_AT)); then
|
||||||
|
log "EMERGENCY: capacity=${capacity}% <= ${HIBERNATE_AT}%, hibernating"
|
||||||
|
notify critical 0 "Hibernating now" \
|
||||||
|
"Battery at ${capacity}% with a charge-controller fault." 1
|
||||||
|
systemctl hibernate
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Discharging or similar: honest reporting, UPower handles it.
|
||||||
|
if ((alerting)); then
|
||||||
|
log "RESOLVED: status turned honest ($status) - UPower safety net active again"
|
||||||
|
notify normal 10000 "Battery status corrected" \
|
||||||
|
"Now reporting \"${status}\" at ${capacity}%. Normal low-battery handling applies." 1
|
||||||
|
alerting=0
|
||||||
|
last_escalation=100
|
||||||
|
fi
|
||||||
|
peak=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
sleep "$POLL_INTERVAL"
|
||||||
|
done
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
PCIE_ADAPTER_SUFFIX=$(lspci | grep I225 | cut -d' ' -f1)
|
||||||
|
PCIE_ADAPTER_ADDRESS=$(ls -1 /sys/bus/pci/devices | grep "${PCIE_ADAPTER_SUFFIX}")
|
||||||
|
|
||||||
|
pkexec bash -c "echo 1 > /sys/bus/pci/devices/${PCIE_ADAPTER_ADDRESS}/remove; echo 1 > /sys/bus/pci/rescan"
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Battery charge-controller fault watchdog
|
||||||
|
Documentation=man:notify-send(1)
|
||||||
|
# Needs the session bus for notifications.
|
||||||
|
After=graphical-session.target
|
||||||
|
PartOf=graphical-session.target
|
||||||
|
# Makes the unit inert on machines without a battery, so it can be
|
||||||
|
# enabled unconditionally on the desktop as well as the laptop.
|
||||||
|
ConditionPathExists=/sys/class/power_supply/BAT0/charge_now
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=%h/.config/scripts/battery-charge-watchdog.sh
|
||||||
|
Restart=always
|
||||||
|
RestartSec=10
|
||||||
|
|
||||||
|
# Set HIBERNATE_AT=5 to add an emergency hibernate floor (0 = notify only).
|
||||||
|
Environment=POLL_INTERVAL=20
|
||||||
|
Environment=REPEAT_INTERVAL=60
|
||||||
|
Environment=DROP_PERMILLE=15
|
||||||
|
Environment=HIBERNATE_AT=0
|
||||||
|
|
||||||
|
# Read-only monitoring; no need for any write access to the system.
|
||||||
|
ProtectSystem=strict
|
||||||
|
ProtectHome=read-only
|
||||||
|
PrivateTmp=yes
|
||||||
|
NoNewPrivileges=yes
|
||||||
|
RestrictNamespaces=yes
|
||||||
|
MemoryMax=64M
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=graphical-session.target
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
export XCURSOR_THEME="Breeze_Light"
|
export XCURSOR_THEME="Breeze_Light"
|
||||||
export XCURSOR_SIZE="24"
|
export XCURSOR_SIZE="24"
|
||||||
|
export QT_QPA_PLATFORMTHEME="qt6ct"
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
export HYPRCURSOR_THEME="Breeze_Light"
|
export HYPRCURSOR_THEME="Breeze_Light"
|
||||||
export HYPRCURSOR_SIZE="24"
|
export HYPRCURSOR_SIZE="24"
|
||||||
|
export QT_QPA_PLATFORMTHEME="qt6ct"
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# SPDIF devices
|
||||||
|
monitor.alsa.rules = [
|
||||||
|
{
|
||||||
|
matches = [
|
||||||
|
{
|
||||||
|
# Matches all sources
|
||||||
|
node.name = "~alsa_input.*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
# Matches all sinks
|
||||||
|
node.name = "~alsa_output.*"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
actions = {
|
||||||
|
update-props = {
|
||||||
|
session.suspend-timeout-seconds = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
# bluetooth devices
|
||||||
|
monitor.bluez.rules = [
|
||||||
|
{
|
||||||
|
matches = [
|
||||||
|
{
|
||||||
|
# Matches all sources
|
||||||
|
node.name = "~bluez_input.*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
# Matches all sinks
|
||||||
|
node.name = "~bluez_output.*"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
actions = {
|
||||||
|
update-props = {
|
||||||
|
session.suspend-timeout-seconds = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
show=drun
|
||||||
|
width=600
|
||||||
|
height=300
|
||||||
|
location=center
|
||||||
|
columns=1
|
||||||
|
|
||||||
|
prompt=Application
|
||||||
|
|
||||||
|
allow_images=true
|
||||||
|
image_size=24
|
||||||
|
allow_markup=true
|
||||||
|
hide_scroll=true
|
||||||
|
parse_search=true
|
||||||
|
|
||||||
|
term=kitty
|
||||||
|
|
||||||
|
matching=contains
|
||||||
|
insensitive=true
|
||||||
|
|
||||||
|
dmenu-parse_action=true
|
||||||
|
run-always_parse_args=true
|
||||||
|
run-show_all=false
|
||||||
|
drun-disable_prime=true
|
||||||
|
drun-display_generic=false
|
||||||
|
|
||||||
|
key_up=Ctrl-k
|
||||||
|
key_down=Ctrl-j
|
||||||
|
key_left=Ctrl-h
|
||||||
|
key_right=Ctrl-l
|
||||||
|
key_pgup=Ctrl-u
|
||||||
|
key_pgdown=Ctrl-d
|
||||||
|
key_expand=Ctrl-e
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
/* MACHHIATO */
|
||||||
|
@define-color rosewater #f4dbd6;
|
||||||
|
@define-color flamingo #f0c6c6;
|
||||||
|
@define-color pink #f5bde6;
|
||||||
|
@define-color mauve #c6a0f6;
|
||||||
|
@define-color red #ed8796;
|
||||||
|
@define-color maroon #ee99a0;
|
||||||
|
@define-color peach #f5a97f;
|
||||||
|
@define-color yellow #eed49f;
|
||||||
|
@define-color green #a6da95;
|
||||||
|
@define-color teal #8bd5ca;
|
||||||
|
@define-color sky #91d7e3;
|
||||||
|
@define-color sapphire #7dc4e4;
|
||||||
|
@define-color blue #8aadf4;
|
||||||
|
@define-color lavender #b7bdf8;
|
||||||
|
@define-color text #cad3f5;
|
||||||
|
@define-color subtext1 #b8c0e0;
|
||||||
|
@define-color subtext0 #a5adcb;
|
||||||
|
@define-color overlay2 #939ab7;
|
||||||
|
@define-color overlay1 #8087a2;
|
||||||
|
@define-color overlay0 #6e738d;
|
||||||
|
@define-color surface2 #5b6078;
|
||||||
|
@define-color surface1 #494d64;
|
||||||
|
@define-color surface0 #363a4f;
|
||||||
|
@define-color base #24273a;
|
||||||
|
@define-color mantle #1e2030;
|
||||||
|
@define-color crust #181926;
|
||||||
|
|
||||||
|
|
||||||
|
* {
|
||||||
|
font-family: 'Noto Sans Nerd Font', 'FiraMono Nerd Font', 'FiraCode Nerd Font Mono', 'RobotoMono Nerd Font Propo', monospace;
|
||||||
|
font-size: 14px;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
window {
|
||||||
|
margin: 0px;
|
||||||
|
padding: 7px;
|
||||||
|
border: 2px solid @yellow;
|
||||||
|
border-radius: 0px;
|
||||||
|
background-color: @crust;
|
||||||
|
}
|
||||||
|
|
||||||
|
#outer-box {
|
||||||
|
margin : 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#input {
|
||||||
|
background-color : @surface0;
|
||||||
|
color : @text;
|
||||||
|
border-radius : 0;
|
||||||
|
padding: 2px 0px;
|
||||||
|
margin-bottom : 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#input:focus {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#input image {
|
||||||
|
color: @yellow;
|
||||||
|
padding: 0 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#scroll {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First Level Entries */
|
||||||
|
#inner-box > #entry {
|
||||||
|
border-radius : 0;
|
||||||
|
border: 1px solid @mantle;
|
||||||
|
background-color : @mantle;
|
||||||
|
color: @text;
|
||||||
|
padding : 7px;
|
||||||
|
padding-left : 22px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#inner-box > #entry:nth-child(odd) {
|
||||||
|
background-color : @base;
|
||||||
|
}
|
||||||
|
|
||||||
|
#inner-box > #entry:selected {
|
||||||
|
background-color: @surface1;
|
||||||
|
color: @blue;
|
||||||
|
border: 1px solid @yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
#inner-box > #entry:selected #text {
|
||||||
|
color: @blue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#inner-box > #entry expander #entry {
|
||||||
|
border-radius : 0;
|
||||||
|
border: none;
|
||||||
|
color: @text;
|
||||||
|
padding : 2px;
|
||||||
|
background-color : @mantle;
|
||||||
|
padding-left: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#inner-box > #entry:nth-child(odd) expander #entry {
|
||||||
|
background-color : @base;
|
||||||
|
}
|
||||||
|
|
||||||
|
#inner-box > #entry:selected expander #entry {
|
||||||
|
background-color : @surface1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#inner-box > #entry:selected expander #entry #text {
|
||||||
|
color: @text;
|
||||||
|
}
|
||||||
|
|
||||||
|
#inner-box > #entry:selected expander #entry:selected {
|
||||||
|
background-color: @surface2;
|
||||||
|
}
|
||||||
|
|
||||||
|
#inner-box > #entry:selected expander #entry:selected #text {
|
||||||
|
color: @yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
#text {
|
||||||
|
border: none;
|
||||||
|
color: @text;
|
||||||
|
margin-left : 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#entry arrow {
|
||||||
|
margin-left : -17px;
|
||||||
|
color: @text;
|
||||||
|
margin-right : 2px;
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"credStore": "secretservice",
|
||||||
|
"auths": {},
|
||||||
|
"currentContext": "default",
|
||||||
|
"plugins": {
|
||||||
|
"-x-cli-hints": {
|
||||||
|
"enabled": "true"
|
||||||
|
},
|
||||||
|
"ai": {
|
||||||
|
"hooks": "build,buildx build,run,compose"
|
||||||
|
},
|
||||||
|
"compose": {
|
||||||
|
"hooks": "logs,compose logs,compose attach,compose up"
|
||||||
|
},
|
||||||
|
"debug": {
|
||||||
|
"hooks": "exec"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"features": {
|
||||||
|
"hooks": "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
[user]
|
[user]
|
||||||
name = {{ .git.user }}
|
name = {{ .git.user }}
|
||||||
email = {{ .git.email }}
|
email = {{ .git.email }}
|
||||||
|
signingkey = {{ .git.signingkey }}
|
||||||
[core]
|
[core]
|
||||||
pager = bat
|
pager = bat
|
||||||
autocrlf = input
|
autocrlf = input
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
updateRefs = true
|
updateRefs = true
|
||||||
|
|
||||||
[branch]
|
[branch]
|
||||||
sort = -comitterdate
|
sort = -committerdate
|
||||||
autosetuprebase = remote
|
autosetuprebase = remote
|
||||||
autosetupmerge = true
|
autosetupmerge = true
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
|
||||||
|
# Added by Toolbox App
|
||||||
|
export PATH="$PATH:/home/frank/.local/share/JetBrains/Toolbox/scripts"
|
||||||
|
|
||||||
Reference in New Issue
Block a user