Compare commits

...

92 commits

Author SHA1 Message Date
Daniel Bulant
eeb9d58310
Parse FocusIn and FocusOut events 2021-08-05 15:54:39 +02:00
Andrey Sidorov
97e3600467 disable failing envs 2020-05-21 22:02:07 +10:00
Andrey Sidorov
bf56aef5a4 skip failing test 2020-05-21 20:54:16 +10:00
Andrey Sidorov
7728cde55e
Merge pull request #189 from sidorares/greenkeeper/async-3.0.1
Update async to the latest version 🚀
2020-05-21 20:20:03 +10:00
Andrey Sidorov
89fd615f8f
Merge pull request #188 from sidorares/greenkeeper/sinon-7.2.5
Update sinon to the latest version 🚀
2020-05-21 20:19:49 +10:00
Andrey Sidorov
1db2cb54c3
Merge pull request #194 from matoruru/patch-1
Remove unnecessary parentheses from require('os').homedir()
2020-05-21 20:17:05 +10:00
Andrey Sidorov
4ece7f2b0b
Merge branch 'master' into greenkeeper/async-3.0.1 2020-05-21 20:16:03 +10:00
Andrey Sidorov
b50b222a74
Merge pull request #118 from vird/patch-1
Array proto crash fix
2020-05-21 20:13:29 +10:00
Andrey Sidorov
9414ed788d deps: update mocha 2020-05-21 20:10:59 +10:00
Andrey Sidorov
c54dddd746 build: bump node versions to 12 + 14 2020-05-21 20:10:43 +10:00
matoruru
c41ad68e34
Remove unnecessary parentheses from require('os').homedir() 2020-05-19 23:20:01 +09:00
Andrey Sidorov
e17e8b04a1
Merge pull request #192 from mat-sz/master
Replaced os-homedir (deprecated) with os.homedir()
2020-04-25 14:41:43 +10:00
Mat Sz
3d6295f0df .gitignore 2020-04-24 19:35:17 +02:00
Mat Sz
a16c1cb8eb replaced os-homedir with os.homedir() 2020-04-24 19:30:32 +02:00
Andrey Sidorov
8ed75f54e1
Merge pull request #190 from roquef/patch-1
Fixes variable declaration typo in example
2019-10-12 10:39:53 +11:00
Roque Francisco
340432893d
Fixes variable declaration typo in example 2019-10-11 15:07:25 -03:00
greenkeeper[bot]
8500b1fc54 chore(package): update async to version 3.0.1 2019-05-26 21:47:27 +00:00
greenkeeper[bot]
43a7e7375a chore(package): update sinon to version 7.2.5 2019-02-27 12:09:30 +00:00
Andrey Sidorov
f6547d3876
Update README.md 2019-01-15 17:24:08 +11:00
Andrey Sidorov
15c7149c6a Add Render.AddGlyphsFromPicture request 2018-12-13 14:55:07 +11:00
Andrey Sidorov
4bddee6d5e
Merge pull request #181 from SpaceboyRoss01/master
Lots more stuff
2018-11-15 09:32:55 +11:00
Spaceboy Ross
8f322e5f8f Missed something but its fixed 2018-11-14 12:27:41 -08:00
Spaceboy Ross
5c46c4f1d3 Added XBell 2018-11-14 12:27:10 -08:00
Spaceboy Ross
29b454ee3d #182 fixed 2018-11-14 12:22:16 -08:00
Spaceboy Ross
66bc53624d Begining of fixing sidorares/node-x11#182 2018-11-14 12:05:24 -08:00
Spaceboy Ross
d1868d5ee8 Fixed the unpack stream so arrays can work 2018-11-14 11:44:12 -08:00
Andrey Sidorov
2d7ffc2bcd Merge branch 'master' of https://github.com/sidorares/node-x11 2018-07-09 14:01:51 +10:00
Andrey Sidorov
4c6617c994 make text example work when default bg color is black 2018-07-09 14:01:14 +10:00
Andrey Sidorov
174cff9a9c
Merge pull request #172 from sidorares/greenkeeper/sinon-6.0.0
Update sinon to the latest version 🚀
2018-06-11 22:12:09 +10:00
greenkeeper[bot]
2bb273993e chore(package): update sinon to version 6.0.0 2018-06-11 05:58:46 +00:00
Andrey Sidorov
d5c4103b1f
Merge pull request #169 from sidorares/greenkeeper/sinon-5.0.1
chore(package): update sinon to version 5.0.1
2018-04-30 19:52:29 +10:00
greenkeeper[bot]
d004af97fa chore(package): update sinon to version 5.0.1 2018-04-30 08:42:48 +00:00
Andrey Sidorov
ce51cefdad
Merge pull request #167 from sidorares/greenkeeper/sinon-5.0.0
Update sinon to the latest version 🚀
2018-03-22 10:16:26 +11:00
greenkeeper[bot]
373b60b975 chore(package): update sinon to version 5.0.0 2018-03-21 17:27:33 +00:00
Andrey Sidorov
85905efeae
Merge pull request #164 from anko/just-some-maintenance
Mr Janitor coming through
2018-01-24 10:00:56 +11:00
Andrey Sidorov
ef001bd4fb
Merge pull request #163 from anko/stop-testing-on-old-node-versions
Stop testing on Node 0.10 + 0.12
2018-01-24 09:51:14 +11:00
Antti Korpi
6f535cb65d Travis: stop testing on Node 0.10 + 0.12
They're breaking the build, because Mocha (a dependency) is using modern
JS features.
2018-01-23 22:36:27 +01:00
Antti Korpi
ed27aa84ff Fix 'root' deprecation warning
This would previously be printed in part of the test log:

    (node:1628) [DEP0016] DeprecationWarning: 'root' is deprecated, use 'global'

Apparently, the global object was once called root, and this assignment
didn't have a `var`, so it was actually setting the global object.

I do wonder why that didn't break anything, but this is clearly what was
intended.
2018-01-23 22:35:49 +01:00
Antti Korpi
e87b183a8f Use sinon.resetHistory; sinon.reset is deprecated 2018-01-23 22:06:42 +01:00
Antti Korpi
fd09ef9848 Nail devDependencies to specific version
This documents what versions it's supposed to work with, and reduces
potential future confusion if contributors accidentally work with
different tool versions.
2018-01-23 21:59:21 +01:00
Andrey Sidorov
4e84ae8e40 2.3.0 2017-08-27 15:11:35 +10:00
Andrey Sidorov
a97f7a179d Merge pull request #150 from jdomenechb/shapenotify
Added ShapeNotify event parsing
2017-08-27 10:10:37 +10:00
jdomenechb
bc9dceebd4 Added ShapeNotify event parsing 2017-08-26 17:00:10 +02:00
Andrey Sidorov
18cbbdf6ee Merge pull request #148 from andrewstart/master
Fix ChangeGC.
2017-08-05 02:11:35 +10:00
Andrew Start
da262fcb8d Add test for ChangeGC. 2017-08-04 12:05:05 -04:00
Andrew Start
8049e70deb Fix ChangeGC. 2017-08-04 11:45:41 -04:00
Andrey Sidorov
eb674cc41c Merge pull request #147 from anko/readme-cleanup
Readme cleanup
2017-07-21 08:45:41 +10:00
Antti Korpi
f13247ec6d Readme cleanup
- Drop headings to level 2 (except the top one).
 - Fix Gitter link.
 - Trim example code indent level.
2017-07-20 17:07:56 +01:00
Andrey Sidorov
6598e75baf add link to xelb 2017-06-09 11:11:34 +10:00
Andrey Sidorov
3ca322cecc 2.2.1 2017-04-21 22:53:52 +10:00
Andrey Sidorov
97a582be5c Merge pull request #141 from drom/master
added dummy function "stash" to help browserify bundler with require prefetch
2017-04-21 22:52:39 +10:00
Aliaksei Chapyzhenka
7341a317bd added node 6 7 regression 2017-04-20 22:36:23 -07:00
Aliaksei Chapyzhenka
37d0130b38 fixed badge 2017-04-20 22:35:15 -07:00
Aliaksei Chapyzhenka
08a6ae573e added dummy function "stash" to help browserify bundler with require prefetch 2017-04-20 22:20:35 -07:00
Andrey Sidorov
0ad31e0ffe Merge pull request #137 from 15lyfromsaturn/master
png rendering example
2016-12-01 10:08:48 +11:00
Svetlana Linuxenko
777becd99e
png rendering example 2016-11-30 18:37:13 +02:00
Andrey Sidorov
77a94b1324 Merge pull request #136 from 15lyfromsaturn/master
double import of templates
2016-11-24 13:57:23 +11:00
Svetlana Linuxenko
9b6492b34a
double import of templates 2016-11-23 20:03:56 +02:00
Andrey Sidorov
562ed74562 Merge pull request #135 from 15lyfromsaturn/master
GCFunction shortcuts
2016-11-19 10:48:47 +11:00
Svetlana Linuxenko
9e967b9734
GCFunction shortcuts 2016-11-18 15:05:28 +02:00
Svetlana Linuxenko
6293ab358b duplicated entry 2016-11-18 12:37:24 +01:00
Andrey Sidorov
e3f6438e1a Merge pull request #132 from 15lyfromsaturn/master
screenshot example fix
2016-11-18 00:20:40 +11:00
Svetlana Linuxenko
9ff1b645d1
screenshot example fix 2016-11-17 12:12:20 +02:00
Santiago Gimeno
77d1666c08
2.2.0 2016-10-11 12:40:17 +02:00
Andrey Sidorov
f2a118d034 Merge pull request #130 from santigimeno/improve_randr
randr: add GetOutputInfo request
2016-10-11 21:17:13 +11:00
Andrey Sidorov
7f39c65c93 Merge pull request #131 from santigimeno/fix_killclient_test
test: fix flaky core-KillKlient test
2016-10-11 21:15:02 +11:00
Santiago Gimeno
f0b0bac336
test: fix flaky core-KillKlient test
Wait for the `CreateNotify` before killing the client, otherwise a
`BadValue` error could be raised.
2016-10-11 12:04:09 +02:00
Santiago Gimeno
e09c8b5429
randr: add GetOutputInfo request 2016-10-11 10:19:30 +02:00
Santiago Gimeno
8ed37aaa31 2.1.1 2016-10-06 14:47:27 +02:00
Andrey Sidorov
ba6d6f63a2 Merge pull request #129 from sidorares/cache_extensions
Cache X11 extensions
2016-10-06 23:11:37 +11:00
Santiago Gimeno
4f241ba2b3 Cache X11 extensions 2016-10-06 12:11:59 +02:00
Andrey Sidorov
f040f8bbba 2.1.0 2016-05-25 16:55:12 +10:00
Andrey Sidorov
88370a111e Merge pull request #125 from Arteris/handshake_error
Unpack handshake error
2016-05-19 12:08:39 +10:00
Ian Scott
b9bebe3a11 Unpack handshake error 2016-05-18 18:14:03 -07:00
Andrey Sidorov
60f8b08037 add unused IDs buffer 2016-05-18 20:22:24 +10:00
Andrey Sidorov
1d77f21ec7 Merge pull request #80 from Arteris/master
Handle cases where depths appear multiple times
2016-05-18 09:14:33 +10:00
Ian Scott
bbaf2a8654 Refactor to keep number of parsed depths in a counter 2016-05-17 14:42:42 -07:00
Ian Scott
7ed7e896e1 Handle cases where depths appear multiple times 2016-05-17 14:41:53 -07:00
Andrey Sidorov
44f9982495 Merge pull request #124 from Arteris/auth_fix2
Fix auth for remote hosts and handle different auth families
2016-05-17 19:51:52 +10:00
Ian Scott
1f5e2310a6 Fix remoteFamily on Node v0.10 2016-05-16 09:45:39 -07:00
Ian Scott
a42f043768 Emit error when handshake fails, such as with bad xauth 2016-05-13 18:59:41 -07:00
Ian Scott
c694394b6d Test xauth in Travis tests 2016-05-13 18:59:33 -07:00
Ian Scott
e8883275bf Fix auth for remote hosts and handle different auth families
- Use the remote address to find the auth cookie instead of the local
  hostname
- Read family type as big endian in Xauthority file
- Don't upgrade 127.0.0.1 TCP connections to unix domain socket (libX11
  and xcb don't do this)
- Don't error if no auth cookie is found; continue without auth
2016-03-21 16:00:52 -07:00
Andrey Sidorov
edbe678f84 Merge pull request #123 from Coldewey/master
Reads message_type from ClientMessage.
2016-02-03 03:12:17 -08:00
plehmkuhl
d327261c74 Adjusted testcase "client-message.js" to match other tests. 2016-02-03 11:42:32 +01:00
plehmkuhl
4fd0385911 Fixed datatype returned by message_type on ClientMessage event.
Added Testcase.
2016-02-03 11:08:58 +01:00
plehmkuhl
27c70c7315 Reads nessage_type from ClientMessage.
See: https://tronche.com/gui/x/xlib/events/client-communication/client-message.html
2016-02-02 16:26:41 +01:00
Andrey Sidorov
f21cdb187b Merge pull request #122 from Arteris/auth_fix
Xauth fixes
2016-01-28 16:58:18 -08:00
Ian Scott
86f977f9bd Handle nonexistent Xauthority file 2016-01-28 16:35:04 -08:00
Ian Scott
582bd1a1b2 Use os-homedir for older node.js versions 2016-01-28 14:51:16 -08:00
Ian Scott
e90c1fd239 Find cookie with same logic as libXau 2016-01-28 14:50:24 -08:00
vird
7e8e972b24 Array proto crash fix
fixed crash when Array has some proto modifications; minor spaces fix
2015-11-29 19:11:19 +02:00
44 changed files with 1961 additions and 935 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
*.log
yarn.lock
package-lock.json
node_modules

View file

@ -1,14 +1,16 @@
before_script: before_script:
- "export DISPLAY=:99.0" - "export XAUTHORITY=/tmp/.Xauthority-Xvfb"
- "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -nolisten $NOLISTEN" - "xauth add :99 . $(mcookie)"
- "xauth add 127.0.0.2:99 . $(mcookie)"
- "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -nolisten $NOLISTEN -auth $XAUTHORITY"
- "sleep 1"
env: env:
- NOLISTEN=tcp - NOLISTEN=tcp DISPLAY=:99.0
- NOLISTEN=unix # - NOLISTEN=unix DISPLAY=:99.0
# - NOLISTEN=unix DISPLAY=127.0.0.2:99.0
language: node_js language: node_js
node_js: node_js:
- '0.10' - '12'
- '0.12' - '14'
- '4.2'
- '5.0'

144
README.md
View file

