Update multi-display workspace handling

Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
2025-02-16 17:15:28 +00:00
parent 7fa058293b
commit a467f953bb
4 changed files with 78 additions and 49 deletions

View File

@@ -20,7 +20,7 @@ function getHyprlandMonitor(gdkmonitor: Gdk.Monitor) {
} }
} }
export default (monitor: Gdk.Monitor, index: number) => <window export default (monitor: Gdk.Monitor) => <window
className='bar' className='bar'
gdkmonitor={monitor} gdkmonitor={monitor}
exclusivity={Astal.Exclusivity.EXCLUSIVE} exclusivity={Astal.Exclusivity.EXCLUSIVE}

View File

@@ -3,32 +3,61 @@ import Hyprland from "gi://AstalHyprland";
import { range } from '../../lib'; import { range } from '../../lib';
const hyprland = Hyprland.get_default(); const hyprland = Hyprland.get_default();
const BLOCK_SIZE = 10;
const Workspace = ({ id }: { id: number }) => {
let maybeWorkspace: Variable<Hyprland.Workspace | undefined>;
let occupied: Variable<boolean>;
try {
const workspace = hyprland.get_workspace(id);
maybeWorkspace = Variable(workspace);
occupied = Variable(workspace.clients.length > 0);
} catch (_) {
maybeWorkspace = Variable(undefined);
occupied = Variable(false);
}
const active = Variable.derive(
[bind(hyprland, "focusedWorkspace")],
focused => focused.id == id
);
hyprland.connect("workspace-added", (_, workspace) => {
if (workspace.id != id) return;
maybeWorkspace.set(workspace);
occupied.set(workspace.clients.length > 0);
workspace.connect("clients", clients => occupied.set(clients.length > 0))
});
hyprland.connect("workspace-removed", (_, workspaceId) => {
if (workspaceId != id) return;
maybeWorkspace.set(undefined);
occupied.set(false);
});
const Workspace = ({ workspace }: { workspace: Hyprland.Workspace }) => {
const className = Variable.derive( const className = Variable.derive(
[bind(hyprland, "focusedWorkspace"), bind(workspace, "clients")], [active, occupied],
(focused, clients) => { (active, occupied) => {
if (focused.id == workspace.id) return "button active"; if (active) return "button active";
if (clients.length > 0) return "button occupied"; if (occupied) return "button occupied";
return "button"; return "button";
}, }
); );
return <box vertical> return <box vertical>
<box vexpand /> <box vexpand />
<eventbox <eventbox onClickRelease={() => hyprland.dispatch("workspace", `${id}`)}>
onClickRelease={() => hyprland.dispatch("workspace", `${workspace.id}`)} <label className={className()} />
>
<label
className={className()}
/>
</eventbox> </eventbox>
<box vexpand /> <box vexpand />
</box>; </box>;
}; };
export default ({ monitor }: { monitor: Hyprland.Monitor }) => { export default ({ monitor }: { monitor: Hyprland.Monitor }) => {
const workspaces = hyprland.get_workspaces().filter(w => w.monitor.id == monitor.id).sort((w1, w2) => w1.id - w2.id); const workspaces = hyprland.get_workspaces();
const displayWorkspaces = workspaces.filter(w => w.monitor.id === monitor.id);
const displayWorkspaceBlockStart = Math.floor((displayWorkspaces[0].id - 1) / BLOCK_SIZE) * 10;
return <eventbox return <eventbox
className="workspaces" className="workspaces"
@@ -37,7 +66,7 @@ export default ({ monitor }: { monitor: Hyprland.Monitor }) => {
}} }}
> >
<box> <box>
{workspaces.map((w) => <Workspace workspace={w} />)} {range(BLOCK_SIZE).map(i => <Workspace id={displayWorkspaceBlockStart + i} />)}
</box> </box>
</eventbox>; </eventbox>;
}; };

View File

@@ -1,24 +1,24 @@
BASE_WS="$1" SELECTED_WORKSPACE_BASE="$1"
ACTION="$2" ACTION="$2"
current_ws_id="$(hyprctl -j activeworkspace | jq -r '.id')"
ws_json="$(hyprctl -j workspaces)"
max_ws_id="$(echo "$ws_json" | jq -r '[.[] | .id] | max')"
BLOCK_SIZE=10 BLOCK_SIZE=10
total_blocks=$(((max_ws_id - 1) / BLOCK_SIZE + 1)) current_workspace_id="$(hyprctl -j activeworkspace | jq -r '.id')"
current_block=$(((current_ws_id - 1) / BLOCK_SIZE)) workspace_json="$(hyprctl -j workspaces)"
target_ws=$((current_block * BLOCK_SIZE + BASE_WS))
if [ "$target_ws" -eq "$current_ws_id" ]; then max_active_workspace_id="$(echo "$workspace_json" | jq -r '[.[] | .id] | max')"
next_block=$(( (current_block + 1) % total_blocks )) total_blocks=$(((max_active_workspace_id - 1) / BLOCK_SIZE + 1))
target_ws=$(( next_block * BLOCK_SIZE + BASE_WS ))
current_block=$(((current_workspace_id - 1) / BLOCK_SIZE))
target_workspace_id=$((current_block * BLOCK_SIZE + SELECTED_WORKSPACE_BASE))
if [ "$target_workspace_id" -eq "$current_workspace_id" ]; then
next_block=$(((current_block + 1) % total_blocks))
target_workspace_id=$((next_block * BLOCK_SIZE + SELECTED_WORKSPACE_BASE))
fi fi
if [ "$ACTION" = "move" ]; then if [ "$ACTION" = "move" ]; then
hyprctl dispatch movetoworkspacesilent "$target_ws" hyprctl dispatch movetoworkspacesilent "$target_workspace_id"
else else
hyprctl dispatch workspace "$target_ws" hyprctl dispatch workspace "$target_workspace_id"
fi fi

View File

@@ -24,26 +24,26 @@
}; };
workspace = [ workspace = [
"1, monitor:eDP-1, layoutopt:orientation:left, persistent:true" "1, monitor:eDP-1, layoutopt:orientation:left"
"2, monitor:eDP-1, layoutopt:orientation:left, persistent:true" "2, monitor:eDP-1, layoutopt:orientation:left"
"3, monitor:eDP-1, layoutopt:orientation:left, persistent:true" "3, monitor:eDP-1, layoutopt:orientation:left"
"4, monitor:eDP-1, layoutopt:orientation:left, persistent:true" "4, monitor:eDP-1, layoutopt:orientation:left"
"5, monitor:eDP-1, layoutopt:orientation:left, persistent:true" "5, monitor:eDP-1, layoutopt:orientation:left"
"6, monitor:eDP-1, layoutopt:orientation:left, persistent:true" "6, monitor:eDP-1, layoutopt:orientation:left"
"7, monitor:eDP-1, layoutopt:orientation:left, persistent:true" "7, monitor:eDP-1, layoutopt:orientation:left"
"8, monitor:eDP-1, layoutopt:orientation:left, persistent:true" "8, monitor:eDP-1, layoutopt:orientation:left"
"9, monitor:eDP-1, layoutopt:orientation:left, persistent:true" "9, monitor:eDP-1, layoutopt:orientation:left"
"10, monitor:eDP-1, layoutopt:orientation:left, persistent:true" "10, monitor:eDP-1, layoutopt:orientation:left"
"11, monitor:HDMI-A-1, layoutopt:orientation:center, persistent:true" "11, monitor:HDMI-A-1, layoutopt:orientation:center"
"12, monitor:HDMI-A-1, layoutopt:orientation:center, persistent:true" "12, monitor:HDMI-A-1, layoutopt:orientation:center"
"13, monitor:HDMI-A-1, layoutopt:orientation:center, persistent:true" "13, monitor:HDMI-A-1, layoutopt:orientation:center"
"14, monitor:HDMI-A-1, layoutopt:orientation:center, persistent:true" "14, monitor:HDMI-A-1, layoutopt:orientation:center"
"15, monitor:HDMI-A-1, layoutopt:orientation:center, persistent:true" "15, monitor:HDMI-A-1, layoutopt:orientation:center"
"16, monitor:HDMI-A-1, layoutopt:orientation:center, persistent:true" "16, monitor:HDMI-A-1, layoutopt:orientation:center"
"17, monitor:HDMI-A-1, layoutopt:orientation:center, persistent:true" "17, monitor:HDMI-A-1, layoutopt:orientation:center"
"18, monitor:HDMI-A-1, layoutopt:orientation:center, persistent:true" "18, monitor:HDMI-A-1, layoutopt:orientation:center"
"19, monitor:HDMI-A-1, layoutopt:orientation:center, persistent:true" "19, monitor:HDMI-A-1, layoutopt:orientation:center"
"20, monitor:HDMI-A-1, layoutopt:orientation:center, persistent:true" "20, monitor:HDMI-A-1, layoutopt:orientation:center"
]; ];
}; };