# SPDX-License-Identifier: LSL-1.0 # Copyright (c) 2026 Markus Maiwald # Stewardship: Self Sovereign Society Foundation # # This file is part of the Nexus Sovereign Core. # See legal/LICENSE_SOVEREIGN.md for license terms. ## Nexus Membrane: Userland Graphics Compositor # libs/membrane/compositor.nim # Phase 35b/d: The Sovereign Compositor + Input Router import ../../core/ion const SYS_TABLE_ADDR = when defined(arm64): 0x50000000'u64 else: 0x83000000'u64 const GAP = 10 # Pixels between windows FOCUS_COLOR = 0xFF00FFFF'u32 # Cyan border for focused window BG_COLOR = 0xFF101020'u32 # Dark Blue background type Surface* = object id*: int32 buffer*: ptr UncheckedArray[uint32] width*, height*: int x*: int # Logical X position on the infinite strip dirty*: bool focused*: bool Compositor* = object surfaces*: seq[Surface] view_x*: int # Viewport scroll position focused_idx*: int # index in seq[Surface] var c*: Compositor # HAL Imports proc hal_surface_alloc*(w, h: uint32): int32 {.importc, cdecl.} proc hal_surface_get_ptr*(id: int32): ptr UncheckedArray[uint32] {.importc, cdecl.} proc get_sys_table(): ptr ion.SysTable = return cast[ptr ion.SysTable](SYS_TABLE_ADDR) proc blit_surface(s: Surface, dest_x, dest_y: int) = let sys = get_sys_table() let fb = cast[ptr UncheckedArray[uint32]](sys.fb_addr) let fb_w = int(sys.fb_width) let fb_h = int(sys.fb_height) # Clipping let start_y = max(0, dest_y) let end_y = min(fb_h, dest_y + s.height) let start_x = max(0, dest_x) let end_x = min(fb_w, dest_x + s.width) if start_x >= end_x or start_y >= end_y: return for y in start_y ..< end_y: let src_y = y - dest_y let src_row = cast[pointer](addr s.buffer[src_y * s.width + (start_x - dest_x)]) let dest_row = cast[pointer](addr fb[y * fb_w + start_x]) let copy_len = (end_x - start_x) * 4 copyMem(dest_row, src_row, copy_len) proc draw_border(x, y, w, h: int, color: uint32) = let sys = get_sys_table() let fb = cast[ptr UncheckedArray[uint32]](sys.fb_addr) let fb_w = int(sys.fb_width) let fb_h = int(sys.fb_height) for ix in x ..< x + w: if ix >= 0 and ix < fb_w: if y >= 0 and y < fb_h: fb[y * fb_w + ix] = color if y + h - 1 >= 0 and y + h - 1 < fb_h: fb[(y + h - 1) * fb_w + ix] = color for iy in y ..< y + h: if iy >= 0 and iy < fb_h: if x >= 0 and x < fb_w: fb[iy * fb_w + x] = color if x + w - 1 >= 0 and x + w - 1 < fb_w: fb[iy * fb_w + (x + w - 1)] = color proc layout*(c: var Compositor) = var current_x = 0 for i, s in c.surfaces.mpairs: s.x = current_x s.focused = (i == c.focused_idx) current_x += s.width + GAP proc process_input(c: var Compositor) = ## Intercept and route input (STUB - not currently used) discard # var pkt: IonPacket # if ion_user_input(addr pkt): # ... input handling commented out until ion_user_* is replaced with kernel APIs proc render_frame*(c: var Compositor) = let sys = get_sys_table() let fb = cast[ptr UncheckedArray[uint32]](sys.fb_addr) let fb_total = sys.fb_width * sys.fb_height for i in 0 ..< int(fb_total): fb[i] = BG_COLOR c.layout() for i, s in c.surfaces: let screen_x = s.x - c.view_x if screen_x + s.width < 0 or screen_x >= int(sys.fb_width): continue let screen_y = (int(sys.fb_height) - s.height) div 2 blit_surface(s, screen_x, screen_y) if s.focused: draw_border(screen_x, screen_y, s.width, s.height, FOCUS_COLOR) proc create_surface*(w, h: int): int32 = let id = hal_surface_alloc(uint32(w), uint32(h)) if id < 0: return -1 let p = hal_surface_get_ptr(id) if p == nil: return -1 var s: Surface s.id = id s.buffer = p s.width = w s.height = h s.dirty = true c.surfaces.add(s) if c.surfaces.len == 1: c.focused_idx = 0 return id proc compositor_step*() = process_input(c) render_frame(c)