mirror of
https://github.com/danbulant/node-x11
synced 2026-07-05 11:10:58 +00:00
Atoms requests, handling replies (work in progress)
This commit is contained in:
parent
3f4c8b5700
commit
3d3658d0b8
10 changed files with 165 additions and 37 deletions
|
|
@ -1,3 +1,5 @@
|
||||||
|
var xutil = require('./xutil');
|
||||||
|
|
||||||
var valueMask = {
|
var valueMask = {
|
||||||
CreateWindow: {
|
CreateWindow: {
|
||||||
backgroundPixmap: 0x00000001,
|
backgroundPixmap: 0x00000001,
|
||||||
|
|
@ -65,7 +67,7 @@ function packValueMask(reqname, values)
|
||||||
{
|
{
|
||||||
var valueBit = reqValueMask[v];
|
var valueBit = reqValueMask[v];
|
||||||
if (!valueBit)
|
if (!valueBit)
|
||||||
throw new Error('CreateWindow: incorrect value param ' + v);
|
throw new Error(reqname + ': incorrect value param ' + v);
|
||||||
masksList.push(valueBit);
|
masksList.push(valueBit);
|
||||||
bitmask |= valueBit;
|
bitmask |= valueBit;
|
||||||
}
|
}
|
||||||
|
|
@ -104,7 +106,7 @@ the way requests are described here
|
||||||
module.exports = {
|
module.exports = {
|
||||||
CreateWindow: [
|
CreateWindow: [
|
||||||
// create request packet - function OR format string
|
// 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
|
// TODO: ??? there is depth field in xproto, but xlib just sets it to zero
|
||||||
var depth = 0;
|
var depth = 0;
|
||||||
|
|
@ -116,7 +118,7 @@ module.exports = {
|
||||||
// create bitmask
|
// create bitmask
|
||||||
var bitmask = 0;
|
var bitmask = 0;
|
||||||
// TODO: slice from function arguments?
|
// 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
|
// TODO: the code is a little bit mess
|
||||||
// additional values need to be packed in the following way:
|
// additional values need to be packed in the following way:
|
||||||
|
|
@ -178,5 +180,25 @@ module.exports = {
|
||||||
}
|
}
|
||||||
return [format, args];
|
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 !!!!');
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ var handshake = require('./handshake');
|
||||||
var EventEmitter = require('events').EventEmitter;
|
var EventEmitter = require('events').EventEmitter;
|
||||||
var PackStream = require('./unpackstream');
|
var PackStream = require('./unpackstream');
|
||||||
var coreRequestsTemplate = require('./corereqs');
|
var coreRequestsTemplate = require('./corereqs');
|
||||||
//var hexy = require('./hexy').hexy;
|
var hexy = require('./hexy').hexy;
|
||||||
|
|
||||||
var Buffer = require('buffer').Buffer;
|
var Buffer = require('buffer').Buffer;
|
||||||
// add 'unpack' method for buffer
|
// add 'unpack' method for buffer
|
||||||
|
|
@ -57,6 +57,8 @@ function XClient(stream)
|
||||||
this.importRequestsFromTemplates(this, coreRequests);
|
this.importRequestsFromTemplates(this, coreRequests);
|
||||||
this.startHandshake();
|
this.startHandshake();
|
||||||
|
|
||||||
|
this.event_consumers = {}; // maps window id to eventemitter
|
||||||
|
|
||||||
// import available extentions
|
// import available extentions
|
||||||
// TODO: lazy import on first call?
|
// TODO: lazy import on first call?
|
||||||
/*
|
/*
|
||||||
|
|
@ -82,8 +84,11 @@ XClient.prototype.importRequestsFromTemplates = function(target, reqs)
|
||||||
// r is request name
|
// r is request name
|
||||||
target[r] = (function(reqName) {
|
target[r] = (function(reqName) {
|
||||||
var reqFunc = function req_proxy() {
|
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);
|
var args = Array.prototype.slice.call(req_proxy.arguments);
|
||||||
|
|
||||||
// TODO: setup last argument to be reply/error callback
|
// TODO: setup last argument to be reply/error callback
|
||||||
// var callback = args.length > 0 ? null : args[args.length - 1];
|
// 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);
|
reqPack = reqTemplate.apply(this, req_proxy.arguments);
|
||||||
var format = reqPack[0];
|
var format = reqPack[0];
|
||||||
var requestArguments = reqPack[1];
|
var requestArguments = reqPack[1];
|
||||||
|
console.error([format, requestArguments]);
|
||||||
client.pack_stream.pack(format, requestArguments);
|
client.pack_stream.pack(format, requestArguments);
|
||||||
client.pack_stream.flush();
|
client.pack_stream.flush();
|
||||||
} else if (templateType == 'Array'){
|
} else if (templateType == 'Array'){
|
||||||
|
|
@ -109,6 +115,7 @@ XClient.prototype.importRequestsFromTemplates = function(target, reqs)
|
||||||
var requestArguments = reqTemplate[1];
|
var requestArguments = reqTemplate[1];
|
||||||
for (a in args)
|
for (a in args)
|
||||||
requestArguments.push(args[a]);
|
requestArguments.push(args[a]);
|
||||||
|
console.error([format, requestArguments]);
|
||||||
client.pack_stream.pack(format, requestArguments);
|
client.pack_stream.pack(format, requestArguments);
|
||||||
client.pack_stream.flush();
|
client.pack_stream.flush();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -149,7 +156,6 @@ XClient.prototype.unpackEvent = function(type, seq, extra, raw)
|
||||||
event.buttons = values[7];
|
event.buttons = values[7];
|
||||||
event.sameScreen = values[8];
|
event.sameScreen = values[8];
|
||||||
}
|
}
|
||||||
//console.log(event);
|
|
||||||
return event;
|
return event;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -176,18 +182,27 @@ XClient.prototype.expectReplyHeader = function()
|
||||||
var extra = res[3];
|
var extra = res[3];
|
||||||
var ev = client.unpackEvent(type, seq_num, extra, buf);
|
var ev = client.unpackEvent(type, seq_num, extra, buf);
|
||||||
client.emit('event', ev);
|
client.emit('event', ev);
|
||||||
// TODO: dispatch, use sequence number
|
var ee = client.event_consumers[ev.wid];
|
||||||
// console.error('event!!!! ' + type);
|
if (ee) {
|
||||||
|
ee.emit('event', ev);
|
||||||
|
}
|
||||||
client.expectReplyHeader();
|
client.expectReplyHeader();
|
||||||
} );
|
} );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var opt_data = res[1];
|
var opt_data = res[1];
|
||||||
var length_total = res[3]; // in 4-bytes units, _including_ this header
|
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 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 ) {
|
client.pack_stream.get( bodylength, function( data ) {
|
||||||
|
|
||||||
|
var handler = this.replyHandlers[seq_num];
|
||||||
|
|
||||||
// TODO: decode and dispatch, use sequence number
|
// 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
|
// wait for new packet from server
|
||||||
client.expectReplyHeader();
|
client.expectReplyHeader();
|
||||||
|
|
|
||||||
|
|
@ -7,15 +7,19 @@ function padded_length(len)
|
||||||
return padded_length;
|
return padded_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: make it return buffer?
|
||||||
|
// str += is slow
|
||||||
function padded_string(str)
|
function padded_string(str)
|
||||||
{
|
{
|
||||||
if (str.length == 0);
|
if (str.length == 0)
|
||||||
return '';
|
return '';
|
||||||
|
|
||||||
var len = padded_length(str.len);
|
var pad = padded_length(str.length) - str.length;
|
||||||
var res = str;
|
var res = str;
|
||||||
for (var i=0; i < len; ++i)
|
for (var i=0; i < pad; ++i)
|
||||||
res += String.fromCharCode(0);
|
res += String.fromCharCode(0);
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.padded_length = padded_length;
|
module.exports.padded_length = padded_length;
|
||||||
|
|
|
||||||
14
test/atoms.js
Normal file
14
test/atoms.js
Normal file
|
|
@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
3
test/c-tests/Makefile
Normal file
3
test/c-tests/Makefile
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
LDFLAGS=-lX11
|
||||||
|
|
||||||
|
simplewin: simplewin.o
|
||||||
BIN
test/c-tests/simplewin
Executable file
BIN
test/c-tests/simplewin
Executable file
Binary file not shown.
42
test/c-tests/simplewin.c
Normal file
42
test/c-tests/simplewin.c
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
BIN
test/c-tests/simplewin.o
Normal file
BIN
test/c-tests/simplewin.o
Normal file
Binary file not shown.
|
|
@ -9,15 +9,43 @@ xclient.on('connect', function(display) {
|
||||||
var white = xclient.display.screen[0].white_pixel;
|
var white = xclient.display.screen[0].white_pixel;
|
||||||
var black = xclient.display.screen[0].black_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 x = 0; x < width; x += 20) {
|
||||||
for (var y = 0; y < width; y += 20) {
|
for (var y = 0; y < width; y += 20) {
|
||||||
// TODO: wnd.createChild() ?
|
// 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.on('mousemove', function(ev) {
|
||||||
ch.unmap();
|
ch.unmap();
|
||||||
setTimeout( function() { ch.map() }, 500);
|
setTimeout( function() { ch.map() }, 500);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -29,33 +29,33 @@ function Window(parent, x, y, w, h, bg)
|
||||||
this.h = h;
|
this.h = h;
|
||||||
this.bg = bg;
|
this.bg = bg;
|
||||||
this.id = this.xclient.AllocID();
|
this.id = this.xclient.AllocID();
|
||||||
|
|
||||||
|
var borderWidth = 1;
|
||||||
|
var _class = 1; // InputOutput
|
||||||
|
var visual = 0; // CopyFromParent
|
||||||
this.xclient.CreateWindow(
|
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();
|
//this.map();
|
||||||
// very ineffitient this way!!!
|
|
||||||
var wnd = this;
|
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 = {
|
eventType2eventName = {
|
||||||
6: 'mousemove'
|
6: 'mousemove'
|
||||||
};
|
};
|
||||||
|
|
||||||
this.xclient.event_consumers[wnd.id] = function( ev )
|
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); // convert to mousemove? (ev already event-spacific)
|
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);
|
util.inherits(Window, EventEmitter);
|
||||||
|
|
||||||
|
|
@ -64,7 +64,7 @@ Window.prototype.map = function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Window.prototype.unmap = function() {
|
Window.prototype.unmap = function() {
|
||||||
this.xclient.UnapWindow(this.id);
|
this.xclient.UnmapWindow(this.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Window;
|
module.exports = Window;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue