From 19120d4f9761c67d99ed1ce3da6084b83f5a49c9 Mon Sep 17 00:00:00 2001 From: srdusr Date: Sat, 30 Aug 2025 19:22:59 +0200 Subject: Linux-specific dotfiles --- linux/home/.config/Code/User/keybindings.json | 274 ++++++ linux/home/.config/Code/User/settings.json | 734 ++++++++++++++++ .../Code/User/snippets/snippet.code-snippets | 126 +++ linux/home/.config/Code/User/spellright.dict | 14 + linux/home/.config/Code/User/vsc.css | 408 +++++++++ linux/home/.config/Code/User/vsc.js | 100 +++ linux/home/.config/X11/.Xresources | 307 +++++++ linux/home/.config/X11/.xbindkeysrc | 31 + linux/home/.config/X11/.xinitrc | 34 + linux/home/.config/X11/.xprofile | 24 + linux/home/.config/ags/.eslintrc.yml | 130 +++ linux/home/.config/ags/.gitignore | 6 + linux/home/.config/ags/assets/arrows-down.svg | 10 + linux/home/.config/ags/assets/arrows-left.svg | 10 + linux/home/.config/ags/assets/arrows-right.svg | 10 + linux/home/.config/ags/assets/arrows-up.svg | 10 + .../.config/ags/assets/battery-flash-symbolic.svg | 4 + linux/home/.config/ags/assets/bomb-kill.svg | 36 + .../.config/ags/assets/chat-bubbles-symbolic.svg | 5 + .../.config/ags/assets/controller-symbolic.svg | 4 + .../home/.config/ags/assets/controls-symbolic.svg | 5 + .../home/.config/ags/assets/dark-mode-symbolic.svg | 4 + linux/home/.config/ags/assets/float.svg | 44 + linux/home/.config/ags/assets/fullscreen.svg | 43 + .../home/.config/ags/assets/hourglass-symbolic.svg | 4 + .../.config/ags/assets/light-mode-symbolic.svg | 4 + linux/home/.config/ags/assets/mixer-symbolic.svg | 6 + .../.config/ags/assets/nix-snowflake-symbolic.svg | 155 ++++ linux/home/.config/ags/assets/nixos-symbolic.svg | 155 ++++ linux/home/.config/ags/assets/nixos.svg | 277 ++++++ linux/home/.config/ags/assets/osk.svg | 132 +++ linux/home/.config/ags/assets/pinned.svg | 36 + .../assets/preferences-desktop-theme-symbolic.svg | 321 +++++++ .../home/.config/ags/assets/processor-symbolic.svg | 17 + linux/home/.config/ags/assets/rotation.svg | 8 + linux/home/.config/ags/assets/swapnext.svg | 8 + linux/home/.config/ags/assets/tbox-close.svg | 49 ++ .../home/.config/ags/assets/terminal-symbolic.svg | 5 + linux/home/.config/ags/assets/togglesplit.svg | 10 + .../home/.config/ags/assets/toolbars-symbolic.svg | 4 + linux/home/.config/ags/assets/wp-next.svg | 10 + linux/home/.config/ags/assets/wp-prev.svg | 10 + linux/home/.config/ags/config.js | 46 + linux/home/.config/ags/default.nix | 104 +++ linux/home/.config/ags/greeter.js | 18 + linux/home/.config/ags/greeter/auth.ts | 109 +++ linux/home/.config/ags/greeter/greeter.scss | 64 ++ linux/home/.config/ags/greeter/greeter.ts | 37 + linux/home/.config/ags/greeter/session.ts | 20 + linux/home/.config/ags/greeter/statusbar.ts | 46 + linux/home/.config/ags/lib/battery.ts | 16 + linux/home/.config/ags/lib/client.js | 134 +++ linux/home/.config/ags/lib/cursorhover.js | 86 ++ linux/home/.config/ags/lib/gtk.ts | 16 + linux/home/.config/ags/lib/hyprland.ts | 80 ++ linux/home/.config/ags/lib/iconUtils.js | 46 + linux/home/.config/ags/lib/icons.ts | 186 +++++ linux/home/.config/ags/lib/init.ts | 19 + linux/home/.config/ags/lib/matugen.ts | 113 +++ linux/home/.config/ags/lib/notifications.ts | 16 + linux/home/.config/ags/lib/option.ts | 115 +++ linux/home/.config/ags/lib/session.ts | 16 + linux/home/.config/ags/lib/tmux.ts | 14 + linux/home/.config/ags/lib/utils.ts | 113 +++ linux/home/.config/ags/lib/variables.ts | 47 ++ linux/home/.config/ags/main.ts | 47 ++ linux/home/.config/ags/options.ts | 261 ++++++ linux/home/.config/ags/package.json | 18 + linux/home/.config/ags/service/asusctl.ts | 52 ++ linux/home/.config/ags/service/brightness.ts | 69 ++ linux/home/.config/ags/service/colorpicker.ts | 56 ++ linux/home/.config/ags/service/nix.ts | 109 +++ linux/home/.config/ags/service/powermenu.ts | 43 + linux/home/.config/ags/service/screenrecord.ts | 102 +++ linux/home/.config/ags/service/wallpaper.ts | 127 +++ linux/home/.config/ags/service/weather.ts | 59 ++ linux/home/.config/ags/style/extra.scss | 67 ++ .../home/.config/ags/style/mixins/a11y-button.scss | 48 ++ linux/home/.config/ags/style/mixins/button.scss | 70 ++ .../.config/ags/style/mixins/floating-widget.scss | 12 + linux/home/.config/ags/style/mixins/hidden.scss | 15 + linux/home/.config/ags/style/mixins/media.scss | 42 + .../home/.config/ags/style/mixins/scrollable.scss | 42 + linux/home/.config/ags/style/mixins/slider.scss | 74 ++ linux/home/.config/ags/style/mixins/spacing.scss | 53 ++ linux/home/.config/ags/style/mixins/switch.scss | 16 + linux/home/.config/ags/style/mixins/unset.scss | 9 + linux/home/.config/ags/style/mixins/widget.scss | 7 + linux/home/.config/ags/style/style.ts | 103 +++ linux/home/.config/ags/tsconfig.json | 19 + linux/home/.config/ags/widget/PopupWindow.ts | 156 ++++ linux/home/.config/ags/widget/RegularWindow.ts | 3 + linux/home/.config/ags/widget/bar/Bar.ts | 57 ++ linux/home/.config/ags/widget/bar/PanelButton.ts | 46 + linux/home/.config/ags/widget/bar/ScreenCorners.ts | 25 + linux/home/.config/ags/widget/bar/bar.scss | 242 ++++++ .../.config/ags/widget/bar/buttons/BatteryBar.ts | 94 +++ .../.config/ags/widget/bar/buttons/ColorPicker.ts | 37 + linux/home/.config/ags/widget/bar/buttons/Date.ts | 15 + .../.config/ags/widget/bar/buttons/Launcher.ts | 49 ++ linux/home/.config/ags/widget/bar/buttons/Media.ts | 92 ++ .../.config/ags/widget/bar/buttons/Messages.ts | 16 + .../.config/ags/widget/bar/buttons/PowerMenu.ts | 15 + .../.config/ags/widget/bar/buttons/ScreenRecord.ts | 21 + .../home/.config/ags/widget/bar/buttons/SysTray.ts | 39 + .../ags/widget/bar/buttons/SystemIndicators.ts | 107 +++ .../home/.config/ags/widget/bar/buttons/Taskbar.ts | 90 ++ .../.config/ags/widget/bar/buttons/Workspaces.ts | 66 ++ .../home/.config/ags/widget/bar/screencorner.scss | 51 ++ .../home/.config/ags/widget/datemenu/DateColumn.ts | 58 ++ linux/home/.config/ags/widget/datemenu/DateMenu.ts | 36 + .../ags/widget/datemenu/NotificationColumn.ts | 113 +++ .../home/.config/ags/widget/datemenu/datemenu.scss | 110 +++ linux/home/.config/ags/widget/desktop/Desktop.ts | 40 + linux/home/.config/ags/widget/dock/Dock.ts | 150 ++++ linux/home/.config/ags/widget/dock/FloatingDock.ts | 70 ++ linux/home/.config/ags/widget/dock/ToolBox.ts | 122 +++ linux/home/.config/ags/widget/dock/ToolBoxDock.ts | 57 ++ linux/home/.config/ags/widget/dock/dock.scss | 73 ++ .../.config/ags/widget/launcher/AppLauncher.ts | 125 +++ linux/home/.config/ags/widget/launcher/Launcher.ts | 134 +++ linux/home/.config/ags/widget/launcher/NixRun.ts | 118 +++ linux/home/.config/ags/widget/launcher/ShRun.ts | 89 ++ .../home/.config/ags/widget/launcher/launcher.scss | 143 ++++ .../ags/widget/notifications/Notification.ts | 138 +++ .../ags/widget/notifications/NotificationPopups.ts | 90 ++ .../ags/widget/notifications/notifications.scss | 79 ++ linux/home/.config/ags/widget/osd/OSD.ts | 111 +++ linux/home/.config/ags/widget/osd/Progress.ts | 74 ++ linux/home/.config/ags/widget/osd/osd.scss | 26 + linux/home/.config/ags/widget/overview/Overview.ts | 41 + linux/home/.config/ags/widget/overview/Window.ts | 48 ++ .../home/.config/ags/widget/overview/Workspace.ts | 76 ++ .../home/.config/ags/widget/overview/overview.scss | 34 + .../home/.config/ags/widget/powermenu/PowerMenu.ts | 56 ++ .../.config/ags/widget/powermenu/Verification.ts | 47 ++ .../.config/ags/widget/powermenu/powermenu.scss | 110 +++ .../ags/widget/quicksettings/QuickSettings.ts | 84 ++ .../ags/widget/quicksettings/ToggleButton.ts | 154 ++++ .../ags/widget/quicksettings/quicksettings.scss | 177 ++++ .../ags/widget/quicksettings/widgets/Bluetooth.ts | 61 ++ .../ags/widget/quicksettings/widgets/Brightness.ts | 23 + .../ags/widget/quicksettings/widgets/DND.ts | 12 + .../ags/widget/quicksettings/widgets/DarkMode.ts | 12 + .../ags/widget/quicksettings/widgets/Header.ts | 69 ++ .../ags/widget/quicksettings/widgets/Media.ts | 153 ++++ .../ags/widget/quicksettings/widgets/MicMute.ts | 18 + .../ags/widget/quicksettings/widgets/Network.ts | 61 ++ .../widget/quicksettings/widgets/PowerProfile.ts | 99 +++ .../ags/widget/quicksettings/widgets/Volume.ts | 161 ++++ linux/home/.config/ags/widget/settings/Group.ts | 34 + linux/home/.config/ags/widget/settings/Page.ts | 19 + linux/home/.config/ags/widget/settings/Row.ts | 55 ++ linux/home/.config/ags/widget/settings/Setter.ts | 93 +++ .../.config/ags/widget/settings/SettingsDialog.ts | 63 ++ .../home/.config/ags/widget/settings/Wallpaper.ts | 31 + linux/home/.config/ags/widget/settings/layout.ts | 147 ++++ .../ags/widget/settings/settingsdialog.scss | 144 ++++ .../.config/betterlockscreen/betterlockscreenrc | 37 + linux/home/.config/bspwm/bspwmrc | 275 ++++++ linux/home/.config/bspwm/scripts/bspdragtofloat | 46 + linux/home/.config/bspwm/scripts/bspswallow | 12 + linux/home/.config/bspwm/scripts/bspwindows | 14 + .../home/.config/bspwm/scripts/bspwm-monitor-setup | 59 ++ .../bspwm/scripts/bspwm-toggle-visibility.sh | 23 + linux/home/.config/bspwm/scripts/close-window | 11 + linux/home/.config/bspwm/scripts/drag-float | 42 + linux/home/.config/bspwm/scripts/external_rules.sh | 71 ++ linux/home/.config/bspwm/scripts/hide-window | 38 + .../.config/dunst/assets/notification/fallback.png | Bin 0 -> 54750 bytes .../.config/dunst/assets/notification/music.png | Bin 0 -> 814 bytes .../.config/dunst/assets/notification/scrot.png | Bin 0 -> 35737 bytes linux/home/.config/dunst/assets/ui/volume-high.svg | 1 + linux/home/.config/dunst/assets/ui/volume-low.svg | 1 + .../home/.config/dunst/assets/ui/volume-medium.svg | 1 + .../home/.config/dunst/assets/ui/volume-muted.svg | 1 + linux/home/.config/dunst/dunstrc | 456 ++++++++++ linux/home/.config/dunst/scripts/openEwwPopup.sh | 36 + linux/home/.config/dunst/scripts/songArtLogger.sh | 17 + linux/home/.config/eww/eww.scss | 11 + linux/home/.config/eww/eww.yuck | 23 + linux/home/.config/hypr/autostart | 34 + linux/home/.config/hypr/hyprland.conf | 175 ++++ linux/home/.config/hypr/scripts/move-scratchpad.sh | 9 + linux/home/.config/hypr/user/binds.conf | 167 ++++ linux/home/.config/hypr/user/env.conf | 23 + linux/home/.config/hypr/user/exec.conf | 4 + linux/home/.config/hypr/user/monitors.conf | 4 + linux/home/.config/hypr/user/window_rules.conf | 70 ++ linux/home/.config/inputrc | 86 ++ linux/home/.config/jgmenu/jgmenurc | 32 + linux/home/.config/jgmenu/menu.csv | 32 + linux/home/.config/kitty/kitty.conf | 827 ++++++++++++++++++ linux/home/.config/mimeapps.list | 14 + linux/home/.config/picom/picom.conf | 494 +++++++++++ .../plank/dock/launchers/Alacritty.dockitem | 2 + .../dock/launchers/com.obsproject.Studio.dockitem | 2 + .../.config/plank/dock/launchers/discord.dockitem | 2 + .../.config/plank/dock/launchers/firefox.dockitem | 2 + .../.config/plank/dock/launchers/gimp.dockitem | 2 + .../plank/dock/launchers/google-chrome.dockitem | 2 + .../.config/plank/dock/launchers/obsidian.dockitem | 2 + .../dock/launchers/org.gnome.Nautilus.dockitem | 2 + .../.config/plank/dock/launchers/spotify.dockitem | 2 + .../.config/plank/dock/launchers/steam.dockitem | 2 + .../.config/plank/dock/launchers/trash.dockitem | 2 + .../plank/dock/launchers/virtualbox.dockitem | 2 + .../home/.config/plank/dock/launchers/vlc.dockitem | 2 + .../plank/dock1/launchers/code-oss.dockitem | 2 + .../dock1/launchers/com.obsproject.Studio.dockitem | 2 + .../.config/plank/dock1/launchers/discord.dockitem | 2 + .../.config/plank/dock1/launchers/firefox.dockitem | 2 + .../plank/dock1/launchers/obsidian.dockitem | 2 + .../launchers/org.qbittorrent.qBittorrent.dockitem | 2 + .../.config/plank/dock1/launchers/pcmanfm.dockitem | 2 + .../plank/dock1/launchers/phototonic.dockitem | 2 + .../.config/plank/dock1/launchers/steam.dockitem | 2 + .../.config/plank/dock1/launchers/trash.dockitem | 2 + .../.config/plank/dock1/launchers/vlc.dockitem | 2 + linux/home/.config/polybar/config.ini | 671 +++++++++++++++ linux/home/.config/polybar/launch.sh | 31 + linux/home/.config/polybar/scripts/bluetooth.sh | 12 + .../home/.config/polybar/scripts/check-network.sh | 21 + .../home/.config/polybar/scripts/check_updates.sh | 118 +++ linux/home/.config/polybar/scripts/cmus.sh | 39 + .../.config/polybar/scripts/get_spotify_status.sh | 52 ++ linux/home/.config/polybar/scripts/menu.sh | 6 + linux/home/.config/polybar/scripts/menu.shsave | 63 ++ linux/home/.config/polybar/scripts/menu_full.sh | 65 ++ linux/home/.config/polybar/scripts/now-playing.sh | 217 +++++ linux/home/.config/polybar/scripts/polybar_wrapper | 92 ++ .../home/.config/polybar/scripts/popup-calendar.sh | 41 + linux/home/.config/polybar/scripts/rofi-power.sh | 45 + .../polybar/scripts/scroll_spotify_status.sh | 12 + linux/home/.config/polybar/scripts/sysmenu.sh | 42 + linux/home/.config/polybar/scripts/sysmenu.shsave | 40 + .../.config/polybar/scripts/system-usb-mount.sh | 53 ++ linux/home/.config/polybar/scripts/temperature.sh | 18 + .../.config/polybar/scripts/toggle_bluetooth.sh | 8 + linux/home/.config/polybar/scripts/vpn.sh | 28 + .../powershell/Microsoft.PowerShell_profile.ps1 | 14 + linux/home/.config/powershell/bloatware.ps1 | 335 ++++++++ linux/home/.config/powershell/bootstrap.ps1 | 396 +++++++++ linux/home/.config/powershell/initialize.ps1 | 227 +++++ linux/home/.config/pypoetry/config.toml | 3 + linux/home/.config/rofi/Notif.rasi | 153 ++++ linux/home/.config/rofi/colors/gruvbox.rasi | 10 + linux/home/.config/rofi/colors/nord.rasi | 10 + linux/home/.config/rofi/colors/simple.rasi | 10 + linux/home/.config/rofi/config.rasi | 178 ++++ linux/home/.config/rofi/options_menu.rasi | 71 ++ linux/home/.config/rofi/rofi-network-manager.conf | 41 + linux/home/.config/rofi/rofi-network-manager.rasi | 127 +++ linux/home/.config/rofi/styles/appmenu.rasi | 186 +++++ linux/home/.config/rofi/styles/powermenu.rasi | 187 +++++ linux/home/.config/rofi/themes/colors.rasi | 18 + linux/home/.config/rofi/themes/dmenu.rasi | 38 + linux/home/.config/rofi/themes/power.rasi | 34 + linux/home/.config/sxhkd/show_help.sh | 3 + linux/home/.config/sxhkd/sxhkdrc | 490 +++++++++++ linux/home/.config/tridactyl/tridactylrc | 170 ++++ linux/home/.config/user-dirs.dirs | 15 + linux/home/.config/user-dirs.locale | 1 + linux/home/.config/waybar/config.jsonc | 292 +++++++ linux/home/.config/waybar/style.css | 434 ++++++++++ linux/home/.config/wezterm/wezterm.lua | 206 +++++ linux/home/.config/windows-terminal/settings.json | 590 +++++++++++++ linux/home/.config/wofi/config | 17 + linux/home/.config/wofi/style.css | 99 +++ linux/home/.config/xkb/symbols/custom-us | 27 + linux/home/.config/xob/launch.sh | 10 + linux/home/.config/xob/manage-brightness | 16 + linux/home/.config/xob/manage-microphone | 56 ++ linux/home/.config/xob/manage-volume | 46 + linux/home/.config/xob/styles.cfg | 100 +++ linux/home/.config/zathura/zathurarc | 27 + linux/home/.config/zsh/.zshenv | 348 ++++++++ linux/home/.config/zsh/.zshrc | 63 ++ linux/home/.config/zsh/user/aliases.zsh | 129 +++ linux/home/.config/zsh/user/bindings.zsh | 39 + linux/home/.config/zsh/user/completion.zsh | 156 ++++ linux/home/.config/zsh/user/functions.zsh | 813 ++++++++++++++++++ linux/home/.config/zsh/user/options.zsh | 50 ++ linux/home/.config/zsh/user/prompt.zsh | 202 +++++ linux/home/.editorconfig | 76 ++ linux/home/.face | Bin 0 -> 11569 bytes linux/home/.gitconfig | 28 + linux/home/.github/workflows/release.yml | 59 ++ linux/home/.gitignore | 48 ++ linux/home/.gitmodules | 12 + linux/home/.gitsubtrees | 8 + linux/home/.local/bin/control-center | 31 + linux/home/.local/bin/eww | Bin 0 -> 22225024 bytes linux/home/.local/bin/ffmpeg | 24 + linux/home/.local/bin/nitrogen | 63 ++ linux/home/.local/bin/notification-center | 26 + linux/home/.local/bin/xcolor-pick | 31 + .../applications/com.obsproject.Studio.desktop | 99 +++ .../.local/share/applications/phototonic.desktop | 17 + .../.local/share/fonts/fantasque_sans_mono.ttf | Bin 0 -> 140224 bytes .../.local/share/fonts/fira_code_nerd_fonts.ttf | Bin 0 -> 1149928 bytes .../.local/share/fonts/hack_nerd_fonts_mono.ttf | Bin 0 -> 1169264 bytes .../home/.local/share/fonts/iosevka_nerd_font.ttf | Bin 0 -> 1301148 bytes .../share/fonts/material_design_iconic_font.ttf | Bin 0 -> 99212 bytes linux/home/.local/share/fonts/symbola.ttf | Bin 0 -> 3424752 bytes linux/home/.prettierrc.yml | 5 + linux/home/.profile | 16 + linux/home/.scripts/Heads-Up-Display | 28 + linux/home/.scripts/README.md | 1 + linux/home/.scripts/bspwm-toggle-visibility.sh | 23 + linux/home/.scripts/bspwm_resize.sh | 67 ++ linux/home/.scripts/check-updates.sh | 0 linux/home/.scripts/colors.sh | 78 ++ linux/home/.scripts/cryptocheck | 31 + linux/home/.scripts/cryptonotify | 19 + linux/home/.scripts/dotfiles.sh | 37 + linux/home/.scripts/ffmpeg | 24 + linux/home/.scripts/get_zle_keymap_select.sh | 13 + linux/home/.scripts/gsettings.sh | 27 + linux/home/.scripts/killandnotify | 4 + linux/home/.scripts/layer.sh | 24 + linux/home/.scripts/neovim.sh | 421 ++++++++++ linux/home/.scripts/opacity-change.sh | 34 + linux/home/.scripts/powermenu | 38 + linux/home/.scripts/qemu-helper.sh | 172 ++++ linux/home/.scripts/random_data.py | 153 ++++ linux/home/.scripts/scratchpad | 64 ++ linux/home/.scripts/spec | 73 ++ linux/home/.scripts/track-books.sh | 19 + linux/home/.scripts/win-nvim.bat | 37 + linux/home/.scripts/win-nvim.ps1 | 39 + linux/home/.vim/autoload/statusline.vim | 227 +++++ .../.vim/pack/plugins/start/vim-tmux-navigator | 1 + linux/home/.vim/vimrc | 296 +++++++ linux/home/.vnc/config | 4 + linux/home/.vnc/xstartup | 16 + linux/home/README.md | 698 ++++++++++++++++ linux/home/assets/desktop.jpg | Bin 0 -> 523045 bytes linux/home/assets/old_desktop.jpg | Bin 0 -> 108709 bytes .../extras/etc/X11/xorg.conf.d/70-synaptics.conf | 15 + linux/home/extras/etc/issue | 14 + .../extras/etc/lightdm/lightdm-gtk-greeter.conf | 17 + .../etc/lightdm/lightdm-webkit2-greeter.conf | 49 ++ linux/home/extras/etc/lightdm/lightdm.conf | 161 ++++ .../etc/udev/rules.d/99-reload-monitor.rules | 1 + linux/home/install.bat | 6 + linux/home/install.sh | 927 +++++++++++++++++++++ linux/home/packages.yml | 436 ++++++++++ 348 files changed, 27966 insertions(+) create mode 100644 linux/home/.config/Code/User/keybindings.json create mode 100644 linux/home/.config/Code/User/settings.json create mode 100644 linux/home/.config/Code/User/snippets/snippet.code-snippets create mode 100644 linux/home/.config/Code/User/spellright.dict create mode 100644 linux/home/.config/Code/User/vsc.css create mode 100644 linux/home/.config/Code/User/vsc.js create mode 100644 linux/home/.config/X11/.Xresources create mode 100644 linux/home/.config/X11/.xbindkeysrc create mode 100755 linux/home/.config/X11/.xinitrc create mode 100644 linux/home/.config/X11/.xprofile create mode 100644 linux/home/.config/ags/.eslintrc.yml create mode 100644 linux/home/.config/ags/.gitignore create mode 100644 linux/home/.config/ags/assets/arrows-down.svg create mode 100644 linux/home/.config/ags/assets/arrows-left.svg create mode 100644 linux/home/.config/ags/assets/arrows-right.svg create mode 100644 linux/home/.config/ags/assets/arrows-up.svg create mode 100644 linux/home/.config/ags/assets/battery-flash-symbolic.svg create mode 100644 linux/home/.config/ags/assets/bomb-kill.svg create mode 100644 linux/home/.config/ags/assets/chat-bubbles-symbolic.svg create mode 100644 linux/home/.config/ags/assets/controller-symbolic.svg create mode 100644 linux/home/.config/ags/assets/controls-symbolic.svg create mode 100644 linux/home/.config/ags/assets/dark-mode-symbolic.svg create mode 100644 linux/home/.config/ags/assets/float.svg create mode 100644 linux/home/.config/ags/assets/fullscreen.svg create mode 100644 linux/home/.config/ags/assets/hourglass-symbolic.svg create mode 100644 linux/home/.config/ags/assets/light-mode-symbolic.svg create mode 100644 linux/home/.config/ags/assets/mixer-symbolic.svg create mode 100644 linux/home/.config/ags/assets/nix-snowflake-symbolic.svg create mode 100644 linux/home/.config/ags/assets/nixos-symbolic.svg create mode 100644 linux/home/.config/ags/assets/nixos.svg create mode 100644 linux/home/.config/ags/assets/osk.svg create mode 100644 linux/home/.config/ags/assets/pinned.svg create mode 100644 linux/home/.config/ags/assets/preferences-desktop-theme-symbolic.svg create mode 100644 linux/home/.config/ags/assets/processor-symbolic.svg create mode 100644 linux/home/.config/ags/assets/rotation.svg create mode 100644 linux/home/.config/ags/assets/swapnext.svg create mode 100644 linux/home/.config/ags/assets/tbox-close.svg create mode 100644 linux/home/.config/ags/assets/terminal-symbolic.svg create mode 100644 linux/home/.config/ags/assets/togglesplit.svg create mode 100644 linux/home/.config/ags/assets/toolbars-symbolic.svg create mode 100644 linux/home/.config/ags/assets/wp-next.svg create mode 100644 linux/home/.config/ags/assets/wp-prev.svg create mode 100644 linux/home/.config/ags/config.js create mode 100644 linux/home/.config/ags/default.nix create mode 100644 linux/home/.config/ags/greeter.js create mode 100644 linux/home/.config/ags/greeter/auth.ts create mode 100644 linux/home/.config/ags/greeter/greeter.scss create mode 100644 linux/home/.config/ags/greeter/greeter.ts create mode 100644 linux/home/.config/ags/greeter/session.ts create mode 100644 linux/home/.config/ags/greeter/statusbar.ts create mode 100644 linux/home/.config/ags/lib/battery.ts create mode 100644 linux/home/.config/ags/lib/client.js create mode 100644 linux/home/.config/ags/lib/cursorhover.js create mode 100644 linux/home/.config/ags/lib/gtk.ts create mode 100644 linux/home/.config/ags/lib/hyprland.ts create mode 100644 linux/home/.config/ags/lib/iconUtils.js create mode 100644 linux/home/.config/ags/lib/icons.ts create mode 100644 linux/home/.config/ags/lib/init.ts create mode 100644 linux/home/.config/ags/lib/matugen.ts create mode 100644 linux/home/.config/ags/lib/notifications.ts create mode 100644 linux/home/.config/ags/lib/option.ts create mode 100644 linux/home/.config/ags/lib/session.ts create mode 100644 linux/home/.config/ags/lib/tmux.ts create mode 100644 linux/home/.config/ags/lib/utils.ts create mode 100644 linux/home/.config/ags/lib/variables.ts create mode 100644 linux/home/.config/ags/main.ts create mode 100644 linux/home/.config/ags/options.ts create mode 100644 linux/home/.config/ags/package.json create mode 100644 linux/home/.config/ags/service/asusctl.ts create mode 100644 linux/home/.config/ags/service/brightness.ts create mode 100644 linux/home/.config/ags/service/colorpicker.ts create mode 100644 linux/home/.config/ags/service/nix.ts create mode 100644 linux/home/.config/ags/service/powermenu.ts create mode 100644 linux/home/.config/ags/service/screenrecord.ts create mode 100644 linux/home/.config/ags/service/wallpaper.ts create mode 100644 linux/home/.config/ags/service/weather.ts create mode 100644 linux/home/.config/ags/style/extra.scss create mode 100644 linux/home/.config/ags/style/mixins/a11y-button.scss create mode 100644 linux/home/.config/ags/style/mixins/button.scss create mode 100644 linux/home/.config/ags/style/mixins/floating-widget.scss create mode 100644 linux/home/.config/ags/style/mixins/hidden.scss create mode 100644 linux/home/.config/ags/style/mixins/media.scss create mode 100644 linux/home/.config/ags/style/mixins/scrollable.scss create mode 100644 linux/home/.config/ags/style/mixins/slider.scss create mode 100644 linux/home/.config/ags/style/mixins/spacing.scss create mode 100644 linux/home/.config/ags/style/mixins/switch.scss create mode 100644 linux/home/.config/ags/style/mixins/unset.scss create mode 100644 linux/home/.config/ags/style/mixins/widget.scss create mode 100644 linux/home/.config/ags/style/style.ts create mode 100644 linux/home/.config/ags/tsconfig.json create mode 100644 linux/home/.config/ags/widget/PopupWindow.ts create mode 100644 linux/home/.config/ags/widget/RegularWindow.ts create mode 100644 linux/home/.config/ags/widget/bar/Bar.ts create mode 100644 linux/home/.config/ags/widget/bar/PanelButton.ts create mode 100644 linux/home/.config/ags/widget/bar/ScreenCorners.ts create mode 100644 linux/home/.config/ags/widget/bar/bar.scss create mode 100644 linux/home/.config/ags/widget/bar/buttons/BatteryBar.ts create mode 100644 linux/home/.config/ags/widget/bar/buttons/ColorPicker.ts create mode 100644 linux/home/.config/ags/widget/bar/buttons/Date.ts create mode 100644 linux/home/.config/ags/widget/bar/buttons/Launcher.ts create mode 100644 linux/home/.config/ags/widget/bar/buttons/Media.ts create mode 100644 linux/home/.config/ags/widget/bar/buttons/Messages.ts create mode 100644 linux/home/.config/ags/widget/bar/buttons/PowerMenu.ts create mode 100644 linux/home/.config/ags/widget/bar/buttons/ScreenRecord.ts create mode 100644 linux/home/.config/ags/widget/bar/buttons/SysTray.ts create mode 100644 linux/home/.config/ags/widget/bar/buttons/SystemIndicators.ts create mode 100644 linux/home/.config/ags/widget/bar/buttons/Taskbar.ts create mode 100644 linux/home/.config/ags/widget/bar/buttons/Workspaces.ts create mode 100644 linux/home/.config/ags/widget/bar/screencorner.scss create mode 100644 linux/home/.config/ags/widget/datemenu/DateColumn.ts create mode 100644 linux/home/.config/ags/widget/datemenu/DateMenu.ts create mode 100644 linux/home/.config/ags/widget/datemenu/NotificationColumn.ts create mode 100644 linux/home/.config/ags/widget/datemenu/datemenu.scss create mode 100644 linux/home/.config/ags/widget/desktop/Desktop.ts create mode 100644 linux/home/.config/ags/widget/dock/Dock.ts create mode 100644 linux/home/.config/ags/widget/dock/FloatingDock.ts create mode 100644 linux/home/.config/ags/widget/dock/ToolBox.ts create mode 100644 linux/home/.config/ags/widget/dock/ToolBoxDock.ts create mode 100644 linux/home/.config/ags/widget/dock/dock.scss create mode 100644 linux/home/.config/ags/widget/launcher/AppLauncher.ts create mode 100644 linux/home/.config/ags/widget/launcher/Launcher.ts create mode 100644 linux/home/.config/ags/widget/launcher/NixRun.ts create mode 100644 linux/home/.config/ags/widget/launcher/ShRun.ts create mode 100644 linux/home/.config/ags/widget/launcher/launcher.scss create mode 100644 linux/home/.config/ags/widget/notifications/Notification.ts create mode 100644 linux/home/.config/ags/widget/notifications/NotificationPopups.ts create mode 100644 linux/home/.config/ags/widget/notifications/notifications.scss create mode 100644 linux/home/.config/ags/widget/osd/OSD.ts create mode 100644 linux/home/.config/ags/widget/osd/Progress.ts create mode 100644 linux/home/.config/ags/widget/osd/osd.scss create mode 100644 linux/home/.config/ags/widget/overview/Overview.ts create mode 100644 linux/home/.config/ags/widget/overview/Window.ts create mode 100644 linux/home/.config/ags/widget/overview/Workspace.ts create mode 100644 linux/home/.config/ags/widget/overview/overview.scss create mode 100644 linux/home/.config/ags/widget/powermenu/PowerMenu.ts create mode 100644 linux/home/.config/ags/widget/powermenu/Verification.ts create mode 100644 linux/home/.config/ags/widget/powermenu/powermenu.scss create mode 100644 linux/home/.config/ags/widget/quicksettings/QuickSettings.ts create mode 100644 linux/home/.config/ags/widget/quicksettings/ToggleButton.ts create mode 100644 linux/home/.config/ags/widget/quicksettings/quicksettings.scss create mode 100644 linux/home/.config/ags/widget/quicksettings/widgets/Bluetooth.ts create mode 100644 linux/home/.config/ags/widget/quicksettings/widgets/Brightness.ts create mode 100644 linux/home/.config/ags/widget/quicksettings/widgets/DND.ts create mode 100644 linux/home/.config/ags/widget/quicksettings/widgets/DarkMode.ts create mode 100644 linux/home/.config/ags/widget/quicksettings/widgets/Header.ts create mode 100644 linux/home/.config/ags/widget/quicksettings/widgets/Media.ts create mode 100644 linux/home/.config/ags/widget/quicksettings/widgets/MicMute.ts create mode 100644 linux/home/.config/ags/widget/quicksettings/widgets/Network.ts create mode 100644 linux/home/.config/ags/widget/quicksettings/widgets/PowerProfile.ts create mode 100644 linux/home/.config/ags/widget/quicksettings/widgets/Volume.ts create mode 100644 linux/home/.config/ags/widget/settings/Group.ts create mode 100644 linux/home/.config/ags/widget/settings/Page.ts create mode 100644 linux/home/.config/ags/widget/settings/Row.ts create mode 100644 linux/home/.config/ags/widget/settings/Setter.ts create mode 100644 linux/home/.config/ags/widget/settings/SettingsDialog.ts create mode 100644 linux/home/.config/ags/widget/settings/Wallpaper.ts create mode 100644 linux/home/.config/ags/widget/settings/layout.ts create mode 100644 linux/home/.config/ags/widget/settings/settingsdialog.scss create mode 100644 linux/home/.config/betterlockscreen/betterlockscreenrc create mode 100755 linux/home/.config/bspwm/bspwmrc create mode 100755 linux/home/.config/bspwm/scripts/bspdragtofloat create mode 100755 linux/home/.config/bspwm/scripts/bspswallow create mode 100755 linux/home/.config/bspwm/scripts/bspwindows create mode 100755 linux/home/.config/bspwm/scripts/bspwm-monitor-setup create mode 100755 linux/home/.config/bspwm/scripts/bspwm-toggle-visibility.sh create mode 100755 linux/home/.config/bspwm/scripts/close-window create mode 100755 linux/home/.config/bspwm/scripts/drag-float create mode 100755 linux/home/.config/bspwm/scripts/external_rules.sh create mode 100755 linux/home/.config/bspwm/scripts/hide-window create mode 100644 linux/home/.config/dunst/assets/notification/fallback.png create mode 100644 linux/home/.config/dunst/assets/notification/music.png create mode 100644 linux/home/.config/dunst/assets/notification/scrot.png create mode 100644 linux/home/.config/dunst/assets/ui/volume-high.svg create mode 100644 linux/home/.config/dunst/assets/ui/volume-low.svg create mode 100644 linux/home/.config/dunst/assets/ui/volume-medium.svg create mode 100644 linux/home/.config/dunst/assets/ui/volume-muted.svg create mode 100644 linux/home/.config/dunst/dunstrc create mode 100755 linux/home/.config/dunst/scripts/openEwwPopup.sh create mode 100755 linux/home/.config/dunst/scripts/songArtLogger.sh create mode 100644 linux/home/.config/eww/eww.scss create mode 100644 linux/home/.config/eww/eww.yuck create mode 100755 linux/home/.config/hypr/autostart create mode 100644 linux/home/.config/hypr/hyprland.conf create mode 100755 linux/home/.config/hypr/scripts/move-scratchpad.sh create mode 100644 linux/home/.config/hypr/user/binds.conf create mode 100644 linux/home/.config/hypr/user/env.conf create mode 100644 linux/home/.config/hypr/user/exec.conf create mode 100644 linux/home/.config/hypr/user/monitors.conf create mode 100644 linux/home/.config/hypr/user/window_rules.conf create mode 100644 linux/home/.config/inputrc create mode 100644 linux/home/.config/jgmenu/jgmenurc create mode 100644 linux/home/.config/jgmenu/menu.csv create mode 100644 linux/home/.config/kitty/kitty.conf create mode 100644 linux/home/.config/mimeapps.list create mode 100644 linux/home/.config/picom/picom.conf create mode 100644 linux/home/.config/plank/dock/launchers/Alacritty.dockitem create mode 100644 linux/home/.config/plank/dock/launchers/com.obsproject.Studio.dockitem create mode 100644 linux/home/.config/plank/dock/launchers/discord.dockitem create mode 100644 linux/home/.config/plank/dock/launchers/firefox.dockitem create mode 100644 linux/home/.config/plank/dock/launchers/gimp.dockitem create mode 100644 linux/home/.config/plank/dock/launchers/google-chrome.dockitem create mode 100644 linux/home/.config/plank/dock/launchers/obsidian.dockitem create mode 100644 linux/home/.config/plank/dock/launchers/org.gnome.Nautilus.dockitem create mode 100644 linux/home/.config/plank/dock/launchers/spotify.dockitem create mode 100644 linux/home/.config/plank/dock/launchers/steam.dockitem create mode 100644 linux/home/.config/plank/dock/launchers/trash.dockitem create mode 100644 linux/home/.config/plank/dock/launchers/virtualbox.dockitem create mode 100644 linux/home/.config/plank/dock/launchers/vlc.dockitem create mode 100644 linux/home/.config/plank/dock1/launchers/code-oss.dockitem create mode 100644 linux/home/.config/plank/dock1/launchers/com.obsproject.Studio.dockitem create mode 100644 linux/home/.config/plank/dock1/launchers/discord.dockitem create mode 100644 linux/home/.config/plank/dock1/launchers/firefox.dockitem create mode 100644 linux/home/.config/plank/dock1/launchers/obsidian.dockitem create mode 100644 linux/home/.config/plank/dock1/launchers/org.qbittorrent.qBittorrent.dockitem create mode 100644 linux/home/.config/plank/dock1/launchers/pcmanfm.dockitem create mode 100644 linux/home/.config/plank/dock1/launchers/phototonic.dockitem create mode 100644 linux/home/.config/plank/dock1/launchers/steam.dockitem create mode 100644 linux/home/.config/plank/dock1/launchers/trash.dockitem create mode 100644 linux/home/.config/plank/dock1/launchers/vlc.dockitem create mode 100644 linux/home/.config/polybar/config.ini create mode 100755 linux/home/.config/polybar/launch.sh create mode 100755 linux/home/.config/polybar/scripts/bluetooth.sh create mode 100755 linux/home/.config/polybar/scripts/check-network.sh create mode 100755 linux/home/.config/polybar/scripts/check_updates.sh create mode 100755 linux/home/.config/polybar/scripts/cmus.sh create mode 100755 linux/home/.config/polybar/scripts/get_spotify_status.sh create mode 100755 linux/home/.config/polybar/scripts/menu.sh create mode 100755 linux/home/.config/polybar/scripts/menu.shsave create mode 100755 linux/home/.config/polybar/scripts/menu_full.sh create mode 100755 linux/home/.config/polybar/scripts/now-playing.sh create mode 100755 linux/home/.config/polybar/scripts/polybar_wrapper create mode 100755 linux/home/.config/polybar/scripts/popup-calendar.sh create mode 100755 linux/home/.config/polybar/scripts/rofi-power.sh create mode 100755 linux/home/.config/polybar/scripts/scroll_spotify_status.sh create mode 100755 linux/home/.config/polybar/scripts/sysmenu.sh create mode 100755 linux/home/.config/polybar/scripts/sysmenu.shsave create mode 100755 linux/home/.config/polybar/scripts/system-usb-mount.sh create mode 100755 linux/home/.config/polybar/scripts/temperature.sh create mode 100755 linux/home/.config/polybar/scripts/toggle_bluetooth.sh create mode 100755 linux/home/.config/polybar/scripts/vpn.sh create mode 100644 linux/home/.config/powershell/Microsoft.PowerShell_profile.ps1 create mode 100644 linux/home/.config/powershell/bloatware.ps1 create mode 100644 linux/home/.config/powershell/bootstrap.ps1 create mode 100644 linux/home/.config/powershell/initialize.ps1 create mode 100644 linux/home/.config/pypoetry/config.toml create mode 100644 linux/home/.config/rofi/Notif.rasi create mode 100644 linux/home/.config/rofi/colors/gruvbox.rasi create mode 100644 linux/home/.config/rofi/colors/nord.rasi create mode 100644 linux/home/.config/rofi/colors/simple.rasi create mode 100644 linux/home/.config/rofi/config.rasi create mode 100644 linux/home/.config/rofi/options_menu.rasi create mode 100644 linux/home/.config/rofi/rofi-network-manager.conf create mode 100644 linux/home/.config/rofi/rofi-network-manager.rasi create mode 100644 linux/home/.config/rofi/styles/appmenu.rasi create mode 100644 linux/home/.config/rofi/styles/powermenu.rasi create mode 100644 linux/home/.config/rofi/themes/colors.rasi create mode 100644 linux/home/.config/rofi/themes/dmenu.rasi create mode 100644 linux/home/.config/rofi/themes/power.rasi create mode 100755 linux/home/.config/sxhkd/show_help.sh create mode 100755 linux/home/.config/sxhkd/sxhkdrc create mode 100644 linux/home/.config/tridactyl/tridactylrc create mode 100644 linux/home/.config/user-dirs.dirs create mode 100644 linux/home/.config/user-dirs.locale create mode 100644 linux/home/.config/waybar/config.jsonc create mode 100644 linux/home/.config/waybar/style.css create mode 100644 linux/home/.config/wezterm/wezterm.lua create mode 100644 linux/home/.config/windows-terminal/settings.json create mode 100644 linux/home/.config/wofi/config create mode 100644 linux/home/.config/wofi/style.css create mode 100644 linux/home/.config/xkb/symbols/custom-us create mode 100755 linux/home/.config/xob/launch.sh create mode 100755 linux/home/.config/xob/manage-brightness create mode 100755 linux/home/.config/xob/manage-microphone create mode 100755 linux/home/.config/xob/manage-volume create mode 100644 linux/home/.config/xob/styles.cfg create mode 100644 linux/home/.config/zathura/zathurarc create mode 100644 linux/home/.config/zsh/.zshenv create mode 100644 linux/home/.config/zsh/.zshrc create mode 100644 linux/home/.config/zsh/user/aliases.zsh create mode 100644 linux/home/.config/zsh/user/bindings.zsh create mode 100644 linux/home/.config/zsh/user/completion.zsh create mode 100644 linux/home/.config/zsh/user/functions.zsh create mode 100644 linux/home/.config/zsh/user/options.zsh create mode 100644 linux/home/.config/zsh/user/prompt.zsh create mode 100644 linux/home/.editorconfig create mode 100644 linux/home/.face create mode 100644 linux/home/.gitconfig create mode 100644 linux/home/.github/workflows/release.yml create mode 100644 linux/home/.gitignore create mode 100644 linux/home/.gitmodules create mode 100644 linux/home/.gitsubtrees create mode 100755 linux/home/.local/bin/control-center create mode 100755 linux/home/.local/bin/eww create mode 100755 linux/home/.local/bin/ffmpeg create mode 100755 linux/home/.local/bin/nitrogen create mode 100755 linux/home/.local/bin/notification-center create mode 100755 linux/home/.local/bin/xcolor-pick create mode 100644 linux/home/.local/share/applications/com.obsproject.Studio.desktop create mode 100644 linux/home/.local/share/applications/phototonic.desktop create mode 100644 linux/home/.local/share/fonts/fantasque_sans_mono.ttf create mode 100644 linux/home/.local/share/fonts/fira_code_nerd_fonts.ttf create mode 100644 linux/home/.local/share/fonts/hack_nerd_fonts_mono.ttf create mode 100644 linux/home/.local/share/fonts/iosevka_nerd_font.ttf create mode 100644 linux/home/.local/share/fonts/material_design_iconic_font.ttf create mode 100644 linux/home/.local/share/fonts/symbola.ttf create mode 100644 linux/home/.prettierrc.yml create mode 100644 linux/home/.profile create mode 100755 linux/home/.scripts/Heads-Up-Display create mode 100644 linux/home/.scripts/README.md create mode 100755 linux/home/.scripts/bspwm-toggle-visibility.sh create mode 100755 linux/home/.scripts/bspwm_resize.sh create mode 100644 linux/home/.scripts/check-updates.sh create mode 100755 linux/home/.scripts/colors.sh create mode 100755 linux/home/.scripts/cryptocheck create mode 100755 linux/home/.scripts/cryptonotify create mode 100755 linux/home/.scripts/dotfiles.sh create mode 100755 linux/home/.scripts/ffmpeg create mode 100755 linux/home/.scripts/get_zle_keymap_select.sh create mode 100755 linux/home/.scripts/gsettings.sh create mode 100755 linux/home/.scripts/killandnotify create mode 100755 linux/home/.scripts/layer.sh create mode 100755 linux/home/.scripts/neovim.sh create mode 100755 linux/home/.scripts/opacity-change.sh create mode 100755 linux/home/.scripts/powermenu create mode 100755 linux/home/.scripts/qemu-helper.sh create mode 100755 linux/home/.scripts/random_data.py create mode 100755 linux/home/.scripts/scratchpad create mode 100755 linux/home/.scripts/spec create mode 100755 linux/home/.scripts/track-books.sh create mode 100644 linux/home/.scripts/win-nvim.bat create mode 100644 linux/home/.scripts/win-nvim.ps1 create mode 100644 linux/home/.vim/autoload/statusline.vim create mode 160000 linux/home/.vim/pack/plugins/start/vim-tmux-navigator create mode 100644 linux/home/.vim/vimrc create mode 100644 linux/home/.vnc/config create mode 100755 linux/home/.vnc/xstartup create mode 100644 linux/home/README.md create mode 100644 linux/home/assets/desktop.jpg create mode 100644 linux/home/assets/old_desktop.jpg create mode 100644 linux/home/extras/etc/X11/xorg.conf.d/70-synaptics.conf create mode 100644 linux/home/extras/etc/issue create mode 100644 linux/home/extras/etc/lightdm/lightdm-gtk-greeter.conf create mode 100644 linux/home/extras/etc/lightdm/lightdm-webkit2-greeter.conf create mode 100644 linux/home/extras/etc/lightdm/lightdm.conf create mode 100644 linux/home/extras/etc/udev/rules.d/99-reload-monitor.rules create mode 100644 linux/home/install.bat create mode 100755 linux/home/install.sh create mode 100644 linux/home/packages.yml (limited to 'linux/home') diff --git a/linux/home/.config/Code/User/keybindings.json b/linux/home/.config/Code/User/keybindings.json new file mode 100644 index 0000000..9d04af3 --- /dev/null +++ b/linux/home/.config/Code/User/keybindings.json @@ -0,0 +1,274 @@ +[ + { + "key": "ctrl+shift+r", + "command": "workbench.action.reloadWindow", + "when": "editorTextFocus" + }, + { + "key": "ctrl+i", + "command": "workbench.action.terminal.sendSequence", + "when": "resourceExtname == .py", + "args": { + "text": "python \"${file}\" < ./i\n" + } + }, + { + "key": "f5", + "command": "python.execInTerminal", + "when": "resourceExtname == .py", + }, + { + "key": "f5", + "command": "workbench.action.terminal.sendSequence", + "when": "resourceExtname == .dart", + "args": { + "text": "dart \"${file}\"\n" + } + }, + { + "key": "f5", + "command": "workbench.action.terminal.sendSequence", + "when": "resourceExtname == .js", + "args": { + "text": "node \"${file}\"\n" + } + }, + { + "key": "f5", + "command": "workbench.action.terminal.sendSequence", + "when": "resourceExtname == .java", + "args": { + "text": "java \"${file}\"\n" + } + }, + { + "key": "f5", + "command": "workbench.action.terminal.sendSequence", + "when": "resourceExtname == .sh", + "args": { + "text": "\"${file}\"\n" + } + }, + { + "key": "f5", + "command": "workbench.action.terminal.sendSequence", + "when": "resourceExtname == .cpp", + "args": { + "text": "g++ -g \"${file}\" -o \"${fileDirname}/${fileBasenameNoExtension}\" && \"${fileDirname}/${fileBasenameNoExtension}\"\n" + } + }, + { + "key": "f5", + "command": "workbench.action.terminal.sendSequence", + "when": "resourceExtname == .c", + "args": { + "text": "gcc -g \"${file}\" -o \"${fileDirname}/${fileBasenameNoExtension}\" && \"${fileDirname}/${fileBasenameNoExtension}\"\n" + } + }, + { + "key": "f5", + "command": "workbench.action.terminal.sendSequence", + "when": "resourceExtname == .asm", + "args": { + "text": "nasm -f elf64 \"${file}\" && ld -o \"${fileDirname}/${fileBasenameNoExtension}\" \"${fileDirname}/${fileBasenameNoExtension}.o\" && \"${fileDirname}/${fileBasenameNoExtension}\"\n" + } + }, + { + "key": "ctrl+i", + "command": "workbench.action.terminal.sendSequence", + "when": "resourceExtname == .cpp", + "args": { + "text": "g++ -g \"${file}\" -o \"${fileDirname}/${fileBasenameNoExtension}\" && \"${fileDirname}/${fileBasenameNoExtension}\" < ./i\n" + } + }, + { + "key": "ctrl+g", + "command": "workbench.action.terminal.sendSequence", + "when": "resourceExtname == .cpp", + "args": { + "text": "g++ -g \"${file}\" -o \"${fileDirname}/${fileBasenameNoExtension}\" -lgraph -lGL -lGLU -lglut && \"${fileDirname}/${fileBasenameNoExtension}\" 2>/dev/null\n" + } + }, + // { + // "key": "f5", + // "command": "workbench.action.tasks.runTask", + // "when": "resourceExtname == .cpp", + // "args": "Build and Run C++" + // }, + { + "key": "shift+f5", + "command": "workbench.action.terminal.sendSequence", + "when": "resourceExtname == .cpp", + "args": { + "text": "g++ -g \"${fileDirname}/*.cpp\" -o \"${fileDirname}/${fileBasenameNoExtension}\" && \"${fileDirname}/${fileBasenameNoExtension}\"\n" + } + }, + // { + // "key": "shift+f5", + // "command": "workbench.action.tasks.runTask", + // "when": "resourceExtname == .cpp", + // "args": "Build and Run C++ (Multiple cpp files)" + // }, + { + "key": "f4", + "command": "workbench.action.debug.continue", + "when": "inDebugMode" + }, + { + "key": "f4", + "command": "workbench.action.debug.start", + "when": "!inDebugMode" + }, + { + "key": "f4", + "command": "workbench.action.debug.start", + "when": "debuggersAvailable && !inDebugMode" + }, + { + "key": "f5", + "command": "-workbench.action.debug.continue", + "when": "inDebugMode" + }, + { + "key": "f5", + "command": "-workbench.action.debug.start", + "when": "!inDebugMode" + }, + { + "key": "f5", + "command": "-workbench.action.debug.start", + "when": "debuggersAvailable && !inDebugMode" + }, + { + "key": "shift+f4", + "command": "workbench.action.debug.stop", + "when": "inDebugMode" + }, + { + "key": "shift+f5", + "command": "-workbench.action.debug.stop", + "when": "inDebugMode" + }, + { + "key": "ctrl+v", + "command": "workbench.action.terminal.paste", + "when": "terminalFocus && terminalProcessSupported" + }, + { + "key": "ctrl+shift+v", + "command": "-workbench.action.terminal.paste", + "when": "terminalFocus && terminalProcessSupported" + }, + { + "key": "ctrl+alt+up", + "command": "editor.action.copyLinesUpAction", + "when": "editorTextFocus && !editorReadonly" + }, + { + "key": "ctrl+alt+down", + "command": "editor.action.copyLinesDownAction", + "when": "editorTextFocus && !editorReadonly" + }, + { + "key": "ctrl+shift+alt+up", + "command": "-editor.action.copyLinesUpAction", + "when": "editorTextFocus && !editorReadonly" + }, + { + "key": "ctrl+shift+alt+down", + "command": "-editor.action.copyLinesDownAction", + "when": "editorTextFocus && !editorReadonly" + }, + { + "key": "ctrl+,", + "command": "-workbench.action.openSettings" + }, + { + "key": "ctrl+,", + "command": "workbench.action.openSettingsJson" + }, + { + "key": "ctrl+i", + "command": "-editor.action.triggerSuggest", + "when": "editorHasCompletionItemProvider && textInputFocus && !editorReadonly" + }, + { + "key": "ctrl+c", + "command": "workbench.action.terminal.copySelection", + "when": "terminalFocus && terminalProcessSupported && terminalTextSelected && terminalTextSelected" + }, + { + "key": "ctrl+shift+c", + "command": "-workbench.action.terminal.copySelection", + "when": "terminalFocus && terminalProcessSupported && terminalTextSelected && terminalTextSelected" + }, + { + "key": "ctrl+k", + "command": "workbench.action.terminal.kill", + "when": "terminalIsOpen && terminalFocus" + }, + { + "key": "delete", + "command": "-workbench.action.terminal.killInstance", + "when": "terminalIsOpen && terminalTabsFocus || terminalProcessSupported && terminalTabsFocus" + }, + { + "key": "ctrl+shift+i", + "command": "-editor.action.formatDocument.none", + "when": "editorTextFocus && !editorHasDocumentFormattingProvider && !editorReadonly" + }, + { + "key": "ctrl+shift+i", + "command": "-notebook.formatCell", + "when": "editorHasDocumentFormattingProvider && editorTextFocus && inCompositeEditor && notebookEditable && !editorReadonly && activeEditor == 'workbench.editor.notebook'" + }, + { + "key": "ctrl+shift+i", + "command": "editor.action.formatDocument", + "when": "editorTextFocus" + }, + { + "key": "ctrl+shift+i", + "command": "-editor.action.formatDocument", + "when": "editorHasDocumentFormattingProvider && editorTextFocus && !editorReadonly && !inCompositeEditor" + }, + { + "key": "ctrl+shift+i", + "command": "workbench.action.toggleDevTools", + "when": "!editorTextFocus" + }, + { + "key": "ctrl+shift+i", + "command": "-workbench.action.toggleDevTools", + "when": "isDevelopment" + }, + { + "key": "ctrl+t", + "command": "-workbench.action.showAllSymbols" + }, + { + "key": "ctrl+t", + "command": "workbench.action.files.newUntitledFile" + }, + { + "key": "ctrl+n", + "command": "-workbench.action.files.newUntitledFile" + }, + { + "key": "ctrl+shift+m", + "command": "github.cweijan.mysql.focus" + }, + { + "key": "ctrl+shift+m", + "command": "-workbench.actions.view.problems", + "when": "workbench.panel.markers.view.active" + }, + { + "key": "ctrl+shift+0", + "command": "workbench.action.zoomReset" + }, + { + "key": "ctrl+numpad0", + "command": "-workbench.action.zoomReset" + } +] diff --git a/linux/home/.config/Code/User/settings.json b/linux/home/.config/Code/User/settings.json new file mode 100644 index 0000000..8686b1b --- /dev/null +++ b/linux/home/.config/Code/User/settings.json @@ -0,0 +1,734 @@ +{ + "workbench.colorCustomizations": { + "[Chromodynamics]": { + "terminal.background": "#060606", + "terminal.foreground": "#e0e0e0", + "terminal.selectionBackground": "#555555", + "titleBar.activeBackground": "#020202", + "titleBar.activeForeground": "#e0e0e0", + "titleBar.inactiveBackground": "#020202", + "titleBar.inactiveForeground": "#e0e0e0", + "tab.inactiveBackground": "#0b0b0b", + "editor.background": "#060606", + "editor.findMatchBorder": "#0c0c0d", + "editor.findMatchHighlightBorder": "#0c0c0d", + "editor.lineHighlightBackground": "#060606", + "editor.selectionBackground": "#222222", + "editor.selectionHighlightBackground": "#e4dddd", + "editor.selectionHighlightBorder": "#0c0c0d", + "editorGroupHeader.tabsBackground": "#0b0b0b", + "editorGutter.background": "#000000", + "sideBar.background": "#060606", + "sideBarSectionHeader.background": "#0b0b0b", + "statusBar.background": "#060606" + }, + "[Sweet Dracula]": { + "editorGroupHeader.tabsBackground": "#161925", + } + }, + "editor.tokenColorCustomizations": { + "[Chromodynamics]": { + "textMateRules": [ + { + "scope": [ + "constant.language.python", + "variable.parameter.function.language.special.self.python" + ], + "settings": { + "foreground": "#66D9EF" + } + }, + { + "scope": [ + "entity.name.function.operator", + "keyword.operator" + ], + "settings": { + "foreground": "#E8364F", + "fontStyle": "" + } + }, + { + "scope": [ + "punctuation.definition.template-expression.begin.js", + "punctuation.definition.template-expression.end.js" + ], + "settings": { + "foreground": "#da70d6", + "fontStyle": "italic" + } + }, + { + "scope": [ + "variable.other.readwrite.js" + ], + "settings": { + "foreground": "#c6c6c6", + "fontStyle": "" + } + } + ] + }, + "textMateRules": [ + { + "scope": [ + "entity.name.type.class", + "storage.type.class", + "storage.modifier", + "storage.type", + "constant", + "comment", + "keyword", + "invalid" + ], + "settings": { + "fontStyle": "italic" + } + } + ] + }, + // Window Settings + "window.commandCenter": false, + "window.menuBarVisibility": "toggle", + "window.newWindowDimensions": "maximized", + "window.restoreWindows": "all", + "window.title": "${activeEditorShort}${separator}${rootName}", + "window.titleBarStyle": "native", + "window.titleSeparator": " ・ ・", + "workbench.editor.enablePreviewFromQuickOpen": false, + "workbench.editor.highlightModifiedTabs": true, + "workbench.editor.restoreViewState": false, + "workbench.editor.sharedViewState": false, + "workbench.editor.showTabs": "multiple", + "workbench.editor.tabCloseButton": "right", + "workbench.editor.tabSizing": "shrink", + "workbench.iconTheme": "sweet-vscode-icons", + "workbench.layoutControl.type": "menu", + "workbench.list.smoothScrolling": true, + "workbench.panel.defaultLocation": "right", + "workbench.startupEditor": "none", + "workbench.statusBar.visible": true, + "workbench.editorAssociations": { + "*.ipynb": "jupyter-notebook" + }, + "workbench.reduceMotion": "off", + // Editor Settings + "editor.acceptSuggestionOnEnter": "smart", + "editor.autoClosingBrackets": "always", + "editor.bracketPairColorization.enabled": true, + "editor.codeActionsOnSave": { + "source.organizeImports": "explicit" + }, + "editor.colorDecorators": false, + "editor.cursorBlinking": "phase", + "editor.cursorSmoothCaretAnimation": "on", + "editor.cursorStyle": "line-thin", + "editor.detectIndentation": false, + "editor.emptySelectionClipboard": false, + "editor.fontFamily": "'Operator Mono SSm Lig Book', 'FiraCode Nerd Font', 'Hack Nerd Font Mono', 'codicon'", + "editor.fontVariations": true, + "editor.fontLigatures": "'ss01', 'ss02', 'ss03', 'ss04', 'ss05', 'ss06', 'zero', 'onum'", + "editor.fontSize": 12, + "editor.fontWeight": "normal", + "editor.formatOnSave": true, + "editor.formatOnType": true, + "editor.glyphMargin": true, + "editor.guides.bracketPairs": "active", + "editor.guides.bracketPairsHorizontal": "active", + "editor.guides.highlightActiveBracketPair": true, + "editor.hover.above": false, + "editor.inlayHints.enabled": "on", + "editor.inlineSuggest.enabled": true, + "editor.insertSpaces": true, + "editor.linkedEditing": true, + "editor.matchBrackets": "never", + "editor.maxTokenizationLineLength": 99999999, + "editor.minimap.enabled": false, + "editor.mouseWheelScrollSensitivity": 1.5, + "editor.occurrencesHighlight": "off", + "editor.renderControlCharacters": true, + "editor.renderFinalNewline": "on", + "editor.renderLineHighlight": "gutter", + "editor.renderWhitespace": "none", + "editor.scrollbar.horizontal": "auto", + "editor.scrollbar.vertical": "auto", + "editor.selectionHighlight": true, + "editor.smoothScrolling": true, + "editor.stickyScroll.enabled": true, + "editor.stickyScroll.maxLineCount": 5, + "editor.stickyTabStops": false, + "editor.suggestSelection": "first", + "editor.suggest.insertMode": "replace", + "editor.suggest.preview": true, + "editor.suggest.snippetsPreventQuickSuggestions": false, + "editor.tabCompletion": "on", + "editor.tabSize": 4, + "editor.wordBasedSuggestions": "matchingDocuments", + "editor.wordBasedSuggestionsMode": "matchingDocuments", + "editor.wordWrap": "on", + "editor.quickSuggestions": { + "other": "on", + "comments": "on", + "strings": "on", + }, + // Emmet Settings + "emmet.excludeLanguages": [], + "emmet.includeLanguages": { + "javascript": "javascriptreact", + "markdown": "html", + "vue-html": "html" + }, + // Explorer Settings + "explorer.compactFolders": false, + "explorer.confirmDelete": false, + "explorer.confirmDragAndDrop": false, + // Customize UI + // "customizeUI.activityBar": "bottom", + // "customizeUI.activityBarHideSettings": true, + // "customizeUI.listRowHeight": 20, + // "customizeUI.font.monospace": "CaskaydiaCove Nerd Font", + // "customizeUI.font.regular": "CaskaydiaCove Nerd Font", + // "customizeUI.fontSizeMap": { + // "13px": "12px", + // "monospace": "12px", + // "tab-title": "12px", + // "window-title": "12.5px" + // }, + // "customizeUI.titleBar": "inline", + // "customizeUI.stylesheet": { + // ":root,::after,::before": "--tab-height: 25px;--tab-radius: 8px;--ui-radius: 6px;--base-color: #bd93f9;--gradient-one: #c50ed2;--gradient-two: #8500f7;--side-pane-color: var(--vscode-editor-background);--focus-border: #3f4f81;--sash-size: 2px !important;--sash-hover-size: 2px !important;", + // ".editor-container": "-webkit-font-smoothing: antialiased;", + // ".monaco-workbench .part.editor > .content > .watermark": "display: none !important;", + // ".monaco-workbench .part.titlebar .window-controls-container .layout-dropdown-container": "margin-left: auto !important;", + // ".monaco-workbench .part.titlebar > .window-controls-container": "width: unset !important;", + // ".monaco-workbench .part.titlebar > .window-controls-container > .window-icon": "width: 30px !important;", + // ".monaco-workbench .part.titlebar > .titlebar-container .window-appicon > .home-bar-icon-badge, .monaco-workbench .part.titlebar > .titlebar-container > .window-appicon:not(.codicon)": "background-image: url(./vsc/vsc.svg) !important;", + // ".monaco-workbench .part.editor > .content .editor-group-container.empty .editor-group-letterpress": "background-image: url(./vsc/vsc-back.svg) !important;", + // ".monaco-workbench .part.editor.has-watermark > .content.empty .editor-group-container > .editor-group-letterpress": "background-position-y: 50% !important;", + // ".monaco-sash.hover:before, .monaco-sash.active:before": "background: linear-gradient(to bottom, var(--gradient-one), var(--gradient-two)) !important;", + // ".monaco-editor .squiggly-error": "background: none !important;border-bottom: 0.5px solid var(--vscode-editorError-foreground) !important;", + // ".monaco-editor .squiggly-warning": "background: none !important;border-bottom: 0.5px solid var(--vscode-editorWarning-foreground) !important;", + // ".monaco-editor .squiggly-info": "background: none !important;border-bottom: 0.5px solid var(--vscode-editorInfo-foreground) !important;", + // ".monaco-editor .squiggly-hint": "background: none !important;border-bottom: 0.5px solid var(--vscode-editorHint-foreground) !important;", + // "body.activity-bar-at-bottom .monaco-workbench .activitybar .active-item-indicator": "display: block !important;", + // ".monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked .active-item-indicator:before": "border: 0 !important;width: 100% !important;height: 3px !important;position: absolute !important;bottom: 0 !important;left: 0 !important;top: unset !important;background-image: linear-gradient(to top, var(--gradient-one), var(--gradient-two)) !important;border-radius: 100vmax !important;", + // ".monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab > .tab-border-bottom-container, .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab > .tab-border-top-container": "background-image: linear-gradient(to left, var(--gradient-one), var(--gradient-two)) !important;height: 3px !important;", + // ".monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .badge .badge-content": "background-image: linear-gradient(90deg, var(--gradient-one), var(--gradient-two)) !important;", + // ".monaco-workbench .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab.dirty > .tab-actions .action-label:not(:hover):before, .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty > .tab-actions .action-label:not(:hover):before": "content: '' !important;", + // ".codicon-git-branch:before": "background: linear-gradient(to bottom, var(--gradient-one), var(--gradient-two)) !important;-webkit-background-clip: text !important;background-clip: text !important;color: rgba(255, 255, 255, 0.4) !important;", + // ".monaco-editor, .split-view-view .monaco-editor-background": "background: url(./vsc/pek.png) bottom right / 10% auto no-repeat scroll;", + // ".monaco-scrollable-element > .scrollbar > .slider": "border-radius: 7px !important;", + // ".monaco-scrollable-element > .scrollbar > .slider.active": "background: linear-gradient(to top, var(--gradient-one), var(--gradient-two)) !important;", + // "canvas.decorationsOverviewRuler, .monaco-scrollable-element > .scrollbar.vertical, .monaco-scrollable-element > .scrollbar.vertical > .slider": "width: 7px !important;", + // ".monaco-scrollable-element > .scrollbar.horizontal, .monaco-scrollable-element > .scrollbar.horizontal > .slider": "height: 7px !important;", + // ".monaco-scrollable-element > .scrollbar.horizontal > .slider": "width: 135px !important;", + // ".monaco-editor .monaco-hover, .monaco-editor .suggest-widget, .monaco-editor .suggest-details": "border-radius: var(--ui-radius) !important;overflow: hidden !important;box-shadow: rgb(0 0 0 / 36%) 0px 2px calc(var(--ui-radius) + 2px) !important;", + // ".pane .pane-body, .pane .pane-body .monaco-list, .pane .pane-body .monaco-list .monaco-scrollable-element, .pane .pane-body .monaco-list .monaco-scrollable-element .monaco-list-rows, .pane .pane-body .monaco-list .monaco-scrollable-element .monaco-list-rows .monaco-list-row": "overflow: visible !important;", + // ".open-editors .monaco-list .monaco-list-row": "padding-left: 0px !important;", + // ".monaco-list-row:hover, .monaco-list-row.selected, .monaco-list-row.focused": "border-radius: 0 var(--ui-radius) var(--ui-radius) 0 !important;", + // ".monaco-workbench .monaco-list:not(.element-focused):focus:before, .monaco-select-box, .monaco-select-box-dropdown-container, .monaco-select-box-dropdown-container .monaco-list-row:hover, .monaco-select-box-dropdown-container .monaco-list-row.selected, .monaco-select-box-dropdown-container .monaco-list-row.focused": "border-radius: var(--ui-radius) !important;", + // ".monaco-list-row.selected::before, .monaco-list-row.selected::after": "--ui-radius: 6px;content: '' !important;display: block !important;position: absolute !important;width: var(--ui-radius) !important;height: var(--ui-radius) !important;left: 0 !important;pointer-events: none !important;", + // ".monaco-list-row.selected::before": "top: calc(0px - var(--ui-radius)) !important;background: radial-gradient(circle at 100% 0%, transparent 70.71%, var(--side-pane-color) 29.289%) no-repeat;background-position: 100% 0%;", + // ".monaco-list-row.selected::after": "bottom: calc(0px - var(--ui-radius)) !important;background: radial-gradient(circle at 100% 100%, transparent 70.71%, var(--side-pane-color) 29.289%) no-repeat;background-position: 100% 100%;", + // ".monaco-button.monaco-text-button": "border-radius: var(--ui-radius) !important;", + // ".monaco-editor .cursors-layer.cursor-smooth-caret-animation > .cursor": "transition: all 100ms ease-out;", + // ".tab:first-child": "margin-left: var(--tab-radius) !important;", + // ".tab:last-child": "margin-right: var(--tab-radius) !important;", + // ".tab.active": "border-radius: var(--tab-radius) var(--tab-radius) 0 0 !important;", + // ".tab.dirty-border-top > .tab-border-top-container": "border-radius: var(--tab-radius) var(--tab-radius) 0 0 !important;", + // ".tab.active::before, .tab.active::after": "content: '' !important;display: block !important;box-sizing: border-box !important;position: absolute !important;z-index: 1;width: var(--tab-radius) !important;height: var(--tab-radius) !important;bottom: 0px !important;pointer-events: none !important;", + // ".tab.active::before": "left: calc(0px - var(--tab-radius)) !important;border-bottom-right-radius: var(--tab-radius) !important;box-shadow: 3px 3px 0 3px var(--vscode-editor-background) !important;", + // ".tab.active::after": "right: 0 !important;transform: translateX(var(--tab-radius)) !important;border-bottom-left-radius: var(--tab-radius) !important;box-shadow: -3px 3px 0 3px var(--vscode-editor-background) !important;", + // ".monaco-workbench .part.sidebar>.title>.title-label h2": "font-weight: bold !important;", + // "body.activity-bar-at-bottom div.monaco-grid-view > div > div > div.monaco-scrollable-element > div.split-view-container > div.split-view-view.visible > div > div > div.monaco-scrollable-element > div.split-view-container > div:nth-child(1) > div > div > div.monaco-scrollable-element > div.split-view-container > div:nth-child(2)": "height: auto !important;", + // "body.activity-bar-at-bottom .monaco-workbench .part.activitybar": "border: none !important; padding: 0px 6px 6px 6px !important;margin-top: -8px !important; background-color: var(--vscode-editor-background) !important; position: relative !important; z-index: 10 !important;", + // "body.activity-bar-at-bottom .monaco-workbench .activitybar.bordered:before": "display: none !important;", + // "body.activity-bar-at-bottom .monaco-workbench .activitybar > .content": "justify-content: center !important; border-radius: 6px; width: unset !important; border: 1px solid #3f4f818c !important;", + // "body.activity-bar-at-bottom .monaco-workbench .activitybar>.content>.composite-bar": "margin-bottom: unset !important;", + // "body.activity-bar-at-bottom .monaco-action-bar .action-item.icon > .action-label": "color: var(--vscode-editor-foreground) !important;opacity: 0.4;", + // "body.activity-bar-at-bottom .monaco-action-bar .action-item.icon.checked > .action-label": "opacity: 1 !important;", + // ".monaco-workbench .part.editor .tabs-and-actions-container .window-controls-container": "display: flex;flex-grow: 0;flex-shrink: 0;text-align: center; -webkit-app-region: no-drag; height: 100%;", + // ".monaco-workbench .part.editor .tabs-and-actions-container .window-controls-container .window-icon": "width: 30px !important;height: 30px !important; display: flex; align-items: center; justify-content: center;", + // ".monaco-workbench .part.editor .tabs-and-actions-container .window-controls-container .window-icon.window-close:hover": "background-color: #FF5555", + // }, + // Terminal Settings + "terminal.integrated.altClickMovesCursor": true, + "terminal.integrated.cursorBlinking": true, + "terminal.integrated.customGlyphs": true, + "terminal.integrated.cursorStyle": "line", + "terminal.integrated.enableMultiLinePasteWarning": false, + "terminal.integrated.fontFamily": "'CaskaydiaCove Nerd Font', 'FiraCode Nerd Font', 'Hack Nerd Font Mono'", + "terminal.integrated.fontSize": 13, + "terminal.integrated.gpuAcceleration": "auto", + "terminal.integrated.scrollback": 200000, + "terminal.integrated.smoothScrolling": true, + "terminal.integrated.tabs.enabled": false, + "terminal.integrated.tabs.enableAnimation": true, + "terminal.integrated.profiles.linux": { + "zsh": { + "path": "/usr/bin/zsh" + } + }, + "terminal.integrated.shellIntegration.enabled": false, + "terminal.integrated.shellIntegration.decorationsEnabled": "never", + // Language Settings + "[python]": { + "editor.semanticHighlighting.enabled": false + }, + "python.analysis.completeFunctionParens": true, + "python.formatting.provider": "black", + "python.formatting.blackArgs": [ + "--line-length", + "120" + ], + "python.languageServer": "Pylance", + "python.linting.ignorePatterns": [ + ".vscode/*.py", + "**/site-packages/**/*.py", + ".git" + ], + "python.linting.enabled": true, + "python.linting.pylintEnabled": true, + "python.linting.pylintArgs": [ + "--rcfile", + "${env:HOME}/.pylintrc" + // "--load-plugins=pylint_django" + ], + "[cpp]": { + "editor.semanticHighlighting.enabled": false, + }, + "C_Cpp.default.includePath": [ + "${workspaceFolder}/**", + "/usr/include", + "/usr/local/include", + "/usr/include/c++/11.1.0" + ], + "C_Cpp.default.defines": [ + "${default}" + ], + "C_Cpp.default.compilerPath": "/usr/bin/g++", + "C_Cpp.default.cppStandard": "c++20", + "C_Cpp.default.cStandard": "c17", + "C_Cpp.default.intelliSenseMode": "gcc-x64", + "C_Cpp.default.compilerArgs": [ + "-g" + ], + "launch": { + "version": "0.2.0", + "configurations": [ + { + "name": "(gdb) Launch", + "type": "cppdbg", + "request": "launch", + "program": "${fileDirname}/${fileBasenameNoExtension}", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "miDebuggerPath": "/usr/bin/gdb", + "preLaunchTask": "Build", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + } + ] + }, + "tasks": { + "version": "2.0.0", + "tasks": [ + { + "label": "Build", + "type": "shell", + "command": "g++ -g \"${file}\" -o \"${fileDirname}/${fileBasenameNoExtension}\"", + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + } + }, + { + "label": "Build (Multiple cpp files)", + "type": "shell", + "command": "g++ -g \"${fileDirname}/*.cpp\" -o \"${fileDirname}/${fileBasenameNoExtension}\"", + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + } + } + ] + }, + "C_Cpp.autocompleteAddParentheses": true, + "C_Cpp.codeFolding": "enabled", + "C_Cpp.clang_format_fallbackStyle": "{ BasedOnStyle: Google, IndentWidth: 2, ColumnLimit: 0}", + "C_Cpp.inlayHints.autoDeclarationTypes.enabled": true, + "C_Cpp.inlayHints.autoDeclarationTypes.showOnLeft": true, + "C_Cpp.inlayHints.parameterNames.enabled": true, + "C_Cpp.inlayHints.parameterNames.hideLeadingUnderscores": true, + "C_Cpp.inlayHints.parameterNames.suppressWhenArgumentContainsName": true, + "C_Cpp.inlayHints.referenceOperator.enabled": true, + "C_Cpp.inlayHints.referenceOperator.showSpace": false, + "css.format.enable": true, + "css.format.newlineBetweenRules": true, + "css.format.newlineBetweenSelectors": true, + "css.format.spaceAroundSelectorSeparator": true, + "[css]": { + "editor.tabSize": 2 + }, + "java.jdt.ls.java.home": "/usr/lib/jvm/java-11-openjdk-amd64", + "java.configuration.runtimes": [ + { + "name": "JavaSE-11", + "path": "/usr/lib/jvm/java-11-openjdk-amd64" + } + ], + "java.server.launchMode": "LightWeight", + "[html]": { + "editor.tabSize": 2 + }, + "html.autoClosingTags": true, + "html.completion.attributeDefaultValue": "singlequotes", + "[dart]": { + "editor.suggestSelection": "first", + "editor.tabCompletion": "onlySnippets", + "editor.wordBasedSuggestions": "off" + }, + "[javascript]": { + "editor.tabSize": 2 + }, + "javascript.autoClosingTags": true, + "javascript.suggest.autoImports": true, + "javascript.suggest.completeFunctionCalls": true, + "javascript.suggest.enabled": true, + "javascript.updateImportsOnFileMove.enabled": "always", + "javascript.validate.enable": false, + "[json]": { + "editor.tabSize": 2 + }, + "json.maxItemsComputed": 100000, + "[markdown]": { + "editor.quickSuggestions": { + "other": "on", + "comments": "on", + "strings": "on", + } + }, + "[scss]": { + "editor.tabSize": 2 + }, + "[typescript]": { + "editor.tabSize": 2 + }, + "typescript.autoClosingTags": true, + "typescript.suggest.autoImports": true, + "typescript.updateImportsOnFileMove.enabled": "always", + "typescript.validate.enable": false, + "[typescriptreact]": { + "editor.tabSize": 2, + "editor.formatOnSave": false, + }, + "js/ts.implicitProjectConfig.checkJs": true, + //Latex + "[latex]": { + "editor.formatOnSave": false + }, + // Empty-Indent Extension + "emptyIndent.highlightColor": "rgba(246,36,89,0.6)", + "emptyIndent.highlightIndent": false, + "emptyIndent.removeIndent": true, + // Github Co-pilot + "github.copilot.inlineSuggest.enable": true, + "github.copilot.enable": { + "*": true, + "yaml": false, + "plaintext": true, + "markdown": false + }, + // Gitlens + "gitlens.currentLine.enabled": true, + "gitlens.hovers.currentLine.over": "line", + "gitlens.codeLens.enabled": false, + "gitlens.statusBar.enabled": true, + // General Setting\ + "color-highlight.markRuler": false, + "color-highlight.markerType": "background", + "debug.onTaskErrors": "showErrors", + "debug.openDebug": "openOnDebugBreak", + "eslint.enable": true, + "extensions.ignoreRecommendations": true, + "files.autoSave": "onWindowChange", + "files.insertFinalNewline": true, + "files.restoreUndoStack": true, + "files.trimFinalNewlines": true, + "files.trimTrailingWhitespace": true, + "git.autofetch": true, + "grammarly.files.include": [ + "**/*.md", + "**/*.txt", + "**/*.tex", + ], + "latex-workshop.latex.autoBuild.cleanAndRetry.enabled": true, + "latex-workshop.latex.autoBuild.run": "never", + "latex-workshop.latex.clean.fileTypes": [ + "*/*.aux", + "*/*.synctex.gz" + ], + "latex-workshop.latex.outDir": "/tmp/Review-Paper/", + "latex-workshop.latex.recipe.default": "latexmk (lualatex)", + "latex-workshop.latex.recipes": [ + { + "name": "latexmk 🔃", + "tools": [ + "latexmk" + ] + }, + { + "name": "latexmk (latexmkrc)", + "tools": [ + "latexmk_rconly" + ] + }, + { + "name": "latexmk (lualatex)", + "tools": [ + "lualatexmk" + ] + }, + { + "name": "latexmk (xelatex)", + "tools": [ + "xelatexmk" + ] + }, + { + "name": "pdflatex ➞ bibtex ➞ pdflatex × 2", + "tools": [ + "pdflatex", + "bibtex", + "pdflatex", + "pdflatex" + ] + }, + { + "name": "Compile Rnw files", + "tools": [ + "rnw2tex", + "latexmk" + ] + }, + { + "name": "Compile Jnw files", + "tools": [ + "jnw2tex", + "latexmk" + ] + }, + { + "name": "tectonic", + "tools": [ + "tectonic" + ] + } + ], + "latex-workshop.latex.tools": [ + { + "name": "latexmk", + "command": "latexmk", + "args": [ + "-synctex=1", + "-interaction=nonstopmode", + "-file-line-error", + "-pdf", + "-outdir=%OUTDIR%", + "%DOC%" + ], + "env": {} + }, + { + "name": "lualatexmk", + "command": "latexmk", + "args": [ + "-synctex=1", + "-interaction=nonstopmode", + "-file-line-error", + "-lualatex", + "-outdir=%OUTDIR%", + "%DOC%" + ], + "env": {} + }, + { + "name": "xelatexmk", + "command": "latexmk", + "args": [ + "-synctex=1", + "-interaction=nonstopmode", + "-file-line-error", + "-xelatex", + "-outdir=%OUTDIR%", + "%DOC%" + ], + "env": {} + }, + { + "name": "latexmk_rconly", + "command": "latexmk", + "args": [ + "%DOC%" + ], + "env": {} + }, + { + "name": "pdflatex", + "command": "pdflatex", + "args": [ + "-synctex=1", + "-interaction=nonstopmode", + "-file-line-error", + "-output-directory=%OUTDIR%", + "%DOC%" + ], + "env": {} + }, + { + "name": "bibtex", + "command": "bibtex", + "args": [ + "%DOCFILE%" + ], + "env": {} + }, + { + "name": "rnw2tex", + "command": "Rscript", + "args": [ + "-e", + "knitr::opts_knit$set(concordance = TRUE); knitr::knit('%DOCFILE_EXT%')" + ], + "env": {} + }, + { + "name": "jnw2tex", + "command": "julia", + "args": [ + "-e", + "using Weave; weave(\"%DOC_EXT%\", doctype=\"tex\")" + ], + "env": {} + }, + { + "name": "jnw2texmintex", + "command": "julia", + "args": [ + "-e", + "using Weave; weave(\"%DOC_EXT%\", doctype=\"texminted\")" + ], + "env": {} + }, + { + "name": "tectonic", + "command": "tectonic", + "args": [ + "--synctex", + "--keep-logs", + "%DOC%.tex" + ], + "env": {} + } + ], + "liveServer.settings.donotShowInfoMsg": true, + "liveServer.settings.donotVerifyTags": true, + "liveServer.settings.file": "404.html", + // "liveServer.settings.https": { + // "enable": true, + // "cert": "/home/proxzima/.ssh/cert/cert.pem", + // "key": "/home/proxzima/.ssh/cert/key.pem", + // "passphrase": "1234" + // }, + "liveServer.settings.useLocalIp": true, + "markdown.preview.markEditorSelection": true, + "markdown.preview.scrollEditorWithPreview": false, + "markdown.preview.scrollPreviewWithEditor": false, + "svgPreview.autoOpen": true, + "svgPreview.scaleToFit": true, + "svgPreview.style": { + "html": { + "background-position": "0 0, 13px 13px", + "background-size": "26px 26px", + "background": "rgba(255, 255, 255, 1)", + // "background-image": "linear-gradient(45deg, #141414 25%, transparent 25%, transparent 75%, #141414 75%, #141414), linear-gradient(45deg, #141414 25%, transparent 25%, transparent 75%, #141414 75%, #141414)" + } + }, + "print.folder.exclude": [ + "{bin,obj,out}", + "node_module", + "**/*.{bin,exe,dll,hex,pdb,pdf,pfx,png,jpg,gif,bmp,suo,pptx,ppt,jar,woff2,woff,ttf,eot,odt,otf,class}" + ], + "print.lineNumbers": "on", + "print.printAndClose": false, + "print.colourScheme": "XCode", + "print.alternateBrowser": true, + "print.browserPath": "/usr/bin/google-chrome", + "spellright.documentTypes": [ + "markdown", + "latex", + "plaintext" + ], + "spellright.language": [ + "en_GB" + ], + "spellright.notificationClass": "information", + "spellright.suggestionsInHints": false, + "spellright.useDocumentSymbolsInCode": true, + "telemetry.telemetryLevel": "off", + "search.exclude": { + "**/bower_components": true, + "**/*.code-search": true, + "**/node_modules": true, + "**/env": true, + "**/venv": true + }, + "files.associations": { + "*.xml": "html", + "*.svg": "html", + "*.json": "jsonc" + }, + "files.exclude": { + "**/.DS_Store": true, + "**/.git": true, + "**/.svn": true, + "**/.hg": true, + "**/CVS": true, + "**/.classpath": true, + "**/.project": true, + "**/.settings": true, + "**/.factorypath": true + }, + "files.watcherExclude": { + "**/.DS_Store/**": true, + "**/.git/objects/**": true, + "**/.git/subtree-cache/**": true, + "**/.svn/**": true, + "**/.hg/**": true, + "**/CVS/**": true, + "**/node_modules/**": true, + "**/env/**": true, + "**/venv/**": true, + "env-*": true + }, + "workbench.colorTheme": "Sweet Dracula", + "security.workspace.trust.untrustedFiles": "open", + "workbench.activityBar.location": "hidden", + "workbench.editor.tabActionLocation": "right", + "workbench.editor.empty.hint": "hidden" +} diff --git a/linux/home/.config/Code/User/snippets/snippet.code-snippets b/linux/home/.config/Code/User/snippets/snippet.code-snippets new file mode 100644 index 0000000..16bdfed --- /dev/null +++ b/linux/home/.config/Code/User/snippets/snippet.code-snippets @@ -0,0 +1,126 @@ +{ + // Place your global snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and + // description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope + // is left empty or omitted, the snippet gets applied to all languages. The prefix is what is + // used to trigger the snippet and the body will be expanded and inserted. Possible variables are: + // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. + // Placeholders with the same ids are connected. + // Example: + "if name is main": { + "scope": "python", + "prefix": "ifn", + "body": [ + "if __name__ == '__main__':", + "\t$0" + ], + "description": "" + }, + "for in": { + "scope": "python", + "prefix": "fori", + "body": [ + "for ${1:item} in ${2:items}:", + "\t$0" + ], + "description": "" + }, + "for in range": { + "scope": "python", + "prefix": "forr", + "body": [ + "for ${1:i} in range($2):", + "\t$0" + ], + "description": "" + }, + "lambda": { + "scope": "python", + "prefix": "lamb", + "body": [ + "lambda ${1:arg} : $0", + ], + "description": "" + }, + "map input": { + "scope": "python", + "prefix": "mapi", + "body": [ + "map(${1:func}, input($2).split())" + ], + "description": "" + }, + "html boiler plate": { + "scope": "html", + "prefix": "html", + "body": [ + "", + "", + "", + "", + " ", + " ", + "", + " ${1:Basic HTML5}", + " ", + " ", + "", + " ", + " ", + " ", + " ", + " ", + "", + " ", + " ", + " ", + "", + " ", + "", + "", + "", + "", + " ${0:}", + " ", + "", + "", + "", + ], + "description": "" + }, + "css boiler plate": { + "scope": "css", + "prefix": "css", + "body": [ + "html {", + " font-family: sans-serif;", + " font-size: 100%;", + " box-sizing: border-box;", + "}", + "", + "*, ::before, ::after {", + " box-sizing: inherit;", + "}", + "", + "html, body {", + " margin: 0;", + " padding: 0;", + " width: 100vw;", + " min-height: 100%;", + " text-rendering: optimizeLegibility;", + "}", + "" + ] + }, + "consoleLog": { + "scope": "javascript", + "prefix": "clg", + "body": "console.log(${1:object});", + "description": "Displays a message in the console" + }, + "consoleLogObject": { + "scope": "javascript", + "prefix": "clo", + "body": "console.log('${1:object} :>> ', ${1:object});", + "description": "Displays an object in the console with its name" + } +} diff --git a/linux/home/.config/Code/User/spellright.dict b/linux/home/.config/Code/User/spellright.dict new file mode 100644 index 0000000..94f1e64 --- /dev/null +++ b/linux/home/.config/Code/User/spellright.dict @@ -0,0 +1,14 @@ +srdusr +gui +url +yara +backend +txt +Regex +github +args +grep +res +yar +shipit +json diff --git a/linux/home/.config/Code/User/vsc.css b/linux/home/.config/Code/User/vsc.css new file mode 100644 index 0000000..8316df0 --- /dev/null +++ b/linux/home/.config/Code/User/vsc.css @@ -0,0 +1,408 @@ +/* *:not(.monaco-editor .margin):not(.monaco-editor .lines-content.monaco-editor-background):not(.monaco-editor .cursors-layer.cursor-smooth-caret-animation > .cursor):not(.monaco-scrollable-element > .scrollbar.vertical > .slider):not(.monaco-scrollable-element > .scrollbar.horizontal > .slider):not(.pane .pane-body .monaco-list .monaco-scrollable-element .monaco-list-rows) { + transition-duration: 100ms !important; +} */ + +:root, +::after, +::before { + --tab-height: 25px; + --tab-radius: 8px; + --ui-radius: 6px; + --base-color: #bd93f9; + --gradient-one: #cba6f7; + --gradient-two: #89b4fa; + --side-pane-color: var(--vscode-editor-background); + --focus-border: #3f4f81; + --sash-size: 2px !important; + --sash-hover-size: 2px !important; +} + +body > .monaco-workbench > .monaco-grid-view > .monaco-grid-branch-node > .monaco-split-view2 > .monaco-scrollable-element > .split-view-container { + background: var(--vscode-editor-background) !important; +} + +.editor-container { + -webkit-font-smoothing: antialiased; +} + +.monaco-workbench .part.titlebar .window-controls-container .window-icon, +.monaco-workbench .part.editor > .content > .watermark { + display: none !important; +} + +.monaco-workbench .part.editor .tabs-and-actions-container .window-controls-container { + display: flex; + flex-grow: 0; + flex-shrink: 0; + text-align: center; + -webkit-app-region: no-drag; + height: 100%; +} + +.monaco-workbench .part.editor .tabs-and-actions-container .window-controls-container .window-icon { + width: 30px !important; + height: 30px !important; + display: flex; + align-items: center; + justify-content: center; +} + +.monaco-workbench .part.editor .tabs-and-actions-container .window-controls-container .window-icon.window-close:hover { + background: #FF5555 !important; +} + +.monaco-workbench .part.titlebar .window-controls-container .layout-dropdown-container { + margin-left: auto !important; +} + +.monaco-workbench .part.titlebar > .window-controls-container { + width: unset !important; +} + +.monaco-workbench .part.titlebar > .window-controls-container > .window-icon { + width: 30px !important; +} + +.monaco-workbench.linux .part.titlebar > .window-title { + font-size: 12.5px !important; +} + +.monaco-workbench .part.titlebar > .titlebar-container .window-appicon > .home-bar-icon-badge, +.monaco-workbench .part.titlebar > .titlebar-container > .window-appicon:not(.codicon) { + background-image: url(./vsc/vsc.svg) !important; +} + +.monaco-workbench .part.editor > .content .editor-group-container.empty .editor-group-letterpress { + background-image: url(./vsc/vsc-back.svg) !important; +} + +.monaco-workbench .part.editor.has-watermark > .content.empty .editor-group-container > .editor-group-letterpress { + background-position-y: 50% !important; +} + +.mac, +.windows, +.linux { + /* font-family: 'CaskaydiaCove Nerd Font' !important; + --monaco-monospace-font: 'CaskaydiaCove Nerd Font' !important; */ + /* font-family: 'Delugia' !important; + --monaco-monospace-font: 'Delugia Mono' !important; */ +} + + +.monaco-workbench .part.sidebar > .title > .title-label h2 { + font-weight: bold !important; +} + +.monaco-sash.hover:before, +.monaco-sash.active:before { + background: linear-gradient(to bottom, var(--gradient-one), var(--gradient-two)) !important; +} + +/* Squiggly lines to straight lines */ + +.monaco-editor .squiggly-error { + background: none !important; + border-bottom: 0.5px solid var(--vscode-editorError-foreground) !important; +} + +.monaco-editor .squiggly-warning { + background: none !important; + border-bottom: 0.5px solid var(--vscode-editorWarning-foreground) !important; +} + +.monaco-editor .squiggly-info { + background: none !important; + border-bottom: 0.5px solid var(--vscode-editorInfo-foreground) !important; +} + +.monaco-editor .squiggly-hint { + background: none !important; + border-bottom: 0.5px solid var(--vscode-editorHint-foreground) !important; +} + +/* */ + +/* Gradient Tab border */ +body.activity-bar-at-bottom .monaco-workbench .activitybar .active-item-indicator { + display: block !important; +} + +.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked .active-item-indicator:before { + border: 0 !important; + width: 3px !important; + height: 100% !important; + position: absolute !important; + top: 0 !important; + left: 0 !important; + background-image: linear-gradient(to top, var(--gradient-one), var(--gradient-two)) !important; + border-radius: 100vmax !important; +} + +.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab > .tab-border-bottom-container, +.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab > .tab-border-top-container { + background-image: linear-gradient(to left, var(--gradient-one), var(--gradient-two)) !important; + height: 3px !important; + display: none !important; +} + +.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .badge .badge-content { + background-image: linear-gradient(90deg, var(--gradient-one), var(--gradient-two)) !important; +} + +/* */ + +/* Hides dirty tab white dot indicator */ + +.monaco-workbench .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab.dirty > .tab-actions .action-label:not(:hover):before, +.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty > .tab-actions .action-label:not(:hover):before { + content: '' !important; +} + +/* */ + +/* Git icon background */ + +.codicon-git-branch:before { + background: linear-gradient(to bottom, var(--gradient-one), var(--gradient-two)) !important; + -webkit-background-clip: text !important; + background-clip: text !important; + color: rgba(255, 255, 255, 0.4) !important; +} + +/* */ + +/* Editor Background */ + +.monaco-editor, +.split-view-view .lines-content.monaco-editor-background { + background: url(./vsc/pek.png) bottom right / 10% auto no-repeat scroll; + /*background: linear-gradient(rgba(0,0,0,.65), rgba(0,0,0,.65)), url(./vsc/bg.jpg) center center / auto 100vh no-repeat scroll;*/ +} + +/* */ + +/* Scrollbar */ +.monaco-scrollable-element > .scrollbar > .slider { + border-radius: 7px !important; +} + +.monaco-scrollable-element > .scrollbar > .slider.active { + background: linear-gradient(to top, var(--gradient-one), var(--gradient-two)) !important; +} + +canvas.decorationsOverviewRuler, +.monaco-scrollable-element > .scrollbar.vertical, +.monaco-scrollable-element > .scrollbar.vertical > .slider { + width: 7px !important; +} + +.monaco-scrollable-element > .scrollbar.vertical > .slider { + transition: all 100ms ease-out; +} + +.monaco-scrollable-element > .scrollbar.horizontal, +.monaco-scrollable-element > .scrollbar.horizontal > .slider { + height: 7px !important; +} + +.monaco-scrollable-element > .scrollbar.horizontal > .slider { + transition: all 100ms ease-out; +} + +.monaco-scrollable-element > .scrollbar.horizontal > .slider { + width: 135px !important; +} + +/* */ + +/* Rounded UI */ + +/* Suggestions */ +.monaco-editor .monaco-hover, +.monaco-editor .suggest-widget, +.monaco-editor .suggest-details { + border-radius: var(--ui-radius) !important; + overflow: hidden !important; + box-shadow: rgb(0 0 0 / 36%) 0px 2px calc(var(--ui-radius) + 2px) !important; +} + +/* Left pane selected file */ +.pane .pane-body, +.pane .pane-body .monaco-list, +.pane .pane-body .monaco-list .monaco-scrollable-element, +.pane .pane-body .monaco-list .monaco-scrollable-element .monaco-list-rows, +.pane .pane-body .monaco-list .monaco-scrollable-element .monaco-list-rows .monaco-list-row { + overflow: visible !important; +} + +.open-editors .monaco-list .monaco-list-row { + padding-left: 0px !important; +} + +.monaco-list-row:hover, +.monaco-list-row.selected, +.monaco-list-row.focused { + border-radius: 0 var(--ui-radius) var(--ui-radius) 0 !important; +} + +.monaco-workbench .monaco-list:not(.element-focused):focus:before, +.monaco-select-box, +.monaco-select-box-dropdown-container, +.monaco-select-box-dropdown-container .monaco-list-row:hover, +.monaco-select-box-dropdown-container .monaco-list-row.selected, +.monaco-select-box-dropdown-container .monaco-list-row.focused { + border-radius: var(--ui-radius) !important; +} + +.monaco-list-row.selected::before, +.monaco-list-row.selected::after { + content: '' !important; + display: block !important; + position: absolute !important; + width: var(--ui-radius) !important; + height: var(--ui-radius) !important; + left: 0 !important; + pointer-events: none !important; +} + +.monaco-list-row.selected::before { + top: calc(0px - var(--ui-radius)) !important; + background: radial-gradient(circle at 100% 0%, transparent 70.71%, var(--side-pane-color) 29.289%) no-repeat; + background-position: 100% 0%; +} + +.monaco-list-row.selected::after { + bottom: calc(0px - var(--ui-radius)) !important; + background: radial-gradient(circle at 100% 100%, transparent 70.71%, var(--side-pane-color) 29.289%) no-repeat; + background-position: 100% 100%; +} + +.monaco-button.monaco-text-button { + border-radius: var(--ui-radius) !important; +} + +/* */ + +/* Smooth cursor */ + +.monaco-editor .cursors-layer.cursor-smooth-caret-animation > .cursor { + transition: all 100ms ease-out; +} + +/* */ + +/* Active tab (Without border) */ + +..tab:first-child { + margin-left: var(--tab-radius) !important; + /* margin-left: calc(var(--tab-radius) - 2px) !important; */ +} + +..tab:last-child { + margin-right: var(--tab-radius) !important; + /* margin-right: calc(var(--tab-radius) - 2px) !important; */ +} + +..tab.active { + /* border: 2px solid var(--base-color) !important; */ + /* background-color: transparent !important; */ + /* rgb(20, 24, 34) */ + border-radius: var(--tab-radius) var(--tab-radius) 0 0 !important; + /* border-bottom: 2px solid #0c0e14 !important; */ + /* z-index: 1 !important; */ +} + +.tab.dirty-border-top > .tab-border-top-container { + border-radius: var(--tab-radius) var(--tab-radius) 0 0 !important; +} + +/* Border bottom radius*/ +..tab.active::before, +..tab.active::after { + content: '' !important; + display: block !important; + box-sizing: border-box !important; + position: absolute !important; + z-index: 1; + width: var(--tab-radius) !important; + height: var(--tab-radius) !important; + bottom: 0px !important; + /* bottom: -2px !important; */ + pointer-events: none !important; + /* border-bottom: 2px solid var(--base-color) !important; */ +} + +...tab.active::before { + left: calc(0px - var(--tab-radius)) !important; + /* transform: translateX(calc(0px - var(--tab-radius))) !important; */ + /* border-right: 2px solid var(--base-color) !important; */ + border-bottom-right-radius: var(--tab-radius) !important; + /* box-shadow: 3px 3px 0 3px var(--tab-color) !important; */ + box-shadow: 3px 3px 0 3px var(--vscode-editor-background) !important; + /* background: radial-gradient(circle at 0% 0%, transparent 70.71%, var(--tab-color) 29.289%) no-repeat; + background-position: 0% 0%; */ +} + +..tab.active::after { + right: 0 !important; + transform: translateX(var(--tab-radius)) !important; + /* border-left: 2px solid var(--base-color) !important; */ + border-bottom-left-radius: var(--tab-radius) !important; + /* box-shadow: -3px 3px 0 3px var(--tab-color) !important; */ + box-shadow: -3px 3px 0 3px var(--vscode-editor-background) !important; + /* background: radial-gradient(circle at 100% 0%, transparent 70.71%, var(--tab-color) 29.289%) no-repeat; + background-position: 100% 0%; */ +} + +/* .tabs-container:before { + content: '' !important; + top: 0 !important; + left: 0 !important; + right: 0 !important; + bottom: 0 !important; + background: linear-gradient(90deg, rgb(12, 14, 20), rgb(189, 172, 255), rgb(189, 147, 249), rgb(189, 147, 249), rgb(189, 147, 249), rgb(189, 172, 249), rgb(12, 14, 20)) !important; + clip: rect(33px, 2600px, 33px, 0px) !important; + position: absolute !important; +} + +.tabs-container:after { + content: '' !important; + top: 0 !important; + left: 0 !important; + right: 0 !important; + bottom: 0 !important; + background: linear-gradient(90deg, rgb(12, 14, 20), rgb(189, 172, 255), rgb(189, 147, 249), rgb(189, 147, 249), rgb(189, 147, 249), rgb(189, 172, 249), rgb(12, 14, 20)) !important; + clip: rect(33px, 2600px, 35px, 0px) !important; + position: absolute !important; +} + +.tab-label > .monaco-icon-label-container::after { + background: transparent !important; +} */ + +/* */ + +.tab{ + border-radius: 12px !important; + margin: 5px !important; + height: 40px !important; + border:2px solid #313244 !important; + background-color: #161925 !important; +} +.tab.active { + border: 2px solid var(--gradient-one) !important; + color: var(--gradient-one) !important; + font-weight: bold !important; +} +.tab.dirty { + border: 2px solid var(--gradient-two) !important; + +} +.tabs-container{ + height: auto !important; + padding: 5px !important; +} +.editor-actions { + height: inherit !important; +} diff --git a/linux/home/.config/Code/User/vsc.js b/linux/home/.config/Code/User/vsc.js new file mode 100644 index 0000000..a14bf5a --- /dev/null +++ b/linux/home/.config/Code/User/vsc.js @@ -0,0 +1,100 @@ +function getOffset(el) { + const rect = el.getBoundingClientRect(); + return { + left: rect.left + window.scrollX, + top: rect.top + window.scrollY, + }; +} + +const prevOffset = {}; + +const displayEffect = (event) => { + if (prevOffset.top === undefined) { + let initialOffset = getOffset(document.getElementsByClassName("cursor")[0]); + prevOffset.top = initialOffset.top; + prevOffset.left = initialOffset.left; + } + + const existingRect = document.getElementById("myRect"); + if (existingRect !== null) { + existingRect.remove(); + } + + setTimeout(function () { + const currOffset = getOffset(document.getElementsByClassName("cursor")[0]); + const top = prevOffset.top; + const left = prevOffset.left; + const rect = document.createElement("div"); + + // console.log("prev: ", top, left); + // console.log("curr: ", currOffset.top, currOffset.left); + + rect.id = "myRect"; + rect.style.cssText = ` + position:absolute; + top:${top}px; + left:${left}px; + width:9px; + height:20px; + z-index:10; + background-color:red; + opacity: 0.5; + `; + rect.animate( + [ + // keyframes + { transform: "scale(1) skew(10deg)" }, + { transform: "scale(0) skew(10deg)" }, + ], + { + // timing options + duration: 500, + easing: "ease-in-out", + direction: "alternate", + iterations: Infinity, + } + ); + + document.body.appendChild(rect); + prevOffset.top = currOffset.top; + prevOffset.left = currOffset.left; + }, 24); +}; + +// NOTE: First enable editor.cursorSmoothCaretAnimation. +// NOTE: Uncomment this to get a cursor trail effect. +// document.addEventListener("keydown", displayEffect); + +const windowControls = document.createElement('div'); +windowControls.className = 'window-controls-container'; +const minimize = document.createElement('div'); +minimize.classList.add('window-icon', 'window-minimize', 'codicon', 'codicon-chrome-minimize'); +const restore = document.createElement('div'); +restore.classList.add('window-icon', 'window-max-restore', 'codicon', 'codicon-chrome-restore'); +const close = document.createElement('div'); +close.classList.add('window-icon', 'window-close', 'codicon', 'codicon-chrome-close'); +windowControls.appendChild(minimize); +windowControls.appendChild(restore); +windowControls.appendChild(close); +// const html = '
'; +// template.innerHTML = html; +// const windowControls = template.content.firstChild; + +var observer = new MutationObserver(function (mutations, me) { + console.warn('Observing if window controls present'); + // const windowControls = document.querySelector(".window-controls-container"); + const tabContainer = document.querySelector(".tabs-and-actions-container"); + + if (windowControls && tabContainer) { + tabContainer.appendChild(windowControls); + console.warn('Observing completed'); + me.disconnect(); + return; + } +}); + + +// observer.observe(document, { +// childList: true, +// subtree: true +// }); diff --git a/linux/home/.config/X11/.Xresources b/linux/home/.config/X11/.Xresources new file mode 100644 index 0000000..be509d1 --- /dev/null +++ b/linux/home/.config/X11/.Xresources @@ -0,0 +1,307 @@ +st.alpha: 255 +!! Transparency (0-1): +*.alpha: 0.2 + +urxvt*shading: 10 +urxvt*tintColor: #000000 +urxvt*blurRadius: 5 +urxvt*transparent: true +urxvt*depth: 32 +urxvt*background: rgba:0000/0000/1111/dddd +!urxvt*background: rgba:0000/0000/0200/c800 +!URxvt*scrollstyle: plain +URxvt.scrollBar: False +!URxvt.font: xft:DejaVu Sans Mono:pixelsize=11:antialias=true +URxvt.font: xft:monospace:Bold:pixelsize=12:antialias=true +!URxvt*transparent: true +!URxvt*shading: 5 +! change to whateva background +URxvt.keysym.C-7: command:\033]11;#ff0000\007 +!URxvt*reverseVideo: True + +URxvt*saveLines : 10000 + +!URxvt.keysym.Control-Up: \033[1;5A +!URxvt.keysym.Control-Down: \033[1;5B +!URxvt.keysym.Control-Left: \033[1;5D +!URxvt.keysym.Control-Right: \033[1;5C + +URxvt.keysym.Control-1: command:\007\033]711;xft:monospace:Bold:pixelsize=12:antialias=true\007 +URxvt.keysym.Control-2: command:\007\033]711;xft:monospace:Bold:pixelsize=18:antialias=true\007 +URxvt.keysym.Control-3: command:\007\033]711;xft:monospace:Bold:pixelsize=28:antialias=true\007 +!URxvt.keysym.Control-1: command:\033]710;xft:Terminus:pixelsize=10:antialias=false\007\033]711;xft:Terminus:Bold:pixelsize=10:antialias=false\007 +!URxvt.keysym.Control-2: command:\033]710;xft:Terminus:pixelsize=14:antialias=false\007\033]711;xft:Terminus:Bold:pixelsize=14:antialias=false\007 +!URxvt.keysym.Control-3: command:\033]710;xft:Terminus:pixelsize=18:antialias=false\007\033]711;xft:Terminus:Bold:pixelsize=18:antialias=false\007 +!URxvt.keysym.Control-4: command:\033]710;xft:Terminus:Bold:pixelsize=20:antialias=false\007\033]711;xft:Terminus:Bold:pixelsize=20:antialias=false\007 +!URxvt.keysym.Control-5: command:\033]710;xft:Terminus:Bold:pixelsize=28:antialias=false\007\033]711;xft:Terminus:Bold:pixelsize=28:antialias=false\007 + + + + + + + +!URxvt.perl-ext-common: selection-to-clipboard +!URxvt.keysym.Shift-Control-V: eval:paste_clipboard +!URxvt.keysym.Shift-Control-C: eval:selection_to_clipboard + + +URxvt.iso14755: false +URxvt.iso14755_52: false + + +!URxvt.scrollBar: true +!URxvt.scrollBar_right: true +!URxvt.scrollBar_floating: true +!URxvt.searchable-scrollback: false +URxvt.url-select.underline: true +URxvt.url-select.autocopy: true +URxvt.cutchars: `""()''*<>[]{|} +URxvt.cursorBlink: True +URxvt.cursorColor: green +URxvt.colorBD: yellow +URxvt.colorUL: green +!URxvt.blurRadius: 5 + + +!! Copy Paste & Other Extensions +!URxvt.perl-ext-common: default,clipboard,url-select,keyboard-select +!URxvt.copyCommand: xclip -i -selection clipboard +!URxvt.pasteCommand: xclip -o -selection clipboard +!URxvt.keysym.M-c: perl:clipboard:copy +!URxvt.keysym.M-v: perl:clipboard:paste +!URxvt.keysym.M-C-v: perl:clipboard:paste_escaped +!URxvt.keysym.M-Escape: perl:keyboard-select:activate +!URxvt.keysym.M-s: perl:keyboard-select:search +!URxvt.keysym.M-u: perl:url-select:select_next +!URxvt.urlLauncher: firefox +!URxvt.underlineURLs: true +!URxvt.urlButton: 1 + + + + +URxvt.keysym.Control-v: eval:paste_clipboard +URxvt.keysym.Control-c: eval:selection_to_clipboard +URxvt.keysym.Control-Meta-c: builtin-string: +URxvt.keysym.Control-Meta-v: builtin-string: + + +URxvt.keysym.Control-k: command:\033]720;1\007 +URxvt.keysym.Control-j: command:\033]721;1\007 + + +URxvt.keysym.Meta-Page_Up: perl:pageup +URxvt.keysym.Meta-Page_Down: perl:pagedown +URxvt.perl-lib: /usr/local/lib/urxvt/perl +URxvt.perl-ext: custom.pl + + +!URxvt*loginShell: true +!URxvt*termName: screen-256color + +!URxvt*perl-ext-common: +!URxvt*perl-ext: + + +!URxvt.keysym.Control-B: eval:scroll_up_pages 1 +!URxvt.keysym.Control-F: eval:scroll_down_pages 1 + + +URxvt.perl-ext-common: default,matcher,clipboard,tabbed +URxvt.clipboard.autocopy: true +URxvt.keysym.M-c: perl:clipboard:copy +URxvt.keysym.M-v: perl:clipboard:paste + +!URxvt.url-launcher: /usr/bin/xdg-open +!URxvt.matcher.button: 1 +!URxvt.keysym.C-Delete: perl:matcher:last +!URxvt.keysym.M-Delete: perl:matcher:list +!URxvt.matcher.rend.0: Uline Bold fg5 + +!URxvt.perl-ext-common: ...,tabbed,... + + +!Key Description +!Shift+Down New tab +!Shift+Left Go to left tab +!Shift+Right Go to right tab +!Ctrl+Left Move tab to the left +!Ctrl+Right Move tab to the right +!Ctrl+d Close tab + + +!URxvt.keysym.Control-k: \033[1;5A +!URxvt.keysym.Control-j: \033[1;5B +!URxvt.keysym.Control-l: \033[1;5C +!URxvt.keysym.Control-h: \033[1;5D + +!^[[5~ + + +rofi.kb-row-up: Up,Control+k,Shift+Tab,Shift+ISO_Left_Tab +rofi.kb-row-down: Down,Control+j +rofi.kb-accept-entry: Control+m,Return,KP_Enter +rofi.terminal: st +rofi.kb-remove-to-eol: Control+Shift+e +rofi.kb-mode-next: Shift+Right,Control+Tab,Control+l +rofi.kb-mode-previous: Shift+Left,Control+Shift+Tab,Control+h +rofi.kb-remove-char-back: BackSpace + + + + +!! Set a default font and font size as below: +!*.font: monospace:size=10 +rofi.font: Noto Sans 11 + +/* name dark light */ +/* black 0 8 */ +/* red 1 9 */ +/* green 2 10 */ +/* yellow 3 11 */ +/* blue 4 12 */ +/* purple 5 13 */ +/* cyan 6 14 */ +/* white 7 15 */ + +/* !! gruvbox: */ +/* *.color0: #1d2021 */ +/* *.color1: #cc241d */ +/* *.color2: #98971a */ +/* *.color3: #d79921 */ +/* *.color4: #458588 */ +/* *.color5: #b16286 */ +/* *.color6: #689d6a */ +/* *.color7: #a89984 */ +/* *.color8: #928374 */ +/* *.color9: #fb4934 */ +/* *.color10: #b8bb26 */ +/* *.color11: #fabd2f */ +/* *.color12: #83a598 */ +/* *.color13: #d3869b */ +/* *.color14: #8ec07c */ +/* *.color15: #ebdbb2 */ +/* *.color256: #1d2021 */ +/* *.color257: #ebdbb2 */ + +* !! gruvbox light: */ +* *.color0: #fbf1c7 */ +* *.color1: #cc241d */ +* *.color2: #98971a */ +* *.color3: #d79921 */ +* *.color4: #458588 */ +* *.color5: #b16286 */ +* *.color6: #689d6a */ +* *.color7: #7c6f64 */ +* *.color8: #928374 */ +* *.color9: #9d0006 */ +* *.color10: #79740e */ +* *.color11: #b57614 */ +* *.color12: #076678 */ +* *.color13: #8f3f71 */ +* *.color14: #427b58 */ +* *.color15: #3c3836 */ +* *.background: #fbf1c7 */ +* *.foreground: #282828 */ +* st.alpha: 0.2 */ + +/* !! brogrammer: */ +/* *.foreground: #d6dbe5 */ +/* *.background: #131313 */ +/* *.color0: #1f1f1f */ +/* *.color8: #d6dbe5 */ +/* *.color1: #f81118 */ +/* *.color9: #de352e */ +/* *.color2: #2dc55e */ +/* *.color10: #1dd361 */ +/* *.color3: #ecba0f */ +/* *.color11: #f3bd09 */ +/* *.color4: #2a84d2 */ +/* *.color12: #1081d6 */ +/* *.color5: #4e5ab7 */ +/* *.color13: #5350b9 */ +/* *.color6: #1081d6 */ +/* *.color14: #0f7ddb */ +/* *.color7: #d6dbe5 */ +/* *.color15: #ffffff */ +/* *.colorBD: #d6dbe5 */ + +/* ! base16 */ +/* *.color0: #181818 */ +/* *.color1: #ab4642 */ +/* *.color2: #a1b56c */ +/* *.color3: #f7ca88 */ +/* *.color4: #7cafc2 */ +/* *.color5: #ba8baf */ +/* *.color6: #86c1b9 */ +/* *.color7: #d8d8d8 */ +/* *.color8: #585858 */ +/* *.color9: #ab4642 */ +/* *.color10: #a1b56c */ +/* *.color11: #f7ca88 */ +/* *.color12: #7cafc2 */ +/* *.color13: #ba8baf */ +/* *.color14: #86c1b9 */ +/* *.color15: #f8f8f8 */ + +/* !! solarized */ +/* *.color0: #073642 */ +/* *.color1: #dc322f */ +/* *.color2: #859900 */ +/* *.color3: #b58900 */ +/* *.color4: #268bd2 */ +/* *.color5: #d33682 */ +/* *.color6: #2aa198 */ +/* *.color7: #eee8d5 */ +/* *.color9: #cb4b16 */ +/* *.color8: #fdf6e3 */ +/* *.color10: #586e75 */ +/* *.color11: #657b83 */ +/* *.color12: #839496 */ +/* *.color13: #6c71c4 */ +/* *.color14: #93a1a1 */ +/* *.color15: #fdf6e3 */ + +/* !! xterm */ +/* *.color0: #000000 */ +/* *.color1: #cd0000 */ +/* *.color2: #00cd00 */ +/* *.color3: #cdcd00 */ +/* *.color4: #0000cd */ +/* *.color5: #cd00cd */ +/* *.color6: #00cdcd */ +/* *.color7: #e5e5e5 */ +/* *.color8: #4d4d4d */ +/* *.color9: #ff0000 */ +/* *.color10: #00ff00 */ +/* *.color11: #ffff00 */ +/* *.color12: #0000ff */ +/* *.color13: #ff00ff */ +/* *.color14: #00ffff */ +/* *.color15: #aabac8 */ +/* *.background: #000000 */ + +/* ! Dracula Xresources palette */ +/* *.foreground: #F8F8F2 */ +/* *.background: #282A36 */ +/* *.color0: #000000 */ +/* *.color8: #4D4D4D */ +/* *.color1: #FF5555 */ +/* *.color9: #FF6E67 */ +/* *.color2: #50FA7B */ +/* *.color10: #5AF78E */ +/* *.color3: #F1FA8C */ +/* *.color11: #F4F99D */ +/* *.color4: #BD93F9 */ +/* *.color12: #CAA9FA */ +/* *.color5: #FF79C6 */ +/* *.color13: #FF92D0 */ +/* *.color6: #8BE9FD */ +/* *.color14: #9AEDFE */ +/* *.color7: #BFBFBF */ +/* *.color15: #E6E6E6 */ + +/* *.background: .color0 */ +/* *.color256: 0#1d2021 */ +/* *.color257: 15#ebdbb2 */ diff --git a/linux/home/.config/X11/.xbindkeysrc b/linux/home/.config/X11/.xbindkeysrc new file mode 100644 index 0000000..481943d --- /dev/null +++ b/linux/home/.config/X11/.xbindkeysrc @@ -0,0 +1,31 @@ +# # Up +# "xdotool mousemove_relative --sync -- 0 -24" +# alt + w +# +# # Left +# "xdotool mousemove_relative --sync -- -24 0" +# alt + a +# +# # Down +# "xdotool mousemove_relative --sync -- 0 24" +# alt + s +# +# # Right +# "xdotool mousemove_relative --sync -- 24 0" +# alt + d +# +# # left + up +# "xdotool mousemove_relative --sync -- -24 -24" +# Shift+alt + q +# +# # right + up +# "xdotool mousemove_relative --sync -- 24 -24" +# Shift+alt + e +# +# # right + down +# "xdotool mousemove_relative --sync -- 24 24" +# Shift+alt + d +# +# # left + down +# "xdotool mousemove_relative --sync -- -24 24" +# Shift+alt + a diff --git a/linux/home/.config/X11/.xinitrc b/linux/home/.config/X11/.xinitrc new file mode 100755 index 0000000..d500044 --- /dev/null +++ b/linux/home/.config/X11/.xinitrc @@ -0,0 +1,34 @@ +#!/bin/sh +# +#░█▀▀░▀█▀░█▀█░█▀▄░▀█▀░█░█ +#░▀▀█░░█░░█▀█░█▀▄░░█░░▄▀▄ +#░▀▀▀░░▀░░▀░▀░▀░▀░░▀░░▀░▀ +# + +# xinitrc.d +if [ -d /etc/X11/xinit/xinitrc.d ]; then + for f in /etc/X11/xinit/xinitrc.d/*; do + [ -x "$f" ] && . "$f" + done + unset f +fi + +# Keyboard layout +setxkbmap -model pc105 -layout us -variant qwerty + +# xinitrc runs automatically when you run startx. + +# There are some small but important commands that need to be run when we start +# the graphical environment. There is a link to this file in ~/.xprofile +# because that file is run automatically if someone uses a display manager +# (login screen) and so they are needed there. To prevent doubling up commands, +# I source them here with the line below. + +# Profile +[[ -f /etc/profile ]] && source /etc/profile + +if [ -f "${XDG_CONFIG_HOME:-$HOME/.config}/X11/.xprofile" ]; then + . "${XDG_CONFIG_HOME:-$HOME/.config}/X11/.xprofile" +else + . "$HOME/.xprofile" +fi diff --git a/linux/home/.config/X11/.xprofile b/linux/home/.config/X11/.xprofile new file mode 100644 index 0000000..bc2e5f8 --- /dev/null +++ b/linux/home/.config/X11/.xprofile @@ -0,0 +1,24 @@ +#!/bin/sh + +# Xresources +[[ -f ~/.config/X11/.Xresources ]] && xrdb -merge ~/.config/X11/.Xresources + +#Xset +xset r rate 150 50 +#xset r rate 290 70 + +# Xbindkeys +xbindkeys -f "$XDG_CONFIG_HOME"/X11/xbindkeysrc + +# XKB +setxkbmap -print | xkbcomp -I"$HOME"/.config/xkb - "$DISPLAY" + +#export XAUTHORITY="$XDG_RUNTIME_DIR/.Xauthority" # This line will break some DMs. +export USERXSESSION="$XDG_CACHE_HOME/X11/xsession" +export USERXSESSIONRC="$XDG_CACHE_HOME/X11/xsessionrc" +export ALTUSERXSESSION="$XDG_CACHE_HOME/X11/Xsession" +export ERRFILE="$XDG_CACHE_HOME/X11/xsession-errors" + +if [[ "$(tty)" = "/dev/tty1" ]]; then + pgrep bspwm || startx "$XDG_CONFIG_HOME/X11/.xinitrc" +fi diff --git a/linux/home/.config/ags/.eslintrc.yml b/linux/home/.config/ags/.eslintrc.yml new file mode 100644 index 0000000..ff96a83 --- /dev/null +++ b/linux/home/.config/ags/.eslintrc.yml @@ -0,0 +1,130 @@ +env: + es2022: true +extends: + - "eslint:recommended" + - "plugin:@typescript-eslint/recommended" +parser: "@typescript-eslint/parser" +parserOptions: + ecmaVersion: 2022 + sourceType: "module" + project: "./tsconfig.json" + warnOnUnsupportedTypeScriptVersion: false +root: true +ignorePatterns: + - types/ +plugins: + - "@typescript-eslint" +rules: + "@typescript-eslint/ban-ts-comment": + - "off" + "@typescript-eslint/no-non-null-assertion": + - "off" + # "@typescript-eslint/no-explicit-any": + # - "off" + "@typescript-eslint/no-unused-vars": + - error + - varsIgnorePattern: (^unused|_$) + argsIgnorePattern: ^(unused|_) + "@typescript-eslint/no-empty-interface": + - "off" + + arrow-parens: + - error + - as-needed + comma-dangle: + - error + - always-multiline + comma-spacing: + - error + - before: false + after: true + comma-style: + - error + - last + curly: + - error + - multi-or-nest + - consistent + dot-location: + - error + - property + eol-last: + - error + eqeqeq: + - error + - always + indent: + - error + - 4 + - SwitchCase: 1 + keyword-spacing: + - error + - before: true + lines-between-class-members: + - error + - always + - exceptAfterSingleLine: true + padded-blocks: + - error + - never + - allowSingleLineBlocks: false + prefer-const: + - error + quotes: + - error + - double + - avoidEscape: true + semi: + - error + - never + nonblock-statement-body-position: + - error + - below + no-trailing-spaces: + - error + no-useless-escape: + - off + max-len: + - error + - code: 100 + func-call-spacing: + - error + array-bracket-spacing: + - error + space-before-function-paren: + - error + - anonymous: never + named: never + asyncArrow: ignore + space-before-blocks: + - error + key-spacing: + - error + object-curly-spacing: + - error + - always +globals: + Widget: readonly + Utils: readonly + App: readonly + Variable: readonly + Service: readonly + pkg: readonly + ARGV: readonly + Debugger: readonly + GIRepositoryGType: readonly + globalThis: readonly + imports: readonly + Intl: readonly + log: readonly + logError: readonly + print: readonly + printerr: readonly + window: readonly + TextEncoder: readonly + TextDecoder: readonly + console: readonly + setTimeout: readonly + setInterval: readonly + clearTimeout: readonly + clearInterval: readonly diff --git a/linux/home/.config/ags/.gitignore b/linux/home/.config/ags/.gitignore new file mode 100644 index 0000000..f56dbd1 --- /dev/null +++ b/linux/home/.config/ags/.gitignore @@ -0,0 +1,6 @@ +node_modules +types +package-lock.json +bun.lockb +flake.lock +.weather diff --git a/linux/home/.config/ags/assets/arrows-down.svg b/linux/home/.config/ags/assets/arrows-down.svg new file mode 100644 index 0000000..5851aed --- /dev/null +++ b/linux/home/.config/ags/assets/arrows-down.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/linux/home/.config/ags/assets/arrows-left.svg b/linux/home/.config/ags/assets/arrows-left.svg new file mode 100644 index 0000000..f3c1b2e --- /dev/null +++ b/linux/home/.config/ags/assets/arrows-left.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/linux/home/.config/ags/assets/arrows-right.svg b/linux/home/.config/ags/assets/arrows-right.svg new file mode 100644 index 0000000..30baa8f --- /dev/null +++ b/linux/home/.config/ags/assets/arrows-right.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/linux/home/.config/ags/assets/arrows-up.svg b/linux/home/.config/ags/assets/arrows-up.svg new file mode 100644 index 0000000..68b9944 --- /dev/null +++ b/linux/home/.config/ags/assets/arrows-up.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/linux/home/.config/ags/assets/battery-flash-symbolic.svg b/linux/home/.config/ags/assets/battery-flash-symbolic.svg new file mode 100644 index 0000000..21b5e33 --- /dev/null +++ b/linux/home/.config/ags/assets/battery-flash-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/linux/home/.config/ags/assets/bomb-kill.svg b/linux/home/.config/ags/assets/bomb-kill.svg new file mode 100644 index 0000000..a6e9f09 --- /dev/null +++ b/linux/home/.config/ags/assets/bomb-kill.svg @@ -0,0 +1,36 @@ + + + + + + + + diff --git a/linux/home/.config/ags/assets/chat-bubbles-symbolic.svg b/linux/home/.config/ags/assets/chat-bubbles-symbolic.svg new file mode 100644 index 0000000..fdee0b3 --- /dev/null +++ b/linux/home/.config/ags/assets/chat-bubbles-symbolic.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/linux/home/.config/ags/assets/controller-symbolic.svg b/linux/home/.config/ags/assets/controller-symbolic.svg new file mode 100644 index 0000000..98bf5d6 --- /dev/null +++ b/linux/home/.config/ags/assets/controller-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/linux/home/.config/ags/assets/controls-symbolic.svg b/linux/home/.config/ags/assets/controls-symbolic.svg new file mode 100644 index 0000000..7df5663 --- /dev/null +++ b/linux/home/.config/ags/assets/controls-symbolic.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/linux/home/.config/ags/assets/dark-mode-symbolic.svg b/linux/home/.config/ags/assets/dark-mode-symbolic.svg new file mode 100644 index 0000000..9f2e6b4 --- /dev/null +++ b/linux/home/.config/ags/assets/dark-mode-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/linux/home/.config/ags/assets/float.svg b/linux/home/.config/ags/assets/float.svg new file mode 100644 index 0000000..dc8078a --- /dev/null +++ b/linux/home/.config/ags/assets/float.svg @@ -0,0 +1,44 @@ + + + + + + + + + diff --git a/linux/home/.config/ags/assets/fullscreen.svg b/linux/home/.config/ags/assets/fullscreen.svg new file mode 100644 index 0000000..e9ab0b8 --- /dev/null +++ b/linux/home/.config/ags/assets/fullscreen.svg @@ -0,0 +1,43 @@ + + + + + + + + + + diff --git a/linux/home/.config/ags/assets/hourglass-symbolic.svg b/linux/home/.config/ags/assets/hourglass-symbolic.svg new file mode 100644 index 0000000..aa4f97c --- /dev/null +++ b/linux/home/.config/ags/assets/hourglass-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/linux/home/.config/ags/assets/light-mode-symbolic.svg b/linux/home/.config/ags/assets/light-mode-symbolic.svg new file mode 100644 index 0000000..d5fb271 --- /dev/null +++ b/linux/home/.config/ags/assets/light-mode-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/linux/home/.config/ags/assets/mixer-symbolic.svg b/linux/home/.config/ags/assets/mixer-symbolic.svg new file mode 100644 index 0000000..ad6cfa8 --- /dev/null +++ b/linux/home/.config/ags/assets/mixer-symbolic.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/linux/home/.config/ags/assets/nix-snowflake-symbolic.svg b/linux/home/.config/ags/assets/nix-snowflake-symbolic.svg new file mode 100644 index 0000000..7bb42ed --- /dev/null +++ b/linux/home/.config/ags/assets/nix-snowflake-symbolic.svg @@ -0,0 +1,155 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/linux/home/.config/ags/assets/nixos-symbolic.svg b/linux/home/.config/ags/assets/nixos-symbolic.svg new file mode 100644 index 0000000..7bb42ed --- /dev/null +++ b/linux/home/.config/ags/assets/nixos-symbolic.svg @@ -0,0 +1,155 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/linux/home/.config/ags/assets/nixos.svg b/linux/home/.config/ags/assets/nixos.svg new file mode 100644 index 0000000..1a756ed --- /dev/null +++ b/linux/home/.config/ags/assets/nixos.svg @@ -0,0 +1,277 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/linux/home/.config/ags/assets/osk.svg b/linux/home/.config/ags/assets/osk.svg new file mode 100644 index 0000000..511420a --- /dev/null +++ b/linux/home/.config/ags/assets/osk.svg @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/linux/home/.config/ags/assets/pinned.svg b/linux/home/.config/ags/assets/pinned.svg new file mode 100644 index 0000000..ce8efb3 --- /dev/null +++ b/linux/home/.config/ags/assets/pinned.svg @@ -0,0 +1,36 @@ + + + + + + + + diff --git a/linux/home/.config/ags/assets/preferences-desktop-theme-symbolic.svg b/linux/home/.config/ags/assets/preferences-desktop-theme-symbolic.svg new file mode 100644 index 0000000..4461454 --- /dev/null +++ b/linux/home/.config/ags/assets/preferences-desktop-theme-symbolic.svg @@ -0,0 +1,321 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/linux/home/.config/ags/assets/processor-symbolic.svg b/linux/home/.config/ags/assets/processor-symbolic.svg new file mode 100644 index 0000000..832dbaf --- /dev/null +++ b/linux/home/.config/ags/assets/processor-symbolic.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/linux/home/.config/ags/assets/rotation.svg b/linux/home/.config/ags/assets/rotation.svg new file mode 100644 index 0000000..7ed7e34 --- /dev/null +++ b/linux/home/.config/ags/assets/rotation.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/linux/home/.config/ags/assets/swapnext.svg b/linux/home/.config/ags/assets/swapnext.svg new file mode 100644 index 0000000..0690cb9 --- /dev/null +++ b/linux/home/.config/ags/assets/swapnext.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/linux/home/.config/ags/assets/tbox-close.svg b/linux/home/.config/ags/assets/tbox-close.svg new file mode 100644 index 0000000..f325d3c --- /dev/null +++ b/linux/home/.config/ags/assets/tbox-close.svg @@ -0,0 +1,49 @@ + + diff --git a/linux/home/.config/ags/assets/terminal-symbolic.svg b/linux/home/.config/ags/assets/terminal-symbolic.svg new file mode 100644 index 0000000..9f82bcf --- /dev/null +++ b/linux/home/.config/ags/assets/terminal-symbolic.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/linux/home/.config/ags/assets/togglesplit.svg b/linux/home/.config/ags/assets/togglesplit.svg new file mode 100644 index 0000000..15d5011 --- /dev/null +++ b/linux/home/.config/ags/assets/togglesplit.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/linux/home/.config/ags/assets/toolbars-symbolic.svg b/linux/home/.config/ags/assets/toolbars-symbolic.svg new file mode 100644 index 0000000..9f4c564 --- /dev/null +++ b/linux/home/.config/ags/assets/toolbars-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/linux/home/.config/ags/assets/wp-next.svg b/linux/home/.config/ags/assets/wp-next.svg new file mode 100644 index 0000000..ac0245d --- /dev/null +++ b/linux/home/.config/ags/assets/wp-next.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/linux/home/.config/ags/assets/wp-prev.svg b/linux/home/.config/ags/assets/wp-prev.svg new file mode 100644 index 0000000..12ed8dd --- /dev/null +++ b/linux/home/.config/ags/assets/wp-prev.svg @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/linux/home/.config/ags/config.js b/linux/home/.config/ags/config.js new file mode 100644 index 0000000..2864dec --- /dev/null +++ b/linux/home/.config/ags/config.js @@ -0,0 +1,46 @@ +import GLib from "gi://GLib" + +const main = "/tmp/ags/main.js" +const entry = `${App.configDir}/main.ts` +const bundler = GLib.getenv("AGS_BUNDLER") || "bun" + +const v = { + ags: pkg.version?.split(".").map(Number) || [], + expect: [1, 8, 0], +} + +try { + switch (bundler) { + case "bun": await Utils.execAsync([ + "bun", "build", entry, + "--outfile", main, + "--external", "resource://*", + "--external", "gi://*", + "--external", "file://*", + ]); break + + case "esbuild": await Utils.execAsync([ + "esbuild", "--bundle", entry, + "--format=esm", + `--outfile=${main}`, + "--external:resource://*", + "--external:gi://*", + "--external:file://*", + ]); break + + default: + throw `"${bundler}" is not a valid bundler` + } + + if (v.ags[1] < v.expect[1] || v.ags[2] < v.expect[2]) { + print(`my config needs at least v${v.expect.join(".")}, yours is v${v.ags.join(".")}`) + App.quit() + } + + await import(`file://${main}`) +} catch (error) { + console.error(error) + App.quit() +} + +export { } diff --git a/linux/home/.config/ags/default.nix b/linux/home/.config/ags/default.nix new file mode 100644 index 0000000..f0e0c41 --- /dev/null +++ b/linux/home/.config/ags/default.nix @@ -0,0 +1,104 @@ +{ + inputs, + writeShellScript, + system, + stdenv, + cage, + swww, + esbuild, + dart-sass, + fd, + fzf, + brightnessctl, + accountsservice, + slurp, + wf-recorder, + wl-clipboard, + wayshot, + swappy, + hyprpicker, + pavucontrol, + networkmanager, + gtk3, + which, +}: let + name = "asztal"; + + ags = inputs.ags.packages.${system}.default.override { + extraPackages = [accountsservice]; + }; + + dependencies = [ + which + dart-sass + fd + fzf + brightnessctl + swww + inputs.matugen.packages.${system}.default + inputs.hyprland.packages.${system}.default + slurp + wf-recorder + wl-clipboard + wayshot + swappy + hyprpicker + pavucontrol + networkmanager + gtk3 + ]; + + addBins = list: builtins.concatStringsSep ":" (builtins.map (p: "${p}/bin") list); + + greeter = writeShellScript "greeter" '' + export PATH=$PATH:${addBins dependencies} + ${cage}/bin/cage -ds -m last ${ags}/bin/ags -- -c ${config}/greeter.js + ''; + + desktop = writeShellScript name '' + export PATH=$PATH:${addBins dependencies} + ${ags}/bin/ags -b ${name} -c ${config}/config.js $@ + ''; + + config = stdenv.mkDerivation { + inherit name; + src = ./.; + + buildPhase = '' + ${esbuild}/bin/esbuild \ + --bundle ./main.ts \ + --outfile=main.js \ + --format=esm \ + --external:resource://\* \ + --external:gi://\* \ + + ${esbuild}/bin/esbuild \ + --bundle ./greeter/greeter.ts \ + --outfile=greeter.js \ + --format=esm \ + --external:resource://\* \ + --external:gi://\* \ + ''; + + installPhase = '' + mkdir -p $out + cp -r assets $out + cp -r style $out + cp -r greeter $out + cp -r widget $out + cp -f main.js $out/config.js + cp -f greeter.js $out/greeter.js + ''; + }; +in + stdenv.mkDerivation { + inherit name; + src = config; + + installPhase = '' + mkdir -p $out/bin + cp -r . $out + cp ${desktop} $out/bin/${name} + cp ${greeter} $out/bin/greeter + ''; + } diff --git a/linux/home/.config/ags/greeter.js b/linux/home/.config/ags/greeter.js new file mode 100644 index 0000000..5c8e369 --- /dev/null +++ b/linux/home/.config/ags/greeter.js @@ -0,0 +1,18 @@ +const main = "/tmp/ags/greeter.js" +const entry = `${App.configDir}/greeter/greeter.ts` + +try { + await Utils.execAsync([ + "bun", "build", entry, + "--outfile", main, + "--external", "resource://*", + "--external", "gi://*", + "--external", "file://*", + ]) + await import(`file://${main}`) +} catch (error) { + console.error(error) + App.quit() +} + +export { } diff --git a/linux/home/.config/ags/greeter/auth.ts b/linux/home/.config/ags/greeter/auth.ts new file mode 100644 index 0000000..23477eb --- /dev/null +++ b/linux/home/.config/ags/greeter/auth.ts @@ -0,0 +1,109 @@ +import AccountsService from "gi://AccountsService?version=1.0" +import GLib from "gi://GLib?version=2.0" +import icons from "lib/icons" + +const { iconFile, realName, userName } = AccountsService.UserManager + .get_default().list_users()[0] + +const loggingin = Variable(false) + +const CMD = GLib.getenv("ASZTAL_DM_CMD") + || "Hyprland" + +const ENV = GLib.getenv("ASZTAL_DM_ENV") + || "WLR_NO_HARDWARE_CURSORS=1 _JAVA_AWT_WM_NONREPARENTING=1" + +async function login(pw: string) { + loggingin.value = true + const greetd = await Service.import("greetd") + return greetd.login(userName, pw, CMD, ENV.split(/\s+/)) + .catch(res => { + loggingin.value = false + response.label = res?.description || JSON.stringify(res) + password.text = "" + revealer.reveal_child = true + }) +} + +const avatar = Widget.Box({ + class_name: "avatar", + hpack: "center", + css: `background-image: url('${iconFile}')`, +}) + +const password = Widget.Entry({ + placeholder_text: "Password", + hexpand: true, + visibility: false, + on_accept: ({ text }) => { login(text || "") }, +}) + +const response = Widget.Label({ + class_name: "response", + wrap: true, + max_width_chars: 35, + hpack: "center", + hexpand: true, + xalign: .5, +}) + +const revealer = Widget.Revealer({ + transition: "slide_down", + child: response, +}) + +export default Widget.Box({ + class_name: "auth", + attribute: { password }, + vertical: true, + children: [ + Widget.Overlay({ + child: Widget.Box( + { + css: "min-width: 200px; min-height: 200px;", + vertical: true, + }, + Widget.Box({ + class_name: "wallpaper", + css: `background-image: url('${WALLPAPER}')`, + }), + Widget.Box({ + class_name: "wallpaper-contrast", + vexpand: true, + }), + ), + overlay: Widget.Box( + { + vpack: "end", + vertical: true, + }, + avatar, + Widget.Box({ + hpack: "center", + children: [ + Widget.Icon(icons.ui.avatar), + Widget.Label(realName || userName), + ], + }), + Widget.Box( + { + class_name: "password", + }, + Widget.Spinner({ + visible: loggingin.bind(), + active: true, + }), + Widget.Icon({ + visible: loggingin.bind().as(b => !b), + icon: icons.ui.lock, + }), + password, + ), + ), + }), + Widget.Box( + { class_name: "response-box" }, + revealer, + ), + ], +}) diff --git a/linux/home/.config/ags/greeter/greeter.scss b/linux/home/.config/ags/greeter/greeter.scss new file mode 100644 index 0000000..e3a5cd8 --- /dev/null +++ b/linux/home/.config/ags/greeter/greeter.scss @@ -0,0 +1,64 @@ +@import "../style/mixins/floating-widget.scss"; +@import "../style/mixins/widget.scss"; +@import "../style/mixins/spacing.scss"; +@import "../style/mixins/unset.scss"; +@import "../style/mixins/a11y-button.scss"; +@import "../widget/bar/bar.scss"; + +window#greeter { + background-color: lighten($bg, 6%); + color: $fg; + + .bar { + background-color: transparent; + + .date { + @include unset($rec: true); + @include panel-button($flat: true, $reactive: false); + } + } + + .auth { + @include floating_widget; + border-radius: $radius; + min-width: 400px; + padding: 0; + + .wallpaper { + min-height: 220px; + background-size: cover; + border-top-left-radius: $radius; + border-top-right-radius: $radius; + } + + .wallpaper-contrast { + min-height: 100px; + } + + .avatar { + border-radius: 99px; + min-width: 140px; + min-height: 140px; + background-size: cover; + box-shadow: 3px 3px 6px 0 $shadow-color; + margin-bottom: $spacing; + } + + + .password { + entry { + @include button; + padding: $padding*.7 $padding; + margin-left: $spacing*.5; + } + + margin: 0 $padding*4; + margin-top: $spacing; + } + + .response-box { + color: $error-bg; + margin: $spacing 0; + } + } +} diff --git a/linux/home/.config/ags/greeter/greeter.ts b/linux/home/.config/ags/greeter/greeter.ts new file mode 100644 index 0000000..eb1493f --- /dev/null +++ b/linux/home/.config/ags/greeter/greeter.ts @@ -0,0 +1,37 @@ +import "./session" +import "style/style" +import GLib from "gi://GLib?version=2.0" +import RegularWindow from "widget/RegularWindow" +import statusbar from "./statusbar" +import auth from "./auth" + +const win = RegularWindow({ + name: "greeter", + setup: self => { + self.set_default_size(500, 500) + self.show_all() + auth.attribute.password.grab_focus() + }, + child: Widget.Overlay({ + child: Widget.Box({ expand: true }), + overlays: [ + Widget.Box({ + vpack: "start", + hpack: "fill", + hexpand: true, + child: statusbar, + }), + Widget.Box({ + vpack: "center", + hpack: "center", + child: auth, + }), + ], + }), +}) + +App.config({ + icons: "./assets", + windows: [win], + cursorTheme: GLib.getenv("XCURSOR_THEME")!, +}) diff --git a/linux/home/.config/ags/greeter/session.ts b/linux/home/.config/ags/greeter/session.ts new file mode 100644 index 0000000..092a5c2 --- /dev/null +++ b/linux/home/.config/ags/greeter/session.ts @@ -0,0 +1,20 @@ +import GLib from "gi://GLib?version=2.0" +import AccountsService from "gi://AccountsService?version=1.0" + +const { userName } = AccountsService.UserManager.get_default().list_users()[0] + +declare global { + const WALLPAPER: string +} + +Object.assign(globalThis, { + TMP: `${GLib.get_tmp_dir()}/greeter`, + OPTIONS: "/var/cache/greeter/options.json", + WALLPAPER: "/var/cache/greeter/background", + // TMP: "/tmp/ags", + // OPTIONS: Utils.CACHE_DIR + "/options.json", + // WALLPAPER: Utils.HOME + "/.config/background", + USER: userName, +}) + +Utils.ensureDirectory(TMP) diff --git a/linux/home/.config/ags/greeter/statusbar.ts b/linux/home/.config/ags/greeter/statusbar.ts new file mode 100644 index 0000000..8076011 --- /dev/null +++ b/linux/home/.config/ags/greeter/statusbar.ts @@ -0,0 +1,46 @@ +import { clock } from "lib/variables" +import options from "options" +import icons from "lib/icons" +import BatteryBar from "widget/bar/buttons/BatteryBar" +import PanelButton from "widget/bar/PanelButton" + +const { scheme } = options.theme +const { monochrome } = options.bar.powermenu +const { format } = options.bar.date + +const poweroff = PanelButton({ + class_name: "powermenu", + child: Widget.Icon(icons.powermenu.shutdown), + on_clicked: () => Utils.exec("shutdown now"), + setup: self => self.hook(monochrome, () => { + self.toggleClassName("colored", !monochrome.value) + self.toggleClassName("box") + }), +}) + +const date = PanelButton({ + class_name: "date", + child: Widget.Label({ + label: clock.bind().as(c => c.format(`${format}`)!), + }), +}) + +const darkmode = PanelButton({ + class_name: "darkmode", + child: Widget.Icon({ icon: scheme.bind().as(s => icons.color[s]) }), + on_clicked: () => scheme.value = scheme.value === "dark" ? "light" : "dark", +}) + +export default Widget.CenterBox({ + class_name: "bar", + hexpand: true, + center_widget: date, + end_widget: Widget.Box({ + hpack: "end", + children: [ + darkmode, + BatteryBar(), + poweroff, + ], + }), +}) diff --git a/linux/home/.config/ags/lib/battery.ts b/linux/home/.config/ags/lib/battery.ts new file mode 100644 index 0000000..3817260 --- /dev/null +++ b/linux/home/.config/ags/lib/battery.ts @@ -0,0 +1,16 @@ +import icons from "./icons" + +export default async function init() { + const bat = await Service.import("battery") + bat.connect("notify::percent", ({ percent, charging }) => { + const low = 30 + if (percent !== low || percent !== low / 2 || !charging) + return + + Utils.notify({ + summary: `${percent}% Battery Percentage`, + iconName: icons.battery.warning, + urgency: "critical", + }) + }) +} diff --git a/linux/home/.config/ags/lib/client.js b/linux/home/.config/ags/lib/client.js new file mode 100644 index 0000000..9fb9164 --- /dev/null +++ b/linux/home/.config/ags/lib/client.js @@ -0,0 +1,134 @@ +import Hyprland from 'resource:///com/github/Aylur/ags/service/hyprland.js'; +import { find_icon } from "./iconUtils.js"; +import { lookUpIcon, timeout } from 'resource:///com/github/Aylur/ags/utils.js'; + + +export let clientMapWorkSpace = {}; + +export function substitute(str) { + const subs = [ + { from: "code-url-handler", to: "visual-studio-code" }, + { from: "Code", to: "visual-studio-code" }, + { from: "GitHub Desktop", to: "github-desktop" }, + { from: "wpsoffice", to: "wps-office2019-kprometheus" }, + { from: "gnome-tweaks", to: "org.gnome.tweaks" }, + { from: "Minecraft* 1.20.1", to: "minecraft" }, + { from: "", to: "image-missing" }, + ]; + + for (const { from, to } of subs) { + if (from === str) { + return to; + } + } + + return str; +} + +function titleToClient(title, className) { + const subs = [ + { from: "musicfox", to: "musicfox" }, + ]; + + for (const { from, to } of subs) { + if (title.indexOf(from) !== -1) { + return to; + } + } + + return className +} + +export const getClientByAdrees = function(address) { + + const clients = Hyprland.clients + + const client = clients.find(item => { + return item.address === address + }) + + return client +} + +//Fullscreen client +export const getFullScreenClientAddress = function(workspace_id) { + + const clients = Hyprland.clients + const client = clients.find(item => { + return item.fullscreen && item.workspace.id === workspace_id + }) + return client +} + +export const ignoreAppsClass = [ + 'image-missing', + 'fcitx', + 'rofi' +] + +export const getClientIcon = (clientClass, title = "") => { + + clientClass.toLowerCase() + clientClass = clientClass.replace(" ", "_"); + + + if (title.length > 0) { + clientClass = titleToClient(title, clientClass) + } + + const awesome_icon = find_icon(clientClass) + if (awesome_icon) { + return awesome_icon + } + + if (lookUpIcon(clientClass)) { + return clientClass + } + + if (find_icon('system')) { + return find_icon('system') + } + + return "" +} + + +export const focus = (client) => { + //client + const { address } = client; + const liveClient = getClientByAdrees(address); + + //special window + if (liveClient.workspace.id < 0) { + const oldWorkSpace = clientMapWorkSpace[address]; + if (oldWorkSpace) { + Utils.exec( + `hyprctl dispatch movetoworkspace ${oldWorkSpace},address:${address}`, + ); + Utils.exec(`hyprctl dispatch workspace ${oldWorkSpace}`); + } + } + + //fullscreen + if (liveClient.fullscreen) { + Utils.exec("hyprctl dispatch focuswindow address:" + address); + return; + } + + //workspace fullscreen client + const currentFullScreenAddress = getFullScreenClientAddress( + liveClient.workspace.id, + ); + if (currentFullScreenAddress) { + const fullScreenAdress = currentFullScreenAddress.address; + Utils.exec("hyprctl dispatch focuswindow address:" + fullScreenAdress); + Utils.exec("hyprctl dispatch fullscreen 1"); + } + + Utils.exec("hyprctl dispatch focuswindow address:" + address); + // Utils.exec('hyprctl dispatch cyclenext') + Utils.exec("hyprctl dispatch alterzorder top,address:" + address); + if (currentFullScreenAddress) { + Utils.exec("hyprctl dispatch fullscreen 1"); + } +}; diff --git a/linux/home/.config/ags/lib/cursorhover.js b/linux/home/.config/ags/lib/cursorhover.js new file mode 100644 index 0000000..d93d021 --- /dev/null +++ b/linux/home/.config/ags/lib/cursorhover.js @@ -0,0 +1,86 @@ +const { Gdk, Gtk } = imports.gi; + +const CLICK_BRIGHTEN_AMOUNT = 0.13; + +export function setupCursorHover(button) { + const display = Gdk.Display.get_default(); + button.connect('enter-notify-event', () => { + const cursor = Gdk.Cursor.new_from_name(display, 'pointer'); + button.get_window().set_cursor(cursor); + }); + + button.connect('leave-notify-event', () => { + const cursor = Gdk.Cursor.new_from_name(display, 'default'); + button.get_window().set_cursor(cursor); + }); + +} + +export function setupCursorHoverAim(button) { + button.connect('enter-notify-event', () => { + const display = Gdk.Display.get_default(); + const cursor = Gdk.Cursor.new_from_name(display, 'crosshair'); + button.get_window().set_cursor(cursor); + }); + + button.connect('leave-notify-event', () => { + const display = Gdk.Display.get_default(); + const cursor = Gdk.Cursor.new_from_name(display, 'default'); + button.get_window().set_cursor(cursor); + }); +} + +export function setupCursorHoverGrab(button) { + button.connect('enter-notify-event', () => { + const display = Gdk.Display.get_default(); + const cursor = Gdk.Cursor.new_from_name(display, 'grab'); + button.get_window().set_cursor(cursor); + }); + + button.connect('leave-notify-event', () => { + const display = Gdk.Display.get_default(); + const cursor = Gdk.Cursor.new_from_name(display, 'default'); + button.get_window().set_cursor(cursor); + }); +} + +// failed radial ripple experiment +// +// var clicked = false; +// var dummy = false; +// var cursorX = 0; +// var cursorY = 0; +// const styleContext = button.get_style_context(); +// var clickColor = styleContext.get_property('background-color', Gtk.StateFlags.HOVER); +// clickColor.green += CLICK_BRIGHTEN_AMOUNT; +// clickColor.blue += CLICK_BRIGHTEN_AMOUNT; +// clickColor.red += CLICK_BRIGHTEN_AMOUNT; +// clickColor = clickColor.to_string(); +// button.add_events(Gdk.EventMask.POINTER_MOTION_MASK); +// button.connect('motion-notify-event', (widget, event) => { +// [dummy, cursorX, cursorY] = event.get_coords(); // Get the mouse coordinates relative to the widget +// if(!clicked) widget.css = ` +// background-image: radial-gradient(circle at ${cursorX}px ${cursorY}px, rgba(0,0,0,0), rgba(0,0,0,0) 0%, rgba(0,0,0,0) 0%, ${clickColor} 0%, ${clickColor} 0%, ${clickColor} 0%, ${clickColor} 0%, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 0%); +// `; +// }); + +// button.connect('button-press-event', (widget, event) => { +// clicked = true; +// [dummy, cursorX, cursorY] = event.get_coords(); // Get the mouse coordinates relative to the widget +// cursorX = Math.round(cursorX); cursorY = Math.round(cursorY); +// widget.css = ` +// background-image: radial-gradient(circle at ${cursorX}px ${cursorY}px, rgba(0,0,0,0), rgba(0,0,0,0) 0%, rgba(0,0,0,0) 0%, ${clickColor} 0%, ${clickColor} 0%, ${clickColor} 0%, ${clickColor} 0%, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 0%); +// `; +// widget.toggleClassName('growingRadial', true); +// widget.css = ` +// background-image: radial-gradient(circle at ${cursorX}px ${cursorY}px, rgba(0,0,0,0), rgba(0,0,0,0) 0%, rgba(0,0,0,0) 0%, ${clickColor} 0%, ${clickColor} 0%, ${clickColor} 70%, ${clickColor} 70%, rgba(0,0,0,0) 70%, rgba(0,0,0,0) 70%); +// ` +// }); +// button.connect('button-release-event', (widget, event) => { +// widget.toggleClassName('growingRadial', false); +// widget.toggleClassName('fadingRadial', false); +// widget.css = ` +// background-image: radial-gradient(circle at ${cursorX}px ${cursorY}px, rgba(0,0,0,0), rgba(0,0,0,0) 0%, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 70%, rgba(0,0,0,0) 70%, rgba(0,0,0,0) 70%, rgba(0,0,0,0) 70%); +// ` +// clicked = false; +// }); diff --git a/linux/home/.config/ags/lib/gtk.ts b/linux/home/.config/ags/lib/gtk.ts new file mode 100644 index 0000000..8cd60a3 --- /dev/null +++ b/linux/home/.config/ags/lib/gtk.ts @@ -0,0 +1,16 @@ +import Gio from "gi://Gio" +import options from "options" + +const settings = new Gio.Settings({ + schema: "org.gnome.desktop.interface", +}) + +function gtk() { + const scheme = options.theme.scheme.value + settings.set_string("color-scheme", `prefer-${scheme}`) +} + +export default function init() { + options.theme.scheme.connect("changed", gtk) + gtk() +} diff --git a/linux/home/.config/ags/lib/hyprland.ts b/linux/home/.config/ags/lib/hyprland.ts new file mode 100644 index 0000000..7f6a68c --- /dev/null +++ b/linux/home/.config/ags/lib/hyprland.ts @@ -0,0 +1,80 @@ +import options from "options" +const { messageAsync } = await Service.import("hyprland") + +const { + hyprland, + theme: { + spacing, + radius, + border: { width }, + blur, + shadows, + dark: { + primary: { bg: darkActive }, + }, + light: { + primary: { bg: lightActive }, + }, + scheme, + }, +} = options + +const deps = [ + "hyprland", + spacing.id, + radius.id, + blur.id, + width.id, + shadows.id, + darkActive.id, + lightActive.id, + scheme.id, +] + +function activeBorder() { + const color = scheme.value === "dark" + ? darkActive.value + : lightActive.value + + return color.replace("#", "") +} + +function sendBatch(batch: string[]) { + const cmd = batch + .filter(x => !!x) + .map(x => `keyword ${x}`) + .join("; ") + + return messageAsync(`[[BATCH]]/${cmd}`) +} + +async function setupHyprland() { + const wm_gaps = Math.floor(hyprland.gaps.value * spacing.value) + + //sendBatch([ + // `general:border_size ${width}`, + // `general:gaps_out ${wm_gaps}`, + // `general:gaps_in ${Math.floor(wm_gaps / 2)}`, + // `general:col.active_border rgba(${activeBorder()}ff)`, + // `general:col.inactive_border rgba(${hyprland.inactiveBorder.value})`, + // `decoration:rounding ${radius}`, + // `decoration:drop_shadow ${shadows.value ? "yes" : "no"}`, + // `dwindle:no_gaps_when_only ${hyprland.gapsWhenOnly.value ? 0 : 1}`, + // `master:no_gaps_when_only ${hyprland.gapsWhenOnly.value ? 0 : 1}`, + //]) + + //await sendBatch(App.windows.map(({ name }) => `layerrule unset, ${name}`)) + + if (blur.value > 0) { + sendBatch(App.windows.flatMap(({ name }) => [ + `layerrule unset, ${name}`, + `layerrule blur, ${name}`, + `layerrule ignorealpha ${/* based on shadow color */.29}, ${name}`, + ])) + } +} + +export default function init() { + options.handler(deps, setupHyprland) + setupHyprland() +} diff --git a/linux/home/.config/ags/lib/iconUtils.js b/linux/home/.config/ags/lib/iconUtils.js new file mode 100644 index 0000000..baba660 --- /dev/null +++ b/linux/home/.config/ags/lib/iconUtils.js @@ -0,0 +1,46 @@ +const { Gio, Gdk, Gtk } = imports.gi; + +function fileExists(filePath) { + let file = Gio.File.new_for_path(filePath); + return file.query_exists(null); +} + +function cartesianProduct(arrays) { + if (arrays.length === 0) { + return [[]]; + } + + const [head, ...tail] = arrays; + const tailCartesian = cartesianProduct(tail); + const result = []; + + for (const item of head) { + for (const tailItem of tailCartesian) { + result.push([item, ...tailItem]); + } + } + return result; +} +import { HOME } from '../utils.ts'; +export const find_icon = app_class => { + const themPath = [ + [`${HOME}/.local/share/icons/WhiteSur/`, `${HOME}/.local/share//icons/WhiteSur-dark/`], + ['512x512/', '128x128/', '64x64/', '96x96/', '72x72/', '48x48/', '36x36/'], + ['apps/', ''], + [app_class + '.png', app_class + '.svg', app_class + '.xpm'], + ]; + + let real_path = ''; + const all_icon_dir = cartesianProduct(themPath); + + for (let index = 0; index < all_icon_dir.length; index++) { + const pathItem = all_icon_dir[index]; + const icon_path = pathItem.join(''); + if (fileExists(icon_path)) { + real_path = icon_path; + break; + } + } + + return real_path; +}; diff --git a/linux/home/.config/ags/lib/icons.ts b/linux/home/.config/ags/lib/icons.ts new file mode 100644 index 0000000..dfc9e18 --- /dev/null +++ b/linux/home/.config/ags/lib/icons.ts @@ -0,0 +1,186 @@ +export const substitutes = { + "transmission-gtk": "transmission", + "blueberry.py": "blueberry", + "Caprine": "facebook-messenger", + "phototonic": "terminal-symbolic", + "com.raggesilver.BlackBox-symbolic": "terminal-symbolic", + "org.wezfurlong.wezterm-symbolic": "terminal-symbolic", + "audio-headset-bluetooth": "audio-headphones-symbolic", + "audio-card-analog-usb": "audio-speakers-symbolic", + "audio-card-analog-pci": "audio-volume-medium-symbolic", + "preferences-system": "emblem-system-symbolic", + "com.github.Aylur.ags-symbolic": "controls-symbolic", + "com.github.Aylur.ags": "controls-symbolic", +} + +export default { + missing: "image-missing-symbolic", + nix: { + nix: "nix-snowflake-symbolic", + }, + app: { + terminal: "terminal-symbolic", + }, + fallback: { + executable: "application-x-executable", + notification: "dialog-information-symbolic", + video: "video-x-generic-symbolic", + // audio: "audio-x-generic-symbolic", + audio: "audio-volume-medium-symbolic", + }, + ui: { + close: "window-close-symbolic", + colorpicker: "color-select-symbolic", + info: "info-symbolic", + link: "external-link-symbolic", + lock: "system-lock-screen-symbolic", + menu: "open-menu-symbolic", + refresh: "view-refresh-symbolic", + search: "system-search-symbolic", + settings: "emblem-system-symbolic", + themes: "preferences-desktop-theme-symbolic", + tick: "object-select-symbolic", + time: "hourglass-symbolic", + toolbars: "toolbars-symbolic", + warning: "dialog-warning-symbolic", + avatar: "avatar-default-symbolic", + arrow: { + right: "pan-end-symbolic", + left: "pan-start-symbolic", + down: "pan-down-symbolic", + up: "pan-up-symbolic", + }, + }, + audio: { + mic: { + muted: "microphone-disabled-symbolic", + low: "microphone-sensitivity-low-symbolic", + medium: "microphone-sensitivity-medium-symbolic", + high: "microphone-sensitivity-high-symbolic", + }, + volume: { + muted: "audio-volume-muted-symbolic", + low: "audio-volume-low-symbolic", + medium: "audio-volume-medium-symbolic", + high: "audio-volume-high-symbolic", + overamplified: "audio-volume-medium-symbolic", + }, + type: { + headset: "audio-headphones-symbolic", + speaker: "audio-speakers-symbolic", + card: "audio-card-symbolic", + }, + mixer: "mixer-symbolic", + }, + powerprofile: { + balanced: "power-profile-balanced-symbolic", + "power-saver": "power-profile-power-saver-symbolic", + performance: "power-profile-performance-symbolic", + }, + asusctl: { + profile: { + Balanced: "power-profile-balanced-symbolic", + Quiet: "power-profile-power-saver-symbolic", + Performance: "power-profile-performance-symbolic", + }, + mode: { + Integrated: "processor-symbolic", + Hybrid: "controller-symbolic", + }, + }, + battery: { + charging: "battery-flash-symbolic", + warning: "battery-empty-symbolic", + }, + bluetooth: { + enabled: "bluetooth-active-symbolic", + disabled: "bluetooth-disabled-symbolic", + }, + brightness: { + indicator: "display-brightness-symbolic", + keyboard: "keyboard-brightness-symbolic", + screen: "display-brightness-symbolic", + }, + powermenu: { + sleep: "weather-clear-night-symbolic", + reboot: "system-reboot-symbolic", + logout: "system-log-out-symbolic", + shutdown: "system-shutdown-symbolic", + }, + recorder: { + recording: "media-record-symbolic", + }, + notifications: { + noisy: "org.gnome.Settings-notifications-symbolic", + silent: "notifications-disabled-symbolic", + message: "chat-bubbles-symbolic", + }, + trash: { + full: "user-trash-full-symbolic", + empty: "user-trash-symbolic", + }, + mpris: { + shuffle: { + enabled: "media-playlist-shuffle-symbolic", + disabled: "media-playlist-consecutive-symbolic", + }, + loop: { + none: "media-playlist-repeat-symbolic", + track: "media-playlist-repeat-song-symbolic", + playlist: "media-playlist-repeat-symbolic", + }, + playing: "media-playback-pause-symbolic", + paused: "media-playback-start-symbolic", + stopped: "media-playback-start-symbolic", + prev: "media-skip-backward-symbolic", + next: "media-skip-forward-symbolic", + }, + system: { + cpu: "org.gnome.SystemMonitor-symbolic", + ram: "drive-harddisk-solidstate-symbolic", + temp: "temperature-symbolic", + }, + color: { + dark: "dark-mode-symbolic", + light: "light-mode-symbolic", + }, + ui: { + arch: "archlinux-logo", + close: "window-close", + colorpicker: "color-select", + info: "info", + link: "external-link", + lock: "system-lock-screen", + menu: "open-menu", + refresh: "view-refresh", + search: "system-search", + settings: "emblem-system", + themes: "preferences-desktop-theme", + tick: "object-select", + time: "hourglass", + toolbars: "toolbars-symbolic", + warning: "dialog-warning", + avatar: "avatar-default", + tbox_osk: "osk", + tbox_appkill: "bomb-kill", + tbox_close: "tbox-close", + tbox_rotate: "rotation", + tbox_moveup: "arrows-up", + tbox_movedown: "arrows-down", + tbox_moveleft: "arrows-left", + tbox_moveright: "arrows-right", + tbox_workspacenext: "wp-next", + tbox_workspaceprev: "wp-prev", + tbox_fullscreen: "fullscreen", + tbox_swapnext: "swapnext", + tbox_float: "float", + tbox_pinned: "pinned", + tbox_split: "togglesplit", + arrow: { + right: "pan-end", + left: "pan-start", + down: "pan-down", + up: "pan-up", + }, + }, +} diff --git a/linux/home/.config/ags/lib/init.ts b/linux/home/.config/ags/lib/init.ts new file mode 100644 index 0000000..e9e396c --- /dev/null +++ b/linux/home/.config/ags/lib/init.ts @@ -0,0 +1,19 @@ +import matugen from './matugen'; +import hyprland from './hyprland'; +import tmux from './tmux'; +import gtk from './gtk'; +import lowBattery from './battery'; +import notifications from './notifications'; + +export default function init() { + try { + gtk(); + tmux(); + matugen(); + lowBattery(); + notifications(); + hyprland(); + } catch (error) { + logError(error); + } +} diff --git a/linux/home/.config/ags/lib/matugen.ts b/linux/home/.config/ags/lib/matugen.ts new file mode 100644 index 0000000..dfccccf --- /dev/null +++ b/linux/home/.config/ags/lib/matugen.ts @@ -0,0 +1,113 @@ +import wallpaper from "service/wallpaper" +import options from "options" +import { sh, dependencies } from "./utils" + +export default function init() { + wallpaper.connect("changed", () => matugen()) + options.autotheme.connect("changed", () => matugen()) +} + +function animate(...setters: Array<() => void>) { + const delay = options.transition.value / 2 + setters.forEach((fn, i) => Utils.timeout(delay * i, fn)) +} + +export async function matugen( + type: "image" | "color" = "image", + arg = wallpaper.wallpaper, +) { + if (!options.autotheme.value || !dependencies("matugen")) + return + + const colors = await sh(`matugen --dry-run -j hex ${type} ${arg}`) + const c = JSON.parse(colors).colors as { light: Colors, dark: Colors } + const { dark, light } = options.theme + + animate( + () => { + dark.widget.value = c.dark.on_surface + light.widget.value = c.light.on_surface + }, + () => { + dark.border.value = c.dark.outline + light.border.value = c.light.outline + }, + () => { + dark.bg.value = c.dark.surface + light.bg.value = c.light.surface + }, + () => { + dark.fg.value = c.dark.on_surface + light.fg.value = c.light.on_surface + }, + () => { + dark.primary.bg.value = c.dark.primary + light.primary.bg.value = c.light.primary + options.bar.battery.charging.value = options.theme.scheme.value === "dark" + ? c.dark.primary : c.light.primary + }, + () => { + dark.primary.fg.value = c.dark.on_primary + light.primary.fg.value = c.light.on_primary + }, + () => { + dark.error.bg.value = c.dark.error + light.error.bg.value = c.light.error + }, + () => { + dark.error.fg.value = c.dark.on_error + light.error.fg.value = c.light.on_error + }, + ) +} + +type Colors = { + background: string + error: string + error_container: string + inverse_on_surface: string + inverse_primary: string + inverse_surface: string + on_background: string + on_error: string + on_error_container: string + on_primary: string + on_primary_container: string + on_primary_fixed: string + on_primary_fixed_variant: string + on_secondary: string + on_secondary_container: string + on_secondary_fixed: string + on_secondary_fixed_variant: string + on_surface: string + on_surface_variant: string + on_tertiary: string + on_tertiary_container: string + on_tertiary_fixed: string + on_tertiary_fixed_variant: string + outline: string + outline_variant: string + primary: string + primary_container: string + primary_fixed: string + primary_fixed_dim: string + scrim: string + secondary: string + secondary_container: string + secondary_fixed: string + secondary_fixed_dim: string + shadow: string + surface: string + surface_bright: string + surface_container: string + surface_container_high: string + surface_container_highest: string + surface_container_low: string + surface_container_lowest: string + surface_dim: string + surface_variant: string + tertiary: string + tertiary_container: string + tertiary_fixed: string + tertiary_fixed_dim: string +} diff --git a/linux/home/.config/ags/lib/notifications.ts b/linux/home/.config/ags/lib/notifications.ts new file mode 100644 index 0000000..0000831 --- /dev/null +++ b/linux/home/.config/ags/lib/notifications.ts @@ -0,0 +1,16 @@ +import options from "options" +const notifs = await Service.import("notifications") + +// TODO: consider adding this to upstream + +const { blacklist } = options.notifications + +export default function init() { + const notify = notifs.constructor.prototype.Notify.bind(notifs) + notifs.constructor.prototype.Notify = function(appName: string, ...rest: unknown[]) { + if (blacklist.value.includes(appName)) + return Number.MAX_SAFE_INTEGER + + return notify(appName, ...rest) + } +} diff --git a/linux/home/.config/ags/lib/option.ts b/linux/home/.config/ags/lib/option.ts new file mode 100644 index 0000000..2d73978 --- /dev/null +++ b/linux/home/.config/ags/lib/option.ts @@ -0,0 +1,115 @@ +import { Variable } from "resource:///com/github/Aylur/ags/variable.js" + +type OptProps = { + persistent?: boolean +} + +export class Opt extends Variable { + static { Service.register(this) } + + constructor(initial: T, { persistent = false }: OptProps = {}) { + super(initial) + this.initial = initial + this.persistent = persistent + } + + initial: T + id = "" + persistent: boolean + toString() { return `${this.value}` } + toJSON() { return `opt:${this.value}` } + + getValue = (): T => { + return super.getValue() + } + + init(cacheFile: string) { + const cacheV = JSON.parse(Utils.readFile(cacheFile) || "{}")[this.id] + if (cacheV !== undefined) + this.value = cacheV + + this.connect("changed", () => { + const cache = JSON.parse(Utils.readFile(cacheFile) || "{}") + cache[this.id] = this.value + Utils.writeFileSync(JSON.stringify(cache, null, 2), cacheFile) + }) + } + + reset() { + if (this.persistent) + return + + if (JSON.stringify(this.value) !== JSON.stringify(this.initial)) { + this.value = this.initial + return this.id + } + } +} + +export const opt = (initial: T, opts?: OptProps) => new Opt(initial, opts) + +function getOptions(object: object, path = ""): Opt[] { + return Object.keys(object).flatMap(key => { + const obj: Opt = object[key] + const id = path ? path + "." + key : key + + if (obj instanceof Variable) { + obj.id = id + return obj + } + + if (typeof obj === "object") + return getOptions(obj, id) + + return [] + }) +} + +export function mkOptions(cacheFile: string, object: T) { + for (const opt of getOptions(object)) + opt.init(cacheFile) + + Utils.ensureDirectory(cacheFile.split("/").slice(0, -1).join("/")) + + const configFile = `${TMP}/config.json` + const values = getOptions(object).reduce((obj, { id, value }) => ({ [id]: value, ...obj }), {}) + Utils.writeFileSync(JSON.stringify(values, null, 2), configFile) + Utils.monitorFile(configFile, () => { + const cache = JSON.parse(Utils.readFile(configFile) || "{}") + for (const opt of getOptions(object)) { + if (JSON.stringify(cache[opt.id]) !== JSON.stringify(opt.value)) + opt.value = cache[opt.id] + } + }) + + function sleep(ms = 0) { + return new Promise(r => setTimeout(r, ms)) + } + + async function reset( + [opt, ...list] = getOptions(object), + id = opt?.reset(), + ): Promise> { + if (!opt) + return sleep().then(() => []) + + return id + ? [id, ...(await sleep(50).then(() => reset(list)))] + : await sleep().then(() => reset(list)) + } + + return Object.assign(object, { + configFile, + array: () => getOptions(object), + async reset() { + return (await reset()).join("\n") + }, + handler(deps: string[], callback: () => void) { + for (const opt of getOptions(object)) { + if (deps.some(i => opt.id.startsWith(i))) + opt.connect("changed", callback) + } + }, + }) +} + diff --git a/linux/home/.config/ags/lib/session.ts b/linux/home/.config/ags/lib/session.ts new file mode 100644 index 0000000..0e3e0cf --- /dev/null +++ b/linux/home/.config/ags/lib/session.ts @@ -0,0 +1,16 @@ +import GLib from "gi://GLib?version=2.0" + +declare global { + const OPTIONS: string + const TMP: string + const USER: string +} + +Object.assign(globalThis, { + OPTIONS: `${GLib.get_user_cache_dir()}/ags/options.json`, + TMP: `${GLib.get_tmp_dir()}/asztal`, + USER: GLib.get_user_name(), +}) + +Utils.ensureDirectory(TMP) +App.addIcons(`${App.configDir}/assets`) diff --git a/linux/home/.config/ags/lib/tmux.ts b/linux/home/.config/ags/lib/tmux.ts new file mode 100644 index 0000000..1372eb2 --- /dev/null +++ b/linux/home/.config/ags/lib/tmux.ts @@ -0,0 +1,14 @@ +import options from "options" +import { sh } from "./utils" + +export async function tmux() { + const { scheme, dark, light } = options.theme + const hex = scheme.value === "dark" ? dark.primary.bg.value : light.primary.bg.value + if (await sh("which tmux")) + sh(`tmux set @main_accent "${hex}"`) +} + +export default function init() { + options.theme.dark.primary.bg.connect("changed", tmux) + options.theme.light.primary.bg.connect("changed", tmux) +} diff --git a/linux/home/.config/ags/lib/utils.ts b/linux/home/.config/ags/lib/utils.ts new file mode 100644 index 0000000..f3ff2e3 --- /dev/null +++ b/linux/home/.config/ags/lib/utils.ts @@ -0,0 +1,113 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { type Application } from "types/service/applications" +import icons, { substitutes } from "./icons" +import Gtk from "gi://Gtk?version=3.0" +import Gdk from "gi://Gdk" +import GLib from "gi://GLib?version=2.0" + +export const HOME = GLib.get_home_dir(); + +export type Binding = import("types/service").Binding + +/** + * @returns substitute icon || name || fallback icon + */ +export function icon(name: string | null, fallback = icons.missing) { + if (!name) + return fallback || "" + + if (GLib.file_test(name, GLib.FileTest.EXISTS)) + return name + + const icon = (substitutes[name] || name) + if (Utils.lookUpIcon(icon)) + return icon + + print(`no icon substitute "${icon}" for "${name}", fallback: "${fallback}"`) + return fallback +} + +/** + * @returns execAsync(["bash", "-c", cmd]) + */ +export async function bash(strings: TemplateStringsArray | string, ...values: unknown[]) { + const cmd = typeof strings === "string" ? strings : strings + .flatMap((str, i) => str + `${values[i] ?? ""}`) + .join("") + + return Utils.execAsync(["bash", "-c", cmd]).catch(err => { + console.error(cmd, err) + return "" + }) +} + +/** + * @returns execAsync(cmd) + */ +export async function sh(cmd: string | string[]) { + return Utils.execAsync(cmd).catch(err => { + console.error(typeof cmd === "string" ? cmd : cmd.join(" "), err) + return "" + }) +} + +export function forMonitors(widget: (monitor: number) => Gtk.Window) { + const n = Gdk.Display.get_default()?.get_n_monitors() || 1 + return range(n, 0).map(widget).flat(1) +} + +/** + * @returns [start...length] + */ +export function range(length: number, start = 1) { + return Array.from({ length }, (_, i) => i + start) +} + +/** + * @returns true if all of the `bins` are found + */ +export function dependencies(...bins: string[]) { + const missing = bins.filter(bin => { + return !Utils.exec(`which ${bin}`) + }) + + if (missing.length > 0) { + console.warn("missing dependencies:", missing.join(", ")) + Utils.notify(`missing dependencies: ${missing.join(", ")}`) + } + + return missing.length === 0 +} + +/** + * run app detached + */ +export function launchApp(app: Application) { + const exe = app.executable + .split(/\s+/) + .filter(str => !str.startsWith("%") && !str.startsWith("@")) + .join(" ") + + bash(`${exe} &`) + app.frequency += 1 +} + +/** + * to use with drag and drop + */ +export function createSurfaceFromWidget(widget: Gtk.Widget) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const cairo = imports.gi.cairo as any + const alloc = widget.get_allocation() + const surface = new cairo.ImageSurface( + cairo.Format.ARGB32, + alloc.width, + alloc.height, + ) + const cr = new cairo.Context(surface) + cr.setSourceRGBA(255, 255, 255, 0) + cr.rectangle(0, 0, alloc.width, alloc.height) + cr.fill() + widget.draw(cr) + return surface +} diff --git a/linux/home/.config/ags/lib/variables.ts b/linux/home/.config/ags/lib/variables.ts new file mode 100644 index 0000000..78d8793 --- /dev/null +++ b/linux/home/.config/ags/lib/variables.ts @@ -0,0 +1,47 @@ +import GLib from "gi://GLib" +// import options from "options" +// +// const intval = options.system.fetchInterval.value +// const tempPath = options.system.temperature.value + +export const clock = Variable(GLib.DateTime.new_now_local(), { + poll: [1000, () => GLib.DateTime.new_now_local()], +}) + +export const uptime = Variable(0, { + poll: [60_000, "cat /proc/uptime", line => + Number.parseInt(line.split(".")[0]) / 60, + ], +}) + + +export const user = { + name: GLib.get_user_name() +} + +export const distro = { + id: GLib.get_os_info("ID"), + logo: GLib.get_os_info("LOGO"), +} + +// const divide = ([total, free]: string[]) => Number.parseInt(free) / Number.parseInt(total) +// +// export const cpu = Variable(0, { +// poll: [intval, "top -b -n 1", out => divide(["100", out.split("\n") +// .find(line => line.includes("Cpu(s)")) +// ?.split(/\s+/)[1] +// .replace(",", ".") || "0"])], +// }) +// +// export const ram = Variable(0, { +// poll: [intval, "free", out => divide(out.split("\n") +// .find(line => line.includes("Mem:")) +// ?.split(/\s+/) +// .splice(1, 2) || ["1", "1"])], +// }) +// +// export const temperature = Variable(0, { +// poll: [intval, `cat ${tempPath}`, n => { +// return Number.parseInt(n) / 100_000 +// }], +// }) diff --git a/linux/home/.config/ags/main.ts b/linux/home/.config/ags/main.ts new file mode 100644 index 0000000..fa18846 --- /dev/null +++ b/linux/home/.config/ags/main.ts @@ -0,0 +1,47 @@ +import "lib/session" +import "style/style" +import init from "lib/init" +import options from "options" +import Bar from "widget/bar/Bar" +import Launcher from "widget/launcher/Launcher" +import NotificationPopups from "widget/notifications/NotificationPopups" +import OSD from "widget/osd/OSD" +import Overview from "widget/overview/Overview" +import PowerMenu from "widget/powermenu/PowerMenu" +import ScreenCorners from "widget/bar/ScreenCorners" +import SettingsDialog from "widget/settings/SettingsDialog" +import Verification from "widget/powermenu/Verification" +import { forMonitors } from "lib/utils" +import { setupQuickSettings } from "widget/quicksettings/QuickSettings" +import { setupDateMenu } from "widget/datemenu/DateMenu" +//import Dock from "widget/dock/Dock"; +import FloatingDock from "widget/dock/FloatingDock" +import ToolBoxDock from "widget/dock/ToolBoxDock" + +App.config({ + onConfigParsed: () => { + setupQuickSettings() + setupDateMenu() + init() + }, + closeWindowDelay: { + "launcher": options.transition.value, + "overview": options.transition.value, + "quicksettings": options.transition.value, + "datemenu": options.transition.value, + }, + windows: () => [ + ...forMonitors(Bar), + //...forMonitors(Dock), + ...forMonitors(FloatingDock), + //...forMonitors(ToolBoxDock), + ...forMonitors(NotificationPopups), + ...forMonitors(ScreenCorners), + ...forMonitors(OSD), + Launcher(), + Overview(), + PowerMenu(), + SettingsDialog(), + Verification(), + ], +}) diff --git a/linux/home/.config/ags/options.ts b/linux/home/.config/ags/options.ts new file mode 100644 index 0000000..4cf5a53 --- /dev/null +++ b/linux/home/.config/ags/options.ts @@ -0,0 +1,261 @@ +import { opt, mkOptions } from 'lib/option'; +import { distro } from 'lib/variables'; +import { icon } from 'lib/utils'; +import { icons } from 'assets'; +import icons from 'lib/icons'; +//import Dock from "./widgets/dock/index.js"; + +const options = mkOptions(OPTIONS, { + autotheme: opt(false), + + wallpaper: { + enable: opt(false), + resolution: opt(1920), + market: opt('random'), + }, + + theme: { + dark: { + primary: { + bg: opt('#51a4e7'), + fg: opt('#141414'), + }, + error: { + bg: opt('#e55f86'), + fg: opt('#141414'), + }, + bg: opt('#171717'), + fg: opt('#eeeeee'), + widget: opt('#eeeeee'), + border: opt('#eeeeee'), + }, + light: { + primary: { + bg: opt('#426ede'), + fg: opt('#eeeeee'), + }, + error: { + bg: opt('#b13558'), + fg: opt('#eeeeee'), + }, + bg: opt('#fffffa'), + fg: opt('#080808'), + widget: opt('#080808'), + border: opt('#080808'), + }, + + blur: opt(0), + scheme: opt<'dark' | 'light'>('dark'), + widget: { opacity: opt(94) }, + border: { + width: opt(1), + opacity: opt(100), + }, + + shadows: opt(true), + padding: opt(7), + spacing: opt(12), + radius: opt(11), + }, + + transition: opt(200), + + font: { + size: opt(13), + name: opt('Ubuntu Nerd Font'), + }, + bar: { + flatButtons: opt(true), + position: opt<'top' | 'bottom'>('top'), + corners: opt(false), + layout: { + start: opt>([ + 'launcher', + 'workspaces', + //"taskbar", + 'expander', + 'messages', + ]), + center: opt>(['date']), + end: opt>([ + 'media', + 'expander', + //"colorpicker", + 'screenrecord', + 'battery', + 'systray', + 'system', + 'powermenu', + ]), + }, + launcher: { + icon: { + colored: opt(true), + icon: opt(icon(distro.logo, icons.ui.search)), + }, + label: { + colored: opt(false), + label: opt(''), + //label: opt(" Applications"), + }, + action: opt(() => App.toggleWindow('launcher')), + }, + date: { + format: opt('%a %d %b %Y %H:%M:%S'), + action: opt(() => App.toggleWindow('datemenu')), + }, + battery: { + bar: opt<'hidden' | 'regular' | 'whole'>('regular'), + charging: opt('#00D787'), + percentage: opt(true), + blocks: opt(7), + width: opt(50), + low: opt(30), + }, + workspaces: { + workspaces: opt(6), + }, + taskbar: { + iconSize: opt(0), + monochrome: opt(false), + exclusive: opt(false), + }, + messages: { + action: opt(() => App.toggleWindow('datemenu')), + }, + systray: { + ignore: opt([ + 'KDE Connect Indicator', + //"spotify-client", + ]), + }, + media: { + monochrome: opt(false), + preferred: opt('spotify'), + direction: opt<'left' | 'right'>('right'), + format: opt('{artists} - {title}'), + length: opt(40), + }, + powermenu: { + monochrome: opt(false), + action: opt(() => App.toggleWindow('powermenu')), + }, + }, + + dock: { + iconSize: opt(44), + pinnedApps: opt([ + 'nemo', + 'firefox', + 'mullvad', + 'qbittorrent', + 'com.obsproject.Studio', + 'vlc', + 'spotify', + //"viewnior", + //"phototonic", + 'gthumb', + 'nomachine', + 'lutris', + 'steam', + 'discord', + 'vscode', + 'wezterm', + 'obsidian', + ]), + toolbox: { + icons: [opt(icon(icons.ui.tbox_close)), opt(icon(icons.ui.tbox_appkill)), opt(icon(icons.ui.tbox_rotate)), opt(icon(icons.ui.tbox_workspaceprev)), opt(icon(icons.ui.tbox_workspacenext)), opt(icon(icons.ui.tbox_moveleft)), opt(icon(icons.ui.tbox_moveright)), opt(icon(icons.ui.tbox_moveup)), opt(icon(icons.ui.tbox_movedown)), opt(icon(icons.ui.tbox_swapnext)), opt(icon(icons.ui.tbox_split)), opt(icon(icons.ui.tbox_float)), opt(icon(icons.ui.tbox_pinned)), opt(icon(icons.ui.tbox_fullscreen)), opt(icon(icons.ui.tbox_osk))], + }, + }, + launcher: { + width: opt(0), + margin: opt(80), + nix: { + pkgs: opt('nixpkgs/nixos-unstable'), + max: opt(8), + }, + sh: { + max: opt(16), + }, + apps: { + iconSize: opt(62), + max: opt(6), + favorites: opt([['firefox', 'nemo', 'obsidian', 'discord', 'spotify']]), + }, + }, + + overview: { + scale: opt(9), + workspaces: opt(6), + monochromeIcon: opt(false), + }, + + powermenu: { + //sleep: opt('systemctl suspend'), + sleep: opt('loginctl suspend'), + //reboot: opt('reboot'), + reboot: opt('loginctl reboot'), + logout: opt('pkill Hyprland'), + //shutdown: opt('shutdown now'), + shutdown: opt('loginctl poweroff'), + layout: opt<'line' | 'box'>('line'), + labels: opt(true), + }, + + quicksettings: { + avatar: { + image: opt(`/var/lib/AccountsService/icons/${Utils.USER}`), + size: opt(40), + }, + width: opt(380), + position: opt<'left' | 'center' | 'right'>('right'), + networkSettings: opt('gtk-launch nm-connection-editor'), + //networkSettings: opt('gtk-launch gnome-control-center'), + media: { + monochromeIcon: opt(true), + coverSize: opt(100), + }, + }, + + datemenu: { + position: opt<'left' | 'center' | 'right'>('center'), + weather: { + interval: opt(60_000), + unit: opt<'metric' | 'imperial' | 'standard'>('metric'), + key: opt(JSON.parse(Utils.readFile(`${App.configDir}/.weather`) || '{}')?.key || ''), + cities: opt>(JSON.parse(Utils.readFile(`${App.configDir}/.weather`) || '{}')?.cities || []), + }, + }, + + osd: { + progress: { + vertical: opt(true), + pack: { + h: opt<'start' | 'center' | 'end'>('end'), + v: opt<'start' | 'center' | 'end'>('center'), + }, + }, + microphone: { + pack: { + h: opt<'start' | 'center' | 'end'>('center'), + v: opt<'start' | 'center' | 'end'>('end'), + }, + }, + }, + + notifications: { + position: opt>(['top', 'right']), + blacklist: opt(['']), + //blacklist: opt(["Spotify"]), + width: opt(440), + }, + + hyprland: { + gaps: opt(2.4), + inactiveBorder: opt('333333ff'), + gapsWhenOnly: opt(false), + }, +}); + +globalThis['options'] = options; +export default options; diff --git a/linux/home/.config/ags/package.json b/linux/home/.config/ags/package.json new file mode 100644 index 0000000..e0586f7 --- /dev/null +++ b/linux/home/.config/ags/package.json @@ -0,0 +1,18 @@ +{ + "name": "ags", + "author": "srdusr", + "repository": { + "type": "git", + "url": "git+https://github.com/srdusr/dotfiles.git" + }, + "devDependencies": { + "@girs/accountsservice-1.0": "^1.0.0-3.2.7", + "@typescript-eslint/eslint-plugin": "^6.20.0", + "eslint": "^8.56.0", + "eslint-config-standard-with-typescript": "^43.0.1", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-n": "^16.6.2", + "eslint-plugin-promise": "^6.1.1", + "typescript": "^5.3.3" + } +} diff --git a/linux/home/.config/ags/service/asusctl.ts b/linux/home/.config/ags/service/asusctl.ts new file mode 100644 index 0000000..16acbd7 --- /dev/null +++ b/linux/home/.config/ags/service/asusctl.ts @@ -0,0 +1,52 @@ +import { sh } from "lib/utils" + +type Profile = "Performance" | "Balanced" | "Quiet" +type Mode = "Hybrid" | "Integrated" + +class Asusctl extends Service { + static { + Service.register(this, {}, { + "profile": ["string", "r"], + "mode": ["string", "r"], + }) + } + + available = !!Utils.exec("which asusctl") + #profile: Profile = "Balanced" + #mode: Mode = "Hybrid" + + async nextProfile() { + await sh("asusctl profile -n") + const profile = await sh("asusctl profile -p") + const p = profile.split(" ")[3] as Profile + this.#profile = p + this.changed("profile") + } + + async setProfile(prof: Profile) { + await sh(`asusctl profile --profile-set ${prof}`) + this.#profile = prof + this.changed("profile") + } + + async nextMode() { + await sh(`supergfxctl -m ${this.#mode === "Hybrid" ? "Integrated" : "Hybrid"}`) + this.#mode = await sh("supergfxctl -g") as Mode + this.changed("profile") + } + + constructor() { + super() + + if (this.available) { + sh("asusctl profile -p").then(p => this.#profile = p.split(" ")[3] as Profile) + sh("supergfxctl -g").then(m => this.#mode = m as Mode) + } + } + + get profiles(): Profile[] { return ["Performance", "Balanced", "Quiet"] } + get profile() { return this.#profile } + get mode() { return this.#mode } +} + +export default new Asusctl diff --git a/linux/home/.config/ags/service/brightness.ts b/linux/home/.config/ags/service/brightness.ts new file mode 100644 index 0000000..a0b8eb5 --- /dev/null +++ b/linux/home/.config/ags/service/brightness.ts @@ -0,0 +1,69 @@ +import { bash, dependencies, sh } from "lib/utils" + +if (!dependencies("brightnessctl")) + App.quit() + +const get = (args: string) => Number(Utils.exec(`brightnessctl ${args}`)) +const screen = await bash`ls -w1 /sys/class/backlight | head -1` +const kbd = await bash`ls -w1 /sys/class/leds | head -1` + +class Brightness extends Service { + static { + Service.register(this, {}, { + "screen": ["float", "rw"], + "kbd": ["int", "rw"], + }) + } + + #kbdMax = get(`--device ${kbd} max`) + #kbd = get(`--device ${kbd} get`) + #screenMax = get("max") + #screen = get("get") / get("max") + + get kbd() { return this.#kbd } + get screen() { return this.#screen } + + set kbd(value) { + if (value < 0 || value > this.#kbdMax) + return + + sh(`brightnessctl -d ${kbd} s ${value} -q`).then(() => { + this.#kbd = value + this.changed("kbd") + }) + } + + set screen(percent) { + if (percent < 0) + percent = 0 + + if (percent > 1) + percent = 1 + + sh(`brightnessctl set ${Math.floor(percent * 100)}% -q`).then(() => { + this.#screen = percent + this.changed("screen") + }) + } + + constructor() { + super() + + const screenPath = `/sys/class/backlight/${screen}/brightness` + const kbdPath = `/sys/class/leds/${kbd}/brightness` + + Utils.monitorFile(screenPath, async f => { + const v = await Utils.readFileAsync(f) + this.#screen = Number(v) / this.#screenMax + this.changed("screen") + }) + + Utils.monitorFile(kbdPath, async f => { + const v = await Utils.readFileAsync(f) + this.#kbd = Number(v) / this.#kbdMax + this.changed("kbd") + }) + } +} + +export default new Brightness diff --git a/linux/home/.config/ags/service/colorpicker.ts b/linux/home/.config/ags/service/colorpicker.ts new file mode 100644 index 0000000..5918f31 --- /dev/null +++ b/linux/home/.config/ags/service/colorpicker.ts @@ -0,0 +1,56 @@ +import icons from "lib/icons" +import { bash, dependencies } from "lib/utils" + +const COLORS_CACHE = Utils.CACHE_DIR + "/colorpicker.json" +const MAX_NUM_COLORS = 10 + +class ColorPicker extends Service { + static { + Service.register(this, {}, { + "colors": ["jsobject"], + }) + } + + #notifID = 0 + #colors = JSON.parse(Utils.readFile(COLORS_CACHE) || "[]") as string[] + + get colors() { return [...this.#colors] } + set colors(colors) { + this.#colors = colors + this.changed("colors") + } + + // TODO: doesn't work? + async wlCopy(color: string) { + if (dependencies("wl-copy")) + bash(`wl-copy ${color}`) + } + + readonly pick = async () => { + if (!dependencies("hyprpicker")) + return + + const color = await bash("hyprpicker -a -r") + if (!color) + return + + this.wlCopy(color) + const list = this.colors + if (!list.includes(color)) { + list.push(color) + if (list.length > MAX_NUM_COLORS) + list.shift() + + this.colors = list + Utils.writeFile(JSON.stringify(list, null, 2), COLORS_CACHE) + } + + this.#notifID = await Utils.notify({ + id: this.#notifID, + iconName: icons.ui.colorpicker, + summary: color, + }) + } +} + +export default new ColorPicker diff --git a/linux/home/.config/ags/service/nix.ts b/linux/home/.config/ags/service/nix.ts new file mode 100644 index 0000000..3bde9fc --- /dev/null +++ b/linux/home/.config/ags/service/nix.ts @@ -0,0 +1,109 @@ +import icons from "lib/icons" +import { bash, dependencies } from "lib/utils" +import options from "options" + +const CACHE = `${Utils.CACHE_DIR}/nixpkgs` +const PREFIX = "legacyPackages.x86_64-linux." +const MAX = options.launcher.nix.max +const nixpkgs = options.launcher.nix.pkgs + +export type Nixpkg = { + name: string + description: string + pname: string + version: string +} + +class Nix extends Service { + static { + Service.register(this, {}, { + "available": ["boolean", "r"], + "ready": ["boolean", "rw"], + }) + } + + #db: { [name: string]: Nixpkg } = {} + #ready = true + + private set ready(r: boolean) { + this.#ready = r + this.changed("ready") + } + + get db() { return this.#db } + get ready() { return this.#ready } + get available() { return Utils.exec("which nix") } + + constructor() { + super() + if (!this.available) + return this + + this.#updateList() + nixpkgs.connect("changed", this.#updateList) + } + + query = async (filter: string) => { + if (!dependencies("fzf", "nix") || !this.#ready) + return [] as string[] + + return bash(`cat ${CACHE} | fzf -f ${filter} -e | head -n ${MAX} `) + .then(str => str.split("\n").filter(i => i)) + } + + nix(cmd: string, bin: string, args: string) { + return Utils.execAsync(`nix ${cmd} ${nixpkgs}#${bin} --impure ${args}`) + } + + run = async (input: string) => { + if (!dependencies("nix")) + return + + try { + const [bin, ...args] = input.trim().split(/\s+/) + + this.ready = false + await this.nix("shell", bin, "--command sh -c 'exit'") + this.ready = true + + this.nix("run", bin, ["--", ...args].join(" ")) + } catch (err) { + if (typeof err === "string") + Utils.notify("NixRun Error", err, icons.nix.nix) + else + logError(err) + } finally { + this.ready = true + } + } + + #updateList = async () => { + if (!dependencies("nix")) + return + + this.ready = false + this.#db = {} + + // const search = await bash(`nix search ${nixpkgs} --json`) + const search = "" + if (!search) { + this.ready = true + return + } + + const json = Object.entries(JSON.parse(search) as { + [name: string]: Nixpkg + }) + + for (const [pkg, info] of json) { + const name = pkg.replace(PREFIX, "") + this.#db[name] = { ...info, name } + } + + const list = Object.keys(this.#db).join("\n") + await Utils.writeFile(list, CACHE) + this.ready = true + } +} + +export default new Nix diff --git a/linux/home/.config/ags/service/powermenu.ts b/linux/home/.config/ags/service/powermenu.ts new file mode 100644 index 0000000..fd16bc1 --- /dev/null +++ b/linux/home/.config/ags/service/powermenu.ts @@ -0,0 +1,43 @@ +import options from "options" + +const { sleep, reboot, logout, shutdown } = options.powermenu + +export type Action = "sleep" | "reboot" | "logout" | "shutdown" + +class PowerMenu extends Service { + static { + Service.register(this, {}, { + "title": ["string"], + "cmd": ["string"], + }) + } + + #title = "" + #cmd = "" + + get title() { return this.#title } + get cmd() { return this.#cmd } + + action(action: Action) { + [this.#cmd, this.#title] = { + sleep: [sleep.value, "Sleep"], + reboot: [reboot.value, "Reboot"], + logout: [logout.value, "Log Out"], + shutdown: [shutdown.value, "Shutdown"], + }[action] + + this.notify("cmd") + this.notify("title") + this.emit("changed") + App.closeWindow("powermenu") + App.openWindow("verification") + } + + readonly shutdown = () => { + this.action("shutdown") + } +} + +const powermenu = new PowerMenu +Object.assign(globalThis, { powermenu }) +export default powermenu diff --git a/linux/home/.config/ags/service/screenrecord.ts b/linux/home/.config/ags/service/screenrecord.ts new file mode 100644 index 0000000..58721d2 --- /dev/null +++ b/linux/home/.config/ags/service/screenrecord.ts @@ -0,0 +1,102 @@ +import GLib from "gi://GLib" +import icons from "lib/icons" +import { dependencies, sh, bash } from "lib/utils" + +const now = () => GLib.DateTime.new_now_local().format("%Y-%m-%d_%H-%M-%S") + +class Recorder extends Service { + static { + Service.register(this, {}, { + "timer": ["int"], + "recording": ["boolean"], + }) + } + + #recordings = Utils.HOME + "/Videos/Screencasting" + #screenshots = Utils.HOME + "/Pictures/Screenshots" + #file = "" + #interval = 0 + + recording = false + timer = 0 + + async start() { + if (!dependencies("slurp", "wf-recorder")) + return + + if (this.recording) + return + + Utils.ensureDirectory(this.#recordings) + this.#file = `${this.#recordings}/${now()}.mp4` + sh(`wf-recorder -g "${await sh("slurp")}" -f ${this.#file} --pixel-format yuv420p`) + + this.recording = true + this.changed("recording") + + this.timer = 0 + this.#interval = Utils.interval(1000, () => { + this.changed("timer") + this.timer++ + }) + } + + async stop() { + if (!this.recording) + return + + await bash("killall -INT wf-recorder") + this.recording = false + this.changed("recording") + GLib.source_remove(this.#interval) + + Utils.notify({ + iconName: icons.fallback.video, + summary: "Screenrecord", + body: this.#file, + actions: { + "Show in Files": () => sh(`xdg-open ${this.#recordings}`), + "View": () => sh(`xdg-open ${this.#file}`), + }, + }) + } + + async screenshot(full = false) { + if (!dependencies("slurp", "wayshot")) + return + + const file = `${this.#screenshots}/${now()}.png` + Utils.ensureDirectory(this.#screenshots) + + if (full) { + await sh(`wayshot -f ${file}`) + } + else { + const size = await sh("slurp") + if (!size) + return + + await sh(`wayshot -f ${file} -s "${size}"`) + } + + bash(`wl-copy < ${file}`) + + Utils.notify({ + image: file, + summary: "Screenshot", + body: file, + actions: { + "Show in Files": () => sh(`xdg-open ${this.#screenshots}`), + "View": () => sh(`xdg-open ${file}`), + "Edit": () => { + if (dependencies("swappy")) + sh(`swappy -f ${file}`) + }, + }, + }) + } +} + +const recorder = new Recorder +Object.assign(globalThis, { recorder }) +export default recorder diff --git a/linux/home/.config/ags/service/wallpaper.ts b/linux/home/.config/ags/service/wallpaper.ts new file mode 100644 index 0000000..865c6d9 --- /dev/null +++ b/linux/home/.config/ags/service/wallpaper.ts @@ -0,0 +1,127 @@ +import options from 'options'; +import { dependencies, sh } from 'lib/utils'; + +export type Resolution = 1920 | 1366 | 3840; +export type Market = 'random' | 'en-US' | 'ja-JP' | 'en-AU' | 'en-GB' | 'de-DE' | 'en-NZ' | 'en-CA'; + +const WP = `${Utils.HOME}/pictures/wallpapers`; +const Cache = `${Utils.HOME}/Pictures/Wallpapers/Bing`; + +class Wallpaper extends Service { + static { + Service.register( + this, + {}, + { + wallpaper: ['string'], + }, + ); + } + + #blockMonitor = false; + + #wallpaper() { + if (!dependencies('swww')) return; + + sh('hyprctl cursorpos').then(pos => { + sh(['swww', 'img', '--transition-type', 'grow', '--transition-pos', pos.replace(' ', ''), WP]).then(() => { + this.changed('wallpaper'); + }); + }); + } + + async #setWallpaper(path: string) { + this.#blockMonitor = true; + + await sh(`cp "${path}" "${WP}"`); + this.#wallpaper(); + + this.#blockMonitor = false; + } + + async #fetchBing() { + // Check if wallpaper functionality is enabled + if (!options.wallpaper.enable.value) { + console.log('Wallpaper functionality is disabled.'); + return; + } + + try { + const res = await Utils.fetch('https://bing.biturl.top/', { + params: { + resolution: options.wallpaper.resolution.value, + format: 'json', + image_format: 'jpg', + index: 'random', + mkt: options.wallpaper.market.value, + }, + }); + + if (!res.ok) { + console.warn('Failed to fetch from Bing:', res.statusText); + return; + } + + const data = await res.json(); + const { url } = data; + + if (!url) { + console.warn('No URL found in Bing response:', data); + return; + } + + const file = `${Cache}/${url.replace('https://www.bing.com/th?id=', '')}`; + + Utils.ensureDirectory(Cache); + + if (!(await Utils.fileExists(file))) { + await sh(`curl "${url}" --output "${file}"`); + await this.#setWallpaper(file); + } else { + console.log(`Wallpaper already exists: ${file}`); + } + } catch (error) { + console.error('Error fetching wallpaper:', error); + } + } + + readonly random = () => { + // Check if wallpaper functionality is enabled + if (!options.wallpaper.enable.value) { + console.log('Wallpaper functionality is disabled.'); + return; + } + this.#fetchBing(); + }; + + readonly set = (path: string) => { + this.#setWallpaper(path); + }; + + get wallpaper() { + return WP; + } + constructor() { + super(); + + // Respect wallpaper.enable option + if (!options.wallpaper.enable.value) { + console.log('Wallpaper functionality is disabled, not starting swww-daemon.'); + return; + } + + if (!dependencies('swww')) return; + + // Monitor and set wallpaper if enabled + Utils.monitorFile(WP, () => { + if (!this.#blockMonitor) this.#wallpaper(); + }); + + // Start swww-daemon only when wallpaper is enabled + Utils.execAsync('swww-daemon') + .then(this.#wallpaper) + .catch(() => null); + } +} + +export default new Wallpaper(); diff --git a/linux/home/.config/ags/service/weather.ts b/linux/home/.config/ags/service/weather.ts new file mode 100644 index 0000000..14f2df2 --- /dev/null +++ b/linux/home/.config/ags/service/weather.ts @@ -0,0 +1,59 @@ +import options from "options" + +const { interval, key, cities, unit } = options.datemenu.weather + +class Weather extends Service { + static { + Service.register(this, {}, { + "forecasts": ["jsobject"], + }) + } + + #forecasts: Forecast[] = [] + get forecasts() { return this.#forecasts } + + async #fetch(placeid: number) { + const url = "https://api.openweathermap.org/data/2.5/forecast" + const res = await Utils.fetch(url, { + params: { + id: placeid, + appid: key.value, + untis: unit.value, + }, + }) + return await res.json() + } + + constructor() { + super() + if (!key.value) + return this + + Utils.interval(interval.value, () => { + Promise.all(cities.value.map(this.#fetch)).then(forecasts => { + this.#forecasts = forecasts as Forecast[] + this.changed("forecasts") + }) + }) + } +} + +export default new Weather + +type Forecast = { + city: { + name: string, + } + list: Array<{ + dt: number + main: { + temp: number + feels_like: number + }, + weather: Array<{ + main: string, + description: string, + icon: string, + }> + }> +} diff --git a/linux/home/.config/ags/style/extra.scss b/linux/home/.config/ags/style/extra.scss new file mode 100644 index 0000000..e7f9d44 --- /dev/null +++ b/linux/home/.config/ags/style/extra.scss @@ -0,0 +1,67 @@ +@import './mixins/button.scss'; + +* { + font-size: $font-size; + font-family: $font-name; +} + +separator { + &.horizontal { + min-height: $border-width; + } + + &.vertical { + min-width: $border-width; + } +} + +window.popup { + >* { + border: none; + box-shadow: none; + } + + menu { + border-radius: $popover-radius; + background-color: $bg; + padding: $popover-padding; + border: $border-width solid $popover-border-color; + + separator { + background-color: $border-color; + } + + menuitem { + @include button; + padding: $spacing * .5; + margin: ($spacing * .5) 0; + + &:first-child { + margin-top: 0; + } + + &:last-child { + margin-bottom: 0; + } + } + } +} + +tooltip { + * { + all: unset; + } + + background-color: transparent; + border: none; + + >*>* { + background-color: $bg; + border-radius: $radius; + border: $border-width solid $popover-border-color; + color: $fg; + padding: 8px; + margin: 4px; + box-shadow: 0 0 3px 0 $shadow-color; + } +} diff --git a/linux/home/.config/ags/style/mixins/a11y-button.scss b/linux/home/.config/ags/style/mixins/a11y-button.scss new file mode 100644 index 0000000..00b24c6 --- /dev/null +++ b/linux/home/.config/ags/style/mixins/a11y-button.scss @@ -0,0 +1,48 @@ +@import './button'; + +@mixin accs-button($flat: false, $reactive: true) { + @include unset; + color: $fg; + + >* { + border-radius: $radius; + transition: $transition; + + @if $flat { + background-color: transparent; + box-shadow: none; + } + + @else { + background-color: $widget-bg; + box-shadow: inset 0 0 0 $border-width $border-color; + } + } + + + @if $reactive { + + &:focus>*, + &.focused>* { + @include button-focus; + } + + &:hover>* { + @include button-hover; + } + + &:active, + &.active, + &.on, + &:checked { + >* { + @include button-active; + } + + &:hover>* { + box-shadow: inset 0 0 0 $border-width $border-color, + inset 0 0 0 99px $hover-bg; + } + } + } +} diff --git a/linux/home/.config/ags/style/mixins/button.scss b/linux/home/.config/ags/style/mixins/button.scss new file mode 100644 index 0000000..79ec275 --- /dev/null +++ b/linux/home/.config/ags/style/mixins/button.scss @@ -0,0 +1,70 @@ +@mixin button-focus() { + box-shadow: inset 0 0 0 $border-width $primary-bg; + background-color: $hover-bg; + color: $hover-fg; +} + +@mixin button-hover() { + box-shadow: inset 0 0 0 $border-width $border-color; + background-color: $hover-bg; + color: $hover-fg; +} + +@mixin button-active() { + box-shadow: inset 0 0 0 $border-width $border-color; + background-image: $active-gradient; + background-color: $primary-bg; + color: $primary-fg; +} + +@mixin button-disabled() { + box-shadow: none; + background-color: transparent; + color: transparentize($fg, 0.7); +} + +@mixin button($flat: false, $reactive: true, $radius: $radius, $focusable: true) { + all: unset; + transition: $transition; + border-radius: $radius; + color: $fg; + + @if $flat { + background-color: transparent; + background-image: none; + box-shadow: none; + } + + @else { + background-color: $widget-bg; + box-shadow: inset 0 0 0 $border-width $border-color; + } + + @if $reactive { + @if $focusable { + &:focus { + @include button-focus; + } + } + + &:hover { + @include button-hover; + } + + &:active, + &.on, + &.active, + &:checked { + @include button-active; + + &:hover { + box-shadow: inset 0 0 0 $border-width $border-color, + inset 0 0 0 99px $hover-bg; + } + } + } + + &:disabled { + @include button-disabled; + } +} diff --git a/linux/home/.config/ags/style/mixins/floating-widget.scss b/linux/home/.config/ags/style/mixins/floating-widget.scss new file mode 100644 index 0000000..613668d --- /dev/null +++ b/linux/home/.config/ags/style/mixins/floating-widget.scss @@ -0,0 +1,12 @@ +@mixin floating-widget { + @if $shadows { + box-shadow: 0 0 5px 0 $shadow-color; + } + + margin: max($spacing, 8px); + border: $border-width solid $popover-border-color; + background-color: $bg; + color: $fg; + border-radius: $popover-radius; + padding: $popover-padding; +} diff --git a/linux/home/.config/ags/style/mixins/hidden.scss b/linux/home/.config/ags/style/mixins/hidden.scss new file mode 100644 index 0000000..ea6a42c --- /dev/null +++ b/linux/home/.config/ags/style/mixins/hidden.scss @@ -0,0 +1,15 @@ +@mixin hidden { + background-color: transparent; + background-image: none; + border-color: transparent; + box-shadow: none; + -gtk-icon-transform: scale(0); + + * { + background-color: transparent; + background-image: none; + border-color: transparent; + box-shadow: none; + -gtk-icon-transform: scale(0); + } +} diff --git a/linux/home/.config/ags/style/mixins/media.scss b/linux/home/.config/ags/style/mixins/media.scss new file mode 100644 index 0000000..3178029 --- /dev/null +++ b/linux/home/.config/ags/style/mixins/media.scss @@ -0,0 +1,42 @@ +@mixin media() { + @include widget; + padding: $padding; + + .cover { + @if $shadows { + box-shadow: 2px 2px 2px 0 $shadow-color; + } + + background-size: cover; + background-position: center; + border-radius: $radius*0.8; + margin-right: $spacing; + } + + button { + @include button($flat: true); + padding: $padding * .5; + + &.play-pause { + margin: 0 ($spacing * .5); + } + + image { + font-size: 1.2em; + } + } + + .artist { + color: transparentize($fg, .2); + font-size: .9em; + } + + scale { + @include slider($width: .5em, $slider: false, $gradient: linear-gradient($fg, $fg)); + margin-bottom: $padding * .5; + + trough { + border: none; + } + } +} diff --git a/linux/home/.config/ags/style/mixins/scrollable.scss b/linux/home/.config/ags/style/mixins/scrollable.scss new file mode 100644 index 0000000..b66f246 --- /dev/null +++ b/linux/home/.config/ags/style/mixins/scrollable.scss @@ -0,0 +1,42 @@ +@mixin scrollable($top: false, $bottom: false) { + + @if $top and $shadows { + undershoot.top { + background: linear-gradient(to bottom, $shadow-color, transparent, transparent, transparent, transparent, transparent); + } + } + + @if $bottom and $shadows { + undershoot.bottom { + background: linear-gradient(to top, $shadow-color, transparent, transparent, transparent, transparent, transparent); + } + } + + scrollbar, + scrollbar * { + all: unset; + } + + scrollbar.vertical { + transition: $transition; + background-color: transparentize($bg, 0.7); + + &:hover { + background-color: transparentize($bg, 0.3); + + slider { + background-color: transparentize($fg, 0.3); + min-width: .6em; + } + } + } + + + scrollbar.vertical slider { + background-color: transparentize($fg, 0.5); + border-radius: $radius; + min-width: .4em; + min-height: 2em; + transition: $transition; + } +} diff --git a/linux/home/.config/ags/style/mixins/slider.scss b/linux/home/.config/ags/style/mixins/slider.scss new file mode 100644 index 0000000..b90e566 --- /dev/null +++ b/linux/home/.config/ags/style/mixins/slider.scss @@ -0,0 +1,74 @@ +@import './unset'; + +@mixin slider($width: 0.7em, $slider-width: .5em, $gradient: $active-gradient, $slider: true, $focusable: true, $radius: $radius) { + @include unset($rec: true); + + trough { + transition: $transition; + border-radius: $radius; + border: $border; + background-color: $widget-bg; + min-height: $width; + min-width: $width; + + highlight, + progress { + border-radius: max($radius - $border-width, 0); + background-image: $gradient; + min-height: $width; + min-width: $width; + } + } + + slider { + box-shadow: none; + background-color: transparent; + border: $border-width solid transparent; + transition: $transition; + border-radius: $radius; + min-height: $width; + min-width: $width; + margin: -$slider-width; + } + + &:hover { + trough { + background-color: $hover-bg; + } + + slider { + @if $slider { + background-color: $fg; + border-color: $border-color; + + @if $shadows { + box-shadow: 0 0 3px 0 $shadow-color; + } + } + } + } + + &:disabled { + + highlight, + progress { + background-color: transparentize($fg, 0.4); + background-image: none; + } + } + + @if $focusable { + trough:focus { + background-color: $hover-bg; + box-shadow: inset 0 0 0 $border-width $primary-bg; + + slider { + @if $slider { + background-color: $fg; + box-shadow: inset 0 0 0 $border-width $primary-bg; + } + } + } + + } +} diff --git a/linux/home/.config/ags/style/mixins/spacing.scss b/linux/home/.config/ags/style/mixins/spacing.scss new file mode 100644 index 0000000..4096fba --- /dev/null +++ b/linux/home/.config/ags/style/mixins/spacing.scss @@ -0,0 +1,53 @@ +@mixin spacing($multiplier: 1, $spacing: $spacing, $rec: false) { + &.horizontal>* { + margin: 0 calc($spacing * $multiplier / 2); + + &:first-child { + margin-left: 0; + } + + &:last-child { + margin-right: 0; + } + } + + &.vertical>* { + margin: calc($spacing * $multiplier / 2) 0; + + &:first-child { + margin-top: 0; + } + + &:last-child { + margin-bottom: 0; + } + } + + @if $rec { + box { + &.horizontal>* { + margin: 0 $spacing * $multiplier / 2; + + &:first-child { + margin-left: 0; + } + + &:last-child { + margin-right: 0; + } + } + + &.vertical>* { + margin: $spacing * $multiplier / 2 0; + + &:first-child { + margin-top: 0; + } + + &:last-child { + margin-bottom: 0; + } + } + } + } +} diff --git a/linux/home/.config/ags/style/mixins/switch.scss b/linux/home/.config/ags/style/mixins/switch.scss new file mode 100644 index 0000000..2abf360 --- /dev/null +++ b/linux/home/.config/ags/style/mixins/switch.scss @@ -0,0 +1,16 @@ +@import './button'; + +@mixin switch { + @include button; + + slider { + background-color: $primary-fg; + border-radius: $radius; + min-width: 24px; + min-height: 24px; + } + + image { + color: transparent; + } +} diff --git a/linux/home/.config/ags/style/mixins/unset.scss b/linux/home/.config/ags/style/mixins/unset.scss new file mode 100644 index 0000000..eb80af5 --- /dev/null +++ b/linux/home/.config/ags/style/mixins/unset.scss @@ -0,0 +1,9 @@ +@mixin unset($rec: false) { + all: unset; + + @if $rec { + * { + all: unset + } + } +} diff --git a/linux/home/.config/ags/style/mixins/widget.scss b/linux/home/.config/ags/style/mixins/widget.scss new file mode 100644 index 0000000..053f1aa --- /dev/null +++ b/linux/home/.config/ags/style/mixins/widget.scss @@ -0,0 +1,7 @@ +@mixin widget { + transition: $transition; + border-radius: $radius; + color: $fg; + background-color: $widget-bg; + border: $border; +} diff --git a/linux/home/.config/ags/style/style.ts b/linux/home/.config/ags/style/style.ts new file mode 100644 index 0000000..a9b94fe --- /dev/null +++ b/linux/home/.config/ags/style/style.ts @@ -0,0 +1,103 @@ +/* eslint-disable max-len */ +import { type Opt } from "lib/option" +import options from "options" +import { bash, dependencies, sh } from "lib/utils" + +const deps = [ + "font", + "theme", + "bar.flatButtons", + "bar.position", + "bar.battery.charging", + "bar.battery.blocks", +] + +const { + dark, + light, + blur, + scheme, + padding, + spacing, + radius, + shadows, + widget, + border, +} = options.theme + +const popoverPaddingMultiplier = 1.6 + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const t = (dark: Opt | string, light: Opt | string) => scheme.value === "dark" + ? `${dark}` : `${light}` + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const $ = (name: string, value: string | Opt) => `$${name}: ${value};` + +const variables = () => [ + $("bg", blur.value ? `transparentize(${t(dark.bg, light.bg)}, ${blur.value / 100})` : t(dark.bg, light.bg)), + $("fg", t(dark.fg, light.fg)), + + $("primary-bg", t(dark.primary.bg, light.primary.bg)), + $("primary-fg", t(dark.primary.fg, light.primary.fg)), + + $("error-bg", t(dark.error.bg, light.error.bg)), + $("error-fg", t(dark.error.fg, light.error.fg)), + + $("scheme", scheme), + $("padding", `${padding}pt`), + $("spacing", `${spacing}pt`), + $("radius", `${radius}px`), + $("transition", `${options.transition}ms`), + + $("shadows", `${shadows}`), + + $("widget-bg", `transparentize(${t(dark.widget, light.widget)}, ${widget.opacity.value / 100})`), + + $("hover-bg", `transparentize(${t(dark.widget, light.widget)}, ${(widget.opacity.value * .9) / 100})`), + $("hover-fg", `lighten(${t(dark.fg, light.fg)}, 8%)`), + + $("border-width", `${border.width}px`), + $("border-color", `transparentize(${t(dark.border, light.border)}, ${border.opacity.value / 100})`), + $("border", "$border-width solid $border-color"), + + $("active-gradient", `linear-gradient(to right, ${t(dark.primary.bg, light.primary.bg)}, darken(${t(dark.primary.bg, light.primary.bg)}, 4%))`), + $("shadow-color", t("rgba(0,0,0,.6)", "rgba(0,0,0,.4)")), + $("text-shadow", t("2pt 2pt 2pt $shadow-color", "none")), + + $("popover-border-color", `transparentize(${t(dark.border, light.border)}, ${Math.max(((border.opacity.value - 1) / 100), 0)})`), + $("popover-padding", `$padding * ${popoverPaddingMultiplier}`), + $("popover-radius", radius.value === 0 ? "0" : "$radius + $popover-padding"), + + $("font-size", `${options.font.size}pt`), + $("font-name", options.font.name), + + // etc + $("charging-bg", options.bar.battery.charging), + $("bar-battery-blocks", options.bar.battery.blocks), + $("bar-position", options.bar.position), + $("hyprland-gaps-multiplier", options.hyprland.gaps), +] + +async function resetCss() { + if (!dependencies("sass", "fd")) + return + + try { + const vars = `${TMP}/variables.scss` + await Utils.writeFile(variables().join("\n"), vars) + + const fd = await sh(`fd ".scss" ${App.configDir}`) + const files = fd.split(/\s+/).map(f => `@import '${f}';`) + const scss = [`@import '${vars}';`, ...files].join("\n") + const css = await bash`echo "${scss}" | sass --stdin` + + App.applyCss(css, true) + } catch (error) { + logError(error) + } +} + +Utils.monitorFile(App.configDir, resetCss) +options.handler(deps, resetCss) +await resetCss() diff --git a/linux/home/.config/ags/tsconfig.json b/linux/home/.config/ags/tsconfig.json new file mode 100644 index 0000000..1708aa3 --- /dev/null +++ b/linux/home/.config/ags/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ES2022", + "lib": [ + "ES2022" + ], + "allowJs": true, + "checkJs": true, + "strict": true, + "noImplicitAny": false, + "baseUrl": ".", + "typeRoots": [ + "./types", + "./node_modules/@girs" + ], + "skipLibCheck": true + } +} diff --git a/linux/home/.config/ags/widget/PopupWindow.ts b/linux/home/.config/ags/widget/PopupWindow.ts new file mode 100644 index 0000000..b53b6fd --- /dev/null +++ b/linux/home/.config/ags/widget/PopupWindow.ts @@ -0,0 +1,156 @@ +import { type WindowProps } from "types/widgets/window" +import { type RevealerProps } from "types/widgets/revealer" +import { type EventBoxProps } from "types/widgets/eventbox" +import type Gtk from "gi://Gtk?version=3.0" +import options from "options" + +type Transition = RevealerProps["transition"] +type Child = WindowProps["child"] + +type PopupWindowProps = Omit & { + name: string + layout?: keyof ReturnType + transition?: Transition, +} + +export const Padding = (name: string, { + css = "", + hexpand = true, + vexpand = true, +}: EventBoxProps = {}) => Widget.EventBox({ + hexpand, + vexpand, + can_focus: false, + child: Widget.Box({ css }), + setup: w => w.on("button-press-event", () => App.toggleWindow(name)), +}) + +const PopupRevealer = ( + name: string, + child: Child, + transition: Transition = "slide_down", +) => Widget.Box( + { css: "padding: 1px;" }, + Widget.Revealer({ + transition, + child: Widget.Box({ + class_name: "window-content", + child, + }), + transitionDuration: options.transition.bind(), + setup: self => self.hook(App, (_, wname, visible) => { + if (wname === name) + self.reveal_child = visible + }), + }), +) + +const Layout = (name: string, child: Child, transition?: Transition) => ({ + "center": () => Widget.CenterBox({}, + Padding(name), + Widget.CenterBox( + { vertical: true }, + Padding(name), + PopupRevealer(name, child, transition), + Padding(name), + ), + Padding(name), + ), + "top": () => Widget.CenterBox({}, + Padding(name), + Widget.Box( + { vertical: true }, + PopupRevealer(name, child, transition), + Padding(name), + ), + Padding(name), + ), + "top-right": () => Widget.Box({}, + Padding(name), + Widget.Box( + { + hexpand: false, + vertical: true, + }, + PopupRevealer(name, child, transition), + Padding(name), + ), + ), + "top-center": () => Widget.Box({}, + Padding(name), + Widget.Box( + { + hexpand: false, + vertical: true, + }, + PopupRevealer(name, child, transition), + Padding(name), + ), + Padding(name), + ), + "top-left": () => Widget.Box({}, + Widget.Box( + { + hexpand: false, + vertical: true, + }, + PopupRevealer(name, child, transition), + Padding(name), + ), + Padding(name), + ), + "bottom-left": () => Widget.Box({}, + Widget.Box( + { + hexpand: false, + vertical: true, + }, + Padding(name), + PopupRevealer(name, child, transition), + ), + Padding(name), + ), + "bottom-center": () => Widget.Box({}, + Padding(name), + Widget.Box( + { + hexpand: false, + vertical: true, + }, + Padding(name), + PopupRevealer(name, child, transition), + ), + Padding(name), + ), + "bottom-right": () => Widget.Box({}, + Padding(name), + Widget.Box( + { + hexpand: false, + vertical: true, + }, + Padding(name), + PopupRevealer(name, child, transition), + ), + ), +}) + +export default ({ + name, + child, + layout = "center", + transition, + exclusivity = "ignore", + ...props +}: PopupWindowProps) => Widget.Window({ + name, + class_names: [name, "popup-window"], + setup: w => w.keybind("Escape", () => App.closeWindow(name)), + visible: false, + keymode: "on-demand", + exclusivity, + layer: "top", + anchor: ["top", "bottom", "right", "left"], + child: Layout(name, child, transition)[layout](), + ...props, +}) diff --git a/linux/home/.config/ags/widget/RegularWindow.ts b/linux/home/.config/ags/widget/RegularWindow.ts new file mode 100644 index 0000000..1e4225d --- /dev/null +++ b/linux/home/.config/ags/widget/RegularWindow.ts @@ -0,0 +1,3 @@ +import Gtk from "gi://Gtk?version=3.0" + +export default Widget.subclass(Gtk.Window) diff --git a/linux/home/.config/ags/widget/bar/Bar.ts b/linux/home/.config/ags/widget/bar/Bar.ts new file mode 100644 index 0000000..9343a36 --- /dev/null +++ b/linux/home/.config/ags/widget/bar/Bar.ts @@ -0,0 +1,57 @@ +import BatteryBar from "./buttons/BatteryBar" +import ColorPicker from "./buttons/ColorPicker" +import Date from "./buttons/Date" +import Launcher from "./buttons/Launcher" +import Media from "./buttons/Media" +import PowerMenu from "./buttons/PowerMenu" +import SysTray from "./buttons/SysTray" +import SystemIndicators from "./buttons/SystemIndicators" +import Taskbar from "./buttons/Taskbar" +import Workspaces from "./buttons/Workspaces" +import ScreenRecord from "./buttons/ScreenRecord" +import Messages from "./buttons/Messages" +import options from "options" + +const { start, center, end } = options.bar.layout +const pos = options.bar.position.bind() + +export type BarWidget = keyof typeof widget + +const widget = { + battery: BatteryBar, + colorpicker: ColorPicker, + date: Date, + launcher: Launcher, + media: Media, + powermenu: PowerMenu, + systray: SysTray, + system: SystemIndicators, + taskbar: Taskbar, + workspaces: Workspaces, + screenrecord: ScreenRecord, + messages: Messages, + expander: () => Widget.Box({ expand: true }), +} + +export default (monitor: number) => Widget.Window({ + monitor, + class_name: "bar", + name: `bar${monitor}`, + exclusivity: "exclusive", + anchor: pos.as(pos => [pos, "right", "left"]), + child: Widget.CenterBox({ + css: "min-width: 2px; min-height: 2px;", + startWidget: Widget.Box({ + hexpand: true, + children: start.bind().as(s => s.map(w => widget[w]())), + }), + centerWidget: Widget.Box({ + hpack: "center", + children: center.bind().as(c => c.map(w => widget[w]())), + }), + endWidget: Widget.Box({ + hexpand: true, + children: end.bind().as(e => e.map(w => widget[w]())), + }), + }), +}) diff --git a/linux/home/.config/ags/widget/bar/PanelButton.ts b/linux/home/.config/ags/widget/bar/PanelButton.ts new file mode 100644 index 0000000..332b46d --- /dev/null +++ b/linux/home/.config/ags/widget/bar/PanelButton.ts @@ -0,0 +1,46 @@ +import options from "options" +import { ButtonProps } from "types/widgets/button" + +type PanelButtonProps = ButtonProps & { + window?: string, + flat?: boolean +} + +export default ({ + window = "", + flat, + child, + setup, + ...rest +}: PanelButtonProps) => Widget.Button({ + child: Widget.Box({ child }), + setup: self => { + let open = false + + self.toggleClassName("panel-button") + self.toggleClassName(window) + + self.hook(options.bar.flatButtons, () => { + self.toggleClassName("flat", flat ?? options.bar.flatButtons.value) + }) + + self.hook(App, (_, win, visible) => { + if (win !== window) + return + + if (open && !visible) { + open = false + self.toggleClassName("active", false) + } + + if (visible) { + open = true + self.toggleClassName("active") + } + }) + + if (setup) + setup(self) + }, + ...rest, +}) diff --git a/linux/home/.config/ags/widget/bar/ScreenCorners.ts b/linux/home/.config/ags/widget/bar/ScreenCorners.ts new file mode 100644 index 0000000..1b35e50 --- /dev/null +++ b/linux/home/.config/ags/widget/bar/ScreenCorners.ts @@ -0,0 +1,25 @@ +import options from "options" + +const { corners } = options.bar + +export default (monitor: number) => Widget.Window({ + monitor, + name: `corner${monitor}`, + class_name: "screen-corner", + anchor: ["top", "bottom", "right", "left"], + click_through: true, + child: Widget.Box({ + class_name: "shadow", + child: Widget.Box({ + class_name: "border", + expand: true, + child: Widget.Box({ + class_name: "corner", + expand: true, + }), + }), + }), + setup: self => self.hook(corners, () => { + self.toggleClassName("corners", corners.value) + }), +}) diff --git a/linux/home/.config/ags/widget/bar/bar.scss b/linux/home/.config/ags/widget/bar/bar.scss new file mode 100644 index 0000000..5c6c2cd --- /dev/null +++ b/linux/home/.config/ags/widget/bar/bar.scss @@ -0,0 +1,242 @@ +@use 'sass:color'; + +$bar-spacing: $spacing * 0.3; +$button-radius: $radius; + +@mixin panel-button($flat: true, $reactive: true) { + @include accs-button($flat, $reactive); + + >* { + border-radius: $button-radius; + margin: $bar-spacing; + background-color: $bg; + } + + label, + image { + font-weight: bold; + } + + >* { + padding: $padding * 0.8 $padding * 1.2; + } +} + +.bar { + .panel-button { + @include panel-button; + + &:not(.flat) { + @include accs-button($flat: false); + } + } + + .launcher { + .colored { + color: transparentize($primary-bg, 0.2); + } + + &:hover .colored { + color: $primary-bg; + } + + &:active .colored, + &.active .colored { + color: $primary-fg; + } + } + + .workspaces { + label { + font-size: 0; + min-width: 5pt; + min-height: 5pt; + border-radius: $radius * 0.6; + box-shadow: inset 0 0 0 $border-width $border-color; + margin: 0 $padding * 0.5; + transition: $transition * 0.5; + background-color: transparentize($fg, 0.8); + + &.occupied { + background-color: transparentize($fg, 0.2); + min-width: 7pt; + min-height: 7pt; + } + + &.active { + // background-color: $primary-bg; + background-image: $active-gradient; + min-width: 20pt; + min-height: 12pt; + } + + &.inctive { + // background-color: $primary-bg; + background-image: $active-gradient; + min-width: 20pt; + min-height: 12pt; + } + } + + &.inactive, + &:active { + label { + background-color: transparentize($primary-fg, 0.3); + + &.occupied { + background-color: transparentize($primary-fg, 0.15); + } + + &.active { + background-color: $primary-fg; + } + + &.inactive { + background-color: $primary-fg; + } + } + } + } + + .media label { + margin: 0 ($spacing * 0.5); + } + + .taskbar .indicator.active { + background-color: $primary-bg; + border-radius: $radius; + min-height: 4pt; + min-width: 6pt; + margin: 2pt; + } + + .powermenu.colored, + .recorder { + image { + color: transparentize($error-bg, 0.3); + } + + &:hover image { + color: transparentize($error-bg, 0.15); + } + + &:active image { + color: $primary-fg; + } + } + + .quicksettings>box>box { + @include spacing($spacing: if($bar-spacing==0, $padding / 2, $bar-spacing)); + } + + .quicksettings:not(.active):not(:active) { + .bluetooth { + color: $primary-bg; + + label { + font-size: $font-size * 0.7; + color: $fg; + text-shadow: $text-shadow; + } + } + } + + .battery-bar { + >* { + padding: 0; + } + + &.bar-hidden>box { + padding: 0 $spacing * 0.5; + + image { + margin: 0; + } + } + + levelbar * { + all: unset; + transition: $transition; + } + + .whole { + @if $shadows { + image { + -gtk-icon-shadow: $text-shadow; + } + + label { + text-shadow: $text-shadow; + } + } + } + + .regular image { + margin-left: $spacing * 0.5; + } + + trough { + @include widget; + min-height: 12pt; + min-width: 12pt; + } + + .regular trough { + margin-right: $spacing * 0.5; + } + + block { + margin: 0; + + &:last-child { + border-radius: 0 $button-radius $button-radius 0; + } + + &:first-child { + border-radius: $button-radius 0 0 $button-radius; + } + } + + .vertical { + block { + &:last-child { + border-radius: 0 0 $button-radius $button-radius; + } + + &:first-child { + border-radius: $button-radius $button-radius 0 0; + } + } + } + + @for $i from 1 through $bar-battery-blocks { + block:nth-child(#{$i}).filled { + background-color: color.mix($bg, $primary-bg, $i * 3); + } + + &.low block:nth-child(#{$i}).filled { + background-color: color.mix($bg, $error-bg, $i * 3); + } + + &.charging block:nth-child(#{$i}).filled { + background-color: color.mix($bg, $charging-bg, $i * 3); + } + + &:active .regular block:nth-child(#{$i}).filled { + background-color: color.mix($bg, $primary-fg, $i * 3); + } + } + + &.low image { + color: $error-bg; + } + + &.charging image { + color: $charging-bg; + } + + &:active image { + color: $primary-fg; + } + } +} diff --git a/linux/home/.config/ags/widget/bar/buttons/BatteryBar.ts b/linux/home/.config/ags/widget/bar/buttons/BatteryBar.ts new file mode 100644 index 0000000..18de329 --- /dev/null +++ b/linux/home/.config/ags/widget/bar/buttons/BatteryBar.ts @@ -0,0 +1,94 @@ +import icons from "lib/icons" +import options from "options" +import PanelButton from "../PanelButton" + +const battery = await Service.import("battery") +const { bar, percentage, blocks, width, low } = options.bar.battery + +const Indicator = () => Widget.Icon({ + setup: self => self.hook(battery, () => { + self.icon = battery.charging || battery.charged + ? icons.battery.charging + : battery.icon_name + }), +}) + +const PercentLabel = () => Widget.Revealer({ + transition: "slide_right", + click_through: true, + reveal_child: percentage.bind(), + child: Widget.Label({ + label: battery.bind("percent").as(p => `${p}%`), + }), +}) + +const LevelBar = () => { + const level = Widget.LevelBar({ + bar_mode: "discrete", + max_value: blocks.bind(), + visible: bar.bind().as(b => b !== "hidden"), + value: battery.bind("percent").as(p => (p / 100) * blocks.value), + }) + const update = () => { + level.value = (battery.percent / 100) * blocks.value + level.css = `block { min-width: ${width.value / blocks.value}pt; }` + } + return level + .hook(width, update) + .hook(blocks, update) + .hook(bar, () => { + level.vpack = bar.value === "whole" ? "fill" : "center" + level.hpack = bar.value === "whole" ? "fill" : "center" + }) +} + +const WholeButton = () => Widget.Overlay({ + vexpand: true, + child: LevelBar(), + class_name: "whole", + pass_through: true, + overlay: Widget.Box({ + hpack: "center", + children: [ + Widget.Icon({ + icon: icons.battery.charging, + visible: Utils.merge([ + battery.bind("charging"), + battery.bind("charged"), + ], (ing, ed) => ing || ed), + }), + Widget.Box({ + hpack: "center", + vpack: "center", + child: PercentLabel(), + }), + ], + }), +}) + +const Regular = () => Widget.Box({ + class_name: "regular", + children: [ + Indicator(), + PercentLabel(), + LevelBar(), + ], +}) + +export default () => PanelButton({ + class_name: "battery-bar", + hexpand: false, + on_clicked: () => { percentage.value = !percentage.value }, + visible: battery.bind("available"), + child: Widget.Box({ + expand: true, + visible: battery.bind("available"), + child: bar.bind().as(b => b === "whole" ? WholeButton() : Regular()), + }), + setup: self => self + .hook(bar, w => w.toggleClassName("bar-hidden", bar.value === "hidden")) + .hook(battery, w => { + w.toggleClassName("charging", battery.charging || battery.charged) + w.toggleClassName("low", battery.percent < low.value) + }), +}) diff --git a/linux/home/.config/ags/widget/bar/buttons/ColorPicker.ts b/linux/home/.config/ags/widget/bar/buttons/ColorPicker.ts new file mode 100644 index 0000000..5b1f3f6 --- /dev/null +++ b/linux/home/.config/ags/widget/bar/buttons/ColorPicker.ts @@ -0,0 +1,37 @@ +import PanelButton from "../PanelButton" +import colorpicker from "service/colorpicker" +import Gdk from "gi://Gdk" + +const css = (color: string) => ` +* { + background-color: ${color}; + color: transparent; +} +*:hover { + color: white; + text-shadow: 2px 2px 3px rgba(0,0,0,.8); +}` + +export default () => { + const menu = Widget.Menu({ + class_name: "colorpicker", + children: colorpicker.bind("colors").as(c => c.map(color => Widget.MenuItem({ + child: Widget.Label(color), + css: css(color), + on_activate: () => colorpicker.wlCopy(color), + }))), + }) + + return PanelButton({ + class_name: "color-picker", + child: Widget.Icon("color-select-symbolic"), + tooltip_text: colorpicker.bind("colors").as(v => `${v.length} colors`), + on_clicked: colorpicker.pick, + on_secondary_click: self => { + if (colorpicker.colors.length === 0) + return + + menu.popup_at_widget(self, Gdk.Gravity.SOUTH, Gdk.Gravity.NORTH, null) + }, + }) +} diff --git a/linux/home/.config/ags/widget/bar/buttons/Date.ts b/linux/home/.config/ags/widget/bar/buttons/Date.ts new file mode 100644 index 0000000..44c2540 --- /dev/null +++ b/linux/home/.config/ags/widget/bar/buttons/Date.ts @@ -0,0 +1,15 @@ +import { clock } from "lib/variables" +import PanelButton from "../PanelButton" +import options from "options" + +const { format, action } = options.bar.date +const time = Utils.derive([clock, format], (c, f) => c.format(f) || "") + +export default () => PanelButton({ + window: "datemenu", + on_clicked: action.bind(), + child: Widget.Label({ + justification: "center", + label: time.bind(), + }), +}) diff --git a/linux/home/.config/ags/widget/bar/buttons/Launcher.ts b/linux/home/.config/ags/widget/bar/buttons/Launcher.ts new file mode 100644 index 0000000..f3fee6b --- /dev/null +++ b/linux/home/.config/ags/widget/bar/buttons/Launcher.ts @@ -0,0 +1,49 @@ +import PanelButton from "../PanelButton" +import options from "options" +import nix from "service/nix" + +const { icon, label, action } = options.bar.launcher + +function Spinner() { + const child = Widget.Icon({ + icon: icon.icon.bind(), + class_name: Utils.merge([ + icon.colored.bind(), + nix.bind("ready"), + ], (c, r) => `${c ? "colored" : ""} ${r ? "" : "spinning"}`), + css: ` + @keyframes spin { + to { -gtk-icon-transform: rotate(1turn); } + } + + image.spinning { + animation-name: spin; + animation-duration: 1s; + animation-timing-function: linear; + animation-iteration-count: infinite; + } + `, + }) + + return Widget.Revealer({ + transition: "slide_left", + child, + reveal_child: Utils.merge([ + icon.icon.bind(), + nix.bind("ready"), + ], (i, r) => Boolean(i || r)), + }) +} + +export default () => PanelButton({ + window: "launcher", + on_clicked: action.bind(), + child: Widget.Box([ + Spinner(), + Widget.Label({ + class_name: label.colored.bind().as(c => c ? "colored" : ""), + visible: label.label.bind().as(v => !!v), + label: label.label.bind(), + }), + ]), +}) diff --git a/linux/home/.config/ags/widget/bar/buttons/Media.ts b/linux/home/.config/ags/widget/bar/buttons/Media.ts new file mode 100644 index 0000000..b3aab61 --- /dev/null +++ b/linux/home/.config/ags/widget/bar/buttons/Media.ts @@ -0,0 +1,92 @@ +import { type MprisPlayer } from "types/service/mpris" +import PanelButton from "../PanelButton" +import options from "options" +import icons from "lib/icons" +import { icon } from "lib/utils" + +const mpris = await Service.import("mpris") +const { length, direction, preferred, monochrome, format } = options.bar.media + +const getPlayer = (name = preferred.value) => + mpris.getPlayer(name) || mpris.players[0] || null + +const Content = (player: MprisPlayer) => { + const revealer = Widget.Revealer({ + click_through: true, + visible: length.bind().as(l => l > 0), + transition: direction.bind().as(d => `slide_${d}` as const), + setup: self => { + let current = "" + self.hook(player, () => { + if (current === player.track_title) + return + + current = player.track_title + self.reveal_child = true + Utils.timeout(3000, () => { + !self.is_destroyed && (self.reveal_child = false) + }) + }) + }, + child: Widget.Label({ + truncate: "end", + max_width_chars: length.bind().as(n => n > 0 ? n : -1), + label: Utils.merge([ + player.bind("track_title"), + player.bind("track_artists"), + format.bind(), + ], () => `${format}` + .replace("{title}", player.track_title) + .replace("{artists}", player.track_artists.join(", ")) + .replace("{artist}", player.track_artists[0] || "") + .replace("{album}", player.track_album) + .replace("{name}", player.name) + .replace("{identity}", player.identity), + ), + }), + }) + + const playericon = Widget.Icon({ + icon: Utils.merge([player.bind("entry"), monochrome.bind()], (entry => { + const name = `${entry}${monochrome.value ? "-symbolic" : ""}` + return icon(name, icons.fallback.audio) + })), + }) + + return Widget.Box({ + attribute: { revealer }, + children: direction.bind().as(d => d === "right" + ? [playericon, revealer] : [revealer, playericon]), + }) +} + +export default () => { + let player = getPlayer() + + const btn = PanelButton({ + class_name: "media", + child: Widget.Icon(icons.fallback.audio), + }) + + const update = () => { + player = getPlayer() + btn.visible = !!player + + if (!player) + return + + const content = Content(player) + const { revealer } = content.attribute + btn.child = content + btn.on_primary_click = () => { player.playPause() } + btn.on_secondary_click = () => { player.playPause() } + btn.on_scroll_up = () => { player.next() } + btn.on_scroll_down = () => { player.previous() } + btn.on_hover = () => { revealer.reveal_child = true } + btn.on_hover_lost = () => { revealer.reveal_child = false } + } + + return btn + .hook(preferred, update) + .hook(mpris, update, "notify::players") +} diff --git a/linux/home/.config/ags/widget/bar/buttons/Messages.ts b/linux/home/.config/ags/widget/bar/buttons/Messages.ts new file mode 100644 index 0000000..a8971e9 --- /dev/null +++ b/linux/home/.config/ags/widget/bar/buttons/Messages.ts @@ -0,0 +1,16 @@ +import icons from "lib/icons" +import PanelButton from "../PanelButton" +import options from "options" + +const n = await Service.import("notifications") +const notifs = n.bind("notifications") +const action = options.bar.messages.action.bind() + +export default () => PanelButton({ + class_name: "messages", + on_clicked: action, + visible: notifs.as(n => n.length > 0), + child: Widget.Box([ + Widget.Icon(icons.notifications.message), + ]), +}) diff --git a/linux/home/.config/ags/widget/bar/buttons/PowerMenu.ts b/linux/home/.config/ags/widget/bar/buttons/PowerMenu.ts new file mode 100644 index 0000000..4432ade --- /dev/null +++ b/linux/home/.config/ags/widget/bar/buttons/PowerMenu.ts @@ -0,0 +1,15 @@ +import icons from "lib/icons" +import PanelButton from "../PanelButton" +import options from "options" + +const { monochrome, action } = options.bar.powermenu + +export default () => PanelButton({ + window: "powermenu", + on_clicked: action.bind(), + child: Widget.Icon(icons.powermenu.shutdown), + setup: self => self.hook(monochrome, () => { + self.toggleClassName("colored", !monochrome.value) + self.toggleClassName("box") + }), +}) diff --git a/linux/home/.config/ags/widget/bar/buttons/ScreenRecord.ts b/linux/home/.config/ags/widget/bar/buttons/ScreenRecord.ts new file mode 100644 index 0000000..1d6eb36 --- /dev/null +++ b/linux/home/.config/ags/widget/bar/buttons/ScreenRecord.ts @@ -0,0 +1,21 @@ +import PanelButton from "../PanelButton" +import screenrecord from "service/screenrecord" +import icons from "lib/icons" + +export default () => PanelButton({ + class_name: "recorder", + on_clicked: () => screenrecord.stop(), + visible: screenrecord.bind("recording"), + child: Widget.Box({ + children: [ + Widget.Icon(icons.recorder.recording), + Widget.Label({ + label: screenrecord.bind("timer").as(time => { + const sec = time % 60 + const min = Math.floor(time / 60) + return `${min}:${sec < 10 ? "0" + sec : sec}` + }), + }), + ], + }), +}) diff --git a/linux/home/.config/ags/widget/bar/buttons/SysTray.ts b/linux/home/.config/ags/widget/bar/buttons/SysTray.ts new file mode 100644 index 0000000..9f569d1 --- /dev/null +++ b/linux/home/.config/ags/widget/bar/buttons/SysTray.ts @@ -0,0 +1,39 @@ +import { type TrayItem } from "types/service/systemtray" +import PanelButton from "../PanelButton" +import Gdk from "gi://Gdk" +import options from "options" + +const systemtray = await Service.import("systemtray") +const { ignore } = options.bar.systray + +const SysTrayItem = (item: TrayItem) => PanelButton({ + class_name: "tray-item", + child: Widget.Icon({ icon: item.bind("icon") }), + tooltip_markup: item.bind("tooltip_markup"), + setup: self => { + const { menu } = item + if (!menu) + return + + const id = menu.connect("popped-up", () => { + self.toggleClassName("active") + menu.connect("notify::visible", () => { + self.toggleClassName("active", menu.visible) + }) + menu.disconnect(id!) + }) + + self.connect("destroy", () => menu.disconnect(id)) + }, + + on_primary_click: btn => item.menu?.popup_at_widget( + btn, Gdk.Gravity.SOUTH, Gdk.Gravity.NORTH, null), + + on_secondary_click: btn => item.menu?.popup_at_widget( + btn, Gdk.Gravity.SOUTH, Gdk.Gravity.NORTH, null), +}) + +export default () => Widget.Box() + .bind("children", systemtray, "items", i => i + .filter(({ id }) => !ignore.value.includes(id)) + .map(SysTrayItem)) diff --git a/linux/home/.config/ags/widget/bar/buttons/SystemIndicators.ts b/linux/home/.config/ags/widget/bar/buttons/SystemIndicators.ts new file mode 100644 index 0000000..cc98548 --- /dev/null +++ b/linux/home/.config/ags/widget/bar/buttons/SystemIndicators.ts @@ -0,0 +1,107 @@ +import PanelButton from '../PanelButton'; +import icons from 'lib/icons'; +import asusctl from 'service/asusctl'; + +const notifications = await Service.import('notifications'); +const bluetooth = await Service.import('bluetooth'); +const audio = await Service.import('audio'); +const network = await Service.import('network'); +const powerprof = await Service.import('powerprofiles'); + +const ProfileIndicator = () => { + const visible = asusctl.available ? asusctl.bind('profile').as(p => p !== 'Balanced') : powerprof.bind('active_profile').as(p => p !== 'balanced'); + + const icon = asusctl.available ? asusctl.bind('profile').as(p => icons.asusctl.profile[p]) : powerprof.bind('active_profile').as(p => icons.powerprofile[p]); + + return Widget.Icon({ visible, icon }); +}; + +const ModeIndicator = () => { + if (!asusctl.available) { + return Widget.Icon({ + setup(self) { + Utils.idle(() => (self.visible = false)); + }, + }); + } + + return Widget.Icon({ + visible: asusctl.bind('mode').as(m => m !== 'Hybrid'), + icon: asusctl.bind('mode').as(m => icons.asusctl.mode[m]), + }); +}; + +const MicrophoneIndicator = () => + Widget.Icon() + .hook(audio, self => (self.visible = audio.recorders.length > 0 || audio.microphone.is_muted || false)) + .hook(audio.microphone, self => { + const vol = audio.microphone.is_muted ? 0 : audio.microphone.volume; + const { muted, low, medium, high } = icons.audio.mic; + const cons = [ + [67, high], + [34, medium], + [1, low], + [0, muted], + ] as const; + self.icon = cons.find(([n]) => n <= vol * 100)?.[1] || ''; + }); + +const DNDIndicator = () => + Widget.Icon({ + visible: notifications.bind('dnd'), + icon: icons.notifications.silent, + }); + +const BluetoothIndicator = () => + Widget.Overlay({ + class_name: 'bluetooth', + passThrough: true, + child: Widget.Icon({ + icon: icons.bluetooth.enabled, + visible: bluetooth.bind('enabled'), + }), + overlay: Widget.Label({ + hpack: 'end', + vpack: 'start', + label: bluetooth.bind('connected_devices').as(c => `${c.length}`), + visible: bluetooth.bind('connected_devices').as(c => c.length > 0), + }), + }); + +const NetworkIndicator = () => + Widget.Icon().hook(network, self => { + const icon = network[network.primary || 'wifi']?.icon_name; + self.icon = icon || ''; + self.visible = !!icon; + }); + +const AudioIndicator = () => + Widget.Icon().hook(audio.speaker, self => { + const vol = audio.speaker.is_muted ? 0 : audio.speaker.volume; + const { muted, low, medium, high, overamplified } = icons.audio.volume; + const cons = [ + [101, overamplified], + [67, high], + [34, medium], + [1, low], + [0, muted], + ] as const; + self.icon = cons.find(([n]) => n <= vol * 100)?.[1] || ''; + }); + +export default () => + PanelButton({ + window: 'quicksettings', + on_clicked: () => App.toggleWindow('quicksettings'), + on_scroll_up: () => (audio.speaker.volume += 0.02), + on_scroll_down: () => (audio.speaker.volume -= 0.02), + child: Widget.Box([ + //ProfileIndicator(), + ModeIndicator(), + DNDIndicator(), + BluetoothIndicator(), + MicrophoneIndicator(), + AudioIndicator(), + NetworkIndicator(), + ]), + }); diff --git a/linux/home/.config/ags/widget/bar/buttons/Taskbar.ts b/linux/home/.config/ags/widget/bar/buttons/Taskbar.ts new file mode 100644 index 0000000..b9c65fa --- /dev/null +++ b/linux/home/.config/ags/widget/bar/buttons/Taskbar.ts @@ -0,0 +1,90 @@ +import { launchApp, icon } from "lib/utils" +import icons from "lib/icons" +import options from "options" +import PanelButton from "../PanelButton" + +const hyprland = await Service.import("hyprland") +const apps = await Service.import("applications") +const { monochrome, exclusive, iconSize } = options.bar.taskbar +const { position } = options.bar + +const focus = (address: string) => hyprland.messageAsync( + `dispatch focuswindow address:${address}`) + +const DummyItem = (address: string) => Widget.Box({ + attribute: { address }, + visible: false, +}) + +const AppItem = (address: string) => { + const client = hyprland.getClient(address) + if (!client || client.class === "") + return DummyItem(address) + + const app = apps.list.find(app => app.match(client.class)) + + const btn = PanelButton({ + class_name: "panel-button", + tooltip_text: Utils.watch(client.title, hyprland, () => + hyprland.getClient(address)?.title || "", + ), + on_primary_click: () => focus(address), + on_middle_click: () => app && launchApp(app), + child: Widget.Icon({ + size: iconSize.bind(), + icon: monochrome.bind().as(m => icon( + (app?.icon_name || client.class) + (m ? "-symbolic" : ""), + icons.fallback.executable + (m ? "-symbolic" : ""), + )), + }), + }) + + return Widget.Box( + { + attribute: { address }, + visible: Utils.watch(true, [exclusive, hyprland], () => { + return exclusive.value + ? hyprland.active.workspace.id === client.workspace.id + : true + }), + }, + Widget.Overlay({ + child: btn, + pass_through: true, + overlay: Widget.Box({ + className: "indicator", + hpack: "center", + vpack: position.bind().as(p => p === "top" ? "start" : "end"), + setup: w => w.hook(hyprland, () => { + w.toggleClassName("active", hyprland.active.client.address === address) + }), + }), + }), + ) +} + +function sortItems(arr: T[]) { + return arr.sort(({ attribute: a }, { attribute: b }) => { + const aclient = hyprland.getClient(a.address)! + const bclient = hyprland.getClient(b.address)! + return aclient.workspace.id - bclient.workspace.id + }) +} + +export default () => Widget.Box({ + class_name: "taskbar", + children: sortItems(hyprland.clients.map(c => AppItem(c.address))), + setup: w => w + .hook(hyprland, (w, address?: string) => { + if (typeof address === "string") + w.children = w.children.filter(ch => ch.attribute.address !== address) + }, "client-removed") + .hook(hyprland, (w, address?: string) => { + if (typeof address === "string") + w.children = sortItems([...w.children, AppItem(address)]) + }, "client-added") + .hook(hyprland, (w, event?: string) => { + if (event === "movewindow") + w.children = sortItems(w.children) + }, "event"), +}) diff --git a/linux/home/.config/ags/widget/bar/buttons/Workspaces.ts b/linux/home/.config/ags/widget/bar/buttons/Workspaces.ts new file mode 100644 index 0000000..a59f61b --- /dev/null +++ b/linux/home/.config/ags/widget/bar/buttons/Workspaces.ts @@ -0,0 +1,66 @@ +import PanelButton from '../PanelButton'; +import options from 'options'; +import { sh, range } from 'lib/utils'; + +const hyprland = await Service.import('hyprland'); +const { workspaces } = options.bar.workspaces; + +const dispatch = arg => { + sh(`hyprctl dispatch workspace ${arg}`); +}; + +const Workspaces = ws => + Widget.Box({ + children: range(ws || 20).map(i => + Widget.Label({ + attribute: i, + vpack: 'center', + label: `${i}`, + setup: self => { + const updateState = () => { + const monitorData = JSON.parse(hyprland.message('j/monitors')); + const activeWorkspaceId = monitorData[0]?.activeWorkspace?.id; + const workspaceData = hyprland.getWorkspace(i); + + if (activeWorkspaceId !== undefined) { + self.toggleClassName('active', activeWorkspaceId === i); + } + self.toggleClassName('occupied', (workspaceData?.windows || 0) > 0); + }; + + // Hook to Hyprland for updates + self.hook(hyprland, updateState); + + // Initial update + updateState(); + }, + }), + ), + setup: box => { + box.hook(hyprland, () => { + const monitorData = JSON.parse(hyprland.message('j/monitors')); + const activeWorkspaceId = monitorData[0]?.activeWorkspace?.id; + + if (activeWorkspaceId !== undefined) { + for (const btn of box.children) { + const workspaceId = btn.attribute; + btn.toggleClassName('active', workspaceId === activeWorkspaceId); + + if (ws === 0) { + btn.visible = hyprland.workspaces.some(workspace => workspace.id === workspaceId); + } + } + } + }); + }, + }); + +export default () => + PanelButton({ + window: 'overview', + class_name: 'workspaces', + on_scroll_up: () => dispatch('m+1'), + on_scroll_down: () => dispatch('m-1'), + on_clicked: () => App.toggleWindow('overview'), + child: workspaces.bind().as(Workspaces), + }); diff --git a/linux/home/.config/ags/widget/bar/screencorner.scss b/linux/home/.config/ags/widget/bar/screencorner.scss new file mode 100644 index 0000000..93cd459 --- /dev/null +++ b/linux/home/.config/ags/widget/bar/screencorner.scss @@ -0,0 +1,51 @@ +$_shadow-size: $padding; +$_radius: $radius * $hyprland-gaps-multiplier; +$_margin: 99px; + +window.screen-corner { + box.shadow { + margin-right: $_margin * -1; + margin-left: $_margin * -1; + + @if $shadows { + box-shadow: inset 0 0 $_shadow-size 0 transparent; + } + + @if $bar-position =='top' { + margin-bottom: $_margin * -1; + } + + @if $bar-position =='bottom' { + margin-top: $_margin * -1; + } + } + + box.border { + @if $bar-position =='top' { + border-top: $border-width none $bg; + //border-top: $border-width solid $bg; + } + + @if $bar-position =='bottom' { + border-bottom: $border-width solid $bg; + } + + margin-right: $_margin; + margin-left: $_margin; + } + + box.corner { + box-shadow: 0 0 0 $border-width $border-color; + } + + &.corners { + box.border { + border-radius: if($radius>0, $radius * $hyprland-gaps-multiplier, 0); + box-shadow: 0 0 0 $_radius $bg; + } + + box.corner { + border-radius: if($radius>0, $radius * $hyprland-gaps-multiplier, 0); + } + } +} diff --git a/linux/home/.config/ags/widget/datemenu/DateColumn.ts b/linux/home/.config/ags/widget/datemenu/DateColumn.ts new file mode 100644 index 0000000..a462302 --- /dev/null +++ b/linux/home/.config/ags/widget/datemenu/DateColumn.ts @@ -0,0 +1,58 @@ +import { clock, uptime } from 'lib/variables'; +import GLib from 'gi://GLib'; +import Gtk from 'gi://Gtk'; + +function up(up: number) { + const h = Math.floor(up / 60); + const m = Math.floor(up % 60); + return `uptime: ${h}:${m < 10 ? '0' + m : m}`; +} + +export default () => + Widget.Box({ + vertical: true, + class_name: 'date-column vertical', + children: [ + Widget.Box({ + class_name: 'clock-box', + vertical: true, + children: [ + Widget.Label({ + class_name: 'clock', + label: clock.bind().as(t => t.format('%H:%M')!), + }), + Widget.Label({ + class_name: 'uptime', + label: uptime.bind().as(up), + }), + ], + }), + Widget.Box({ + class_name: 'calendar', + children: [ + (() => { + const calendar = Widget.Calendar({ + hexpand: true, + hpack: 'center', + }); + + // Get today's date and mark it + const today = new Date(); + calendar.select_day(today.getDate()); + calendar.select_month(today.getMonth(), today.getFullYear()); + calendar.mark_day(today.getDate()); // This should trigger styling + + // Prevent scrolling from triggering GNOME Calendar + const eventBox = Widget.EventBox({ + child: calendar, + onPrimaryClick: () => { + GLib.spawn_command_line_async('gnome-calendar'); + }, + }); + + return eventBox; + })(), + ], + }), + ], + }); diff --git a/linux/home/.config/ags/widget/datemenu/DateMenu.ts b/linux/home/.config/ags/widget/datemenu/DateMenu.ts new file mode 100644 index 0000000..f7fdf6d --- /dev/null +++ b/linux/home/.config/ags/widget/datemenu/DateMenu.ts @@ -0,0 +1,36 @@ +import PopupWindow from "widget/PopupWindow" +import NotificationColumn from "./NotificationColumn" +import DateColumn from "./DateColumn" +import options from "options" + +const { bar, datemenu } = options +const pos = bar.position.bind() +const layout = Utils.derive([bar.position, datemenu.position], (bar, qs) => + `${bar}-${qs}` as const, +) + +const Settings = () => Widget.Box({ + class_name: "datemenu horizontal", + vexpand: false, + children: [ + NotificationColumn(), + Widget.Separator({ orientation: 1 }), + DateColumn(), + ], +}) + +const DateMenu = () => PopupWindow({ + name: "datemenu", + exclusivity: "exclusive", + transition: pos.as(pos => pos === "top" ? "slide_down" : "slide_up"), + layout: layout.value, + child: Settings(), +}) + +export function setupDateMenu() { + App.addWindow(DateMenu()) + layout.connect("changed", () => { + App.removeWindow("datemenu") + App.addWindow(DateMenu()) + }) +} diff --git a/linux/home/.config/ags/widget/datemenu/NotificationColumn.ts b/linux/home/.config/ags/widget/datemenu/NotificationColumn.ts new file mode 100644 index 0000000..07d6829 --- /dev/null +++ b/linux/home/.config/ags/widget/datemenu/NotificationColumn.ts @@ -0,0 +1,113 @@ +import { type Notification as Notif } from "types/service/notifications" +import Notification from "widget/notifications/Notification" +import options from "options" +import icons from "lib/icons" + +const notifications = await Service.import("notifications") +const notifs = notifications.bind("notifications") + +const Animated = (n: Notif) => Widget.Revealer({ + transition_duration: options.transition.value, + transition: "slide_down", + child: Notification(n), + setup: self => Utils.timeout(options.transition.value, () => { + if (!self.is_destroyed) + self.reveal_child = true + }), +}) + +const ClearButton = () => Widget.Button({ + on_clicked: notifications.clear, + sensitive: notifs.as(n => n.length > 0), + child: Widget.Box({ + children: [ + Widget.Label("Clear "), + Widget.Icon({ + icon: notifs.as(n => icons.trash[n.length > 0 ? "full" : "empty"]), + }), + ], + }), +}) + +const Header = () => Widget.Box({ + class_name: "header", + children: [ + Widget.Label({ label: "Notifications", hexpand: true, xalign: 0 }), + ClearButton(), + ], +}) + +const NotificationList = () => { + const map: Map> = new Map + const box = Widget.Box({ + vertical: true, + children: notifications.notifications.map(n => { + const w = Animated(n) + map.set(n.id, w) + return w + }), + visible: notifs.as(n => n.length > 0), + }) + + function remove(_: unknown, id: number) { + const n = map.get(id) + if (n) { + n.reveal_child = false + Utils.timeout(options.transition.value, () => { + n.destroy() + map.delete(id) + }) + } + } + + return box + .hook(notifications, remove, "closed") + .hook(notifications, (_, id: number) => { + if (id !== undefined) { + if (map.has(id)) + remove(null, id) + + const n = notifications.getNotification(id)! + + const w = Animated(n) + map.set(id, w) + box.children = [w, ...box.children] + } + }, "notified") +} + +const Placeholder = () => Widget.Box({ + class_name: "placeholder", + vertical: true, + vpack: "center", + hpack: "center", + vexpand: true, + hexpand: true, + visible: notifs.as(n => n.length === 0), + children: [ + Widget.Icon(icons.notifications.silent), + Widget.Label("Your inbox is empty"), + ], +}) + +export default () => Widget.Box({ + class_name: "notifications", + css: options.notifications.width.bind().as(w => `min-width: ${w}px`), + vertical: true, + children: [ + Header(), + Widget.Scrollable({ + vexpand: true, + hscroll: "never", + class_name: "notification-scrollable", + child: Widget.Box({ + class_name: "notification-list vertical", + vertical: true, + children: [ + NotificationList(), + Placeholder(), + ], + }), + }), + ], +}) diff --git a/linux/home/.config/ags/widget/datemenu/datemenu.scss b/linux/home/.config/ags/widget/datemenu/datemenu.scss new file mode 100644 index 0000000..6fd9257 --- /dev/null +++ b/linux/home/.config/ags/widget/datemenu/datemenu.scss @@ -0,0 +1,110 @@ +@import "../notifications/notifications.scss"; + +@mixin calendar { + @include widget; + padding: $padding*2 $padding*2 0; + + calendar { + all: unset; + + &.button { + @include button($flat: true); + } + + &:selected { + box-shadow: inset 0 -8px 0 0 transparentize($primary-bg, 0.5), + inset 0 0 0 1px $primary-bg; + border-radius: $radius*0.6; + } + + &.header { + background-color: transparent; + border: none; + color: transparentize($fg, 0.5); + } + + &.highlight { + background-color: transparent; + color: transparentize($primary-bg, 0.5); + } + + &:indeterminate { + color: transparentize($fg, 0.9); + } + + font-size: 1.1em; + padding: .2em; + } +} + +window#datemenu .datemenu { + @include floating-widget; + + .notifications { + .header { + margin-bottom: $spacing; + margin-right: $spacing; + + >label { + margin-left: $radius * .5; + } + + button { + @include button; + padding: $padding*.7 $padding; + } + } + + .notification-scrollable { + @include scrollable($top: true, $bottom: true); + } + + .notification-list { + margin-right: $spacing; + } + + .notification { + @include notification; + @include widget; + padding: $padding; + margin-bottom: $spacing; + } + + .placeholder { + image { + font-size: 7em; + } + + label { + font-size: 1.2em; + } + } + } + + + separator { + background-color: $popover-border-color; + border-radius: $radius; + margin-right: $spacing; + } + + .datemenu { + @include spacing; + } + + .clock-box { + padding: $padding; + + .clock { + font-size: 5em; + } + + .uptime { + color: transparentize($fg, 0.2); + } + } + + .calendar { + @include calendar; + } +} diff --git a/linux/home/.config/ags/widget/desktop/Desktop.ts b/linux/home/.config/ags/widget/desktop/Desktop.ts new file mode 100644 index 0000000..f711967 --- /dev/null +++ b/linux/home/.config/ags/widget/desktop/Desktop.ts @@ -0,0 +1,40 @@ +import options from "options" +import { matugen } from "lib/matugen" +const mpris = await Service.import("mpris") + +const pref = () => options.bar.media.preferred.value + +export default (monitor: number) => Widget.Window({ + monitor, + layer: "bottom", + name: `desktop${monitor}`, + class_name: "desktop", + anchor: ["top", "bottom", "left", "right"], + child: Widget.Box({ + expand: true, + css: options.theme.dark.primary.bg.bind().as(c => ` + transition: 500ms; + background-color: ${c}`), + child: Widget.Box({ + class_name: "wallpaper", + expand: true, + vpack: "center", + hpack: "center", + setup: self => self + .hook(mpris, () => { + const img = mpris.getPlayer(pref())!.cover_path + matugen("image", img) + Utils.timeout(500, () => self.css = ` + background-image: url('${img}'); + background-size: contain; + background-repeat: no-repeat; + transition: 200ms; + min-width: 700px; + min-height: 700px; + border-radius: 30px; + box-shadow: 25px 25px 30px 0 rgba(0,0,0,0.5);`, + ) + }), + }), + }), +}) diff --git a/linux/home/.config/ags/widget/dock/Dock.ts b/linux/home/.config/ags/widget/dock/Dock.ts new file mode 100644 index 0000000..c55f89f --- /dev/null +++ b/linux/home/.config/ags/widget/dock/Dock.ts @@ -0,0 +1,150 @@ +import { launchApp } from "lib/utils"; +import options from "options"; +import * as Gtk from "gi://Gtk?version=3.0"; +import { type ButtonProps } from "types/widgets/button"; +import { type BoxProps } from "types/widgets/box"; + +const hyprland = await Service.import("hyprland"); +const applications = await Service.import("applications"); + +const focus = (address: string) => hyprland.messageAsync(`dispatch focuswindow address:${address}`); + +const AppButton = ({ icon, pinned = false, term, ...rest }: ButtonProps & { term?: string }): Gtk.Button & ButtonProps => { + const { iconSize } = options.dock; + + const buttonBox = Widget.Box({ + class_name: 'box', + child: Widget.Icon({ + icon, + size: iconSize, + }), + }); + + const button = Widget.Button({ + ...rest, + class_name: '', + child: pinned ? buttonBox : Widget.Overlay({ + child: buttonBox, + pass_through: false, + overlays: [], + }), + }); + + return Object.assign(button, {}); +}; + +const createAppButton = ({ app, term, ...params }) => { + return AppButton({ + icon: app.icon_name || '', + term, + ...params, + }); +}; + +const filterValidClients = (clients: any[]) => { + return clients.filter(client => ( + client.mapped && + [client.class, client.title, client.initialClass].every(prop => typeof prop === 'string' && prop !== '') + )); +}; + +const Taskbar = (): Gtk.Box & BoxProps => { + const addedApps = new Set(); + + const updateTaskbar = (clients: any[]) => { + const validClients = filterValidClients(clients); + + const focusedAddress = hyprland?.active.client?.address; + const running = validClients.filter(client => client.mapped); + const focused = running.find(client => client.address === focusedAddress); + + return validClients.map(client => { + if (![client.class, client.title, client.initialClass].every(prop => typeof prop === 'string' && prop !== '')) { + return null; + } + + if (addedApps.has(client.title)) { + return null; + } + + for (const appName of options.dock.pinnedApps.value) { + if (!appName || typeof appName !== 'string') { + continue; + } + + if (client.class.includes(appName) || client.title.includes(appName) + || client.initialClass.includes(appName)) { + return null; + } + } + + const matchingApp = applications?.list.find(app => ( + app.match(client.title) || app.match(client.class) || app.match(client.initialClass) + )); + + if (matchingApp) { + addedApps.add(client.title); + return createAppButton({ + app: matchingApp, + term: matchingApp.title, + on_primary_click: () => { + const clickAddress = client.address || focusedAddress; + clickAddress && focus(clickAddress); + }, + on_secondary_click: () => launchApp(matchingApp), + }); + a + } + return null; + }); + }; + + return Widget.Box({ + vertical: false, + }) + .bind('children', hyprland, 'clients', updateTaskbar); +}; + +const PinnedApps = (): Gtk.Box & BoxProps => { + const updatePinnedApps = (pinnedApps: string[]) => { + return pinnedApps + .map(term => ({ app: applications?.query(term)?.[0], term })) + .filter(({ app }) => app) + .map(({ app, term = true }) => createAppButton({ + app, + term, + pinned: true, + on_primary_click: () => { + const matchingClients = hyprland?.clients.filter(client => ( + typeof client.class === 'string' && + typeof client.title === 'string' && + typeof client.initialClass === 'string' && + (client.class.includes(term) || client.title.includes(term) || client.initialClass.includes(term)) + )); + + if (matchingClients.length > 0) { + const { address } = matchingClients[0]; + address && focus(address); + } else { + launchApp(app); + } + }, + on_secondary_click: () => launchApp(app), + })); + }; + + return Widget.Box({ + class_name: 'pins', + vertical: false, + homogeneous: true, + }) + .bind('children', options.dock.pinnedApps, 'value', updatePinnedApps); +}; + +const Dock = (): Gtk.Box & BoxProps => Widget.Box({ + class_name: 'dock', + vertical: false, + children: [PinnedApps(), Taskbar()], +}); + +export default Dock; diff --git a/linux/home/.config/ags/widget/dock/FloatingDock.ts b/linux/home/.config/ags/widget/dock/FloatingDock.ts new file mode 100644 index 0000000..369f56f --- /dev/null +++ b/linux/home/.config/ags/widget/dock/FloatingDock.ts @@ -0,0 +1,70 @@ +import options from 'options'; +import Dock from './Dock.ts'; +const hyprland = await Service.import('hyprland'); +const apps = await Service.import('applications'); + +const { Gdk, Gtk } = imports.gi; +import type Gtk from 'gi://Gtk?version=3.0'; +import { type WindowProps } from 'types/widgets/window'; +import { type RevealerProps } from 'types/widgets/revealer'; +import { type EventBoxProps } from 'types/widgets/eventbox'; + +/** @param {number} monitor */ +const FloatingDock = (monitor: number): Gtk.Window & WindowProps => { + const update = () => { + const ws = Hyprland.getWorkspace(Hyprland.active.workspace.id); + if (Hyprland.getMonitor(monitor)?.name === ws?.monitor) self.reveal_child = ws?.windows === 0; + }; + const revealer: Gtk.Revealer & RevealerProps = Widget.Revealer({ + transition: 'slide_up', + transitionDuration: 90, + child: Dock(), + setup: self => self.hook(hyprland, update, 'client-added').hook(hyprland, update, 'client-removed').hook(hyprland.active.workspace, update), + }); + + const window = Widget.Window({ + monitor, + //halign: 'fill', + halign: 'end', + //layer: "overlay", + layer: 'dock', + name: `dock${monitor}`, + click_through: false, + class_name: 'floating-dock', + // class_name: 'floating-dock-no-gap', + // class_name: "f-dock-wrap", + + typeHint: Gdk.WindowTypeHint.DOCK, + exclusivity: 'false', + + anchor: ['bottom'], + child: Widget.Box({ + vertical: false, + halign: 'bottom', + hpack: 'start', + children: [ + revealer, + Widget.Box({ + class_name: 'padding', + css: 'padding: 9px; margin: 0;', + vertical: false, + halign: 'bottom', + hpack: 'start', + }), + ], + }), + }); + + window + .on('enter-notify-event', () => { + revealer.reveal_child = true; + }) + .on('leave-notify-event', () => { + revealer.reveal_child = false; + }) + .bind('visible', options.bar.position, 'value', v => v !== 'left'); + + return window; +}; + +export default FloatingDock; diff --git a/linux/home/.config/ags/widget/dock/ToolBox.ts b/linux/home/.config/ags/widget/dock/ToolBox.ts new file mode 100644 index 0000000..51fda72 --- /dev/null +++ b/linux/home/.config/ags/widget/dock/ToolBox.ts @@ -0,0 +1,122 @@ +import options from "options"; +import { sh } from "lib/utils"; +import * as Gtk from "gi://Gtk?version=3.0"; +import { type ButtonProps } from "types/widgets/button"; +import { type BoxProps } from "types/widgets/box"; + +const hyprland = await Service.import("hyprland"); +const { icons } = options.dock.toolbox; +const buttonToggles = {}; + +const dispatch = (action: string, arg: string) => { + //console.log(`Performing action: ${action} with argument: ${arg}`); + sh(`hyprctl dispatch ${action} ${arg}`); +}; + +const keyword = (action: string, arg: string) => { + //console.log(`Performing action: ${action} with argument: ${arg}`); + sh(`hyprctl keyword ${action} ${arg}`); +}; + +const ToggleSwitch = (buttonIndex, actionOn, argOn, actionOff, argOff, actionExec) => { + buttonToggles[buttonIndex] = !buttonToggles[buttonIndex]; + const { action, arg } = buttonToggles[buttonIndex] ? { action: actionOn, arg: argOn } : { action: actionOff, arg: argOff }; + actionExec(action, arg); +}; + +const ToggleOnMulti = (buttonIndex, actionOn, argOn, actionOff, argOff, actionExec) => { + buttonToggles[buttonIndex] = !buttonToggles[buttonIndex]; + if (buttonToggles[buttonIndex]) { + actionOn.forEach(({ action, arg }) => { + actionExec(action, arg); + }); + } else { + actionExec(actionOff, argOff); + } +}; + +const execAction = (trigger, actionIndex, actionOn, argOn, actionOff, argOff, action, arg, actionExec) => { + switch (trigger) { + case 'toggleOn-multi': + ToggleOnMulti(actionIndex, actionOn, argOn, actionOff, argOff, actionExec); + break; + case 'toggle-switch': + ToggleSwitch(actionIndex, actionOn, argOn, actionOff, argOff, actionExec); + break; + case 'oneshot': + actionExec(action, arg); + break; + default: + break; + } +}; + +const buttonConfigs = [ + { actionExec: dispatch, trigger: 'oneshot', actionIndex: 0, action: 'killactive', arg: '' }, + { actionExec: dispatch, trigger: 'oneshot', actionIndex: 1, action: 'exec hyprctl', arg: 'kill' }, + { + actionExec: keyword, + trigger: 'toggle-switch', + actionIndex: 2, + actionOn: 'monitor', argOn: 'eDP-1,2736x1824,0x0,0,transform,1', + actionOff: 'monitor', argOff: 'eDP-1,2736x1824,0x0,0,transform,0' + }, + { actionExec: dispatch, trigger: 'oneshot', actionIndex: 3, action: 'workspace', arg: 'r-1' }, + { actionExec: dispatch, trigger: 'oneshot', actionIndex: 4, action: 'workspace', arg: 'r+1' }, + { actionExec: dispatch, trigger: 'oneshot', actionIndex: 5, action: 'movewindow', arg: 'l' }, + { actionExec: dispatch, trigger: 'oneshot', actionIndex: 6, action: 'movewindow', arg: 'r' }, + { actionExec: dispatch, trigger: 'oneshot', actionIndex: 7, action: 'movewindow', arg: 'u' }, + { actionExec: dispatch, trigger: 'oneshot', actionIndex: 8, action: 'movewindow', arg: 'd' }, + { actionExec: dispatch, trigger: 'oneshot', actionIndex: 9, action: 'swapnext', arg: 'next' }, + { actionExec: dispatch, trigger: 'oneshot', actionIndex: 10, action: 'togglesplit', arg: '' }, + { + actionExec: dispatch, + trigger: 'toggleOn-multi', + actionIndex: 11, + actionOn: [ + { action: 'setfloating', arg: 'active' }, + { action: 'resizeactive', arg: 'exact 90% 90%' }, + { action: 'centerwindow', arg: '' }, + ], + actionOff: 'settiled', argOff: 'active' + }, + { actionExec: dispatch, trigger: 'oneshot', actionIndex: 12, action: 'pin', arg: '' }, + { actionExec: dispatch, trigger: 'oneshot', actionIndex: 13, action: 'fullscreen', arg: '0' }, + { + actionExec: dispatch, + trigger: 'toggle-switch', + actionIndex: 14, + actionOn: 'exec', argOn: 'wvctl 1', + actionOff: 'exec', argOff: 'wvctl 0' + }, +]; + +const ToolBox = () => { + const ToolBoxButtons = () => { + const buttons = buttonConfigs.map(({ actionIndex, actionOn, argOn, actionOff, argOff, actionExec, trigger, action, arg }) => { + const execActionWrapper = () => execAction(trigger, actionIndex, actionOn, argOn, actionOff, argOff, action, arg, actionExec); + + return Widget.Button({ + child: Widget.Icon({ + icon: icons[actionIndex].bind(), + }), + on_clicked: execActionWrapper, + }); + }); + + return Widget.Box({ + vertical: true, + homogeneous: true, + children: buttons, + }); + }; + + return Widget.Box({ + class_name: "toolbox", + vertical: true, + homogeneous: true, + children: [ToolBoxButtons()], + }); +}; + +export default ToolBox; diff --git a/linux/home/.config/ags/widget/dock/ToolBoxDock.ts b/linux/home/.config/ags/widget/dock/ToolBoxDock.ts new file mode 100644 index 0000000..21beaeb --- /dev/null +++ b/linux/home/.config/ags/widget/dock/ToolBoxDock.ts @@ -0,0 +1,57 @@ +import options from "options"; +import ToolBox from "./ToolBox.ts"; +const hyprland = await Service.import("hyprland"); +const apps = await Service.import("applications"); + +import type Gtk from "gi://Gtk?version=3.0"; +import { type WindowProps } from "types/widgets/window"; +import { type RevealerProps } from "types/widgets/revealer"; +import { type EventBoxProps } from "types/widgets/eventbox"; + +/** @param {number} monitor */ +const ToolBoxDock = (monitor: number): Gtk.Window & WindowProps => { + + const revealer: Gtk.Revealer & RevealerProps = Widget.Revealer({ + transition: 'slide_left', + transitionDuration: 50, + child: ToolBox(), + }); + + const window = Widget.Window({ + monitor, + halign: 'fill', + layer: "overlay", + name: `toolbox${monitor}`, + click_through: false, + class_name: 'floating-toolbox', + anchor: ['right'], + child: Widget.Box({ + vertical: true, + halign: 'top', + hpack: 'fill', + children: [ + revealer, + Widget.Box({ + class_name: 'padding', + css: 'padding: 14px;', + vertical: true, + halign: 'top', + hpack: 'fill', + }), + ], + }), + }); + + window + .on('enter-notify-event', () => { + revealer.reveal_child = true; + }) + .on('leave-notify-event', () => { + revealer.reveal_child = false; + }) + .bind('visible', options.bar.position, 'value', v => v !== 'left'); + + return window; +}; + +export default ToolBoxDock; diff --git a/linux/home/.config/ags/widget/dock/dock.scss b/linux/home/.config/ags/widget/dock/dock.scss new file mode 100644 index 0000000..9dc6256 --- /dev/null +++ b/linux/home/.config/ags/widget/dock/dock.scss @@ -0,0 +1,73 @@ +@use 'sass:color'; + +.floating-dock { + padding-left: 0.2rem; + padding-right: 0.2rem; + padding-top: 0.3rem; + padding-bottom: 0.3rem; + border-radius: 1rem; +} + +.dock { + // @include floating-widget; + border-radius: $radius; + background-color: transparentize($bg, 0.07); + min-width: 0; + padding: 6; + + // Common styles for both PinnedApps and Taskbar buttons + button { + @include button($flat: true); + border-radius: 4; + padding: 2; + + .box { + margin: 0em; + min-width: 1em; + min-height: 0em; + padding: 0; + } + + image { + margin: 0px; + } + + .indicator { + background-color: transparentize($primary-bg, 0.3); + border-radius: $radius; + min-height: 1pt; + min-width: 16pt; + margin: 1pt; + } + } +} + +.toolbox { + // @include floating-widget; + border-radius: $radius; + background-color: transparentize($bg, 0.07); + min-width: 0; + padding: 6; + + // Common styles for both PinnedApps and Taskbar buttons + button { + @include button($flat: true); + border-radius: 0; + padding: 0; + + image { + margin: 0px; + font-size: 32px; + } + + &:hover, + &:active, + &:focus { + // Override hover, active, and focus styles for buttons in .toolbox + background-color: transparent; + border: none; + box-shadow: none; + outline: none; + } + } +} diff --git a/linux/home/.config/ags/widget/launcher/AppLauncher.ts b/linux/home/.config/ags/widget/launcher/AppLauncher.ts new file mode 100644 index 0000000..08258de --- /dev/null +++ b/linux/home/.config/ags/widget/launcher/AppLauncher.ts @@ -0,0 +1,125 @@ +import { type Application } from 'types/service/applications'; +import { launchApp, icon } from 'lib/utils'; +import options from 'options'; +import icons from 'lib/icons'; + +const apps = await Service.import('applications'); +const { query } = apps; +const { iconSize } = options.launcher.apps; + +const QuickAppButton = (app: Application) => + Widget.Button({ + hexpand: true, + tooltip_text: app.name, + on_clicked: () => { + App.closeWindow('launcher'); + launchApp(app); + }, + child: Widget.Icon({ + size: iconSize.bind(), + icon: icon(app.icon_name, icons.fallback.executable), + }), + }); + +const AppItem = (app: Application) => { + const title = Widget.Label({ + class_name: 'title', + label: app.name, + hexpand: true, + xalign: 0, + vpack: 'center', + truncate: 'end', + }); + + const description = Widget.Label({ + class_name: 'description', + label: app.description || '', + hexpand: true, + wrap: true, + max_width_chars: 30, + xalign: 0, + justification: 'left', + vpack: 'center', + }); + + const appicon = Widget.Icon({ + icon: icon(app.icon_name, icons.fallback.executable), + size: iconSize.bind(), + }); + + const textBox = Widget.Box({ + vertical: true, + vpack: 'center', + children: app.description ? [title, description] : [title], + }); + + return Widget.Button({ + class_name: 'app-item', + attribute: { app }, + child: Widget.Box({ + children: [appicon, textBox], + }), + on_clicked: () => { + App.closeWindow('launcher'); + launchApp(app); + }, + }); +}; +export function Favorites() { + const favs = options.launcher.apps.favorites.bind(); + return Widget.Revealer({ + visible: favs.as(f => f.length > 0), + child: Widget.Box({ + vertical: true, + children: favs.as(favs => + favs.flatMap(fs => [ + Widget.Separator(), + Widget.Box({ + class_name: 'quicklaunch horizontal', + children: fs + .map(f => query(f)?.[0]) + .filter(f => f) + .map(QuickAppButton), + }), + ]), + ), + }), + }); +} + +export function Launcher() { + const applist = Variable(query('')); + const max = options.launcher.apps.max; + let first = applist.value[0]; + + function SeparatedAppItem(app: Application) { + return Widget.Revealer({ attribute: { app } }, Widget.Box({ vertical: true }, Widget.Separator(), AppItem(app))); + } + + const list = Widget.Box({ + vertical: true, + children: applist.bind().as(list => list.map(SeparatedAppItem)), + setup: self => self.hook(apps, () => (applist.value = query('')), 'notify::frequents'), + }); + + return Object.assign(list, { + filter(text: string | null) { + first = query(text || '')[0]; + list.children.reduce((i, item) => { + if (!text || i >= max.value) { + item.reveal_child = false; + return i; + } + if (item.attribute.app.match(text)) { + item.reveal_child = true; + return ++i; + } + item.reveal_child = false; + return i; + }, 0); + }, + launchFirst() { + launchApp(first); + }, + }); +} diff --git a/linux/home/.config/ags/widget/launcher/Launcher.ts b/linux/home/.config/ags/widget/launcher/Launcher.ts new file mode 100644 index 0000000..90b4d58 --- /dev/null +++ b/linux/home/.config/ags/widget/launcher/Launcher.ts @@ -0,0 +1,134 @@ +import { type Binding } from 'lib/utils'; +import PopupWindow, { Padding } from 'widget/PopupWindow'; +import icons from 'lib/icons'; +import options from 'options'; +import nix from 'service/nix'; +import * as AppLauncher from './AppLauncher'; +import * as NixRun from './NixRun'; +import * as ShRun from './ShRun'; + +const { width, margin } = options.launcher; +const isnix = nix.available; + +function Launcher() { + const favs = AppLauncher.Favorites(); + const applauncher = AppLauncher.Launcher(); + const sh = ShRun.ShRun(); + const shicon = ShRun.Icon(); + const nix = NixRun.NixRun(); + const nixload = NixRun.Spinner(); + + function HelpButton(cmd: string, desc: string | Binding) { + return Widget.Box( + { vertical: true }, + Widget.Separator(), + Widget.Button( + { + class_name: 'help', + on_clicked: () => { + entry.grab_focus(); + entry.text = `:${cmd} `; + entry.set_position(-1); + }, + }, + Widget.Box([ + Widget.Label({ + class_name: 'name', + label: `:${cmd}`, + }), + Widget.Label({ + hexpand: true, + hpack: 'end', + class_name: 'description', + label: desc, + }), + ]), + ), + ); + } + + const help = Widget.Revealer({ + child: Widget.Box( + { vertical: true }, + HelpButton('sh', 'run a binary'), + isnix + ? HelpButton( + 'nx', + options.launcher.nix.pkgs.bind().as(pkg => `run a nix package from ${pkg}`), + ) + : Widget.Box(), + ), + }); + + const entry = Widget.Entry({ + hexpand: true, + primary_icon_name: icons.ui.search, + on_accept: ({ text }) => { + if (text?.startsWith(':nx')) nix.run(text.substring(3)); + else if (text?.startsWith(':sh')) sh.run(text.substring(3)); + else applauncher.launchFirst(); + + App.toggleWindow('launcher'); + entry.text = ''; + }, + on_change: ({ text }) => { + text ||= ''; + favs.reveal_child = text === ''; + help.reveal_child = text.split(' ').length === 1 && text?.startsWith(':'); + + if (text?.startsWith(':nx')) nix.filter(text.substring(3)); + else nix.filter(''); + + if (text?.startsWith(':sh')) sh.filter(text.substring(3)); + else sh.filter(''); + + if (!text?.startsWith(':')) applauncher.filter(text); + }, + }); + + function focus() { + entry.text = ''; + entry.set_position(-1); + entry.select_region(0, -1); + entry.grab_focus(); + favs.reveal_child = true; + } + + const layout = Widget.Box({ + css: width.bind().as(v => `min-width: ${v}pt;`), + class_name: 'launcher', + vertical: true, + vpack: 'start', + setup: self => + self.hook(App, (_, win, visible) => { + if (win !== 'launcher') return; + + entry.text = ''; + if (visible) focus(); + }), + children: [ + Widget.Box([entry, nixload, shicon]), + favs, + help, + applauncher, + //nix, + sh, + ], + }); + + return Widget.Box( + { vertical: true, css: 'padding: 1px' }, + Padding('applauncher', { + css: margin.bind().as(v => `min-height: ${v}pt;`), + vexpand: false, + }), + layout, + ); +} + +export default () => + PopupWindow({ + name: 'launcher', + layout: 'top', + child: Launcher(), + }); diff --git a/linux/home/.config/ags/widget/launcher/NixRun.ts b/linux/home/.config/ags/widget/launcher/NixRun.ts new file mode 100644 index 0000000..cec9e09 --- /dev/null +++ b/linux/home/.config/ags/widget/launcher/NixRun.ts @@ -0,0 +1,118 @@ +import icons from "lib/icons" +import nix, { type Nixpkg } from "service/nix" + +const iconVisible = Variable(false) + +function Item(pkg: Nixpkg) { + const name = Widget.Label({ + class_name: "name", + label: pkg.name.split(".").at(-1), + }) + + const subpkg = pkg.name.includes(".") ? Widget.Label({ + class_name: "description", + hpack: "end", + hexpand: true, + label: ` ${pkg.name.split(".").slice(0, -1).join(".")}`, + }) : null + + const version = Widget.Label({ + class_name: "version", + label: pkg.version, + hexpand: true, + hpack: "end", + }) + + const description = pkg.description ? Widget.Label({ + class_name: "description", + label: pkg.description, + justification: "left", + wrap: true, + hpack: "start", + max_width_chars: 40, + }) : null + + return Widget.Box( + { + attribute: { name: pkg.name }, + vertical: true, + }, + Widget.Separator(), + Widget.Button( + { + class_name: "nix-item", + on_clicked: () => { + nix.run(pkg.name) + App.closeWindow("launcher") + }, + }, + Widget.Box( + { vertical: true }, + Widget.Box([name, version]), + Widget.Box([ + description as ReturnType, + subpkg as ReturnType, + ]), + ), + ), + ) +} + +export function Spinner() { + const icon = Widget.Icon({ + icon: icons.nix.nix, + class_name: "spinner", + css: ` + @keyframes spin { + to { -gtk-icon-transform: rotate(1turn); } + } + + image.spinning { + animation-name: spin; + animation-duration: 1s; + animation-timing-function: linear; + animation-iteration-count: infinite; + } + `, + setup: self => self.hook(nix, () => { + self.toggleClassName("spinning", !nix.ready) + }), + }) + + return Widget.Revealer({ + transition: "slide_left", + child: icon, + reveal_child: Utils.merge([ + nix.bind("ready"), + iconVisible.bind(), + ], (ready, show) => !ready || show), + }) +} + +export function NixRun() { + const list = Widget.Box>({ + vertical: true, + }) + + const revealer = Widget.Revealer({ + child: list, + }) + + async function filter(term: string) { + iconVisible.value = Boolean(term) + + if (!term) + revealer.reveal_child = false + + if (term.trim()) { + const found = await nix.query(term) + list.children = found.map(k => Item(nix.db[k])) + revealer.reveal_child = true + } + } + + return Object.assign(revealer, { + filter, + run: nix.run, + }) +} diff --git a/linux/home/.config/ags/widget/launcher/ShRun.ts b/linux/home/.config/ags/widget/launcher/ShRun.ts new file mode 100644 index 0000000..c4215ef --- /dev/null +++ b/linux/home/.config/ags/widget/launcher/ShRun.ts @@ -0,0 +1,89 @@ +import icons from "lib/icons" +import options from "options" +import { bash, dependencies } from "lib/utils" + +const iconVisible = Variable(false) + +const MAX = options.launcher.sh.max +const BINS = `${Utils.CACHE_DIR}/binaries` +bash("{ IFS=:; ls -H $PATH; } | sort ") + .then(bins => Utils.writeFile(bins, BINS)) + +async function query(filter: string) { + if (!dependencies("fzf")) + return [] as string[] + + return bash(`cat ${BINS} | fzf -f ${filter} | head -n ${MAX}`) + .then(str => Array.from(new Set(str.split("\n").filter(i => i)).values())) + .catch(err => { print(err); return [] }) +} + +function run(args: string) { + Utils.execAsync(args) + .then(out => { + print(`:sh ${args.trim()}:`) + print(out) + }) + .catch(err => { + Utils.notify("ShRun Error", err, icons.app.terminal) + }) +} + +function Item(bin: string) { + return Widget.Box( + { + attribute: { bin }, + vertical: true, + }, + Widget.Separator(), + Widget.Button({ + child: Widget.Label({ + label: bin, + hpack: "start", + }), + class_name: "sh-item", + on_clicked: () => { + Utils.execAsync(bin) + App.closeWindow("launcher") + }, + }), + ) +} + +export function Icon() { + const icon = Widget.Icon({ + icon: icons.app.terminal, + class_name: "spinner", + }) + + return Widget.Revealer({ + transition: "slide_left", + child: icon, + reveal_child: iconVisible.bind(), + }) +} + +export function ShRun() { + const list = Widget.Box>({ + vertical: true, + }) + + const revealer = Widget.Revealer({ + child: list, + }) + + async function filter(term: string) { + iconVisible.value = Boolean(term) + + if (!term) + revealer.reveal_child = false + + if (term.trim()) { + const found = await query(term) + list.children = found.map(Item) + revealer.reveal_child = true + } + } + + return Object.assign(revealer, { filter, run }) +} diff --git a/linux/home/.config/ags/widget/launcher/launcher.scss b/linux/home/.config/ags/widget/launcher/launcher.scss new file mode 100644 index 0000000..926abc3 --- /dev/null +++ b/linux/home/.config/ags/widget/launcher/launcher.scss @@ -0,0 +1,143 @@ +@use "sass:math"; +@use "sass:color"; + +window#launcher .launcher { + @include floating_widget; + + .quicklaunch { + @include spacing; + + button { + @include button($flat: true); + padding: $padding; + } + } + + entry { + @include button; + padding: $padding; + margin: $spacing; + + selection { + color: color.mix($fg, $bg, 50%); + background-color: transparent; + } + + label, + image { + color: $fg; + } + } + + image.spinner { + color: $primary-bg; + margin-right: $spacing; + } + + separator { + margin: 4pt 0; + background-color: $popover-border-color; + } + + button.app-item { + @include button($flat: true, $reactive: false); + + >box { + @include spacing(0.5); + } + + transition: $transition; + padding: $padding; + + label { + transition: $transition; + + &.title { + color: $fg; + } + + &.description { + color: transparentize($fg, 0.3); + } + } + + image { + transition: $transition; + } + + &:hover, + &:focus { + .title { + color: $primary-bg; + } + + .description { + color: transparentize($primary-bg, .4); + } + + image { + -gtk-icon-shadow: 2px 2px $primary-bg; + } + } + + &:active { + background-color: transparentize($primary-bg, 0.5); + border-radius: $radius; + box-shadow: inset 0 0 0 $border-width $border-color; + + .title { + color: $fg; + } + } + } + + button.help, + button.nix-item { + @include button($flat: true, $reactive: false); + padding: 0 ($padding * .5); + + label { + transition: $transition; + color: $fg; + } + + .name { + font-size: 1.2em; + font-weight: bold; + } + + .description { + color: transparentize($fg, .3) + } + + &:hover, + &:focus { + label { + text-shadow: $text-shadow; + } + + .name, + .version { + color: $primary-bg; + } + + .description { + color: transparentize($primary-bg, .3) + } + } + } + + button.sh-item { + @include button($flat: true, $reactive: false); + padding: 0 ($padding * .5); + + transition: $transition; + color: $fg; + + &:hover, + &:focus { + color: $primary-bg; + text-shadow: $text-shadow; + } + } +} diff --git a/linux/home/.config/ags/widget/notifications/Notification.ts b/linux/home/.config/ags/widget/notifications/Notification.ts new file mode 100644 index 0000000..c1c8dd8 --- /dev/null +++ b/linux/home/.config/ags/widget/notifications/Notification.ts @@ -0,0 +1,138 @@ +import { type Notification } from "types/service/notifications" +import GLib from "gi://GLib" +import icons from "lib/icons" + +const time = (time: number, format = "%H:%M") => GLib.DateTime + .new_from_unix_local(time) + .format(format) + +const NotificationIcon = ({ app_entry, app_icon, image }: Notification) => { + if (image) { + return Widget.Box({ + vpack: "start", + hexpand: false, + class_name: "icon img", + css: ` + background-image: url("${image}"); + background-size: cover; + background-repeat: no-repeat; + background-position: center; + min-width: 78px; + min-height: 78px; + `, + }) + } + + let icon = icons.fallback.notification + if (Utils.lookUpIcon(app_icon)) + icon = app_icon + + if (Utils.lookUpIcon(app_entry || "")) + icon = app_entry || "" + + return Widget.Box({ + vpack: "start", + hexpand: false, + class_name: "icon", + css: ` + min-width: 78px; + min-height: 78px; + `, + child: Widget.Icon({ + icon, + size: 58, + hpack: "center", hexpand: true, + vpack: "center", vexpand: true, + }), + }) +} + +export default (notification: Notification) => { + const content = Widget.Box({ + class_name: "content", + children: [ + NotificationIcon(notification), + Widget.Box({ + hexpand: true, + vertical: true, + children: [ + Widget.Box({ + children: [ + Widget.Label({ + class_name: "title", + xalign: 0, + justification: "left", + hexpand: true, + max_width_chars: 24, + truncate: "end", + wrap: true, + label: notification.summary.trim(), + use_markup: true, + }), + Widget.Label({ + class_name: "time", + vpack: "start", + label: time(notification.time), + }), + Widget.Button({ + class_name: "close-button", + vpack: "start", + child: Widget.Icon("window-close-symbolic"), + on_clicked: notification.close, + }), + ], + }), + Widget.Label({ + class_name: "description", + hexpand: true, + use_markup: true, + xalign: 0, + justification: "left", + label: notification.body.trim(), + max_width_chars: 24, + wrap: true, + }), + ], + }), + ], + }) + + const actionsbox = notification.actions.length > 0 ? Widget.Revealer({ + transition: "slide_down", + child: Widget.EventBox({ + child: Widget.Box({ + class_name: "actions horizontal", + children: notification.actions.map(action => Widget.Button({ + class_name: "action-button", + on_clicked: () => notification.invoke(action.id), + hexpand: true, + child: Widget.Label(action.label), + })), + }), + }), + }) : null + + const eventbox = Widget.EventBox({ + vexpand: false, + on_primary_click: notification.dismiss, + on_hover() { + if (actionsbox) + actionsbox.reveal_child = true + }, + on_hover_lost() { + if (actionsbox) + actionsbox.reveal_child = true + + notification.dismiss() + }, + child: Widget.Box({ + vertical: true, + children: actionsbox ? [content, actionsbox] : [content], + }), + }) + + return Widget.Box({ + class_name: `notification ${notification.urgency}`, + child: eventbox, + }) +} diff --git a/linux/home/.config/ags/widget/notifications/NotificationPopups.ts b/linux/home/.config/ags/widget/notifications/NotificationPopups.ts new file mode 100644 index 0000000..a4a2b54 --- /dev/null +++ b/linux/home/.config/ags/widget/notifications/NotificationPopups.ts @@ -0,0 +1,90 @@ +import Notification from "./Notification" +import options from "options" + +const notifications = await Service.import("notifications") +const { transition } = options +const { position } = options.notifications +const { timeout, idle } = Utils + +function Animated(id: number) { + const n = notifications.getNotification(id)! + const widget = Notification(n) + + const inner = Widget.Revealer({ + transition: "slide_left", + transition_duration: transition.value, + child: widget, + }) + + const outer = Widget.Revealer({ + transition: "slide_down", + transition_duration: transition.value, + child: inner, + }) + + const box = Widget.Box({ + hpack: "end", + child: outer, + }) + + idle(() => { + outer.reveal_child = true + timeout(transition.value, () => { + inner.reveal_child = true + }) + }) + + return Object.assign(box, { + dismiss() { + inner.reveal_child = false + timeout(transition.value, () => { + outer.reveal_child = false + timeout(transition.value, () => { + box.destroy() + }) + }) + }, + }) +} + +function PopupList() { + const map: Map> = new Map + const box = Widget.Box({ + hpack: "end", + vertical: true, + css: options.notifications.width.bind().as(w => `min-width: ${w}px;`), + }) + + function remove(_: unknown, id: number) { + map.get(id)?.dismiss() + map.delete(id) + } + + return box + .hook(notifications, (_, id: number) => { + if (id !== undefined) { + if (map.has(id)) + remove(null, id) + + if (notifications.dnd) + return + + const w = Animated(id) + map.set(id, w) + box.children = [w, ...box.children] + } + }, "notified") + .hook(notifications, remove, "dismissed") + .hook(notifications, remove, "closed") +} + +export default (monitor: number) => Widget.Window({ + monitor, + name: `notifications${monitor}`, + anchor: position.bind(), + class_name: "notifications", + child: Widget.Box({ + css: "padding: 2px;", + child: PopupList(), + }), +}) diff --git a/linux/home/.config/ags/widget/notifications/notifications.scss b/linux/home/.config/ags/widget/notifications/notifications.scss new file mode 100644 index 0000000..369932f --- /dev/null +++ b/linux/home/.config/ags/widget/notifications/notifications.scss @@ -0,0 +1,79 @@ +@mixin notification() { + &.critical { + box-shadow: inset 0 0 0.5em 0 $error-bg; + } + + &:hover button.close-button { + @include button-hover; + background-color: transparentize($error-bg, 0.5); + } + + .content { + .title { + margin-right: $spacing; + color: $fg; + font-size: 1.1em; + } + + .time { + color: transparentize($fg, 0.2); + } + + .description { + font-size: 0.9em; + color: transparentize($fg, 0.2); + } + + .icon { + border-radius: $radius * 0.8; + margin-right: $spacing; + + &.img { + border: $border; + } + } + } + + box.actions { + @include spacing(0.5); + margin-top: $spacing; + + button { + @include button; + border-radius: $radius * 0.8; + font-size: 1.2em; + padding: $padding * 0.7; + } + } + + button.close-button { + @include button($flat: true); + margin-left: $spacing / 2; + border-radius: $radius * 0.8; + min-width: 1.2em; + min-height: 1.2em; + + &:hover { + background-color: transparentize($error-bg, 0.2); + } + + &:active { + background-image: none; + background-color: $error-bg; + } + } +} + +window.notifications { + @include unset; + + .notification { + @include notification; + @include floating-widget; + border-radius: $radius; + + .description { + min-width: 200px; + } + } +} diff --git a/linux/home/.config/ags/widget/osd/OSD.ts b/linux/home/.config/ags/widget/osd/OSD.ts new file mode 100644 index 0000000..8239a08 --- /dev/null +++ b/linux/home/.config/ags/widget/osd/OSD.ts @@ -0,0 +1,111 @@ +import { icon } from "lib/utils" +import icons from "lib/icons" +import Progress from "./Progress" +import brightness from "service/brightness" +import options from "options" + +const audio = await Service.import("audio") +const { progress, microphone } = options.osd + +const DELAY = 2500 + +function OnScreenProgress(vertical: boolean) { + const indicator = Widget.Icon({ + size: 42, + vpack: "start", + }) + const progress = Progress({ + vertical, + width: vertical ? 42 : 300, + height: vertical ? 300 : 42, + child: indicator, + }) + + const revealer = Widget.Revealer({ + transition: "slide_left", + child: progress, + }) + + let count = 0 + function show(value: number, icon: string) { + revealer.reveal_child = true + indicator.icon = icon + progress.setValue(value) + count++ + Utils.timeout(DELAY, () => { + count-- + + if (count === 0) + revealer.reveal_child = false + }) + } + + return revealer + .hook(brightness, () => show( + brightness.screen, + icons.brightness.screen, + ), "notify::screen") + .hook(brightness, () => show( + brightness.kbd, + icons.brightness.keyboard, + ), "notify::kbd") + .hook(audio.speaker, () => show( + audio.speaker.volume, + icon(audio.speaker.icon_name || "", icons.audio.type.speaker), + ), "notify::volume") +} + +function MicrophoneMute() { + const icon = Widget.Icon({ + class_name: "microphone", + }) + + const revealer = Widget.Revealer({ + transition: "slide_up", + child: icon, + }) + + let count = 0 + let mute = audio.microphone.stream?.is_muted ?? false + + return revealer.hook(audio.microphone, () => Utils.idle(() => { + if (mute !== audio.microphone.stream?.is_muted) { + mute = audio.microphone.stream!.is_muted + icon.icon = icons.audio.mic[mute ? "muted" : "high"] + revealer.reveal_child = true + count++ + + Utils.timeout(DELAY, () => { + count-- + if (count === 0) + revealer.reveal_child = false + }) + } + })) +} + +export default (monitor: number) => Widget.Window({ + monitor, + name: `indicator${monitor}`, + class_name: "indicator", + layer: "overlay", + click_through: true, + anchor: ["right", "left", "top", "bottom"], + child: Widget.Box({ + css: "padding: 2px;", + expand: true, + child: Widget.Overlay( + { child: Widget.Box({ expand: true }) }, + Widget.Box({ + hpack: progress.pack.h.bind(), + vpack: progress.pack.v.bind(), + child: progress.vertical.bind().as(OnScreenProgress), + }), + Widget.Box({ + hpack: microphone.pack.h.bind(), + vpack: microphone.pack.v.bind(), + child: MicrophoneMute(), + }), + ), + }), +}) diff --git a/linux/home/.config/ags/widget/osd/Progress.ts b/linux/home/.config/ags/widget/osd/Progress.ts new file mode 100644 index 0000000..bcf27da --- /dev/null +++ b/linux/home/.config/ags/widget/osd/Progress.ts @@ -0,0 +1,74 @@ +import type Gtk from "gi://Gtk?version=3.0" +import GLib from "gi://GLib?version=2.0" +import { range } from "lib/utils" +import options from "options" + +type ProgressProps = { + height?: number + width?: number + vertical?: boolean + child: Gtk.Widget +} + +export default ({ + height = 18, + width = 180, + vertical = false, + child, +}: ProgressProps) => { + const fill = Widget.Box({ + class_name: "fill", + hexpand: vertical, + vexpand: !vertical, + hpack: vertical ? "fill" : "start", + vpack: vertical ? "end" : "fill", + child, + }) + + const container = Widget.Box({ + class_name: "progress", + child: fill, + css: ` + min-width: ${width}px; + min-height: ${height}px; + `, + }) + + let fill_size = 0 + let animations: number[] = [] + + return Object.assign(container, { + setValue(value: number) { + if (value < 0) + return + + if (animations.length > 0) { + for (const id of animations) + GLib.source_remove(id) + + animations = [] + } + + const axis = vertical ? "height" : "width" + const axisv = vertical ? height : width + const min = vertical ? width : height + const preferred = (axisv - min) * value + min + + if (!fill_size) { + fill_size = preferred + fill.css = `min-${axis}: ${preferred}px;` + return + } + + const frames = options.transition.value / 10 + const goal = preferred - fill_size + const step = goal / frames + + animations = range(frames, 0).map(i => Utils.timeout(5 * i, () => { + fill_size += step + fill.css = `min-${axis}: ${fill_size}px` + animations.shift() + })) + }, + }) +} diff --git a/linux/home/.config/ags/widget/osd/osd.scss b/linux/home/.config/ags/widget/osd/osd.scss new file mode 100644 index 0000000..33df6d2 --- /dev/null +++ b/linux/home/.config/ags/widget/osd/osd.scss @@ -0,0 +1,26 @@ +window.indicator { + .progress { + @include floating-widget; + padding: $padding * 0.5; + border-radius: if($radius >0, calc($radius + $padding * 0.5), 0); + @debug $radius; + + .fill { + border-radius: $radius; + background-color: $primary-bg; + color: $primary-fg; + + image { + -gtk-icon-transform: scale(0.7); + } + } + } + + .microphone { + @include floating-widget; + margin: $spacing * 2; + padding: $popover-padding * 2; + font-size: 58px; + color: transparentize($fg, 0.1); + } +} diff --git a/linux/home/.config/ags/widget/overview/Overview.ts b/linux/home/.config/ags/widget/overview/Overview.ts new file mode 100644 index 0000000..8911920 --- /dev/null +++ b/linux/home/.config/ags/widget/overview/Overview.ts @@ -0,0 +1,41 @@ +import PopupWindow from "widget/PopupWindow" +import Workspace from "./Workspace" +import options from "options" +import { range } from "lib/utils" + +const hyprland = await Service.import("hyprland") + +const Overview = (ws: number) => Widget.Box({ + class_name: "overview horizontal", + children: ws > 0 + ? range(ws).map(Workspace) + : hyprland.workspaces + .map(({ id }) => Workspace(id)) + .sort((a, b) => a.attribute.id - b.attribute.id), + + setup: w => { + if (ws > 0) + return + + w.hook(hyprland, (w, id?: string) => { + if (id === undefined) + return + + w.children = w.children + .filter(ch => ch.attribute.id !== Number(id)) + }, "workspace-removed") + w.hook(hyprland, (w, id?: string) => { + if (id === undefined) + return + + w.children = [...w.children, Workspace(Number(id))] + .sort((a, b) => a.attribute.id - b.attribute.id) + }, "workspace-added") + }, +}) + +export default () => PopupWindow({ + name: "overview", + layout: "center", + child: options.overview.workspaces.bind().as(Overview), +}) diff --git a/linux/home/.config/ags/widget/overview/Window.ts b/linux/home/.config/ags/widget/overview/Window.ts new file mode 100644 index 0000000..02f71eb --- /dev/null +++ b/linux/home/.config/ags/widget/overview/Window.ts @@ -0,0 +1,48 @@ +import { type Client } from "types/service/hyprland" +import { createSurfaceFromWidget, icon } from "lib/utils" +import Gdk from "gi://Gdk" +import Gtk from "gi://Gtk?version=3.0" +import options from "options" +import icons from "lib/icons" + +const monochrome = options.overview.monochromeIcon +const TARGET = [Gtk.TargetEntry.new("text/plain", Gtk.TargetFlags.SAME_APP, 0)] +const hyprland = await Service.import("hyprland") +const apps = await Service.import("applications") +const dispatch = (args: string) => hyprland.messageAsync(`dispatch ${args}`) + +export default ({ address, size: [w, h], class: c, title }: Client) => Widget.Button({ + class_name: "client", + attribute: { address }, + tooltip_text: `${title}`, + child: Widget.Icon({ + css: options.overview.scale.bind().as(v => ` + min-width: ${(v / 100) * w}px; + min-height: ${(v / 100) * h}px; + `), + icon: monochrome.bind().as(m => { + const app = apps.list.find(app => app.match(c)) + if (!app) + return icons.fallback.executable + (m ? "-symbolic" : "") + + + return icon( + app.icon_name + (m ? "-symbolic" : ""), + icons.fallback.executable + (m ? "-symbolic" : ""), + ) + }), + }), + on_secondary_click: () => dispatch(`closewindow address:${address}`), + on_clicked: () => { + dispatch(`focuswindow address:${address}`) + App.closeWindow("overview") + }, + setup: btn => btn + .on("drag-data-get", (_w, _c, data) => data.set_text(address, address.length)) + .on("drag-begin", (_, context) => { + Gtk.drag_set_icon_surface(context, createSurfaceFromWidget(btn)) + btn.toggleClassName("hidden", true) + }) + .on("drag-end", () => btn.toggleClassName("hidden", false)) + .drag_source_set(Gdk.ModifierType.BUTTON1_MASK, TARGET, Gdk.DragAction.COPY), +}) diff --git a/linux/home/.config/ags/widget/overview/Workspace.ts b/linux/home/.config/ags/widget/overview/Workspace.ts new file mode 100644 index 0000000..1b8d60b --- /dev/null +++ b/linux/home/.config/ags/widget/overview/Workspace.ts @@ -0,0 +1,76 @@ +import Window from "./Window" +import Gdk from "gi://Gdk" +import Gtk from "gi://Gtk?version=3.0" +import options from "options" + +const TARGET = [Gtk.TargetEntry.new("text/plain", Gtk.TargetFlags.SAME_APP, 0)] +const scale = (size: number) => (options.overview.scale.value / 100) * size +const hyprland = await Service.import("hyprland") + +const dispatch = (args: string) => hyprland.messageAsync(`dispatch ${args}`) + +const size = (id: number) => { + const def = { h: 1080, w: 1920 } + const ws = hyprland.getWorkspace(id) + if (!ws) + return def + + const mon = hyprland.getMonitor(ws.monitorID) + return mon ? { h: mon.height, w: mon.width } : def +} + +export default (id: number) => { + const fixed = Widget.Fixed() + + // TODO: early return if position is unchaged + async function update() { + const json = await hyprland.messageAsync("j/clients").catch(() => null) + if (!json) + return + + fixed.get_children().forEach(ch => ch.destroy()) + const clients = JSON.parse(json) as typeof hyprland.clients + clients + .filter(({ workspace }) => workspace.id === id) + .forEach(c => { + const x = c.at[0] - (hyprland.getMonitor(c.monitor)?.x || 0) + const y = c.at[1] - (hyprland.getMonitor(c.monitor)?.y || 0) + c.mapped && fixed.put(Window(c), scale(x), scale(y)) + }) + fixed.show_all() + } + + return Widget.Box({ + attribute: { id }, + tooltipText: `${id}`, + class_name: "workspace", + vpack: "center", + css: options.overview.scale.bind().as(v => ` + min-width: ${(v / 100) * size(id).w}px; + min-height: ${(v / 100) * size(id).h}px; + `), + setup(box) { + box.hook(options.overview.scale, update) + box.hook(hyprland, update, "notify::clients") + box.hook(hyprland.active.client, update) + box.hook(hyprland.active.workspace, () => { + box.toggleClassName("active", hyprland.active.workspace.id === id) + }) + }, + child: Widget.EventBox({ + expand: true, + on_primary_click: () => { + App.closeWindow("overview") + dispatch(`workspace ${id}`) + }, + setup: eventbox => { + eventbox.drag_dest_set(Gtk.DestDefaults.ALL, TARGET, Gdk.DragAction.COPY) + eventbox.connect("drag-data-received", (_w, _c, _x, _y, data) => { + const address = new TextDecoder().decode(data.get_data()) + dispatch(`movetoworkspacesilent ${id},address:${address}`) + }) + }, + child: fixed, + }), + }) +} diff --git a/linux/home/.config/ags/widget/overview/overview.scss b/linux/home/.config/ags/widget/overview/overview.scss new file mode 100644 index 0000000..4665b52 --- /dev/null +++ b/linux/home/.config/ags/widget/overview/overview.scss @@ -0,0 +1,34 @@ +window#overview .overview { + @include floating-widget; + @include spacing; + + .workspace { + &.active>widget { + border-color: $primary-bg; + } + + >widget { + @include widget; + border-radius: if($radius ==0, 0, $radius + $padding); + + &:hover { + background-color: $hover-bg; + } + + &:drop(active) { + border-color: $primary-bg; + } + } + } + + .client { + @include button; + border-radius: $radius; + margin: $padding; + + &.hidden { + @include hidden; + transition: 0; + } + } +} diff --git a/linux/home/.config/ags/widget/powermenu/PowerMenu.ts b/linux/home/.config/ags/widget/powermenu/PowerMenu.ts new file mode 100644 index 0000000..fe0a0e9 --- /dev/null +++ b/linux/home/.config/ags/widget/powermenu/PowerMenu.ts @@ -0,0 +1,56 @@ +import PopupWindow from "widget/PopupWindow" +import powermenu, { type Action } from "service/powermenu" +import icons from "lib/icons" +import options from "options" +import type Gtk from "gi://Gtk?version=3.0" + +const { layout, labels } = options.powermenu + +const SysButton = (action: Action, label: string) => Widget.Button({ + on_clicked: () => powermenu.action(action), + child: Widget.Box({ + vertical: true, + class_name: "system-button", + children: [ + Widget.Icon(icons.powermenu[action]), + Widget.Label({ + label, + visible: labels.bind(), + }), + ], + }), +}) + +export default () => PopupWindow({ + name: "powermenu", + transition: "crossfade", + child: Widget.Box({ + class_name: "powermenu horizontal", + setup: self => self.hook(layout, () => { + self.toggleClassName("box", layout.value === "box") + self.toggleClassName("line", layout.value === "line") + }), + children: layout.bind().as(layout => { + switch (layout) { + case "line": return [ + SysButton("shutdown", "Shutdown"), + SysButton("logout", "Log Out"), + SysButton("reboot", "Reboot"), + SysButton("sleep", "Sleep"), + ] + case "box": return [ + Widget.Box( + { vertical: true }, + SysButton("shutdown", "Shutdown"), + SysButton("logout", "Log Out"), + ), + Widget.Box( + { vertical: true }, + SysButton("reboot", "Reboot"), + SysButton("sleep", "Sleep"), + ), + ] + } + }), + }), +}) diff --git a/linux/home/.config/ags/widget/powermenu/Verification.ts b/linux/home/.config/ags/widget/powermenu/Verification.ts new file mode 100644 index 0000000..e85c81a --- /dev/null +++ b/linux/home/.config/ags/widget/powermenu/Verification.ts @@ -0,0 +1,47 @@ +import PopupWindow from "widget/PopupWindow" +import powermenu from "service/powermenu" + +export default () => PopupWindow({ + name: "verification", + transition: "crossfade", + child: Widget.Box({ + class_name: "verification", + vertical: true, + children: [ + Widget.Box({ + class_name: "text-box", + vertical: true, + children: [ + Widget.Label({ + class_name: "title", + label: powermenu.bind("title"), + }), + Widget.Label({ + class_name: "desc", + label: "Are you sure?", + }), + ], + }), + Widget.Box({ + class_name: "buttons horizontal", + vexpand: true, + vpack: "end", + homogeneous: true, + children: [ + Widget.Button({ + child: Widget.Label("No"), + on_clicked: () => App.toggleWindow("verification"), + setup: self => self.hook(App, (_, name: string, visible: boolean) => { + if (name === "verification" && visible) + self.grab_focus() + }), + }), + Widget.Button({ + child: Widget.Label("Yes"), + on_clicked: () => Utils.exec(powermenu.cmd), + }), + ], + }), + ], + }), +}) diff --git a/linux/home/.config/ags/widget/powermenu/powermenu.scss b/linux/home/.config/ags/widget/powermenu/powermenu.scss new file mode 100644 index 0000000..d5ce0de --- /dev/null +++ b/linux/home/.config/ags/widget/powermenu/powermenu.scss @@ -0,0 +1,110 @@ +window#powermenu, +window#verification { + // the fraction has to be more than hyprland ignorealpha + background-color: rgba(0, 0, 0, .4); +} + +window#verification .verification { + @include floating-widget; + padding: $popover-padding * 1.5; + min-width: 300px; + min-height: 100px; + + .text-box { + margin-bottom: $spacing; + + .title { + font-size: 1.6em; + } + + .desc { + color: transparentize($fg, 0.1); + font-size: 1.1em; + } + } + + .buttons { + @include spacing; + margin-top: $padding; + + button { + @include button; + font-size: 1.5em; + padding: $padding; + } + } +} + +window#powermenu .powermenu { + @include floating-widget; + + &.line { + padding: $popover-padding * 1.5; + + button { + padding: $popover-padding; + } + + label { + margin-bottom: $spacing * -.5; + } + } + + &.box { + padding: $popover-padding * 2; + + button { + padding: $popover-padding * 1.5; + } + + label { + margin-bottom: $spacing * -1; + } + } + + button { + @include unset; + + image { + @include button; + border-radius: $radius + ($popover-padding * 1.4); + min-width: 1.7em; + min-height: 1.7em; + font-size: 4em; + } + + label, + image { + color: transparentize($fg, 0.1); + } + + label { + margin-top: $spacing * .3; + } + + &:hover { + image { + @include button-hover; + } + + label { + color: $fg; + } + } + + &:focus image { + @include button-focus; + } + + &:active image { + @include button-active; + } + + &:focus, + &:active { + label { + color: $primary-bg; + } + } + } +} diff --git a/linux/home/.config/ags/widget/quicksettings/QuickSettings.ts b/linux/home/.config/ags/widget/quicksettings/QuickSettings.ts new file mode 100644 index 0000000..2c0d6ac --- /dev/null +++ b/linux/home/.config/ags/widget/quicksettings/QuickSettings.ts @@ -0,0 +1,84 @@ +import type Gtk from "gi://Gtk?version=3.0" +import { ProfileSelector, ProfileToggle } from "./widgets/PowerProfile" +import { Header } from "./widgets/Header" +import { Volume, Microhone, SinkSelector, AppMixer } from "./widgets/Volume" +import { Brightness } from "./widgets/Brightness" +import { NetworkToggle, WifiSelection } from "./widgets/Network" +import { BluetoothToggle, BluetoothDevices } from "./widgets/Bluetooth" +import { DND } from "./widgets/DND" +import { DarkModeToggle } from "./widgets/DarkMode" +import { MicMute } from "./widgets/MicMute" +import { Media } from "./widgets/Media" +import PopupWindow from "widget/PopupWindow" +import options from "options" + +const { bar, quicksettings } = options +const media = (await Service.import("mpris")).bind("players") +const layout = Utils.derive([bar.position, quicksettings.position], (bar, qs) => + `${bar}-${qs}` as const, +) + +const Row = ( + toggles: Array<() => Gtk.Widget> = [], + menus: Array<() => Gtk.Widget> = [], +) => Widget.Box({ + vertical: true, + children: [ + Widget.Box({ + homogeneous: true, + class_name: "row horizontal", + children: toggles.map(w => w()), + }), + ...menus.map(w => w()), + ], +}) + +const Settings = () => Widget.Box({ + vertical: true, + class_name: "quicksettings vertical", + css: quicksettings.width.bind().as(w => `min-width: ${w}px;`), + children: [ + Header(), + Widget.Box({ + class_name: "sliders-box vertical", + vertical: true, + children: [ + Row( + [Volume], + [SinkSelector, AppMixer], + ), + Microhone(), + Brightness(), + ], + }), + Row( + [NetworkToggle, BluetoothToggle], + [WifiSelection, BluetoothDevices], + ), + Row( + [ProfileToggle, DarkModeToggle], + [ProfileSelector], + ), + Row([MicMute, DND]), + Widget.Box({ + visible: media.as(l => l.length > 0), + child: Media(), + }), + ], +}) + +const QuickSettings = () => PopupWindow({ + name: "quicksettings", + exclusivity: "exclusive", + transition: bar.position.bind().as(pos => pos === "top" ? "slide_down" : "slide_up"), + layout: layout.value, + child: Settings(), +}) + +export function setupQuickSettings() { + App.addWindow(QuickSettings()) + layout.connect("changed", () => { + App.removeWindow("quicksettings") + App.addWindow(QuickSettings()) + }) +} diff --git a/linux/home/.config/ags/widget/quicksettings/ToggleButton.ts b/linux/home/.config/ags/widget/quicksettings/ToggleButton.ts new file mode 100644 index 0000000..62a2e67 --- /dev/null +++ b/linux/home/.config/ags/widget/quicksettings/ToggleButton.ts @@ -0,0 +1,154 @@ +import { type Props as IconProps } from "types/widgets/icon" +import { type Props as LabelProps } from "types/widgets/label" +import type GObject from "gi://GObject?version=2.0" +import type Gtk from "gi://Gtk?version=3.0" +import icons from "lib/icons" + +export const opened = Variable("") +App.connect("window-toggled", (_, name: string, visible: boolean) => { + if (name === "quicksettings" && !visible) + Utils.timeout(500, () => opened.value = "") +}) + +export const Arrow = (name: string, activate?: false | (() => void)) => { + let deg = 0 + let iconOpened = false + const icon = Widget.Icon(icons.ui.arrow.right).hook(opened, () => { + if (opened.value === name && !iconOpened || opened.value !== name && iconOpened) { + const step = opened.value === name ? 10 : -10 + iconOpened = !iconOpened + for (let i = 0; i < 9; ++i) { + Utils.timeout(15 * i, () => { + deg += step + icon.setCss(`-gtk-icon-transform: rotate(${deg}deg);`) + }) + } + } + }) + return Widget.Button({ + child: icon, + class_name: "arrow", + on_clicked: () => { + opened.value = opened.value === name ? "" : name + if (typeof activate === "function") + activate() + }, + }) +} + +type ArrowToggleButtonProps = { + name: string + icon: IconProps["icon"] + label: LabelProps["label"] + activate: () => void + deactivate: () => void + activateOnArrow?: boolean + connection: [GObject.Object, () => boolean] +} +export const ArrowToggleButton = ({ + name, + icon, + label, + activate, + deactivate, + activateOnArrow = true, + connection: [service, condition], +}: ArrowToggleButtonProps) => Widget.Box({ + class_name: "toggle-button", + setup: self => self.hook(service, () => { + self.toggleClassName("active", condition()) + }), + children: [ + Widget.Button({ + child: Widget.Box({ + hexpand: true, + children: [ + Widget.Icon({ + class_name: "icon", + icon, + }), + Widget.Label({ + class_name: "label", + max_width_chars: 10, + truncate: "end", + label, + }), + ], + }), + on_clicked: () => { + if (condition()) { + deactivate() + if (opened.value === name) + opened.value = "" + } else { + activate() + } + }, + }), + Arrow(name, activateOnArrow && activate), + ], +}) + +type MenuProps = { + name: string + icon: IconProps["icon"] + title: LabelProps["label"] + content: Gtk.Widget[] +} +export const Menu = ({ name, icon, title, content }: MenuProps) => Widget.Revealer({ + transition: "slide_down", + reveal_child: opened.bind().as(v => v === name), + child: Widget.Box({ + class_names: ["menu", name], + vertical: true, + children: [ + Widget.Box({ + class_name: "title-box", + children: [ + Widget.Icon({ + class_name: "icon", + icon, + }), + Widget.Label({ + class_name: "title", + truncate: "end", + label: title, + }), + ], + }), + Widget.Separator(), + Widget.Box({ + vertical: true, + class_name: "content vertical", + children: content, + }), + ], + }), +}) + +type SimpleToggleButtonProps = { + icon: IconProps["icon"] + label: LabelProps["label"] + toggle: () => void + connection: [GObject.Object, () => boolean] +} +export const SimpleToggleButton = ({ + icon, + label, + toggle, + connection: [service, condition], +}: SimpleToggleButtonProps) => Widget.Button({ + on_clicked: toggle, + class_name: "simple-toggle", + setup: self => self.hook(service, () => { + self.toggleClassName("active", condition()) + }), + child: Widget.Box([ + Widget.Icon({ icon }), + Widget.Label({ + max_width_chars: 10, + truncate: "end", + label, + }), + ]), +}) diff --git a/linux/home/.config/ags/widget/quicksettings/quicksettings.scss b/linux/home/.config/ags/widget/quicksettings/quicksettings.scss new file mode 100644 index 0000000..bd18ff1 --- /dev/null +++ b/linux/home/.config/ags/widget/quicksettings/quicksettings.scss @@ -0,0 +1,177 @@ +window#quicksettings .quicksettings { + @include floating-widget; + @include spacing; + + padding: $popover-padding * 1.4; + + .avatar { + @include widget; + border-radius: $radius * 3; + } + + .header { + @include spacing(.5); + color: transparentize($fg, .15); + + button { + @include button; + padding: $padding; + + image { + font-size: 1.4em; + } + } + } + + .sliders-box { + @include widget; + padding: $padding; + + button { + @include button($flat: true); + padding: $padding * .5; + } + + .volume button.arrow:last-child { + margin-left: $spacing * .4; + } + + .volume, + .brightness { + padding: $padding * .5; + } + + scale { + @include slider; + margin: 0 ($spacing * .5); + + &.muted highlight { + background-image: none; + background-color: transparentize($fg, $amount: .2); + } + } + } + + .row { + @include spacing; + } + + .menu { + @include unset; + @include widget; + padding: $padding; + margin-top: $spacing; + + .icon { + margin: 0 ($spacing * .5); + margin-left: $spacing * .2; + } + + .title { + font-weight: bold; + } + + separator { + margin: ($radius * .5); + background-color: $border-color; + } + + button { + @include button($flat: true); + padding: ($padding * .5); + + image:first-child { + margin-right: $spacing * .5; + } + } + + .bluetooth-devices { + @include spacing(.5); + } + + switch { + @include switch; + } + } + + .sliders-box .menu { + margin: ($spacing * .5) 0; + + &.app-mixer { + .mixer-item { + padding: $padding * .5; + padding-left: 0; + padding-right: $padding * 2; + + scale { + @include slider($width: .5em); + } + + image { + font-size: 1.2em; + margin: 0 $padding; + } + } + } + } + + .toggle-button { + @include button; + font-weight: bold; + + image { + font-size: 1.3em; + } + + label { + margin-left: $spacing * .3; + } + + button { + @include button($flat: true); + + &:first-child { + padding: $padding * 1.2; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + + &:last-child { + padding: $padding * .5; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + } + + &.active { + background-color: $primary-bg; + + label, + image { + color: $primary-fg; + } + } + } + + .simple-toggle { + @include button; + font-weight: bold; + padding: $padding * 1.2; + + label { + margin-left: $spacing * .3; + } + + image { + font-size: 1.3em; + } + } + + .media { + @include spacing; + + .player { + @include media; + } + } +} diff --git a/linux/home/.config/ags/widget/quicksettings/widgets/Bluetooth.ts b/linux/home/.config/ags/widget/quicksettings/widgets/Bluetooth.ts new file mode 100644 index 0000000..649e654 --- /dev/null +++ b/linux/home/.config/ags/widget/quicksettings/widgets/Bluetooth.ts @@ -0,0 +1,61 @@ +import { type BluetoothDevice } from "types/service/bluetooth" +import { Menu, ArrowToggleButton } from "../ToggleButton" +import icons from "lib/icons" + +const bluetooth = await Service.import("bluetooth") + +export const BluetoothToggle = () => ArrowToggleButton({ + name: "bluetooth", + icon: bluetooth.bind("enabled").as(p => icons.bluetooth[p ? "enabled" : "disabled"]), + label: Utils.watch("Disabled", bluetooth, () => { + if (!bluetooth.enabled) + return "Disabled" + + if (bluetooth.connected_devices.length === 1) + return bluetooth.connected_devices[0].alias + + return `${bluetooth.connected_devices.length} Connected` + }), + connection: [bluetooth, () => bluetooth.enabled], + deactivate: () => bluetooth.enabled = false, + activate: () => bluetooth.enabled = true, +}) + +const DeviceItem = (device: BluetoothDevice) => Widget.Box({ + children: [ + Widget.Icon(device.icon_name + "-symbolic"), + Widget.Label(device.name), + Widget.Label({ + label: `${device.battery_percentage}%`, + visible: device.bind("battery_percentage").as(p => p > 0), + }), + Widget.Box({ hexpand: true }), + Widget.Spinner({ + active: device.bind("connecting"), + visible: device.bind("connecting"), + }), + Widget.Switch({ + active: device.connected, + visible: device.bind("connecting").as(p => !p), + setup: self => self.on("notify::active", () => { + device.setConnection(self.active) + }), + }), + ], +}) + +export const BluetoothDevices = () => Menu({ + name: "bluetooth", + icon: icons.bluetooth.disabled, + title: "Bluetooth", + content: [ + Widget.Box({ + class_name: "bluetooth-devices", + hexpand: true, + vertical: true, + children: bluetooth.bind("devices").as(ds => ds + .filter(d => d.name) + .map(DeviceItem)), + }), + ], +}) diff --git a/linux/home/.config/ags/widget/quicksettings/widgets/Brightness.ts b/linux/home/.config/ags/widget/quicksettings/widgets/Brightness.ts new file mode 100644 index 0000000..a3ce565 --- /dev/null +++ b/linux/home/.config/ags/widget/quicksettings/widgets/Brightness.ts @@ -0,0 +1,23 @@ +import icons from "lib/icons" +import brightness from "service/brightness" + +const BrightnessSlider = () => Widget.Slider({ + draw_value: false, + hexpand: true, + value: brightness.bind("screen"), + on_change: ({ value }) => brightness.screen = value, +}) + +export const Brightness = () => Widget.Box({ + class_name: "brightness", + children: [ + Widget.Button({ + vpack: "center", + child: Widget.Icon(icons.brightness.indicator), + on_clicked: () => brightness.screen = 0, + tooltip_text: brightness.bind("screen").as(v => + `Screen Brightness: ${Math.floor(v * 100)}%`), + }), + BrightnessSlider(), + ], +}) diff --git a/linux/home/.config/ags/widget/quicksettings/widgets/DND.ts b/linux/home/.config/ags/widget/quicksettings/widgets/DND.ts new file mode 100644 index 0000000..7fc1fd0 --- /dev/null +++ b/linux/home/.config/ags/widget/quicksettings/widgets/DND.ts @@ -0,0 +1,12 @@ +import { SimpleToggleButton } from "../ToggleButton" +import icons from "lib/icons" + +const n = await Service.import("notifications") +const dnd = n.bind("dnd") + +export const DND = () => SimpleToggleButton({ + icon: dnd.as(dnd => icons.notifications[dnd ? "silent" : "noisy"]), + label: dnd.as(dnd => dnd ? "Silent" : "Noisy"), + toggle: () => n.dnd = !n.dnd, + connection: [n, () => n.dnd], +}) diff --git a/linux/home/.config/ags/widget/quicksettings/widgets/DarkMode.ts b/linux/home/.config/ags/widget/quicksettings/widgets/DarkMode.ts new file mode 100644 index 0000000..9ec94df --- /dev/null +++ b/linux/home/.config/ags/widget/quicksettings/widgets/DarkMode.ts @@ -0,0 +1,12 @@ +import { SimpleToggleButton } from "../ToggleButton" +import icons from "lib/icons" +import options from "options" + +const { scheme } = options.theme + +export const DarkModeToggle = () => SimpleToggleButton({ + icon: scheme.bind().as(s => icons.color[s]), + label: scheme.bind().as(s => s === "dark" ? "Dark" : "Light"), + toggle: () => scheme.value = scheme.value === "dark" ? "light" : "dark", + connection: [scheme, () => scheme.value === "dark"], +}) diff --git a/linux/home/.config/ags/widget/quicksettings/widgets/Header.ts b/linux/home/.config/ags/widget/quicksettings/widgets/Header.ts new file mode 100644 index 0000000..44c26f2 --- /dev/null +++ b/linux/home/.config/ags/widget/quicksettings/widgets/Header.ts @@ -0,0 +1,69 @@ +import icons from "lib/icons" +import { uptime } from "lib/variables" +import options from "options" +import powermenu, { Action } from "service/powermenu" + +const battery = await Service.import("battery") +const { image, size } = options.quicksettings.avatar + +function up(up: number) { + const h = Math.floor(up / 60) + const m = Math.floor(up % 60) + return `${h}h ${m < 10 ? "0" + m : m}m` +} + +const Avatar = () => Widget.Box({ + class_name: "avatar", + css: Utils.merge([image.bind(), size.bind()], (img, size) => ` + min-width: ${size}px; + min-height: ${size}px; + background-image: url('${img}'); + background-size: cover; + `), +}) + +const SysButton = (action: Action) => Widget.Button({ + vpack: "center", + child: Widget.Icon(icons.powermenu[action]), + on_clicked: () => powermenu.action(action), +}) + +export const Header = () => Widget.Box( + { class_name: "header horizontal" }, + Avatar(), + Widget.Box({ + vertical: true, + vpack: "center", + children: [ + Widget.Box({ + visible: battery.bind("available"), + children: [ + Widget.Icon({ icon: battery.bind("icon_name") }), + Widget.Label({ label: battery.bind("percent").as(p => `${p}%`) }), + ], + }), + Widget.Box([ + Widget.Icon({ icon: icons.ui.time }), + Widget.Label({ label: uptime.bind().as(up) }), + + //Widget.Label({ label: `${user.name}\n` }), + // //Widget.Label({ label: uptime.bind().value }), + // Widget.Label({ label: `${user.name}\n ${uptime.bind().value}` }), + // //Widget.Icon({ icon: icons.ui.time }), + ]), + + ], + }), + Widget.Box({ hexpand: true }), + Widget.Button({ + vpack: "center", + child: Widget.Icon(icons.ui.settings), + on_clicked: () => { + App.closeWindow("quicksettings") + App.closeWindow("settings-dialog") + App.openWindow("settings-dialog") + }, + }), + SysButton("logout"), + SysButton("shutdown"), +) diff --git a/linux/home/.config/ags/widget/quicksettings/widgets/Media.ts b/linux/home/.config/ags/widget/quicksettings/widgets/Media.ts new file mode 100644 index 0000000..52254ea --- /dev/null +++ b/linux/home/.config/ags/widget/quicksettings/widgets/Media.ts @@ -0,0 +1,153 @@ +import { type MprisPlayer } from "types/service/mpris" +import icons from "lib/icons" +import options from "options" +import { icon } from "lib/utils" + +const mpris = await Service.import("mpris") +const players = mpris.bind("players") +const { media } = options.quicksettings + +function lengthStr(length: number) { + const min = Math.floor(length / 60) + const sec = Math.floor(length % 60) + const sec0 = sec < 10 ? "0" : "" + return `${min}:${sec0}${sec}` +} + +const Player = (player: MprisPlayer) => { + const cover = Widget.Box({ + class_name: "cover", + vpack: "start", + css: Utils.merge([ + player.bind("cover_path"), + player.bind("track_cover_url"), + media.coverSize.bind(), + ], (path, url, size) => ` + min-width: ${size}px; + min-height: ${size}px; + background-image: url('${path || url}'); + `), + }) + + const title = Widget.Label({ + class_name: "title", + max_width_chars: 20, + truncate: "end", + hpack: "start", + label: player.bind("track_title"), + }) + + const artist = Widget.Label({ + class_name: "artist", + max_width_chars: 20, + truncate: "end", + hpack: "start", + label: player.bind("track_artists").as(a => a.join(", ")), + }) + + const positionSlider = Widget.Slider({ + class_name: "position", + draw_value: false, + on_change: ({ value }) => player.position = value * player.length, + setup: self => { + const update = () => { + const { length, position } = player + self.visible = length > 0 + self.value = length > 0 ? position / length : 0 + } + self.hook(player, update) + self.hook(player, update, "position") + self.poll(1000, update) + }, + }) + + const positionLabel = Widget.Label({ + class_name: "position", + hpack: "start", + setup: self => { + const update = (_: unknown, time?: number) => { + self.label = lengthStr(time || player.position) + self.visible = player.length > 0 + } + self.hook(player, update, "position") + self.poll(1000, update) + }, + }) + + const lengthLabel = Widget.Label({ + class_name: "length", + hpack: "end", + visible: player.bind("length").as(l => l > 0), + label: player.bind("length").as(lengthStr), + }) + + const playericon = Widget.Icon({ + class_name: "icon", + hexpand: true, + hpack: "end", + vpack: "start", + tooltip_text: player.identity || "", + icon: Utils.merge([player.bind("entry"), media.monochromeIcon.bind()], (e, s) => { + const name = `${e}${s ? "-symbolic" : ""}` + return icon(name, icons.fallback.audio) + }), + }) + + const playPause = Widget.Button({ + class_name: "play-pause", + on_clicked: () => player.playPause(), + visible: player.bind("can_play"), + child: Widget.Icon({ + icon: player.bind("play_back_status").as(s => { + switch (s) { + case "Playing": return icons.mpris.playing + case "Paused": + case "Stopped": return icons.mpris.stopped + } + }), + }), + }) + + const prev = Widget.Button({ + on_clicked: () => player.previous(), + visible: player.bind("can_go_prev"), + child: Widget.Icon(icons.mpris.prev), + }) + + const next = Widget.Button({ + on_clicked: () => player.next(), + visible: player.bind("can_go_next"), + child: Widget.Icon(icons.mpris.next), + }) + + return Widget.Box( + { class_name: "player", vexpand: false }, + cover, + Widget.Box( + { vertical: true }, + Widget.Box([ + title, + playericon, + ]), + artist, + Widget.Box({ vexpand: true }), + positionSlider, + Widget.CenterBox({ + class_name: "footer horizontal", + start_widget: positionLabel, + center_widget: Widget.Box([ + prev, + playPause, + next, + ]), + end_widget: lengthLabel, + }), + ), + ) +} + +export const Media = () => Widget.Box({ + vertical: true, + class_name: "media vertical", + children: players.as(p => p.map(Player)), +}) diff --git a/linux/home/.config/ags/widget/quicksettings/widgets/MicMute.ts b/linux/home/.config/ags/widget/quicksettings/widgets/MicMute.ts new file mode 100644 index 0000000..b6e9454 --- /dev/null +++ b/linux/home/.config/ags/widget/quicksettings/widgets/MicMute.ts @@ -0,0 +1,18 @@ +import { SimpleToggleButton } from "../ToggleButton" +import icons from "lib/icons" +const { microphone } = await Service.import("audio") + +const icon = () => microphone.is_muted || microphone.stream?.is_muted + ? icons.audio.mic.muted + : icons.audio.mic.high + +const label = () => microphone.is_muted || microphone.stream?.is_muted + ? "Muted" + : "Unmuted" + +export const MicMute = () => SimpleToggleButton({ + icon: Utils.watch(icon(), microphone, icon), + label: Utils.watch(label(), microphone, label), + toggle: () => microphone.is_muted = !microphone.is_muted, + connection: [microphone, () => microphone?.is_muted || false], +}) diff --git a/linux/home/.config/ags/widget/quicksettings/widgets/Network.ts b/linux/home/.config/ags/widget/quicksettings/widgets/Network.ts new file mode 100644 index 0000000..eb14ab4 --- /dev/null +++ b/linux/home/.config/ags/widget/quicksettings/widgets/Network.ts @@ -0,0 +1,61 @@ +import { Menu, ArrowToggleButton } from "../ToggleButton" +import icons from "lib/icons.js" +import { dependencies, sh } from "lib/utils" +import options from "options" +const { wifi } = await Service.import("network") + +export const NetworkToggle = () => ArrowToggleButton({ + name: "network", + icon: wifi.bind("icon_name"), + label: wifi.bind("ssid").as(ssid => ssid || "Not Connected"), + connection: [wifi, () => wifi.enabled], + deactivate: () => wifi.enabled = false, + activate: () => { + wifi.enabled = true + wifi.scan() + }, +}) + +export const WifiSelection = () => Menu({ + name: "network", + icon: wifi.bind("icon_name"), + title: "Wifi Selection", + content: [ + Widget.Box({ + vertical: true, + setup: self => self.hook(wifi, () => self.children = + wifi.access_points.map(ap => Widget.Button({ + on_clicked: () => { + if (dependencies("nmcli")) + Utils.execAsync(`nmcli device wifi connect ${ap.bssid}`) + }, + child: Widget.Box({ + children: [ + Widget.Icon(ap.iconName), + Widget.Label(ap.ssid || ""), + Widget.Icon({ + icon: icons.ui.tick, + hexpand: true, + hpack: "end", + setup: self => Utils.idle(() => { + if (!self.is_destroyed) + self.visible = ap.active + }), + }), + ], + }), + })), + ), + }), + Widget.Separator(), + Widget.Button({ + on_clicked: () => sh(options.quicksettings.networkSettings.value), + child: Widget.Box({ + children: [ + Widget.Icon(icons.ui.settings), + Widget.Label("Network"), + ], + }), + }), + ], +}) diff --git a/linux/home/.config/ags/widget/quicksettings/widgets/PowerProfile.ts b/linux/home/.config/ags/widget/quicksettings/widgets/PowerProfile.ts new file mode 100644 index 0000000..f566aaf --- /dev/null +++ b/linux/home/.config/ags/widget/quicksettings/widgets/PowerProfile.ts @@ -0,0 +1,99 @@ +import { ArrowToggleButton, Menu } from "../ToggleButton" +import icons from "lib/icons" + +import asusctl from "service/asusctl" +const asusprof = asusctl.bind("profile") + +const AsusProfileToggle = () => ArrowToggleButton({ + name: "asusctl-profile", + icon: asusprof.as(p => icons.asusctl.profile[p]), + label: asusprof, + connection: [asusctl, () => asusctl.profile !== "Balanced"], + activate: () => asusctl.setProfile("Quiet"), + deactivate: () => asusctl.setProfile("Balanced"), + activateOnArrow: false, +}) + +const AsusProfileSelector = () => Menu({ + name: "asusctl-profile", + icon: asusprof.as(p => icons.asusctl.profile[p]), + title: "Profile Selector", + content: [ + Widget.Box({ + vertical: true, + hexpand: true, + children: [ + Widget.Box({ + vertical: true, + children: asusctl.profiles.map(prof => Widget.Button({ + on_clicked: () => asusctl.setProfile(prof), + child: Widget.Box({ + children: [ + Widget.Icon(icons.asusctl.profile[prof]), + Widget.Label(prof), + ], + }), + })), + }), + ], + }), + Widget.Separator(), + Widget.Button({ + on_clicked: () => Utils.execAsync("rog-control-center"), + child: Widget.Box({ + children: [ + Widget.Icon(icons.ui.settings), + Widget.Label("Rog Control Center"), + ], + }), + }), + ], +}) + + +const pp = await Service.import("powerprofiles") +const profile = pp.bind("active_profile") +const profiles = pp.profiles.map(p => p.Profile) + +const pretty = (str: string) => str + .split("-") + .map(str => `${str.at(0)?.toUpperCase()}${str.slice(1)}`) + .join(" ") + +const PowerProfileToggle = () => ArrowToggleButton({ + name: "asusctl-profile", + icon: profile.as(p => icons.powerprofile[p]), + label: profile.as(pretty), + connection: [pp, () => pp.active_profile !== profiles[1]], + activate: () => pp.active_profile = profiles[0], + deactivate: () => pp.active_profile = profiles[1], + activateOnArrow: false, +}) + +const PowerProfileSelector = () => Menu({ + name: "asusctl-profile", + icon: profile.as(p => icons.powerprofile[p]), + title: "Profile Selector", + content: [Widget.Box({ + vertical: true, + hexpand: true, + child: Widget.Box({ + vertical: true, + children: profiles.map(prof => Widget.Button({ + on_clicked: () => pp.active_profile = prof, + child: Widget.Box({ + children: [ + Widget.Icon(icons.powerprofile[prof]), + Widget.Label(pretty(prof)), + ], + }), + })), + }), + })], +}) + +export const ProfileToggle = asusctl.available + ? AsusProfileToggle : PowerProfileToggle + +export const ProfileSelector = asusctl.available + ? AsusProfileSelector : PowerProfileSelector diff --git a/linux/home/.config/ags/widget/quicksettings/widgets/Volume.ts b/linux/home/.config/ags/widget/quicksettings/widgets/Volume.ts new file mode 100644 index 0000000..077439a --- /dev/null +++ b/linux/home/.config/ags/widget/quicksettings/widgets/Volume.ts @@ -0,0 +1,161 @@ +import { type Stream } from "types/service/audio" +import { Arrow, Menu } from "../ToggleButton" +import { dependencies, icon, sh } from "lib/utils" +import icons from "lib/icons.js" +const audio = await Service.import("audio") + +type Type = "microphone" | "speaker" + +const VolumeIndicator = (type: Type = "speaker") => Widget.Button({ + vpack: "center", + on_clicked: () => audio[type].is_muted = !audio[type].is_muted, + child: Widget.Icon({ + icon: audio[type].bind("icon_name") + .as(i => icon(i || "", icons.audio.volume.medium)), + tooltipText: audio[type].bind("volume") + .as(vol => `Volume: ${Math.floor(vol * 100)}%`), + }), +}) + +const micIndicator = (type: Type = "microphone") => Widget.Button({ + vpack: "center", + on_clicked: () => audio[type].is_muted = !audio[type].is_muted, + child: Widget.Icon({ + icon: audio[type].bind("icon_name") + .as(i => icon(i || "", icons.audio.mic.medium)), + tooltipText: audio[type].bind("volume") + .as(vol => `Volume: ${Math.floor(vol * 100)}%`), + }), +}) + +const VolumeSlider = (type: Type = "speaker") => Widget.Slider({ + hexpand: true, + draw_value: false, + on_change: ({ value, dragging }) => { + if (dragging) { + audio[type].volume = value + audio[type].is_muted = false + } + }, + value: audio[type].bind("volume"), + class_name: audio[type].bind("is_muted").as(m => m ? "muted" : ""), +}) + +export const Volume = () => Widget.Box({ + class_name: "volume", + children: [ + VolumeIndicator("speaker"), + VolumeSlider("speaker"), + Widget.Box({ + vpack: "center", + child: Arrow("sink-selector"), + }), + Widget.Box({ + vpack: "center", + child: Arrow("app-mixer"), + visible: audio.bind("apps").as(a => a.length > 0), + }), + ], +}) + +export const Microhone = () => Widget.Box({ + class_name: "slider horizontal", + visible: audio.bind("recorders").as(a => a.length > 0), + children: [ + micIndicator("microphone"), + VolumeSlider("microphone"), + ], +}) + +const MixerItem = (stream: Stream) => Widget.Box( + { + hexpand: true, + class_name: "mixer-item horizontal", + }, + Widget.Icon({ + tooltip_text: stream.bind("name").as(n => n || ""), + icon: stream.bind("name").as(n => { + return Utils.lookUpIcon(n || "") + ? (n || "") + : icons.fallback.audio + }), + }), + Widget.Box( + { vertical: true }, + Widget.Label({ + xalign: 0, + truncate: "end", + max_width_chars: 28, + label: stream.bind("description").as(d => d || ""), + }), + Widget.Slider({ + hexpand: true, + draw_value: false, + value: stream.bind("volume"), + on_change: ({ value }) => stream.volume = value, + }), + ), +) + +const SinkItem = (stream: Stream) => Widget.Button({ + hexpand: true, + on_clicked: () => audio.speaker = stream, + child: Widget.Box({ + children: [ + Widget.Icon({ + icon: icon(stream.icon_name || "", icons.fallback.audio), + tooltip_text: stream.icon_name || "", + }), + Widget.Label((stream.description || "").split(" ").slice(0, 4).join(" ")), + Widget.Icon({ + icon: icons.ui.tick, + hexpand: true, + hpack: "end", + visible: audio.speaker.bind("stream").as(s => s === stream.stream), + }), + ], + }), +}) + +const SettingsButton = () => Widget.Button({ + on_clicked: () => { + if (dependencies("pavucontrol")) + sh("pavucontrol") + }, + hexpand: true, + child: Widget.Box({ + children: [ + Widget.Icon(icons.ui.settings), + Widget.Label("Settings"), + ], + }), +}) + +export const AppMixer = () => Menu({ + name: "app-mixer", + icon: icons.audio.mixer, + title: "App Mixer", + content: [ + Widget.Box({ + vertical: true, + class_name: "vertical mixer-item-box", + children: audio.bind("apps").as(a => a.map(MixerItem)), + }), + Widget.Separator(), + SettingsButton(), + ], +}) + +export const SinkSelector = () => Menu({ + name: "sink-selector", + icon: icons.audio.type.headset, + title: "Sink Selector", + content: [ + Widget.Box({ + vertical: true, + children: audio.bind("speakers").as(a => a.map(SinkItem)), + }), + Widget.Separator(), + SettingsButton(), + ], +}) diff --git a/linux/home/.config/ags/widget/settings/Group.ts b/linux/home/.config/ags/widget/settings/Group.ts new file mode 100644 index 0000000..e9356e0 --- /dev/null +++ b/linux/home/.config/ags/widget/settings/Group.ts @@ -0,0 +1,34 @@ +import icons from "lib/icons" +import Row from "./Row" + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export default (title: string, ...rows: ReturnType>[]) => Widget.Box( + { + class_name: "group", + vertical: true, + }, + Widget.Box([ + Widget.Label({ + hpack: "start", + vpack: "end", + class_name: "group-title", + label: title, + setup: w => Utils.idle(() => w.visible = !!title), + }), + title ? Widget.Button({ + hexpand: true, + hpack: "end", + child: Widget.Icon(icons.ui.refresh), + class_name: "group-reset", + sensitive: Utils.merge( + rows.map(({ attribute: { opt } }) => opt.bind().as(v => v !== opt.initial)), + (...values) => values.some(b => b), + ), + on_clicked: () => rows.forEach(row => row.attribute.opt.reset()), + }) : Widget.Box(), + ]), + Widget.Box({ + vertical: true, + children: rows, + }), +) diff --git a/linux/home/.config/ags/widget/settings/Page.ts b/linux/home/.config/ags/widget/settings/Page.ts new file mode 100644 index 0000000..220e560 --- /dev/null +++ b/linux/home/.config/ags/widget/settings/Page.ts @@ -0,0 +1,19 @@ +import Group from "./Group" + +export default ( + name: string, + icon: string, + ...groups: ReturnType>[] +) => Widget.Box({ + class_name: "page", + attribute: { name, icon }, + child: Widget.Scrollable({ + css: "min-height: 300px;", + child: Widget.Box({ + class_name: "page-content", + vexpand: true, + vertical: true, + children: groups, + }), + }), +}) diff --git a/linux/home/.config/ags/widget/settings/Row.ts b/linux/home/.config/ags/widget/settings/Row.ts new file mode 100644 index 0000000..1e17096 --- /dev/null +++ b/linux/home/.config/ags/widget/settings/Row.ts @@ -0,0 +1,55 @@ +import { Opt } from "lib/option" +import Setter from "./Setter" +import icons from "lib/icons" + +export type RowProps = { + opt: Opt + title: string + note?: string + type?: + | "number" + | "color" + | "float" + | "object" + | "string" + | "enum" + | "boolean" + | "img" + | "font" + enums?: string[] + max?: number + min?: number +} + +export default (props: RowProps) => Widget.Box( + { + attribute: { opt: props.opt }, + class_name: "row", + tooltip_text: props.note ? `note: ${props.note}` : "", + }, + Widget.Box( + { vertical: true, vpack: "center" }, + Widget.Label({ + xalign: 0, + class_name: "row-title", + label: props.title, + }), + Widget.Label({ + xalign: 0, + class_name: "id", + label: props.opt.id, + }), + ), + Widget.Box({ hexpand: true }), + Widget.Box( + { vpack: "center" }, + Setter(props), + ), + Widget.Button({ + vpack: "center", + class_name: "reset", + child: Widget.Icon(icons.ui.refresh), + on_clicked: () => props.opt.reset(), + sensitive: props.opt.bind().as(v => v !== props.opt.initial), + }), +) diff --git a/linux/home/.config/ags/widget/settings/Setter.ts b/linux/home/.config/ags/widget/settings/Setter.ts new file mode 100644 index 0000000..7e455c9 --- /dev/null +++ b/linux/home/.config/ags/widget/settings/Setter.ts @@ -0,0 +1,93 @@ +import { type RowProps } from "./Row" +import { Opt } from "lib/option" +import icons from "lib/icons" +import Gdk from "gi://Gdk" + +function EnumSetter(opt: Opt, values: string[]) { + const lbl = Widget.Label({ label: opt.bind().as(v => `${v}`) }) + const step = (dir: 1 | -1) => { + const i = values.findIndex(i => i === lbl.label) + opt.setValue(dir > 0 + ? i + dir > values.length - 1 ? values[0] : values[i + dir] + : i + dir < 0 ? values[values.length - 1] : values[i + dir], + ) + } + const next = Widget.Button({ + child: Widget.Icon(icons.ui.arrow.right), + on_clicked: () => step(+1), + }) + const prev = Widget.Button({ + child: Widget.Icon(icons.ui.arrow.left), + on_clicked: () => step(-1), + }) + return Widget.Box({ + class_name: "enum-setter", + children: [lbl, prev, next], + }) +} + +export default function Setter({ + opt, + type = typeof opt.value as RowProps["type"], + enums, + max = 1000, + min = 0, +}: RowProps) { + switch (type) { + case "number": return Widget.SpinButton({ + setup(self) { + self.set_range(min, max) + self.set_increments(1, 5) + self.on("value-changed", () => opt.value = self.value as T) + self.hook(opt, () => self.value = opt.value as number) + }, + }) + + case "float": + case "object": return Widget.Entry({ + on_accept: self => opt.value = JSON.parse(self.text || ""), + setup: self => self.hook(opt, () => self.text = JSON.stringify(opt.value)), + }) + + case "string": return Widget.Entry({ + on_accept: self => opt.value = self.text as T, + setup: self => self.hook(opt, () => self.text = opt.value as string), + }) + + case "enum": return EnumSetter(opt as unknown as Opt, enums!) + case "boolean": return Widget.Switch() + .on("notify::active", self => opt.value = self.active as T) + .hook(opt, self => self.active = opt.value as boolean) + + case "img": return Widget.FileChooserButton({ + on_file_set: ({ uri }) => { opt.value = uri!.replace("file://", "") as T }, + }) + + case "font": return Widget.FontButton({ + show_size: false, + use_size: false, + setup: self => self + .hook(opt, () => self.font = opt.value as string) + .on("font-set", ({ font }) => opt.value = font! + .split(" ").slice(0, -1).join(" ") as T), + }) + + case "color": return Widget.ColorButton() + .hook(opt, self => { + const rgba = new Gdk.RGBA() + rgba.parse(opt.value as string) + self.rgba = rgba + }) + .on("color-set", ({ rgba: { red, green, blue } }) => { + const hex = (n: number) => { + const c = Math.floor(255 * n).toString(16) + return c.length === 1 ? `0${c}` : c + } + opt.value = `#${hex(red)}${hex(green)}${hex(blue)}` as T + }) + + default: return Widget.Label({ + label: `no setter with type ${type}`, + }) + } +} diff --git a/linux/home/.config/ags/widget/settings/SettingsDialog.ts b/linux/home/.config/ags/widget/settings/SettingsDialog.ts new file mode 100644 index 0000000..be0c35e --- /dev/null +++ b/linux/home/.config/ags/widget/settings/SettingsDialog.ts @@ -0,0 +1,63 @@ +import RegularWindow from "widget/RegularWindow" +import layout from "./layout" +import icons from "lib/icons" +import options from "options" + +const current = Variable(layout[0].attribute.name) + +const Header = () => Widget.CenterBox({ + class_name: "header", + start_widget: Widget.Button({ + class_name: "reset", + on_clicked: options.reset, + hpack: "start", + vpack: "start", + child: Widget.Icon(icons.ui.refresh), + tooltip_text: "Reset", + }), + center_widget: Widget.Box({ + class_name: "pager horizontal", + children: layout.map(({ attribute: { name, icon } }) => Widget.Button({ + xalign: 0, + class_name: current.bind().as(v => `${v === name ? "active" : ""}`), + on_clicked: () => current.value = name, + child: Widget.Box([ + Widget.Icon(icon), + Widget.Label(name), + ]), + })), + }), + end_widget: Widget.Button({ + class_name: "close", + hpack: "end", + vpack: "start", + child: Widget.Icon(icons.ui.close), + on_clicked: () => App.closeWindow("settings-dialog"), + }), +}) + +const PagesStack = () => Widget.Stack({ + transition: "slide_left_right", + children: layout.reduce((obj, page) => ({ ...obj, [page.attribute.name]: page }), {}), + shown: current.bind() as never, +}) + +export default () => RegularWindow({ + name: "settings-dialog", + class_name: "settings-dialog", + title: "Settings", + setup(win) { + win.on("delete-event", () => { + win.hide() + return true + }) + win.set_default_size(500, 600) + }, + child: Widget.Box({ + vertical: true, + children: [ + Header(), + PagesStack(), + ], + }), +}) diff --git a/linux/home/.config/ags/widget/settings/Wallpaper.ts b/linux/home/.config/ags/widget/settings/Wallpaper.ts new file mode 100644 index 0000000..998f3b7 --- /dev/null +++ b/linux/home/.config/ags/widget/settings/Wallpaper.ts @@ -0,0 +1,31 @@ +import wallpaper from "service/wallpaper" + +export default () => Widget.Box( + { class_name: "row wallpaper" }, + Widget.Box( + { vertical: true }, + Widget.Label({ + xalign: 0, + class_name: "row-title", + label: "Wallpaper", + vpack: "start", + }), + Widget.Button({ + on_clicked: wallpaper.random, + label: "Random", + }), + Widget.FileChooserButton({ + on_file_set: ({ uri }) => wallpaper.set(uri!.replace("file://", "")), + }), + ), + Widget.Box({ hexpand: true }), + Widget.Box({ + class_name: "preview", + css: wallpaper.bind("wallpaper").as(wp => ` + min-height: 120px; + min-width: 200px; + background-image: url('${wp}'); + background-size: cover; + `), + }), +) diff --git a/linux/home/.config/ags/widget/settings/layout.ts b/linux/home/.config/ags/widget/settings/layout.ts new file mode 100644 index 0000000..2b45810 --- /dev/null +++ b/linux/home/.config/ags/widget/settings/layout.ts @@ -0,0 +1,147 @@ +/* eslint-disable max-len */ +import Row from "./Row" +import Group from "./Group" +import Page from "./Page" +import Wallpaper from "./Wallpaper" +import options from "options" +import icons from "lib/icons" + +const { + autotheme: at, + font, + theme, + bar: b, + launcher: l, + overview: ov, + powermenu: pm, + quicksettings: qs, + osd, + hyprland: h, +} = options + +const { + dark, + light, + blur, + scheme, + padding, + spacing, + radius, + shadows, + widget, + border, +} = theme + +export default [ + Page("Theme", icons.ui.themes, + Group("", + Wallpaper() as ReturnType, + Row({ opt: at, title: "Auto Generate Color Scheme" }), + Row({ opt: scheme, title: "Color Scheme", type: "enum", enums: ["dark", "light"] }), + ), + Group("Dark Colors", + Row({ opt: dark.bg, title: "Background", type: "color" }), + Row({ opt: dark.fg, title: "Foreground", type: "color" }), + Row({ opt: dark.primary.bg, title: "Primary", type: "color" }), + Row({ opt: dark.primary.fg, title: "On Primary", type: "color" }), + Row({ opt: dark.error.bg, title: "Error", type: "color" }), + Row({ opt: dark.error.fg, title: "On Error", type: "color" }), + Row({ opt: dark.widget, title: "Widget", type: "color" }), + Row({ opt: dark.border, title: "Border", type: "color" }), + ), + Group("Light Colors", + Row({ opt: light.bg, title: "Background", type: "color" }), + Row({ opt: light.fg, title: "Foreground", type: "color" }), + Row({ opt: light.primary.bg, title: "Primary", type: "color" }), + Row({ opt: light.primary.fg, title: "On Primary", type: "color" }), + Row({ opt: light.error.bg, title: "Error", type: "color" }), + Row({ opt: light.error.fg, title: "On Error", type: "color" }), + Row({ opt: light.widget, title: "Widget", type: "color" }), + Row({ opt: light.border, title: "Border", type: "color" }), + ), + Group("Theme", + Row({ opt: shadows, title: "Shadows" }), + Row({ opt: widget.opacity, title: "Widget Opacity", max: 100 }), + Row({ opt: border.opacity, title: "Border Opacity", max: 100 }), + Row({ opt: border.width, title: "Border Width" }), + Row({ opt: blur, title: "Blur", note: "0 to disable", max: 70 }), + ), + Group("UI", + Row({ opt: padding, title: "Padding" }), + Row({ opt: spacing, title: "Spacing" }), + Row({ opt: radius, title: "Roundness" }), + Row({ opt: font.size, title: "Font Size" }), + Row({ opt: font.name, title: "Font Name", type: "font" }), + ), + ), + Page("Bar", icons.ui.toolbars, + Group("General", + Row({ opt: b.flatButtons, title: "Flat Buttons" }), + Row({ opt: b.position, title: "Position", type: "enum", enums: ["top", "bottom"] }), + Row({ opt: b.corners, title: "Corners" }), + ), + Group("Launcher", + Row({ opt: b.launcher.icon.icon, title: "Icon" }), + Row({ opt: b.launcher.icon.colored, title: "Colored Icon" }), + Row({ opt: b.launcher.label.label, title: "Label" }), + Row({ opt: b.launcher.label.colored, title: "Colored Label" }), + ), + Group("Workspaces", + Row({ opt: b.workspaces.workspaces, title: "Number of Workspaces", note: "0 to make it dynamic" }), + ), + Group("Taskbar", + Row({ opt: b.taskbar.iconSize, title: "Icon Size" }), + Row({ opt: b.taskbar.monochrome, title: "Monochrome" }), + Row({ opt: b.taskbar.exclusive, title: "Exclusive to workspaces" }), + ), + Group("Date", + Row({ opt: b.date.format, title: "Date Format" }), + ), + Group("Media", + Row({ opt: b.media.monochrome, title: "Monochrome" }), + Row({ opt: b.media.preferred, title: "Preferred Player" }), + Row({ opt: b.media.direction, title: "Slide Direction", type: "enum", enums: ["left", "right"] }), + Row({ opt: b.media.format, title: "Format of the Label" }), + Row({ opt: b.media.length, title: "Max Length of Label" }), + ), + Group("Battery", + Row({ opt: b.battery.bar, title: "Style", type: "enum", enums: ["hidden", "regular", "whole"] }), + Row({ opt: b.battery.blocks, title: "Number of Blocks" }), + Row({ opt: b.battery.width, title: "Width of Bar" }), + Row({ opt: b.battery.charging, title: "Charging Color", type: "color" }), + ), + Group("Powermenu", + Row({ opt: b.powermenu.monochrome, title: "Monochrome" }), + ), + ), + Page("General", icons.ui.settings, + Group("Hyprland", + Row({ opt: h.gapsWhenOnly, title: "Gaps When Only" }), + ), + Group("Launcher", + Row({ opt: l.width, title: "Width" }), + Row({ opt: l.apps.iconSize, title: "Icon Size" }), + Row({ opt: l.apps.max, title: "Max Items" }), + ), + Group("Overview", + Row({ opt: ov.scale, title: "Scale", max: 100 }), + Row({ opt: ov.workspaces, title: "Workspaces", max: 11, note: "set this to 0 to make it dynamic" }), + Row({ opt: ov.monochromeIcon, title: "Monochrome Icons" }), + ), + Group("Powermenu", + Row({ opt: pm.layout, title: "Layout", type: "enum", enums: ["box", "line"] }), + Row({ opt: pm.labels, title: "Show Labels" }), + ), + Group("Quicksettings", + Row({ opt: qs.avatar.image, title: "Avatar", type: "img" }), + Row({ opt: qs.avatar.size, title: "Avatar Size" }), + Row({ opt: qs.media.monochromeIcon, title: "Media Monochrome Icons" }), + Row({ opt: qs.media.coverSize, title: "Media Cover Art Size" }), + ), + Group("On Screen Indicator", + Row({ opt: osd.progress.vertical, title: "Vertical" }), + Row({ opt: osd.progress.pack.h, title: "Horizontal Alignment", type: "enum", enums: ["start", "center", "end"] }), + Row({ opt: osd.progress.pack.v, title: "Vertical Alignment", type: "enum", enums: ["start", "center", "end"] }), + ), + ), +] as const diff --git a/linux/home/.config/ags/widget/settings/settingsdialog.scss b/linux/home/.config/ags/widget/settings/settingsdialog.scss new file mode 100644 index 0000000..b8c9820 --- /dev/null +++ b/linux/home/.config/ags/widget/settings/settingsdialog.scss @@ -0,0 +1,144 @@ +window.settings-dialog { + background-color: $bg; + color: $fg; + + .header { + .pager { + @include spacing(.5); + } + + padding: $padding; + + button { + @include button; + font-weight: bold; + padding: $padding*.5 $padding; + + box { + @include spacing($spacing: .3em); + } + } + + button.close { + padding: $padding * .5; + } + + button.reset { + @include button($flat: true); + padding: $padding*.5; + } + } + + .page { + @include scrollable($top: true); + + .page-content { + padding: $padding*2; + padding-top: 0; + } + } + + .group { + .group-title { + color: $primary-bg; + margin-bottom: $spacing*.5; + } + + .group-reset { + @include button($flat: true); + margin: $spacing * .5; + padding: $padding * .5; + + &:disabled { + color: transparent; + } + } + + &:not(:first-child) { + margin-top: $spacing; + } + } + + .row { + background-color: $widget-bg; + padding: $padding; + border: $border; + border-top: none; + + &:first-child { + border-radius: $radius $radius 0 0; + border: $border; + } + + &:last-child { + border-radius: 0 0 $radius $radius; + } + + &:first-child:last-child { + border-radius: $radius; + border: $border; + } + + button.reset { + margin-left: $spacing; + } + + label.id, + label.note { + color: transparentize($fg, .4) + } + + entry, + button { + @include button; + padding: $padding; + } + + switch { + @include switch; + } + + spinbutton { + @include unset; + + entry { + border-radius: $radius 0 0 $radius; + } + + button { + border-radius: 0; + } + + button:last-child { + border-radius: 0 $radius $radius 0; + } + } + + .enum-setter { + label { + background-color: $widget-bg; + border: $border; + padding: 0 $padding; + border-radius: $radius 0 0 $radius; + } + + button { + border-radius: 0; + } + + button:last-child { + border-radius: 0 $radius $radius 0; + } + } + + &.wallpaper { + button { + margin-top: $spacing * .5; + } + + .preview { + border-radius: $radius; + } + } + } +} diff --git a/linux/home/.config/betterlockscreen/betterlockscreenrc b/linux/home/.config/betterlockscreen/betterlockscreenrc new file mode 100644 index 0000000..4cdfbe8 --- /dev/null +++ b/linux/home/.config/betterlockscreen/betterlockscreenrc @@ -0,0 +1,37 @@ +# ~/.config/betterlockscreenrc + +# default options +display_on=0 +span_image=false +lock_timeout=300 +fx_list=(dim blur dimblur pixel dimpixel color) +dim_level=40 +blur_level=1 +pixel_scale=10,1000 +solid_color=333333 +wallpaper_cmd="feh --bg-fill" +quiet=false +# i3lockcolor_bin="i3lock-color" # Manually set command for i3lock-color + +# default theme +loginbox=00000066 +loginshadow=00000000 +locktext="Type password to unlock..." +font="sans-serif" +ringcolor=ffffffff +insidecolor=00000000 +separatorcolor=00000000 +ringvercolor=ffffffff +insidevercolor=00000000 +ringwrongcolor=ffffffff +insidewrongcolor=d23c3dff +timecolor=ffffffff +time_format="%H:%M:%S" +greetercolor=ffffffff +layoutcolor=ffffffff +keyhlcolor=d23c3dff +bshlcolor=d23c3dff +verifcolor=ffffffff +wrongcolor=d23c3dff +modifcolor=d23c3dff +bgcolor=000000ff diff --git a/linux/home/.config/bspwm/bspwmrc b/linux/home/.config/bspwm/bspwmrc new file mode 100755 index 0000000..d30d6db --- /dev/null +++ b/linux/home/.config/bspwm/bspwmrc @@ -0,0 +1,275 @@ +#! /bin/sh + +################################################################################ +# ██████╗ ███████╗██████╗ ██╗ ██╗███╗ ███╗ # +# ██╔══██╗██╔════╝██╔══██╗██║ ██║████╗ ████║ # +# ██████╔╝███████╗██████╔╝██║ █╗ ██║██╔████╔██║ # +# ██╔══██╗╚════██║██╔═══╝ ██║███╗██║██║╚██╔╝██║ # +# ██████╔╝███████║██║ ╚███╔███╔╝██║ ╚═╝ ██║ # +# ╚═════╝ ╚══════╝╚═╝ ╚══╝╚══╝ ╚═╝ ╚═╝ # +################################## By: srdusr ################################## + +# ############################################################################## +# # ENV VARS # +# ############################################################################## + +## Environments +export PATH="${PATH}:${HOME}/.config/bspwm/bin" + +# Get the name of the primary monitor +mainmonitor=$(xrandr --query | awk '/ primary/{print $1}') + +## Monitors +# If no primary monitor is identified, use the first connected monitor +if [ "$mainmonitor" = "" ]; then + mainmonitor=$(xrandr --query | awk '/ connected/ {print $1; exit}') +fi + +# Set up workspaces on the primary monitor +bspc monitor "$mainmonitor" -d 󰲡 󰲣 󰲥 󰲧 󰲩 #1 2 3 4 5 + +# Check the number of connected monitors +connected_monitors=$(xrandr --query | grep -c " connected") + +if [ "$connected_monitors" -gt 1 ]; then + # Get the name of the secondary monitor (exclude the primary monitor) + secondmonitor=$(xrandr --query | awk '/ connected/ && $1 != "'"$mainmonitor"'" {print $1; exit}') + + # Set up workspaces on the secondary monitor + bspc monitor "$secondmonitor" -d 󰲫 󰲭 󰲯 󰲱 󰿭 #6 7 8 9 10 + # Check if the secondary monitor is connected and configure the layout + if [ "$secondmonitor" != "" ]; then + xrandr --output "$mainmonitor" --primary --auto --output "$secondmonitor" --auto --right-of "$mainmonitor" + fi +fi + +#INTERNAL_MONITOR="LVDS-1" +#EXTERNAL_MONITOR="HDMI-1" +## on first load setup default workspaces +#if [[ "$1" = 0 ]]; then +# if [[ $(xrandr -q | grep "${EXTERNAL_MONITOR} connected") ]]; then +# bspc monitor "$EXTERNAL_MONITOR" -d 1 2 3 4 5 +# bspc monitor "$INTERNAL_MONITOR" -d 6 7 8 9 10 +# bspc wm -O "$EXTERNAL_MONITOR" "$INTERNAL_MONITOR" +# else +# bspc monitor "$INTERNAL_MONITOR" -d 1 2 3 4 5 6 7 8 9 10 +# fi +#fi + +# ############################################################################## +# # FUNCTIONS # +# ############################################################################## + +config() { bspc config "$@" & } +rule() { bspc rule -a "$@" & } +run_once() { + if [ ! "$(pgrep -f "$1")" ]; then + "$@" & + fi +} + +# ############################################################################## +# # WINDOW RULES # +# ############################################################################## + +## Rules +bspc rule -r *:* # remove all rules first +rule '*' --one-shot state=below private=border_width:10 +#rule '*:Tiled' --one-shot state=tiled rectangle=50x50+0+50 +#rule '*' --one-shot state=floating rectangle=1028x374+0+50 +#rule \* rectangle=680x700+340+40 +rule '*:*:Picture-in-Picture' state=floating sticky=on layer=above +rule '*:*:Picture in picture' state=floating sticky=on layer=above +rule firefox:Toolkit focus=on state=floating sticky=on layer=above rectangle=400x280+955+475 #320x190+1030+480 #522x316-10+280 +rule "https://www.youtube.com - Enhancer for YouTube™ — Mozilla Firefox" state=floating sticky=on layer=above +rule Wezterm state=floating +rule Zathura state=tiled +rule Pavucontrol state=floating rectangle=490x260+862+37 +rule Blueman-manager state=floating rectangle=536x420+818+37 #490x260-9+37 +rule scratchpad sticky=on state=floating # SCRATCHPAD +rule heads-up-display sticky=on state=floating rectangle=360x160+990+35 # Heads Up Display (scratchpad) +rule Onboard sticky=on state=floating rectangle=700x205+480-89 # Virtual keyboard +rule Plank layer=above border=off +rule Protonvpn state=floating +rule qBittorrent desktop='^2' +rule discord desktop='^4' +rule firefox -o desktop=^1 +rule stalonetray state=floating manage=off +#bspc rule -a Spotify:spotify desktop='^󰲥' state=tiled +#bspc rule -a '*:spotify' desktop='^3' state=tiled + +# ############################################################################## +# # AUTOSTART APPS # +# ############################################################################## + +# Clear cache +#rm "$HOME"/.cache/dunst.log +#rm "$HOME"/.cache/fake_battery_capacity +#rm "$HOME"/.cache/eww-calendar.lock +#rm "$HOME"/.cache/eww-escreen.lock +#rm "$HOME"/.cache/eww-control-center.lock +#rm -r "$HOME"/.cache/dunst/ + +# Autostart applications +#"$HOME"/.config/bspwm/scripts/bspwm_setup_monitors & +pgrep -x sxhkd > /dev/null || sxhkd & +pgrep -x plank > /dev/null || plank & +pgrep -x jgmenu > /dev/null || bspc rule -a jgmenu desktop='^H' state=floating hidden=on && jgmenu --hide-on-startup & +picom --config "$HOME"/.config/picom/picom.conf & +rm "$HOME"/.jgmenu-lockfile +"$HOME"/.config/polybar/launch.sh & +run_once unclutter & # Remove mouse when idle +run_once "$HOME"/.scripts/lockscreen-wallpaper & +run_once xss-lock -- betterlockscreen -l & +nitrogen --force-setter=xinerama --restore & +run_once redshift & +run_once low-bat-notifier & +pkill persistentQuickUtilities.sh; "$HOME"/.config/bspwm/scripts/persistentQuickUtilities.sh & +#xfce4-panel --disable-wm-check & + +# Start polkit agent +#[ "$(pidof xfce-polkit)" != "" ] || /usr/lib/xfce-polkit/xfce-polkit & +run_once /usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 & + +# Volume and brightness indicator (xob) +source "$HOME"/.virtualenvs/bin/activate # Activate virtual environment +run_once "$HOME"/.config/xob/launch.sh & +deactivate # Deactivate virtual environment + +# Eww +pkill eww +eww daemon + +xset m 0 0 # Disable mouse drift + +pgrep -x plank.sh > /dev/null || plank.sh & + +#wmname LG3D # Fixes Java applications +# Solve java apps issues (e.g. JetBrains IDEs like PyCharm, CLion, etc). # +#export _JAVA_AWT_WM_NONREPARENTING=1 + +#export QT_QPA_PLATFORMTHEME="qt5ct" # Use qt5ct to set Qt theme + +# Start MPD and mpDris2 +#exec mpd & +#exec mpDris2 & + +# Systray +#run_once signal-desktop --start-in-tray & #--use-tray-icon +#run_once onboard --not-show-in=DESKTOPS & +if ! pgrep -x "stalonetray" > /dev/null; then + stalonetray & +fi + +declare -a restart=(clipit blueman-applet caffeine) +for i in "${restart[@]}"; do + pgrep -x "$i" | xargs kill + sleep 0.5 + eval "$i" & +done + +while ! pgrep -x "clipit" > /dev/null || ! pgrep -x "blueman-applet" > /dev/null || ! pgrep -x "caffeine" > /dev/null; do + #sleep 0.5 + systray & +done +xdo hide -N stalonetray +touch "/tmp/syshide.lock" + +# ############################################################################## +# # CONFIGURATION # +# ############################################################################## + +## Config +PANEL_HEIGHT=24 +config top_padding "$PANEL_HEIGHT" +config honor_size_hints true +config automatic_scheme alternate +config initial_polarity second_child +config pointer_modifier mod4 +config click_to_focus none +config pointer_action1 move +config pointer_action2 resize_side +config pointer_action3 resize_corner +config focus_follows_pointer true +config remove_disabled_monitors true +config remove_unplugged_monitors true +config merge_overlapping_monitors true +config border_width 4 +config border_radius 10 +config window_gap 10 +config split_ratio 0.52 +config borderless_monocle true +config gapless_monocle true +config swallow_first_click false +config normal_border_color "#000000" +config focused_border_color "#000000" +config active_border_color "#000000" +config presel_feedback_color "#BF616A" + +# ############################################################################## +# # MISCELLANEOUS # +# ############################################################################## + +## Fullscreen +bspc subscribe node_state | while read -r _ _ _ _ state flag; do + if [[ "$state" != fullscreen ]]; then continue; fi + if [[ "$flag" == on ]]; then + xdo lower -N Plank + #"$(which eww)" -c "$HOME"/.config/eww close-all + else + xdo raise -N Plank + #"$(which eww)" -c "$HOME"/.config/eww open bar + fi +done & + +## Title-bar +rm -rf /tmp/title-bar_debug.log +rm -rf /tmp/title-bar.lock + +processes=("title-bar" "update-title" "lemonbar") + +for process in "${processes[@]}"; do + if pidof -q "$process"; then + pkill -x "$process" > /dev/null; sleep 0.1 + fi +done + +# Check if title-bar is already running +if ! pgrep -x "title-bar" >/dev/null; then + # Create a lock file + lockfile="/tmp/title-bar.lock" + + # Check if the lock file exists + if [ ! -e "$lockfile" ]; then + # Create the lock file + touch "$lockfile" + + # Function to handle BSPWM events + handle_bspwm_events() { + while read; do + if ! pgrep -x "title-bar" >/dev/null; then + bash "$HOME/.scripts/title-bar" & + fi + done + } + + # Start bspc subscribe in the background and pass events to the handler function + bspc subscribe | handle_bspwm_events & + + # Remove the lock file when the script exits + trap 'rm -f "$lockfile"' EXIT + else + echo "title-bar is already running." + fi +fi + +start_dunst() { + # stop dunst if it has been started by any application that called notify-send + killall -q dunst + # Wait until the processes have been shut down + while pgrep -u "$UID" -x dunst >/dev/null; do sleep .05; done + while ! pgrep -u "$UID" -x dunst >/dev/null; do sleep .05; done +} +start_dunst & + +config external_rules_command ~/.config/bspwm/scripts/external_rules.sh & diff --git a/linux/home/.config/bspwm/scripts/bspdragtofloat b/linux/home/.config/bspwm/scripts/bspdragtofloat new file mode 100755 index 0000000..e2f88a2 --- /dev/null +++ b/linux/home/.config/bspwm/scripts/bspdragtofloat @@ -0,0 +1,46 @@ +#!/bin/env bash + +: "${BSPWM_DIR:="${XDG_CONFIG_HOME:-$HOME/.config}/bspwm"}" + +status_file="$BSPWM_DIR/tmp/drag_to_float" + +[[ "$1" = stop ]] && { + [[ -e "$status_file" ]] \ + && rm -r -- "$status_file" + exit +} + +[[ -e "$status_file" ]] \ + && exit + +< <(bspc query -T -n pointed.window | jq -r '"\(.id) \(.client.state)"') read -r node node_state + +[[ -z "$node" ]] \ + && exit + +case "$node_state" in + floating) + ;; + tiled|pseudo_tiled) + node_tiled_rect=($(bspc query -T -n "$node" | jq -r '.client.tiledRectangle[]')) + bspc node "$node" -t floating + xdo move -x "${node_tiled_rect[0]}" -y "${node_tiled_rect[1]}" "$node" + xdo resize -w "${node_tiled_rect[2]}" -h "${node_tiled_rect[3]}" "$node" ;; + *) # fullscreen + exit ;; +esac + +eval "$(xdotool getmouselocation --shell)" +x="$X" y="$Y" +touch -- "$status_file" +while [[ -e "$status_file" ]]; do + eval "$(xdotool getmouselocation --shell)" + (( X != x || Y != y )) && { + bspc node "$node" -v "$((X - x))" "$((Y - y))" + x="$X" y="$Y" + } + sleep .01 +done + +[[ -e "$status_file" ]] \ + && rm -r -- "$status_file" diff --git a/linux/home/.config/bspwm/scripts/bspswallow b/linux/home/.config/bspwm/scripts/bspswallow new file mode 100755 index 0000000..dea343f --- /dev/null +++ b/linux/home/.config/bspwm/scripts/bspswallow @@ -0,0 +1,12 @@ +#!/bin/bash + +NODE_CURRENT=$(bspc query -N -n focused) +$@ & +PID_COMMAND=$! +WATCH=$(bspc subscribe -c 1 node_add) +NODE_NEW=${WATCH%% *} +bspc node -s $NODE_CURRENT +bspc node $NODE_CURRENT --flag hidden=on +wait $PID_COMMAND +bspc node $NODE_CURRENT --flag hidden=off +bspc node $NODE_CURRENT --focus diff --git a/linux/home/.config/bspwm/scripts/bspwindows b/linux/home/.config/bspwm/scripts/bspwindows new file mode 100755 index 0000000..26deeab --- /dev/null +++ b/linux/home/.config/bspwm/scripts/bspwindows @@ -0,0 +1,14 @@ +#!/bin/sh +# bspwindows +# get targets for drawing borders/whatever on in bspwm + +target="${1:-active}" + +case "$target" in + active) + bspc query -N -n .local.descendant_of.window.leaf.!fullscreen + ;; + inactive) + bspc query -N -n .local.!descendant_of.window.leaf.!fullscreen + ;; +esac diff --git a/linux/home/.config/bspwm/scripts/bspwm-monitor-setup b/linux/home/.config/bspwm/scripts/bspwm-monitor-setup new file mode 100755 index 0000000..6e38bb7 --- /dev/null +++ b/linux/home/.config/bspwm/scripts/bspwm-monitor-setup @@ -0,0 +1,59 @@ +#!/usr/bin/env bash + +INTERNAL_MONITOR="eDP" +EXTERNAL_MONITOR="HDMI-A-0" + +monitor_add() { + # Move first 5 desktops to external monitor + for desktop in $(bspc query -D --names -m "$INTERNAL_MONITOR" | sed 5q); do + bspc desktop "$desktop" --to-monitor "$EXTERNAL_MONITOR" + done + # Remove default desktop created by bspwm + bspc desktop Desktop --remove + # reorder monitors + bspc wm -O "$EXTERNAL_MONITOR" "$INTERNAL_MONITOR" +} + +monitor_remove() { + # Add default temp desktop because a minimum of one desktop is required per monitor + bspc monitor "$EXTERNAL_MONITOR" -a Desktop + + # Move all desktops except the last default desktop to internal monitor + for desktop in $(bspc query -D -m "$EXTERNAL_MONITOR"); do + bspc desktop "$desktop" --to-monitor "$INTERNAL_MONITOR" + done + + # delete default desktops + bspc desktop Desktop --remove + # reorder desktops + bspc monitor "$INTERNAL_MONITOR" -o 1 2 3 4 5 6 7 8 9 10 +} + +if [[ $(xrandr -q | grep "${EXTERNAL_MONITOR} connected") ]]; then + # set xrandr rules for docked setup + xrandr --output "$INTERNAL_MONITOR" --mode 1920x1080 --pos 0x0 --rotate normal --output "$EXTERNAL_MONITOR" --primary --mode 1920x1080 --pos 1920x780 --rotate normal + if [[ $(bspc query -D -m "${EXTERNAL_MONITOR}" | wc -l) -ne 5 ]]; then + monitor_add + fi + bspc wm -O "$EXTERNAL_MONITOR" "$INTERNAL_MONITOR" +else + # set xrandr rules for mobile setup + xrandr --output "$INTERNAL_MONITOR" --primary --mode 1920x1080 --pos 0x0 --rotate normal --output "$EXTERNAL_MONITOR" --off + if [[ $(bspc query -D -m "${INTERNAL_MONITOR}" | wc -l) -ne 10 ]]; then + monitor_remove + fi +fi + +# Set wallpaper +~/.local/bin/setbg.sh & + +# Kill and relaunch polybar +kill -9 $(pgrep -f 'polybar') >/dev/null 2>&1 +polybar-msg cmd quit >/dev/null 2>&1 +while pgrep -u $UID -x polybar >/dev/null; do sleep 1; done +if [[ $(xrandr -q | grep "${EXTERNAL_MONITOR} connected") ]]; then + polybar --reload primary -c ~/.config/polybar/config.ini /var/tmp/polybar-primary.log 2>&1 200>&- & + polybar --reload secondary -c ~/.config/polybar/config.ini /var/tmp/polybar-secondary.log 2>&1 200>&- & +else + polybar --reload primary -c ~/.config/polybar/config.ini /var/tmp/polybar-primary.log 2>&1 200>&- & +fi diff --git a/linux/home/.config/bspwm/scripts/bspwm-toggle-visibility.sh b/linux/home/.config/bspwm/scripts/bspwm-toggle-visibility.sh new file mode 100755 index 0000000..45a4c53 --- /dev/null +++ b/linux/home/.config/bspwm/scripts/bspwm-toggle-visibility.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# Created By: srdusr +# Created On: Mon 18 Sep 2023 18:37:21 CAT +# Project: Bspwm script to toggle visibility of initial window and bring focus back to it + +# Get the ID of the currently focused desktop +current_desktop_id=$(bspc query -D -d focused --names) + +# Get the ID of the first hidden window in the current desktop +hidden_window_id=$(bspc query -N -d "$current_desktop_id" -n .hidden | head -n 1) + +# Check if there's a hidden window in the current desktop +if [[ -n "$hidden_window_id" ]]; then + # There's a hidden window, so unhide it + bspc node "$hidden_window_id" -g hidden=off + # Bring focus back to the previously hidden window + bspc node -f "$hidden_window_id" +else + # There's no hidden window in the current desktop, hide the first available window + first_window_id=$(bspc query -N -n focused.window) + bspc node "$first_window_id" -g hidden=on +fi diff --git a/linux/home/.config/bspwm/scripts/close-window b/linux/home/.config/bspwm/scripts/close-window new file mode 100755 index 0000000..8f7f36b --- /dev/null +++ b/linux/home/.config/bspwm/scripts/close-window @@ -0,0 +1,11 @@ +#!/bin/sh +# +# close or kill a bspwm window + +# show wallpaper if last tile +bspc query -N -n .focused.tiled.window &> /dev/null \ + && ! bspc query -N -n .!focused.local.tiled.window &> /dev/null \ + && show-wallpaper -d + +# close focused window +[ "$1" = "kill" ] && bspc node -k || bspc node -c diff --git a/linux/home/.config/bspwm/scripts/drag-float b/linux/home/.config/bspwm/scripts/drag-float new file mode 100755 index 0000000..788e978 --- /dev/null +++ b/linux/home/.config/bspwm/scripts/drag-float @@ -0,0 +1,42 @@ +#!/bin/env bash + +: "${BUTTON:=1}" + +node="$(bspc query -N -n pointed)" + +die() { + jobs -p | xargs -r -n1 -I{} kill {} + exit +} + +trap 'die' USR1 + +{ bspc subscribe node_focus | while read -r _ _ _ wid; do + (( wid != node )) && break; done; kill -USR1 "$$" ;} & +{ while xinput list \ + | sed -nE 's,.*id=([0-9]+).*slave\s+pointer.*,\1,p' \ + | xargs -r -n1 -I{} xinput query-state {} 2> /dev/null \ + | grep -qF "button[${BUTTON}]=down"; do sleep .3; done; kill -USR1 "$$" ;} & + +if bspc node "$node.tiled" -f; then + node_tiled_rect=($(bspc query -T -n "$node" | jq -r '.client.tiledRectangle[]')) + bspc node "$node" -t floating + xdo move -x "${node_tiled_rect[0]}" -y "${node_tiled_rect[1]}" "$node" + xdo resize -w "${node_tiled_rect[2]}" -h "${node_tiled_rect[3]}" "$node" +elif bspc node "$node.floating" -f; then + : +else + die +fi + +eval "$(xdotool getmouselocation --shell)" +x="$X" y="$Y" +while :; do + eval "$(xdotool getmouselocation --shell)" + (( X != x || Y != y )) && { + bspc node "$node" -v "$((X - x))" "$((Y - y))" + x="$X" y="$Y" + } +done + +wait diff --git a/linux/home/.config/bspwm/scripts/external_rules.sh b/linux/home/.config/bspwm/scripts/external_rules.sh new file mode 100755 index 0000000..7b07ae8 --- /dev/null +++ b/linux/home/.config/bspwm/scripts/external_rules.sh @@ -0,0 +1,71 @@ +#!/bin/env bash +# +# external_rules_command +# +# Absolute path to the command used to retrieve rule consequences. +# The command will receive the following arguments: window ID, class +# name, instance name, and intermediate consequences. The output of +# that command must have the following format: key1=value1 +# key2=value2 ... (the valid key/value pairs are given in the +# description of the rule command). +# +# +# Rule +# General Syntax +# rule COMMANDS +# +# Commands +# -a, --add (|*)[:(|*)] [-o|--one-shot] +# [monitor=MONITOR_SEL|desktop=DESKTOP_SEL|node=NODE_SEL] +# [state=STATE] [layer=LAYER] [split_dir=DIR] [split_ratio=RATIO] +# [(hidden|sticky|private|locked|marked|center|follow|manage|focus|border)=(on|off)] +# [rectangle=WxH+X+Y] +# Create a new rule. +# +# -r, --remove +# ^|head|tail|(|*)[:(|*)]... +# Remove the given rules. +# +# -l, --list +# List the rules. + +# Programs to specific desktops +wid=$1 +class=$2 +instance=$3 +consequences=$4 + +main() { + case "$class" in + firefox) + if [ "$instance" = "Toolkit" ]; then + echo "state=floating sticky=on" + fi + ;; + Spotify) + echo desktop=^5 follow=on focus=on + ;; + "") + sleep 0.5 + + wm_class=("$(xprop -id "$wid" | grep "WM_CLASS" | grep -Po '"\K[^,"]+')") + + class=${wm_class[-1]} + + [[ ${#wm_class[@]} == "2" ]] && instance=${wm_class[0]} + + [[ -n "$class" ]] && main + ;; + esac +} + +main + +# Allow floating windows over fullscreen +wid="$1" +class="$2" +instance="$3" +eval "$4" + +[[ "$state" = floating ]] && + echo 'layer=above' diff --git a/linux/home/.config/bspwm/scripts/hide-window b/linux/home/.config/bspwm/scripts/hide-window new file mode 100755 index 0000000..c350a0e --- /dev/null +++ b/linux/home/.config/bspwm/scripts/hide-window @@ -0,0 +1,38 @@ +#!/bin/bash + +CMD=${1:-help} +shift + +help() { + echo "Available commands:" + echo " * unhide - select and unhide window" +} + +unhide() { + action=${1:-list} + case $action in + "list") + selection=$(for id in "$(bspc query -N -n .hidden)"; do + title=$(xtitle "$id") + [[ -z "$title" ]] && title="" + echo "$id" "$title" + done | rofi -dmenu -i -p "Hidden windows" | cut -f1 -d' ') + + [[ -z "$selection" ]] && exit 1 + + bspc node "$selection" -g hidden=off + ;; + esac + } + + case $CMD in + "help") + help + ;; + "unhide") + unhide "$1" + ;; + *) + help + ;; + esac diff --git a/linux/home/.config/dunst/assets/notification/fallback.png b/linux/home/.config/dunst/assets/notification/fallback.png new file mode 100644 index 0000000..204aeda Binary files /dev/null and b/linux/home/.config/dunst/assets/notification/fallback.png differ diff --git a/linux/home/.config/dunst/assets/notification/music.png b/linux/home/.config/dunst/assets/notification/music.png new file mode 100644 index 0000000..ae91be3 Binary files /dev/null and b/linux/home/.config/dunst/assets/notification/music.png differ diff --git a/linux/home/.config/dunst/assets/notification/scrot.png b/linux/home/.config/dunst/assets/notification/scrot.png new file mode 100644 index 0000000..1e12f38 Binary files /dev/null and b/linux/home/.config/dunst/assets/notification/scrot.png differ diff --git a/linux/home/.config/dunst/assets/ui/volume-high.svg b/linux/home/.config/dunst/assets/ui/volume-high.svg new file mode 100644 index 0000000..43152c9 --- /dev/null +++ b/linux/home/.config/dunst/assets/ui/volume-high.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/linux/home/.config/dunst/assets/ui/volume-low.svg b/linux/home/.config/dunst/assets/ui/volume-low.svg new file mode 100644 index 0000000..09b3650 --- /dev/null +++ b/linux/home/.config/dunst/assets/ui/volume-low.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/linux/home/.config/dunst/assets/ui/volume-medium.svg b/linux/home/.config/dunst/assets/ui/volume-medium.svg new file mode 100644 index 0000000..6b3c1fa --- /dev/null +++ b/linux/home/.config/dunst/assets/ui/volume-medium.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/linux/home/.config/dunst/assets/ui/volume-muted.svg b/linux/home/.config/dunst/assets/ui/volume-muted.svg new file mode 100644 index 0000000..50434d4 --- /dev/null +++ b/linux/home/.config/dunst/assets/ui/volume-muted.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/linux/home/.config/dunst/dunstrc b/linux/home/.config/dunst/dunstrc new file mode 100644 index 0000000..8989a2d --- /dev/null +++ b/linux/home/.config/dunst/dunstrc @@ -0,0 +1,456 @@ +# See dunst(5) for all configuration options + +[global] + ### Display ### + + # Which monitor should the notifications be displayed on. + monitor = 0 + + # Display notification on focused monitor. Possible modes are: + # mouse: follow mouse pointer + # keyboard: follow window with keyboard focus + # none: don't follow anything + # + # "keyboard" needs a window manager that exports the + # _NET_ACTIVE_WINDOW property. + # This should be the case for almost all modern window managers. + # + # If this option is set to mouse or keyboard, the monitor option + # will be ignored. + follow = none + + ### Geometry ### + + # dynamic width from 0 to 300 + width = (200, 300) + # constant width of 300 + # width = 300 + + # The maximum height of a single notification, excluding the frame. + height = 300 + + # Position the notification in the top right corner + origin = bottom-right + + # Offset from the origin + offset = 6x30 + # offset = 10x35 # i3 gaps = 20x20 + # (H_Right_Gap/2) x (25+V_Bottom_Gap/2) + + # Scale factor. It is auto-detected if value is 0. + scale = 0 + + # Maximum number of notification (0 means no limit) + notification_limit = 0 + + ### Progress bar ### + + # Turn on the progess bar. It appears when a progress hint is passed with + # for example dunstify -h int:value:12 + progress_bar = true + + # Set the progress bar height. This includes the frame, so make sure + # it's at least twice as big as the frame width. + progress_bar_height = 10 + + # Set the frame width of the progress bar + progress_bar_frame_width = 1 + + # Set the minimum width for the progress bar + progress_bar_min_width = 150 + + # Set the maximum width for the progress bar + progress_bar_max_width = 300 + + # Show how many messages are currently hidden (because of + # notification_limit). + indicate_hidden = yes + + # The transparency of the window. Range: [0; 100]. + # This option will only work if a compositing window manager is + # present (e.g. xcompmgr, compiz, etc.). (X11 only) + transparency = 0 + + # Draw a line of "separator_height" pixel height between two + # notifications. + # Set to 0 to disable. + separator_height = 2 + + # Padding between text and separator. + padding = 11 + + # Horizontal padding. + horizontal_padding = 11 + + # Padding between text and icon. + text_icon_padding = 0 + + # Defines width in pixels of frame around the notification window. + # Set to 0 to disable. + frame_width = 2 + + # Define a color for the separator. + # possible values are: + # * auto: dunst tries to find a color fitting to the background; + # * foreground: use the same color as the foreground; + # * frame: use the same color as the frame; + # * anything else will be interpreted as a X color. + separator_color = "#1a1b26" + + # Sort messages by urgency. + sort = yes + + # Don't remove messages, if the user is idle (no mouse or keyboard input) + # for longer than idle_threshold seconds. + # Set to 0 to disable. + # A client can set the 'transient' hint to bypass this. See the rules + # section for how to disable this if necessary + idle_threshold = 120 + + ### Text ### + + font = JetBrainsMono Nerd Font Medium 9 + + # The spacing between lines. If the height is smaller than the + # font height, it will get raised to the font height. + line_height = 5 + + # Possible values are: + # full: Allow a small subset of html markup in notifications: + # bold + # italic + # strikethrough + # underline + # + # For a complete reference see + # . + # + # strip: This setting is provided for compatibility with some broken + # clients that send markup even though it's not enabled on the + # server. Dunst will try to strip the markup but the parsing is + # simplistic so using this option outside of matching rules for + # specific applications *IS GREATLY DISCOURAGED*. + # + # no: Disable markup parsing, incoming notifications will be treated as + # plain text. Dunst will not advertise that it has the body-markup + # capability if this is set as a global setting. + # + # It's important to note that markup inside the format option will be parsed + # regardless of what this is set to. + markup = full + + # The format of the message. Possible variables are: + # %a appname + # %s summary + # %b body + # %i iconname (including its path) + # %I iconname (without its path) + # %p progress value if set ([ 0%] to [100%]) or nothing + # %n progress value if set without any extra characters + # %% Literal % + # Markup is allowed + format = "%s\n%b" + + # Alignment of message text. + # Possible values are "left", "center" and "right". + alignment = center + + # Vertical alignment of message text and icon. + # Possible values are "top", "center" and "bottom". + vertical_alignment = center + + # Show age of message if message is older than show_age_threshold + # seconds. + # Set to -1 to disable. + show_age_threshold = 60 + + # Specify where to make an ellipsis in long lines. + # Possible values are "start", "middle" and "end". + ellipsize = middle + + # Ignore newlines '\n' in notifications. + ignore_newline = no + + # Stack together notifications with the same content + stack_duplicates = true + + # Hide the count of stacked notifications with the same content + hide_duplicate_count = true + + # Display indicators for URLs (U) and actions (A). + show_indicators = yes + + ### Icons ### + + # Align icons left/right/off + icon_position = left + + # Scale small icons up to this size, set to 0 to disable. Helpful + # for e.g. small files or high-dpi screens. In case of conflict, + # max_icon_size takes precedence over this. + min_icon_size = 0 + + # Scale larger icons down to this size, set to 0 to disable + max_icon_size = 32 + + # Paths to default icons. + #icon_path = /usr/share/icons/gnome/16x16/status/:/usr/share/icons/gnome/16x16/devices/ + #icon_path = /usr/share/icons/Qogir/16/status:/usr/share/icons/Qogir/16/devices/:/usr/share/icons/Qogir/16/apps/:/usr/share/pixmaps/ + icon_path = /usr/share/icons/gnome/16x16/status/:/usr/share/icons/gnome/16x16/devices/ + + ### History ### + + # Should a notification popped up from history be sticky or timeout + # as if it would normally do. + sticky_history = yes + + #history_file = ~/.cache/dunst/history + + # Maximum amount of notifications kept in history + rhistory_length = 100 + + ### Misc/Advanced ### + + # dmenu path. + dmenu = /usr/bin/dmenu -p dunst: + + # Browser for opening urls in context menu. + browser = /usr/bin/brave + + # Always run rule-defined scripts, even if the notification is suppressed + always_run_script = true + + # Define the title of the windows spawned by dunst + title = Dunst + + # Define the class of the windows spawned by dunst + class = Dunst + + # Define the corner radius of the notification window + # in pixel size. If the radius is 0, you have no rounded + # corners. + # The radius will be automatically lowered if it exceeds half of the + # notification height to avoid clipping text and/or icons. + corner_radius = 10 + + # Ignore the dbus closeNotification message. + # Useful to enforce the timeout set by dunst configuration. Without this + # parameter, an application may close the notification sent before the + # user defined timeout. + ignore_dbusclose = false + + ### Wayland ### + # These settings are Wayland-specific. They have no effect when using X11 + + # Uncomment this if you want to let notications appear under fullscreen + # applications (default: overlay) + # layer = top + + # Set this to true to use X11 output on Wayland. + force_xwayland = false + + ### Legacy + + # Use the Xinerama extension instead of RandR for multi-monitor support. + # This setting is provided for compatibility with older nVidia drivers that + # do not support RandR and using it on systems that support RandR is highly + # discouraged. + # + # By enabling this setting dunst will not be able to detect when a monitor + # is connected or disconnected which might break follow mode if the screen + # layout changes. + force_xinerama = false + + ### mouse + + # Defines list of actions for each mouse event + # Possible values are: + # * none: Don't do anything. + # * do_action: Invoke the action determined by the action_name rule. If there is no + # such action, open the context menu. + # * open_url: If the notification has exactly one url, open it. If there are multiple + # ones, open the context menu. + # * close_current: Close current notification. + # * close_all: Close all notifications. + # * context: Open context menu for the notification. + # * context_all: Open context menu for all notifications. + # These values can be strung together for each mouse event, and + # will be executed in sequence. + mouse_left_click = close_current + mouse_middle_click = do_action, close_current + mouse_right_click = close_all + +# Experimental features that may or may not work correctly. Do not expect them +# to have a consistent behaviour across releases. +[experimental] + # Calculate the dpi to use on a per-monitor basis. + # If this setting is enabled the Xft.dpi value will be ignored and instead + # dunst will attempt to calculate an appropriate dpi value for each monitor + # using the resolution and physical size. This might be useful in setups + # where there are multiple screens with very different dpi values. + per_monitor_dpi = false + +# Every section that isn't one of the above is interpreted as a rules to +# override settings for certain messages. +# +# Messages can be matched by +# appname (discouraged, see desktop_entry) +# body +# category +# desktop_entry +# icon +# match_transient +# msg_urgency +# stack_tag +# summary +# +# and you can override the +# background +# foreground +# format +# frame_color +# fullscreen +# new_icon +# set_stack_tag +# set_transient +# set_category +# timeout +# urgency +# skip_display +# history_ignore +# action_name +# word_wrap +# ellipsize +# alignment +# +# Shell-like globbing will get expanded. +# +# Instead of the appname filter, it's recommended to use the desktop_entry filter. +# GLib based applications export their desktop-entry name. In comparison to the appname, +# the desktop-entry won't get localized. +# +# SCRIPTING +# You can specify a script that gets run when the rule matches by +# setting the "script" option. +# The script will be called as follows: +# script appname summary body icon urgency +# where urgency can be "LOW", "NORMAL" or "CRITICAL". +# +# NOTE: It might be helpful to run dunst -print in a terminal in order +# to find fitting options for rules. + +# Disable the transient hint so that idle_threshold cannot be bypassed from the +# client +#[transient_disable] +# match_transient = yes +# set_transient = no +# +# Make the handling of transient notifications more strict by making them not +# be placed in history. +#[transient_history_ignore] +# match_transient = yes +# history_ignore = yes + +# fullscreen values +# show: show the notifications, regardless if there is a fullscreen window opened +# delay: displays the new notification, if there is no fullscreen window active +# If the notification is already drawn, it won't get undrawn. +# pushback: same as delay, but when switching into fullscreen, the notification will get +# withdrawn from screen again and will get delayed like a new notification +#[fullscreen_delay_everything] +# fullscreen = delay +[fullscreen_show_critical] + msg_urgency = critical + fullscreen = show +[fullscreen_show_normal] + msg_urgency = normal + fullscreen = show + + +#[espeak] +# summary = "*" +# script = dunst_espeak.sh + +#[script-test] +# summary = "*script*" +# script = dunst_test.sh + +#[ignore] +# # This notification will not be displayed +# summary = "foobar" +# skip_display = true + +#[history-ignore] +# # This notification will not be saved in history +# summary = "foobar" +# history_ignore = yes + +#[skip-display] +# # This notification will not be displayed, but will be included in the history +# summary = "foobar" +# skip_display = yes + +#[signed_on] +# appname = Pidgin +# summary = "*signed on*" +# urgency = low +# +#[signed_off] +# appname = Pidgin +# summary = *signed off* +# urgency = low +# +#[says] +# appname = Pidgin +# summary = *says* +# urgency = critical +# +#[twitter] +# appname = Pidgin +# summary = *twitter.com* +# urgency = normal +# + +[openEwwPopup] + script = ~/.config/dunst/scripts/openEwwPopup.sh + +[songArtLogger] + script = ~/.config/dunst/scripts/songArtLogger.sh + +[stack-volumes] + appname = "some_volume_notifiers" + set_stack_tag = "volume" + +[flameshot-urgency] + appname = flameshot + urgency = low + +[whatsapp-alignment] + appname = whatsapp-nativefier-d40211 + alignment = left + +[discord-alignment] + appname = discord + alignment = left + +[signal-alignment] + appname = Signal + alignment = left + +[urgency_low] + background = "#16161e" + foreground = "#c0caf5" + frame_color = "#1f2335" + timeout = 3 + +[urgency_normal] + background = "#16161e" + foreground = "#c0caf5" + frame_color = "#3d59a1" + timeout = 15 + +[urgency_critical] + background = "#191D24" + foreground = "#c0caf5" + frame_color = "#db4b4b" + timeout = 60 diff --git a/linux/home/.config/dunst/scripts/openEwwPopup.sh b/linux/home/.config/dunst/scripts/openEwwPopup.sh new file mode 100755 index 0000000..d22e981 --- /dev/null +++ b/linux/home/.config/dunst/scripts/openEwwPopup.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +DND_LOCK_FILE="$HOME/.cache/dnd-lock.lock" +EWW_BIN="$HOME/.local/bin/eww" + +finish() { + ${EWW_BIN} update noti=false; sleep 0.075 + ${EWW_BIN} close notification-popup +} + +# Run eww daemon if not running +if [[ ! `pidof eww` ]]; then + ${EWW_BIN} daemon + sleep 1 +else + if [[ ! -f "$DND_LOCK_FILE" ]]; then + KILLED=false + for pid in $(pidof -x openEwwPopup.sh); do + if [ $pid != $$ ]; then + kill -9 $pid + KILLED=true + fi + done >/dev/nullx + + if ! $KILLED; then + sleep 0.5 + ${EWW_BIN} update noti=true + ${EWW_BIN} open notification-popup + canberra-gtk-play -i message + fi + + sleep 5 + finish + unset KILLED + fi +fi diff --git a/linux/home/.config/dunst/scripts/songArtLogger.sh b/linux/home/.config/dunst/scripts/songArtLogger.sh new file mode 100755 index 0000000..f73beb4 --- /dev/null +++ b/linux/home/.config/dunst/scripts/songArtLogger.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +TMP_DIR="$HOME/.cache/dunst" +TMP_COVER_PATH="$TMP_DIR/$DUNST_SUMMARY.png" +TMP_TEMP_PATH="$TMP_DIR/temp.png" + +if [ ! -d "$TMP_DIR" ]; then + mkdir -p "$TMP_DIR" +fi + +ART_FROM_SPOTIFY="$(playerctl -p %any,spotify metadata mpris:artUrl | sed -e 's/open.spotify.com/i.scdn.co/g')" + +if [[ $(playerctl -p spotify,%any,firefox,chromium,brave,mpd metadata mpris:artUrl) ]]; then + curl -s "$ART_FROM_SPOTIFY" --output "$TMP_COVER_PATH" +fi + +cp "$TMP_TEMP_PATH" "$TMP_COVER_PATH" \ No newline at end of file diff --git a/linux/home/.config/eww/eww.scss b/linux/home/.config/eww/eww.scss new file mode 100644 index 0000000..9405a6a --- /dev/null +++ b/linux/home/.config/eww/eww.scss @@ -0,0 +1,11 @@ +@import "./src/scss/variables"; +@import "./src/scss/overrides"; +@import "./src/scss/modules"; + +@import "./src/scss/bar/index.scss"; +@import "./src/scss/control-center/index.scss"; +@import "./src/scss/exitscreen/index.scss"; +@import "./src/scss/info-center/index.scss"; +@import "./src/scss/lockscreen/index.scss"; +@import "./src/scss/notification-center/index.scss"; +@import "./src/scss/notification-popup/index.scss"; diff --git a/linux/home/.config/eww/eww.yuck b/linux/home/.config/eww/eww.yuck new file mode 100644 index 0000000..191b30c --- /dev/null +++ b/linux/home/.config/eww/eww.yuck @@ -0,0 +1,23 @@ +(include "./src/yuck/_variables.yuck") +(include "./src/yuck/_modules.yuck") + +(include "./src/yuck/bar/_widgets.yuck") +(include "./src/yuck/bar/_windows.yuck") + +(include "./src/yuck/control-center/_widgets.yuck") +(include "./src/yuck/control-center/_windows.yuck") + +(include "./src/yuck/exitscreen/_widgets.yuck") +(include "./src/yuck/exitscreen/_windows.yuck") + +(include "./src/yuck/info-center/_widgets.yuck") +(include "./src/yuck/info-center/_windows.yuck") + +(include "./src/yuck/lockscreen/_widgets.yuck") +(include "./src/yuck/lockscreen/_windows.yuck") + +(include "./src/yuck/notification-center/_widgets.yuck") +(include "./src/yuck/notification-center/_windows.yuck") + +(include "./src/yuck/notification-popup/_widgets.yuck") +(include "./src/yuck/notification-popup/_windows.yuck") diff --git a/linux/home/.config/hypr/autostart b/linux/home/.config/hypr/autostart new file mode 100755 index 0000000..2805e42 --- /dev/null +++ b/linux/home/.config/hypr/autostart @@ -0,0 +1,34 @@ +#!/usr/bin/bash + +# Policy Authentication Agent +/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1 & + +eval "$(/usr/bin/gnome-keyring-daemon --start --components=gpg,pkcs11,secrets,ssh)" +export "$(gnome-keyring-daemon --start --components=gpg,pkcs11,secrets,ssh)" + +# Setup Environment +systemctl --user import-environment WAYLAND_DISPLAY XDG_CURRENT_DESKTOP & +dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY XDG_CURRENT_DESKTOP --all & +#dbus-update-activation-environment DISPLAY XAUTHORITY WAYLAND_DISPLAY & + +# variables +scripts=~/.scripts + +# gsettings +#gsettings set org.gnome.desktop.interface gtk-theme 'Tokyonight-Dark-BL-LB' +#gsettings set org.gnome.desktop.interface font-name 'CaskaydiaCove Nerd Font 9' +#gsettings set org.gnome.desktop.interface icon-theme 'Tokyonight-Moon' +#gsettings set org.gnome.desktop.interface cursor-theme 'Sweet-cursors' + +# For nemo +gsettings set org.cinnamon.desktop.default-applications.terminal exec wezterm + +# music daemon +mpd & + +# other +hyprctl setcursor Sweet-cursors 24 +wl-paste --watch cliphist store & +notify-send -a aurora "hello $(whoami)" & +sleep 2 +mpd-mpris & diff --git a/linux/home/.config/hypr/hyprland.conf b/linux/home/.config/hypr/hyprland.conf new file mode 100644 index 0000000..620dc55 --- /dev/null +++ b/linux/home/.config/hypr/hyprland.conf @@ -0,0 +1,175 @@ +# Sourcing external config files +source=~/.config/hypr/user/monitors.conf +source=~/.config/hypr/user/exec.conf +source=~/.config/hypr/user/env.conf +source=~/.config/hypr/user/binds.conf +source=~/.config/hypr/user/window_rules.conf + + +# Defaults +$term = wezterm +$browser = firefox +#$gmail = firefox --new-instance -P app "https://mail.google.com/" --class appProfile +$editor = nvim +#$explorer = nemo +#$music = g4music +$notepad = code --profile notepad --unity-launch ~/Templates +$launcher = wofi --show drun -n +$launcher_alt = wofi --show run -n +#$discord = discord +#env = GTK_THEME,Breeze-Dark + + +general { + gaps_in = 5 + gaps_out = 5 + border_size = 2 + col.active_border = rgba(cba6f7ff) rgba(89b4faff) rgba(94e2d5ff) 10deg + col.inactive_border = 0xff313244 + # whether to apply the sensitivity to raw input (e.g. used by games where you aim using your mouse) + apply_sens_to_raw = 0 + layout = "master"; + resize_on_border = yes + extend_border_grab_area = 20 +} + + +input { + kb_layout = custom-us + #sensitivity = 0.75 # for mouse cursor + sensitivity = 0 + follow_mouse = 0 + scroll_method = 2fg + + touchpad { + natural_scroll = false + disable_while_typing = true + tap-to-click = true + } +} + + +decoration { + rounding = 10 + active_opacity = 0.95 + inactive_opacity = 0.9 + fullscreen_opacity = 0.95 + + dim_inactive = false + dim_strength = 0.05 + + blur { + enabled = true + #enabled = false + size = 3 + passes = 1 + + vibrancy = 0.1696 + } + + drop_shadow = true + shadow_range = 4 + shadow_render_power = 3 + col.shadow = rgba(1a1a1aee) + #blur = true + #blur_size = 5 + #blur_passes = 4 + #blur_new_optimizations = true + #blur_xray = true + #blur_ignore_opacity = true + + #drop_shadow = true + #shadow_ignore_window = true + #shadow_range = 20 + #shadow_render_power = 3 + #col.shadow = 0x55161925 + col.shadow_inactive = 0x22161925 + # Your blur "amount" is blur_size * blur_passes, but high blur_size (over around 5-ish) will produce artifacts. + # if you want heavy blur, you need to up the blur_passes. + # the more passes, the more you can up the blur_size without noticing artifacts. + + # Blurring layerSurfaces + # blurls = gtk-layer-shell + # blurls = waybar + # blurls = lockscreen + blurls = rofi + blurls = wofi + blurls = firefox +} + + +animations { + enabled = true + # bezier = overshot, 0.05, 0.9, 0.1, 1.1 + bezier = overshot, 0.13, 0.99, 0.29, 1.1 + animation = windows, 1, 4, overshot, slide + animation = border, 1, 10, default + animation = fade, 1, 10, default + animation = workspaces, 1, 6, overshot, slidevert +} + + +dwindle { + pseudotile = true # enable pseudotiling on dwindle + force_split = 0 + #col.group_border = 0xff89dceb + #col.group_border_active = 0xfff9e2af + preserve_split = true +} + + +master { + new_on_top = true + no_gaps_when_only = false +} + + +gestures { + workspace_swipe = true + workspace_swipe_invert = false + workspace_swipe_fingers = 3 +} + + +misc { + disable_hyprland_logo = true + + focus_on_activate = true + + enable_swallow = true + #swallow_regex = ^(scratchpad)$ +} + + +binds { + allow_workspace_cycles = true +} + + +custom { + +} + + +layerrule = blur, bar0 +layerrule = noanim, bar0 +layerrule = ignorealpha 0.2, bar0 +layerrule = blur, dock0 +layerrule = noanim, dock0 +layerrule = ignorealpha 0.2, dock0 +layerrule = blur, indicator0 +layerrule = ignorealpha 0.2, indicator0 +layerrule = blur, toolbox0 +layerrule = noanim, toolbox0 +layerrule = ignorealpha 0.2, toolbox0 +layerrule = blur, applauncher +layerrule = ignorealpha 0.2, applauncher +layerrule = blur, datemenu +layerrule = ignorealpha 0.2, datemenu +layerrule = blur, quicksettings +layerrule = ignorealpha 0.2, quicksettings +layerrule = blur, wlroots +layerrule = ignorealpha 0.2, wlroots +layerrule = blur, notifications0 +layerrule = ignorealpha 0.2, notifications0 + diff --git a/linux/home/.config/hypr/scripts/move-scratchpad.sh b/linux/home/.config/hypr/scripts/move-scratchpad.sh new file mode 100755 index 0000000..a8d0731 --- /dev/null +++ b/linux/home/.config/hypr/scripts/move-scratchpad.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +# Number of pixels to move down +pixels_to_move=10 + +# Get the PID of each scratchpad window and move it down +for pid in "$(hyprctl -j clients | jq -r '.[] | select(.class == "scratchpad") | .pid')"; do + hyprctl dispatch movewindowpixel 0 "$pixels_to_move",pid:"$pid" +done diff --git a/linux/home/.config/hypr/user/binds.conf b/linux/home/.config/hypr/user/binds.conf new file mode 100644 index 0000000..a337a0e --- /dev/null +++ b/linux/home/.config/hypr/user/binds.conf @@ -0,0 +1,167 @@ +# Window Manager keybindings + +# Scratchpad +bind = SUPER, semicolon, exec, ~/.scripts/scratchpad && bash ~/.config/hypr/scripts/move-scratchpad.sh +bind = SUPER, X, exec, ~/.scripts/scratchpad && bash ~/.config/hypr/scripts/move-scratchpad.sh +#bind = SUPER, semicolon, exec, ~/.scripts/scratchpad +#bind = SUPER, X, exec, ~/.scripts/scratchpad + +# HUD +bind = SUPER, E, exec, ~/.scripts/heads-up-display + +# Package manager Terminal +bind = SUPER, Q, exec, ~/.scripts/pac + +# Mouse binds +bindm = SUPER, mouse:272, movewindow +bindm = SUPER, mouse:273, resizewindow +bind = SUPER, mouse_down, workspace, e-1 +bind = SUPER, mouse_up, workspace, e+1 + +# Screenshot binds +bind = , Print, exec,~/.scripts/screenshot_full +bind = ALT, Print, exec,~/.scripts/screenshot + +# Application binds +$term=wezterm +bind = SUPER, T, exec, $term -e tmux new-session -A -s term +bind = SUPER, Enter, exec, $term -e tmux new-session -A -s term +bind = SUPER, W, exec, $browser +#bind = SUPER, G, exec, $notepad + +# ags +bind = SUPER_SHIFT, R, exec, ags -q; ags; notify-send "ags reloaded" +bind=SUPER, Space, exec, ags -t launcher +bind=,XF86PowerOff, exec, ags -t powermenu +bind=SUPER, escape, exec, ags -t powermenu +bind=SUPER, Tab, exec, ags -t overview +#bind = SUPER, Space, exec, ags -r "toggleLauncher()" + +# Clipboard +bind = SUPER, V, exec, pkill wofi || cliphist list | wofi --dmenu -p clippick -l top_right -x -15 -y 10 -n | cliphist decode | wl-copy + + +# Hyprland keys +bind=SUPER_SHIFT,Escape,exec,hyprctl reload; notify-send "Config Reloaded" +bind = SUPER, D, killactive, +#bind = SUPER_SHIFT, S, movetoworkspace,special +#bind = SUPER, S, togglespecialworkspace, + + +# Other dispatchers +bind = ALT, Tab, cyclenext +bind = SUPER, C, cyclenext +bind = SUPER, F, fullscreen +#bind = SUPER, T, exec, hyprctl dispatch centerwindow none +bind = SUPER, M, fullscreen, 1 +bind = SUPER_SHIFT, M, fakefullscreen + + +bind = SUPER, P, pseudo, +bind = SUPER, S, togglefloating, +bind = SUPER_SHIFT, G, togglegroup, +bind = SUPER, tab, changegroupactive, +bind = SUPER_SHIFT, I, togglesplit, # dwindle + + +# Move window with SUPER + Shift + arrow keys +# [↑] +# [←] [↓] [→] +bind = SUPER_SHIFT, left, movewindow, l +bind = SUPER_SHIFT, right, movewindow, r +bind = SUPER_SHIFT, up, movewindow, u +bind = SUPER_SHIFT, down, movewindow, d +bind = SUPER_SHIFT, H, movewindow, l +bind = SUPER_SHIFT, L, movewindow, r +bind = SUPER_SHIFT, K, movewindow, u +bind = SUPER_SHIFT, J, movewindow, d + +# Move window focus with SUPER + arrow keys +# [↑] +# [←] [↓] [→] +bind = SUPER, left, movefocus, l +bind = SUPER, right, movefocus, r +bind = SUPER, up, movefocus, u +bind = SUPER, down, movefocus, d +bind = SUPER, H, movefocus, l +bind = SUPER, L, movefocus, r +bind = SUPER, K, movefocus, u +bind = SUPER, J, movefocus, d + +# Move To a workspaces +bind = SUPER, 1, workspace, 1 +bind = SUPER, 2, workspace, 2 +bind = SUPER, 3, workspace, 3 +bind = SUPER, 4, workspace, 4 +bind = SUPER, 5, workspace, 5 +bind = SUPER, 6, workspace, 6 +bind = SUPER, 7, workspace, 7 +bind = SUPER, 8, workspace, 8 +bind = SUPER, 9, workspace, 9 + +# Move windows between workspaces +bind = SUPER_SHIFT, 1, movetoworkspace, 1 +bind = SUPER_SHIFT, 2, movetoworkspace, 2 +bind = SUPER_SHIFT, 3, movetoworkspace, 3 +bind = SUPER_SHIFT, 4, movetoworkspace, 4 +bind = SUPER_SHIFT, 5, movetoworkspace, 5 +bind = SUPER_SHIFT, 6, movetoworkspace, 6 +bind = SUPER_SHIFT, 7, movetoworkspace, 7 +bind = SUPER_SHIFT, 8, movetoworkspace, 8 +bind = SUPER_SHIFT, 9, movetoworkspace, 9 + + +# Use this to get thw XF86 bind (FN + Fx combination) for your keyboard +# xev | grep -A2 --line-buffered '^KeyRelease' | sed -n '/keycode /s/^.*keycode \([0-9]*\).* (.*, \(.*\)).*$/\1 \2/p' + +# Volume Control +#binde = , XF86AudioRaiseVolume, exec, pactl set-sink-volume @DEFAULT_SINK@ +1% +#binde = , XF86AudioLowerVolume, exec, pactl set-sink-volume @DEFAULT_SINK@ -1% +bind = , XF86AudioMute, exec, pactl set-sink-mute @DEFAULT_SINK@ toggle +bind = , XF86AudioMicMute, exec, pactl set-source-mute @DEFAULT_SOURCE@ toggle +bind = ALT, down, exec, pactl set-sink-volume @DEFAULT_SINK@ -5% +bind = ALT, up, exec, pactl set-sink-volume @DEFAULT_SINK@ +5% + +# Media Control +bind = , XF86AudioMedia, exec, playerctl play-pause +bind = , XF86AudioPlay, exec, playerctl play-pause +bind = , XF86AudioStop, exec, playerctl stop +bind = , XF86AudioPrev, exec, playerctl previous +bind = , XF86AudioNext, exec, playerctl next + +# Use arrow keys as multimedia keys +bind = ALT_SHIFT, left, exec, playerctl previous +bind = ALT_SHIFT, up, exec, playerctl play-pause +bind = ALT_SHIFT, right, exec, playerctl next + +# Brightness Control +binde = , XF86MonBrightnessUp, exec, light -A 1 +binde = , XF86MonBrightnessDown, exec, light -U 1 + +bind = ALT, left, exec, brightnessctl set 10%- # Screen brightness down FN+F7 +bind = ALT, right, exec, brightnessctl set 10%+ # Screen brightness up FN+F8 + +# Screensaver key +bind = , XF86ScreenSaver, exec,~/.scripts/lock + +bind = SUPER_SHIFT, Y, exec, spotify +bind = SUPER_SHIFT, D, exec, discord +bind = SUPER , W, exec, firefox +bind = SUPER_SHIFT, B, exec, rofi-rbw + +# Others +#bind = , XF86Mail, exec,$gmail +#bind = , XF86HomePage, exec, $explorer ~/ +#bind = , XF86Calculator, exec, qalculate-gtk +#bind = , XF86Search, exec, wofi + +$mainMod = SUPER +bind = $mainMod, tilde, exec, ~/.scripts/translate.sh +bind = $mainMod CONTROL, k, exec, ~/.scripts/killmenu + + + +# trigger when the switch is turning on +# bindl = , switch:on:Lid Switch, exec, hyprctl keyword monitor ", 1920x1080@60, auto, 1" +# trigger when the switch is turning off +bindl = , switch:off:Lid Switch, exec, playerctl --all-players stop; ~/.scripts/lock; systemctl suspend diff --git a/linux/home/.config/hypr/user/env.conf b/linux/home/.config/hypr/user/env.conf new file mode 100644 index 0000000..93f7694 --- /dev/null +++ b/linux/home/.config/hypr/user/env.conf @@ -0,0 +1,23 @@ +#Environment Variables for the Hyprland session + +# XDG +env = XDG_CURRENT_DESKTOP,Hyprland +env = XDG_SESSION_TYPE,wayland +env = XDG_SESSION_DESKTOP,Hyprland + +# QT +env = QT_AUTO_SCREEN_SCALE_FACTOR,1 +env = QT_QPA_PLATFORM=wayland;xcb # Not yet working for onlyoffice-editor +env = QT_WAYLAND_DISABLE_WINDOWDECORATION,1 +env = QT_QPA_PLATFORMTHEME,qt6ct + +# GTK +#env = GDK_BACKEND=wayland + +# Toolkit +#env = SDL_VIDEODRIVER,wayland +env = _JAVA_AWT_WM_NONEREPARENTING,1 +env = CLUTTER_BACKEND,wayland +env = GDK_BACKEND,wayland,x11 +env = MOZ_ENABLE_WAYLAND,1 + diff --git a/linux/home/.config/hypr/user/exec.conf b/linux/home/.config/hypr/user/exec.conf new file mode 100644 index 0000000..22846d9 --- /dev/null +++ b/linux/home/.config/hypr/user/exec.conf @@ -0,0 +1,4 @@ +exec-once=$HOME/.config/hypr/autostart +exec-once = swww kill; swww init --format xrgb +exec = ags +exec =$HOME/.scripts/move-qemu.sh diff --git a/linux/home/.config/hypr/user/monitors.conf b/linux/home/.config/hypr/user/monitors.conf new file mode 100644 index 0000000..7464786 --- /dev/null +++ b/linux/home/.config/hypr/user/monitors.conf @@ -0,0 +1,4 @@ +monitor=auto,preferred,auto, 1, bitdepth,10 +#monitor=, 1920x1080@60, auto, 1 +#monitor=, 1366x768@60, auto, 1 +#monitor=LVDS-1, 1366x768@60, auto, 1, bitdepth,10 diff --git a/linux/home/.config/hypr/user/window_rules.conf b/linux/home/.config/hypr/user/window_rules.conf new file mode 100644 index 0000000..3964de2 --- /dev/null +++ b/linux/home/.config/hypr/user/window_rules.conf @@ -0,0 +1,70 @@ +# {{@@ header() @@}} +# vim:fileencoding=utf-8:ft=conf:foldmethod=marker + +# Workspaces +windowrulev2 = workspace 1 silent, class:firefox +windowrulev2 = workspace 4 silent, class:discord +windowrulev2 = workspace 5 silent, class:Spotify + +# Scratchpad +$scratchpad = class:^(scratchpad)$ +windowrulev2 = opacity 1 0.9,class:^(scratchpad)$ +windowrulev2 = float,$scratchpad +#windowrule = float,^(scratchpad)$ +#windowrule = move 15 40, ^(scratchpad)$ +#windowrule = move center,^(scratchpad)$ +#$scratchpadsize = size 98% 93% +#windowrulev2 = tile,$scratchpad +#windowrulev2 = pin,$scratchpad +#windowrulev2=windowdance,$scratchpad +#windowrulev2 = move 100%-20,$scratchpad +#windowrulev2 = $scratchpadsize,$scratchpad + +# HUD +windowrule = float, ^(heads-up-display)$ +windowrule = pin, ^(heads-up-display)$ +windowrule = size 325 160, ^(heads-up-display)$ +windowrule = move 1020 50, ^(heads-up-display)$ + +# Package manager Terminal +windowrule = float, ^(pac)$ +windowrule = pin, ^(pac)$ +windowrule = size 325 160, ^(pac)$ +windowrule = move 50 50, ^(pac)$ + +# Picture-in-Picture +windowrulev2 = idleinhibit fullscreen, title:^Picture-in-Picture$ +windowrulev2 = float, title:^Picture-in-Picture$ +windowrulev2 = pin, title:^Picture-in-Picture$ +windowrulev2 = move 920 480, title:^Picture-in-Picture$ +windowrulev2 = size 425 260, title:^Picture-in-Picture$ + +# Firefox +windowrulev2 = float, class:^(firefox)$, title:^(Firefox — Sharing Indicator)$ +windowrulev2 = opacity 1 1,class:^(firefox)$ + +# Applications +windowrule = float,^(rlr)$ +windowrule = float,^(pavucontrol)$ +windowrule = float,^(blueman-manager)$ +windowrule = float,^(nm-connection-editor)$ +windowrule = float,^(mediainfo-gui)$ +windowrulev2 = float, class:^(nemo)$, title:^(.*Properties)$ +windowrulev2 = float, class:^(Nemo-preview-start)$ +windowrulev2 = move 100%-433 53, class:^(wofi)$, title:^(clippick)$ +windowrulev2 = animation popin, class:^(wlogout)$, title:^(wlogout)$ +windowrulev2 = float, class:^(wlogout)$, title:^(wlogout)$ +windowrulev2 = animation slide, class:^(wofi)$ +#windowrulev2 = float, class:^(steam)$ +windowrule = float,^(com.github.neithern.g4music)$ +windowrule = size 670 635,^(com.github.neithern.g4music)$ +windowrule = move center,^(com.github.neithern.g4music)$ +windowrulev2 = opacity 0.0 override,class:^(xwaylandvideobridge)$ +windowrulev2 = noanim,class:^(xwaylandvideobridge)$ +windowrulev2 = noinitialfocus,class:^(xwaylandvideobridge)$ +windowrulev2 = maxsize 1 1,class:^(xwaylandvideobridge)$ +windowrulev2 = noblur,class:^(xwaylandvideobridge)$ + +# Blur +windowrule = noblur,^(firefox)$ # disables blur for firefox +windowrule = noblur,^(scratchpad)$ # disables blur for firefox diff --git a/linux/home/.config/inputrc b/linux/home/.config/inputrc new file mode 100644 index 0000000..adfeec4 --- /dev/null +++ b/linux/home/.config/inputrc @@ -0,0 +1,86 @@ +$include /etc/inputrc + +"\f": clear-screen + +set bell-style none +set meta-flag on +set input-meta on +set convert-meta off +set output-meta on +set show-all-if-ambiguous on # set show-all-if-unmodified on + +# Color files by types +# Note that this may cause completion text blink in some terminals (e.g. xterm). +set colored-stats On +# Append char to indicate type +set visible-stats On +# Mark symlinked directories +set mark-symlinked-directories On +# Color the common prefix +set colored-completion-prefix On +# Color the common prefix in menu-complete +set menu-complete-display-prefix On + +# set editing-mode vi +set show-mode-in-prompt on +set keyseq-timeout 0 # Reduce the delay between pressing escape and the cursor change +set vi-cmd-mode-string "\1\e[2 q\2" +set vi-ins-mode-string "\1\e[6 q\2" + +$if mode=vi + set keymap vi-command + # these are for vi-command mode + "\e[A": history-search-backward + "\e[B": history-search-forward + j: history-search-forward + k: history-search-backward + set keymap vi-insert + # these are for vi-insert mode + "\e[A": history-search-backward + "\e[B": history-search-forward + "jk" # escape +$endif + +$if mode=emacs + + "\C-P": history-search-backward + "\C-N": history-search-forward + + # for linux console and RH/Debian xterm + "\e[1~": beginning-of-line + "\e[4~": end-of-line + "\e[5~": beginning-of-history + "\e[6~": end-of-history + "\e[7~": beginning-of-line + "\e[3~": delete-char + "\e[2~": quoted-insert + "\e[5C": forward-word + "\e[5D": backward-word + "\e\e[C": forward-word + "\e\e[D": backward-word + "\e[1;5C": forward-word + "\e[1;5D": backward-word + + # for rxvt + "\e[8~": end-of-line + + # for non RH/Debian xterm, can't hurt for RH/DEbian xterm + "\eOH": beginning-of-line + "\eOF": end-of-line + + # for freebsd console + "\e[H": beginning-of-line + "\e[F": end-of-line + +$endif + +#set editing-mode emacs +set editing-mode vi + +# # switch between vi or emacs +# set keymap emacs +# "\e[": vi-editing-mode +# set keymap vi-insert +# "\e[": emacs-editing-mode +# set keymap vi-command +# "\e[": emacs-editing-mode diff --git a/linux/home/.config/jgmenu/jgmenurc b/linux/home/.config/jgmenu/jgmenurc new file mode 100644 index 0000000..d35eee6 --- /dev/null +++ b/linux/home/.config/jgmenu/jgmenurc @@ -0,0 +1,32 @@ +stay_alive = 1 +tint2_look = 0 +position_mode = pointer +terminal_exec = wezterm +terminal_args = -x +sub_spacing = 5 +menu_width = 200 +menu_padding_top = 5 +menu_padding_right = 2 +menu_padding_bottom = 5 +menu_padding_left = 2 +menu_radius = 7 +menu_border = 0 +menu_halign = left +sub_hover_action = 1 +item_margin_y = 5 +item_height = 30 +item_padding_x = 8 +item_radius = 6 +item_border = 0 +sep_height = 5 +font = Roboto Medium 15px +icon_theme = Papirus +icon_size = 24 +color_menu_bg = #171B20 80 +color_menu_border = #c0caf5 +color_norm_bg = #171B20 0 +color_norm_fg = #b6beca 100 +color_sel_bg = #74bee9 50 +color_sel_fg = #b6beca 100 +color_sep_fg = b6beca 80 +csv_cmd = cat ~/.config/jgmenu/menu.csv diff --git a/linux/home/.config/jgmenu/menu.csv b/linux/home/.config/jgmenu/menu.csv new file mode 100644 index 0000000..dbece5a --- /dev/null +++ b/linux/home/.config/jgmenu/menu.csv @@ -0,0 +1,32 @@ +Terminal,scratchpad,utilities-terminal +Web-browser,firefox,web-browser +Neovim,kitty -e nvim,nvim +Ranger,wezterm -e ranger,stock_folder +^sep() + +Extras,^checkout(extras),add +^sep() + +Critical,^checkout(critical),gtk-dialog-warning +^sep() + +Lock,betterlockscreen --lock,system-lock-screen +Logout,pkill -KILL -u "$USER" &,system-log-out + +Exit,^checkout(exit),exit + +^tag(exit) +Suspend,systemctl suspend,system-suspend +Reboot,reboot,system-reboot +Poweroff,poweroff,system-shutdown + +^tag(extras) +Change wallpaper,nitrogen,nitrogen +Randomize Wallpaper,random-wall +Control-center,~/.config/eww/scripts/openControlCenter.sh +Reload eww,pkill -f eww && eww daemon + +^tag(critical) +Restart BSPWM,control_box -bspres +Restart SXHKD,control_box -kbres,input-keyboard +Restart Pipewire,control_box -soundres,audio-speakers diff --git a/linux/home/.config/kitty/kitty.conf b/linux/home/.config/kitty/kitty.conf new file mode 100644 index 0000000..cbf9f70 --- /dev/null +++ b/linux/home/.config/kitty/kitty.conf @@ -0,0 +1,827 @@ + +# vim:fileencoding=utf-8:ft=conf:foldmethod=marker + +#: Fonts {{{ + +#: kitty has very powerful font management. You can configure +#: individual font faces and even specify special fonts for particular +#: characters. + +font_family JetBrains Mono Medium +bold_font auto +italic_font auto +bold_italic_font auto + +#: You can specify different fonts for the bold/italic/bold-italic +#: variants. By default they are derived automatically, by the OSes +#: font system. Setting them manually is useful for font families that +#: have many weight variants like Book, Medium, Thick, etc. For +#: example: + +#: font_family Operator Mono Book +#: bold_font Operator Mono Medium +#: italic_font Operator Mono Book Italic +#: bold_italic_font Operator Mono Medium Italic + +font_size 9.0 + +#: Font size (in pts) + +# adjust_line_height 0 +# adjust_column_width 0 + +#: Change the size of each character cell kitty renders. You can use +#: either numbers, which are interpreted as pixels or percentages +#: (number followed by %), which are interpreted as percentages of the +#: unmodified values. You can use negative pixels or percentages less +#: than 100% to reduce sizes (but this might cause rendering +#: artifacts). + +# symbol_map U+E0A0-U+E0A2,U+E0B0-U+E0B3 PowerlineSymbols + +#: Map the specified unicode codepoints to a particular font. Useful +#: if you need special rendering for some symbols, such as for +#: Powerline. Avoids the need for patched fonts. Each unicode code +#: point is specified in the form U+. You +#: can specify multiple code points, separated by commas and ranges +#: separated by hyphens. symbol_map itself can be specified multiple +#: times. Syntax is:: + +#: symbol_map codepoints Font Family Name + +# box_drawing_scale 0.001, 1, 1.5, 2 + +#: Change the sizes of the lines used for the box drawing unicode +#: characters These values are in pts. They will be scaled by the +#: monitor DPI to arrive at a pixel value. There must be four values +#: corresponding to thin, normal, thick, and very thick lines. + +#: }}} + +#: Cursor customization {{{ + +# cursor magenta +cursor white + +#: Default cursor color + +# cursor_shape block + +#: The cursor shape can be one of (block, beam, underline) + +cursor_blink_interval 0.5 +cursor_stop_blinking_after 15.0 + +#: The interval (in seconds) at which to blink the cursor. Set to zero +#: to disable blinking. Note that numbers smaller than repaint_delay +#: will be limited to repaint_delay. Stop blinking cursor after the +#: specified number of seconds of keyboard inactivity. Set to zero to +#: never stop blinking. + +#: }}} + +#: Scrollback {{{ + +scrollback_lines 20000 + +#: Number of lines of history to keep in memory for scrolling back. +#: Memory is allocated on demand. + +# scrollback_pager less --chop-long-lines --RAW-CONTROL-CHARS +INPUT_LINE_NUMBER + +#: Program with which to view scrollback in a new window. The +#: scrollback buffer is passed as STDIN to this program. If you change +#: it, make sure the program you use can handle ANSI escape sequences +#: for colors and text formatting. INPUT_LINE_NUMBER in the command +#: line above will be replaced by an integer representing which line +#: should be at the top of the screen. + +wheel_scroll_multiplier 5 + +#: Modify the amount scrolled by the mouse wheel or touchpad. Use +#: negative numbers to change scroll direction. + +#: }}} + +#: Mouse {{{ + +url_color #0087BD +url_style curly + +#: The color and style for highlighting URLs on mouse-over. url_style +#: can be one of: none, single, double, curly + +open_url_modifiers kitty_mod + +#: The modifier keys to press when clicking with the mouse on URLs to +#: open the URL + +open_url_with default + +#: The program with which to open URLs that are clicked on. The +#: special value default means to use the operating system's default +#: URL handler. + +copy_on_select yes + +#: Copy to clipboard on select. With this enabled, simply selecting +#: text with the mouse will cause the text to be copied to clipboard. +#: Useful on platforms such as macOS/Wayland that do not have the +#: concept of primary selectons. Note that this is a security risk, +#: as all programs, including websites open in your browser can read +#: the contents of the clipboard. + +# rectangle_select_modifiers ctrl+alt + +#: The modifiers to use rectangular selection (i.e. to select text in +#: a rectangular block with the mouse) + +# select_by_word_characters :@-./_~?&=%+# + +#: Characters considered part of a word when double clicking. In +#: addition to these characters any character that is marked as an +#: alpha-numeric character in the unicode database will be matched. + +click_interval 0.5 + +#: The interval between successive clicks to detect double/triple +#: clicks (in seconds) + +# mouse_hide_wait 3.0 + +#: Hide mouse cursor after the specified number of seconds of the +#: mouse not being used. Set to zero to disable mouse cursor hiding. + +# focus_follows_mouse no + +#: Set the active window to the window under the mouse when moving the +#: mouse around + +#: }}} + +#: Performance tuning {{{ + +repaint_delay 10 + +#: Delay (in milliseconds) between screen updates. Decreasing it, +#: increases frames-per-second (FPS) at the cost of more CPU usage. +#: The default value yields ~100 FPS which is more than sufficient for +#: most uses. Note that to actually achieve 100 FPS you have to either +#: set sync_to_monitor to no or use a monitor with a high refresh +#: rate. + +# input_delay 3 + +#: Delay (in milliseconds) before input from the program running in +#: the terminal is processed. Note that decreasing it will increase +#: responsiveness, but also increase CPU usage and might cause flicker +#: in full screen programs that redraw the entire screen on each loop, +#: because kitty is so fast that partial screen updates will be drawn. + +# sync_to_monitor yes + +#: Sync screen updates to the refresh rate of the monitor. This +#: prevents tearing (https://en.wikipedia.org/wiki/Screen_tearing) +#: when scrolling. However, it limits the rendering speed to the +#: refresh rate of your monitor. With a very high speed mouse/high +#: keyboard repeat rate, you may notice some slight input latency. If +#: so, set this to no. + +#: }}} + +#: Terminal bell {{{ + +enable_audio_bell no + +#: Enable/disable the audio bell. Useful in environments that require +#: silence. + +# visual_bell_duration 0.5 + +#: Visual bell duration. Flash the screen when a bell occurs for the +#: specified number of seconds. Set to zero to disable. + +window_alert_on_bell yes + +#: Request window attention on bell. Makes the dock icon bounce on +#: macOS or the taskbar flash on linux. + +bell_on_tab yes + +#: Show a bell symbol on the tab if a bell occurs in one of the +#: windows in the tab and the window is not the currently focused +#: window + +#: }}} + +#: Window layout {{{ + +# remember_window_size yes +# initial_window_width 640 +# initial_window_height 400 + +#: If enabled, the window size will be remembered so that new +#: instances of kitty will have the same size as the previous +#: instance. If disabled, the window will initially have size +#: configured by initial_window_width/height, in pixels. You can use a +#: suffix of "c" on the width/height values to have them interpreted +#: as number of cells instead of pixels. + +enabled_layouts * + +#: The enabled window layouts. A comma separated list of layout names. +#: The special value * means all layouts. The first listed layout will +#: be used as the startup layout. For a list of available layouts, see +#: the layouts. + +# window_resize_step_cells 2 +# window_resize_step_lines 2 + +#: The step size (in units of cell width/cell height) to use when +#: resizing windows. The cells value is used for horizontal resizing +#: and the lines value for vertical resizing. + +window_border_width 1 + +#: The width (in pts) of window borders. Will be rounded to the +#: nearest number of pixels based on screen resolution. Note that +#: borders are displayed only when more than one window is visible. +#: They are meant to separate multiple windows. + +window_margin_width 0 + +#: The window margin (in pts) (blank area outside the border) + +# single_window_margin_width -1000.0 + +#: The window margin (in pts) to use when only a single window is +#: visible. Negative values will cause the value of +#: window_margin_width to be used instead. + +window_padding_width 2 + +#: The window padding (in pts) (blank area between the text and the +#: window border) + +active_border_color #282c34 + +#: The color for the border of the active window + +inactive_border_color #22262d + +#: The color for the border of inactive windows + +# bell_border_color #ff5a00 + +#: The color for the border of inactive windows in which a bell has +#: occurred + +inactive_text_alpha .6 + +#: Fade the text in inactive windows by the specified amount (a number +#: between zero and one, with zero being fully faded). + +#: }}} + +#: Tab bar {{{ + +# tab_bar_edge bottom + +#: Which edge to show the tab bar on, top or bottom + +tab_bar_margin_width 4 + +#: The margin to the left and right of the tab bar (in pts) + +tab_bar_style fade + +#: The tab bar style, can be one of: fade or separator. In the fade +#: style, each tab's edges fade into the background color, in the +#: separator style, tabs are separated by a configurable separator. + +# tab_fade 0.25 0.5 0.75 1 +tab_fade 1 1 1 + +#: Control how each tab fades into the background when using fade for +#: the tab_bar_style. Each number is an alpha (between zero and one) +#: that controls how much the corresponding cell fades into the +#: background, with zero being no fade and one being full fade. You +#: can change the number of cells used by adding/removing entries to +#: this list. + +# tab_separator " " + +#: The separator between tabs in the tab bar when using separator as +#: the tab_bar_style. + +active_tab_foreground #282c34 +active_tab_background #abb2bf +active_tab_font_style bold +inactive_tab_foreground #5c6370 +inactive_tab_background #22262d +inactive_tab_font_style normal + +#: Tab bar colors and styles + +#: }}} + +#: Color scheme {{{ + +foreground #d8dee9 +#background #1d1f21 +background #000000 + +#: The foreground and background colors + +background_opacity 0.7 +dynamic_background_opacity yes +# Increase background opacity ctrl+shift+a>m + +# Decrease background opacity ctrl+shift+a>l + +# Full background opacity ctrl+shift+a>1 + +# Reset background opacity ctrl+shift+a>d + +#: The opacity of the background. A number between 0 and 1, where 1 is +#: opaque and 0 is fully transparent. This will only work if +#: supported by the OS (for instance, when using a compositor under +#: X11). Note that it only sets the default background color's +#: opacity. This is so that things like the status bar in vim, +#: powerline prompts, etc. still look good. But it means that if you +#: use a color theme with a background color in your editor, it will +#: not be rendered as transparent. Instead you should change the +#: default background color in your kitty config and not use a +#: background color in the editor color scheme. Or use the escape +#: codes to set the terminals default colors in a shell script to +#: launch your editor. Be aware that using a value less than 1.0 is a +#: (possibly significant) performance hit. If you want to dynamically +#: change transparency of windows set dynamic_background_opacity to +#: yes (this is off by default as it has a performance cost) + +dim_opacity 1.0 + +#: How much to dim text that has the DIM/FAINT attribute set. One +#: means no dimming and zero means fully dimmed (i.e. invisible). + +selection_foreground #000000 +selection_background #FFFACD + +#: The foreground and background for text selected with the mouse + + +#: The 16 terminal colors. There are 8 basic colors, each color has a +#: dull and bright version. You can also set the remaining colors from +#: the 256 color table as color16 to color255. + +#: black +color0 #313539 +color8 #676f78 + +#: red +color1 #b02626 +color9 #b55454 + +#: green +color2 #40a62f +color10 #78a670 + +#: yellow +color3 #f2e635 +color11 #faf380 + +#: blue +color4 #314ad0 +color12 #707fd0 + +#: magenta +color5 #b30ad0 +color13 #c583d0 + +#: cyan +color6 #32d0fc +color14 #8adaf1 + +#: white +color7 #acadb1 +color15 #e0e3e7 + + +#: }}} + +#: Advanced {{{ + +# shell zsh + +#: The shell program to execute. The default value of . means to use +#: whatever shell is set as the default shell for the current user. +#: Note that on macOS if you change this, you might need to add +#: --login to ensure that the shell starts in interactive mode and +#: reads its startup rc files. + +editor . + +#: The console editor to use when editing the kitty config file or +#: similar tasks. A value of . means to use the environment variable +#: EDITOR. Note that this environment variable has to be set not just +#: in your shell startup scripts but system-wide, otherwise kitty will +#: not see it. + +# Confirm when closing where 0 disables it; -1 enables it +confirm_os_window_close 0 + +# close_on_child_death nvim + +#: Close the window when the child process (shell) exits. If no (the +#: default), the terminal will remain open when the child exits as +#: long as there are still processes outputting to the terminal (for +#: example disowned or backgrounded processes). If yes, the window +#: will close as soon as the child process exits. Note that setting it +#: to yes means that any background processes still using the terminal +#: can fail silently because their stdout/stderr/stdin no longer work. + +# allow_remote_control no + +#: Allow other programs to control kitty. If you turn this on other +#: programs can control all aspects of kitty, including sending text +#: to kitty windows, opening new windows, closing windows, reading the +#: content of windows, etc. Note that this even works over ssh +#: connections. + +# startup_session none + +#: Path to a session file to use for all kitty instances. Can be +#: overridden by using the kitty --session command line option for +#: individual instances. See sessions in the kitty documentation for +#: details. Note that relative paths are interpreted with respect to +#: the kitty config directory. Environment variables in the path are +#: expanded. + +# clipboard_control write-clipboard write-primary +clipboard_control write-primary write-clipboard no-append + +#: Allow programs running in kitty to read and write from the +#: clipboard. You can control exactly which actions are allowed. The +#: set of possible actions is: write-clipboard read-clipboard write- +#: primary read-primary The default is to allow writing to the +#: clipboard and primary selection. Note that enabling the read +#: functionality is a security risk as it means that any program, even +#: one running on a remote server via SSH can read your clipboard. + +#term xterm-kitty + +#: The value of the TERM environment variable to set. Changing this +#: can break many terminal programs, only change it if you know what +#: you are doing, not because you read some advice on Stack Overflow +#: to change it. + +#: }}} + +#: OS specific tweaks {{{ + +# macos_titlebar_color #22262d + +#: Change the color of the kitty window's titlebar on macOS. A value +#: of system means to use the default system color, a value of +#: background means to use the background color of the currently +#: active window and finally you can use an arbitrary color, such as +#: #12af59 or red. WARNING: This option works by using a hack, as +#: there is no proper Cocoa API for it. It sets the background color +#: of the entire window and makes the titlebar transparent. As such it +#: is incompatible with background_opacity. If you want to use both, +#: you are probably better off just hiding the titlebar with +#: macos_hide_titlebar. + +# macos_hide_titlebar no + +#: Hide the kitty window's title bar on macOS. + +hide_window_decorations yes + +#: Hide the window decorations (title bar and window borders) on X11 +#: and Wayland. Whether this works and exactly what effect it has +#: depends on the window manager, as it is the job of the window +#: manager/compositor to draw window decorations. + +# macos_option_as_alt yes + +#: Use the option key as an alt key. With this set to no, kitty will +#: use the macOS native Option+Key = unicode character behavior. This +#: will break any Alt+key keyboard shortcuts in your terminal +#: programs, but you can use the macOS unicode input technique. + +# macos_hide_from_tasks no + +#: Hide the kitty window from running tasks (Option+Tab) on macOS. + +# macos_quit_when_last_window_closed no + +#: Have kitty quit when all the top-level windows are closed. By +#: default, kitty will stay running, even with no open windows, as is +#: the expected behavior on macOS. + +linux_display_server x11 + +#: Choose between Wayland and X11 backends. By default, an appropriate +#: backend based on the system state is chosen automatically. Set it +#: to x11 or wayland to force the choice. + +#: }}} + +#: Keyboard shortcuts {{{ + +#: For a list of key names, see: GLFW keys +#: . The name to use +#: is the part after the GLFW_KEY_ prefix. For a list of modifier +#: names, see: GLFW mods +#: + +#: On Linux you can also use XKB key names to bind keys that are not +#: supported by GLFW. See XKB keys +#: for a list of key names. The name to use is the part +#: after the XKB_KEY_ prefix. Note that you should only use an XKB key +#: name for keys that are not present in the list of GLFW keys. + +#: You can use the special action no_op to unmap a keyboard shortcut +#: that is assigned in the default configuration. + +#: You can combine multiple actions to be triggered by a single +#: shortcut, using the syntax below:: + +#: map key combine action1 action2 action3 ... + +#: For example:: + +#: map kitty_mod+e combine : new_window : next_layout + +#: this will create a new window and switch to the next available +#: layout + +#: You can use multi-key shortcuts using the syntax shown below:: + +#: map key1>key2>key3 action + +#: For example:: + +#: map ctrl+f>2 set_font_size 20 + +# kitty_mod ctrl+shift + +#: The value of kitty_mod is used as the modifier for all default +#: shortcuts, you can change it in your kitty.conf to change the +#: modifiers for all the default shortcuts. + +# clear_all_shortcuts no + +#: You can have kitty remove all shortcut definition seen up to this +#: point. Useful, for instance, to remove the default shortcuts. + +#: Clipboard {{{ + +# map cmd+c copy_to_clipboard +#map kitty_mod+c copy_to_clipboard +# map cmd+v paste_from_clipboard +#map kitty_mod+v paste_from_clipboard +#map kitty_mod+s paste_from_selection +map shift+insert paste_from_selection +# map kitty_mod+o pass_selection_to_program +map ctrl+c copy_to_clipboard +map ctrl+v paste_from_clipboard + +#: You can also pass the contents of the current selection to any +#: program using pass_selection_to_program. By default, the system's +#: open program is used, but you can specify your own, for example:: + +#: map kitty_mod+o pass_selection_to_program firefox + +#: You can pass the current selection to a terminal program running in +#: a new kitty window, by using the @selection placeholder:: + +#: map kitty_mod+y new_window less @selection + +#: }}} + +#: Scrolling {{{ + +#map kitty_mod+up scroll_line_up +#map ctrl+k scroll_line_up +#map kitty_mod+k scroll_line_up +#map kitty_mod+down scroll_line_down +#map ctrl+j scroll_line_down +#map kitty_mod+j scroll_line_down +map kitty_mod+page_up scroll_page_up +map kitty_mod+page_down scroll_page_down +map kitty_mod+b scroll_page_up +map kitty_mod+f scroll_page_down +# map kitty_mod+home scroll_home +# map kitty_mod+end scroll_end +# map kitty_mod+h show_scrollback + +#: You can send the contents of the current screen + history buffer as +#: stdin to an arbitrary program using the placeholders @text (which +#: is the plain text) and @ansi (which includes text styling escape +#: codes). For only the current screen, use @screen or @ansi_screen. +#: For example, the following command opens the scrollback buffer in +#: less in a new window:: + +#: map kitty_mod+y new_window @ansi less +G -R + +#: }}} + +#: Window management {{{ + +# map kitty_mod+enter new_window +map kitty_mod+enter no_op +map kitty_mod+enter new_window_with_cwd + +#: You can open a new window running an arbitrary program, for +#: example:: + +#: map kitty_mod+y new_window mutt + +#: You can open a new window with the current working directory set to +#: the working directory of the current window using:: + +#: map ctrl+alt+enter new_window_with_cwd + +# map cmd+n new_os_window +# map kitty_mod+n new_os_window +# map kitty_mod+w close_window +# map kitty_mod+] next_window +# map kitty_mod+[ previous_window +map kitty_mod+j previous_window +map kitty_mod+k next_window +map kitty_mod+up move_window_forward +map kitty_mod+down move_window_backward +# map kitty_mod+f move_window_forward +# map kitty_mod+b move_window_backward +# map kitty_mod+` move_window_to_top +# map kitty_mod+r start_resizing_window +# map kitty_mod+1 first_window +# map kitty_mod+2 second_window +# map kitty_mod+3 third_window +# map kitty_mod+4 fourth_window +# map kitty_mod+5 fifth_window +# map kitty_mod+6 sixth_window +# map kitty_mod+7 seventh_window +# map kitty_mod+8 eighth_window +# map kitty_mod+9 ninth_window +# map kitty_mod+0 tenth_window +#: }}} + +#: Tab management {{{ + +# map kitty_mod+right next_tab +# map kitty_mod+left previous_tab +map kitty_mod+] no_op +map kitty_mod+] next_tab +map kitty_mod+[ no_op +map kitty_mod+[ previous_tab +# map kitty_mod+t new_tab +# map kitty_mod+q close_tab +# map kitty_mod+. move_tab_forward +# map kitty_mod+, move_tab_backward +map kitty_mod+right no_op +map kitty_mod+right move_tab_forward +map kitty_mod+left no_op +map kitty_mod+left move_tab_backward +# map kitty_mod+alt+t set_tab_title +map kitty_mod+t no_op +map kitty_mod+t new_tab_with_cwd + +#: You can also create shortcuts to go to specific tabs, with 1 being +#: the first tab:: + +#: map ctrl+alt+1 goto_tab 1 +#: map ctrl+alt+2 goto_tab 2 + +#: Just as with new_window above, you can also pass the name of +#: arbitrary commands to run when using new_tab and use +#: new_tab_with_cwd. +#: }}} + +#: Layout management {{{ + +# map kitty_mod+l next_layout + +#: You can also create shortcuts to switch to specific layouts:: + +map kitty_mod+0 no_op +map kitty_mod+0 goto_layout stack +map kitty_mod+9 no_op +map kitty_mod+9 goto_layout tall +map kitty_mod+8 no_op +map kitty_mod+8 goto_layout fat +#: map ctrl+alt+t goto_layout tall +#: map ctrl+alt+s goto_layout stack +#: }}} + +#: Font sizes {{{ + +#: You can change the font size for all top-level kitty windows at a +#: time or only the current one. + +map kitty_mod+equal change_font_size all +2.0 +map kitty_mod+minus change_font_size all -2.0 +map kitty_mod+backspace change_font_size all 0 + +#: To setup shortcuts for specific font sizes:: + +#: map kitty_mod+f6 change_font_size all 10.0 + +#: To setup shortcuts to change only the current window's font size:: + +#: map kitty_mod+f6 change_font_size current 10.0 +#: }}} + +#: Select and act on visible text {{{ + +#: Use the hints kitten to select text and either pass it to an +#: external program or insert it into the terminal or copy it to the +#: clipboard. + +# map kitty_mod+e kitten hints + +#: Open a currently visible URL using the keyboard. The program used +#: to open the URL is specified in open_url_with. + +# map kitty_mod+p>f kitten hints --type path --program - + +#: Select a path/filename and insert it into the terminal. Useful, for +#: instance to run git commands on a filename output from a previous +#: git command. + +# map kitty_mod+p>shift+f kitten hints --type path + +#: Select a path/filename and open it with the default open program. + +# map kitty_mod+p>l kitten hints --type line --program - + +#: Select a line of text and insert it into the terminal. Use for the +#: output of things like: ls -1 + +# map kitty_mod+p>w kitten hints --type word --program - + +#: Select words and insert into terminal. + +# map kitty_mod+p>h kitten hints --type hash --program - + +#: Select something that looks like a hash and insert it into the +#: terminal. Useful with git, which uses sha1 hashes to identify +#: commits + + +#: The hints kitten has many more modes of operation that you can map +#: to different shortcuts. For a full description see kittens/hints. +#: }}} + +#: Miscellaneous {{{ + + +# map kitty_mod+f11 toggle_fullscreen +# map kitty_mod+u input_unicode_character +# map kitty_mod+f2 edit_config_file +# map kitty_mod+escape kitty_shell window + +#: Open the kitty shell in a new window/tab/overlay/os_window to +#: control kitty using commands. + +# map kitty_mod+a>m set_background_opacity +0.1 +# map kitty_mod+a>l set_background_opacity -0.1 +# map kitty_mod+a>1 set_background_opacity 1 +# map kitty_mod+a>d set_background_opacity default +# +# map kitty_mod+a>m set_background_opacity +0.1 +# map kitty_mod+a>l set_background_opacity -0.1 +map kitty_mod+, set_background_opacity 1 +map kitty_mod+. set_background_opacity default + +#: You can tell kitty to send arbitrary (UTF-8) encoded text to the +#: client program when pressing specified shortcut keys. For example:: + +#: map ctrl+alt+a send_text all Special text + +#: This will send "Special text" when you press the ctrl+alt+a key +#: combination. The text to be sent is a python string literal so you +#: can use escapes like \x1b to send control codes or \u21fb to send +#: unicode characters (or you can just input the unicode characters +#: directly as UTF-8 text). The first argument to send_text is the +#: keyboard modes in which to activate the shortcut. The possible +#: values are normal or application or kitty or a comma separated +#: combination of them. The special keyword all means all modes. The +#: modes normal and application refer to the DECCKM cursor key mode +#: for terminals, and kitty refers to the special kitty extended +#: keyboard protocol. + +#: Another example, that outputs a word and then moves the cursor to +#: the start of the line (same as pressing the Home key):: + +#: map ctrl+alt+a send_text normal Word\x1b[H +#: map ctrl+alt+a send_text application Word\x1bOH + +#: }}} + +map ctrl+space send_text all \x10 + +# }}} diff --git a/linux/home/.config/mimeapps.list b/linux/home/.config/mimeapps.list new file mode 100644 index 0000000..85d088c --- /dev/null +++ b/linux/home/.config/mimeapps.list @@ -0,0 +1,14 @@ +[Default Applications] +application/pdf=zathura.desktop; +application/tex=zathura.desktop; +image/png=phototonic.desktop +image/jpeg=phototonic.desktop; +video/mp4=mpv.desktop; +video/mkv=mpv.desktop; +inode/directory=pcmanfm.desktop + +[Added Associations] +image/png=phototonic.desktop; + +[Removed Associations] + diff --git a/linux/home/.config/picom/picom.conf b/linux/home/.config/picom/picom.conf new file mode 100644 index 0000000..d189670 --- /dev/null +++ b/linux/home/.config/picom/picom.conf @@ -0,0 +1,494 @@ +################################# +# Animations # +################################# +# requires https://github.com/jonaburg/picom +# (These are also the default values) +transition-length = 300 +transition-pow-x = 0.1 +transition-pow-y = 0.1 +transition-pow-w = 0.1 +transition-pow-h = 0.1 +size-transition = true + + +################################# +# Corners # +################################# +# requires: https://github.com/sdhand/compton or https://github.com/jonaburg/picom +corner-radius = 10.0; +rounded-corners-exclude = [ +#"window_type = 'normal'", +# "class_g = 'Bspwm' && class_i = 'presel_feedback'", +# "class_g = 'URxvt'", +# "class_g = 'alacritty'", +# "class_g = 'Org.gnome.Nautilus'", +# "class_g = 'Nemo'", +# "class_g = 'firefox'", +# "class_g = 'Rofi'", +# "class_g = 'Spotify'", +# "class_g = 'discord'", +# "class_g = 'Code'", +# "class_g = 'TelegramDesktop'", +# "class_g = 'YouTube Music'", + "class_g = 'Polybar'" +# "class_g = 'qutebrowser'", +# "class_g = 'Zathura'", +# "class_g = 'Pavucontrol'" + +]; +round-borders = 1; +#round-borders-exclude = [ +# "class_g = 'TelegramDesktop'", +#]; + + + +################################# +# Shadows # +################################# + + +# Enabled client-side shadows on windows. Note desktop windows +# (windows with '_NET_WM_WINDOW_TYPE_DESKTOP') never get shadow, +# unless explicitly requested using the wintypes option. +# +shadow = false; +#shadow = true; + +# The blur radius for shadows, in pixels. (defaults to 12) +# shadow-radius = 12 +shadow-radius = 20; + +# The opacity of shadows. (0.0 - 1.0, defaults to 0.75) +# shadow-opacity = .75 + +# The left offset for shadows, in pixels. (defaults to -15) +# shadow-offset-x = -15 +shadow-offset-x = -5; + +# The top offset for shadows, in pixels. (defaults to -15) +# shadow-offset-y = -15 +shadow-offset-y = -5; + +# Avoid drawing shadows on dock/panel windows. This option is deprecated, +# you should use the *wintypes* option in your config file instead. +# +# no-dock-shadow = false + +# Don't draw shadows on drag-and-drop windows. This option is deprecated, +# you should use the *wintypes* option in your config file instead. +# +# no-dnd-shadow = false + +# Red color value of shadow (0.0 - 1.0, defaults to 0). +# shadow-red = 0 + +# Green color value of shadow (0.0 - 1.0, defaults to 0). +# shadow-green = 0 + +# Blue color value of shadow (0.0 - 1.0, defaults to 0). +# shadow-blue = 0 + +# Do not paint shadows on shaped windows. Note shaped windows +# here means windows setting its shape through X Shape extension. +# Those using ARGB background is beyond our control. +# Deprecated, use +# shadow-exclude = 'bounding_shaped' +# or +# shadow-exclude = 'bounding_shaped && !rounded_corners' +# instead. +# +# shadow-ignore-shaped = '' + +# Specify a list of conditions of windows that should have no shadow. +# +# examples: +# shadow-exclude = "n:e:Notification"; +# +# shadow-exclude = [] +shadow-exclude = [ + "name = 'Notification'", + "class_g = 'Conky'", + #"class_g ?= 'Notify-osd'", + "class_g = 'Cairo-clock'", + "class_g = 'Polybar'", + "class_g = 'Nwg-menu'", + # "class_g = 'Rofi'" + "_GTK_FRAME_EXTENTS@:c" + ]; + +# Specify a X geometry that describes the region in which shadow should not +# be painted in, such as a dock window region. Use +# shadow-exclude-reg = "x10+0+0" +# for example, if the 10 pixels on the bottom of the screen should not have shadows painted on. +# +# shadow-exclude-reg = "" + +# Crop shadow of a window fully on a particular Xinerama screen to the screen. +# xinerama-shadow-crop = false + + +################################# +# Fading # +################################# + + +# Fade windows in/out when opening/closing and when opacity changes, +# unless no-fading-openclose is used. +# fading = false +fading = true + +# Opacity change between steps while fading in. (0.01 - 1.0, defaults to 0.028) +# fade-in-step = 0.028 +fade-in-step = 0.08; + +# Opacity change between steps while fading out. (0.01 - 1.0, defaults to 0.03) +# fade-out-step = 0.03 +fade-out-step = 0.08; + +# The time between steps in fade step, in milliseconds. (> 0, defaults to 10) +# fade-delta = 10 + +# Specify a list of conditions of windows that should not be faded. +# fade-exclude = [] + +# Do not fade on window open/close. +# no-fading-openclose = false + +# Do not fade destroyed ARGB windows with WM frame. Workaround of bugs in Openbox, Fluxbox, etc. +# no-fading-destroyed-argb = false + + +################################# +# Transparency / Opacity # +################################# + +# Opacity of inactive windows. (0.1 - 1.0, defaults to 1.0) +# inactive-opacity = 1 +inactive-opacity = 1; + +# Opacity of window titlebars and borders. (0.1 - 1.0, disabled by default) +# frame-opacity = 1.0 +frame-opacity = 1; + +# Default opacity for dropdown menus and popup menus. (0.0 - 1.0, defaults to 1.0) +# menu-opacity = 1.0 + +# Let inactive opacity set by -i override the '_NET_WM_OPACITY' values of windows. +# inactive-opacity-override = true +inactive-opacity-override = false; + +# Default opacity for active windows. (0.0 - 1.0, defaults to 1.0) +active-opacity = 1.0; + +# Dim inactive windows. (0.0 - 1.0, defaults to 0.0) +inactive-dim = 0.2 + +# Specify a list of conditions of windows that should always be considered focused. +# focus-exclude = [] +focus-exclude = ["class_g = 'Plank'", "class_g = 'Nwg-menu'", "class_g = 'st'", "class_g = 'kitty'", "class_g = 'wezterm'", "class_g = 'Alacritty'", "class_g = 'firefox'"]; + +# Use fixed inactive dim value, instead of adjusting according to window opacity. +# inactive-dim-fixed = 1.0 + +# Specify a list of opacity rules, in the format `PERCENT:PATTERN`, +# like `50:name *= "Firefox"`. picom-trans is recommended over this. +# Note we don't make any guarantee about possible conflicts with other +# programs that set '_NET_WM_WINDOW_OPACITY' on frame or client windows. +# example: +# opacity-rule = [ "80:class_g = 'URxvt'" ]; +opacity-rule = ["80:class_g = 'betterlockscreen'", "80:class_g = 'URxvt'", "100:class_g = 'firefox'", "100:class_g = 'Zathura'", "80:class_g = 'Spotify'", "80:class_g *?= 'Rofi'", "100:class_g = 'kitty' && focused", "100:class_g = 'kitty' && !focused", "100:class_g = 'Alacritty' && focused", "100:class_g = 'Alacritty' && !focused", "100:class_g = 'wezterm' && focused", "100:class_g = 'wezterm' && !focused"]; +# +#opacity-rule = ["85:class_g ?= 'Alacritty' && focused"]; + +#blur-background-exclude = ["class_g = 'scratchpad'"]; + +################################# +# Background-Blurring # +################################# + + +# Parameters for background blurring, see the *BLUR* section for more information. +blur-method = "dual_kawase"; +#blur-method = "gaussian"; +blur-strength = 6; +# blur-size = 12 +# +# blur-deviation = false + +# Blur background of semi-transparent / ARGB windows. +# Bad in performance, with driver-dependent behavior. +# The name of the switch may change without prior notifications. +# +blur-background = false; + +# Blur background of windows when the window frame is not opaque. +# Implies: +# blur-background +# Bad in performance, with driver-dependent behavior. The name may change. +# +# blur-background-frame = false + + +# Use fixed blur strength rather than adjusting according to window opacity. +#blur-background-fixed = false + + +# Specify the blur convolution kernel, with the following format: +# example: +# blur-kern = "5,5,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1"; +# +# blur-kern = '' +#blur-kern = "3x3box"; +blur-kern = "7x7box"; + +# Exclude conditions for background blur. +# blur-background-exclude = [] +blur-background-exclude = [ + "window_type = 'dock'", + "window_type = 'desktop'", + "_GTK_FRAME_EXTENTS@:c", + "class_g = 'kitty'", + "class_g = 'Alacritty'", + "class_g = 'wezterm'", +# "class_g = 'Polybar'", + "class_g = 'URxvt'", + "class_g = 'scratchpad'", + "class_g = 'heads-up-display'", + "class_g = 'Firefox'", + "class_g = 'firefox'", + "class_g = 'discord'", + "class_g = 'Rofi'", + "class_g = 'Zathura'", + "class_g = 'Notification'", +]; + +################################# +# General Settings # +################################# + +# Daemonize process. Fork to background after initialization. Causes issues with certain (badly-written) drivers. +# daemon = false + +# Specify the backend to use: `xrender`, `glx`, or `xr_glx_hybrid`. +# `xrender` is the default one. +# +#experimental-backends = true; +#backend = 'glx' +backend = "glx"; +#backend = "xrender"; + +# Enable/disable VSync. +# vsync = false +vsync = true + +# Enable remote control via D-Bus. See the *D-BUS API* section below for more details. +# dbus = false + +# Try to detect WM windows (a non-override-redirect window with no +# child that has 'WM_STATE') and mark them as active. +# +# mark-wmwin-focused = false +mark-wmwin-focused = true; + +# Mark override-redirect windows that doesn't have a child window with 'WM_STATE' focused. +mark-ovredir-focused = false; +#mark-ovredir-focused = true; + +# Try to detect windows with rounded corners and don't consider them +# shaped windows. The accuracy is not very high, unfortunately. +# +# detect-rounded-corners = false +detect-rounded-corners = true; + +# Detect '_NET_WM_OPACITY' on client windows, useful for window managers +# not passing '_NET_WM_OPACITY' of client windows to frame windows. +# +# detect-client-opacity = false +detect-client-opacity = true; + +# Specify refresh rate of the screen. If not specified or 0, picom will +# try detecting this with X RandR extension. +# +# refresh-rate = 60 +refresh-rate = 0 + +# Limit picom to repaint at most once every 1 / 'refresh_rate' second to +# boost performance. This should not be used with +# vsync drm/opengl/opengl-oml +# as they essentially does sw-opti's job already, +# unless you wish to specify a lower refresh rate than the actual value. +# +# sw-opti = + +# Use EWMH '_NET_ACTIVE_WINDOW' to determine currently focused window, +# rather than listening to 'FocusIn'/'FocusOut' event. Might have more accuracy, +# provided that the WM supports it. +# +# use-ewmh-active-win = false + +# Unredirect all windows if a full-screen opaque window is detected, +# to maximize performance for full-screen windows. Known to cause flickering +# when redirecting/unredirecting windows. +# +# unredir-if-possible = false + +# Delay before unredirecting the window, in milliseconds. Defaults to 0. +# unredir-if-possible-delay = 0 + +# Conditions of windows that shouldn't be considered full-screen for unredirecting screen. +# unredir-if-possible-exclude = [] + +# Use 'WM_TRANSIENT_FOR' to group windows, and consider windows +# in the same group focused at the same time. +# +# detect-transient = false +detect-transient = true + +# Use 'WM_CLIENT_LEADER' to group windows, and consider windows in the same +# group focused at the same time. 'WM_TRANSIENT_FOR' has higher priority if +# detect-transient is enabled, too. +# +# detect-client-leader = false +detect-client-leader = true + +# Resize damaged region by a specific number of pixels. +# A positive value enlarges it while a negative one shrinks it. +# If the value is positive, those additional pixels will not be actually painted +# to screen, only used in blur calculation, and such. (Due to technical limitations, +# with use-damage, those pixels will still be incorrectly painted to screen.) +# Primarily used to fix the line corruption issues of blur, +# in which case you should use the blur radius value here +# (e.g. with a 3x3 kernel, you should use `--resize-damage 1`, +# with a 5x5 one you use `--resize-damage 2`, and so on). +# May or may not work with *--glx-no-stencil*. Shrinking doesn't function correctly. +# +# resize-damage = 1 + +# Specify a list of conditions of windows that should be painted with inverted color. +# Resource-hogging, and is not well tested. +# +# invert-color-include = [] + +# GLX backend: Avoid using stencil buffer, useful if you don't have a stencil buffer. +# Might cause incorrect opacity when rendering transparent content (but never +# practically happened) and may not work with blur-background. +# My tests show a 15% performance boost. Recommended. +# +# glx-no-stencil = false + +# GLX backend: Avoid rebinding pixmap on window damage. +# Probably could improve performance on rapid window content changes, +# but is known to break things on some drivers (LLVMpipe, xf86-video-intel, etc.). +# Recommended if it works. +# +# glx-no-rebind-pixmap = false + +# Disable the use of damage information. +# This cause the whole screen to be redrawn everytime, instead of the part of the screen +# has actually changed. Potentially degrades the performance, but might fix some artifacts. +# The opposing option is use-damage +# +# no-use-damage = false +use-damage = true + +# Use X Sync fence to sync clients' draw calls, to make sure all draw +# calls are finished before picom starts drawing. Needed on nvidia-drivers +# with GLX backend for some users. +# +# xrender-sync-fence = false + +# GLX backend: Use specified GLSL fragment shader for rendering window contents. +# See `compton-default-fshader-win.glsl` and `compton-fake-transparency-fshader-win.glsl` +# in the source tree for examples. +# +# glx-fshader-win = '' + +# Force all windows to be painted with blending. Useful if you +# have a glx-fshader-win that could turn opaque pixels transparent. +# +# force-win-blend = false + +# Do not use EWMH to detect fullscreen windows. +# Reverts to checking if a window is fullscreen based only on its size and coordinates. +# +# no-ewmh-fullscreen = false + +# Dimming bright windows so their brightness doesn't exceed this set value. +# Brightness of a window is estimated by averaging all pixels in the window, +# so this could comes with a performance hit. +# Setting this to 1.0 disables this behaviour. Requires --use-damage to be disabled. (default: 1.0) +# +# max-brightness = 1.0 + +# Make transparent windows clip other windows like non-transparent windows do, +# instead of blending on top of them. +# +# transparent-clipping = false + +# Set the log level. Possible values are: +# "trace", "debug", "info", "warn", "error" +# in increasing level of importance. Case doesn't matter. +# If using the "TRACE" log level, it's better to log into a file +# using *--log-file*, since it can generate a huge stream of logs. +# +# log-level = "debug" +log-level = "warn"; + +# Set the log file. +# If *--log-file* is never specified, logs will be written to stderr. +# Otherwise, logs will to written to the given file, though some of the early +# logs might still be written to the stderr. +# When setting this option from the config file, it is recommended to use an absolute path. +# +# log-file = '/path/to/your/log/file' + +# Show all X errors (for debugging) +# show-all-xerrors = false + +# Write process ID to a file. +# write-pid-path = '/path/to/your/log/file' + +# Window type settings +# +# 'WINDOW_TYPE' is one of the 15 window types defined in EWMH standard: +# "unknown", "desktop", "dock", "toolbar", "menu", "utility", +# "splash", "dialog", "normal", "dropdown_menu", "popup_menu", +# "tooltip", "notification", "combo", and "dnd". +# +# Following per window-type options are available: :: +# +# fade, shadow::: +# Controls window-type-specific shadow and fade settings. +# +# opacity::: +# Controls default opacity of the window type. +# +# focus::: +# Controls whether the window of this type is to be always considered focused. +# (By default, all window types except "normal" and "dialog" has this on.) +# +# full-shadow::: +# Controls whether shadow is drawn under the parts of the window that you +# normally won't be able to see. Useful when the window has parts of it +# transparent, and you want shadows in those areas. +# +# redir-ignore::: +# Controls whether this type of windows should cause screen to become +# redirected again after been unredirected. If you have unredir-if-possible +# set, and doesn't want certain window to cause unnecessary screen redirection, +# you can set this to `true`. +# +wintypes: +{ + #normal = { full-shadow = true; }; + #menu = { full-shadow = true; }; + tooltip = { fade = true; shadow = true; opacity = 0.75; focus = true; full-shadow = false; }; + dock = { shadow = false; }; + dnd = { shadow = false; }; + popup_menu = { full-shadow = false opacity = 0.8; }; + #utility = { full-shadow = true; }; + #toolbar = { full-shadow = true; }; + notification = { opacity = 0.75; } +}; + diff --git a/linux/home/.config/plank/dock/launchers/Alacritty.dockitem b/linux/home/.config/plank/dock/launchers/Alacritty.dockitem new file mode 100644 index 0000000..b3091c5 --- /dev/null +++ b/linux/home/.config/plank/dock/launchers/Alacritty.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=file:///usr/share/applications/Alacritty.desktop diff --git a/linux/home/.config/plank/dock/launchers/com.obsproject.Studio.dockitem b/linux/home/.config/plank/dock/launchers/com.obsproject.Studio.dockitem new file mode 100644 index 0000000..7626308 --- /dev/null +++ b/linux/home/.config/plank/dock/launchers/com.obsproject.Studio.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=file:///usr/share/applications/com.obsproject.Studio.desktop diff --git a/linux/home/.config/plank/dock/launchers/discord.dockitem b/linux/home/.config/plank/dock/launchers/discord.dockitem new file mode 100644 index 0000000..c6736ba --- /dev/null +++ b/linux/home/.config/plank/dock/launchers/discord.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=file:///usr/share/applications/discord.desktop diff --git a/linux/home/.config/plank/dock/launchers/firefox.dockitem b/linux/home/.config/plank/dock/launchers/firefox.dockitem new file mode 100644 index 0000000..0dbfff7 --- /dev/null +++ b/linux/home/.config/plank/dock/launchers/firefox.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=file:///usr/share/applications/firefox.desktop diff --git a/linux/home/.config/plank/dock/launchers/gimp.dockitem b/linux/home/.config/plank/dock/launchers/gimp.dockitem new file mode 100644 index 0000000..c9f9438 --- /dev/null +++ b/linux/home/.config/plank/dock/launchers/gimp.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=file:///usr/share/applications/gimp.desktop diff --git a/linux/home/.config/plank/dock/launchers/google-chrome.dockitem b/linux/home/.config/plank/dock/launchers/google-chrome.dockitem new file mode 100644 index 0000000..cd04294 --- /dev/null +++ b/linux/home/.config/plank/dock/launchers/google-chrome.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=file:///usr/share/applications/google-chrome.desktop diff --git a/linux/home/.config/plank/dock/launchers/obsidian.dockitem b/linux/home/.config/plank/dock/launchers/obsidian.dockitem new file mode 100644 index 0000000..0170dbd --- /dev/null +++ b/linux/home/.config/plank/dock/launchers/obsidian.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=file:///usr/share/applications/obsidian.desktop diff --git a/linux/home/.config/plank/dock/launchers/org.gnome.Nautilus.dockitem b/linux/home/.config/plank/dock/launchers/org.gnome.Nautilus.dockitem new file mode 100644 index 0000000..ae5f8d9 --- /dev/null +++ b/linux/home/.config/plank/dock/launchers/org.gnome.Nautilus.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=file:///usr/share/applications/org.gnome.Nautilus.desktop diff --git a/linux/home/.config/plank/dock/launchers/spotify.dockitem b/linux/home/.config/plank/dock/launchers/spotify.dockitem new file mode 100644 index 0000000..8ae95b4 --- /dev/null +++ b/linux/home/.config/plank/dock/launchers/spotify.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=file:///usr/share/applications/spotify.desktop diff --git a/linux/home/.config/plank/dock/launchers/steam.dockitem b/linux/home/.config/plank/dock/launchers/steam.dockitem new file mode 100644 index 0000000..143d3b4 --- /dev/null +++ b/linux/home/.config/plank/dock/launchers/steam.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=file:///usr/share/applications/steam.desktop diff --git a/linux/home/.config/plank/dock/launchers/trash.dockitem b/linux/home/.config/plank/dock/launchers/trash.dockitem new file mode 100644 index 0000000..567a63e --- /dev/null +++ b/linux/home/.config/plank/dock/launchers/trash.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=docklet://trash diff --git a/linux/home/.config/plank/dock/launchers/virtualbox.dockitem b/linux/home/.config/plank/dock/launchers/virtualbox.dockitem new file mode 100644 index 0000000..fa95934 --- /dev/null +++ b/linux/home/.config/plank/dock/launchers/virtualbox.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=file:///usr/share/applications/virtualbox.desktop diff --git a/linux/home/.config/plank/dock/launchers/vlc.dockitem b/linux/home/.config/plank/dock/launchers/vlc.dockitem new file mode 100644 index 0000000..c20771a --- /dev/null +++ b/linux/home/.config/plank/dock/launchers/vlc.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=file:///usr/share/applications/vlc.desktop diff --git a/linux/home/.config/plank/dock1/launchers/code-oss.dockitem b/linux/home/.config/plank/dock1/launchers/code-oss.dockitem new file mode 100644 index 0000000..3d8af2b --- /dev/null +++ b/linux/home/.config/plank/dock1/launchers/code-oss.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=file:///usr/share/applications/code-oss.desktop diff --git a/linux/home/.config/plank/dock1/launchers/com.obsproject.Studio.dockitem b/linux/home/.config/plank/dock1/launchers/com.obsproject.Studio.dockitem new file mode 100644 index 0000000..39554a1 --- /dev/null +++ b/linux/home/.config/plank/dock1/launchers/com.obsproject.Studio.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=file:///home/srdusr/.local/share/applications/com.obsproject.Studio.desktop diff --git a/linux/home/.config/plank/dock1/launchers/discord.dockitem b/linux/home/.config/plank/dock1/launchers/discord.dockitem new file mode 100644 index 0000000..c6736ba --- /dev/null +++ b/linux/home/.config/plank/dock1/launchers/discord.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=file:///usr/share/applications/discord.desktop diff --git a/linux/home/.config/plank/dock1/launchers/firefox.dockitem b/linux/home/.config/plank/dock1/launchers/firefox.dockitem new file mode 100644 index 0000000..0dbfff7 --- /dev/null +++ b/linux/home/.config/plank/dock1/launchers/firefox.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=file:///usr/share/applications/firefox.desktop diff --git a/linux/home/.config/plank/dock1/launchers/obsidian.dockitem b/linux/home/.config/plank/dock1/launchers/obsidian.dockitem new file mode 100644 index 0000000..0170dbd --- /dev/null +++ b/linux/home/.config/plank/dock1/launchers/obsidian.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=file:///usr/share/applications/obsidian.desktop diff --git a/linux/home/.config/plank/dock1/launchers/org.qbittorrent.qBittorrent.dockitem b/linux/home/.config/plank/dock1/launchers/org.qbittorrent.qBittorrent.dockitem new file mode 100644 index 0000000..7475952 --- /dev/null +++ b/linux/home/.config/plank/dock1/launchers/org.qbittorrent.qBittorrent.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=file:///usr/share/applications/org.qbittorrent.qBittorrent.desktop diff --git a/linux/home/.config/plank/dock1/launchers/pcmanfm.dockitem b/linux/home/.config/plank/dock1/launchers/pcmanfm.dockitem new file mode 100644 index 0000000..bc3af9d --- /dev/null +++ b/linux/home/.config/plank/dock1/launchers/pcmanfm.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=file:///usr/share/applications/pcmanfm.desktop diff --git a/linux/home/.config/plank/dock1/launchers/phototonic.dockitem b/linux/home/.config/plank/dock1/launchers/phototonic.dockitem new file mode 100644 index 0000000..e391893 --- /dev/null +++ b/linux/home/.config/plank/dock1/launchers/phototonic.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=file:///home/srdusr/.local/share/applications/phototonic.desktop diff --git a/linux/home/.config/plank/dock1/launchers/steam.dockitem b/linux/home/.config/plank/dock1/launchers/steam.dockitem new file mode 100644 index 0000000..143d3b4 --- /dev/null +++ b/linux/home/.config/plank/dock1/launchers/steam.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=file:///usr/share/applications/steam.desktop diff --git a/linux/home/.config/plank/dock1/launchers/trash.dockitem b/linux/home/.config/plank/dock1/launchers/trash.dockitem new file mode 100644 index 0000000..567a63e --- /dev/null +++ b/linux/home/.config/plank/dock1/launchers/trash.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=docklet://trash diff --git a/linux/home/.config/plank/dock1/launchers/vlc.dockitem b/linux/home/.config/plank/dock1/launchers/vlc.dockitem new file mode 100644 index 0000000..c20771a --- /dev/null +++ b/linux/home/.config/plank/dock1/launchers/vlc.dockitem @@ -0,0 +1,2 @@ +[PlankDockItemPreferences] +Launcher=file:///usr/share/applications/vlc.desktop diff --git a/linux/home/.config/polybar/config.ini b/linux/home/.config/polybar/config.ini new file mode 100644 index 0000000..afb14a8 --- /dev/null +++ b/linux/home/.config/polybar/config.ini @@ -0,0 +1,671 @@ +;========================================================== +; +; +; ██████╗ ██████╗ ██╗ ██╗ ██╗██████╗ █████╗ ██████╗ +; ██╔══██╗██╔═══██╗██║ ╚██╗ ██╔╝██╔══██╗██╔══██╗██╔══██╗ +; ██████╔╝██║ ██║██║ ╚████╔╝ ██████╔╝███████║██████╔╝ +; ██╔═══╝ ██║ ██║██║ ╚██╔╝ ██╔══██╗██╔══██║██╔══██╗ +; ██║ ╚██████╔╝███████╗██║ ██████╔╝██║ ██║██║ ██║ +; ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ +; +; +; To learn more about how to configure Polybar +; go to https://github.com/polybar/polybar +; +; The README contains a lot of information +; +;========================================================== + +[settings] +screenchange-reload = true +pseudo-transparency = true +;throttle-output = 5 +;throttle-output-for = 10 +;compositing-background = source +;compositing-foreground = over +;compositing-overline = over +;compositing-underline = over +;compositing-border = over + +[colors] +foreground = #fafafa +foreground-alt = #aaCECCC9 +;background = #aa000000 +background = #dd000000 +background-alt = #aaCECCC9 +disabled = #707880 +alert = #ff8989 +blue = #61afef +dark_blue = #42A5F5 +light_blue = #ADD8E6 +nord = #81a1c1 +purple = #c882e7 +orange = #E57C46 +gray = #676E95 +red = #EC7875 +pink = #EC407A +yellow = #FDD835 +amber = #FBC02D +indigo = #6C77BB +green = #61C766 +lime = #B9C244 + +[fonts] +font0 = "SF Pro Mono:style=Display Bold:size=10;2" +font1 = "Material Design Icons:style=Bold:size=11.5;2" +font2 = "Material Design Icons:style=Bold:size=13.5;2" +font3 = "SF Pro:style=Medium:size=10.5;2" +font4 = "SF Pro:style=Regular:size=13;2" +font5 = "UbuntuMono Nerd font:size=11;2" +font6 = "Feather:style=Regular:size=15;4" +font7 = "Font Awesome 6 Pro Solid:style=Solid:size=14;4" +font8 = "JetBrainsMono Nerd Font:size=9;2" +font9 = "Fira Nerd font:size=11;2" +font10 = "RobotoMono Nerd Font:weight=bold:size=9;2" +font11 = "RobotoMono Nerd Font:size=10;3" +font12 = "RobotoMono Nerd Font:size=11;3" + +[common] +line-size = 1pt +enable-ipc = true +wm-restack = bspwm +dpi = 96 +font-0 = ${fonts.font0} +font-1 = ${fonts.font1} +font-2 = ${fonts.font2} +font-3 = ${fonts.font3} +font-4 = ${fonts.font4} +font-5 = ${fonts.font5} +font-6 = ${fonts.font6} +font-7 = ${fonts.font7} +font-8 = ${fonts.font8} +font-9 = ${fonts.font9} +font-10 = ${fonts.font10} +font-11 = ${fonts.font11} +font-12 = ${fonts.font12} +background = ${colors.background} +foreground = ${colors.foreground} + +[bar/main-0] +monitor = ${env:MONITOR:} +width = 99% +offset-x = 0.5% +offset-y = 0.5% +height = 20pt +radius = 10.0 +fixed-center = true +inherit = common +;modules-left = space space menu space space space bspwm space space +modules-left = space space menu space space space bspwm space space big_space space space cpu space sep space memory space sep space temperature space sep space battery +modules-center = space space date space space +;modules-center = space space cpu space sep space memory space sep space temperature space sep space battery big_space date big_space wireless-network space sep space netspeed space sep space vpn space space +;modules-right = space space mic space sep space volume space sep space backlight space sep space inbox space sep space systray space space sep control space space +modules-right = space space wireless-network space sep space netspeed space sep space vpn space space big_space space space mic space sep space volume space sep space backlight space sep space inbox space sep space systray space space sep control space space + +[bar/main-1] +monitor = ${env:MONITOR:} +;width = 260px +width = 180px +offset-x = 0%:+10px +offset-y = 0.5% +height = 20pt +radius = 10.0 +fixed-center = true +inherit = common +modules-left = space space menu space space space bspwm space space + +[bar/main-2] +monitor = ${env:MONITOR:} +;width = 230px +;offset-x = 33.3333%:-130px +width = 295px +offset-x = 33.3333%:-195px +offset-y = 0.5% +height = 20pt +radius = 10.0 +fixed-center = true +inherit = common +modules-center = space space cpu space sep space memory space sep space temperature space sep space battery space space + +[bar/main-3] +monitor = ${env:MONITOR:} +;width = 220px +;width = 150px +width = 170px +;offset-x = 50%:-110px +;offset-x = 50%:-110px +offset-x = 50%:-85px +offset-y = 0.5% +height = 20pt +radius = 10.0 +fixed-center = true +inherit = common +font-0 = "RobotoMono Nerd Font:weight=bold:size=9;2" +font-1 = "RobotoMono Nerd Font:size=10;3" +font-2 = "RobotoMono Nerd Font:size=11;3" +;modules-center = space space day space sep space date space sep space time space space +modules-center = space space date space space + +[bar/main-4] +monitor = ${env:MONITOR:} +;width = 230px +;offset-x = 66.6667%:-100px +width = 295px +offset-x = 66.6667%:-100px +offset-y = 0.5% +height = 20pt +radius = 10.0 +fixed-center = true +;padding-right = 4 +inherit = common +;modules-center = space space space sep space vpn space space +modules-center = space space wireless-network space sep space netspeed space sep space vpn space space +;modules-center = space space wireless-network netspeed space sep space space space + +[bar/main-5] +monitor = ${env:MONITOR:} +;width = 260px +width = 180px +offset-x = 100%:-190px +offset-y = 0.5% +height = 20pt +radius = 10.0 +fixed-center = true +padding-left = 2 +;padding-right = 2 +inherit = common +modules-right = space space mic space sep space volume space sep space backlight space sep space inbox space sep space systray space space sep control space space + + +;; Modules + +[module/bspwm] +type = internal/bspwm +format = +format-padding = 2 +format-foreground = ${colors.foreground} +index-sort = true +enable-click = true +reverse-scroll = false +label-focused = ● +label-focused-padding = 1 +label-occupied = "%name%" +label-occupied-foreground = ${colors.foreground} +label-occupied-padding = 1 +;label-empty = ○ +label-empty="%name%" +label-empty-foreground = ${colors.disabled} +label-empty-padding = 1 +format-font = 5 + +[module/xwindow] +type = internal/xwindow +format =