diff options
Diffstat (limited to 'modules/workstation/windowing')
19 files changed, 559 insertions, 0 deletions
diff --git a/modules/workstation/windowing/default.nix b/modules/workstation/windowing/default.nix new file mode 100644 index 000000000000..f7ff2b8a4272 --- /dev/null +++ b/modules/workstation/windowing/default.nix @@ -0,0 +1,13 @@ +{ pkgs, ... }: + +{ + imports = [ + ./firefox ./foot ./gtk ./sway + ]; + + environment.systemPackages = with pkgs; [ + breeze-icons gnome3.adwaita-icon-theme gnome3.gnome-mines + gnome-podcasts hicolor-icon-theme imv libreoffice okular pinball + playerctl wf-recorder + ]; +} diff --git a/modules/workstation/windowing/firefox/default.nix b/modules/workstation/windowing/firefox/default.nix new file mode 100644 index 000000000000..ccd9afd87843 --- /dev/null +++ b/modules/workstation/windowing/firefox/default.nix @@ -0,0 +1,19 @@ +{ pkgs, ... }: + +{ + environment.systemPackages = with pkgs; [ + (wrapFirefox firefox-unwrapped { + extraPolicies = { + DefaultDownloadDirectory = "/tmp"; + DisablePocket = true; + FirefoxHome = { + TopSites = false; + SponsoredTopSites = false; + SponsoredPocket = false; + }; + }; + }) + ]; + + environment.variables.BROWSER = "firefox"; +} diff --git a/modules/workstation/windowing/foot/default.nix b/modules/workstation/windowing/foot/default.nix new file mode 100644 index 000000000000..5c66f18eb03f --- /dev/null +++ b/modules/workstation/windowing/foot/default.nix @@ -0,0 +1,7 @@ +{ pkgs, ... }: + +{ + users.users.qyliss.xdg.config.paths."foot/foot.ini" = ./foot.ini; + + environment.systemPackages = with pkgs; [ foot ]; +} diff --git a/modules/workstation/windowing/foot/foot.ini b/modules/workstation/windowing/foot/foot.ini new file mode 100644 index 000000000000..d041f42bceac --- /dev/null +++ b/modules/workstation/windowing/foot/foot.ini @@ -0,0 +1,2 @@ +[main] +font = monospace:size=12 diff --git a/modules/workstation/windowing/gtk/default.nix b/modules/workstation/windowing/gtk/default.nix new file mode 100644 index 000000000000..df66f8fbb72d --- /dev/null +++ b/modules/workstation/windowing/gtk/default.nix @@ -0,0 +1,9 @@ +{ pkgs, ... }: + +{ + users.users.qyliss.xdg.config.paths."gtk-3.0/settings.ini" = + pkgs.copyPathToStore ./settings.ini; + + # Needed for Dino to not draw its title bar. + environment.variables.GTK_CSD = "0"; +} diff --git a/modules/workstation/windowing/gtk/settings.ini b/modules/workstation/windowing/gtk/settings.ini new file mode 100644 index 000000000000..29322c1b3a0d --- /dev/null +++ b/modules/workstation/windowing/gtk/settings.ini @@ -0,0 +1,2 @@ +[Settings] +gtk-application-prefer-dark-theme=1 diff --git a/modules/workstation/windowing/streaming/default.nix b/modules/workstation/windowing/streaming/default.nix new file mode 100644 index 000000000000..d6d5451ca6ff --- /dev/null +++ b/modules/workstation/windowing/streaming/default.nix @@ -0,0 +1,30 @@ +{ config, pkgs, ... }: + +let + obsStateDir = "${config.users.users.qyliss.home}/state/obs-studio"; +in + +{ + environment.systemPackages = with pkgs; [ carla obs-studio qpwgraph ]; + + environment.variables.LV2_PATH = with pkgs; lib.makeSearchPathOutput "out" "lib/lv2" [ + calf + dragonfly-reverb + lsp-plugins + x42-plugins + + # Workaround for https://github.com/werman/noise-suppression-for-voice/issues/158 + (runCommand "rrnoise-plugin-mono-lv2" {} '' + mkdir $out + cd ${rnnoise-plugin} + cp -R --parents lib/lv2/rnnoise_mono.lv2 $out + '') + ]; + + systemd.tmpfiles.rules = [ + "d ${obsStateDir} 0700 qyliss qyliss" + ]; + + users.users.qyliss.xdg.config.paths."obs-studio" = + pkgs.runCommand "obs-studio" {} "ln -s ${obsStateDir} $out"; +} diff --git a/modules/workstation/windowing/sway/choose_workspace.nix b/modules/workstation/windowing/sway/choose_workspace.nix new file mode 100644 index 000000000000..fc162d627b60 --- /dev/null +++ b/modules/workstation/windowing/sway/choose_workspace.nix @@ -0,0 +1,9 @@ +{ substituteAll, bemenu, jq }: + +substituteAll { + dir = "bin"; + name = "choose_workspace"; + src = ./choose_workspace.sh.in; + isExecutable = true; + inherit bemenu jq; +} diff --git a/modules/workstation/windowing/sway/choose_workspace.sh.in b/modules/workstation/windowing/sway/choose_workspace.sh.in new file mode 100644 index 000000000000..963746e0c810 --- /dev/null +++ b/modules/workstation/windowing/sway/choose_workspace.sh.in @@ -0,0 +1,17 @@ +#! @shell@ -ue +swaymsg -t get_workspaces | + @jq@/bin/jq -r \ + '(to_entries | map(select(.value.focused)) | .[0].key), .[].name' | + ( + read index + exec @bemenu@/bin/bemenu \ + -p workspace \ + -I "$index" \ + -H 24 \ + --fn 'monospace 10' \ + --nf '#777777' \ + --hb '#285577' \ + --hf '#ffffff' \ + --tf '#777777' \ + --ff '#ffffff' + ) diff --git a/modules/workstation/windowing/sway/config.in b/modules/workstation/windowing/sway/config.in new file mode 100644 index 000000000000..52efc1fa90e3 --- /dev/null +++ b/modules/workstation/windowing/sway/config.in @@ -0,0 +1,125 @@ +set $mod Mod4 +set $left h +set $down j +set $up k +set $right l + +default_border pixel +default_floating_border normal + +client.focused_inactive #333333 #5f676a #ffffff #484e50 #5f676a00 +client.unfocused #333333 #222222 #888888 #292d2e #22222200 + +for_window [app_id="float"] floating enable +for_window [app_id="firefox" title="Picture-in-Picture"] floating enable +for_window [class="Tor Browser"] floating enable +for_window [class="XDvi"] floating enable +for_window [instance="xdvi"] floating enable +for_window [class="XDvi" instance="xdvi"] floating disable +for_window [app_id="firefox" title="NoScript.*"] floating enable + +# Stop the Firefox sharing indicator (that appears when on an +# audio/video call) tiling, or appearing in the center of the display, +# or being focused. +no_focus [title="(Firefox|Nightly) . Sharing Indicator"] +for_window [title="(Firefox|Nightly) . Sharing Indicator"] { + floating enable + sticky enable + + # I'd really like this to be at the top, horizontally centered. + # Or maybe at the bottom right. But there's not really a way to + # do that in sway configuration, as far as I can tell. I think + # I'd need to exec a program that would measure the display size + # and compute the coordinates or something. That sounds horrible + # and fragile, so top left it is. + move position 0 0 +} + +input * natural_scroll enabled + +bindsym $mod+Return exec foot +bindsym $mod+backslash exec firefox +bindsym $mod+BackSpace kill +bindsym $mod+d exec swaymsg exec "$(choosebin --tiebreak=begin,length,index)" + +# Brightness control +bindsym $mod+F5 exec brightnessctl s 10%- +bindsym $mod+F6 exec brightnessctl s 10%+ + +# MPRIS +bindsym $mod+F7 exec playerctl play-pause + +# PulseAudio +bindsym $mod+F8 exec pactl set-sink-mute @DEFAULT_SINK@ toggle +bindsym $mod+F9 exec pactl set-sink-volume @DEFAULT_SINK@ -5% +bindsym $mod+F10 exec pactl set-sink-volume @DEFAULT_SINK@ +5% +bindsym XF86AudioLowerVolume exec pactl set-sink-volume @DEFAULT_SINK@ -5% +bindsym XF86AudioRaiseVolume exec pactl set-sink-volume @DEFAULT_SINK@ +5% + +# Drag floating windows by holding down $mod and left mouse button. +# Resize them with right mouse button + $mod. +# Despite the name, also works for non-floating windows. +# Change normal to inverse to use left mouse button for resizing and right +# mouse button for dragging. +floating_modifier $mod normal + +# reload the configuration file +bindsym $mod+Shift+c reload + +# exit sway (logs you out of your Wayland session) +bindsym $mod+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' + +bindsym $mod+$left focus left +bindsym $mod+$down focus down +bindsym $mod+$up focus up +bindsym $mod+$right focus right + +bindsym $mod+Shift+$left move left +bindsym $mod+Shift+$down move down +bindsym $mod+Shift+$up move up +bindsym $mod+Shift+$right move right + +bindsym $mod+g exec swaymsg workspace "$(@choose_workspace@)" +bindsym $mod+Shift+g exec swaymsg move container to workspace "$(@choose_workspace@)" + +bindsym $mod+b splith +bindsym $mod+v splitv + +bindsym $mod+s layout stacking +bindsym $mod+w layout tabbed +bindsym $mod+e layout toggle split + +bindsym $mod+f fullscreen + +bindsym $mod+Shift+space floating toggle +bindsym $mod+space focus mode_toggle + +bindsym $mod+a focus parent + +bindsym $mod+Shift+minus move scratchpad +bindsym $mod+minus scratchpad show + +mode "resize" { + bindsym $left resize shrink width 10px + bindsym $down resize grow height 10px + bindsym $up resize shrink height 10px + bindsym $right resize grow width 10px + + bindsym Return mode "default" + bindsym Escape mode "default" +} +bindsym $mod+r mode "resize" + +bar { + position top + + status_command @status_command@ + + colors { + statusline #ffffff + background #00000077 + inactive_workspace #33333377 #00000077 #FFFFFF77 + } +} + +@extraConfig@ diff --git a/modules/workstation/windowing/sway/default.nix b/modules/workstation/windowing/sway/default.nix new file mode 100644 index 000000000000..675ef8dbc031 --- /dev/null +++ b/modules/workstation/windowing/sway/default.nix @@ -0,0 +1,49 @@ +{ pkgs, lib, config, ... }: + +let + inherit (lib) mdDoc mkOption optionalString; + inherit (lib.types) lines nullOr path; + inherit (pkgs) callPackage substituteAll; + + cfg = config.programs.sway; +in + +{ + imports = [ ./swayidle ./swaylock ./wlsunset ./xdg-desktop-portal-wlr ]; + + options = { + programs.sway.extraConfig = mkOption { + type = lines; + description = mdDoc "Lines to append to sway's config file"; + default = ""; + }; + + programs.sway.wallpaper = mkOption { + type = nullOr path; + description = mdDoc "Path to wallpaper for sway and swaylock"; + default = null; + }; + }; + + config = { + environment.systemPackages = with pkgs; [ bemenu choose swayidle ]; + + programs.sway.enable = true; + programs.sway.wallpaper = callPackage ./wallpaper.nix { }; + programs.sway.extraPackages = []; # extra packages can go in systemPackages. + + programs.swayidle.enable = true; + + users.users.qyliss.xdg.config.paths."sway/config" = substituteAll { + src = ./config.in; + choose_workspace = + "${callPackage ./choose_workspace.nix { }}/bin/choose_workspace"; + status_command = "${callPackage ./status.nix { }}/bin/status"; + extraConfig = cfg.extraConfig + optionalString (cfg.wallpaper != null) '' + output * bg ${cfg.wallpaper} fill + ''; + }; + + xdg.portal.extraPortals = with pkgs; [ xdg-desktop-portal-gtk ]; + }; +} diff --git a/modules/workstation/windowing/sway/status.cpp b/modules/workstation/windowing/sway/status.cpp new file mode 100644 index 000000000000..1f73458d86b2 --- /dev/null +++ b/modules/workstation/windowing/sway/status.cpp @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +// Copyright 2020 Alyssa Ross +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <https://www.gnu.org/licenses/>. + +#include <chrono> +#include <fcntl.h> +#include <filesystem> +#include <iostream> +#include <thread> +#include <unistd.h> + +namespace fs = std::filesystem; + +using fs::directory_iterator; +using std::chrono::seconds; +using std::generic_category; +using std::put_time; +using std::stoi; +using std::string; +using std::stringstream; +using std::system_error; +using std::this_thread::sleep_for; +using std::time; + +enum BatteryStatus { + Unknown, + Charging, + Discharging, + NotCharging, + Full, +}; + +class Battery { +public: + Battery(string name); + + string name() { return m_name; } + fs::path path(); + BatteryStatus status(); + int capacity(); + int charge_now(); + +private: + string m_name; + string attr(string name); +}; + +Battery::Battery(string name) +{ + m_name = name; +} + +fs::path Battery::path() +{ + static fs::path base = "/sys/class/power_supply"; + return base / name(); +} + +BatteryStatus Battery::status() +{ + auto status = attr("status"); + + if (status == "Charging") + return Charging; + if (status == "Discharging") + return Discharging; + if (status == "Not charging") + return NotCharging; + if (status == "Full") + return Full; + + return Unknown; +} + +int Battery::capacity() +{ + return stoi(attr("capacity")); +} + +int Battery::charge_now() +{ + return stoi(attr("charge_now")); +} + +string Battery::attr(string name) +{ + // Use read() to make sure this is done in a single read syscall, + // because sysfs doesn't like multiple reads. + int fd = open((path() / name).c_str(), O_RDONLY); + if (fd == -1) + throw system_error(errno, generic_category()); + char buf[13]; + int len = read(fd, &buf, 13); + if (len == -1) + throw system_error(errno, generic_category()); + close(fd); + string value (buf, len); + if (value.back() == '\n') + value.pop_back(); + return value; +} + +int main(void) +{ + while (true) { + // Buffer output so it can be done all at once in a single write(), + // because of <https://github.com/swaywm/sway/issues/3857>. + stringstream out; + + for (const auto& entry : directory_iterator("/sys/class/power_supply")) { + auto name = entry.path().filename().string(); + + Battery battery (name); + auto batdisplay = false; + + try { + switch (battery.status()) { + case Charging: + out << "↑"; + break; + case Discharging: + out << "↓"; + break; + default: + out << " "; + } + batdisplay = true; + } catch (const system_error& ex) { + switch (ex.code().value()) { + case ENOENT: + break; + case ENODEV: + out << "? "; + batdisplay = true; + break; + default: + throw ex; + } + } + + try { + int capacity = battery.capacity(); + out << capacity << "%"; + batdisplay = true; + } catch (const system_error& ex) { + switch (ex.code().value()) { + case ENOENT: + break; + case ENODEV: + out << "??%"; + batdisplay = true; + break; + default: + throw ex; + } + + try { + int charge_now = battery.charge_now(); + out << charge_now; + batdisplay = true; + } catch (const system_error& ex) { + switch (ex.code().value()) { + case ENOENT: + break; + case ENODEV: + out << "??????"; + batdisplay = true; + break; + default: + throw ex; + } + } + } + + if (batdisplay) + out << " "; + } + + auto t = time(nullptr); + out << put_time(localtime(&t), "%F %T") << "\n"; + + auto buf = out.str(); + if (write(STDOUT_FILENO, buf.c_str(), buf.length()) == -1) + perror("write"); + + sleep_for(seconds(1)); + } +} diff --git a/modules/workstation/windowing/sway/status.nix b/modules/workstation/windowing/sway/status.nix new file mode 100644 index 000000000000..2697317d7611 --- /dev/null +++ b/modules/workstation/windowing/sway/status.nix @@ -0,0 +1,6 @@ +{ runCommandCC }: + +runCommandCC "status" {} '' + mkdir -p $out/bin + c++ -std=c++17 -o $out/bin/status ${./status.cpp} +'' diff --git a/modules/workstation/windowing/sway/swayidle/default.nix b/modules/workstation/windowing/sway/swayidle/default.nix new file mode 100644 index 000000000000..8e5f264b5038 --- /dev/null +++ b/modules/workstation/windowing/sway/swayidle/default.nix @@ -0,0 +1,23 @@ +{ lib, config, ... }: + +let + cfg = config.programs.swayidle; +in + +with lib; + +{ + options = { + programs.swayidle.enable = mkEnableOption "swayidle"; + }; + + config = mkIf cfg.enable { + programs.sway.extraConfig = '' + exec swayidle \ + timeout 300 'swaylock -c 000000' \ + timeout 600 'swaymsg "output * dpms off"' \ + resume 'swaymsg "output * dpms on"' \ + before-sleep 'swaylock -c 000000' + ''; + }; +} diff --git a/modules/workstation/windowing/sway/swaylock/config.in b/modules/workstation/windowing/sway/swaylock/config.in new file mode 100644 index 000000000000..c6f280aa8f5b --- /dev/null +++ b/modules/workstation/windowing/sway/swaylock/config.in @@ -0,0 +1,3 @@ +image=@wallpaper@ +indicator-idle-visible +show-failed-attempts diff --git a/modules/workstation/windowing/sway/swaylock/default.nix b/modules/workstation/windowing/sway/swaylock/default.nix new file mode 100644 index 000000000000..be15c87ade32 --- /dev/null +++ b/modules/workstation/windowing/sway/swaylock/default.nix @@ -0,0 +1,12 @@ +{ pkgs, config, ... }: + +{ + imports = [ ../../../../xdg ]; + + environment.systemPackages = with pkgs; [ swaylock ]; + + users.users.qyliss.xdg.config.paths."swaylock/config" = pkgs.substituteAll { + src = ./config.in; + wallpaper = config.programs.sway.wallpaper; + }; +} diff --git a/modules/workstation/windowing/sway/wallpaper.nix b/modules/workstation/windowing/sway/wallpaper.nix new file mode 100644 index 000000000000..bed6bbe33a6b --- /dev/null +++ b/modules/workstation/windowing/sway/wallpaper.nix @@ -0,0 +1,10 @@ +{ fetchurl }: + +fetchurl { + url = "https://mir-s3-cdn-cf.behance.net/project_modules/2800_opt_1/36731876964505.5c793fa788b5d.jpg"; + sha256 = "1c6camdipng8ws41sgpcxzrxb96crgip3wirqjgf2ajn60qg3v64"; + + meta = { + homepage = "https://www.behance.net/gallery/76964505/IQOO-style-frame-and-scene-design"; + }; +} diff --git a/modules/workstation/windowing/sway/wlsunset/default.nix b/modules/workstation/windowing/sway/wlsunset/default.nix new file mode 100644 index 000000000000..ba954f3cd3bd --- /dev/null +++ b/modules/workstation/windowing/sway/wlsunset/default.nix @@ -0,0 +1,9 @@ +{ pkgs, ... }: + +{ + environment.systemPackages = with pkgs; [ wlsunset ]; + + programs.sway.extraConfig = '' + exec wlsunset -l 51.5 -L 13.6 + ''; +} diff --git a/modules/workstation/windowing/sway/xdg-desktop-portal-wlr/default.nix b/modules/workstation/windowing/sway/xdg-desktop-portal-wlr/default.nix new file mode 100644 index 000000000000..892e6a280d4c --- /dev/null +++ b/modules/workstation/windowing/sway/xdg-desktop-portal-wlr/default.nix @@ -0,0 +1,13 @@ +{ pkgs, ... }: + +{ + xdg.portal.wlr.enable = true; + + programs.sway.extraConfig = '' + exec ${pkgs.writeShellScript "sway-portal-environment" '' + set -e + dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP + systemctl --user stop pipewire xdg-desktop-portal xdg-desktop-portal-wlr + ''} + ''; +} |