diff options
Diffstat (limited to 'src/gui/gui.zig')
| -rw-r--r-- | src/gui/gui.zig | 65 |
1 files changed, 47 insertions, 18 deletions
diff --git a/src/gui/gui.zig b/src/gui/gui.zig index c21ad069..7e34a928 100644 --- a/src/gui/gui.zig +++ b/src/gui/gui.zig @@ -68,10 +68,35 @@ const overlay_frag_glsl_es = if (is_emscripten) @embedFile("overlay.frag.es.glsl // web: no ptys — the whole state replays from a dump embedded at build time const embedded_dump = if (is_emscripten) @embedFile("embedded.dump.zon") else ""; -// default page colors — the same "terminal native dark" the prototype used +/// What the shell paints where the core painted nothing: behind the grid — the +/// strip left over when the window is not a whole number of cells tall — and +/// inside every cell the core left at its default background. The FALLBACK +/// for it, that is: the ground itself is the active theme's own background, +/// read off the core once a frame (see `ground`), and this is what a theme +/// with none of its own gets. +/// +/// A theme declares no background (the curated `dark`, every vendored +/// `*_transparent`) to mean "wear whatever the terminal is wearing", and a +/// window has nothing to wear. The AppKit shell answers that by going +/// see-through over an NSVisualEffectView — pardes_theme_bg, docs/macos.md — +/// and this shell cannot follow it there: SDL's GPU API refuses to claim a +/// SDL_WINDOW_TRANSPARENT window at all ("The GPU API doesn't support +/// transparent windows", SDL_gpu.c), because D3D12 has no transparent +/// swapchain and the API says no everywhere rather than only where it must. +/// So a themeless window keeps the terminal-native dark it always wore. const bg_default = [3]u8{ 18, 18, 18 }; const fg_default = [3]u8{ 204, 204, 204 }; +/// The ground under this frame. The theme's OWN background and not the +/// animated chrome colour: taglines fade between themes over a handful of +/// frames, document backgrounds switch the instant the theme does, and this is +/// one of those. Asked per frame, so a `Theme` command takes hold without a +/// relaunch — and asked at all because a hand-agreed constant was a black line +/// along the two edges of every light-themed window. +fn ground(theme_bg: ?[3]u8) [3]u8 { + return theme_bg orelse bg_default; +} + // the plan9 arrow cursor, bytes verbatim from 9front /sys/src/9/port/ // devmouse.c (Cursor arrow, 16x16 MSB-first): clr is the white outline, set // the black ink, offset {-1,-1} puts the hot point at (1,1) in the bitmap. @@ -1656,7 +1681,7 @@ fn runNative(init: std.process.Init, opts_in: pardes.Options) !void { core.update(.tick); _ = frame_arena.reset(.retain_capacity); const surface = try core.render(frame_arena.allocator()); - renderFrame(&g, gpa, surface, core.crt_on, core.show_debug) catch |err| log.err("render: {t}", .{err}); + renderFrame(&g, gpa, surface, core.theme().bg, core.crt_on, core.show_debug) catch |err| log.err("render: {t}", .{err}); } } @@ -1965,7 +1990,7 @@ fn webFrame(arg: ?*anyopaque) callconv(.c) void { core.update(.tick); _ = st.frame_arena.reset(.retain_capacity); const surface = core.render(st.frame_arena.allocator()) catch return; - renderFrameGl(g, st.gpa, surface, core.show_debug) catch return; + renderFrameGl(g, st.gpa, surface, core.theme().bg, core.show_debug) catch return; } /// the canvas follows the page (CSS); the SDL window follows the canvas, @@ -3210,7 +3235,7 @@ fn stepScroll(g: *Gui, core: *pardes.Pardes, gpa: std.mem.Allocator) void { /// to the body, which is the whole of the clipping — the shell draws the grid /// in one flat pass, so without it the overhanging rows would land on the /// pane's own tag and on whatever is below it. -fn emitScrollRows(g: *Gui, instances: [*]CellInstance, base: u32, surface: *pardes.Surface, layout: CellLayout, win_w: f32, win_h: f32) u32 { +fn emitScrollRows(g: *Gui, instances: [*]CellInstance, base: u32, surface: *pardes.Surface, layout: CellLayout, win_w: f32, win_h: f32, page: [3]u8) u32 { if (g.scroll_pane == null or g.scroll_lag == 0) return 0; const r = g.scroll_rect; if (r.w <= config.GUTTER or r.h <= pardes.BOX_H) return 0; @@ -3230,7 +3255,7 @@ fn emitScrollRows(g: *Gui, instances: [*]CellInstance, base: u32, surface: *pard var col = x0; while (col < x0 + bw) : (col += 1) { const sidx: u32 = @as(u32, row) * surface.cols + col; - emitInstance(g, instances, base + n, col, row, shifted, win_w, win_h, surface.at(col, row), sidx == cursor_idx and !cursor_bar); + emitInstance(g, instances, base + n, col, row, shifted, win_w, win_h, surface.at(col, row), sidx == cursor_idx and !cursor_bar, page); n += 1; } } @@ -3240,7 +3265,7 @@ fn emitScrollRows(g: *Gui, instances: [*]CellInstance, base: u32, surface: *pard const erow: u16 = if (g.scroll_lag > 0) y0 + bh else y0 - 1; var i: u16 = 0; while (i < bw) : (i += 1) { - emitInstance(g, instances, base + n, x0 + i, erow, shifted, win_w, win_h, &g.scroll_edge[i], false); + emitInstance(g, instances, base + n, x0 + i, erow, shifted, win_w, win_h, &g.scroll_edge[i], false, page); n += 1; } } @@ -3545,7 +3570,7 @@ fn drawNativeImagesGpu(g: *Gui, rp: ?*c.SDL_GPURenderPass, surface: *pardes.Surf c.SDL_SetGPUScissor(pass, &whole); } -fn renderFrame(g: *Gui, gpa: std.mem.Allocator, surface: *pardes.Surface, crt_on: bool, debug_on: bool) !void { +fn renderFrame(g: *Gui, gpa: std.mem.Allocator, surface: *pardes.Surface, theme_bg: ?[3]u8, crt_on: bool, debug_on: bool) !void { const cmd = c.SDL_AcquireGPUCommandBuffer(g.device) orelse return; var sw: u32 = 0; var sh: u32 = 0; @@ -3592,12 +3617,13 @@ fn renderFrame(g: *Gui, gpa: std.mem.Allocator, surface: *pardes.Surface, crt_on // re-creating the buffer on every frame that starts or ends a slide. if (cells != 0) try ensureVbuf(g, cells * 2); + const page = ground(theme_bg); var color_target = std.mem.zeroes(c.SDL_GPUColorTargetInfo); color_target.texture = scene; color_target.clear_color = .{ - .r = @as(f32, @floatFromInt(bg_default[0])) / 255.0, - .g = @as(f32, @floatFromInt(bg_default[1])) / 255.0, - .b = @as(f32, @floatFromInt(bg_default[2])) / 255.0, + .r = @as(f32, @floatFromInt(page[0])) / 255.0, + .g = @as(f32, @floatFromInt(page[1])) / 255.0, + .b = @as(f32, @floatFromInt(page[2])) / 255.0, .a = 1.0, }; color_target.load_op = c.SDL_GPU_LOADOP_CLEAR; @@ -3618,10 +3644,10 @@ fn renderFrame(g: *Gui, gpa: std.mem.Allocator, surface: *pardes.Surface, crt_on var col: u16 = 0; while (col < surface.cols) : (col += 1) { const idx: u32 = @as(u32, row) * surface.cols + col; - emitInstance(g, instances, idx, col, row, layout, win_w, win_h, surface.at(col, row), idx == cursor_idx and !cursor_bar); + emitInstance(g, instances, idx, col, row, layout, win_w, win_h, surface.at(col, row), idx == cursor_idx and !cursor_bar, page); } } - const shifted = emitScrollRows(g, instances, cells, surface, layout, win_w, win_h); + const shifted = emitScrollRows(g, instances, cells, surface, layout, win_w, win_h, page); c.SDL_UnmapGPUTransferBuffer(g.device, g.vxfer.?); // emitInstance may have rasterized new glyphs into the staging atlas; @@ -3698,12 +3724,14 @@ fn emitInstance( win_h: f32, cell: *const pardes.Cell, is_cursor: bool, + /// the ground this frame: what a default background resolves to + page: [3]u8, ) void { // Resolve the cell style to concrete fg/bg. A normal block cursor reverses // the cell; the insert cursor is a separate overlay, so the glyph beneath // it remains in this base pass. var fg = fg_default; - var bg = bg_default; + var bg = page; var reverse = is_cursor; if (!cell.default) { const st = cell.style; @@ -3713,7 +3741,7 @@ fn emitInstance( .rgb => |rgb| rgb, }; bg = switch (st.bg) { - .default => bg_default, + .default => page, .index => |i| palColor(i), .rgb => |rgb| rgb, }; @@ -4065,17 +4093,18 @@ fn makeShader(device: *c.SDL_GPUDevice, code: []const u8, stage: c.SDL_GPUShader // re-upload each frame; attribs re-specified per draw (no VAO to manage). // ===================================================================== -fn renderFrameGl(g: *Gui, gpa: std.mem.Allocator, surface: *pardes.Surface, debug_on: bool) !void { +fn renderFrameGl(g: *Gui, gpa: std.mem.Allocator, surface: *pardes.Surface, theme_bg: ?[3]u8, debug_on: bool) !void { var pw: c_int = 0; var ph: c_int = 0; _ = c.SDL_GetWindowSizeInPixels(g.window, &pw, &ph); const sw: u32 = @intCast(@max(pw, 1)); const sh: u32 = @intCast(@max(ph, 1)); c.glViewport(0, 0, @intCast(sw), @intCast(sh)); + const page = ground(theme_bg); c.glClearColor( - @as(f32, @floatFromInt(bg_default[0])) / 255.0, - @as(f32, @floatFromInt(bg_default[1])) / 255.0, - @as(f32, @floatFromInt(bg_default[2])) / 255.0, + @as(f32, @floatFromInt(page[0])) / 255.0, + @as(f32, @floatFromInt(page[1])) / 255.0, + @as(f32, @floatFromInt(page[2])) / 255.0, 1.0, ); c.glClear(c.GL_COLOR_BUFFER_BIT); |
