diff options
Diffstat (limited to 'src/macos.zig')
| -rw-r--r-- | src/macos.zig | 125 |
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; |
