diff options
Diffstat (limited to 'src/syslua/lx/gip.lua')
-rw-r--r-- | src/syslua/lx/gip.lua | 177 |
1 files changed, 177 insertions, 0 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 |