1
0
mirror of https://github.com/20kdc/OC-KittenOS.git synced 2024-11-23 10:58:06 +11:00

All the current progress, including KTC1 draft in case there's no other standard

KTC1 is only a draft for now, and if there's something equivalent to replace it,
 I will not hesitate to do so.
This commit is contained in:
20kdc 2018-04-12 00:04:16 +01:00
parent 6c0659de60
commit a5372eafe1
12 changed files with 449 additions and 125 deletions

52
KTC1.md Normal file
View File

@ -0,0 +1,52 @@
# KTC1 Specification
KittenOS Texture Compression 1 is an image compression format that, while not
size-optimized or performance-optimized for OC screens, is optimized for
streaming from disk, and always produces precise results.
KTC1's concepts are "inspired by" ETC1, and it was conceived after evaluating
ETC1 for use in KittenOS NEO. ETC1, however, is not optimally fit for
OpenComputers rendering, and thus KTC1 was created to provide an equal-size
solution that better fit these requirements.
A 256-colour palette is assumed, and it is assumed that the palette is provided
outside of KTC1's context.
A KTC1 block is one OpenComputers character (2x4 pixels), and is 4 bytes long.
The format amounts to a foreground palette index, a background palette index,
and a Unicode character index in the Basic Multilingual Plane.
The unicode character is displayed with the given colours at the position of the
block.
The renderer does not get more complicated when more blocks are involved.
Simply put, blocks that are overlapped by a previous wide character are to be
totally ignored.
The size of this format is equivalent to 4-bit indexed data and to ETC1.
For standardization's sake, the container format for KTC1 has an 8-byte header:
"OC" followed by two 16-bit big-endian unsigned integers, for width
and height in blocks, the bytes-per-block count for this format (4) as
an unsigned byte, and the amount of "comment" bytes that go after the image,
as another unsigned byte.
Example image, showing a 4x4 white "A" on black, with a standard text
black "A" on white underneath:
4F 43 00 02 00 02 04 00
FF 00 28 6E FF 00 28 B5
00 FF 00 41 00 FF 00 00
## Additional Notes
A KTC1 file is theoretically a "lossless" screenshot under the limits of the
OpenComputers system assuming the palette is correct.
The Basic Multilingual Plane access allows mixing images and text inside a
KTC1 file, and covers all characters that OpenComputers supports.
This makes KTC1 an interesting option for use as a mixed text/image interchange
format between applications.

View File

