aboutsummaryrefslogblamecommitdiff
path: root/src/syslua/lx/gip.lua
blob: 8ae06bfdca6b6f5b7a6f822bd7c957291eaaf303 (plain) (tree)
















































































































































































                                                                                                                                                       
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