koekeishiya / yabai

A tiling window manager for macOS based on binary space partitioning
MIT License
24.15k stars 645 forks source link

Question: Can I make all non-resizeable windows float (preference windows, autosuggestion windows etc)? #1317

Open donaldhubduck opened 2 years ago

donaldhubduck commented 2 years ago

I have searched a lot for this but can't find any real answer to how to do this. I'm a bit new to this – sorry if this is a noob question with obvious answer. I really like Yabai so far and this is absolutely not a big issue for me.

For some small non-resizable windows it seems to work that they become float but some are not.

Example When I have a finder window and calendar window open – then the both window share the space which is great.

working layout

But if I for example open the finder preferences window – then the preferences window is not floating which results in the calendar window is pushed down and a lot of space is unused plus that the layout becomes "broken".

broken layout

My try to resolve this I use the finder preferences window as an example here but this happens to some other small windows (for example the autosuggestion box inside calendar app or the finder file transfer window).

I have tried writing this code in the yabairc but it dont seem to work: yabai -m rule --add can-resize="^false$" manage=off

This is my yabairc

#!/usr/bin/env sh

# sudo yabai --load-sa
# yabai -m signal --add event=dock_did_restart action="sudo yabai --load-sa"

# global settings
yabai -m config mouse_follows_focus          off
yabai -m config focus_follows_mouse          off
yabai -m config window_origin_display        default
yabai -m config window_placement             second_child
yabai -m config window_topmost               off
yabai -m config window_shadow                off
yabai -m config window_opacity               off
yabai -m config window_opacity_duration      0.0
yabai -m config active_window_opacity        1.0
yabai -m config normal_window_opacity        0.80
yabai -m config window_border                on
yabai -m config window_border_width          6
yabai -m config active_window_border_color   0xffbf616a
yabai -m config normal_window_border_color   0xff4c566a
yabai -m config insert_feedback_color        0xffebcb8b
yabai -m config split_ratio                  0.50
yabai -m config auto_balance                 off
yabai -m config mouse_modifier               fn
yabai -m config mouse_action1                move
yabai -m config mouse_action2                resize
yabai -m config mouse_drop_action            swap

# general space settings
yabai -m config layout                       bsp
yabai -m config top_padding                  0
yabai -m config bottom_padding               0
yabai -m config left_padding                 0
yabai -m config right_padding                0
yabai -m config window_gap                   10

# apps to not manage (ignore)
yabai -m rule --add app="^System Preferences$" manage=off
yabai -m rule --add app="^Archive Utility$" manage=off
yabai -m rule --add app="^Wally$" manage=off
yabai -m rule --add app="^Pika$" manage=off
yabai -m rule --add app="^balenaEtcher$" manage=off
yabai -m rule --add app="^Creative Cloud$" manage=off
yabai -m rule --add app="^Logi Options$" manage=off
yabai -m rule --add app="^Alfred Preferences$" manage=off

yabai -m rule --add can-resize="^false$" manage=off

echo "yabai configuration loaded.."

Do I need to have the SIP disabled and scripting-addition loaded?

Does anyone know a way to do this? Thanks!

If there is no way to do this to all windows then it is fine. Yabai seems really great and I love how powerful it seems to be!

carlos-gtz commented 2 years ago

I'm still new, but something I noticed here is that can-resize isn't a valid argument

Maybe you could try to query yabai -m query --windows and see if there are other things you could get that can match the rules arguments. For the moment is what I'm doing per-app

TiagoDamascena commented 2 years ago

You can do this using signals, isn't perfect but works. Maybe this comment can help:

https://github.com/koekeishiya/yabai/issues/924#issuecomment-859727411

koekeishiya commented 2 years ago

Ideally signals should be allowed to run and override certain parts of yabai's event handler logic. That would in theory make it possible to run a signal on window_created and make the window float without having it first be tiled, avoiding a change in dimensions and the visual flicker.

donaldhubduck commented 2 years ago

I'm still new, but something I noticed here is that can-resize isn't a valid argument

Maybe you could try to query yabai -m query --windows and see if there are other things you could get that can match the rules arguments. For the moment is what I'm doing per-app

Thanks for the input! Yeah, you are totally right. Unfortunately it seems like there is no valid argument that I can use when I query the windows. It seems like using signals might do the trick!

donaldhubduck commented 2 years ago

You can do this using signals, isn't perfect but works. Maybe this comment can help:

#924 (comment)

Wow! That seems to be exactly what I am looking for! Thanks a lot for finding it.

Unfortunately it does not seem to work for me when I add the signal which seem to work for them.

As I said in the opening post – this is not a big deal as I love how Yabai works as is. But it would be nice if it worked.

I have tried the following (between each step I restarted the yabai service):

  1. added the signal-code yabai -m signal --add event=window_created action='yabai -m query --windows --window $YABAI_WINDOW_ID | jq -er ".resizable == 0 and .floating == 0" && yabai -m window $YABAI_WINDOW_ID --toggle float' from the link you gave me. which seems to work for them.
  2. Installed the program JQ with homebrew.
  3. Added label='test' active='yes' to the end of the signal-code above in this list. This was to see if the signal seemed to be active with the command yabai -m signal --list. It seemed like it was active.

This is now my .yabairc file:

#!/usr/bin/env sh

# sudo yabai --load-sa
# yabai -m signal --add event=dock_did_restart action="sudo yabai --load-sa"

# global settings
yabai -m config mouse_follows_focus          off
yabai -m config focus_follows_mouse          off
yabai -m config window_origin_display        default
yabai -m config window_placement             second_child
yabai -m config window_topmost               off
yabai -m config window_shadow                off
yabai -m config window_opacity               off
yabai -m config window_opacity_duration      0.0
yabai -m config active_window_opacity        1.0
yabai -m config normal_window_opacity        0.80
yabai -m config window_border                on
yabai -m config window_border_width          6
yabai -m config active_window_border_color   0xffd8dee9
yabai -m config normal_window_border_color   0xff4c566a
yabai -m config insert_feedback_color        0xffbf616a
yabai -m config split_ratio                  0.50
yabai -m config auto_balance                 off
yabai -m config mouse_modifier               fn
yabai -m config mouse_action1                move
yabai -m config mouse_action2                resize
yabai -m config mouse_drop_action            swap

# general space settings
yabai -m config layout                       bsp
yabai -m config top_padding                  0
yabai -m config bottom_padding               0
yabai -m config left_padding                 0
yabai -m config right_padding                0
yabai -m config window_gap                   24

# Space labels
yabai -m space 1 --label "Start"
yabai -m space 2 --label "Browser"
yabai -m space 3 --label "Code"
yabai -m space 4 --label "Misc"

# Start
yabai -m rule --add app="Finder" space="Start"
yabai -m rule --add app="Filezilla" space="Start"
yabai -m rule --add app="Activity Monitor" space="Start"
yabai -m rule --add app="Todoist" space="Start"

# Browser
yabai -m rule --add app="Firefox" space="Browser"
yabai -m rule --add app="Brave" space="Browser"
yabai -m rule --add app="Safari" space="Browser"
yabai -m rule --add app="iTerm" space="Browser"

# Programming
yabai -m rule --add app="Visual Studio Code" space="Code"

# Misc
yabai -m rule --add app="Calendar" space="Misc"
yabai -m rule --add app="Discord" space="Misc"
yabai -m rule --add app="App Store" space="Misc"

# apps to not manage (ignore)
yabai -m rule --add app="^System Preferences$" manage=off
yabai -m rule --add app="^Archive Utility$" manage=off
yabai -m rule --add app="^Wally$" manage=off
yabai -m rule --add app="^Pika$" manage=off
yabai -m rule --add app="^balenaEtcher$" manage=off
yabai -m rule --add app="^Creative Cloud$" manage=off
yabai -m rule --add app="^Logi Options$" manage=off
yabai -m rule --add app="^Alfred Preferences$" manage=off
yabai -m rule --add label="Finder" app="^Finder$" title="(Co(py|nnect)|Move|Info|Pref)" manage=off
yabai -m rule --add label="Safari" app="^Safari$" title="^(General|(Tab|Password|Website|Extension)s|AutoFill|Se(arch|curity)|Privacy|Advance)$" manage=off
yabai -m rule --add label="macfeh" app="^macfeh$" manage=off
yabai -m rule --add label="App Store" app="^App Store$" manage=off
yabai -m rule --add label="Activity Monitor" app="^Activity Monitor$" manage=off
yabai -m rule --add label="KeePassXC" app="^KeePassXC$" manage=off
yabai -m rule --add label="Calculator" app="^Calculator$" manage=off
yabai -m rule --add label="Dictionary" app="^Dictionary$" manage=off
yabai -m rule --add label="mpv" app="^mpv$" manage=off
yabai -m rule --add label="Software Update" title="Software Update" manage=off
yabai -m rule --add label="About This Mac" app="System Information" title="About This Mac" manage=off

echo "yabai configuration loaded.."

yabai -m signal --add event=window_created action='yabai -m query --windows --window $YABAI_WINDOW_ID | jq -er ".resizable == 0 and .floating == 0" && yabai -m window $YABAI_WINDOW_ID --toggle float' label='test' active='yes'

When I query the windows I get the following for the Calendar-window and the Calendar settings-window:

{
    "id":710,
    "pid":7693,
    "app":"Calendar",
    "title":"General",
    "frame":{
        "x":908.0000,
        "y":0.0000,
        "w":537.0000,
        "h":539.0000
    },
    "role":"AXWindow",
    "subrole":"AXStandardWindow",
    "display":1,
    "space":4,
    "level":0,
    "opacity":1.0000,
    "split-type":"vertical",
    "stack-index":0,
    "can-move":true,
    "can-resize":false,
    "has-focus":false,
    "has-shadow":true,
    "has-border":true,
    "has-parent-zoom":false,
    "has-fullscreen-zoom":false,
    "is-native-fullscreen":false,
    "is-visible":false,
    "is-minimized":false,
    "is-hidden":false,
    "is-floating":false,
    "is-sticky":false,
    "is-topmost":false,
    "is-grabbed":false
},{
    "id":706,
    "pid":7693,
    "app":"Calendar",
    "title":"Calendar",
    "frame":{
        "x":-0.0000,
        "y":0.0000,
        "w":884.0000,
        "h":1120.0000
    },
    "role":"AXWindow",
    "subrole":"AXStandardWindow",
    "display":1,
    "space":4,
    "level":0,
    "opacity":1.0000,
    "split-type":"vertical",
    "stack-index":0,
    "can-move":true,
    "can-resize":true,
    "has-focus":false,
    "has-shadow":true,
    "has-border":true,
    "has-parent-zoom":false,
    "has-fullscreen-zoom":false,
    "is-native-fullscreen":false,
    "is-visible":false,
    "is-minimized":false,
    "is-hidden":false,
    "is-floating":false,
    "is-sticky":false,
    "is-topmost":false,
    "is-grabbed":false
},
koekeishiya commented 2 years ago

The property name is is-floating and can-resize now, so the posted signal is incorrect. I also think $YABAI_WINDOW_ID needs to be escaped, \$YABAI_WINDOW_ID.

donaldhubduck commented 2 years ago

The property name is is-floating and can-resize now, so the posted signal is incorrect. I also think $YABAI_WINDOW_ID needs to be escaped, \$YABAI_WINDOW_ID.

I see! Thanks a lot for pointing it out! Maybe this was changed in yabai since they (here) wrote that signal.

When I write the following command in my terminal (I am a complete noob to scripting) it seems to check if the current active window (the terminal window) is can-resize: true and if that is correct it will make the window toggle float.:

yabai -m query --windows --window $YABAI_WINDOW_ID | jq -er '."can-resize" == true' && yabai -m window $YABAI_WINDOW_ID --toggle float

And when I run the following command with the same active window (the terminal window) it doesnt make it float which makes me believe it works as I intend.

yabai -m query --windows --window $YABAI_WINDOW_ID | jq -er '."can-resize" == 0' && yabai -m window $YABAI_WINDOW_ID --toggle float

But when I use this signal it doesnt seem to work. I probably have a typing error or missunderstood something:

yabai -m signal --add event=window_created action='yabai -m query --windows --window $YABAI_WINDOW_ID | jq -er ".'can-resize' == true" && yabai -m window $YABAI_WINDOW_ID --toggle float'

I also tried to escape the $YABAI_WINDOW_ID with this:

yabai -m signal --add event=window_created action='yabai -m query --windows --window \$YABAI_WINDOW_ID | jq -er ".'can-resize' == true" && yabai -m window \$YABAI_WINDOW_ID --toggle float'

I need to go to bed now but I will continue to experiment with this tomorrow! :)

carlos-gtz commented 2 years ago

@donaldhubduck

How about:

yabai -m query --windows --window $YABAI_WINDOW_ID | jq -e '."can-resize"' || yabai -m window $YABAI_WINDOW_ID --toggle float

Btw, since you have your yabairc with yabai -m config layout bsp, you will notice a flickering as it will tile the window created and then it will float it. That happens because you are toggling the layout.

So, maybe a solution would be to not have yabai -m config layout at all, then have one signal to tile those who can resize. I don't know what should be the solution, but maybe @koekeishiya could tell us and we could add it in the wiki (maybe we could gather some of these in the examples/tricks part)

