Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scratchpad like functionality for single window #2203

Closed
koekeishiya opened this issue Apr 3, 2024 · 23 comments
Closed

Scratchpad like functionality for single window #2203

koekeishiya opened this issue Apr 3, 2024 · 23 comments
Labels
suggestion Request for new feature or some form of enhancement

Comments

@koekeishiya
Copy link
Owner

koekeishiya commented Apr 3, 2024

Just some thoughts, design not final..

It would be nice to be able to bring a specific window to the front of the currently active space, do something with the window, and just get rid of it when done, all with a single bind.

This would likely be set up using window rules, assigning a unique identifier, and optionally its desired size. Windows that are given such an identifier would automatically be marked as floating, and hidden in some way.

It would then be possible to just use a window --toggle identifier to toggle visibility. Syntax might look like:

Rule property: scratchpad=<LABEL>.
Window command: yabai -m window --toggle <LABEL>

# set identifier, set frame, and hide window
yabai -m rule --add app="kitty" title="dropdown" scratchpad="terminal" grid="6:6:1:1:4:4"

# show window on active space and make it focused, or hide if already visible
yabai -m window --toggle terminal

Maybe some visual effects would be nice:

yabai -m config window_scratchpad_transition off|fade|slide|dropdown

@koekeishiya koekeishiya added the suggestion Request for new feature or some form of enhancement label Apr 3, 2024
@matthewtraughber
Copy link

This would be a pretty awesome addition. +1

While I've got something working with yabai and hammerspoon [1] (calling quake-mode.sh WezTerm via a keybinding), a "native" solution would definitely be preferred.

[1] https://github.com/matthewtraughber/dots-etc/blob/master/yabai/quake-mode.sh

koekeishiya added a commit that referenced this issue Apr 3, 2024
@koekeishiya koekeishiya added the addressed on master; not released Fixed upstream, but not yet released label Apr 3, 2024
@koekeishiya
Copy link
Owner Author

koekeishiya commented Apr 3, 2024

Window commands

yabai -m window [<WINDOW_SEL>] --toggle float|sticky|pip|shadow|split|zoom-parent|zoom-fullscreen|native-fullscreen|expose|<LABEL>

Toggle the given property of the selected window.
The following properties require System Integrity Protection to be partially disabled: sticky, pip, shadow, LABEL (scratchpad identifier) .

yabai -m window [<WINDOW_SEL>] --scratchpad [<LABEL>|recover]

Unique identifier used to identify a window scratchpad.
An identifier may only be assigned to a single window at any given time.
A scratchpad window will automatically be treated as a (manage=off) floating window.
If the scratchpad is already taken by another window, this assignment will fail.
If the scratchpad is re-assigned, the previous identifier will become available.
If no value is given, the window will seize to be a scratchpad window.
The special value 'recover' can be used to forcefully bring all scratchpad windows to the front.
This can be useful if windows become inaccessible due to a restart or crash.
System Integrity Protection must be partially disabled.

Rule property

scratchpad=<LABEL>

Unique identifier used to identify a window scratchpad.
An identifier may only be assigned to a single window at any given time.
A scratchpad window will automatically be treated as a (manage=off) floating window.
If this rule matches multiple windows, only the first window that matched will be assigned this scratchpad identifier.
System Integrity Protection must be partially disabled.

New window and rule query property: "scratchpad": string

Sample:

# yabairc
# mark window as scratchpad using rule and set size (scratchpad windows are manage=off automatically)
yabai -m rule --add app="^Spotify$" scratchpad=spotify grid=11:11:1:1:9:9
yabai -m rule --add app="^Discord$" title!="^Discord Updater$" scratchpad=discord grid=11:11:1:1:9:9
yabai -m rule --add app="^Transmission$" scratchpad=transmission grid=11:11:1:1:9:9

# skhdrc
# show all scratchpad windows if inaccessible due to yabai restart or crash
cmd + alt - r : yabai -m window --scratchpad recover

# toggle scratchpad windows or launch application if not running
cmd + alt - s : yabai -m window --toggle spotify || open  -a Spotify
cmd + alt - d : yabai -m window --toggle discord || open -a Discord
cmd + alt - t : yabai -m window --toggle transmission || open -a Transmission

@matthewtraughber
Copy link

Haha, that was fast. I haven't built yabai from source yet, so it'll be a little bit before I can test this out.

Was recently messing around with hyprland's special workspaces (scratchpads) - any technical reason why we couldn't assign multiple windows to a yabai "scratchpad"?

@koekeishiya
Copy link
Owner Author

koekeishiya commented Apr 4, 2024

While possible, alllowing multiple windows would complicate things quite a bit. I didn't really see the value in that.

Might as well use rules to assign multiple windows to the same macOS space at that point and label the space instead. Use the 'space --switch ..' command to activate that space.

@dvrkoo
Copy link

dvrkoo commented Apr 4, 2024

I also use hyprland special workspace on my desktop machines and I love it. I never really put more than one window in it, while it could be handy I don't find it a necessity and I don't even think it would fit the idea of it.
Taking the chance to tank you for the amazing work you've been doing with yabai recently, it's almost perfect from a feature perspective.

@koekeishiya
Copy link
Owner Author

koekeishiya commented Apr 4, 2024

Cheers. I think it is pretty solid right now, but there are a thousand things I'd like to do still.
Unfortunately there is only so much time I can allocate for this project.

Regarding multiple windows per scratchpad; it is possible to toggle multiple scratchpads simultaneously, giving the illusion that there are multiple windows: yabai -m window --toggle spotify --toggle discord.

They are in essence just floating windows, so can be moved and resized using window --grid, window --move, window --resize at any time.

@PhrantiK
Copy link

PhrantiK commented Apr 4, 2024

This is super rad - I too have a uberjank hammerspoon/yabai mashup making scratchpads work, looking forward to trying this out.

You've been on a mission recently, massive thanks from me as well!

@matthewtraughber
Copy link

Might as well use rules to assign multiple windows to the same macOS space at that point and label the space instead. Use the 'space --switch ..' command to activate that space.

Yeah, makes sense.

Regarding multiple windows per scratchpad; it is possible to toggle multiple scratchpads simultaneously, giving the illusion that there are multiple windows: yabai -m window --toggle spotify --toggle discord.

They are in essence just floating windows, so can be moved and resized using window --grid, window --move, window --resize at any time.

Oh nice!

Gonna reiterate what everyone's been saying here - massive thanks for everything you're doing (and have already done). I would have left macOS years ago if I hadn't found yabai.

@JZL
Copy link

JZL commented Apr 4, 2024

I agree with @matthewtraughber, thanks so much. If yabai doesn't start up even for 10 minutes, I feel like my laptop is a completely different, almost unusable computer.

Scratchpads are also integral to my workflow from i3 so I've been using @arpandaze 's very nice https://github.com/arpandaze/scratchpad-rs until seeing this. It could be an alternative if someone wants to customize a 3rd party software instead - I found the code very readable and hackable as needed (rust).

Thanks!

@farzadmf
Copy link

farzadmf commented Apr 4, 2024

Question about this change (and other new changes in general): since my memory only stores things for 3 seconds 😆 , I was wondering if the docs are updated to reflect these new features.

For example, I just check the wiki (the window commands section); I tried searching for scratchpad, and I didn't find anything

@koekeishiya
Copy link
Owner Author

Wiki is only a small sample of available commands. I don't have the bandwidth to keep that much details up to date. Use the man page for full docs: (which is always up to date for head and you can check the same file for the version that that you are interested in): https://github.com/koekeishiya/yabai/blob/master/doc/yabai.asciidoc

@farzadmf
Copy link

farzadmf commented Apr 5, 2024

Nice! Thank you for taking the time to reply. That's all I wanted to know.

