Fixes#7706
We previously had a very specific backwards compatibility handler for
handling renamed fields. We always knew that wouldn't scale but I wanted
to wait for a real case. Well, #7706 is a real case, so here we are.
This commit makes our backwards compatibility handler more general
purpose, and makes a special-case handler for renamed fields built on
top of this same general purpose system. The new system lets us do a lot
more with regards to backwards compatibility.
To start, this addresses #7706 by allowing us to handle a removed single
enum value of a still-existing field.
In the future, I think this may continue to get _more_ general purpose
by moving the handlers from functions to structs so we can have more
metadata like descriptions and so on that we may use to generate docs or
other help strings.
Fixes#7706
We previously had a very specific backwards compatibility handler for
handling renamed fields. We always knew that wouldn't scale but I wanted
to wait for a real case. Well, #7706 is a real case, so here we are.
This commit makes our backwards compatibility handler more general
purpose, and makes a special-case handler for renamed fields built on
top of this same general purpose system. The new system lets us do a lot
more with regards to backwards compatibility.
To start, this addresses #7706 by allowing us to handle a removed single
enum value of a still-existing field.
Also fixes crashes in both vanilla GTK and Adwaita implementations of
`closeTab`, which erroneously close windows twice when there are no more
tabs left (we probably already handle it somewhere else).
This replaces #7433. The improvements are:
1) Install the systemd user service in the proper directory depending
on if it's a 'user' install or a 'system' install. This is controlled
either by using the `--system` build flag (as most packages will) or by
the `-Dsystem-package` flag.
2) Add the absolute path to the `ghostty` binary in the application
file, the DBus service, and the systemd user service. This is done so
that they do not depend on `ghostty` being in the `PATH` of whatever
is launching Ghostty. That `PATH` is not necessarily the same as the
`PATH` in a user shell (especially for DBus activation and systemd user
services).
3) Adjust the DBus bus name that is expected by the system depending on
the optimization level that Ghostty is compiled with.
Adds support for background images via the `background-image` config.
Resolves#3645, supersedes PRs #4226 and #5233.
See docs of added config keys for usage details.
Reverts two commits:
977cd530c7bb9551de93900170bdaec4601b1b5b
820b7e432b57cd08c49d2e76cce4cb78016f0418
These break build from source on Linux for two reasons:
1.) The systemd user service needs to be installed in the `share`
prefix, not the `lib` prefix. This lets it get picked up in `~/.local`
but is also correct for just standard FHS paths.
2.) The `ghostty` path in the systemd user service needs to be absolute.
We should interpolate in the build install prefix to form an absolute
path.
Introduces host resources directory as a new concept: A directory
containing application resources that can only be accessed from the host
operating system. This is significant for sandboxed application runtimes
like Flatpak where shells spawned on the host should have access to
application resources to enable integrations.
Alongside this, apprt is now allowed to override the resources lookup
logic.
This adds a new CLI `ghostty +edit-config`. This will open the config
file in the user's specified `$EDITOR`. If Ghostty has never been
configured, this will also create the initial config file with some
default templated contents (the same as that which we introduced back in
Ghostty 1.0.1 or something -- not new behavior here).
This is useful on its own because it will find the correct configuration
path to open. If users are terminal users anyway (not a big stretch
since this is a terminal app), this will allow them to easily edit
config right away.
This is also forward looking: I want to replace our "Open Config" action
to open a Ghostty window executing this command so that users can edit
their config in a terminal editor. This has been heavily requested since
forever (short of a full GUI settings editor, which is not ready yet). I
don't do this in this PR but plan to in a future PR.
Even further forward looking: when we have an API, we can have
`edit-config` auto-reload the config on exit. This isn't possible today
but this is where we'd put that.
This adds a new CLI `ghostty +edit-config`. This will open the config
file in the user's specified `$EDITOR`. If Ghostty has never been
configured, this will also create the initial config file with some
default templated contents (the same as that which we introduced back in
Ghostty 1.0.1 or something -- not new behavior here).
This is useful on its own because it will find the correct configuration
path to open. If users are terminal users anyway (not a big stretch
since this is a terminal app), this will allow them to easily edit
config right away.
This is also forward looking: I want to replace our "Open Config" action
to open a Ghostty window executing this command so that users can edit
their config in a terminal editor. This has been heavily requested since
forever (short of a full GUI settings editor, which is not ready yet). I
don't do this in this PR but plan to in a future PR.
This adds a new configuration `input` that allows passing either raw
text or file contents as stdin when starting the terminal.
The input is sent byte-for-byte to the terminal, so control characters
such as `\n` will be interpreted by the shell and can be used to run
programs in the context of the loaded shell.
Example: `ghostty --input="hello, world\n"` will start the your default
shell, run `echo hello, world`, and then show the prompt.
It's here, the long-foretold and long-procrastinated renderer rework!
Hopefully this makes it easier to adapt and modify the renderer in the
future and ensures feature parity between Metal and OpenGL. Despite
having been a lot of work to write initially, with the abstraction layer
in place I feel like working on the renderer will be a much more
pleasant experience going forward.
## Key points
- CPU-side renderer logic is now mostly unified via a generic
`Renderer`.
- A graphics API abstraction layer over OpenGL and Metal has been
introduced.
- Minimum OpenGL version bumped to `4.3`, so can no longer be run on
macOS; I used the nix VM stuff for my testing during development. (Edit
by @mitchellh: Note for readers that Ghostty still works on macOS, but
the OpenGL backend doesn't, only the Metal one)
- The OpenGL backend now supports linear blending! Woohoo! The default
`alpha-blending` has been updated to `linear-corrected` since it's
essentially a strict improvement over `native`. The default on macOS is
still `native` though to match other mac apps in appearance, since macOS
users are more sensitive to text appearance.
- Custom shaders can now be hot reloaded.
- The background color is once again drawn by us, so custom shaders can
interact with it properly. In general, custom shaders should be a little
more robust.
## The abstraction layer
The general hierarchy of the abstraction layer is as such:
```
[ GraphicsAPI ] - Responsible for configuring the runtime surface
| | and providing render `Target`s that draw to it,
| | as well as `Frame`s and `Pipeline`s.
| V
| [ Target ] - Represents an abstract target for rendering, which
| could be a surface directly but is also used as an
| abstraction for off-screen frame buffers.
V
[ Frame ] - Represents the context for drawing a given frame,
| provides `RenderPass`es for issuing draw commands
| to, and reports the frame health when complete.
V
[ RenderPass ] - Represents a render pass in a frame, consisting of
: one or more `Step`s applied to the same target(s),
[ Step ] - - - - each describing the input buffers and textures and
: the vertex/fragment functions and geometry to use.
:_ _ _ _ _ _ _ _ _ _/
v
[ Pipeline ] - Describes a vertex and fragment function to be used
for a `Step`; the `GraphicsAPI` is responsible for
these and they should be constructed and cached
ahead of time.
[ Buffer ] - An abstraction over a GPU buffer.
[ Texture ] - An abstraction over a GPU texture.
```
More specific documentation can be found on the relevant structures.
## Miscellany
Renderers (which effectively just means the generic renderer) are now
expected to only touch GPU resources in `init`, certain lifecycle
functions such as the `displayRealized`/`displayUnrealized` callbacks
from GTK-- and `drawFrame`; and are also expected to be thread-safe.
This allows the renderer thread to build the CPU-side buffers
(`updateFrame`) even if we can only *draw* from the app thread.
Because of this change, we can draw synchronously from the main thread
on macOS when necessary to always have a frame of the correct size
during a resize animation. This was necessary to allow the background to
be drawn by our GPU code (instead of setting a background color on the
layer) while still avoiding holes during resize.
The OpenGL backend now theoretically has access to multi-buffering, but
it's disabled (by setting the buffer count to 1) because it
synchronously waits for frames to complete anyway which means that the
extra buffers were just a waste of memory.
## Validation
To validate that there are no significant or obvious problems, I
exercised both backends with a variety of configurations, and visually
inspected the results. Everything looks to be in order.
The images are available in a gist here:
https://gist.github.com/qwerasd205/c1bd3e4c694d888e41612e53c0560179
## Memory
Here's a comparison of memory usage for ReleaseFast builds on macOS,
between `main` and this branch.
Memory figures given are values from Activity Monitor measuring windows
of the same size, with two tabs with 3 splits each.
||Before|After|
|-:|-|-|
|**Memory**|247.9 MB|224.2 MB|
|**Real Memory**|174.4 MB|172.5 MB|
Happily, the rework has slightly *reduced* the memory footprint- likely
due to removing the overhead of `CAMetalLayer`. (The footprint could be
reduced much further if we got rid of multi-buffering and satisfied
ourselves with blocking for each frame, but that's a discussion for
another day.)
If someone could do a similar comparison for Linux, that'd be much
appreciated!
## Notes / future work
- There are a couple structures that *can* be unified using the
abstraction layer, but I haven't gotten around to unifying yet.
Specifically, in `renderer/(opengl|metal)/`, there's `cell.zig` and
`image.zig`, both of which are substantially identical between the two
backends. `shaders.zig` may also be a candidate for unification, but
that might be *overly* DRY.
- ~~I did not double-check the documentation for config options, which
may mention whether certain options can be hot-reloaded; if it does then
that will need to be updated.~~ Fixed: be5908f
- The `fragCoord` for custom shaders originates at the top left for
Metal, but *bottom* left for OpenGL; fixing this will be a bit annoying,
since the screen texture is likewise vertically flipped between the two.
Some shaders rely on the fragcoord for things like falling particles, so
this does need to be fixed.
- `Target` should be improved to support multiple types of targets right
now it only represents a framebuffer or iosurface, but it should also be
able to represent a texture; right now a kind of messy tagged union is
used so that steps can accept both.
- Custom shader cursor uniforms (#6912) and terminal background images
(#4226, #5233) should be much more straightforward to implement on top
of this rework, and I plan to make follow-up PRs for them once this is
merged.
- I *do* want to do a rework of the pipelines themselves, since the way
we're rendering stuff is a bit messy currently, but this is already a
huge enough PR as it is- so for now the renderer still uses the same
rendering passes that Metal did before.
- We should probably add a system requirements section to the README
where we can note the minimum required OpenGL version of `4.3`, any even
slightly modern Linux system will support this, but it would be good to
document it somewhere user-facing anyway.
# TODO BEFORE MERGE
- [x] Have multiple people test this on both macOS and linux.
- [ ] ~~Have someone with a better dev setup on linux check for memory
leaks and other problems.~~ (Skipped, will merge and let tip users
figure this out, someone should *specifically* look for memory leaks
before the next versioned release though.)
- [x] Address any code review feedback.
This commit is very large, representing about a month of work with many
interdependent changes that don't separate cleanly in to atomic commits.
The main change here is unifying the renderer logic to a single generic
renderer, implemented on top of an abstraction layer over OpenGL/Metal.
I'll write a more complete summary of the changes in the description of
the PR.
Conversion of #7497 to a PR. This implements a feature requested in
#7331: an option to hide the default window buttons on macOS for a
cleaner aesthetic.
~~Builds on #7502 as it requires the same change to avoid the main
toolbar title showing on top of the tab bar.~~ EDIT: rebased on main now
that #7502 was merged.
I aligned the scope of the new option with `macos-titlebar-style`, since
they both customize titlebar elements. This means it has the same edge
case quirks: For example, if you change the setting, reload the config,
and then open a new tab, the appearance of the current window will
depend on which tab is in the foreground. I did it this way because
`macos-titlebar-style` provided an easy template for which derived
configs and functions to modify. Let me know if you want me to try
adjusting this so that a change in the setting also takes effect for
current windows/tabs, which I _think_ should be possible.
Screenshots:
* `macos-titlebar-style = transparent` (default)


* `macos-titlebar-style = tabs`


Related to #7433
This extracts our "launched from desktop" logic into a config option.
The default value is detection using the same logic as before, but now
this can be overridden by the user.
This also adds the systemd and dbus activation sources from #7433.
There are a number of reasons why we decided to do this:
1. It automatically gets us caching since the configuration is only
loaded once (per reload, a rare occurrence).
2. It allows us to override the logic when testing. Previously, we
had to do more complex environment faking to get the same
behavior.
3. It forces exhaustive switches in any desktop handling code, which
will make it easier to ensure valid behaviors if we introduce new
launch sources (as we are in #7433).
4. It lowers code complexity since callsites don't need to have N
`launchedFromX()` checks and can use a single value.
Fixes#7481
We unfortunately don't have a great way to unit test this since our
logic relies on argv and I'm too lazy to extract it out right now.
The core issue is that we previously detected if font-families changed
by comparing lengths. This doesn't work because the CLI args can reset
and add families back to a lesser length. This caused an integer
overflow.
We can fix this by not being clever and introducing the overwrite logic
directly into the config type. I unit tested that.
Fixes#7481
We unfortunately don't have a great way to unit test this since our
logic relies on argv and I'm too lazy to extract it out right now.
The core issue is that we previously detected if font-families changed
by comparing lengths. This doesn't work because the CLI args can reset
and add families back to a lesser length. This caused an integer
overflow.
We can fix this by not being clever and introducing the overwrite logic
directly into the config type. I unit tested that.
See commit messages for details.
If some of the commits in this PR have problems with them I'm perfectly
fine with the others being cherry-picked out while the problems are
addressed.
The biggest/broadest reaching changes in this PR come from converting a
lot of code to use decl literals where possible, so there are a lot of
files where only a handful of lines are modified very slightly.
This commit changes a LOT of areas of the code to use decl literals
instead of redundantly referring to the type.
These changes were mostly driven by some regex searches and then manual
adjustment on a case-by-case basis.
I almost certainly missed quite a few places where decl literals could
be used, but this is a good first step in converting things, and other
instances can be addressed when they're discovered.
I tested GLFW+Metal and building the framework on macOS and tested a GTK
build on Linux, so I'm 99% sure I didn't introduce any syntax errors or
other problems with this. (fingers crossed)
Fixes#7392
Docs:
> Whether to clear selected text when typing. This defaults to `true`.
> This is typical behavior for most terminal emulators as well as
> text input fields. If you set this to `false`, then the selected text
> will not be cleared when typing.
>
> "Typing" is specifically defined as any non-modifier (shift, control,
> alt, etc.) keypress that produces data to be sent to the application
> running within the terminal (e.g. the shell). Additionally, selection
> is cleared when any preedit or composition state is started (e.g.
> when typing languages such as Japanese).
>
> If this is `false`, then the selection can still be manually
> cleared by clicking once or by pressing `escape`.