MuhammedZakir commented 2 years ago

@carlos-gtz: you forgot to pass -e flag to jq. :-)

carlos-gtz commented 2 years ago

Thanks, adding that up to my answer :)

donaldhubduck commented 2 years ago

@carlos-gtz

I really appreciate all the help! :)

How about:

yabai -m query --windows --window $YABAI_WINDOW_ID | jq -e '."can-resize"' || yabai -m window $YABAI_WINDOW_ID --toggle float

Wouldn't I need to check if can-resize is true or not for it to work? I tried to add the code to the signal so it looks like this:

yabai -m signal --add event=window_created action='yabai -m query --windows --window $YABAI_WINDOW_ID | jq -er '."can-resize"' || yabai -m window $YABAI_WINDOW_ID --toggle float'

But it doesn't seem to do anything unfortunately. I also tried to check if can-resize is false with the following signal:

yabai -m signal --add event=window_created action='yabai -m query --windows --window $YABAI_WINDOW_ID | jq -er '."can-resize" == 0' || yabai -m window $YABAI_WINDOW_ID --toggle float'

But no luck.

I tried changing some here and there but I can't seem to get the signals to work. Maybe my scripting-addition is not loaded correctly.

Btw, since you have your yabairc with yabai -m config layout bsp, you will notice a flickering as it will tile the window created and then it will float it. That happens because you are toggling the layout.

So, maybe a solution would be to not have yabai -m config layout at all, then have one signal to tile those who can resize. I don't know what should be the solution, but maybe @koekeishiya could tell us and we could add it in the wiki (maybe we could gather some of these in the examples/tricks part)

Love this idea!

I tried and commented out the layout bsp in my yabairc. Then I reloaded yabai (which I always do inbetween changes). All windows are now floating (which is intended). Then I wrote the following command in my terminal just to try it out:

yabai -m query --windows --window $YABAI_WINDOW_ID | jq -er '."can-resize" == true' && yabai -m window $YABAI_WINDOW_ID --toggle float

But the terminal window stay float somehow.

I guess I do quite many obvious mistakes when I try stuff :D

Right now I am thinking of leaving it be, because it is not that annoying that very few windows that cannot resize "tries" to take up half of the screen.

carlos-gtz commented 2 years ago

Wouldn't I need to check if can-resize is true or not for it to work? It should be fine as you will get the true/false result and use it on the || comparison for the -toggle float part.

It works for me when I do it on the terminal 🤔

My terminal is float, then I do this to tile it. yabai -m query --windows --window $YABAI_WINDOW_ID | jq -e '."can-resize"' && yabai -m window $YABAI_WINDOW_ID --toggle float

If the window can't be resized, then I do this: yabai -m query --windows --window $YABAI_WINDOW_ID | jq -e '."can-resize"' || yabai -m window $YABAI_WINDOW_ID --toggle float

Here is one trick for you to try this without using signals. You can sleep the command before execute it.

How about you comment all your current rules and signals? Then try this and see if it works.

koekeishiya commented 2 years ago

You need to escape the $YABAI_WINDOW_ID variable properly, so that it is not evaluated in the config script. See my earlier comment.

XA21X commented 2 years ago

Thanks for the tips. This works nicely for me:

yabai -m signal --add event=window_created action='yabai -m query --windows --window $YABAI_WINDOW_ID | jq -er ".\"can-resize\" or .\"is-floating\"" || yabai -m window $YABAI_WINDOW_ID --toggle float'

Edit^: Blindly toggling it was undoing my manage=off rules, so I added the is-floating check as well. A workaround for the lack of #945.

Note that $ does not need to be escaped with \ because of the single quotes. It makes sense in the few examples above when invoking the commands directly.

It would be great if we could have floating turned on by default and have the reversed rule to avoid flickering etc, but I couldn't get that to work - it doesn't seem to be supported at the moment.

BlkPingu commented 1 year ago

How can I avoid that the new window jumps to the parent window instead of staying in the middle of the screen? @XA21X

kabeersvohra commented 1 year ago

I have added some changes to your command @XA21X which make it on the top layer and centred in the screen:

yabai -m signal --add event=window_created action='
  yabai -m query --windows --window $YABAI_WINDOW_ID | jq -er ".\"can-resize\" or .\"is-floating\"" || \
  yabai -m window $YABAI_WINDOW_ID --toggle float && \
  yabai -m window $YABAI_WINDOW_ID --layer above && \
  yabai -m window $YABAI_WINDOW_ID --grid 3:3:1:1:1:1
