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

Focus empty workspace on mouse hover #459

Closed
danijar opened this issue Mar 26, 2020 · 18 comments
Closed

Focus empty workspace on mouse hover #459

danijar opened this issue Mar 26, 2020 · 18 comments
Labels
enhancement New feature or request

Comments

@danijar
Copy link

danijar commented Mar 26, 2020

I'm using the option yabai -m config focus_follows_mouse autoraise, which works great in most cases. However, when using multiple displays, moving the mouse to a display with an empty screen does not focus that screen. As a result, opening the terminal via shortcut opens it on the wrong screen and my status bar icon also shows the wrong screen as active.

@dominiklohmann
Copy link
Collaborator

dominiklohmann commented Mar 26, 2020

This issue is not as trivial as you might think. What qualifies as an empty space? Is it...

  • a space without any windows assigned to it,
  • a space without any tiled windows assigned to it, or
  • a space without any tiled or floating windows assigned to it?
  • How does of all this work with sticky windows?

Edit: Generally speaking, this is a great feature suggestion, and I'd love to toy around with this. Just saying that the conditions need to be fleshed out a bit.

@dominiklohmann dominiklohmann added the enhancement New feature or request label Mar 26, 2020
@koekeishiya
Copy link
Owner

Note that this is not necessarily feasible to implement in an efficient manner. It will require more caching which will lead to a higher risk of synchronization issues towards the actual state of the operating system.

@koekeishiya
Copy link
Owner

I think a better solution to the problem you are having is to simply introduce a new config setting spawn_at_cursor_display or something, that simply tiles a newly launched application or created window at the active space of the display that holds the cursor. This does not require much change, and the performance impact will be negligible.

@danijar
Copy link
Author

danijar commented Mar 26, 2020

Thanks for considering this! spawn_at_cursor_display would be a small improvement. i3wm has a similar feature that often provided problems, e.g. for programs with multiple windows or programs with loading banners. It would also not solve the issue of the system status bar being greyed out and any spaces indicator based on yabai -m query --spaces --space not updating.

For actually focusing the new screen, it seems that the following steps would be necessary:

  • Detect when the cursor moves to a different display. Is there a system event to catch this? Otherwise, would checking the cursor position on every cursor move be a performance problem?
  • Find the currently active screen on the new display. Assuming we have the display ID, the can find screens on that display via yabai -m query --spaces. I'm not sure whether there is a way to query the current screen on an unfocused display. Is this what you said yabai would have to keep track of?
  • Focus the new screen. This is of course easy with yabai -m space --focus <id>.

Once the new screen is focused, the internal book keeping that yabai might need to do for that display would be in sync with the system again.

@koekeishiya
Copy link
Owner

koekeishiya commented Mar 26, 2020

i3wm has a similar feature that often provided problems, e.g. for programs with multiple windows or programs with loading banners.

That won't be a problem in yabai, due to how the macOS APIs work. The only situation where this setting would not apply would be for windows that yabai cannot manage at all, e.g in this situation: #304

It would also not solve the issue of the system status bar being greyed out and any spaces indicator based on yabai -m query --spaces --space not updating.

This is more or less because of how macOS is designed. A display, or even desktop does not really have the concept of being focused - only applications can be focused. What's happening when you click on the desktop to focus a display is that it actually focuses Finder, somehow.
I assume this is done through either the desktop window itself, or an invisible kind of thing that they pull off for this purpose.

For actually focusing the new screen, it seems that the following steps would be necessary:

Detect when the cursor moves to a different display. Is there a system event to catch this? Otherwise, would checking the cursor position on every cursor move be a performance problem?

There is no system event for this, so we would have to check every time the cursor is moved. We also don't want to impact the performance of moving the mouse around in general, or even just moving around on the same display. This is why caching is a bit complex. Actually focusing the display is easy, and is working properly for empty displays if you are using yabai -m display --focus whatever

@dominiklohmann
Copy link
Collaborator

dominiklohmann commented Mar 26, 2020

For what it's worth, this can (with a notable performance penalty) be implemented already using a mix of signals and queries:

  • Track the signal event=mouse_moved
  • Compare the coordinates passed to the event to the focused displays frame:
    1. If it's inside, do nothing
    2. If it's, query for all displays:
      a. If the visible space on that display has windows, do nothing
      b. If there are no windows on the visible display for that space, focus the display

