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.
See before/after screenshots. Before, without the space, it's wrong. I
fixed that and added a newline, since a big paragraph like that looks a
bit wrong in a dialog popup.
Feel free to ignore or close this, because this is personal and if I
could figure out the syntax, I'm sure I could overwrite the keybindings
in the config myself.
But here's my case: `Ctrl+[` sends escape and I use that instead of
`Esc` because it's easier to reach (capslock is remapped to `ctrl`, so
`ctrl+[` is homerow only).
Kitty uses it's own "kittymod" combo for a lot of keybindings and for
the equivalent of these two, it uses `Ctrl+shift`. That's already taken
by other keybindings, so I added `.super` here.
Again: feel free to ignore. Personal preference. If you close this PR,
I'll have to tweak my config on Linux.
The GTK app has a really thin, white border around the terminal
contents. It's really distracting when in fullscreen.
At first I thought it's the window that has a border, but turns out
that's not it. It's the GTK Notebook widget. Luckily for us, GTK4 has a
single API call that allows us to turn off the border.
Fixes#210
We were previously taking any `CSI <symbol> <data> m` as SGR. But SGR is
only if "symbol" is empty. There are other forms of `CSI m` that set the
intermediate symbol to `?` or `>` and we don't implement those. We
shouldn't treat that as a SGR attribute either.
See #201 for more information.
Problem is that while we fall back to a default value to pass to
`setlocale`, we don't set a `LANG` and instead reset it to `""`.
What this does here is it changes the resetting to `""` and instead sets
it to the default value.
This fixes#99 for me.
Without this fix I end up with paddings of `3.333333` because my DPI is
`125.0` on Linux. If I set it to `144.0` manually so that the `/ 72`
gives me a clean `2.0`, the blurry fonts are gone.
I do think the calculation here is correct (even though I'm not sure
whether we should use 72? Why not 96? Or another system value?), so
let's use `std.math.floor` to get us to a "clean" padding of `3.0`.
That also solves blurry fonts for me.
Fixes#201
I don't fully understand locales, but it appears that the locale
returned from NSLocale can be "valid" in general but invalid according
to libc's locale API. If you attempt to `setlocale` with this bad
locale, it defaults everything to "C", which ends up breaking a lot of
things.
This commit validates the locale, and if it is invalid, we default to
"en_US.UTF-8" so things tend to work. This behavior can be overridden
using standard environment variables (LANG, LC_ALL, etc.).
This also doesn't touch env vars so further subprocesses from the shell
see original locale env vars.