@ -120,11 +120,11 @@ local function monitorGPUColours(m, cb, bg, fg)
local nbg = m[5]
local nfg = m[6]
if nbg ~= bg then
cb.setBackground(bg)
pcall(cb.setBackground, bg)
m[5] = bg
end
if nfg ~= fg then
cb.setForeground(fg)
pcall(cb.setForeground, fg)
m[6] = fg
end
end
@ -138,11 +138,11 @@ local function doBackgroundLine(m, mg, bdx, bdy, bdl)
monitorGPUColours(m, mg, 0x000000, 0xFFFFFF)
local str = unicode.sub(statusLine, bdx, bdx + bdl - 1)
local strl = unicode.len(str)
mg.set(bdx, bdy, unicode.undoSafeTextFormat(str))
mg.fill(bdx + strl, bdy, bdl - strl, 1, " ")
pcall(mg.set, bdx, bdy, unicode.undoSafeTextFormat(str))
pcall(mg.fill, bdx + strl, bdy, bdl - strl, 1, " ")
else
monitorGPUColours(m, mg, 0x000020, 0)
mg.fill(bdx, bdy, bdl, 1, " ")
pcall(mg.fill, bdx, bdy, bdl, 1, " ")
end
end
@ -265,7 +265,7 @@ local function moveSurface(surface, m, x, y, w, h, force)
if renderingAllowed() and not force then
local cb, b = monitors[m][1]()
if b then
monitorResetBF(b)
monitorResetBF(monitors[m])
end
if cb then
cb.copy(ox, oy, w, h, x - ox, y - oy)
@ -326,7 +326,7 @@ local function handleSpan(target, x, y, text, bg, fg)
base = unicode.sub(text, buildingSegment, buildingSegmentE)
-- rely on undoSafeTextFormat for this transform now
monitorGPUColours(m, cb, bg, fg)
cb.set(buildingSegmentWX, buildingSegmentWY, unicode.undoSafeTextFormat(base))
pcall(cb.set, buildingSegmentWX, buildingSegmentWY, unicode.undoSafeTextFormat(base))
buildingSegment = nil
end
end
@ -520,15 +520,37 @@ everestProvider(function (pkg, pid, sendSig)
end
end)
-- THE EVEREST USER API ENDS (now for the session API, which just does boring stuff)
-- used later on for lost monitor, too
local function disclaimMonitor(mon)
neo.ensureType(mon, "string")
screens.disclaim(mon)
for k, v in ipairs(monitors) do
if v[2] == mon then
table.remove(monitors, k)
reconcileAll()
return true
end
end
return false
end
everestSessionProvider(function (pkg, pid, sendSig)
return {
endSession = function (gotoBristol)
neo.ensureType(gotoBristol, "boolean")
shuttingDown = true
if gotoBristol then
suggestAppsStop()
dying()
end
end,
getMonitors = function ()
local details = {}
for k, v in ipairs(monitors) do
details[k] = v[2]
end
return details
end,
disclaimMonitor = disclaimMonitor
}
end)
-- THE EVEREST SESSION API ENDS
@ -539,7 +561,14 @@ end)
-- Alt-Up/Down/Left/Right: Move surface
local isAltDown = false
local isCtrDown = false
local function key(ka, kc, down)
local function key(ku, ka, kc, down)
local ku = screens.getMonitorByKeyboard(ku)
if not ku then return end
for k, v in ipairs(monitors) do
if v[2] == mu then
lIM = k
end
end
local focus = surfaces[1]
if kc == 29 then isCtrDown = down end
if kc == 56 then isAltDown = down end
@ -617,16 +646,10 @@ 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)
key(s[2], s[3], s[4], true)
end
if s[1] == "h.key_up" then
key(s[3], s[4], false)
key(s[2], s[3], s[4], false)
end
if s[1] == "h.clipboard" then
if surfaces[1] then
@ -697,13 +720,7 @@ while not shuttingDown do
performClaim(s[3])
end
if s[2] == "lost" then
for k, v in ipairs(monitors) do
if v[2] == s[3] then
table.remove(monitors, k)
reconcileAll()
break
end
end
handleLostMonitor(s[3])
end
end
if s[1] == "x.neo.sys.manage" then

View File

