diff --git a/.travis.yml b/.travis.yml index e8b7e71..49d8be2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,5 +4,4 @@ before_script: language: node_js node_js: - - 0.6 - 0.8 \ No newline at end of file diff --git a/README.md b/README.md index e26aaa5..63f4956 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ Core requsests usage: # Other implementations - - C: XLib - http://codesearch.google.com/codesearch/p?hl=en#xEHUuo8Crmg/sites/ftp.x.org/pub/X11R7.2/src/update/everything/libX11-X11R7.2-1.1.1.tar.bz2%7CnOqwAyDlYlo/libX11-X11R7.2-1.1.1/src/OpenDis.c&q=XOpenDisplay&d=3 + - C: XLib - http://www.sbin.org/doc/Xlib/ http://www.tronche.com/gui/x/xlib/ http://www.x.org/docs/X11/xlib.pdf - C: XCB - http://xcb.freedesktop.org/ - Python: http://sourceforge.net/projects/python-xlib/ ( github fork: https://github.com/Ademan/python-xlib-branch pypi: http://pypi.python.org/pypi/Python%20Xlib ) - Python/twisted: https://launchpad.net/twisted-x11 diff --git a/lib/x11/corereqs.js b/lib/x11/corereqs.js index a3cdefc..f71aca7 100644 --- a/lib/x11/corereqs.js +++ b/lib/x11/corereqs.js @@ -84,7 +84,7 @@ function packValueMask(reqname, values) var args = []; for (m in masksList) { - valueName = reqValueMaskName[masksList[m]]; + var valueName = reqValueMaskName[masksList[m]]; args.push( values[valueName] ); } return [bitmask, args] @@ -162,7 +162,7 @@ module.exports = { // 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) + for (var m in masksList) { var valueName = valueMaskName['CreateWindow'][masksList[m]]; args.push( values[valueName] ); @@ -179,7 +179,7 @@ module.exports = { var vals = packValueMask('CreateWindow', values); var args = [2, packetLength, wid, vals[0]]; var valArr = vals[1]; - for (v in valArr) + for (var v in valArr) { format += 'L'; args.push(valArr[v]); @@ -244,6 +244,12 @@ module.exports = { } ], + RaiseWindow: [ + function(win) { + return ['CxSLSxxCxxx', [12, 4, win, 64]]; + } + ], + QueryTree: [ ['CxSL', [15, 2]], @@ -385,6 +391,14 @@ module.exports = { return res; } ], + + SetInputFocus: [ + + function (wid, revertTo) // revertTo: 0 - None, 1 - PointerRoot, 2 - Parent + { + return [ 'CCSLL', [42, revertTo, 3, wid, 0] ]; + } + ], WarpPointer: [ @@ -439,7 +453,7 @@ module.exports = { var vals = packValueMask('CreateGC', values); args.push(vals[0]); // values bitmask var valArr = vals[1]; - for (v in valArr) + for (var v in valArr) { format += 'L'; // TODO: we know format string length in advance and += inefficient for string args.push(valArr[v]); @@ -456,7 +470,7 @@ module.exports = { var vals = packValueMask('CreateGC', values); args.push(vals[0]); // values bitmask var valArr = vals[1]; - for (v in valArr) + for (var v in valArr) { format += 'L'; // TODO: we know format string length in advance and += inefficient for string args.push(valArr[v]); diff --git a/lib/x11/ext/big-requests.js b/lib/x11/ext/big-requests.js index 7e24cbb..19b61e9 100644 --- a/lib/x11/ext/big-requests.js +++ b/lib/x11/ext/big-requests.js @@ -7,7 +7,7 @@ exports.requireExt = function(display, callback) X.QueryExtension('BIG-REQUESTS', function(err, ext) { if (!ext.present) - callback(new Error('extension not available')); + return callback(new Error('extension not available')); ext.Enable = function( cb ) { diff --git a/lib/x11/ext/composite.js b/lib/x11/ext/composite.js index 7a41030..7e739de 100644 --- a/lib/x11/ext/composite.js +++ b/lib/x11/ext/composite.js @@ -20,7 +20,7 @@ exports.requireExt = function(display, callback) X.QueryExtension('Composite', function(err, ext) { if (!ext.present) - callback(new Error('extension not available')); + return callback(new Error('extension not available')); ext.Redirect = { Automatic: 0, diff --git a/lib/x11/ext/dpms.js b/lib/x11/ext/dpms.js new file mode 100644 index 0000000..2aeefdf --- /dev/null +++ b/lib/x11/ext/dpms.js @@ -0,0 +1,100 @@ +// http://www.x.org/releases/X11R7.6/doc/xextproto/dpms.txt + +var x11 = require('..'); +// TODO: move to templates +exports.requireExt = function(display, callback) +{ + var X = display.client; + X.QueryExtension('DPMS', function(err, ext) { + + if (!ext.present) + return callback(new Error('extension not available')); + + ext.GetVersion = function(clientMaj, clientMin, callback) + { + X.seq_num++; + X.pack_stream.pack('CCSSS', [ext.majorOpcode, 0, 2, clientMaj, clientMin]); + X.replies[X.seq_num] = [ + function(buf, opt) { + var res = buf.unpack('SS'); + return res; + }, + callback + ]; + X.pack_stream.flush(); + }; + + ext.Capable = function(callback) + { + X.seq_num++; + X.pack_stream.pack('CCS', [ext.majorOpcode, 1, 1]); + X.replies[X.seq_num] = [ + function(buf, opt) { + var res = buf.unpack('C'); + return res; + }, + callback + ]; + X.pack_stream.flush(); + }; + + ext.GetTimeouts = function(callback) + { + X.seq_num++; + X.pack_stream.pack('CCS', [ext.majorOpcode, 2, 1]); + X.replies[X.seq_num] = [ + function(buf, opt) { + var res = buf.unpack('SSS'); + return res; + }, + callback + ]; + X.pack_stream.flush(); + }; + + ext.SetTimeouts = function(standby_t, suspend_t, off_t) + { + X.seq_num++; + X.pack_stream.pack('CCSSSSxx', [ext.majorOpcode, 3, 3, standby_t, suspend_t, off_t]); + X.pack_stream.flush(); + }; + + ext.Enable = function() + { + X.seq_num++; + X.pack_stream.pack('CCS', [ext.majorOpcode, 4, 1]); + X.pack_stream.flush(); + }; + + ext.Disable = function() + { + X.seq_num++; + X.pack_stream.pack('CCS', [ext.majorOpcode, 5, 1]); + X.pack_stream.flush(); + }; + + ext.ForceLevel = function(level) // 0 : On, 1 : Standby, 2 : Suspend, 3 : Off + { + X.seq_num++; + X.pack_stream.pack('CCSSxx', [ext.majorOpcode, 6, 2, level]); + X.pack_stream.flush(); + }; + + ext.Info = function(callback) + { + X.seq_num++; + X.pack_stream.pack('CCS', [ext.majorOpcode, 7, 1]); + X.replies[X.seq_num] = [ + function(buf, opt) { + var res = buf.unpack('SC'); + return res; + }, + callback + ]; + X.pack_stream.flush(); + }; + + callback(ext); + }); +}; + diff --git a/lib/x11/ext/render.js b/lib/x11/ext/render.js index 5a580e5..4f3c010 100644 --- a/lib/x11/ext/render.js +++ b/lib/x11/ext/render.js @@ -22,7 +22,7 @@ exports.requireExt = function(display, callback) if (!ext.present) { - callback(new Error('extension not available')); + return callback(new Error('extension not available')); } ext.QueryVersion = function(clientMaj, clientMin, callback) diff --git a/lib/x11/ext/shape.js b/lib/x11/ext/shape.js index 8374c15..acb54ba 100644 --- a/lib/x11/ext/shape.js +++ b/lib/x11/ext/shape.js @@ -17,7 +17,7 @@ exports.requireExt = function(display, callback) X.QueryExtension('SHAPE', function(err, ext) { if (!ext.present) - callback(new Error('extension not available')); + return callback(new Error('extension not available')); ext.Kind = { Bounding: 0, diff --git a/lib/x11/ext/xc-misc.js b/lib/x11/ext/xc-misc.js index c15fb8d..1f0bc42 100644 --- a/lib/x11/ext/xc-misc.js +++ b/lib/x11/ext/xc-misc.js @@ -9,7 +9,7 @@ exports.requireExt = function(display, callback) X.QueryExtension('XC-MISC', function(err, ext) { if (!ext.present) - callback(new Error('extension not available')); + return callback(new Error('extension not available')); ext.QueryVersion = function(clientMaj, clientMin, cb) { diff --git a/lib/x11/ext/xtest.js b/lib/x11/ext/xtest.js index 82b0c90..689c0b6 100644 --- a/lib/x11/ext/xtest.js +++ b/lib/x11/ext/xtest.js @@ -8,16 +8,18 @@ exports.requireExt = function(display, callback) X.QueryExtension('XTEST', function(err, ext) { if (!ext.present) - callback(new Error('extension not available')); + return callback(new Error('extension not available')); - ext.QueryVersion = function(clientMaj, clientMin, callback) + ext.GetVersion = function(clientMaj, clientMin, callback) { X.seq_num++; - X.pack_stream.pack('CCSLL', [ext.majorOpcode, 0, 3, clientMaj, clientMin]); + X.pack_stream.pack('CCSCxS', [ext.majorOpcode, 0, 2, clientMaj, clientMin]); X.replies[X.seq_num] = [ function(buf, opt) { - var res = buf.unpack('LL'); - return res; + var res = buf.unpack('S'); + // Major version is in byte 1 of Reply Header + // Minor version is in the body of the reply + return [ opt, res[0] ]; }, callback ]; diff --git a/lib/x11/xcore.js b/lib/x11/xcore.js index 9c0b9ac..824c5bb 100644 --- a/lib/x11/xcore.js +++ b/lib/x11/xcore.js @@ -290,19 +290,19 @@ XClient.prototype.unpackEvent = function(type, seq, extra, code, raw) event.name = 'SelectionRequest'; event.time = extra; var values = raw.unpack('LLLLL'); - event.owner = raw[0]; - event.requestor = raw[1]; - event.selection = raw[2]; - event.target = raw[3]; - event.property = raw[4]; + event.owner = values[0]; + event.requestor = values[1]; + event.selection = values[2]; + event.target = values[3]; + event.property = values[4]; } else if (type == 31) {// SelectionNotify event.name = 'SelectionNotify'; event.time = extra; var values = raw.unpack('LLLL'); - event.requestor = raw[0]; - event.selection = raw[1]; - event.target = raw[2]; - event.property = raw[3]; + event.requestor = values[0]; + event.selection = values[1]; + event.target = values[2]; + event.property = values[3]; } return event; } diff --git a/package.json b/package.json index e0fb545..5c2b9aa 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ , "description": "A pure node.js JavaScript client implementing X Window (X11) protocol." , "keywords": ["X Window", "ui", "gui", "widgets", "desktop", "XWindow", "X"] , "homepage": "https://github.com/sidorares/node-x11" -, "version" : "0.0.10" +, "version" : "0.0.11" , "maintainers" : [ { "name": "Andrey Sidorov" , "email": "sidoares@yandex.ru" @@ -11,19 +11,17 @@ ] , "bugs" : { "url" : "http://github.com/sidorares/node-x11/issues" } , "licenses" : [ { "type" : "MIT" } ] -, "repositories" : - [ { "type" : "git" - , "url" : "http://github.com/sidorares/node-x11" - } - ] +, "repository" : { "type" : "git", "url" : "http://github.com/sidorares/node-x11.git" } + , "main" : "./lib/x11" , "engines" : { "node" : "*" } , "devDependencies": { "mocha": "*", - "should": "*" + "should": "*", + "async": "*" } , "scripts": { - "test": "mocha -t 80000", + "test": "node test-runner.js", "prepublish" : "npm prune" } } diff --git a/test-runner.js b/test-runner.js new file mode 100644 index 0000000..93b303e --- /dev/null +++ b/test-runner.js @@ -0,0 +1,89 @@ +var x11 = require('./lib/x11'); +var Mocha = require('mocha'); +var fs = require('fs'); +var path = require('path'); +var util = require('util'); +var async = require('async'); + +var mocha = new Mocha({ + timeout : 80000 +}); + +// 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(dpy) { + 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(dpy) { + 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)); + } + + 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(); + } + }, + function(err) { + mocha.run(function() { + process.exit(); + }); + } +); diff --git a/test/dpms.js b/test/dpms.js new file mode 100644 index 0000000..46601b6 --- /dev/null +++ b/test/dpms.js @@ -0,0 +1,101 @@ +var x11 = require('../lib/x11'); +var should = require('should'); +var assert = require('assert'); +var util = require('util'); + +describe('DPMS extension', function() { + var display; + var X; + var dpms; + before(function(done) { + var client = x11.createClient(function(dpy) { + display = dpy; + X = display.client; + X.require('dpms', function(ext) { + if (util.isError(ext)) { + done(ext); + } else { + dpms = ext; + done(); + } + }); + }); + + client.on('error', done); + }); + + describe('Setting the DPMS timeouts to specific values', function() { + + var prev_timeouts; + before(function(done) { + dpms.GetTimeouts(function(err, timeouts) { + prev_timeouts = timeouts; + done(err); + }); + }); + + it('GetTimeouts should return those values', function(done) { + dpms.SetTimeouts(110, 110, 110); + dpms.GetTimeouts(function(err, timeouts) { + if (!err) timeouts.should.eql([110, 110, 110]); + done(err); + }); + }); + + after(function(done) { + dpms.SetTimeouts(prev_timeouts[0], prev_timeouts[1], prev_timeouts[2]); + dpms.GetTimeouts(function(err, timeouts) { + if (!err) timeouts.should.eql(prev_timeouts); + done(err); + }); + }); + }); + + describe('Changing status and level of DPMS', function() { + var prev_status; + var prev_level; + before(function(done) { + dpms.Info(function(err, info) { + if (!err) { + prev_level = info[0]; + prev_status = info[1]; + } + + done(err); + }); + }); + + it('Info should return the correct values', function(done) { + if (prev_status === 0) dpms.Enable(); // for force level to work dpms must be enabled + var new_level = prev_level === 0 ? 1 : 0; + dpms.ForceLevel(new_level); + dpms.Info(function(err, info) { + if (!err) { + info[0].should.equal(new_level); + info[1].should.equal(1); + } + + done(err); + }); + }); + + after(function(done) { + dpms.ForceLevel(prev_level); + if (prev_status) dpms.Enable(); + else dpms.Disable(); + dpms.Info(function(err, info) { + if (!err) { + info[0].should.equal(prev_level); + info[1].should.equal(prev_status); + } + + done(err); + }); + }); + }); + + after(function(done) { + X.terminate(); + X.on('end', done); + }); +}); diff --git a/test/xtest.js b/test/xtest.js new file mode 100644 index 0000000..3d018af --- /dev/null +++ b/test/xtest.js @@ -0,0 +1,40 @@ +var x11 = require('../lib/x11'); +var should = require('should'); +var assert = require('assert'); +var util = require('util'); + +describe('XTEST extension', function() { + var display; + var X; + var xtest; + before(function(done) { + var client = x11.createClient(function(dpy) { + display = dpy; + X = display.client; + X.require('xtest', function(ext) { + if (util.isError(ext)) { + done(ext); + } else { + xtest = ext; + done(); + } + }); + }); + + client.on('error', done); + }); + + describe('GetVersion', function() { + it('should return version 2.2', function(done) { + xtest.GetVersion(2, 2, function(err, version) { + version.should.eql([2, 2]); + done(); + }); + }); + }); + + after(function(done) { + X.terminate(); + X.on('end', done); + }); +});