Thank you for the amazing work you're doing

@Pe8er
Copy link

Pe8er commented Apr 5, 2024

@koekeishiya thank you for this feature!! I stumbled into a small problem I hope you can help me figure out. Whenever I use the script (via Raycast or terminal, same result) to toggle let's say Messages scratchpad:

yabai -m window --toggle Messages || open -a Messages

and if Messages isn't running at the time, the following happens:

  1. Yabai reports unknown value 'Messages' given to command '--toggle' for domain 'window'
  2. App launches, window shows floating for split second and disappears.

If I trigger the scratchpad again, it shows up and works normally until I quit the app. I went through my yabairc a million times, looking for something that might cause this and I have no idea where to go from here. Is there something wrong with my setup / syntax or…?

Thanks a ton!

yabai -V output:

 yabai -V
process_create: xpc service 'ViewBridgeAuxiliary' detected! ignoring..
process_create: xpc service 'CursorUIViewService' detected! ignoring..
process_create: xpc service 'Mail Networking' detected! ignoring..
process_create: xpc service 'Mail Web Content' detected! ignoring..
process_create: xpc service 'Mail Graphics and Media' detected! ignoring..
process_create: xpc service 'Mail Web Content' detected! ignoring..
process_create: xpc service 'Mail Web Content' detected! ignoring..
process_manager_add_running_processes: Finder (78439) was found! caching psn..
process_create: xpc service 'Adobe Content Synchronizer Finder Extension' detected! ignoring..
process_create: xpc service 'ShareSheetUI (Finder)' detected! ignoring..
process_create: xpc service 'Mail Web Content' detected! ignoring..
process_create: xpc service 'Mail Web Content' detected! ignoring..
process_create: xpc service 'Mail Web Content' detected! ignoring..
process_create: xpc service 'Mail Web Content' detected! ignoring..
process_create: xpc service 'Open and Save Panel Service (Adobe After Effects)' detected! ignoring..
process_create: xpc service 'QuickLookUIService (Open and Save Panel Service (Adobe After Effects))' detected! ignoring..
process_create: xpc service 'Dock Extra' detected! ignoring..
process_create: xpc service 'Dock Extra' detected! ignoring..
process_create: xpc service 'nsattributedstringagent' detected! ignoring..
process_create: xpc service 'com.apple.CoreSimulator.CoreSimulatorService' detected! ignoring..
process_create: xpc service 'Simulator' detected! ignoring..
process_create: xpc service 'ThumbnailExtension_macOS' detected! ignoring..
process_create: xpc service 'ExternalQuickLookSatellite-x86_64' detected! ignoring..
window_manager_add_existing_application_windows: Finder has windows that are not yet resolved
window_manager_create_and_add_window:63706 iTerm2 - -zsh (AXWindow:AXStandardWindow:1)
window_manager_begin: AppLocker (1513) is not observable, subscribing to activationPolicy changes
window_manager_begin: Spotlight (745) is not observable, subscribing to activationPolicy changes
window_manager_add_existing_application_windows: Adobe After Effects has windows that are not yet resolved
window_manager_begin: nbagent (87232) is not observable, subscribing to activationPolicy changes
window_manager_begin: calaccessd (2145) is not observable, subscribing to activationPolicy changes
window_manager_begin: CoreServicesUIAgent (75356) is not observable, subscribing to activationPolicy changes
window_manager_begin: Raycast (82796) is not observable, subscribing to activationPolicy changes
window_manager_begin: Universal Control (1327) is not observable, subscribing to activationPolicy changes
window_manager_begin: Keychain Circle Notification (7264) is not observable, subscribing to activationPolicy changes
window_manager_begin: BackgroundTaskManagementAgent (78979) is not observable, subscribing to activationPolicy changes
window_manager_begin: loginwindow (380) is not observable, subscribing to activationPolicy changes
window_manager_add_existing_application_windows: Things has windows that are not yet resolved
window_manager_add_existing_application_windows: Mail has windows that are not yet resolved
window_manager_begin: Private Internet Access (83864) is not observable, subscribing to activationPolicy changes
window_manager_begin: avconferenced (1270) is not observable, subscribing to activationPolicy changes
window_manager_begin: Creative Cloud Core Service (84037) is not observable, subscribing to activationPolicy changes
window_manager_begin: TextInputMenuAgent (797) is not observable, subscribing to activationPolicy changes
window_manager_begin: universalAccessAuthWarn (91872) is not observable, subscribing to activationPolicy changes
window_manager_begin: familycircled (731) is not observable, subscribing to activationPolicy changes
window_manager_begin: karabiner_console_user_server (75771) is not observable, subscribing to activationPolicy changes
window_manager_add_existing_application_windows: Music has windows that are not yet resolved
window_manager_add_existing_application_windows: Notes has windows that are not yet resolved
window_manager_begin: CoreLocationAgent (7202) is not observable, subscribing to activationPolicy changes
window_manager_begin: Wi-Fi (676) is not observable, subscribing to activationPolicy changes
window_manager_begin: Menuwhere (701) is not observable, subscribing to activationPolicy changes
window_manager_begin: PowerChime (31404) is not observable, subscribing to activationPolicy changes
window_manager_begin: Raycast Helper (Extensions) (36717) is not observable, subscribing to activationPolicy changes
window_manager_begin: photolibraryd (34140) is not observable, subscribing to activationPolicy changes
window_manager_begin: Family (52591) is not observable, subscribing to activationPolicy changes
window_manager_begin: AirPlayUIAgent (791) is not observable, subscribing to activationPolicy changes
window_manager_begin: Adobe Content Synchronizer (84035) is not observable, subscribing to activationPolicy changes
window_manager_begin: TeamProjectsLocalHub (28533) is not observable, subscribing to activationPolicy changes
window_manager_begin: next-server (80014) is not observable, subscribing to activationPolicy changes
window_manager_begin: Syncthing (708) is not observable, subscribing to activationPolicy changes
window_manager_begin: Wallpaper (643) is not observable, subscribing to activationPolicy changes
window_manager_begin: universalaccessd (624) is not observable, subscribing to activationPolicy changes
window_manager_begin: FigmaAgent (83145) is not observable, subscribing to activationPolicy changes
window_manager_begin: Wallet (75308) is not observable, subscribing to activationPolicy changes
window_manager_begin: Creative Cloud Libraries Synchronizer (13328) is not observable, subscribing to activationPolicy changes
window_manager_begin: chronod (714) is not observable, subscribing to activationPolicy changes
window_manager_begin: Notification Center (695) is not observable, subscribing to activationPolicy changes
window_manager_begin: Control Center (631) is not observable, subscribing to activationPolicy changes
window_manager_add_existing_application_windows: Figma has windows that are not yet resolved
window_manager_begin: com.apple.PressAndHold (766) is not observable, subscribing to activationPolicy changes
window_manager_begin: UserNotificationCenter (83198) is not observable, subscribing to activationPolicy changes
window_manager_begin: UIKitSystem (746) is not observable, subscribing to activationPolicy changes
window_manager_create_and_add_window:62344 VSCodium - yabairc — .dotfiles (AXWindow:AXStandardWindow:1)
window_manager_begin: Things Helper (703) is not observable, subscribing to activationPolicy changes
window_manager_add_existing_application_windows: Arc has windows that are not yet resolved
window_manager_begin: yabai (92243) is not observable, subscribing to activationPolicy changes
window_manager_begin: Shortcuts Events (35171) is not observable, subscribing to activationPolicy changes
window_manager_begin: Karabiner-NotificationWindow (75918) is not observable, subscribing to activationPolicy changes
window_manager_begin: Dock (30858) is not observable, subscribing to activationPolicy changes
window_manager_begin: AdGuard for Safari (1116) is not observable, subscribing to activationPolicy changes
window_manager_begin: SystemUIServer (632) is not observable, subscribing to activationPolicy changes
window_manager_begin: Creative Cloud Interprocess Service (44085) is not observable, subscribing to activationPolicy changes
EVENT_HANDLER_WINDOW_TITLE_CHANGED: iTerm2 63706
EVENT_HANDLER_DAEMON_MESSAGE: signal --add event=dock_did_restart action=sudo yabai --load-sa
EVENT_HANDLER_DAEMON_MESSAGE: signal --add event=window_created action=sketchybar --trigger space_windows_change
EVENT_HANDLER_DAEMON_MESSAGE: signal --add event=window_destroyed action=sketchybar --trigger space_windows_change
EVENT_HANDLER_DAEMON_MESSAGE: config window_placement second_child focus_follows_mouse autofocus menubar_opacity 0.0 window_animation_duration 0.0 layout bsp auto_balance off top_padding 0 bottom_padding 8 left_padding 8 right_padding 8 window_gap 8
EVENT_HANDLER_WINDOW_TITLE_CHANGED: iTerm2 63706
setup space 1 : Web
EVENT_HANDLER_WINDOW_RESIZED: iTerm2 63706
EVENT_HANDLER_WINDOW_MOVED:DEBOUNCED iTerm2 63706
EVENT_HANDLER_WINDOW_RESIZED:DEBOUNCED VSCodium 62344
EVENT_HANDLER_WINDOW_MOVED:DEBOUNCED VSCodium 62344
EVENT_HANDLER_WINDOW_RESIZED:DEBOUNCED VSCodium 62344
EVENT_HANDLER_WINDOW_RESIZED:DEBOUNCED iTerm2 63706
EVENT_HANDLER_WINDOW_RESIZED:DEBOUNCED VSCodium 62344
EVENT_HANDLER_WINDOW_RESIZED:DEBOUNCED iTerm2 63706
EVENT_HANDLER_WINDOW_MOVED:DEBOUNCED iTerm2 63706
EVENT_HANDLER_WINDOW_RESIZED:DEBOUNCED VSCodium 62344
EVENT_HANDLER_WINDOW_MOVED:DEBOUNCED VSCodium 62344
EVENT_HANDLER_WINDOW_RESIZED:DEBOUNCED iTerm2 63706
EVENT_HANDLER_WINDOW_RESIZED:DEBOUNCED VSCodium 62344
EVENT_HANDLER_WINDOW_MOVED:DEBOUNCED VSCodium 62344
EVENT_HANDLER_WINDOW_RESIZED:DEBOUNCED iTerm2 63706
EVENT_HANDLER_WINDOW_RESIZED:DEBOUNCED VSCodium 62344
EVENT_HANDLER_WINDOW_MOVED:DEBOUNCED VSCodium 62344
EVENT_HANDLER_DAEMON_MESSAGE: query --spaces --space 1
EVENT_HANDLER_WINDOW_TITLE_CHANGED: iTerm2 63706
EVENT_HANDLER_DAEMON_MESSAGE: space 1 --label Web
yabai -m space 1 --label Web
setup space 2 : Mail
EVENT_HANDLER_DAEMON_MESSAGE: query --spaces --space 2
EVENT_HANDLER_DAEMON_MESSAGE: space 2 --label Mail
yabai -m space 2 --label Mail
setup space 3 : Todo
EVENT_HANDLER_DAEMON_MESSAGE: query --spaces --space 3
EVENT_HANDLER_DAEMON_MESSAGE: space 3 --label Todo
yabai -m space 3 --label Todo
setup space 4 : Code
EVENT_HANDLER_DAEMON_MESSAGE: query --spaces --space 4
EVENT_HANDLER_DAEMON_MESSAGE: space 4 --label Code
yabai -m space 4 --label Code
setup space 5 : Music
EVENT_HANDLER_DAEMON_MESSAGE: query --spaces --space 5
EVENT_HANDLER_DAEMON_MESSAGE: space 5 --label Music
yabai -m space 5 --label Music
setup space 6 : Design
EVENT_HANDLER_DAEMON_MESSAGE: query --spaces --space 6
EVENT_HANDLER_DAEMON_MESSAGE: space 6 --label Design
yabai -m space 6 --label Design
setup space 7 : Presentation
EVENT_HANDLER_DAEMON_MESSAGE: query --spaces --space 7
EVENT_HANDLER_DAEMON_MESSAGE: space 7 --label Presentation
yabai -m space 7 --label Presentation
EVENT_HANDLER_DAEMON_MESSAGE: rule --add app=^(Arc|Discord)$ space=^1
EVENT_HANDLER_DAEMON_MESSAGE: rule --add app=^(Mail)$ space=^2
EVENT_HANDLER_DAEMON_MESSAGE: rule --add app=^(Things|Notes)$ space=^3
EVENT_HANDLER_DAEMON_MESSAGE: rule --add app=^(VSCodium|iTerm)$ space=^4
EVENT_HANDLER_DAEMON_MESSAGE: rule --add app=^Music$ space=^5
EVENT_HANDLER_DAEMON_MESSAGE: rule --add app=^(Figma|Adobe After Effects 2024|Adobe Photoshop Lightroom Classic|Photoshop)$ space=^6
EVENT_HANDLER_DAEMON_MESSAGE: rule --add app=^(Keynote|Microsoft PowerPoint)$ space=^7
EVENT_HANDLER_DAEMON_MESSAGE: rule --add app=^(Steam Helper|Raycast|Calculator|Software Update|Dictionary|VLC|System Preferences|System Settings|zoom.us|Photo Booth|Archive Utility|App Store|Clock|Karabiner-Elements|Plexamp|Alfred Preferences|ImageOptim|The Unarchiver|Installer|Hosting AU|Numi)$ manage=off
EVENT_HANDLER_DAEMON_MESSAGE: rule --add label=Small windows title=(Co(py|nnect)|Move|Info|Pref) manage=off
EVENT_HANDLER_DAEMON_MESSAGE: rule --add label=GLMv4 app=^GLMv4$ title=(Preparations for Measurements) manage=off
EVENT_HANDLER_DAEMON_MESSAGE: rule --add label=Cyberduck app=^Cyberduck$ title=(Transfers) manage=off
EVENT_HANDLER_DAEMON_MESSAGE: rule --add label=Mail New Message app=^Mail$ title=(New Message) manage=off
EVENT_HANDLER_DAEMON_MESSAGE: rule --add label=About This Mac app=System Information title=About This Mac manage=off
EVENT_HANDLER_DAEMON_MESSAGE: rule --add label=Activity Windows title=^Activity$ manage=off
EVENT_HANDLER_DAEMON_MESSAGE: rule --add app=^Adobe (After Effects|Audition|Media Encoder|Lightroom)$ role=AXLayoutArea subrole=AXFloatingWindow manage=on
EVENT_HANDLER_DAEMON_MESSAGE: rule --add app=^IINA$ sticky=on manage=off
EVENT_HANDLER_DAEMON_MESSAGE: rule --add app=^Messages$ scratchpad=Messages grid=11:11:1:1:9:9
EVENT_HANDLER_DAEMON_MESSAGE: rule --add app=^Transmission$ scratchpad=Transmission grid=11:11:1:1:9:9
EVENT_HANDLER_DAEMON_MESSAGE: rule --apply
Yabai configuration loaded…
EVENT_HANDLER_WINDOW_TITLE_CHANGED: iTerm2 63706
EVENT_HANDLER_WINDOW_TITLE_CHANGED: iTerm2 63706
EVENT_HANDLER_DAEMON_MESSAGE: window --toggle Messages
EVENT_HANDLER_APPLICATION_LAUNCHED: Messages (92295) is not finished launching, subscribing to finishedLaunching changes
-[workspace_context observeValueForKeyPath:ofObject:change:context:]: Messages (92295) finished launching
EVENT_HANDLER_APPLICATION_LAUNCHED: Messages (92295)
window_manager_create_and_add_window:63719 Messages - Karina Jarząb (AXWindow:AXStandardWindow:1)
EVENT_HANDLER_APPLICATION_FRONT_SWITCHED: Messages (92295)
event_signal_flush: transmitting window_created to 1 subscriber(s)
EVENT_HANDLER_APPLICATION_FRONT_SWITCHED: iTerm2 (79212)

