Workspace rules alone only affect future workspace creation. Add moveworkspacetomonitor dispatches so existing workspaces are moved to the correct monitor when an external display is connected.
262 lines
7.5 KiB
Nix
262 lines
7.5 KiB
Nix
{
|
|
inputs,
|
|
pkgs,
|
|
lib,
|
|
config,
|
|
...
|
|
}:
|
|
let
|
|
enabled = config.mod.hyprland.enable;
|
|
|
|
monitorScript = pkgs.writeShellScript "hyprland-monitor-handler" ''
|
|
INTERNAL="eDP-1"
|
|
EXTERNAL_MONITORS="HDMI-A-1 DP-3"
|
|
HYPRCTL="${pkgs.hyprland}/bin/hyprctl"
|
|
JQ="${pkgs.jq}/bin/jq"
|
|
|
|
get_active_external() {
|
|
# Return the first connected external monitor
|
|
for mon in $EXTERNAL_MONITORS; do
|
|
if $HYPRCTL monitors -j | $JQ -e ".[] | select(.name == \"$mon\")" > /dev/null 2>&1; then
|
|
echo "$mon"
|
|
return 0
|
|
fi
|
|
done
|
|
return 1
|
|
}
|
|
|
|
bind_workspaces() {
|
|
local external
|
|
|
|
if external=$(get_active_external); then
|
|
# External monitor connected: 1-5 on external, 6-10 on internal
|
|
for ws in 1 2 3 4 5; do
|
|
$HYPRCTL keyword workspace "$ws, monitor:$external, default:true"
|
|
$HYPRCTL dispatch moveworkspacetomonitor "$ws $external"
|
|
done
|
|
for ws in 6 7 8 9 10; do
|
|
$HYPRCTL keyword workspace "$ws, monitor:$INTERNAL, default:true"
|
|
$HYPRCTL dispatch moveworkspacetomonitor "$ws $INTERNAL"
|
|
done
|
|
else
|
|
# No external monitor: all workspaces on internal
|
|
for ws in 1 2 3 4 5 6 7 8 9 10; do
|
|
$HYPRCTL keyword workspace "$ws, monitor:$INTERNAL, default:true"
|
|
$HYPRCTL dispatch moveworkspacetomonitor "$ws $INTERNAL"
|
|
done
|
|
fi
|
|
}
|
|
|
|
handle_event() {
|
|
case $1 in
|
|
monitoradded*|monitorremoved*)
|
|
sleep 0.5
|
|
bind_workspaces
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Bind workspaces on startup
|
|
bind_workspaces
|
|
|
|
${pkgs.socat}/bin/socat -U - UNIX-CONNECT:"$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock" | while read -r line; do
|
|
handle_event "$line"
|
|
done
|
|
'';
|
|
in
|
|
{
|
|
options = {
|
|
mod.hyprland = {
|
|
enable = lib.mkEnableOption "enable hyprland module";
|
|
};
|
|
};
|
|
|
|
config = lib.mkIf enabled {
|
|
programs.hyprland = {
|
|
enable = true;
|
|
package = inputs.hyprland.packages.${pkgs.stdenv.hostPlatform.system}.hyprland;
|
|
portalPackage =
|
|
inputs.hyprland.packages.${pkgs.stdenv.hostPlatform.system}.xdg-desktop-portal-hyprland;
|
|
|
|
xwayland = {
|
|
enable = true;
|
|
};
|
|
};
|
|
|
|
home-manager.users.alex = {
|
|
wayland.windowManager.hyprland = {
|
|
enable = true;
|
|
|
|
extraConfig = ''
|
|
exec-once=waybar
|
|
exec-once=hyprctl setcursor Adwaita 24
|
|
|
|
env = GDK_DPI_SCALE,1.5
|
|
env = HYPRCURSOR_THEME,Adwaita
|
|
env = HYPRCURSOR_SIZE,24
|
|
|
|
monitor=eDP-1, 1920x1200, auto-center-down, 1
|
|
monitor=HDMI-A-1, 2560x1440@100, auto-center-up, 1
|
|
monitor=DP-3, 2560x1440@60, auto-center-up, 1
|
|
|
|
workspace = w[tv1], gapsout:0, gapsin:0
|
|
workspace = f[1], gapsout:0, gapsin:0
|
|
windowrule = border_size 0, match:float 0, match:workspace w[tv1]
|
|
windowrule = rounding 0, match:float 0, match:workspace w[tv1]
|
|
windowrule = border_size 0, match:float 0, match:workspace f[1]
|
|
windowrule = rounding 0, match:float 0, match:workspace f[1]
|
|
|
|
# https://wiki.archlinux.org/title/Hyprland#Jetbrains_apps_focus_issues
|
|
windowrule = match:xwayland true, no_initial_focus on
|
|
|
|
exec-once=dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP
|
|
'';
|
|
|
|
settings = {
|
|
"$mod" = "SUPER";
|
|
|
|
animations.enabled = false;
|
|
|
|
xwayland = {
|
|
force_zero_scaling = true;
|
|
};
|
|
|
|
input = {
|
|
kb_layout = "se";
|
|
|
|
# 2 - Cursor focus will be detached from keyboard focus. Clicking on a window will move keyboard focus to that window.
|
|
follow_mouse = 2;
|
|
|
|
sensitivity = 0.3;
|
|
accel_profile = "flat";
|
|
touchpad = {
|
|
natural_scroll = false;
|
|
tap-and-drag = false;
|
|
};
|
|
};
|
|
|
|
cursor = {
|
|
zoom_factor = 1;
|
|
zoom_rigid = true;
|
|
};
|
|
|
|
general = {
|
|
layout = "dwindle";
|
|
|
|
gaps_in = 0; # gaps between windows
|
|
gaps_out = 0; # gaps between windows and monitor edges
|
|
|
|
"col.active_border" = "rgba(${config.lib.colors.foreground}ff)";
|
|
"col.inactive_border" = "rgba(${config.lib.colors.background}ff)";
|
|
};
|
|
|
|
dwindle = {
|
|
force_split = 2;
|
|
};
|
|
|
|
bind =
|
|
let
|
|
ws =
|
|
x:
|
|
let
|
|
n = if (x + 1) < 10 then (x + 1) else 0;
|
|
in
|
|
builtins.toString n;
|
|
|
|
select = builtins.genList (x: "$mod, ${ws x}, workspace, ${builtins.toString (x + 1)}") 10;
|
|
move = builtins.genList (
|
|
x: "$mod SHIFT, ${ws x}, movetoworkspacesilent, ${builtins.toString (x + 1)}"
|
|
) 10;
|
|
|
|
magnifier = pkgs.writeShellScript "magnifier" ''
|
|
CURRENT=$(${pkgs.hyprland}/bin/hyprctl getoption cursor:zoom_factor -j | ${pkgs.jq}/bin/jq .float)
|
|
DELTA=0.1
|
|
|
|
UPDATED=1
|
|
case $1 in
|
|
--increase)
|
|
UPDATED=$(echo $CURRENT + $DELTA | ${pkgs.bc}/bin/bc) ;;
|
|
--decrease)
|
|
UPDATED=$(echo $CURRENT - $DELTA | ${pkgs.bc}/bin/bc) ;;
|
|
--reset)
|
|
UPDATED=1
|
|
esac
|
|
|
|
if (( $(echo "$UPDATED < 1" | bc) )); then UPDATED=1; fi
|
|
${pkgs.hyprland}/bin/hyprctl keyword cursor:zoom_factor $UPDATED
|
|
'';
|
|
in
|
|
select
|
|
++ move
|
|
++ [
|
|
"$mod, ESCAPE, killactive"
|
|
|
|
"$mod, f, fullscreen, 1"
|
|
"$mod SHIFT, f, togglefloating, active"
|
|
|
|
"$mod, h, movefocus, l"
|
|
"$mod, j, movefocus, d"
|
|
"$mod, k, movefocus, u"
|
|
"$mod, l, movefocus, r"
|
|
|
|
"$mod CONTROL, 1, exec, ${magnifier} --increase"
|
|
"$mod CONTROL, 2, exec, ${magnifier} --decrease"
|
|
"$mod CONTROL, 3, exec, ${magnifier} --reset"
|
|
];
|
|
|
|
bindm = [
|
|
# mouse movements
|
|
"$mod, mouse:272, movewindow" # left click
|
|
"$mod, mouse:273, resizewindow" # right click
|
|
];
|
|
|
|
misc = {
|
|
disable_hyprland_logo = true;
|
|
disable_splash_rendering = true;
|
|
};
|
|
};
|
|
};
|
|
|
|
home.packages = [
|
|
pkgs.wdisplays
|
|
pkgs.bc
|
|
];
|
|
|
|
systemd.user.services.hyprland-monitors = {
|
|
Unit = {
|
|
Description = "Hyprland monitor hotplug handler";
|
|
PartOf = [ "graphical-session.target" ];
|
|
After = [ "graphical-session.target" ];
|
|
};
|
|
Service = {
|
|
Type = "simple";
|
|
ExecStart = "${monitorScript}";
|
|
Restart = "on-failure";
|
|
RestartSec = 5;
|
|
};
|
|
Install = {
|
|
WantedBy = [ "graphical-session.target" ];
|
|
};
|
|
};
|
|
};
|
|
|
|
# To start electron apps like `chromium` with wayland support
|
|
environment.sessionVariables.NIXOS_OZONE_WL = "1";
|
|
|
|
# The XDG portal is needed for screen sharing
|
|
xdg.portal = {
|
|
enable = true;
|
|
|
|
# override "trace: warning: xdg-desktop-portal 1.17 reworked how portal implementations are loaded ..."
|
|
config.common.default = "*";
|
|
|
|
extraPortals = [ pkgs.xdg-desktop-portal-wlr ];
|
|
};
|
|
|
|
# openGL is needed for wayland/hyprland
|
|
hardware.graphics.enable = true;
|
|
|
|
boot.kernelParams = [ "i915.enable_psr=0" ];
|
|
};
|
|
}
|