This commit is quite large because it's fairly interconnected and can't
be split up in a logical way. The main part of this commit is that alpha
blending is now always done in the Display P3 color space, and depending
on the configured `window-colorspace` colors will be converted from sRGB
or assumed to already be Display P3 colors. In addition, a config option
`text-blending` has been added which allows the user to configure linear
blending (AKA "gamma correction"). Linear alpha blending also applies to
images and makes custom shaders receive linear colors rather than sRGB.
In addition, an experimental option has been added which corrects linear
blending's tendency to make dark text look too thin and bright text look
too thick. Essentially it's a correction curve on the alpha channel that
depends on the luminance of the glyph being drawn.
As recommended in
https://github.com/ghostty-org/ghostty/pull/4927#issuecomment-2585003934,
adds a config option `maximize` for starting a window in a maximized
state in terms of window properties. Also adds a `toggle_maximize`
keybind to allow users to manually toggle this feature on and off.
It might make more sense to make this an optional config value so that
we don't toggle the state off if the WM already handles that for us, but
I'll let a reviewer decide.
Closes https://github.com/ghostty-org/ghostty/issues/4646
Previously, the logic navigated to the second-to-last tab instead of the
last tab due to an off-by-one error. This updates the implementation so
that the index calculation to accurately target the last tab. In the
`gotoLastTab` method there was a decrement in the number of max number
of tabs and another increment in the `goToTab` method to get the actual
tab index.
## Description
When pasting URLs from clipboard, the behavior varies based on the
source:
1. From browser address bar:
- Pasteboard types: ["public.utf8-plain-text", "NSStringPboardType"]
- Handled as plain text, resulting in correct full URL paste
2. From clipboard history tools, such as Raycast clipboard history:
- Pasteboard types include "public.url" and related URL types
- URL was being processed through NSURL, which only extracted the path
component
- This resulted in incomplete URLs
## Changes
- Modified `getOpinionatedStringContents()` to differentiate URL types:
- For file URLs (`file://`): preserve existing behavior, return path
only
- For web URLs (`http://`, `https://`): return full URL string via
`absoluteString`
- For non-URL content: maintain existing plain text handling
## Related Issues
Fixes#5026
@caarlos0 Could you please help check if this resolves the issue you
were encountering?
Fixes#5022
The CSI SGR sequence (CSI m) is unique in that its the only CSI sequence
that allows colons as delimiters between some parameters, and the colon
vs. semicolon changes the semantics of the parameters.
Previously, Ghostty assumed that an SGR sequence was either all colons
or all semicolons, and would change its behavior based on the first
delimiter it encountered.
This is incorrect. It is perfectly valid for an SGR sequence to have
both colons and semicolons as delimiters. For example, Kakoune sends the
following:
;4:3;38;2;175;175;215;58:2::190:80:70m
This is equivalent to:
- unset (0)
- curly underline (4:3)
- foreground color (38;2;175;175;215)
- underline color (58:2::190:80:70)
This commit changes the behavior of Ghostty to track the delimiter per
parameter, rather than per sequence. It also updates the SGR parser to
be more robust and handle the various edge cases that can occur. Tests
were added for the new cases.
Fixes#5022
The CSI SGR sequence (CSI m) is unique in that its the only CSI sequence
that allows colons as delimiters between some parameters, and the colon
vs. semicolon changes the semantics of the parameters.
Previously, Ghostty assumed that an SGR sequence was either all colons
or all semicolons, and would change its behavior based on the first
delimiter it encountered.
This is incorrect. It is perfectly valid for an SGR sequence to have
both colons and semicolons as delimiters. For example, Kakoune sends
the following:
;4:3;38;2;175;175;215;58:2::190:80:70m
This is equivalent to:
- unset (0)
- curly underline (4:3)
- foreground color (38;2;175;175;215)
- underline color (58:2::190:80:70)
This commit changes the behavior of Ghostty to track the delimiter per
parameter, rather than per sequence. It also updates the SGR parser to
be more robust and handle the various edge cases that can occur. Tests
were added for the new cases.
Previously, the logic navigated to the second-to-last tab instead of the
last tab due to an off-by-one error. This updates the implementation so
that the index calculation to accurately target the last tab.
In the `gotoLastTab` method there was a decrement in the number of max
number of tabs and another increment in the `goToTab` method to get the
actual tab index.
Fixes#4999
We need to set the level to popUpMenu so that we can move the window
offscreen and animate it over the main menu, but we must reset it back
to floating after the animation is complete so that other higher-level
windows can be shown on top of it such as IME windows.
Fixes#4999
We need to set the level to popUpMenu so that we can move the window
offscreen and animate it over the main menu, but we must reset it back
to floating after the animation is complete so that other higher-level
windows can be shown on top of it such as IME windows.
Fixes#3345
Piggybacking on the logic introduced PR
https://github.com/ghostty-org/ghostty/pull/3997, this patch prevents
mouse motion events with the same cursor position triggered by the
window title updating from un-hiding the mouse even when
`mouse-hide-while-typing` config item is true.
Ghostty with libadwaita older than 1.4.0 (in my case, that of debian
bookworm) will segfault when you exit ghostty with ctrl+d. This was
already fixed by #3694 but it re-appeared during a refactor. The fix
simply uses a reference to `tab.window.window` to call
`gtk_window_destroy`, because `tab.window` has already been [destroyed
by a signal
handler](6cbd69da78/src/apprt/gtk/Tab.zig (L130-L137))
triggered in the old libadwaita path.
Original issue: #3135
This PR ensures one can drag and drop the following things to the
terminal window:
- File (Inserts the file path into the terminal)
- URL
- Text
This resolves#4932
#4235 introduced a crash when you closed the last tab in a window. In
`NotebookAdw.closeTab` a `defer` was added that references `self`. If
the last tab is closed we destroy the window. As part of that process
`self` becomes invalid because the window has been de-initialized. The
`defer` fires at the end of the function, referencing the invalid
pointer and causing a crash.
```
info(surface): surface closed addr=7fffe400a000
debug(gtk): window destroy
(process:1032400): Gtk-CRITICAL **: 18:40:17.674: gtk_widget_unparent: assertion 'GTK_IS_WIDGET (widget)' failed
Segmentation fault at address 0x7ffff4dad040
/home/jeff/dev/ghostty/src/apprt/gtk/notebook_adw.zig:128:19: 0x340226a in closeTab (ghostty)
defer self.forcing_close = false;
^
/home/jeff/dev/ghostty/src/apprt/gtk/notebook.zig:157:40: 0x336ca86 in closeTab (ghostty)
.adw => |*adw| adw.closeTab(tab),
^
/home/jeff/dev/ghostty/src/apprt/gtk/Window.zig:468:27: 0x327628d in closeTab (ghostty)
self.notebook.closeTab(tab);
^
/home/jeff/dev/ghostty/src/apprt/gtk/Tab.zig:121:25: 0x336581b in remove (ghostty)
self.window.closeTab(self);
^
/home/jeff/dev/ghostty/src/apprt/gtk/Surface.zig:207:34: 0x326a213 in remove (ghostty)
.tab_ => |t| t.remove(),
^
/home/jeff/dev/ghostty/src/apprt/gtk/Surface.zig:722:30: 0x31e3a3a in close (ghostty)
self.container.remove();
^
/home/jeff/dev/ghostty/src/Surface.zig:733:26: 0x31e1dc4 in close (ghostty)
self.rt_surface.close(self.needsConfirmQuit());
^
/home/jeff/dev/ghostty/src/Surface.zig:925:23: 0x31e143e in handleMessage (ghostty)
self.close();
^
/home/jeff/dev/ghostty/src/App.zig:486:34: 0x31e2d05 in surfaceMessage (ghostty)
try surface.handleMessage(msg);
^
/home/jeff/dev/ghostty/src/App.zig:252:62: 0x31e3005 in drainMailbox (ghostty)
.surface_message => |msg| try self.surfaceMessage(msg.surface, msg.message),
^
/home/jeff/dev/ghostty/src/App.zig:138:26: 0x31e378e in tick (ghostty)
try self.drainMailbox(rt_app);
^
/home/jeff/dev/ghostty/src/apprt/gtk/App.zig:1279:31: 0x31e3e42 in run (ghostty)
try self.core_app.tick(self);
^
/home/jeff/dev/ghostty/src/main_ghostty.zig:112:24: 0x31e52f4 in main (ghostty)
try app_runtime.run();
^
/nix/store/h6lccra69nr23676qq32h9qn1fba24v1-zig-0.13.0/lib/std/start.zig:524:37: 0x31e5e0e in main (ghostty)
const result = root.main() catch |err| {
^
???:?:?: 0x7ffff682a1fb in ??? (libc.so.6)
Unwind information for `libc.so.6:0x7ffff682a1fb` was not available, trace may be incomplete
fish: Job 2, './zig-out/bin/ghostty --config-…' terminated by signal SIGABRT (Abort)
```
As of version 1.0.1 (macOS build) when running the toggle visibility
action a window with tabs is made into multiple windows.
This PR ensures terminal tabs are reconstructed and correctly placed
into its parent window.
# Demo
https://github.com/user-attachments/assets/44f14bca-15a1-4717-ba0a-44f0767feec3
FYI: I will create another PR to ensure the right tab is focused after
the main window is restored.
Solves #4329
Two major changes:
1. Hiding uses `NSApp.hide` which hides all windows, preserves tabs, and
yields focus to the next app.
2. Unhiding manually tracks and brings forward only the windows we hid.
Proper focus should be retained.