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

[feat. discussion] Add an explicit always_on_top configuration option and launch option #7145

Closed
dljsjr opened this issue Feb 22, 2024 · 6 comments

Comments

@dljsjr
Copy link

dljsjr commented Feb 22, 2024

Request for Discussion before Opening PR

Is your feature request related to a problem? Please describe.

There have been several requests for a guake/yakuake/iTerm2.app-style hotkey window for kitty over time, and the current consensus opinion of the project is that this should be the responsibility of the window manager. I agree with this.

However, sometimes this requires special window hints to be set on the window before the WM allows you to do so in every situation. I can't speak for X11 or Wayland, but here's an example of what I mean on macOS:

If you want to create a truly always on top window, then the application must set flags and hints on the window handle explicitly. This covers situations such as showing on all Spaces, or dropping in front of a native full screen window. There is no way for an external tool or WM to influence this without disabling SIP and using code injection. Opinions of SIP aside, it is evident that there may often be users that would both like to have this feature and keep SIP enabled, meaning the application should support setting the correct hints on the windows.

Prior art for this type of behavior can be found in the iTerm2.app's "Hotkey Window" functionality.

Describe the solution you'd like

I'm proposing the addition of a kitty configuration option such as always_on_top, that when set to y/yes/true, will set the appropriate GLFW Window Hints at the GLFW layer, as well as setting platform specific masks for Cocoa/x11/Wayland.

In truth, based on what research I've done, I think that GLFW handles this correctly for x11 and Wayland if the GLFW_FLOATING hint is set, which would be the primary change that would come from this configuration being set to true.

Then there is the macOS platform specific work to set the various flags/masks.

Describe alternatives you've considered

There are WM's for macOS such as yabai that can handle this externally if you disable SIP.

Regardless of whether it's held that SIP is a good idea or not, there will always be use cases where it cannot be disabled. For example, an MDM/corporate controlled laptop where the MDM policies disallow turning SIP off but allow users to install their own apps for productivity (a very common setup).

Additional context

I have already forked the repository and implemented this on a branch: https://github.com/dljsjr/kitty/tree/feat/floating-window-config

It supports setting always_on_top via the conf file or CLI -o allow_on_top= override syntax, as well as via an --always-on-top flag for the launch command.

A proof-of-concept for how this flag enables WM tools to create drop-down terminals on macOS is also available: https://github.com/dljsjr/Visor.spoon/tree/feat/animated-terminal

The WM in this case is Hammerspoon, which is a more general automation utility for macOS that has WM functionality as well.

If this is something that the project finds valuable, I'm happy to open a PR. But I wanted to adhere to the contribution guidelines first and make sure that this wasn't against the direction that the maintainers would want to go. I'm also not against making this a macOS specific configuration like the other macOS specific options. I'm not sure what the value of using these hints are on Linux, as I primarily use Linux without a DE and only use a DE on macOS.

@kovidgoyal
Copy link
Owner

On wayland _glfwPlatformSetWindowFloating is unimplemented. On X11 it sets _NET_WM_STATE_ABOVE which is a hint that the window should be above most other windows. For reference see: https://specifications.freedesktop.org/wm-spec/wm-spec-1.4.html#STACKINGORDER However what effect it actually has is window manager dependent. On macOS it sets the window level to floating which means the window will be below all non floating windows. I see in your fork you want to change that to status level which puts it above all none status windows. But there are alos some collection level changes What effect do they have?

And more generally, I dont think this should be a config option. There is no reason to expect it to apply to all kitty OS windows. It would instead be an action that can be mapped and that toggles the state and possibly also a CLI option under --start-as. The action would need major caveats that its effect is advisory only and requires co-operation from the window manager.

@dljsjr
Copy link
Author

dljsjr commented Feb 26, 2024

I see in your fork you want to change that to status level which puts it above all none status windows

Having the NSWindowLevel set to Status is required for the window to be truly on top of anything in its space, including the Dock and global Menu Bar if either of them aren't set to auto-hide. NSFloatingWindowLevel doesn't allow you to do that.

That said, having typed it out now, the better implementation is probably not overriding the intent of the GLFW floating bit; instead I should probably propagate the always-on-top request in to the Cocoa wrapper and branch on that.


But there are alos some collection level changes What effect do they have?

The values for that bitmask can be found here: https://developer.apple.com/documentation/appkit/nswindow/collectionbehavior

They control how windows will behave under the various macOS features that will "collect" windows for you, such as Mission Control/Expose, Native Full Screen, across Spaces, and in Stage Manager.

  • canJoinAllApplications allows the window to be shown without switching away from the active app group when in Stage Manager, and also implies fullScreenAuxiliary for displaying over top of native Full Screen windows.
  • canJoinAllSpaces means that the window can show on any Space, instead of taking you back to the Space where the window is assigned whenever it gains focus
  • transient means that the window doesn't show when activating Mission Control, and that it doesn't belong to a Space
  • IgnoresCycle excludes the window from the window cycling functionality (Cmd+`)

So the Collection Behaviors are used to allow for creating a truly always-on-top window that can display over a full screen app, stage manager group, across any Space, and while also not participating in window cycling or Mission Control.


And more generally, I dont think this should be a config option. There is no reason to expect it to apply to all kitty OS windows. It would instead be an action that can be mapped and that toggles the state and possibly also a CLI option under --start-as. The action would need major caveats that its effect is advisory only and requires co-operation from the window manager.

Agreed that this probably makes more sense than having it as a config. Thanks for the feedback.

@kovidgoyal
Copy link
Owner

OK, I can accept this as an action and additional value to --start-as.
And yes dont change the floating implementation, create a new window
attribute for it, named alwaysontop or something similar and implement
it in the cocoa backend. The wayland one will remain unimplemented,
given the general feature poorness of wayland I doubt it's implementable
there. The X11 implementation can just set the on top window hint just as
the floating one does now.

@kovidgoyal
Copy link
Owner

Closing, feel free to continue discussion in a PR.

@unphased
Copy link

Is there any ongoing work or PR related to this item? This capability is also missing from Alacritty I might add (at least as far as I know). The best way to get always on top behavior is not by hacking focus via other tools like hammerspoon but by allowing the app in question to declare to the OS that the user wants it to be on top of everything even when unfocused.

The use case is typically in response to a key bind (toggle probably) or an IPC command to control this state.

@kovidgoyal
Copy link
Owner

Nope, there isnt.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants