rumpk/libs/membrane/compositor.nim

141 lines
3.9 KiB
Nim

# 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)