Astal icon indicating copy to clipboard operation
Astal copied to clipboard

hyprland workspace client list not updated after move unless focused

Open Not-a-true-statement opened this issue 10 months ago • 2 comments

Describe the bug Hyprland does not update workspace or clients bind on client move to another workspace. The only value which is updated is lastClient.

The comand in the hyprland config is movetoworkspacesilent, which does not move the focus to another workspace after moving the client. movetoworkspace works as expected, presumably because the focus is moved to where the client is moved.

Expected behavior To show the correct number of clients per workspace after moving a client to another workspace even when using movetoworkspacesilent to move client.

Additional context

Keybindings bind = $mainMod SHIFT, 1, movetoworkspacesilent, 1 bind = $mainMod SHIFT, 2, movetoworkspacesilent, 2 bind = $mainMod SHIFT, 3, movetoworkspacesilent, 3 bind = $mainMod SHIFT, 4, movetoworkspacesilent, 4 bind = $mainMod SHIFT, 5, movetoworkspacesilent, 5 bind = $mainMod SHIFT, 6, movetoworkspacesilent, 6 bind = $mainMod SHIFT, 7, movetoworkspacesilent, 7 bind = $mainMod SHIFT, 8, movetoworkspacesilent, 8 bind = $mainMod SHIFT, 9, movetoworkspacesilent, 9 bind = $mainMod SHIFT, 0, movetoworkspacesilent, 10

Here is a sample code ` function verticalWidget(gdkMonitor: Gdk.Monitor): JSX.Element {

// Find correct monitor, or return empty if none found.
const currentHyprlandMonitor = hyprland.get_monitor_by_name(getMonitorName(gdkMonitor) ?? "");
if (!currentHyprlandMonitor) return <></>
print(`Monitor:${currentHyprlandMonitor.id} assigned a bar`)

return <box className="workspaces-widget-vertical" vertical={true}>
    {Variable.derive([bind(hyprland, "workspaces"), bind(hyprland, "clients"), bind(hyprland,"focusedWorkspace"),bind(hyprland,"focusedClient")])().as((values) => {

        let workspaces = values[0]; //only updates when switching workspace
        let clients = values[1];
        let focusedWorkspace = values[2];

        // Sort
        workspaces = showAllWorkspaces ? workspaces : workspaces.filter(val => val.monitor.id === currentHyprlandMonitor.id);
        workspaces.sort((a, b) => a.id - b.id);

        return workspaces.map((workspace) => 
            <button
                className={workspace === focusedWorkspace ? "focused" : ""}
                onClicked={() => {
                    workspace.move_to(currentHyprlandMonitor);
                    workspace.focus();
                }}
            >
                <box vertical={true}>
                    {`${workspace.id}:${workspace.clients.length} + ${clients.filter(val=>val.workspace===workspace).length}`}
                </box>
            </button>
        );
    })}
</box>

} `

Not-a-true-statement avatar Feb 11 '25 08:02 Not-a-true-statement

I believe I have the same issue. When I move a client from one workspace to another using drag-and-drop (SUPER, mouse:272, movewindow), neither the workspaces nor the clients list updates.

To verify, I print out the list of workspaces every time it changes:

import { bind } from "astal"
import { Gtk } from "astal/gtk3"
import Hyprland from "gi://AstalHyprland"
import Clients from "./Clients"

const hyprland = Hyprland.get_default()

interface Props {
    monitorId: number
}

export default function Workspaces({ monitorId }: Props) {
    const workspaces = bind(hyprland, "workspaces").as((ws) =>
        ws
//-------------------------------------------------------------------
            .map((workspace) => {
                print("workspace", workspace.name)
                return workspace
            })
//-------------------------------------------------------------------
            .filter((workspace) => workspace.monitor.id === monitorId)
            .sort((a, b) => a.id - b.id)
            .map((workspace) => (
                <button
                    halign={Gtk.Align.CENTER}
                    onClick={() =>
                        hyprland.dispatch("workspace", workspace.name)
                    }
                >
                    <box orientation={Gtk.Orientation.HORIZONTAL} spacing={4}>
                        <label>
                            {workspace.name[workspace.name.length - 1]}
                        </label>
                        <Clients workspaceId={workspace.id} />
                    </box>
                </button>
            )),
    )

    return (
        <box orientation={Gtk.Orientation.HORIZONTAL} halign={Gtk.Align.CENTER}>
            {workspaces}
        </box>
    )
}

Expected Behavior:

When I move a client using drag-and-drop, the printed list of workspaces should update.

Actual Behavior:

  • The workspace list does not update when moving a client via movewindow.
  • However, when using split-movetoworkspace, it correctly triggers updates (I currently use the split-monitor-workspaces plugin).

It seems like drag-and-drop moves are not firing the appropriate signal to AstalHyprland. Could this be a missing event, or does AstalHyprland need explicit handling for drag-and-drop workspace changes?

anders130 avatar Feb 26 '25 19:02 anders130

A simple workaround to just listen manually, not sure why client-moved is firing here but not when you bind to clients

const hypr = Hyprland.get_default();
const [clients, setClients] = createState(hypr.get_clients());
hypr.connect('client-added', (_, client) => {
	setClients((c) => [...c, client]);
});
hypr.connect('client-removed', (_, address) => {
	setClients((c) => c.filter((c) => c.address != address));
});
hypr.connect('client-moved', (hy, _) => {
	setClients((_) => hy.get_clients());
});

spotdemo4 avatar Jul 20 '25 09:07 spotdemo4