Yabai: Disable tiling for a display

Created on 2 Dec 2019  路  1Comment  路  Source: koekeishiya/yabai

Is it possible to disable tiling for a display? I'd like windows to behave similar to vanilla macOS (except for the bar space).
I'm running on a MBP 13'' and tiling doesn't go too well with that size. I do, however, use tiling extensively when using external displays.

Thanks.

question

Most helpful comment

_Note: I wrote a lot more than I intended to at first, but maybe people can learn about some advanced features of yabai from this._

Let's walk you through how you can already do this with yabai's existing API.

Problem Space

What tools do we need, and where is their documentation located at?

|Tool|Documentation|
|-:|:-|
|yabai| https://github.com/koekeishiya/yabai/blob/master/doc/yabai.asciidoc|
|jq|https://stedolan.github.io/jq/manual/|

Having read the documentation, what are the obvious limitations we are trying to work around?

  1. yabai let's you configure the layout per space, but not per display
  2. Additional spaces can be created without using yabai
  3. Spaces may be moved between displays

With that in mind, let's solve each of these individually.

Solution Space

1. a) How do we identify the target display?

We can either use the display with the smallest size, the first one by index (mostly reliable), or the main display (that's the one whose (frame.x, frame.y) == (0, 0)).

I'll choose to use the display with the index 1 for this solution, as it's the easiest to read.

1. b) How do we set the layout for a given space?

The yabai documentation holds the answer to this:

yabai -m space [<selector>] --layout <bsp|float>

1. c) How do we set the layout for all spaces on one display?

First of all, we want to do this in our yabairc so the code always executes right after yabai starts.

We can get a list of all spaces from a given display using yabai -m query --displays --display <selector>. A valid selector here would be the index 1, or the named selector first.

We can then use jq to print all mission-control indices associated with the display, and use xargs to make yabai execute a command for every single one of them.

yabai -m query --displays --display 1 |
  jq '.spaces[]' |
  xargs -I{} yabai -m space {} --layout float

Running this, you may notice lots of cannot set layout for a macOS fullscreen space! error messages. Let's fix these by excluding fullscreen spaces from our query. You may notice that display queries do not carry this information, so we need to switch a space query instead.

yabai -m query --spaces --display 1 |
  jq '.[] | select(."native-fullscreen" == 0).index' |
  xargs -I{} yabai -m space {} --layout float

Works like a charm!

2. How do we handle new spaces?

yabai cannot currently notify you when new spaces are created, as this is unsupported by the signal API. What you can do, however, is register for the space_changed signal, which triggers whenever the space focus changes.

The space_changed signal carries two points of data: $YABAI_SPACE_ID (id of the newly focused space) and $YABAI_RECENT_SPACE_ID (id of the previously focused space).

We can then figure out if $YABAI_SPACE_ID is a non-fullscreen space on the target display, and if it is, change its layout to float.

yabai -m signal --add event=space_changed action="$action"

Now, what does this $action need to look like?

read -r -d '' action <<- 'EOF'
  yabai -m query --spaces --display 1 |
    jq ".[] | select(.id == $YABAI_SPACE_ID and .\"native-fullscreen\" == 0).index" |
    xargs -I{} yabai -m space {} --layout float
EOF

This can still be improved by also switching the space back to bsp if it's on another display, but I won't show that here.

3. What if a space gets moved between displays?

Think about it: While a space is being moved between displays, it cannot be focused. If you can live without immediately changing the layout of moved spaces, the signal from 2. might be good enough already.

Future Improvement Ideas

yabais signal API is limited to events that macOS emits, which is why there are no space_moved, space_created, or space_destroyed events.

Such events would need to be artificially created by yabai, but could in turn improve the signal API. These are not a thing yet.

>All comments

_Note: I wrote a lot more than I intended to at first, but maybe people can learn about some advanced features of yabai from this._

Let's walk you through how you can already do this with yabai's existing API.

Problem Space

What tools do we need, and where is their documentation located at?

|Tool|Documentation|
|-:|:-|
|yabai| https://github.com/koekeishiya/yabai/blob/master/doc/yabai.asciidoc|
|jq|https://stedolan.github.io/jq/manual/|

Having read the documentation, what are the obvious limitations we are trying to work around?

  1. yabai let's you configure the layout per space, but not per display
  2. Additional spaces can be created without using yabai
  3. Spaces may be moved between displays

With that in mind, let's solve each of these individually.

Solution Space

1. a) How do we identify the target display?

We can either use the display with the smallest size, the first one by index (mostly reliable), or the main display (that's the one whose (frame.x, frame.y) == (0, 0)).

I'll choose to use the display with the index 1 for this solution, as it's the easiest to read.

1. b) How do we set the layout for a given space?

The yabai documentation holds the answer to this:

yabai -m space [<selector>] --layout <bsp|float>

1. c) How do we set the layout for all spaces on one display?

First of all, we want to do this in our yabairc so the code always executes right after yabai starts.

We can get a list of all spaces from a given display using yabai -m query --displays --display <selector>. A valid selector here would be the index 1, or the named selector first.

We can then use jq to print all mission-control indices associated with the display, and use xargs to make yabai execute a command for every single one of them.

yabai -m query --displays --display 1 |
  jq '.spaces[]' |
  xargs -I{} yabai -m space {} --layout float

Running this, you may notice lots of cannot set layout for a macOS fullscreen space! error messages. Let's fix these by excluding fullscreen spaces from our query. You may notice that display queries do not carry this information, so we need to switch a space query instead.

yabai -m query --spaces --display 1 |
  jq '.[] | select(."native-fullscreen" == 0).index' |
  xargs -I{} yabai -m space {} --layout float

Works like a charm!

2. How do we handle new spaces?

yabai cannot currently notify you when new spaces are created, as this is unsupported by the signal API. What you can do, however, is register for the space_changed signal, which triggers whenever the space focus changes.

The space_changed signal carries two points of data: $YABAI_SPACE_ID (id of the newly focused space) and $YABAI_RECENT_SPACE_ID (id of the previously focused space).

We can then figure out if $YABAI_SPACE_ID is a non-fullscreen space on the target display, and if it is, change its layout to float.

yabai -m signal --add event=space_changed action="$action"

Now, what does this $action need to look like?

read -r -d '' action <<- 'EOF'
  yabai -m query --spaces --display 1 |
    jq ".[] | select(.id == $YABAI_SPACE_ID and .\"native-fullscreen\" == 0).index" |
    xargs -I{} yabai -m space {} --layout float
EOF

This can still be improved by also switching the space back to bsp if it's on another display, but I won't show that here.

3. What if a space gets moved between displays?

Think about it: While a space is being moved between displays, it cannot be focused. If you can live without immediately changing the layout of moved spaces, the signal from 2. might be good enough already.

Future Improvement Ideas

yabais signal API is limited to events that macOS emits, which is why there are no space_moved, space_created, or space_destroyed events.

Such events would need to be artificially created by yabai, but could in turn improve the signal API. These are not a thing yet.

Was this page helpful?
0 / 5 - 0 ratings