Skip to content

Eliminate the 0.3s sleep intentionally slowing down state query via yabai #9

@AdamWagner

Description

@AdamWagner

The unfortunate sleep command
Sadly, on a 16" "macbook pro, at least 0.03 delay is required to ensure yabai -m query … returns the focused window and not the previously focused window. See bin/yabai-get-stacks.

Without the sleep, the active stacked-window indicator remains on the previously active stacked-window once every ~1 in 5 focus events — particularly when changing focus rapidly.

Why does yabai query occasionally not return new state when called by Hammerspoon's hs.window.filter.windowFocused event?

Hypothesis: if a yabai query blocks a subsequent query, sequential calls may accumulate and eventually fall behind the current state? Actually, this doesn't really make sense, wouldn't this mean the last call would be late, and therefore be slow, but reflect the latest state?

ALTERNATIVE no. 1
For events that will certainly result in a stack indicator update (e.g., windowFocused), we could call this continuously w/ exponential backoff until the response is different.

This seems like it would provide the best of both worlds: responsive updates when the yabai query reflects the change, and eventual consistency when it doesn't.

The cost is additional calls to yabai -m query …, which may be significant. There may be other costs I'm not considering, e.g., what happens when there are 5 focus events in 5 seconds?

ALTERNATIVE no. 2
Avoid shelling out to yabai at all and instead synthesize stacks entirely in hammerspoon. This is the approach recommended in #8.

sleep 0.03

yabai -m query --windows --space \
  | jq --raw-output --compact-output --monochrome-output '
      map(del(.title))                             # titles may break lua json parsing
    | map(select(
      .subrole == "AXStandardWindow" and  
      .visible == 1))                              # minimized == 0 may be preferrable?
    | map(.frameFlat = "\(.frame.x)|\(.frame.y)")  # frame x,y to string to group wins → stacks
    | sort_by(.["stack-index"])
    | group_by(.frameFlat)                         # … the aforementioned grouping
    | map(select(length > 1))                      # we only care about *stacks*, which contain > 1 window
    '

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions