#!/usr/bin/env bash # Apps opened at login. Run once per login by autostart-apps.service (see # modules/home/services.nix), after Waybar, so the tray exists. # # OpenDeck, WowUp to the tray # Faugus its window on workspace 1 # Signal, Discord workspace 3, Signal on top and Discord below it # # Which workspace a window lands on (and Faugus' position) is decided by the # temporary "startup-*" window rules in startup.lua, which also closes the window # WowUp opens. This script starts the apps and then stacks Signal # above Discord. Apps that are already running are left alone, so it is safe to run # again by hand. SIGNAL_HEIGHT=802 # px; Discord gets the rest of the (portrait) monitor running() { pgrep -f "$1" >/dev/null 2>&1; } # Each app is started as its own systemd service (app-*.service), with systemd as # its parent rather than this script: Discord and WowUp run in a bubblewrap # sandbox that exits with its parent process, so they would close as soon as # this script finished. `systemctl --user list-units 'app-*'` shows them. launch() { uwsm app -t service -- "$@" >/dev/null 2>&1; } dispatch() { hyprctl dispatch "$1" >/dev/null 2>&1; } # Tray apps only show an icon if the tray already exists when they start. for _ in $(seq 40); do busctl --user status org.kde.StatusNotifierWatcher >/dev/null 2>&1 && break sleep 0.5 done # OpenDeck starts hidden with its flag. WowUp has one too but shows its window # anyway; startup.lua closes that window (see "startup-wowup" there). running '(^|/)\.?opendeck(-wrapped)? ' || launch opendeck --hide running 'wowup-cf' || launch wowup-cf --hidden running 'faugus\.(launcher|tray_only)' || launch faugus-launcher running 'signal-desktop.*/app\.asar' || launch signal-desktop # themed, see pkgs/signal-desktop-themed running '/Discord( |$)' || launch discord # --- Stack Signal above Discord ------------------------------------------------ # Prints "address y width height" of the first mapped, tiled window whose class is $1, # ignoring small ones (Discord's updater splash). window() { hyprctl clients -j | python3 -c ' import json, sys for c in json.load(sys.stdin): if c["class"] == sys.argv[1] and c.get("mapped", True) and not c["floating"] and c["size"][0] > 500: print(c["address"], c["at"][1], c["size"][0], c["size"][1]) break ' "$1" } for _ in $(seq 180); do read -r signal_addr signal_y signal_w signal_h <<<"$(window signal)" read -r discord_addr discord_y _ _ <<<"$(window discord)" [ -n "$signal_addr" ] && [ -n "$discord_addr" ] && break sleep 0.5 done [ -n "$signal_addr" ] && [ -n "$discord_addr" ] || exit 0 if [ "$signal_y" -gt "$discord_y" ]; then dispatch "hl.dsp.window.move({ direction = \"u\", window = \"address:$signal_addr\" })" sleep 0.3 read -r signal_addr signal_y signal_w signal_h <<<"$(window signal)" fi if [ "$signal_h" != "$SIGNAL_HEIGHT" ]; then dispatch "hl.dsp.window.resize({ x = $signal_w, y = $SIGNAL_HEIGHT, window = \"address:$signal_addr\" })" fi