diff --git a/js/x11/core/ext/randr.js b/js/x11/core/ext/randr.js new file mode 100644 index 0000000..5da7f06 --- /dev/null +++ b/js/x11/core/ext/randr.js @@ -0,0 +1,307 @@ +// http://www.x.org/releases/X11R7.6/doc/randrproto/randrproto.txt + +var x11 = Require('x11/core/x11'); +// TODO: move to templates + +exports.requireExt = function(display, callback) +{ + var X = display.client; + X.QueryExtension('RANDR', function(err, ext) { + + if (!ext.present) + return callback(new Error('extension not available')); + + //ext.ReportLevel = { + //}; + + ext.QueryVersion = function(clientMaj, clientMin, callback) + { + X.seq_num++; + X.pack_stream.pack('CCSLL', [ext.majorOpcode, 0, 3, clientMaj, clientMin]); + X.replies[X.seq_num] = [ + function(buf, opt) { + var res = buf.unpack('LL'); + return res; + }, + callback + ]; + X.pack_stream.flush(); + }, + + ext.events = { + RRScreenChangeNotify: 0 + }, + + ext.NotifyMask = { + ScreenChange: 1, + CrtcChange: 2, + OutputChange: 4, + OutputProperty: 8, + All: 15 + }; + + ext.Rotation = { + Rotate_0: 1, + Rotate_90: 2, + Rotate_180: 4, + Rotate_270: 8, + Reflect_X: 16, + Reflect_Y: 32 + }; + + ext.ConfigStatus = { + Sucess: 0, + InvalidConfigTime: 1, + InvalidTime: 2, + Failed: 3 + }; + + ext.ModeFlag = { + HSyncPositive: 1, + HSyncNegative: 2, + VSyncPositive: 4, + VSyncNegative: 8, + Interlace: 16, + DoubleScan: 32, + CSync: 64, + CSyncPositive: 128, + CSyncNegative: 256, + HSkewPresent: 512, + BCast: 1024, + PixelMultiplex: 2048, + DoubleClock: 4096, + ClockDivideBy2: 8192 + } + + ext.SetScreenConfig = function(win, ts, configTs, sizeId, rotation, rate, cb) { + X.seq_num ++; + X.pack_stream.pack('CCSLLLSSSS', [ext.majorOpcode, 2, 6, win, ts, configTs, sizeId, rotation, rate, 0]); + X.replies[X.seq_num] = [ + function(buf, opt) { + var res = buf.unpack('LLLSSLL'); + return { + status : opt, + newTs : res [0], + configTs : res[1], + root : res[2], + subpixelOrder : res[3] + } + }, + function(err, res) { + var err; + if (res.status !== 0) { + err = new Error('SetScreenConfig error'); + err.code = res.status; + } + + cb(err, res); + } + ]; + + X.pack_stream.flush(); + }, + + ext.SelectInput = function(win, mask) + { + X.seq_num++; + X.pack_stream.pack('CCSLSS', [ext.majorOpcode, 4, 3, win, mask, 0]); + X.pack_stream.flush(); + }, + + ext.GetScreenInfo = function(win, cb) { + X.seq_num ++; + X.pack_stream.pack('CCSL', [ext.majorOpcode, 5, 2, win]); + X.replies[X.seq_num] = [ + function(buf, opt) { + var i, j; + var res = buf.unpack('LLLSSSSSS'); + var info = { + rotations : opt, + root : res [0], + timestamp : res[1], + config_timestamp : res[2], + sizeID : res[4], + rotation : res[5], + rate : res[6], + rates: [] + }; + + var nSizes = res[3]; + var nRates = res[7]; + + var screens_len = nSizes << 2; + var format = Array(screens_len + 1).join('S'); + res = buf.unpack(format, 24); + info.screens = []; + for (i = 0; i < screens_len; i += 4) { + info.screens.push({ + px_width : res[i], + px_height : res[i + 1], + mm_width : res[i + 2], + mm_height : res[i + 3] + }); + } + + format = Array(nRates + 1).join('S'); + info.rates = buf.unpack(format, 24 + screens_len * 2); + return info; + }, + cb + ]; + + X.pack_stream.flush(); + }, + + ext.GetScreenResources = function(win, cb) + { + X.seq_num ++; + X.pack_stream.pack('CCSL', [ext.majorOpcode, 8, 2, win]); + X.replies[X.seq_num] = [ + function(buf, opt) { + var i; + var pos = 0; + var res = buf.unpack('LLSSSSxxxxxxxx'); + var resources = { + timestamp : res[0], + config_timestamp : res[1], + modeinfos : [] + }; + + pos += 24; + var format = Array(res[2] + 1).join('L'); + resources.crtcs = buf.unpack(format, pos); + pos += res[2] << 2; + format = Array(res[3] + 1).join('L'); + resources.outputs = buf.unpack(format, pos); + pos += res[3] << 2; + format = Array(res[4] + 1).join('LSSLSSSSSSSSL'); + res_modes = buf.unpack(format, pos); + pos += res[4] << 5; + for (i = 0; i < res[4]; i+= 13) { + resources.modeinfos.push({ + id : res_modes[i + 0], + width : res_modes[i + 1], + height : res_modes[i + 2], + dot_clock : res_modes[i + 3], + h_sync_start : res_modes[i + 4], + h_sync_end : res_modes[i + 5], + h_total : res_modes[i + 6], + h_skew : res_modes[i + 7], + v_sync_start : res_modes[i + 8], + v_sync_end : res_modes[i + 9], + v_total : res_modes[i + 10], + modeflags : res_modes[i + 12], + name : buf.slice(pos, pos + res_modes[i + 11]).toString() + }); + + pos += res_modes[i + 11]; + } + + return resources; + }, + cb + ]; + + X.pack_stream.flush(); + }, + ext.GetOutputInfo = function(output, ts, cb) + { + X.seq_num ++; + X.pack_stream.pack('CCSLL', [ext.majorOpcode, 9, 3, output, ts ]); + X.replies[X.seq_num] = [ + function(buf, opt) { + var i; + var pos = 0; + var res = buf.unpack('LLLLCCSSSSS'); + var info = { + timestamp : res[0], + crtc : res[1], + mm_width : res[2], + mm_height : res[3], + connection : res[4], + subpixelOrder : res[5], + preferredModes: res[8] + }; + + pos += 28; + var format = Array(res[6] + 1).join('L'); + info.crtcs = buf.unpack(format, pos); + pos += res[6] << 2; + format = Array(res[7] + 1).join('L'); + info.modes = buf.unpack(format, pos); + pos += res[7] << 2; + format = Array(res[9] + 1).join('L'); + info.clones = buf.unpack(format, pos); + pos += res[9] << 2; + info.name = buf.slice(pos, pos + res_modes[10]).toString('binary'); + return info; + }, + cb + ]; + + X.pack_stream.flush(); + }, + ext.GetCrtcInfo = function(crtc, configTs, cb) { + X.seq_num ++; + X.pack_stream.pack('CCSLL', [ext.majorOpcode, 20, 3, crtc, configTs ]); + X.replies[X.seq_num] = [ + function(buf, opt) { + var pos = 0; + var res = buf.unpack('LssSSLSSSS'); + var info = { + status : opt, + timestamp : res[0], + x : res[1], + y : res[2], + width : res[3], + height : res[4], + mode : res[5], + rotation : res[6], + rotations : res[7] + }; + + pos += 24; + var format = Array(res[8] + 1).join('L'); + info.output = buf.unpack(format, pos); + format = Array(res[9] + 1).join('L'); + info.possible = buf.unpack(format, pos); + return info; + }, + cb + ]; + + X.pack_stream.flush(); + }, + + X.eventParsers[ext.firstEvent + ext.events.RRScreenChangeNotify] = function(type, seq, extra, code, raw) + { + var event = {}; + event.raw = raw; + event.type = type + event.seq = seq; + event.rotation = code; + var values = raw.unpack('LLLSSSSSS'); + event.time = extra + event.configtime = values[0]; + event.root = values[1]; + event.requestWindow = values[2]; + event.sizeId = values[3]; + event.subpixelOrder = values[4]; + event.width = values[5]; + event.height = values[6]; + event.physWidth = values[7]; + event.physHeight = values[8]; + + event.name = 'RRScreenChangeNotify'; + return event; + }; + + + ext.QueryVersion(255, 255, function(err, version) { + if (err) return callback(err); + ext.major_version = version[0]; + ext.minor_version = version[1]; + callback(null, ext); + }); + }); +}