mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-17 09:16:11 +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(),
|
.quit => try self.setQuit(),
|
||||||
.surface_message => |msg| try self.surfaceMessage(msg.surface, msg.message),
|
.surface_message => |msg| try self.surfaceMessage(msg.surface, msg.message),
|
||||||
.redraw_surface => |surface| try self.redrawSurface(rt_app, surface),
|
.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);
|
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
|
/// Create a new window
|
||||||
pub fn newWindow(self: *App, rt_app: *apprt.App, msg: Message.NewWindow) !void {
|
pub fn newWindow(self: *App, rt_app: *apprt.App, msg: Message.NewWindow) !void {
|
||||||
if (!@hasDecl(apprt.App, "newWindow")) {
|
if (!@hasDecl(apprt.App, "newWindow")) {
|
||||||
@ -304,6 +310,10 @@ pub const Message = union(enum) {
|
|||||||
/// message if it needs to.
|
/// message if it needs to.
|
||||||
redraw_surface: *apprt.Surface,
|
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 {
|
const NewWindow = struct {
|
||||||
/// The parent surface
|
/// The parent surface
|
||||||
parent: ?*Surface = null,
|
parent: ?*Surface = null,
|
||||||
|
@ -584,10 +584,16 @@ pub fn activateInspector(self: *Surface) !void {
|
|||||||
self.inspector = ptr;
|
self.inspector = ptr;
|
||||||
|
|
||||||
// Put the inspector onto the render state
|
// Put the inspector onto the render state
|
||||||
self.renderer_state.mutex.lock();
|
{
|
||||||
defer self.renderer_state.mutex.unlock();
|
self.renderer_state.mutex.lock();
|
||||||
assert(self.renderer_state.inspector == null);
|
defer self.renderer_state.mutex.unlock();
|
||||||
self.renderer_state.inspector = self.inspector;
|
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.
|
/// Deactivate the inspector and stop collecting any information.
|
||||||
@ -602,6 +608,10 @@ pub fn deactivateInspector(self: *Surface) void {
|
|||||||
self.renderer_state.inspector = null;
|
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
|
// Deinit the inspector
|
||||||
inspector.deinit();
|
inspector.deinit();
|
||||||
self.alloc.destroy(inspector);
|
self.alloc.destroy(inspector);
|
||||||
|
@ -181,6 +181,11 @@ pub const App = struct {
|
|||||||
// No-op, we use a threaded interface so we're constantly drawing.
|
// 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 {
|
pub fn newWindow(self: *App, parent: ?*CoreSurface) !void {
|
||||||
_ = self;
|
_ = self;
|
||||||
|
|
||||||
|
@ -279,6 +279,12 @@ pub fn redrawSurface(self: *App, surface: *Surface) void {
|
|||||||
surface.redraw();
|
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.
|
/// Called by CoreApp to create a new window with a new surface.
|
||||||
pub fn newWindow(self: *App, parent_: ?*CoreSurface) !void {
|
pub fn newWindow(self: *App, parent_: ?*CoreSurface) !void {
|
||||||
const alloc = self.core_app.alloc;
|
const alloc = self.core_app.alloc;
|
||||||
|
@ -239,10 +239,14 @@ pub fn deinit(self: *Surface) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn render(self: *Surface) !void {
|
fn render(self: *Surface) !void {
|
||||||
if (self.inspector) |v| v.queueRender();
|
|
||||||
try self.core_surface.renderer.draw();
|
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.
|
/// Invalidate the surface so that it forces a redraw on the next tick.
|
||||||
pub fn redraw(self: *Surface) void {
|
pub fn redraw(self: *Surface) void {
|
||||||
c.gtk_gl_area_queue_render(self.gl_area);
|
c.gtk_gl_area_queue_render(self.gl_area);
|
||||||
|
@ -48,11 +48,6 @@ cursor_h: xev.Timer,
|
|||||||
cursor_c: xev.Completion = .{},
|
cursor_c: xev.Completion = .{},
|
||||||
cursor_c_cancel: 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.
|
/// The surface we're rendering to.
|
||||||
surface: *apprt.Surface,
|
surface: *apprt.Surface,
|
||||||
|
|
||||||
@ -69,6 +64,16 @@ 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,
|
||||||
|
|
||||||
|
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
|
/// 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.
|
||||||
@ -225,7 +230,7 @@ fn drainMailbox(self: *Thread) !void {
|
|||||||
// If we're focused, we immediately show the cursor again
|
// If we're focused, we immediately show the cursor again
|
||||||
// and then restart the timer.
|
// and then restart the timer.
|
||||||
if (self.cursor_c.state() != .active) {
|
if (self.cursor_c.state() != .active) {
|
||||||
self.cursor_blink_visible = true;
|
self.flags.cursor_blink_visible = true;
|
||||||
self.cursor_h.run(
|
self.cursor_h.run(
|
||||||
&self.loop,
|
&self.loop,
|
||||||
&self.cursor_c,
|
&self.cursor_c,
|
||||||
@ -239,7 +244,7 @@ fn drainMailbox(self: *Thread) !void {
|
|||||||
},
|
},
|
||||||
|
|
||||||
.reset_cursor_blink => {
|
.reset_cursor_blink => {
|
||||||
self.cursor_blink_visible = true;
|
self.flags.cursor_blink_visible = true;
|
||||||
if (self.cursor_c.state() == .active) {
|
if (self.cursor_c.state() == .active) {
|
||||||
self.cursor_h.reset(
|
self.cursor_h.reset(
|
||||||
&self.loop,
|
&self.loop,
|
||||||
@ -265,6 +270,8 @@ fn drainMailbox(self: *Thread) !void {
|
|||||||
defer config.alloc.destroy(config.ptr);
|
defer config.alloc.destroy(config.ptr);
|
||||||
try self.renderer.changeConfig(config.ptr);
|
try self.renderer.changeConfig(config.ptr);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
.inspector => |v| self.flags.has_inspector = v,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -322,10 +329,15 @@ fn renderCallback(
|
|||||||
return .disarm;
|
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.renderer.render(
|
||||||
t.surface,
|
t.surface,
|
||||||
t.state,
|
t.state,
|
||||||
t.cursor_blink_visible,
|
t.flags.cursor_blink_visible,
|
||||||
) catch |err|
|
) catch |err|
|
||||||
log.warn("error rendering err={}", .{err});
|
log.warn("error rendering err={}", .{err});
|
||||||
|
|
||||||
@ -365,7 +377,7 @@ fn cursorTimerCallback(
|
|||||||
return .disarm;
|
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.wakeup.notify() catch {};
|
||||||
|
|
||||||
t.cursor_h.run(&t.loop, &t.cursor_c, CURSOR_BLINK_INTERVAL, Thread, t, cursorTimerCallback);
|
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,
|
alloc: Allocator,
|
||||||
ptr: *renderer.Renderer.DerivedConfig,
|
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.
|
/// The underlying IO implementation.
|
||||||
impl: *termio.Impl,
|
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
|
/// 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).
|
/// this is a blocking queue so if it is full you will get errors (or block).
|
||||||
mailbox: *Mailbox,
|
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
|
/// 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.
|
||||||
@ -174,17 +179,18 @@ fn drainMailbox(self: *Thread) !void {
|
|||||||
defer config.alloc.destroy(config.ptr);
|
defer config.alloc.destroy(config.ptr);
|
||||||
try self.impl.changeConfig(config.ptr);
|
try self.impl.changeConfig(config.ptr);
|
||||||
},
|
},
|
||||||
|
.inspector => |v| self.flags.has_inspector = v,
|
||||||
.resize => |v| self.handleResize(v),
|
.resize => |v| self.handleResize(v),
|
||||||
.clear_screen => |v| try self.impl.clearScreen(v.history),
|
.clear_screen => |v| try self.impl.clearScreen(v.history),
|
||||||
.scroll_viewport => |v| try self.impl.scrollViewport(v),
|
.scroll_viewport => |v| try self.impl.scrollViewport(v),
|
||||||
.jump_to_prompt => |v| try self.impl.jumpToPrompt(v),
|
.jump_to_prompt => |v| try self.impl.jumpToPrompt(v),
|
||||||
.start_synchronized_output => self.startSynchronizedOutput(),
|
.start_synchronized_output => self.startSynchronizedOutput(),
|
||||||
.linefeed_mode => |v| self.linefeed_mode = v,
|
.linefeed_mode => |v| self.flags.linefeed_mode = v,
|
||||||
.write_small => |v| try self.impl.queueWrite(v.data[0..v.len], self.linefeed_mode),
|
.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.linefeed_mode),
|
.write_stable => |v| try self.impl.queueWrite(v, self.flags.linefeed_mode),
|
||||||
.write_alloc => |v| {
|
.write_alloc => |v| {
|
||||||
defer v.alloc.free(v.data);
|
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,
|
ptr: *termio.Impl.DerivedConfig,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// Activate or deactivate the inspector.
|
||||||
|
inspector: bool,
|
||||||
|
|
||||||
/// Resize the window.
|
/// Resize the window.
|
||||||
resize: Resize,
|
resize: Resize,
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user