├── screenshots └── 2013-4-13-simple-shm.jpg ├── src ├── array.h ├── interface.h ├── proxy.h ├── array.cc ├── interface.cc ├── client.cc └── proxy.cc ├── examples ├── list_interfaces.coffee ├── util.coffee ├── simple-shm.coffee ├── mouse.coffee └── keyboard.coffee ├── binding.gyp ├── README.md ├── COPYING ├── client.js ├── tools └── nodeland-scanner.py └── client-protocol.js /screenshots/2013-4-13-simple-shm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheery/node-wayland/HEAD/screenshots/2013-4-13-simple-shm.jpg -------------------------------------------------------------------------------- /src/array.h: -------------------------------------------------------------------------------- 1 | namespace ArrayBuffer { 2 | Local New(size_t size, void* data); 3 | Local Wrap(size_t size, void* data); 4 | void SetData(Local array, size_t size, void* data); 5 | void* GetData(Local array, size_t* size); 6 | } 7 | -------------------------------------------------------------------------------- /examples/list_interfaces.coffee: -------------------------------------------------------------------------------- 1 | wl = require('../client') 2 | 3 | display = wl.connect() 4 | 5 | registry = display.get_registry() 6 | registry.listen { 7 | global: (id, name, version) -> 8 | console.log 'global', id, name, version 9 | } 10 | 11 | display.roundtrip() 12 | display.disconnect() 13 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "wayland_client", 5 | "sources": [ 6 | "src/array.cc", 7 | "src/interface.cc", 8 | "src/proxy.cc", 9 | "src/client.cc", 10 | ], 11 | "libraries": [ 12 | " object) { 5 | Interface* wli = ObjectWrap::Unwrap(object); 6 | return wli->interface; 7 | }; 8 | static void Init(Handle target); 9 | static Handle New(const Arguments& args); 10 | static Handle GetName(const Arguments& args); 11 | static Handle GetInterfaceByName(const Arguments& args); 12 | 13 | static Persistent constructor; 14 | }; 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | These are work-in-progress node.js bindings. I'll supply examples and screenshots when it can be used. 2 | 3 | It should work with wayland 1.4.0 and newer. 4 | 5 | Task List: 6 | 7 | * Verify that the Proxy::Marshal doesn't leak memory and works properly in every situation. 8 | * Verify that interface signature handling code is correct. 9 | * Write some more examples, see whether the new bindings work properly. 10 | * Verify that everything works. 11 | * Find a good method for listener to provide the correct proxy. 12 | * Provide interface parser, for users to access weston interfaces from their apps. 13 | * Write example for drag&drop and copy&paste. 14 | * Find some code that crashes, then put the system go into known state instead of crashing. 15 | * Provide wayland-egl bindings and tune cheery's webgl-bindings to work with wayland. 16 | * Write a small toolkit that provides every feature provided by wayland. 17 | * Find nice lib which loads PNG or JPG files in RGBA -format. 18 | * Write a tiny blitting engine. 19 | * Fill the task list with more tasks when you know what to do. 20 | 21 | 22 | Bitcoin address for donations: 19Cjd98dNM4SRoNP1t1qbYunYCz8TgjQAm (node-wayland) 23 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright © 2013 Henri Tuhola and other contributors (if they arise) 2 | 3 | Permission to use, copy, modify, distribute, and sell this software and its 4 | documentation for any purpose is hereby granted without fee, provided that 5 | the above copyright notice appear in all copies and that both that copyright 6 | notice and this permission notice appear in supporting documentation, and 7 | that the name of the copyright holders not be used in advertising or 8 | publicity pertaining to distribution of the software without specific, 9 | written prior permission. The copyright holders make no representations 10 | about the suitability of this software for any purpose. It is provided "as 11 | is" without express or implied warranty. 12 | 13 | THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 14 | INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 15 | EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 16 | CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 17 | DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 18 | TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 19 | OF THIS SOFTWARE. 20 | -------------------------------------------------------------------------------- /client.js: -------------------------------------------------------------------------------- 1 | var wl = require('./build/Release/wayland_client'); 2 | var interfaces = require('./client-protocol').interfaces; 3 | 4 | wl_display = interfaces.wl_display 5 | wl_display.prototype.roundtrip = function() { 6 | wl.display_roundtrip(this.proxy); 7 | }; 8 | 9 | wl_display.prototype.disconnect = function() { 10 | wl.display_disconnect(this.proxy); 11 | }; 12 | 13 | wl_display.prototype.fileno = function() { 14 | return wl.display_fileno(this.proxy); 15 | }; 16 | 17 | wl_display.prototype.flush = function() { 18 | wl.display_flush(this.proxy); 19 | }; 20 | 21 | wl_display.prototype.dispatch = function() { 22 | return wl.display_dispatch(this.proxy); 23 | }; 24 | 25 | exports.connect = function(name) { 26 | return new wl_display(wl.connect(name)); 27 | }; 28 | 29 | exports.connect_to_fd = function(fd) { 30 | return new wl_display(wl.connect_to_fd(fd)); 31 | }; 32 | exports.interfaces = interfaces; 33 | 34 | exports.create_anonymous_file = function() { 35 | return wl.create_anonymous_file(); 36 | }; 37 | 38 | exports.mmap_fd = function(fd, size) { 39 | data = wl.mmap_fd(fd, size); 40 | data.free = function() { wl.munmap_fd(this); } 41 | return data; 42 | }; 43 | 44 | exports.munmap_fd = function(data) { 45 | wl.munmap_fd(data); 46 | }; 47 | -------------------------------------------------------------------------------- /src/proxy.h: -------------------------------------------------------------------------------- 1 | struct paddle { 2 | Persistent object; 3 | }; 4 | 5 | class Proxy : public node::ObjectWrap { 6 | struct listener { 7 | Persistent value; 8 | }; 9 | 10 | static int 11 | wl_nodejs_proxy_dispatcher(const void *data, void *target, uint32_t opcode, 12 | const struct wl_message *message, union wl_argument *args); 13 | struct listener* listener; 14 | public: 15 | static inline Proxy* AsProxy(Handle object){ 16 | Proxy* proxy = ObjectWrap::Unwrap(object); 17 | if (proxy->proxy == NULL) return NULL; 18 | return proxy; 19 | }; 20 | 21 | void Free(); 22 | 23 | static void Init(Handle target); 24 | static Handle New(const Arguments& args); 25 | static Handle Destroy(const Arguments& args); 26 | static Handle GetId(const Arguments& args); 27 | static Handle GetClass(const Arguments& args); 28 | static Handle Create(const Arguments& args); 29 | static Handle Listen(const Arguments& args); 30 | static Handle Spy(const Arguments& args); 31 | static Handle Marshal(const Arguments& args); 32 | 33 | static Persistent constructor; 34 | 35 | const struct wl_interface* interface; 36 | struct wl_proxy* proxy; 37 | struct paddle* paddle; 38 | }; 39 | -------------------------------------------------------------------------------- /src/array.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace v8; 6 | 7 | extern "C" { 8 | #include 9 | #include 10 | #include 11 | } 12 | 13 | #include "array.h" 14 | 15 | static Persistent arraybuffer_constructor; 16 | 17 | namespace ArrayBuffer { 18 | void DemandInit() { 19 | if (arraybuffer_constructor.IsEmpty()) { 20 | Local global = Context::GetCurrent()->Global(); 21 | Local val = global->Get(String::New("ArrayBuffer")); 22 | assert(!val.IsEmpty() && "type not found: ArrayBuffer"); 23 | assert(val->IsFunction() && "not a constructor: ArrayBuffer"); 24 | arraybuffer_constructor = Persistent::New(val.As()); 25 | } 26 | }; 27 | Local New(size_t size, void* data) { 28 | DemandInit(); 29 | Local arg_size = Integer::NewFromUnsigned(size); 30 | Local array = arraybuffer_constructor->NewInstance(1, &arg_size); 31 | if (data != NULL) SetData(array, size, data); 32 | return array; 33 | } 34 | Local Wrap(size_t size, void* data) { 35 | DemandInit(); 36 | Local arg_size = Integer::NewFromUnsigned(size); 37 | Local array = arraybuffer_constructor->NewInstance(1, &arg_size); 38 | array->SetIndexedPropertiesToExternalArrayData(data, kExternalByteArray, size); 39 | return array; 40 | } 41 | 42 | void SetData(Local array, size_t size, void* data) { 43 | void* dst = array->GetIndexedPropertiesExternalArrayData(); 44 | memcpy(dst, data, size); 45 | } 46 | 47 | void* GetData(Local array, size_t* size) { 48 | *size = array->Get(String::NewSymbol("byteLength"))->IntegerValue(); 49 | return array->GetIndexedPropertiesExternalArrayData(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /examples/util.coffee: -------------------------------------------------------------------------------- 1 | wl = require '../client' 2 | fs = require 'fs' 3 | 4 | exports.get_globals = (registry) -> 5 | out = {} 6 | registry.listen global: (id, name, version) -> 7 | out[name] ?= [] 8 | out[name].push {id, version} 9 | 10 | return { 11 | bind_one: (name, version) -> 12 | unless out[name] and out[name].length > 0 13 | return null 14 | {id, newest} = out[name].pop() 15 | version ?= newest 16 | return registry.bind(id, wl.interfaces[name], version) 17 | } 18 | 19 | exports.create_buffer = (shm, width, height) -> 20 | format = shm.FORMAT_XRGB8888 21 | stride = width*4 22 | size = stride*height 23 | fd = wl.create_anonymous_file() 24 | fs.truncateSync(fd, size) 25 | data = wl.mmap_fd(fd, size) 26 | pool = shm.create_pool(fd, size) 27 | buffer = pool.create_buffer(0, width, height, stride, format) 28 | obj = {width, height, format, stride, size, data, buffer, busy:false} 29 | buffer.listen release: () -> obj.busy = false 30 | pool.destroy() 31 | fs.close(fd) 32 | return obj 33 | 34 | exports.create_surface 35 | 36 | exports.create_widget = (compositor, shell, shm, width, height) -> 37 | surface = compositor.create_surface() 38 | shellface = shell.get_shell_surface(surface) 39 | shellface.listen 40 | ping: (serial) -> shellface.pong(serial) 41 | 42 | front = exports.create_buffer(shm, width, height) 43 | back = exports.create_buffer(shm, width, height) 44 | 45 | return { 46 | surface, 47 | shellface, 48 | width, 49 | height, 50 | buffers: {front, back} 51 | flip: () -> 52 | {front, back} = @buffers 53 | surface.attach(back.buffer, 0, 0) 54 | surface.damage(0, 0, @width, @height) 55 | surface.commit() 56 | back.busy = true 57 | @buffers = front:back, back:front 58 | frame: (fn) -> 59 | if @callback then throw "frame already requested" 60 | @callback = @surface.frame() 61 | @callback.listen done: (time) => 62 | @callback.destroy() 63 | @callback = undefined 64 | fn.call(@, time / 1000) 65 | } 66 | -------------------------------------------------------------------------------- /examples/simple-shm.coffee: -------------------------------------------------------------------------------- 1 | wl = require '../client' 2 | fs = require 'fs' 3 | 4 | display = wl.connect() 5 | use = { 6 | wl_compositor: ['compositor', 1], 7 | wl_shell: ['shell', 1], 8 | wl_shm: ['shm', 1], 9 | } 10 | registry = display.get_registry() 11 | registry.listen { 12 | global: (id, name, version) -> 13 | target = use[name] 14 | if target 15 | [key, version] = target 16 | display[key] = registry.bind(id, wl.interfaces[name], version) 17 | } 18 | display.roundtrip() 19 | 20 | display.shm.formats = 0 21 | display.shm.listen { 22 | format: (format) -> 23 | display.shm.formats |= 1 << format 24 | } 25 | display.roundtrip() 26 | unless display.shm.formats & (1 << wl.FORMAT_XRGB8888) 27 | throw "SHM_FORMAT_XRGB8888 not available" 28 | 29 | window = {} 30 | window.surface = display.compositor.create_surface() 31 | window.shell_surface = display.shell.get_shell_surface(window.surface) 32 | window.shell_surface.listen { 33 | ping: (serial) -> window.shell_surface.pong(serial) 34 | } 35 | window.shell_surface.set_title("simple-shm") 36 | window.shell_surface.set_toplevel() 37 | #if you uncomment this line, remove the set_toplevel -line. 38 | #window.shell_surface.set_fullscreen(window.shell_surface.FULLSCREEN_METHOD_SCALE, 30, null) 39 | 40 | info = {} 41 | info.width = 256 42 | info.height = 256 43 | info.format = display.shm.FORMAT_XRGB8888 44 | info.stride = info.width*4 45 | info.size = info.stride*info.height 46 | info.fd = wl.create_anonymous_file() 47 | fs.truncateSync(info.fd, info.size) 48 | data = wl.mmap_fd(info.fd, info.size) 49 | 50 | for i in [0...info.width*info.height] 51 | x = i % info.width 52 | y = Math.floor(i / info.width) 53 | value = 0xA0 54 | x_even = Math.floor(x/16) % 2 == 0 55 | y_even = Math.floor(y/16) % 2 == 0 56 | if x_even ^ y_even 57 | value = 0x40 58 | data[i*4+3] = value 59 | data[i*4+2] = value 60 | data[i*4+1] = value 61 | data[i*4+0] = value 62 | 63 | pool = display.shm.create_pool(info.fd, info.size) 64 | buffer = pool.create_buffer(0, info.width, info.height, info.stride, info.format) 65 | info.busy = false 66 | buffer.listen { 67 | release: () -> info.busy = false 68 | } 69 | pool.destroy() 70 | fs.close(info.fd) 71 | 72 | window.surface.attach buffer, 0, 0 73 | window.surface.damage 0, 0, info.width, info.height 74 | window.surface.commit() 75 | info.busy = true 76 | 77 | ret = 0 78 | while ret != -1 79 | ret = display.dispatch() 80 | console.log ret 81 | -------------------------------------------------------------------------------- /src/interface.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace v8; 6 | 7 | extern "C" { 8 | #include 9 | #include 10 | #include 11 | } 12 | 13 | #include "interface.h" 14 | 15 | Persistent Interface::constructor; 16 | 17 | void Interface::Init(Handle target) { 18 | Local tpl = FunctionTemplate::New(New); 19 | tpl->SetClassName(String::NewSymbol("Interface")); 20 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 21 | NODE_SET_PROTOTYPE_METHOD(tpl, "get_name", GetName); 22 | constructor = Persistent::New(tpl->GetFunction()); 23 | target->Set(String::NewSymbol("Interface"), constructor); 24 | } 25 | 26 | Handle Interface::New(const Arguments& args) { 27 | HandleScope scope; 28 | Interface* interface = new Interface(); 29 | interface->interface = (const struct wl_interface*)External::Unwrap(args[0]); 30 | interface->Wrap(args.This()); 31 | return args.This(); 32 | }; 33 | Handle Interface::GetName(const Arguments& args) { 34 | HandleScope scope; 35 | const struct wl_interface* interface = Unwrap(args.This()); 36 | return scope.Close(String::New(interface->name)); 37 | } 38 | 39 | static const struct wl_interface* interfaces[] = { 40 | &wl_display_interface, 41 | &wl_registry_interface, 42 | &wl_callback_interface, 43 | &wl_compositor_interface, 44 | &wl_shm_pool_interface, 45 | &wl_shm_interface, 46 | &wl_buffer_interface, 47 | &wl_data_offer_interface, 48 | &wl_data_source_interface, 49 | &wl_data_device_interface, 50 | &wl_data_device_manager_interface, 51 | &wl_shell_interface, 52 | &wl_shell_surface_interface, 53 | &wl_surface_interface, 54 | &wl_seat_interface, 55 | &wl_pointer_interface, 56 | &wl_keyboard_interface, 57 | &wl_touch_interface, 58 | &wl_output_interface, 59 | &wl_region_interface, 60 | NULL, 61 | }; 62 | 63 | static const struct wl_interface* get_interface_by_name(const char* name) { 64 | for (int i = 0; interfaces[i] != NULL; i++) { 65 | if (strcmp(interfaces[i]->name, name) == 0) { return interfaces[i]; } 66 | } 67 | return NULL; 68 | } 69 | 70 | Handle Interface::GetInterfaceByName(const Arguments& args) { 71 | HandleScope scope; 72 | v8::String::AsciiValue string(args[0]); 73 | const struct wl_interface* interface = get_interface_by_name(*string); 74 | if (interface == NULL) return scope.Close(Undefined()); 75 | const unsigned argc = 1; 76 | Handle argv[argc] = { External::Wrap((void*)interface) }; 77 | Local instance = Interface::constructor->NewInstance(argc, argv); 78 | return scope.Close(instance); 79 | } 80 | -------------------------------------------------------------------------------- /examples/mouse.coffee: -------------------------------------------------------------------------------- 1 | wl = require '../client' 2 | fs = require 'fs' 3 | 4 | display = wl.connect() 5 | 6 | use = { 7 | wl_compositor: ['compositor', 1], 8 | wl_shell: ['shell', 1], 9 | wl_shm: ['shm', 1], 10 | wl_seat: ['seat', 1], 11 | } 12 | registry = display.get_registry() 13 | registry.listen { 14 | global: (id, name, version) -> 15 | target = use[name] 16 | if target 17 | [key, version] = target 18 | display[key] = registry.bind(id, wl.interfaces[name], version) 19 | } 20 | display.roundtrip() 21 | 22 | display.shm.formats = 0 23 | display.shm.listen { 24 | format: (format) -> 25 | display.shm.formats |= 1 << format 26 | } 27 | 28 | display.seat.capabilities = 0 29 | display.seat.listen { 30 | capabilities: (flags) -> this.capabilities = flags 31 | } 32 | display.roundtrip() 33 | unless display.shm.formats & (1 << wl.FORMAT_XRGB8888) 34 | throw "SHM_FORMAT_XRGB8888 not available" 35 | unless display.seat.capabilities & display.seat.CAPABILITY_POINTER 36 | throw "seat has no mouse" 37 | 38 | window = {} 39 | window.surface = display.compositor.create_surface() 40 | window.shell_surface = display.shell.get_shell_surface(window.surface) 41 | window.shell_surface.listen { 42 | ping: (serial) -> window.shell_surface.pong(serial) 43 | } 44 | window.shell_surface.set_title("simple-shm") 45 | window.shell_surface.set_toplevel() 46 | 47 | info = {} 48 | info.width = 256 49 | info.height = 256 50 | info.format = display.shm.FORMAT_XRGB8888 51 | info.stride = info.width*4 52 | info.size = info.stride*info.height 53 | info.fd = wl.create_anonymous_file() 54 | fs.truncateSync(info.fd, info.size) 55 | data = wl.mmap_fd(info.fd, info.size) 56 | 57 | for i in [0...info.width*info.height] 58 | x = i % info.width 59 | y = Math.floor(i / info.width) 60 | value = 0xA0 61 | x_even = Math.floor(x/16) % 2 == 0 62 | y_even = Math.floor(y/16) % 2 == 0 63 | if x_even ^ y_even 64 | value = 0x40 65 | data[i*4+3] = value 66 | data[i*4+2] = value 67 | data[i*4+1] = value 68 | data[i*4+0] = value 69 | 70 | pool = display.shm.create_pool(info.fd, info.size) 71 | buffer = pool.create_buffer(0, info.width, info.height, info.stride, info.format) 72 | info.busy = false 73 | buffer.listen { 74 | release: () -> info.busy = false 75 | } 76 | pool.destroy() 77 | fs.close(info.fd) 78 | 79 | window.surface.attach buffer, 0, 0 80 | window.surface.damage 0, 0, info.width, info.height 81 | window.surface.commit() 82 | info.busy = true 83 | 84 | display.roundtrip() 85 | 86 | console.log "window surface id #{window.surface.proxy.get_id()}" 87 | 88 | # the enter and leave events return an ID to proxy, though 89 | # I'm not sure which way to retrieve it yet. 90 | # so I just drop out an id. 91 | 92 | # interface requests a cursor image at enter. I give it nothing 93 | # so the cursor disappears when it goes into my window. 94 | 95 | # the seat seems to not allow me to grab it for the program. 96 | 97 | pointer = display.seat.get_pointer() 98 | pointer.listen { 99 | motion: (time, x, y) -> 100 | console.log "motion #{time} (#{x},#{y})" 101 | button: (serial, time, button, state) -> 102 | console.log "button #{serial} #{time} #{button} #{state}" 103 | if state == 1 and this.inside == window.surface.proxy.get_id() 104 | window.shell_surface.move(display.seat, serial) 105 | axis: (time, axis, value) -> 106 | console.log "button #{time} #{axis} #{value}" 107 | enter: (serial, which, x, y) -> 108 | console.log "enter #{serial} #{which} (#{x},#{y})" 109 | this.set_cursor(serial, null, 0, 0) 110 | this.inside = which 111 | leave: (serial, which) -> 112 | console.log "leave #{serial} #{which}" 113 | this.inside = null 114 | } 115 | 116 | ret = 0 117 | while ret != -1 118 | ret = display.dispatch() 119 | console.log ret 120 | -------------------------------------------------------------------------------- /examples/keyboard.coffee: -------------------------------------------------------------------------------- 1 | wl = require '../client' 2 | util = require './util' 3 | 4 | display = wl.connect() 5 | registry = display.get_registry() 6 | 7 | globals = util.get_globals(registry) 8 | display.roundtrip() 9 | 10 | compositor = globals.bind_one('wl_compositor', 1) 11 | shell = globals.bind_one('wl_shell', 1) 12 | shm = globals.bind_one('wl_shm', 1) 13 | seat = globals.bind_one('wl_seat', 1) 14 | data_device_manager = globals.bind_one('wl_data_device_manager', 1) 15 | 16 | shm.formats = 0 17 | shm.listen format: (format) -> @formats |= 1 << format 18 | seat.capabilities = 0 19 | seat.listen capabilities: (flags) -> @capabilities = flags 20 | display.roundtrip() 21 | unless shm.formats & (1 << wl.FORMAT_XRGB8888) 22 | throw "SHM_FORMAT_XRGB8888 not available" 23 | unless seat.capabilities & seat.CAPABILITY_POINTER 24 | throw "seat has no mouse" 25 | unless seat.capabilities & seat.CAPABILITY_KEYBOARD 26 | throw "seat has no keyboard" 27 | 28 | cursor = util.create_buffer(shm, 32, 32) 29 | cursor.surface = compositor.create_surface() 30 | update_cursor = () -> 31 | for i in [0...cursor.width*cursor.height] 32 | x = (i % cursor.width) 33 | y = Math.floor(i / cursor.width) 34 | x_even = Math.floor(x/4) % 2 == 0 35 | y_even = Math.floor(y/4) % 2 == 0 36 | value = 0xff 37 | if x_even ^ y_even 38 | value = 0x40 39 | cursor.data[i*4+3] = value 40 | cursor.data[i*4+2] = value 41 | cursor.data[i*4+1] = value 42 | cursor.data[i*4+0] = value 43 | 44 | cursor.surface.attach(cursor.buffer, 0, 0) 45 | cursor.surface.damage(0, 0, cursor.width, cursor.height) 46 | cursor.surface.commit() 47 | cursor.busy = true 48 | 49 | 50 | window = util.create_widget(compositor, shell, shm, 256, 256) 51 | window.shellface.set_toplevel() 52 | window.fullscreen = false 53 | 54 | redraw = (time) -> 55 | {width, height, data, busy} = window.buffers.back 56 | if busy then throw "buffers busy, can't draw" 57 | 58 | offset = Math.sin(time) 59 | 60 | for i in [0...width*height] 61 | x = (i % width) 62 | y = Math.floor(i / width) 63 | value = 0x80 + offset * 0x80 64 | x_even = Math.floor(x/16) % 2 == 0 65 | y_even = Math.floor(y/16) % 2 == 0 66 | if x_even ^ y_even 67 | value = 0x40 68 | data[i*4+3] = value 69 | data[i*4+2] = value 70 | data[i*4+1] = value 71 | data[i*4+0] = value 72 | 73 | window.frame(redraw) 74 | window.flip() 75 | 76 | redraw(0) 77 | 78 | keyboard = seat.get_keyboard() 79 | keyboard.listen { 80 | enter: (serial, surface, keys) -> 81 | console.log "keyboard enter", serial, surface, keys 82 | leave: (serial, surface) -> 83 | console.log "keyboard leave", serial, surface 84 | key: (serial, time, key, state) -> 85 | console.log "key", serial, time, key, state 86 | if key == 87 and state == 1 87 | if window.fullscreen 88 | window.fullscreen = false 89 | window.shellface.set_toplevel() 90 | else 91 | window.fullscreen = true 92 | window.shellface.set_fullscreen( 93 | window.shellface.FULLSCREEN_METHOD_SCALE, 94 | 30, 95 | null 96 | ) 97 | } 98 | 99 | pointer = seat.get_pointer() 100 | pointer.inside = null 101 | pointer.listen { 102 | motion: (time, x, y) -> 103 | # console.log "motion #{time} (#{x},#{y})" 104 | button: (serial, time, button, state) -> 105 | console.log "button #{serial} #{time} #{button} #{state}" 106 | console.log 'this inside', this.inside 107 | console.log 'window surface', window.surface 108 | if state == 1 and this.inside == window.surface 109 | window.shellface.move(seat, serial) 110 | axis: (time, axis, value) -> 111 | # console.log "button #{time} #{axis} #{value}" 112 | enter: (serial, which, x, y) -> 113 | console.log "enter #{serial} #{which} (#{x},#{y})" 114 | this.set_cursor(serial, cursor.surface, 32, 32) 115 | update_cursor() 116 | this.inside = which 117 | leave: (serial, which) -> 118 | # console.log "leave #{serial} #{which}" 119 | this.inside = null 120 | } 121 | 122 | # create_data_source 123 | data_device = data_device_manager.get_data_device(seat) 124 | data_device.proxy.listen (args...) -> 125 | console.log args 126 | 127 | ret = 0 128 | while ret != -1 129 | ret = display.dispatch() 130 | console.log ret 131 | -------------------------------------------------------------------------------- /tools/nodeland-scanner.py: -------------------------------------------------------------------------------- 1 | from lxml import etree 2 | from sys import stdout, stderr 3 | 4 | def mk_comment(text): 5 | return '/*'+text.strip(' ')+'*/\n' 6 | 7 | header_gen = u"""var wl = require('./build/Release/wayland_client'); 8 | var interfaces = {}; 9 | exports.interfaces = interfaces; 10 | """ 11 | interface_template = u"""function %(name)s(proxy) { 12 | this.proxy = proxy; 13 | proxy.spy(this); 14 | }; 15 | %(name)s.prototype = { 16 | %(prototype)s 17 | }; 18 | %(name)s.interface = wl.get_interface_by_name(%(name)r); 19 | interfaces[%(name)r] = %(name)s 20 | 21 | """ 22 | default_proxy_template = """ listen: function(listeners) { 23 | var self = this; 24 | this.proxy.listen(function(name){ 25 | if (listeners[name]) listeners[name].apply(self, Array.prototype.slice.call(arguments, 1)); 26 | }); 27 | }, 28 | destroy: function() { 29 | this.proxy.destroy() 30 | }""" 31 | request_template = u""" %(name)s: function(%(args)s) { 32 | this.proxy.marshal(%(argv)s); 33 | }""" 34 | factory_template = u""" %(name)s: function(%(args)s) { 35 | new_id = this.proxy.create(%(spy)s.interface); 36 | this.proxy.marshal(%(argv)s); 37 | return new %(spy)s(new_id); 38 | }""" 39 | factory_dyn_template = u""" %(name)s: function(%(args)s) { 40 | new_id = this.proxy.create(spy.interface); 41 | this.proxy.marshal(%(argv)s); 42 | return new spy(new_id); 43 | }""" 44 | 45 | def generate_request(index, request): 46 | data = dict(name = request.attrib['name'], magic=index) 47 | args = [] 48 | argv = [str(index)] 49 | template = request_template 50 | for node in request: 51 | if node.tag == 'arg' and node.attrib['type'] in ('int', 'uint', 'fd', 'string', 'fixed'): 52 | name = node.attrib['name'] 53 | args.append(name) 54 | argv.append(name) 55 | elif node.tag == 'arg' and node.attrib['type'] == 'object': 56 | name = node.attrib['name'] 57 | args.append(name) 58 | argv.append('(%(var)s === null || %(var)s === undefined)?%(var)s:%(var)s.proxy' % dict(var=name)) 59 | elif node.tag == 'arg' and node.attrib['type'] == 'new_id': 60 | if 'interface' in node.attrib: 61 | template = factory_template 62 | data['spy'] = node.attrib['interface'] 63 | argv.append('new_id') 64 | else: 65 | template = factory_dyn_template 66 | args.append('spy, version') 67 | argv.append('spy.interface.get_name(), version, new_id') 68 | elif node.tag == 'description': 69 | continue 70 | else: 71 | stderr.write("%s %r %r" % (node.tag, node.attrib, node[:])) 72 | stderr.write("\n") 73 | raise Exception("unknown argument node %r" % node) 74 | data['args'] = ', '.join(args) 75 | data['argv'] = ', '.join(argv) 76 | return template % data 77 | 78 | def generate_enum_const(enum_name, const): 79 | data = dict( 80 | name=('%s_%s' % (enum_name, const.attrib['name'])).upper(), 81 | value=const.attrib['value'], 82 | ) 83 | return '%(name)s: %(value)s' % data 84 | 85 | def generate_interface(interface): 86 | count = 0 87 | methods = [] 88 | enums = [] 89 | name = interface.attrib['name'] 90 | if name != 'wl_display': 91 | methods.append(default_proxy_template) 92 | for node in interface: 93 | if node.tag == 'description': 94 | continue 95 | elif node.tag == 'request': 96 | methods.append(generate_request(count, node)) 97 | count += 1 98 | elif node.tag == 'event': 99 | continue 100 | elif node.tag == 'enum': 101 | enum_name = node.attrib['name'] 102 | for node in node: 103 | if node.tag == 'entry': 104 | enums.append(generate_enum_const(enum_name, node)) 105 | elif node.tag == 'description': 106 | continue 107 | else: 108 | stderr.write("%s %r %r" % (node.tag, node.attrib, node[:])) 109 | stderr.write("\n") 110 | raise Exception("unknown entry node %r" % node) 111 | elif node.tag == etree.Comment: 112 | continue 113 | else: 114 | raise Exception("unknown interface node %r" % node) 115 | return dict(prototype=',\n'.join(methods + enums)) 116 | 117 | root = etree.parse("wayland.xml").getroot() 118 | stdout.write(header_gen) 119 | for node in root: 120 | if node.tag == 'copyright': 121 | stdout.write(mk_comment(node.text).encode('utf-8')) 122 | elif node.tag == 'interface': 123 | data = generate_interface(node) 124 | data.update(node.attrib) 125 | stdout.write((interface_template % data).encode('utf-8')) 126 | else: 127 | raise Exception("unknown root node") 128 | -------------------------------------------------------------------------------- /src/client.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace v8; 6 | 7 | extern "C" { 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | } 14 | 15 | #include "array.h" 16 | #include "interface.h" 17 | #include "proxy.h" 18 | 19 | //class Display : public node::ObjectWrap { 20 | // struct wl_display* display; 21 | // static inline Display* AsDisplay(Handle object) { 22 | // Display* display = ObjectWrap::Unwrap(object); 23 | // if (display->display == NULL) return NULL; 24 | // return display; 25 | // }; 26 | //public: 27 | // static void Init(Handle target) { 28 | // Local tpl = FunctionTemplate::New(New); 29 | // tpl->SetClassName(String::NewSymbol("Display")); 30 | // tpl->InstanceTemplate()->SetInternalFieldCount(1); 31 | // NODE_SET_PROTOTYPE_METHOD(tpl, "close", Close); 32 | // NODE_SET_PROTOTYPE_METHOD(tpl, "fileno", Fileno); 33 | // NODE_SET_PROTOTYPE_METHOD(tpl, "flush", Flush); 34 | // NODE_SET_PROTOTYPE_METHOD(tpl, "roundtrip", Roundtrip); 35 | // //tpl->PrototypeTemplate()->Set( String::NewSymbol("close"), FunctionTemplate::New(Close)->GetFunction()); 36 | // Persistent constructor = Persistent::New(tpl->GetFunction()); 37 | // target->Set(String::NewSymbol("Display"), constructor); 38 | // }; 39 | // static Handle New(const Arguments& args) { 40 | // HandleScope scope; 41 | // Display* display = new Display(); 42 | // display->display = wl_display_connect(NULL); 43 | // if (display->display == NULL) return ThrowException(String::New("failed to connect")); 44 | // display->Wrap(args.This()); 45 | // return args.This(); 46 | // }; 47 | // 48 | //}; 49 | static Handle Connect(const Arguments& args) { 50 | HandleScope scope; 51 | const char* name; 52 | if (args[0]->IsUndefined() || args[0]->IsNull()) { 53 | name = NULL; 54 | } else { 55 | v8::String::AsciiValue string(args[0]); 56 | name = *string; 57 | } 58 | wl_display* display = wl_display_connect(name); 59 | if (display == NULL) return ThrowException(String::New("failed to connect")); 60 | const unsigned argc = 2; 61 | Handle argv[argc] = { 62 | External::Wrap(display), 63 | External::Wrap((void*)&wl_display_interface), 64 | }; 65 | Local instance = Proxy::constructor->NewInstance(argc, argv); 66 | return scope.Close(instance); 67 | } 68 | 69 | static Handle ConnectToFd(const Arguments& args) { 70 | HandleScope scope; 71 | wl_display* display = wl_display_connect_to_fd(args[0]->IntegerValue()); 72 | if (display == NULL) return ThrowException(String::New("failed to connect")); 73 | const unsigned argc = 2; 74 | Handle argv[argc] = { 75 | External::Wrap(display), 76 | External::Wrap((void*)&wl_display_interface), 77 | }; 78 | Local instance = Proxy::constructor->NewInstance(argc, argv); 79 | return scope.Close(instance); 80 | } 81 | 82 | static Handle DisplayDisconnect(const Arguments& args) { 83 | HandleScope scope; 84 | Proxy* display = Proxy::AsProxy(args[0]->ToObject()); 85 | if (display == NULL) return ThrowException(String::New("not connected")); 86 | wl_display_disconnect((wl_display*)display->proxy); 87 | display->Free(); 88 | return scope.Close(Undefined()); 89 | }; 90 | static Handle DisplayFileno(const Arguments& args) { 91 | HandleScope scope; 92 | Proxy* display = Proxy::AsProxy(args[0]->ToObject()); 93 | if (display == NULL) return ThrowException(String::New("not connected")); 94 | return scope.Close(Integer::New(wl_display_get_fd((wl_display*)display->proxy))); 95 | }; 96 | 97 | static Handle DisplayFlush(const Arguments& args) { 98 | HandleScope scope; 99 | Proxy* display = Proxy::AsProxy(args[0]->ToObject()); 100 | if (display == NULL) return ThrowException(String::New("not connected")); 101 | wl_display_flush((wl_display*)display->proxy); 102 | return scope.Close(Undefined()); 103 | }; 104 | 105 | static Handle DisplayRoundtrip(const Arguments& args) { 106 | HandleScope scope; 107 | Proxy* display = Proxy::AsProxy(args[0]->ToObject()); 108 | if (display == NULL) return ThrowException(String::New("not connected")); 109 | wl_display_roundtrip((wl_display*)display->proxy); 110 | return scope.Close(Undefined()); 111 | }; 112 | 113 | static Handle DisplayDispatch(const Arguments& args) { 114 | HandleScope scope; 115 | Proxy* display = Proxy::AsProxy(args[0]->ToObject()); 116 | if (display == NULL) return ThrowException(String::New("not connected")); 117 | return scope.Close(Integer::New(wl_display_dispatch((wl_display*)display->proxy))); 118 | }; 119 | 120 | static Handle MemoryMapFile(const Arguments& args) { 121 | HandleScope scope; 122 | size_t size = args[1]->IntegerValue(); 123 | void* data = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, args[0]->IntegerValue(), 0); 124 | return scope.Close(ArrayBuffer::Wrap(size, data)); 125 | }; 126 | 127 | static Handle MemoryUnmapFile(const Arguments& args) { 128 | HandleScope scope; 129 | size_t size; 130 | void* data = ArrayBuffer::GetData(args[0]->ToObject(), &size); 131 | munmap(data, size); 132 | return scope.Close(Undefined()); 133 | }; 134 | 135 | static 136 | int create_anon_file() { 137 | char name[] = "/tmp/wayland-shared-XXXXXX"; 138 | int fd = mkostemp(name, O_CLOEXEC); 139 | if (fd >= 0) unlink(name); 140 | return fd; 141 | } 142 | 143 | static Handle CreateAnonFile(const Arguments& args) { 144 | HandleScope scope; 145 | return scope.Close(Integer::New(create_anon_file())); 146 | }; 147 | 148 | static void Init(Handle target) { 149 | Interface::Init(target); 150 | Proxy::Init(target); 151 | target->Set(String::NewSymbol("connect"), 152 | FunctionTemplate::New(Connect)->GetFunction()); 153 | target->Set(String::NewSymbol("connect_to_fd"), 154 | FunctionTemplate::New(ConnectToFd)->GetFunction()); 155 | target->Set(String::NewSymbol("get_interface_by_name"), 156 | FunctionTemplate::New(Interface::GetInterfaceByName)->GetFunction()); 157 | target->Set(String::NewSymbol("display_disconnect"), 158 | FunctionTemplate::New(DisplayDisconnect)->GetFunction()); 159 | target->Set(String::NewSymbol("display_fileno"), 160 | FunctionTemplate::New(DisplayFileno)->GetFunction()); 161 | target->Set(String::NewSymbol("display_flush"), 162 | FunctionTemplate::New(DisplayFlush)->GetFunction()); 163 | target->Set(String::NewSymbol("display_roundtrip"), 164 | FunctionTemplate::New(DisplayRoundtrip)->GetFunction()); 165 | target->Set(String::NewSymbol("display_dispatch"), 166 | FunctionTemplate::New(DisplayDispatch)->GetFunction()); 167 | target->Set(String::NewSymbol("mmap_fd"), 168 | FunctionTemplate::New(MemoryMapFile)->GetFunction()); 169 | target->Set(String::NewSymbol("munmap_fd"), 170 | FunctionTemplate::New(MemoryUnmapFile)->GetFunction()); 171 | target->Set(String::NewSymbol("create_anonymous_file"), 172 | FunctionTemplate::New(CreateAnonFile)->GetFunction()); 173 | 174 | // target->Set(String::NewSymbol("wl_display_interface"), External::Wrap(NULL));//const_cast(&wl_display_interface))); 175 | // 176 | // target->Set(String::NewSymbol("wl_registry_interface"), External::Wrap((void*)&wl_registry_interface)); 177 | // target->Set(String::NewSymbol("wl_callback_interface"), External::Wrap((void*)&wl_callback_interface)); 178 | // target->Set(String::NewSymbol("wl_compositor_interface"), External::Wrap((void*)&wl_compositor_interface)); 179 | // target->Set(String::NewSymbol("wl_shm_pool_interface"), External::Wrap((void*)&wl_shm_pool_interface)); 180 | // target->Set(String::NewSymbol("wl_shm_interface"), External::Wrap((void*)&wl_shm_interface)); 181 | // target->Set(String::NewSymbol("wl_buffer_interface"), External::Wrap((void*)&wl_buffer_interface)); 182 | // target->Set(String::NewSymbol("wl_data_offer_interface"), External::Wrap((void*)&wl_data_offer_interface)); 183 | // target->Set(String::NewSymbol("wl_data_source_interface"), External::Wrap((void*)&wl_data_source_interface)); 184 | // target->Set(String::NewSymbol("wl_data_device_interface"), External::Wrap((void*)&wl_data_device_interface)); 185 | // target->Set(String::NewSymbol("wl_data_device_manager_interface"), External::Wrap((void*)&wl_data_device_manager_interface)); 186 | // target->Set(String::NewSymbol("wl_shell_interface"), External::Wrap((void*)&wl_shell_interface)); 187 | // target->Set(String::NewSymbol("wl_shell_surface_interface"), External::Wrap((void*)&wl_shell_surface_interface)); 188 | // target->Set(String::NewSymbol("wl_surface_interface"), External::Wrap((void*)&wl_surface_interface)); 189 | // target->Set(String::NewSymbol("wl_seat_interface"), External::Wrap((void*)&wl_seat_interface)); 190 | // target->Set(String::NewSymbol("wl_pointer_interface"), External::Wrap((void*)&wl_pointer_interface)); 191 | // target->Set(String::NewSymbol("wl_keyboard_interface"), External::Wrap((void*)&wl_keyboard_interface)); 192 | // target->Set(String::NewSymbol("wl_touch_interface"), External::Wrap((void*)&wl_touch_interface)); 193 | // target->Set(String::NewSymbol("wl_output_interface"), External::Wrap((void*)&wl_output_interface)); 194 | // target->Set(String::NewSymbol("wl_region_interface"), External::Wrap((void*)&wl_region_interface)); 195 | } 196 | NODE_MODULE(wayland_client, Init); 197 | -------------------------------------------------------------------------------- /src/proxy.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace v8; 6 | 7 | extern "C" { 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | // for the stub 14 | #include 15 | } 16 | 17 | #include "array.h" 18 | #include "interface.h" 19 | #include "proxy.h" 20 | 21 | Persistent Proxy::constructor; 22 | 23 | void Proxy::Init(Handle target) { 24 | Local tpl = FunctionTemplate::New(New); 25 | tpl->SetClassName(String::NewSymbol("Proxy")); 26 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 27 | NODE_SET_PROTOTYPE_METHOD(tpl, "destroy", Destroy); 28 | NODE_SET_PROTOTYPE_METHOD(tpl, "get_id", GetId); 29 | NODE_SET_PROTOTYPE_METHOD(tpl, "get_class", GetClass); 30 | NODE_SET_PROTOTYPE_METHOD(tpl, "create", Create); 31 | NODE_SET_PROTOTYPE_METHOD(tpl, "listen", Listen); 32 | NODE_SET_PROTOTYPE_METHOD(tpl, "spy", Spy); 33 | NODE_SET_PROTOTYPE_METHOD(tpl, "marshal", Marshal); 34 | constructor = Persistent::New(tpl->GetFunction()); 35 | target->Set(String::NewSymbol("Proxy"), constructor); 36 | } 37 | 38 | Handle Proxy::New(const Arguments& args) { 39 | HandleScope scope; 40 | Proxy* proxy = new Proxy(); 41 | proxy->proxy = (wl_proxy*)External::Unwrap(args[0]); 42 | proxy->interface = (const struct wl_interface*)External::Unwrap(args[1]); 43 | proxy->listener = NULL; 44 | proxy->paddle = (struct paddle*)malloc(sizeof(struct paddle*)); 45 | proxy->paddle->object = Persistent::New(args.This()); 46 | proxy->Wrap(args.This()); 47 | wl_proxy_set_user_data(proxy->proxy, proxy->paddle); 48 | return args.This(); 49 | }; 50 | 51 | void Proxy::Free() { 52 | if (listener) { 53 | listener->value.Dispose(); 54 | free(listener); 55 | listener = NULL; 56 | } 57 | if (paddle) { 58 | paddle->object.Dispose(); 59 | free(paddle); 60 | } 61 | proxy = NULL; 62 | } 63 | 64 | Handle Proxy::Destroy(const Arguments& args) { 65 | HandleScope scope; 66 | Proxy* proxy = AsProxy(args.This()); 67 | if (proxy == NULL) return ThrowException(String::New("proxy is dead")); 68 | wl_proxy_destroy(proxy->proxy); 69 | proxy->Free(); 70 | return scope.Close(Undefined()); 71 | }; 72 | 73 | Handle Proxy::GetId(const Arguments& args) { 74 | HandleScope scope; 75 | Proxy* proxy = AsProxy(args.This()); 76 | if (proxy == NULL) return ThrowException(String::New("proxy is dead")); 77 | uint32_t id = wl_proxy_get_id(proxy->proxy); 78 | return scope.Close(Integer::New(id)); 79 | }; 80 | 81 | Handle Proxy::GetClass(const Arguments& args) { 82 | HandleScope scope; 83 | Proxy* proxy = AsProxy(args.This()); 84 | if (proxy == NULL) return ThrowException(String::New("proxy is dead")); 85 | const char* classname = wl_proxy_get_class(proxy->proxy); 86 | return scope.Close(String::New(classname)); 87 | }; 88 | 89 | Handle Proxy::Create(const Arguments& args) { 90 | HandleScope scope; 91 | Proxy* proxy = AsProxy(args.This()); 92 | if (proxy == NULL) return ThrowException(String::New("proxy is dead")); 93 | const struct wl_interface* interface = Interface::Unwrap(args[0]->ToObject()); 94 | wl_proxy* child_proxy = wl_proxy_create(proxy->proxy, interface); 95 | 96 | const unsigned argc = 2; 97 | Handle argv[argc] = { 98 | External::Wrap(child_proxy), 99 | External::Wrap((void*)interface), 100 | }; 101 | Local instance = Proxy::constructor->NewInstance(argc, argv); 102 | return scope.Close(instance); 103 | } 104 | 105 | Handle Proxy::Listen(const Arguments& args) { 106 | HandleScope scope; 107 | Proxy* proxy = AsProxy(args.This()); 108 | if (proxy == NULL) return ThrowException(String::New("proxy is dead")); 109 | if (proxy->listener != NULL) return ThrowException(String::New("listener added already")); 110 | proxy->listener = (struct listener*)malloc(sizeof(struct listener)); 111 | proxy->listener->value = Persistent::New(args[0]); 112 | wl_proxy_add_dispatcher(proxy->proxy, wl_nodejs_proxy_dispatcher, proxy->listener, proxy->paddle); 113 | return scope.Close(Undefined()); 114 | } 115 | 116 | Handle Proxy::Spy(const Arguments& args) { 117 | HandleScope scope; 118 | Proxy* proxy = AsProxy(args.This()); 119 | if (proxy == NULL) return ThrowException(String::New("proxy is dead")); 120 | proxy->paddle->object.Dispose(); 121 | proxy->paddle->object = Persistent::New(args[0]->ToObject()); 122 | return scope.Close(Undefined()); 123 | } 124 | 125 | static 126 | int wl_argument_from_value(union wl_argument* arg, Local value, int which, int nullable) { 127 | switch (which) { 128 | case 'i': arg->i = value->Int32Value(); break; 129 | case 'u': arg->u = value->Uint32Value(); break; 130 | case 'f': arg->f = wl_fixed_from_double(value->NumberValue()); break; 131 | case 's': 132 | { 133 | // Copy to memory if things break down. 134 | v8::String::Utf8Value string(value); 135 | arg->s = *string; 136 | } break; 137 | case 'o': 138 | case 'n': 139 | { 140 | if (value->IsUndefined() || value->IsNull()) { 141 | arg->o = NULL; 142 | if (!nullable) return 0; 143 | } else { 144 | Proxy* proxy = Proxy::AsProxy(value->ToObject()); 145 | arg->o = (wl_object*)proxy->proxy; 146 | } 147 | } break; 148 | case 'a': 149 | // Remember to unallocate this. 150 | arg->a = (struct wl_array*)malloc(sizeof(struct wl_array)); 151 | arg->a->alloc = 0; 152 | arg->a->data = ArrayBuffer::GetData(value->ToObject(), &arg->a->size); 153 | break; 154 | case 'h': arg->h = value->IntegerValue(); break; 155 | default: 156 | return 0; 157 | } 158 | return 1; 159 | } 160 | 161 | static 162 | void wl_cleanup_argument(union wl_argument* arg, int which) { 163 | switch (which) { 164 | case 'i': break; 165 | case 'u': break; 166 | case 'f': break; 167 | case 's': break; 168 | case 'o': 169 | case 'n': break; 170 | case 'a': free((void*)arg->a); break; 171 | case 'h': break; 172 | } 173 | } 174 | 175 | Local wl_argument_to_value(union wl_argument* arg, int which) { 176 | switch (which) { 177 | case 'i': return Integer::New(arg->i); 178 | case 'u': return Integer::NewFromUnsigned(arg->u); 179 | case 'f': return Number::New(wl_fixed_to_double(arg->f)); 180 | case 's': return String::New(arg->s); 181 | case 'o': 182 | case 'n': { 183 | if (arg->o == NULL) { 184 | return *Null(); 185 | } else { 186 | struct paddle* paddle = (struct paddle*)wl_proxy_get_user_data((wl_proxy*)arg->o); 187 | return *paddle->object; 188 | } 189 | } 190 | case 'a': return ArrayBuffer::New(arg->a->size, arg->a->data); 191 | case 'h': return Integer::New(arg->h); 192 | default: 193 | printf("unknown argument signature=%c\n", which); 194 | assert(false); 195 | } 196 | return *Undefined(); 197 | } 198 | 199 | Handle Proxy::Marshal(const Arguments& args) { 200 | HandleScope scope; 201 | Proxy* proxy = AsProxy(args.This()); 202 | if (proxy == NULL) return ThrowException(String::New("proxy is dead")); 203 | uint32_t opcode = args[0]->Uint32Value(); 204 | const char* signature = proxy->interface->methods[opcode].signature; 205 | int nargs = 0; 206 | for (int i = 0; signature[i]; i++) { 207 | if (signature[i] != '?') nargs++; 208 | } 209 | if (nargs != args.Length() - 1) { 210 | return ThrowException(String::New("argc doesn't match the signature")); 211 | } 212 | union wl_argument *argv = (union wl_argument*)calloc(nargs, sizeof *argv); 213 | int j = 0; 214 | int arg_ok = 1; 215 | for (int i = 0; i < nargs; i++) { 216 | int nullable = 0; 217 | if (signature[j] == '?') { nullable = 1; j++; } 218 | arg_ok &= wl_argument_from_value(argv+i, args[i+1], signature[j++], nullable); 219 | } 220 | if (arg_ok) wl_proxy_marshal_array(proxy->proxy, opcode, argv); 221 | j = 0; 222 | for (int i = 0; i < nargs; i++) { 223 | /*int nullable = 0;*/ 224 | if (signature[j] == '?') { /*nullable = 1;*/ j++; } 225 | wl_cleanup_argument(argv+i, signature[j++]); 226 | } 227 | free(argv); 228 | if (!arg_ok) return ThrowException(String::New("bad argument list")); 229 | return scope.Close(Undefined()); 230 | } 231 | 232 | inline int isnum(char ch) { return ('0' <= ch && ch <= '9'); } 233 | 234 | int 235 | Proxy::wl_nodejs_proxy_dispatcher(const void *data, void *target, uint32_t opcode, 236 | const struct wl_message *message, union wl_argument *args) 237 | { 238 | struct listener* listener = (struct listener*)data; 239 | // printf("proxy data %p with target %p and opcode %i\n", data, target, opcode); 240 | // SelfRef* ref = (SelfRef*)target; 241 | // Proxy* proxy = AsProxy(ref->object); 242 | Persistent callback = Persistent::Cast(listener->value); 243 | 244 | unsigned argc = 1; 245 | 246 | for (int i = 0; message->signature[i] > 0; i++) { 247 | char which = message->signature[i]; 248 | if (which != '?' && !isnum(which)) argc++; 249 | } 250 | 251 | Local argv[argc]; 252 | argv[0] = String::New(message->name); 253 | int j = 0; 254 | for (unsigned i = 0; i < argc-1; i++) { 255 | /*int nullable = 0;*/ 256 | if (message->signature[j] == '?') { /*nullable = 1;*/ j++; } 257 | if (isnum(message->signature[j])) { /*version;*/ j++; } 258 | argv[i+1] = wl_argument_to_value(args+i, message->signature[j++]); 259 | } 260 | callback->Call(Context::GetCurrent()->Global(), argc, argv); 261 | 262 | 263 | 264 | // const char *signature; 265 | // int nargs, nrefs; 266 | // 267 | // jvalue *jargs; 268 | // JNIEnv *env; 269 | // jobject jlistener, jproxy; 270 | // jmethodID mid; 271 | // 272 | // proxy = target; 273 | // 274 | // env = wl_jni_get_env(); 275 | // 276 | // /* Count the number of arguments and references */ 277 | // nargs = 0; 278 | // nrefs = 0; 279 | // for (signature = message->signature; *signature != '\0'; ++signature) { 280 | // switch (*signature) { 281 | // /* These types will require references */ 282 | // case 'f': 283 | // case 's': 284 | // case 'o': 285 | // case 'a': 286 | // case 'n': 287 | // ++nrefs; 288 | // /* These types don't require references */ 289 | // case 'u': 290 | // case 'i': 291 | // case 'h': 292 | // ++nargs; 293 | // break; 294 | // case '?': 295 | // break; 296 | // } 297 | // } 298 | // 299 | // jargs = malloc((nargs + 1) * sizeof *jargs); 300 | // if (jargs == NULL) { 301 | // wl_jni_throw_OutOfMemoryError(env, NULL); 302 | // goto exception_check; 303 | // } 304 | // 305 | // if ((*env)->PushLocalFrame(env, nrefs + 2) < 0) 306 | // goto exception_check; 307 | // 308 | // jproxy = wl_jni_proxy_to_java(env, proxy); 309 | // if ((*env)->ExceptionCheck(env)) { 310 | // goto pop_local_frame; 311 | // } else if (jproxy == NULL) { 312 | // wl_jni_throw_NullPointerException(env, "Proxy should not be null"); 313 | // goto pop_local_frame; 314 | // } 315 | // 316 | // jlistener = (*env)->GetObjectField(env, jproxy, Proxy.listener); 317 | // if ((*env)->ExceptionCheck(env)) 318 | // goto pop_local_frame; 319 | // 320 | // wl_jni_arguments_to_java(env, args, jargs + 1, message->signature, nargs, 321 | // JNI_TRUE, 322 | // (jobject(*)(JNIEnv *, struct wl_object *))&wl_jni_proxy_to_java); 323 | // 324 | // if ((*env)->ExceptionCheck(env)) 325 | // goto pop_local_frame; 326 | // 327 | // jargs[0].l = jproxy; 328 | // mid = ((jmethodID *)data)[opcode]; 329 | // (*env)->CallVoidMethodA(env, jlistener, mid, jargs); 330 | // 331 | //pop_local_frame: 332 | // (*env)->PopLocalFrame(env, NULL); 333 | // free(jargs); 334 | // 335 | //exception_check: 336 | // if ((*env)->ExceptionCheck(env)) 337 | // return -1; 338 | // else 339 | // return 0; 340 | 341 | return 0; 342 | } 343 | -------------------------------------------------------------------------------- /client-protocol.js: -------------------------------------------------------------------------------- 1 | var wl = require('./build/Release/wayland_client'); 2 | var interfaces = {}; 3 | exports.interfaces = interfaces; 4 | /* 5 | Copyright © 2008-2011 Kristian Høgsberg 6 | Copyright © 2010-2011 Intel Corporation 7 | 8 | Permission to use, copy, modify, distribute, and sell this 9 | software and its documentation for any purpose is hereby granted 10 | without fee, provided that the above copyright notice appear in 11 | all copies and that both that copyright notice and this permission 12 | notice appear in supporting documentation, and that the name of 13 | the copyright holders not be used in advertising or publicity 14 | pertaining to distribution of the software without specific, 15 | written prior permission. The copyright holders make no 16 | representations about the suitability of this software for any 17 | purpose. It is provided "as is" without express or implied 18 | warranty. 19 | 20 | THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS 21 | SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 22 | FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 23 | SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 24 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 25 | AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 26 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 27 | THIS SOFTWARE. 28 | */ 29 | function wl_display(proxy) { 30 | this.proxy = proxy; 31 | proxy.spy(this); 32 | }; 33 | wl_display.prototype = { 34 | sync: function() { 35 | new_id = this.proxy.create(wl_callback.interface); 36 | this.proxy.marshal(0, new_id); 37 | return new wl_callback(new_id); 38 | }, 39 | get_registry: function() { 40 | new_id = this.proxy.create(wl_registry.interface); 41 | this.proxy.marshal(1, new_id); 42 | return new wl_registry(new_id); 43 | }, 44 | ERROR_INVALID_OBJECT: 0, 45 | ERROR_INVALID_METHOD: 1, 46 | ERROR_NO_MEMORY: 2 47 | }; 48 | wl_display.interface = wl.get_interface_by_name('wl_display'); 49 | interfaces['wl_display'] = wl_display 50 | 51 | function wl_registry(proxy) { 52 | this.proxy = proxy; 53 | proxy.spy(this); 54 | }; 55 | wl_registry.prototype = { 56 | listen: function(listeners) { 57 | var self = this; 58 | this.proxy.listen(function(name){ 59 | if (listeners[name]) listeners[name].apply(self, Array.prototype.slice.call(arguments, 1)); 60 | }); 61 | }, 62 | destroy: function() { 63 | this.proxy.destroy() 64 | }, 65 | bind: function(name, spy, version) { 66 | new_id = this.proxy.create(spy.interface); 67 | this.proxy.marshal(0, name, spy.interface.get_name(), version, new_id); 68 | return new spy(new_id); 69 | } 70 | }; 71 | wl_registry.interface = wl.get_interface_by_name('wl_registry'); 72 | interfaces['wl_registry'] = wl_registry 73 | 74 | function wl_callback(proxy) { 75 | this.proxy = proxy; 76 | proxy.spy(this); 77 | }; 78 | wl_callback.prototype = { 79 | listen: function(listeners) { 80 | var self = this; 81 | this.proxy.listen(function(name){ 82 | if (listeners[name]) listeners[name].apply(self, Array.prototype.slice.call(arguments, 1)); 83 | }); 84 | }, 85 | destroy: function() { 86 | this.proxy.destroy() 87 | } 88 | }; 89 | wl_callback.interface = wl.get_interface_by_name('wl_callback'); 90 | interfaces['wl_callback'] = wl_callback 91 | 92 | function wl_compositor(proxy) { 93 | this.proxy = proxy; 94 | proxy.spy(this); 95 | }; 96 | wl_compositor.prototype = { 97 | listen: function(listeners) { 98 | var self = this; 99 | this.proxy.listen(function(name){ 100 | if (listeners[name]) listeners[name].apply(self, Array.prototype.slice.call(arguments, 1)); 101 | }); 102 | }, 103 | destroy: function() { 104 | this.proxy.destroy() 105 | }, 106 | create_surface: function() { 107 | new_id = this.proxy.create(wl_surface.interface); 108 | this.proxy.marshal(0, new_id); 109 | return new wl_surface(new_id); 110 | }, 111 | create_region: function() { 112 | new_id = this.proxy.create(wl_region.interface); 113 | this.proxy.marshal(1, new_id); 114 | return new wl_region(new_id); 115 | } 116 | }; 117 | wl_compositor.interface = wl.get_interface_by_name('wl_compositor'); 118 | interfaces['wl_compositor'] = wl_compositor 119 | 120 | function wl_shm_pool(proxy) { 121 | this.proxy = proxy; 122 | proxy.spy(this); 123 | }; 124 | wl_shm_pool.prototype = { 125 | listen: function(listeners) { 126 | var self = this; 127 | this.proxy.listen(function(name){ 128 | if (listeners[name]) listeners[name].apply(self, Array.prototype.slice.call(arguments, 1)); 129 | }); 130 | }, 131 | destroy: function() { 132 | this.proxy.destroy() 133 | }, 134 | create_buffer: function(offset, width, height, stride, format) { 135 | new_id = this.proxy.create(wl_buffer.interface); 136 | this.proxy.marshal(0, new_id, offset, width, height, stride, format); 137 | return new wl_buffer(new_id); 138 | }, 139 | destroy: function() { 140 | this.proxy.marshal(1); 141 | }, 142 | resize: function(size) { 143 | this.proxy.marshal(2, size); 144 | } 145 | }; 146 | wl_shm_pool.interface = wl.get_interface_by_name('wl_shm_pool'); 147 | interfaces['wl_shm_pool'] = wl_shm_pool 148 | 149 | function wl_shm(proxy) { 150 | this.proxy = proxy; 151 | proxy.spy(this); 152 | }; 153 | wl_shm.prototype = { 154 | listen: function(listeners) { 155 | var self = this; 156 | this.proxy.listen(function(name){ 157 | if (listeners[name]) listeners[name].apply(self, Array.prototype.slice.call(arguments, 1)); 158 | }); 159 | }, 160 | destroy: function() { 161 | this.proxy.destroy() 162 | }, 163 | create_pool: function(fd, size) { 164 | new_id = this.proxy.create(wl_shm_pool.interface); 165 | this.proxy.marshal(0, new_id, fd, size); 166 | return new wl_shm_pool(new_id); 167 | }, 168 | ERROR_INVALID_FORMAT: 0, 169 | ERROR_INVALID_STRIDE: 1, 170 | ERROR_INVALID_FD: 2, 171 | FORMAT_ARGB8888: 0, 172 | FORMAT_XRGB8888: 1 173 | }; 174 | wl_shm.interface = wl.get_interface_by_name('wl_shm'); 175 | interfaces['wl_shm'] = wl_shm 176 | 177 | function wl_buffer(proxy) { 178 | this.proxy = proxy; 179 | proxy.spy(this); 180 | }; 181 | wl_buffer.prototype = { 182 | listen: function(listeners) { 183 | var self = this; 184 | this.proxy.listen(function(name){ 185 | if (listeners[name]) listeners[name].apply(self, Array.prototype.slice.call(arguments, 1)); 186 | }); 187 | }, 188 | destroy: function() { 189 | this.proxy.destroy() 190 | }, 191 | destroy: function() { 192 | this.proxy.marshal(0); 193 | } 194 | }; 195 | wl_buffer.interface = wl.get_interface_by_name('wl_buffer'); 196 | interfaces['wl_buffer'] = wl_buffer 197 | 198 | function wl_data_offer(proxy) { 199 | this.proxy = proxy; 200 | proxy.spy(this); 201 | }; 202 | wl_data_offer.prototype = { 203 | listen: function(listeners) { 204 | var self = this; 205 | this.proxy.listen(function(name){ 206 | if (listeners[name]) listeners[name].apply(self, Array.prototype.slice.call(arguments, 1)); 207 | }); 208 | }, 209 | destroy: function() { 210 | this.proxy.destroy() 211 | }, 212 | accept: function(serial, mime_type) { 213 | this.proxy.marshal(0, serial, mime_type); 214 | }, 215 | receive: function(mime_type, fd) { 216 | this.proxy.marshal(1, mime_type, fd); 217 | }, 218 | destroy: function() { 219 | this.proxy.marshal(2); 220 | } 221 | }; 222 | wl_data_offer.interface = wl.get_interface_by_name('wl_data_offer'); 223 | interfaces['wl_data_offer'] = wl_data_offer 224 | 225 | function wl_data_source(proxy) { 226 | this.proxy = proxy; 227 | proxy.spy(this); 228 | }; 229 | wl_data_source.prototype = { 230 | listen: function(listeners) { 231 | var self = this; 232 | this.proxy.listen(function(name){ 233 | if (listeners[name]) listeners[name].apply(self, Array.prototype.slice.call(arguments, 1)); 234 | }); 235 | }, 236 | destroy: function() { 237 | this.proxy.destroy() 238 | }, 239 | offer: function(mime_type) { 240 | this.proxy.marshal(0, mime_type); 241 | }, 242 | destroy: function() { 243 | this.proxy.marshal(1); 244 | } 245 | }; 246 | wl_data_source.interface = wl.get_interface_by_name('wl_data_source'); 247 | interfaces['wl_data_source'] = wl_data_source 248 | 249 | function wl_data_device(proxy) { 250 | this.proxy = proxy; 251 | proxy.spy(this); 252 | }; 253 | wl_data_device.prototype = { 254 | listen: function(listeners) { 255 | var self = this; 256 | this.proxy.listen(function(name){ 257 | if (listeners[name]) listeners[name].apply(self, Array.prototype.slice.call(arguments, 1)); 258 | }); 259 | }, 260 | destroy: function() { 261 | this.proxy.destroy() 262 | }, 263 | start_drag: function(source, origin, icon, serial) { 264 | this.proxy.marshal(0, (source === null || source === undefined)?source:source.proxy, (origin === null || origin === undefined)?origin:origin.proxy, (icon === null || icon === undefined)?icon:icon.proxy, serial); 265 | }, 266 | set_selection: function(source, serial) { 267 | this.proxy.marshal(1, (source === null || source === undefined)?source:source.proxy, serial); 268 | } 269 | }; 270 | wl_data_device.interface = wl.get_interface_by_name('wl_data_device'); 271 | interfaces['wl_data_device'] = wl_data_device 272 | 273 | function wl_data_device_manager(proxy) { 274 | this.proxy = proxy; 275 | proxy.spy(this); 276 | }; 277 | wl_data_device_manager.prototype = { 278 | listen: function(listeners) { 279 | var self = this; 280 | this.proxy.listen(function(name){ 281 | if (listeners[name]) listeners[name].apply(self, Array.prototype.slice.call(arguments, 1)); 282 | }); 283 | }, 284 | destroy: function() { 285 | this.proxy.destroy() 286 | }, 287 | create_data_source: function() { 288 | new_id = this.proxy.create(wl_data_source.interface); 289 | this.proxy.marshal(0, new_id); 290 | return new wl_data_source(new_id); 291 | }, 292 | get_data_device: function(seat) { 293 | new_id = this.proxy.create(wl_data_device.interface); 294 | this.proxy.marshal(1, new_id, (seat === null || seat === undefined)?seat:seat.proxy); 295 | return new wl_data_device(new_id); 296 | } 297 | }; 298 | wl_data_device_manager.interface = wl.get_interface_by_name('wl_data_device_manager'); 299 | interfaces['wl_data_device_manager'] = wl_data_device_manager 300 | 301 | function wl_shell(proxy) { 302 | this.proxy = proxy; 303 | proxy.spy(this); 304 | }; 305 | wl_shell.prototype = { 306 | listen: function(listeners) { 307 | var self = this; 308 | this.proxy.listen(function(name){ 309 | if (listeners[name]) listeners[name].apply(self, Array.prototype.slice.call(arguments, 1)); 310 | }); 311 | }, 312 | destroy: function() { 313 | this.proxy.destroy() 314 | }, 315 | get_shell_surface: function(surface) { 316 | new_id = this.proxy.create(wl_shell_surface.interface); 317 | this.proxy.marshal(0, new_id, (surface === null || surface === undefined)?surface:surface.proxy); 318 | return new wl_shell_surface(new_id); 319 | } 320 | }; 321 | wl_shell.interface = wl.get_interface_by_name('wl_shell'); 322 | interfaces['wl_shell'] = wl_shell 323 | 324 | function wl_shell_surface(proxy) { 325 | this.proxy = proxy; 326 | proxy.spy(this); 327 | }; 328 | wl_shell_surface.prototype = { 329 | listen: function(listeners) { 330 | var self = this; 331 | this.proxy.listen(function(name){ 332 | if (listeners[name]) listeners[name].apply(self, Array.prototype.slice.call(arguments, 1)); 333 | }); 334 | }, 335 | destroy: function() { 336 | this.proxy.destroy() 337 | }, 338 | pong: function(serial) { 339 | this.proxy.marshal(0, serial); 340 | }, 341 | move: function(seat, serial) { 342 | this.proxy.marshal(1, (seat === null || seat === undefined)?seat:seat.proxy, serial); 343 | }, 344 | resize: function(seat, serial, edges) { 345 | this.proxy.marshal(2, (seat === null || seat === undefined)?seat:seat.proxy, serial, edges); 346 | }, 347 | set_toplevel: function() { 348 | this.proxy.marshal(3); 349 | }, 350 | set_transient: function(parent, x, y, flags) { 351 | this.proxy.marshal(4, (parent === null || parent === undefined)?parent:parent.proxy, x, y, flags); 352 | }, 353 | set_fullscreen: function(method, framerate, output) { 354 | this.proxy.marshal(5, method, framerate, (output === null || output === undefined)?output:output.proxy); 355 | }, 356 | set_popup: function(seat, serial, parent, x, y, flags) { 357 | this.proxy.marshal(6, (seat === null || seat === undefined)?seat:seat.proxy, serial, (parent === null || parent === undefined)?parent:parent.proxy, x, y, flags); 358 | }, 359 | set_maximized: function(output) { 360 | this.proxy.marshal(7, (output === null || output === undefined)?output:output.proxy); 361 | }, 362 | set_title: function(title) { 363 | this.proxy.marshal(8, title); 364 | }, 365 | set_class: function(class_) { 366 | this.proxy.marshal(9, class_); 367 | }, 368 | RESIZE_NONE: 0, 369 | RESIZE_TOP: 1, 370 | RESIZE_BOTTOM: 2, 371 | RESIZE_LEFT: 4, 372 | RESIZE_TOP_LEFT: 5, 373 | RESIZE_BOTTOM_LEFT: 6, 374 | RESIZE_RIGHT: 8, 375 | RESIZE_TOP_RIGHT: 9, 376 | RESIZE_BOTTOM_RIGHT: 10, 377 | TRANSIENT_INACTIVE: 0x1, 378 | FULLSCREEN_METHOD_DEFAULT: 0, 379 | FULLSCREEN_METHOD_SCALE: 1, 380 | FULLSCREEN_METHOD_DRIVER: 2, 381 | FULLSCREEN_METHOD_FILL: 3 382 | }; 383 | wl_shell_surface.interface = wl.get_interface_by_name('wl_shell_surface'); 384 | interfaces['wl_shell_surface'] = wl_shell_surface 385 | 386 | function wl_surface(proxy) { 387 | this.proxy = proxy; 388 | proxy.spy(this); 389 | }; 390 | wl_surface.prototype = { 391 | listen: function(listeners) { 392 | var self = this; 393 | this.proxy.listen(function(name){ 394 | if (listeners[name]) listeners[name].apply(self, Array.prototype.slice.call(arguments, 1)); 395 | }); 396 | }, 397 | destroy: function() { 398 | this.proxy.destroy() 399 | }, 400 | destroy: function() { 401 | this.proxy.marshal(0); 402 | }, 403 | attach: function(buffer, x, y) { 404 | this.proxy.marshal(1, (buffer === null || buffer === undefined)?buffer:buffer.proxy, x, y); 405 | }, 406 | damage: function(x, y, width, height) { 407 | this.proxy.marshal(2, x, y, width, height); 408 | }, 409 | frame: function() { 410 | new_id = this.proxy.create(wl_callback.interface); 411 | this.proxy.marshal(3, new_id); 412 | return new wl_callback(new_id); 413 | }, 414 | set_opaque_region: function(region) { 415 | this.proxy.marshal(4, (region === null || region === undefined)?region:region.proxy); 416 | }, 417 | set_input_region: function(region) { 418 | this.proxy.marshal(5, (region === null || region === undefined)?region:region.proxy); 419 | }, 420 | commit: function() { 421 | this.proxy.marshal(6); 422 | }, 423 | set_buffer_transform: function(transform) { 424 | this.proxy.marshal(7, transform); 425 | } 426 | }; 427 | wl_surface.interface = wl.get_interface_by_name('wl_surface'); 428 | interfaces['wl_surface'] = wl_surface 429 | 430 | function wl_seat(proxy) { 431 | this.proxy = proxy; 432 | proxy.spy(this); 433 | }; 434 | wl_seat.prototype = { 435 | listen: function(listeners) { 436 | var self = this; 437 | this.proxy.listen(function(name){ 438 | if (listeners[name]) listeners[name].apply(self, Array.prototype.slice.call(arguments, 1)); 439 | }); 440 | }, 441 | destroy: function() { 442 | this.proxy.destroy() 443 | }, 444 | get_pointer: function() { 445 | new_id = this.proxy.create(wl_pointer.interface); 446 | this.proxy.marshal(0, new_id); 447 | return new wl_pointer(new_id); 448 | }, 449 | get_keyboard: function() { 450 | new_id = this.proxy.create(wl_keyboard.interface); 451 | this.proxy.marshal(1, new_id); 452 | return new wl_keyboard(new_id); 453 | }, 454 | get_touch: function() { 455 | new_id = this.proxy.create(wl_touch.interface); 456 | this.proxy.marshal(2, new_id); 457 | return new wl_touch(new_id); 458 | }, 459 | CAPABILITY_POINTER: 1, 460 | CAPABILITY_KEYBOARD: 2, 461 | CAPABILITY_TOUCH: 4 462 | }; 463 | wl_seat.interface = wl.get_interface_by_name('wl_seat'); 464 | interfaces['wl_seat'] = wl_seat 465 | 466 | function wl_pointer(proxy) { 467 | this.proxy = proxy; 468 | proxy.spy(this); 469 | }; 470 | wl_pointer.prototype = { 471 | listen: function(listeners) { 472 | var self = this; 473 | this.proxy.listen(function(name){ 474 | if (listeners[name]) listeners[name].apply(self, Array.prototype.slice.call(arguments, 1)); 475 | }); 476 | }, 477 | destroy: function() { 478 | this.proxy.destroy() 479 | }, 480 | set_cursor: function(serial, surface, hotspot_x, hotspot_y) { 481 | this.proxy.marshal(0, serial, (surface === null || surface === undefined)?surface:surface.proxy, hotspot_x, hotspot_y); 482 | }, 483 | BUTTON_STATE_RELEASED: 0, 484 | BUTTON_STATE_PRESSED: 1, 485 | AXIS_VERTICAL_SCROLL: 0, 486 | AXIS_HORIZONTAL_SCROLL: 1 487 | }; 488 | wl_pointer.interface = wl.get_interface_by_name('wl_pointer'); 489 | interfaces['wl_pointer'] = wl_pointer 490 | 491 | function wl_keyboard(proxy) { 492 | this.proxy = proxy; 493 | proxy.spy(this); 494 | }; 495 | wl_keyboard.prototype = { 496 | listen: function(listeners) { 497 | var self = this; 498 | this.proxy.listen(function(name){ 499 | if (listeners[name]) listeners[name].apply(self, Array.prototype.slice.call(arguments, 1)); 500 | }); 501 | }, 502 | destroy: function() { 503 | this.proxy.destroy() 504 | }, 505 | KEYMAP_FORMAT_XKB_V1: 1, 506 | KEY_STATE_RELEASED: 0, 507 | KEY_STATE_PRESSED: 1 508 | }; 509 | wl_keyboard.interface = wl.get_interface_by_name('wl_keyboard'); 510 | interfaces['wl_keyboard'] = wl_keyboard 511 | 512 | function wl_touch(proxy) { 513 | this.proxy = proxy; 514 | proxy.spy(this); 515 | }; 516 | wl_touch.prototype = { 517 | listen: function(listeners) { 518 | var self = this; 519 | this.proxy.listen(function(name){ 520 | if (listeners[name]) listeners[name].apply(self, Array.prototype.slice.call(arguments, 1)); 521 | }); 522 | }, 523 | destroy: function() { 524 | this.proxy.destroy() 525 | } 526 | }; 527 | wl_touch.interface = wl.get_interface_by_name('wl_touch'); 528 | interfaces['wl_touch'] = wl_touch 529 | 530 | function wl_output(proxy) { 531 | this.proxy = proxy; 532 | proxy.spy(this); 533 | }; 534 | wl_output.prototype = { 535 | listen: function(listeners) { 536 | var self = this; 537 | this.proxy.listen(function(name){ 538 | if (listeners[name]) listeners[name].apply(self, Array.prototype.slice.call(arguments, 1)); 539 | }); 540 | }, 541 | destroy: function() { 542 | this.proxy.destroy() 543 | }, 544 | SUBPIXEL_UNKNOWN: 0, 545 | SUBPIXEL_NONE: 1, 546 | SUBPIXEL_HORIZONTAL_RGB: 2, 547 | SUBPIXEL_HORIZONTAL_BGR: 3, 548 | SUBPIXEL_VERTICAL_RGB: 4, 549 | SUBPIXEL_VERTICAL_BGR: 5, 550 | TRANSFORM_NORMAL: 0, 551 | TRANSFORM_90: 1, 552 | TRANSFORM_180: 2, 553 | TRANSFORM_270: 3, 554 | TRANSFORM_FLIPPED: 4, 555 | TRANSFORM_FLIPPED_90: 5, 556 | TRANSFORM_FLIPPED_180: 6, 557 | TRANSFORM_FLIPPED_270: 7, 558 | MODE_CURRENT: 0x1, 559 | MODE_PREFERRED: 0x2 560 | }; 561 | wl_output.interface = wl.get_interface_by_name('wl_output'); 562 | interfaces['wl_output'] = wl_output 563 | 564 | function wl_region(proxy) { 565 | this.proxy = proxy; 566 | proxy.spy(this); 567 | }; 568 | wl_region.prototype = { 569 | listen: function(listeners) { 570 | var self = this; 571 | this.proxy.listen(function(name){ 572 | if (listeners[name]) listeners[name].apply(self, Array.prototype.slice.call(arguments, 1)); 573 | }); 574 | }, 575 | destroy: function() { 576 | this.proxy.destroy() 577 | }, 578 | destroy: function() { 579 | this.proxy.marshal(0); 580 | }, 581 | add: function(x, y, width, height) { 582 | this.proxy.marshal(1, x, y, width, height); 583 | }, 584 | subtract: function(x, y, width, height) { 585 | this.proxy.marshal(2, x, y, width, height); 586 | } 587 | }; 588 | wl_region.interface = wl.get_interface_by_name('wl_region'); 589 | interfaces['wl_region'] = wl_region 590 | 591 | --------------------------------------------------------------------------------