aboutsummaryrefslogtreecommitdiff
path: root/src/syslua
diff options
context:
space:
mode:
authorAlex Auvolat <alex@adnab.me>2018-04-01 23:23:34 +0200
committerAlex Auvolat <alex@adnab.me>2018-04-01 23:23:34 +0200
commita36c6528b10cb5b5d48fbf30a941443f738c9dd1 (patch)
tree19249d98dbe3a55d5f18050797959d7ca64a97bd /src/syslua
parent67db86ec53336da886153797deb643483e9596d0 (diff)
downloadkogata-a36c6528b10cb5b5d48fbf30a941443f738c9dd1.tar.gz
kogata-a36c6528b10cb5b5d48fbf30a941443f738c9dd1.zip
Terminal inside Lua window manager
Diffstat (limited to 'src/syslua')
-rw-r--r--src/syslua/lx/gip.lua177
-rw-r--r--src/syslua/lx/gui.lua19
-rw-r--r--src/syslua/lx/protodef.lua29
-rw-r--r--src/syslua/lx/sysdef.lua2
-rw-r--r--src/syslua/lx/tk.lua56
5 files changed, 274 insertions, 9 deletions
diff --git a/src/syslua/lx/gip.lua b/src/syslua/lx/gip.lua
new file mode 100644
index 0000000..8ae06bf
--- /dev/null
+++ b/src/syslua/lx/gip.lua
@@ -0,0 +1,177 @@
+local sys = require 'lx.sys'
+local protodef = require 'lx.protodef'
+local mainloop = require 'lx.mainloop'
+
+local gip = {}
+
+gip.proto = {
+ -- Definitions from proto/gip.h
+ GIPF_DOUBLE_BUFFER = 0x1,
+ GIPF_DAMAGE_NOTIF = 0x2,
+ GIPF_MODESET = 0x4,
+ GIPF_MOUSE_XY = 0x10,
+ GIPF_MOUSE_CURSOR = 0x20,
+
+ GIPC_RESET = 0,
+ GIPR_INITIATE = 1,
+ GIPR_OK = 2,
+ GIPR_FAILURE = 3,
+ GIPC_ENABLE_FEATURES = 4,
+ GIPC_DISABLE_FEATURES = 5,
+
+ GIPN_BUFFER_INFO = 10,
+ GIPC_QUERY_MODE = 11,
+ GIPR_MODE_INFO = 12,
+ GIPC_SET_MODE = 13,
+
+ GIPN_BUFFER_DAMAGE = 14,
+ GIPC_SWITCH_BUFFER = 15,
+
+ GIPN_KEY_DOWN = 20,
+ GIPN_KEY_UP = 21,
+
+ GIPN_MOUSE_DATA = 30,
+ GIPN_MOUSE_XY = 31,
+ GIPN_MOUSE_PRESSED = 32,
+ GIPN_MOUSE_RELEASED = 33,
+
+ gip_msg_header = {
+ fmt = 'LLL', -- code, req_id, arg
+ len = 12
+ },
+ -- buffer_info_msg = protodef.token .. protodef.fb_info
+ buffer_info_msg = {
+ len = protodef.token.len + protodef.fb_info.len
+ },
+ -- mode_info_msg = protodef.fb_info
+ mode_info_msg = {
+ len = protodef.fb_info.len
+ },
+ -- buffer_damage_msg = protodef.fb_region
+ buffer_damage_msg = {
+ len = protodef.fb_region.len
+ },
+}
+
+gip.new_handler = function(fd)
+ local h = {}
+ h.fd = fd
+
+ -- Replacable callbacks
+ function h:cb_reset(req_id, arg) end
+ function h:cb_initiate(req_id, arg) end
+ function h:cb_ok(req_id, arg) end
+ function h:cb_failure(req_id, arg) end
+ function h:cb_enable_features(req_id, arg) end
+ function h:cb_disable_features(req_id, arg) end
+ function h:cb_query_mode(req_id, arg) end
+ function h:cb_set_mode(req_id, arg) end
+ function h:cb_switch_buffer(req_id, arg) end
+ function h:cb_key_down(req_id, arg) end
+ function h:cb_key_up(req_id, arg) end
+ function h:cb_buffer_info(req_id, arg, token, fb_info) end
+ function h:cb_mode_info(req_id, arg, fb_info) end
+ function h:cb_buffer_damage(req_id, arg, region) end
+ function h:cb_unknown_message(code, req_id, arg) error("Unknown GIP message") end
+ function h:fd_error() error("GIP FD error") end
+
+ h.requests_in_progress = {}
+ h.msg_id = 0
+
+ h.mainloop_fd = mainloop.add_fd(h.fd, function() h:fd_error() end)
+
+ function h:send_msg(code, req_id, arg, data)
+ if req_id == nil then
+ req_id = h.msg_id
+ h.msg_id = h.msg_id + 1
+ end
+
+ local msgdata = string.pack(gip.proto.gip_msg_header.fmt, code, req_id, arg)
+ if code == gip.proto.GIPN_BUFFER_INFO then
+ msgdata = msgdata .. string.pack(protodef.token.fmt, data.tok)
+ .. string.pack(protodef.fb_info.fmt, data.geom.width, data.geom.height,
+ data.geom.pitch, data.geom.bpp, data.geom.memory_model)
+ elseif code == gip.proto.GIPN_MODE_INFO then
+ error("Not implemented") --TODO
+ elseif code == gip.proto.GIPN_BUFFER_DAMAGE then
+ error("Not implemented") --TODO
+ end
+
+ h.mainloop_fd:write(msgdata)
+ return req_id
+ end
+
+ function h:cmd(code, arg, data, cb)
+ local req_id = h:send_msg(code, nil, arg, data)
+ h.requests_in_progress[req_id] = cb
+ end
+
+ function h:got_reply(code, req_id, arg, data)
+ if h.requests_in_progress[req_id] ~= nil then
+ h.requests_in_progress[req_id](code, arg, data)
+ h.requests_in_progress[req_id] = nil
+ end
+ end
+
+ local function gip_handler(ev)
+ local code, req_id, arg = string.unpack(gip.proto.gip_msg_header.fmt, ev)
+
+ if code == gip.proto.GIPC_RESET then
+ h:cb_reset(req_id, arg)
+ elseif code == gip.proto.GIPR_INITIATE then
+ h:cb_initiate(req_id, arg)
+ h:got_reply(code, req_id, arg)
+ elseif code == gip.proto.GIPR_OK then
+ h:cb_ok(req_id, arg)
+ h:got_reply(code, req_id, arg)
+ elseif code == gip.proto.GIPR_FAILURE then
+ h:cb_failure(req_id, arg)
+ h:got_reply(code, req_id, arg)
+ elseif code == gip.proto.GIPC_ENABLE_FEATURE then
+ h:cb_enable_feature(req_id, arg)
+ elseif code == gip.proto.GIPC_DISABLE_FEATURE then
+ h:cb_disable_feature(req_id, arg)
+ elseif code == gip.proto.GIPC_QUERY_MODE then
+ h:cb_query_mode(req_id, arg)
+ elseif code == gip.proto.GIPC_SET_MODE then
+ h:cb_set_mode(req_id, arg)
+ elseif code == gip.proto.GIPC_SWITCH_BUFFER then
+ h:cb_switch_buffer(req_id, arg)
+ elseif code == gip.proto.GIPN_KEY_DOWN then
+ h:cb_key_down(req_id, arg)
+ elseif code == gip.proto.GIPN_KEY_UP then
+ h:cb_key_up(req_id, arg)
+ elseif code == gip.proto.GIPN_BUFFER_INFO then
+ h.mainloop_fd:expect(gip.proto.buffer_info_msg.len, function(msg)
+ local tok, p1 = string.unpack(protodef.token.fmt, msg)
+ local w, h, pitch, bpp, mm = string.unpack(protodef.fb_info.fmt, msg, p1)
+ h:cb_buffer_info(req_id, arg, token, {
+ width = w, height = h,
+ pitch = pitch, bpp = bpp, memory_model = mm })
+ end)
+ elseif code == gip.proto.GIPR_MODE_INFO then
+ h.mainloop_fd:expect(gip.proto.mode_info_msg.len, function(msg)
+ local w, h, pitch, bpp, mm = string.unpack(protodef.fb_info.fmt, msg)
+ local info = {
+ width = w, height = h,
+ pitch = pitch, bpp = bpp, memory_model = mm }
+ h:cb_mode_info(req_id, arg, info)
+ h:got_reply(code, req_id, arg, info)
+ end)
+ elseif code == gip.proto.GIPN_BUFFER_DAMAGE then
+ h.mainloop_fd:expect(gip.proto.buffer_damage_msg.len, function(msg)
+ local rx, ry, rw, rh = string.unpack(protodef.fb_region.fmt, msg)
+ h:cb_buffer_damage(req_id, arg, { x = rx, y = ry, w = rw, h = rh })
+ end)
+ else
+ h:cb_unknown_message(code, req_id, arg)
+ end
+
+ h.mainloop_fd:expect(gip.proto.gip_msg_header.len, gip_handler)
+ end
+ h.mainloop_fd:expect(gip.proto.gip_msg_header.len, gip_handler)
+
+ return h
+end
+
+return gip
diff --git a/src/syslua/lx/gui.lua b/src/syslua/lx/gui.lua
index 6cfb545..9342025 100644
--- a/src/syslua/lx/gui.lua
+++ b/src/syslua/lx/gui.lua
@@ -1,5 +1,6 @@
local sys = require 'lx.sys'
-local sysdef= require 'lx.sysdef'
+local sysdef = require 'lx.sysdef'
+local protodef = require 'lx.protodef'
local ioctl = require 'lx.ioctl'
local draw = require 'lx.draw'
@@ -44,12 +45,12 @@ function gui.open_io()
gui.pckbd_mainloop_fd = mainloop.add_fd(gui.pckbd_fd, function() error('pckbd fd error') end)
local function pckbd_handler(ev)
- local scancode, ty = string.unpack("HH", ev)
+ local scancode, ty = string.unpack(protodef.kbd_event.fmt, ev)
gui.on_keyboard(scancode, ty)
- gui.pckbd_mainloop_fd:expect(4, pckbd_handler)
+ gui.pckbd_mainloop_fd:expect(protodef.kbd_event.len, pckbd_handler)
end
- gui.pckbd_mainloop_fd:expect(4, pckbd_handler)
+ gui.pckbd_mainloop_fd:expect(protodef.kbd_event.len, pckbd_handler)
gui.kbdlib = kbd.init()
@@ -59,13 +60,13 @@ function gui.open_io()
gui.pcmouse_mainloop_fd = mainloop.add_fd(gui.pcmouse_fd, function() error("pcmouse fd error") end)
local function pcmouse_handler(ev)
- local dx, dy, dw, lb, rb, mb = string.unpack("hhbBBB", ev)
+ local dx, dy, dw, lb, rb, mb = string.unpack(protodef.mouse_event.fmt, ev)
local change_but = false
while not change_but do
- local bytes, n = sys.read(gui.pcmouse_fd, 1, 8)
+ local bytes, n = sys.read(gui.pcmouse_fd, 1, protodef.mouse_event.len)
if n == 8 then
- local dx2, dy2, dw2, lb2, rb2, mb2 = string.unpack("hhbBBB", ev)
+ local dx2, dy2, dw2, lb2, rb2, mb2 = string.unpack(protodef.mouse_event.fmt, ev)
change_but = change_but or (lb2 ~= lb) or (rb2 ~= rb) or (mb2 ~= mb)
dx = dx + dx2
dy = dy + dy2
@@ -78,9 +79,9 @@ function gui.open_io()
end
gui.on_mouse(dx, dy, dw, lb, rb, mb)
- gui.pcmouse_mainloop_fd:expect(8, pcmouse_handler)
+ gui.pcmouse_mainloop_fd:expect(protodef.mouse_event.len, pcmouse_handler)
end
- gui.pcmouse_mainloop_fd:expect(8, pcmouse_handler)
+ gui.pcmouse_mainloop_fd:expect(protodef.mouse_event.len, pcmouse_handler)
end
function gui.open_gip()
diff --git a/src/syslua/lx/protodef.lua b/src/syslua/lx/protodef.lua
new file mode 100644
index 0000000..f7f3fc0
--- /dev/null
+++ b/src/syslua/lx/protodef.lua
@@ -0,0 +1,29 @@
+local protodef = {
+ mouse_event = {
+ -- common/include/proto/mouse.h
+ fmt = 'hhbBBB',
+ len = 8
+ },
+ kbd_event = {
+ -- common/include/proto/keyboard.h
+ fmt = 'HH',
+ len = 4
+ },
+ token = {
+ -- common/include/proto/token.h
+ fmt = 'c16',
+ len = 16
+ }
+}
+
+-- common/include/proto/fb.h
+protodef.fb_info = {
+ fmt = 'lllll',
+ len = 20
+}
+protodef.fb_region = {
+ fmt = 'llll',
+ len = 16
+}
+
+return protodef
diff --git a/src/syslua/lx/sysdef.lua b/src/syslua/lx/sysdef.lua
index 43015e2..e2144bc 100644
--- a/src/syslua/lx/sysdef.lua
+++ b/src/syslua/lx/sysdef.lua
@@ -62,4 +62,6 @@ return {
PS_FINISHED = 3,
PS_FAILURE = 4,
PS_KILLED = 5,
+
}
+
diff --git a/src/syslua/lx/tk.lua b/src/syslua/lx/tk.lua
index e8686ba..f38efe2 100644
--- a/src/syslua/lx/tk.lua
+++ b/src/syslua/lx/tk.lua
@@ -1,5 +1,8 @@
local draw = require 'lx.draw'
local sys = require 'lx.sys'
+local gui = require 'lx.gui'
+local gip = require 'lx.gip'
+local kbdcode = require 'lx.kbdcode'
local tk = {}
@@ -225,6 +228,10 @@ function tk.widget(width, height, opts)
self.left_click_valid = false
end
+ function w:on_keyboard(scancode, ty)
+ -- Handler for raw keyboard event
+ end
+
function w:on_text_input(char)
-- Handler for text input
end
@@ -266,6 +273,12 @@ function tk.init(gui, root_widget)
root_widget:do_resize(gui.surface:width(), gui.surface:height())
+ local prev_gui_on_keyboard = gui.on_keyboard
+ gui.on_keyboard = function(scancode, ty)
+ root_widget:on_keyboard(scancode, ty)
+ prev_gui_on_keyboard(scancode, ty)
+ end
+
gui.on_key_down = function(key) root_widget:on_key_down(key) end
gui.on_key_up = function(key) root_widget:on_key_up(key) end
gui.on_text_input = function(key) root_widget:on_text_input(char) end
@@ -919,8 +932,51 @@ function tk.window_manager()
end
end
+ function wm:on_keyboard(scancode, ty)
+ wm.windows[#wm.windows].content:on_keyboard(scancode, ty)
+ end
+
return wm
end
+function tk.gipwidget(opts)
+ local w = tk.widget(nil, nil, opts)
+
+ w.geom = {
+ bpp = gui.surface_geom.bpp,
+ memory_model = gui.surface_geom.memory_model,
+ width = opts.width,
+ height = opts.height,
+ pitch = opts.width * gui.surface_geom.bpp // 8
+ }
+ w.shm_fd = sys.make_shm(w.geom.height * w.geom.pitch)
+ w.framebuffer = draw.surface_from_fd(w.shm_fd, w.geom)
+
+ w.ch_srv, w.ch_cli = sys.make_channel(false)
+ w.gip_handler = gip.new_handler(w.ch_srv)
+
+ function w.gip_handler:cb_reset(req_id, arg)
+ w.gip_handler:send_msg(gip.proto.GIPR_INITIATE, req_id, gip.proto.GIPF_DAMAGE_NOTIF)
+ w.gip_handler:send_msg(gip.proto.GIPN_BUFFER_INFO, 0, 0, { tok = sys.gen_token(w.shm_fd), geom = w.geom })
+ end
+
+ function w.gip_handler:cb_buffer_damage(req_id, arg, region)
+ w:redraw(region.x, region.y, region.w, region.h)
+ end
+
+ function w:draw(x0, y0, buf)
+ if x0 < self.framebuffer:width() and y0 < self.framebuffer:height() then
+ buf:blit(0, 0, self.framebuffer:sub(x0, y0, self.framebuffer:width(), self.framebuffer:height()))
+ end
+ end
+
+ function w:on_keyboard(scancode, ty)
+ sys.dbg_print("gipwidget:on_keyboard " .. tostring(scancode) .. "\n")
+ w.gip_handler:send_msg(ty == kbdcode.event.KEYPRESS and gip.proto.GIPN_KEY_DOWN or gip.proto.GIPN_KEY_UP, nil, scancode)
+ end
+
+ return w
+end
+
return tk