mirror of
https://github.com/danbulant/node-x11
synced 2026-05-21 21:39:13 +00:00
306 lines
9.1 KiB
JavaScript
306 lines
9.1 KiB
JavaScript
var xutil = require('./xutil');
|
|
var hexy = require('./hexy').hexy;
|
|
|
|
var valueMask = {
|
|
CreateWindow: {
|
|
backgroundPixmap: 0x00000001,
|
|
backgroundPixel : 0x00000002,
|
|
borderPixmap : 0x00000004,
|
|
borderPixel : 0x00000008,
|
|
bitGrawity : 0x00000010,
|
|
winGravity : 0x00000020,
|
|
backingStore : 0x00000040,
|
|
backingPlanes : 0x00000080,
|
|
backingPixel : 0x00000100,
|
|
overrideRedirect: 0x00000200,
|
|
saveUnder : 0x00000400,
|
|
eventMask : 0x00000800,
|
|
doNotPropagateMask: 0x00001000,
|
|
colormap : 0x00002000,
|
|
cursor : 0x00004000
|
|
},
|
|
CreateGC: {
|
|
'function' : 0x00000001, // TODO: alias? _function?
|
|
planeMask : 0x00000002,
|
|
foreground : 0x00000004,
|
|
background : 0x00000008,
|
|
lineWidth : 0x00000010,
|
|
lineStyle : 0x00000020,
|
|
capStyle : 0x00000040,
|
|
joinStyle : 0x00000080,
|
|
fillStyle : 0x00000100,
|
|
fillRule : 0x00000200,
|
|
tile : 0x00000400,
|
|
stipple : 0x00000800,
|
|
tileStippleXOrigin: 0x00001000,
|
|
tileStippleYOrigin: 0x00002000,
|
|
font : 0x00004000,
|
|
subwindowMode: 0x00008000,
|
|
graphicsExposures: 0x00010000,
|
|
clipXOrigin : 0x00020000,
|
|
clipYOrigin : 0x00040000,
|
|
clipMask : 0x00080000,
|
|
dashOffset : 0x00100000,
|
|
dashes : 0x00200000,
|
|
arcMode : 0x00400000
|
|
}
|
|
};
|
|
|
|
var valueMaskName = {};
|
|
for (var req in valueMask) {
|
|
var masks = valueMask[req];
|
|
var names = valueMaskName[req] = {};
|
|
for (var m in masks)
|
|
names[masks[m]] = m;
|
|
}
|
|
|
|
function packValueMask(reqname, values)
|
|
{
|
|
var bitmask = 0;
|
|
var masksList = [];
|
|
var reqValueMask = valueMask[reqname];
|
|
var reqValueMaskName = valueMaskName[reqname];
|
|
|
|
if (!reqValueMask)
|
|
throw new Error(reqname + ': no value mask description');
|
|
|
|
for (var v in values)
|
|
{
|
|
var valueBit = reqValueMask[v];
|
|
if (!valueBit)
|
|
throw new Error(reqname + ': incorrect value param ' + v);
|
|
masksList.push(valueBit);
|
|
bitmask |= valueBit;
|
|
}
|
|
masksList.sort();
|
|
var args = [];
|
|
for (m in masksList)
|
|
{
|
|
valueName = reqValueMaskName[masksList[m]];
|
|
args.push( values[valueName] );
|
|
}
|
|
return [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
|
|
|
|
*/
|
|
|
|
module.exports = {
|
|
CreateWindow: [
|
|
// create request packet - function OR format string
|
|
function(id, parentId, x, y, width, height, borderWidth, _class, visual, values) {
|
|
// TODO: ??? there is depth field in xproto, but xlib just sets it to zero
|
|
var depth = 0;
|
|
|
|
var packetLength = 8 + (values ? Object.keys(values).length : 0);
|
|
// TODO: should be CCSLLssSSSSLL - x,y are signed
|
|
var format = 'CCSLLSSSSSSLL';
|
|
|
|
// create bitmask
|
|
var bitmask = 0;
|
|
// TODO: slice from function arguments?
|
|
var args = [1, depth, packetLength, id, parentId, x, y, width, height, borderWidth, _class, visual];
|
|
|
|
// 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: replace with packValueMask
|
|
var masksList = [];
|
|
for (var v in values)
|
|
{
|
|
var valueBit = valueMask['CreateWindow'][v];
|
|
if (!valueBit)
|
|
{
|
|
throw new Error('CreateWindow: incorrect value param ' + v);
|
|
}
|
|
masksList.push(valueBit);
|
|
bitmask |= valueBit;
|
|
format += 'L';
|
|
}
|
|
// values packed in order of corresponding bit
|
|
masksList.sort();
|
|
// set bits to indicate additional values we are sending in this request
|
|
args.push(bitmask);
|
|
// add values in the order of the bits
|
|
// TODO: maybe it's better just to scan all 32 bits anstead of sorting parameters we are actually have?
|
|
for (m in masksList)
|
|
{
|
|
valueName = valueMaskName['CreateWindow'][masksList[m]];
|
|
args.push( values[valueName] );
|
|
}
|
|
return [format, args];
|
|
}
|
|
|
|
],
|
|
|
|
MapWindow: [
|
|
// 8 - opcode, 2 - length
|
|
[ 'CxSL', [8, 2] ]
|
|
],
|
|
|
|
UnmapWindow: [
|
|
[ 'CxSL', [10, 2] ]
|
|
],
|
|
|
|
// opcode 55
|
|
CreateGC: [
|
|
function(cid, drawable, values) {
|
|
var format = 'CxSLLL';
|
|
var packetLength = 4 + (values ? Object.keys(values).length : 0);
|
|
var args = [55, packetLength, cid, drawable];
|
|
var vals = packValueMask('CreateGC', values);
|
|
args.push(vals[0]); // values bitmask
|
|
var valArr = vals[1];
|
|
for (v in valArr)
|
|
{
|
|
format += 'L'; // TODO: we know format string length in advance and += inefficient for string
|
|
args.push(valArr[v]);
|
|
}
|
|
return [format, args];
|
|
}
|
|
],
|
|
|
|
// 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) {
|
|
var res = buf.unpack('L')[0];
|
|
return res;
|
|
}
|
|
],
|
|
|
|
GetAtomName: [
|
|
[ 'CxSL', [17, 2] ],
|
|
function(buf) {
|
|
var nameLen = buf.unpack('S')[0];
|
|
// Atom value starting from 24th byte in the buffer
|
|
return buf.unpackString(nameLen, 24);
|
|
}
|
|
],
|
|
|
|
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];
|
|
}
|
|
],
|
|
|
|
PolyPoint: [
|
|
function(coordMode, drawable, gc, points)
|
|
{
|
|
var format = 'CCSLL';
|
|
var args = [64, coordMode, 3+points.length, drawable, gc];
|
|
for (var i=0; i < points.length; ++i)
|
|
{
|
|
format += 'S';
|
|
args.push(points[i]);
|
|
}
|
|
console.error([format, args]);
|
|
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, drawable, gc];
|
|
for (var i=0; i < points.length; ++i)
|
|
{
|
|
format += 'S';
|
|
args.push(points[i]);
|
|
}
|
|
console.error([format, args]);
|
|
return [format, args];
|
|
}
|
|
|
|
],
|
|
|
|
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];
|
|
}
|
|
],
|
|
|
|
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;
|
|
res.push(buf.unpackString(len, off));
|
|
off += len;
|
|
}
|
|
return res;
|
|
}
|
|
]
|
|
}
|