From 9a28a63ba3cf32b9851ae66f66c4e82b8affa684 Mon Sep 17 00:00:00 2001 From: Ivan Malison Date: Fri, 8 May 2026 12:37:08 -0700 Subject: [PATCH] Add Hyprland rofi layout selector --- dotfiles/config/hypr/hyprland.lua | 17 ++++++++ dotfiles/lib/bin/hypr_rofi_layout | 70 +++++++++++++++++++++++++++++++ nixos/hyprland.nix | 14 +++++++ 3 files changed, 101 insertions(+) create mode 100755 dotfiles/lib/bin/hypr_rofi_layout diff --git a/dotfiles/config/hypr/hyprland.lua b/dotfiles/config/hypr/hyprland.lua index a8ca1f2e..986f7420 100644 --- a/dotfiles/config/hypr/hyprland.lua +++ b/dotfiles/config/hypr/hyprland.lua @@ -728,6 +728,22 @@ local function set_layout(layout) end end +_G.im_hyprland_set_layout = function(layout) + if not layout_names[layout] then + hl.notification.create({ + text = "Unknown layout: " .. tostring(layout), + duration = 1800, + icon = notification_icons.warning, + color = "rgba(edb443ff)", + font_size = 13, + }) + return + end + + set_layout(layout) + notify_layout(layout) +end + local function sync_layout_for_active_workspace() current_layout = current_workspace_layout() hl.config({ general = { layout = hyprland_layout(current_layout) } }) @@ -2308,6 +2324,7 @@ bind(hyper .. " + P", exec("rofi-pass")) bind(hyper .. " + H", exec([[grim -g "$(slurp)" - | swappy -f -]])) bind(hyper .. " + C", exec("rofi_tmcodex.sh")) bind(hyper .. " + SHIFT + L", exec("hyprlock")) +bind(hyper .. " + L", exec("hypr_rofi_layout")) bind(hyper .. " + K", exec("rofi_kill_process.sh")) bind(hyper .. " + SHIFT + K", exec("rofi_kill_all.sh")) bind(hyper .. " + R", exec("rofi-systemd")) diff --git a/dotfiles/lib/bin/hypr_rofi_layout b/dotfiles/lib/bin/hypr_rofi_layout new file mode 100755 index 00000000..1458d6df --- /dev/null +++ b/dotfiles/lib/bin/hypr_rofi_layout @@ -0,0 +1,70 @@ +#!/usr/bin/env bash +set -euo pipefail + +ensure_hyprland_instance() { + if [[ -n "${HYPRLAND_INSTANCE_SIGNATURE:-}" ]]; then + return + fi + + local runtime="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}" + local hypr_dir="$runtime/hypr" + if [[ ! -d "$hypr_dir" ]]; then + return + fi + + local socket_dir + socket_dir="$( + find "$hypr_dir" -mindepth 2 -maxdepth 2 -name .socket.sock -printf '%T@ %h\n' 2>/dev/null | + sort -nr | + awk 'NR == 1 { print $2 }' + )" + + if [[ -n "$socket_dir" ]]; then + export HYPRLAND_INSTANCE_SIGNATURE="${socket_dir##*/}" + fi +} + +current_layout() { + local state_file="${XDG_RUNTIME_DIR:-}/hyprland-layout-state" + if [[ -r "$state_file" ]]; then + awk -F= '$1 == "layout" { print $2; exit }' "$state_file" + fi +} + +ensure_hyprland_instance + +layouts=( + "nStack Columns" + "master Large main" + "grid Grid" + "monocle Monocle" +) + +current="$(current_layout || true)" +selected_row=0 +labels=() + +for index in "${!layouts[@]}"; do + layout="${layouts[$index]%%$'\t'*}" + label="${layouts[$index]#*$'\t'}" + labels+=("$label") + + if [[ "$layout" == "$current" ]]; then + selected_row="$index" + fi +done + +selection="$( + printf '%s\n' "${labels[@]}" | + rofi -dmenu -i -p "Layout" -selected-row "$selected_row" +)" || exit 0 + +for entry in "${layouts[@]}"; do + layout="${entry%%$'\t'*}" + label="${entry#*$'\t'}" + + if [[ "$label" == "$selection" ]]; then + hyprctl dispatch "_G.im_hyprland_set_layout(\"$layout\")" >/dev/null + exit 0 + fi +done diff --git a/nixos/hyprland.nix b/nixos/hyprland.nix index 237e46eb..6cee82a8 100644 --- a/nixos/hyprland.nix +++ b/nixos/hyprland.nix @@ -116,6 +116,19 @@ exec ${../dotfiles/lib/bin/hypr_shell_ui} "$@" ''; }; + hyprRofiLayout = pkgs.writeShellApplication { + name = "hypr_rofi_layout"; + runtimeInputs = [ + pkgs.coreutils + pkgs.findutils + pkgs.gawk + pkgs.rofi + hyprlandPackage + ]; + text = '' + exec ${../dotfiles/lib/bin/hypr_rofi_layout} "$@" + ''; + }; hyprscratchSettings = { daemon_options = "clean"; global_options = ""; @@ -267,6 +280,7 @@ ddcutil # Monitor input switching over DDC/CI # For scripts + hyprRofiLayout hyprRofiWindow hyprShellUi jq