diff --git a/js/x11/core/corereqs.js b/js/x11/core/corereqs.js new file mode 100644 index 0000000..70711ec --- /dev/null +++ b/js/x11/core/corereqs.js @@ -0,0 +1,1084 @@ +// full list of event/error/request codes for all extensions: +// http://www.opensource.apple.com/source/X11server/X11server-106.7/kdrive/xorg-server-1.6.5-apple3/dix/protocol.txt + +var xutil = Require('x11/core/xutil'); +var hexy = Require('x11/core/hexy').hexy; + +var valueMask = { + CreateWindow: { + backgroundPixmap : { + mask: 0x00000001, + format: 'L' + }, + backgroundPixel : { + mask: 0x00000002, + format: 'L' + }, + borderPixmap : { + mask: 0x00000004, + format: 'L' + }, + borderPixel : { + mask: 0x00000008, + format: 'L' + }, + bitGravity : { + mask: 0x00000010, + format: 'Cxxx' + }, + winGravity : { + mask: 0x00000020, + format: 'Cxxx' + }, + backingStore : { + mask: 0x00000040, + format: 'Cxxx' + }, + backingPlanes : { + mask: 0x00000080, + format: 'L' + }, + backingPixel : { + mask: 0x00000100, + format: 'L' + }, + overrideRedirect : { + mask: 0x00000200, + format: 'Cxxx' + }, + saveUnder : { + mask: 0x00000400, + format: 'Cxxx' + }, + eventMask : { + mask: 0x00000800, + format: 'L' + }, + doNotPropagateMask : { + mask: 0x00001000, + format: 'L' + }, + colormap : { + mask: 0x00002000, + format: 'L' + }, + cursor : { + mask: 0x00004000, + format: 'L' + } + }, + CreateGC: { + 'function' : { // TODO: alias? _function? + mask: 0x00000001, + format: 'Cxxx' + }, + planeMask : { + mask: 0x00000002, + format: 'L' + }, + foreground : { + mask: 0x00000004, + format: 'L' + }, + background : { + mask: 0x00000008, + format: 'L' + }, + lineWidth : { + mask: 0x00000010, + format: 'Sxx' + }, + lineStyle : { + mask: 0x00000020, + format: 'Cxxx' + }, + capStyle : { + mask: 0x00000040, + format: 'Cxxx' + }, + joinStyle : { + mask: 0x00000080, + format: 'Cxxx' + }, + fillStyle : { + mask: 0x00000100, + format: 'Cxxx' + }, + fillRule : { + mask: 0x00000200, + format: 'Cxxx' + }, + tile : { + mask: 0x00000400, + format: 'L' + }, + stipple : { + mask: 0x00000800, + format: 'L' + }, + tileStippleXOrigin : { + mask: 0x00001000, + format: 'sxx' + }, + tileStippleYOrigin : { + mask: 0x00002000, + format: 'sxx' + }, + font : { + mask: 0x00004000, + format: 'L' + }, + subwindowMode : { + mask: 0x00008000, + format: 'Cxxx' + }, + graphicsExposures : { + mask: 0x00010000, + format: 'Cxxx' + }, + clipXOrigin : { + mask: 0x00020000, + format: 'Sxx' + }, + clipYOrigin : { + mask: 0x00040000, + format: 'Sxx' + }, + clipMask : { + mask: 0x00080000, + format: 'L' + }, + dashOffset : { + mask: 0x00100000, + format: 'Sxx' + }, + dashes : { + mask: 0x00200000, + format: 'Cxxx' + }, + arcMode : { + mask: 0x00400000, + format: 'Cxxx' + } + }, + ConfigureWindow: { + x : { + mask: 0x000001, + format: 'sxx' + }, + y : { + mask: 0x000002, + format: 'sxx' + }, + width : { + mask: 0x000004, + format: 'Sxx' + }, + height : { + mask: 0x000008, + format: 'Sxx' + }, + borderWidth : { + mask: 0x000010, + format: 'Sxx' + }, + sibling : { + mask: 0x000020, + format: 'L' + }, + stackMode : { + mask: 0x000040, + format: 'Cxxx' + } + } +}; + + +var valueMaskName = {}; +for (var req in valueMask) { + var masks = valueMask[req]; + var names = valueMaskName[req] = {}; + for (var m in masks) + names[masks[m].mask] = m; +} + +function packValueMask(reqname, values) +{ + var bitmask = 0; + var masksList = []; + var format = ''; + var reqValueMask = valueMask[reqname]; + var reqValueMaskName = valueMaskName[reqname]; + + if (!reqValueMask) + throw new Error(reqname + ': no value mask description'); + + for (var value in values) + { + var v = reqValueMask[value]; + if (v) { + var valueBit = v.mask; + if (!valueBit) + throw new Error(reqname + ': incorrect value param ' + value); + masksList.push(valueBit); + bitmask |= valueBit; + } + } + + /* numeric sort */ + masksList.sort(function(a, b) { + return a - b; + }); + + var args = []; + for (m in masksList) + { + var valueName = reqValueMaskName[masksList[m]]; + format += reqValueMask[valueName].format + args.push( values[valueName] ); + } + return [format, bitmask, args] +} + +/* + +the way requests are described here + +- outgoing request + + 1) as function + client.CreateWindow( params, params ) -> + req = reqs.CreateWindow[0]( param, param ); + pack_stream.pack(req[0], req[1]); + + 2) as array: [format, [opcode, request_length, additional known params]] + + client.MapWindow[0](id) -> + req = reqs.MwpWindow; + req[1].push(id); + pack_stream.pack( req[0], req[1] ); + +- reply + +*/ + +var templates = { + CreateWindow: [ + // create request packet - function OR format string + function(id, parentId, x, y, width, height, borderWidth, depth, _class, visual, values) { + + if (borderWidth === undefined) + borderWidth = 0; + if (depth === undefined) + depth = 0; + if (_class === undefined) + _class = 0; + if (visual === undefined) + visual = 0; + if (values === undefined) + values = {} + + var format = 'CCSLLssSSSSLL'; + + // TODO: slice from function arguments? + + // TODO: the code is a little bit mess + // additional values need to be packed in the following way: + // bitmask (bytes #24 to #31 in the packet) - 32 bit indicating what adittional arguments we supply + // values list (bytes #32 .. #32+4*num_values) in order of corresponding bits TODO: it's actually not 4*num. Some values are 4b ytes, some - 1 byte + + var vals = packValueMask('CreateWindow', values); + var packetLength = 8 + (values ? vals[2].length : 0); + var args = [1, depth, packetLength, id, parentId, x, y, width, height, borderWidth, _class, visual]; + format += vals[0]; + args.push(vals[1]); + args = args.concat(vals[2]); + return [format, args]; + } + + ], + + ChangeWindowAttributes:[ + function(wid, values) { + var format = 'CxSLSxx'; + var vals = packValueMask('CreateWindow', values); + var packetLength = 3 + (values ? vals[2].length : 0); + var args = [2, packetLength, wid, vals[1]]; + var valArr = vals[2]; + format += vals[0]; + args = args.concat(valArr); + return [format, args]; + } + ], + + GetWindowAttributes: [ + ['CxSL', [3, 2]], + function(buf, backingStore) + { + // TODO: change from array to named object fields + var res = buf.unpack('LSCCLLCCCCLLLS'); + var ret = { + backingStore: backingStore + }; + ( "visual klass bitGravity winGravity backingPlanes backingPixel" + + " saveUnder mapIsInstalled mapState overrideRedirect colormap" + + " allEventMasks myEventMasks doNotPropogateMask" ) + .split(' ').forEach(function(field, index) { + ret[field] = res[index]; + }); + return ret; + } + ], + + DestroyWindow: [ + [ 'CxSL', [4, 2] ] + ], + + ChangeSaveSet: [ + function(isInsert, wid) + { + return [ 'CCSL', [6, (isInsert ? 0 : 1), 2, wid]] + } + ], + + // wid, newParentId, x, y + ReparentWindow: [ + [ 'CxSLLss', [7, 4]] + ], + + MapWindow: [ + // 8 - opcode, 2 - length, wid added as parameter + [ 'CxSL', [8, 2] ] + ], + + UnmapWindow: [ + [ 'CxSL', [10, 2] ] + ], + + ConfigureWindow: [ + /* + * options : { + * x : x_value, + * y : y_value, + * width : width_value, + * height : height_value, + * borderWidth : borderWidth_value, + * sibling : sibling_value + * } + */ + function(win, options) { + var vals = packValueMask('ConfigureWindow', options); + var format = 'CxSLSxx' + vals[0]; + var args = [12, vals[2].length + 3, win, vals[1]]; + args = args.concat(vals[2]); + return [format, args]; + } + ], + + ResizeWindow: [ + function(win, width, height) { + return module.exports.ConfigureWindow[0](win, { width : width, height: height }); + } + ], + + MoveWindow: [ + function(win, x, y) { + return module.exports.ConfigureWindow[0](win, { x : x, y: y }); + } + ], + + MoveResizeWindow: [ + function(win, x, y, width, height) { + return module.exports.ConfigureWindow[0](win, { x : x, y: y, width : width, height: height }); + } + ], + + RaiseWindow: [ + function(win) { + return module.exports.ConfigureWindow[0](win, { stackMode : 0 }); + } + ], + + LowerWindow: [ + function(win) { + return module.exports.ConfigureWindow[0](win, { stackMode : 1 }); + } + ], + + QueryTree: [ + ['CxSL', [15, 2]], + + function(buf) { + var tree = {}; + var res = buf.unpack('LLS'); + tree.root = res[0]; + tree.parent = res[1]; + tree.children = []; + for (var i=0; i < res[2]; ++i) + tree.children.push(buf.unpack('L', 24 + i*4)[0]); + return tree; + } + ], + + // opcode 16 + InternAtom: [ + function (returnOnlyIfExist, value) + { + var padded = xutil.padded_string(value); + return ['CCSSxxa', [16, returnOnlyIfExist ? 1 : 0, 2+padded.length/4, value.length, padded] ]; + }, + + function(buf, seq_num) { + var res = buf.unpack('L')[0]; + var pending_atom = this.pending_atoms[seq_num]; + if (!this.atoms[pending_atom]) { + this.atoms[pending_atom] = res; + this.atom_names[res] = pending_atom; + } + + delete this.pending_atoms[seq_num]; + return res; + } + ], + + GetAtomName: [ + [ 'CxSL', [17, 2] ], + function(buf, seq_num) { + var nameLen = buf.unpack('S')[0]; + // Atom value starting from 24th byte in the buffer + var name = buf.unpackString(nameLen, 24); + var pending_atom = this.pending_atoms[seq_num]; + if (!this.atoms[pending_atom]) { + this.atom_names[pending_atom] = name; + this.atoms[name] = pending_atom; + } + + delete this.pending_atoms[seq_num]; + return name; + } + ], + + ChangeProperty: [ + // mode: 0 replace, 1 prepend, 2 append + // format: 8/16/32 + function(mode, wid, name, type, units, data) + { + var padded4 = (data.length + 3) >> 2; + var pad = new Buffer( (padded4<<2) - data.length); + var format = 'CCSLLLCxxxLaa'; + var requestLength = 6 + padded4; + var dataLenInFormatUnits = data.length / (units >> 3); + return [format, [18, mode, requestLength, wid, name, type, units, dataLenInFormatUnits, data, pad] ]; + } + ], + + // TODO: test + DeleteProperty: [ + function(wid, prop) { + return [ 'CxSLL', [19, 3, wid, prop] ]; + } + ], + + GetProperty: [ + + function(del, wid, name, type, longOffset, longLength) // - offest and maxLength in 4-byte units + { + return [ 'CCSLLLLL', [20, del, 6, wid, name, type, longOffset, longLength ] ]; + }, + + function(buf, format) { + var res = buf.unpack('LLL'); + var prop = {}; + prop.type = res[0]; + prop.bytesAfter = res[1]; + var len = res[2]*(format >> 3) + prop.data = buf.slice(24, 24+len); + return prop; + } + ], + + ListProperties: [ + + function(wid) + { + return ['CxSL', [21, 2, wid]]; + }, + + function(buf) { + var n = buf.unpack('S')[0]; + var i; + var atoms = []; + for(i=0; i < n; ++i) { + atoms.push(buf.unpack('L', 24+4*i)[0]); + //console.log([n, i, atoms]); + } + return atoms; + } + ], + + SetSelectionOwner: [ + function(owner, selection, time) + { + if (!time) + time = 0; // current time + return ['CxSLLL', [22, 4, owner, selection, time]]; + } + ], + + GetSelectionOwner: [ + function(selection) + { + return ['CxSL', [23, 2, selection]]; + }, + + function(buf) { + return buf.unpack('L')[0]; + } + ], + + ConvertSelection: [ + function(requestor, selection, target, property, time) { + if (!time) + time = 0; + return ['CxSLLLLL', [24, 6, requestor, selection, target, property, time]]; + } + ], + + SendEvent: [ + + function(destination, propagate, eventMask, eventRawData) + { + return [ 'CCSLLa', [25, propagate, 11, destination, eventMask, eventRawData] ]; + } + ], + + GrabPointer: [ + function(wid, ownerEvents, mask, pointerMode, keybMode, confineTo, cursor, time) { + return [ 'CCSLSCCLLL', [ 26, ownerEvents, 6, wid, mask, pointerMode, keybMode, + confineTo, cursor, time] ]; + }, + function(buf, status) { + return status; + } + ], + + UngrabPointer: [ + function(time) { + return [ 'CxSL', [ 27, 2, time] ]; + } + ], + + GrabButton: [ + function(wid, ownerEvents, mask, pointerMode, keybMode, confineTo, cursor, button, modifiers) { + return [ 'CCSLSCCLLCxS', [ 28, ownerEvents, 6, wid, mask, pointerMode, keybMode, confineTo, + cursor, button, modifiers ] ]; + } + ], + + UngrabButton: [ + function(wid, button, modifiers) { + return [ 'CCSLSxx', [ 29, button, 3, wid, modifiers ] ]; + } + ], + + ChangeActivePointerGrab: [ + function(cursor, time, mask) { + return [ 'CxSLLSxx', [ 30, 4, cursor, time, mask ] ]; + } + ], + + GrabKeyboard: [ + function(wid, ownerEvents, time, pointerMode, keybMode) { + return [ 'CCSLLCCxx', [ 31, ownerEvents, 4, wid, time, pointerMode, keybMode ] ]; + }, + function(buf, status) { + return status; + } + ], + + UngrabKeyboard: [ + function(time) { + return [ 'CxSL', [ 32, 2, time ] ]; + } + ], + + GrabKey: [ + function(wid, ownerEvents, modifiers, key, pointerMode, keybMode) { + return [ 'CCSLSCCCxxx', [ 33, ownerEvents, 4, wid, modifiers, key, pointerMode, keybMode ] ]; + } + ], + + UngrabKey: [ + function(wid, key, modifiers) { + return [ 'CCSLSxx', [ 34, key, 3, wid, modifiers ] ]; + } + ], + + AllowEvents: [ + function(mode, ts) { + return [ 'CCSL', [ 35, mode, 2, ts ] ]; + } + ], + + GrabServer: [ + [ 'CxS', [36, 1]] + ], + + UngrabServer: [ + [ 'CxS', [37, 1]] + ], + + QueryPointer: [ + [ 'CxSL', [38, 2] ], + function(buf, sameScreen) { + var res = buf.unpack('LLssssS'); + return { + root: res[0], + child: res[1], + rootX: res[2], + rootY: res[3], + childX: res[4], + childY: res[5], + keyMask: res[6], + sameScreen : sameScreen + }; + } + ], + + TranslateCoordinates: [ + function(srcWid, dstWid, srcX, srcY) { + return [ 'CxSLLSS', [ 40, 4, srcWid, dstWid, srcX, srcY ] ]; + }, + function(buf, sameScreen) + { + var res = buf.unpack('Lss'); + var ext = {}; + ext.child = res[0]; + ext.destX = res[1]; + ext.destY = res[2]; + ext.sameScreen = sameScreen; + return ext; + } + ], + + WarpPointer: [ + + function (srcWin, dstWin, srcX, srcY, srcWidth, srcHeight, dstX, dstY) + { + return [ 'CxSLLssSSss', [41, 6, srcWin, dstWin, srcX, srcY, srcWidth, srcHeight, dstX, dstY] ]; + } + ], + + SetInputFocus: [ + + function (wid, revertTo) // revertTo: 0 - None, 1 - PointerRoot, 2 - Parent + { + return [ 'CCSLL', [42, revertTo, 3, wid, 0] ]; + } + ], + + GetInputFocus: [ + function() { + return [ 'CxS', [ 43, 1 ] ]; + }, + function(buf, revertTo) + { + return { + focus : buf.unpack('L')[0], + revertTo : revertTo + }; + } + ], + + OpenFont: [ + function(name,fid) { + var padded = xutil.padded_string(name); + return ['CxSLSxxa', [45, 3+padded.length/4, fid, name.length, padded] ]; + } + ], + + ListFonts: [ + function(pattern, max) + { + var req_len = 2+xutil.padded_length(pattern.length)/4; + return [ 'CxSSSp', [49, req_len, max, pattern.length, pattern] ]; + }, + + function(buf) { + console.log(buf); + // TODO: move to buffer.unpackStringList + var res = []; + var off = 24; + while (off < buf.length) + { + var len = buf[off++]; + if (len == 0) + break; + if (off + len > buf.length) + { + len = buf.length - off; + if (len <= 0) + break; + } + res.push(buf.unpackString(len, off)); + off += len; + } + return res; + } + ], + + CreatePixmap: [ + function(pid, drawable, depth, width, height) { + return [ 'CCSLLSS', [53, depth, 4, pid, drawable, width, height] ]; + } + ], + + FreePixmap: [ + function (pixmap) { + return [ 'CxSL', [54, 2, pixmap] ]; + } + ], + + CreateCursor: [ + function(cid, source, mask, foreRGB, backRGB, x, y) { + foreR = foreRGB.R + foreG = foreRGB.G + foreB = foreRGB.B + + backR = backRGB.R + backG = backRGB.G + backB = backRGB.B + return [ 'CxSLLLSSSSSSSS', [93, 8, cid, source, mask, foreR, foreG, foreB, backR, backG, backB, x, y] ]; + } + ], + + // opcode 55 + CreateGC: [ + function(cid, drawable, values) { + var format = 'CxSLLL'; + var vals = packValueMask('CreateGC', values); + var packetLength = 4 + (values ? vals[2].length : 0); + var args = [55, packetLength, cid, drawable]; + format += vals[0] + args.push(vals[1]); // values bitmask + args = args.concat(vals[2]) + return [format, args]; + } + ], + + ChangeGC: [ + function(cid, values) { + var format = 'CxSLL'; + var vals = packValueMask('CreateGC', values); + var packetLength = 3 + (values ? vals[2].length : 0); + var args = [56, packetLength, cid]; + format += vals[0] + args.push(vals[1]); // values bitmask + args = args.concat(vals[2]) + return [format, args]; + } + ], + + ClearArea: [ + function(wid, x, y, width, height, exposures) { + return [ 'CCSLssSS', [61, exposures, 4, wid, x, y, width, height] ]; + } + ], + + // + CopyArea: [ + function(srcDrawable, dstDrawable, gc, srcX, srcY, dstX, dstY, width, height) { + return [ 'CxSLLLssssSS', [62, 7, srcDrawable, dstDrawable, gc, srcX, srcY, dstX, dstY, width, height] ]; + } + ], + + + PolyPoint: [ + function(coordMode, drawable, gc, points) + { + var format = 'CCSLL'; + var args = [64, coordMode, 3+points.length/2, drawable, gc]; + for (var i=0; i < points.length; ++i) + { + format += 'S'; + args.push(points[i]); + } + return [format, args]; + } + ], + + PolyLine: [ + // TODO: remove copy-paste - exectly same as PolyPoint, only differ with opcode + function(coordMode, drawable, gc, points) + { + var format = 'CCSLL'; + var args = [65, coordMode, 3+points.length/2, drawable, gc]; + for (var i=0; i < points.length; ++i) + { + format += 'S'; + args.push(points[i]); + } + return [format, args]; + } + + ], + + PolyRectangle: [ + function(drawable, gc, coords) { // x1, y1, w1, h1, x2, y2, w2, h2... + var format = 'CxSLL'; + var numrects4bytes = coords.length/2; + var args = [67, 3+numrects4bytes, drawable, gc]; + for (var i=0; i < coords.length; ++i) + { + format += 'S'; + args.push(coords[i]); + } + return [format, args]; + } + ], + + PolyArc: [ + function(drawable, gc, coords) { // x1, y1, w1, h1, a11, a12, ... + var format = 'CxSLL'; + var numrects4bytes = coords.length/2; + var args = [68, 3+numrects4bytes, drawable, gc]; + for (var i=0; i < coords.length; ++i) + { + format += 'S'; + args.push(coords[i]); + } + return [format, args]; + } + ], + + FillPoly: [ + // TODO: remove copy-paste - exectly same as PolyPoint, only differ with opcode + function(drawable, gc, shape, coordMode, points) + { + var format = 'CxSLLCCxx'; + var args = [69, 4+points.length/2, drawable, gc, shape, coordMode]; + for (var i=0; i < points.length; ++i) + { + format += 'S'; + args.push(points[i]); + } + return [format, args]; + } + + ], + + PolyFillRectangle: [ + function(drawable, gc, coords) { // x1, y1, w1, h1, x2, y2, w2, h2... + var format = 'CxSLL'; + var numrects4bytes = coords.length/2; + var args = [70, 3+numrects4bytes, drawable, gc]; + for (var i=0; i < coords.length; ++i) + { + format += 'S'; + args.push(coords[i]); + } + return [format, args]; + } + ], + + PolyFillArc: [ + function(drawable, gc, coords) { // x1, y1, w1, h1, a11, a12, ... + var format = 'CxSLL'; + var numrects4bytes = coords.length/2; + var args = [71, 3+numrects4bytes, drawable, gc]; + for (var i=0; i < coords.length; ++i) + { + format += 'S'; + args.push(coords[i]); + } + return [format, args]; + } + ], + + + PutImage: [ + // format: 0 - Bitmap, 1 - XYPixmap, 2 - ZPixmap + function(format, drawable, gc, width, height, dstX, dstY, leftPad, depth, data) { + var padded = xutil.padded_length(data.length); + var reqLen = 6 + padded/4; // (length + 3) >> 2 ??? + var padLength = padded - data.length; + var pad = new Buffer(padLength); // TODO: new pack format 'X' - skip amount of bytes supplied in numerical argument + + // TODO: move code to calculate reqLength and use BigReq if needed outside of corereq.js + // NOTE: big req is used here (first 'L' in format, 0 and +1 in params), won't work if not enabled + return [ 'CCSLLLSSssCCxxaa', [72, format, 0, 1+reqLen, drawable, gc, width, height, dstX, dstY, leftPad, depth, data, pad]]; + } + ], + + GetImage: [ + function(format, drawable, x, y, width, height, planeMask) + { + return [ 'CCSLssSSL', [73, format, 5, drawable, x, y, width, height, planeMask]]; + }, + function(buf, depth) + { + var visualId = buf.unpack('L')[0]; + return { + depth: depth, + visualId: visualId, + data: buf.slice(24) + }; + } + ], + + PolyText8: [ + function(drawable, gc, x, y, items) { + var format = 'CxSLLss'; + var numItems = items.length; + var reqLen = 16; + var args = [74, 0, drawable, gc, x, y]; + for (var i=0; i < numItems; ++i) + { + var it = items[i]; + if (typeof it == 'string') + { + if (it.length > 254) // TODO: split string in set of items + throw 'not supported yet'; + format += 'CCa'; + args.push(it.length); + args.push(0); // delta??? + args.push(it); + reqLen += 2 + it.length; + } else { + throw 'not supported yet'; + } + } + var len4 = xutil.padded_length(reqLen)/4; + var padLen = len4*4 - reqLen; + args[1] = len4; // set request length to calculated value + var pad = ''; + for (var i=0; i < padLen; ++i) + pad += String.fromCharCode(0); + format += 'a'; + args.push(pad); + return [format, args]; + } + ], + + CreateColormap: + [ + function(cmid, wid, vid, alloc) + { + return ['CCSLLL', [78, alloc, 4, cmid, wid, vid]]; + } + ], + + AllocColor: [ + [ 'CxSLSSSxx', [84, 4] ], // params: colormap, red, green, blue + + function(buf) { + var res = buf.unpack('SSSxL'); + var color = {}; + color.red = res[0]; + color.blue = res[1]; + color.green = res[2]; + color.pixel = res[3]>>8; // it looks like 3 first bytes contain RGB value in response + return color; + } + ], + + QueryExtension: [ + function(name) { + var padded = xutil.padded_string(name); + return ['CxSSxxa', [98, 2+padded.length/4, name.length, padded] ]; + }, + + function(buf) { + var res = buf.unpack('CCCC'); + var ext = {}; + ext.present = res[0]; + ext.majorOpcode = res[1]; + ext.firstEvent = res[2]; + ext.firstError = res[3]; + return ext; + } + + ], + + ListExtensions: [ + [ 'CxS', [99, 1] ], + + function(buf) { + // TODO: move to buffer.unpackStringList + var res = []; + var off = 24; + while (off < buf.length) + { + var len = buf[off++]; + if (len == 0) + break; + if (off + len > buf.length) + { + len = buf.length - off; + if (len <= 0) + break; + } + res.push(buf.unpackString(len, off)); + off += len; + } + return res; + } + ], + + GetKeyboardMapping: [ + function(startCode, num) { + return [ 'CxSCCxx', [101, 2, startCode, num] ] + }, + function(buff, listLength) { + var res = []; + var format = ''; + for (var i=0; i < listLength; ++i) + format += 'L'; + for (var offset=24; offset < buff.length - 4*listLength; offset += 4*listLength) + res.push(buff.unpack(format, offset)); + return res; + } + ], + + // todo: move up to keep reque + GetGeometry: [ + function(drawable){ + return ['CxSL', [14, 2, drawable]] + }, + function(buff, depth) + { + var res = buff.unpack('LssSSSx'); + var ext = {}; + ext.windowid = res[0] + ext.xPos = res[1]; + ext.yPos = res[2]; + ext.width = res[3]; + ext.height = res[4]; + ext.borderWidth = res[5]; + ext.depth = depth; + return ext; + } + ], + + KillClient: [ + function(resource) { + return [ 'CxSL', [113, 2, resource] ]; + } + ], + + SetScreenSaver: [ + function(timeout, interval, preferBlanking, allowExposures) { + return [ 'CxSssCCxx', [107, 3, timeout, interval, preferBlanking, allowExposures]]; + } + ], + + ForceScreenSaver: [ + function(activate) { + return [ 'CCS', [115, activate?1:0, 1] ]; + } + ] +}; + +templates.KillKlient = templates.KillClient; + +module.exports = templates;