all threads are notified of inspector state, trigger render

This commit is contained in:
Mitchell Hashimoto
2023-10-22 08:46:30 -07:00
parent afa08ffc02
commit 5a299e14e4
9 changed files with 81 additions and 22 deletions

View File

@ -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,

View File

@ -584,12 +584,18 @@ 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;
}
// 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.
pub fn deactivateInspector(self: *Surface) void {
const inspector = self.inspector orelse return;
@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -34,4 +34,7 @@ pub const Message = union(enum) {
alloc: Allocator,
ptr: *renderer.Renderer.DerivedConfig,
},
/// Activate or deactivate the inspector.
inspector: bool,
};

View File

@ -62,13 +62,18 @@ sync_reset_cancel_c: xev.Completion = .{},
/// The underlying IO implementation.
impl: *termio.Impl,
/// 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,
/// 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,
/// 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
@ -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);
},
}
}

View File

@ -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,