diff --git a/lib/x11/corereqs.js b/lib/x11/corereqs.js index e3eeaea..efa1bdc 100644 --- a/lib/x11/corereqs.js +++ b/lib/x11/corereqs.js @@ -1,3 +1,5 @@ +var xutil = require('./xutil'); + var valueMask = { CreateWindow: { backgroundPixmap: 0x00000001, @@ -65,7 +67,7 @@ function packValueMask(reqname, values) { var valueBit = reqValueMask[v]; if (!valueBit) - throw new Error('CreateWindow: incorrect value param ' + v); + throw new Error(reqname + ': incorrect value param ' + v); masksList.push(valueBit); bitmask |= valueBit; } @@ -105,7 +107,10 @@ module.exports = { CreateWindow: [ // create request packet - function OR format string function(id, parentId, x, y, width, height, borderWidth, _class, visual, values) { +<<<<<<< HEAD console.log('CreateWindow called', id); +======= +>>>>>>> 3d3658d0b81642440a915e706d2c28b412c1a383 // TODO: ??? there is depth field in xproto, but xlib just sets it to zero var depth = 0; @@ -179,5 +184,25 @@ module.exports = { } return [format, args]; } + ], + + // opcode 16 + InternAtom: [ + function (returnOnlyIfExist, value) + { + var padded = xutil.padded_string(value); + return ['CCSSa', [16, returnOnlyIfExist ? 1 : 0, 2+padded.length/4, value.length, value] ]; + }, + + function(stream, buf) { + console.error('Intern Atom reply !!!!'); + } + ], + + GetAtomName: [ + [ 'CxSL', [17, 2] ], + function(stream, buf) { + console.error('Intern GetAtomName reply !!!!'); + } ] } diff --git a/lib/x11/xcore.js b/lib/x11/xcore.js index 3c7f5c5..f1db47f 100644 --- a/lib/x11/xcore.js +++ b/lib/x11/xcore.js @@ -7,7 +7,7 @@ var handshake = require('./handshake'); var EventEmitter = require('events').EventEmitter; var PackStream = require('./unpackstream'); var coreRequestsTemplate = require('./corereqs'); -//var hexy = require('./hexy').hexy; +var hexy = require('./hexy').hexy; var Buffer = require('buffer').Buffer; // add 'unpack' method for buffer @@ -57,6 +57,8 @@ function XClient(stream) this.importRequestsFromTemplates(this, coreRequests); this.startHandshake(); + this.event_consumers = {}; // maps window id to eventemitter + // import available extentions // TODO: lazy import on first call? /* @@ -82,7 +84,11 @@ XClient.prototype.importRequestsFromTemplates = function(target, reqs) // r is request name target[r] = (function(reqName) { var reqFunc = function req_proxy() { + client.seq_num++; // TODO: handle overflow (seq should be last 15 (?) bits of the number + + // is it fast? var args = Array.prototype.slice.call(req_proxy.arguments); + // TODO: setup last argument to be reply/error callback // var callback = args.length > 0 ? null : args[args.length - 1]; @@ -101,6 +107,7 @@ XClient.prototype.importRequestsFromTemplates = function(target, reqs) reqPack = reqTemplate.apply(this, req_proxy.arguments); var format = reqPack[0]; var requestArguments = reqPack[1]; + console.error([format, requestArguments]); client.pack_stream.pack(format, requestArguments); client.pack_stream.flush(); } else if (templateType == 'Array'){ @@ -108,6 +115,7 @@ XClient.prototype.importRequestsFromTemplates = function(target, reqs) var requestArguments = reqTemplate[1]; for (a in args) requestArguments.push(args[a]); + console.error([format, requestArguments]); client.pack_stream.pack(format, requestArguments); client.pack_stream.flush(); } else { @@ -127,6 +135,30 @@ XClient.prototype.AllocID = function() return (this.display.rsrc_id << this.display.rsrc_shift) + this.display.resource_base; } +XClient.prototype.unpackEvent = function(type, seq, extra, raw) +{ + var event = {}; // TODO: constructor & base functions + event.type = type; + event.seq = seq; + + if (type == 6) { // motion event + var values = raw.unpack('LLLSSSSSC'); //TODO: should be LLLLsssssSC + //event.raw = values; + // TODO: use unpackTo??? + event.time = extra; + event.root = values[0]; + event.wid = values[1]; + event.child = values[2]; + event.rootx = values[3]; + event.rooty = values[4]; + event.x = values[5]; + event.y = values[6]; + event.buttons = values[7]; + event.sameScreen = values[8]; + } + return event; +} + XClient.prototype.expectReplyHeader = function() { var client = this; @@ -147,18 +179,30 @@ XClient.prototype.expectReplyHeader = function() } else if (type > 1) { client.pack_stream.get(24, function(buf) { - // TODO: dispatch, use sequence number - console.error('event!!!! ' + type); + var extra = res[3]; + var ev = client.unpackEvent(type, seq_num, extra, buf); + client.emit('event', ev); + var ee = client.event_consumers[ev.wid]; + if (ee) { + ee.emit('event', ev); + } client.expectReplyHeader(); } ); return; } var opt_data = res[1]; - var length_total = res[3]; // in 4-bytes units, _including_ this header - var bodylength = (length_total-2)*4; // length of the data in bytes + var length_total = res[3]; // in 4-bytes units, _including_ this header + var bodylength = 24 + length_total*4; // 24 is rest if 32-bytes header + + console.log(res); + console.log('reply of length ' + bodylength + ' should follow'); client.pack_stream.get( bodylength, function( data ) { + + var handler = this.replyHandlers[seq_num]; + // TODO: decode and dispatch, use sequence number - console.error('reply data!!!'); + console.error('reply data!!!!!!!!!!'); + console.error(hexy(data, { prefix: 'InternAtom reply' })); // wait for new packet from server client.expectReplyHeader(); diff --git a/lib/x11/xutil.js b/lib/x11/xutil.js index b401faf..87e4599 100644 --- a/lib/x11/xutil.js +++ b/lib/x11/xutil.js @@ -7,15 +7,19 @@ function padded_length(len) return padded_length; } +// TODO: make it return buffer? +// str += is slow function padded_string(str) { - if (str.length == 0); + if (str.length == 0) return ''; - var len = padded_length(str.len); + var pad = padded_length(str.length) - str.length; var res = str; - for (var i=0; i < len; ++i) + for (var i=0; i < pad; ++i) res += String.fromCharCode(0); + + return res; } module.exports.padded_length = padded_length; diff --git a/test/atoms.js b/test/atoms.js new file mode 100644 index 0000000..fba1db7 --- /dev/null +++ b/test/atoms.js @@ -0,0 +1,14 @@ +var x11 = require('../lib/x11'); + +var xclient = x11.createClient(); + +xclient.on('connect', function(display) { + var X = this; + var hello = 'Hello, node.js'; + X.InternAtom(false, hello, function(atomId) { + console.log(atomId); + }); + X.InternAtom(true, 'test', function(atomId) { + console.log(atomId); + }); +}); diff --git a/test/c-tests/Makefile b/test/c-tests/Makefile new file mode 100644 index 0000000..9b00c85 --- /dev/null +++ b/test/c-tests/Makefile @@ -0,0 +1,3 @@ +LDFLAGS=-lX11 + +simplewin: simplewin.o diff --git a/test/c-tests/simplewin b/test/c-tests/simplewin new file mode 100755 index 0000000..d310a8f Binary files /dev/null and b/test/c-tests/simplewin differ diff --git a/test/c-tests/simplewin.c b/test/c-tests/simplewin.c new file mode 100644 index 0000000..a3f3926 --- /dev/null +++ b/test/c-tests/simplewin.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include + +int main(void) { + Display *d; + Window w, w1; + XEvent e; + char *msg = "Hello, world!"; + int s; + + d = XOpenDisplay(NULL); + if (d == NULL) { + fprintf(stderr, "Cannot open display\n"); + exit(1); + } + + s = DefaultScreen(d); + w = XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 100, 100, 1, + BlackPixel(d, s), WhitePixel(d, s)); + + w1 = XCreateSimpleWindow(d, RootWindow(d, s), 50, 50, 50, 50, 1, + BlackPixel(d, s), WhitePixel(d, s)); + XSelectInput(d, w, ExposureMask | KeyPressMask); + XSelectInput(d, w1, ExposureMask); + XMapWindow(d, w); + XMapWindow(d, w1); + + while (1) { + XNextEvent(d, &e); + if (e.type == Expose) { + XFillRectangle(e.xany.display, e.xany.window, DefaultGC(d, s), 20, 20, 10, 10); + XDrawString(e.xany.display, e.xany.window, DefaultGC(d, s), 10, 50, msg, strlen(msg)); + } + if (e.type == KeyPress) + break; + } + + XCloseDisplay(d); + return 0; +} diff --git a/test/c-tests/simplewin.o b/test/c-tests/simplewin.o new file mode 100644 index 0000000..41e84e6 Binary files /dev/null and b/test/c-tests/simplewin.o differ diff --git a/test/createwindow.js b/test/createwindow.js index ccf484e..1aa932e 100644 --- a/test/createwindow.js +++ b/test/createwindow.js @@ -9,4 +9,9 @@ xclient.on('connect', function(display) { X.CreateWindow(wid, root, 10, 10, 400, 300, 1, 1, 0, { backgroundPixel: 0, eventMask: 0x00000040 }); X.MapWindow(wid); + + var wid1 = X.AllocID(); + X.CreateWindow(wid1, root, 10, 10, 40, 30, 1, 1, 0, { backgroundPixel: xclient.display.screen[0].white_pixel, eventMask: 0x00000040 }); + X.MapWindow(wid1); + }); \ No newline at end of file diff --git a/test/testwnd.js b/test/testwnd.js deleted file mode 100644 index cb0b09d..0000000 --- a/test/testwnd.js +++ /dev/null @@ -1,23 +0,0 @@ -var x11 = require('../lib/x11'); -var Window = require('./wndwrap'); - -var width = 700; -var height = 500; - -var xclient = x11.createClient(); -xclient.on('connect', function(display) { - var white = xclient.display.screen[0].white_pixel; - var black = xclient.display.screen[0].black_pixel; - - var mainwnd = new Window(xclient, 0, 0, width, height, black); - for (var x = 0; x < width; x += 20) { - for (var y = 0; y < width; y += 20) { - // TODO: wnd.createChild() ? - var ch = new Window(xclient, x + 1, y + 1, 18, 18, 0, white); - ch.on('mousemove', function(ev) { - ch.unmap(); - setTimeout( function() { ch.map() }, 500); - }); - } - } -}); diff --git a/test/wndwrap.js b/test/wndwrap.js deleted file mode 100644 index 04bd867..0000000 --- a/test/wndwrap.js +++ /dev/null @@ -1,70 +0,0 @@ -var EventEmitter = require('events').EventEmitter; -var util = require('util'); // util.inherits - -function Window(parent, x, y, w, h, bg) -{ - if (parent.constructor && parent.constructor.name == 'XClient') - { - this.xclient = parent; - if (!this.xclient.rootWindow) - { - // quick hack - var rootWnd = { - id: this.xclient.display.screen[0].root, - xclient: this.xclient - }; - rootWnd.parent = null; - this.parent = this.xclient.rootWnd; - this.xclient.rootWindow = rootWnd; - } - this.parent = this.xclient.rootWindow; - } else { - this.parent = parent; - this.xclient = parent.xclient; - } - - this.x = x; - this.y = y; - this.w = w; - this.h = h; - this.bg = bg; - this.id = this.xclient.AllocID(); - this.xclient.CreateWindow( - this.id, this.parent.id, this.x, this.y, this.w, this.h, 1, 1, 0, { backgroundPixel: this.bg, eventMask: 0x00000040 } - ); - this.map(); - // very ineffitient this way!!! - var wnd = this; - this.xclient.on('event', function(ev) - { - if (ev.type == 6 && ev.wid == wnd.id) - { - wnd.emit('mousemove', ev); - } - }); - /* - // TODO: right way to handle events - // need to modify xcore to dispatch events to event_consumers - // - eventType2eventName = { - 6: 'mousemove' - }; - - this.xclient.event_consumers[wnd.id] = function( ev ) - { - wnd.emit(eventType2eventName, ev); // convert to mousemove? (ev already event-spacific) - }; - - */ -} -util.inherits(Window, EventEmitter); - -Window.prototype.map = function() { - this.xclient.MapWindow(this.id); -} - -Window.prototype.unmap = function() { - this.xclient.UnapWindow(this.id); -} - -module.exports = Window;