mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-14 11:35:48 +00:00
Merge remote-tracking branch 'upstream/main' into grapheme-width-changes
This commit is contained in:
@@ -120,14 +120,16 @@ struct TerminalCommandPaletteView: View {
|
||||
/// Custom commands from the command-palette-entry configuration.
|
||||
private var terminalOptions: [CommandOption] {
|
||||
guard let appDelegate = NSApp.delegate as? AppDelegate else { return [] }
|
||||
return appDelegate.ghostty.config.commandPaletteEntries.map { c in
|
||||
CommandOption(
|
||||
title: c.title,
|
||||
description: c.description
|
||||
) {
|
||||
onAction(c.action)
|
||||
return appDelegate.ghostty.config.commandPaletteEntries
|
||||
.filter(\.isSupported)
|
||||
.map { c in
|
||||
CommandOption(
|
||||
title: c.title,
|
||||
description: c.description
|
||||
) {
|
||||
onAction(c.action)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Commands for jumping to other terminal surfaces.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="24093.7" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="24506" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="24093.7"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="24506"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
@@ -17,7 +17,7 @@
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="0.0" y="0.0" width="800" height="600"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="3008" height="1661"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1512" height="949"/>
|
||||
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="800" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="24093.7" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="24506" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="24093.7"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="24506"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
@@ -17,7 +17,7 @@
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="0.0" y="0.0" width="800" height="600"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="3008" height="1661"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1512" height="949"/>
|
||||
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="800" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
|
||||
@@ -269,16 +269,10 @@ extension Ghostty {
|
||||
// Builds up the "input.ScrollMods" bitmask
|
||||
var mods: Int32 = 0
|
||||
|
||||
var x = event.scrollingDeltaX
|
||||
var y = event.scrollingDeltaY
|
||||
let x = event.scrollingDeltaX
|
||||
let y = event.scrollingDeltaY
|
||||
if event.hasPreciseScrollingDeltas {
|
||||
mods = 1
|
||||
|
||||
// We do a 2x speed multiplier. This is subjective, it "feels" better to me.
|
||||
x *= 2;
|
||||
y *= 2;
|
||||
|
||||
// TODO(mitchellh): do we have to scale the x/y here by window scale factor?
|
||||
}
|
||||
|
||||
// Determine our momentum value
|
||||
|
||||
@@ -1133,15 +1133,18 @@ pub const Inspector = struct {
|
||||
yoff: f64,
|
||||
mods: input.ScrollMods,
|
||||
) void {
|
||||
_ = mods;
|
||||
|
||||
self.queueRender();
|
||||
cimgui.c.ImGui_SetCurrentContext(self.ig_ctx);
|
||||
const io: *cimgui.c.ImGuiIO = cimgui.c.ImGui_GetIO();
|
||||
|
||||
// For precision scrolling (trackpads), the values are in pixels which
|
||||
// scroll way too fast. Scale them down to approximate discrete wheel
|
||||
// notches. imgui expects 1.0 to scroll ~5 lines of text.
|
||||
const scale: f64 = if (mods.precision) 0.1 else 1.0;
|
||||
cimgui.c.ImGuiIO_AddMouseWheelEvent(
|
||||
io,
|
||||
@floatCast(xoff),
|
||||
@floatCast(yoff),
|
||||
@floatCast(xoff * scale),
|
||||
@floatCast(yoff * scale),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1202,10 +1205,11 @@ pub const Inspector = struct {
|
||||
// Determine our delta time
|
||||
const now = try std.time.Instant.now();
|
||||
io.DeltaTime = if (self.instant) |prev| delta: {
|
||||
const since_ns = now.since(prev);
|
||||
const since_s: f32 = @floatFromInt(since_ns / std.time.ns_per_s);
|
||||
const since_ns: f64 = @floatFromInt(now.since(prev));
|
||||
const ns_per_s: f64 = @floatFromInt(std.time.ns_per_s);
|
||||
const since_s: f32 = @floatCast(since_ns / ns_per_s);
|
||||
break :delta @max(0.00001, since_s);
|
||||
} else (1 / 60);
|
||||
} else (1.0 / 60.0);
|
||||
self.instant = now;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -131,21 +131,17 @@ pub const ImguiWidget = extern struct {
|
||||
|
||||
/// Initialize the frame. Expects that the context is already current.
|
||||
fn newFrame(self: *Self) void {
|
||||
// If we can't determine the time since the last frame we default to
|
||||
// 1/60th of a second.
|
||||
const default_delta_time = 1 / 60;
|
||||
|
||||
const priv = self.private();
|
||||
|
||||
const io: *cimgui.c.ImGuiIO = cimgui.c.ImGui_GetIO();
|
||||
|
||||
// Determine our delta time
|
||||
const now = std.time.Instant.now() catch unreachable;
|
||||
io.DeltaTime = if (priv.instant) |prev| delta: {
|
||||
const since_ns = now.since(prev);
|
||||
const since_s: f32 = @floatFromInt(since_ns / std.time.ns_per_s);
|
||||
const since_ns: f64 = @floatFromInt(now.since(prev));
|
||||
const ns_per_s: f64 = @floatFromInt(std.time.ns_per_s);
|
||||
const since_s: f32 = @floatCast(since_ns / ns_per_s);
|
||||
break :delta @max(0.00001, since_s);
|
||||
} else default_delta_time;
|
||||
} else (1.0 / 60.0);
|
||||
|
||||
priv.instant = now;
|
||||
}
|
||||
|
||||
@@ -583,10 +583,12 @@ fn renderModesWindow(self: *Inspector) void {
|
||||
const tag: terminal.modes.ModeTag = @bitCast(@as(terminal.modes.ModeTag.Backing, field.value));
|
||||
|
||||
cimgui.c.ImGui_TableNextRow();
|
||||
cimgui.c.ImGui_PushIDInt(@intCast(field.value));
|
||||
defer cimgui.c.ImGui_PopID();
|
||||
{
|
||||
_ = cimgui.c.ImGui_TableSetColumnIndex(0);
|
||||
var value: bool = t.modes.get(@field(terminal.Mode, field.name));
|
||||
_ = cimgui.c.ImGui_Checkbox("", &value);
|
||||
_ = cimgui.c.ImGui_Checkbox("##checkbox", &value);
|
||||
}
|
||||
{
|
||||
_ = cimgui.c.ImGui_TableSetColumnIndex(1);
|
||||
|
||||
@@ -254,7 +254,7 @@ fn threadMain_(self: *Thread) !void {
|
||||
);
|
||||
|
||||
// Start the draw timer
|
||||
self.startDrawTimer();
|
||||
self.syncDrawTimer();
|
||||
|
||||
// Run
|
||||
log.debug("starting renderer thread", .{});
|
||||
@@ -292,11 +292,33 @@ fn setQosClass(self: *const Thread) void {
|
||||
}
|
||||
}
|
||||
|
||||
fn startDrawTimer(self: *Thread) void {
|
||||
// If our renderer doesn't support animations then we never run this.
|
||||
if (!@hasDecl(rendererpkg.Renderer, "hasAnimations")) return;
|
||||
if (!self.renderer.hasAnimations()) return;
|
||||
if (self.config.custom_shader_animation == .false) return;
|
||||
fn syncDrawTimer(self: *Thread) void {
|
||||
skip: {
|
||||
// If we have an inspector, we always run the draw timer.
|
||||
if (self.flags.has_inspector) break :skip;
|
||||
|
||||
// If our renderer supports animations and has them, then we
|
||||
// always have a draw timer.
|
||||
if (@hasDecl(rendererpkg.Renderer, "hasAnimations") and
|
||||
self.renderer.hasAnimations())
|
||||
{
|
||||
break :skip;
|
||||
}
|
||||
|
||||
// If our config says to always animate, we do so.
|
||||
switch (self.config.custom_shader_animation) {
|
||||
// Always animate
|
||||
.always => break :skip,
|
||||
// Only when focused
|
||||
.true => if (self.flags.focused) break :skip,
|
||||
// Never animate
|
||||
.false => {},
|
||||
}
|
||||
|
||||
// We're skipping the draw timer. Stop it on the next iteration.
|
||||
self.draw_active = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Set our active state so it knows we're running. We set this before
|
||||
// even checking the active state in case we have a pending shutdown.
|
||||
@@ -316,11 +338,6 @@ fn startDrawTimer(self: *Thread) void {
|
||||
);
|
||||
}
|
||||
|
||||
fn stopDrawTimer(self: *Thread) void {
|
||||
// This will stop the draw on the next iteration.
|
||||
self.draw_active = false;
|
||||
}
|
||||
|
||||
/// Drain the mailbox.
|
||||
fn drainMailbox(self: *Thread) !void {
|
||||
// There's probably a more elegant way to do this...
|
||||
@@ -377,12 +394,10 @@ fn drainMailbox(self: *Thread) !void {
|
||||
// Set it on the renderer
|
||||
try self.renderer.setFocus(v);
|
||||
|
||||
if (!v) {
|
||||
if (self.config.custom_shader_animation != .always) {
|
||||
// Stop the draw timer
|
||||
self.stopDrawTimer();
|
||||
}
|
||||
// We always resync our draw timer (may disable it)
|
||||
self.syncDrawTimer();
|
||||
|
||||
if (!v) {
|
||||
// If we're not focused, then we stop the cursor blink
|
||||
if (self.cursor_c.state() == .active and
|
||||
self.cursor_c_cancel.state() == .dead)
|
||||
@@ -397,9 +412,6 @@ fn drainMailbox(self: *Thread) !void {
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Start the draw timer
|
||||
self.startDrawTimer();
|
||||
|
||||
// If we're focused, we immediately show the cursor again
|
||||
// and then restart the timer.
|
||||
if (self.cursor_c.state() != .active) {
|
||||
@@ -446,8 +458,7 @@ fn drainMailbox(self: *Thread) !void {
|
||||
|
||||
// Stop and start the draw timer to capture the new
|
||||
// hasAnimations value.
|
||||
self.stopDrawTimer();
|
||||
self.startDrawTimer();
|
||||
self.syncDrawTimer();
|
||||
},
|
||||
|
||||
.search_viewport_matches => |v| {
|
||||
@@ -466,7 +477,12 @@ fn drainMailbox(self: *Thread) !void {
|
||||
self.renderer.search_matches_dirty = true;
|
||||
},
|
||||
|
||||
.inspector => |v| self.flags.has_inspector = v,
|
||||
.inspector => |v| {
|
||||
self.flags.has_inspector = v;
|
||||
// Reset our draw timer state, which might change due
|
||||
// to the inspector change.
|
||||
self.syncDrawTimer();
|
||||
},
|
||||
|
||||
.macos_display_id => |v| {
|
||||
if (@hasDecl(rendererpkg.Renderer, "setMacOSDisplayID")) {
|
||||
|
||||
Reference in New Issue
Block a user