1 Commits

Author SHA1 Message Date
Thorsten Ball
850bf3e945 macos: add support for non-native fullscreen mode
This adds support for what's commonly referred to as "non-native
fullscreen": a fullscreen-mode that doesn't use macOS' native fullscreen
mechanism and thus doesn't use animations and a separate space on which
to display the fullscreen window. Instead it's really fast and it allows
the user to `Cmd+tab` to other windows, with the fullscreen-ed window
staying in the background.

Another name for it is "traditional fullscreen" since it was the default
pre Mac OS X Lion, if I remember correctly.

Other applications that offer macOS non-native fullscreen:

- Kitty: https://sw.kovidgoyal.net/kitty/conf/#opt-kitty.macos_traditional_fullscreen
- wezterm: https://wezfurlong.org/wezterm/config/lua/config/native_macos_fullscreen_mode.html
- MacVim
- IINA: fc66b27d50/iina/MainWindowController.swift (L1401-L1423)
- mpv: https://mpv.io/manual/stable/#options-native-fs
- iTerm2

Adding this wasn't straightforward, as it turned out. Mainly because
SwiftUI's app lifecycle management doesn't allow one to use a custom
class for the windows it creates. And without custom classes we'd always
get a warning when entering/leaving fullscreen mode.

So what I did here is the following:

- remove SwiftUI app lifecycle management
- introduce `MainMenu.xib` to define the main menu via interface builder
- add `GhosttyAppController` to handle requests from the app
- add a `main.swift` file to boot up the app without a storyboard and
  without SwiftUI lifecycle management
- introduce the `FullScreenHandler` to manage non-native fullscreen -
  this is where the "magic" is

But since removing the SwiftUI lifecycle management also means removing
the top-level `App` that means I had to introduce the menu (which I
mentioned), but also tab and window management.

So I also added the `WindowService` which manages open tabs and windows.
It's based on the ideas presented in

    https://christiantietze.de/posts/2019/07/nswindow-tabbing-multiple-nswindowcontroller/

and essentially keeps tracks of windows.

Then there's some auxilliary changes: `CustomWindow` and `WindowController` and so on.

Now everything still works, in addition to non-native fullscreen:

* opening/closing of tabs
* opening/closing of windows
* splits
* `gotoTab`

Worthy of note: when toggling back from non-native fullscreen to
non-fullscreen I had to manually implement the logic to re-add the
window back to a tabgroup. The only other app that supports tabs with
non-native FS is iTerm2 and they have implemented their own tab
management to keep the tab bar even in non-native FS -- that's a bit too
much for me. Every other app has non-native apps and doesn't have to
wory about it.
2023-08-04 14:12:30 -07:00