diff --git a/lib/x11/corereqs.js b/lib/x11/corereqs.js index bcdae15..24edcfb 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; } @@ -104,7 +106,7 @@ the way requests are described here module.exports = { CreateWindow: [ // create request packet - function OR format string - function(id, parentId, x, y, width, height, borderWidth, class, visual, values) { + function(id, parentId, x, y, width, height, borderWidth, _class, visual, values) { // TODO: ??? there is depth field in xproto, but xlib just sets it to zero var depth = 0; @@ -116,7 +118,7 @@ module.exports = { // create bitmask var bitmask = 0; // TODO: slice from function arguments? - var args = [1, depth, packetLength, id, parentId, x, y, width, height, borderWidth, class, visual]; + var args = [1, depth, packetLength, id, parentId, x, y, width, height, borderWidth, _class, visual]; // TODO: the code is a little bit mess // additional values need to be packed in the following way: @@ -178,5 +180,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 e758c5d..d281e89 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,8 +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 overflw (seq should be last 15 (?) bits of the number + 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]; @@ -102,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'){ @@ -109,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 { @@ -149,7 +156,6 @@ XClient.prototype.unpackEvent = function(type, seq, extra, raw) event.buttons = values[7]; event.sameScreen = values[8]; } - //console.log(event); return event; } @@ -176,18 +182,27 @@ XClient.prototype.expectReplyHeader = function() var extra = res[3]; var ev = client.unpackEvent(type, seq_num, extra, buf); client.emit('event', ev); - // TODO: dispatch, use sequence number - // console.error('event!!!! ' + type); + 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/testwnd.js b/test/testwnd.js index cb0b09d..aef6076 100644 --- a/test/testwnd.js +++ b/test/testwnd.js @@ -9,15 +9,43 @@ 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); + var mainwnd = new Window(xclient, 0, 0, width, height, white); + //mainwnd.on('mousemove', function(ev) { + // console.log(ev.x, ev.y); + //}); + var ch = new Window(mainwnd, 10, 10, 50, 70, black); + ch.on('mousemove', function(ev) { + console.log(ev); + //ch.unmap(); + //setTimeout( function() { ch.map() }, 500); + }); + + mainwnd.map(); + + setInterval( function() { + console.log(ch.mapped); + if (!ch.mapped) + { + ch.map(); + ch.mapped = true; + } + else { + ch.unmap(); + ch.mapped = false; + } + }, 500); + + /* 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); + var ch = new Window(mainwnd, x + 1, y + 1, 18, 18, 0, black); + //ch.map(); ch.on('mousemove', function(ev) { ch.unmap(); setTimeout( function() { ch.map() }, 500); }); } } + */ }); diff --git a/test/wndwrap.js b/test/wndwrap.js index 04bd867..f0cb058 100644 --- a/test/wndwrap.js +++ b/test/wndwrap.js @@ -29,33 +29,33 @@ function Window(parent, x, y, w, h, bg) this.h = h; this.bg = bg; this.id = this.xclient.AllocID(); + + var borderWidth = 1; + var _class = 1; // InputOutput + var visual = 0; // CopyFromParent 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.id, this.parent.id, this.x, this.y, this.w, this.h, + borderWidth, _class, visual, + { + backgroundPixel: this.bg, + eventMask: 0x00000040 + } ); - this.map(); - // very ineffitient this way!!! + //this.map(); + 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) - }; - - */ + var ee = new EventEmitter(); + this.xclient.event_consumers[wnd.id] = ee; + // TODO: do we need to have wnd as EventEmitter AND EventEmitter stored in event_consumers ? + ee.on('event', function( ev ) + { + wnd.emit(eventType2eventName[ev.type], ev); // convert to mousemove? (ev is already event-spacific) + }); + // TODO: track delete events and remove wmd from consumers list } util.inherits(Window, EventEmitter); @@ -64,7 +64,7 @@ Window.prototype.map = function() { } Window.prototype.unmap = function() { - this.xclient.UnapWindow(this.id); + this.xclient.UnmapWindow(this.id); } module.exports = Window;