summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMitchell Hashimoto <mitchell.hashimoto@gmail.com>2024-01-09 09:21:15 -0800
committerMitchell Hashimoto <mitchell.hashimoto@gmail.com>2024-01-09 09:21:15 -0800
commit96d33fef20dbe2742ae718beccd6cc42719016ba (patch)
tree53a91778fb3f92502658a67512704ccac3c1cad2 /src
parent92697bad1240ac647b2bc7f471f87fb7f65f7305 (diff)
custom shader animation can be set to "always" to always remain active
Fixes #1225 The `custom-shader-animation` configuration can now be set to "always" which keeps animation active even if the terminal is unfocused.
Diffstat (limited to 'src')
-rw-r--r--src/Surface.zig18
-rw-r--r--src/config.zig1
-rw-r--r--src/config/Config.zig19
-rw-r--r--src/renderer/Metal.zig5
-rw-r--r--src/renderer/OpenGL.zig4
-rw-r--r--src/renderer/Thread.zig32
-rw-r--r--src/renderer/message.zig36
7 files changed, 88 insertions, 27 deletions
diff --git a/src/Surface.zig b/src/Surface.zig
index aa75bb0e6..a25b2fe74 100644
--- a/src/Surface.zig
+++ b/src/Surface.zig
@@ -511,6 +511,7 @@ pub fn init(
// Create the renderer thread
var render_thread = try renderer.Thread.init(
alloc,
+ config,
rt_surface,
&self.renderer,
&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
// our messages aren't huge.
- var renderer_config_ptr = try self.alloc.create(Renderer.DerivedConfig);
- errdefer self.alloc.destroy(renderer_config_ptr);
+ var renderer_message = try renderer.Message.initChangeConfig(self.alloc, config);
+ errdefer renderer_message.deinit();
var termio_config_ptr = try self.alloc.create(termio.Impl.DerivedConfig);
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);
errdefer termio_config_ptr.deinit();
- _ = self.renderer_thread.mailbox.push(.{
- .change_config = .{
- .alloc = self.alloc,
- .ptr = renderer_config_ptr,
- },
- }, .{ .forever = {} });
+
+ _ = self.renderer_thread.mailbox.push(renderer_message, .{ .forever = {} });
_ = self.io_thread.mailbox.push(.{
.change_config = .{
.alloc = self.alloc,
diff --git a/src/config.zig b/src/config.zig
index 398f5fa92..78e033361 100644
--- a/src/config.zig
+++ b/src/config.zig
@@ -10,6 +10,7 @@ pub const url = @import("config/url.zig");
pub const CopyOnSelect = Config.CopyOnSelect;
pub const Keybinds = Config.Keybinds;
pub const MouseShiftCapture = Config.MouseShiftCapture;
+pub const CustomShaderAnimation = Config.CustomShaderAnimation;
pub const NonNativeFullscreen = Config.NonNativeFullscreen;
pub const OptionAsAlt = Config.OptionAsAlt;
pub const ShellIntegrationFeatures = Config.ShellIntegrationFeatures;
diff --git a/src/config/Config.zig b/src/config/Config.zig
index 9881580b9..3f093865f 100644
--- a/src/config/Config.zig
+++ b/src/config/Config.zig
@@ -815,15 +815,21 @@ keybind: Keybinds = .{},
/// If true (default), the focused terminal surface will run an animation
/// 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
-/// 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
/// when the terminal is updated. This is more efficient but the shader will
/// 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
/// 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
/// 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
/// c_int because it needs to be extern compatible
/// If this is changed, you must also update ghostty.h
diff --git a/src/renderer/Metal.zig b/src/renderer/Metal.zig
index 9c17702e0..9e9fbaea4 100644
--- a/src/renderer/Metal.zig
+++ b/src/renderer/Metal.zig
@@ -155,7 +155,6 @@ pub const DerivedConfig = struct {
invert_selection_fg_bg: bool,
min_contrast: f32,
custom_shaders: std.ArrayListUnmanaged([:0]const u8),
- custom_shader_animation: bool,
links: link.Set,
pub fn init(
@@ -218,7 +217,6 @@ pub const DerivedConfig = struct {
null,
.custom_shaders = custom_shaders,
- .custom_shader_animation = config.@"custom-shader-animation",
.links = links,
.arena = arena,
@@ -488,8 +486,7 @@ pub fn threadExit(self: *const Metal) void {
/// True if our renderer has animations so that a higher frequency
/// timer is used.
pub fn hasAnimations(self: *const Metal) bool {
- return self.custom_shader_state != null and
- self.config.custom_shader_animation;
+ return self.custom_shader_state != null;
}
/// Returns the grid size for a given screen size. This is safe to call
diff --git a/src/renderer/OpenGL.zig b/src/renderer/OpenGL.zig
index 66fd966ee..af6910c0a 100644
--- a/src/renderer/OpenGL.zig
+++ b/src/renderer/OpenGL.zig
@@ -252,7 +252,6 @@ pub const DerivedConfig = struct {
invert_selection_fg_bg: bool,
min_contrast: f32,
custom_shaders: std.ArrayListUnmanaged([:0]const u8),
- custom_shader_animation: bool,
links: link.Set,
pub fn init(
@@ -315,7 +314,6 @@ pub const DerivedConfig = struct {
null,
.custom_shaders = custom_shaders,
- .custom_shader_animation = config.@"custom-shader-animation",
.links = links,
.arena = arena,
@@ -558,7 +556,7 @@ pub fn threadExit(self: *const OpenGL) void {
/// timer is used.
pub fn hasAnimations(self: *const OpenGL) bool {
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.
diff --git a/src/renderer/Thread.zig b/src/renderer/Thread.zig
index 156d6cd6d..178dca14e 100644
--- a/src/renderer/Thread.zig
+++ b/src/renderer/Thread.zig
@@ -7,6 +7,7 @@ const builtin = @import("builtin");
const xev = @import("xev");
const renderer = @import("../renderer.zig");
const apprt = @import("../apprt.zig");
+const configpkg = @import("../config.zig");
const BlockingQueue = @import("../blocking_queue.zig").BlockingQueue;
const tracy = @import("tracy");
const trace = tracy.trace;
@@ -72,6 +73,9 @@ mailbox: *Mailbox,
/// Mailbox to send messages to the app thread
app_mailbox: App.Mailbox,
+/// Configuration we need derived from the main config.
+config: DerivedConfig,
+
flags: packed struct {
/// 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
@@ -82,11 +86,22 @@ flags: packed struct {
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
/// 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.
pub fn init(
alloc: Allocator,
+ config: *const configpkg.Config,
surface: *apprt.Surface,
renderer_impl: *renderer.Renderer,
state: *renderer.State,
@@ -122,6 +137,7 @@ pub fn init(
return Thread{
.alloc = alloc,
+ .config = DerivedConfig.init(config),
.loop = loop,
.wakeup = wakeup_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 (!@hasDecl(renderer.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
// 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);
if (!v) {
- // Stop the draw timer
- self.stopDrawTimer();
+ if (self.config.custom_shader_animation != .always) {
+ // Stop the draw timer
+ self.stopDrawTimer();
+ }
// If we're not focused, then we stop the cursor blink
if (self.cursor_c.state() == .active and
@@ -308,8 +327,9 @@ fn drainMailbox(self: *Thread) !void {
},
.change_config => |config| {
- defer config.alloc.destroy(config.ptr);
- try self.renderer.changeConfig(config.ptr);
+ defer message.deinit();
+ try self.changeConfig(config.thread);
+ try self.renderer.changeConfig(config.impl);
// Stop and start the draw timer to capture the new
// hasAnimations value.
@@ -322,6 +342,10 @@ fn drainMailbox(self: *Thread) !void {
}
}
+fn changeConfig(self: *Thread, config: *const DerivedConfig) !void {
+ self.config = config.*;
+}
+
fn wakeupCallback(
self_: ?*Thread,
_: *xev.Loop,
diff --git a/src/renderer/message.zig b/src/renderer/message.zig
index 3278a2c1c..73faa0ad7 100644
--- a/src/renderer/message.zig
+++ b/src/renderer/message.zig
@@ -1,6 +1,7 @@
const std = @import("std");
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
+const configpkg = @import("../config.zig");
const font = @import("../font/main.zig");
const renderer = @import("../renderer.zig");
const terminal = @import("../terminal/main.zig");
@@ -45,9 +46,42 @@ pub const Message = union(enum) {
/// The derived configuration to update the renderer with.
change_config: struct {
alloc: Allocator,
- ptr: *renderer.Renderer.DerivedConfig,
+ thread: *renderer.Thread.DerivedConfig,
+ impl: *renderer.Renderer.DerivedConfig,
},
/// Activate or deactivate the inspector.
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 => {},
+ }
+ }
};