'
jqtmviyu commented 1 year ago

I have some changes for above command

yabairc

systemApp='^(System Preferences|System Information|Finder|Calendar|Mail|App Store|Activity Monitor|Dictionary)$'

manageOffApp='^(IINA|Stats|LICEcap)$'

yabai -m rule --add app="${systemApp}|${manageOffApp}" manage=off

yabai -m signal --add event=window_created \
  action='yabai -m query --windows --window $YABAI_WINDOW_ID \
  | jq -er ".\"can-resize\" or .\"is-floating\"" || \
  yabai -m window $YABAI_WINDOW_ID --toggle float' \
  app!="${systemApp}|${manageOffApp}"

skhdrc

alt + ctrl - i : json_text=$(yabai -m query --windows --window mouse | jq -r tostring | tr -d '{}"' | tr ',' '\n') ; \
                 appName=$(echo "$json_text" | sed -n 's/^app:\(.*\)/\1/p') ; \
                 result=$(osascript -e "display dialog \"$json_text\" buttons {\"Close\", \"manageOff\"} default button \"Close\"") ; \
                 echo "$result" | grep -q "manageOff" && \
                 perl -i -pe "s/manageOffApp\=\'\^\(/manageOffApp\=\'\^\($appName\|/g" ~/.config/yabai/yabairc && \
                 yabai --restart-service
gshpychka commented 10 months ago

How can I avoid that the new window jumps to the parent window instead of staying in the middle of the screen? @XA21X

Doesn't seem like this is possible, since the signal is executed after the windows is spawned. Unless anyone else has figured out a better way.

CassandraCat commented 10 months ago

child windows all have 'can resize' set to true in yabai.

hakusaro commented 9 months ago

I have some changes for above command

@jqtmviyu can you elaborate more on why you approached it this way?

ubuntudroid commented 8 months ago

I have added some changes to your command @XA21X which make it on the top layer and centred in the screen:

yabai -m signal --add event=window_created action='
  yabai -m query --windows --window $YABAI_WINDOW_ID | jq -er ".\"can-resize\" or .\"is-floating\"" || \
  yabai -m window $YABAI_WINDOW_ID --toggle float && \
  yabai -m window $YABAI_WINDOW_ID --layer above && \
  yabai -m window $YABAI_WINDOW_ID --grid 3:3:1:1:1:1
'

@kabeersvohra That's lovely! 😍 The only part which doesn't seem to work is the centering. For me the window always appears in the bottom left edge... 🤔

benvp commented 6 months ago

I have added some changes to your command @XA21X which make it on the top layer and centred in the screen:

yabai -m signal --add event=window_created action='
  yabai -m query --windows --window $YABAI_WINDOW_ID | jq -er ".\"can-resize\" or .\"is-floating\"" || \
  yabai -m window $YABAI_WINDOW_ID --toggle float && \
  yabai -m window $YABAI_WINDOW_ID --layer above && \
  yabai -m window $YABAI_WINDOW_ID --grid 3:3:1:1:1:1
'

@kabeersvohra That's lovely! 😍 The only part which doesn't seem to work is the centering. For me the window always appears in the bottom left edge... 🤔

Had the same issue. For now I somewhat solved it with putting it into a single command. Getting a little flickering, though.

yabai -m signal --add event=window_created action='
  yabai -m query --windows --window $yabai_window_id | jq -er ".\"can-resize\" or .\"is-floating\"" || \
  yabai -m window $yabai_window_id --toggle float --layer above --grid 4:4:1:1:2:2
'
OfficialCRUGG commented 6 months ago

@benvp Thanks for that snippet! Do you by any chance know how I'd add manual exceptions to this? One of my programs is identified was not resizable, due to it doing some hacky workarounds, even though it can be resized just fine.

benvp commented 6 months ago

I'm not experienced with jq but I think you can query for the app or title of the json returned from the windows query.

I'd filter out the apps by checking the app or title field and exclude them.

jq -er "(.\"can-resize\" or .\"is-floating\") and (.app | contains(\"Alacritty\" | not)

This would be the final snippet. Didn't test it, but maybe it points into the right direction.


 yabai -m signal --add event=window_created action='
  yabai -m query --windows --window $yabai_window_id | jq -er "(.\"can-resize\" or .\"is-floating\") and (.\"app\" | contains(\"Alacritty\") | not)" || \
  yabai -m window $yabai_window_id --toggle float --layer above --grid 4:4:1:1:2:2
'