diff --git a/flake.lock b/flake.lock index f93c7b6..5b8c7a2 100755 --- a/flake.lock +++ b/flake.lock @@ -80,6 +80,29 @@ "type": "github" } }, + "glide": { + "inputs": { + "home-manager": [ + "home-manager" + ], + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1773656868, + "narHash": "sha256-IvWd8A3MM2qASf2U5diOoYEc2dCxqR4BOhB5RuOQnZM=", + "owner": "glide-browser", + "repo": "glide.nix", + "rev": "1a3dd001865f6ac5a3562d2cb484388672ad6eaf", + "type": "github" + }, + "original": { + "owner": "glide-browser", + "repo": "glide.nix", + "type": "github" + } + }, "home-manager": { "inputs": { "nixpkgs": [ @@ -252,6 +275,7 @@ }, "root": { "inputs": { + "glide": "glide", "home-manager": "home-manager", "impermanence": "impermanence", "llm-agents": "llm-agents", diff --git a/flake.nix b/flake.nix index a03200b..a92e6f5 100755 --- a/flake.nix +++ b/flake.nix @@ -11,6 +11,12 @@ # to avoid problems caused by different versions of nixpkgs. inputs.nixpkgs.follows = "nixpkgs"; }; + glide = { + url = "github:glide-browser/glide.nix"; + # optionally: follow your flake's inputs + inputs.nixpkgs.follows = "nixpkgs"; + inputs.home-manager.follows = "home-manager"; + }; impermanence.url = "github:nix-community/impermanence"; plasma-manager = { url = "github:nix-community/plasma-manager"; @@ -29,6 +35,7 @@ impermanence, plasma-manager, llm-agents, + glide, # nix-flatpak, }@inputs: let diff --git a/global/default.nix b/global/default.nix index 3eb42da..faec720 100755 --- a/global/default.nix +++ b/global/default.nix @@ -235,6 +235,14 @@ haruna ]; + fonts.packages = with pkgs; [ + twitter-color-emoji + ]; + + fonts.fontconfig.defaultFonts = { + emoji = [ "Twitter Color Emoji" ]; + }; + services.usbmuxd = { enable = true; package = pkgs.usbmuxd2; diff --git a/machines/latitude/configuration.nix b/machines/latitude/configuration.nix index ea2939b..5c225b5 100755 --- a/machines/latitude/configuration.nix +++ b/machines/latitude/configuration.nix @@ -17,7 +17,7 @@ ../../modules/development/default.nix ../../modules/fabrication/default.nix ../../modules/gaming/default.nix - ../../modules/kde/default.nix + ../../modules/sway/default.nix ../../modules/virtualization/default.nix # ../../modules/vr/default.nix # ../../global/eraseyourdarlings.nix diff --git a/machines/latitude/hardware-configuration.nix b/machines/latitude/hardware-configuration.nix index c8f1f07..e90be79 100755 --- a/machines/latitude/hardware-configuration.nix +++ b/machines/latitude/hardware-configuration.nix @@ -14,6 +14,8 @@ (modulesPath + "/installer/scan/not-detected.nix") ]; + # services.tlp.enable = true; + boot.initrd.availableKernelModules = [ "xhci_pci" "thunderbolt" @@ -27,13 +29,13 @@ boot.extraModulePackages = [ ]; fileSystems."/" = { - device = "/dev/disk/by-uuid/d9fee0ac-b35f-4d21-9461-3497af72d8bd"; + device = "/dev/disk/by-label/NIXROOT"; fsType = "ext4"; }; - boot.resumeDevice = "/dev/disk/by-uuid/d9fee0ac-b35f-4d21-9461-3497af72d8bd"; + boot.resumeDevice = "/dev/disk/by-label/NIXSWAP"; fileSystems."/boot" = { - device = "/dev/disk/by-uuid/299C-03A0"; + device = "/dev/disk/by-label/NIXBOOT"; fsType = "vfat"; options = [ "fmask=0022" @@ -43,14 +45,13 @@ swapDevices = [ { - device = "/.swapfile"; - size = 16 * 1024; + device = "/dev/disk/by-label/NIXSWAP"; } ]; services.power-profiles-daemon.enable = true; # Suspend first then hibernate when closing the lid - services.logind.settings.Login.LidSwitch = "suspend-then-hibernate"; + services.logind.settings.Login.LidSwitch = "ignore"; # Hibernate on power button pressed services.logind.settings.Login.PowerKey = "hibernate"; services.logind.settings.Login.PowerKeyLongPress = "poweroff"; @@ -58,14 +59,27 @@ # Suspend first boot.kernelParams = [ "mem_sleep_default=deep" - "resume_offset=62050304" ]; # Define time delay for hibernation - systemd.sleep.extraConfig = '' - HibernateDelaySec=15m - SuspendState=mem - ''; + systemd.sleep.settings.Sleep = { + HibernateDelaySec = 300; + }; + + # facial recognition + security.pam.howdy.enable = true; + services.howdy.enable = true; + services.linux-enable-ir-emitter.enable = true; # lmao + # by default face is good enough + security.pam.howdy.control = "sufficient"; + services.howdy.settings = { + core = { + workaround = "off"; + }; + video = { + timeout = "20"; + }; + }; nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux"; hardware.cpu.intel.updateMicrocode = lib.mkDefault config.hardware.enableRedistributableFirmware; diff --git a/machines/latitude/home.nix b/machines/latitude/home.nix index 5bb26d7..0c05993 100755 --- a/machines/latitude/home.nix +++ b/machines/latitude/home.nix @@ -13,6 +13,7 @@ imports = [ ../../home/default.nix + ../../modules/sway/home.nix # ../../modules/kde/home.nix ]; diff --git a/modules/sway/default.nix b/modules/sway/default.nix new file mode 100644 index 0000000..4fa3209 --- /dev/null +++ b/modules/sway/default.nix @@ -0,0 +1,77 @@ +{ + config, + pkgs, + lib, + inputs, + ... +}: +let + configure-gtk = pkgs.writeTextFile { + name = "configure-gtk"; + destination = "/bin/configure-gtk"; + executable = true; + text = + let + schema = pkgs.gsettings-desktop-schemas; + datadir = "${schema}/share/gsettings-schemas/${schema.name}"; + in + '' + export XDG_DATA_DIRS=${datadir}:$XDG_DATA_DIRS + gnome_schema=org.gnome.desktop.interface + gsettings set $gnome_schema gtk-theme 'Dracula' + ''; + }; +in +{ + environment.systemPackages = with pkgs; [ + wl-clipboard # Copy/Paste functionality. + mako # Notification utility. + ]; + + # Enables Gnome Keyring to store secrets for applications. + services.gnome.gnome-keyring.enable = true; + + xdg.portal = { + enable = true; + extraPortals = [ + pkgs.xdg-desktop-portal-gtk + pkgs.xdg-desktop-portal-wlr + ]; + }; + + security.polkit.enable = true; + + # Enable Sway. + programs.sway = { + enable = true; + wrapperFeatures.gtk = false; + extraPackages = [ + pkgs.foot + pkgs.swayidle + pkgs.swaylock + pkgs.wmenu + pkgs.wl-clipboard + pkgs.mako + pkgs.kdePackages.spectacle + pkgs.kdePackages.kate + pkgs.kdePackages.filelight + inputs.glide.packages.${pkgs.stdenv.hostPlatform.system}.default + pkgs.swaybg + pkgs.pulseaudioFull + pkgs.waybar + pkgs.dracula-theme # gtk theme + pkgs.brightnessctl + configure-gtk + ]; + }; + + services.greetd = { + enable = true; + settings = { + default_session = { + command = "${pkgs.tuigreet}/bin/tuigreet --remember --time --cmd sway"; + user = "greeter"; + }; + }; + }; +} diff --git a/modules/sway/home.nix b/modules/sway/home.nix new file mode 100644 index 0000000..a0a4e9f --- /dev/null +++ b/modules/sway/home.nix @@ -0,0 +1,308 @@ +{ pkgs, ... }: +{ + wayland.windowManager.sway = { + enable = true; + wrapperFeatures.gtk = true; # Fixes common issues with GTK 3 apps + config = rec { + modifier = "Mod4"; + # Use kitty as default terminal + terminal = "foot"; + keybindings = { + # Brightness Controls + "XF86MonBrightnessDown" = "exec brightnessctl s 5%-"; + "XF86MonBrightnessUp" = "exec brightnessctl s 5%+"; + + # Volume Controls + "XF86AudioRaiseVolume" = "exec pactl set-sink-volume @DEFAULT_SINK@ +1%"; + "XF86AudioLowerVolume" = "exec pactl set-sink-volume @DEFAULT_SINK@ -1%"; + "XF86AudioMute" = "exec pactl set-sink-mute @DEFAULT_SINK@ toggle"; + + "Mod4+q" = "kill"; + "Mod4+Return" = "exec foot"; + "Mod4+Shift+q" = "kill"; + "Mod4+d" = "exec wmenu-run"; + + "Mod4+Left" = "focus left"; + "Mod4+Down" = "focus down"; + "Mod4+Up" = "focus up"; + "Mod4+Right" = "focus right"; + + "Mod4+Shift+Left" = "move left"; + "Mod4+Shift+Down" = "move down"; + "Mod4+Shift+Up" = "move up"; + "Mod4+Shift+Right" = "move right"; + + "Mod4+b" = "splith"; + "Mod4+v" = "splitv"; + "Mod4+f" = "fullscreen toggle"; + "Mod4+a" = "focus parent"; + + "Mod4+s" = "layout stacking"; + "Mod4+w" = "layout tabbed"; + "Mod4+e" = "layout toggle split"; + + "Mod4+Shift+space" = "floating toggle"; + "Mod4+space" = "focus mode_toggle"; + + "Mod4+1" = "workspace number 1"; + "Mod4+2" = "workspace number 2"; + "Mod4+3" = "workspace number 3"; + "Mod4+4" = "workspace number 4"; + "Mod4+5" = "workspace number 5"; + "Mod4+6" = "workspace number 6"; + "Mod4+7" = "workspace number 7"; + "Mod4+8" = "workspace number 8"; + "Mod4+9" = "workspace number 9"; + "Mod4+0" = "workspace number 10"; + + "Mod4+Shift+1" = "move container to workspace number 1"; + "Mod4+Shift+2" = "move container to workspace number 2"; + "Mod4+Shift+3" = "move container to workspace number 3"; + "Mod4+Shift+4" = "move container to workspace number 4"; + "Mod4+Shift+5" = "move container to workspace number 5"; + "Mod4+Shift+6" = "move container to workspace number 6"; + "Mod4+Shift+7" = "move container to workspace number 7"; + "Mod4+Shift+8" = "move container to workspace number 8"; + "Mod4+Shift+9" = "move container to workspace number 9"; + "Mod4+Shift+0" = "move container to workspace number 10"; + + "Mod4+Shift+minus" = "move scratchpad"; + "Mod4+minus" = "scratchpad show"; + + "Mod4+p" = "[app_id=\"trilium\"] scratchpad show, resize set 90 ppt 90 ppt, move position center"; + "Mod4+g" = "exec glide-browser"; + + "Mod4+Shift+i" = "exec makoctl invoke && makoctl dismiss"; + "Mod4+i" = "exec makoctl dismiss"; + + "Mod4+Shift+c" = "reload"; + "Mod4+Shift+e" = + "exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'"; + + "Mod4+r" = "mode resize"; + + "Mod4+c" = "[app_id=\"discord\"] scratchpad show, resize set 90 ppt 90 ppt, move position center"; + + "Mod4+j" = "[class=\"Jami\"] scratchpad show, resize set 90 ppt 90 ppt, move position center"; + + }; + bars = [ + { + command = "${pkgs.waybar}/bin/waybar"; + } + ]; + output = { + eDP-1 = { + scale = "1.25"; + }; + }; + input = { + "type:touchpad" = { + # Enables or disables tap for specified input device. + tap = "enabled"; + # Enables or disables natural (inverted) scrolling for the specified input device. + natural_scroll = "enabled"; + # Enables or disables disable-while-typing for the specified input device. + dwt = "disabled"; + }; + }; + bindswitches = { + "lid:on" = { + reload = true; + locked = true; + action = "exec systemctl suspend-then-hibernate"; + }; + }; + startup = [ + # { command = "swaybg -i ~/.background-image -m fill"; } + { command = "discord --enable-features=UseOzonePlatform --ozone-platform=wayland"; } + { command = "trilium"; } + { command = "jami"; } + ]; + window.commands = [ + { + criteria = { + app_id = "discord"; + }; + command = "move scratchpad"; + } + { + criteria = { + app_id = "trilium"; + }; + command = "move scratchpad"; + } + { + criteria = { + class = "Jami"; + }; + command = "move scratchpad"; + } + ]; + }; + extraConfig = '' + exec_always swaymsg output "*" bg ~/.background-image fill + ''; + }; + + # yeah this was written by ai if it wasn't obvious + systemd.user.services.random-background = { + Unit = { + Description = "Update ~/.background_image with a random wallpaper"; + }; + Service = { + Type = "oneshot"; + # pkgs.writeShellScript creates an executable script in the nix store + ExecStart = "${pkgs.writeShellScript "random-bg-script" '' + # Nix uses 'set -e' by default, meaning any command failure kills the script. + # We use native bash features to safely handle finding the image and socket. + + WALLPAPER_DIR="$HOME/wallpapers" + TARGET="$HOME/.background_image" + + if [ ! -d "$WALLPAPER_DIR" ]; then + echo "Wallpaper directory not found." + exit 0 + fi + + # 1. Get a random image safely (|| true prevents set -e crashes if find returns nothing) + RANDOM_IMG=$(${pkgs.findutils}/bin/find "$WALLPAPER_DIR" -type f \( -iname \*.jpg -o -iname \*.png -o -iname \*.jpeg \) 2>/dev/null | ${pkgs.coreutils}/bin/shuf -n 1 || true) + + if [ -n "$RANDOM_IMG" ]; then + # 2. Update symlink + ${pkgs.coreutils}/bin/ln -sf "$RANDOM_IMG" "$TARGET" + + # 3. Safely find the socket using native Bash globbing. + # systemd user services natively provide the correct $XDG_RUNTIME_DIR (/run/user/1000) + shopt -s nullglob + SOCKETS=("$XDG_RUNTIME_DIR"/sway-ipc.*.sock) + + # 4. Check if the bash array found any socket files + if [ ''${#SOCKETS[@]} -gt 0 ]; then + export SWAYSOCK="''${SOCKETS[0]}" + echo "Using socket: $SWAYSOCK" + + # 5. Execute swaymsg + ${pkgs.sway}/bin/swaymsg output "*" bg "$RANDOM_IMG" fill + echo "Updated background to $RANDOM_IMG" + else + echo "Error: Could not find any sway socket in $XDG_RUNTIME_DIR" + exit 1 + fi + else + echo "No images found in $WALLPAPER_DIR" + fi + ''}"; + }; + }; + + systemd.user.timers.random-background = { + Unit = { + Description = "Run random-background service every hour"; + }; + Timer = { + OnCalendar = "minutely"; + Persistent = true; + }; + Install = { + WantedBy = [ "timers.target" ]; + }; + }; + + programs.waybar = { + enable = true; + style = ./waybar.css; + settings = { + mainBar = { + layer = "top"; + position = "bottom"; # Puts the bar at the bottom + height = 30; + + # Define what goes where on the bar + modules-left = [ + "sway/workspaces" + "sway/mode" + ]; + modules-center = [ "sway/window" ]; + modules-right = [ + "backlight" + "pulseaudio" + "battery" + "clock" + "tray" + ]; + backlight = { + format = "{icon} {percent}%"; + format-icons = [ + "🌑" + "🌘" + "🌗" + "🌖" + "🌕" + ]; + }; + pulseaudio = { + format = "{icon} {volume}%"; + format-muted = "🔇 Muted"; + format-icons = { + default = [ + "🔈" + "🔉" + "🔊" + ]; + }; + scroll-step = 1; + on-click = "pactl set-sink-mute @DEFAULT_SINK@ toggle"; + }; + + clock = { + format = "{:%Y-%m-%d %H:%M}"; + tooltip-format = "{:%Y %B}\n{calendar}"; + }; + battery = { + states = { + warning = 30; + critical = 15; + }; + format = "{icon} {capacity}% ({time})"; + format-charging = "⚡ {capacity}% ({time})"; + format-plugged = "🔌 {capacity}% ({time})"; + format-icons = [ + "đŸĒĢ" + "🔋" + "🔋" + "🔋" + "🔋" + ]; + }; + }; + }; + }; + + services.swayidle.events = { + "before-sleep" = "${pkgs.swaylock}/bin/swaylock -fF"; + }; + services.swayidle.enable = true; + + # Configure Qt to use kvantum theming + qt = { + enable = true; + platformTheme.name = "org.kde.breezedark.desktop"; + style = { + name = "org.kde.breezedark.desktop"; + }; + }; + + # Install packages for better Qt support and kvantum themes + home.packages = with pkgs; [ + kdePackages.breeze + ]; + + # Environment variables for kvantum theming + home.sessionVariables = { + QT_QPA_PLATFORMTHEME = "org.kde.breezedark.desktop"; + QT_STYLE_OVERRIDE = "org.kde.breezedark.desktop"; + GTK_THEME = "Materia-dark-compact"; + }; + +} diff --git a/modules/sway/waybar.css b/modules/sway/waybar.css new file mode 100644 index 0000000..327775a --- /dev/null +++ b/modules/sway/waybar.css @@ -0,0 +1,329 @@ +* { + /* `otf-font-awesome` is required to be installed for icons */ + font-family: Roboto, Helvetica, Arial, sans-serif; + font-size: 13px; +} + +window#waybar { + background-color: rgba(43, 48, 59, 0.5); + border-bottom: 3px solid rgba(100, 114, 125, 0.5); + color: #ffffff; + transition-property: background-color; + transition-duration: .5s; +} + +window#waybar.hidden { + opacity: 0.2; +} + +/* +window#waybar.empty { + background-color: transparent; +} +window#waybar.solo { + background-color: #FFFFFF; +} +*/ + +window#waybar.termite { + background-color: #3F3F3F; +} + +window#waybar.chromium { + background-color: #000000; + border: none; +} + +button { + /* Use box-shadow instead of border so the text isn't offset */ + box-shadow: inset 0 -3px transparent; + /* Avoid rounded borders under each button name */ + border: none; + border-radius: 0; +} + +/* https://github.com/Alexays/Waybar/wiki/FAQ#the-workspace-buttons-have-a-strange-hover-effect */ +button:hover { + background: inherit; + box-shadow: inset 0 -3px #ffffff; +} + +/* you can set a style on hover for any module like this */ +#pulseaudio:hover { + background-color: #a37800; +} + +#workspaces button { + padding: 0 5px; + background-color: transparent; + color: #ffffff; +} + +#workspaces button:hover { + background: rgba(0, 0, 0, 0.2); +} + +#workspaces button.focused, +#workspaces button.active { + background-color: #64727D; + box-shadow: inset 0 -3px #ffffff; +} + +#workspaces button.urgent { + background-color: #eb4d4b; +} + +#mode { + background-color: #64727D; + box-shadow: inset 0 -3px #ffffff; +} + +#clock, +#battery, +#cpu, +#memory, +#disk, +#temperature, +#backlight, +#network, +#pulseaudio, +#wireplumber, +#custom-media, +#tray, +#mode, +#idle_inhibitor, +#scratchpad, +#power-profiles-daemon, +#mpd { + padding: 0 10px; + color: #ffffff; +} + +#window, +#workspaces { + margin: 0 4px; +} + +/* If workspaces is the leftmost module, omit left margin */ +.modules-left>widget:first-child>#workspaces { + margin-left: 0; +} + +/* If workspaces is the rightmost module, omit right margin */ +.modules-right>widget:last-child>#workspaces { + margin-right: 0; +} + +#clock { + background-color: #64727D; +} + +#battery { + background-color: #ffffff; + color: #000000; +} + +#battery.charging, +#battery.plugged { + color: #ffffff; + background-color: #26A65B; +} + +@keyframes blink { + to { + background-color: #ffffff; + color: #000000; + } +} + +/* Using steps() instead of linear as a timing function to limit cpu usage */ +#battery.critical:not(.charging) { + background-color: #f53c3c; + color: #ffffff; + animation-name: blink; + animation-duration: 0.5s; + animation-timing-function: steps(12); + animation-iteration-count: infinite; + animation-direction: alternate; +} + +#power-profiles-daemon { + padding-right: 15px; +} + +#power-profiles-daemon.performance { + background-color: #f53c3c; + color: #ffffff; +} + +#power-profiles-daemon.balanced { + background-color: #2980b9; + color: #ffffff; +} + +#power-profiles-daemon.power-saver { + background-color: #2ecc71; + color: #000000; +} + +label:focus { + background-color: #000000; +} + +#cpu { + background-color: #2ecc71; + color: #000000; +} + +#memory { + background-color: #9b59b6; +} + +#disk { + background-color: #964B00; +} + +#backlight { + background-color: #90b1b1; +} + +#network { + background-color: #2980b9; +} + +#network.disconnected { + background-color: #f53c3c; +} + +#pulseaudio { + background-color: #f1c40f; + color: #000000; +} + +#pulseaudio.muted { + background-color: #90b1b1; + color: #2a5c45; +} + +#wireplumber { + background-color: #fff0f5; + color: #000000; +} + +#wireplumber.muted { + background-color: #f53c3c; +} + +#custom-media { + background-color: #66cc99; + color: #2a5c45; + min-width: 100px; +} + +#custom-media.custom-spotify { + background-color: #66cc99; +} + +#custom-media.custom-vlc { + background-color: #ffa000; +} + +#temperature { + background-color: #f0932b; +} + +#temperature.critical { + background-color: #eb4d4b; +} + +#tray { + background-color: #2980b9; +} + +#tray>.passive { + -gtk-icon-effect: dim; +} + +#tray>.needs-attention { + -gtk-icon-effect: highlight; + background-color: #eb4d4b; +} + +#idle_inhibitor { + background-color: #2d3436; +} + +#idle_inhibitor.activated { + background-color: #ecf0f1; + color: #2d3436; +} + +#mpd { + background-color: #66cc99; + color: #2a5c45; +} + +#mpd.disconnected { + background-color: #f53c3c; +} + +#mpd.stopped { + background-color: #90b1b1; +} + +#mpd.paused { + background-color: #51a37a; +} + +#language { + background: #00b093; + color: #740864; + padding: 0 5px; + margin: 0 5px; + min-width: 16px; +} + +#keyboard-state { + background: #97e1ad; + color: #000000; + padding: 0 0px; + margin: 0 5px; + min-width: 16px; +} + +#keyboard-state>label { + padding: 0 5px; +} + +#keyboard-state>label.locked { + background: rgba(0, 0, 0, 0.2); +} + +#scratchpad { + background: rgba(0, 0, 0, 0.2); +} + +#scratchpad.empty { + background-color: transparent; +} + +#privacy { + padding: 0; +} + +#privacy-item { + padding: 0 5px; + color: white; +} + +#privacy-item.screenshare { + background-color: #cf5700; +} + +#privacy-item.audio-in { + background-color: #1ca000; +} + +#privacy-item.audio-out { + background-color: #0069d4; +} \ No newline at end of file