@ -47,14 +47,14 @@ local settings = {
local function loadSettings()
pcall(function ()
local fw = require("sys-filewrap")
local se = require("serial")
local fw = require("sys-filewrap").create
local se = require("serial").deserialize
local st = fw(fs.primary, "data/sys-glacier/sysconf.lua", false)
local cfg = st.read("*a")
st.close()
st = nil
fw = nil
cfg = se.deserialize(cfg)
cfg = se(cfg)
for k, v in pairs(cfg) do
if type(k) == "string" then
if type(v) == "string" then
@ -65,11 +65,11 @@ local function loadSettings()
end)
end
local function saveSettings()
local fw = require("sys-filewrap")
local se = require("serial")
local fw = require("sys-filewrap").create
local se = require("serial").serialize
fs.primary.makeDirectory("data/sys-glacier")
local st = fw(fs.primary, "data/sys-glacier/sysconf.lua", true)
st.write(se.serialize(settings))
st.write(se(settings))
st.close()
end
@ -252,7 +252,6 @@ donkonitRDProvider(function (pkg, pid, sendSig)
end
end
end,
getClaimable = function ()
local c = {}
-- do we have gpu?

View File

@ -78,24 +78,31 @@ nexus = {
end
}
local function matchesSvc(xd, pkg, perm)
local function getPfx(xd, pkg)
-- This is to ensure the prefix naming scheme is FOLLOWED!
-- sys- : System, part of KittenOS NEO and thus tries to present a "unified fragmented interface" in 'neo'
-- app- : Application - these can have ad-hoc relationships. It is EXPECTED these have a GUI
-- svc- : Service - Same as Application but with no expectation of desktop usability
-- Libraries "have no rights" as they are essentially loadable blobs of Lua code.
-- They have access via the calling program, and have a subset of the NEO Kernel API
-- Apps can register with their own name, w/ details
local pfx = nil
if pkg:sub(1, 4) == "app-" then pfx = "app" end
if pkg:sub(1, 4) == "svc-" then pfx = "svc" end
if pfx then
-- Apps can register with their own name, w/ details
return xd .. pfx .. "." .. pkg:sub(5)
end
end
local function matchesSvc(xd, pkg, perm)
local pfx = getPfx(xd, pkg)
if pfx then
local permAct = perm
local paP = permAct:match("/[a-z0-9/%.]*$")
if paP then
permAct = permAct:sub(1, #permAct - #paP)
end
if permAct == xd .. pfx .. "." .. pkg:sub(5) then
if permAct == pfx then
return "allow"
end
end
@ -113,6 +120,9 @@ donkonitDFProvider(function (pkg, pid, sendSig)
end
return {
showFileDialogAsync = function (forWrite)
if not rawequal(forWrite, nil) then
require("sys-filewrap").ensureMode(forWrite)
end
-- Not hooked into the event API, so can't safely interfere
-- Thus, this is async and uses a return event.
local tag = {}
@ -124,6 +134,7 @@ donkonitDFProvider(function (pkg, pid, sendSig)
end)
return tag
end,
myApi = getPfx("", pkg),
lockPerm = function (perm)
-- Are we allowed to?
if not matchesSvc("x.", pkg, perm) then
@ -141,22 +152,22 @@ donkonitDFProvider(function (pkg, pid, sendSig)
end,
-- Paths must begin with / implicitly
list = function (path)
if type(path) ~= "string" then error("Expected path to be string") end
neo.ensureType(path, "string")
path = prefixNS .. path
neo.ensurePath(path, prefixWS)
if path:sub(#path, #path) ~= "/" then error("Expected / at end") end
return fs.primary.list(path:sub(1, #path - 1))
end,
makeDirectory = function (path)
if type(path) ~= "string" then error("Expected path to be string") end
neo.ensureType(path, "string")
path = prefixNS .. path
neo.ensurePath(path, prefixWS)
if path:sub(#path, #path) == "/" then error("Expected no / at end") end
return fs.primary.makeDirectory(path)
end,
rename = function (path1, path2)
if type(path1) ~= "string" then error("Expected path to be string") end
if type(path2) ~= "string" then error("Expected path to be string") end
neo.ensureType(path1, "string")
neo.ensureType(path2, "string")
path1 = prefixNS .. path1
path2 = prefixNS .. path2
neo.ensurePath(path1, prefixWS)
@ -166,12 +177,12 @@ donkonitDFProvider(function (pkg, pid, sendSig)
return fs.primary.rename(path1, path2)
end,
open = function (path, mode)
if type(path) ~= "string" then error("Expected path to be string") end
if type(mode) ~= "boolean" then error("Expected mode to be boolean (writing)") end
neo.ensureType(path, "string")
-- mode verified by filewrap
path = prefixNS .. path
neo.ensurePath(path, prefixWS)
if path:sub(#path, #path) == "/" then error("Expected no / at end") end
local fw, closer = require("sys-filewrap")(fs.primary, path, mode)
local fw, closer = require("sys-filewrap").create(fs.primary, path, mode)
local oc = fw.close
fw.close = function ()
oc()
@ -181,14 +192,14 @@ donkonitDFProvider(function (pkg, pid, sendSig)
return fw
end,
remove = function (path)
if type(path) ~= "string" then error("Expected path to be string") end
neo.ensureType(path, "string")
path = prefixNS .. path
neo.ensurePath(path, prefixWS)
if path:sub(#path, #path) == "/" then error("Expected no / at end") end
return fs.primary.remove(path)
end,
stat = function (path)
if type(path) ~= "string" then error("Expected path to be string") end
neo.ensureType(path, "string")
path = prefixNS .. path
neo.ensurePath(path, prefixWS)
if path:sub(#path, #path) == "/" then error("Expected no / at end") end

View File

@ -31,22 +31,24 @@ local function shutdown(reboot)
end
local function rstfbDraw(gpu)
gpu.setBackground(0xFFFFFF)
gpu.setForeground(0x000000)
pcall(gpu.setBackground, 0xFFFFFF)
pcall(gpu.setForeground, 0x000000)
end
local function basicDraw(gpu)
scrW, scrH = gpu.getResolution()
gpu.fill(1, 1, scrW, scrH, " ")
gpu.set(2, 2, "KittenOS NEO")
local ok, sw, sh = pcall(gpu.getResolution)
if not ok then return end
scrW, scrH = sw, sh
pcall(gpu.fill, 1, 1, scrW, scrH, " ")
pcall(gpu.set, 2, 2, "KittenOS NEO")
end
local function advDraw(gpu)
basicDraw(gpu)
local usage = math.floor((os.totalMemory() - os.freeMemory()) / 1024)
gpu.set(2, 3, "RAM Usage: " .. usage .. "K / " .. math.floor(os.totalMemory() / 1024) .. "K")
pcall(gpu.set, 2, 3, "RAM Usage: " .. usage .. "K / " .. math.floor(os.totalMemory() / 1024) .. "K")
for i = 1, #warnings do
gpu.set(2, 6 + i, warnings[i])
pcall(gpu.set, 2, 6 + i, warnings[i])
end
end
@ -91,10 +93,12 @@ local function retrieveNssMonitor(nss)
if gpu then
local gcb = gpu()
if gcb then
table.insert(subpool, {gpu, v})
pcall(function ()
gcb.setBackground(0x000020)
local w, h = gcb.getResolution()
gcb.fill(1, 1, w, h, " ")
table.insert(subpool, {gpu, v})
end)
end
end
end
@ -107,9 +111,7 @@ local function retrieveNssMonitor(nss)
end
-- done with search
local gpu = gpuG()
scrW, scrH = gpu.getResolution()
rstfbDraw(gpu)
gpu.fill(1, 1, scrW, scrH, " ")
performDisclaim = function (full)
nss.disclaim(subpool[1][2])
if full then
@ -212,7 +214,7 @@ local function finalPrompt()
local gpu = gpuG()
rstfbDraw(gpu)
basicDraw(gpu)
gpu.set(2, 4, "Shutting down...")
pcall(gpu.set, 2, 4, "Shutting down...")
shutdown(false)
end
end, 2, scrH - 1, unicode.len(shButton)},
@ -223,7 +225,7 @@ local function finalPrompt()
local gpu = gpuG()
rstfbDraw(gpu)
basicDraw(gpu)
gpu.set(2, 4, "Rebooting...")
pcall(gpu.set, 2, 4, "Rebooting...")
shutdown(true)
end
end, 3 + unicode.len(shButton), scrH - 1, unicode.len(rbButton)},
@ -234,7 +236,7 @@ local function finalPrompt()
local gpu = gpuG()
rstfbDraw(gpu)
basicDraw(gpu)
gpu.set(2, 4, "Login to activate Safe Mode.")
pcall(gpu.set, 2, 4, "Login to activate Safe Mode.")
sleep(1)
gpu = gpuG()
safeModeActive = true
@ -249,14 +251,14 @@ local function finalPrompt()
local gpu = gpuG()
for k, v in ipairs(controls) do
if k == control then
gpu.setBackground(0x000000)
gpu.setForeground(0xFFFFFF)
pcall(gpu.setBackground, 0x000000)
pcall(gpu.setForeground, 0xFFFFFF)
else
gpu.setBackground(0xFFFFFF)
gpu.setForeground(0x000000)
pcall(gpu.setBackground, 0xFFFFFF)
pcall(gpu.setForeground, 0x000000)
end
gpu.fill(v[3], v[4], v[5], 1, " ")
gpu.set(v[3], v[4], v[1]())
pcall(gpu.fill, v[3], v[4], v[5], 1, " ")
pcall(gpu.set, v[3], v[4], v[1]())
end
-- event handling...
local sig = {coroutine.yield()}
@ -336,9 +338,9 @@ local function initializeSystem()
gpu.bind(screen, true)
local gW, gH = gpu.maxResolution()
gW, gH = math.min(80, gW), math.min(25, gH)
gpu.setResolution(gW, gH)
pcall(gpu.setResolution, gW, gH)
pcall(gpu.setDepth, gpu.maxDepth()) -- can crash on OCEmu if done at the "wrong time"
gpu.setForeground(0x000000)
pcall(gpu.setForeground, 0x000000)
end
local w = 1
local steps = {
@ -373,12 +375,12 @@ local function initializeSystem()
end
if ev[1] == "k.timer" then
if gpu then
gpu.setForeground(0x000000)
pcall(gpu.setForeground, 0x000000)
if w < stepCount then
local n = math.floor((w / stepCount) * 255)
gpu.setBackground((n * 0x10000) + (n * 0x100) + n)
pcall(gpu.setBackground, (n * 0x10000) + (n * 0x100) + n)
else
gpu.setBackground(0xFFFFFF)
pcall(gpu.setBackground, 0xFFFFFF)
end
basicDraw(gpu)
end
@ -440,7 +442,7 @@ if finalPrompt() then
basicDraw(gpu)
local nsm = neo.requestAccess("x.neo.sys.manage")
if nsm then
gpu.set(2, 4, "Rebooting for Safe Mode...")
pcall(gpu.set, 2, 4, "Rebooting for Safe Mode...")
for _, v in ipairs(nsm.listSettings()) do
if v ~= "password" then
nsm.delSetting(v)
@ -448,10 +450,10 @@ if finalPrompt() then
end
else
-- assume sysconf.lua did something very bad
gpu.set(2, 4, "No NSM. Wiping configuration completely.")
pcall(gpu.set, 2, 4, "No NSM. Wiping configuration completely.")
local fs = neo.requestAccess("c.filesystem")
if not fs then
gpu.set(2, 4, "Failed to get permission, you're doomed.")
pcall(gpu.set, 2, 4, "Failed to get permission, you're doomed.")
end
fs.primary.remove("/data/sys-glacier/sysconf.lua")
end

View File

@ -270,13 +270,17 @@ wrapTable = wrapMeta(table)
wrapString = wrapMeta(string)
wrapUnicode = wrapMeta(unicode)
wrapCoroutine = wrapMeta(coroutine)
wrapOs = wrapMeta({
totalMemory = computer.totalMemory, freeMemory = computer.freeMemory,
energy = computer.energy, maxEnergy = computer.maxEnergy,
clock = os.clock, date = os.date, difftime = os.difftime,
time = os.time, uptime = computer.uptime, address = computer.address
})
-- inject stuff into os
os.totalMemory = computer.totalMemory
os.freeMemory = computer.freeMemory
os.energy = computer.energy
os.maxEnergy = computer.maxEnergy
os.uptime = computer.uptime
os.address = computer.address
wrapOs = wrapMeta(os)
wrapDebug = wrapMeta(debug)
wrapBit32 = wrapMeta(bit32)
wrapUtf8 = wrapMeta(utf8)
baseProcEnvCore = {
_VERSION = _VERSION,
@ -287,6 +291,8 @@ baseProcEnvCore = {
coroutine = wrapCoroutine,
os = wrapOs,
debug = wrapDebug,
bit32 = wrapBit32,
utf8 = wrapUtf8,
require = loadLibraryInner,
assert = assert, ipairs = ipairs,
load = load,
@ -382,7 +388,7 @@ function retrieveAccess(perm, pkg, pid)
-- "c.<hw>": Component
-- "s.<event>": Signal receiver (with responsibilities for Security Request watchers)
-- "s.k.<...>": Kernel stuff
-- "s.k.procnew" : New process (pkg, pid)
-- "s.k.procnew" : New process (pkg, pid, ppkg, ppid)
-- "s.k.procdie" : Process dead (pkg, pid, reason, usage)
-- "s.k.registration" : Registration of service alert ("x." .. etc)
-- "s.k.deregistration" : Registration of service alert ("x." .. etc)
@ -480,7 +486,7 @@ function retrieveAccess(perm, pkg, pid)
end
end
function start(pkg, ...)
function start(pkg, ppkg, ppid, ...)
local proc = {}
local pid = lastPID
lastPID = lastPID + 1
@ -571,7 +577,7 @@ function start(pkg, ...)
env.neo.scheduleTimer = function (time)
ensureType(time, "number")
local tag = {}
table.insert(timers, {time, execEvent, pid, "k.timer", tag, time, ofs})
table.insert(timers, {time, execEvent, pid, "k.timer", tag, time})
return tag
end
@ -587,9 +593,9 @@ function start(pkg, ...)
proc.deathCBs = {function () pcall(function () env.neo.dead = true end) end}
proc.cpuUsage = 0
-- Note the target process doesn't get the procnew (the dist occurs before it's creation)
pcall(distEvent, nil, "k.procnew", pkg, pid)
pcall(distEvent, nil, "k.procnew", pkg, pid, ppkg, ppid)
processes[pid] = proc
table.insert(timers, {0, execEvent, pid, ...})
table.insert(timers, {0, execEvent, pid, ppkg, ppid, ...})
return pid
end

View File

@ -113,7 +113,7 @@ getFsNode = function (fs, parent, fsc, path, mode)
end,
unknownAvailable = mode ~= nil,
selectUnknown = function (text)
local rt, re = require("sys-filewrap")(fsc, path .. text, mode)
local rt, re = require("sys-filewrap").create(fsc, path .. text, mode)
if not rt then
return false, dialog("Open Error: " .. tostring(re), parent)
end
@ -130,8 +130,14 @@ getFsNode = function (fs, parent, fsc, path, mode)
return nil, parent
end})
if mode ~= nil then
table.insert(n, {"Open", function ()
local rt, re = require("sys-filewrap")(fsc, path, mode)
local tx = "Open"
if mode == true then
tx = "Save"
elseif mode == "append" then
tx = "Append"
end
table.insert(n, {tx, function ()
local rt, re = require("sys-filewrap").create(fsc, path, mode)
if not rt then
return false, dialog("Open Error: " .. tostring(re), parent)
end
@ -139,7 +145,7 @@ getFsNode = function (fs, parent, fsc, path, mode)
end})
end
table.insert(n, {"Copy", function ()
local rt, re = require("sys-filewrap")(fsc, path, false)
local rt, re = require("sys-filewrap").create(fsc, path, false)
if not rt then
return false, dialog("Open Error: " .. tostring(re), parent)
end

View File

@ -1,9 +1,25 @@
-- This is released into the public domain.
-- No warranty is provided, implied or otherwise.
return function(dev, file, mode)
local function ensureMode(mode)
local n = "rb"
if mode then n = "wb" end
if type(mode) == "boolean" then
if mode then
n = "wb"
end
elseif type(mode) == "string" then
if mode == "append" then
n = "ab"
else
error("Invalid fmode " .. mode)
end
else
error("Invalid fmode")
end
return n
end
local function create(dev, file, mode)
local n = ensureMode(mode)
local handle, r = dev.open(file, n)
if not handle then return nil, r end
local open = true
@ -14,15 +30,8 @@ return function(dev, file, mode)
dev.close(handle)
end)
end
local function seeker(whence, point)
local function reader(len)
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 = ""
local c = dev.read(handle, neo.readBufSize)
@ -35,16 +44,31 @@ return function(dev, file, mode)
if type(len) ~= "number" then error("Length of read must be number or '*a'") end
return dev.read(handle, len)
end
local function writer(txt)
if not open then return end
neo.ensureType(txt, "string")
return dev.write(handle, txt)
end
local function seeker(whence, point)
if not open then return end
return dev.seek(handle, whence, point)
end
if mode == "rb" then
return {
close = closer,
seek = seeker,
read = reader
}, closer
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)
if not ok then error(tostring(b)) end
end
read = reader,
write = writer
}, closer
end
end
return {
createMode = createMode,
create = create
}

View File

@ -36,6 +36,7 @@ return {
"docs/us-nxapp",
"docs/us-setti",
"docs/ul-seria",
"docs/ul-fwrap",
"docs/ul-event",
"docs/ul-fmttx",
"docs/ul-neoux",

View File

@ -57,7 +57,7 @@ The following are just wrapMeta'd
host libraries (*: altered):
math, table, string, unicode*,
coroutine, os*, debug
coroutine, os*, debug, utf8, bit32
unicode is extended with:
safeTextFormat(s, p):
@ -92,14 +92,11 @@ Programs that thus try to work around
as-needed if and when the issue is
resolved.
os is replaced with (wrapMeta'd):
os is extended with:
totalMemory = computer.totalMemory,
freeMemory = computer.freeMemory,
energy = computer.energy,
maxEnergy = computer.maxEnergy,
clock = os.clock, date = os.date,
difftime = os.difftime,
time = os.time,
uptime = computer.uptime,
address = computer.address
@ -317,6 +314,38 @@ The additional things available to
and timers stick around after the
process that owns them is dead.
The list of events, tacked on at the
end here:
k.procnew(pkg, pid, ppkg, ppid):
New process creation, with parent
information (for seat tracking)
This is not given to the process
being created, as all of this gets
given to it anyway on main function
start.
k.procdie(pkg, pid, reason, cpuTime):
Process death.
k.registration(uid):
Registration of an access.
k.deregistration(uid):
Deregistration of an access.
k.securityresponse(perm, obj):
Response to a security request made
with neo.requestAccess or such.
k.timer(tag, time):
A timer. Includes the planned uptime
for comparison.
h.*(...):
Hardware signals, by type, such
as "h.key_up"
With that, I hope I have documented
the kernel's interface to programs.

49
repository/docs/ul-fwrap Normal file
View File

@ -0,0 +1,49 @@
"sys-filewrap" is responsible for
wrapping a filesystem object with a
file-like mechanism.
It simply provides two functions:
ensureMode(mode): Ensures that a
mode is valid, and translates it.
create(dev, file, mode):
Open a file using a given proxy,
filename and mode.
The mode you give to it can be one of
the following:
false: Read "rb"
true: Write "wb"
"append": Append "ab"
May have some readability
propertiues - just in
case, I've added 'read',
but don't get your hopes
up...
It returns two things - a table, that
being the file object, and the
'close' function from that object,
for closing the file without using
a potentially modifiable table.
If the table is nil, then the "close"
function is actually a string, that
being the error.
The possible functions are:
[arw] close(): Closes the file.
[arw] seek(whence, pos): Seeks in
the file.
[aw] write(data): Writes to the
file.
[arw] read(data): Reads from the
file.
NOTE: Some of these may not actually
work. They're just there as more or
less a "do no harm" approach.
-- This is released into
the public domain.
-- No warranty is provided,
implied or otherwise.

View File

@ -18,6 +18,16 @@ For programs with the prefixes "svc-"
pattern "/[a-z0-9/%.]*$", or none
at all.
Examples:
r.app.nucleus:
Registers x.app.nucleus from
app-nucleus
r.svc.nucleus/ABCD:
Registers x.svc.nucleus/ABCD from
svc-nucleus
For how this registration works,
and how to access the resulting
service, please see the kn-perms
@ -33,31 +43,149 @@ APIs registered in this manner are
mechanism if they so wish, and this
will cause a silent failure of the
lockPerm function.)
A mechanism may also be introduced
in later versions of KittenOS NEO to
easily allow changing your svc/app's
own API to a "ask"-style security
model, but this will not be the
default, and may still be overridden
by a user with access to the
Advanced Settings control panel.
As for the system APIs...
-- x.neo.pub.base @ sys-icecap --
-- x.neo.pub.session @ <a shell> --
Gaining access to this API creates
this application's data directory,
wherever that is.
This API is
Paths for the IO parts of this API
must start with "/", and must follow
the standard KittenOS NEO path
safety rules in the kernel.
-- x.neo.pub.window @ <a shell> --
showFileDialogAsync(mode): Shows a
filedialog with a given filemode,
or nil for "none". Returns a new,
empty table as a "tag", and emits a
"filedialog" event on completion.
myApi: A string such as "svc.abc"
for the program svc-abc, used for
automatically finding the correct
API name to register for your app.
lockPerm(perm): Changes the default
permission setting for anything the
process should have permission to
define according to the matchesSvc
function, so that the user must be
asked before a program can access
the permission.
NOTE: LIST REQUIRES "/" AT THE END
AND START, WHILE THE REST CANNOT
HAVE IT AT THE END BUT MUST AT THE
START, BECAUSE THE ROOT IS "/".
There's logic here, specifically to
stop you trying to do nonsense like
deleting your own data directory...
list(path): After ensuring that the
path has a "/" at the end, lists
the contents of a directory
accessible to the application.
Returns a table containing
file/directory names, with "/"
postfixes for directories. If this
contains the invalid names "." or
"..", please report as a bug at
once, this shouldn't happen.
Everything after here ensures that
there is a "/" at the start and no
"/" at the end
makeDirectory(path): Creates the
directory with the given path.
Returns whatever the component call
did.
rename(pathA, pathB): Renames or
moves a file or directory around.
Returns whatever the component call
did.
open(path, mode): Opens a file with
a given mode (see ul-fwrap for the
list of modes).
Returns the file object,
remove(path): Removes a file.
stat(path): "I got lazy, so I took 3
API functions and combined them as
one API function!" - 20kdc
Returns {
isDirectory
size
lastModified
}
spaceUsed, spaceTotal, isReadOnly:
The filesystem proxy functions.
Events:
api, "filedialog", tag, res
-- x.neo.pub.session @ <a shell> --
This API must be implemented by any
program that the user wants to use
as a shell.
A shell should set up a Saving Throw
with sys-glacier in case of errors.
endSession(backToInit): Stops the
current session, and optionally
starts up sys-init.
endSession(false) is for switching
to a new shell.
endSession(true) is for logging out
of the session.
getMonitors(): Returns an ipairs-
form list of screen addresses for
use in disclaimMonitor and the
subsequent screens.claim call.
disclaimMonitor(address):
Disclaims a monitor. Returns true
on success. The monitor may be
reclaimed if something causes the
shell to be notified of the
monitor's existence (such as a
monitor rescan in Glacier).
No events are given. Deregistration
is equivalent to stating that you
are no longer in control of the
session, and that something else is.
-- x.neo.pub.window @ sys-everest --
This API is the reference definition
of how the windowing system works in
KittenOS NEO.
-- x.neo.sys.manage @ sys-glacier --
This API is how settings and ST are
managed
-- x.neo.sys.screens @ sys-glacier --
This API is how screens are managed
-- x.neo.pub.globals @ sys-glacier --
This API is some public global stuff
and spooky screen control???
-- This is released into
the public domain.
-- No warranty is provided,