diff --git a/.travis.yml b/.travis.yml index 49d8be2..2b8e294 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,4 +4,4 @@ before_script: language: node_js node_js: - - 0.8 \ No newline at end of file + - 0.10 diff --git a/lib/ext/randr.js b/lib/ext/randr.js index 2329a53..6b6cddf 100644 --- a/lib/ext/randr.js +++ b/lib/ext/randr.js @@ -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 = {}; diff --git a/test-runner.js b/test-runner.js index 309d27e..13ce5f0 100644 --- a/test-runner.js +++ b/test-runner.js @@ -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); + }); + }); + + } + ); +}); diff --git a/test/core-properties.js b/test/core-properties.js index a97f35a..8061c21 100644 --- a/test/core-properties.js +++ b/test/core-properties.js @@ -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(); //}); diff --git a/test/errors.js b/test/errors.js index 2ff8332..0a3386d 100644 --- a/test/errors.js +++ b/test/errors.js @@ -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; + } + }); }); }); diff --git a/test/randr.js b/test/randr.js new file mode 100644 index 0000000..97d101d --- /dev/null +++ b/test/randr.js @@ -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); + }); +});