All the fixes, and app-klogo

This commit is contained in:
20kdc 2018-03-28 22:15:09 +01:00
parent c2b373f261
commit 8e0c74c41b
12 changed files with 380 additions and 61 deletions

View File

@ -4,6 +4,10 @@
local event = require("event")(neo)
local neoux = require("neoux")(event, neo)
-- label
-- [ ]
-- <read><write>
-- 1234567890123456789012345
-- ABCDEF12 Lua BIOS
-- <get><set> <data> <label>
-- 21FEDCBA Nuclear Disk
-- <get><set> <data> <label>

50
code/apps/app-klogo.lua Normal file
View File

@ -0,0 +1,50 @@
-- This is released into the public domain.
-- No warranty is provided, implied or otherwise.
local event = require("event")(neo)
local neoux = require("neoux")(event, neo)
local braille = require("braille")
local icecap = neo.requireAccess("x.neo.pub.base", "loadimg")
local qt = icecap.open("/logo.data", false)
local lc = {}
local lcdq = {}
local queueSize = 4
if os.totalMemory() > (256 * 1024) then
queueSize = 40
end
for i = 1, queueSize do
lcdq[i] = 0
end
local function getLine(y)
if not lc[y] then
local idx = (y - 1) * 120
qt.seek("set", idx)
if lcdq[1] then
lc[table.remove(lcdq, 1)] = nil
end
table.insert(lcdq, y)
lc[y] = qt.read(120) or ""
end
return lc[y]
end
local running = true
neoux.create(20, 10, nil, neoux.tcwindow(20, 10, {
braille.new(1, 1, 20, 10, {
selectable = true,
get = function (window, x, y, bg, fg, selected, colour)
local data = getLine(y)
local idx = ((x - 1) * 3) + 1
return data:byte(idx) or 255, data:byte(idx + 1) or 0, data:byte(idx + 2) or 255
end
}, 1)
}, function (w)
w.close()
running = false
end, 0xFFFFFF, 0))
while running do
event.pull()
end

View File

@ -62,20 +62,25 @@ local lIM = 1
local shuttingDown = false
local savingThrow = neo.requestAccess("x.neo.sys.manage")
local function dying()
local primary = (monitors[1] or {})[2] or ""
for _, v in ipairs(monitors) do
pcall(screens.disclaim, v[2])
end
monitors = {}
neo.executeAsync("sys-init", primary)
-- In this case the surfaces are leaked and hold references here. They have to be removed manually.
-- Do this via a "primary event" (k.deregistration) and "deathtrap events"
-- If a process evades the deathtrap then it clearly has reason to stay alive regardless of Everest status.
-- Also note, should savingThrow fail, neo.dead is now a thing.
for _, v in ipairs(surfaces) do
pcall(v[6], "line", 1)
pcall(v[6], "line", 2)
end
end
if savingThrow then
savingThrow.registerForShutdownEvent()
savingThrow.registerSavingThrow(function ()
neo.executeAsync("sys-init", monitors[1][2])
-- In this case the surfaces are leaked and hold references here. They have to be removed manually.
-- Do this via a "primary event" (k.deregistration) and "deathtrap events"
-- If a process evades the deathtrap then it clearly has reason to stay alive regardless of Everest status.
-- Also note, should savingThrow fail, neo.dead is now a thing.
monitors = {}
for _, v in ipairs(surfaces) do
pcall(v[6], "line", 1)
pcall(v[6], "line", 2)
end
end)
savingThrow.registerSavingThrow(dying)
end
local function renderingAllowed()
@ -165,8 +170,8 @@ local function updateRegion(monitorId, x, y, w, h, surfaceSpanCache)
doBackgroundLine(m, mg, bdx, bdy, bdl)
backgroundMarkStart = nil
end
if not surfaceSpanCache[monitorId .. t .. "_" .. ty] then
surfaceSpanCache[monitorId .. t .. "_" .. ty] = true
if not surfaceSpanCache[monitorId .. "_" .. t .. "_" .. ty] then
surfaceSpanCache[monitorId .. "_" .. t .. "_" .. ty] = true
surfaces[t][6]("line", ty)
end
elseif not backgroundMarkStart then
@ -211,15 +216,26 @@ local function reconcileAll()
-- About to update whole screen anyway so avoid the wait.
v[1], v[2], v[3] = ensureOnscreen(v[1], v[2], v[3], v[4], v[5])
end
for k, v in ipairs(monitors) do
local k = 1
while k <= #monitors do
local v = monitors[k]
local mon, rb = v[1]()
if rb then
monitorResetBF(v)
end
if mon then
-- This *can* return null if something went wonky. Let's detect that
v[3], v[4] = mon.getResolution()
if not v[3] then
neo.emergency("everest: monitor went AWOL and nobody told me u.u")
table.remove(monitors, k)
v = nil
end
end
if v then
updateRegion(k, 1, 1, v[3], v[4], {})
k = k + 1
end
updateRegion(k, 1, 1, v[3], v[4], {})
end
updateStatus()
end
@ -246,6 +262,14 @@ local function moveSurface(surface, m, x, y, w, h, force)
end
if cb then
cb.copy(ox, oy, w, h, x - ox, y - oy)
if surface == surfaces[1] then
local cacheControl = {}
for i = 1, h do
cacheControl[om .. "_1_" .. i] = true
end
updateRegion(om, ox, oy, ow, oh, cacheControl)
return
end
end
end
end
@ -445,6 +469,17 @@ everestProvider(function (pkg, pid, sendSig)
moveSurface(surf, nil, x, y, w, h, true)
return w, (h - 1)
end,
getDepth = function ()
if neo.dead then return false end
local m = monitors[surf[1]]
if not m then return false end
local cb, rb = m[1]()
if not cb then return false end
if rb then
monitorResetBF(m)
end
return cb.getDepth()
end,
span = function (x, y, text, bg, fg)
if neo.dead then error("everest died") end
if type(x) ~= "number" then error("X must be number.") end
@ -481,8 +516,7 @@ everestSessionProvider(function (pkg, pid, sendSig)
endSession = function (gotoBristol)
shuttingDown = true
if gotoBristol then
-- Notably, savingThrow only triggers for error-death...
neo.executeAsync("sys-init", (monitors[1] or {})[2])
dying()
end
end
}
@ -545,14 +579,16 @@ local function key(ka, kc, down)
end
end
if focus then
lIM = focus[1]
if kc ~= 56 then
lIM = focus[1]
end
focus[6]("key", ka, kc, down)
end
end
-- take all displays!
local function performClaim(s3)
local gpu = screens.claim(s3)
local gpu, _ = screens.claim(s3)
local gpucb = gpu and (gpu())
if gpucb then
local w, h = gpucb.getResolution()
@ -571,6 +607,12 @@ while not shuttingDown do
local s = {coroutine.yield()}
if renderingAllowed() then
if s[1] == "h.key_down" then
local m = screens.getMonitorByKeyboard(s[2])
for k, v in ipairs(monitors) do
if v[2] == m then
lIM = k
end
end
key(s[3], s[4], true)
end
if s[1] == "h.key_up" then

View File

@ -43,7 +43,7 @@ local settings = {
["pub.clipboard"] = "",
["sys-init.shell"] = "sys-everest",
["run.sys-icecap"] = "yes",
-- scr.w/h/d.<uuid>
-- scr.w/h/d/t.<uuid>
}
local function loadSettings()
@ -96,8 +96,9 @@ local function getGPU(monitor)
local bestD = 0
for v in gpus.list() do
v.bind(monitor.address, false)
currentGPUBinding[v.address] = monitor.address
local d = v.maxDepth()
currentGPUBinding[v.address] = nil
local w, h = v.maxResolution()
local d = v.maxDepth() * w * h
if d > bestD then
bestG = v
bestD = d
@ -131,22 +132,27 @@ local function getMonitorSettings(a)
local w = tonumber(settings["scr.w." .. a]) or 80
local h = tonumber(settings["scr.h." .. a]) or 25
local d = tonumber(settings["scr.d." .. a]) or 8
local t = ((settings["scr.t." .. a] == "yes") and "yes") or "no"
w, h, d = math.floor(w), math.floor(h), math.floor(d)
return w, h, d
return w, h, d, t
end
local function setupMonitor(gpu, monitor)
monitor.setPrecise(true)
monitor.turnOn()
gpu.bind(monitor.address, false)
currentGPUBinding[gpu.address] = monitor.address
local maxW, maxH = gpu.maxResolution()
local maxD = gpu.maxDepth()
local w, h, d = getMonitorSettings(monitor.address)
local w, h, d, t = getMonitorSettings(monitor.address)
w, h, d = math.min(w, maxW), math.min(h, maxH), math.min(d, maxD)
monitor.setTouchModeInverted(t == "yes")
settings["scr.w." .. monitor.address] = tostring(w)
settings["scr.h." .. monitor.address] = tostring(h)
settings["scr.d." .. monitor.address] = tostring(d)
sRattle("scr.w." .. monitor.address, tostring(w))
sRattle("scr.h." .. monitor.address, tostring(h))
sRattle("scr.d." .. monitor.address, tostring(d))
sRattle("scr.t." .. monitor.address, t)
gpu.setResolution(w, h)
gpu.setDepth(d)
pcall(saveSettings)
@ -226,6 +232,15 @@ donkonitRDProvider(function (pkg, pid, sendSig)
end
end}
return {
getMonitorByKeyboard = function (kb)
for v in screens.list() do
for _, v2 in ipairs(v.getKeyboards()) do
if v2 == kb then
return v.address
end
end
end
end,
getClaimable = function ()
local c = {}
-- do we have gpu?
@ -272,7 +287,7 @@ donkonitRDProvider(function (pkg, pid, sendSig)
return v, didBind
end
end
end
end, v
end
end
end

View File

@ -329,10 +329,10 @@ local function initializeSystem()
if gpu then
screen = screen.address
gpu.bind(screen, true)
gpu.setDepth(gpu.maxDepth())
local gW, gH = gpu.maxResolution()
gW, gH = math.min(80, gW), math.min(25, gH)
gpu.setResolution(gW, gH)
pcall(gpu.setDepth, gpu.maxDepth()) -- can crash on OCEmu if done at the "wrong time"
gpu.setForeground(0x000000)
end
local w = 1
@ -420,12 +420,6 @@ end
-- Actual sequence
if callerPkg ~= nil then
-- Everest can call into this to force a login screen
-- In this case Everest dies, then starts Bristol.
--
if callerPkg ~= "sys-everest" then
return
end
screen = callerScr
-- Skip to "System initialized" (Everest either logged off, or died & used a Saving Throw to restart)
else

View File

@ -15,6 +15,7 @@ return {
"libs/event.lua",
"libs/serial.lua",
"libs/neoux.lua",
"libs/braille.lua",
"libs/sys-filewrap.lua"
},
},
@ -103,6 +104,22 @@ return {
"apps/app-taskmgr.lua"
}
},
["app-klogo"] = {
desc = "KittenOS NEO Logo",
v = 0,
deps = {
"neo"
},
dirs = {
"apps",
"data",
"data/app-klogo"
},
files = {
"apps/app-klogo.lua",
"data/app-klogo/logo.data"
},
},
["app-flash"] = {
desc = "KittenOS NEO EEPROM Flasher",
v = 0,
@ -142,6 +159,7 @@ return {
"neo-icecap",
"neo-secpolicy",
"neo-coreapps",
"app-klogo",
"app-flash",
"app-claw"
},

Binary file not shown.

View File

@ -209,21 +209,11 @@ local function execEvent(k, ...)
local r, reason = coroutine.resume(v.co, ...)
-- Mostly reliable accounting
v.cpuUsage = v.cpuUsage + (computer.uptime() - timerA)
local dead = not r
local hasReason = dead
if not dead then
if coroutine.status(v.co) == "dead" then
dead = true
end
end
reason = ((not r) and tostring(reason)) or nil
local dead = (not not reason) or coroutine.status(v.co) == "dead"
if dead then
if hasReason then
reason = tostring(reason)
else
reason = nil
end
termProc(k, reason)
return hasReason
return not not reason
end
end
end
@ -349,6 +339,7 @@ function runProgramPolicy(ipkg, pkg, pid, ...)
return nil, "non-sys app trying to start sys app"
end
end
return true
end
function retrieveAccess(perm, pkg, pid)
@ -459,22 +450,26 @@ end
local start = nil
function start(pkg, ...)
local args = {...}
local proc = {}
local pid = lastPID
lastPID = lastPID + 1
local function startFromUser(ipkg, ...)
ensureType(pkg, "string")
ensurePathComponent(pkg .. ".lua")
runProgramPolicy(ipkg, pkg, pid, ...)
return start(ipkg, pkg, pid, ...)
ensureType(ipkg, "string")
ensurePathComponent(ipkg .. ".lua")
local k, r = runProgramPolicy(ipkg, pkg, pid, ...)
if k then
return start(ipkg, pkg, pid, ...)
else
return k, r
end
end
local function osExecuteCore(handler, ...)
local pid, err = startFromUser(...)
while pid do
local sig = {coroutine.yield()}
handler(table.unpack(sig))
if sig[1] == "k.procdie" then
if sig[3] == pid then
return 0, sig[4]
@ -528,11 +523,11 @@ function start(pkg, ...)
if not handler then handler = function() end end
while true do
local n = {coroutine.yield()}
handler(table.unpack(n))
if n[1] == "k.securityresponse" then
-- Security response - if it involves the permission, then take it
if n[2] == perm then return n[3] end
end
handler(table.unpack(n))
end
end
env.neo.requireAccess = function (perm, reason)
@ -552,7 +547,7 @@ function start(pkg, ...)
if not appfunc then
return nil, r
end
proc.co = coroutine.create(function (...) local r = {xpcall(appfunc, debug.traceback)} if not r[1] then error(table.unpack(r, 2)) end return table.unpack(r, 2) end)
proc.co = coroutine.create(function (...) local r = {xpcall(appfunc, debug.traceback, ...)} if not r[1] then error(table.unpack(r, 2)) end return table.unpack(r, 2) end)
proc.pkg = pkg
proc.access = {
-- These permissions are the "critical set".

177
code/libs/braille.lua Normal file
View File

@ -0,0 +1,177 @@
-- This is released into the public domain.
-- No warranty is provided, implied or otherwise.
-- Braille Neoux Component
-- Callbacks :
-- selectable (boolean)
-- key(window, update, a, c, d)
-- touch(window, update, x, y, button)
-- drag(window, update, x, y, button)
-- drop(window, update, x, y, button)
-- scroll(window, update, x, y, button)
-- get(window, x, y, bg, fg, selected) -> r,g,b (REQUIRED)
-- REMINDER:
-- 03
-- 14
-- 25
-- 67
local function dotDist(ra, ga, ba, rb, gb, bb)
local dR, dG, dB = math.abs(ra - rb), math.abs(ga - gb), math.abs(ba - bb)
return (dR * 0.299) + (dG * 0.587) + (dB * 0.114)
end
local function dotGet(p, ra, ga, ba, rb, gb, bb, rc, gc, bc, pos, col)
if not col then
-- Use our own magic
local res = false
local luma = (ra * 0.299) + (ga * 0.587) + (ba * 0.114)
if luma > 96 and luma < 160 then
res = pos
elseif luma >= 160 then
res = true
end
return (res and p) or 0
end
local distA = dotDist(ra, ga, ba, rb, gb, bb)
local distB = dotDist(ra, ga, ba, rc, gc, bc)
local distAB = dotDist(rb, gb, bb, rc, gc, bc)
local distC = dotDist(ra, ga, ba, (rb + rc) / 2, (gb + gc) / 2, (bb + bc) / 2)
-- If A and B are close,
if (distAB < 32) and (distC < (math.min(distA, distB) * 4)) then
return (pos and p) or 0
end
return ((distB < distA) and p) or 0
end
local function cTransform(core)
return function (window, update, x, y, xI, yI, blah)
x = x + math.ceil(xI - 0.5)
y = y + math.ceil((yI - 0.25) * 4)
core(window, update, x, y, blah)
end
end
local function colourize(mark, ...)
local t = {...}
local bCR = 0
local bCG = 0
local bCB = 0
if not mark then
local nLuma = -1
for i = 1, #t do
local luma = (t[i][1] * 0.299) + (t[i][2] * 0.587) + (t[i][3] * 0.114)
if luma > nLuma then
bCR = t[i][1]
bCG = t[i][2]
bCB = t[i][3]
nLuma = luma
end
end
return bCR, bCG, bCB
else
local bCTS = math.huge
for i = 1, #t do
local ts = -dotDist(mark[1], mark[2], mark[3], table.unpack(t[i]))
if ts < bCTS then
bCR = t[i][1]
bCG = t[i][2]
bCB = t[i][3]
bCTS = ts
end
end
end
return bCR, bCG, bCB
end
local function packRGB(r, g, b)
return (r * 65536) + (g * 256) + b
end
heldRef = neo.wrapMeta({
new = function (x, y, w, h, cbs, colour)
local control
control = {
x = x,
y = y,
w = w,
h = h,
selectable = cbs.selectable,
key = cbs.key,
touch = cbs.touch and cTransform(cbs.touch),
drag = cbs.drag and cTransform(cbs.drag),
drop = cbs.drop and cTransform(cbs.drop),
scroll = cbs.scroll and cTransform(cbs.scroll),
line = function (window, x, y, iy, bg, fg, selected)
local colour = (window.getDepth() > 1) and colour
local str = ""
local bgR = 0
local bgG = 0
local bgB = 0
local fgR = 255
local fgG = 255
local fgB = 255
bg = 0
fg = 0xFFFFFF
local ca = 0
for p = 1, control.w do
local i = 0x2800
local xb = (p * 2) - 1
local yb = (iy * 4) - 3
local dot0R, dot0G, dot0B = cbs.get(window, xb, yb, bg, fg, selected, colour)
local dot1R, dot1G, dot1B = cbs.get(window, xb, yb + 1, bg, fg, selected, colour)
local dot2R, dot2G, dot2B = cbs.get(window, xb, yb + 2, bg, fg, selected, colour)
local dot3R, dot3G, dot3B = cbs.get(window, xb + 1, yb, bg, fg, selected, colour)
local dot4R, dot4G, dot4B = cbs.get(window, xb + 1, yb + 1, bg, fg, selected, colour)
local dot5R, dot5G, dot5B = cbs.get(window, xb + 1, yb + 2, bg, fg, selected, colour)
local dot6R, dot6G, dot6B = cbs.get(window, xb, yb + 3, bg, fg, selected, colour)
local dot7R, dot7G, dot7B = cbs.get(window, xb + 1, yb + 3, bg, fg, selected, colour)
if colour then
local obgR, obgG, obgB = colourize(nil,
{dot0R, dot0G, dot0B},
{dot1R, dot1G, dot1B},
{dot2R, dot2G, dot2B},
{dot3R, dot3G, dot3B},
{dot4R, dot4G, dot4B},
{dot5R, dot5G, dot5B},
{dot6R, dot6G, dot6B},
{dot7R, dot7G, dot7B}
)
local ofgR, ofgG, ofgB = colourize({obgR, obgG, obgB},
{dot0R, dot0G, dot0B},
{dot1R, dot1G, dot1B},
{dot2R, dot2G, dot2B},
{dot3R, dot3G, dot3B},
{dot4R, dot4G, dot4B},
{dot5R, dot5G, dot5B},
{dot6R, dot6G, dot6B},
{dot7R, dot7G, dot7B}
)
if ((dotDist(obgR, obgG, obgB, bgR, bgG, bgB) > colour) and
(dotDist(obgR, obgG, obgB, fgR, fgG, fgB) > colour)) or
((dotDist(ofgR, ofgG, ofgB, bgR, bgG, bgB) > colour) and
(dotDist(ofgR, ofgG, ofgB, fgR, fgG, fgB) > colour)) then
if ca ~= 0 then
window.span(x, y, str, bg, fg)
str = ""
end
x = x + ca
ca = 0
bg = packRGB(obgR, obgG, obgB)
fg = packRGB(ofgR, ofgG, ofgB)
bgR, bgG, bgB = obgR, obgG, obgB
fgR, fgG, fgB = ofgR, ofgG, ofgB
end
end
i = i + dotGet(1, dot0R, dot0G, dot0B, bgR, bgG, bgB, fgR, fgG, fgB, true, colour)
i = i + dotGet(2, dot1R, dot1G, dot1B, bgR, bgG, bgB, fgR, fgG, fgB, false, colour)
i = i + dotGet(4, dot2R, dot2G, dot2B, bgR, bgG, bgB, fgR, fgG, fgB, true, colour)
i = i + dotGet(8, dot3R, dot3G, dot3B, bgR, bgG, bgB, fgR, fgG, fgB, false, colour)
i = i + dotGet(16, dot4R, dot4G, dot4B, bgR, bgG, bgB, fgR, fgG, fgB, true, colour)
i = i + dotGet(32, dot5R, dot5G, dot5B, bgR, bgG, bgB, fgR, fgG, fgB, false, colour)
i = i + dotGet(64, dot6R, dot6G, dot6B, bgR, bgG, bgB, fgR, fgG, fgB, false, colour)
i = i + dotGet(128, dot7R, dot7G, dot7B, bgR, bgG, bgB, fgR, fgG, fgB, true, colour)
str = str .. unicode.char(i)
ca = ca + 1
end
window.span(x, y, str, bg, fg)
end,
}
return control
end,
})
return heldRef

View File

@ -4,6 +4,15 @@
-- neoux: Implements utilities on top of Everest & event:
-- Everest crash protection
-- Control reference
-- x/y/w/h: ints, position/size, 1,1 TL
-- selectable: boolean
-- key(window, update, char, code, down)
-- touch(window, update, x, y, xI, yI, button)
-- drag(window, update, x, y, xI, yI, button)
-- drop(window, update, x, y, xI, yI, button)
-- scroll(window, update, x, y, xI, yI, amount)
-- Global forces reference. Otherwise, nasty duplication happens.
newNeoux = function (event, neo)
-- this is why neo access is 'needed'
@ -106,6 +115,12 @@ newNeoux = function (event, neo)
window.getSize = function ()
return windowCore[2], windowCore[3]
end
window.getDepth = function ()
if windowCore[1] then
return windowCore[1].getDepth()
end
return 1
end
window.setSize = function (w, h)
windowCore[2] = w
windowCore[3] = h
@ -286,7 +301,10 @@ newNeoux = function (event, neo)
if c1 then doZone(window, c1, cache) end
if c2 then doZone(window, c2, cache) end
end
-- Attach .update for external interference
for k, v in ipairs(controls) do
v.update = function (window) doZone(window, v, {}) end
end
return function (window, ev, a, b, c, d, e)
-- X,Y,Xi,Yi,B
if ev == "touch" then
@ -372,7 +390,7 @@ newNeoux = function (event, neo)
selectable = false,
line = function (window, x, y, lined, bg, fg, selected)
-- Can't be selected normally so ignore that flag
window.span(x, y, lines[lined], bg, fg)
window.span(x, y, lines[lined], bg, fg)
end
}
end
@ -401,7 +419,7 @@ newNeoux = function (event, neo)
end
end
end,
touch = function (window, update, x, y)
touch = function (window, update, x, y, button)
callback(window)
end,
line = function (window, x, y, lind, bg, fg, selected)

View File

@ -46,7 +46,7 @@ local function prepareNodeI(node)
if a <= 1 then
return true, true, node.name
end
local camY = math.max(1, selection - 4)
local camY = math.max(1, selection - 3)
local idx = a + camY - 2
if node.unknownAvailable then
if idx == #l + 1 then
@ -131,7 +131,7 @@ local function prepareNodeI(node)
key(wnd, a, b, c)
end
if evt == "touch" then
local ns = b + math.max(1, selection - 4) - 2
local ns = b + math.max(1, selection - 3) - 2
local max = #l
if node.unknownAvailable then
max = max + 1

View File

@ -14,9 +14,14 @@ return function(dev, file, mode)
dev.close(handle)
end)
end
local function seeker(whence, point)
if not open then return end
return dev.seek(handle, whence, point)
end
if not mode then
return {
close = closer,
seek = seeker,
read = function (len)
if len == "*a" then
local ch = ""
@ -34,6 +39,7 @@ return function(dev, file, mode)
else
return {
close = closer,
seek = seeker,
write = function (txt)
if type(txt) ~= "string" then error("Write data must be string-bytearray") end
local ok, b = dev.write(handle, txt)