From 52b01c341b58359a857f20505798a693f3f328ef Mon Sep 17 00:00:00 2001 From: Naomi Carrigan Date: Thu, 22 Aug 2024 08:25:35 -0700 Subject: [PATCH] feat: more personalisation of hyprland --- docs/environment.md | 1142 ++++++++++++++++++++++++++++++++++++++++++- docs/index.html | 2 + 2 files changed, 1124 insertions(+), 20 deletions(-) diff --git a/docs/environment.md b/docs/environment.md index 983a22e..5f4cfab 100644 --- a/docs/environment.md +++ b/docs/environment.md @@ -21,8 +21,8 @@ This is the current diagnostic report from `hyfetch`. .o+` OS: Arch Linux x86_64 `ooo/ Host: MS-7B86 4.0 `+oooo: Kernel: 6.10.3-arch1-2 - `+oooooo: Uptime: 2 mins - -+oooooo+: Packages: 2 (npm), 1159 (pacman), 46 (steam) + `+oooooo: Uptime: 1 hour, 36 mins + -+oooooo+: Packages: 2 (npm), 1147 (pacman), 33 (steam) `/:-:++oooo+: Shell: zsh 5.9 `/++++/+++++++: Resolution: 1920x1080, 3840x2160, 1920x1080, 1024x768 `/++++++++++++++: WM: Hyprland @@ -32,7 +32,7 @@ This is the current diagnostic report from `hyfetch`. -osssssso. :ssssssso. Terminal: alacritty :osssssss/ osssso+++. CPU: AMD Ryzen 5 3600X (12) @ 3.8GHz /ossssssss/ +ssssooo/- GPU: NVIDIA GeForce GTX 1070 Ti - `/ossssso+/:- -:/+osssso+- Memory: 2.98 GiB / 31.29 GiB (9%) + `/ossssso+/:- -:/+osssso+- Memory: 4.53 GiB / 31.29 GiB (14%) `+sso+:-` `.-/+oso: Network: 1 Gbps `++:. `-/+/ BIOS: American Megatrends Inc. 5.14 (11/07/2019) .` `/ @@ -90,7 +90,7 @@ Operating System Version: X Server Vendor: The X.Org Foundation X Server Release: 12401002 X Window Manager: Hyprland :D - Steam Runtime Version: steam-runtime_0.20240610.91380 + Steam Runtime Version: steam-runtime_0.20240806.97925 Video Card: Driver: NVIDIA Corporation NVIDIA GeForce GTX 1070 Ti/PCIe/SSE2 Driver Version: 4.6.0 NVIDIA 555.58.02 @@ -116,7 +116,7 @@ Miscellaneous: UI Language: English LANG: en_GB.UTF-8 Total Hard Disk Space Available: 420968 MB - Largest Free Hard Disk Block: 192821 MB + Largest Free Hard Disk Block: 118179 MB Storage: Number of SSDs: 1 SSD sizes: 500G @@ -219,7 +219,7 @@ zork3 1-12 -#### 2.2. Explicit Installations +### 2.2. Explicit Installations These are all of the packages Naomi has specifically installed. This list is generated with `yay -Qe`. @@ -1817,10 +1817,15 @@ $menu = wofi --show=drun ### AUTOSTART ### ################# +# This creates the GUI for apps to ask for sudo perms exec-once = /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 -exec-once = aw-qt +# Wallpaper exec-once = hyprpaper +# Task bar exec-once = waybar +# Dark theming +exec-once = gsettings set org.gnome.desktop.interface gtk-theme "Sweet-Ambar-Blue-Dark-v40" +exec-once = gsettings set org.gnome.desktop.interface color-scheme prefer-dark # Execute startup script exec-once = ~/.config/hypr/startup.sh @@ -1836,7 +1841,6 @@ env = GBM_BACKEND,nvidia-drm env = __GLX_VENDOR_LIBRARY_NAME,nvidia env = WLR_NO_HARDWARE_CURSOES,1 env = WLR_RENDERER,gles2 -# env = WLR_DRM_NO_ATOMIC,1 debug { disable_logs = false @@ -1846,13 +1850,13 @@ debug { ### LOOK AND FEEL ### ##################### -general { +general { gaps_in = 5 gaps_out = 20 border_size = 2 - col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg - col.inactive_border = rgba(595959aa) - resize_on_border = false + col.active_border = rgba(00c7a9ee) rgba(00ffd9ee) 45deg + col.inactive_border = rgba(00806cff) + resize_on_border = true allow_tearing = false layout = dwindle } @@ -1860,7 +1864,7 @@ general { decoration { rounding = 10 active_opacity = 1.0 - inactive_opacity = 1.0 + inactive_opacity = 0.5 drop_shadow = true shadow_range = 4 shadow_render_power = 3 @@ -1893,7 +1897,7 @@ master { new_status = master } -misc { +misc { force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers disable_hyprland_logo = false # If true disables the random hyprland logo / anime girl background. :( } @@ -1908,8 +1912,11 @@ input { kb_model = kb_options = kb_rules = + follow_mouse = 1 + sensitivity = 0 # -1.0 - 1.0, 0 means no modification. + touchpad { natural_scroll = false } @@ -1919,11 +1926,6 @@ gestures { workspace_swipe = false } -device { - name = epic-mouse-v1 - sensitivity = -0.5 -} - #################### ### KEYBINDINGSS ### #################### @@ -1985,15 +1987,1115 @@ bind = $mainMod, L, exec, swaylock # Emoji Picker bind = $mainMod, code:60, exec, wofi-emoji +# Volume +bind = , XF86AudioRaiseVolume, exec, pactl set-sink-volume @DEFAULT_SINK@ +1% +bind = , XF86AudioLowerVolume, exec, pactl set-sink-volume @DEFAULT_SINK@ -1% +bind = , XF86AudioMute, exec, pactl set-sink-mute @DEFAULT_SINK@ toggle + +# Media controls +bind = , XF86AudioPlay, exec, playerctl play-pause +bind = , XF86AudioNext, exec, playerctl next +bind = , XF86AudioPrev, exec, playerctl previous + ############################## ### WINDOWS AND WORKSPACES ### ############################## windowrulev2 = suppressevent maximize, class:.* # You'll probably like this. -windowrulev2 = opacity 1 override 0.5,class:.* windowrulev2 = opacity 1 override 1,title:FreeTube ``` +#### `startup.sh` + +This just boots Naomi's programs. + +```sh +#!/bin/bash + +# Function to launch app with delay +launch_app() { + $2 & + sleep $1 +} + +# Workspace 1 +hyprctl dispatch workspace 1 +launch_app 20 discord +launch_app 5 hexchat + +# Workspace 2 +hyprctl dispatch workspace 2 +launch_app 5 brave + +# Workspace 3 +hyprctl dispatch workspace 3 +launch_app alacritty +``` + +### 3.6 Waybar + +These manage Naomi's waybar instance. These are a modification of [MechaBar](https://github.com/Sejjy/MechaBar). + +All of these files go in `~/.config/waybar`. + +#### `config.jsonc` + +```json +{ + "layer": "top", + "position": "top", + "mode": "dock", + "height": 20, + "exclusive": true, + "passthrough": false, + "gtk-layer-shell": true, + "reload_style_on_change": true, + +// positions + "modules-left": [ + "custom/paddl", + "custom/ws", // window icon + "custom/left1", + + "hyprland/workspaces", // workspaces + "custom/right1", + + "custom/paddw", + "hyprland/window" // window title + ], + "modules-center": [ + "custom/paddc", + "custom/left2", + "custom/cpuinfo", // temperature + + "custom/left3", + "memory", // memory + + "custom/left4", + "cpu", // cpu + "custom/leftin1", + + "custom/left5", + "custom/arch", // arch logo + "custom/right2", + + "custom/rightin1", + "clock#time", // time + "custom/right3", + + "clock#date", // date + "custom/right4", + + "custom/wifi", // connection + "custom/right5" + ], + "modules-right": [ + "custom/media", // media info + + "custom/left6", + "pulseaudio", // output device + + "custom/left7", + "tray", // brightness + + "custom/left8", + "battery", // battery + + "custom/leftin2", + "custom/power" // power button + ], + +// modules + "custom/ws": { + "format": " ", + "tooltip": false, + "on-click": "wofi --show=drun" + }, + + "hyprland/workspaces": { + "all-outputs": false, + "active-only": false, + "on-click": "activate", + "disable-scroll": true, + "sort-by-number": true + }, + + "hyprland/window": { + "format": "{}", + "separate-outputs": true, + "rewrite": { + "naomi@technomancer:(.*)": " $1", + "(.*)naomi@technomancer:~": " naomi@technomancer", + "(.*) — Mozilla Firefox": "󰈹 $1", + "(.*)Mozilla Firefox": "󰈹 Firefox", + "(.*) - Visual Studio Code": "󰨞 $1", + "(.*)Visual Studio Code": "󰨞 Visual Studio Code", + "(.*)Spotify Premium": " Spotify Premium", + "Discord": " Discord", + "GNU Image Manipulation Program": " GNU Image Manipulation Program", + "OBS(.*)": "󰐌 OBS Studio", + "VLC media player": "󰕼 VLC Media Player", + "ONLYOFFICE Desktop Editors": " OnlyOffice Desktop", + "qView": " qView", + "(.*).jpg": " $1.jpg", + "(.*).png": " $1.png", + "(.*).svg": " $1.svg", + "/": " File Manager", + "": " Naomi 󰅂 Technomancer" + }, + "min-length": 5, + "max-length": 45 + }, + + "custom/cpuinfo": { + "exec": "~/.config/waybar/scripts/cpuinfo.sh", + "return-type": "json", + "format": "{}", + "tooltip": true, + "interval": 5, + "min-length": 8, + "max-length": 8 + }, + + "memory": { + "states": {"c": 90}, + "format": "󰘚 {percentage}%", + "format-c": "󰀪 {percentage}%", + "tooltip": true, + "tooltip-format": "{used:0.1f}GB / {total:0.1f}GB", + "interval": 20, + "min-length": 7, + "max-length": 7 + }, + + "cpu": { + "format": "󰻠 {usage}%", + "tooltip": false, + "interval": 5, + "min-length": 6, + "max-length": 6 + }, + + "custom/arch": { + "format": " ", + "tooltip": false, + "on-click": "alacritty" + }, + + "clock#time": { + "format": "󱑂 {:%H:%M}", + "tooltip": false, + "min-length": 8, + "max-length": 8 + }, + + "clock#date": { + "format": "󱨴 {:%m-%d}", + "tooltip-format": "{calendar}", + "calendar": { + "mode": "month", + "mode-mon-col": 3, + "on-click-right": "mode", + "format": { + "months": "{}", + "weekdays": "{}", + "today": "{}" + } + }, + "actions": {"on-click-right": "mode"}, + "min-length": 8, + "max-length": 8 + }, + + "custom/wifi": { + "exec": "~/.config/waybar/scripts/network-status.sh", + "interval": 30, + "format": "󰢾 Internet", + "tooltip": true, + "tooltip-format": "{}", + "on-click": "~/.config/waybar/scripts/network-menu.sh", + }, + + "custom/media": { + "exec": "/usr/bin/python3 ~/.config/waybar/scripts/mediaplayer.py", + "format": "{}", + "return-type": "json", + "on-click": "playerctl play-pause", + "min-length": 5, + "max-length": 35 + }, + + "pulseaudio": { + "format": "{icon} {volume}%", + "format-muted": "婢 {volume}%", + "format-icons": { + "headphone": "󰋋", + "default": ["󰖀", "󰕾"] + }, + "on-click": "pactl set-sink-mute @DEFAULT_SINK@ toggle", + "on-right-click": "pavucontrol -t 3", + "on-scroll-up": "pactl set-sink-volume @DEFAULT_SINK@ +1%", + "on-scroll-down": "pactl set-sink-volume @DEFAULT_SINK@ -1%", + "scroll-step": 10, + "min-length": 6, + "max-length": 6 + }, + + "backlight": { + "device": "intel_backlight", + "format": "{icon} {percent}%", + "format-icons": ["", "", "", "", "", "", "", "", ""], + "tooltip": false, + "on-scroll-up": "brightnessctl set 5%+", + "on-scroll-down": "brightnessctl set 5%-", + "min-length": 6, + "max-length": 6 + }, + + "battery": { + "states": { + "good": 95, + "warning": 30, + "critical": 20 + }, + "format": "{icon} {capacity}%", + // "format-icons": ["", "", "", "", ""], + "format-icons": ["󰂎", "󰁺", "󰁻", "󰁼", "󰁽", "󰁾", "󰁿", "󰂀", "󰂁", "󰂂", "󰁹"], + "format-charging": "󱘖 {capacity}%", + "format-plugged": "󱘖 {capacity}%", + "tooltip-format": "{time}", + "interval": 1, + "min-length": 6, + "max-length": 6 + }, + + "custom/power": { + "format": " ", + "tooltip": false, + "on-click": "swaylock", + "on-click-right": "shutdown now", + "interval" : 86400 + }, + + "tray": { + "icon-size": 20, + "spacing": 10, + "show-passive-items": true + }, + +// padding + "custom/paddl": { + "format": " ", + "tooltip": false + }, + "custom/paddw": { + "format": " ", + "tooltip": false + }, + "custom/paddc": { + "format": " ", + "tooltip": false + }, + "custom/paddr": { + "format": "", + "tooltip": false + }, + +// LEFT arrows + "custom/left1": { + "format": "", + "tooltip": false + }, + "custom/left2": { + "format": "", + "tooltip": false + }, + "custom/left3": { + "format": "", + "tooltip": false + }, + "custom/left4": { + "format": "", + "tooltip": false + }, + "custom/left5": { + "format": "", + "tooltip": false + }, + "custom/left6": { + "format": "", + "tooltip": false + }, + "custom/left7": { + "format": "", + "tooltip": false + }, + "custom/left8": { + "format": "", + "tooltip": false + }, + +// RIGHT arrows + "custom/right1": { + "format": "", + "tooltip": false + }, + "custom/right2": { + "format": "", + "tooltip": false + }, + "custom/right3": { + "format": "", + "tooltip": false + }, + "custom/right4": { + "format": "", + "tooltip": false + }, + "custom/right5": { + "format": "", + "tooltip": false + }, + +// LEFT inverse + "custom/leftin1": { + "format": "", + "tooltip": false + }, + "custom/leftin2": { + "format": "", + "tooltip": false + }, + +// RIGHT inverse + "custom/rightin1": { + "format": "", + "tooltip": false + } +} +``` + +#### `style.css` + +```css +* { + border: none; + font-family: "JetBrainsMono Nerd Font"; + font-weight: bold; + font-size: 10px; + min-height: 11px; + color: @text; +} + +@import "theme.css"; + +window#waybar { + background: @bar-bg; +} + +tooltip { + background: @main-bg; + color: @main-fg; + border: solid; + border-radius: 7px; + border-width: 1px; + border-color: @text; +} + +/* WORKSPACE BUTTONS */ +#workspaces button { + box-shadow: none; + text-shadow: 0px 0px 2px rgba(0, 0, 0, 1); + padding: 0px; + border-radius: 8px; + margin-top: 2px; + margin-bottom: 2px; + margin-left: 0px; + padding-left: 2px; + padding-right: 2px; + margin-right: 0px; + color: @main-fg; + animation: ws_normal 20s ease-in-out 1; +} +#workspaces button.active { + box-shadow: 0px 0px 2px 1px rgba(0, 0, 0, 1); + text-shadow: 0px 0px 2px rgba(0, 0, 0, 0.6); + background: @wb-act-bg; + color: @wb-act-fg; + margin-left: 2px; + padding-left: 8px; + padding-right: 8px; + margin-right: 2px; + animation: ws_active 20s ease-in-out 1; + transition: all 0.4s cubic-bezier(.55,-0.68,.48,1.682); +} +#workspaces button:hover { + background: @wb-hvr-bg; + color: @wb-hvr-fg; + animation: ws_hover 20s ease-in-out 1; + transition: all 0.3s cubic-bezier(.55,-0.68,.48,1.682); +} + +/* SPACING */ +#custom-ws, +#workspaces, +#window, +#custom-cpuinfo +#memory, +#cpu, +#clock, +#pulseaudio, +#backlight, +#battery, +#custom-power, +#mpris, +#custom-notifications { + margin-bottom: 0px; + opacity: 1; + padding-left: 4px; + padding-right: 4px; +} + +/* COLORS */ +@define-color text #00ffd5; +@define-color workspaces #004452; + +@define-color cpuinfo #004452; +@define-color memory #006151; +@define-color cpu #008f77; + +@define-color arch #00ffd5; + +@define-color time #008f77; +@define-color date #006151; +@define-color wifi #004452; + +@define-color pulseaudio #004452; +@define-color backlight #006151; +@define-color battery #008f77; +@define-color power #00ffd5; + +/* MODULES */ +/* WINDOW ICON */ +#custom-paddl { + font-size: 11.5pt; + margin-bottom: -2px; + padding-right: 2px; + background: @main-bg; +} +#custom-ws { + text-shadow: 0px 0px 2px rgba(0, 0, 0, 1); + background: @main-bg; +} +#custom-left1 { + font-size: 11.5pt; + color: @workspaces; + background: @main-bg; + margin-bottom: -2px; + text-shadow: -1px 0px 2px rgba(0, 0, 0, 1); + padding-left: 2px; +} + +/* WORKSPACES */ +#workspaces { + padding: 0; + background: @workspaces; +} +#custom-right1 { + font-size: 11.5pt; + color: @workspaces; + background: @main-bg; + margin-bottom: -2px; + text-shadow: 1px 0px 2px rgba(0, 0, 0, 1); + padding-right: 3px; +} + +/* WINDOW TITLE */ +#window { + text-shadow: 0px 0px 2px rgba(0, 0, 0, 1); +} + +/* TEMPERATURE */ +#custom-paddc { + padding-right: 3px; +} +#custom-left2 { + font-size: 11.5pt; + color: @cpuinfo; + background: @main-bg; + margin-bottom: -2px; + border-radius: 10px; + text-shadow: -1px 0px 2px rgba(0, 0, 0, 1); + padding-left: 3px; +} +#custom-cpuinfo { + padding-left: 1px; + text-shadow: 0px 0px 2px rgba(0, 0, 0, 1); + background: @cpuinfo; +} + +/* MEMORY */ +#custom-left3 { + font-size: 11.5pt; + color: @memory; + background: @cpuinfo; + margin-bottom: -2px; + text-shadow: -1px 0px 2px rgba(0, 0, 0, 1); + padding-left: 3px; +} +#memory { + padding-left: 1px; + text-shadow: 0px 0px 2px rgba(0, 0, 0, 1); + background: @memory; +} + +/* CPU */ +#custom-left4 { + font-size: 11.5pt; + color: @cpu; + background: @memory; + margin-bottom: -2px; + text-shadow: -1px 0px 2px rgba(0, 0, 0, 1); + padding-left: 3px; +} +#cpu { + text-shadow: 0px 0px 2px rgba(0, 0, 0, 1); + background: @cpu; +} +#custom-leftin1 { + font-size: 11.5pt; + color: @cpu; + margin-bottom: -2px; +} + +/* ARCH LOGO */ +#custom-left5 { + font-size: 11.5pt; + color: @arch; + background: @main-bg; + margin-bottom: -2px; + text-shadow: -1px 0px 2px rgba(0, 0, 0, 0.6); + padding-left: 3px; +} +#custom-arch { + text-shadow: none; + color: black; + font-size: 11pt; + padding-left: 4px; + padding-right: 0px; + background: @arch; + margin-bottom: -2px; + text-shadow: 0px 0px 2px rgba(0, 0, 0, 1); +} +#custom-right2 { + font-size: 11.5pt; + color: @arch; + background: @main-bg; + margin-bottom: -2px; + text-shadow: 1px 0px 2px rgba(0, 0, 0, 1); + padding-right: 3px; +} + +/* TIME */ +#custom-rightin1 { + font-size: 11.5pt; + color: @time; + margin-bottom: -2px; +} +#clock.time { + text-shadow: 0px 0px 2px rgba(0, 0, 0, 1); + background: @time; +} +#custom-right3 { + font-size: 11.5pt; + color: @time; + background: @date; + margin-bottom: -2px; + text-shadow: 1px 0px 2px rgba(0, 0, 0, 1); + padding-right: 3px; +} + +/* DATE */ +#clock.date { + text-shadow: 0px 0px 2px rgba(0, 0, 0, 1); + background: @date; +} +#custom-right4 { + font-size: 11.5pt; + color: @date; + background: @wifi; + margin-bottom: -2px; + text-shadow: 1px 0px 2px rgba(0, 0, 0, 1); + padding-right: 3px; +} + +/* CONNECTION */ +#custom-wifi { + padding-left: 4px; + padding-right: 4px; + text-shadow: 0px 0px 2px rgba(0, 0, 0, 1); + background: @wifi; +} +#custom-right5 { + font-size: 11.5pt; + color: @wifi; + background: @main-bg; + margin-bottom: -2px; + text-shadow: 1px 0px 2px rgba(0, 0, 0, 1); + padding-right: 3px; +} + +/* MEDIA INFO */ +#custom-media { + background-color: @main-bg; + padding-left: 8px; + padding-right: 8px; +} + +/* OUTPUT DEVICE */ +#custom-left6 { + font-size: 11.5pt; + color: @pulseaudio; + background: @main-bg; + margin-bottom: -2px; + text-shadow: -1px 0px 2px rgba(0, 0, 0, 1); + padding-left: 3px; +} +#pulseaudio { + text-shadow: 0px 0px 2px rgba(0, 0, 0, 1); + background: @pulseaudio; +} + +/* BRIGHTNESS */ +#custom-left7 { + font-size: 11.5pt; + color: @backlight; + background: @pulseaudio; + margin-bottom: -2px; + text-shadow: -1px 0px 2px rgba(0, 0, 0, 1); + padding-left: 2px; +} +#backlight { + text-shadow: 0px 0px 2px rgba(0, 0, 0, 1); + background: @backlight; +} + +/* TRAY */ +#custom-left8 { + font-size: 11.5pt; + color: @battery; + background: @backlight; + margin-bottom: -2px; + text-shadow: -1px 0px 2px rgba(0, 0, 0, 1); + padding-left: 2px; +} +#tray { + text-shadow: 0px 0px 2px rgba(0, 0, 0, 1); + background: @backlight; +} + +#tray > .passive { + -gtk-icon-effect: dim; +} + +#tray > .needs-attention { + -gtk-icon-effect: highlight; + background-color: #eb4d4b; +} + +/* POWER BUTTON */ +#custom-leftin2 { + font-size: 11.5pt; + color: @battery; + background: @main-bg; + margin-bottom: -2px; +} +#custom-power { + color: @main-bg; + background: @power; + box-shadow: 0px 0px 2px 1px rgba(0, 0, 0, 1); + text-shadow: 0px 0px 2px rgba(0, 0, 0, 0.6); + border-radius: 20px; + margin-top: 2px; + margin-right: 4px; + margin-bottom: 2px; + padding-left: 10px; + padding-right: 7px; +} +#custom-paddr { + font-size: 11.5pt; + color: @main-bg; + margin-bottom: -2px; +} +``` + +#### `theme.css` + +```css +@define-color bar-bg #00473c; +/* @define-color bar-bg rgba(0, 0, 0, 0); */ + +@define-color main-bg #00473c; +@define-color main-fg #00ebc7; + +@define-color wb-act-bg #00ebc7; +@define-color wb-act-fg #00473c; +/* @define-color wb-act-bg #a6adc8; */ +/* @define-color wb-act-fg #313244; */ + +@define-color wb-hvr-bg #00ebc7; +@define-color wb-hvr-fg #00473c; +/* @define-color wb-hvr-bg #f5c2e7; */ +/* @define-color wb-hvr-fg #313244; */ +``` + +#### Scripts + +There are a few scripts necessary for waybar to work. These all go in `~/.config/waybar/scripts`: + +
+ cpuinfo.sh + +```sh +#!/usr/bin/env sh + +# CPU model +model=$(cat /proc/cpuinfo | grep 'model name' | head -n 1 | awk -F ': ' '{print $2}') + +# CPU utilization +utilization=$(top -bn1 | awk '/^%Cpu/ {print 100 - $8}') + +# Clock speed +freqlist=$(cat /proc/cpuinfo | grep "cpu MHz" | awk '{ print $4 }') +maxfreq=$(cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq | sed 's/...$//') +frequency=$(echo $freqlist | tr ' ' '\n' | awk "{ sum+=\$1 } END {printf \"%.0f/$maxfreq MHz\", sum/NR}") + +# CPU temp +temp=$(sensors | awk '/Package id 0/ {print $4}' | awk -F '[+.]' '{print $2}') +if [ -z "$temp" ]; then + temp=$(sensors | awk '/Tctl/ {print $2}' | tr -d '+°C') +fi +if [ -z "$temp" ]; then + temp="N/A" +fi + +# map icons +set_ico="{\"thermo\":{\"0\":\"󱃃\",\"45\":\"󰔏\",\"65\":\"󱃂\",\"85\":\"󰸁\"},\"util\":{\"0\":\"󰾆\",\"30\":\"󰾅\",\"60\":\"󰓅\",\"90\":\"󰀪\"}}" +eval_ico() { + map_ico=$(echo "${set_ico}" | jq -r --arg aky "$1" --argjson avl "$2" '.[$aky] | keys_unsorted | map(tonumber) | map(select(. <= $avl)) | max') + echo "${set_ico}" | jq -r --arg aky "$1" --arg avl "$map_ico" '.[$aky] | .[$avl]' +} + +thermo=$(eval_ico thermo $temp) +speedo=$(eval_ico util $utilization) + +# Print cpu info (json) +echo "{\"text\":\"${thermo} ${temp}°C\", \"tooltip\":\"${model}\n${thermo} Temperature: ${temp}°C\n${speedo} Utilization: ${utilization}%\n󰘚 Clock Speed: ${frequency}\"}" +``` + +
+ +
+ mediaplayer.py + +```py +#!/usr/bin/env python3 +import gi +gi.require_version("Playerctl", "2.0") +from gi.repository import Playerctl, GLib +from gi.repository.Playerctl import Player +import argparse +import logging +import sys +import signal +import gi +import json +import os +from typing import List + +logger = logging.getLogger(__name__) + +def signal_handler(sig, frame): + logger.info("Received signal to stop, exiting") + sys.stdout.write("\n") + sys.stdout.flush() + # loop.quit() + sys.exit(0) + + +class PlayerManager: + def __init__(self, selected_player=None, excluded_player=[]): + self.manager = Playerctl.PlayerManager() + self.loop = GLib.MainLoop() + self.manager.connect( + "name-appeared", lambda *args: self.on_player_appeared(*args)) + self.manager.connect( + "player-vanished", lambda *args: self.on_player_vanished(*args)) + + signal.signal(signal.SIGINT, signal_handler) + signal.signal(signal.SIGTERM, signal_handler) + signal.signal(signal.SIGPIPE, signal.SIG_DFL) + self.selected_player = selected_player + self.excluded_player = excluded_player.split(',') if excluded_player else [] + + self.init_players() + + def init_players(self): + for player in self.manager.props.player_names: + if player.name in self.excluded_player: + continue + if self.selected_player is not None and self.selected_player != player.name: + logger.debug(f"{player.name} is not the filtered player, skipping it") + continue + self.init_player(player) + + def run(self): + logger.info("Starting main loop") + self.loop.run() + + def init_player(self, player): + logger.info(f"Initialize new player: {player.name}") + player = Playerctl.Player.new_from_name(player) + player.connect("playback-status", + self.on_playback_status_changed, None) + player.connect("metadata", self.on_metadata_changed, None) + self.manager.manage_player(player) + self.on_metadata_changed(player, player.props.metadata) + + def get_players(self) -> List[Player]: + return self.manager.props.players + + def write_output(self, text, player): + logger.debug(f"Writing output: {text}") + + output = {"text": text, + "class": "custom-" + player.props.player_name, + "alt": player.props.player_name} + + sys.stdout.write(json.dumps(output) + "\n") + sys.stdout.flush() + + def clear_output(self): + sys.stdout.write("\n") + sys.stdout.flush() + + def on_playback_status_changed(self, player, status, _=None): + logger.debug(f"Playback status changed for player {player.props.player_name}: {status}") + self.on_metadata_changed(player, player.props.metadata) + + def get_first_playing_player(self): + players = self.get_players() + logger.debug(f"Getting first playing player from {len(players)} players") + if len(players) > 0: + # if any are playing, show the first one that is playing + # reverse order, so that the most recently added ones are preferred + for player in players[::-1]: + if player.props.status == "Playing": + return player + # if none are playing, show the first one + return players[0] + else: + logger.debug("No players found") + return None + + def show_most_important_player(self): + logger.debug("Showing most important player") + # show the currently playing player + # or else show the first paused player + # or else show nothing + current_player = self.get_first_playing_player() + if current_player is not None: + self.on_metadata_changed(current_player, current_player.props.metadata) + else: + self.clear_output() + + def on_metadata_changed(self, player, metadata, _=None): + logger.debug(f"Metadata changed for player {player.props.player_name}") + player_name = player.props.player_name + artist = player.get_artist() + title = player.get_title() + title = title.replace("&", "&") + + track_info = "" + if player_name == "spotify" and "mpris:trackid" in metadata.keys() and ":ad:" in player.props.metadata["mpris:trackid"]: + track_info = "Advertisement" + elif artist is not None and title is not None: + track_info = f"{artist} - {title}" + else: + track_info = title + + if track_info: + if player.props.status == "Playing" and player_name == "spotify": + track_info = "󰓇 " + track_info + if player.props.status == "Playing" and player_name == "firefox": + track_info = "󰗃 " + track_info + elif player.props.status != "Playing": + track_info = "󰏦 " + track_info + # only print output if no other player is playing + current_playing = self.get_first_playing_player() + if current_playing is None or current_playing.props.player_name == player.props.player_name: + self.write_output(track_info, player) + else: + logger.debug(f"Other player {current_playing.props.player_name} is playing, skipping") + + def on_player_appeared(self, _, player): + logger.info(f"Player has appeared: {player.name}") + if player.name in self.excluded_player: + logger.debug( + "New player appeared, but it's in exclude player list, skipping") + return + if player is not None and (self.selected_player is None or player.name == self.selected_player): + self.init_player(player) + else: + logger.debug( + "New player appeared, but it's not the selected player, skipping") + + def on_player_vanished(self, _, player): + logger.info(f"Player {player.props.player_name} has vanished") + self.show_most_important_player() + +def parse_arguments(): + parser = argparse.ArgumentParser() + + # Increase verbosity with every occurrence of -v + parser.add_argument("-v", "--verbose", action="count", default=0) + + parser.add_argument("-x", "--exclude", "- Comma-separated list of excluded player") + + # Define for which player we"re listening + parser.add_argument("--player") + + parser.add_argument("--enable-logging", action="store_true") + + return parser.parse_args() + + +def main(): + arguments = parse_arguments() + + # Initialize logging + if arguments.enable_logging: + logfile = os.path.join(os.path.dirname( + os.path.realpath(__file__)), "media-player.log") + logging.basicConfig(filename=logfile, level=logging.DEBUG, + format="%(asctime)s %(name)s %(levelname)s:%(lineno)d %(message)s") + + # Logging is set by default to WARN and higher. + # With every occurrence of -v it's lowered by one + logger.setLevel(max((3 - arguments.verbose) * 10, 0)) + + logger.info("Creating player manager") + if arguments.player: + logger.info(f"Filtering for player: {arguments.player}") + if arguments.exclude: + logger.info(f"Exclude player {arguments.exclude}") + + player = PlayerManager(arguments.player, arguments.exclude) + player.run() + + +if __name__ == "__main__": + main() +``` + +
+ +
+ network-menu.sh + +```sh +#!/bin/bash + +# Ensure nmcli is installed +if ! command -v nmcli &> /dev/null +then + echo "nmcli could not be found" + exit 1 +fi + +# Get the list of available wired connections +connections=$(nmcli -f NAME,TYPE connection show | grep ethernet | awk '{print $1}') + +# If no connections are found, exit +if [ -z "$connections" ]; then + echo "No wired connections found" + exit 1 +fi + +# Show connections in a menu using rofi +selected=$(echo "$connections" | wofi -dmenu -i -p "Select Wired Connection") + +# If a connection was selected, activate it +if [ -n "$selected" ]; then + nmcli connection up "$selected" +fi +``` + +
+ +
+ network-status.sh + +```sh +#!/bin/bash + +# Get the name of the active Ethernet connection +connection=$(nmcli -t -f NAME,TYPE,STATE connection show --active | awk -F: '/ethernet:activated/ {print $1}') + +# If no active Ethernet connection is found, check if any Ethernet interface is connected +if [ -z "$connection" ]; then + interface=$(nmcli -t -f DEVICE,TYPE,STATE device status | awk -F: '/ethernet:connected/ {print $1}') + if [ -n "$interface" ]; then + connection="Connected (Unconfigured)" + else + connection="No Connection" + fi +fi + +# Output the connection name or status +echo "${connection}" +``` + +
+ +### 3.7 Alacritty + +This one goes in `~/.config/alacritty/alacritty.toml`. + +```toml +# Primary colors +[colors.primary] +background = '#00332b' +foreground = '#00ffd9' + +# Colors used for 'custom_cursor_colors' +[colors.cursor] +text = '#00ffd9' +cursor = '#00ffd9' + +# Colors 0 through 7 +[colors.normal] +black = '#337167' +red = '#a87a9a' +green = '#5da286' +yellow = '#9e9e57' +blue = '#58699d' +magenta = '#9b4b9b' +cyan = '#006151' +white = '#5dc6b6' + +# Colors 8 through 15 +[colors.bright] +black = '#64d3c1' +red = '#ffb8ea' +green = '#8af0c7' +yellow = '#fdfd86' +blue = '#8aa4f5' +magenta = '#ff7aff' +cyan = '#00ffd5' +white = '#00ffd9' +``` + ## 4. Code Editor Naomi uses VSCodium as her current code editor. diff --git a/docs/index.html b/docs/index.html index c59933c..7714a8b 100644 --- a/docs/index.html +++ b/docs/index.html @@ -94,6 +94,8 @@ + +