I've just toyed around with it and it causes serious battery strain because the event is triggered so much. Obviously an implementation internal to yabai would run more smoothly, but hooking anything to event=mouse_moved is generally a bad idea.

@danijar
Copy link
Author

danijar commented Mar 27, 2020

I see. Maybe a better solution would be to have a background script separate from yabai that queries the cursor position every couple of hundred milliseconds? The script would

  • Query the cursor position
  • Find the display ID from that
  • Find the last used space on that display
  • Focus the space

I don't want to take too much of your time --- if you have any tips on how this could be done I'd appreciate it. I also think this might be interesting for other yabai users with multi display setup.

@danijar
Copy link
Author

danijar commented Apr 10, 2020

Having used yabai for two weeks now, it's been a great improve in productivity! However, I keep running into the issue described in this thread.

  • Maybe there is a way to detect the focus event of the MacOS Desktop UI element?
  • Maybe it could be solved by adding a display-sized window to every space that floats behind other windows and passes mouse events through to the Desktop?
  • I personally don't even use the Desktop, so if there is a solution that hides it under a window that takes focus events, I'd be fine with that.

@ThinkChaos
Copy link

This is something I'd like, and I think the method of getting the cursor position would already be a great improvement.

@StarWitch
Copy link

I would also be in favour of this functionality.

@koekeishiya
Copy link
Owner

I simply do not see how this can be implemented efficiently enough to be acceptable. Feel free to give it a try, but I probably won't invest a lot of time into this myself.

@koekeishiya
Copy link
Owner

I managed to get this working without any noticable performance degradation.

@koekeishiya koekeishiya added the addressed on master; not released Fixed upstream, but not yet released label Jun 5, 2020
@koekeishiya
Copy link
Owner

koekeishiya commented Jun 5, 2020

Note that we don't actually care if the space of the display is empty or not. If the display is not empty it will focus the window that was below the cursor at the position that it had when it entered that display (as it previously did).

If yabai does not know of any windows on that space, we give focus to the space by first checking if there is some AXElement at that point, and focus the owning window of said element if one exists.

If no element was found at said point, we simply synthesize a mouse click event to force a focus change through the invisible finder desktop window.

To avoid awkward cursor jumps none of the above methods will trigger mff.

@danijar
Copy link
Author

danijar commented Jun 5, 2020

Thanks @koekeishiya, this is gonna be a big improvement!

@danijar
Copy link
Author

danijar commented Jun 6, 2020

I found a small bug with this. It doesn't make this any less useful to me but I still wanted to point it out in case you want to fix it. I have a setup with one display above another. When moving the cursor slowly enough from the top to the bottom display, the cursor enters via a pixel that's part of the Mac status bar. Depending on whether there is a clickable UI element under that pixel, it will be clicked, which sometimes opens up a list with menu items. I don't know if it's possible to simulate a click at a location different from the cursor --- if so, a practical solution might be just to simulate the click in the center of the display.

@koekeishiya
Copy link
Owner

koekeishiya commented Jun 7, 2020

I don't know if it's possible to simulate a click at a location different from the cursor --- if so, a practical solution might be just to simulate the click in the center of the display.

That is possible yes, but it will also cause the cursor to jump to the center of the display.

Edit: Actually it might be possible without the cursor jump.

@danijar
Copy link
Author

danijar commented Jun 7, 2020

Another idea would be to wait for the cursor to stop before simulating the click, which would probably be an improvement because most of the time one moves beyond the status bar. Anyway, it's not much of a problem in practice anyway, it might just be a bit confusing to people who don't know how this is implemented.

@koekeishiya
Copy link
Owner

koekeishiya commented Jun 7, 2020

Fixed it by simply preventing ffm from triggering as long as the mouse is above the menubar. I think this is the most efficient solution from a technical pov, but it also has no risk of accidentally clicking a ui element, as the old check that looks for a window/ui element at the given point will still apply and prevent the click.

koekeishiya added a commit that referenced this issue Jun 7, 2020
@koekeishiya koekeishiya removed the addressed on master; not released Fixed upstream, but not yet released label Jun 8, 2020
unrevre pushed a commit to unrevre/yabai that referenced this issue Jan 26, 2022
unrevre pushed a commit to unrevre/yabai that referenced this issue Jan 26, 2022
unrevre pushed a commit to unrevre/yabai that referenced this issue Jan 26, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants