Compare commits

...

298 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
Andrey Sidorov
ce238c7c0b 2.0.5 2016-01-15 16:02:20 +11:00
Andrey Sidorov
70519cbb38 handle Internet cookie addresses correctly. Fixes #121 2016-01-15 16:01:54 +11:00
Andrey Sidorov
0d7346fbac 2.0.4 2016-01-15 00:37:26 +11:00
Andrey Sidorov
7e22a439e8 don't overwrite ClientMessage type 2016-01-15 00:37:15 +11:00
Andrey Sidorov
72f79ea9f9 2.0.3 2016-01-02 13:31:52 +11:00
Andrey Sidorov
9a7adcefb1 fix Render.Triangles index bug 2016-01-02 13:31:34 +11:00
Andrey Sidorov
62c6df1c6d add link to Xplain 2015-12-16 17:02:01 +11:00
Andrey Sidorov
f1e41dab05 2.0.2 2015-12-11 15:27:44 +11:00
Andrey Sidorov
97dba66197 fix incorrect format in SetPictureTransform 2015-12-11 15:15:10 +11: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
Andrey Sidorov
6627fd5168 Merge pull request #116 from ahstro/patch-1
Missing space
2015-11-15 02:52:59 -08:00
Anton Strömkvist
7f0b054dbc Missing space
`varblack` => `var black`
2015-11-15 11:15:00 +01:00
Andrey Sidorov
0ad17ed7e4 2.0.1 2015-11-10 15:11:48 +11:00
Andrey Sidorov
abde205593 2.0.0 2015-11-10 14:58:43 +11:00
Andrey Sidorov
b39672b9d3 Merge pull request #113 from aurium/master
Enhance keySyms
2015-11-09 19:56:33 -08:00
Andrey Sidorov
84ecd7afe3 Merge pull request #115 from sidorares/render-improvements
Render improvements
2015-11-09 19:52:07 -08:00
Andrey Sidorov
b635b3209d increment seq_num before assigning callback so response mapping is correct 2015-11-08 23:59:10 +11:00
Andrey Sidorov
c473fe4f72 fix closing '})' 2015-11-08 16:57:21 +11:00
Andrey Sidorov
737ecc7b60 build: add node 0.12, 4.2 and 5.0 to matrix 2015-11-08 16:56:16 +11:00
Andrey Sidorov
4a3f3f6075 fix formatting; fix binomial filter params check; set format beforehand for SetPictureTransform 2015-11-08 16:53:24 +11:00
Andrey Sidorov
21cc95a8bb add test to verify all ext files are at least parseable 2015-11-08 16:51:34 +11:00
Andrey Sidorov
a49c9adeb3 don't increment seq_num if exception is thrown 2015-11-08 12:13:53 +11:00
Andrey Sidorov
39a9931cbf add example for AddTraps, SetPictureTransform and SetPictureFilter 2015-11-06 13:57:39 +11:00
Andrey Sidorov
fa9dbe2000 add Render.AddTraps request 2015-11-04 16:44:25 +11:00
Aurélio A. Heckert
6ad3f94b93 Lazily load keySyms 2015-11-02 15:31:38 -03:00
Aurélio A. Heckert
d8cd686ea3 Shows how to use keySyms data 2015-10-31 17:38:48 -03:00
Aurélio A. Heckert
de2b73ca2b Enhance keySyms
* Direct translate from X.Org's xproto/keysymdef.h
* Adds the key description as JSON data
* Update examples where the `x11.keySyms` API changes
2015-10-31 17:37:58 -03:00
Andrey Sidorov
f21c8d3c2a Update README.md 2015-10-26 10:21:05 +11:00
Andrey Sidorov
5c72df00e5 added PolyEdge,PolyMode,Repeat,Subpixel and Filters constants 2015-10-26 10:18:13 +11:00
Andrey Sidorov
c5fb01edaa added PictOp constant codes 2015-10-26 10:09:01 +11:00
Andrey Sidorov
63fbe2e671 add SetPictureTransform 2015-10-26 09:54:37 +11:00
Andrey Sidorov
6a69754e55 Update README.md 2015-10-26 09:33:40 +11:00
Andrey Sidorov
edd6126808 Merge pull request #112 from aurium/patch-2
Adds missed AltGr keycode
2015-10-25 14:12:07 +11:00
Aurélio A. Heckert
68e261dabe Adds missed AltGr keycode
`XK_ISO_Level3_Shift` is the code name for `AltGr`.

`NoSymbol` will help us to know when a keycode is meaningless or if it is unknown.

Also, i believe http://cgit.freedesktop.org/xorg/proto/xproto/tree/keysymdef.h is a better source to find keycodes. :-)
2015-10-24 18:07:29 -03:00
Andrey Sidorov
31785d9a5b fix Render.SetPictureFilter 2015-10-23 10:41:30 +11:00
Andrey Sidorov
51b03c5173 update callback to accept error as first parameter 2015-10-23 09:56:16 +11:00
Andrey Sidorov
71599b100f Merge pull request #104 from santigimeno/test_create_notify
src: fix CreateNotify parsing and add new test
2015-10-01 21:42:31 +10:00
Santiago Gimeno
dbe2d97bee src: fix some more events parsing
- DestroyNotify, UnmapNotify, MapNotify and MapRequest.
- Add some tests.
2015-10-01 11:53:04 +02:00
Santiago Gimeno
3b18e43fe6 src: fix CreateNotify parsing and add new test
- The first 4 fields in an event 'CCSL' are already unpacked in
  expectReplyHeader. No need to get the L field again: it is already in the
  'extra' variable.
2015-10-01 11:35:26 +02:00
Andrey Sidorov
bd991fa6e3 Merge pull request #103 from sidorares/create-notify-fix
fix CreateNotify parsing #102
2015-10-01 12:50:28 +10:00
Andrey Sidorov
28fdbadb0b fix CreateNotify parsing #102 2015-09-29 23:18:11 +10:00
Andrey Sidorov
573f83feab Merge pull request #101 from klepthys/master
included an example using node-xpm module
2015-09-22 22:50:02 +10:00
Sebastien Dumetz
91ff5d451f included an example using node-xpm module 2015-09-22 13:57:10 +02:00
Andrey Sidorov
f13a438e94 Merge pull request #95 from Arteris/tcp_fallback
Fall back to TCP if socket does not exist
2015-06-27 13:34:40 +10:00
Ian Scott
140960145b Test Travis with Xvfb doing -nolisten tcp and -nolisten unix 2015-06-26 18:19:10 -07:00
Ian Scott
c00a790c2b Fix XClient arguments 2015-06-25 15:57:20 -07:00
Ian Scott
2d7d6cbc8f Fall back to TCP if socket does not exist
Also have client emit error on stream error if there is no initCb.
2015-06-25 15:47:02 -07:00
Andrey Sidorov
fb817b8e2b add tinywm 2015-06-18 09:41:46 +10:00
Andrey Sidorov
39ec8aca60 Add xoowm and basedwm to list of users 2015-06-18 09:36:43 +10:00
Andrey Sidorov
472cdf5cfc Update README.md 2015-06-11 10:42:52 +10:00
Andrey Sidorov
90ea482119 Merge pull request #93 from megadonkey/shape
Adds Shape extension request Rectangles; fixes Mask
2015-05-30 17:10:31 +10:00
Michael J M Thomson
749b877d99 Added Shape rectangles example. Fixed shape mask test 2015-05-29 16:15:03 +10:00
Michael J M Thomson
fafa42e6e6 Add Shape Rectangles test. Fix Shape Mask test 2015-05-29 14:28:05 +10:00
Michael J M Thomson
520be559e8 Add function Rectangles. Fix function Mask 2015-05-29 11:17:34 +10:00
Andrey Sidorov
e7d9ba7cb4 Merge pull request #89 from Arteris/add_freepicture
Add FreePicture to XRender
2015-04-21 07:20:39 +10:00
Ian Scott
dc90e2760d Add FreePicture to XRender 2015-04-20 10:46:24 -07:00
Andrey Sidorov
76f148345b Update README.md 2015-03-19 23:18:58 +11:00
Andrey Sidorov
20886399ed Merge pull request #84 from dizzib/dev_clear_area
Add ClearArea method
2015-03-15 13:43:31 +11:00
Andrey Sidorov
b0a926d3de add xoowm to a list of users 2015-03-13 12:58:22 +11:00
dizzib
33f953db32 replace timeout with expose 2015-03-06 09:34:59 +00:00
dizzib
45ab095ef2 add ClearArea 2015-03-04 13:26:20 +00:00
Andrey Sidorov
28aa28eccb fix sendevent example 2015-03-01 14:54:36 +11:00
Andrey Sidorov
9b603d4375 1.0.3 2015-02-19 20:45:24 +11:00
Andrey Sidorov
a5cced0dbc start changelog 2015-02-19 20:45:06 +11:00
Andrey Sidorov
ad59dbea4b Merge pull request #82 from santigimeno/fix_randr_test
test: fix randr.js test
2015-01-21 23:39:25 +11:00
Andrey Sidorov
ac450d184a Merge pull request #81 from santigimeno/allow_events
Allow events
2015-01-21 23:38:56 +11:00
Santiago Gimeno
2e7bf6cb18 test: fix randr.js test 2015-01-21 12:41:19 +01:00
Santiago Gimeno
b27831d1d2 test: add allow-events test
- Ported from X Test Suite @ http://cgit.freedesktop.org/xorg/test/xts/
2015-01-21 12:40:31 +01:00
Santiago Gimeno
b3ca6fb04b src: add AllowEvents core request 2015-01-20 13:57:08 +01:00
Santiago Gimeno
5e14ac2301 Merge pull request #78 from Arteris/master
Remove debug messages from MappingNotify
2015-01-14 19:20:31 +01:00
Ian Scott
3e3f1805a2 Remove debug messages from MappingNotify 2015-01-14 10:08:59 -08:00
Andrey Sidorov
ef2c30793a Merge pull request #77 from santigimeno/value_mask_fixes
src: ignore invalid mask values
2015-01-09 08:53:22 +11:00
Santiago Gimeno
76ce6c4141 src: ignore invalid mask values
- Avoiding a TypeError exception @ packValueMask.
- Added a test.
2015-01-08 13:33:06 +01:00
Andrey Sidorov
ea67111025 Update README.md 2015-01-04 10:04:41 +11:00
Andrey Sidorov
5e76aafd30 Merge pull request #75 from timroes/master
Add LowerWindow method
2015-01-04 08:35:24 +11:00
Andrey Sidorov
1d9c7f2f4b Merge pull request #76 from timroes/leaveNotify
feat: fix format of LeaveNotify event
2015-01-04 08:30:53 +11:00
Tim Roes
ff73173cd5 feat: fix format of LeaveNotify event 2015-01-03 21:33:06 +01:00
Tim Roes
2f66f04d9f feat: add LowerWindow method 2015-01-03 20:41:33 +01:00
Santiago Gimeno
7351c47bc8 Version 1.0.2 2014-12-10 12:57:28 +01:00
Santiago Gimeno
8f5f6f91d2 Update maintainer list 2014-12-10 12:57:01 +01:00
Andrey Sidorov
c54f073b14 Merge pull request #74 from sidorares/fix_create_window
Fix CreateWindow and CreateGC attributes encoding
2014-12-10 09:01:57 +11:00
Santiago Gimeno
5712dfd4c9 src: maskList.sort @ packValueMask must be numeric 2014-12-09 16:15:03 +01:00
Santiago Gimeno
ca5bcb7df4 test: clean configure-request test 2014-12-09 10:34:49 +01:00
Santiago Gimeno
28e9343487 src: fix CreateGC attributes encoding
- Every attribute must have 4 byte length.
- Add test.
2014-12-09 10:33:19 +01:00
Santiago Gimeno
e5be17ac46 src: fix CreateWindow attributes encoding
- Every attribute must have 4 byte length.
- Add test.
2014-12-09 10:33:19 +01:00
Andrey Sidorov
0fc0a6a411 Merge pull request #73 from sidorares/fix_configure_request
events: fix ConfigureRequest parsing
2014-12-09 20:26:49 +11:00
Santiago Gimeno
7c86cedcab events: fix ConfigureRequest parsing
- Add test that would fail without this change.
2014-12-09 10:00:17 +01:00
Andrey Sidorov
5abfc86d1c Merge pull request #72 from anko/fix-ext-tests
Fix null-reference errors from extension-tests
2014-11-04 08:30:57 +11:00
An Ko
52a8739daf Check for errors directly instead of with isError 2014-11-03 16:43:37 +01:00
An Ko
19b937094b Assign to local vars instead of globals
These were being assigned to globals for some reason.

The tests return the same results when they're local, so I'll assume
this was a typo.
2014-11-03 16:06:20 +01:00
An Ko
6d76962bb2 Correspondingly rename xtest callback param
The first parameter is the error param after all.

The test logic is unchanged.
2014-11-03 16:01:05 +01:00
An Ko
c67043f1ed Receive xrandr & dpms exts correctly in tests
This makes tests pass that were failing with null reference errors.

`XClient.require` was passing the callback function to `requireExt`,
which called it with parameters `null, ext` on success. The callback
itself seemed to assume it will get only one parameter, which is either
the extension on an error, hence why it tried to call methods on a
`null`.
2014-11-03 15:52:34 +01:00
Andrey Sidorov
def55ef359 fix example errors 2014-10-24 17:12:56 +11:00
Andrey Sidorov
e0256e4941 Merge pull request #71 from gitter-badger/gitter-badge
Add a Gitter chat badge to README.md
2014-10-09 08:46:25 +11:00
The Gitter Badger
7739cc0ddf Added Gitter badge 2014-10-08 21:36:58 +00:00
Andrey Sidorov
b89376a00e route event to parent if parent id exist 2014-10-08 20:41:45 +11:00
Andrey Sidorov
bcc4eba348 fix failing test due to window -> wid rename 2014-10-08 15:08:04 +11:00
Andrey Sidorov
74750ca95b 1.0.1 2014-10-08 14:59:32 +11:00
Andrey Sidorov
6643bd97f7 use wid instead of window for consistency 2014-10-08 14:58:47 +11:00
Andrey Sidorov
cb3cfa91eb fix in rates calculations in GetScreenInfo 2014-10-04 20:46:29 +10:00
Andrey Sidorov
3e3846d6e6 Merge pull request #70 from Champii/master
CreateCursor, valueMask and format
2014-09-24 08:46:14 +10:00
champii
47b791dc42 coding style 2014-09-23 16:31:08 +02:00
champii
6d6c8d3b9f Extensions, tests and exemples are now cps-style 2014-09-23 16:09:18 +02:00
champii
4feba92047 fixed PR 2014-09-23 15:41:37 +02:00
champii
0c95b39c28 Norme 2014-09-23 15:32:49 +02:00
champii
b69f67222b added FreeCursor call 2014-09-23 15:32:49 +02:00
champii
d46d43a22e Trying to fix tests 2014-09-23 15:32:48 +02:00
champii
48f132b3fe ConfigureWindow, CreateWindow and CreateGC now give good format size to buffer, fixed some tests 2014-09-23 15:32:48 +02:00
champii
3b6f692d54 Trying to fix PutImage BadLength 2014-09-23 15:32:48 +02:00
champii
793b551b7a fixed putImage 2014-09-23 15:32:48 +02:00
champii
21002831a0 trying to use PutImage 2014-09-23 15:32:48 +02:00
champii
2e2a87f6ff trying to use PutImage 2014-09-23 15:32:48 +02:00
champii
643c004fb5 removed log 2014-09-23 15:32:48 +02:00
champii
965b5ca997 Test 2014-09-23 15:32:48 +02:00
champii
e5e4eac0e5 Added CreateCursor Method 2014-09-23 15:32:48 +02:00
Andrey Sidorov
bcee037683 Merge pull request #61 from sidorares/render-glyphs
WIP: Render extension text related functions
2014-09-08 12:27:40 +10:00
Andrey Sidorov
91a2c4a8cc don't send undefined args for CreateWindow 2014-09-08 12:12:14 +10:00
Andrey Sidorov
c1e788b159 Merge pull request #67 from santigimeno/fix_kill
Really fix KillClient / KillKlient
2014-07-29 08:44:16 +10:00
Santiago Gimeno
db42c54427 Really fix KillClient / KillKlient 2014-07-28 19:01:12 +02:00
Andrey Sidorov
ae71050a5d Merge pull request #65 from santigimeno/fixkillklient
Fix name of KillClient request
2014-07-07 21:32:54 +10:00
Santiago Gimeno
18404d0de1 Fix name of KillClient request
- s/KillKlient/KillClient
- Keep KillClient for backwards compatibility.
2014-07-07 13:13:43 +02:00
Andrey Sidorov
421261aaac add MappingNotify event 2014-05-02 14:37:37 +10:00
Andrey Sidorov
cefaaf942f fix in changefont glyphele serialization 2014-04-04 14:23:51 +11:00
Andrey Sidorov
cd29ef9dde support 16 and 32 bit strings 2014-04-03 01:25:40 +11:00
Andrey Sidorov
88266bd3cb link to big list of request codes 2014-04-03 01:24:45 +11:00
Andrey Sidorov
17d5a7f285 delete pre-rendered font 2014-04-01 23:43:31 +11:00
Andrey Sidorov
368b88104f use text from args 2014-04-01 23:43:04 +11:00
Andrey Sidorov
8e8900f663 example deps 2014-04-01 23:42:23 +11:00
Andrey Sidorov
b9264546a9 tabs 2014-04-01 23:42:04 +11:00
Andrey Sidorov
8c81c10edc move text example to separate folder 2014-03-31 14:39:59 +11:00
Andrey Sidorov
01c607cd3e cleanups 2014-03-31 14:06:11 +11:00
Andrey Sidorov
33005e8f76 fix: signed 13 and 32 bit ints (l and s formats) 2014-03-31 14:05:51 +11:00
Andrey Sidorov
a930aa4d13 gradient example 2014-03-31 11:22:05 +11:00
Andrey Sidorov
9731bc454e use solid pixap, resize glyphs to have width multiples of 4 2014-03-31 10:53:57 +11:00
Andrey Sidorov
8cfac532ec ComositeGlyph fixes 2014-03-31 10:52:57 +11:00
Andrey Sidorov
5b4bcbbe92 add CreateSolidFill request 2014-03-29 23:52:51 +11:00
Andrey Sidorov
f0d25c325e add FreePixmap request 2014-03-29 18:46:12 +11:00
Andrey Sidorov
6b0f257581 add pre-redndered json stringified font 2014-03-28 17:46:21 +11:00
Andrey Sidorov
39afe27793 add XRender error handling 2014-03-28 17:44:27 +11:00
Andrey Sidorov
54bd06c136 fix: add length to AddGlyph 2014-03-26 11:20:34 +11:00
Andrey Sidorov
79cf131815 fix: incorrect FreeGlyphSet format 2014-03-26 09:17:38 +11:00
Andrey Sidorov
ff0a950994 CreateGlyphSet / AddGlyphs 2014-03-26 00:30:58 +11:00
Andrey Sidorov
b24f718d7d glyphs example 2014-03-26 00:29:57 +11:00
Andrey Sidorov
0d9b317ebb fix outdated code 2014-03-26 00:29:32 +11:00
Andrey Sidorov
dc1050afb4 link to a very good glx implementation 2014-03-25 22:14:26 +11:00
Andrey Sidorov
1b2c0cbfd5 add more links to X11 implementations 2014-03-25 22:13:24 +11:00
Andrey Sidorov
942f48a5e9 cleanup tabs 2014-03-25 21:31:16 +11:00
Andrey Sidorov
66e94be8de Merge pull request #60 from santigimeno/add_CreateRegionFromWindow
Add create region from window
2014-03-22 09:52:57 +11:00
Santiago Gimeno
a8a8a9f0f2 Fix typo in crtcs field 2014-03-21 16:09:24 +01:00
Santiago Gimeno
0288e45f08 Add XFixes CreateRegionFromWindow request
- And add WINDOW_REGION_KIND type.
2014-03-21 16:07:51 +01:00
Andrey Sidorov
cf5eb392d6 Merge pull request #59 from santigimeno/fix_CreateNotify
Fix create notify
2014-03-21 22:34:01 +11:00
Santiago Gimeno
4376fcac49 Fix parsing of CreateNotify event 2014-03-21 12:29:22 +01:00
Santiago Gimeno
550b2a9329 Merge branch 'master', remote branch 'upstream/master'
* upstream/master:
  Add some REGION-related XFIXES requests
  Add GetCrtcInfo and fix in GetScreenResources

* master:
2014-03-21 12:21:00 +01:00
Andrey Sidorov
140d92c339 Merge pull request #58 from santigimeno/xfixes_requests
Add some REGION-related XFIXES requests
2014-03-20 10:38:21 +11:00
Santiago Gimeno
5d49ed338c Add some REGION-related XFIXES requests
- CreateRegion, DestroyRegion, UnionRegion, TranslateRegion and FetchRegion
2014-03-19 17:01:27 +01:00
Andrey Sidorov
0e49f39d65 Merge pull request #56 from santigimeno/more_RANDR
Add GetCrtcInfo and fix in GetScreenResources
2014-03-14 08:40:56 +11:00
Santiago Gimeno
3e98160fea Add GetCrtcInfo and fix in GetScreenResources 2014-03-13 13:24:37 +01:00
Andrey Sidorov
5fbf0476e6 0.10.0 2014-03-13 00:06:12 +11:00
Andrey Sidorov
b9b8451f9b Merge pull request #54 from santigimeno/randr_requests
Add RANDR SetScreenConfig GetScreenInfo requests
2014-03-12 20:00:13 +11:00
Santiago Gimeno
7268da486f Remove unnecessary log 2014-03-11 18:02:46 +01:00
Santiago Gimeno
3d3bcfa901 Small type and style issues 2014-03-11 18:01:04 +01:00
Santiago Gimeno
b6a76b51d7 Some more test fixes
- Fix error.js test.
- Make sure test_runner exits with the correct error code.
- Comment tests not implemented in core-properties.
2014-03-11 17:57:29 +01:00
Santiago Gimeno
7d23cbfb9e Set node version in travis to 0.10
- As the tests were failing due to using setImmediate.
- Remove one log.
2014-03-11 16:26:57 +01:00
Santiago Gimeno
b95302ff1a Add basic RANDR integration test
- Some improvements in test-runner.
2014-03-11 15:59:58 +01:00
Santiago Gimeno
88ac8179c6 Add GetScreenResources request and MODEFLAG type
- Don't include the length fields in GetScreenResources and SetScreenConfig
  replies as the're redundant.
2014-03-11 10:25:21 +01:00
Santiago Gimeno
76f969e311 Add RANDR SetScreenConfig GetScreenInfo requests
- Also added ROTATION and CONFIGSTATUS types.
2014-03-10 15:42:44 +01:00
Andrey Sidorov
73dda10b1a glx error parsers #49 2014-03-08 19:05:21 +11:00
Andrey Sidorov
0113db66af unly delete seq2stack entry when in debug mode 2014-03-08 18:09:54 +11:00
Andrey Sidorov
75ad329b4f fix tests 2014-03-08 18:04:28 +11:00
Andrey Sidorov
56001da581 use property setter in debug mode to map seq num to stack trace 2014-03-08 18:04:09 +11:00
Andrey Sidorov
d436abf9b9 0.9.0 2014-03-06 22:53:21 +11:00
Andrey Sidorov
6f455fffd9 added BindTexImage / ReleaseTexImage 2014-03-06 22:52:15 +11:00
Andrey Sidorov
10b68eecad add VendorPrivate and CreatePixmap 2014-03-06 10:51:19 +11:00
Andrey Sidorov
13d3f680b9 add ProgramString and BindProgram 2014-03-06 10:50:35 +11:00
Andrey Sidorov
a9c2254aed use RenderLarge for TexImage2D 2014-03-03 11:56:33 +11:00
Andrey Sidorov
bd119318e0 RenderLarge request 2014-03-03 11:56:01 +11:00
Andrey Sidorov
ebb77199fc fix in error parsing: bad_value, min/maj opcode now calculated correctly 2014-03-03 11:55:44 +11:00
Andrey Sidorov
a5e75b4e7d remove debug 2014-03-03 11:54:49 +11:00
Andrey Sidorov
cd3753ee97 0.8.0 2014-02-18 10:34:31 +11:00
Andrey Sidorov
1545b39196 add TexImage2D and TexParameter functions 2014-02-18 10:34:00 +11:00
Andrey Sidorov
baf67a3c69 Merge branch 'master' of github.com:sidorares/node-x11 2014-02-14 16:41:33 +11:00
Andrey Sidorov
e354b8332b fix offset in GenTextures result 2014-02-14 16:40:20 +11:00
Santiago Gimeno
c37d12ba25 Version 0.7.1 2014-02-06 18:10:30 +01:00
Andrey Sidorov
17610f899d cleanup test 2014-02-03 11:31:23 +11:00
Andrey Sidorov
c192da63f2 Merge pull request #47 from santigimeno/fix_configure_notify
Fix some event names
2014-01-28 16:41:04 -08:00
Santiago Gimeno
1e36e5d426 Fix some event names
- ButtonPress, ButtonRelease, MotionNotify and EnterNotify
2014-01-28 12:14:19 +01:00
Santiago Gimeno
69825534f6 Fix ConfigureNotify event name 2014-01-28 10:59:49 +01:00
Andrey Sidorov
d4179af963 Update README.md 2013-12-16 12:03:22 +11:00
Andrey Sidorov
f7c2a77e9d Update README.md 2013-12-16 11:54:22 +11:00
Andrey Sidorov
d73ba2051c Merge pull request #45 from bitdeli-chef/master
Add a Bitdeli Badge to README
2013-12-02 21:51:27 -08:00
Bitdeli Chef
460f0a1961 Add a Bitdeli badge to README 2013-12-03 05:53:39 +00:00
Andrey Sidorov
416d91ee67 0.7.0 2013-11-26 09:13:14 +11:00
Andrey Sidorov
fab98cfb56 Merge pull request #44 from santigimeno/grab-ungrab-server
Add GrabServer and UngrabServer requests
2013-11-25 13:58:16 -08:00
Santiago Gimeno
ea5976e42d Add GrabServer and UngrabServer requests 2013-11-25 14:53:19 +01:00
Santiago Gimeno
6cfbcc5136 Version 0.6.0 2013-11-19 13:13:09 +01:00
Andrey Sidorov
e1f307a8b1 Merge pull request #43 from santigimeno/add_eventmask_to_client
Expose eventMask in X client.
2013-11-19 04:11:10 -08:00
Santiago Gimeno
ec6c56a191 Expose eventMask in X client. 2013-11-19 13:09:12 +01:00
Santiago Gimeno
a638523dd9 0.5.0 2013-11-19 09:55:41 +01:00
Andrey Sidorov
b443cadb40 Merge pull request #42 from santigimeno/add_client_message_event
Add ClientMessage event
2013-11-18 12:53:16 -08:00
Santiago Gimeno
690d24413b Add ClientMessage event 2013-11-18 17:34:27 +01:00
Andrey Sidorov
f2b6f8775b Merge pull request #39 from santigimeno/add_unmapnotify
Handle UnmapNotify event
2013-11-05 15:44:02 -08:00
Andrey Sidorov
77461403e8 Merge pull request #41 from santigimeno/improve_change_property_test
Improve change-property test (added check for PropertyNotify being sent)
2013-11-05 13:52:39 -08:00
Santiago Gimeno
53e5260c92 Improve change-property test
- So it also tests PropertyChange event notification
2013-11-05 16:02:01 +01:00
Santiago Gimeno
90148d64a8 Update DestroyNotify and MapNotify handling
- To be better aligned with the spec.
2013-11-05 10:22:26 +01:00
Santiago Gimeno
85773377e9 Handle UnmapNotify event 2013-11-05 10:21:42 +01:00
Andrey Sidorov
3746e369fa Merge pull request #40 from santigimeno/add_change_property_test
Add ChangeProperty test
2013-11-04 12:51:47 -08:00
Santiago Gimeno
d571226c0b Add ChangeProperty test 2013-11-04 16:30:43 +01:00
99 changed files with 7219 additions and 2392 deletions

4
.gitignore vendored Normal file
View file

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

View file

@ -1,7 +1,16 @@
before_script:
- "export DISPLAY=:99.0"
- "sh -e /etc/init.d/xvfb start"
- "export XAUTHORITY=/tmp/.Xauthority-Xvfb"
- "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:
- NOLISTEN=tcp DISPLAY=:99.0
# - NOLISTEN=unix DISPLAY=:99.0
# - NOLISTEN=unix DISPLAY=127.0.0.2:99.0
language: node_js
node_js:
- 0.8
- '12'
- '14'

2
Changelog.md Normal file
View file

@ -0,0 +1,2 @@
1.0.3 - 19/02/2015
- cleanup debug logs #83

160
README.md
View file

@ -1,73 +1,119 @@
# About
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.
# install
# node-x11
`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:
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.
[![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)
# 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:
var x11 = require('x11');
```js
var x11 = require('x11');
var Exposure = x11.eventMask.Exposure;
var PointerMotion = x11.eventMask.PointerMotion;
var Exposure = x11.eventMask.Exposure;
var PointerMotion = x11.eventMask.PointerMotion;
x11.createClient(function(err, display) {
if (!err) {
var X = display.client;
var root = display.screen[0].root;
var wid = X.AllocID();
X.CreateWindow(
wid, root, // new window id, parent
0, 0, 100, 100, // x, y, w, h
0, 0, 0, 0, // border, depth, class, visual
{ eventMask: Exposure|PointerMotion } // other parameters
);
X.MapWindow(wid);
var gc = X.AllocID();
X.CreateGC(gc, wid);
X.on('event', function(ev) {
if (ev.type == 12)
{
X.PolyText8(wid, gc, 50, 50, ['Hello, Node.JS!']);
}
});
X.on('error', function(e) {
console.log(e);
});
} else {
console.log(err);
}
x11.createClient(function(err, display) {
if (!err) {
var X = display.client;
var root = display.screen[0].root;
var wid = X.AllocID();
X.CreateWindow(
wid,
root, // new window id, parent
0,
0,
500,
500, // x, y, w, h
0,
0,
0,
0, // border, depth, class, visual
{ eventMask: Exposure | PointerMotion } // other parameters
);
X.MapWindow(wid);
var gc = X.AllocID();
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) {
if (ev.type == 12) {
X.PolyFillRectangle(wid, cidWhite, [0, 0, 500, 500]);
X.PolyText8(wid, cidBlack, 50, 50, ['Hello, Node.JS!']);
}
});
X.on('error', function(e) {
console.log(e);
});
} else {
console.log(err);
}
});
```
# Screenshots
## Screenshots
![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)
![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)
![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)
![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)
# Protocol documentation
## In use
- http://www.x.org/releases/X11R7.6/doc/
- 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
- [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
# Other implementations
## X11 resources/documentation:
- C: XLib - http://www.sbin.org/doc/Xlib/ http://www.tronche.com/gui/x/xlib/ http://www.x.org/docs/X11/xlib.pdf
- C: XCB - http://xcb.freedesktop.org/
- Python: http://sourceforge.net/projects/python-xlib/ ( github fork: https://github.com/Ademan/python-xlib-branch pypi: http://pypi.python.org/pypi/Python%20Xlib )
- Python/twisted: https://launchpad.net/twisted-x11
- Perl: http://search.cpan.org/~smccam/X11-Protocol-0.56/Protocol.pm
- [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)
## Other implementations
- 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
- https://github.com/GothAck/javascript-x-server
- https://github.com/ttaubert/x-server-js

View file

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

View file

@ -12,10 +12,10 @@ var ButtonRelease = x11.eventMask.ButtonRelease;
// image and coords file from http://www.patrick-wied.at/projects/heatmap-keyboard/
// TODO: add simple tool to use&tag coords in own keyboard photo
// jpeg decoder is slightly modified version of https://github.com/notmasteryet/jpgjs
var kbdImg = require('./node-jpg').readJpeg('./keyboard.jpg');
var kbdImg = require('./node-jpg').readJpeg(__dirname+'/keyboard.jpg');
var keycoords = require('./coordinates');
// from https://github.com/substack/node-keysym
// from https://github.com/substack/node-keysym
var keysyms = require('./keysyms').records;
var ks2name = {};
for (var k in keysyms)
@ -23,18 +23,18 @@ for (var k in keysyms)
var kk2name = {};
x11.createClient(function(err, display)
x11.createClient(function(err, display)
{
var X = display.client;
X.require('big-requests', function(BigReq)
var X = display.client;
X.require('big-requests', function(err, BigReq)
{
X.require('render', function(Render) {
X.require('render', function(err, Render) {
X.Render = Render;
BigReq.Enable(function(err, maxLen)
{
var min = display.min_keycode;
var max = display.max_keycode;
X.GetKeyboardMapping(min, max-min, function(err, list)
X.GetKeyboardMapping(min, max-min, function(err, list)
{
// map keycode to key name
for (var i=0; i < list.length; ++i)
@ -62,26 +62,26 @@ function main(X)
var win = X.AllocID();
X.CreateWindow(
win, root,
0, 0, kbdImg.width, kbdImg.height,
win, root,
0, 0, kbdImg.width, kbdImg.height,
0, 0, 0, 0,
{
backgroundPixel: white, eventMask: Exposure|KeyPress|ButtonPress
{
backgroundPixel: white, eventMask: Exposure|KeyPress|ButtonPress
}
);
X.MapWindow(win);
var win1 = X.AllocID();
X.CreateWindow(
win1, root,
0, 0, kbdImg.width, kbdImg.height,
win1, root,
0, 0, kbdImg.width, kbdImg.height,
0, 0, 0, 0,
{
backgroundPixel: white, eventMask: Exposure|KeyPress|ButtonPress
{
backgroundPixel: white, eventMask: Exposure|KeyPress|ButtonPress
}
);
X.MapWindow(win1);
var gc = X.AllocID();
X.CreateGC(gc, win);
@ -103,15 +103,15 @@ function main(X)
var picKbd = X.AllocID();
X.PutImage(2, pixmapKbd, gc, kbdImg.width, kbdImg.height, 0, 0, 0, 24, kbdImg.data);
Render.CreatePicture(picKbd, pixmapKbd, Render.rgb24);
var pixmapHeat = X.AllocID();
X.CreatePixmap(pixmapHeat, win, 32, kbdImg.width, kbdImg.height);
var picHeat = X.AllocID();
Render.CreatePicture(picHeat, pixmapHeat, Render.rgba32);
var picWin = X.AllocID();
Render.CreatePicture(picWin, win, Render.rgb24);
var picWin1 = X.AllocID();
Render.CreatePicture(picWin1, win1, Render.rgb24);
@ -135,12 +135,12 @@ function main(X)
mindist = dist;
}
}
Render.Composite(3, picKbd, 0, picWin, 0, 0, 0, 0, 0, 0, kbdImg.width, kbdImg.height);
Render.Composite(3, picHeatPush, 0, picWin, 0, 0, 0, 0, x -150/2, y-150/2, 150, 150);
} if (ev.type == 2) {
var name = kk2name[ev.keycode];
for (var n in name)
{
@ -152,7 +152,7 @@ function main(X)
Render.Composite(3, picHeatPush, 0, picHeat, 0, 0, 0, 0, pt[0] -150/2, pt[1]-150/2, 150, 150);
Render.Composite(3, picHeatPush, 0, picWin1, 0, 0, 0, 0, pt[0] -150/2, pt[1]-150/2, 150, 150);
break;
} else {
//console.log(name);

View file

@ -571,7 +571,7 @@ module.exports.readJpeg = function(path)
var imageData = {};
imageData.width = j.width;
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);
return imageData;
}

View file

@ -0,0 +1,69 @@
var x11 = require('..');
// The list provided by GetKeyboardMapping has sublists where each position
// represents the result for some key composition.
keyComposition = [
'Key',
'shift + Key',
'modeSwitch + Key',
'modeSwitch + shift + Key',
'altGr + Key',
'altGr + shift + Key'
]
x11.createClient(function(err, display){
if (err) throw err
var min = display.min_keycode, // TODO: explain min_keycode
max = display.max_keycode, // TODO: explain max_keycode
chr2Data = [], // allow us to find a char by the charcode
key2Data = []; // associate chars to a keycode
// The keySyms is a hash of mnemonic char names, associated to an integer
// charcode and its description.
for (codeName in x11.keySyms) {
keyData = x11.keySyms[codeName];
chr2Data[keyData.code] = { codeName: codeName, description: keyData.description };
}
var X = display.client,
wid = X.AllocID(), // Get a free integer id to a new window.
root = display.screen[0].root, // The mother window. Like your window manager.
evKeyPress = x11.eventMask.KeyPress, // Allow to filter for KeyPress events.
white = display.screen[0].white_pixel; // Will paint the window.
// Get the local key mapping to build key2Data.
X.GetKeyboardMapping(min, max-min, function(err, list) {
for (var i=0; i < list.length; ++i) {
var name = key2Data[i+min] = [];
var sublist = list[i];
for (var j=0; j < sublist.length; ++j)
name.push(chr2Data[sublist[j]]);
}
});
// Launch a window to listen by key events:
X.CreateWindow(wid, root, 0, 0, 100, 100, 0, 0, 0, 0, { backgroundPixel: white, eventMask: evKeyPress });
X.MapWindow(wid);
X.on('event', function(ev) {
if (ev.type == 2) { // filter by KeyPress. Useful if you have a more open eventMask.
var key = key2Data[ev.keycode]; // key is a list of chars related to the pressed key.
if (key) {
console.log('\n>> key pressed:', ev.keycode);
for (var i=0; i<key.length; i++) // Describe each related char
if (key[i])
console.log(
key[i].codeName, '\t', (
key[i].description ? key[i].description : 'no description'
), (
keyComposition[i] ? '\t' + keyComposition[i] : ''
)
);
}
else
console.log('>> keyCode '+ ev.keycode +' was not recognized.');
}
});
});

View file

@ -294,7 +294,7 @@ x11.createClient(function(error, display) {
var root = display.screen[0].root;
var width = 500;
var height = 500;
X.require('glx', function(GLX) {
X.require('glx', function(err, GLX) {
var depth = 24;
findBestVisual(display, function(err, visual) {

View file

@ -13,7 +13,7 @@ var listId = 1;
x11.createClient(function(err, display) {
var X = display.client;
var root = display.screen[0].root;
X.require('glx', function(GLX) {
X.require('glx', function(err, GLX) {
var visual = 0;
var visuals = display.screen[0].depths[24];
for (visual in visuals) {

View file

@ -304,7 +304,7 @@ x11.createClient(function(err, display) {
var root = display.screen[0].root;
var width = 1000;
var height = 1000;
X.require('glx', function(GLX) {
X.require('glx', function(err, GLX) {
var visual = 0xa1;
var win = X.AllocID();
X.CreateWindow(win, root, 0, 0, width, height, 0, 0, 0, 0, { eventMask: eventmask });

View file

@ -8,7 +8,7 @@ for(var i=0; i < 20000; ++i) {
var xclient = x11.createClient(function(err, display) {
var X = display.client;
var root = display.screen[0].root;
X.require('glx', function(GLX) {
X.require('glx', function(err, GLX) {
var screen = 0;
var isDirect = 0;
var ctx = X.AllocID();

View file

@ -10,10 +10,10 @@ var gradNo = 0;
var xclient = x11.createClient(function(err, display) {
X = display.client;
var root = display.screen[0].root;
X.require('render', function(rendExt) {
X.require('render', function(err, rendExt) {
Render = rendExt;
var wid = X.AllocID();
var white = display.screen[0].white_pixel;
var black = display.screen[0].black_pixel;
X.CreateWindow(wid, root, 10, 10, 400, 300, 0, 0, 0, 0, { backgroundPixel: white, eventMask: PointerMotion|ButtonPress|ButtonRelease });
@ -36,8 +36,8 @@ var xclient = x11.createClient(function(err, display) {
function draw(x, y) {
Render.Composite(3, pictGrad[gradNo], 0, pict, 0, 0, 0, 0, x-50, y-50, 100, 100);
}
}
X.on('event', function(ev) {
if (ev.type == 4 && ev.keycode == 1)
pressed = true;
@ -45,14 +45,14 @@ var xclient = x11.createClient(function(err, display) {
pressed = false;
else if (ev.type == 5 && ev.keycode == 4)
{
gradNo--;
gradNo--;
if (gradNo < 0)
gradNo = 0;
console.log(gradNo);
}
else if (ev.type == 5 && ev.keycode == 5)
{
gradNo++;
gradNo++;
if (gradNo > 9)
gradNo = 9;
console.log(gradNo);

View file

@ -874,7 +874,7 @@ module.exports.readPng = function(path)
var imageData = {};
imageData.width = j.width;
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);
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

View file

@ -1,94 +1,47 @@
//var logo = require('./node-png').readPng('./node-logo.png');
var logo = require('./node-png').readPng('./node-logo.png');
var x11 = require('../../lib');
var Exposure = x11.eventMask.Exposure;
var KeyPress = x11.eventMask.KeyPress;
var KeyRelease = x11.eventMask.KeyRelease;
var ButtonPress = x11.eventMask.ButtonPress;
var ButtonRelease = x11.eventMask.ButtonRelease;
var PointerMotion = x11.eventMask.PointerMotion;
var interv = 0;
var total_frames = 0;
var last_frames = 0;
x11.createClient(function(err, display)
{
console.log('111111');
var X = display.client;
X.require('big-requests', function(BigReq)
{
X.require('render', function(Render) {
X.Render = Render;
BigReq.Enable(function(err, maxLen)
{
console.log('222222');
var root = display.screen[0].root;
var white = display.screen[0].white_pixel;
var black = display.screen[0].black_pixel;
var win, picWin, piclogoi, pic;
function showpic(path)
{
console.log(path);
pic = require('./node-png').readPng(path);
/*
var d = pic.data; var l = pic.data.length;
for (var p=0; p < l; p+=4)
{
b = d[p];
d[p] = d[p+2];
d[p+2] = b;
}
*/
console.log(pic);
win = X.AllocID();
X.CreateWindow(
win, root,
0, 0, pic.width, pic.height,
0, 0, 0, 0,
{
backgroundPixel: white, eventMask: Exposure|KeyPress|ButtonPress|PointerMotion
}
);
X.MapWindow(win);
X.gc = X.AllocID();
X.CreateGC(X.gc, win);
//X.PutImage(2, win, X.gc, pic.width, pic.height, 0, 0, 0, 24, pic.data);
//piclogo = X.AllocID();
//Render.CreatePicture(piclogo, pixmaplogo, Render.rgb24);
//picWin = X.AllocID();
//Render.CreatePicture(picWin, win, Render.rgb24);
}
showpic(process.argv[2]);
X.on('event', function(ev) {
if (ev.type == 12) // expose
{
X.PutImage(2, win, X.gc, pic.width, pic.height, 0, 0, 0, 24, pic.data);
//Render.Composite(3, piclogo, 0, picWin, 0, 0, 0, 0, 0, 0, logo.width, logo.height);
}
var X = display.client;
X.require('render', function(err, Render) {
var root = display.screen[0].root;
main(root, X, Render);
});
});
X.on('error', function(err) {
console.log(err);
});
});
});
});
});
function main(root, X, Render) {
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);
// TODO: add proper png pixel conversion here
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);
});
}

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);
}
});
}

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

@ -8,16 +8,16 @@ x11.createClient(function(err, display) {
var id = wid ? wid : root;
var gc = X.AllocID();
X.CreateGC(gc, id);
X.CreateGC(gc, id);
var width = 0;
var hwight = 0;
X.GetGeometry(id, function(clientGeom) {
X.GetGeometry(id, function(err, clientGeom) {
width = clientGeom.width;
height = clientGeom.height;
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.CopyArea(idScreenshot, dispwin, gc, 0, 0, 0, 0, width, height);
@ -25,21 +25,21 @@ x11.createClient(function(err, display) {
//var idScreenshot = X.AllocID();
//X.CreatePixmap(idScreenshot, root, 24, clientGeom.width, clientGeom.height);
// ask recursively each window to copy itself to pixmap
function drawWithKids(list, cb)
{
if (list.length == 0)
return cb();
return cb();
var p = list.pop();
var win = p.win;
if (win == dispwin)
return drawWithKids(list, cb);
X.GetWindowAttributes(win, function(res) {
X.GetWindowAttributes(win, function(err, res) {
if (res[8] == 0)
return drawWithKids(list, cb);
X.GetGeometry(win, function(geom) {
// (srcDrawable, dstDrawable, gc, srcX, srcY, dstX, dstY, width, height)
return drawWithKids(list, cb);
X.GetGeometry(win, function(err, geom) {
// (srcDrawable, dstDrawable, gc, srcX, srcY, dstX, dstY, width, height)
if (win != root)
X.CopyArea(win, dispwin, gc, 0, 0, p.x + geom.xPos, p.y + geom.yPos, geom.width, geom.height);
//X.CopyArea(win, idScreenshot, gc, 0, 0, p.x + geom.xPos, p.y + geom.yPos, geom.width, geom.height);
@ -63,15 +63,19 @@ x11.createClient(function(err, display) {
// console.log(data);
//});
console.log('DONE! ready');
X.terminate();
X.terminate();
//var dispwin = X.AllocID();
//X.CreateWindow(dispwin, root, 0, 0, width, height, 1, 1, 0, { eventMask: x11.eventMask.Exposure });
//X.MapWindow(dispwin);
//X.CopyArea(idScreenshot, dispwin, gc, 0, 0, 0, 0, width, height);
});
*/
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);
// format, drawable, gc, width, height, dstX, dstY, leftPad, depth, 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

@ -9,21 +9,21 @@ var x11 = require('../../lib');
x11.createClient(
function(err, display) {
var X = display.client;
X.require('render', function(Render) {
X.require('render', function(err, Render) {
var root = display.screen[0].root;
var win = X.AllocID();
var white = display.screen[0].white_pixel;
var black = display.screen[0].black_pixel;
X.CreateWindow(win, root, 0, 0, 500, 500, 0, 0, 0, 0,
{
backgroundPixel: white,
X.CreateWindow(win, root, 0, 0, 500, 500, 0, 0, 0, 0,
{
backgroundPixel: white,
eventMask: x11.eventMask.Exposure | x11.eventMask.ButtonPress | x11.eventMask.PointerMotion
});
X.MapWindow(win);
var picture = X.AllocID();
Render.CreatePicture(picture, win, Render.rgb24, { polyEdge: 1, polyMode: 0 } );
Render.CreatePicture(picture, win, Render.rgb24, { polyEdge: 1, polyMode: 0 } );
var pixmap = X.AllocID();
X.CreatePixmap(pixmap, win, 32, 2500, 2500);
var pix_pict = X.AllocID();
@ -34,30 +34,30 @@ x11.createClient(
//RenderRadialGradient(pic_grad, [0,0], [1000,100], 10, 1000,
//RenderConicalGradient(pic_grad, [250,250], 360,
[
[0, [0,0,0,0x3000 ] ],
[0.1, [0xfff, 0, 0xffff, 0x1000] ] ,
[0.25, [0xffff, 0, 0xfff, 0x3000] ] ,
[0.5, [0xffff, 0, 0xffff, 0x4000] ] ,
[1, [0xffff, 0xffff, 0, 0x8000] ]
[0, [0,0,0,0x3000 ] ],
[0.1, [0xfff, 0, 0xffff, 0x1000] ] ,
[0.25, [0xffff, 0, 0xfff, 0x3000] ] ,
[0.5, [0xffff, 0, 0xffff, 0x4000] ] ,
[1, [0xffff, 0xffff, 0, 0x8000] ]
]);
var pic_grad1 = X.AllocID();
Render.ConicalGradient(pic_grad1, [250,250], 10,
[
[0, [0,0,0,0x5000 ] ],
[0.1, [0xfff, 0, 0xffff, 0x3000] ] ,
[0.25, [0xffff, 0, 0xfff, 0x2000] ] ,
[0.5, [0xffff, 0, 0xffff, 0x1000] ] ,
[1, [0xffff, 0xffff, 0, 0x8000] ]
[0, [0,0,0,0x5000 ] ],
[0.1, [0xfff, 0, 0xffff, 0x3000] ] ,
[0.25, [0xffff, 0, 0xfff, 0x2000] ] ,
[0.5, [0xffff, 0, 0xffff, 0x1000] ] ,
[1, [0xffff, 0xffff, 0, 0x8000] ]
]);
var pic_grad2 = X.AllocID();
Render.RadialGradient(pic_grad2, [250,250], [250,250], 0, 250,
[
[0, [0,0,0,0x5000 ] ],
[0, [0,0,0,0x5000 ] ],
[0.99, [0xffff, 0xffff, 0, 0xffff] ],
[1, [0xffff, 0xffff, 0, 0x0] ]
[1, [0xffff, 0xffff, 0, 0x0] ]
]);
var pixmap1 = X.AllocID();
@ -112,7 +112,7 @@ x11.createClient(
draw();
} else {
draw();
}
}
});
});
}

View file

@ -4,10 +4,10 @@ var PointerMotion = x11.eventMask.PointerMotion;
var xclient = x11.createClient(function(err, display) {
var X = display.client;
var root = display.screen[0].root;
display.client.require('render', function(Render) {
display.client.require('render', function(err, Render) {
var wid = X.AllocID();
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.MapWindow(wid);
@ -24,8 +24,8 @@ var xclient = x11.createClient(function(err, display) {
function draw(x, y) {
Render.Composite(3, pictGrad, 0, pict, 0, 0, 0, 0, x-26, y-26, 52, 52);
}
}
X.on('event', function(ev) {
draw(ev.x, ev.y);
});

View file

@ -0,0 +1,14 @@
{
"name": "text",
"version": "0.0.0",
"description": "ERROR: No README.md file found!",
"main": "render-glyph.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "BSD-2-Clause",
"dependencies": {
"freetype2_render": "~0.1.2"
}
}

View file

@ -0,0 +1,145 @@
var x11 = require('../../../lib');
var fs = require('fs');
var PointerMotion = x11.eventMask.PointerMotion;
var Exposure = x11.eventMask.Exposure;
var ft2 = require('freetype2_render');
var fontface= ft2.parse(fs.readFileSync(process.argv[2]))
//console.log(fontface.hasKerning(), process.argv[2], '\n', fontface);
//process.exit(0);
/*
fontface.available_characters.forEach(function(left) {
fontface.available_characters.forEach(function(right) {
var kern = fontface.kerning(left, right, 50, 0, 96, 0);
if (kern.x != 0 || kern.y != 0)
console.log(left, right, kern);
});
});
*/
//console.log(fontface.kerning('A'.charCodeAt(0), 'V'.charCodeAt(0), 50, 0, 96, 0))
function padWidth(buf, width) {
var height = buf.length / width;
if (width %4 === 0)
return buf;
else {
var stride = (width+3)&~3;
var res = Buffer.alloc(height*stride);
res.fill(0);
for (var y=0; y < height; ++y) {
// memcpy(tmpbitmap+y*stride, bitmap->buffer+y*ginfo.width, ginfo.width);
buf.copy(res, y*stride, y*width, y*width + width);
}
return res;
}
}
var xclient = x11.createClient({ debug: true }, function(err, display) {
var X = display.client;
var root = display.screen[0].root;
display.client.require('render', function(err, Render) {
var wid = X.AllocID();
var white = display.screen[0].white_pixel;
var black = display.screen[0].black_pixel;
X.CreateWindow(wid, root, 10, 10, 400, 300, 0, 0, 0, 0, { backgroundPixel: white, eventMask: Exposure|PointerMotion });
X.MapWindow(wid);
var glyphSet = X.AllocID();
Render.CreateGlyphSet(glyphSet, Render.a8);
var pict = X.AllocID();
Render.CreatePicture(pict, wid, Render.rgb24);
var pix = X.AllocID();
X.CreatePixmap(pix, root, 32, 1, 1);
var pictSolidPix = X.AllocID();
Render.CreatePicture(pictSolidPix, pix, Render.rgba32, {repeat: 1});
Render.FillRectangles(1, pictSolidPix, [0x0, 0x0, 0x0, 0xffff], [0, 0, 100, 100]);
//X.FreePixmap(pix);
var pictGrad = X.AllocID();
Render.RadialGradient(pictGrad, [260,260], [260,260], 0, 260,
[
[0, [0x0000, 0x0, 0, 0xffff ] ],
[0.3, [0xffff, 0x0, 0, 0xffff ] ],
[0.997, [0xffff, 0xf, 0, 0x1] ],
[1, [0x0000, 0x0, 0, 0xffff ] ],
]
);
var pictLinearGrad = X.AllocID();
Render.LinearGradient(pictLinearGrad, [0,0], [1000,100],
[
[0, [0,0,0,0xffff ] ],
// [0.1, [0xfff, 0, 0xffff, 0x1000] ] ,
// [0.25, [0xffff, 0, 0xfff, 0x3000] ] ,
// [0.5, [0xffff, 0, 0xffff, 0x4000] ] ,
[1, [0xffff, 0xffff, 0, 0xffff] ]
]);
var size = parseInt(process.argv[3]*64);
console.log(fontface.available_characters.length);
var glyphs = fontface.available_characters.map(function(ch) { return fontface.render(ch, size, 0, 96, 0); });
var glyphFromCode = [];
glyphs.forEach(function(g) {
if (!g.image || (g.image.length == 0)) {
g.image = Buffer.alloc(64);
g.image.fill(0);
g.width = 8;
g.height = 8;
g.x = 0;
g.y = 0;
}
else {
g.origWidth = g.width;
g.image = padWidth(g.image, g.width);
g.width = g.image.length / g.height;
}
glyphFromCode[g.id] = g;
});
Render.AddGlyphs(glyphSet, glyphs);
var text = process.argv[4];
var elems = [];
var pos = 0;
var start = 0;
var offX = 0;
while (pos + 1 < text.length) {
var kern = fontface.kerning(text.charCodeAt(pos), text.charCodeAt(pos+1), size, 0, 96, 0);
console.log(kern, text[pos], text[pos+1]);
if (kern.x) {
elems.push([offX, 0, text.slice(start, pos+1)]);
start = pos+1;
offX = Math.round(size*kern.x/(26.6*64*64));
}
pos++;
}
elems.push([offX, 0, text.slice(start, text.length)]);
elems[0][1] = 60;
console.log(elems);
function draw(x, y) {
if (!y)
y = 0;
if (!x)
x = 0;
// TODO: example with multiple glyphsets in one CompositeGlyphs call
Render.FillRectangles(1, pict, [0xffff, 0xffff, 0xffff, 0xffff], [0, 0, 3000, 3000]);
//Render.Composite(3, pictLinearGrad, 0, pict, 0, 0, 0, 0, 0, 0, 2500, 2500);
// op, src, dst, maskFormat, gsid, srcX, srcY, dstX, dstY, glyphs
//Render.CompositeGlyphs8(3, pictSolidPix, pict, 0, glyphSet, 0, 0, [[10, 60, process.argv[4]]]);
var yoff = 2*parseInt(process.argv[3]);
Render.CompositeGlyphs32(3, pictSolidPix, pict, 0, glyphSet, 260-x, yoff+260-y, elems);
Render.CompositeGlyphs32(3, pictSolidPix, pict, 0, glyphSet, 260-x, yoff+260-y, [[0, 140, text]]);
}
X.on('event', function(ev) {
draw(ev.x, ev.y);
});
});
});

View file

@ -3,18 +3,18 @@ var x11 = require('../../lib');
x11.createClient(function(err, display) {
var X = display.client;
var root = display.screen[0].root;
X.require('apple-wm', function(AppleWM) {
X.require('apple-wm', function(err, AppleWM) {
//AppleWM.SetFrontProcess();
//AppleWM.CanQuit(true);
//AppleWM.CanQuit(true);
AppleWM.SelectInput(AppleWM.NotifyMask.All)
/*
for (level in AppleWM.WindowLevel)
{
var win = X.AllocID();
X.CreateWindow(win, root, 0, 0, 300, 300);
X.MapWindow(win);
X.ChangeProperty(0, win, X.atoms.WM_NAME, X.atoms.STRING, 8, level);
X.ChangeProperty(0, win, X.atoms.WM_NAME, X.atoms.STRING, 8, level);
AppleWM.SetWindowLevel(win, AppleWM.WindowLevel[level]);
};
*/
@ -22,7 +22,7 @@ x11.createClient(function(err, display) {
var win1 = X.AllocID();
X.CreateWindow(win1, root, 0, 0, 300, 300);
X.MapWindow(win1);
X.ChangeProperty(0, win1, X.atoms.WM_NAME, X.atoms.STRING, 8, "parent");
X.ChangeProperty(0, win1, X.atoms.WM_NAME, X.atoms.STRING, 8, "parent");
var win2 = X.AllocID();
X.CreateWindow(win2, root, 0, 0, 200, 200);
X.MapWindow(win2);
@ -37,12 +37,12 @@ x11.createClient(function(err, display) {
// (screen, window, frameClass, attr, ix, iy, iw, ih, ox, oy, ow, oh, titleLength)
var gc = X.AllocID();
X.CreateGC(gc, win);
function r(v) { var res = parseInt(Math.random()*v); console.log(res); return res;}
function r(v) { var res = parseInt(Math.random()*v); console.log(res); return res;}
function df() { X.PolyFillRectangle(win, gc, [0, 0, 1000, 1000]); AppleWM.FrameDraw(0, win, 65535, r(65535), 30, 30, 500, 50, 0, 0, 550, 100, "title title");}
//setInterval(df, 100);
X.on('event', function(ev) { console.log("Event", ev); df(); });
});
X.on('error', function(err) { console.log("Error", err); });
});

View file

@ -0,0 +1,51 @@
// the code is taken from https://github.com/mattlockyer/iat455/blob/6493c882f1956703133c1bffa1d7ee9a83741cbe/assignment1/assignment/effects/blur-effect-dyn.js
// (c) Matt Lockyer, https://github.com/mattlockyer
function hypotenuse(x1, y1, x2, y2) {
var xSquare = Math.pow(x1 - x2, 2);
var ySquare = Math.pow(y1 - y2, 2);
return Math.sqrt(xSquare + ySquare);
}
/*
* Generates a kernel used for the gaussian blur effect.
*
* @param dimension is an odd integer
* @param sigma is the standard deviation used for our gaussian function.
*
* @returns an array with dimension^2 number of numbers, all less than or equal
* to 1. Represents our gaussian blur kernel.
*/
function generateGaussianKernel(dimension, sigma) {
if (!(dimension % 2) || Math.floor(dimension) !== dimension || dimension<3) {
throw new Error(
'The dimension must be an odd integer greater than or equal to 3'
);
}
var kernel = [];
var twoSigmaSquare = 2 * sigma * sigma;
var centre = (dimension - 1) / 2;
for (var i = 0; i < dimension; i++) {
for (var j = 0; j < dimension; j++) {
var distance = hypotenuse(i, j, centre, centre);
// The following is an algorithm that came from the gaussian blur
// wikipedia page [1].
//
// http://en.wikipedia.org/w/index.php?title=Gaussian_blur&oldid=608793634#Mechanics
var gaussian = (1 / Math.sqrt(
Math.PI * twoSigmaSquare
)) * Math.exp((-1) * (Math.pow(distance, 2) / twoSigmaSquare));
kernel.push(gaussian);
}
}
// Returns the unit vector of the kernel array.
var sum = kernel.reduce(function (c, p) { return c + p; });
return kernel.map(function (e) { return e / sum; });
}
module.exports = generateGaussianKernel;

View file

@ -6,7 +6,7 @@ var Pixmap = require('./pixmap').Pixmap;
var Buffer = require('buffer').Buffer;
require('../../lib/unpackbuffer').addUnpack(Buffer);
var reversed = new Buffer(256);
var reversed = Buffer.alloc(256);
for (var i=0; i < 256; ++i)
{
var res = 0;
@ -42,4 +42,4 @@ module.exports.decodeBuffer = function(buffer)
data[i] = 255 - reversed[data[i]];
return new Pixmap(header.bpp, header.width, header.height, data);
}
}

View file

@ -0,0 +1,15 @@
var x11 = require('../../lib');
var Window = require('./wndwrap');
x11.createClient(function(err, display) {
var X = display.client;
var w = new Window(X, 0, 0, 700, 500);
w.map();
w.on('expose', function() {
var gc = X.AllocID();
X.CreateGC(gc, w.id, { foreground: w.black, background: w.white });
X.PolyFillRectangle(w.id, gc, [50, 50, 600, 400]);
X.ClearArea(w.id, 0, 0, 300, 300, 0);
});
});

View file

@ -3,8 +3,8 @@ var x11 = require('../../lib');
x11.createClient(function(err, display) {
var X = display.client;
var root = display.screen[0].root;
X.require('composite', function(Composite) {
X.require('damage', function(Damage) {
X.require('composite', function(err, Composite) {
X.require('damage', function(err, Damage) {
var wid = parseInt(process.argv[2]);
//Composite.GetOverlayWindow(wid, function(err, overlayid) {
// console.log("OVERLAY:", err, overlayid);

View file

@ -3,7 +3,7 @@ var x11 = require('../../lib');
x11.createClient(function(err, display) {
var X = display.client;
var root = display.screen[0].root;
X.require('damage', function(Damage) {
X.require('damage', function(err, Damage) {
console.log(Damage);
var id = parseInt(process.argv[2]);
var damage = X.AllocID();
@ -14,5 +14,5 @@ x11.createClient(function(err, display) {
});
});
X.on('error', function(err) { console.log(err); });
});

View file

@ -3,7 +3,7 @@ var x11 = require('../../lib');
x11.createClient(function(err, display) {
var X = display.client;
var root = display.screen[0].root;
X.require('fixes', function(Fixes) {
X.require('fixes', function(err, Fixes) {
console.log(Fixes);
var win = X.AllocID();
X.CreateWindow(win, root, 0, 0, 100, 100);

View file

@ -1,9 +1,11 @@
var x11 = require('../../lib');
var x11 = require('../../../lib');
var keysym = require('keysym');
var ks = x11.keySyms;
var ks2Name = {};
for (var key in ks)
ks2Name[ ks[key] ] = key;
ks2Name[ ks[key].code ] = key;
var kk2Name = {};
x11.createClient(function(err, display) {
@ -16,7 +18,7 @@ x11.createClient(function(err, display) {
var name = kk2Name[i+min] = [];
var sublist = list[i];
for (var j =0; j < sublist.length; ++j)
name.push(ks2Name[sublist[j]]);
name.push([ks2Name[sublist[j]], sublist[j]]);
}
var root = display.screen[0].root;
@ -27,7 +29,19 @@ x11.createClient(function(err, display) {
X.MapWindow(wid);
X.on('event', function(ev) {
console.log([ev.keycode, kk2Name[ev.keycode]]);
console.log(ev.type);
console.log(ev);
//console.log([ev.keycode, kk2Name[ev.keycode], keysym.fromKeysym(kk2Name[ev.keycode][0][1])]);
var shift = ev.buttons & 1;
var keySyms = kk2Name[ev.keycode];
if (keySyms) {
var codePoint = keysym.fromKeysym(keySyms[shift ? 1 : 0][1]).unicode;
if (codePoint == 13)
codePoint = 10;
if (codePoint != 0)
process.stdout.write(String.fromCharCode(codePoint));
//console.log('\n', codePoint);
}
});
});
});

View file

@ -0,0 +1,11 @@
{
"name": "keyboard",
"version": "0.0.0",
"description": "",
"main": "getkeyboardmapping.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}

View file

@ -8,7 +8,7 @@ var xclient = x11.createClient();
var Exposure = x11.eventMask.Exposure;
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)
{
bitmap[i] = i % 256;

View file

@ -1,11 +1,10 @@
var Buffer = require('buffer').Buffer;
var x11 = require('../../lib');
var xclient = x11.createClient();
var Exposure = x11.eventMask.Exposure;
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)
{
var byteNum = i%4;
@ -17,17 +16,14 @@ for (var i=0; i < bitmap.length; ++i)
bitmap[i] = parseInt((i/256)%256);
if (byteNum == 2)
bitmap[i] = parseInt((i/1024)%256);
}
xclient.on('connect', function(err, display) {
x11.createClient(function(err, display) {
if (err) throw err;
var X = display.client;
X.require('big-requests', function(BigReq) {
BigReq.Enable(function(maxLen) { console.log( maxLen ); });
X.require('render', function(Render) {
var X = display.client;
X.require('render', function(err, Render) {
var root = display.screen[0].root;
var white = display.screen[0].white_pixel;
@ -36,23 +32,23 @@ X.require('render', function(Render) {
var wid = X.AllocID();
X.CreateWindow(
wid, root,
10, 10, 400, 300,
wid, root,
10, 10, 400, 300,
1, 1, 0,
{
backgroundPixel: white, eventMask: Exposure|PointerMotion
{
backgroundPixel: white, eventMask: Exposure|PointerMotion
}
);
X.MapWindow(wid);
var gc = X.AllocID();
X.CreateGC(gc, wid, { foreground: black, background: white } );
var pixmap1 = X.AllocID();
X.CreatePixmap(pixmap1, wid, 32, 128, 128);
var pic = X.AllocID();
var pic = X.AllocID();
Render.CreatePicture(pic, pixmap1, Render.rgba32);
var pic1 = X.AllocID();
Render.CreatePicture(pic1, wid, Render.rgb24);
@ -64,7 +60,7 @@ X.require('render', function(Render) {
X.PutImage(2, pixmap1, gc, 128, 128, 0, 0, 0, 32, bitmap);
//Render.Composite(3, pic1, 0, pic, 0, 0, 0, 0, 30, 40, 128, 128);
}
}
});
X.on('error', function(e) {
console.log(e);
@ -72,5 +68,4 @@ X.require('render', function(Render) {
});
});
});

View file

@ -3,7 +3,7 @@ var x11 = require('../../lib');
x11.createClient(function(err, display) {
var X = display.client;
var root = display.screen[0].root;
X.require('randr', function(Randr) {
X.require('randr', function(err, Randr) {
//console.log(Randr);
//Randr.QueryVersion(1, 4, console.log);
Randr.SelectInput(root, Randr.NotifyMask.ScreenChange);

View file

@ -1,11 +1,11 @@
var x11 = require('../../lib');
var xclient = x11.createClient();
var xclient = x11.createClient({debug: true});
var Exposure = x11.eventMask.Exposure;
var PointerMotion = x11.eventMask.PointerMotion;
var pts = [];
xclient.on('connect', function(err, display) {
xclient.on('connect', function(display) {
var X = this;
var root = display.screen[0].root;
var white = display.screen[0].white_pixel;
@ -13,18 +13,16 @@ xclient.on('connect', function(err, display) {
function createWindow()
{
var wid = X.AllocID();
X.CreateWindow(
wid, root,
10, 10, 400, 300,
1, 1, 0,
{
backgroundPixel: white, eventMask: Exposure|PointerMotion
}
);
X.MapWindow(wid);
return wid;
var wid = X.AllocID();
// id, parentId, x, y, width, height, borderWidth, depth, _class, visual, values
X.CreateWindow(
wid, root,
10, 10, 400, 300,
0, 0, 0, 0, {
backgroundPixel: white, eventMask: Exposure|PointerMotion
});
X.MapWindow(wid);
return wid;
}
var wid = createWindow();
@ -59,7 +57,7 @@ xclient.on('connect', function(err, display) {
}
});
X.on('error', function(e) {
console.log(e);
});
//X.on('error', function(e) {
// console.log(e);
//});
});

View file

@ -0,0 +1,22 @@
var x11 = require('../../lib');
var Expose = 12;
x11.createClient(function(err, display) {
var X = display.client;
var root = display.screen[0].root;
X.require('shape', function(err, Shape) {
var win = X.AllocID();
X.CreateWindow(win, root, 0, 0, 200, 200);
X.ChangeWindowAttributes(win, { backgroundPixel: display.screen[0].black_pixel });
X.MapWindow(win);
Shape.Rectangles(Shape.Op.Set, Shape.Kind.Bounding, win, 0, 0, [
[40, 40, 40, 40], [120, 40, 40, 40],
[0, 120, 20, 20], [180, 120, 20, 20],
[20, 140, 30, 20], [150, 140, 30, 20],
[50, 160, 100, 20]
]);
});
X.on('error', function(err) { console.log(err); });
});

View file

@ -3,25 +3,30 @@ var x11 = require('../../lib');
x11.createClient(function(err, display) {
var X = display.client;
var root = display.screen[0].root;
X.require('shape', function(Shape) {
X.require('shape', function(err, Shape) {
var win = X.AllocID();
X.CreateWindow(win, root, 0, 0, 200, 200);
var gc = X.AllocID();
X.CreateGC(gc, win);
//X.MapWindow(win);
Shape.SelectInput(win, 1);
X.ChangeWindowAttributes(win, { backgroundPixel: display.screen[0].white_pixel });
X.MapWindow(win);
X.ClearArea(win, 0, 0, 200, 200, false);
Shape.SelectInput(win, true);
Shape.InputSelected(win, function(err, isSelected) {
console.log("IsSelected: " + isSelected);
});
//var pid = X.AllocID();
//X.CreatePixmap(pid, win, 2, 200, 200);
//X.PolyText8(pid, gc, 0, 0, ['Hello, Node.JS!', ' Hello, world!']);
//Shape.Mask(Shape.Op.Set, Shape.Kind.Input, win, 0, 0, pid);
var bitmap = X.AllocID();
X.CreatePixmap(bitmap, win, 1, 200, 200);
var gc = X.AllocID();
X.CreateGC(gc, bitmap, { foreground: 1 });
// X.PolyText8(bitmap, gc, 0, 0, ['Hello, Node.JS!', ' Hello, world!']);
X.PolyFillArc(bitmap, gc, [0, 0, 200, 200, 0, 360 * 64]);
Shape.Mask(Shape.Op.Set, Shape.Kind.Bounding, win, 0, 0, bitmap);
X.on('event', function(ev) {
console.log(ev);
});
});
X.on('error', function(err) { console.log(err); });
});

View file

@ -7,7 +7,7 @@ x11.createClient(function(err, display) {
X.SetScreenSaver(20, 10, 2, 2);
X.require('screen-saver', function(SS) {
X.require('screen-saver', function(err, SS) {
SS.SelectInput(root, SS.eventMask.Notify|SS.eventMask.Cycle);
//console.log(SS);
//setTimeout(function() {
@ -15,7 +15,7 @@ x11.createClient(function(err, display) {
//}, 5000);
setInterval(function() {
SS.QueryInfo(root, function(err, info) {
console.log(info.until);
console.log(info.until);
//SS.SelectInput(root, SS.eventMask.Notify|SS.eventMask.Cycle);
});
}, 1000);
@ -24,5 +24,5 @@ x11.createClient(function(err, display) {
});
});
X.on('error', function(err) { console.log(err); });
});

View file

@ -25,18 +25,18 @@ x11.createClient(function(err, display) {
var cmid = X.AllocID();
var depth = 32;
X.CreateColormap(cmid, root, visual, 0); // 0=AllocNone, 1 AllocAll
X.CreateColormap(cmid, root, visual, 0); // 0=AllocNone, 1 AllocAll
X.CreateWindow(wid, root, 10, 10, 168, 195, 1, depth, 1, visual, { eventMask: x11.eventMask.Exposure, colormap: cmid, backgroundPixel: 0, borderPixel: 0 });
X.MapWindow(wid);
var gc = X.AllocID();
X.require('render', function(Render) {
X.require('render', function(err, Render) {
var pict = X.AllocID();
Render.CreatePicture(pict, wid, Render.rgba32);
var gradients = [];
function randomLinear() {
var stops = [];
for (var i=0; i<3; ++i)
@ -49,8 +49,8 @@ x11.createClient(function(err, display) {
parseInt(Math.random()*65535),
parseInt(Math.random()*65535),
parseInt(Math.random()*65535)]]);
console.log(colors);
console.log(colors);
var gradient = X.AllocID();
Render.LinearGradient(gradient, [0, 0], [100+parseInt(Math.random()*500), parseInt(100+Math.random()*300)], colors);
@ -64,7 +64,7 @@ x11.createClient(function(err, display) {
var gid = parseInt(Math.random()*gradients.length);
console.log(gradients[gid]);
Render.Composite(1, gradients[gid], 0, pict, 0, 0, 0, 0, 0, 0, 400, 300);
}, 2000);
}, 2000);
});
//X.CreateGC(gc, wid, { foreground: black, background: white } );
//setInterval(function() {

View file

@ -0,0 +1,125 @@
var _ = require('underscore');
var x11 = require('../../lib');
var Exposure = x11.eventMask.Exposure;
var PointerMotion = x11.eventMask.PointerMotion;
var ButtonPress = x11.eventMask.ButtonPress;
var draw;
var useConvo3 = true;
x11.createClient({ debug: true}, function(err, display) {
var X = display.client;
var root = display.screen[0].root;
var wid = X.AllocID();
X.CreateWindow(
wid, root,
0, 0, 800, 600,
0, 0, 0, 0,
{
eventMask: Exposure|PointerMotion|ButtonPress
}
);
X.MapWindow(wid);
X.require('render', function(err, Render) {
Render.QueryFilters(console.log);
var pixMask = X.AllocID();
X.CreatePixmap(pixMask, wid, 8, 600, 600);
var pictTraps = X.AllocID();
Render.CreatePicture(pictTraps, pixMask, Render.a8);
var pictWin = X.AllocID();
Render.CreatePicture(pictWin, wid, Render.rgb24);
var pictSolid = X.AllocID();
r = 0.2; g = 0.2; b = 0.2; a = 1;
Render.CreateSolidFill(pictSolid, r, g, b, a);
var pixBuff = X.AllocID();
X.CreatePixmap(pixBuff, wid, 24, 600, 600);
var pictBuff = X.AllocID();
Render.CreatePicture(pictBuff, pixBuff, Render.rgb24);
var convo5 = [ 5, 5, 0.0030, 0.0133, 0.0219, 0.0133, 0.0030,
0.0133, 0.0596, 0.0983, 0.0596, 0.0133,
0.0219, 0.0983, 0.1621, 0.0983, 0.0219,
0.0133, 0.0596, 0.0983, 0.0596, 0.0133,
0.0030, 0.0133, 0.0219, 0.0133, 0.0030];
var convo3 = [3, 3, 0.01, 0.08, 0.01, 0.08, 0.64, 0.08, 0.01, 0.08, 0.01];
var convo5 = [21, 21].concat(require('./blur-convolution')(21, 11));
//Render.SetPictureFilter(pictBuff, 'convolution', convo3);
//Render.SetPictureFilter(pictTraps, 'convolution', convo3);
//Render.SetPictureFilter(pictBuff, 'bilinear', []);
Render.SetPictureFilter(pictBuff, 'best', []);
draw1 = function(x, y) {
console.log('draw 1', x, y);
var r = 3 + 2*Math.floor(x / 100);
var convo = [r, r].concat(require('./blur-convolution')(r, r));
Render.SetPictureFilter(pictBuff, 'convolution', convo);
var a = (x-400)/500;
var m = [
Math.cos(a), Math.sin(a), 0,
-Math.sin(a), Math.cos(a), 0,
0, 0, 1
];
// Render.SetPictureTransform(pictTraps, m)
var r, g, b;
// fill window
r = 1; g = 1; b = 1; a = 0.5;
Render.FillRectangles(1, pictBuff, [r, g, b, a], [0, 0, 1000, 1000])
// fill traps
r = 0; g = 0; b = 0; a = 0;
Render.FillRectangles(1, pictTraps, [r, g, b, a], [0, 0, 1000, 1000])
Render.AddTraps(pictTraps, 0, 0, [
x, 200, y,
//150, 200, 50,
5, 250, 300,
110, 200, 310,
50, 150, 500
]);
// (op, src, mask, dst, srcX, srcY, maskX, maskY, dstX, dstY, width, height)
//Render.Composite(Render.PictOp.Over, pictSolid, pictTraps, pictWin, 0, 0, 0, 0, 0, 0, 800, 600);
//Render.PictOp.Over
Render.Composite(Render.PictOp.Over, pictSolid, pictTraps, pictBuff, 0, 0, 0, 0, 0, 0, 800, 600);
Render.Composite(Render.PictOp.Over, pictBuff, 0, pictWin, 0, 0, 0, 0, 0, 0, 800, 600);
};
draw = function(x, y) {
var f = _.debounce(function() {
draw1(x, y);
}, 100);
f();
};
});
}).on('error', function(err) {
console.log(err);
}).on('event', function(ev) {
//console.log(ev);
if (ev.name == 'MotionNotify') {
draw(ev.x, ev.y);
} else if (ev.name == 'ButtonPress') {
useConvo3 = !useConvo3;
draw(ev.x, ev.y);
//console.log(ev);
}
});

View file

@ -3,7 +3,7 @@ var x11 = require('../../lib');
x11.createClient(function(err, display) {
var X = display.client;
var root = display.screen[0].root;
X.require('xc-misc', function(Misc) {
X.require('xc-misc', function(err, Misc) {
var xid = X.AllocID();
console.log("first ID from connection: " + xid);
debugger;
@ -15,5 +15,5 @@ x11.createClient(function(err, display) {
});
});
X.on('error', function(err) { console.log("Error", err); });
});

View file

@ -3,7 +3,7 @@ var x11 = require('../../lib');
var xclient = x11.createClient(function(err, display) {
var X = display.client;
var root = display.screen[0].root;
display.client.require('xtest', function(Test) {
display.client.require('xtest', function(err, Test) {
console.log(Test);
setInterval(function() {
Test.FakeInput(Test.KeyPress, 65, 0, root, 0, 0); // space

View file

@ -25,7 +25,7 @@ var Buffer = require('buffer').Buffer;
var startpos = [4, 15];
var cupsize = [10, 20];
var cup = new Buffer(cupsize[0]*cupsize[1]);
var cup = Buffer.alloc(cupsize[0]*cupsize[1]);
var moveInterval;
function clearCup()
@ -250,7 +250,7 @@ x11.createClient(function(err, display) {
var ks = x11.keySyms;
var ks2Name = {};
for (var key in ks)
ks2Name[ ks[key] ] = key;
ks2Name[ ks[key].code ] = key;
var kk2Name = {};
var min = display.min_keycode;
var max = display.max_keycode;

View file

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

View file

@ -7,7 +7,7 @@
// It should create a pleasant looking hex dumb by default:
//
// 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))
//
@ -258,4 +258,4 @@ console.log(hexy(data, format))
console.log("doen")
*/
exports.hexy = hexy
exports.hexy = hexy

View file

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

View file

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

View file

@ -34,7 +34,7 @@ function ReadFixedRequest(length, callback)
this.length = length;
this.callback = callback;
//clog(length);
this.data = new Buffer(length);
this.data = Buffer.alloc(length);
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 arg = 0;
for (var i = 0; i < format.length; ++i)

View file

@ -30,8 +30,8 @@ var KeyPress = x11.eventMask.KeyPress;
var KeyRelease = x11.eventMask.KeyRelease;
x11.createClient(function(err, display) {
var X = display.client;
X.require('big-requests', function(BigReq) {
var X = display.client;
X.require('big-requests', function(err, BigReq) {
BigReq.Enable(function(err, maxLen) {
var keycode2keysym = [];
var min = display.min_keycode;
@ -54,19 +54,19 @@ x11.createClient(function(err, display) {
var wid = X.AllocID();
X.CreateWindow(wid, root, 0, 0, r.width, r.height);
X.ChangeWindowAttributes(wid, {
backgroundPixel: black,
eventMask: Exposure|PointerMotion|ButtonPress|ButtonRelease|KeyPress|KeyRelease
X.ChangeWindowAttributes(wid, {
backgroundPixel: black,
eventMask: Exposure|PointerMotion|ButtonPress|ButtonRelease|KeyPress|KeyRelease
});
X.ChangeProperty(0, wid, X.atoms.WM_NAME, X.atoms.STRING, 8, r.title);
X.MapWindow(wid);
var gc = X.AllocID();
X.CreateGC(gc, wid, { foreground: black, background: white } );
//var pixbuf = X.AllocID();
//X.CreatePixmap(pixbuf, wid, 32, r.width, r.height);
//var pic = X.AllocID();
//var pic = X.AllocID();
//Render.CreatePicture(pic, pixbuf, Render.rgba32);
var buttonsState = 0;
@ -86,7 +86,7 @@ x11.createClient(function(err, display) {
// set button bit
if (ev.type == 4)
buttonsState |= buttonBit;
else
else
buttonsState &= ~buttonBit;
r.pointerEvent(ev.x, ev.y, buttonsState);
} else if (ev.type == 2 || ev.type == 3) {
@ -121,7 +121,7 @@ x11.createClient(function(err, display) {
});
}); // r.on('connect)
}); // GetKeyboardMapping
}); // GetKeyboardMapping
}); // BigReq.Enable
}); // require('big-requests

View file

@ -80,7 +80,7 @@ function ManageWindow(wid)
x11.createClient(function(err, display) {
X = display.client;
X.require('render', function(Render) {
X.require('render', function(err, Render) {
X.Render = Render;
root = display.screen[0].root;

View file

@ -0,0 +1,75 @@
/* XPM */
static char * node_logo_xpm[] = {
"245 66 6 1",
" c None",
". c #FFFFFF",
"+ c #8CC84B",
"@ c #8DC84C",
"# c #89C746",
"$ c #8AC748",
" .. ",
" .... ",
" ...... ",
" ....... ",
" ......... ",
" ........... ",
" ............ ",
" ............ ",
" ............ ",
" ............ ",
" ............ ",
" ............ ",
" ............ ",
" ............ ",
" ............ ",
" ............ ",
" ............ ",
" ............ ",
" ............ ",
" ............ ",
" ............ ",
" ............ ",
" ............ ",
" ............ ++ ",
" .... ++++ .. ............ .... ++++++ .. . .",
" ........ ++++++++ ...... ............ ....... +++++++++ .. .",
" ............ ++++++++++++ ....................... ........... ++++++ ++++++ ...",
" ............... ++++++++++++++ ......................... .............. +++++++ ++++++ ",
" .................. ++++++++++++++++++ .......................... .................. ++++++ ++++++ ",
" ...................... ++++++++++++++++++++++ ............................ ..................... ++++++ ++++++ ",
" .......................... +++++++++++++++++++++++++ .............................. ......................... ++++++ ++++++ ",
" ............................. ++++++++++++++++++++++++++++ ................................ ............................ +++++++ ++++++ ",
" ................................ ++++++++++++++++++++++++++++++++ ................................. ................................ ++++++ ++++++ ",
" .................................... ++++++++++++++++++++++++++++++++++++ ................................... ................................... +++++ ++++++ ",
" .................................... ++++++++++++++++++++++++++++++++++++ .................................... ..................................... ++++ ++++ ",
" .................................... ++++++++++++++++++++++++++++++++++++ ..................................... ..................................... +++ +++ ",
" .................................... ++++++++++++++++++++++++++++++++++++ ..................................... ..................................... +++ + ++++++++ +++ ",
" .................................... ++++++++++++++++++++++++++++++++++++ ..................................... ..................................... +++ +++ ++++++++++++ +++ ",
" ................ ................ ++++++++++++++++++++++++++++++++++++ .................. ................. ................. ................. +++ +++ ++++++++++++++ +++ ",
" ............... ............... ++++++++++++++++++++++++++++++++++++ ................ ............... ................ ............... +++ +++ ++++ ++++ +++ ",
" ............. ............. ++++++++++++++++++++++++++++++++++++ ............... .............. .............. .............. +++ +++ +++ +++ +++ ",
" ............ ............ ++++++++++++++++++++++++++++++++++++ ............. ............ ............. ++@# ............ +++ +++ +++ +++ +++ ",
" ............ ............ ++++++++++++++++++++++++++++++++++++ ............. ............ ............. #@+++++ .......... +++ +++ ++++++ +++ ",
" ............ ............ ++++++++++++++++++++++++++++++++++++ ............. ............ ............. +++++++ ........ +++ +++ +++++++++++ +++ ",
" ............ ............ ++++++++++++++++++++++++++++++++++++ ............. ............ ............. +++++++ ...... +++ +++ ++++++++++++ +++ ",
" ............ ............ ++++++++++++++++++++++++++++++++++++ ............. ............ ............. +++++++ .... +++ +++ +++++++++++ +++ ",
" ............ ............ ++++++++++++++++++++++++++++++++++++ ............. ............ ............. @++++++ ... +++ +++ +++++ +++ ",
" ............ ............ ++++++++++++++++++++++++++++++++++++ ............. ............ ............. $+++ +++ +++ +++ +++ +++ ",
" ............ ............ ++++++++++++++++++++++++++++++++++++ ............. ............. .............. +++ +++ ++++ +++ +++ ",
" ............ ............ ++++++++++++++++++++++++++++++++++++ ............... .............. ............... +++ +++ ++++ ++++ +++ ",
" ............ ............ ++++++++++++++++++++++++++++++++++++ ................. ................ ................. +++ +++ ++++++++++++++ +++ ",
" ............ ............ ++++++++++++++++++++++++++++++++++++ ..................................... ................... +++ +++ +++++++++++++ +++ ",
" ............ ............ ++++++++++++++++++++++++++++++++++++ ..................................... .................... +++ +++ +++++++++ +++ ",
" ............ ............ ++++++++++++++++++++++++++++++++++++ ..................................... ...................... +++ +++ +++ ",
" ............ ............ ++++++++++++++++++++++++++++++++++++ .................................... ........................ +++++ +++ ++++ ",
" ........... ........... ++++++++++++++++++++++++++++++++++++ .................................... ......................... ++++++ ++++ +++++ ",
" ......... ......... ++++++++++++++++++++++++++++++++ .................................. ........................ ++++++++++++ ++++++ ",
" ........ ........ ++++++++++++++++++++++++++++ .............................. ......................... +++++++++ ++++++ ",
" ...... ...... ++++++++++++++++++++++++++ .......................... ........................ ++++++ ++++++ ",
" .... .... ++++++++++++++++++++++ ...................... ...................... ++++++ ",
" .. .. ++++++++++++++++++ .................... .................. ++++ ++++++ ",
" ++++++++++++++ ................ ............... ++++++ ++++++ ",
" ++++++++++++ ............ ........... ++++++++++++ ",
" ++++++++ ......... ........ +++++++++ ",
" ++++ ...... .... +++++ ",
" .. "};

151
examples/xpm/node-xpm.js Normal file
View file

@ -0,0 +1,151 @@
/* Extracted from https://github.com/klepthys/node-xpm
* This code is available as a standalone module named xpm
/*
The MIT License (MIT)
Copyright (c) 2015 Sebastien Dumetz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
var fs = require('fs');
function PixmapFromFile (path,options){
if(!options && typeof path == "object"){
this.options = path;
path = null;
}else{
this.options = options||{};
}
if(path){
return this.parse(fs.readFileSync(path, {encoding:"utf-8"}));
}
}
/**
*
* @param {[type]} data utf-8 file data
* @param {Function} callback optionnal callback.
*/
PixmapFromFile.prototype.parse = function (data) {
if(!/^\/\*\s*XPM\s*\*\/$/m.test(data)){
throw new Error("Not an XPM file");
}
var size = this.getSize(data);
var content = this.getArray(data,size);
var colors = this.mapColors(data,size);
size.data = this.toBuffer(colors,content,size);
return size;
};
PixmapFromFile.prototype.getSize = function(data){
var match = /{\n?"([0-9\s]*)\s?"/.exec(data);
if(!match){
throw new Error("can't parse size infos");
}
var values = match[1].split(" ").map(function(i){return parseInt(i)});
return {width:values[0],height:values[1],count:values[2],length:values[3]}
}
PixmapFromFile.prototype.getArray = function(data,size){
//var reg = new RegExp('"((?!(?:[0-9]+\\s?){4}).{'+size.length+'}(?!\\sc\\s).*)"',"g"); //Works also but much less simple
var reg = new RegExp('"(.{'+size.width*size.length+'})"',"g");
var res;
var rows = [];
while((res = reg.exec(data)) !== null){
rows.push(res[1]);
}
if(rows.length != size.height){
throw new Error("found : "+rows.length+" rows. Should have found :"+size.height+" rows.");
}
return rows;
}
// return RGBA color
PixmapFromFile.prototype.mapColors = function(content,size){
var reg = new RegExp('"(.' + ((size.length > 1)? "{"+(size.length)+"}" : "") + ")\\s+c\\s+#?(None|[0-9a-fA-F]{6})\"","gm");
var res;
var colors = {};
while((res = reg.exec(content)) !== null){
if(res[2] === "None"){
colors[res[1]] = "00000000"
}else{
colors[res[1]] = res[2]+"FF";//RGBA
}
}
if(Object.keys(colors).length != size.count){
throw new Error("found : "+Object.keys(colors).length+" colors. Should have found :"+size.count+" colors.");
}
return colors;
}
PixmapFromFile.prototype.toBuffer = function (colors,content,size) {
var buf = Buffer.alloc(size.width*size.height*4);
var offset = 0, byte,color;
var copy;
if( !this.options.format || this.options.format.toUpperCase() === "BGRA"){
copy = this.copyBGRABuffer;
}else if(this.options.format && this.options.format.toUpperCase() === "RGBA"){
copy = this.copyRGBABuffer;
}else{
throw new Error("invalid format option : ",this.options.format," valid values are BGRA (default) or RGBA")
}
content.forEach(function(row){
//console.log("parsing : ",row)
while(row && row.length >0){
var code = row.slice(0,size.length);
row = row.slice(size.length);
if(!colors[code]){
throw new Error("unknown color : ",code);
}
offset = copy(buf,offset,colors[code]);;
}
});
return buf;
};
/**
* Takes an array of rows. Each char/sequence represents a colored pixel
* @param {[type]} content [description]
* @return {Buffer} A 1d array of pixels in RGBA
*/
PixmapFromFile.prototype.copyBGRABuffer = function(buf, offset, color){
[4,2,0,6].forEach(function(i){
buf.writeUInt8(parseInt(color[i]+color[i+1],16),offset);
offset ++;
});
return offset;
}
PixmapFromFile.prototype.copyRGBABuffer = function(buf, offset, color){
buf.writeUInt32BE(parseInt(color,16),offset);
return offset+4;
}
PixmapFromFile.prototype.open = function(path,callback){
var self = this;
fs.readFile(path, {encoding:"utf-8"}, function(err,data){
if(err){
return callback(err);
}else{
callback(null,self.parse(data));
}
});
}
module.exports = PixmapFromFile;

53
examples/xpm/test.js Normal file
View file

@ -0,0 +1,53 @@
#!/usr/bin/env node
var x11 = require('../../lib');
var PixmapFromFile = require('./node-xpm.js');
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;
var pixmap = new PixmapFromFile();
pixmap.open("node-logo.xpm",function(err,logo){
if(err){
console.log(new Error().stack);
return console.error("pixmap open Error : ",err);
}
main(root, X, Render,logo);
});
});
});
function main(root, X, Render, logo) {
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);
// TODO: add proper png pixel conversion here
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);
});
}

View file

@ -1,91 +1,110 @@
// 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 Buffer = require('buffer').Buffer;
// add 'unpack' method for 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 )
{
var offset = 0;
var auth = [];
var cookieProperties = ['address', 'display', 'authName', 'authData'];
function handleCookieProperty(property) {
var length = buf.unpack('n', offset)[0];
offset += 2;
cookie[property] = buf.unpackString(length, offset);
offset += length;
}
while (offset < buf.length)
{
var cookie = {};
var typeToName = {
256: 'Local',
65535: 'Wild',
254: 'Netname',
253: 'Krb5Principal',
252: 'LocalHost',
0: 'Internet',
1: 'DECnet',
2: 'Chaos',
5: 'ServerInterpreted',
6: 'InternetV6'
};
cookie.type = buf.unpack('n')[0];
var cookie = {};
cookie.type = buf.readUInt16BE(offset);
if (!typeToName[cookie.type]) {
console.warn('Unknown address type');
}
offset += 2;
//JSHint becomes angry when handleCookieProperty is declared inside loop
cookieProperties.forEach(handleCookieProperty);
cookieProperties.forEach(function(property) {
var length = buf.unpack('n', offset)[0];
offset += 2;
if (cookie.type === 0 && property == 'address') { // Internet
// 4 bytes of ip addess, convert to w.x.y.z string
cookie.address = [ buf[offset], buf[offset+1], buf[offset+2], buf[offset+3]]
.map(function(octet) { return octet.toString(10) }).join('.');
} else {
cookie[property] = buf.unpackString(length, offset);
}
offset += length;
});
auth.push(cookie);
}
return auth;
}
module.exports = function( display, host, cb )
{
var XAuthorityFile = process.env.XAUTHORITY;
if (!XAuthorityFile)
{
if ( process.platform.match(/win/) ) {
// http://www.straightrunning.com/XmingNotes/trouble.php
//
// The Xming magic cookie program, xauth (user-based), uses an
// Xauthority file (not the traditional .Xauthority file) in
// the %HOME% directory. To use xauth from Command Processor
// e.g. on Windows machine 192.168.0.2 with user colin...
XAuthorityFile = process.env.USERPROFILE + '\\Xauthority';
var homedir = require('os').homedir;
var path = require('path');
function readXauthority(cb) {
var filename = process.env.XAUTHORITY || path.join(homedir(), '.Xauthority');
fs.readFile(filename, function(err, data) {
if (!err)
return cb(null, data);
if(err.code == 'ENOENT') {
// Xming/windows uses %HOME%/Xauthority ( .Xauthority with no dot ) - try with this name
filename = process.env.XAUTHORITY || path.join(homedir(), 'Xauthority');
fs.readFile(filename, function (err, data) {
if (err.code == 'ENOENT') {
cb(null, null);
} else {
XAuthorityFile = process.env.HOME + '/.Xauthority';
cb(err);
}
});
} else {
cb(err);
}
});
}
fs.readFile(XAuthorityFile, function (err, data) {
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) {
if(err) return cb(err);
if (err)
{
if (err.code == 'ENOENT')
{
cb('','');
return;
}
throw err;
}
var auth = parseXauth(data);
for (var cookieNum in auth)
{
var cookie = auth[cookieNum];
if (cookie.display == display && cookie.address == host)
{
cb( cookie.authName, cookie.authData );
return;
}
}
// throw 'No auth cookie matching display=' + display + ' and host=' + host;
cb( '', '' );
});
if (!data) {
return cb(null, {
authName: '',
authData: ''
});
}
var auth = parseXauth(data);
for (var cookieNum in auth)
{
var cookie = auth[cookieNum];
if ((typeToName[cookie.family] === 'Wild' || (cookie.type === family && cookie.address === host)) &&
(cookie.display.length === 0 || cookie.display === display))
return cb( null, cookie );
}
// If no cookie is found, proceed without authentication
cb(null, {
authName: '',
authData: ''
});
});
};

View file

@ -1,94 +1,244 @@
// full list of event/error/request codes for all extensions:
// http://www.opensource.apple.com/source/X11server/X11server-106.7/kdrive/xorg-server-1.6.5-apple3/dix/protocol.txt
var xutil = require('./xutil');
var hexy = require('./hexy').hexy;
var valueMask = {
CreateWindow: {
backgroundPixmap: 0x00000001,
backgroundPixel : 0x00000002,
borderPixmap : 0x00000004,
borderPixel : 0x00000008,
bitGravity : 0x00000010,
winGravity : 0x00000020,
backingStore : 0x00000040,
backingPlanes : 0x00000080,
backingPixel : 0x00000100,
overrideRedirect: 0x00000200,
saveUnder : 0x00000400,
eventMask : 0x00000800,
doNotPropagateMask: 0x00001000,
colormap : 0x00002000,
cursor : 0x00004000
backgroundPixmap : {
mask: 0x00000001,
format: 'L'
},
backgroundPixel : {
mask: 0x00000002,
format: 'L'
},
borderPixmap : {
mask: 0x00000004,
format: 'L'
},
borderPixel : {
mask: 0x00000008,
format: 'L'
},
bitGravity : {
mask: 0x00000010,
format: 'Cxxx'
},
winGravity : {
mask: 0x00000020,
format: 'Cxxx'
},
backingStore : {
mask: 0x00000040,
format: 'Cxxx'
},
backingPlanes : {
mask: 0x00000080,
format: 'L'
},
backingPixel : {
mask: 0x00000100,
format: 'L'
},
overrideRedirect : {
mask: 0x00000200,
format: 'Cxxx'
},
saveUnder : {
mask: 0x00000400,
format: 'Cxxx'
},
eventMask : {
mask: 0x00000800,
format: 'L'
},
doNotPropagateMask : {
mask: 0x00001000,
format: 'L'
},
colormap : {
mask: 0x00002000,
format: 'L'
},
cursor : {
mask: 0x00004000,
format: 'L'
}
},
CreateGC: {
'function' : 0x00000001, // TODO: alias? _function?
planeMask : 0x00000002,
foreground : 0x00000004,
background : 0x00000008,
lineWidth : 0x00000010,
lineStyle : 0x00000020,
capStyle : 0x00000040,
joinStyle : 0x00000080,
fillStyle : 0x00000100,
fillRule : 0x00000200,
tile : 0x00000400,
stipple : 0x00000800,
tileStippleXOrigin: 0x00001000,
tileStippleYOrigin: 0x00002000,
font : 0x00004000,
subwindowMode: 0x00008000,
graphicsExposures: 0x00010000,
clipXOrigin : 0x00020000,
clipYOrigin : 0x00040000,
clipMask : 0x00080000,
dashOffset : 0x00100000,
dashes : 0x00200000,
arcMode : 0x00400000
'function' : { // TODO: alias? _function?
mask: 0x00000001,
format: 'Cxxx'
},
planeMask : {
mask: 0x00000002,
format: 'L'
},
foreground : {
mask: 0x00000004,
format: 'L'
},
background : {
mask: 0x00000008,
format: 'L'
},
lineWidth : {
mask: 0x00000010,
format: 'Sxx'
},
lineStyle : {
mask: 0x00000020,
format: 'Cxxx'
},
capStyle : {
mask: 0x00000040,
format: 'Cxxx'
},
joinStyle : {
mask: 0x00000080,
format: 'Cxxx'
},
fillStyle : {
mask: 0x00000100,
format: 'Cxxx'
},
fillRule : {
mask: 0x00000200,
format: 'Cxxx'
},
tile : {
mask: 0x00000400,
format: 'L'
},
stipple : {
mask: 0x00000800,
format: 'L'
},
tileStippleXOrigin : {
mask: 0x00001000,
format: 'sxx'
},
tileStippleYOrigin : {
mask: 0x00002000,
format: 'sxx'
},
font : {
mask: 0x00004000,
format: 'L'
},
subwindowMode : {
mask: 0x00008000,
format: 'Cxxx'
},
graphicsExposures : {
mask: 0x00010000,
format: 'Cxxx'
},
clipXOrigin : {
mask: 0x00020000,
format: 'Sxx'
},
clipYOrigin : {
mask: 0x00040000,
format: 'Sxx'
},
clipMask : {
mask: 0x00080000,
format: 'L'
},
dashOffset : {
mask: 0x00100000,
format: 'Sxx'
},
dashes : {
mask: 0x00200000,
format: 'Cxxx'
},
arcMode : {
mask: 0x00400000,
format: 'Cxxx'
}
},
ConfigureWindow: {
x: 0x000001,
y: 0x000002,
width: 0x000004,
height: 0x000008,
borderWidth: 0x000010,
sibling: 0x000020,
stackMode: 0x000040
x : {
mask: 0x000001,
format: 'sxx'
},
y : {
mask: 0x000002,
format: 'sxx'
},
width : {
mask: 0x000004,
format: 'Sxx'
},
height : {
mask: 0x000008,
format: 'Sxx'
},
borderWidth : {
mask: 0x000010,
format: 'Sxx'
},
sibling : {
mask: 0x000020,
format: 'L'
},
stackMode : {
mask: 0x000040,
format: 'Cxxx'
}
}
};
var valueMaskName = {};
for (var req in valueMask) {
var masks = valueMask[req];
var names = valueMaskName[req] = {};
for (var m in masks)
names[masks[m]] = m;
names[masks[m].mask] = m;
}
function packValueMask(reqname, values)
{
var bitmask = 0;
var masksList = [];
var format = '';
var reqValueMask = valueMask[reqname];
var reqValueMaskName = valueMaskName[reqname];
if (!reqValueMask)
throw new Error(reqname + ': no value mask description');
for (var v in values)
for (var value in values)
{
var valueBit = reqValueMask[v];
if (!valueBit)
throw new Error(reqname + ': incorrect value param ' + v);
masksList.push(valueBit);
bitmask |= valueBit;
var v = reqValueMask[value];
if (v) {
var valueBit = v.mask;
if (!valueBit)
throw new Error(reqname + ': incorrect value param ' + value);
masksList.push(valueBit);
bitmask |= valueBit;
}
}
masksList.sort();
/* numeric sort */
masksList.sort(function(a, b) {
return a - b;
});
var args = [];
for (m in masksList)
for (var i=0,length=masksList.length;i<length;i++)
{
var valueName = reqValueMaskName[masksList[m]];
args.push( values[valueName] );
var value = masksList[i];
var valueName = reqValueMaskName[value];
format += reqValueMask[valueName].format
args.push( values[valueName] );
}
return [bitmask, args]
return [format, bitmask, args]
}
/*
@ -113,7 +263,7 @@ the way requests are described here
*/
module.exports = {
var templates = {
CreateWindow: [
// create request packet - function OR format string
function(id, parentId, x, y, width, height, borderWidth, depth, _class, visual, values) {
@ -129,45 +279,21 @@ module.exports = {
if (values === undefined)
values = {}
var packetLength = 8 + (values ? Object.keys(values).length : 0);
var format = 'CCSLLssSSSSLL';
// create bitmask
var bitmask = 0;
// TODO: slice from function arguments?
var args = [1, depth, packetLength, id, parentId, x, y, width, height, borderWidth, _class, visual];
// TODO: the code is a little bit mess
// additional values need to be packed in the following way:
// bitmask (bytes #24 to #31 in the packet) - 32 bit indicating what adittional arguments we supply
// values list (bytes #32 .. #32+4*num_values) in order of corresponding bits TODO: it's actually not 4*num. Some values are 4b ytes, some - 1 byte
// TODO: replace with packValueMask
var masksList = [];
for (var v in values)
{
var valueBit = valueMask['CreateWindow'][v];
if (!valueBit)
{
throw new Error('CreateWindow: incorrect value param ' + v);
}
masksList.push(valueBit);
bitmask |= valueBit;
format += 'L'; // TODO: not all values are 4 bytes CARD32!!!
}
// values packed in order of corresponding bit
masksList.sort();
// set bits to indicate additional values we are sending in this request
args.push(bitmask);
// add values in the order of the bits
// TODO: maybe it's better just to scan all 32 bits anstead of sorting parameters we are actually have?
for (var m in masksList)
{
var valueName = valueMaskName['CreateWindow'][masksList[m]];
args.push( values[valueName] );
}
var vals = packValueMask('CreateWindow', values);
var packetLength = 8 + (values ? vals[2].length : 0);
var args = [1, depth, packetLength, id, parentId, x, y, width, height, borderWidth, _class, visual];
format += vals[0];
args.push(vals[1]);
args = args.concat(vals[2]);
return [format, args];
}
@ -175,16 +301,13 @@ module.exports = {
ChangeWindowAttributes:[
function(wid, values) {
var format = 'CxSLL';
var packetLength = 3 + (values ? Object.keys(values).length : 0);
var format = 'CxSLSxx';
var vals = packValueMask('CreateWindow', values);
var args = [2, packetLength, wid, vals[0]];
var valArr = vals[1];
for (var v in valArr)
{
format += 'L';
args.push(valArr[v]);
}
var packetLength = 3 + (values ? vals[2].length : 0);
var args = [2, packetLength, wid, vals[1]];
var valArr = vals[2];
format += vals[0];
args = args.concat(valArr);
return [format, args];
}
],
@ -245,63 +368,14 @@ module.exports = {
* }
*/
function(win, options) {
var format = 'CxSLSxx';
var n = 3;
var mask = 0;
var params = [];
if (options.x !== undefined) {
mask |= valueMask.ConfigureWindow.x;
format += 'sxx';
params.push(options.x);
++ n;
}
if (options.y !== undefined) {
mask |= valueMask.ConfigureWindow.y;
format += 'sxx';
params.push(options.y);
++ n;
}
if (options.width !== undefined) {
mask |= valueMask.ConfigureWindow.width;
format += 'Sxx';
params.push(options.width);
++ n;
}
if (options.height !== undefined) {
mask |= valueMask.ConfigureWindow.height;
format += 'Sxx';
params.push(options.height);
++ n;
}
if (options.borderWidth !== undefined) {
mask |= valueMask.ConfigureWindow.borderWidth;
format += 'Sxx';
params.push(options.borderWidth);
++ n;
}
if (options.sibling !== undefined) {
mask |= valueMask.ConfigureWindow.sibling;
format += 'L';
params.push(options.sibling);
++ n;
}
if (options.stackMode !== undefined) {
mask |= valueMask.ConfigureWindow.stackMode;
format += 'Cxxx';
params.push(options.stackMode);
++ n;
}
return [format, [12, n, win, mask].concat(params)];
var vals = packValueMask('ConfigureWindow', options);
var format = 'CxSLSxx' + vals[0];
var args = [12, vals[2].length + 3, win, vals[1]];
args = args.concat(vals[2]);
return [format, args];
}
],
ResizeWindow: [
function(win, width, height) {
return module.exports.ConfigureWindow[0](win, { width : width, height: height });
@ -326,6 +400,11 @@ module.exports = {
}
],
LowerWindow: [
function(win) {
return module.exports.ConfigureWindow[0](win, { stackMode : 1 });
}
],
QueryTree: [
['CxSL', [15, 2]],
@ -386,7 +465,7 @@ module.exports = {
function(mode, wid, name, type, units, data)
{
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 requestLength = 6 + padded4;
var dataLenInFormatUnits = data.length / (units >> 3);
@ -409,7 +488,7 @@ module.exports = {
},
function(buf, format) {
var res = buf.unpack('LLL');
var res = buf.unpack('LLL');
var prop = {};
prop.type = res[0];
prop.bytesAfter = res[1];
@ -516,7 +595,7 @@ module.exports = {
function(buf, status) {
return status;
}
],
],
UngrabKeyboard: [
function(time) {
@ -527,7 +606,7 @@ module.exports = {
GrabKey: [
function(wid, ownerEvents, modifiers, key, pointerMode, keybMode) {
return [ 'CCSLSCCCxxx', [ 33, ownerEvents, 4, wid, modifiers, key, pointerMode, keybMode ] ];
}
}
],
UngrabKey: [
@ -535,6 +614,20 @@ module.exports = {
return [ 'CCSLSxx', [ 34, key, 3, wid, modifiers ] ];
}
],
AllowEvents: [
function(mode, ts) {
return [ 'CCSL', [ 35, mode, 2, ts ] ];
}
],
GrabServer: [
[ 'CxS', [36, 1]]
],
UngrabServer: [
[ 'CxS', [37, 1]]
],
QueryPointer: [
[ 'CxSL', [38, 2] ],
@ -552,7 +645,7 @@ module.exports = {
};
}
],
TranslateCoordinates: [
function(srcWid, dstWid, srcX, srcY) {
return [ 'CxSLLSS', [ 40, 4, srcWid, dstWid, srcX, srcY ] ];
@ -576,7 +669,7 @@ module.exports = {
return [ 'CCSLL', [42, revertTo, 3, wid, 0] ];
}
],
GetInputFocus: [
function() {
return [ 'CxS', [ 43, 1 ] ];
@ -634,20 +727,35 @@ module.exports = {
}
],
FreePixmap: [
function (pixmap) {
return [ 'CxSL', [54, 2, pixmap] ];
}
],
CreateCursor: [
function(cid, source, mask, foreRGB, backRGB, x, y) {
foreR = foreRGB.R
foreG = foreRGB.G
foreB = foreRGB.B
backR = backRGB.R
backG = backRGB.G
backB = backRGB.B
return [ 'CxSLLLSSSSSSSS', [93, 8, cid, source, mask, foreR, foreG, foreB, backR, backG, backB, x, y] ];
}
],
// opcode 55
CreateGC: [
function(cid, drawable, values) {
var format = 'CxSLLL';
var packetLength = 4 + (values ? Object.keys(values).length : 0);
var args = [55, packetLength, cid, drawable];
var vals = packValueMask('CreateGC', values);
args.push(vals[0]); // values bitmask
var valArr = vals[1];
for (var v in valArr)
{
format += 'L'; // TODO: we know format string length in advance and += inefficient for string
args.push(valArr[v]);
}
var packetLength = 4 + (values ? vals[2].length : 0);
var args = [55, packetLength, cid, drawable];
format += vals[0]
args.push(vals[1]); // values bitmask
args = args.concat(vals[2])
return [format, args];
}
],
@ -655,20 +763,22 @@ module.exports = {
ChangeGC: [
function(cid, values) {
var format = 'CxSLL';
var packetLength = 3 + (values ? Object.keys(values).length : 0);
var args = [56, packetLength, cid];
var vals = packValueMask('CreateGC', values);
args.push(vals[0]); // values bitmask
var valArr = vals[1];
for (var v in valArr)
{
format += 'L'; // TODO: we know format string length in advance and += inefficient for string
args.push(valArr[v]);
}
var packetLength = 3 + (values ? vals[2].length : 0);
var args = [56, packetLength, cid];
format += vals[0]
args.push(vals[1]); // values bitmask
args = args.concat(vals[2])
return [format, args];
}
],
ClearArea: [
function(wid, x, y, width, height, exposures) {
return [ 'CCSLssSS', [61, exposures, 4, wid, x, y, width, height] ];
}
],
//
CopyArea: [
function(srcDrawable, dstDrawable, gc, srcX, srcY, dstX, dstY, width, height) {
@ -741,7 +851,7 @@ module.exports = {
var padded = xutil.padded_length(data.length);
var reqLen = 6 + padded/4; // (length + 3) >> 2 ???
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
// NOTE: big req is used here (first 'L' in format, 0 and +1 in params), won't work if not enabled
@ -760,7 +870,7 @@ module.exports = {
return {
depth: depth,
visualId: visualId,
data: buf.slice(20)
data: buf.slice(24)
};
}
],
@ -899,7 +1009,7 @@ module.exports = {
}
],
KillKlient: [
KillClient: [
function(resource) {
return [ 'CxSL', [113, 2, resource] ];
}
@ -910,12 +1020,20 @@ module.exports = {
return [ 'CxSssCCxx', [107, 3, timeout, interval, preferBlanking, allowExposures]];
}
],
Bell: [
function(percent) {
return ["CxCs",[108,1]];
}
],
ForceScreenSaver: [
function(activate) {
return [ 'CCS', [115, activate?1:0, 1] ];
}
]
};
templates.KillKlient = templates.KillClient;
}
module.exports = templates;

View file

@ -18,10 +18,10 @@ var xutil = require('../xutil');
#define X_AppleWMAttachTransient 13
*/
exports.requireExt = function(display, callback)
exports.requireExt = function(display, callback)
{
var X = display.client;
X.QueryExtension('Apple-WM', function(err, ext) {
X.QueryExtension('Apple-WM', function(err, ext) {
if (!ext.present)
callback(new Error('extension not available'));
@ -32,7 +32,7 @@ exports.requireExt = function(display, callback)
X.pack_stream.pack('CCS', [ext.majorOpcode, 0, 1]);
X.replies[X.seq_num] = [
function(buf, opt) {
var res = buf.unpack('SSL');
var res = buf.unpack('SSL');
return res;
},
cb
@ -52,7 +52,7 @@ exports.requireExt = function(display, callback)
X.pack_stream.pack('CCSSSSSSSSSSS', [ext.majorOpcode, 1, 6, frame_class, frame_rect, ix, iy, iw, ih, ox, oy, ow, oh, cb]);
X.replies[X.seq_num] = [
function(buf, opt) {
var res = buf.unpack('SSSS');
var res = buf.unpack('SSSS');
return {
x: res[0],
y: res[1],
@ -64,7 +64,7 @@ exports.requireExt = function(display, callback)
];
X.pack_stream.flush();
}
ext.FrameHitTest = function(frame_class, px, py, ix, iy, iw, ih, ox, oy, ow, oh, cb)
{
X.seq_num++;
@ -80,7 +80,7 @@ exports.requireExt = function(display, callback)
}
// from /usr/include/Xplugin.h
// from /usr/include/Xplugin.h
ext.FrameClass = {
DecorLarge: 1,
Reserved1: 2,
@ -107,7 +107,7 @@ exports.requireExt = function(display, callback)
CloseBoxClicked: 0x800,
CollapseBoxClicked: 0x1000,
ZoomBoxClicked: 0x2000,
GrowBox: 0x4000
GrowBox: 0x4000
};
ext.FrameDraw = function(screen, window, frameClass, attr, ix, iy, iw, ih, ox, oy, ow, oh, title)
@ -189,7 +189,7 @@ exports.requireExt = function(display, callback)
var reqlen = 8;
var extlength = 0;
items.forEach(function(i) {
});
}
@ -209,13 +209,13 @@ exports.requireExt = function(display, callback)
X.pack_stream.flush();
}
callback(ext);
callback(null, ext);
/*
ext.QueryVersion(function(err, vers) {
ext.major = vers[0];
ext.minor = vers[1];
ext.patch = vers[2];
callback(ext);
callback(null, ext);
});
*/
@ -248,7 +248,7 @@ exports.requireExt = function(display, callback)
CopyToPasteboard: 0
}
};
X.eventParsers[ext.firstEvent + ext.events.AppleWMControllerNotify] =
X.eventParsers[ext.firstEvent + ext.events.AppleWMActivationNotify] =
X.eventParsers[ext.firstEvent + ext.events.AppleWMPasteboardNotify] = function(type, seq, extra, code, raw)

View file

@ -1,11 +1,11 @@
// http://www.x.org/releases/X11R7.6/doc/bigreqsproto/bigreq.html
// TODO: move to templates
exports.requireExt = function(display, callback)
exports.requireExt = function(display, callback)
{
var X = display.client;
X.QueryExtension('BIG-REQUESTS', function(err, ext) {
X.QueryExtension('BIG-REQUESTS', function(err, ext) {
if (!ext.present)
return callback(new Error('extension not available'));
@ -21,6 +21,6 @@ exports.requireExt = function(display, callback)
];
X.pack_stream.flush();
}
callback(ext);
callback(null, ext);
});
}

View file

@ -14,15 +14,15 @@
var x11 = require('..');
// TODO: move to templates
exports.requireExt = function(display, callback)
exports.requireExt = function(display, callback)
{
var X = display.client;
X.QueryExtension('Composite', function(err, ext) {
X.QueryExtension('Composite', function(err, ext) {
if (!ext.present)
return callback(new Error('extension not available'));
ext.Redirect = {
ext.Redirect = {
Automatic: 0,
Manual: 1
};
@ -33,7 +33,7 @@ exports.requireExt = function(display, callback)
X.pack_stream.pack('CCSLL', [ext.majorOpcode, 0, 3, clientMaj, clientMin]);
X.replies[X.seq_num] = [
function(buf, opt) {
var res = buf.unpack('LL');
var res = buf.unpack('LL');
return res;
},
callback
@ -82,7 +82,7 @@ exports.requireExt = function(display, callback)
X.pack_stream.pack('CCSLL', [ext.majorOpcode, 6, 3, window, pixmap]);
X.pack_stream.flush();
}
ext.GetOverlayWindow = function(window, callback)
{
X.seq_num++;
@ -96,19 +96,22 @@ exports.requireExt = function(display, callback)
];
X.pack_stream.flush();
}
ext.ReleaseOverlayWindow = function(window)
{
X.seq_num++;
X.pack_stream.pack('CCSL', [ext.majorOpcode, 8, 2, window]);
X.pack_stream.flush();
}
// currently version 0.4 TODO: bump up with coordinate translations
ext.QueryVersion(0, 4, function(err, vers) {
if (err)
return callback(err);
ext.major = vers[0];
ext.minor = vers[1];
callback(ext);
callback(null, ext);
});
});
}

View file

@ -3,19 +3,19 @@
var x11 = require('..');
// TODO: move to templates
exports.requireExt = function(display, callback)
exports.requireExt = function(display, callback)
{
var X = display.client;
X.QueryExtension('DAMAGE', function(err, ext) {
X.QueryExtension('DAMAGE', function(err, ext) {
if (!ext.present)
return callback(new Error('extension not available'));
ext.ReportLevel = {
ext.ReportLevel = {
RawRectangles: 0,
DeltaRectangles: 1,
BoundingBox: 2,
NonEmpty: 3
NonEmpty: 3
};
ext.QueryVersion = function(clientMaj, clientMin, callback)
@ -24,7 +24,7 @@ exports.requireExt = function(display, callback)
X.pack_stream.pack('CCSLL', [ext.majorOpcode, 0, 3, clientMaj, clientMin]);
X.replies[X.seq_num] = [
function(buf, opt) {
var res = buf.unpack('LL');
var res = buf.unpack('LL');
return res;
},
callback
@ -59,18 +59,20 @@ exports.requireExt = function(display, callback)
X.pack_stream.pack('CCSLL', [ext.majorOpcode, 4, 3, damage, region]);
X.pack_stream.flush();
}
ext.QueryVersion(1, 1, function(err, vers) {
if (err)
return callback(err);
ext.major = vers[0];
ext.minor = vers[1];
callback(ext);
callback(null, ext);
});
ext.events = {
DamageNotify: 0
}
X.eventParsers[ext.firstEvent + ext.events.DamageNotify] = function(type, seq, extra, code, raw)
X.eventParsers[ext.firstEvent + ext.events.DamageNotify] = function(type, seq, extra, code, raw)
{
var event = {};
event.level = code;
@ -80,16 +82,16 @@ exports.requireExt = function(display, callback)
event.damage = values[0];
event.time = values[1];
event.area = {
x: values[2],
y: values[3],
w: values[4],
h: values[5]
x: values[2],
y: values[3],
w: values[4],
h: values[5]
};
event.geometry = {
x: values[6],
y: values[7],
w: values[8],
h: values[9]
x: values[6],
y: values[7],
w: values[8],
h: values[9]
};
event.name = 'DamageNotify';
return event;

View file

@ -94,7 +94,7 @@ exports.requireExt = function(display, callback)
X.pack_stream.flush();
};
callback(ext);
callback(null, ext);
});
};

View file

@ -3,10 +3,23 @@
var x11 = require('..');
// TODO: move to templates
exports.requireExt = function(display, callback)
function parse_rectangle(buf, pos) {
if (!pos) {
pos = 0;
}
return {
x : buf[pos],
y : buf[pos + 1],
width : buf[pos + 2],
height : buf[pos + 3]
}
}
exports.requireExt = function(display, callback)
{
var X = display.client;
X.QueryExtension('XFIXES', function(err, ext) {
X.QueryExtension('XFIXES', function(err, ext) {
if (!ext.present)
return callback(new Error('extension not available'));
@ -17,7 +30,7 @@ exports.requireExt = function(display, callback)
X.pack_stream.pack('CCSLL', [ext.majorOpcode, 0, 3, clientMaj, clientMin]);
X.replies[X.seq_num] = [
function(buf, opt) {
var res = buf.unpack('LL');
var res = buf.unpack('LL');
return res;
},
callback
@ -35,17 +48,90 @@ exports.requireExt = function(display, callback)
X.pack_stream.flush();
};
ext.WindowRegionKind = {
Bounding : 0,
Clip : 1
};
ext.CreateRegion = function(region, rects) {
X.seq_num ++;
var format = 'CCSL';
format += Array(rects.length + 1).join('ssSS');
var args = [ ext.majorOpcode, 5, 2 + (rects.length << 1), region ];
rects.forEach(function(rect) {
args.push(rect.x);
args.push(rect.y);
args.push(rect.width);
args.push(rect.height);
});
X.pack_stream.pack(format, args);
X.pack_stream.flush();
}
ext.CreateRegionFromWindow = function(region, wid, kind) {
X.seq_num ++;
X.pack_stream.pack('CCSLLCxxx', [ ext.majorOpcode, 7, 4, region, wid, kind ]);
X.pack_stream.flush();
}
ext.DestroyRegion = function(region) {
X.seq_num ++;
X.pack_stream.pack('CCSL', [ ext.majorOpcode, 10, 2, region ]);
X.pack_stream.flush();
}
ext.UnionRegion = function(src1, src2, dst) {
X.seq_num ++;
X.pack_stream.pack('CCSLLL', [ ext.majorOpcode, 13, 4, src1, src2, dst ]);
X.pack_stream.flush();
}
ext.TranslateRegion = function(region, dx, dy) {
X.seq_num ++;
X.pack_stream.pack('CCSLss', [ ext.majorOpcode, 17, 3, region, dx, dy ]);
X.pack_stream.flush();
}
ext.FetchRegion = function(region, cb) {
X.seq_num ++;
X.pack_stream.pack('CCSL', [ ext.majorOpcode, 19, 2, region ]);
X.replies[X.seq_num] = [
function(buf, opt) {
var n_rectangles = (buf.length - 24) >> 3;
var format = 'ssSSxxxxxxxxxxxxxxxx';
format += Array(n_rectangles + 1).join('ssSS');
var res = buf.unpack(format);
var reg = {
extents : parse_rectangle(res),
rectangles : []
};
for (var i = 0; i < n_rectangles; ++ i) {
reg.rectangles.push(parse_rectangle(res, 4 + (i << 2)));
}
return reg;
},
cb
];
X.pack_stream.flush();
}
ext.QueryVersion(5, 0, function(err, vers) {
if (err)
return callback(err);
ext.major = vers[0];
ext.minor = vers[1];
callback(ext);
callback(null, ext);
});
ext.events = {
DamageNotify: 0
}
X.eventParsers[ext.firstEvent + ext.events.DamageNotify] = function(type, seq, extra, code, raw)
X.eventParsers[ext.firstEvent + ext.events.DamageNotify] = function(type, seq, extra, code, raw)
{
var event = {};
event.level = code;
@ -55,16 +141,16 @@ exports.requireExt = function(display, callback)
event.damage = values[0];
event.time = values[1];
event.area = {
x: values[2],
y: values[3],
w: values[4],
h: values[5]
x: values[2],
y: values[3],
w: values[4],
h: values[5]
};
event.geometry = {
x: values[6],
y: values[7],
w: values[8],
h: values[9]
x: values[6],
y: values[7],
w: values[8],
h: values[9]
};
event.name = 'DamageNotify';
return event;

View file

@ -8,6 +8,9 @@
http://www.opengl.org/wiki/Tutorial:_OpenGL_3.0_Context_Creation_(GLX)
https://github.com/xderoche/J11/blob/master/src/gnu/x11/extension/glx/GL.java
*/
var x11 = require('..');
// TODO: move to templates
@ -49,6 +52,18 @@ exports.requireExt = function(display, callback)
X.pack_stream.flush();
}
ext.CreateGLXPixmap = function(screen, visual, pixmap, glxpixmap) {
X.seq_num++;
X.pack_stream.pack('CCSLLLL', [ext.majorOpcode, 13, 5, screen, visual, pixmap, glxpixmap]);
console.log('CreateGlxPix', X.seq_num);
console.log(ext.majorOpcode, 13, 5, screen, visual, pixmap, glxpixmap);
console.trace();
X.pack_stream.flush();
}
ext.QueryExtensionsString = function(screen, callback) {
X.seq_num++;
X.pack_stream.pack('CCSL', [ext.majorOpcode, 18, 2, screen]);
@ -164,7 +179,7 @@ exports.requireExt = function(display, callback)
function(buf, opt) {
var format = Buffer(count);
format.fill('L');
return buf.unpack(format.toString());
return buf.unpack('xxxxxxxxxxxxxxxxxxxxxxxx' + format.toString());
},
callback
];
@ -213,7 +228,6 @@ exports.requireExt = function(display, callback)
ext.Render = function(ctx, data) {
X.seq_num++;
var length = 0;
//console.log(data);
if (Buffer.isBuffer(data))
length = 2+data.length/4;
else if (Array.isArray(data)) {
@ -221,7 +235,6 @@ exports.requireExt = function(display, callback)
for (var i=0; i < data.length; ++i)
length += data[i].length/4;
}
//console.log('LENGTH: ', length);
X.pack_stream.pack('CCSL', [ext.majorOpcode, 1, length, ctx]);
if (Buffer.isBuffer(data))
X.pack_stream.write_queue.push(data);
@ -233,11 +246,80 @@ exports.requireExt = function(display, callback)
X.pack_stream.flush();
}
ext.VendorPrivate = function(ctx, code, data) {
X.seq_num++;
X.pack_stream.pack('CCSLL', [ext.majorOpcode, 16, 3+data.length/4, code, ctx]);
X.pack_stream.write_queue.push(data);
X.pack_stream.flush();
}
// 1330 - X_GLXvop_BindTexImageEXT
// 1331 - X_GLXvop_ReleaseTexImageEXT
ext.BindTexImage = function(ctx, drawable, buffer, attribs) {
if (!attribs)
attribs = [];
var data = Buffer.alloc(12 + attribs.length*4);
data.writeUInt32LE(drawable, 0);
data.writeUInt32LE(buffer, 4);
data.writeUInt32LE(attribs.length, 8);
for (var i=0; i < attribs.length; ++i)
data.writeUint32LE(attribs.length, 12+i*4);
ext.VendorPrivate(ctx, 1330, data);
}
ext.ReleaseTexImage = function(ctx, drawable, buffer) {
var data = Buffer.alloc(8);
data.writeUint32LE(drawable, 0);
data.writeUint32LE(buffer, 4);
ext.VendorPrivate(ctx, 1331, data);
}
// VendorPrivateWithReply - opcode 17
ext.RenderLarge = function(ctx, requestNum, requestTotal, data) {
X.seq_num++;
//var data = Buffer.concat(data);
var padLength = 4 - data.length % 4;
if (padLength == 4)
padLength = 0;
var length = 4 + (data.length+padLength) / 4;
X.pack_stream.pack('CCSLSSL', [ext.majorOpcode, 2, length, ctx, requestNum, requestTotal, data.length]);
X.pack_stream.write_queue.push(data);
var pad = Buffer.alloc(padLength);
pad.fill(0);
X.pack_stream.write_queue.push(pad);
X.pack_stream.flush();
}
ext.renderPipeline = function(ctx) {
return require('./glxrender')(this, ctx);
}
callback(ext);
var errors = [
"context",
"contect state",
"drawable",
"pixmap",
"context tag",
"current window",
"Render request",
"RenderLarge request",
"(unsupported) VendorPrivate request",
"FB config",
"pbuffer",
"current drawable",
"window"
];
errors.forEach(function(message, code) {
X.errorParsers[ext.firstError + code] = function(err) {
err.message = "GLX: Bad " + message;
};
});
callback(null, ext);
});
}

View file

@ -2,7 +2,7 @@
var constants = require('./glxconstants');
var MAX_SMALL_RENDER=65000;
var MAX_SMALL_RENDER=65536-16;
module.exports = function(GLX, ctx) {
buffers = [];
@ -10,17 +10,13 @@ module.exports = function(GLX, ctx) {
function commandBuffer(opcode, len) {
if (currentLength + len > MAX_SMALL_RENDER) {
console.log("Flushing buffer ", currentLength);
render();
}
if (len > MAX_SMALL_RENDER)
{
throw Error('Buffer too big. Please implement RenderLarge request');
// renderLarge();
}
throw Error('Buffer too big. Make sure you are using RenderLarge for large commands');
currentLength += len;
var res = Buffer(len);
var res = Buffer.alloc(len);
res.writeUInt16LE(len, 0);
res.writeUInt16LE(opcode, 2);
return res;
@ -101,6 +97,14 @@ module.exports = function(GLX, ctx) {
buffers.push(res);
}
function serialize3i(opcode, i1, i2, i3) {
var res = commandBuffer(opcode, 16);
res.writeUInt32LE(i1, 4);
res.writeUInt32LE(i2, 8);
res.writeUInt32LE(i3, 12);
buffers.push(res);
}
function serialize2i1f(opcode, i1, i2, f1) {
var res = commandBuffer(opcode, 16);
res.writeUInt32LE(i1, 4);
@ -109,6 +113,15 @@ module.exports = function(GLX, ctx) {
buffers.push(res);
}
function serialize2ifv(opcode, i1, i2, fv) {
var res = commandBuffer(opcode, 12 + fv.length*4);
res.writeUInt32LE(i1, 4);
res.writeUInt32LE(i2, 8);
for (var i=0; i < fv.length; ++i)
res.writeFloatLE(fv[i], 12+i*4);
buffers.push(res);
}
function serialize2i4f(opcode, i1, i2, f1, f2, f3, f4) {
var res = commandBuffer(opcode, 28);
res.writeUInt32LE(i1, 4);
@ -121,8 +134,16 @@ module.exports = function(GLX, ctx) {
}
function render(ctxLocal) {
if (!ctxLocal) // ctxLocal overrides ctx passed during creation of renderContext
ctxLocal = ctx;
if (buffers.length == 0) {
buffers = [];
currentLength = 0;
return;
}
GLX.Render(ctxLocal, buffers);
buffers = [];
currentLength = 0;
@ -222,7 +243,7 @@ module.exports = function(GLX, ctx) {
serialize2i(85, target, mode);
},
BindTexture: function(target, texture) {
serialize2i(4117, target, texture);
serialize2i(4117, target, texture);
},
TexEnvf: function(target, pname, param) {
serialize2i1f(112, target, pname, param);
@ -230,7 +251,114 @@ module.exports = function(GLX, ctx) {
TexParameterf: function(target, pname, param) {
serialize2i1f(105, target, pname, param);
},
TexCoords2f: function(x, y) {
TexParameterfv: function(target, pname, param) {
serialize2ifv(106, target, pname, param);
},
TexParameteri: function(target, pname, param) {
serialize3i(107, target, pname, param);
},
TexImage2D: function(target, level, internalFormat, width, height, border, format, type, data) {
render();
var typeSize = [];
typeSize[constants.FLOAT] = 4;
typeSize[constants.BYTE] = 1;
typeSize[constants.UNSIGNED_BYTE] = 1;
var res = Buffer.alloc(60 + data.length*typeSize[type]);
res.writeUInt32LE(res.length, 0);
res.writeUInt32LE(110, 4);
res[8] = 0; // swapbytes
res[9] = 0; // lsbfirst
res.writeUInt16LE(0, 10); // unused
/*
defaults: (from http://stackoverflow.com/questions/21563590/glteximage2d-protocol-arguments?noredirect=1#comment32577251_21563590 )
GL_UNPACK_SWAP_BYTES boolean false true or false
GL_UNPACK_LSB_FIRST boolean false true or false
GL_UNPACK_ROW_LENGTH integer 0 [0,oo)
GL_UNPACK_SKIP_ROWS integer 0 [0,oo)
GL_UNPACK_SKIP_PIXELS integer 0 [0,oo)
GL_UNPACK_ALIGNMENT integer 4 1, 2, 4, or 8
*/
res.writeUInt32LE(0, 12); // rowlength
res.writeUInt32LE(0, 16); // skiprows
res.writeUInt32LE(0, 20); // skippixels
res.writeUInt32LE(4, 24); // alignment
res.writeUInt32LE(target, 28);
res.writeUInt32LE(level, 32);
res.writeUInt32LE(internalFormat, 36);
res.writeUInt32LE(width, 40);
res.writeUInt32LE(height, 44);
res.writeUInt32LE(border, 48);
res.writeUInt32LE(format, 52);
res.writeUInt32LE(type, 56);
switch(type) {
case constants.FLOAT:
for (var i=0; i < data.length; ++i)
res.writeFloatLE(data[i], 60+i*typeSize[type]);
break;
case constants.BYTE:
case constants.UNSIGNED_BYTE:
for (var i=0; i < data.length; ++i)
res[60+i] = data[i];
break;
default:
throw new Error('unsupported texture type:' + type);
}
// bake sure buffer for glxRender request is emptied first
render();
var dataLen = res.length;
var maxSize = 262124;
var totalRequests = 1 + parseInt(dataLen / maxSize) - 1;
if (dataLen % maxSize)
totalRequests++;
// for some reason RenderLarge does not like everything to be sent in one go
// add one extra buffer request for small requests
if (dataLen < maxSize) {
GLX.RenderLarge(ctx, 1, 2, res);
GLX.RenderLarge(ctx, 2, 2, Buffer(0));
return;
}
var pos = 0;
var reqNum = 1;
while(dataLen > 0) {
if (dataLen < maxSize) {
GLX.RenderLarge(ctx, reqNum, totalRequests, res.slice(pos));
break;
} else {
GLX.RenderLarge(ctx, reqNum, totalRequests, res.slice(pos, pos + maxSize));
pos += maxSize;
dataLen -= maxSize;
reqNum++;
}
}
},
ProgramString: function(target, format, src) {
serialize3i(target, format, src);
buffers.push(Buffer(src));
},
BindProgram: function(target, program) {
serialize2i(target, format, src);
},
TexCoord2f: function(x, y) {
serialize2f(54, x, y);
}
};

View file

@ -3,16 +3,15 @@
var x11 = require('..');
// TODO: move to templates
exports.requireExt = function(display, callback)
exports.requireExt = function(display, callback)
{
var X = display.client;
X.QueryExtension('RANDR', function(err, ext) {
debugger;
X.QueryExtension('RANDR', function(err, ext) {
if (!ext.present)
return callback(new Error('extension not available'));
//ext.ReportLevel = {
//ext.ReportLevel = {
//};
ext.QueryVersion = function(clientMaj, clientMin, callback)
@ -41,6 +40,67 @@ exports.requireExt = function(display, callback)
All: 15
};
ext.Rotation = {
Rotate_0: 1,
Rotate_90: 2,
Rotate_180: 4,
Rotate_270: 8,
Reflect_X: 16,
Reflect_Y: 32
};
ext.ConfigStatus = {
Sucess: 0,
InvalidConfigTime: 1,
InvalidTime: 2,
Failed: 3
};
ext.ModeFlag = {
HSyncPositive: 1,
HSyncNegative: 2,
VSyncPositive: 4,
VSyncNegative: 8,
Interlace: 16,
DoubleScan: 32,
CSync: 64,
CSyncPositive: 128,
CSyncNegative: 256,
HSkewPresent: 512,
BCast: 1024,
PixelMultiplex: 2048,
DoubleClock: 4096,
ClockDivideBy2: 8192
}
ext.SetScreenConfig = function(win, ts, configTs, sizeId, rotation, rate, cb) {
X.seq_num ++;
X.pack_stream.pack('CCSLLLSSSS', [ext.majorOpcode, 2, 6, win, ts, configTs, sizeId, rotation, rate, 0]);
X.replies[X.seq_num] = [
function(buf, opt) {
var res = buf.unpack('LLLSSLL');
return {
status : opt,
newTs : res [0],
configTs : res[1],
root : res[2],
subpixelOrder : res[3]
}
},
function(err, res) {
var err;
if (res.status !== 0) {
err = new Error('SetScreenConfig error');
err.code = res.status;
}
cb(err, res);
}
];
X.pack_stream.flush();
},
ext.SelectInput = function(win, mask)
{
X.seq_num++;
@ -48,12 +108,177 @@ exports.requireExt = function(display, callback)
X.pack_stream.flush();
},
X.eventParsers[ext.firstEvent + ext.events.RRScreenChangeNotify] = function(type, seq, extra, code, raw)
ext.GetScreenInfo = function(win, cb) {
X.seq_num ++;
X.pack_stream.pack('CCSL', [ext.majorOpcode, 5, 2, win]);
X.replies[X.seq_num] = [
function(buf, opt) {
var i, j;
var res = buf.unpack('LLLSSSSSS');
var info = {
rotations : opt,
root : res [0],
timestamp : res[1],
config_timestamp : res[2],
sizeID : res[4],
rotation : res[5],
rate : res[6],
rates: []
};
var nSizes = res[3];
var nRates = res[7];
var screens_len = nSizes << 2;
var format = Array(screens_len + 1).join('S');
res = buf.unpack(format, 24);
info.screens = [];
for (i = 0; i < screens_len; i += 4) {
info.screens.push({
px_width : res[i],
px_height : res[i + 1],
mm_width : res[i + 2],
mm_height : res[i + 3]
});
}
format = Array(nRates + 1).join('S');
info.rates = buf.unpack(format, 24 + screens_len * 2);
return info;
},
cb
];
X.pack_stream.flush();
},
ext.GetScreenResources = function(win, cb)
{
var event = {};
event.raw = raw;
X.seq_num ++;
X.pack_stream.pack('CCSL', [ext.majorOpcode, 8, 2, win]);
X.replies[X.seq_num] = [
function(buf, opt) {
var i;
var pos = 0;
var res = buf.unpack('LLSSSSxxxxxxxx');
var resources = {
timestamp : res[0],
config_timestamp : res[1],
modeinfos : []
};
pos += 24;
var format = Array(res[2] + 1).join('L');
resources.crtcs = buf.unpack(format, pos);
pos += res[2] << 2;
format = Array(res[3] + 1).join('L');
resources.outputs = buf.unpack(format, pos);
pos += res[3] << 2;
format = Array(res[4] + 1).join('LSSLSSSSSSSSL');
res_modes = buf.unpack(format, pos);
pos += res[4] << 5;
for (i = 0; i < res[4]; i+= 13) {
resources.modeinfos.push({
id : res_modes[i + 0],
width : res_modes[i + 1],
height : res_modes[i + 2],
dot_clock : res_modes[i + 3],
h_sync_start : res_modes[i + 4],
h_sync_end : res_modes[i + 5],
h_total : res_modes[i + 6],
h_skew : res_modes[i + 7],
v_sync_start : res_modes[i + 8],
v_sync_end : res_modes[i + 9],
v_total : res_modes[i + 10],
modeflags : res_modes[i + 12],
name : buf.slice(pos, pos + res_modes[i + 11]).toString()
});
pos += res_modes[i + 11];
}
return resources;
},
cb
];
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) {
X.seq_num ++;
X.pack_stream.pack('CCSLL', [ext.majorOpcode, 20, 3, crtc, configTs ]);
X.replies[X.seq_num] = [
function(buf, opt) {
var pos = 0;
var res = buf.unpack('LssSSLSSSS');
var info = {
status : opt,
timestamp : res[0],
x : res[1],
y : res[2],
width : res[3],
height : res[4],
mode : res[5],
rotation : res[6],
rotations : res[7]
};
pos += 24;
var format = Array(res[8] + 1).join('L');
info.output = buf.unpack(format, pos);
format = Array(res[9] + 1).join('L');
info.possible = buf.unpack(format, pos);
return info;
},
cb
];
X.pack_stream.flush();
},
X.eventParsers[ext.firstEvent + ext.events.RRScreenChangeNotify] = function(type, seq, extra, code, raw)
{
var event = {};
event.raw = raw;
event.type = type
event.seq = seq;
event.seq = seq;
event.rotation = code;
var values = raw.unpack('LLLSSSSSS');
event.time = extra
@ -68,10 +293,15 @@ exports.requireExt = function(display, callback)
event.physHeight = values[8];
event.name = 'RRScreenChangeNotify';
console.log(event);
return event;
return event;
};
callback(ext);
ext.QueryVersion(255, 255, function(err, version) {
if (err) return callback(err);
ext.major_version = version[0];
ext.minor_version = version[1];
callback(null, ext);
});
});
}

File diff suppressed because it is too large Load diff

View file

@ -3,10 +3,10 @@
var x11 = require('..');
// TODO: move to templates
exports.requireExt = function(display, callback)
exports.requireExt = function(display, callback)
{
var X = display.client;
X.QueryExtension('MIT-SCREEN-SAVER', function(err, ext) {
X.QueryExtension('MIT-SCREEN-SAVER', function(err, ext) {
if (!ext.present)
return callback(new Error('extension not available'));
@ -18,7 +18,7 @@ exports.requireExt = function(display, callback)
X.pack_stream.pack('CCSCCxx', [ext.majorOpcode, 0, 2, clientMaj, clientMin]);
X.replies[X.seq_num] = [
function(buf, opt) {
var res = buf.unpack('CC');
var res = buf.unpack('CC');
return res;
},
cb
@ -26,18 +26,18 @@ exports.requireExt = function(display, callback)
X.pack_stream.flush();
}
ext.State = {
ext.State = {
Off: 0,
On: 1,
Disabled: 2
};
ext.Kind = {
ext.Kind = {
Blanked: 0,
Internal: 1,
External: 2
};
ext.QueryInfo = function(drawable, callback)
{
X.seq_num++;
@ -51,7 +51,7 @@ exports.requireExt = function(display, callback)
info.until = res[1];
info.idle = res[2];
info.eventMask = res[3];
info.kind = res[4]
info.kind = res[4]
return info;
},
callback
@ -73,10 +73,11 @@ exports.requireExt = function(display, callback)
}
ext.QueryVersion(1, 1, function(err, vers) {
if (err)
return callback(err);
ext.major = vers[0];
ext.minor = vers[1];
callback(ext);
callback(null, ext);
});
ext.events = {
@ -89,7 +90,7 @@ exports.requireExt = function(display, callback)
Cycle: 2
}
X.eventParsers[ext.firstEvent + ext.events.ScreenSaverNotify] = function(type, seq, extra, code, raw)
X.eventParsers[ext.firstEvent + ext.events.ScreenSaverNotify] = function(type, seq, extra, code, raw)
{
var event = {};
event.state = code;

View file

@ -3,7 +3,7 @@
var x11 = require('..');
// TODO: move to templates
exports.requireExt = function(display, callback)
exports.requireExt = function(display, callback)
{
function captureStack()
{
@ -14,14 +14,14 @@ exports.requireExt = function(display, callback)
}
var X = display.client;
X.QueryExtension('SHAPE', function(err, ext) {
X.QueryExtension('SHAPE', function(err, ext) {
if (!ext.present)
return callback(new Error('extension not available'));
ext.Kind = {
ext.Kind = {
Bounding: 0,
Clip: 1,
Clip: 1,
Input: 2
};
@ -31,16 +31,23 @@ exports.requireExt = function(display, callback)
Intersect: 2,
Subtract: 3,
Invert: 4
}
};
ext.Ordering = {
Unsorted: 0,
YSorted: 1,
YXSorted: 2,
YXBanded: 3
};
ext.QueryVersion = function(cb)
{
X.seq_num++;
captureStack();
// captureStack();
X.pack_stream.pack('CCSLL', [ext.majorOpcode, 0, 1]);
X.replies[X.seq_num] = [
function(buf, opt) {
var res = buf.unpack('SS');
var res = buf.unpack('SS');
return res;
},
cb
@ -48,18 +55,36 @@ exports.requireExt = function(display, callback)
X.pack_stream.flush();
}
// Accepts rectangles as [[x, y, width, height]]
ext.Rectangles = function( op, kind, window, x, y, rectangles, ordering /* = Ordering.Unsorted */ )
{
if (ordering === undefined)
ordering = ext.Ordering.Unsorted;
var length = 4 + rectangles.length * 2;
X.seq_num++;
// captureStack();
X.pack_stream.pack('CCSCCCxLss', [ext.majorOpcode, 1, length, op, kind, ordering, window, x, y]);
for (var i = 0; i < rectangles.length; ++i) {
var r = rectangles[i];
X.pack_stream.pack('ssSS', r);
}
X.pack_stream.flush();
}
ext.Mask = function( op, kind, window, x, y, bitmap )
{
X.seq_num++;
captureStack();
X.pack_stream.pack('CCSCCxxLssL', [ext.majorOpcode, 2, 5, op, kind, x, y, bitmap]);
// captureStack();
X.pack_stream.pack('CCSCCxxLssL', [ext.majorOpcode, 2, 5, op, kind, window, x, y, bitmap]);
X.pack_stream.flush();
}
ext.SelectInput = function( window, enable )
{
X.seq_num++;
captureStack();
// captureStack();
X.pack_stream.pack('CCSLCxxx', [ext.majorOpcode, 6, 3, window, enable ]);
X.pack_stream.flush();
}
@ -67,7 +92,7 @@ exports.requireExt = function(display, callback)
ext.InputSelected = function( window, cb )
{
X.seq_num++;
captureStack();
// captureStack();
X.pack_stream.pack('CCSL', [ext.majorOpcode, 7, 2, window ]);
X.replies[X.seq_num] = [
function(buf, opt) {
@ -78,14 +103,40 @@ exports.requireExt = function(display, callback)
X.pack_stream.flush();
}
callback(ext);
callback(null, ext);
/*
ext.QueryVersion(function(err, version) {
ext.major = version[0];
ext.minor = version[1];
callback(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;
};
});
}

View file

@ -3,10 +3,10 @@
var x11 = require('..');
// TODO: move to templates
exports.requireExt = function(display, callback)
exports.requireExt = function(display, callback)
{
var X = display.client;
X.QueryExtension('XC-MISC', function(err, ext) {
X.QueryExtension('XC-MISC', function(err, ext) {
if (!ext.present)
return callback(new Error('extension not available'));
@ -17,7 +17,7 @@ exports.requireExt = function(display, callback)
X.pack_stream.pack('CCSSS', [ext.majorOpcode, 0, 2, clientMaj, clientMin]);
X.replies[X.seq_num] = [
function(buf, opt) {
var res = buf.unpack('SS');
var res = buf.unpack('SS');
return res;
},
cb
@ -31,7 +31,7 @@ exports.requireExt = function(display, callback)
X.pack_stream.pack('CCS', [ext.majorOpcode, 1, 1]);
X.replies[X.seq_num] = [
function(buf, opt) {
var res = buf.unpack('LL');
var res = buf.unpack('LL');
return {
startId: res[0],
count: res[1]
@ -60,9 +60,11 @@ exports.requireExt = function(display, callback)
}
ext.QueryVersion(1, 1, function(err, vers) {
if (err)
return callback(err);
ext.major = vers[0];
ext.minor = vers[1];
callback(ext);
callback(null, ext);
});
});
}

View file

@ -2,10 +2,10 @@
var x11 = require('..');
// TODO: move to templates
exports.requireExt = function(display, callback)
exports.requireExt = function(display, callback)
{
var X = display.client;
X.QueryExtension('XTEST', function(err, ext) {
X.QueryExtension('XTEST', function(err, ext) {
if (!ext.present)
return callback(new Error('extension not available'));
@ -39,7 +39,7 @@ exports.requireExt = function(display, callback)
X.pack_stream.flush();
}
callback(ext);
callback(null, ext);
});
}

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

@ -12,15 +12,15 @@ function readVisuals(bl, visuals, n_visuals, cb)
var visual = {};
bl.unpackTo( visual,
[
'L vid',
'C class',
'C bits_per_rgb',
'L vid',
'C class',
'C bits_per_rgb',
'S map_ent',
'L red_mask',
'L green_mask',
'L blue_mask',
'xxxx'
],
],
function() {
var vid = visual.vid;
// delete visual.vid;
@ -28,57 +28,65 @@ function readVisuals(bl, visuals, n_visuals, cb)
if (Object.keys(visuals).length == n_visuals)
cb()
else
readVisuals(bl, visuals, n_visuals, cb);
});
}
function readDepths(bl, display, depths, n_depths, cb)
{
if (n_depths == 0)
{
cb();
return;
}
bl.unpack( 'CxSxxxx', function(res) {
var dep = res[0];
var n_visuals = res[1];
var visuals = {};
readVisuals(bl, visuals, n_visuals, function()
{
depths[dep] = visuals;
if (Object.keys(depths).length == n_depths)
cb();
else
readDepths(bl, display, depths, n_depths, cb);
});
readVisuals(bl, visuals, n_visuals, cb);
});
}
function readScreens(bl, display, cbDisplayReady)
{
var numParsedDepths = 0;
var readDepths = function(bl, display, depths, n_depths, cb)
{
if (n_depths == 0)
{
cb();
return;
}
bl.unpack( 'CxSxxxx', function(res) {
var dep = res[0];
var n_visuals = res[1];
var visuals = {};
readVisuals(bl, visuals, n_visuals, function()
{
if (dep in depths) {
for (var visual in visuals) {
depths[dep][visual] = visuals[visual];
}
} else {
depths[dep] = visuals;
}
numParsedDepths++;
if (numParsedDepths == n_depths)
cb();
else
readDepths(bl, display, depths, n_depths, cb);
});
});
}
// for (i=0; i < display.screen_num; ++i)
{
var scr = {};
bl.unpackTo( scr,
[
'L root',
'L root',
'L default_colormap',
'L white_pixel',
'L white_pixel',
'L black_pixel',
'L input_masks',
'S pixel_width',
'S pixel_height',
'S mm_width',
'S mm_height',
'S min_installed_maps',
'L input_masks',
'S pixel_width',
'S pixel_height',
'S mm_width',
'S mm_height',
'S min_installed_maps',
'S max_installed_maps',
'L root_visual',
'L root_visual',
'C root_depth',
'C backing_stores',
'C root_depth',
'C num_depths'
],
],
function () {
var depths = {};
readDepths(bl, display, depths, scr.num_depths, function() {
@ -86,17 +94,17 @@ function readScreens(bl, display, cbDisplayReady)
scr.depths = depths;
delete scr.num_depths;
display.screen.push(scr);
if (display.screen.length == display.screen_num)
{
delete display.screen_num;
cbDisplayReady(display);
cbDisplayReady(null, display);
return;
} else {
readScreens(bl, display, cbDisplayReady);
}
});
});
});
}
}
@ -104,13 +112,18 @@ function readServerHello(bl, cb)
{
bl.unpack('C', function(res) {
if (res[0] == 0)
{
// conection time error
// unpack error (? TODO)
var err = new Error;
cb(err); // TODO: detect that this is error on xcore side
// unpack error
bl.unpack('Cxxxxxx', function (rlen) {
bl.get(rlen[0], function (reason) {
var err = new Error;
err.message = 'X server connection failed: ' + reason.toString();
cb(err);
});
});
// TODO: do we need to close stream from our side?
// TODO: api to close source stream via attached unpackstream
return;
@ -124,10 +137,10 @@ bl.unpack('C', function(res) {
'S major',
'S minor',
'S xlen',
'L release',
'L resource_base',
'L resource_mask',
'L motion_buffer_size',
'L release',
'L resource_base',
'L resource_mask',
'L motion_buffer_size',
'S vlen',
'S max_request_length',
'C screen_num',
@ -139,8 +152,8 @@ bl.unpack('C', function(res) {
'C min_keycode',
'C max_keycode',
'xxxx'
],
],
function()
{
var pvlen = xutil.padded_length(display.vlen);
@ -148,12 +161,12 @@ bl.unpack('C', function(res) {
// setup data to generate resource id
// TODO: cleaunup code here
var mask = display.resource_mask;
display.rsrc_shift = 0;
display.rsrc_shift = 0;
while (!( (mask >> display.rsrc_shift) & 1) )
display.rsrc_shift++;
display.rsrc_id = 0;
bl.get(pvlen, function(vendor)
bl.get(pvlen, function(vendor)
{
display.vendor = vendor.toString().substr(0, display.vlen); // utf8 by default?
@ -172,7 +185,7 @@ bl.unpack('C', function(res) {
readScreens(bl, display, cb);
}
});
}
}
});
}
);
@ -189,25 +202,28 @@ function getByteOrder() {
}
}
function writeClientHello(stream, displayNum, authHost)
function writeClientHello(stream, displayNum, authHost, authFamily)
{
getAuthString( displayNum, authHost, function( authType, authData ) {
getAuthString( displayNum, authHost, authFamily, function( err, cookie ) {
if (err) {
throw err;
}
var byte_order = getByteOrder();
var protocol_major = 11; // TODO: config? env?
var protocol_minor = 0;
stream.pack(
'CxSSSSxxpp',
[
'CxSSSSxxpp',
[
byte_order,
protocol_major,
protocol_minor,
authType.length,
authData.length,
authType,
authData
cookie.authName.length,
cookie.authData.length,
cookie.authName,
cookie.authData
]
);
stream.flush();
stream.flush();
});
}

View file

@ -7,7 +7,7 @@
// It should create a pleasant looking hex dumb by default:
//
// 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))
//
@ -258,4 +258,4 @@ console.log(hexy(data, format))
console.log("doen")
*/
exports.hexy = hexy
exports.hexy = hexy

View file

@ -1,13 +1,20 @@
var core = require('./xcore');
var em = require('./eventmask').eventMask;
var keysyms = require('./keysyms');
var server = require('./xserver');
module.exports.createClient = core.createClient;
module.exports.createServer = server.createServer;
module.exports.eventMask = em;
module.exports.keySyms = keysyms;
Object.defineProperty(module.exports, 'keySyms', {
enumerable: true,
get: function() { return require('./keysyms'); }
});
Object.defineProperty(module.exports, 'gcFunction', {
enumerable: true,
get: function() { return require('./gcfunction'); }
});
//TODO:
// keepe everything in namespace for consistensy (eventMask, keySyms, class, destination ...

File diff suppressed because it is too large Load diff

35
lib/keysyms.update.sh Executable file
View file

@ -0,0 +1,35 @@
#!/bin/bash -e
keysymdef_url=http://cgit.freedesktop.org/xorg/proto/xproto/plain/keysymdef.h
keysymdef=$(mktemp)
wget $keysymdef_url -O $keysymdef
(
echo "
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\\
This file is automatically translated from X.Org's xproto/keysymdef.h
Please, do not update this file with your hands, run $(basename "$0").
\\* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
module.exports = {
"
sed -r '
s/#ifdef\s+/\/\/ Group /
s/#endif.*//
s/#define\s+([^ ]+)(\s+)([^ ]+)\s*\/\*\s*([^\*]+[^ ])\s*\*\// \1:\2{ code: \3, description: "\4" },/
s/(\b)U\+([0-9A-F]+)(\b)/\1(\\u\2)\3/i
s/#define\s+([^ ]+)(\s+)([^ ]+)/ \1:\2{ code: \3, description: null },/
#s/#define\s+([^ ]+)(\s+[^ ]+)/ \1:\2,/
' $keysymdef
echo -n '
NoSymbol: 0
};'
) > "$(dirname "$0")/keysyms.js"
rm $keysymdef

View file

@ -23,7 +23,7 @@ function ReadFixedRequest(length, callback)
{
this.length = length;
this.callback = callback;
this.data = new Buffer(length);
this.data = Buffer.alloc(length);
this.received_bytes = 0;
}
@ -55,7 +55,7 @@ ReadFormatRequest.prototype.execute = function(bufferlist, tag1, tag2)
// maybe best approach is to wait all data required for format and then process fixed buffer
// TODO: byte order!!!
switch (arg) {
case 'C':
case 'C':
this.data.push(bufferlist.getbyte());
break;
case 'S':
@ -121,7 +121,7 @@ UnpackStream.prototype.unpackTo = function(destination, names_formats, callback)
{
var names = [];
var format = '';
for (var i=0; i < names_formats.length; ++i)
{
var off = 0;
@ -172,7 +172,7 @@ UnpackStream.prototype.resume = function()
}
UnpackStream.prototype.getbyte = function()
{
{
var res = 0;
var b = this.readlist[0];
if (this.offset + 1 < b.length)
@ -180,7 +180,7 @@ UnpackStream.prototype.getbyte = function()
res = b[this.offset];
this.offset++;
this.length--;
} else {
// last byte in current buffer, shift read list
@ -201,8 +201,8 @@ UnpackStream.prototype.pstr = function(str)
var len = xutil.padded_length(str.length);
if (len == 0)
return; // nothing to write
var buf = new Buffer(len);
buf.write(str, 'binary');
var buf = Buffer.alloc(len);
buf.write(str, 'binary');
this.write_queue.push(buf);
}
*/
@ -211,7 +211,7 @@ UnpackStream.prototype.pstr = function(str)
UnpackStream.prototype.pack = function(format, args)
{
var packetlength = 0;
var arg = 0;
for (var i = 0; i < format.length; ++i)
{
@ -231,27 +231,37 @@ UnpackStream.prototype.pack = function(format, args)
}
}
var buf = new Buffer(packetlength);
var buf = Buffer.alloc(packetlength);
var offset = 0;
var arg = 0;
for (var i = 0; i < format.length; ++i)
{
switch(format[i])
{
case 'x':
case 'x':
buf[offset++] = 0;
break;
case 'C':
var n = args[arg++];
buf[offset++] = n;
break;
case 's': // TODO: implement signed INT16!!!
case 's':
var n = args[arg++];
buf.writeInt16LE(n, offset);
offset += 2;
break;
case 'S':
var n = args[arg++];
buf[offset++] = n & 0xff;
buf[offset++] = (n >> 8) & 0xff;
break;
case 'l': // TODO: implement signed INT32!!!
case 'l':
var n = args[arg++];
buf.writeInt32LE(n, offset);
offset += 4;
break;
case 'L':
var n = args[arg++];
buf[offset++] = n & 0xff;
@ -259,12 +269,14 @@ UnpackStream.prototype.pack = function(format, args)
buf[offset++] = (n >> 16) & 0xff;
buf[offset++] = (n >> 24) & 0xff;
break;
case 'a': // string or buffer
case 'a': // string, buffer, or array
var str = args[arg++];
if (Buffer.isBuffer(str))
{
str.copy(buf, offset);
offset += str.length;
} else if(Array.isArray(str)) {
for(var item of str) buf[offset++] = item;
} else {
// TODO: buffer.write could be faster
for (var c = 0; c < str.length; ++c)
@ -281,7 +293,7 @@ UnpackStream.prototype.pack = function(format, args)
for (; c < len; ++c)
buf[offset++] = 0;
break;
}
}
}
this.write_queue.push(buf);
this.write_length += buf.length;
@ -290,7 +302,7 @@ UnpackStream.prototype.pack = function(format, args)
UnpackStream.prototype.flush = function(stream)
{
// TODO: measure performance benefit of
// TODO: measure performance benefit of
// creating and writing one big concatenated buffer
// TODO: check write result

View file

@ -6,7 +6,6 @@ var handshake = require('./handshake');
var EventEmitter = require('events').EventEmitter;
var PackStream = require('./unpackstream');
var coreRequestsTemplate = require('./corereqs');
var hexy = require('./hexy').hexy;
var Buffer = require('buffer').Buffer;
@ -18,30 +17,62 @@ var os = require('os');
var xerrors = require('./xerrors');
var coreRequests = require('./corereqs');
var stdatoms = require('./stdatoms');
var em = require('./eventmask').eventMask;
function XClient(stream, displayNum, screenNum, options)
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)
{
EventEmitter.call(this);
this.stream = stream;
this.options = options ? options : {};
// TODO: this is probably not used
this.core_requests = {};
this.ext_requests = {};
this.displayNum = displayNum;
this.screenNum = screenNum;
this.authHost = os.hostname();
}
util.inherits(XClient, EventEmitter);
XClient.prototype.init = function(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();
// data received from stream is dispached to
// read requests set by calls to .unpack and .unpackTo
//stream.pipe(pack_stream);
// pack_stream write requests are buffered and
// flushed to stream as result of call to .flush
// TODO: listen for drain event and flush automatically
// TODO: listen for drain event and flush automatically
//pack_stream.pipe(stream);
var client = this;
pack_stream.on('data', function( data ) {
@ -54,7 +85,7 @@ function XClient(stream, displayNum, screenNum, options)
//console.error(hexy(data, {prefix: 'to unpacker '}));
//for (var i=0; i < data.length; ++i)
// console.log('>>> ' + data[i]);
pack_stream.write(data);
pack_stream.write(data);
});
stream.on('end', function() {
client.emit('end');
@ -63,9 +94,27 @@ function XClient(stream, displayNum, screenNum, options)
this.pack_stream = pack_stream;
this.rsrc_id = 0; // generated for each new resource
this.seq_num = 0; // incremented in each request. (even if we don't expect reply)
this.seq2stack = {}; // debug: map seq_num to stack at the moment request was issued
var cli = this;
if (cli.options.debug) {
this.seq_num_ = 0;
this.seq2stack = {}; // debug: map seq_num to stack at the moment request was issued
Object.defineProperty(cli, "seq_num", {
set : function(v) {
cli.seq_num_ = v;
var err = new Error();
Error.captureStackTrace(err, arguments.callee);
err.timestamp = Date.now();
cli.seq2stack[client.seq_num] = err;
},
get: function() {
return cli.seq_num_;
}
});
} else {
this.seq_num = 0;
}
// in/out packets indexed by sequence ID
this.replies = {};
this.atoms = stdatoms;
@ -77,16 +126,20 @@ function XClient(stream, displayNum, screenNum, options)
return names;
})();
this.eventMask = em;
this.event_consumers = {}; // maps window id to eventemitter TODO: bad name
this.eventParsers = {};
this.eventParsers = {};
this.errorParsers = {};
this._extensions = {};
this.importRequestsFromTemplates(this, coreRequests);
this.startHandshake();
this._closing = false;
this._unusedIds = [];
}
util.inherits(XClient, EventEmitter);
// TODO: close() = set 'closing' flag, watch it in replies and writeQueue, terminate if empty
XClient.prototype.terminate = function()
@ -121,31 +174,19 @@ XClient.prototype.importRequestsFromTemplates = function(target, reqs)
for (var r in reqs)
{
// r is request name
target[r] = (function(reqName) {
target[r] = (function(reqName) {
var reqFunc = function req_proxy() {
if (client._closing)
throw new Error('client is in closing state');
// simple overflow handling (this means that currently there is no way to have more than 65535 requests in the queue
// TODO: edge cases testing
// TODO: edge cases testing
if (client.seq_num == 65535)
client.seq_num = 0;
else
client.seq_num++;
// disable long stack trace for the moment, it's too expensive
// performance when enabled (travis-ci worker, Xfvb): 70000 requests finished in 52196 ms, 1341.0989347842747 req/sec
// without: 70000 requests finished in 14904 ms, 4696.725711218465 req/sec
// MBPro, XQuartz: with 3600 req/sec, without 24200 req/sec
if (this.options.debug === true) {
var err = new Error();
err.name = reqName; //???
Error.captureStackTrace(err, arguments.callee);
err.timestamp = Date.now();
client.seq2stack[client.seq_num] = err;
}
// is it fast?
var args = Array.prototype.slice.call(req_proxy.arguments);
@ -168,45 +209,45 @@ XClient.prototype.importRequestsFromTemplates = function(target, reqs)
var value = req_proxy.arguments[1];
if (client.atoms[value]) {
-- client.seq_num;
return process.nextTick(function() {
return setImmediate(function() {
callback(undefined, client.atoms[value]);
});
} else {
client.pending_atoms[client.seq_num] = value;
}
}
// call template with input arguments (not including callback which is last argument TODO currently with callback. won't hurt)
//reqPack = reqTemplate.call(args);
var reqPack = reqTemplate.apply(this, req_proxy.arguments);
var reqPack = reqTemplate.apply(this, req_proxy.arguments);
var format = reqPack[0];
var requestArguments = reqPack[1];
if (callback)
this.replies[this.seq_num] = [reqReplTemplate[1], callback];
client.pack_stream.pack(format, requestArguments);
var b = client.pack_stream.write_queue[0];
client.pack_stream.flush();
} else if (templateType == 'Array'){
if (reqName === 'GetAtomName') {
var atom = req_proxy.arguments[0];
if (client.atom_names[atom]) {
-- client.seq_num;
return process.nextTick(function() {
return setImmediate(function() {
callback(undefined, client.atom_names[atom]);
});
} else {
client.pending_atoms[client.seq_num] = atom;
}
}
var format = reqTemplate[0];
var requestArguments = [];
for (var a = 0; a < reqTemplate[1].length; ++a)
requestArguments.push(reqTemplate[1][a]);
requestArguments.push(reqTemplate[1][a]);
for (var a in args)
requestArguments.push(args[a]);
@ -226,19 +267,26 @@ XClient.prototype.importRequestsFromTemplates = function(target, reqs)
XClient.prototype.AllocID = function()
{
// TODO: handle overflow (XCMiscGetXIDRange from XC_MISC ext)
// TODO: unused id buffer
this.display.rsrc_id++;
return (this.display.rsrc_id << this.display.rsrc_shift) + this.display.resource_base;
}
if (this._unusedIds.length > 0) {
return this._unusedIds.pop();
}
// TODO: handle overflow (XCMiscGetXIDRange from XC_MISC ext)
this.display.rsrc_id++;
return (this.display.rsrc_id << this.display.rsrc_shift) + this.display.resource_base;
};
XClient.prototype.unpackEvent = function(type, seq, extra, code, raw)
XClient.prototype.ReleaseID = function(id) {
this._unusedIds.push(id);
};
// TODO: move core events unpackers to corereqs.js
XClient.prototype.unpackEvent = function(type, seq, extra, code, raw, headerBuf)
{
var event = {}; // TODO: constructor & base functions
// Remove the most significant bit. See Chapter 1, Event Format section in X11 protocol
// specification
type = type & 0x7F;
event.type = type;
type = type & 0x7F;
event.type = type;
event.seq = seq;
var extUnpacker = this.eventParsers[type];
@ -251,9 +299,9 @@ XClient.prototype.unpackEvent = function(type, seq, extra, code, raw)
var values = raw.unpack('LLLssssSC');
//event.raw = values;
// TODO: use unpackTo???
event.name = [,,'KeyPress', 'KeyRelease', 'MouseDown', 'MouseUp', 'MouseMove'][type]
event.name = [,,'KeyPress', 'KeyRelease', 'ButtonPress', 'ButtonRelease', 'MotionNotify'][type]
event.time = extra;
event.keycode = code;
event.keycode = code;
event.root = values[0];
event.wid = values[1];
event.child = values[2];
@ -263,8 +311,8 @@ XClient.prototype.unpackEvent = function(type, seq, extra, code, raw)
event.y = values[6];
event.buttons = values[7];
event.sameScreen = values[8];
} else if (type == 7) { //EnterWindow
event.name = 'EnterWindow'
} else if (type == 7 || type == 8) { //EnterNotify || LeaveNotify
event.name = type === 7 ? 'EnterNotify' : 'LeaveNotify';
var values = raw.unpack('LLLssssSC');
event.root = values[0]
event.wid = values[1]
@ -274,7 +322,14 @@ XClient.prototype.unpackEvent = function(type, seq, extra, code, raw)
event.x = values[5];
event.y = values[6];
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
var values = raw.unpack('SSSSS');
event.name = 'Expose'
@ -285,35 +340,44 @@ XClient.prototype.unpackEvent = function(type, seq, extra, code, raw)
event.height = values[3];
event.count = values[4]; // TODO: ???
} else if (type == 16) { // CreateNotify
var values = raw.unpack('LLssSSSc');
var values = raw.unpack('LssSSSc');
event.name = 'CreateNotify'
event.parent = extra;
event.wid = values[0];
event.x = values[2];
event.y = values[3];
event.width = values[4];
event.height = values[5];
event.x = values[1];
event.y = values[2];
event.width = values[3];
event.height = values[4];
event.borderWidth = values[5];
event.overrideRedirect = values[6] ? true : false;
// x, y, width, height, border
} else if (type == 17) { // destroy notify
var values = raw.unpack('LL');
var values = raw.unpack('L');
event.name = 'DestroyNotify'
event.wid = extra;
event.wid1 = values[0];
event.event = extra;
event.wid = values[0];
} else if (type == 18) { // UnmapNotify
var values = raw.unpack('LC');
event.name = 'UnmapNotify'
event.event = extra;
event.wid = values[0];
event.fromConfigure = values[1] ? true : false;
} else if (type == 19) { // MapNotify
var values = raw.unpack('LLC');
var values = raw.unpack('LC');
event.name = 'MapNotify'
event.wid = extra;
event.wid1 = values[0];
event.event = extra;
event.wid = values[0];
event.overrideRedirect = values[1] ? true : false;
} else if (type == 20) {
var values = raw.unpack('LL');
var values = raw.unpack('L');
event.name = 'MapRequest'
event.parent = extra;
event.wid = values[0];
} else if (type == 22) {
var values = raw.unpack('LLssSSSC');
event.name = 'Overlap' //?
event.name = 'ConfigureNotify';
event.wid = extra;
// TODO rename
event.wid1 = values[0];
event.aboveSibling = values[1];
event.x = values[2];
@ -323,28 +387,30 @@ XClient.prototype.unpackEvent = function(type, seq, extra, code, raw)
event.borderWidth = values[6];
event.overrideRedirect = values[7];
} else if (type == 23) {
var values = raw.unpack('LLLssSSS');
event.name = 'ConfigureRequest'
var values = raw.unpack('LLssSSSS');
event.name = 'ConfigureRequest';
event.stackMode = code;
event.parent = extra;
event.wid = values[0];
event.x = values[1]
event.y = values[2]
event.width = values[3]
event.height = values[4]
event.borderWidth = values[5];
//
event.sibling = values[1];
event.x = values[2]
event.y = values[3]
event.width = values[4]
event.height = values[5]
event.borderWidth = values[6];
//
// The value-mask indicates which components were specified in
// the request. The value-mask and the corresponding values are reported as given
// in the request. The remaining values are filled in from the current geometry of the
// window, except in the case of sibling and stack-mode, which are reported as None
// and Above (respectively) if not given in the request.
event.mask = values[6];
event.mask = values[6];
// 322, [ 12582925, 0, 0, 484, 316, 1, 12, 0
//console.log([extra, code, values]);
} else if (type == 28) {// PropertyNotify
event.name = 'PropertyNotify';
var values = raw.unpack('LLC');
event.window = extra;
event.wid = extra;
event.atom = values[0];
event.time = values[1];
event.state = values[2];
@ -356,56 +422,75 @@ XClient.prototype.unpackEvent = function(type, seq, extra, code, raw)
event.selection = values[1];
} else if (type == 30) {// SelectionRequest
event.name = 'SelectionRequest';
// TODO check this
event.time = extra;
var values = raw.unpack('LLLLL');
event.owner = values[0];
event.requestor = values[1];
event.selection = values[2];
event.target = values[3];
event.property = values[4];
event.property = values[4];
} else if (type == 31) {// SelectionNotify
event.name = 'SelectionNotify';
// TODO check this
event.time = extra;
var values = raw.unpack('LLLL');
event.requestor = values[0];
event.selection = values[1];
event.target = values[2];
event.property = values[3];
event.property = values[3];
} else if (type == 33) {// ClientMessage
event.name = 'ClientMessage';
event.format = code;
event.wid = extra;
event.message_type = raw.unpack('L')[0];
var format = (code === 32) ? 'LLLLL' : (code === 16) ? 'SSSSSSSSSS' : 'CCCCCCCCCCCCCCCCCCCC';
event.data = raw.unpack(format, 4);
} else if (type == 34) {
event.name = 'MappingNotify';
event.request = headerBuf[4];
event.firstKeyCode = headerBuf[5];
event.count = headerBuf[6];
}
return event;
}
XClient.prototype.expectReplyHeader = function()
{
// TODO: BigReq!!!!
// TODO: move error parsers to corereqs.js
var client = this;
client.pack_stream.get( 8, function(headerBuf) {
var res = headerBuf.unpack('CCSL');
var type = res[0];
var seq_num = res[2];
var bad_value = res[3];
if (type == 0)
{
{
var error_code = res[1];
var error = new Error();
error.error = error_code;
error.seq = seq_num;
error.message = xerrors.errorText[error_code];
if (client.options.debug)
error.stack = client.seq2stack[error.seq]
if (client.options.debug) {
error.longstack = client.seq2stack[error.seq]
console.log(client.seq2stack[error.seq].stack);
}
// unpack error packet (32 bytes for all error types, 8 of them in CCSL header)
client.pack_stream.get(24, function(buf) {
// TODO: dispatch, use sequence number
//TODO: add more generic way to read common values
// if (error_code == 14)
{
var res = buf.unpack('LSC');
error.badParam = res[0]; // id: GC, WinID, Font, Atom etc; Value
error.minorOpcode = res[1];
error.majorOpcode = res[2];
var res = buf.unpack('SC');
error.message = xerrors.errorText[error_code];
error.badParam = bad_value;
error.minorOpcode = res[0];
error.majorOpcode = res[1];
var extUnpacker = client.errorParsers[error_code];
if (extUnpacker) {
extUnpacker(error, error_code, seq_num, bad_value, buf);
}
var handler = client.replies[seq_num];
if (handler) {
var callback = handler[1];
@ -413,33 +498,39 @@ XClient.prototype.expectReplyHeader = function()
if (!handled)
client.emit('error', error);
// TODO: should we delete seq2stack and reply even if there is no handler?
delete client.seq2stack[seq_num];
if (client.options.debug)
delete client.seq2stack[seq_num];
delete client.replies[seq_num];
} else
client.emit('error', error);
client.expectReplyHeader();
} );
} );
return;
} else if (type > 1)
{
client.pack_stream.get(24, function(buf) {
var extra = res[3];
var code = res[1];
var ev = client.unpackEvent(type, seq_num, extra, code, buf);
var ev = client.unpackEvent(type, seq_num, extra, code, buf, headerBuf);
// raw event 32-bytes packet (primarily for use in SendEvent);
// TODO: Event::pack based on event parameters, inverse to unpackEvent
ev.rawData = new Buffer(32);
ev.rawData = Buffer.alloc(32);
headerBuf.copy(ev.rawData);
buf.copy(ev.rawData, 8);
client.emit('event', ev);
var ee = client.event_consumers[ev.wid];
if (ee) {
ee.emit('event', ev);
}
if (ev.parent) {
ee = client.event_consumers[ev.parent];
if (ee)
ee.emit('child-event', ev);
}
client.expectReplyHeader();
} );
} );
return;
}
@ -448,7 +539,7 @@ XClient.prototype.expectReplyHeader = function()
var bodylength = 24 + length_total*4; // 24 is rest if 32-bytes header
client.pack_stream.get( bodylength, function( data ) {
var handler = client.replies[seq_num];
if (handler) {
var unpack = handler[0];
@ -464,32 +555,48 @@ XClient.prototype.expectReplyHeader = function()
}
// wait for new packet from server
client.expectReplyHeader();
});
}
});
}
);
}
XClient.prototype.startHandshake = function()
{
XClient.prototype.startHandshake = function() {
var client = this;
handshake.writeClientHello(this.pack_stream, this.displayNum, this.authHost);
handshake.readServerHello(this.pack_stream, function(display)
handshake.writeClientHello(this.pack_stream, this.displayNum, this.authHost, this.authFamily);
handshake.readServerHello(this.pack_stream, function(err, display)
{
// TODO: readServerHello can set error state in display
// emit error in that case
if (err) {
client.emit('error', err);
return;
}
client.expectReplyHeader();
client.display = display;
display.client = client;
client.emit('connect', display);
});
});
}
XClient.prototype.require = function(extName, callback)
{
var ext = require('./ext/' + extName);
ext.requireExt(this.display, callback);
}
var self = this;
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)
{
@ -509,8 +616,6 @@ module.exports.createClient = function(options, initCb)
throw new Error("Cannot parse display");
var host = displayMatch[1];
if (!host)
host = '127.0.0.1';
var displayNum = displayMatch[2];
if (!displayNum)
@ -518,9 +623,11 @@ module.exports.createClient = function(options, initCb)
var screenNum = displayMatch[3];
if (!screenNum)
screenNum = 0;
// open stream
var stream;
var connected = false;
var cbCalled = false;
var socketPath;
// try local socket on non-windows platforms
@ -529,45 +636,59 @@ module.exports.createClient = function(options, initCb)
if (process.platform == 'darwin' || process.platform == 'mac')
{
// socket path on OSX is /tmp/launch-(some id)/org.x:0
if (display[0] == '/')
if (display[0] == '/')
{
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;
if(socketPath)
{
stream = net.createConnection(socketPath);
}
else
{
stream = net.createConnection(6000 + parseInt(displayNum), host);
}
var client = new XClient(stream, displayNum, screenNum, options);
var client = new XClient(displayNum, screenNum, options);
var connectStream = function() {
if (socketPath) {
stream = net.createConnection(socketPath);
} else {
stream = net.createConnection(6000 + parseInt(displayNum), host);
}
stream.on('connect', function() {
connected = true;
client.init(stream);
});
stream.on('error', function(err) {
if (!connected && socketPath && err.code === 'ENOENT') {
// Retry connection with TCP on localhost
socketPath = null;
host = 'localhost';
connectStream();
} else if (initCb && !cbCalled) {
cbCalled = true;
initCb(err);
} else {
client.emit('error', err);
}
});
};
connectStream();
if (initCb)
{
client.on('connect', function(display) {
// Once connected don't call initCb on error, just emit
stream.removeListener('error', initCb);
stream.on('error', function(err) {
client.emit('error', err);
});
// opt-in BigReq
if (!options.disableBigRequests) {
client.require('big-requests', function(BigReq) {
client.require('big-requests', function(err, BigReq) {
if (err)
return initCb(err)
BigReq.Enable(function(err, maxLen) {
display.max_request_length = maxLen;
cbCalled = true;
initCb(undefined, display);
});
});
} else {
cbCalled = true;
initCb(undefined, display);
}
});
stream.on('error', initCb);
}
return client;
}

View file

@ -12,11 +12,15 @@
"X"
],
"homepage": "https://github.com/sidorares/node-x11",
"version": "0.4.0",
"version": "2.3.0",
"maintainers": [
{
"name": "Andrey Sidorov",
"email": "sidoares@yandex.ru"
},
{
"name": "Santiago Gimeno",
"email": "santiago.gimeno@gmail.com"
}
],
"bugs": {
@ -36,14 +40,15 @@
"node": "*"
},
"devDependencies": {
"mocha": "*",
"should": "*",
"sax": "*",
"async": "*",
"sinon": "*"
"async": "^3.0.1",
"mocha": "^7.1.2",
"sax": "^1.2.4",
"should": "^13.2.1",
"sinon": "^7.2.5"
},
"scripts": {
"test": "node test-runner.js",
"prepublish": "npm prune"
}
},
"dependencies": {}
}

View file

@ -2,90 +2,109 @@ var x11 = require('./lib');
var Mocha = require('mocha');
var fs = require('fs');
var path = require('path');
var util = require('util');
var async = require('async');
var mocha = new Mocha({
timeout : 80000
timeout : 80000,
reporter : 'spec'
});
// To be able to perform the tests we need the server:
// 1 - to support the dpms extension.
// 2 - dpms version is 1.1.
// 3 - to be dpms capable.
var run_dpms_test = function(cb) {
var client = x11.createClient(function(err, dpy) {
if (err) return cb(false);
var display = dpy;
var X = display.client;
X.require('dpms', function(ext) {
if (!util.isError(ext)) {
dpms = ext;
dpms.GetVersion(undefined, undefined, function(err, version) {
if (!err && version[0] === 1 && version[1] === 1) {
dpms.Capable(function(err, capable) {
if (!err && capable[0] == 1) cb(true);
else cb(false);
});
} else {
cb(false);
}
});
} else {
cb(false);
}
});
});
client.on('error', function() {
cb(false);
});
};
var run_xtest_test = function(cb) {
var client = x11.createClient(function(err, dpy) {
if (err) return cb(false);
var display = dpy;
var X = display.client;
X.require('dpms', function(ext) {
if (!util.isError(ext)) cb(true);
else cb(false);
});
});
client.on('error', function() {
cb(false);
});
};
// Add all files from test root directory
async.forEach(
fs.readdirSync('./test'),
function(file, cb) {
if (file === 'dpms.js') {
run_dpms_test(function(run) {
if (run) {
mocha.addFile(path.join('./test', file));
var run_dpms_test = function(X, cb) {
X.require('dpms', function(err, ext) {
if (!err) {
var dpms = ext;
dpms.GetVersion(undefined, undefined, function(err, version) {
if (!err && version[0] === 1 && version[1] === 1) {
dpms.Capable(function(err, capable) {
if (!err && capable[0] == 1) cb(true);
else cb(false);
});
} else {
cb(false);
}
cb();
});
} else if (file === 'xtest.js') {
run_xtest_test(function(run) {
if (run) {
mocha.addFile(path.join('./test', file));
}
cb();
});
} else {
mocha.addFile(path.join('./test', file));
cb();
cb(false);
}
},
function(err) {
mocha.run(function() {
process.exit();
});
});
};
var run_xtest_test = function(X, cb) {
X.require('xtest', function(err) {
if (!err) cb(true);
else cb(false);
});
};
var run_randr_test = function(X, cb) {
X.require('randr', function(err, ext) {
if (!err) {
var randr = ext;
randr.QueryVersion(1, 2, function(err, version) {
if (err) {
cb(false);
} else {
cb((version[0] === 1) && (version[1] >= 2));
}
});
} else {
cb(false);
}
});
};
x11.createClient(function(err, display) {
if (err) {
console.log('Could not create X client');
process.exit(-1);
}
);
var X = display.client;
// Add all files from test root directory
async.forEach(
fs.readdirSync('./test'),
function(file, cb) {
if (file === 'dpms.js') {
run_dpms_test(X, function(run) {
if (run) {
mocha.addFile(path.join('./test', file));
}
cb();
});
} else if (file === 'xtest.js') {
run_xtest_test(X, function(run) {
if (run) {
mocha.addFile(path.join('./test', file));
}
cb();
});
} else if (file === 'randr.js') {
run_randr_test(X, function(run) {
if (run) {
mocha.addFile(path.join('./test', file));
}
cb();
});
} else {
mocha.addFile(path.join('./test', file));
cb();
}
},
function() {
X.terminate();
X.on('end', function() {
mocha.run(function(failures) {
process.exit(failures);
});
});
}
);
});

103
test/allow-events.js Normal file
View file

@ -0,0 +1,103 @@
var x11 = require('../lib');
var should = require('should');
var assert = require('assert');
// This test was ported from X Test Suite @ http://cgit.freedesktop.org/xorg/test/xts/
function warp_pointer(wid, x, y, cb) {
var self = this;
this.X.QueryPointer(wid, function(err, old_pointer) {
if (err) {
return cb(err);
}
self.X.WarpPointer(0,
wid,
0,
0,
0,
0,
x,
y);
self.X.QueryPointer(wid, function(err, new_pointer) {
if (err) {
return cb(err);
}
cb(undefined, {
old_x : old_pointer.childX,
old_y : old_pointer.childY,
new_x : new_pointer.childX,
new_y : new_pointer.childY
});
});
});
}
function is_pointer_frozen(cb) {
var self = this;
warp_pointer.call(this, this.wid, 0, 0, function(err) {
if (err) {
return cb(err);
}
warp_pointer.call(self, self.wid, 1, 1, function(err, data) {
if (err) {
return cb(err);
}
cb(undefined, data.old_x === data.new_x);
});
});
}
describe('AllowEvents', function() {
before(function(done) {
var self = this;
var client = x11.createClient(function(err, dpy) {
should.not.exist(err);
self.X = dpy.client;
self.screen = dpy.screen[0];
self.root = self.screen.root;
self.wid = self.X.AllocID();
self.X.CreateWindow(self.wid,
self.root,
0,
0,
self.screen.pixel_width,
self.screen.pixel_height);
self.X.MapWindow(self.wid);
done();
});
client.on('error', function (err) {
console.error('Error : ', err);
});
});
it('if pointer is frozen by the client calling AllowEvents with AsyncPointer should resume the processing', function(done) {
var self = this;
this.X.GrabPointer(
this.wid,
false,
x11.eventMask.PointerMotion,
0, // sync
1, // async
0, // None
0, // None
0
);
is_pointer_frozen.call(this, function(err, frozen) {
should.not.exist(err);
frozen.should.equal(true);
self.X.AllowEvents(0, 0);
is_pointer_frozen.call(self, function(err, frozen) {
should.not.exist(err);
frozen.should.equal(false);
done();
});
});
});
});

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 my_name;
/*
@ -94,7 +94,7 @@ describe('Atoms and atom names cache', function() {
function(err) {
should.not.exist(err);
should.exist(my_name);
self.spy.reset();
self.spy.resetHistory();
self.X.InternAtom(true, my_name, function(err, atom) {
should.not.exist(err);
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);
});
});

93
test/change-property.js Normal file
View file

@ -0,0 +1,93 @@
var x11 = require('../lib');
var should = require('should');
var TEST_PROPERTY = 'My Test Property';
describe('ChangeProperty', 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.wid_helper = self.X.AllocID();
self.X.CreateWindow(self.wid, dpy.screen[0].root, 0, 0, 1, 1); // 1x1 pixel window
self.X.QueryTree(dpy.screen[0].root, function(err, list) {
should.not.exist(err);
list.children.indexOf(self.wid).should.not.equal(-1);
self.X.ChangeWindowAttributes(self.wid, { eventMask: x11.eventMask.PropertyChange });
done();
});
});
client.on('error', done);
});
it('should add a new WINDOW property with length 1', function(done) {
var self = this;
this.X.InternAtom(false, TEST_PROPERTY, function(err, atom) {
should.not.exist(err);
var raw = Buffer.alloc(4);
raw.writeUInt32LE(self.wid, 0);
self.X.ChangeProperty(0, self.wid, atom, self.X.atoms.WINDOW, 32, raw);
self.X.once('event', function(ev) {
ev.type.should.equal(28);
ev.atom.should.equal(atom);
ev.wid.should.equal(self.wid);
self.X.GetProperty(0, self.wid, atom, self.X.atoms.WINDOW, 0, 1000000000, function(err, prop) {
should.not.exist(err);
prop.data.readUInt32LE(0).should.equal(self.wid);
done();
});
});
});
});
it('should add a new WINDOW property with length 2', function(done) {
var self = this;
this.X.InternAtom(false, TEST_PROPERTY, function(err, atom) {
should.not.exist(err);
var raw = Buffer.from(new Array(8));
raw.writeUInt32LE(self.wid, 0);
raw.writeUInt32LE(self.wid_helper, 4);
self.X.ChangeProperty(0, self.wid, atom, self.X.atoms.ATOM, 32, raw);
self.X.once('event', function(ev) {
ev.type.should.equal(28);
ev.atom.should.equal(atom);
ev.wid.should.equal(self.wid);
self.X.GetProperty(0, self.wid, atom, self.X.atoms.ATOM, 0, 1000000000, function(err, prop) {
should.not.exist(err);
prop.data.readUInt32LE(0).should.equal(self.wid);
prop.data.readUInt32LE(4).should.equal(self.wid_helper);
done();
});
});
});
});
it('should replace a the WINDOW property with length 0', function(done) {
var self = this;
this.X.InternAtom(false, TEST_PROPERTY, function(err, atom) {
should.not.exist(err);
var raw = Buffer.alloc(0);
self.X.ChangeProperty(0, self.wid, atom, self.X.atoms.WINDOW, 32, raw);
self.X.once('event', function(ev) {
ev.type.should.equal(28);
ev.atom.should.equal(atom);
ev.wid.should.equal(self.wid);
self.X.GetProperty(0, self.wid, atom, self.X.atoms.WINDOW, 0, 1000000000, function(err, prop) {
should.not.exist(err);
prop.data.length.should.equal(0);
done();
});
});
});
});
after(function(done) {
this.X.DestroyWindow(this.wid);
this.X.terminate();
this.X.on('end', done);
});
});

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();
});
});

53
test/configure-request.js Normal file
View file

@ -0,0 +1,53 @@
var x11 = require('../lib');
var should = require('should');
describe('ConfigureRequest', function() {
before(function(done) {
var self = this;
var client = x11.createClient(function(err, dpy) {
should.not.exist(err);
self.X = dpy.client;
self.root = dpy.screen[0].root;
self.wid = self.X.AllocID();
/* self.X acts like a WM */
self.X.ChangeWindowAttributes(self.root, { eventMask: x11.eventMask.SubstructureRedirect });
self.X.CreateWindow(self.wid, self.root, 0, 0, 1, 1); // 1x1 pixel window
self.X.QueryTree(self.root, function(err, list) {
should.not.exist(err);
list.children.indexOf(self.wid).should.not.equal(-1);
done();
});
});
client.on('error', function (err) {
console.error('Error : ', err);
});
});
it('should be emitted to the WM if this.wid is configured by a client', 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('ConfigureRequest');
ev.x.should.equal(0);
ev.y.should.equal(20);
ev.width.should.equal(200);
ev.height.should.equal(300);
ev.wid.should.equal(self.wid);
done();
});
var X = dpy.client;
X.MoveResizeWindow(self.wid, 0, 20, 200, 300);
});
client.on('error', done);
});
after(function(done) {
this.X.DestroyWindow(this.wid);
this.X.on('end', done);
this.X.terminate();
});
});

View file

@ -22,34 +22,35 @@ describe('ConfigureWindow', function() {
});
});
client.on('error', done);
client.on('error', function (err) {
console.error('Error : ', err);
});
});
it('should ResizeWindow correctly to 200x300 pixels', function(done) {
var self = this;
this.X.ResizeWindow(this.wid, 200, 300);
this.X.once('event', function(ev) {
ev.type.should.equal(22); /* ConfigureNotify */
ev.height.should.equal(300);
ev.width.should.equal(200);
done();
});
this.X.ResizeWindow(this.wid, 200, 300);
});
it('should MoveWindow correctly to x: 100, y: 150 pixels', function(done) {
var self = this;
this.X.MoveWindow(this.wid, 100, 150);
this.X.once('event', function(ev) {
ev.type.should.equal(22); /* ConfigureNotify */
ev.x.should.equal(100);
ev.y.should.equal(150);
done();
});
this.X.MoveWindow(this.wid, 100, 150);
});
it('should MoveResizeWindow correctly to x: 200, y: 250 and 500x100 pixels', function(done) {
var self = this;
this.X.MoveResizeWindow(this.wid, 200, 250, 500, 100);
this.X.once('event', function(ev) {
ev.type.should.equal(22); /* ConfigureNotify */
ev.x.should.equal(200);
@ -58,22 +59,45 @@ describe('ConfigureWindow', function() {
ev.width.should.equal(500);
done();
});
this.X.MoveResizeWindow(this.wid, 200, 250, 500, 100);
});
it('should RaiseWindow correctly', function(done) {
var self = this;
this.X.RaiseWindow(this.wid);
this.X.once('event', function(ev) {
ev.type.should.equal(22); /* ConfigureNotify */
ev.aboveSibling.should.equal(self.wid_helper);
done();
});
this.X.RaiseWindow(this.wid);
});
it('should LowerWindow correctly', function(done) {
var self = this;
this.X.once('event', function(ev) {
ev.type.should.equal(22); /* ConfigureNotify */
ev.aboveSibling.should.equal(0); /* 0 -> no window below this */
done();
});
this.X.LowerWindow(this.wid);
});
it('should ignore invalid mask values', function(done) {
this.X.once('event', function(ev) {
ev.x.should.equal(0);
done();
});
this.X.ConfigureWindow(this.wid, { foo : 3, x : 0 }, function(err) {
console.log(err);
});
});
after(function(done) {
this.X.removeAllListeners('event');
this.X.DestroyWindow(this.wid);
this.X.DestroyWindow(this.wid_helper);
this.X.terminate();
this.X.on('end', done);
this.X.terminate();
});
});

View file

@ -52,9 +52,16 @@ describe('Client', function() {
});
it('returns error when connecting to non existent display', function(done) {
var errorCbCalled = false;
var client = x11.createClient({ display : ':44' }, function(err, display) {
assert(util.isError(err));
errorCbCalled = true;
done();
});
// TODO: stop writing to socket after first error
client.on('error', function() {
if (!errorCbCalled)
done('should not reach here before first done()');
});
});
});

View file

@ -48,4 +48,56 @@ describe('CreateWindow request', function() {
});
});
it('should work with any kind of attributes too', function(done) {
var wid = X.AllocID();
X.CreateWindow(wid, display.screen[0].root, 0, 0, 1, 1, 0, 0, 0, 0, { overrideRedirect : true }); // 1x1 pixel window
X.QueryTree(display.screen[0].root, function(err, list) {
should.not.exist(err);
list.children.should.containEql(wid);
done();
});
});
it('should emit CreateNotify event when', function(done) {
var wid = X.AllocID();
var root = display.screen[0].root;
X.ChangeWindowAttributes(root, { eventMask: x11.eventMask.SubstructureNotify });
X.on('event', function(ev) {
switch (ev.name) {
case 'CreateNotify':
ev.parent.should.equal(root);
ev.wid.should.equal(wid);
ev.x.should.equal(0);
ev.y.should.equal(0);
ev.width.should.equal(1);
ev.height.should.equal(1);
ev.borderWidth.should.equal(0);
ev.overrideRedirect.should.equal(false);
break;
case 'MapNotify':
ev.event.should.equal(root);
ev.wid.should.equal(wid);
ev.overrideRedirect.should.equal(false);
X.UnmapWindow(wid);
break;
case 'UnmapNotify':
ev.event.should.equal(root);
ev.wid.should.equal(wid);
ev.fromConfigure.should.equal(false);
X.DestroyWindow(wid);
break;
case 'DestroyNotify':
ev.event.should.equal(root);
ev.wid.should.equal(wid);
done();
break;
}
});
X.CreateWindow(wid, root, 0, 0, 1, 1); // 1x1 pixel window
X.MapWindow(wid);
})
});

View file

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

View file

@ -57,7 +57,7 @@ describe('Window property', function() {
assert.equal(ev.atom, X.atoms.WM_NAME, 'atom in notification should be same as in ChangeProperty');
// TODO: replace 0 with X.PropertyNewValue
assert.equal(ev.state, 0, 'atom in notification should be same as in ChangeProperty');
assert.equal(ev.window, wid, 'window in notification should be same as in ChangeProperty');
assert.equal(ev.wid, wid, 'window in notification should be same as in ChangeProperty');
done();
return;
}
@ -82,8 +82,8 @@ describe('Window property', function() {
});
});
it('should exist in the ListProperties result after inserted');
it('should not exist after GetProperty with delete flag called');
// it('should exist in the ListProperties result after inserted');
// it('should not exist after GetProperty with delete flag called');
//it('should not exist after GetProperty with delete flag called', function(done) {
// done();
//});

46
test/createGC.js Normal file
View file

@ -0,0 +1,46 @@
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
}
);
});
after(function(done) {
this.X.DestroyWindow(this.wid);
this.X.on('end', done);
this.X.terminate();
});
});

View file

@ -12,13 +12,10 @@ describe('DPMS extension', function() {
if (!err) {
display = dpy;
X = display.client;
X.require('dpms', function(ext) {
if (util.isError(ext)) {
done(ext);
} else {
dpms = ext;
done();
}
X.require('dpms', function(err, ext) {
should.not.exist(err);
dpms = ext;
done();
});
} else {
done(err);

View file

@ -5,27 +5,31 @@ var assert = require('assert');
describe('Client', function() {
var display;
beforeEach(function(done) {
var client = x11.createClient(function(err, dpy) {
console.log(err)
before(function(done) {
var client = x11.createClient({ debug: false }, function(err, dpy) {
should.not.exist(err);
display = dpy;
done(err);
done();
});
});
it('should emit error which is instance of Error with sequence number corresponding to source request', function(done) {
display.client.options.debug = true;
display.client.CreateWindow(); // should emit error
var times = 0;
//id, parentId, x, y, width, height, borderWidth, depth, _class, visual, values
display.client.CreateWindow(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {});
var seq = display.client.seq_num;
display.client.once('error', function(err) {
assert.equal(err.constructor, Error);
assert.equal(seq, err.seq);
display.client.CreateWindow(); // should emit error
seq = display.client.seq_num;
display.client.once('error', function(err) {
assert.equal(seq, err.seq);
done();
});
});
display.client.on('error', function(err) {
switch (++ times) {
case 11:
display.client.removeAllListeners('error');
done();
break;
default:
assert.equal(err.constructor, Error);
assert.equal(seq, err.seq);
display.client.CreateWindow(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {}); // should emit error
seq = display.client.seq_num;
}
});
});
});

63
test/randr.js Normal file
View file

@ -0,0 +1,63 @@
var x11 = require('../lib');
var async = require('async');
var should = require('should');
var assert = require('assert');
var util = require('util');
describe('RANDR extension', function() {
before(function(done) {
var self = this;
var client = x11.createClient(function(err, dpy) {
should.not.exist(err);
self.X = dpy.client;
self.screen = dpy.screen[0];
self.root = self.screen.root;
self.X.require('randr', function(err, ext) {
should.not.exist(err);
self.randr = ext;
/* We HAVE to QueryVersion before using it. Otherwise it does not work as expected */
self.randr.QueryVersion(1, 2, done);
});
});
client.on('error', done);
});
it('GetScreenInfo should get same px and mm width and height as in display.screen[0]', function(done) {
var self = this;
this.randr.GetScreenInfo(this.root, function(err, info) {
should.not.exist(err);
var active_screen = info.screens[info.sizeID];
active_screen.px_width.should.equal(self.screen.pixel_width);
active_screen.px_height.should.equal(self.screen.pixel_height);
active_screen.mm_width.should.equal(self.screen.mm_width);
active_screen.mm_height.should.equal(self.screen.mm_height);
done();
});
});
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) {
this.X.terminate();
this.X.on('end', done);
});
});

16
test/smoke-require-ext.js Normal file
View file

@ -0,0 +1,16 @@
var fs = require('fs');
var assert = require('assert');
describe('all extension modules', function() {
it('should not throw when require\'d', function(done) {
var extFolder = __dirname + '/../lib/ext';
fs.readdir(extFolder, function(err, list) {
assert.ifError(err);
list.forEach(function(name) {
var m = require(extFolder + '/' + name);
});
done();
});
});
})

View file

@ -12,13 +12,10 @@ describe('XTEST extension', function() {
if (!err) {
display = dpy;
X = display.client;
X.require('xtest', function(ext) {
if (util.isError(ext)) {
done(ext);
} else {
xtest = ext;
done();
}
X.require('xtest', function(err, ext) {
should.not.exist(err);
xtest = ext;
done();
});
} else {
done(err);