diff --git a/homes/julian/features/hyprland/default.nix b/homes/julian/features/hyprland/default.nix index 26c5f1e..21fae08 100644 --- a/homes/julian/features/hyprland/default.nix +++ b/homes/julian/features/hyprland/default.nix @@ -37,6 +37,7 @@ home.packages = with pkgs; [ hyprpicker brightnessctl + playerctl frajul.hyprshot-gui frajul.wl-ocr @@ -52,7 +53,7 @@ builtins.concatLists ( map ( monitor: - map (ws: "hyprctl dispatch moveworkspacetomonitor ${ws} ${monitor.name}") monitor.workspaces + map (ws: "hyprctl dispatch 'hl.dsp.workspace.move({workspace=\"${ws}\", monitor=\"${monitor.name}\"})'") monitor.workspaces ) config.monitors ) @@ -70,51 +71,35 @@ LIBSEAT_BACKEND = "logind"; }; - # services.hypridle = { - # enable = true; - # settings = { - # general = { - # after_sleep_cmd = "hyprctl dispatch dpms on"; - # ignore_dbus_inhibit = false; - # lock_cmd = "hyprlock"; - # }; - - # listener = [ - # { - # timeout = 300; # 5min - # on-timeout = "brightnessctl -s set 10"; # set monitor backlight to minimum, avoid 0 on OLED monitor. - # on-resume = "brightnessctl -r"; # monitor backlight restore. - # } - - # { - # timeout = 360; # 6min - # on-timeout = "hyprlock"; # lock screen when timeout has passed - # } - - # { - # timeout = 600; # 10min - # on-timeout = "hyprctl dispatch dpms off"; # screen off when timeout has passed - # on-resume = "hyprctl dispatch dpms on"; # screen on when activity is detected after timeout has fired. - # } - # ]; - # }; - # }; - - # services.hypridle.enable = true; # can be configured - services.network-manager-applet.enable = true; wayland.windowManager.hyprland = { - # Whether to enable Hyprland wayland compositor enable = true; - # package = config.lib.nixGL.wrap ( - # pkgs.hyprland.override { - # # nixgl needed? - # wrapRuntimeDeps = false; - # } - # ); - configType = "hyprlang"; + configType = "lua"; + extraConfig = + # Variables controllable by nix + '' + -- Nix controlled variables + local terminal = "${config.terminal}" + local fileManager = "pcmanfm" + local menu = "wofi --show drun,run" + local calculator = "qalculate-gtk" + local browser = "firefox" + local editor = "emacs" + '' + + "-- Main config from `hyprland.lua`\n" + + builtins.readFile ./hyprland.lua + + "-- Assign workspaces to monitors\n" + + lib.concatStringsSep "\n" ( + builtins.concatLists ( + map ( + monitor: + map (ws: "hl.workspace_rule({ workspace = \"${ws}\", monitor = \"${monitor.name}\"})") monitor.workspaces + ) + config.monitors + ) + ); systemd = { enable = true; @@ -131,313 +116,10 @@ ]; }; - # package = inputs.hyprland.packages."${pkgs.system}".hyprland; # does only work with nixos-unstable - - # The hyprland package to use (simplifies use of plugins) - # package = inputs.hyprland.packages.${pkgs.system}.hyprland; - # Whether to enable XWayland xwayland.enable = true; - # Optional - # Whether to enable hyprland-session.target on hyprland startup - # systemd.enable = true; - # Make PATH available to systemd services - # systemd.variables = [ "--all" ]; - plugins = [ - # inputs.hyprland-plugins.packages.${pkgs.system}.hyprbars # does only work with nixos-unstable # hyprlandPlugins.hyprbars ]; - - submaps = { - "resize".settings = { - binde = [ - ", right, resizeactive, 20" - ", left, resizeactive, -20 0" - ", up, resizeactive, 0 -20" - ", down, resizeactive, 0 20" - ", l, resizeactive, 20" - ", h, resizeactive, -20 0" - ", k, resizeactive, 0 -20" - ", j, resizeactive, 0 20" - ]; - - bind = [ - ", q, submap, reset" - ", escape, submap, reset" - - ", catchall, submap, reset" # make any other keypress cancel the submap - ]; - }; - "open, reset".settings = { - bind = [ - ", e, exec, emacs" - ", m, exec, open-messaging" - ", b, exec, firefox" - - ", catchall, submap, reset" # make any other keypress cancel the submap - ]; - }; - }; - - # Disable animations for selection, fixes screenshots - extraConfig = '' - layerrule { - name = no_anim_for_selection - no_anim = on - match:namespace = selection - } - ''; - - settings = { - "$mod" = "SUPER"; - - # Environment variables programs like emacs have access to - env = "TERMINAL,${config.terminal}"; - - # Monitors - monitor = ",preferred,auto,1"; - - # Autostart - exec-once = [ - (lib.getExe pkgs.firefox) - (lib.getExe pkgs.waybar) - ]; - - # Look and Feel - general = { - gaps_in = 5; - gaps_out = 5; - - layout = "dwindle"; - }; - - decoration = { - # power saving - blur.enabled = false; - # power saving - shadow.enabled = false; - }; - - # Dwindle layout - dwindle = { - # pseudotile = true; # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below - preserve_split = true; # You probably want this - smart_split = false; - smart_resizing = false; - force_split = 2; - # no_gaps_when_only = 2; # with border - }; - - # Master layout - master = { - new_status = "slave"; - # no_gaps_when_only = 2; # with border - mfact = 0.5; # Do not make master bigger - }; - - animations = { - enabled = true; - - animation = [ - "windows,1,3,default,slide" - "fade,1,3,default" - "layers,1,3,default,slide" - "border,1,3,default" - "workspaces,1,3,default,slide" - ]; - }; - - exec = [ - # "hyprctl setcursor ${config.gtk.cursorTheme.name} ${toString config.gtk.cursorTheme.size}" - "correct-workspace-locations" - ]; - - misc = { - # disable auto polling for config file changes - disable_autoreload = true; - - force_default_wallpaper = 0; - - # vfr = true; # power saving - }; - - cursor = { - no_hardware_cursors = 1; # disable hardware cursors to fix tearing on kardorf - }; - - render = { - # we do, in fact, want direct scanout - direct_scanout = true; - }; - - # Input - input = { - kb_layout = "de"; - natural_scroll = false; - follow_mouse = 1; - }; - - # Window rules - # windowrulev2 = [ - # "suppressevent maximize, class:.*" - # "workspace 1, class:firefox" - # "workspace 8, class:Zotero" - # "workspace 9, class:nheko" - # "workspace 9, class:Element" - # "workspace 9, class:discord" - # "workspace 9, class:org.telegram.desktop" - # "workspace 10, class:thunderbird" - # "float, class:qalculate-gtk" - # "tile, class:MATLAB, title:MATLAB" - # ]; - - # Workspace rules - workspace = - [ - # smart gaps (none when only one window in workspace) - "w[t1], gapsin:0, gapsout:0, border:1" - "w[tg1], gapsin:0, gapsout:0, border:1" - "f[1], gapsin:0, gapsout:0, border:1" - ] - # builds like "1, e-DP1" "2, HDMI-1" etc. - ++ builtins.concatLists ( - map (monitor: map (ws: "${ws}, monitor:${monitor.name}") monitor.workspaces) config.monitors - ); - - # Mouse binds - bindm = [ - "$mod, mouse:272, movewindow" # leftclick - "$mod, mouse:273, resizewindow" # rightclick - ]; - - # binds - bind = - [ - # compositor commands - # - # - "$mod, R, submap, resize" - "$mod, O, submap, open" - # - - "$mod, SPACE, focuswindow, floating" - "$mod SHIFT, SPACE, togglefloating," - "$mod, F, fullscreen," - "$mod, X, killactive," - - # "$mod, -, togglesplit," # dwindle - - # opening applications - "$mod, D, exec, wofi --show drun,run" - "$mod, E, exec, pcmanfm" - "$mod, Return, exec, ${config.terminal}" - "$mod, B, exec, firefox" - "$mod, C, exec, qalculate-gtk" - - # other commands - "$mod SHIFT, E, exec, wlogout -p layer-shell" - "$mod, Escape, exec, wlogout -p layer-shell" - "$mod SHIFT, R, exec, hyprctl reload" - "$mod, Print, exec, hyprshot-gui" - ", Print, exec, hyprshot-gui" - "$mod, P, exec, toggle-screen-mirroring; correct-workspace-locations" - - # "$mod SHIFT, E, exec, pkill Hyprland" - # "$mod, G, togglegroup," - # "$mod SHIFT, N, changegroupactive, f" - # "$mod SHIFT, P, changegroupactive, b" - # "$mod ALT, ,resizeactive," - - # media keys - ", XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+" - ", XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-" - ", XF86AudioPlay, exec, playerctl play-pause" - ", XF86AudioPause, exec, playerctl pause" - ", XF86AudioStop, exec, playerctl stop" - ", XF86AudioNext, exec, playerctl next" - ", XF86AudioPrev, exec, playerctl previous" - ", XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle" - ", XF86MonBrightnessUp, exec, brightnessctl --class backlight set 5%+" - ", XF86MonBrightnessDown, exec, brightnessctl --class backlight set 5%-" - - # move focus - "$mod, left, movefocus, l" - "$mod, H, movefocus, l" - "$mod, right, movefocus, r" - "$mod, L, movefocus, r" - "$mod, up, movefocus, u" - "$mod, K, movefocus, u" - "$mod, down, movefocus, d" - "$mod, J, movefocus, d" - - # move window - "$mod SHIFT, left, movewindow, l" - "$mod SHIFT, H, movewindow, l" - "$mod SHIFT, right, movewindow, r" - "$mod SHIFT, L, movewindow, r" - "$mod SHIFT, up, movewindow, u" - "$mod SHIFT, K, movewindow, u" - "$mod SHIFT, down, movewindow, d" - "$mod SHIFT, J, movewindow, d" - - # Switch workspaces with mainMod + [0-9] - "$mod, 1, workspace, 1" - "$mod, 2, workspace, 2" - "$mod, 3, workspace, 3" - "$mod, 4, workspace, 4" - "$mod, 5, workspace, 5" - "$mod, 6, workspace, 6" - "$mod, 7, workspace, 7" - "$mod, 8, workspace, 8" - "$mod, 9, workspace, 9" - "$mod, 0, workspace, 10" - - # Move active window to a workspace with mainMod + SHIFT + [0-9] - "$mod SHIFT, 1, movetoworkspace, 1" - "$mod SHIFT, 2, movetoworkspace, 2" - "$mod SHIFT, 3, movetoworkspace, 3" - "$mod SHIFT, 4, movetoworkspace, 4" - "$mod SHIFT, 5, movetoworkspace, 5" - "$mod SHIFT, 6, movetoworkspace, 6" - "$mod SHIFT, 7, movetoworkspace, 7" - "$mod SHIFT, 8, movetoworkspace, 8" - "$mod SHIFT, 9, movetoworkspace, 9" - "$mod SHIFT, 0, movetoworkspace, 10" - - # Move active window to a workspace without following with mainMod + CTRL + [0-9] - "$mod CTRL, 1, movetoworkspacesilent, 1" - "$mod CTRL, 2, movetoworkspacesilent, 2" - "$mod CTRL, 3, movetoworkspacesilent, 3" - "$mod CTRL, 4, movetoworkspacesilent, 4" - "$mod CTRL, 5, movetoworkspacesilent, 5" - "$mod CTRL, 6, movetoworkspacesilent, 6" - "$mod CTRL, 7, movetoworkspacesilent, 7" - "$mod CTRL, 8, movetoworkspacesilent, 8" - "$mod CTRL, 9, movetoworkspacesilent, 9" - "$mod CTRL, 0, movetoworkspacesilent, 10" - ] - ++ - # Screen lock - ( - let - swaylock = lib.getExe config.programs.swaylock.package; - in - lib.optionals config.programs.swaylock.enable [ - "$mod,TAB,exec,${swaylock} --daemonize" - ] - ) - ++ - # Notification manager - ( - let - makoctl = lib.getExe' config.services.mako.package "makoctl"; - in - lib.optionals config.services.mako.enable [ - "$mod,w,exec,${makoctl} dismiss" - "$mod SHIFT,W,exec,${makoctl} restore" - ] - ); - }; }; } diff --git a/homes/julian/features/hyprland/hyprland.lua b/homes/julian/features/hyprland/hyprland.lua new file mode 100644 index 0000000..e76d25d --- /dev/null +++ b/homes/julian/features/hyprland/hyprland.lua @@ -0,0 +1,363 @@ +------------------ +---- MONITORS ---- +------------------ + +-- See https://wiki.hypr.land/Configuring/Basics/Monitors/ +hl.monitor({ + output = "", + mode = "preferred", + position = "auto", + scale = "auto", + mirror = "", +}) + +------------------- +---- AUTOSTART ---- +------------------- + +-- See https://wiki.hypr.land/Configuring/Basics/Autostart/ +hl.on("hyprland.start", function() + hl.exec_cmd("waybar") + hl.exec_cmd("firefox") +end) +hl.on("config.reloaded", function() + hl.exec_cmd("correct-workspace-locations") +end) + +------------------------------- +---- ENVIRONMENT VARIABLES ---- +------------------------------- + +-- See https://wiki.hypr.land/Configuring/Advanced-and-Cool/Environment-variables/ +-- hl.env("XCURSOR_SIZE", "24") +-- hl.env("HYPRCURSOR_SIZE", "24") +hl.env("TERMINAL", terminal) -- e.g. for emacs + +----------------------- +----- PERMISSIONS ----- +----------------------- + +-- See https://wiki.hypr.land/Configuring/Advanced-and-Cool/Permissions/ +-- Please note permission changes here require a Hyprland restart and are not applied on-the-fly +-- for security reasons + +-- hl.config({ +-- ecosystem = { +-- enforce_permissions = true, +-- }, +-- }) + +-- hl.permission("/usr/(bin|local/bin)/grim", "screencopy", "allow") +-- hl.permission("/usr/(lib|libexec|lib64)/xdg-desktop-portal-hyprland", "screencopy", "allow") +-- hl.permission("/usr/(bin|local/bin)/hyprpm", "plugin", "allow") + +----------------------- +---- LOOK AND FEEL ---- +----------------------- + +-- Refer to https://wiki.hypr.land/Configuring/Basics/Variables/ +hl.config({ + general = { + gaps_in = 5, + gaps_out = 5, + + border_size = 2, + + -- Set to true to enable resizing windows by clicking and dragging on borders and gaps + resize_on_border = true, + + -- Please see https://wiki.hypr.land/Configuring/Advanced-and-Cool/Tearing/ before you turn this on + allow_tearing = false, + + layout = "dwindle", + }, + + decoration = { + -- power saving + shadow = { + enabled = false, + }, + + -- power saving + blur = { + enabled = false, + }, + }, + + animations = { + enabled = true, + }, + + misc = { + disable_autoreload = true, + }, + cursor = { + no_hardware_cursors = 1, -- disable hardware cursors to fix tearing on kardorf + }, + render = { + direct_scanout = 1, + }, +}) + +-- Default curves and animations, see https://wiki.hypr.land/Configuring/Advanced-and-Cool/Animations/ +hl.curve("easeOutQuint", { type = "bezier", points = { { 0.23, 1 }, { 0.32, 1 } } }) +hl.curve("easeInOutCubic", { type = "bezier", points = { { 0.65, 0.05 }, { 0.36, 1 } } }) +hl.curve("linear", { type = "bezier", points = { { 0, 0 }, { 1, 1 } } }) +hl.curve("almostLinear", { type = "bezier", points = { { 0.5, 0.5 }, { 0.75, 1 } } }) +hl.curve("quick", { type = "bezier", points = { { 0.15, 0 }, { 0.1, 1 } } }) + +-- Default springs +hl.curve("easy", { type = "spring", mass = 1, stiffness = 71.2633, dampening = 15.8273644 }) + +hl.animation({ leaf = "global", enabled = true, speed = 10, bezier = "default" }) +hl.animation({ leaf = "border", enabled = true, speed = 5.39, bezier = "easeOutQuint" }) +hl.animation({ leaf = "windows", enabled = true, speed = 4.79, spring = "easy" }) +hl.animation({ leaf = "windowsIn", enabled = true, speed = 4.1, spring = "easy", style = "popin 87%" }) +hl.animation({ leaf = "windowsOut", enabled = true, speed = 1.49, bezier = "linear", style = "popin 87%" }) +hl.animation({ leaf = "fadeIn", enabled = true, speed = 1.73, bezier = "almostLinear" }) +hl.animation({ leaf = "fadeOut", enabled = true, speed = 1.46, bezier = "almostLinear" }) +hl.animation({ leaf = "fade", enabled = true, speed = 3.03, bezier = "quick" }) +hl.animation({ leaf = "layers", enabled = true, speed = 3.81, bezier = "easeOutQuint" }) +hl.animation({ leaf = "layersIn", enabled = true, speed = 4, bezier = "easeOutQuint", style = "fade" }) +hl.animation({ leaf = "layersOut", enabled = true, speed = 1.5, bezier = "linear", style = "fade" }) +hl.animation({ leaf = "fadeLayersIn", enabled = true, speed = 1.79, bezier = "almostLinear" }) +hl.animation({ leaf = "fadeLayersOut", enabled = true, speed = 1.39, bezier = "almostLinear" }) +hl.animation({ leaf = "workspaces", enabled = true, speed = 1.94, bezier = "almostLinear", style = "fade" }) +hl.animation({ leaf = "workspacesIn", enabled = true, speed = 1.21, bezier = "almostLinear", style = "fade" }) +hl.animation({ leaf = "workspacesOut", enabled = true, speed = 1.94, bezier = "almostLinear", style = "fade" }) +hl.animation({ leaf = "zoomFactor", enabled = true, speed = 7, bezier = "quick" }) + +-- Ref https://wiki.hypr.land/Configuring/Basics/Workspace-Rules/ +-- "Smart gaps" / "No gaps when only" +hl.workspace_rule({ workspace = "w[tv1]", gaps_out = 0, gaps_in = 0 }) +hl.workspace_rule({ workspace = "f[1]", gaps_out = 0, gaps_in = 0 }) + +-- See https://wiki.hypr.land/Configuring/Layouts/Dwindle-Layout/ for more +hl.config({ + dwindle = { + preserve_split = true, + smart_split = true, + smart_resizing = true, + -- force_split = 2, + }, +}) + +-- See https://wiki.hypr.land/Configuring/Layouts/Master-Layout/ for more +hl.config({ + master = { + new_status = "master", + }, +}) + +-- See https://wiki.hypr.land/Configuring/Layouts/Scrolling-Layout/ for more +hl.config({ + scrolling = { + fullscreen_on_one_column = true, + }, +}) + +---------------- +---- MISC ---- +---------------- + +hl.config({ + misc = { + force_default_wallpaper = -1, -- Set to 0 or 1 to disable the anime mascot wallpapers + disable_hyprland_logo = false, -- If true disables the random hyprland logo / anime girl background. :( + }, +}) + +--------------- +---- INPUT ---- +--------------- + +hl.config({ + input = { + kb_layout = "de", + follow_mouse = 1, + touchpad = { + natural_scroll = false, + }, + }, +}) + +--------------------- +---- KEYBINDINGS ---- +--------------------- + +local mainMod = "SUPER" + +-- Example binds, see https://wiki.hypr.land/Configuring/Basics/Binds/ for more +hl.bind(mainMod .. " + RETURN", hl.dsp.exec_cmd(terminal)) +hl.bind(mainMod .. " + E", hl.dsp.exec_cmd(fileManager)) +hl.bind(mainMod .. " + D", hl.dsp.exec_cmd(menu)) +hl.bind(mainMod .. " + B", hl.dsp.exec_cmd(browser)) +hl.bind(mainMod .. " + C", hl.dsp.exec_cmd(calculator)) +hl.bind(mainMod .. " + V", hl.dsp.exec_cmd(editor)) + +hl.bind(mainMod .. " + X", hl.dsp.window.close()) +hl.bind(mainMod .. " + SHIFT + E", hl.dsp.exec_cmd("wlogout -p layer-shell")) +hl.bind(mainMod .. " + ESCAPE", hl.dsp.exec_cmd("wlogout -p layer-shell")) +hl.bind(mainMod .. " + SHIFT + R", hl.dsp.exec_cmd("hyprctl reload")) +hl.bind(mainMod .. " + PRINT", hl.dsp.exec_cmd("hyprshot-gui")) +hl.bind("PRINT", hl.dsp.exec_cmd("hyprshot-gui")) +hl.bind(mainMod .. " + P", hl.dsp.exec_cmd("toggle-screen-mirroring; correct-workspace-locations")) +hl.bind(mainMod .. " + TAB", hl.dsp.exec_cmd("swaylock --daemonize")) +hl.bind(mainMod .. " + W", hl.dsp.exec_cmd("makoctl dismiss")) +hl.bind(mainMod .. " + SHIFT + W", hl.dsp.exec_cmd("makoctl restore")) +hl.bind(mainMod .. " + R", hl.dsp.submap("resize")) +hl.bind(mainMod .. " + O", hl.dsp.submap("open")) + +-- hl.bind(mainMod .. " + P", hl.dsp.window.pseudo()) +-- hl.bind(mainMod .. " + J", hl.dsp.layout("togglesplit")) -- dwindle only + +hl.bind(mainMod .. " + SHIFT + SPACE", hl.dsp.window.float({ action = "toggle" })) +hl.bind(mainMod .. " + SPACE", hl.dsp.focus({ window = "floating" })) +hl.bind(mainMod .. " + F", hl.dsp.window.fullscreen({ action = "toggle" })) + +-- Move focus with mainMod + arrow keys +hl.bind(mainMod .. " + left", hl.dsp.focus({ direction = "left" })) +hl.bind(mainMod .. " + right", hl.dsp.focus({ direction = "right" })) +hl.bind(mainMod .. " + up", hl.dsp.focus({ direction = "up" })) +hl.bind(mainMod .. " + down", hl.dsp.focus({ direction = "down" })) +hl.bind(mainMod .. " + H", hl.dsp.focus({ direction = "left" })) +hl.bind(mainMod .. " + L", hl.dsp.focus({ direction = "right" })) +hl.bind(mainMod .. " + K", hl.dsp.focus({ direction = "up" })) +hl.bind(mainMod .. " + J", hl.dsp.focus({ direction = "down" })) + +-- Move window with mainMod + SHIFT + arrow keys +hl.bind(mainMod .. " + SHIFT + left", hl.dsp.window.move({ direction = "left" })) +hl.bind(mainMod .. " + SHIFT + right", hl.dsp.window.move({ direction = "right" })) +hl.bind(mainMod .. " + SHIFT + up", hl.dsp.window.move({ direction = "up" })) +hl.bind(mainMod .. " + SHIFT + down", hl.dsp.window.move({ direction = "down" })) +hl.bind(mainMod .. " + SHIFT + H", hl.dsp.window.move({ direction = "left" })) +hl.bind(mainMod .. " + SHIFT + L", hl.dsp.window.move({ direction = "right" })) +hl.bind(mainMod .. " + SHIFT + K", hl.dsp.window.move({ direction = "up" })) +hl.bind(mainMod .. " + SHIFT + J", hl.dsp.window.move({ direction = "down" })) + +for i = 1, 10 do + local key = i % 10 -- 10 maps to key 0 + -- Switch workspaces + hl.bind(mainMod .. " + " .. key, hl.dsp.focus({ workspace = i })) + -- Move active window to a workspace + hl.bind(mainMod .. " + SHIFT + " .. key, hl.dsp.window.move({ workspace = i })) + -- Move active window to a workspace without following + hl.bind(mainMod .. " + CTRL + " .. key, hl.dsp.window.move({ workspace = i })) +end + +-- Example special workspace (scratchpad) +-- hl.bind(mainMod .. " + S", hl.dsp.workspace.toggle_special("magic")) +-- hl.bind(mainMod .. " + SHIFT + S", hl.dsp.window.move({ workspace = "special:magic" })) + +-- Scroll through existing workspaces with mainMod + scroll +hl.bind(mainMod .. " + mouse_down", hl.dsp.focus({ workspace = "e+1" })) +hl.bind(mainMod .. " + mouse_up", hl.dsp.focus({ workspace = "e-1" })) + +-- Move/resize windows with mainMod + LMB/RMB and dragging +hl.bind(mainMod .. " + mouse:272", hl.dsp.window.drag(), { mouse = true }) -- leftclick +hl.bind(mainMod .. " + mouse:273", hl.dsp.window.resize(), { mouse = true }) -- rightclick + +-- Laptop multimedia keys for volume and LCD brightness +hl.bind( + "XF86AudioRaiseVolume", + hl.dsp.exec_cmd("wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+"), + { locked = true, repeating = true } +) +hl.bind( + "XF86AudioLowerVolume", + hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"), + { locked = true, repeating = true } +) +hl.bind( + "XF86AudioMute", + hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"), + { locked = true, repeating = true } +) +hl.bind( + "XF86AudioMicMute", + hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"), + { locked = true, repeating = true } +) +hl.bind("XF86MonBrightnessUp", hl.dsp.exec_cmd("brightnessctl -e4 -n2 set 5%+"), { locked = true, repeating = true }) +hl.bind("XF86MonBrightnessDown", hl.dsp.exec_cmd("brightnessctl -e4 -n2 set 5%-"), { locked = true, repeating = true }) + +-- Requires playerctl +hl.bind("XF86AudioNext", hl.dsp.exec_cmd("playerctl next"), { locked = true }) +hl.bind("XF86AudioPause", hl.dsp.exec_cmd("playerctl play-pause"), { locked = true }) +hl.bind("XF86AudioPlay", hl.dsp.exec_cmd("playerctl play-pause"), { locked = true }) +hl.bind("XF86AudioPrev", hl.dsp.exec_cmd("playerctl previous"), { locked = true }) + +hl.define_submap("resize", function() + -- Set repeating binds for resizing the active window. + hl.bind("right", hl.dsp.window.resize({ x = 20, y = 0, relative = true }), { repeating = true }) + hl.bind("left", hl.dsp.window.resize({ x = -20, y = 0, relative = true }), { repeating = true }) + hl.bind("up", hl.dsp.window.resize({ x = 0, y = 20, relative = true }), { repeating = true }) + hl.bind("down", hl.dsp.window.resize({ x = 0, y = -20, relative = true }), { repeating = true }) + hl.bind("H", hl.dsp.window.resize({ x = 20, y = 0, relative = true }), { repeating = true }) + hl.bind("L", hl.dsp.window.resize({ x = -20, y = 0, relative = true }), { repeating = true }) + hl.bind("K", hl.dsp.window.resize({ x = 0, y = 20, relative = true }), { repeating = true }) + hl.bind("J", hl.dsp.window.resize({ x = 0, y = -20, relative = true }), { repeating = true }) + + -- Use `reset` to go back to the global submap + hl.bind("escape", hl.dsp.submap("reset")) +end) + +hl.define_submap("open", "reset", function() + hl.bind("E", hl.dsp.exec_cmd("emacs")) + hl.bind("M", hl.dsp.exec_cmd("open-messaging")) + hl.bind("B", hl.dsp.exec_cmd("firefox")) + + -- Use `reset` to go back to the global submap + hl.bind("escape", hl.dsp.submap("reset")) +end) + +-------------------------------- +---- WINDOWS AND WORKSPACES ---- +-------------------------------- + +-- See https://wiki.hypr.land/Configuring/Basics/Window-Rules/ +-- and https://wiki.hypr.land/Configuring/Basics/Workspace-Rules/ + +-- Default workspaces for certain windows +hl.window_rule({ match = { class = "firefox" }, workspace = "1" }) +hl.window_rule({ match = { class = "Zotero" }, workspace = "8" }) +hl.window_rule({ match = { class = "nheko" }, workspace = "9" }) +hl.window_rule({ match = { class = "element" }, workspace = "9" }) +hl.window_rule({ match = { class = "discord" }, workspace = "9" }) +hl.window_rule({ match = { class = "org.telegram.desktop" }, workspace = "9" }) +hl.window_rule({ match = { class = "thunderbird" }, workspace = "10" }) + +-- Float calculator +hl.window_rule({ match = { class = "qalculate-gtk" }, float = true }) + +-- Example window rules that are useful + +hl.window_rule({ + -- Ignore maximize requests from all apps. + name = "suppress-maximize-events", + match = { class = ".*" }, + + suppress_event = "maximize", +}) + +hl.window_rule({ + -- Fix some dragging issues with XWayland + name = "fix-xwayland-drags", + match = { + class = "^$", + title = "^$", + xwayland = true, + float = true, + fullscreen = false, + pin = false, + }, + + no_focus = true, +}) + +-- Disable animations for selection, fixes screenshots +hl.layer_rule({ + name = "no-anim-overlay", + match = { namespace = "^my-overlay$" }, -- selection + no_anim = true, +}) diff --git a/homes/julian/features/hyprland/toggle-screen-mirroring.sh b/homes/julian/features/hyprland/toggle-screen-mirroring.sh index 52de189..32ebc22 100644 --- a/homes/julian/features/hyprland/toggle-screen-mirroring.sh +++ b/homes/julian/features/hyprland/toggle-screen-mirroring.sh @@ -2,66 +2,18 @@ # A hyprland script for a laptop-external-monitor setup, toggling between which is in use -# Launch at startup to make hyprland disable the internal monitor if an external monitor is detected and enabled -# Additionally it's called with a keybind to switch between a laptop monitor and an external display -# Ideally the conditional monitor behaviour was instead done directly in hyprland.conf, but I'm not sure whether that's possible -# -# Relevant info: -# - hyprctl monitors: identifies currently enabled monitors -# - hyprctl monitors all: identifies ALL connected monitors - including those not in use -# -# Suggested use: -# Add this line somewhere after the regular monitor configuration in hyprland.conf: -# exec = /path/to/hyprland-monitors-toggle.sh -# Add a keybind to run this script on demand: -# bind =,SomeKeyHere, exec, /path/to/hyprland-monitors-toggle.sh - -#move_all_workspaces_to_monitor() { -# TARGET_MONITOR="$1" - -# hyprctl workspaces | grep ^workspace | cut --delimiter ' ' --fields 3 | xargs -I '{}' hyprctl dispatch moveworkspacetomonitor '{}' "$TARGET_MONITOR" - -# # Previous approach -# #hyprctl swapactiveworkspaces $EXTERNAL_MONITOR $INTERNAL_MONITOR -#} - # TODO: Detect these instead of hardcoding them INTERNAL_MONITOR="eDP-1" EXTERNAL_MONITOR="HDMI-A-1" -# NUM_MONITORS=$(hyprctl monitors all | grep --count Monitor) -# NUM_MONITORS_ACTIVE=$(hyprctl monitors | grep --count Monitor) - -# Make sure all -# if [ "$NUM_MONITORS_ACTIVE" -eq 1 ]; then -# move_all_workspaces_to_monitor $INTERNAL_MONITOR -# exit -# fi - MIRROR_SETTING=$(hyprctl monitors all -j | jq -r '.[] | select(.name == "HDMI-A-1") | .mirrorOf') -# # For dynamically toggling which monitor is active later via a keybind -# if [ "$NUM_MONITORS" -gt 1 ]; then # Handling multiple monitors -# if hyprctl monitors | cut --delimiter ' ' --fields 2 | grep --quiet ^$EXTERNAL_MONITOR; then -# hyprctl keyword monitor $INTERNAL_MONITOR,preferred,0x0,1 -# move_all_workspaces_to_monitor $INTERNAL_MONITOR -# hyprctl keyword monitor "$EXTERNAL_MONITOR, disable" -# else -# hyprctl keyword monitor $EXTERNAL_MONITOR,preferred,0x0,1 -# move_all_workspaces_to_monitor $EXTERNAL_MONITOR -# hyprctl keyword monitor "$INTERNAL_MONITOR, disable" -# fi -# else # If the external monitor is disconnected without running this script first, it might become the case that no monitor is on - therefore turn on the laptop monitor! -# hyprctl keyword monitor $INTERNAL_MONITOR,preferred,0x0,1 -# move_all_workspaces_to_monitor $INTERNAL_MONITOR -# fi - -echo setting: +echo "current setting: " echo $MIRROR_SETTING if [ "$MIRROR_SETTING" = "none" ]; then echo "mirroring..." - hyprctl keyword monitor "$EXTERNAL_MONITOR, preferred, auto, 1, mirror, $INTERNAL_MONITOR" + hyprctl eval "hl.monitor({output=\"$EXTERNAL_MONITOR\", mode=\"preferred\", position=\"auto\", scale=\"auto\", mirror=\"$INTERNAL_MONITOR\"})" else - hyprctl keyword monitor "$EXTERNAL_MONITOR, disable" # shortly disable monitor so waybar recognizes the new monitor again # TODO: find better solution - hyprctl keyword monitor "$EXTERNAL_MONITOR, preferred, auto, 1" + # hyprctl keyword monitor "$EXTERNAL_MONITOR, disable" # shortly disable monitor so waybar recognizes the new monitor again # TODO: find better solution + hyprctl eval "hl.monitor({output=\"$EXTERNAL_MONITOR\", mode=\"preferred\", position=\"auto\", scale=\"auto\", mirror=\"\"})" fi