This is a similar question as a person is asking on StackExchange https://apple.stackexchange.com/questions/51030/how-do-i-give-focus-to-the-correct-window-when-closing-another-applications-win
For me the scenario is as follows:
Now I would expect that after closing iterm on display 1 focus would go to chrome on display 1, but instead it jumps to iterm on display 2 which is not very intuitive.
Is there maybe a way yabai can handle this?
Had this in my yabairc for ages now and it works perfectly. It doesn't quite handle all use cases, but it's a huge improvement. This can obviously be adapated to suit your needs exactly.
#! /usr/bin/env zsh
# If no window on the current space is focused after a window is destroyed or
# minimized, or an application is hidden, focus the window under the cursor.
yabai -m signal --add event=window_destroyed \
action="${functions[focus_under_cursor]}"
yabai -m signal --add event=window_minimized \
action="${functions[focus_under_cursor]}"
yabai -m signal --add event=application_hidden \
action="${functions[focus_under_cursor]}"
function focus_under_cursor {
if yabai -m query --windows --space |
jq -er 'map(select(.focused == 1)) | length == 0' >/dev/null; then
yabai -m window --focus mouse 2>/dev/null || true
fi
}
Wow that looks perfect! I'll try your script and get back to you with my experience.
After some initial experimentation it seems that the signal hook is called too late. It seems that the following happens:
yabai -m window --focus mouse 2>/dev/null || true because another window is already selectedNote I'm running yabai with SIP enabled version yabai-v2.4.3.
Also adding the following event hander shows that window_focused is called before window_destroyed:
yabai -m signal --add event=window_focused action="echo SWITCHED TO WINDOW: \$YABAI_WINDOW_ID"
This means your script @dominiklohmann doesn't work for me 馃槩, as every time the focus_under_cursor callback is when a window is already selected.
Now looking into if I can maintain a historical list of focussed window ID's and once window_destroyed is called switch back to the (second to) last entry.
This is why I said that my snippet can be easily adapted to suit your needs. I've just shown you something that I was using for ages on my local machine that serves a similar purpose, that can be used as a building block.
Note that signals are run asynchronously. You cannot stop macOS from focusing the window, so you'll have to essentially jump back to the desired window in the action.
This is why I said that my snippet can be easily adapted to suit your needs. I've just shown you something that I was using for ages on my local machine that serves a similar purpose, that can be used as a building block.
Note that signals are run asynchronously. You cannot stop macOS from focusing the window, so you'll have to essentially jump back to the desired window in the action.
Ah okay good to know, thanks!
Hacked something together just now, which does what I want AFAIK. It'll focus on the previous window once the active window is destroyed. Due to the async nature of signals and macos already focussing a different window for you, you see some back and forth but that's to be expected.
function record_window_id {
json=$(yabai -m query --windows)
window_id=$(echo $json | jq -er 'map(select(.focused == 1))[0].id')
ruby $HOME/yabai_focus.rb write $window_id
}
function focus_previous_window {
previous_window_id=$(ruby $HOME/yabai_focus.rb read $YABAI_WINDOW_ID)
yabai -m window --focus $previous_window_id
}
yabai -m signal --add event=window_focused action="${functions[record_window_id]}"
yabai -m signal --add event=application_front_switched action="${functions[record_window_id]}"
yabai -m signal --add event=window_destroyed action="${functions[focus_previous_window]}"
require 'fileutils'
FILE="/tmp/yabai_focus_tmp"
HISTORY_SIZE=10
action = ARGV[0]
value = ARGV[1]
def log(message)
STDERR.puts message
end
def read_file
!File.exist?(FILE) && FileUtils.touch(FILE)
File.readlines(FILE).map do |item|
item.strip
end
end
log "RUNNING `#{action}` - `#{value}`"
case action
when 'write'
window_ids = read_file
window_ids.unshift(value)
window_ids = window_ids[0...HISTORY_SIZE]
File.open(FILE, 'w+') do |f|
f.puts(window_ids)
end
log "new window ids: #{window_ids}"
when 'clear'
File.delete(FILE)
when 'read'
window_ids = read_file
destroyed_window_id = value
log "reading window ids: `#{window_ids}`"
log "destroyed window id: `#{destroyed_window_id}`"
# Get the index in the list where the destroyed window id is
index_destroyed_window_id = window_ids.index(destroyed_window_id)
# Only items after the destroyed window id are considered previous
applicable_window_ids = window_ids[index_destroyed_window_id..]
log "applicable window ids: `#{applicable_window_ids}`"
# Now search for the first window_id which is not the destroyed one
previous_window_id = applicable_window_ids.find do |window_id|
window_id != destroyed_window_id
end
log "previous window id: `#{previous_window_id}`"
puts previous_window_id
else
raise "Unknown action `#{action}`"
end
Hi @dominiklohmann, I benefit a lot from many of your replies and absorb lots of knowledge I am not familiar with, especially the bash scripts and the coding skills. Thank you. Do you mind to share your yabairc, skhdrc and the scripts related to yabai you use? I really want to read them and continue to learn something from them.
Most helpful comment
Hi @dominiklohmann, I benefit a lot from many of your replies and absorb lots of knowledge I am not familiar with, especially the bash scripts and the coding skills. Thank you. Do you mind to share your yabairc, skhdrc and the scripts related to yabai you use? I really want to read them and continue to learn something from them.