diff options
Diffstat (limited to 'src/syslua/lx')
-rw-r--r-- | src/syslua/lx/gip.lua | 177 | ||||
-rw-r--r-- | src/syslua/lx/gui.lua | 19 | ||||
-rw-r--r-- | src/syslua/lx/protodef.lua | 29 | ||||
-rw-r--r-- | src/syslua/lx/sysdef.lua | 2 | ||||
-rw-r--r-- | src/syslua/lx/tk.lua | 56 |
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 |