@ -1,48 +1,60 @@
# About # node-x11
[![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/sidorares/node-x11?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
X11 protocol client for node.js
Implements core X11 protocol, as well as Xrender, Damage, Composite, Big-Requests, Dpms, Screensaver, XFixes, Shape, XTest, XC-Misc, GLX and Apple-WM extensions. X11 protocol client for Node.js: implements the core X11 protocol, as well as Xrender, Damage, Composite, Big-Requests, Dpms, Screensaver, XFixes, Shape, XTest, XC-Misc, GLX, and Apple-WM extensions.
# install
`npm install x11`
Windows users:
1) install [XMing](http://www.straightrunning.com/XmingNotes/) or [Cygwin/X](http://x.cygwin.com/)
2) get node-x11 copy (using [git](http://code.google.com/p/msysgit/downloads/list?can=3) or from [Github](https://github.com/sidorares/node-x11/archives/master ))
#CI build status:
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/sidorares/node-x11?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build Status](https://secure.travis-ci.org/sidorares/node-x11.png)](http://travis-ci.org/sidorares/node-x11) [![Build Status](https://secure.travis-ci.org/sidorares/node-x11.png)](http://travis-ci.org/sidorares/node-x11)
# example ## Install
npm install x11
Windows users:
1. install [XMing](http://www.straightrunning.com/XmingNotes/) or [Cygwin/X](http://x.cygwin.com/)
2. get node-x11 copy (using [git](http://code.google.com/p/msysgit/downloads/list?can=3) or from [Github](https://github.com/sidorares/node-x11/archives/master))
## Example
Core requests usage: Core requests usage:
```js ```js
var x11 = require('x11'); var x11 = require('x11');
var Exposure = x11.eventMask.Exposure; var Exposure = x11.eventMask.Exposure;
var PointerMotion = x11.eventMask.PointerMotion; var PointerMotion = x11.eventMask.PointerMotion;
x11.createClient(function(err, display) { x11.createClient(function(err, display) {
if (!err) { if (!err) {
var X = display.client; var X = display.client;
var root = display.screen[0].root; var root = display.screen[0].root;
var wid = X.AllocID(); var wid = X.AllocID();
X.CreateWindow( X.CreateWindow(
wid, root, // new window id, parent wid,
0, 0, 100, 100, // x, y, w, h root, // new window id, parent
0, 0, 0, 0, // border, depth, class, visual 0,
{ eventMask: Exposure|PointerMotion } // other parameters 0,
500,
500, // x, y, w, h
0,
0,
0,
0, // border, depth, class, visual
{ eventMask: Exposure | PointerMotion } // other parameters
); );
X.MapWindow(wid); X.MapWindow(wid);
var gc = X.AllocID(); var gc = X.AllocID();
X.CreateGC(gc, wid); X.CreateGC(gc, wid);
var white = display.screen[0].white_pixel;
var black = display.screen[0].black_pixel;
cidBlack = X.AllocID();
cidWhite = X.AllocID();
X.CreateGC(cidBlack, wid, { foreground: black, background: white });
X.CreateGC(cidWhite, wid, { foreground: white, background: black });
X.on('event', function(ev) { X.on('event', function(ev) {
if (ev.type == 12) if (ev.type == 12) {
{ X.PolyFillRectangle(wid, cidWhite, [0, 0, 500, 500]);
X.PolyText8(wid, gc, 50, 50, ['Hello, Node.JS!']); X.PolyText8(wid, cidBlack, 50, 50, ['Hello, Node.JS!']);
} }
}); });
X.on('error', function(e) { X.on('error', function(e) {
@ -51,55 +63,57 @@ Core requests usage:
} else { } else {
console.log(err); console.log(err);
} }
}); });
``` ```
# Screenshots ## Screenshots
![tetris game](https://lh6.googleusercontent.com/-RCRY9A7WwnA/Tlww0FHP7NI/AAAAAAAAAwo/nxfSxsw6xow/s400/tetris.png) ![tetris game](https://lh6.googleusercontent.com/-RCRY9A7WwnA/Tlww0FHP7NI/AAAAAAAAAwo/nxfSxsw6xow/s400/tetris.png)
![XRENDER gradients](https://lh4.googleusercontent.com/-VS0BMYYmq6M/Tlww0Y1ij0I/AAAAAAAAAws/pVWsPZ63Yeo/s400/render-gradients.png) ![XRENDER gradients](https://lh4.googleusercontent.com/-VS0BMYYmq6M/Tlww0Y1ij0I/AAAAAAAAAws/pVWsPZ63Yeo/s400/render-gradients.png)
![OpenGL glxgears](http://img-fotki.yandex.ru/get/4123/37511094.30/0_81712_6c2ebb11_L) ![OpenGL glxgears](http://img-fotki.yandex.ru/get/4123/37511094.30/0_81712_6c2ebb11_L)
![OpenGL teapot](http://img-fotki.yandex.ru/get/4132/37511094.30/0_81713_82a5ac48_L) ![OpenGL teapot](http://img-fotki.yandex.ru/get/4132/37511094.30/0_81713_82a5ac48_L)
# In use ## In use
- [ntk](https://github.com/sidorares/ntk) - higher level toolkit on top of X11
- [node-remote](https://github.com/AndrewSwerlick/node-remote) - media center controller
- [tiles](https://github.com/dominictarr/tiles) - tiling window manager
- [vnc](https://github.com/sidorares/node-vnc) - vnc client.
- [node-ewmh](https://github.com/santigimeno/node-ewmh) - set of EWMH helpers.
- [OdieWM](https://github.com/bu/OdieWM) - window manager
- [Dbusmenu](https://github.com/sidorares/node-dbusmenu) - unity global menu client.
- [AirWM](https://github.com/AirWM/AirWM) - tiling window manager
- [npdf](https://github.com/sidorares/npdf) - pdf viewer
- [tinywm](https://github.com/Airblader/node-tinywm) The famous [TinyWM](https://github.com/mackstann/tinywm) written in node.js
- [basedwm](https://github.com/anko/basedwm) Infinite-desktop panning X window manager in LiveScript
# X11 resources/documentation: - [ntk](https://github.com/sidorares/ntk) - higher level toolkit on top of X11
- [node-remote](https://github.com/AndrewSwerlick/node-remote) - media center controller
- [tiles](https://github.com/dominictarr/tiles) - tiling window manager
- [vnc](https://github.com/sidorares/node-vnc) - vnc client.
- [node-ewmh](https://github.com/santigimeno/node-ewmh) - set of EWMH helpers.
- [OdieWM](https://github.com/bu/OdieWM) - window manager
- [Dbusmenu](https://github.com/sidorares/node-dbusmenu) - unity global menu client.
- [AirWM](https://github.com/AirWM/AirWM) - tiling window manager
- [npdf](https://github.com/sidorares/npdf) - pdf viewer
- [tinywm](https://github.com/Airblader/node-tinywm) The famous [TinyWM](https://github.com/mackstann/tinywm) written in node.js
- [basedwm](https://github.com/anko/basedwm) Infinite-desktop panning X window manager in LiveScript
- [Xplain](https://github.com/magcius/xplain) - A series of articles to help explain the X Window System http://magcius.github.io/xplain/article/ ## X11 resources/documentation:
- [Official X11 docs](http://www.x.org/releases/X11R7.6/doc/)
- [protocol specification](http://www.x.org/releases/X11R7.6/doc/xproto/x11protocol.pdf)
- C Xlib to X11 request mapping table http://tronche.com/gui/x/xlib/appendix/a.html
- [How to write composite manager](http://www.talisman.org/~erlkonig/misc/x11-composite-tutorial/)
- [Extended Window Manager Hints specification](http://standards.freedesktop.org/wm-spec/wm-spec-1.3.html)
# Other implementations - [Xplain](https://github.com/magcius/xplain) - A series of articles to help explain the X Window System http://magcius.github.io/xplain/article/
- [Official X11 docs](http://www.x.org/releases/X11R7.6/doc/)
- [protocol specification](http://www.x.org/releases/X11R7.6/doc/xproto/x11protocol.pdf)
- C Xlib to X11 request mapping table http://tronche.com/gui/x/xlib/appendix/a.html
- [How to write composite manager](http://www.talisman.org/~erlkonig/misc/x11-composite-tutorial/)
- [Extended Window Manager Hints specification](http://standards.freedesktop.org/wm-spec/wm-spec-1.3.html)
- C: XLib - http://www.sbin.org/doc/Xlib/ http://www.tronche.com/gui/x/xlib/ http://www.x.org/docs/X11/xlib.pdf ## Other implementations
- 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 )
- https://github.com/alexer/python-xlib-render
- Python/twisted: https://launchpad.net/twisted-x11
- Perl: http://search.cpan.org/~smccam/X11-Protocol-0.56/Protocol.pm
- Go: https://github.com/BurntSushi/xgb
- Java: https://github.com/xderoche/J11
- Ruby: https://github.com/dj2/x-ruby-bindings
- Clojure: https://github.com/noodlewiz/xcljb
- Guile: https://github.com/mwitmer/guile-xcb
# Server side (protocol + functionality) implementations for js + DOM - 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 )
- https://github.com/alexer/python-xlib-render
- Python/twisted: https://launchpad.net/twisted-x11
- Perl: http://search.cpan.org/~smccam/X11-Protocol-0.56/Protocol.pm
- Go: https://github.com/BurntSushi/xgb
- Java: https://github.com/xderoche/J11
- Ruby: https://github.com/dj2/x-ruby-bindings
- Clojure: https://github.com/noodlewiz/xcljb
- Guile: https://github.com/mwitmer/guile-xcb
- Emacs lisp: https://github.com/ch11ng/xelb ( autogenerated from XCB XML )
## Server side (protocol + functionality) implementations for js + DOM
would be really great to make completely web based playground page, connecting node-x11 api to DOM based implementation would be really great to make completely web based playground page, connecting node-x11 api to DOM based implementation
- https://github.com/GothAck/javascript-x-server - https://github.com/GothAck/javascript-x-server
- https://github.com/ttaubert/x-server-js - https://github.com/ttaubert/x-server-js

View file

@ -252,7 +252,7 @@ function genReq(req, last)
if (req.body.length == 0) if (req.body.length == 0)
{ {
result.push(' function() {'); result.push(' function() {');
result.push(' return new Buffer([' + req.opcode + ', 0, 1, 0]);'); result.push(' return Buffer.from([' + req.opcode + ', 0, 1, 0]);');
} else { } else {
result.push(' function (args) {'); result.push(' function (args) {');
result.push(' var extraLength = 0;'); result.push(' var extraLength = 0;');
@ -287,10 +287,10 @@ function genReq(req, last)
var reqLen4 = ((reqLen + 3) >> 2); var reqLen4 = ((reqLen + 3) >> 2);
if (extraLength) if (extraLength)
result.push(' var data = new Buffer(' + reqLen + ' + extraLength);'); result.push(' var data = Buffer.alloc(' + reqLen + ' + extraLength);');
else { else {
result.pop(); result.pop();
result.push(' var data = new Buffer(' + reqLen + ');'); result.push(' var data = Buffer.alloc(' + reqLen + ');');
} }
result.push(' data[0] = ' + req.opcode + ';'); result.push(' data[0] = ' + req.opcode + ';');
if (req.body.length != 0) { if (req.body.length != 0) {

View file

@ -571,7 +571,7 @@ module.exports.readJpeg = function(path)
var imageData = {}; var imageData = {};
imageData.width = j.width; imageData.width = j.width;
imageData.height = j.height; imageData.height = j.height;
imageData.data = new Buffer(j.width*j.height*4); imageData.data = Buffer.from(j.width*j.height*4);
j.copyToImageData(imageData); j.copyToImageData(imageData);
return imageData; return imageData;
} }

View file

@ -874,7 +874,7 @@ module.exports.readPng = function(path)
var imageData = {}; var imageData = {};
imageData.width = j.width; imageData.width = j.width;
imageData.height = j.height; imageData.height = j.height;
imageData.data = new Buffer(j.width*j.height*4); imageData.data = Buffer.alloc(j.width*j.height*4);
j.render(imageData); j.render(imageData);
return imageData; return imageData;
} }

344
examples/png/png-decoder.js Normal file
View file

@ -0,0 +1,344 @@
/*
* Simple png decoder
* https://github.com/b37t1td/png-decoder
*/
var CRCTable = new Int32Array([
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
]);
var crc32 = function(buf) {
var crc = -1;
for (var i = 0; i < buf.length; i++) {
crc = CRCTable[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8);
}
return crc ^ -1;
};
/*
* BE byteArray implementation
* by Svetlana Linuxenko <linuxenko@yahoo.com>
*/
/* eslint no-undef: 0 */
var byteArray = Uint8Array;
var cmp = function(a, b) {
if (!b) b = a; a = this;
return a.filter(function(c,i) { return c === b[i]; }).length === a.length;
};
var toInt = function(a) {
if (!a) a = this.slice(this.off, 4);
return (a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3];
//return a[0] | (a[1] << 8) | (a[2] << 16) | (a[3] << 24);
};
var toBytes = function(int) {
return new byteArray([
(int >> 24) & 0xff,
(int >> 16) & 0xff,
(int >> 8) & 0xff,
int & 0xff
]);
};
var nextInt = function() {
return this.toInt(this.slice(this.off, (this.off += 4)));
};
var nextIntBytes = function() {
return this.nextBytes(4);
};
var nextBytes = function(size) {
return this.slice(this.off, (this.off += size));
};
var nextByte = function() {
return this.nextBytes(1)[0];
};
var insertInt = function(int) {
this.insertBytes(this.toBytes(int));
};
var insertBytes = function(bytes, length) {
length = length || 4;
this.set(bytes, this.off, length);
this.off += length;
};
var insertByte = function(byte) {
this.set([byte], this.off, (this.off += 1));
};
byteArray.prototype.cmp = cmp;
byteArray.prototype.toInt = toInt;
byteArray.prototype.nextInt = nextInt;
byteArray.prototype.nextIntBytes = nextIntBytes;
byteArray.prototype.toBytes = toBytes;
byteArray.prototype.insertInt = insertInt;
byteArray.prototype.insertBytes = insertBytes;
byteArray.prototype.nextBytes = nextBytes;
byteArray.prototype.nextByte = nextByte;
byteArray.prototype.insertByte = insertByte;
Object.defineProperty(byteArray.prototype , 'off', {
enumerable: false,
configurable: false,
writable: true,
value : 0
});
var SIGNATURE = new byteArray([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
var IHDR = new byteArray([0x49, 0x48, 0x44, 0x52]);
var IDAT = new byteArray([0x49, 0x44, 0x41, 0x54]);
var IEND = new byteArray([0x49, 0x45, 0x4e, 0x44]);
/*
* Decoder
*/
var zlib = require('zlib');
var inflateFunction = function(data) {
return zlib.inflateSync(Buffer.from(data));
};
var Decoder = function() { };
Decoder.prototype.parse = function(data) {
if (!(data instanceof byteArray)) {
data = new byteArray(data);
}
if (!SIGNATURE.cmp(data.nextBytes(SIGNATURE.length))) {
throw new Error('Not png');
}
while (data.off < data.length) {
var len = data.nextInt();
var hdr = data.nextBytes(len + 4);
if (crc32(hdr) !== data.nextInt()) {
throw new Error('Crc error');
}
if (IHDR.cmp(hdr)) {
this._IHDR = this._chunkIHDR(hdr.slice(4, len + 4));
if (this._IHDR.palette !== 8) {
throw new Error('Depth error');
}
if (this._IHDR.compression !== 0) {
throw new Error('Compression error');
}
if (this._IHDR.filter !== 0) {
throw new Error('Filter error');
}
if (this._IHDR.interlace !== 0) {
throw new Error('Interlace error');
}
switch (this._IHDR.colorType){
case 0: this.bpp = 1; break;
case 2: this.bpp = 3; break;
case 3: this.bpp = 1; break;
case 4: this.bpp = 2; break;
case 6: this.bpp = 4; break;
default: throw new Error('ColorType error');
}
this.chunks = [];
}
if (IDAT.cmp(hdr)) {
if (!this._IHDR) {
throw new Error('IHDR error');
}
this._chunkIDAT(hdr.slice(4, len + 4));
}
if (IEND.cmp(hdr)) {
return this._chunkIEND();
}
}
throw new Error('Data error');
};
Decoder.prototype._chunkIEND = function() {
var tmp = [];
for (var i = 0; i < this.chunks.length; i++) {
for (var j = 0; j < this.chunks[i].length; j++) {
tmp.push(this.chunks[i][j]);
}
}
return this.filter(inflateFunction(tmp));
};
Decoder.prototype._chunkIDAT = function(chunk) {
this.chunks.push(chunk);
};
Decoder.prototype._chunkIHDR = function(chunk) {
return {
width : chunk.nextInt(),
height : chunk.nextInt(),
palette : chunk.nextByte(),
colorType : chunk.nextByte(),
compression : chunk.nextByte(),
filter : chunk.nextByte(),
interlace : chunk.nextByte()
};
};
Decoder.prototype.filter = function(data) {
var bpp = this.bpp;
var width = this._IHDR.width, height = this._IHDR.height;
var pixels = new byteArray((width * height) * bpp);
var filter, line, left, leftup, up, pixel;
var lineWidth = width * bpp, byte, off;
for (var y = 0; y < height; y++) {
filter = data.nextByte();
line = data.nextBytes(lineWidth);
for (var x = 0; x < lineWidth; x++) {
if (filter !== 0) {
off = (y * lineWidth) + x;
}
byte = line.nextByte();
switch(filter) {
case 0: //None
pixel = byte;
break;
case 1: // Sub Raw(x) + Raw(x - bpp)
if (x < bpp) {
pixel = byte;
break;
}
pixel = pixels[off - bpp] + byte & 0xff;
break;
case 2: // Up(x) = Raw(x) + Prior(x)
if (y === 0) {
pixel = byte;
break;
}
pixel = pixels[off - lineWidth] + byte & 0xff;
break;
case 3: // Average(x) = Raw(x) + floor((Raw(x-bpp)+Prior(x))/2)
if (y === 0) {
if (x < bpp) {
pixel = byte;
} else {
pixel = (byte + (pixels[off - bpp] >> 1)) & 0xff;
}
break;
}
if (x < bpp) {
pixel = (byte + (pixels[off - lineWidth] >> 1)) & 0xff;
break;
}
pixel = (byte + (pixels[off - bpp] + pixels[off - lineWidth] >> 1)) & 0xff;
break;
case 4: // Paeth
if (y === 0) {
if (x < bpp) {
pixel = byte;
} else {
pixel = (byte + (pixels[off - bpp])) & 0xff;
}
break;
}
if (x < bpp) {
pixel = (byte + (pixels[off - lineWidth])) & 0xff;
break;
}
up = pixels[off - lineWidth];
left = pixels[off - bpp];
leftup = pixels[(off - lineWidth) - bpp];
var p = left + up - leftup,
pleft = Math.abs(p - left),
pup = Math.abs(p - up),
pleftup = Math.abs(p - leftup);
if (pleft <= pup && pleft <= pleftup){
pixel = byte + left & 0xff;
break;
} else if (pup <= pleftup) {
pixel = byte + up & 0xff;
break;
}
pixel = byte + leftup & 0xff;
break;
default:
throw new Error('Filter error: ' + filter);
}
pixels.insertByte(pixel);
}
}
return pixels;
};
module.exports = Decoder;

BIN
examples/png/screen.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

80
examples/png/test1.js Normal file
View file

@ -0,0 +1,80 @@
//var logo = require('./node-png').readPng('./node-logo.png');
var fs = require('fs');
var Decoder = require('./png-decoder');
var decoder = new Decoder();
var logo = {
data : Buffer.from(decoder.parse(fs.readFileSync('./screen.png'))),
width : decoder._IHDR.width,
height : decoder._IHDR.height
};
var x11 = require('../../lib');
var Exposure = x11.eventMask.Exposure;
x11.createClient(function(err, display)
{
var X = display.client;
X.require('render', function(err, Render) {
var root = display.screen[0].root;
main(root, X, Render, display);
});
});
function main(root, X, Render, display) {
var win, picWin, pic, gc;
win = X.AllocID();
X.CreateWindow(
win, root,
0, 0, logo.width, logo.height,
0, 0, 0, 0,
{ eventMask: Exposure }
);
X.MapWindow(win);
gc = X.AllocID();
X.CreateGC(gc, win);
var logoPixmap = X.AllocID();
X.CreatePixmap(logoPixmap, win, 24, logo.width, logo.height);
var rscreen = display.screen[0];
var screen =
rscreen.depths[rscreen.root_depth][
Object.keys(rscreen.depths[rscreen.root_depth])[0]];
var rmask = parseInt(screen.red_mask, 10);
var gmask = parseInt(screen.green_mask, 10);
var bmask = parseInt(screen.blue_mask, 10);
for (var y = 0; y < logo.height; y++) {
for (var x = 0; x < logo.width; x++) {
var pixel = Buffer.from([
logo.data[(x + logo.width * y) * 4],
logo.data[(x + logo.width * y) * 4 + 1],
logo.data[(x + logo.width * y) * 4 + 2], 0]).readInt32LE();
logo.data[(x + logo.width * y) * 4 ] = (pixel & rmask) >> 16;
logo.data[(x + logo.width * y) * 4 + 1] = (pixel & gmask) >> 8;
logo.data[(x + logo.width * y) * 4 + 2] = (pixel & bmask) >> 0;
logo.data[(x + logo.width * y) * 4 + 3] = 0x00;
}
}
X.PutImage(2, logoPixmap, gc, logo.width, logo.height, 0, 0, 0, 24, logo.data);
var logoPicture = X.AllocID();
Render.CreatePicture(logoPicture, logoPixmap, Render.rgb24);
var winPicture = X.AllocID();
Render.CreatePicture(winPicture, win, Render.rgb24);
X.on('event', function(ev) {
if (ev.name == 'Expose') {
Render.Composite(3, logoPicture, 0, winPicture, 0, 0, 0, 0, 0, 0, logo.width, logo.height);
}
});
}

8
examples/screenshot.js Executable file → Normal file
View file

@ -17,7 +17,7 @@ x11.createClient(function(err, display) {
var dispwin = X.AllocID(); var dispwin = X.AllocID();
X.CreateWindow(dispwin, root, 0, 0, width, height, 1, 1, 0, { eventMask: x11.eventMask.Exposure }); X.CreateWindow(dispwin, root, 0, 0, width, height, 0, 0, 0, 0, { eventMask: x11.eventMask.Exposure });
X.MapWindow(dispwin); X.MapWindow(dispwin);
//X.CopyArea(idScreenshot, dispwin, gc, 0, 0, 0, 0, width, height); //X.CopyArea(idScreenshot, dispwin, gc, 0, 0, 0, 0, width, height);
@ -71,7 +71,11 @@ x11.createClient(function(err, display) {
}); });
*/ */
X.GetImage(2, root, 0, 0, width, height, 0xffffffff, function(image) { X.GetImage(2, id, 0, 0, width, height, 0xffffffff, function(err, image) {
if (err) {
console.log(err);
process.exit(1);
}
console.log(image); console.log(image);
// format, drawable, gc, width, height, dstX, dstY, leftPad, depth, data // format, drawable, gc, width, height, dstX, dstY, leftPad, depth, data
X.PutImage(2, dispwin, gc, width, height, 0, 0, 0, 24, image.data); X.PutImage(2, dispwin, gc, width, height, 0, 0, 0, 24, image.data);

View file

@ -0,0 +1,36 @@
/*
* GCFunction usage example
*/
var x11 = require('../../lib');
x11.createClient(function(err, display) {
var X = display.client;
var root = display.screen[0].root;
var white = display.screen[0].white_pixel;
var black = display.screen[0].black_pixel;
var wid = X.AllocID();
X.CreateWindow(wid, root, 0, 0, 400, 300, 0, 0, 0, 0, {
backgroundPixel: black,
eventMask: x11.eventMask.ButtonPress|x11.eventMask.Exposure });
var gc = X.AllocID();
X.CreateGC(gc, wid, {foreground : white, 'function' : x11.gcFunction.GXinvert});
X.MapWindow(wid);
X.on('event', function(ev) {
if (ev.type === 12) {
X.PolyFillRectangle(wid, gc, [0, 0, 400, 300]);
}
if (ev.type === 4) {
var x = ev.x;
var y = ev.y;
X.PolyFillRectangle(wid, gc, [x - 25, y - 25, 50, 50]);
}
});
});

View file

@ -7,7 +7,7 @@ var xclient = x11.createClient(function(err, display) {
display.client.require('render', function(err, Render) { display.client.require('render', function(err, Render) {
var wid = X.AllocID(); var wid = X.AllocID();
var white = display.screen[0].white_pixel; var white = display.screen[0].white_pixel;
varblack = display.screen[0].black_pixel; var black = display.screen[0].black_pixel;
X.CreateWindow(wid, root, 10, 10, 400, 300, 0, 0, 0, 0, { backgroundPixel: white, eventMask: PointerMotion }); X.CreateWindow(wid, root, 10, 10, 400, 300, 0, 0, 0, 0, { backgroundPixel: white, eventMask: PointerMotion });
X.MapWindow(wid); X.MapWindow(wid);

View file

@ -26,7 +26,7 @@ function padWidth(buf, width) {
return buf; return buf;
else { else {
var stride = (width+3)&~3; var stride = (width+3)&~3;
var res = new Buffer(height*stride); var res = Buffer.alloc(height*stride);
res.fill(0); res.fill(0);
for (var y=0; y < height; ++y) { for (var y=0; y < height; ++y) {
// memcpy(tmpbitmap+y*stride, bitmap->buffer+y*ginfo.width, ginfo.width); // memcpy(tmpbitmap+y*stride, bitmap->buffer+y*ginfo.width, ginfo.width);
@ -88,7 +88,7 @@ var xclient = x11.createClient({ debug: true }, function(err, display) {
var glyphFromCode = []; var glyphFromCode = [];
glyphs.forEach(function(g) { glyphs.forEach(function(g) {
if (!g.image || (g.image.length == 0)) { if (!g.image || (g.image.length == 0)) {
g.image = new Buffer(64); g.image = Buffer.alloc(64);
g.image.fill(0); g.image.fill(0);
g.width = 8; g.width = 8;
g.height = 8; g.height = 8;

View file

@ -6,7 +6,7 @@ var Pixmap = require('./pixmap').Pixmap;
var Buffer = require('buffer').Buffer; var Buffer = require('buffer').Buffer;
require('../../lib/unpackbuffer').addUnpack(Buffer); require('../../lib/unpackbuffer').addUnpack(Buffer);
var reversed = new Buffer(256); var reversed = Buffer.alloc(256);
for (var i=0; i < 256; ++i) for (var i=0; i < 256; ++i)
{ {
var res = 0; var res = 0;

View file

@ -8,7 +8,7 @@ var xclient = x11.createClient();
var Exposure = x11.eventMask.Exposure; var Exposure = x11.eventMask.Exposure;
var PointerMotion = x11.eventMask.PointerMotion; var PointerMotion = x11.eventMask.PointerMotion;
var bitmap = new Buffer(128*128/8); // 16384 bits, 2048 bytes bitmap var bitmap = Buffer.alloc(128*128/8); // 16384 bits, 2048 bytes bitmap
for (var i=0; i < bitmap.length; ++i) for (var i=0; i < bitmap.length; ++i)
{ {
bitmap[i] = i % 256; bitmap[i] = i % 256;

View file

@ -4,7 +4,7 @@ var x11 = require('../../lib');
var Exposure = x11.eventMask.Exposure; var Exposure = x11.eventMask.Exposure;
var PointerMotion = x11.eventMask.PointerMotion; var PointerMotion = x11.eventMask.PointerMotion;
var bitmap = new Buffer(128*128*4); // 16384 bits, 2048 bytes bitmap var bitmap = Buffer.alloc(128*128*4); // 16384 bits, 2048 bytes bitmap
for (var i=0; i < bitmap.length; ++i) for (var i=0; i < bitmap.length; ++i)
{ {
var byteNum = i%4; var byteNum = i%4;

View file

@ -25,7 +25,7 @@ var Buffer = require('buffer').Buffer;
var startpos = [4, 15]; var startpos = [4, 15];
var cupsize = [10, 20]; var cupsize = [10, 20];
var cup = new Buffer(cupsize[0]*cupsize[1]); var cup = Buffer.alloc(cupsize[0]*cupsize[1]);
var moveInterval; var moveInterval;
function clearCup() function clearCup()

View file

@ -56,8 +56,8 @@ var pc2 = [
function deskey(key, edf) function deskey(key, edf)
{ {
var i, j, l, m, n; var i, j, l, m, n;
var pc1m = new Buffer(56); var pc1m = Buffer.alloc(56);
var pcr = new Buffer(56); var pcr = Buffer.alloc(56);
var kn = new Array(32); var kn = new Array(32);
for ( j = 0; j < 56; j++ ) { for ( j = 0; j < 56; j++ ) {
@ -388,17 +388,17 @@ function desfunc(block, keys)
module.exports.response = function(challenge, password) module.exports.response = function(challenge, password)
{ {
var key = new Buffer(8); var key = Buffer.alloc(8);
key.fill(0); key.fill(0);
key.write(password.substring(0,8)); key.write(password.substring(0,8));
var in1 = challenge.slice(0,8); var in1 = challenge.slice(0,8);
var in2 = challenge.slice(8,16); var in2 = challenge.slice(8,16);
var res1 = new Buffer(8); var res1 = Buffer.alloc(8);
var res2 = new Buffer(8); var res2 = Buffer.alloc(8);
deskey(key, EN0); deskey(key, EN0);
des(in1, res1); des(in1, res1);
des(in2, res2); des(in2, res2);
var resp = new Buffer(16); var resp = Buffer.alloc(16);
res1.copy(resp); res1.copy(resp);
res2.copy(resp, 8); res2.copy(resp, 8);
return resp; return resp;

View file

@ -7,7 +7,7 @@
// It should create a pleasant looking hex dumb by default: // It should create a pleasant looking hex dumb by default:
// //
// var hexy = require('hexy.js'), // var hexy = require('hexy.js'),
// b = new Buffer("\000\001\003\005\037\012\011bcdefghijklmnopqrstuvwxyz0123456789") // b = Buffer.from("\000\001\003\005\037\012\011bcdefghijklmnopqrstuvwxyz0123456789")
// //
// console.log(hexy.hexy(b)) // console.log(hexy.hexy(b))
// //

View file

@ -400,7 +400,7 @@ RfbClient.prototype.readHextileTile = function(rect, cb)
}); });
return; return;
} }
tile.buffer = new Buffer(tilebuflen); tile.buffer = Buffer.alloc(tilebuflen);
function solidBackground() { function solidBackground() {
clog('solidBackground'); clog('solidBackground');
@ -667,8 +667,8 @@ function createConnection(params)
var wstream = fs.createWriteStream(params.rfbFileOut); var wstream = fs.createWriteStream(params.rfbFileOut);
wstream.write('FBS 001.001\n'); wstream.write('FBS 001.001\n');
stream.on('data', function(data) { stream.on('data', function(data) {
var sizeBuf = new Buffer(4); var sizeBuf = Buffer.alloc(4);
var timeBuf = new Buffer(4); var timeBuf = Buffer.alloc(4);
var size = data.length; var size = data.length;
sizeBuf.writeInt32BE(size, 0); sizeBuf.writeInt32BE(size, 0);
wstream.write(sizeBuf); wstream.write(sizeBuf);
@ -676,7 +676,7 @@ function createConnection(params)
timeBuf.writeInt32BE(+new Date() - start, 0); timeBuf.writeInt32BE(+new Date() - start, 0);
wstream.write(timeBuf); wstream.write(timeBuf);
var padding = 3 - ((size - 1) & 0x03); var padding = 3 - ((size - 1) & 0x03);
var pbuf = new Buffer(padding); var pbuf = Buffer.alloc(padding);
wstream.write(pbuf); wstream.write(pbuf);
}).on('end', function() { }).on('end', function() {
wstream.end(); wstream.end();

View file

@ -62,7 +62,7 @@ RfbServer.prototype.processSecurity = function()
break; break;
case rfb.security.VNC: case rfb.security.VNC:
// generate random 16 byte challenge // generate random 16 byte challenge
serv.challenge = new Buffer(16); serv.challenge = Buffer.alloc(16);
serv.challenge.write('1234567890abcdef'); serv.challenge.write('1234567890abcdef');
console.log(['sending challenge', serv.challenge]); console.log(['sending challenge', serv.challenge]);
serv.pack_stream.pack('a', [serv.challenge]).flush(); serv.pack_stream.pack('a', [serv.challenge]).flush();

View file

@ -34,7 +34,7 @@ function ReadFixedRequest(length, callback)
this.length = length; this.length = length;
this.callback = callback; this.callback = callback;
//clog(length); //clog(length);
this.data = new Buffer(length); this.data = Buffer.alloc(length);
this.received_bytes = 0; this.received_bytes = 0;
} }
@ -328,7 +328,7 @@ UnpackStream.prototype.pack = function(format, args)
} }
} }
var buf = new Buffer(packetlength); var buf = Buffer.alloc(packetlength);
var offset = 0; var offset = 0;
var arg = 0; var arg = 0;
for (var i = 0; i < format.length; ++i) for (var i = 0; i < format.length; ++i)

View file

@ -95,7 +95,7 @@ PixmapFromFile.prototype.mapColors = function(content,size){
} }
PixmapFromFile.prototype.toBuffer = function (colors,content,size) { PixmapFromFile.prototype.toBuffer = function (colors,content,size) {
var buf = new Buffer(size.width*size.height*4); var buf = Buffer.alloc(size.width*size.height*4);
var offset = 0, byte,color; var offset = 0, byte,color;
var copy; var copy;
if( !this.options.format || this.options.format.toUpperCase() === "BGRA"){ if( !this.options.format || this.options.format.toUpperCase() === "BGRA"){

View file

@ -1,10 +1,24 @@
// TODO: http://en.wikipedia.org/wiki/X_Window_authorization // TODO: differentiate between auth types (i.e., MIT-MAGIC-COOKIE-1 and XDM-AUTHORIZATION-1)
// and choose the best based on the algorithm in libXau's XauGetBestAuthByAddr
var fs = require('fs'); var fs = require('fs');
var Buffer = require('buffer').Buffer; var Buffer = require('buffer').Buffer;
// add 'unpack' method for buffer // add 'unpack' method for buffer
require('./unpackbuffer').addUnpack(Buffer); require('./unpackbuffer').addUnpack(Buffer);
var typeToName = {
256: 'Local',
65535: 'Wild',
254: 'Netname',
253: 'Krb5Principal',
252: 'LocalHost',
0: 'Internet',
1: 'DECnet',
2: 'Chaos',
5: 'ServerInterpreted',
6: 'Internet6'
};
function parseXauth( buf ) function parseXauth( buf )
{ {
var offset = 0; var offset = 0;
@ -14,20 +28,7 @@ function parseXauth( buf )
while (offset < buf.length) while (offset < buf.length)
{ {
var cookie = {}; var cookie = {};
var typeToName = { cookie.type = buf.readUInt16BE(offset);
256: 'Local',
65535: 'Wild',
254: 'Netname',
253: 'Krb5Principal',
252: 'LocalHost',
0: 'Internet',
1: 'DECnet',
2: 'Chaos',
5: 'ServerInterpreted',
6: 'InternetV6'
};
cookie.type = buf.readUInt16LE(offset);
console.log('Cookie type: ');
if (!typeToName[cookie.type]) { if (!typeToName[cookie.type]) {
console.warn('Unknown address type'); console.warn('Unknown address type');
} }
@ -49,36 +50,61 @@ function parseXauth( buf )
return auth; return auth;
} }
var os = require('os'); var homedir = require('os').homedir;
var path = require('path'); var path = require('path');
function readXauthority(cb) { function readXauthority(cb) {
var filename = process.env.XAUTHORITY || path.join(os.homedir(), '.Xauthority'); var filename = process.env.XAUTHORITY || path.join(homedir(), '.Xauthority');
fs.readFile(filename, function(err, data) { fs.readFile(filename, function(err, data) {
if (!err) if (!err)
return cb(null, data); return cb(null, data);
if(err.code == 'ENOENT') { if(err.code == 'ENOENT') {
// Xming/windows uses %HOME%/Xauthority ( .Xauthority with no dot ) - try with this name // Xming/windows uses %HOME%/Xauthority ( .Xauthority with no dot ) - try with this name
filename = process.env.XAUTHORITY || path.join(os.homedir(), 'Xauthority'); filename = process.env.XAUTHORITY || path.join(homedir(), 'Xauthority');
return fs.readFile(filename, cb); fs.readFile(filename, function (err, data) {
if (err.code == 'ENOENT') {
cb(null, null);
} else {
cb(err);
}
});
} else { } else {
cb(err); cb(err);
} }
}); });
} }
module.exports = function( display, host, cb ) module.exports = function( display, host, socketFamily, cb )
{ {
var family;
if (socketFamily === 'IPv4') {
family = 0; // Internet
} else if (socketFamily === 'IPv6') {
family = 6; // Internet6
} else {
family = 256; // Local
}
readXauthority(function(err, data) { readXauthority(function(err, data) {
if(err) return cb(err); if(err) return cb(err);
if (!data) {
return cb(null, {
authName: '',
authData: ''
});
}
var auth = parseXauth(data); var auth = parseXauth(data);
for (var cookieNum in auth) for (var cookieNum in auth)
{ {
var cookie = auth[cookieNum]; var cookie = auth[cookieNum];
if (cookie.display === display && cookie.address === host) if ((typeToName[cookie.family] === 'Wild' || (cookie.type === family && cookie.address === host)) &&
(cookie.display.length === 0 || cookie.display === display))
return cb( null, cookie ); return cb( null, cookie );
} }
cb(new Error('No auth cookie matching display=' + display + ' and host=' + host)); // If no cookie is found, proceed without authentication
cb(null, {
authName: '',
authData: ''
});
}); });
}; };

View file

@ -231,9 +231,10 @@ function packValueMask(reqname, values)
}); });
var args = []; var args = [];
for (m in masksList) for (var i=0,length=masksList.length;i<length;i++)
{ {
var valueName = reqValueMaskName[masksList[m]]; var value = masksList[i];
var valueName = reqValueMaskName[value];
format += reqValueMask[valueName].format format += reqValueMask[valueName].format
args.push( values[valueName] ); args.push( values[valueName] );
} }
@ -464,7 +465,7 @@ var templates = {
function(mode, wid, name, type, units, data) function(mode, wid, name, type, units, data)
{ {
var padded4 = (data.length + 3) >> 2; var padded4 = (data.length + 3) >> 2;
var pad = new Buffer( (padded4<<2) - data.length); var pad = Buffer.alloc( (padded4<<2) - data.length);
var format = 'CCSLLLCxxxLaa'; var format = 'CCSLLLCxxxLaa';
var requestLength = 6 + padded4; var requestLength = 6 + padded4;
var dataLenInFormatUnits = data.length / (units >> 3); var dataLenInFormatUnits = data.length / (units >> 3);
@ -726,12 +727,6 @@ var templates = {
} }
], ],
FreePixmap: [
function(pixmap) {
return [ 'CxSL', [ 54, 2, pixmap ] ];
}
],
FreePixmap: [ FreePixmap: [
function (pixmap) { function (pixmap) {
return [ 'CxSL', [54, 2, pixmap] ]; return [ 'CxSL', [54, 2, pixmap] ];
@ -771,13 +766,9 @@ var templates = {
var vals = packValueMask('CreateGC', values); var vals = packValueMask('CreateGC', values);
var packetLength = 3 + (values ? vals[2].length : 0); var packetLength = 3 + (values ? vals[2].length : 0);
var args = [56, packetLength, cid]; var args = [56, packetLength, cid];
args.push(vals[0]); // values bitmask format += vals[0]
var valArr = vals[1]; args.push(vals[1]); // values bitmask
for (var v in valArr) args = args.concat(vals[2])
{
format += 'L'; // TODO: we know format string length in advance and += inefficient for string
args.push(valArr[v]);
}
return [format, args]; return [format, args];
} }
], ],
@ -860,7 +851,7 @@ var templates = {
var padded = xutil.padded_length(data.length); var padded = xutil.padded_length(data.length);
var reqLen = 6 + padded/4; // (length + 3) >> 2 ??? var reqLen = 6 + padded/4; // (length + 3) >> 2 ???
var padLength = padded - data.length; var padLength = padded - data.length;
var pad = new Buffer(padLength); // TODO: new pack format 'X' - skip amount of bytes supplied in numerical argument var pad = Buffer.alloc(padLength); // TODO: new pack format 'X' - skip amount of bytes supplied in numerical argument
// TODO: move code to calculate reqLength and use BigReq if needed outside of corereq.js // TODO: move code to calculate reqLength and use BigReq if needed outside of corereq.js
// NOTE: big req is used here (first 'L' in format, 0 and +1 in params), won't work if not enabled // NOTE: big req is used here (first 'L' in format, 0 and +1 in params), won't work if not enabled
@ -1030,6 +1021,12 @@ var templates = {
} }
], ],
Bell: [
function(percent) {
return ["CxCs",[108,1]];
}
],
ForceScreenSaver: [ ForceScreenSaver: [
function(activate) { function(activate) {
return [ 'CCS', [115, activate?1:0, 1] ]; return [ 'CCS', [115, activate?1:0, 1] ];

View file

@ -258,7 +258,7 @@ exports.requireExt = function(display, callback)
ext.BindTexImage = function(ctx, drawable, buffer, attribs) { ext.BindTexImage = function(ctx, drawable, buffer, attribs) {
if (!attribs) if (!attribs)
attribs = []; attribs = [];
var data = new Buffer(12 + attribs.length*4); var data = Buffer.alloc(12 + attribs.length*4);
data.writeUInt32LE(drawable, 0); data.writeUInt32LE(drawable, 0);
data.writeUInt32LE(buffer, 4); data.writeUInt32LE(buffer, 4);
data.writeUInt32LE(attribs.length, 8); data.writeUInt32LE(attribs.length, 8);
@ -268,7 +268,7 @@ exports.requireExt = function(display, callback)
} }
ext.ReleaseTexImage = function(ctx, drawable, buffer) { ext.ReleaseTexImage = function(ctx, drawable, buffer) {
var data = new Buffer(8); var data = Buffer.alloc(8);
data.writeUint32LE(drawable, 0); data.writeUint32LE(drawable, 0);
data.writeUint32LE(buffer, 4); data.writeUint32LE(buffer, 4);
ext.VendorPrivate(ctx, 1331, data); ext.VendorPrivate(ctx, 1331, data);
@ -287,7 +287,7 @@ exports.requireExt = function(display, callback)
X.pack_stream.pack('CCSLSSL', [ext.majorOpcode, 2, length, ctx, requestNum, requestTotal, data.length]); X.pack_stream.pack('CCSLSSL', [ext.majorOpcode, 2, length, ctx, requestNum, requestTotal, data.length]);
X.pack_stream.write_queue.push(data); X.pack_stream.write_queue.push(data);
var pad = new Buffer(padLength); var pad = Buffer.alloc(padLength);
pad.fill(0); pad.fill(0);
X.pack_stream.write_queue.push(pad); X.pack_stream.write_queue.push(pad);
X.pack_stream.flush(); X.pack_stream.flush();

View file

@ -16,7 +16,7 @@ module.exports = function(GLX, ctx) {
throw Error('Buffer too big. Make sure you are using RenderLarge for large commands'); throw Error('Buffer too big. Make sure you are using RenderLarge for large commands');
currentLength += len; currentLength += len;
var res = Buffer(len); var res = Buffer.alloc(len);
res.writeUInt16LE(len, 0); res.writeUInt16LE(len, 0);
res.writeUInt16LE(opcode, 2); res.writeUInt16LE(opcode, 2);
return res; return res;
@ -266,7 +266,7 @@ module.exports = function(GLX, ctx) {
typeSize[constants.BYTE] = 1; typeSize[constants.BYTE] = 1;
typeSize[constants.UNSIGNED_BYTE] = 1; typeSize[constants.UNSIGNED_BYTE] = 1;
var res = new Buffer(60 + data.length*typeSize[type]); var res = Buffer.alloc(60 + data.length*typeSize[type]);
res.writeUInt32LE(res.length, 0); res.writeUInt32LE(res.length, 0);
res.writeUInt32LE(110, 4); res.writeUInt32LE(110, 4);

View file

@ -204,7 +204,43 @@ exports.requireExt = function(display, callback)
X.pack_stream.flush(); X.pack_stream.flush();
}, },
ext.GetOutputInfo = function(output, ts, cb)
{
X.seq_num ++;
X.pack_stream.pack('CCSLL', [ext.majorOpcode, 9, 3, output, ts ]);
X.replies[X.seq_num] = [
function(buf, opt) {
var i;
var pos = 0;
var res = buf.unpack('LLLLCCSSSSS');
var info = {
timestamp : res[0],
crtc : res[1],
mm_width : res[2],
mm_height : res[3],
connection : res[4],
subpixelOrder : res[5],
preferredModes: res[8]
};
pos += 28;
var format = Array(res[6] + 1).join('L');
info.crtcs = buf.unpack(format, pos);
pos += res[6] << 2;
format = Array(res[7] + 1).join('L');
info.modes = buf.unpack(format, pos);
pos += res[7] << 2;
format = Array(res[9] + 1).join('L');
info.clones = buf.unpack(format, pos);
pos += res[9] << 2;
info.name = buf.slice(pos, pos + res_modes[10]).toString('binary');
return info;
},
cb
];
X.pack_stream.flush();
},
ext.GetCrtcInfo = function(crtc, configTs, cb) { ext.GetCrtcInfo = function(crtc, configTs, cb) {
X.seq_num ++; X.seq_num ++;
X.pack_stream.pack('CCSLL', [ext.majorOpcode, 20, 3, crtc, configTs ]); X.pack_stream.pack('CCSLL', [ext.majorOpcode, 20, 3, crtc, configTs ]);

View file

@ -5,19 +5,14 @@ var xutil = require('../xutil');
// http://cgit.freedesktop.org/xcb/proto/tree/src/render.xml?id=HEAD // http://cgit.freedesktop.org/xcb/proto/tree/src/render.xml?id=HEAD
// and http://www.x.org/releases/X11R7.6/doc/renderproto/renderproto.txt // and http://www.x.org/releases/X11R7.6/doc/renderproto/renderproto.txt
// TODO: move to templates // TODO: move to templates
exports.requireExt = function(display, callback) exports.requireExt = function(display, callback) {
{
var X = display.client; var X = display.client;
X.QueryExtension('RENDER', function(err, ext) { X.QueryExtension('RENDER', function(err, ext) {
if (!ext.present) {
if (!ext.present)
{
return callback(new Error('extension not available')); return callback(new Error('extension not available'));
} }
ext.QueryVersion = function(clientMaj, clientMin, callback) ext.QueryVersion = function(clientMaj, clientMin, callback) {
{
X.seq_num++; X.seq_num++;
X.pack_stream.pack('CCSLL', [ext.majorOpcode, 0, 3, clientMaj, clientMin]); X.pack_stream.pack('CCSLL', [ext.majorOpcode, 0, 3, clientMaj, clientMin]);
X.replies[X.seq_num] = [ X.replies[X.seq_num] = [
@ -28,14 +23,13 @@ exports.requireExt = function(display, callback)
callback callback
]; ];
X.pack_stream.flush(); X.pack_stream.flush();
} };
ext.QueryPictFormat = function(callback) ext.QueryPictFormat = function(callback) {
{
X.pack_stream.pack('CCS', [ext.majorOpcode, 1, 1]); X.pack_stream.pack('CCS', [ext.majorOpcode, 1, 1]);
X.seq_num++; X.seq_num++;
X.replies[X.seq_num] = [ X.replies[X.seq_num] = [
function (buf, opt) { function(buf, opt) {
var res = {}; var res = {};
var res1 = buf.unpack('LLLLL'); var res1 = buf.unpack('LLLLL');
var num_formats = res1[0]; var num_formats = res1[0];
@ -46,8 +40,7 @@ exports.requireExt = function(display, callback)
// formats list: // formats list:
var offset = 24; var offset = 24;
res.formats = []; res.formats = [];
for (var i=0; i < num_formats; ++i) for (var i = 0; i < num_formats; ++i) {
{
var format = {}; var format = {};
var f = buf.unpack('LCCxxSSSSSSSSL', offset); var f = buf.unpack('LCCxxSSSSSSSSL', offset);
res.formats.push(f); res.formats.push(f);
@ -58,10 +51,9 @@ exports.requireExt = function(display, callback)
callback callback
]; ];
X.pack_stream.flush(); X.pack_stream.flush();
} };
ext.QueryFilters = function(callback) ext.QueryFilters = function(callback) {
{
X.pack_stream.pack('CCSL', [ext.majorOpcode, 29, 2, display.screen[0].root]); X.pack_stream.pack('CCSL', [ext.majorOpcode, 29, 2, display.screen[0].root]);
X.seq_num++; X.seq_num++;
X.replies[X.seq_num] = [ X.replies[X.seq_num] = [
@ -71,26 +63,24 @@ exports.requireExt = function(display, callback)
var num_filters = h[1]; var num_filters = h[1];
var aliases = []; var aliases = [];
var offset = 24; // LL + 16 bytes pad var offset = 24; // LL + 16 bytes pad
for (var i=0; i < num_aliases; ++i) for (var i = 0; i < num_aliases; ++i) {
{
aliases.push(buf.unpack('S', offset)[0]); aliases.push(buf.unpack('S', offset)[0]);
offset+=2; offset += 2;
} }
var filters = []; var filters = [];
for (var i=0; i < num_filters; ++i) for (var i = 0; i < num_filters; ++i) {
{
var len = buf.unpack('C', offset)[0]; var len = buf.unpack('C', offset)[0];
//if (!len) break; //if (!len) break;
offset++; offset++;
filters.push(buf.toString('ascii', offset, offset+len)); filters.push(buf.toString('ascii', offset, offset + len));
offset+=len; offset += len;
} }
return [aliases, filters]; return [aliases, filters];
}, },
callback callback
]; ];
X.pack_stream.flush(); X.pack_stream.flush();
} };
var valueList = [ var valueList = [
['repeat', 'Cxxx'], ['repeat', 'Cxxx'],
@ -116,22 +106,19 @@ exports.requireExt = function(display, callback)
x: 1 x: 1
}; };
ext.CreatePicture = function(pid, drawable, pictformat, values) ext.CreatePicture = function(pid, drawable, pictformat, values) {
{
var mask = 0; var mask = 0;
var reqLen = 5; // + (values + pad)/4 var reqLen = 5; // + (values + pad)/4
var format = 'CCSLLLL'; var format = 'CCSLLLL';
var params = [ext.majorOpcode, 4, reqLen, pid, drawable, pictformat, mask]; var params = [ext.majorOpcode, 4, reqLen, pid, drawable, pictformat, mask];
if (values) if (values) {
{
var valuesLength = 0; var valuesLength = 0;
for (var i=0; i < valueList.length; ++i) for (var i = 0; i < valueList.length; ++i) {
{
var name = valueList[i][0]; var name = valueList[i][0];
var val = values[name]; var val = values[name];
if (val) { if (val) {
mask |= (1 << i); mask |= 1 << i;
params.push(val); params.push(val);
var valueFormat = valueList[i][1]; var valueFormat = valueList[i][1];
format += valueFormat; format += valueFormat;
@ -140,8 +127,7 @@ exports.requireExt = function(display, callback)
} }
var pad4 = (valuesLength + 3) >> 2; var pad4 = (valuesLength + 3) >> 2;
var toPad = (pad4 << 2) - valuesLength; var toPad = (pad4 << 2) - valuesLength;
for (var i=0; i < toPad; ++i) for (var i = 0; i < toPad; ++i) format += 'x';
format += 'x';
reqLen += pad4; reqLen += pad4;
params[2] = reqLen; params[2] = reqLen;
params[6] = mask; params[6] = mask;
@ -149,7 +135,7 @@ exports.requireExt = function(display, callback)
X.pack_stream.pack(format, params); X.pack_stream.pack(format, params);
X.pack_stream.flush(); X.pack_stream.flush();
X.seq_num++; X.seq_num++;
} };
ext.FreePicture = function(pid) { ext.FreePicture = function(pid) {
X.pack_stream.pack('CCSL', [ext.majorOpcode, 7, 2, pid]); X.pack_stream.pack('CCSL', [ext.majorOpcode, 7, 2, pid]);
@ -157,16 +143,14 @@ exports.requireExt = function(display, callback)
X.seq_num++; X.seq_num++;
}; };
function floatToFix(f) function floatToFix(f) {
{ return parseInt(f * 65536);
return parseInt(f*65536);
} }
function colorToFix(f) function colorToFix(f) {
{
if (f < 0) f = 0; if (f < 0) f = 0;
if (f > 1) f = 1; if (f > 1) f = 1;
return parseInt(f*65535); return parseInt(f * 65535);
} }
ext.SetPictureTransform = function(pid, matrix) { ext.SetPictureTransform = function(pid, matrix) {
@ -174,7 +158,7 @@ exports.requireExt = function(display, callback)
if (matrix.length !== 9) if (matrix.length !== 9)
throw 'Render.SetPictureTransform: incorrect transform matrix. Must be array of 9 numbers'; throw 'Render.SetPictureTransform: incorrect transform matrix. Must be array of 9 numbers';
var params = [ext.majorOpcode, 28, 11, pid]; var params = [ext.majorOpcode, 28, 11, pid];
for (var i=0; i < 9; ++i) { for (var i = 0; i < 9; ++i) {
if (typeof matrix[i] !== 'number') if (typeof matrix[i] !== 'number')
throw 'Render.SetPictureTransform: matrix element must be a number'; throw 'Render.SetPictureTransform: matrix element must be a number';
params.push(floatToFix(matrix[i])); params.push(floatToFix(matrix[i]));
@ -185,35 +169,43 @@ exports.requireExt = function(display, callback)
}; };
// see example of blur filter here: https://github.com/richoH/rxvt-unicode/blob/master/src/background.C // see example of blur filter here: https://github.com/richoH/rxvt-unicode/blob/master/src/background.C
ext.SetPictureFilter = function(pid, name, filterParams) ext.SetPictureFilter = function(pid, name, filterParams) {
{ if (filterParams === 0) filterParams = [0];
if (filterParams === 0) if (!filterParams) filterParams = [];
filterParams = [0]; if (!Array.isArray(filterParams)) filterParams = [filterParams];
if (!filterParams)
filterParams = [];
if (!Array.isArray(filterParams))
filterParams = [filterParams];
var reqLen = 2; var reqLen = 2;
var format = 'CCSLSxxp'; var format = 'CCSLSxxp';
var params = [ext.majorOpcode, 30, reqLen, pid, name.length, name]; var params = [ext.majorOpcode, 30, reqLen, pid, name.length, name];
reqLen += xutil.padded_length(name.length+3)/4 + filterParams.length; reqLen += xutil.padded_length(name.length + 3) / 4 + filterParams.length;
if (name == 'nearest' || name == 'bilinear' || name == 'fast' || name == 'good' || name == 'best') { if (
name == 'nearest' ||
name == 'bilinear' ||
name == 'fast' ||
name == 'good' ||
name == 'best'
) {
if (filterParams.length !== 0) { if (filterParams.length !== 0) {
throw 'Render.SetPictureFilter: "' + name + '" - unexpected parameters for filters'; throw 'Render.SetPictureFilter: "' + name + '" - unexpected parameters for filters';
} }
} else if (name == 'convolution') { } else if (name == 'convolution') {
if (filterParams.length < 2 || ((filterParams[0]*filterParams[1] + 2) !== filterParams.length) ) { if (
filterParams.length < 2 ||
filterParams[0] * filterParams[1] + 2 !== filterParams.length
) {
throw 'Render.SetPictureFilter: "convolution" - incorrect matrix dimensions. Must be flat array [ w, h, elem1, elem2, ... ]'; throw 'Render.SetPictureFilter: "convolution" - incorrect matrix dimensions. Must be flat array [ w, h, elem1, elem2, ... ]';
} }
for (var i=0; i < filterParams.length; ++i) { for (var i = 0; i < filterParams.length; ++i) {
format += 'L'; format += 'L';
params.push(floatToFix(filterParams[i])); params.push(floatToFix(filterParams[i]));
} }
} else if (name == 'binomial' || name == 'gaussian') { } else if (name == 'binomial' || name == 'gaussian') {
if (filterParams.length !== 1) { if (filterParams.length !== 1) {
throw 'Render.SetPictureFilter: "' + name + '" - incorrect number of parameters, must be exactly 1 number, instead got: ' + filterParams; throw 'Render.SetPictureFilter: "' +
name +
'" - incorrect number of parameters, must be exactly 1 number, instead got: ' +
filterParams;
} }
format += 'L'; format += 'L';
params.push(floatToFix(filterParams[0])); params.push(floatToFix(filterParams[0]));
@ -226,16 +218,23 @@ exports.requireExt = function(display, callback)
X.seq_num++; X.seq_num++;
}; };
ext.CreateSolidFill = function(pid, r, g, b, a) ext.CreateSolidFill = function(pid, r, g, b, a) {
{ X.pack_stream.pack('CCSLSSSS', [
X.pack_stream.pack('CCSLSSSS', [ext.majorOpcode, 33, 4, pid, colorToFix(r), colorToFix(g), colorToFix(b), colorToFix(a)]); ext.majorOpcode,
33,
4,
pid,
colorToFix(r),
colorToFix(g),
colorToFix(b),
colorToFix(a)
]);
X.pack_stream.flush(); X.pack_stream.flush();
X.seq_num++; X.seq_num++;
}; };
ext.RadialGradient = function(pid, p1, p2, r1, r2, stops) ext.RadialGradient = function(pid, p1, p2, r1, r2, stops) {
{ var reqLen = 9 + stops.length * 3; //header + params + 1xStopfix+2xColors
var reqLen = 9+stops.length*3; //header + params + 1xStopfix+2xColors
var format = 'CCSLLLLLLLL'; var format = 'CCSLLLLLLLL';
var params = [ext.majorOpcode, 35, reqLen, pid]; var params = [ext.majorOpcode, 35, reqLen, pid];
params.push(floatToFix(p1[0])); // L params.push(floatToFix(p1[0])); // L
@ -248,27 +247,23 @@ exports.requireExt = function(display, callback)
// [ [float stopDist, [float r, g, b, a] ], ...] // [ [float stopDist, [float r, g, b, a] ], ...]
// stop distances // stop distances
for (var i=0; i < stops.length; ++i) for (var i = 0; i < stops.length; ++i) {
{
format += 'L'; format += 'L';
// TODO: we know total params length in advance. ? params[index] = // TODO: we know total params length in advance. ? params[index] =
params.push(floatToFix(stops[i][0])) params.push(floatToFix(stops[i][0]));
} }
// colors // colors
for (var i=0; i < stops.length; ++i) for (var i = 0; i < stops.length; ++i) {
{
format += 'SSSS'; format += 'SSSS';
for (var j=0; j < 4; ++j) for (var j = 0; j < 4; ++j) params.push(colorToFix(stops[i][1][j]));
params.push(colorToFix(stops[i][1][j]));
} }
X.pack_stream.pack(format, params); X.pack_stream.pack(format, params);
X.pack_stream.flush(); X.pack_stream.flush();
X.seq_num++; X.seq_num++;
}; };
ext.LinearGradient = function(pid, p1, p2, stops) ext.LinearGradient = function(pid, p1, p2, stops) {
{ var reqLen = 7 + stops.length * 3; //header + params + 1xStopfix+2xColors
var reqLen = 7+stops.length*3; //header + params + 1xStopfix+2xColors
var format = 'CCSLLLLLL'; var format = 'CCSLLLLLL';
var params = [ext.majorOpcode, 34, reqLen, pid]; var params = [ext.majorOpcode, 34, reqLen, pid];
params.push(floatToFix(p1[0])); // L params.push(floatToFix(p1[0])); // L
@ -280,27 +275,23 @@ exports.requireExt = function(display, callback)
// [ [float stopDist, [float r, g, b, a] ], ...] // [ [float stopDist, [float r, g, b, a] ], ...]
// stop distances // stop distances
for (var i=0; i < stops.length; ++i) for (var i = 0; i < stops.length; ++i) {
{
format += 'L'; format += 'L';
// TODO: we know total params length in advance. ? params[index] = // TODO: we know total params length in advance. ? params[index] =
params.push(floatToFix(stops[i][0])) params.push(floatToFix(stops[i][0]));
} }
// colors // colors
for (var i=0; i < stops.length; ++i) for (var i = 0; i < stops.length; ++i) {
{
format += 'SSSS'; format += 'SSSS';
for (var j=0; j < 4; ++j) for (var j = 0; j < 4; ++j) params.push(colorToFix(stops[i][1][j]));
params.push(colorToFix(stops[i][1][j]));
} }
X.pack_stream.pack(format, params); X.pack_stream.pack(format, params);
X.pack_stream.flush(); X.pack_stream.flush();
X.seq_num++; X.seq_num++;
} };
ext.ConicalGradient = function(pid, center, angle, stops) ext.ConicalGradient = function(pid, center, angle, stops) {
{ var reqLen = 6 + stops.length * 3; //header + params + 1xStopfix+2xColors
var reqLen = 6+stops.length*3; //header + params + 1xStopfix+2xColors
var format = 'CCSLLLLL'; var format = 'CCSLLLLL';
var params = [ext.majorOpcode, 36, reqLen, pid]; var params = [ext.majorOpcode, 36, reqLen, pid];
params.push(floatToFix(center[0])); // L params.push(floatToFix(center[0])); // L
@ -311,64 +302,81 @@ exports.requireExt = function(display, callback)
// [ [float stopDist, [float r, g, b, a] ], ...] // [ [float stopDist, [float r, g, b, a] ], ...]
// stop distances // stop distances
for (var i=0; i < stops.length; ++i) for (var i = 0; i < stops.length; ++i) {
{
format += 'L'; format += 'L';
// TODO: we know total params length in advance. ? params[index] = // TODO: we know total params length in advance. ? params[index] =
params.push(floatToFix(stops[i][0])) params.push(floatToFix(stops[i][0]));
} }
// colors // colors
for (var i=0; i < stops.length; ++i) for (var i = 0; i < stops.length; ++i) {
{
format += 'SSSS'; format += 'SSSS';
for (var j=0; j < 4; ++j) for (var j = 0; j < 4; ++j) params.push(colorToFix(stops[i][1][j]));
params.push(colorToFix(stops[i][1][j]));
} }
X.pack_stream.pack(format, params); X.pack_stream.pack(format, params);
X.pack_stream.flush(); X.pack_stream.flush();
X.seq_num++; X.seq_num++;
} };
ext.FillRectangles = function(op, pid, color, rects) ext.FillRectangles = function(op, pid, color, rects) {
{ var reqLen = 5 + rects.length / 2;
var reqLen = 5+rects.length/2;
var format = 'CCSCxxxLSSSS'; var format = 'CCSCxxxLSSSS';
var params = [ext.majorOpcode, 26, reqLen, op, pid]; var params = [ext.majorOpcode, 26, reqLen, op, pid];
for (var j=0; j < 4; ++j) for (var j = 0; j < 4; ++j) params.push(colorToFix(color[j]));
params.push(colorToFix(color[j])); for (var i = 0; i < rects.length; i += 4) {
for (var i=0; i < rects.length; i+=4)
{
format += 'ssSS'; format += 'ssSS';
params.push(rects[i*4]); params.push(rects[i * 4]);
params.push(rects[i*4 + 1]); params.push(rects[i * 4 + 1]);
params.push(rects[i*4 + 2]); params.push(rects[i * 4 + 2]);
params.push(rects[i*4 + 3]); params.push(rects[i * 4 + 3]);
} }
X.pack_stream.pack(format, params); X.pack_stream.pack(format, params);
X.pack_stream.flush(); X.pack_stream.flush();
X.seq_num++; X.seq_num++;
} };
ext.Composite = function(op, src, mask, dst, srcX, srcY, maskX, maskY, dstX, dstY, width, height) ext.Composite = function(
{ op,
X.pack_stream.pack( src,
'CCSCxxxLLLssssssSS', mask,
[ext.majorOpcode, 8, 9, op, src, mask, dst, srcX, srcY, maskX, maskY, dstX, dstY, width, height] dst,
) srcX,
srcY,
maskX,
maskY,
dstX,
dstY,
width,
height
) {
X.pack_stream
.pack('CCSCxxxLLLssssssSS', [
ext.majorOpcode,
8,
9,
op,
src,
mask,
dst,
srcX,
srcY,
maskX,
maskY,
dstX,
dstY,
width,
height
])
.flush(); .flush();
X.seq_num++; X.seq_num++;
} };
// note that Trapezoids is considered deprecated by Render extension // note that Trapezoids is considered deprecated by Render extension
ext.Trapezoids = function(op, src, srcX, srcY, dst, maskFormat, trapz) ext.Trapezoids = function(op, src, srcX, srcY, dst, maskFormat, trapz) {
{
var format = 'CCSCxxxLLLss'; var format = 'CCSCxxxLLLss';
var params = [ext.majorOpcode, 10, 6+trapz.length, op, src, dst, maskFormat, srcX, srcY]; var params = [ext.majorOpcode, 10, 6 + trapz.length, op, src, dst, maskFormat, srcX, srcY];
for (var i=0; i < trapz.length; i++) for (var i = 0; i < trapz.length; i++) {
{
format += 'llllllllll'; format += 'llllllllll';
for (var j=0; j < 10; ++j) for (var j = 0; j < 10; ++j) params.push(floatToFix(trapz[i * 10 + j]));
params.push(floatToFix(trapz[i*10 + j]));
} }
X.pack_stream.pack(format, params); X.pack_stream.pack(format, params);
X.pack_stream.flush(); X.pack_stream.flush();
@ -377,9 +385,8 @@ exports.requireExt = function(display, callback)
ext.AddTraps = function(pic, offX, offY, trapList) { ext.AddTraps = function(pic, offX, offY, trapList) {
var format = 'CCSLss'; var format = 'CCSLss';
var params = [ext.majorOpcode, 32, 3+trapList.length, pic, offX, offY]; var params = [ext.majorOpcode, 32, 3 + trapList.length, pic, offX, offY];
for (var i=0; i < trapList.length; i++) for (var i = 0; i < trapList.length; i++) {
{
format += 'l'; format += 'l';
params.push(floatToFix(trapList[i])); params.push(floatToFix(trapList[i]));
} }
@ -388,12 +395,10 @@ exports.requireExt = function(display, callback)
X.seq_num++; X.seq_num++;
}; };
ext.Triangles = function(op, src, srcX, srcY, dst, maskFormat, tris) ext.Triangles = function(op, src, srcX, srcY, dst, maskFormat, tris) {
{
var format = 'CCSCxxxLLLss'; var format = 'CCSCxxxLLLss';
var params = [ext.majorOpcode, 11, 6+tris.length, op, src, dst, maskFormat, srcX, srcY]; var params = [ext.majorOpcode, 11, 6 + tris.length, op, src, dst, maskFormat, srcX, srcY];
for (var i=0; i < tris.length; i+=6) for (var i = 0; i < tris.length; i += 6) {
{
format += 'llllll'; format += 'llllll';
//TODO: Array.copy //TODO: Array.copy
params.push(floatToFix(tris[i + 0])); // x1 params.push(floatToFix(tris[i + 0])); // x1
@ -406,25 +411,25 @@ exports.requireExt = function(display, callback)
X.pack_stream.pack(format, params); X.pack_stream.pack(format, params);
X.pack_stream.flush(); X.pack_stream.flush();
X.seq_num++; X.seq_num++;
} };
ext.CreateGlyphSet = function(gsid, format) { ext.CreateGlyphSet = function(gsid, format) {
X.pack_stream.pack('CCSLL', [ext.majorOpcode, 17, 3, gsid, format]); X.pack_stream.pack('CCSLL', [ext.majorOpcode, 17, 3, gsid, format]);
X.pack_stream.flush(); X.pack_stream.flush();
X.seq_num++; X.seq_num++;
} };
ext.ReferenceGlyphSet = function(gsid, existing) { ext.ReferenceGlyphSet = function(gsid, existing) {
X.pack_stream.pack('CCSLL', [ext.majorOpcode, 18, 3, gsid, existing]); X.pack_stream.pack('CCSLL', [ext.majorOpcode, 18, 3, gsid, existing]);
X.pack_stream.flush(); X.pack_stream.flush();
X.seq_num++; X.seq_num++;
} };
ext.FreeGlyphSet = function(gsid) { ext.FreeGlyphSet = function(gsid) {
X.pack_stream.pack('CCSL', [ext.majorOpcode, 19, 2, gsid]); X.pack_stream.pack('CCSL', [ext.majorOpcode, 19, 2, gsid]);
X.pack_stream.flush(); X.pack_stream.flush();
X.seq_num++; X.seq_num++;
} };
ext.AddGlyphs = function(gsid, glyphs) { ext.AddGlyphs = function(gsid, glyphs) {
var numGlyphs = glyphs.length; var numGlyphs = glyphs.length;
@ -436,11 +441,11 @@ exports.requireExt = function(display, callback)
for (var i = 0; i < numGlyphs; i++) { for (var i = 0; i < numGlyphs; i++) {
glyph = glyphs[i]; glyph = glyphs[i];
if (glyph.width % 4 !== 0) { if (glyph.width % 4 !== 0) {
var stride = (glyph.width+3)&~3; var stride = (glyph.width + 3) & ~3;
var res = new Buffer(glyph.height*stride); var res = Buffer.alloc(glyph.height * stride);
res.fill(0); res.fill(0);
for (var y=0; y < glyph.height; ++y) { for (var y = 0; y < glyph.height; ++y) {
glyph.image.copy(res, y*stride, y*glyph.width, y*glyph.width + glyph.width); glyph.image.copy(res, y * stride, y * glyph.width, y * glyph.width + glyph.width);
} }
glyph.image = res; glyph.image = res;
glyph.width = stride; glyph.width = stride;
@ -450,12 +455,12 @@ exports.requireExt = function(display, callback)
glyph.offX = glyph.offX / 64; glyph.offX = glyph.offX / 64;
glyph.offY = glyph.offY / 64; glyph.offY = glyph.offY / 64;
} }
var len = numGlyphs * 4 + imageBytes/4 + 3; var len = numGlyphs * 4 + imageBytes / 4 + 3;
// TODO: check length, use bigReq // TODO: check length, use bigReq
// X.pack_stream.pack('CCSLL', [ext.majorOpcode, 20, len, gsid, glyphs.length]); // X.pack_stream.pack('CCSLL', [ext.majorOpcode, 20, len, gsid, glyphs.length]);
// BigReq: S + [ length ] replaced with SL + [ 0, length+1 ] // BigReq: S + [ length ] replaced with SL + [ 0, length+1 ]
X.pack_stream.pack('CCSLLL', [ext.majorOpcode, 20, 0, len+1, gsid, glyphs.length]); X.pack_stream.pack('CCSLLL', [ext.majorOpcode, 20, 0, len + 1, gsid, glyphs.length]);
// glyph ids // glyph ids
for (i = 0; i < numGlyphs; i++) { for (i = 0; i < numGlyphs; i++) {
@ -463,7 +468,14 @@ exports.requireExt = function(display, callback)
} }
// width + heiht + origin xy + advance xy // width + heiht + origin xy + advance xy
for (i = 0; i < numGlyphs; i++) { for (i = 0; i < numGlyphs; i++) {
X.pack_stream.pack('SSssss', [glyphs[i].width, glyphs[i].height, -glyphs[i].x, glyphs[i].y, glyphs[i].offX, glyphs[i].offY]); X.pack_stream.pack('SSssss', [
glyphs[i].width,
glyphs[i].height,
-glyphs[i].x,
glyphs[i].y,
glyphs[i].offX,
glyphs[i].offY
]);
} }
// image // image
for (i = 0; i < numGlyphs; i++) { for (i = 0; i < numGlyphs; i++) {
@ -471,12 +483,29 @@ exports.requireExt = function(display, callback)
} }
X.pack_stream.flush(); X.pack_stream.flush();
X.seq_num++; X.seq_num++;
} };
//AddGlyphsFromPicture, opcode=21 (not in spec) // As far as I know this is not implemented in any X server and always retuen "Bad implementation"
// FreeGlyps - opcode 22 // Also documentation looks misleading as it's not mention glyph ids.
// gsid(L) , glyphs.length (L) + each glyph id (L) ext.AddGlyphsFromPicture = function(gsid, src, glyphs) {
// var len = 3 + glyphs.length * 5;
X.pack_stream.pack('CCSLLL', [ext.majorOpcode, 21, 0, len + 1, gsid, src]);
for (i = 0; i < glyphs.length; i++) {
X.pack_stream.pack('L', [glyphs[i].id]);
}
for (i = 0; i < glyphs.length; i++) {
X.pack_stream.pack('SSssssss', [
glyphs[i].width,
glyphs[i].height,
-glyphs[i].x,
glyphs[i].y,
glyphs[i].offX,
glyphs[i].offY,
glyphs[i].srcX,
glyphs[i].srcY
]);
}
};
// each GlyphEle: // each GlyphEle:
// 1 byte - number of glyphs // 1 byte - number of glyphs
@ -492,53 +521,160 @@ exports.requireExt = function(display, callback)
// glyphs as input: // glyphs as input:
// [ "just string (0,0) offset is used", [ 10, 10, "string offseted 10,10 from previous pen position" ], 1234567 ] 1234567 is glypfset id or FONT // [ "just string (0,0) offset is used", [ 10, 10, "string offseted 10,10 from previous pen position" ], 1234567 ] 1234567 is glypfset id or FONT
// TODO: pre-process input so strings larger than 254 chars are supported // TODO: pre-process input so strings larger than 254 chars are supported
// (split them into multiple entries with 0,0 offset) // (split them into multiple entries with 0,0 offset)
var formatFromBits = [,,,,,,,,'C',,,,,,,,'S',,,,,,,,,,,,,,,,'L']; var formatFromBits = [
var bufferWriteBits = [,,,,,,,,'writeUInt8',,,,,,,,'writeUInt16LE',,,,,,,,,,,,,,,,'writeUInt32LE']; ,
,
,
,
,
,
,
,
'C',
,
,
,
,
,
,
,
'S',
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
'L'
];
var bufferWriteBits = [
,
,
,
,
,
,
,
,
'writeUInt8',
,
,
,
,
,
,
,
'writeUInt16LE',
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
'writeUInt32LE'
];
// 8/16/32 bit string + 4-byte pad // 8/16/32 bit string + 4-byte pad
function wstring(bits, s) { function wstring(bits, s) {
var charLength = bits / 8; var charLength = bits / 8;
var dataLength = s.length*charLength; var dataLength = s.length * charLength;
var res = new Buffer(xutil.padded_length(dataLength)); var res = Buffer.alloc(xutil.padded_length(dataLength));
debugger; debugger;
var write = res[bufferWriteBits[bits]] var write = res[bufferWriteBits[bits]];
res.fill(0); res.fill(0);
for(var i=0; i < s.length; i++) for (var i = 0; i < s.length; i++) write.call(res, s.charCodeAt(i), i * charLength);
write.call(res, s.charCodeAt(i), i*charLength);
return res; return res;
} }
var compositeGlyphsOpcodeFromBits = [,,,,,,,,23,,,,,,,,24,,,,,,,,,,,,,,,,25]; var compositeGlyphsOpcodeFromBits = [
ext.CompositeGlyphs = function(glyphBits, op, src, dst, maskFormat, gsid, srcX, srcY, glyphs) ,
{ ,
,
,
,
,
,
,
23,
,
,
,
,
,
,
,
24,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
,
25
];
ext.CompositeGlyphs = function(glyphBits, op, src, dst, maskFormat, gsid, srcX, srcY, glyphs) {
var opcode = compositeGlyphsOpcodeFromBits[glyphBits]; var opcode = compositeGlyphsOpcodeFromBits[glyphBits];
var charFormat = formatFromBits[glyphBits]; var charFormat = formatFromBits[glyphBits];
var charLength = glyphBits / 8; var charLength = glyphBits / 8;
var length = 7; var length = 7;
var glyphs_length_split = []; var glyphs_length_split = [];
for (var i=0; i < glyphs.length; ++i) { for (var i = 0; i < glyphs.length; ++i) {
var g = glyphs[i]; var g = glyphs[i];
switch (typeof g) { switch (typeof g) {
case 'string': case 'string':
length += xutil.padded_length(g.length*charLength)/4 + 2; length += xutil.padded_length(g.length * charLength) / 4 + 2;
break; break;
case 'object': case 'object':
length += xutil.padded_length(g[2].length*charLength)/4 + 2; length += xutil.padded_length(g[2].length * charLength) / 4 + 2;
break; break;
case 'number': // glyphset id case 'number': // glyphset id
length += 3; length += 3;
break; break;
} }
} }
X.pack_stream.pack( X.pack_stream.pack('CCSCxxxLLLLss', [
'CCSCxxxLLLLss', ext.majorOpcode,
[ext.majorOpcode, opcode, length, op, src, dst, maskFormat, gsid, srcX, srcY] opcode,
); length,
for (var i=0; i < glyphs.length; ++i) { op,
src,
dst,
maskFormat,
gsid,
srcX,
srcY
]);
for (var i = 0; i < glyphs.length; ++i) {
var g = glyphs[i]; var g = glyphs[i];
switch (typeof g) { switch (typeof g) {
case 'string': case 'string':
@ -556,18 +692,15 @@ exports.requireExt = function(display, callback)
X.seq_num++; X.seq_num++;
}; };
ext.CompositeGlyphs8 = function(op, src, dst, maskFormat, gsid, srcX, srcY, glyphs) ext.CompositeGlyphs8 = function(op, src, dst, maskFormat, gsid, srcX, srcY, glyphs) {
{
return ext.CompositeGlyphs(8, op, src, dst, maskFormat, gsid, srcX, srcY, glyphs); return ext.CompositeGlyphs(8, op, src, dst, maskFormat, gsid, srcX, srcY, glyphs);
}; };
ext.CompositeGlyphs16 = function(op, src, dst, maskFormat, gsid, srcX, srcY, glyphs) ext.CompositeGlyphs16 = function(op, src, dst, maskFormat, gsid, srcX, srcY, glyphs) {
{
return ext.CompositeGlyphs(16, op, src, dst, maskFormat, gsid, srcX, srcY, glyphs); return ext.CompositeGlyphs(16, op, src, dst, maskFormat, gsid, srcX, srcY, glyphs);
}; };
ext.CompositeGlyphs32 = function(op, src, dst, maskFormat, gsid, srcX, srcY, glyphs) ext.CompositeGlyphs32 = function(op, src, dst, maskFormat, gsid, srcX, srcY, glyphs) {
{
return ext.CompositeGlyphs(32, op, src, dst, maskFormat, gsid, srcX, srcY, glyphs); return ext.CompositeGlyphs(32, op, src, dst, maskFormat, gsid, srcX, srcY, glyphs);
}; };
@ -590,32 +723,36 @@ exports.requireExt = function(display, callback)
// 11 - colormap or none // 11 - colormap or none
ext.QueryPictFormat(function(err, formats) { ext.QueryPictFormat(function(err, formats) {
if (err) if (err) return callback(err);
return callback(err); for (var i = 0; i < formats.formats.length; ++i) {
for (var i=0; i < formats.formats.length; ++i) {
var f = formats.formats[i]; var f = formats.formats[i];
if (f[2] == 1 && f[10] == 1) if (f[2] == 1 && f[10] == 1) ext.mono1 = f[0];
ext.mono1 = f[0] ; if (f[2] == 24 && f[3] == 16 && f[5] == 8 && f[7] == 0) ext.rgb24 = f[0];
if (f[2] == 24 && f[3] == 16 && f[5] == 8 && f[7] == 0)
ext.rgb24 = f[0];
// 1, 32, 16, 255, 8, 255, 0, 255, 24, 255, 0 // 1, 32, 16, 255, 8, 255, 0, 255, 24, 255, 0
if (f[2] == 32 && f[3] == 16 && f[4] == 255 && f[5] == 8 && f[6] == 255 && f[7] == 0 && f[9] == 24) if (
ext.rgba32 = f[0] ; f[2] == 32 &&
if (f[2] == 8 && f[10] == 255) f[3] == 16 &&
ext.a8 = f[0]; f[4] == 255 &&
f[5] == 8 &&
f[6] == 255 &&
f[7] == 0 &&
f[9] == 24
)
ext.rgba32 = f[0];
if (f[2] == 8 && f[10] == 255) ext.a8 = f[0];
} }
callback(null, ext); callback(null, ext);
}); });
[ [
"PICTFORMAT argument does not name a defined PICTFORMAT", 'PICTFORMAT argument does not name a defined PICTFORMAT',
"PICTURE argument does not name a defined PICTURE", 'PICTURE argument does not name a defined PICTURE',
"PICTOP argument does not name a defined PICTOP", 'PICTOP argument does not name a defined PICTOP',
"GLYPHSET argument does not name a defined GLYPHSET", 'GLYPHSET argument does not name a defined GLYPHSET',
"GLYPH argument does not name a defined GLYPH in the glyphset" 'GLYPH argument does not name a defined GLYPH in the glyphset'
].forEach(function(desc, code) { ].forEach(function(desc, code) {
X.errorParsers[ext.firstError + code] = function(err) { X.errorParsers[ext.firstError + code] = function(err) {
err.message = "XRender: a value for a " + desc; err.message = 'XRender: a value for a ' + desc;
}; };
}); });
@ -673,23 +810,23 @@ exports.requireExt = function(display, callback)
/*, /*,
* Operators only available in version 0.11, * Operators only available in version 0.11,
*/ */
BlendMinimum : 0x30, BlendMinimum: 0x30,
Multiply : 0x30, Multiply: 0x30,
Screen : 0x31, Screen: 0x31,
Overlay : 0x32, Overlay: 0x32,
Darken : 0x33, Darken: 0x33,
Lighten : 0x34, Lighten: 0x34,
ColorDodge : 0x35, ColorDodge: 0x35,
ColorBurn : 0x36, ColorBurn: 0x36,
HardLight : 0x37, HardLight: 0x37,
SoftLight : 0x38, SoftLight: 0x38,
Difference : 0x39, Difference: 0x39,
Exclusion : 0x3a, Exclusion: 0x3a,
HSLHue : 0x3b, HSLHue: 0x3b,
HSLSaturation: 0x3c, HSLSaturation: 0x3c,
HSLColor : 0x3d, HSLColor: 0x3d,
HSLLuminosity: 0x3e, HSLLuminosity: 0x3e,
BlendMaximum : 0x3e BlendMaximum: 0x3e
}; };
ext.PolyEdge = { ext.PolyEdge = {
@ -713,9 +850,9 @@ exports.requireExt = function(display, callback)
Unknown: 0, Unknown: 0,
HorizontalRGB: 1, HorizontalRGB: 1,
HorizontalBGR: 2, HorizontalBGR: 2,
VerticalRGB : 3, VerticalRGB: 3,
VerticalBGR : 4, VerticalBGR: 4,
None : 5 None: 5
}; };
ext.Filters = { ext.Filters = {
@ -727,4 +864,4 @@ exports.requireExt = function(display, callback)
Best: 'best' Best: 'best'
}; };
}); });
} };

View file

@ -112,5 +112,31 @@ exports.requireExt = function(display, callback)
callback(null, ext); callback(null, ext);
}); });
*/ */
ext.events = {
ShapeNotify: 0
}
X.eventParsers[ext.firstEvent + ext.events.ShapeNotify] = function(type, seq, extra, code, raw)
{
var event = {};
event.type = type;
event.kind = code;
event.seq = seq;
event.window = extra;
var values = raw.unpack('ssSSLC');
event.x = values[0];
event.y = values[1];
event.width = values[2];
event.height = values[3];
event.time = values[4];
event.shaped = values[5];
event.name = 'ShapeNotify';
return event;
};
}); });
} }

22
lib/gcfunction.js Normal file
View file

@ -0,0 +1,22 @@
/*
* GCFunction named shortcuts
*/
module.exports = {
GXclear : 0x0,
GXand : 0x1,
GXandReverse : 0x2,
GXcopy : 0x3,
GXandInverted : 0x4,
GXnoop : 0x5,
GXxor : 0x6,
GXor : 0x7,
GXnor : 0x8,
GXequiv : 0x9,
GXinvert : 0xa,
GXorReverse : 0xb,
GXcopyInverted : 0xc,
GXorInverted : 0xd,
GXnand : 0xe,
GXset : 0xf
};

View file

@ -32,8 +32,11 @@ function readVisuals(bl, visuals, n_visuals, cb)
}); });
} }
function readDepths(bl, display, depths, n_depths, cb) function readScreens(bl, display, cbDisplayReady)
{ {
var numParsedDepths = 0;
var readDepths = function(bl, display, depths, n_depths, cb)
{
if (n_depths == 0) if (n_depths == 0)
{ {
cb(); cb();
@ -46,17 +49,22 @@ function readDepths(bl, display, depths, n_depths, cb)
var visuals = {}; var visuals = {};
readVisuals(bl, visuals, n_visuals, function() readVisuals(bl, visuals, n_visuals, function()
{ {
if (dep in depths) {
for (var visual in visuals) {
depths[dep][visual] = visuals[visual];
}
} else {
depths[dep] = visuals; depths[dep] = visuals;
if (Object.keys(depths).length == n_depths) }
numParsedDepths++;
if (numParsedDepths == n_depths)
cb(); cb();
else else
readDepths(bl, display, depths, n_depths, cb); readDepths(bl, display, depths, n_depths, cb);
}); });
}); });
} }
function readScreens(bl, display, cbDisplayReady)
{
// for (i=0; i < display.screen_num; ++i) // for (i=0; i < display.screen_num; ++i)
{ {
var scr = {}; var scr = {};
@ -90,7 +98,7 @@ function readScreens(bl, display, cbDisplayReady)
if (display.screen.length == display.screen_num) if (display.screen.length == display.screen_num)
{ {
delete display.screen_num; delete display.screen_num;
cbDisplayReady(display); cbDisplayReady(null, display);
return; return;
} else { } else {
readScreens(bl, display, cbDisplayReady); readScreens(bl, display, cbDisplayReady);
@ -108,9 +116,14 @@ bl.unpack('C', function(res) {
if (res[0] == 0) if (res[0] == 0)
{ {
// conection time error // conection time error
// unpack error (? TODO) // unpack error
bl.unpack('Cxxxxxx', function (rlen) {
bl.get(rlen[0], function (reason) {
var err = new Error; var err = new Error;
cb(err); // TODO: detect that this is error on xcore side err.message = 'X server connection failed: ' + reason.toString();
cb(err);
});
});
// TODO: do we need to close stream from our side? // TODO: do we need to close stream from our side?
// TODO: api to close source stream via attached unpackstream // TODO: api to close source stream via attached unpackstream
return; return;
@ -189,10 +202,12 @@ function getByteOrder() {
} }
} }
function writeClientHello(stream, displayNum, authHost) function writeClientHello(stream, displayNum, authHost, authFamily)
{ {
getAuthString( displayNum, authHost, function( err, cookie ) { getAuthString( displayNum, authHost, authFamily, function( err, cookie ) {
debugger; if (err) {
throw err;
}
var byte_order = getByteOrder(); var byte_order = getByteOrder();
var protocol_major = 11; // TODO: config? env? var protocol_major = 11; // TODO: config? env?
var protocol_minor = 0; var protocol_minor = 0;

View file

@ -7,7 +7,7 @@
// It should create a pleasant looking hex dumb by default: // It should create a pleasant looking hex dumb by default:
// //
// var hexy = require('hexy.js'), // var hexy = require('hexy.js'),
// b = new Buffer("\000\001\003\005\037\012\011bcdefghijklmnopqrstuvwxyz0123456789") // b = Buffer.alloc("\000\001\003\005\037\012\011bcdefghijklmnopqrstuvwxyz0123456789")
// //
// console.log(hexy.hexy(b)) // console.log(hexy.hexy(b))
// //

View file

@ -11,6 +11,11 @@ Object.defineProperty(module.exports, 'keySyms', {
get: function() { return require('./keysyms'); } get: function() { return require('./keysyms'); }
}); });
Object.defineProperty(module.exports, 'gcFunction', {
enumerable: true,
get: function() { return require('./gcfunction'); }
});
//TODO: //TODO:
// keepe everything in namespace for consistensy (eventMask, keySyms, class, destination ... // keepe everything in namespace for consistensy (eventMask, keySyms, class, destination ...
// or put most used constants to top namespace? (currently class and destination in top) // or put most used constants to top namespace? (currently class and destination in top)

View file

@ -23,7 +23,7 @@ function ReadFixedRequest(length, callback)
{ {
this.length = length; this.length = length;
this.callback = callback; this.callback = callback;
this.data = new Buffer(length); this.data = Buffer.alloc(length);
this.received_bytes = 0; this.received_bytes = 0;
} }
@ -201,7 +201,7 @@ UnpackStream.prototype.pstr = function(str)
var len = xutil.padded_length(str.length); var len = xutil.padded_length(str.length);
if (len == 0) if (len == 0)
return; // nothing to write return; // nothing to write
var buf = new Buffer(len); var buf = Buffer.alloc(len);
buf.write(str, 'binary'); buf.write(str, 'binary');
this.write_queue.push(buf); this.write_queue.push(buf);
} }
@ -231,7 +231,7 @@ UnpackStream.prototype.pack = function(format, args)
} }
} }
var buf = new Buffer(packetlength); var buf = Buffer.alloc(packetlength);
var offset = 0; var offset = 0;
var arg = 0; var arg = 0;
for (var i = 0; i < format.length; ++i) for (var i = 0; i < format.length; ++i)
@ -269,12 +269,14 @@ UnpackStream.prototype.pack = function(format, args)
buf[offset++] = (n >> 16) & 0xff; buf[offset++] = (n >> 16) & 0xff;
buf[offset++] = (n >> 24) & 0xff; buf[offset++] = (n >> 24) & 0xff;
break; break;
case 'a': // string or buffer case 'a': // string, buffer, or array
var str = args[arg++]; var str = args[arg++];
if (Buffer.isBuffer(str)) if (Buffer.isBuffer(str))
{ {
str.copy(buf, offset); str.copy(buf, offset);
offset += str.length; offset += str.length;
} else if(Array.isArray(str)) {
for(var item of str) buf[offset++] = item;
} else { } else {
// TODO: buffer.write could be faster // TODO: buffer.write could be faster
for (var c = 0; c < str.length; ++c) for (var c = 0; c < str.length; ++c)

View file

@ -6,7 +6,6 @@ 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 hexy = require('./hexy').hexy; var hexy = require('./hexy').hexy;
var Buffer = require('buffer').Buffer; var Buffer = require('buffer').Buffer;
@ -20,6 +19,25 @@ var coreRequests = require('./corereqs');
var stdatoms = require('./stdatoms'); var stdatoms = require('./stdatoms');
var em = require('./eventmask').eventMask; var em = require('./eventmask').eventMask;
function stash ()
{
require('./ext/apple-wm');
require('./ext/big-requests');
require('./ext/composite');
require('./ext/damage');
require('./ext/dpms');
require('./ext/fixes');
require('./ext/glxconstants');
require('./ext/glx');
require('./ext/glxrender');
require('./ext/randr');
require('./ext/render');
require('./ext/screen-saver');
require('./ext/shape');
require('./ext/xc-misc');
require('./ext/xtest');
}
function XClient(displayNum, screenNum, options) function XClient(displayNum, screenNum, options)
{ {
EventEmitter.call(this); EventEmitter.call(this);
@ -31,7 +49,6 @@ function XClient(displayNum, screenNum, options)
this.displayNum = displayNum; this.displayNum = displayNum;
this.screenNum = screenNum; this.screenNum = screenNum;
this.authHost = os.hostname();
} }
util.inherits(XClient, EventEmitter); util.inherits(XClient, EventEmitter);
@ -39,6 +56,14 @@ XClient.prototype.init = function(stream)
{ {
this.stream = stream; this.stream = stream;
this.authHost = stream.remoteAddress;
// Node v0.10.x does not have stream.remoteFamily, so dig in to find it
this.authFamily = stream._getpeername ? stream._getpeername().family : stream.remoteFamily;
if (!this.authHost || this.authHost === '127.0.0.1' || this.authHost === '::1') {
this.authHost = os.hostname();
this.authFamily = null;
}
var pack_stream = new PackStream(); var pack_stream = new PackStream();
// data received from stream is dispached to // data received from stream is dispached to
@ -107,11 +132,13 @@ XClient.prototype.init = function(stream)
this.event_consumers = {}; // maps window id to eventemitter TODO: bad name this.event_consumers = {}; // maps window id to eventemitter TODO: bad name
this.eventParsers = {}; this.eventParsers = {};
this.errorParsers = {}; this.errorParsers = {};
this._extensions = {};
this.importRequestsFromTemplates(this, coreRequests); this.importRequestsFromTemplates(this, coreRequests);
this.startHandshake(); this.startHandshake();
this._closing = false; this._closing = false;
this._unusedIds = [];
} }
// TODO: close() = set 'closing' flag, watch it in replies and writeQueue, terminate if empty // TODO: close() = set 'closing' flag, watch it in replies and writeQueue, terminate if empty
@ -240,12 +267,17 @@ XClient.prototype.importRequestsFromTemplates = function(target, reqs)
XClient.prototype.AllocID = function() XClient.prototype.AllocID = function()
{ {
if (this._unusedIds.length > 0) {
return this._unusedIds.pop();
}
// TODO: handle overflow (XCMiscGetXIDRange from XC_MISC ext) // TODO: handle overflow (XCMiscGetXIDRange from XC_MISC ext)
// TODO: unused id buffer
this.display.rsrc_id++; this.display.rsrc_id++;
return (this.display.rsrc_id << this.display.rsrc_shift) + this.display.resource_base; return (this.display.rsrc_id << this.display.rsrc_shift) + this.display.resource_base;
} };
XClient.prototype.ReleaseID = function(id) {
this._unusedIds.push(id);
};
// TODO: move core events unpackers to corereqs.js // TODO: move core events unpackers to corereqs.js
XClient.prototype.unpackEvent = function(type, seq, extra, code, raw, headerBuf) XClient.prototype.unpackEvent = function(type, seq, extra, code, raw, headerBuf)
@ -290,7 +322,14 @@ XClient.prototype.unpackEvent = function(type, seq, extra, code, raw, headerBuf)
event.x = values[5]; event.x = values[5];
event.y = values[6]; event.y = values[6];
event.values = values event.values = values
} else if (type == 9) { // FocusIn
event.name = "FocusIn";
event.mode = raw.unpack('C')[0];
event.wid = extra;
} else if (type == 10) { // FocusOut
event.name = "FocusOut";
event.mode = raw.unpack('C')[0];
event.wid = extra;
} else if (type == 12) { // Expose } else if (type == 12) { // Expose
var values = raw.unpack('SSSSS'); var values = raw.unpack('SSSSS');
event.name = 'Expose' event.name = 'Expose'
@ -404,6 +443,7 @@ XClient.prototype.unpackEvent = function(type, seq, extra, code, raw, headerBuf)
event.name = 'ClientMessage'; event.name = 'ClientMessage';
event.format = code; event.format = code;
event.wid = extra; event.wid = extra;
event.message_type = raw.unpack('L')[0];
var format = (code === 32) ? 'LLLLL' : (code === 16) ? 'SSSSSSSSSS' : 'CCCCCCCCCCCCCCCCCCCC'; var format = (code === 32) ? 'LLLLL' : (code === 16) ? 'SSSSSSSSSS' : 'CCCCCCCCCCCCCCCCCCCC';
event.data = raw.unpack(format, 4); event.data = raw.unpack(format, 4);
} else if (type == 34) { } else if (type == 34) {
@ -475,7 +515,7 @@ XClient.prototype.expectReplyHeader = function()
// raw event 32-bytes packet (primarily for use in SendEvent); // raw event 32-bytes packet (primarily for use in SendEvent);
// TODO: Event::pack based on event parameters, inverse to unpackEvent // TODO: Event::pack based on event parameters, inverse to unpackEvent
ev.rawData = new Buffer(32); ev.rawData = Buffer.alloc(32);
headerBuf.copy(ev.rawData); headerBuf.copy(ev.rawData);
buf.copy(ev.rawData, 8); buf.copy(ev.rawData, 8);
@ -523,11 +563,13 @@ XClient.prototype.expectReplyHeader = function()
XClient.prototype.startHandshake = function() { XClient.prototype.startHandshake = function() {
var client = this; var client = this;
handshake.writeClientHello(this.pack_stream, this.displayNum, this.authHost); handshake.writeClientHello(this.pack_stream, this.displayNum, this.authHost, this.authFamily);
handshake.readServerHello(this.pack_stream, function(display) handshake.readServerHello(this.pack_stream, function(err, display)
{ {
// TODO: readServerHello can set error state in display if (err) {
// emit error in that case client.emit('error', err);
return;
}
client.expectReplyHeader(); client.expectReplyHeader();
client.display = display; client.display = display;
display.client = client; display.client = client;
@ -537,9 +579,24 @@ XClient.prototype.startHandshake = function() {
XClient.prototype.require = function(extName, callback) XClient.prototype.require = function(extName, callback)
{ {
var ext = require('./ext/' + extName); var self = this;
ext.requireExt(this.display, callback); var ext = this._extensions[extName];
} if (ext) {
return process.nextTick(function() {
callback(null, ext);
});
}
ext = require('./ext/' + extName);
ext.requireExt(this.display, function(err, _ext) {
if (err) {
return callback(err);
}
self._extensions[extName] = _ext;
callback(null, _ext);
});
};
module.exports.createClient = function(options, initCb) module.exports.createClient = function(options, initCb)
{ {
@ -559,8 +616,6 @@ module.exports.createClient = function(options, initCb)
throw new Error("Cannot parse display"); throw new Error("Cannot parse display");
var host = displayMatch[1]; var host = displayMatch[1];
if (!host)
host = '127.0.0.1';
var displayNum = displayMatch[2]; var displayNum = displayMatch[2];
if (!displayNum) if (!displayNum)
@ -585,10 +640,9 @@ module.exports.createClient = function(options, initCb)
{ {
socketPath = display; socketPath = display;
} }
} else if(host == '127.0.0.1') //TODO check if it's consistent with xlib (DISPLAY=127.0.0.1:0 -> local unix socket or port 6000?) } else if(!host)
socketPath = '/tmp/.X11-unix/X' + displayNum; socketPath = '/tmp/.X11-unix/X' + displayNum;
} }
//socketPath = '/tmp/.X11-unix/X' + displayNum;
var client = new XClient(displayNum, screenNum, options); var client = new XClient(displayNum, screenNum, options);
var connectStream = function() { var connectStream = function() {

View file

@ -12,7 +12,7 @@
"X" "X"
], ],
"homepage": "https://github.com/sidorares/node-x11", "homepage": "https://github.com/sidorares/node-x11",
"version": "2.0.5", "version": "2.3.0",
"maintainers": [ "maintainers": [
{ {
"name": "Andrey Sidorov", "name": "Andrey Sidorov",
@ -40,14 +40,15 @@
"node": "*" "node": "*"
}, },
"devDependencies": { "devDependencies": {
"mocha": "*", "async": "^3.0.1",
"should": "*", "mocha": "^7.1.2",
"sax": "*", "sax": "^1.2.4",
"async": "*", "should": "^13.2.1",
"sinon": "*" "sinon": "^7.2.5"
}, },
"scripts": { "scripts": {
"test": "node test-runner.js", "test": "node test-runner.js",
"prepublish": "npm prune" "prepublish": "npm prune"
} },
"dependencies": {}
} }

View file

@ -63,7 +63,7 @@ describe('Atoms and atom names cache', function() {
}); });
}); });
it('should be used after the first request for non-std atom_names', function(done) { xit('should be used after the first request for non-std atom_names', function(done) {
var self = this; var self = this;
var my_name; var my_name;
/* /*
@ -94,7 +94,7 @@ describe('Atoms and atom names cache', function() {
function(err) { function(err) {
should.not.exist(err); should.not.exist(err);
should.exist(my_name); should.exist(my_name);
self.spy.reset(); self.spy.resetHistory();
self.X.InternAtom(true, my_name, function(err, atom) { self.X.InternAtom(true, my_name, function(err, atom) {
should.not.exist(err); should.not.exist(err);
my_atom.should.equal(atom); my_atom.should.equal(atom);

34
test/cache-extensions.js Normal file
View file

@ -0,0 +1,34 @@
var x11 = require('../lib');
var should = require('should');
describe('requiring an X11 extension on same connection', function() {
before(function(done) {
var self = this;
var client = x11.createClient(function(err, dpy) {
should.not.exist(err);
self.X = dpy.client;
done();
});
client.on('error', function (err) {
console.error('Error : ', err);
});
});
it('should be cached', function(done) {
var self = this;
this.X.require('xtest', function(err, randr) {
should.not.exist(err);
self.X.require('xtest', function(err, randr1) {
should.not.exist(err);
randr.should.equal(randr1);
done();
});
});
});
after(function(done) {
this.X.terminate();
this.X.on('end', done);
});
});

View file

@ -27,7 +27,7 @@ describe('ChangeProperty', function() {
var self = this; var self = this;
this.X.InternAtom(false, TEST_PROPERTY, function(err, atom) { this.X.InternAtom(false, TEST_PROPERTY, function(err, atom) {
should.not.exist(err); should.not.exist(err);
var raw = new Buffer(4); var raw = Buffer.alloc(4);
raw.writeUInt32LE(self.wid, 0); raw.writeUInt32LE(self.wid, 0);
self.X.ChangeProperty(0, self.wid, atom, self.X.atoms.WINDOW, 32, raw); self.X.ChangeProperty(0, self.wid, atom, self.X.atoms.WINDOW, 32, raw);
self.X.once('event', function(ev) { self.X.once('event', function(ev) {
@ -47,7 +47,7 @@ describe('ChangeProperty', function() {
var self = this; var self = this;
this.X.InternAtom(false, TEST_PROPERTY, function(err, atom) { this.X.InternAtom(false, TEST_PROPERTY, function(err, atom) {
should.not.exist(err); should.not.exist(err);
var raw = new Buffer(new Array(8)); var raw = Buffer.from(new Array(8));
raw.writeUInt32LE(self.wid, 0); raw.writeUInt32LE(self.wid, 0);
raw.writeUInt32LE(self.wid_helper, 4); raw.writeUInt32LE(self.wid_helper, 4);
self.X.ChangeProperty(0, self.wid, atom, self.X.atoms.ATOM, 32, raw); self.X.ChangeProperty(0, self.wid, atom, self.X.atoms.ATOM, 32, raw);
@ -69,7 +69,7 @@ describe('ChangeProperty', function() {
var self = this; var self = this;
this.X.InternAtom(false, TEST_PROPERTY, function(err, atom) { this.X.InternAtom(false, TEST_PROPERTY, function(err, atom) {
should.not.exist(err); should.not.exist(err);
var raw = new Buffer(0); var raw = Buffer.alloc(0);
self.X.ChangeProperty(0, self.wid, atom, self.X.atoms.WINDOW, 32, raw); self.X.ChangeProperty(0, self.wid, atom, self.X.atoms.WINDOW, 32, raw);
self.X.once('event', function(ev) { self.X.once('event', function(ev) {
ev.type.should.equal(28); ev.type.should.equal(28);

54
test/changeGC.js Normal file
View file

@ -0,0 +1,54 @@
var x11 = require('../lib');
var should = require('should');
describe('CreateGC', function() {
before(function(done) {
var self = this;
this.client = x11.createClient(function(err, dpy) {
should.not.exist(err);
self.X = dpy.client;
self.root = dpy.screen[0].root;
self.white = dpy.screen[0].white_pixel;
self.black = dpy.screen[0].black_pixel;
self.wid = self.X.AllocID();
self.X.CreateWindow(self.wid, self.root, 0, 0, 1, 1); // 1x1 pixel window
self.X.MapWindow(self.wid);
self.X.QueryTree(self.root, function(err, list) {
should.not.exist(err);
list.children.indexOf(self.wid).should.not.equal(-1);
done();
});
});
});
it('should create a Graphic Context correctly', function() {
var self = this;
this.client.on('error', function(err) {
should.not.exist(err);
});
this.gc = this.X.AllocID();
this.X.CreateGC(this.gc,
this.wid,
{
foreground: this.black,
background: this.white,
lineStyle : 0
}
);
this.X.ChangeGC(this.gc,
{
foreground: 0xffff00,
background: 0x0000ff,
lineStyle : 2
}
);
});
after(function(done) {
this.X.DestroyWindow(this.wid);
this.X.on('end', done);
this.X.terminate();
});
});

114
test/client-message.js Normal file
View file

@ -0,0 +1,114 @@
var x11 = require('../lib');
var UnpackStream = require('../lib/unpackstream.js');
var should = require('should');
//Used Atoms
var ATOM = {};
describe('ClientMessage', function() {
before(function(done) {
var self = this;
var client = x11.createClient(function(err, dpy) {
should.not.exist(err);
self.X = dpy.client;
self.wid = self.X.AllocID();
self.X.CreateWindow(self.wid, dpy.screen[0].root, 0, 0, 1, 1); // 1x1 pixel window
self.X.InternAtom(false, 'TEST_ATOM_1', function(err, atom) {
should.not.exist(err);
ATOM['TEST_ATOM_1'] = atom;
done();
});
});
client.on('error', done);
});
it('should receive client message with format=8', function(done) {
var self = this;
var client = x11.createClient(function(err, dpy) {
should.not.exist(err);
self.X.once('event', function(ev) {
ev.name.should.equal('ClientMessage');
ev.wid.should.equal(self.wid);
ev.message_type.should.equal(ATOM.TEST_ATOM_1);
ev.data.should.be.an.Array();
ev.data.length.should.equal(20);
done();
});
var X = dpy.client;
var eventData = Buffer.alloc(32);
eventData.writeInt8(33, 0); //Event Type 33 = ClientMessage
eventData.writeInt8(8, 1); //Format
eventData.writeInt32LE(self.wid, 4); //Window ID
eventData.writeInt32LE(ATOM.TEST_ATOM_1, 8); //Message Type
X.SendEvent(self.wid, false, 0, eventData);
});
client.on('error', done);
});
it('should receive client message with format=16', function(done) {
var self = this;
var client = x11.createClient(function(err, dpy) {
should.not.exist(err);
self.X.once('event', function(ev) {
ev.name.should.equal('ClientMessage');
ev.wid.should.equal(self.wid);
ev.message_type.should.equal(ATOM.TEST_ATOM_1);
ev.data.should.be.an.Array();
ev.data.length.should.equal(10);
done();
});
var X = dpy.client;
var eventData = Buffer.alloc(32);
eventData.writeInt8(33, 0); //Event Type 33 = ClientMessage
eventData.writeInt8(16, 1); //Format
eventData.writeInt32LE(self.wid, 4); //Window ID
eventData.writeInt32LE(ATOM.TEST_ATOM_1, 8); //Message Type
X.SendEvent(self.wid, false, 0, eventData);
});
client.on('error', done);
});
it('should receive client message with format=32', function(done) {
var self = this;
var client = x11.createClient(function(err, dpy) {
should.not.exist(err);
self.X.once('event', function(ev) {
ev.name.should.equal('ClientMessage');
ev.wid.should.equal(self.wid);
ev.message_type.should.equal(ATOM.TEST_ATOM_1);
ev.data.should.be.an.Array();
ev.data.length.should.equal(5);
done();
});
var X = dpy.client;
var eventData = Buffer.alloc(32);
eventData.writeInt8(33, 0); //Event Type 33 = ClientMessage
eventData.writeInt8(32, 1); //Format
eventData.writeInt32LE(self.wid, 4); //Window ID
eventData.writeInt32LE(ATOM.TEST_ATOM_1, 8); //Message Type
X.SendEvent(self.wid, false, 0, eventData);
});
client.on('error', done);
});
after(function(done) {
this.X.DestroyWindow(this.wid);
this.X.on('end', done);
this.X.terminate();
});
});

View file

@ -8,43 +8,41 @@ describe('KillKlient request', function() {
var X; var X;
beforeEach(function(done) { beforeEach(function(done) {
var client = x11.createClient(function(err, dpy) { var client = x11.createClient(function(err, dpy) {
if (!err) { should.not.exist(err);
display = dpy; display = dpy;
X = display.client; X = display.client;
} var root = display.screen[0].root;
var eventMask = x11.eventMask.SubstructureNotify;
X.ChangeWindowAttributes(root, { eventMask: eventMask });
done();
});
done(err); client.on('error', done);
});
client.on('error', function(err) {
done(err);
});
}); });
afterEach(function(done) { afterEach(function(done) {
X.terminate();
X.on('end', done); X.on('end', done);
X = null; X.terminate();
display = null;
}); });
it('should exist as client member', function(done) { it('should exist as client member', function() {
should.exist(X.KillKlient); should.exist(X.KillKlient);
assert.equal(typeof X.KillKlient, 'function'); assert.equal(typeof X.KillKlient, 'function');
done();
}); });
it('should terminate other client connection', function(done) { it('should terminate other client connection', function(done) {
x11.createClient(function(err, dpy) { x11.createClient(function(err, dpy) {
if (!err) { should.not.exist(err);
var otherclient = dpy.client; var otherclient = dpy.client;
var wnd = otherclient.AllocID(); var wnd = otherclient.AllocID();
otherclient.CreateWindow(wnd, dpy.screen[0].root, 0, 0, 1, 1); X.once('event', function(ev) {
otherclient.on('end', done); ev.name.should.equal('CreateNotify');
ev.wid.should.equal(wnd);
X.KillKlient(wnd); X.KillKlient(wnd);
} else {
done(err);
}
});
}); });
otherclient.CreateWindow(wnd, dpy.screen[0].root, 0, 0, 1, 1);
otherclient.on('end', done);
});
});
}); });

View file

@ -1,4 +1,5 @@
var x11 = require('../lib'); var x11 = require('../lib');
var async = require('async');
var should = require('should'); var should = require('should');
var assert = require('assert'); var assert = require('assert');
var util = require('util'); var util = require('util');
@ -35,6 +36,26 @@ describe('RANDR extension', function() {
}); });
}); });
it('GetScreenResources && GetOutputInfo', function(done) {
var self = this;
this.randr.GetScreenResources(this.root, function(err, resources) {
should.not.exist(err);
should.exist(resources);
async.each(
resources.outputs,
function(output, cb) {
self.randr.GetOutputInfo(output, 0, function(err, info) {
should.not.exist(err);
should.exist(info);
cb();
});
},
done
);
});
});
after(function(done) { after(function(done) {
this.X.terminate(); this.X.terminate();
this.X.on('end', done); this.X.on('end', done);