mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-17 17:26:09 +03:00
Merge pull request #1522 from mitchellh/metal-occlusion
macOS: send occluded state to renderers, trigger draw on visible
This commit is contained in:
@ -1563,10 +1563,10 @@ pub fn textCallback(self: *Surface, text: []const u8) !void {
|
|||||||
/// of focus state. This is used to pause rendering when the surface
|
/// of focus state. This is used to pause rendering when the surface
|
||||||
/// is not visible, and also re-render when it becomes visible again.
|
/// is not visible, and also re-render when it becomes visible again.
|
||||||
pub fn occlusionCallback(self: *Surface, visible: bool) !void {
|
pub fn occlusionCallback(self: *Surface, visible: bool) !void {
|
||||||
// If we became visible, then we queue a render. This helps scenarios
|
_ = self.renderer_thread.mailbox.push(.{
|
||||||
// where the apprt pauses rendering when the surface is not visible,
|
.visible = visible,
|
||||||
// i.e. macOS with Metal (see issue #1510).
|
}, .{ .forever = {} });
|
||||||
if (visible) try self.queueRender();
|
try self.queueRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn focusCallback(self: *Surface, focused: bool) !void {
|
pub fn focusCallback(self: *Surface, focused: bool) !void {
|
||||||
|
@ -82,6 +82,10 @@ flags: packed struct {
|
|||||||
|
|
||||||
/// This is true when the inspector is active.
|
/// This is true when the inspector is active.
|
||||||
has_inspector: bool = false,
|
has_inspector: bool = false,
|
||||||
|
|
||||||
|
/// This is true when the view is visible. This is used to determine
|
||||||
|
/// if we should be rendering or not.
|
||||||
|
visible: bool = true,
|
||||||
} = .{},
|
} = .{},
|
||||||
|
|
||||||
pub const DerivedConfig = struct {
|
pub const DerivedConfig = struct {
|
||||||
@ -242,6 +246,23 @@ fn drainMailbox(self: *Thread) !void {
|
|||||||
while (self.mailbox.pop()) |message| {
|
while (self.mailbox.pop()) |message| {
|
||||||
log.debug("mailbox message={}", .{message});
|
log.debug("mailbox message={}", .{message});
|
||||||
switch (message) {
|
switch (message) {
|
||||||
|
.visible => |v| {
|
||||||
|
// Set our visible state
|
||||||
|
self.flags.visible = v;
|
||||||
|
|
||||||
|
// If we became visible then we immediately trigger a draw.
|
||||||
|
// We don't need to update frame data because that should
|
||||||
|
// still be happening.
|
||||||
|
if (v) self.drawFrame();
|
||||||
|
|
||||||
|
// Note that we're explicitly today not stopping any
|
||||||
|
// cursor timers, draw timers, etc. These things have very
|
||||||
|
// little resource cost and properly maintaining their active
|
||||||
|
// state across different transitions is going to be bug-prone,
|
||||||
|
// so its easier to just let them keep firing and have them
|
||||||
|
// check the visible state themselves to control their behavior.
|
||||||
|
},
|
||||||
|
|
||||||
.focus => |v| {
|
.focus => |v| {
|
||||||
// Set it on the renderer
|
// Set it on the renderer
|
||||||
try self.renderer.setFocus(v);
|
try self.renderer.setFocus(v);
|
||||||
@ -341,6 +362,27 @@ fn changeConfig(self: *Thread, config: *const DerivedConfig) !void {
|
|||||||
self.config = config.*;
|
self.config = config.*;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trigger a draw. This will not update frame data or anything, it will
|
||||||
|
/// just trigger a draw/paint.
|
||||||
|
fn drawFrame(self: *Thread) void {
|
||||||
|
// If we're invisible, we do not draw.
|
||||||
|
if (!self.flags.visible) return;
|
||||||
|
|
||||||
|
// If we're doing single-threaded GPU calls then we just wake up the
|
||||||
|
// app thread to redraw at this point.
|
||||||
|
if (renderer.Renderer == renderer.OpenGL and
|
||||||
|
renderer.OpenGL.single_threaded_draw)
|
||||||
|
{
|
||||||
|
_ = self.app_mailbox.push(
|
||||||
|
.{ .redraw_surface = self.surface },
|
||||||
|
.{ .instant = {} },
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
self.renderer.drawFrame(self.surface) catch |err|
|
||||||
|
log.warn("error drawing err={}", .{err});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn wakeupCallback(
|
fn wakeupCallback(
|
||||||
self_: ?*Thread,
|
self_: ?*Thread,
|
||||||
_: *xev.Loop,
|
_: *xev.Loop,
|
||||||
@ -388,19 +430,8 @@ fn drawCallback(
|
|||||||
return .disarm;
|
return .disarm;
|
||||||
};
|
};
|
||||||
|
|
||||||
// If we're doing single-threaded GPU calls then we just wake up the
|
// Draw
|
||||||
// app thread to redraw at this point.
|
t.drawFrame();
|
||||||
if (renderer.Renderer == renderer.OpenGL and
|
|
||||||
renderer.OpenGL.single_threaded_draw)
|
|
||||||
{
|
|
||||||
_ = t.app_mailbox.push(
|
|
||||||
.{ .redraw_surface = t.surface },
|
|
||||||
.{ .instant = {} },
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
t.renderer.drawFrame(t.surface) catch |err|
|
|
||||||
log.warn("error drawing err={}", .{err});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only continue if we're still active
|
// Only continue if we're still active
|
||||||
if (t.draw_active) {
|
if (t.draw_active) {
|
||||||
@ -436,18 +467,8 @@ fn renderCallback(
|
|||||||
) catch |err|
|
) catch |err|
|
||||||
log.warn("error rendering err={}", .{err});
|
log.warn("error rendering err={}", .{err});
|
||||||
|
|
||||||
// If we're doing single-threaded GPU calls then we also wake up the
|
|
||||||
// app thread to redraw at this point.
|
|
||||||
if (renderer.Renderer == renderer.OpenGL and
|
|
||||||
renderer.OpenGL.single_threaded_draw)
|
|
||||||
{
|
|
||||||
_ = t.app_mailbox.push(.{ .redraw_surface = t.surface }, .{ .instant = {} });
|
|
||||||
return .disarm;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw
|
// Draw
|
||||||
t.renderer.drawFrame(t.surface) catch |err|
|
t.drawFrame();
|
||||||
log.warn("error drawing err={}", .{err});
|
|
||||||
|
|
||||||
return .disarm;
|
return .disarm;
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,11 @@ pub const Message = union(enum) {
|
|||||||
/// the renderer is expected to handle all of these.
|
/// the renderer is expected to handle all of these.
|
||||||
focus: bool,
|
focus: bool,
|
||||||
|
|
||||||
|
/// A change in the view occlusion state. This can be used to determine
|
||||||
|
/// if the window is visible or not. A window can be not visible (occluded)
|
||||||
|
/// and still have focus.
|
||||||
|
visible: bool,
|
||||||
|
|
||||||
/// Reset the cursor blink by immediately showing the cursor then
|
/// Reset the cursor blink by immediately showing the cursor then
|
||||||
/// restarting the timer.
|
/// restarting the timer.
|
||||||
reset_cursor_blink: void,
|
reset_cursor_blink: void,
|
||||||
|
Reference in New Issue
Block a user