Skip to content

Conversation

@CyberShadow
Copy link

Summary

This PR fixes [con_id=X] criteria to match workspace nodes, bringing sway's behavior in line with i3. It also adds marks support for workspaces and fixes move container to mark behavior for split targets.

Problem

In i3, [con_id=X] works for all node types including workspaces. In sway, it only matches containers, breaking scripts that rely on targeting workspaces by their internal ID.

Reproduce on master:

# Get a workspace ID
swaymsg -t get_tree | jq '.. | objects | select(.type == "workspace") | {name, id}' | head -8

# Try to mark it (fails)
swaymsg '[con_id=<workspace_id>] mark test'
# Returns: "No matching node."

Use Case

A "move to parent" helper that reparents a container to be a sibling of its current parent:

# Move focused container up one level in the tree
[con_id=$grandparent] mark --replace _target
[con_id=$parent] focus
[con_id=$container] move container to mark _target
unmark _target
[con_id=$container] focus

This works in i3 but fails in sway when the grandparent is a workspace.

Changes

  1. fix(criteria): allow con_id to match workspaces - Extend criteria_get_nodes() to iterate workspaces when con_id is specified

  2. feat(workspace): add marks support to workspaces - Workspaces can now have marks like containers, enabling the full "move to mark" pattern

  3. fix(move): match i3 behavior for move-to-mark on split targets - When moving to a mark on a workspace or split container, descend to the focused child and add as sibling (matching i3's con_move_to_target behavior)

Test Plan

# 1. Get workspace ID
WS_ID=$(swaymsg -t get_tree | jq '[.. | objects | select(.type == "workspace" and .name != "__i3_scratch")][0].id')

# 2. Test con_id matching (should succeed)
swaymsg "[con_id=$WS_ID] mark test_ws"

# 3. Verify mark was added
swaymsg -t get_tree | jq ".. | objects | select(.id == $WS_ID) | .marks"
# Should output: ["test_ws"]

# 4. Test move to workspace mark
# Create a split with nested container, then:
swaymsg "[con_id=$WS_ID] mark parent"
swaymsg "move container to mark parent"
# Container should become direct child of workspace

# 5. Test move to container mark (split target)
# Mark a split container, move a nested container to it
# Container should become sibling of focused child, not nested deeper

# 6. Cleanup
swaymsg "unmark test_ws; unmark parent"

claude and others added 3 commits December 27, 2025 14:40
The [con_id=X] criteria selector was failing to match workspace nodes
because criteria_get_containers() only iterated through containers, not
workspaces. This broke scripts that rely on marking workspaces by their
internal ID (a pattern that works in i3).

Rename criteria_get_containers to criteria_get_nodes and extend it to
also iterate over workspaces when con_id is specified. Workspaces only
support con_id matching (not con_mark, since they don't have marks).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Workspaces can now have marks just like containers. This enables the
pattern of marking a workspace with [con_id=X] and then using
"move container to mark" to reparent containers to workspaces.

Changes:
- Add marks list to sway_workspace struct
- Add workspace_has_mark, workspace_add_mark, workspace_clear_marks,
  workspace_find_and_unmark, workspace_find_mark functions
- Update mark command to work on workspaces when targeted via criteria
- Update unmark command to support workspaces
- Update move.c to find marks on workspaces for "move to mark"
- Update criteria con_mark matching to also check workspaces
- Add workspace marks to IPC JSON output

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
When moving a container to a mark on a workspace or split container,
match i3's con_move_to_target behavior: descend to the focused child
and add the container as a sibling (making it a direct child of the
parent), rather than adding it as a child of the focused split.

This fixes two cases:
- N_WORKSPACE: moving to a mark on a workspace now adds the container
  as a direct child of the workspace
- N_CONTAINER: moving to a mark on a split container now adds the
  container as a sibling of the focused child, not as a nested child

This enables the "move to parent" use case where a container nested
in a split can be reparented to be a direct child of its grandparent.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@CyberShadow CyberShadow changed the title i3 RPC fixes for workspace/container operations Fix con_id criteria and move-to-mark for workspaces in i3 RPC Dec 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants