From 76f969e311920c4d1317a62d9653ce5ef52d17d0 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Mon, 10 Mar 2014 00:56:22 +0100 Subject: [PATCH 1/7] Add RANDR SetScreenConfig GetScreenInfo requests - Also added ROTATION and CONFIGSTATUS types. --- lib/ext/randr.js | 92 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/lib/ext/randr.js b/lib/ext/randr.js index 2329a53..1a25a3d 100644 --- a/lib/ext/randr.js +++ b/lib/ext/randr.js @@ -40,6 +40,50 @@ 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.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 +91,54 @@ 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], + nSizes : res[3], + sizeID : res[4], + rotation : res[5], + rate : res[6], + nInfo : res[7] + }; + + var screens_len = info.nSizes * 4; + var format = Array(screens_len + 1).join('S'); + res = buf.unpack(format, 24); + info.screens = []; + for (i = 0; i < screens_len; i += 4) { + console.log(i); + info.screens.push({ + px_width : res[i], + px_height : res[i + 1], + mm_width : res[i + 2], + mm_height : res[i + 3] + }); + } + + format = Array(info.nInfo + 1).join('S'); + res = buf.unpack(format, 24 + screens_len * 2); + i = 0, j = 0; + 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(); + }, + X.eventParsers[ext.firstEvent + ext.events.RRScreenChangeNotify] = function(type, seq, extra, code, raw) { var event = {}; From 88ac8179c68e1208a46ce27a3a831e4dc309c06b Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 11 Mar 2014 10:24:15 +0100 Subject: [PATCH 2/7] Add GetScreenResources request and MODEFLAG type - Don't include the length fields in GetScreenResources and SetScreenConfig replies as the're redundant. --- lib/ext/randr.js | 82 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 75 insertions(+), 7 deletions(-) diff --git a/lib/ext/randr.js b/lib/ext/randr.js index 1a25a3d..6b6cddf 100644 --- a/lib/ext/randr.js +++ b/lib/ext/randr.js @@ -56,6 +56,23 @@ exports.requireExt = function(display, callback) 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]); @@ -103,19 +120,18 @@ exports.requireExt = function(display, callback) root : res [0], timestamp : res[1], config_timestamp : res[2], - nSizes : res[3], sizeID : res[4], rotation : res[5], - rate : res[6], - nInfo : res[7] + rate : res[6] }; - var screens_len = info.nSizes * 4; + 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) { - console.log(i); info.screens.push({ px_width : res[i], px_height : res[i + 1], @@ -124,9 +140,8 @@ exports.requireExt = function(display, callback) }); } - format = Array(info.nInfo + 1).join('S'); + format = Array(nInfo + 1).join('S'); res = buf.unpack(format, 24 + screens_len * 2); - i = 0, j = 0; 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]); } @@ -139,6 +154,59 @@ exports.requireExt = function(display, callback) 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 = {}; From b95302ff1aba99ece571a79d9ff21113ae163aae Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 11 Mar 2014 15:59:58 +0100 Subject: [PATCH 3/7] Add basic RANDR integration test - Some improvements in test-runner. --- test-runner.js | 166 ++++++++++++++++++++++++++++--------------------- test/randr.js | 42 +++++++++++++ 2 files changed, 136 insertions(+), 72 deletions(-) create mode 100644 test/randr.js diff --git a/test-runner.js b/test-runner.js index 309d27e..f30e9d7 100644 --- a/test-runner.js +++ b/test-runner.js @@ -6,86 +6,108 @@ 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 { + console.log(version); + 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) { + console.log('RUN: ' + 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() { + process.exit(); + }); + }); + + } + ); +}); 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); + }); +}); From 7d23cbfb9e20520c6d4bb28c8fae2762e7ffb22f Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 11 Mar 2014 16:26:57 +0100 Subject: [PATCH 4/7] Set node version in travis to 0.10 - As the tests were failing due to using setImmediate. - Remove one log. --- .travis.yml | 2 +- test-runner.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) 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/test-runner.js b/test-runner.js index f30e9d7..6a049aa 100644 --- a/test-runner.js +++ b/test-runner.js @@ -88,7 +88,6 @@ x11.createClient(function(err, display) { }); } else if (file === 'randr.js') { run_randr_test(X, function(run) { - console.log('RUN: ' + run); if (run) { mocha.addFile(path.join('./test', file)); } From b6a76b51d737d9c90161031f70b4e2acf2137b87 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 11 Mar 2014 17:57:29 +0100 Subject: [PATCH 5/7] Some more test fixes - Fix error.js test. - Make sure test_runner exits with the correct error code. - Comment tests not implemented in core-properties. --- test-runner.js | 4 ++-- test/core-properties.js | 4 ++-- test/errors.js | 32 ++++++++++++++++++-------------- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/test-runner.js b/test-runner.js index 6a049aa..845e989 100644 --- a/test-runner.js +++ b/test-runner.js @@ -102,8 +102,8 @@ x11.createClient(function(err, display) { function() { X.terminate(); X.on('end', function() { - mocha.run(function() { - process.exit(); + 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..80b0c30 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) { + display.client.on('error', function(err) { + switch (++ times) { + case 11: + display.client.removeAllListeners('error'); + done(1); + break; + default: + assert.equal(err.constructor, Error); assert.equal(seq, err.seq); - done(); - }); - }); - }); + display.client.CreateWindow(); // should emit error + seq = display.client.seq_num; + } + }); }); + }); From 3d3bcfa90181e18c5cfe5f8c8f773986d110b8a0 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 11 Mar 2014 18:01:04 +0100 Subject: [PATCH 6/7] Small type and style issues --- test/errors.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/test/errors.js b/test/errors.js index 80b0c30..0a3386d 100644 --- a/test/errors.js +++ b/test/errors.js @@ -19,16 +19,16 @@ describe('Client', function() { var seq = display.client.seq_num; display.client.on('error', function(err) { switch (++ times) { - case 11: - display.client.removeAllListeners('error'); - done(1); - break; - default: - assert.equal(err.constructor, Error); - assert.equal(seq, err.seq); - display.client.CreateWindow(); // should emit error - seq = display.client.seq_num; - } + 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; + } }); -}); }); +}); From 7268da486fc5a85d4bf1b01311157bfdf87eb81b Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Tue, 11 Mar 2014 18:02:46 +0100 Subject: [PATCH 7/7] Remove unnecessary log --- test-runner.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test-runner.js b/test-runner.js index 845e989..13ce5f0 100644 --- a/test-runner.js +++ b/test-runner.js @@ -49,7 +49,6 @@ var run_randr_test = function(X, cb) { if (err) { cb(false); } else { - console.log(version); cb((version[0] === 1) && (version[1] >= 2)); } });