mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-17 01:06:08 +03:00
all threads are notified of inspector state, trigger render
This commit is contained in:
10
src/App.zig
10
src/App.zig
@ -205,6 +205,7 @@ fn drainMailbox(self: *App, rt_app: *apprt.App) !void {
|
||||
.quit => try self.setQuit(),
|
||||
.surface_message => |msg| try self.surfaceMessage(msg.surface, msg.message),
|
||||
.redraw_surface => |surface| try self.redrawSurface(rt_app, surface),
|
||||
.redraw_inspector => |surface| try self.redrawInspector(rt_app, surface),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -232,6 +233,11 @@ fn redrawSurface(self: *App, rt_app: *apprt.App, surface: *apprt.Surface) !void
|
||||
rt_app.redrawSurface(surface);
|
||||
}
|
||||
|
||||
fn redrawInspector(self: *App, rt_app: *apprt.App, surface: *apprt.Surface) !void {
|
||||
if (!self.hasSurface(&surface.core_surface)) return;
|
||||
rt_app.redrawInspector(surface);
|
||||
}
|
||||
|
||||
/// Create a new window
|
||||
pub fn newWindow(self: *App, rt_app: *apprt.App, msg: Message.NewWindow) !void {
|
||||
if (!@hasDecl(apprt.App, "newWindow")) {
|
||||
@ -304,6 +310,10 @@ pub const Message = union(enum) {
|
||||
/// message if it needs to.
|
||||
redraw_surface: *apprt.Surface,
|
||||
|
||||
/// Redraw the inspector. This is called whenever some non-OS event
|
||||
/// causes the inspector to need to be redrawn.
|
||||
redraw_inspector: *apprt.Surface,
|
||||
|
||||
const NewWindow = struct {
|
||||
/// The parent surface
|
||||
parent: ?*Surface = null,
|
||||
|
@ -584,10 +584,16 @@ pub fn activateInspector(self: *Surface) !void {
|
||||
self.inspector = ptr;
|
||||
|
||||
// Put the inspector onto the render state
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
assert(self.renderer_state.inspector == null);
|
||||
self.renderer_state.inspector = self.inspector;
|
||||
{
|
||||
self.renderer_state.mutex.lock();
|
||||
defer self.renderer_state.mutex.unlock();
|
||||
assert(self.renderer_state.inspector == null);
|
||||
self.renderer_state.inspector = self.inspector;
|
||||
}
|
||||
|
||||
// Notify our components we have an inspector active
|
||||
_ = self.renderer_thread.mailbox.push(.{ .inspector = true }, .{ .forever = {} });
|
||||
_ = self.io_thread.mailbox.push(.{ .inspector = true }, .{ .forever = {} });
|
||||
}
|
||||
|
||||
/// Deactivate the inspector and stop collecting any information.
|
||||
@ -602,6 +608,10 @@ pub fn deactivateInspector(self: *Surface) void {
|
||||
self.renderer_state.inspector = null;
|
||||
}
|
||||
|
||||
// Notify our components we have deactivated inspector
|
||||
_ = self.renderer_thread.mailbox.push(.{ .inspector = false }, .{ .forever = {} });
|
||||
_ = self.io_thread.mailbox.push(.{ .inspector = false }, .{ .forever = {} });
|
||||
|
||||
// Deinit the inspector
|
||||
inspector.deinit();
|
||||
self.alloc.destroy(inspector);
|
||||
|
@ -181,6 +181,11 @@ pub const App = struct {
|
||||
// No-op, we use a threaded interface so we're constantly drawing.
|
||||
}
|
||||
|
||||
pub fn redrawInspector(self: *App, surface: *Surface) void {
|
||||
_ = self;
|
||||
surface.queueInspectorRender();
|
||||
}
|
||||
|
||||
pub fn newWindow(self: *App, parent: ?*CoreSurface) !void {
|
||||
_ = self;
|
||||
|
||||
|
@ -279,6 +279,12 @@ pub fn redrawSurface(self: *App, surface: *Surface) void {
|
||||
surface.redraw();
|
||||
}
|
||||
|
||||
/// Redraw the inspector for the given surface.
|
||||
pub fn redrawInspector(self: *App, surface: *Surface) void {
|
||||
_ = self;
|
||||
surface.queueInspectorRender();
|
||||
}
|
||||
|
||||
/// Called by CoreApp to create a new window with a new surface.
|
||||
pub fn newWindow(self: *App, parent_: ?*CoreSurface) !void {
|
||||
const alloc = self.core_app.alloc;
|
||||
|
@ -239,10 +239,14 @@ pub fn deinit(self: *Surface) void {
|
||||
}
|
||||
|
||||
fn render(self: *Surface) !void {
|
||||
if (self.inspector) |v| v.queueRender();
|
||||
try self.core_surface.renderer.draw();
|
||||
}
|
||||
|
||||
/// Queue the inspector to render if we have one.
|
||||
pub fn queueInspectorRender(self: *Surface) void {
|
||||
if (self.inspector) |v| v.queueRender();
|
||||
}
|
||||
|
||||
/// Invalidate the surface so that it forces a redraw on the next tick.
|
||||
pub fn redraw(self: *Surface) void {
|
||||
c.gtk_gl_area_queue_render(self.gl_area);
|
||||
|
@ -48,11 +48,6 @@ cursor_h: xev.Timer,
|
||||
cursor_c: xev.Completion = .{},
|
||||
cursor_c_cancel: xev.Completion = .{},
|
||||
|
||||
/// 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
|
||||
/// thread automatically.
|
||||
cursor_blink_visible: bool = false,
|
||||
|
||||
/// The surface we're rendering to.
|
||||
surface: *apprt.Surface,
|
||||
|
||||
@ -69,6 +64,16 @@ mailbox: *Mailbox,
|
||||
/// Mailbox to send messages to the app thread
|
||||
app_mailbox: App.Mailbox,
|
||||
|
||||
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
|
||||
/// thread automatically.
|
||||
cursor_blink_visible: bool = false,
|
||||
|
||||
/// This is true when the inspector is active.
|
||||
has_inspector: bool = false,
|
||||
} = .{},
|
||||
|
||||
/// 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.
|
||||
@ -225,7 +230,7 @@ fn drainMailbox(self: *Thread) !void {
|
||||
// If we're focused, we immediately show the cursor again
|
||||
// and then restart the timer.
|
||||
if (self.cursor_c.state() != .active) {
|
||||
self.cursor_blink_visible = true;
|
||||
self.flags.cursor_blink_visible = true;
|
||||
self.cursor_h.run(
|
||||
&self.loop,
|
||||
&self.cursor_c,
|
||||
@ -239,7 +244,7 @@ fn drainMailbox(self: *Thread) !void {
|
||||
},
|
||||
|
||||
.reset_cursor_blink => {
|
||||
self.cursor_blink_visible = true;
|
||||
self.flags.cursor_blink_visible = true;
|
||||
if (self.cursor_c.state() == .active) {
|
||||
self.cursor_h.reset(
|
||||
&self.loop,
|
||||
@ -265,6 +270,8 @@ fn drainMailbox(self: *Thread) !void {
|
||||
defer config.alloc.destroy(config.ptr);
|
||||
try self.renderer.changeConfig(config.ptr);
|
||||
},
|
||||
|
||||
.inspector => |v| self.flags.has_inspector = v,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -322,10 +329,15 @@ fn renderCallback(
|
||||
return .disarm;
|
||||
};
|
||||
|
||||
// If we have an inspector, let the app know we want to rerender that.
|
||||
if (t.flags.has_inspector) {
|
||||
_ = t.app_mailbox.push(.{ .redraw_inspector = t.surface }, .{ .instant = {} });
|
||||
}
|
||||
|
||||
t.renderer.render(
|
||||
t.surface,
|
||||
t.state,
|
||||
t.cursor_blink_visible,
|
||||
t.flags.cursor_blink_visible,
|
||||
) catch |err|
|
||||
log.warn("error rendering err={}", .{err});
|
||||
|
||||
@ -365,7 +377,7 @@ fn cursorTimerCallback(
|
||||
return .disarm;
|
||||
};
|
||||
|
||||
t.cursor_blink_visible = !t.cursor_blink_visible;
|
||||
t.flags.cursor_blink_visible = !t.flags.cursor_blink_visible;
|
||||
t.wakeup.notify() catch {};
|
||||
|
||||
t.cursor_h.run(&t.loop, &t.cursor_c, CURSOR_BLINK_INTERVAL, Thread, t, cursorTimerCallback);
|
||||
|
@ -34,4 +34,7 @@ pub const Message = union(enum) {
|
||||
alloc: Allocator,
|
||||
ptr: *renderer.Renderer.DerivedConfig,
|
||||
},
|
||||
|
||||
/// Activate or deactivate the inspector.
|
||||
inspector: bool,
|
||||
};
|
||||
|
@ -62,14 +62,19 @@ sync_reset_cancel_c: xev.Completion = .{},
|
||||
/// The underlying IO implementation.
|
||||
impl: *termio.Impl,
|
||||
|
||||
/// True if linefeed mode is enabled. This is duplicated here so that the
|
||||
/// write thread doesn't need to grab a lock to check this on every write.
|
||||
linefeed_mode: bool = false,
|
||||
|
||||
/// The mailbox that can be used to send this thread messages. Note
|
||||
/// this is a blocking queue so if it is full you will get errors (or block).
|
||||
mailbox: *Mailbox,
|
||||
|
||||
flags: packed struct {
|
||||
/// True if linefeed mode is enabled. This is duplicated here so that the
|
||||
/// write thread doesn't need to grab a lock to check this on every write.
|
||||
linefeed_mode: bool = false,
|
||||
|
||||
/// This is true when the inspector is active.
|
||||
has_inspector: bool = false,
|
||||
} = .{},
|
||||
|
||||
/// 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.
|
||||
@ -174,17 +179,18 @@ fn drainMailbox(self: *Thread) !void {
|
||||
defer config.alloc.destroy(config.ptr);
|
||||
try self.impl.changeConfig(config.ptr);
|
||||
},
|
||||
.inspector => |v| self.flags.has_inspector = v,
|
||||
.resize => |v| self.handleResize(v),
|
||||
.clear_screen => |v| try self.impl.clearScreen(v.history),
|
||||
.scroll_viewport => |v| try self.impl.scrollViewport(v),
|
||||
.jump_to_prompt => |v| try self.impl.jumpToPrompt(v),
|
||||
.start_synchronized_output => self.startSynchronizedOutput(),
|
||||
.linefeed_mode => |v| self.linefeed_mode = v,
|
||||
.write_small => |v| try self.impl.queueWrite(v.data[0..v.len], self.linefeed_mode),
|
||||
.write_stable => |v| try self.impl.queueWrite(v, self.linefeed_mode),
|
||||
.linefeed_mode => |v| self.flags.linefeed_mode = v,
|
||||
.write_small => |v| try self.impl.queueWrite(v.data[0..v.len], self.flags.linefeed_mode),
|
||||
.write_stable => |v| try self.impl.queueWrite(v, self.flags.linefeed_mode),
|
||||
.write_alloc => |v| {
|
||||
defer v.alloc.free(v.data);
|
||||
try self.impl.queueWrite(v.data, self.linefeed_mode);
|
||||
try self.impl.queueWrite(v.data, self.flags.linefeed_mode);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,9 @@ pub const Message = union(enum) {
|
||||
ptr: *termio.Impl.DerivedConfig,
|
||||
},
|
||||
|
||||
/// Activate or deactivate the inspector.
|
||||
inspector: bool,
|
||||
|
||||
/// Resize the window.
|
||||
resize: Resize,
|
||||
|
||||
|
Reference in New Issue
Block a user