My yabairc:

#!/bin/bash

# Unload the macOS WindowManager process
launchctl unload -F /System/Library/LaunchAgents/com.apple.WindowManager.plist >/dev/null 2>&1 &

# Load scripting additions
sudo yabai --load-sa

#Setup basic signals
yabai -m signal --add event=dock_did_restart action="sudo yabai --load-sa"
yabai -m signal --add event=window_created action="sketchybar --trigger space_windows_change"
yabai -m signal --add event=window_destroyed action="sketchybar --trigger space_windows_change"

# Float small, non-resizable windows
# 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_config=(
  window_placement          second_child
  focus_follows_mouse       autofocus
  menubar_opacity           0.0
  window_animation_duration 0.0
  layout                    bsp
  auto_balance              off
  top_padding               0
  bottom_padding            8
  left_padding              8
  right_padding             8
  window_gap                8
)

yabai -m config ${yabai_config[*]}

# Setup spaces
function setup_space {
  local idx="$1"
  local name="$2"
  local space=
  echo "setup space $idx : $name"

  space=$(yabai -m query --spaces --space "$idx")
  if [ -z "$space" ]; then
    yabai -m space --create
  fi

  yabai -m space "$idx" --label "$name"
  echo yabai -m space "$idx" --label "$name"
}

setup_space 1 Web
setup_space 2 Mail
setup_space 3 Todo
setup_space 4 Code
setup_space 5 Music
setup_space 6 Design
setup_space 7 Presentation

