Merge pull request #54 from santigimeno/randr_requests

Add RANDR SetScreenConfig GetScreenInfo requests
This commit is contained in:
Andrey Sidorov 2014-03-12 20:00:13 +11:00
commit b9b8451f9b
6 changed files with 315 additions and 89 deletions

View file

@ -4,4 +4,4 @@ before_script:
language: node_js
node_js:
- 0.8
- 0.10

View file

@ -40,6 +40,67 @@ exports.requireExt = function(display, callback)
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++;
@ -47,6 +108,105 @@ exports.requireExt = function(display, callback)
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]
};
var nSizes = res[3];
var nInfo = 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(nInfo + 1).join('S');
res = buf.unpack(format, 24 + screens_len * 2);
for (i = 0, j = 0; i < info.screens.length; ++i, j += res[j] + 1) {
info.screens[i].rates = res.slice(j + 1, j + 1 + res[j]);
}
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.crcs = 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_modes[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();
},
X.eventParsers[ext.firstEvent + ext.events.RRScreenChangeNotify] = function(type, seq, extra, code, raw)
{
var event = {};

View file

@ -6,86 +6,106 @@ var util = require('util');
var async = require('async');
var mocha = new Mocha({
timeout : 80000
timeout : 80000,
reporter : 'spec'
});
// To be able to perform the tests we need the server:
// 1 - to support the dpms extension.
// 2 - dpms version is 1.1.
// 3 - to be dpms capable.
var run_dpms_test = function(cb) {
var client = x11.createClient(function(err, dpy) {
if (err) return cb(false);
var display = dpy;
var X = display.client;
X.require('dpms', function(ext) {
if (!util.isError(ext)) {
dpms = ext;
dpms.GetVersion(undefined, undefined, function(err, version) {
if (!err && version[0] === 1 && version[1] === 1) {
dpms.Capable(function(err, capable) {
if (!err && capable[0] == 1) cb(true);
else cb(false);
});
} else {
cb(false);
}
});
} else {
cb(false);
}
});
});
client.on('error', function() {
cb(false);
});
};
var run_xtest_test = function(cb) {
var client = x11.createClient(function(err, dpy) {
if (err) return cb(false);
var display = dpy;
var X = display.client;
X.require('dpms', function(ext) {
if (!util.isError(ext)) cb(true);
else cb(false);
});
});
client.on('error', function() {
cb(false);
});
};
// Add all files from test root directory
async.forEach(
fs.readdirSync('./test'),
function(file, cb) {
if (file === 'dpms.js') {
run_dpms_test(function(run) {
if (run) {
mocha.addFile(path.join('./test', file));
var run_dpms_test = function(X, cb) {
X.require('dpms', function(ext) {
if (!util.isError(ext)) {
dpms = ext;
dpms.GetVersion(undefined, undefined, function(err, version) {
if (!err && version[0] === 1 && version[1] === 1) {
dpms.Capable(function(err, capable) {
if (!err && capable[0] == 1) cb(true);
else cb(false);
});
} else {
cb(false);
}
cb();
});
} else if (file === 'xtest.js') {
run_xtest_test(function(run) {
if (run) {
mocha.addFile(path.join('./test', file));
}
cb();
});
} else {
mocha.addFile(path.join('./test', file));
cb();
cb(false);
}
},
function(err) {
mocha.run(function() {
process.exit();
});
});
};
var run_xtest_test = function(X, cb) {
X.require('xtest', function(ext) {
if (!util.isError(ext)) cb(true);
else cb(false);
});
};
var run_randr_test = function(X, cb) {
X.require('randr', function(ext) {
if (!util.isError(ext)) {
randr = ext;
randr.QueryVersion(1, 2, function(err, version) {
if (err) {
cb(false);
} else {
cb((version[0] === 1) && (version[1] >= 2));
}
});
} else {
cb(false);
}
});
};
x11.createClient(function(err, display) {
if (err) {
console.log('Could not create X client');
process.exit(-1);
}
);
var X = display.client;
// Add all files from test root directory
async.forEach(
fs.readdirSync('./test'),
function(file, cb) {
if (file === 'dpms.js') {
run_dpms_test(X, function(run) {
if (run) {
mocha.addFile(path.join('./test', file));
}
cb();
});
} else if (file === 'xtest.js') {
run_xtest_test(X, function(run) {
if (run) {
mocha.addFile(path.join('./test', file));
}
cb();
});
} else if (file === 'randr.js') {
run_randr_test(X, function(run) {
if (run) {
mocha.addFile(path.join('./test', file));
}
cb();
});
} else {
mocha.addFile(path.join('./test', file));
cb();
}
},
function() {
X.terminate();
X.on('end', function() {
mocha.run(function(failures) {
process.exit(failures);
});
});
}
);
});

View file

@ -82,8 +82,8 @@ describe('Window property', function() {
});
});
it('should exist in the ListProperties result after inserted');
it('should not exist after GetProperty with delete flag called');
// it('should exist in the ListProperties result after inserted');
// it('should not exist after GetProperty with delete flag called');
//it('should not exist after GetProperty with delete flag called', function(done) {
// done();
//});

View file

@ -5,26 +5,30 @@ var assert = require('assert');
describe('Client', function() {
var display;
beforeEach(function(done) {
var client = x11.createClient({ debug: true }, function(err, dpy) {
console.log(err)
before(function(done) {
var client = x11.createClient({ debug: false }, function(err, dpy) {
should.not.exist(err);
display = dpy;
done(err);
done();
});
});
it('should emit error which is instance of Error with sequence number corresponding to source request', function(done) {
var times = 0;
display.client.CreateWindow(); // should emit error
var seq = display.client.seq_num;
display.client.once('error', function(err) {
assert.equal(err.constructor, Error);
assert.equal(seq, err.seq);
display.client.CreateWindow(); // should emit error
seq = display.client.seq_num;
display.client.once('error', function(err) {
assert.equal(seq, err.seq);
done();
});
});
display.client.on('error', function(err) {
switch (++ times) {
case 11:
display.client.removeAllListeners('error');
done();
break;
default:
assert.equal(err.constructor, Error);
assert.equal(seq, err.seq);
display.client.CreateWindow(); // should emit error
seq = display.client.seq_num;
}
});
});
});

42
test/randr.js Normal file
View file

@ -0,0 +1,42 @@
var x11 = require('../lib');
var should = require('should');
var assert = require('assert');
var util = require('util');
describe('RANDR extension', function() {
before(function(done) {
var self = this;
var client = x11.createClient(function(err, dpy) {
should.not.exist(err);
self.X = dpy.client;
self.screen = dpy.screen[0];
self.root = self.screen.root;
self.X.require('randr', function(ext) {
util.isError(ext).should.equal(false);
self.randr = ext;
/* We HAVE to QueryVersion before using it. Otherwise it does not work as expected */
self.randr.QueryVersion(1, 2, done);
});
});
client.on('error', done);
});
it('GetScreenInfo should get same px and mm width and height as in display.screen[0]', function(done) {
var self = this;
this.randr.GetScreenInfo(this.root, function(err, info) {
should.not.exist(err);
var active_screen = info.screens[info.sizeID];
active_screen.px_width.should.equal(self.screen.pixel_width);
active_screen.px_height.should.equal(self.screen.pixel_height);
active_screen.mm_width.should.equal(self.screen.mm_width);
active_screen.mm_height.should.equal(self.screen.mm_height);
done();
});
});
after(function(done) {
this.X.terminate();
this.X.on('end', done);
});
});