mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-17 09:16:11 +03:00
Merge pull request #1266 from mitchellh/shader-animation
custom shader animation can be set to "always" to always remain active
This commit is contained in:
@ -511,6 +511,7 @@ pub fn init(
|
|||||||
// Create the renderer thread
|
// Create the renderer thread
|
||||||
var render_thread = try renderer.Thread.init(
|
var render_thread = try renderer.Thread.init(
|
||||||
alloc,
|
alloc,
|
||||||
|
config,
|
||||||
rt_surface,
|
rt_surface,
|
||||||
&self.renderer,
|
&self.renderer,
|
||||||
&self.renderer_state,
|
&self.renderer_state,
|
||||||
@ -831,23 +832,14 @@ fn changeConfig(self: *Surface, config: *const configpkg.Config) !void {
|
|||||||
|
|
||||||
// We need to store our configs in a heap-allocated pointer so that
|
// We need to store our configs in a heap-allocated pointer so that
|
||||||
// our messages aren't huge.
|
// our messages aren't huge.
|
||||||
var renderer_config_ptr = try self.alloc.create(Renderer.DerivedConfig);
|
var renderer_message = try renderer.Message.initChangeConfig(self.alloc, config);
|
||||||
errdefer self.alloc.destroy(renderer_config_ptr);
|
errdefer renderer_message.deinit();
|
||||||
var termio_config_ptr = try self.alloc.create(termio.Impl.DerivedConfig);
|
var termio_config_ptr = try self.alloc.create(termio.Impl.DerivedConfig);
|
||||||
errdefer self.alloc.destroy(termio_config_ptr);
|
errdefer self.alloc.destroy(termio_config_ptr);
|
||||||
|
|
||||||
// Update our derived configurations for the renderer and termio,
|
|
||||||
// then send them a message to update.
|
|
||||||
renderer_config_ptr.* = try Renderer.DerivedConfig.init(self.alloc, config);
|
|
||||||
errdefer renderer_config_ptr.deinit();
|
|
||||||
termio_config_ptr.* = try termio.Impl.DerivedConfig.init(self.alloc, config);
|
termio_config_ptr.* = try termio.Impl.DerivedConfig.init(self.alloc, config);
|
||||||
errdefer termio_config_ptr.deinit();
|
errdefer termio_config_ptr.deinit();
|
||||||
_ = self.renderer_thread.mailbox.push(.{
|
|
||||||
.change_config = .{
|
_ = self.renderer_thread.mailbox.push(renderer_message, .{ .forever = {} });
|
||||||
.alloc = self.alloc,
|
|
||||||
.ptr = renderer_config_ptr,
|
|
||||||
},
|
|
||||||
}, .{ .forever = {} });
|
|
||||||
_ = self.io_thread.mailbox.push(.{
|
_ = self.io_thread.mailbox.push(.{
|
||||||
.change_config = .{
|
.change_config = .{
|
||||||
.alloc = self.alloc,
|
.alloc = self.alloc,
|
||||||
|
@ -10,6 +10,7 @@ pub const url = @import("config/url.zig");
|
|||||||
pub const CopyOnSelect = Config.CopyOnSelect;
|
pub const CopyOnSelect = Config.CopyOnSelect;
|
||||||
pub const Keybinds = Config.Keybinds;
|
pub const Keybinds = Config.Keybinds;
|
||||||
pub const MouseShiftCapture = Config.MouseShiftCapture;
|
pub const MouseShiftCapture = Config.MouseShiftCapture;
|
||||||
|
pub const CustomShaderAnimation = Config.CustomShaderAnimation;
|
||||||
pub const NonNativeFullscreen = Config.NonNativeFullscreen;
|
pub const NonNativeFullscreen = Config.NonNativeFullscreen;
|
||||||
pub const OptionAsAlt = Config.OptionAsAlt;
|
pub const OptionAsAlt = Config.OptionAsAlt;
|
||||||
pub const ShellIntegrationFeatures = Config.ShellIntegrationFeatures;
|
pub const ShellIntegrationFeatures = Config.ShellIntegrationFeatures;
|
||||||
|
@ -815,15 +815,21 @@ keybind: Keybinds = .{},
|
|||||||
/// If true (default), the focused terminal surface will run an animation
|
/// If true (default), the focused terminal surface will run an animation
|
||||||
/// loop when custom shaders are used. This uses slightly more CPU (generally
|
/// loop when custom shaders are used. This uses slightly more CPU (generally
|
||||||
/// less than 10%) but allows the shader to animate. This only runs if there
|
/// less than 10%) but allows the shader to animate. This only runs if there
|
||||||
/// are custom shaders.
|
/// are custom shaders and the terminal is focused.
|
||||||
///
|
///
|
||||||
/// If this is set to false, the terminal and custom shader will only render
|
/// If this is set to false, the terminal and custom shader will only render
|
||||||
/// when the terminal is updated. This is more efficient but the shader will
|
/// when the terminal is updated. This is more efficient but the shader will
|
||||||
/// not animate.
|
/// not animate.
|
||||||
///
|
///
|
||||||
|
/// This can also be set to "always", which will always run the animation
|
||||||
|
/// loop regardless of whether the terminal is focused or not. The animation
|
||||||
|
/// loop will still only run when custom shaders are used. Note that this
|
||||||
|
/// will use more CPU per terminal surface and can become quite expensive
|
||||||
|
/// depending on the shader and your terminal usage.
|
||||||
|
///
|
||||||
/// This value can be changed at runtime and will affect all currently
|
/// This value can be changed at runtime and will affect all currently
|
||||||
/// open terminals.
|
/// open terminals.
|
||||||
@"custom-shader-animation": bool = true,
|
@"custom-shader-animation": CustomShaderAnimation = .true,
|
||||||
|
|
||||||
/// If anything other than false, fullscreen mode on macOS will not use the
|
/// If anything other than false, fullscreen mode on macOS will not use the
|
||||||
/// native fullscreen, but make the window fullscreen without animations and
|
/// native fullscreen, but make the window fullscreen without animations and
|
||||||
@ -2079,6 +2085,15 @@ fn equalField(comptime T: type, old: T, new: T) bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Valid values for custom-shader-animation
|
||||||
|
/// c_int because it needs to be extern compatible
|
||||||
|
/// If this is changed, you must also update ghostty.h
|
||||||
|
pub const CustomShaderAnimation = enum(c_int) {
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
always,
|
||||||
|
};
|
||||||
|
|
||||||
/// Valid values for macos-non-native-fullscreen
|
/// Valid values for macos-non-native-fullscreen
|
||||||
/// c_int because it needs to be extern compatible
|
/// c_int because it needs to be extern compatible
|
||||||
/// If this is changed, you must also update ghostty.h
|
/// If this is changed, you must also update ghostty.h
|
||||||
|
@ -155,7 +155,6 @@ pub const DerivedConfig = struct {
|
|||||||
invert_selection_fg_bg: bool,
|
invert_selection_fg_bg: bool,
|
||||||
min_contrast: f32,
|
min_contrast: f32,
|
||||||
custom_shaders: std.ArrayListUnmanaged([:0]const u8),
|
custom_shaders: std.ArrayListUnmanaged([:0]const u8),
|
||||||
custom_shader_animation: bool,
|
|
||||||
links: link.Set,
|
links: link.Set,
|
||||||
|
|
||||||
pub fn init(
|
pub fn init(
|
||||||
@ -218,7 +217,6 @@ pub const DerivedConfig = struct {
|
|||||||
null,
|
null,
|
||||||
|
|
||||||
.custom_shaders = custom_shaders,
|
.custom_shaders = custom_shaders,
|
||||||
.custom_shader_animation = config.@"custom-shader-animation",
|
|
||||||
.links = links,
|
.links = links,
|
||||||
|
|
||||||
.arena = arena,
|
.arena = arena,
|
||||||
@ -488,8 +486,7 @@ pub fn threadExit(self: *const Metal) void {
|
|||||||
/// True if our renderer has animations so that a higher frequency
|
/// True if our renderer has animations so that a higher frequency
|
||||||
/// timer is used.
|
/// timer is used.
|
||||||
pub fn hasAnimations(self: *const Metal) bool {
|
pub fn hasAnimations(self: *const Metal) bool {
|
||||||
return self.custom_shader_state != null and
|
return self.custom_shader_state != null;
|
||||||
self.config.custom_shader_animation;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the grid size for a given screen size. This is safe to call
|
/// Returns the grid size for a given screen size. This is safe to call
|
||||||
|
@ -252,7 +252,6 @@ pub const DerivedConfig = struct {
|
|||||||
invert_selection_fg_bg: bool,
|
invert_selection_fg_bg: bool,
|
||||||
min_contrast: f32,
|
min_contrast: f32,
|
||||||
custom_shaders: std.ArrayListUnmanaged([:0]const u8),
|
custom_shaders: std.ArrayListUnmanaged([:0]const u8),
|
||||||
custom_shader_animation: bool,
|
|
||||||
links: link.Set,
|
links: link.Set,
|
||||||
|
|
||||||
pub fn init(
|
pub fn init(
|
||||||
@ -315,7 +314,6 @@ pub const DerivedConfig = struct {
|
|||||||
null,
|
null,
|
||||||
|
|
||||||
.custom_shaders = custom_shaders,
|
.custom_shaders = custom_shaders,
|
||||||
.custom_shader_animation = config.@"custom-shader-animation",
|
|
||||||
.links = links,
|
.links = links,
|
||||||
|
|
||||||
.arena = arena,
|
.arena = arena,
|
||||||
@ -558,7 +556,7 @@ pub fn threadExit(self: *const OpenGL) void {
|
|||||||
/// timer is used.
|
/// timer is used.
|
||||||
pub fn hasAnimations(self: *const OpenGL) bool {
|
pub fn hasAnimations(self: *const OpenGL) bool {
|
||||||
const state = self.gl_state orelse return false;
|
const state = self.gl_state orelse return false;
|
||||||
return state.custom != null and self.config.custom_shader_animation;
|
return state.custom != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Callback when the focus changes for the terminal this is rendering.
|
/// Callback when the focus changes for the terminal this is rendering.
|
||||||
|
@ -7,6 +7,7 @@ const builtin = @import("builtin");
|
|||||||
const xev = @import("xev");
|
const xev = @import("xev");
|
||||||
const renderer = @import("../renderer.zig");
|
const renderer = @import("../renderer.zig");
|
||||||
const apprt = @import("../apprt.zig");
|
const apprt = @import("../apprt.zig");
|
||||||
|
const configpkg = @import("../config.zig");
|
||||||
const BlockingQueue = @import("../blocking_queue.zig").BlockingQueue;
|
const BlockingQueue = @import("../blocking_queue.zig").BlockingQueue;
|
||||||
const tracy = @import("tracy");
|
const tracy = @import("tracy");
|
||||||
const trace = tracy.trace;
|
const trace = tracy.trace;
|
||||||
@ -72,6 +73,9 @@ mailbox: *Mailbox,
|
|||||||
/// Mailbox to send messages to the app thread
|
/// Mailbox to send messages to the app thread
|
||||||
app_mailbox: App.Mailbox,
|
app_mailbox: App.Mailbox,
|
||||||
|
|
||||||
|
/// Configuration we need derived from the main config.
|
||||||
|
config: DerivedConfig,
|
||||||
|
|
||||||
flags: packed struct {
|
flags: packed struct {
|
||||||
/// This is true when a blinking cursor should be visible and false
|
/// This is true when a blinking cursor should be visible and false
|
||||||
/// when it should not be visible. This is toggled on a timer by the
|
/// when it should not be visible. This is toggled on a timer by the
|
||||||
@ -82,11 +86,22 @@ flags: packed struct {
|
|||||||
has_inspector: bool = false,
|
has_inspector: bool = false,
|
||||||
} = .{},
|
} = .{},
|
||||||
|
|
||||||
|
pub const DerivedConfig = struct {
|
||||||
|
custom_shader_animation: configpkg.CustomShaderAnimation,
|
||||||
|
|
||||||
|
pub fn init(config: *const configpkg.Config) DerivedConfig {
|
||||||
|
return .{
|
||||||
|
.custom_shader_animation = config.@"custom-shader-animation",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// Initialize the thread. This does not START the thread. This only sets
|
/// Initialize the thread. This does not START the thread. This only sets
|
||||||
/// up all the internal state necessary prior to starting the thread. It
|
/// up all the internal state necessary prior to starting the thread. It
|
||||||
/// is up to the caller to start the thread with the threadMain entrypoint.
|
/// is up to the caller to start the thread with the threadMain entrypoint.
|
||||||
pub fn init(
|
pub fn init(
|
||||||
alloc: Allocator,
|
alloc: Allocator,
|
||||||
|
config: *const configpkg.Config,
|
||||||
surface: *apprt.Surface,
|
surface: *apprt.Surface,
|
||||||
renderer_impl: *renderer.Renderer,
|
renderer_impl: *renderer.Renderer,
|
||||||
state: *renderer.State,
|
state: *renderer.State,
|
||||||
@ -122,6 +137,7 @@ pub fn init(
|
|||||||
|
|
||||||
return Thread{
|
return Thread{
|
||||||
.alloc = alloc,
|
.alloc = alloc,
|
||||||
|
.config = DerivedConfig.init(config),
|
||||||
.loop = loop,
|
.loop = loop,
|
||||||
.wakeup = wakeup_h,
|
.wakeup = wakeup_h,
|
||||||
.stop = stop_h,
|
.stop = stop_h,
|
||||||
@ -199,6 +215,7 @@ fn startDrawTimer(self: *Thread) void {
|
|||||||
// If our renderer doesn't suppoort animations then we never run this.
|
// If our renderer doesn't suppoort animations then we never run this.
|
||||||
if (!@hasDecl(renderer.Renderer, "hasAnimations")) return;
|
if (!@hasDecl(renderer.Renderer, "hasAnimations")) return;
|
||||||
if (!self.renderer.hasAnimations()) return;
|
if (!self.renderer.hasAnimations()) return;
|
||||||
|
if (self.config.custom_shader_animation == .false) return;
|
||||||
|
|
||||||
// Set our active state so it knows we're running. We set this before
|
// 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.
|
// even checking the active state in case we have a pending shutdown.
|
||||||
@ -236,8 +253,10 @@ fn drainMailbox(self: *Thread) !void {
|
|||||||
try self.renderer.setFocus(v);
|
try self.renderer.setFocus(v);
|
||||||
|
|
||||||
if (!v) {
|
if (!v) {
|
||||||
|
if (self.config.custom_shader_animation != .always) {
|
||||||
// Stop the draw timer
|
// Stop the draw timer
|
||||||
self.stopDrawTimer();
|
self.stopDrawTimer();
|
||||||
|
}
|
||||||
|
|
||||||
// If we're not focused, then we stop the cursor blink
|
// If we're not focused, then we stop the cursor blink
|
||||||
if (self.cursor_c.state() == .active and
|
if (self.cursor_c.state() == .active and
|
||||||
@ -308,8 +327,9 @@ fn drainMailbox(self: *Thread) !void {
|
|||||||
},
|
},
|
||||||
|
|
||||||
.change_config => |config| {
|
.change_config => |config| {
|
||||||
defer config.alloc.destroy(config.ptr);
|
defer message.deinit();
|
||||||
try self.renderer.changeConfig(config.ptr);
|
try self.changeConfig(config.thread);
|
||||||
|
try self.renderer.changeConfig(config.impl);
|
||||||
|
|
||||||
// Stop and start the draw timer to capture the new
|
// Stop and start the draw timer to capture the new
|
||||||
// hasAnimations value.
|
// hasAnimations value.
|
||||||
@ -322,6 +342,10 @@ fn drainMailbox(self: *Thread) !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn changeConfig(self: *Thread, config: *const DerivedConfig) !void {
|
||||||
|
self.config = config.*;
|
||||||
|
}
|
||||||
|
|
||||||
fn wakeupCallback(
|
fn wakeupCallback(
|
||||||
self_: ?*Thread,
|
self_: ?*Thread,
|
||||||
_: *xev.Loop,
|
_: *xev.Loop,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
const configpkg = @import("../config.zig");
|
||||||
const font = @import("../font/main.zig");
|
const font = @import("../font/main.zig");
|
||||||
const renderer = @import("../renderer.zig");
|
const renderer = @import("../renderer.zig");
|
||||||
const terminal = @import("../terminal/main.zig");
|
const terminal = @import("../terminal/main.zig");
|
||||||
@ -45,9 +46,42 @@ pub const Message = union(enum) {
|
|||||||
/// The derived configuration to update the renderer with.
|
/// The derived configuration to update the renderer with.
|
||||||
change_config: struct {
|
change_config: struct {
|
||||||
alloc: Allocator,
|
alloc: Allocator,
|
||||||
ptr: *renderer.Renderer.DerivedConfig,
|
thread: *renderer.Thread.DerivedConfig,
|
||||||
|
impl: *renderer.Renderer.DerivedConfig,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Activate or deactivate the inspector.
|
/// Activate or deactivate the inspector.
|
||||||
inspector: bool,
|
inspector: bool,
|
||||||
|
|
||||||
|
/// Initialize a change_config message.
|
||||||
|
pub fn initChangeConfig(alloc: Allocator, config: *const configpkg.Config) !Message {
|
||||||
|
const thread_ptr = try alloc.create(renderer.Thread.DerivedConfig);
|
||||||
|
errdefer alloc.destroy(thread_ptr);
|
||||||
|
const config_ptr = try alloc.create(renderer.Renderer.DerivedConfig);
|
||||||
|
errdefer alloc.destroy(config_ptr);
|
||||||
|
|
||||||
|
thread_ptr.* = renderer.Thread.DerivedConfig.init(config);
|
||||||
|
config_ptr.* = try renderer.Renderer.DerivedConfig.init(alloc, config);
|
||||||
|
errdefer config_ptr.deinit();
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.change_config = .{
|
||||||
|
.alloc = alloc,
|
||||||
|
.thread = thread_ptr,
|
||||||
|
.impl = config_ptr,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *const Message) void {
|
||||||
|
switch (self.*) {
|
||||||
|
.change_config => |v| {
|
||||||
|
v.impl.deinit();
|
||||||
|
v.alloc.destroy(v.impl);
|
||||||
|
v.alloc.destroy(v.thread);
|
||||||
|
},
|
||||||
|
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user