Skip to content
New issue

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

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

Already on GitHub? # to your account

toggle topmost not working #1704

Closed
Subjective opened this issue Apr 14, 2023 · 5 comments
Closed

toggle topmost not working #1704

Subjective opened this issue Apr 14, 2023 · 5 comments
Labels
bug Something isn't working obscure Weird behaviour that is difficult to debug

Comments

@Subjective
Copy link

It seems that whenever the toggle topmost option is used, is-topmost is not set to true. Toggling topmost does make the selected window topmost, but it can't set topmost off. This is problematic for apps like Arc browser that have a floating app switcher, since the app switcher will be hidden underneath the main window.
Here's the output before and after running yabai -m window --toggle topmost (they are the same):

Before
{
	"id":13896,
	"pid":96854,
	"app":"kitty",
	"title":"yabai -m query --windows",
	"frame":{
		"x":1731.0000,
		"y":40.0000,
		"w":1694.0000,
		"h":1384.0000
	},
	"role":"AXWindow",
	"subrole":"AXStandardWindow",
	"display":1,
	"space":2,
	"level":0,
	"opacity":1.0000,
	"split-type":"vertical",
	"split-child":"second_child",
	"stack-index":0,
	"can-move":true,
	"can-resize":true,
	"has-focus":true,
	"has-shadow":true,
	"has-border":true,
	"has-parent-zoom":false,
	"has-fullscreen-zoom":false,
	"is-native-fullscreen":false,
	"is-visible":true,
	"is-minimized":false,
	"is-hidden":false,
	"is-floating":false,
	"is-sticky":false,
	"is-topmost":false,
	"is-grabbed":false
}
After
{
"id":13896,
"pid":96854,
"app":"kitty",
"title":"yabai -m query --windows",
"frame":{
"x":1731.0000,
"y":40.0000,
"w":1694.0000,
"h":1384.0000
},
"role":"AXWindow",
"subrole":"AXStandardWindow",
"display":1,
"space":2,
"level":0,
"opacity":1.0000,
"split-type":"vertical",
"split-child":"second_child",
"stack-index":0,
"can-move":true,
"can-resize":true,
"has-focus":true,
"has-shadow":true,
"has-border":true,
"has-parent-zoom":false,
"has-fullscreen-zoom":false,
"is-native-fullscreen":false,
"is-visible":true,
"is-minimized":false,
"is-hidden":false,
"is-floating":false,
"is-sticky":false,
"is-topmost":false,
"is-grabbed":false
}

Screen Recording 2023-04-13 at 9 44 05 PM

@koekeishiya
Copy link
Owner

This is a weird issue. When I run yabai manually through a terminal session, toggle topmost works fine, and the query system outputs the correct value. When I run yabai as a service through launchd, I am able to make a window topmost but the query system still outputs false (and the internal check says the window is not topmost) making it unable to toggle back.

@koekeishiya koekeishiya added bug Something isn't working obscure Weird behaviour that is difficult to debug labels May 23, 2023
@koekeishiya
Copy link
Owner

koekeishiya commented May 23, 2023

For some reason SLSGetWindowLevel(g_connection, window->id, &level); does not properly return the window level when yabai is running as a launchd service???? This problem can be solved by using an alternative way to retrieve the window level. Note that the mentioned function works just fine when yabai runs through a terminal.

The alternative method of retrieving the window level is unfortunately not a viable workaround, because it is prone to this crash issue: #1475

@wxwern
Copy link

wxwern commented Jun 5, 2023

If it helps, I am experiencing this issue and was able to replicate the issue in a terminal session.

It seems to query the window level correctly only upon initial launch. After changing the topmost state with the --toggle topmost command, it does not return the correct value when queried again, breaking topmost related operations on that window until yabai is restarted again.

For me to reproduce this (after stopping the yabai service):

$ yabai >> /dev/null 2>&1 & # start yabai via terminal session
[1] 45441

$ yabai -m query --windows --window | jq '."is-topmost"' # after yabai loads, topmost initially false
false

$ yabai -m window --toggle topmost # toggle this terminal window

$ yabai -m query --windows --window | jq '."is-topmost"' # topmost does not update after toggle
false

$ kill $(pgrep -f yabai) && yabai >> /dev/null 2>&1 & # restart yabai and wait till loaded
[2] 46060
[1]  + 45441 terminated  yabai >> /dev/null 2>&1

$ yabai -m query --windows --window | jq '."is-topmost"' # after yabai loads, topmost correctly updated to true
true

@koekeishiya
Copy link
Owner

koekeishiya commented Jun 5, 2023

Doesn't really help as long as I cannot reliably reproduce the issue in a terminal session using those instructions (or other ways that I've tried). The difference as I mentioned is the return value of the SLSGetWindowLevel(g_connection, window->id, &level); function.

You are correct that doing the topmost change, and restarting yabai makes it retrieve the correct value when running as a service, but subsequent invocations do not return the updated value. These functions are very primitive, and only really call the macOS APIs.

Here is how we check if a window is topmost:

int window_level(struct window *window)
{
    int level = 0;
    SLSGetWindowLevel(g_connection, window->id, &level);
    return level;
}

bool window_is_topmost(struct window *window)
{
    bool is_topmost = window_level(window) == CGWindowLevelForKey(LAYER_ABOVE);
    return is_topmost;
}

Notice that there is no form of caching here; we just ask the OS. Yet (for me anyway) it works fine when running the exact same code through a terminal, but it does not work when running through launchd. When running through launchd, the initial invocation does correctly get the level and topmost value, but subsequent invocations do not properly get the value.

I verified that by changing the way we retrieve the window level the topmost function works properlty from launchd as well, but for reasons mentioned above this is not a solution. Since you can reproduce the problem while simply running through a terminal, that is even weirder.

I am not saying there might not be a bug here, but it is not particularly obvious to me what exactly the cause of the issue could be, based on these observations. As you can see the code in yabai is literally just asking macOS to report the current state.

@koekeishiya
Copy link
Owner

Implemented a fix on master. I've attemted to add some safeguard to avoid the crashes observed in #1475, but time will tell.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
bug Something isn't working obscure Weird behaviour that is difficult to debug
Projects
None yet
Development

No branches or pull requests

3 participants