summaryrefslogtreecommitdiff
path: root/src/macos.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/macos.zig')
-rw-r--r--src/macos.zig125
1 files changed, 123 insertions, 2 deletions
diff --git a/src/macos.zig b/src/macos.zig
index d3b33c55..a7ee3164 100644
--- a/src/macos.zig
+++ b/src/macos.zig
@@ -773,6 +773,10 @@ fn initCore(runtime: ?*const Runtime, cols_arg: u16, rows_arg: u16) !void {
for (&st.ptys, 0..) |*slot, id| if (slot.*) |*pt| startReader(st, pt, @intCast(id));
pardes.lsp.setStatusSink(st, lspStatusSink);
+ // From here the core is touched only inside the entry points above,
+ // each of which takes the turn for its own duration; between them the
+ // 9P connections have it.
+ pardes.turn.rest();
}
fn wakeNinep(ctx: ?*anyopaque) void {
@@ -781,6 +785,7 @@ fn wakeNinep(ctx: ?*anyopaque) void {
}
export fn pardes_deinit() void {
+ pardes.turn.wake();
const st = &(state orelse return);
if (st.ninep) |listener| {
listener.deinit(st.gpa);
@@ -823,6 +828,8 @@ export fn pardes_deinit() void {
}
export fn pardes_should_quit() bool {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return true);
return st.core.quit;
}
@@ -890,11 +897,15 @@ test "the animation clock spends real time, not callbacks" {
}
export fn pardes_animating() bool {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return false);
return st.core.animationActive() or st.rotate_coasting or st.scroll_coasting;
}
export fn pardes_theme_bg() u32 {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const th = if (state) |*st| st.core.theme() else &pardes.themes[0];
const bg = th.bg orelse return color_default;
return @as(u32, bg[0]) << 16 | @as(u32, bg[1]) << 8 | bg[2];
@@ -913,6 +924,8 @@ export fn pardes_theme_bg() u32 {
/// own (pardes_theme_bg == PARDES_COLOR_DEFAULT) drops the ground entirely,
/// whatever percentage is set here.
export fn pardes_window_opacity() u8 {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return 100);
st.core.settings.window_opacity_pending = false;
return st.core.settings.window_opacity;
@@ -920,6 +933,8 @@ export fn pardes_window_opacity() u8 {
/// Public AppKit backdrop strength, independent of background paint opacity.
export fn pardes_window_blur() u8 {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
return if (state) |st| st.core.settings.window_blur else 0;
}
@@ -928,10 +943,14 @@ fn taglineFontPercent(core: ?*const pardes.Pardes) u8 {
}
export fn pardes_gui_tagline_font_percent() u8 {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
return taglineFontPercent(if (state) |*st| st.core else null);
}
export fn pardes_tagline_band_offset(row: u16, canvas_h: f32, cell_h: u32, tagline_h: u32) u32 {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
return pardes.taglineBandOffset(row, canvas_h, cell_h, tagline_h, if (state) |*st| st.core.settings.workspace_tag else true);
}
@@ -940,16 +959,22 @@ export fn pardes_topbar_pane_border_px(cell_h: u32, tagline_h: u32) u32 {
}
export fn pardes_tagline_origin_col(col: u16, row: u16) f32 {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return @floatFromInt(col));
return pardes.taglineOriginColForFrame(st.core, col, row);
}
export fn pardes_grid_col_at(x: f32, row: u16, body_w: f32, tagline_w: f32) u16 {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return pardes.gridColAt(null, x, row, body_w, tagline_w));
return pardes.gridColAt(st.core, x, row, body_w, tagline_w);
}
export fn pardes_topbar_pane_border_rgb() u32 {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const rgb = pardes.config.gui_topbar_pane_border_rgb orelse fromTheme: {
const st = state orelse return color_default;
break :fromTheme st.core.chromeTheme().border;
@@ -958,11 +983,15 @@ export fn pardes_topbar_pane_border_rgb() u32 {
}
export fn pardes_tag_active_bg() u32 {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = state orelse return color_default;
const rgb = st.core.chromeTheme().tag_active_bg;
return @as(u32, rgb[0]) << 16 | @as(u32, rgb[1]) << 8 | rgb[2];
}
export fn pardes_tagline_bg() u32 {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = state orelse return color_default;
const rgb = st.core.chromeTheme().tag_bg;
return @as(u32, rgb[0]) << 16 | @as(u32, rgb[1]) << 8 | rgb[2];
@@ -1008,6 +1037,8 @@ test "the fallback preference order crosses the ABI intact and ends at the bound
}
export fn pardes_scene() Scene {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return .{});
const seconds = @as(f64, @floatFromInt(st.scene_ns)) / @as(f64, std.time.ns_per_s);
return .{
@@ -1018,6 +1049,8 @@ export fn pardes_scene() Scene {
}
export fn pardes_postprocessor_unavailable() void {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return);
st.core.disableSceneEffects();
st.core.settings.panel_transition = .off;
@@ -1026,6 +1059,8 @@ export fn pardes_postprocessor_unavailable() void {
}
export fn pardes_panel_animation_failed() void {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return);
st.core.abandonPanelAnimations();
}
@@ -1210,6 +1245,8 @@ fn reloadWatchedFile(st: *State, pane: u8, announce: bool) bool {
}
export fn pardes_watch_changed(pane: u8, generation: u32) void {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return);
if (pane >= watch_slot_count) return;
if (st.file_watches.notify(pane, generation)) wake(st);
@@ -1265,11 +1302,13 @@ fn drainInbox(st: *State) bool {
}
export fn pardes_tick() bool {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return false);
st.inbox.wake_pending.store(false, .release);
var did = drainInbox(st);
if (st.ninep) |listener| {
- const drained = listener.tick(st.core);
+ const drained = listener.tick();
did = did or drained.count != 0;
if (drained.pending) wake(st);
}
@@ -1277,7 +1316,9 @@ export fn pardes_tick() bool {
did = true;
st.core.perform(effect);
}
+ pardes.turn.settle();
if (restoreCore(st)) did = true;
+ pardes.turn.restoreSettled();
return did;
}
@@ -1309,7 +1350,7 @@ fn restoreCore(st: *State) bool {
const generation = st.file_watches.stop(st.gpa, id);
hostWatchFile(id, generation, null, 0);
};
- if (st.ninep) |listener| listener.reset(st.core);
+ if (st.ninep) |listener| listener.reset(replacement);
replacement.host = hostFor(st);
st.core.deinit();
st.core = replacement;
@@ -1485,6 +1526,8 @@ test "mac Restore cancels a PTY reader waiting for output capacity" {
}
export fn pardes_animation_tick() bool {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return false);
const now: u64 = @intCast(@max(0, monotonicNs()));
@@ -1546,6 +1589,8 @@ export fn pardes_animation_tick() bool {
}
export fn pardes_key(cp_arg: u32, text_ptr: ?[*]const u8, len: usize, mods: u32) void {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return);
if (cp_arg > std.math.maxInt(u21)) return;
const text: []const u8 = if (text_ptr) |p| p[0..len] else "";
@@ -1559,16 +1604,22 @@ export fn pardes_key(cp_arg: u32, text_ptr: ?[*]const u8, len: usize, mods: u32)
}
export fn pardes_paste(text_ptr: ?[*]const u8, len: usize) void {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return);
const text: []const u8 = if (text_ptr) |p| p[0..len] else "";
st.core.update(.{ .paste = text });
}
export fn pardes_mouse(button_arg: c_int, kind_arg: c_int, col: u16, row: u16, mods: u32) void {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
mouseWithHit(button_arg, kind_arg, col, row, mods, null, null);
}
export fn pardes_mouse_pixel(button_arg: c_int, kind_arg: c_int, col: u16, row: u16, mods: u32, x: f32, y: f32, bw: f32, bh: f32, tw: f32, th: f32) void {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return);
const source = st.core.presentation.pointerFractional(st.core.screen_w, st.core.screen_h, x / @max(1, bw), y / @max(1, bh));
var hit: ?pardes.Mouse.BodyHit = null;
@@ -1620,11 +1671,15 @@ fn mouseWithHit(button_arg: c_int, kind_arg: c_int, col: u16, row: u16, mods: u3
}
export fn pardes_pointer_leave() void {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return);
st.core.update(.pointer_leave);
}
export fn pardes_scroll(delta_rows: f32, delta_cols: f32, col: u16, row: u16) void {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return);
st.scroll_col = col;
st.scroll_row = row;
@@ -1636,6 +1691,8 @@ export fn pardes_scroll(delta_rows: f32, delta_cols: f32, col: u16, row: u16) vo
/// spinning dial. Also drops whatever the last gesture left banked, so the
/// first millimetre of a new swipe cannot inherit a nearly-complete row.
export fn pardes_scroll_begin() void {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return);
st.scroll_lag = 0;
st.scroll_lag_x = 0;
@@ -1655,6 +1712,8 @@ export fn pardes_scroll_begin() void {
/// momentum simply takes the gesture over, and the tail of that momentum is
/// below the fling floor, so its end arms nothing.
export fn pardes_scroll_end() void {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return);
const last = st.scroll_last_ns;
st.scroll_last_ns = 0;
@@ -1671,6 +1730,8 @@ export fn pardes_scroll_end() void {
}
export fn pardes_rotate(degrees: f32) void {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return);
if (degrees == 0) {
st.rotate_lag = 0;
@@ -1684,6 +1745,8 @@ export fn pardes_rotate(degrees: f32) void {
}
export fn pardes_rotate_end() void {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return);
const last = st.rotate_last_ns;
st.rotate_last_ns = 0;
@@ -1726,6 +1789,8 @@ fn spendRotation(st: *State, degrees: f32) void {
}
export fn pardes_command(text_ptr: ?[*]const u8, len: usize) void {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return);
const text: []const u8 = if (text_ptr) |p| p[0..len] else "";
if (text.len == 0) return;
@@ -1733,6 +1798,8 @@ export fn pardes_command(text_ptr: ?[*]const u8, len: usize) void {
}
export fn pardes_resize(cols_arg: u16, rows_arg: u16, cell_w: u16, cell_h: u16) void {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return);
const cols = @max(1, cols_arg);
const rows = @max(1, rows_arg);
@@ -1747,6 +1814,8 @@ export fn pardes_resize(cols_arg: u16, rows_arg: u16, cell_w: u16, cell_h: u16)
}
export fn pardes_frame() u32 {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return 0);
const tz = tracy.zone(@src(), "pardes_frame");
defer tz.end();
@@ -1921,26 +1990,36 @@ fn collectImages(st: *State, surface: *const pardes.Surface) void {
}
export fn pardes_frame_images() u32 {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return 0);
return @intCast(st.images_len);
}
export fn pardes_frame_image_list() ?[*]const Image {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return null);
return if (st.images_len == 0) null else st.images.ptr;
}
export fn pardes_frame_panel_tracks() u32 {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return 0);
return @intCast(st.panel_tracks_len);
}
export fn pardes_frame_panel_track_list() ?[*]const PanelTrack {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return null);
return if (st.panel_tracks_len == 0) null else st.panel_tracks[0..].ptr;
}
export fn pardes_frame_presented(animated_panels: bool) bool {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return false);
const was_animating = st.core.animationActive();
if (animated_panels)
@@ -1951,11 +2030,15 @@ export fn pardes_frame_presented(animated_panels: bool) bool {
}
export fn pardes_frame_cells() ?[*]const Cell {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return null);
return if (st.frame_len == 0) null else st.cells.ptr;
}
export fn pardes_frame_previous_cells() ?[*]const Cell {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return null);
return if (st.panel_diff_len != st.frame_len or st.panel_diff_len == 0)
null
@@ -1964,6 +2047,8 @@ export fn pardes_frame_previous_cells() ?[*]const Cell {
}
export fn pardes_frame_changed_cells() ?[*]const u8 {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return null);
return if (st.panel_diff_len != st.frame_len or st.panel_diff_len == 0)
null
@@ -1972,16 +2057,22 @@ export fn pardes_frame_changed_cells() ?[*]const u8 {
}
export fn pardes_frame_cols() u16 {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return 0);
return st.frame_cols;
}
export fn pardes_frame_rows() u16 {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return 0);
return st.frame_rows;
}
export fn pardes_cursor_x() i32 {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return -1);
if (tagCursorCovered(st.core)) return -1;
return if (st.core.surface.cursor) |c| c.x else -1;
@@ -2000,6 +2091,8 @@ export fn pardes_tag_layer_limit() u32 {
}
export fn pardes_tag_layer_value(index: u32, field: u32) u32 {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return 0);
if (index >= pardes.MAX_TAG_LAYERS) return 0;
const layer = &st.core.surface.tag_layers[index];
@@ -2025,6 +2118,8 @@ export fn pardes_tag_layer_value(index: u32, field: u32) u32 {
}
export fn pardes_tag_layer_cells(index: u32) ?[*]const Cell {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return null);
if (index >= pardes.MAX_TAG_LAYERS) return null;
const layer = &st.core.surface.tag_layers[index];
@@ -2036,6 +2131,8 @@ export fn pardes_tag_layer_cells(index: u32) ?[*]const Cell {
}
export fn pardes_body_layer_value(index: u32, field: u32) u32 {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return 0);
if (index >= pardes.MAX_PANES) return 0;
const layer = &st.core.surface.body_layers[index];
@@ -2056,6 +2153,8 @@ export fn pardes_body_layer_value(index: u32, field: u32) u32 {
}
export fn pardes_body_layer_cells(index: u32) ?[*]const Cell {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return null);
if (index >= pardes.MAX_PANES) return null;
const layer = &st.core.surface.body_layers[index];
@@ -2071,27 +2170,37 @@ export fn pardes_body_layer_limit() u32 {
}
export fn pardes_row_metrics(body_w: u16, body_h: u16, tagline_w: u16, tagline_h: u16) void {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return);
st.core.update(.{ .resize = .{ .cols = st.core.screen_w, .rows = st.core.screen_h, .cell_pixels = st.core.cell_pixels, .row_metrics = .{ .body_w = @max(1, body_w), .body_h = @max(1, body_h), .tagline_w = @max(1, tagline_w), .tagline_h = @max(1, tagline_h) } } });
}
export fn pardes_pointer_shape() u32 {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return 0);
return @intFromEnum(st.core.surface.pointer_shape);
}
export fn pardes_cursor_y() i32 {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return -1);
if (tagCursorCovered(st.core)) return -1;
return if (st.core.surface.cursor) |c| c.y else -1;
}
export fn pardes_cursor_bar() bool {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return false);
return if (st.core.surface.cursor) |c| c.bar else false;
}
export fn pardes_take_haptic() c_int {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return 0);
return switch (st.core.takeHaptic()) {
.none => 0,
@@ -2103,6 +2212,8 @@ export fn pardes_take_haptic() c_int {
var font_path_z: [4096:0]u8 = undefined;
export fn pardes_font_take(size_hundredths: *u16) ?[*:0]const u8 {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return null);
if (comptime !pardes.font_picker) return null;
const want = st.core.takeFontRequest() orelse return null;
@@ -2118,6 +2229,8 @@ export fn pardes_font_observe(
len: usize,
point_hundredths: u16,
) bool {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return false);
const ptr = effective_name orelse return false;
if (len == 0 or len > 255 or point_hundredths == 0) return false;
@@ -2129,6 +2242,8 @@ export fn pardes_font_ack(
len: usize,
point_hundredths: u16,
) bool {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return false);
const ptr = effective_name orelse return false;
if (len == 0 or len > 255 or point_hundredths == 0) return false;
@@ -2136,6 +2251,8 @@ export fn pardes_font_ack(
}
export fn pardes_font_reject() void {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return);
st.core.rejectFont();
}
@@ -2143,6 +2260,8 @@ export fn pardes_font_reject() void {
var active_path_z: [4096:0]u8 = undefined;
export fn pardes_active_path() ?[*:0]const u8 {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return null);
const path = activeFilePath(st) orelse return null;
if (path.len == 0 or path.len >= active_path_z.len) return null;
@@ -2152,6 +2271,8 @@ export fn pardes_active_path() ?[*:0]const u8 {
}
export fn pardes_active_dirty() bool {
+ pardes.turn.wake();
+ defer pardes.turn.rest();
const st = &(state orelse return false);
const pane = st.core.panes[st.core.active] orelse return false;
const f = if (pane.file) |*x| x else return false;