From 56a4f570599688a690a2ee090f1af14292293d7d Mon Sep 17 00:00:00 2001 From: Adam Wolf Date: Thu, 27 Feb 2025 23:19:45 -0600 Subject: [PATCH] apprt/gtk: handle syncing background opacity at the opengl level --- src/Surface.zig | 16 ++++++++++++++++ src/apprt/gtk/App.zig | 14 ++++++++++---- src/apprt/gtk/Window.zig | 13 ++++++------- src/renderer/OpenGL.zig | 11 +++++++++++ src/renderer/Thread.zig | 5 +++++ src/renderer/message.zig | 3 +++ 6 files changed, 51 insertions(+), 11 deletions(-) diff --git a/src/Surface.zig b/src/Surface.zig index 757495d1d..f26e8278c 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -1561,6 +1561,22 @@ pub fn setFontSize(self: *Surface, size: font.face.DesiredSize) !void { self.queueRender() catch unreachable; } +/// Change the surface background opacity. This function may be reused anywhere that +/// might want to change the opacity of the surface. +/// +/// This can only be called from the main thread. +pub fn setBackgroundOpacity(self: *Surface, opacity: f64) void { + log.debug("set background opacity={}", .{opacity}); + + // Notify our render thread of the new opacity. + _ = self.renderer_thread.mailbox.push(.{ + .background_opacity = opacity, + }, .{ .forever = {} }); + + // Schedule render which also drains our mailbox + self.queueRender() catch unreachable; +} + /// This queues a render operation with the renderer thread. The render /// isn't guaranteed to happen immediately but it will happen as soon as /// practical. diff --git a/src/apprt/gtk/App.zig b/src/apprt/gtk/App.zig index cf837530a..d62dd41cd 100644 --- a/src/apprt/gtk/App.zig +++ b/src/apprt/gtk/App.zig @@ -499,7 +499,7 @@ pub fn performAction( .toggle_tab_overview => self.toggleTabOverview(target), .toggle_split_zoom => self.toggleSplitZoom(target), .toggle_window_decorations => self.toggleWindowDecorations(target), - .toggle_background_opacity => self.toggleBackgroundOpacity(target), + .toggle_background_opacity => try self.toggleBackgroundOpacity(target), .quit_timer => self.quitTimer(value), .prompt_title => try self.promptTitle(target), .toggle_quick_terminal => return try self.toggleQuickTerminal(), @@ -798,9 +798,9 @@ fn toggleQuickTerminal(self: *App) !bool { } fn toggleBackgroundOpacity( - _: *App, + self: *App, target: apprt.Target, -) void { +) !void { switch (target) { .app => {}, .surface => |v| { @@ -811,7 +811,13 @@ fn toggleBackgroundOpacity( ); return; }; - window.toggleBackgroundOpacity(); + + const opacity = try window.toggleBackgroundOpacity(); + + // Cycle through all surfaces and set the background opacity so they stay in sync + for (self.core_app.surfaces.items) |surface| { + surface.core_surface.setBackgroundOpacity(opacity); + } }, } } diff --git a/src/apprt/gtk/Window.zig b/src/apprt/gtk/Window.zig index 1734ef3ca..16fcb70e7 100644 --- a/src/apprt/gtk/Window.zig +++ b/src/apprt/gtk/Window.zig @@ -662,14 +662,13 @@ pub fn toggleWindowDecorations(self: *Window) void { } /// Toggle the background opacity for this window. -pub fn toggleBackgroundOpacity(self: *Window) void { - if (self.app.config.@"background-opacity" >= 1) return; +pub fn toggleBackgroundOpacity(self: *Window) !f64 { + if (self.app.config.@"background-opacity" >= 1) return self.app.config.@"background-opacity"; - if (c.gtk_widget_has_css_class(@ptrCast(self.window), "background") == 1) { - c.gtk_widget_remove_css_class(@ptrCast(self.window), "background"); - } else { - c.gtk_widget_add_css_class(@ptrCast(self.window), "background"); - } + self.config.background_opacity = if (self.config.background_opacity == 1.0) self.app.config.@"background-opacity" else 1.0; + try self.syncAppearance(); + + return self.config.background_opacity; } /// Grabs focus on the currently selected tab. diff --git a/src/renderer/OpenGL.zig b/src/renderer/OpenGL.zig index 3e674c715..30e5a2efe 100644 --- a/src/renderer/OpenGL.zig +++ b/src/renderer/OpenGL.zig @@ -653,6 +653,17 @@ pub fn setVisible(self: *OpenGL, visible: bool) void { _ = visible; } +/// Set the backgrond opacity in the config. +/// +/// Must be called on the render thread. +pub fn setBackgroundOpacity(self: *OpenGL, opacity: f64) void { + if (single_threaded_draw) self.draw_mutex.lock(); + defer if (single_threaded_draw) self.draw_mutex.unlock(); + + // We don't want to go below 0 or above 1 + self.config.background_opacity = @max(0, @min(1, opacity)); +} + /// Set the new font grid. /// /// Must be called on the render thread. diff --git a/src/renderer/Thread.zig b/src/renderer/Thread.zig index 03b41ab30..fb70b1276 100644 --- a/src/renderer/Thread.zig +++ b/src/renderer/Thread.zig @@ -420,6 +420,11 @@ fn drainMailbox(self: *Thread) !void { self.renderer.markDirty(); }, + .background_opacity => |opacity| { + self.renderer.setBackgroundOpacity(opacity); + self.renderer.markDirty(); + }, + .cursor_color => |color| { self.renderer.cursor_color = color; self.renderer.markDirty(); diff --git a/src/renderer/message.zig b/src/renderer/message.zig index d6255661f..8bd1eb8e7 100644 --- a/src/renderer/message.zig +++ b/src/renderer/message.zig @@ -48,6 +48,9 @@ pub const Message = union(enum) { /// Change the background color as set by an OSC 11 command, if any. background_color: ?terminal.color.RGB, + /// Change the background opacity. + background_opacity: f64, + /// Change the cursor color. This can be done separately from changing the /// config file in response to an OSC 12 command. cursor_color: ?terminal.color.RGB,