# Assign apps to specific spaces
yabai -m rule --add app="^(Arc|Discord)$" space=^1
yabai -m rule --add app="^(Mail)$" space=^2
yabai -m rule --add app="^(Things|Notes)$" space=^3
yabai -m rule --add app="^(VSCodium|iTerm)$" space=^4
yabai -m rule --add app="^Music$" space=^5
yabai -m rule --add app="^(Figma|Adobe After Effects 2024|Adobe Photoshop Lightroom Classic|Photoshop)$" space=^6
yabai -m rule --add app="^(Keynote|Microsoft PowerPoint)$" space=^7

# https://github.com/koekeishiya/yabai/issues/2170
# yabai -m rule --add app=".*" sub-layer=normal

# Manage apps and windows
yabai -m rule --add app="^(Steam Helper|Raycast|Calculator|Software Update|Dictionary|VLC|System Preferences|System Settings|zoom.us|Photo Booth|Archive Utility|App Store|Clock|Karabiner-Elements|Plexamp|Alfred Preferences|ImageOptim|The Unarchiver|Installer|Hosting AU|Numi)$" manage=off
yabai -m rule --add label="Small windows" title="(Co(py|nnect)|Move|Info|Pref)" manage=off
yabai -m rule --add label="GLMv4" app="^GLMv4$" title="(Preparations for Measurements)" manage=off
yabai -m rule --add label="Cyberduck" app="^Cyberduck$" title="(Transfers)" manage=off
yabai -m rule --add label="Mail New Message" app="^Mail$" title="(New Message)" manage=off
yabai -m rule --add label="About This Mac" app="System Information" title="About This Mac" manage=off
yabai -m rule --add label="Activity Windows" title="^Activity$" manage=off
yabai -m rule --add app="^Adobe (After Effects|Audition|Media Encoder|Lightroom)$" role="AXLayoutArea" subrole="AXFloatingWindow" manage=on
yabai -m rule --add app="^IINA$" sticky=on manage=off

# Define scratchpads
# https://github.com/koekeishiya/yabai/issues/2203
yabai -m rule --add app="^Messages$" scratchpad=Messages grid=11:11:1:1:9:9
yabai -m rule --add app="^Transmission$" scratchpad=Transmission grid=11:11:1:1:9:9


# Apply rules to existing windows
yabai -m rule --apply

echo "Yabai configuration loaded…"

@koekeishiya
Copy link
Owner Author

Eh, I think I accidentally left in code that automatically hides the window when assigned to a scratchpad through a rule.

@koekeishiya
Copy link
Owner Author

Fixed on master.

@Keep-Simple
Copy link

Hi, thanks for the feature!
I'm having an issue:
to reproduce open 2 windows on a single space, fullscreen one of them (not native fullscreen)
then trigger the scratchpad window, then 3 windows are visible, instead of scratchpad one and fullscreened in the background

@koekeishiya
Copy link
Owner Author

That's intentional. Scratchpad is not meant to replace spaces for separation of windows. The scratchpad is simply a window that can be toggled into focus at any time regardless of which display or space is active. If you have window opacity enabled and the scratchpad window doesn't cover the entire screen, you will see the other windows in the back.

@dvrkoo
Copy link

dvrkoo commented Apr 8, 2024

Hey is there any intention of making scratchpad work with single instances of application? For example having one window of terminal in the scratchpad and other windows in tiling mode in a space? or like the ability to have the shortcut to launch an application in scratchpad without having to give it a window rule (I don't always need discord to be in a scratchpad)

@hahuang65
Copy link

hahuang65 commented Apr 8, 2024

For example having one window of terminal in the scratchpad and other windows in tiling mode in a space

I need to figure this out too. My terminal doesn't allow me to set title in a way that sticks such that Yabai can detect it.

Historically, I've had to script it so that after I launch a window, I get the latest window for that app, and then grab the ID. But this isn't something I can do with the new scratchpad feature, since it only accepts --app and --title.

launch_scratchpad() {
  ~/.scripts/term
  sleep 0.25
  scratchpad_id=$(yabai -m query --windows | jq 'map(select(.app == "WezTerm" or .app == "wezterm-gui")) | sort_by(.id) | last | .id')
  position_scratchpad "$scratchpad_id"
}

position_scratchpad() {
  scratchpad_id=$1
  yabai -m window --focus "$scratchpad_id"
  yabai -m window "$scratchpad_id" --toggle float
  yabai -m window "$scratchpad_id" --grid 11:11:1:1:9:9
}

Is it possible to dynamically add a rule based on window ID. I understand that's a hack.

@koekeishiya
Copy link
Owner Author

You can do: yabai -m window window_id --scratchpad my_scratchad instead of using a rule.

@rpoovey
Copy link

rpoovey commented May 7, 2024

Hey! Thanks for this feature. I started using this on my Linux Hyprland desktop and thought “I wonder if yabai has this?” And here it was. Awesome!

Wanted some clarification on how the workflow is supposed to go. Am I correct in thinking that assigning the window rules per your above examples and then the proper skhd toggle bind set up. That pressing it while the app is hidden/closed should:

  1. Bring it to the front and float. Open if not already running.
  2. Pressing the bind again should then hide the application?

Number two doesn’t seem to be happening and I have to press cmd + h to hide the app.

Thanks again.

@Kryan90
Copy link

Kryan90 commented Jun 3, 2024

For anyone trying to use this and getting weird partially-working behavior, I had missed that this requires partially disabling System Integrity Protection

@jbriales
Copy link

You can do: yabai -m window window_id --scratchpad my_scratchad instead of using a rule.

I had missed this. Maybe worth documenting the scratchpad actions/options in the Wiki/man?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
suggestion Request for new feature or some form of enhancement
Projects
None yet
Development

No branches or pull requests