diff --git a/.config/ags/modules/.configuration/user_options.js b/.config/ags/modules/.configuration/user_options.js index fcc7ee6c5..aef4724f9 100644 --- a/.config/ags/modules/.configuration/user_options.js +++ b/.config/ags/modules/.configuration/user_options.js @@ -38,6 +38,16 @@ let configOptions = { 'warnTitles': ["Low battery", "Very low battery", 'Critical Battery'], 'warnMessages': ["Plug in the charger", "You there?", 'PLUG THE CHARGER ALREADY'], }, + 'brightness': { + // Object of controller names for each monitor, either "brightnessctl" or "ddcutil" or "auto" + // 'default' one will be used if unspecified + // Examples + // 'eDP-1': "brightnessctl", + // 'DP-1': "ddcutil", + 'controllers': { + 'default': "auto", + }, + }, 'music': { 'preferredPlayer': "plasma-browser-integration", }, @@ -159,4 +169,4 @@ function overrideConfigRecursive(userOverrides, configOptions = {}) { overrideConfigRecursive(userOverrides, configOptions); globalThis['userOptions'] = configOptions; -export default configOptions; \ No newline at end of file +export default configOptions; diff --git a/.config/ags/modules/bar/main.js b/.config/ags/modules/bar/main.js index 7f74c541a..0a0d8f42e 100644 --- a/.config/ags/modules/bar/main.js +++ b/.config/ags/modules/bar/main.js @@ -46,7 +46,7 @@ export const Bar = async (monitor = 0) => { const minHeight = styleContext.get_property('min-height', Gtk.StateFlags.NORMAL); // execAsync(['bash', '-c', `hyprctl keyword monitor ,addreserved,${minHeight},0,0,0`]).catch(print); }, - startWidget: (await WindowTitle()), + startWidget: (await WindowTitle(monitor)), centerWidget: Widget.Box({ className: 'spacing-h-4', children: [ diff --git a/.config/ags/modules/bar/normal/spaceleft.js b/.config/ags/modules/bar/normal/spaceleft.js index 6fbe5d394..b3d796b63 100644 --- a/.config/ags/modules/bar/normal/spaceleft.js +++ b/.config/ags/modules/bar/normal/spaceleft.js @@ -39,16 +39,16 @@ const WindowTitle = async () => { } -export default async () => { +export default async (monitor = 0) => { const optionalWindowTitleInstance = await WindowTitle(); return Widget.EventBox({ onScrollUp: () => { Indicator.popup(1); // Since the brightness and speaker are both on the same window - Brightness.screen_value += 0.05; + Brightness[monitor].screen_value += 0.05; }, onScrollDown: () => { Indicator.popup(1); // Since the brightness and speaker are both on the same window - Brightness.screen_value -= 0.05; + Brightness[monitor].screen_value -= 0.05; }, onPrimaryClick: () => { App.toggleWindow('sideleft'); @@ -75,4 +75,4 @@ export default async () => { ] }) }); -} \ No newline at end of file +} diff --git a/.config/ags/modules/bar/normal/tray.js b/.config/ags/modules/bar/normal/tray.js index 71ca062ca..727c28bbf 100644 --- a/.config/ags/modules/bar/normal/tray.js +++ b/.config/ags/modules/bar/normal/tray.js @@ -5,11 +5,7 @@ const { Gravity } = imports.gi.Gdk; const SysTrayItem = (item) => Button({ className: 'bar-systray-item', - child: Icon({ - hpack: 'center', - icon: `${item.icon}`, - setup: (self) => self.hook(item, (self) => self.icon = item.icon), - }), + child: Icon({hpack: 'center'}).bind('icon', item, 'icon'), setup: (self) => self .hook(item, (self) => self.tooltipMarkup = item['tooltip-markup']) , diff --git a/.config/ags/modules/cheatsheet/data_keybinds.js b/.config/ags/modules/cheatsheet/data_keybinds.js index 1dbcd0eb9..b64156797 100644 --- a/.config/ags/modules/cheatsheet/data_keybinds.js +++ b/.config/ags/modules/cheatsheet/data_keybinds.js @@ -71,6 +71,7 @@ export const keybindList = [[ "name": "Utilities", "binds": [ { "keys": ["PrtSc"], "action": "Screenshot >> clipboard" }, + { "keys": ["Ctrl", "PrtSc"], "action": "Screenshot >> file + clipboard" }, { "keys": ["󰖳", "Shift", "+", "S"], "action": "Screen snip >> clipboard" }, { "keys": ["󰖳", "Shift", "+", "T"], "action": "Image to text >> clipboard" }, { "keys": ["󰖳", "Shift", "+", "C"], "action": "Color picker" }, diff --git a/.config/ags/modules/cheatsheet/main.js b/.config/ags/modules/cheatsheet/main.js index 21644e7cd..4b7b67bc6 100644 --- a/.config/ags/modules/cheatsheet/main.js +++ b/.config/ags/modules/cheatsheet/main.js @@ -86,7 +86,7 @@ export const sheetContent = ExpandingIconTabContainer({ export default (id) => PopupWindow({ name: `cheatsheet${id}`, layer: 'overlay', - keymode: 'exclusive', + keymode: 'on-demand', visible: false, child: Widget.Box({ vertical: true, diff --git a/.config/ags/modules/indicators/indicatorvalues.js b/.config/ags/modules/indicators/indicatorvalues.js index 18f228626..755d63e8b 100644 --- a/.config/ags/modules/indicators/indicatorvalues.js +++ b/.config/ags/modules/indicators/indicatorvalues.js @@ -49,16 +49,16 @@ const OsdValue = ({ }); } -export default () => { +export default (monitor = 0) => { const brightnessIndicator = OsdValue({ name: 'Brightness', extraClassName: 'osd-brightness', extraProgressClassName: 'osd-brightness-progress', - labelSetup: (self) => self.hook(Brightness, self => { - self.label = `${Math.round(Brightness.screen_value * 100)}`; + labelSetup: (self) => self.hook(Brightness[monitor], self => { + self.label = `${Math.round(Brightness[monitor].screen_value * 100)}`; }, 'notify::screen-value'), - progressSetup: (self) => self.hook(Brightness, (progress) => { - const updateValue = Brightness.screen_value; + progressSetup: (self) => self.hook(Brightness[monitor], (progress) => { + const updateValue = Brightness[monitor].screen_value; progress.value = updateValue; }, 'notify::screen-value'), }); @@ -109,4 +109,4 @@ export default () => { ] }) }); -} \ No newline at end of file +} diff --git a/.config/ags/modules/indicators/main.js b/.config/ags/modules/indicators/main.js index db3fc4c8c..16741937f 100644 --- a/.config/ags/modules/indicators/main.js +++ b/.config/ags/modules/indicators/main.js @@ -22,7 +22,7 @@ export default (monitor = 0) => Widget.Window({ className: 'osd-window', css: 'min-height: 2px;', children: [ - IndicatorValues(), + IndicatorValues(monitor), MusicControls(), NotificationPopups(), ColorScheme(), @@ -30,4 +30,3 @@ export default (monitor = 0) => Widget.Window({ }) }), }); - diff --git a/.config/ags/modules/overview/main.js b/.config/ags/modules/overview/main.js index 185c6010c..2b664ebd4 100644 --- a/.config/ags/modules/overview/main.js +++ b/.config/ags/modules/overview/main.js @@ -5,7 +5,7 @@ import PopupWindow from '../.widgethacks/popupwindow.js'; export default (id = '') => PopupWindow({ name: `overview${id}`, // exclusivity: 'ignore', - keymode: 'exclusive', + keymode: 'on-demand', visible: false, anchor: ['top'], layer: 'overlay', diff --git a/.config/ags/modules/session/main.js b/.config/ags/modules/session/main.js index cf4f8010f..32640f1bf 100644 --- a/.config/ags/modules/session/main.js +++ b/.config/ags/modules/session/main.js @@ -5,7 +5,7 @@ import PopupWindow from '../.widgethacks/popupwindow.js'; export default (id = 0) => PopupWindow({ // On-screen keyboard name: `session${id}`, visible: false, - keymode: 'exclusive', + keymode: 'on-demand', layer: 'overlay', exclusivity: 'ignore', anchor: ['top', 'bottom', 'left', 'right'], diff --git a/.config/ags/modules/sideleft/apis/waifu.js b/.config/ags/modules/sideleft/apis/waifu.js index 733b79559..9bed5e688 100644 --- a/.config/ags/modules/sideleft/apis/waifu.js +++ b/.config/ags/modules/sideleft/apis/waifu.js @@ -19,7 +19,8 @@ async function getImageViewerApp(preferredApp) { .then((output) => { if (output != '') return preferredApp; else return 'xdg-open'; - }); + }) + .catch(print); } const IMAGE_REVEAL_DELAY = 13; // Some wait for inits n other weird stuff @@ -408,4 +409,4 @@ export const sendMessage = (text) => { } else WaifuService.fetch(text); -} \ No newline at end of file +} diff --git a/.config/ags/modules/sideleft/main.js b/.config/ags/modules/sideleft/main.js index 994d17752..a9ddf2232 100644 --- a/.config/ags/modules/sideleft/main.js +++ b/.config/ags/modules/sideleft/main.js @@ -2,7 +2,7 @@ import PopupWindow from '../.widgethacks/popupwindow.js'; import SidebarLeft from "./sideleft.js"; export default () => PopupWindow({ - keymode: 'exclusive', + keymode: 'on-demand', anchor: ['left', 'top', 'bottom'], name: 'sideleft', layer: 'overlay', diff --git a/.config/ags/modules/sideleft/sideleft.js b/.config/ags/modules/sideleft/sideleft.js index 1869d0b85..d27ad1876 100644 --- a/.config/ags/modules/sideleft/sideleft.js +++ b/.config/ags/modules/sideleft/sideleft.js @@ -40,7 +40,7 @@ const pinButton = Button({ sideleftContent.toggleClassName('sidebar-pinned', self.attribute.enabled); if (self.attribute.enabled) { - sideleftWindow.exclusivity = 'exclusive'; + sideleftWindow.exclusivity = 'on-demad'; } else { sideleftWindow.exclusivity = 'normal'; diff --git a/.config/ags/modules/sideright/main.js b/.config/ags/modules/sideright/main.js index 5abe8b03a..e961cbb0a 100644 --- a/.config/ags/modules/sideright/main.js +++ b/.config/ags/modules/sideright/main.js @@ -2,7 +2,7 @@ import PopupWindow from '../.widgethacks/popupwindow.js'; import SidebarRight from "./sideright.js"; export default () => PopupWindow({ - keymode: 'exclusive', + keymode: 'on-demand', anchor: ['right', 'top', 'bottom'], name: 'sideright', layer: 'overlay', diff --git a/.config/ags/scripts/color_generation/colorgen.sh b/.config/ags/scripts/color_generation/colorgen.sh index 4194e377a..0010496ac 100755 --- a/.config/ags/scripts/color_generation/colorgen.sh +++ b/.config/ags/scripts/color_generation/colorgen.sh @@ -11,8 +11,6 @@ lightdark="dark" transparency="opaque" materialscheme="vibrant" terminalscheme="$HOME/.config/ags/scripts/templates/terminal/scheme-base.json" -# terminalscheme="$HOME/.config/ags/scripts/templates/terminal/scheme-catppuccin.json" -# terminalscheme="$HOME/.config/ags/scripts/templates/terminal/scheme-vscode.json" if [ ! -f $colormodefile ]; then echo "dark" > $colormodefile diff --git a/.config/ags/scripts/record-script.sh b/.config/ags/scripts/record-script.sh index 1509c1689..5c9183e60 100755 --- a/.config/ags/scripts/record-script.sh +++ b/.config/ags/scripts/record-script.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash getdate() { - date '+%Y%m%d_%H-%M-%S' + date '+%Y-%m-%d_%H.%M.%S' } getaudiooutput() { pactl list sources | grep 'Name' | grep 'monitor' | cut -d ' ' -f2 diff --git a/.config/ags/scripts/templates/terminal/scheme-monochrome.json b/.config/ags/scripts/templates/terminal/scheme-monochrome.json new file mode 100644 index 000000000..5807a26e4 --- /dev/null +++ b/.config/ags/scripts/templates/terminal/scheme-monochrome.json @@ -0,0 +1,36 @@ +{ + "dark": { + "term0": "#000000", + "term1": "#FFFFFF", + "term2": "#CCCCCC", + "term3": "#8f8f8f", + "term4": "#FFFFFF", + "term5": "#111111", + "term6": "#CCCCCC", + "term7": "#FFFFFF", + "term8": "#404040", + "term9": "#CCCCCC", + "term10": "#FFFFFF", + "term11": "#909090", + "term12": "#CCCCCC", + "term13": "#808080", + "term14": "#CCCCCC", + "term15": "#FFFFFF" + }, + "light": { + "term0": "#EAE9EA", + "term1": "#777777", + "term2": "#000000", + "term3": "#000000", + "term4": "#000000", + "term5": "#000000", + "term6": "#000000", + "term7": "#202020", + "term8": "#000000", + "term9": "#000000", + "term10": "#CCCCCC", + "term11": "#808080", + "term12": "#CCCCCC", + "term13": "#FFFFFF" + } +} diff --git a/.config/ags/scss/_colors.scss b/.config/ags/scss/_colors.scss index c89954719..fe82a9074 100644 --- a/.config/ags/scss/_colors.scss +++ b/.config/ags/scss/_colors.scss @@ -1,5 +1,5 @@ $rootTransparency: 0.31; // Transparency = 1 - opacity -$transparency: 0.8; +$transparency: 0.75; // Transparent versions @if $transparent == True { diff --git a/.config/ags/scss/_osd.scss b/.config/ags/scss/_osd.scss index a3d284796..ef21f435c 100644 --- a/.config/ags/scss/_osd.scss +++ b/.config/ags/scss/_osd.scss @@ -83,7 +83,7 @@ } .osd-colorscheme-settings { - background-color: $layer0; + background-color: $layer1; padding: 0.313rem 0.626rem; @include small-rounding; } diff --git a/.config/ags/services/brightness.js b/.config/ags/services/brightness.js index 89bfbac10..04fccd0ca 100644 --- a/.config/ags/services/brightness.js +++ b/.config/ags/services/brightness.js @@ -1,10 +1,11 @@ +import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js'; import Service from 'resource:///com/github/Aylur/ags/service.js'; import * as Utils from 'resource:///com/github/Aylur/ags/utils.js'; const { exec, execAsync } = Utils; import { clamp } from '../modules/.miscutils/mathfuncs.js'; -class BrightnessService extends Service { +class BrightnessServiceBase extends Service { static { Service.register( this, @@ -23,7 +24,7 @@ class BrightnessService extends Service { percent = clamp(percent, 0, 1); this._screenValue = percent; - Utils.execAsync(`brightnessctl s ${percent * 100}% -q`) + Utils.execAsync(this.setBrightnessCmd(percent)) .then(() => { // signals has to be explicity emitted this.emit('screen-changed', percent); @@ -35,13 +36,6 @@ class BrightnessService extends Service { .catch(print); } - constructor() { - super(); - const current = Number(exec('brightnessctl g')); - const max = Number(exec('brightnessctl m')); - this._screenValue = current / max; - } - // overwriting connectWidget method, lets you // change the default event that widgets connect to connectWidget(widget, callback, event = 'screen-changed') { @@ -49,11 +43,101 @@ class BrightnessService extends Service { } } -// the singleton instance -const service = new BrightnessService(); +class BrightnessCtlService extends BrightnessServiceBase { + static { + Service.register(this); + } + + constructor() { + super(); + const current = Number(exec('brightnessctl g')); + const max = Number(exec('brightnessctl m')); + this._screenValue = current / max; + } + + setBrightnessCmd(percent) { + return `brightnessctl s ${percent * 100}% -q`; + } +} + +class BrightnessDdcService extends BrightnessServiceBase { + static { + Service.register(this); + } + + constructor(busNum) { + super(); + this._busNum = busNum; + Utils.execAsync(`ddcutil -b ${this._busNum} getvcp 10 --brief`) + .then((out) => { + // only the last line is useful + out = out.split('\n'); + out = out[out.length - 1]; + + out = out.split(' '); + const current = Number(out[3]); + const max = Number(out[4]); + this._screenValue = current / max; + }) + .catch(print); + } + + setBrightnessCmd(percent) { + return `ddcutil -b ${this._busNum} setvcp 10 ${Math.round(percent * 100)}`; + } +} + +async function listDdcMonitorsSnBus() { + let ddcSnBus = {}; + try { + const out = await Utils.execAsync('ddcutil detect --brief'); + const displays = out.split('\n\n'); + displays.forEach(display => { + const reg = /^Display \d+/; + if (!reg.test(display)) + return; + const lines = display.split('\n'); + const sn = lines[3].split(':')[3]; + const busNum = lines[1].split('/dev/i2c-')[1]; + ddcSnBus[sn] = busNum; + }); + } catch (err) { + print(err); + } + return ddcSnBus; +} + +// Service instance +const numMonitors = Hyprland.monitors.length; +const service = Array(numMonitors); +const ddcSnBus = await listDdcMonitorsSnBus(); +for (let i = 0; i < service.length; i++) { + const monitorName = Hyprland.monitors[i].name; + const monitorSn = Hyprland.monitors[i].serial; + const preferredController = userOptions.brightness.controllers[monitorName] + || userOptions.brightness.controllers.default || "auto"; + if (preferredController) { + switch (preferredController) { + case "brightnessctl": + service[i] = new BrightnessCtlService(); + break; + case "ddcutil": + service[i] = new BrightnessDdcService(ddcSnBus[monitorSn]); + break; + case "auto": + if (monitorSn in ddcSnBus) + service[i] = new BrightnessDdcService(ddcSnBus[monitorSn]); + else + service[i] = new BrightnessCtlService(); + break; + default: + throw new Error(`Unknown brightness controller ${preferredController}`); + } + } +} // make it global for easy use with cli -globalThis.brightness = service; +globalThis.brightness = service[0]; // export to use in other modules -export default service; \ No newline at end of file +export default service; diff --git a/.config/hypr/hyprland/general.conf b/.config/hypr/hyprland/general.conf index 264dc15c7..5a6c9389b 100644 --- a/.config/hypr/hyprland/general.conf +++ b/.config/hypr/hyprland/general.conf @@ -126,7 +126,7 @@ animations { # animation = layers, 1, 2, md3_decel, slide animation = layersIn, 1, 3, menu_decel, slide animation = layersOut, 1, 1.6, menu_accel - animation = fadeLayersIn, 0, 2, menu_decel + animation = fadeLayersIn, 1, 2, menu_decel animation = fadeLayersOut, 1, 4.5, menu_accel animation = workspaces, 1, 7, menu_decel, slide # animation = workspaces, 1, 2.5, softAcDecel, slide diff --git a/.config/hypr/hyprland/keybinds.conf b/.config/hypr/hyprland/keybinds.conf index dc79b59eb..1817634c5 100644 --- a/.config/hypr/hyprland/keybinds.conf +++ b/.config/hypr/hyprland/keybinds.conf @@ -41,6 +41,7 @@ bind = Control+Shift+Alt+Super, Delete, exec, systemctl poweroff || loginctl pow # Screenshot, Record, OCR, Color picker, Clipboard history bind = Super+Shift+Alt, S, exec, grim -g "$(slurp)" - | swappy -f - bindl=,Print,exec,grim - | wl-copy +bindl= Control,Print, exec, mkdir -p ~/Pictures/Screenshots && ~/.config/ags/scripts/grimblast.sh copysave screen ~/Pictures/Screenshots/Screenshot_"$(date '+%Y-%m-%d_%H.%M.%S')".png bind = Super+Shift, S, exec, ~/.config/ags/scripts/grimblast.sh --freeze copy area bind = Super+Alt, R, exec, ~/.config/ags/scripts/record-script.sh bind = Control+Alt, R, exec, ~/.config/ags/scripts/record-script.sh --fullscreen diff --git a/.github/ISSUE_TEMPLATE/1-issue.md b/.github/ISSUE_TEMPLATE/1-issue.md index f66d8ba10..040a827fd 100644 --- a/.github/ISSUE_TEMPLATE/1-issue.md +++ b/.github/ISSUE_TEMPLATE/1-issue.md @@ -7,8 +7,7 @@ assignees: '' --- -- **(For usage) I have read the [wiki](https://end-4.github.io/dots-hyprland-wiki/en/i-i/02usage)** -- **(For troubleshooting) I have read the [wiki](https://end-4.github.io/dots-hyprland-wiki/en/i-i/03troubleshooting)** +- **I have read the [Usage](https://end-4.github.io/dots-hyprland-wiki/en/i-i/02usage) and the [Troubleshooting](https://end-4.github.io/dots-hyprland-wiki/en/i-i/03troubleshooting) pages of the wiki** - **I have made sure that both my config and system packages are up to date** - Linux distro: diff --git a/install.sh b/install.sh index 392837512..c4ed16da7 100755 --- a/install.sh +++ b/install.sh @@ -136,7 +136,8 @@ case $SKIP_PLASMAINTG in ;; esac -v sudo usermod -aG video,input "$(whoami)" +v sudo usermod -aG video,i2c,input "$(whoami)" +v bash -c "echo i2c-dev | sudo tee /etc/modules-load.d/i2c-dev.conf" v systemctl --user enable ydotool --now ##################################################################################### @@ -306,4 +307,3 @@ case $existed_hypr_conf in printf "\e[33mPlease use \"~/.config/hypr/hyprland.conf.new\" as a reference for a proper format.\e[0m\n" printf "\e[33mIf this is your first time installation, you must overwrite \"~/.config/hypr/hyprland.conf\" with \"~/.config/hypr/hyprland.conf.new\".\e[0m\n" ;;esac - diff --git a/scriptdata/dependencies.conf b/scriptdata/dependencies.conf index e2d770ed1..c93a37c6c 100644 --- a/scriptdata/dependencies.conf +++ b/scriptdata/dependencies.conf @@ -3,7 +3,7 @@ ### Ones which need cleanbuild (see install.sh): # hyprland-git -# python-materialyoucolor-git gradience-git dart-sass python-material-color-utilities +# python-materialyoucolor-git gradience-git python-material-color-utilities ### Basic coreutils cliphist cmake curl fuzzel rsync wget ripgrep gojq npm meson typescript gjs axel @@ -26,10 +26,13 @@ pavucontrol wireplumber libdbusmenu-gtk3 playerctl swww webp-pixbuf-loader gtk-layer-shell gtk3 gtksourceview3 gobject-introspection upower yad ydotool ### Gnome -polkit-gnome gnome-keyring gnome-control-center blueberry networkmanager brightnessctl gammastep gnome-bluetooth-3.0 +polkit-gnome gnome-keyring gnome-control-center blueberry networkmanager gammastep gnome-bluetooth-3.0 + +### Backlight +brightnessctl ddcutil ### Widgets -python-pywayland python-psutil hypridle-git hyprlock-git wlogout wl-clipboard hyprpicker-git anyrun-git +dart-sass python-pywayland python-psutil hypridle-git hyprlock-git wlogout wl-clipboard hyprpicker-git anyrun-git ### Fonts and Themes adw-gtk3-git qt5ct qt5-wayland fontconfig ttf-readex-pro ttf-jetbrains-mono-nerd ttf-material-symbols-variable-git ttf-space-mono-nerd fish foot starship diff --git a/uninstall.sh b/uninstall.sh index 4c2dc6a72..174958eae 100755 --- a/uninstall.sh +++ b/uninstall.sh @@ -35,16 +35,18 @@ v rm -rf "$HOME/.local/bin/fuzzel-emoji" ############################################################################################################################## -# Undo Step 1: Remove added user from video and input groups and remove yay packages -printf '\e[36mRemoving user from video and input groups and removing packages...\n\e[97m' +# Undo Step 1: Remove added user from video, i2c, and input groups and remove yay packages +printf '\e[36mRemoving user from video, i2c, and input groups and removing packages...\n\e[97m' user=$(whoami) v sudo deluser "$user" video +v sudo deluser "$user" i2c v sudo deluser "$user" input +v sudo rm /etc/modules-load.d/i2c-dev.conf ############################################################################################################################## read -p "Do you want to uninstall packages used by the dotfiles?\nCtrl+C to exit, or press Enter to proceed" # Removing installed yay packages and dependencies -v yay -Rns adw-gtk3-git brightnessctl cava foot fuzzel gjs gojq gradience-git grim gtk-layer-shell hyprland-git lexend-fonts-git libdbusmenu-gtk3 plasma-browser-integration playerctl python-build python-material-color-utilities python-poetry python-pywal ripgrep sassc swww slurp starship swayidle hyprlock-git tesseract ttf-jetbrains-mono-nerd ttf-material-symbols-variable-git ttf-space-mono-nerd typescript webp-pixbuf-loader wl-clipboard wlogout yad ydotool +v yay -Rns adw-gtk3-git brightnessctl cava ddcutil foot fuzzel gjs gojq gradience-git grim gtk-layer-shell hyprland-git lexend-fonts-git libdbusmenu-gtk3 plasma-browser-integration playerctl python-build python-material-color-utilities python-poetry python-pywal ripgrep sassc swww slurp starship swayidle hyprlock-git tesseract ttf-jetbrains-mono-nerd ttf-material-symbols-variable-git ttf-space-mono-nerd typescript webp-pixbuf-loader wl-clipboard wlogout yad ydotool printf '\e[36mUninstall Complete.\n\e[97m'