Skip to content

ChromeWorkers #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 37 additions & 146 deletions chrome/content/main.js
Original file line number Diff line number Diff line change
@@ -1,151 +1,42 @@
Components.utils.import("resource://gre/modules/ctypes.jsm");
var worker = new ChromeWorker("ruby_bridge.js");

var start = true
worker.onmessage = function(e){
if (start){

document.getElementById('ruby_version').innerHTML = e.data
start = false
}else{
if (e.data.lastIndexOf('test:', 0) === 0)
{

alert(e.data)
}
else{
document.getElementById('dispa').innerHTML = e.data
}
}
};


function make_call_to_ruby() {
worker.postMessage(document.getElementById('scrtext').value);

var lib;
var script;
var mainrb;
(function() {
var cmdLine = window.arguments[0];
cmdLine = cmdLine.QueryInterface(Components.interfaces.nsICommandLine);
var rubylib = cmdLine.handleFlagWithParam('rubylib', false);
lib = ctypes.open(rubylib);
mainrb = cmdLine.handleFlagWithParam('main', null);
script = cmdLine.handleFlagWithParam('script', null);
})();
var ID = ctypes.uintptr_t;
var VALUE = ctypes.PointerType(ctypes.uintptr_t);
var VALUE_ARRAY = ctypes.ArrayType(VALUE);
var rb_intern = lib.declare("rb_intern", ctypes.default_abi, ID, ctypes.char.ptr);
var rb_eval_string = lib.declare("rb_eval_string", ctypes.default_abi, VALUE, ctypes.char.ptr);
var rb_const_get = lib.declare("rb_const_get", ctypes.default_abi, VALUE, VALUE, ID);
var rb_string_value_cstr = lib.declare("rb_string_value_cstr", ctypes.default_abi, ctypes.char.ptr, VALUE.ptr);
var rb_str_new_cstr = lib.declare("rb_str_new_cstr", ctypes.default_abi, VALUE, ctypes.char.ptr);
var rb_require = lib.declare("rb_require", ctypes.default_abi, VALUE, ctypes.char.ptr);
var rb_funcall = lib.declare("rb_funcallv", ctypes.default_abi, VALUE, VALUE, ID, ctypes.int, VALUE_ARRAY);
var rb_ull2inum = lib.declare("rb_ull2inum", ctypes.default_abi, VALUE, ctypes.uint64_t);
lib.declare("ruby_init", ctypes.default_abi, ctypes.void_t)();
(function() {
var chararray = ctypes.ArrayType(ctypes.char.ptr);
var ruby_options = lib.declare("ruby_options", ctypes.default_abi, ctypes.void_t, ctypes.int, chararray);
var args = chararray(3);
args[0].value = ctypes.char.array()('dummy');
args[1].value = ctypes.char.array()('-e');
args[2].value = ctypes.char.array()(';');
ruby_options(3, args);
})();
rb_require(mainrb);
var obj_class = rb_eval_string("Object");
var nil_object = rb_eval_string("nil");
var no_args = VALUE_ARRAY(0);

window.addEventListener('load', function() {
var vs = rb_eval_string('"#{RUBY_VERSION}p#{RUBY_PATCHLEVEL} [#{RUBY_PLATFORM}]"');
document.getElementById('ruby_version').innerHTML = rb_string_value_cstr(vs.address()).readString();
if (script) {
rb_require(script);
}
});

function callRuby() {
var arg = VALUE_ARRAY(1);
arg[0] = rb_str_new_cstr(document.getElementById('scrtext').value);
var vs = rb_funcall(obj_class, rb_intern('eval_expression'), 1, arg)
document.getElementById('dispa').innerHTML = rb_string_value_cstr(vs.address()).readString();
}

var firedEvents = {};
var xul_elements = {};

function getElement(id) {
return getElementFromString(id.readString());
}
function getElementFromString(elem_id) {
if (xul_elements[elem_id]) {
return xul_elements[elem_id];
}
if (elem_id === 'window') {
return window;
} else if (elem_id === 'document') {
return document;
} else if (elem_id.indexOf('frevent:') == 0) {
return firedEvents['ev' + elem_id.substring(8)];
}
return document.getElementById(elem_id);
}

function propSetter(id, args) {
var elem = getElement(id);
var argv = JSON.parse(args.readString());
elem[argv.name] = argv.args[0];
}

function methodCaller(id, args) {
var elem = getElement(id);
var argv = JSON.parse(args.readString());
var fun = elem[argv.name];
var ret;
if (typeof fun === 'function') {
for (var i = 0; i < argv.args.length; i++) {
if (typeof argv.args[i] === 'string'
&& argv.args[i].indexOf('_XUL::ELEMENT::') == 0) {
argv.args[i] = getElementFromString(argv.args[i].substring(15));
}
}
ret = fun.apply(elem, argv.args);
} else if (fun) {
ret = fun;
}
if (typeof ret === 'undefined') {
ret = 'undefined';
} else if (ret == null) {
ret = 'nil';
} else {
if (typeof ret === 'object' && ret.toString() === '[object XULElement]') {
if (ret.id == '') {
ret.id = '#' + Math.random().toString();
xul_elements[ret.id] = ret;
}
ret = '_XUL::ELEMENT::' + ret.id;
} else {
ret = ret.toString();
}
}
return ctypes.char.array()(ret);
}

function registerEvent(id, args) {
var elem = getElement(id);
var argv = JSON.parse(args.readString())
elem['cb' + argv.key] = function(e) {
firedEvents['ev' + argv.key] = e;
var args = VALUE_ARRAY(1);
args[0].value = rb_str_new_cstr(argv.key);
rb_funcall(obj_class, rb_intern('notify_event'), 1, args);
firedEvents['ev' + argv.key] = null;
};
elem.addEventListener(argv.name, elem['cb' + argv.key]);
}

function removeEvent(id, args) {
var elem = getElement(id);
var argv = JSON.parse(args.readString())
elem.removeEventListener(argv.name, elem['cb' + argv.key]);
}

window.addEventListener('close', function () {
worker.postMessage('[[close]]')
});

var funcPtrType = ctypes.FunctionType(ctypes.default_abi, ctypes.char.ptr, [ctypes.char.ptr, ctypes.char.ptr]).ptr;
var methodcaller = funcPtrType(methodCaller);
var procPtrType = ctypes.FunctionType(ctypes.default_abi, ctypes.void_t, [ctypes.char.ptr, ctypes.char.ptr]).ptr;
var propsetter = procPtrType(propSetter);
var regevent = procPtrType(registerEvent);
var removeevent = procPtrType(removeEvent);
(function() {
var args = VALUE_ARRAY(4);
args[0].value = rb_ull2inum(ctypes.cast(methodcaller, ctypes.uint64_t));
args[1].value = rb_ull2inum(ctypes.cast(propsetter, ctypes.uint64_t));
args[2].value = rb_ull2inum(ctypes.cast(regevent, ctypes.uint64_t));
args[3].value = rb_ull2inum(ctypes.cast(removeevent, ctypes.uint64_t));
rb_funcall(obj_class, rb_intern('init_fireruby'), args.length, args);
})();
window.addEventListener('load', function() {
(function() {
var cmdLine = window.arguments[0];
cmdLine = cmdLine.QueryInterface(Components.interfaces.nsICommandLine);
rubylib = cmdLine.handleFlagWithParam('rubylib', false);
mainrb = cmdLine.handleFlagWithParam('main', false);
script = cmdLine.handleFlagWithParam('script', false);
})();
worker.postMessage({'command':'init', 'rubylib':rubylib, 'mainrb':mainrb})

window.addEventListener('close', function () {
lib.close();
});
});
129 changes: 9 additions & 120 deletions chrome/content/main.rb
Original file line number Diff line number Diff line change
@@ -1,18 +1,8 @@
# coding: utf-8

require 'fiddle'
require 'json'

def init_fireruby(caller, setter, registerevent, removeevent)
caller_ptr = Fiddle::Pointer.new(caller)
$jsfun = Fiddle::Function.new(caller_ptr, [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP], Fiddle::TYPE_VOIDP)
setter_ptr = Fiddle::Pointer.new(setter)
$jssetter = Fiddle::Function.new(setter_ptr, [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP], Fiddle::TYPE_VOID)
reg_ptr = Fiddle::Pointer.new(registerevent)
$jsregevent = Fiddle::Function.new(reg_ptr, [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP], Fiddle::TYPE_VOID)
rmv_ptr = Fiddle::Pointer.new(removeevent)
$jsrmvevent = Fiddle::Function.new(rmv_ptr, [Fiddle::TYPE_VOIDP, Fiddle::TYPE_VOIDP], Fiddle::TYPE_VOID)
end

require 'fiddle'

def eval_expression(str)
begin
Expand All @@ -22,112 +12,11 @@ def eval_expression(str)
end
end

$dom_events = {}

def notify_event(e)
blk = $dom_events[e]
if blk
if blk.arity == 1
blk.call(DOM.new("frevent:#{e}"))
else
blk.call()
end
end
def init_fireruby(param1, param2,param3)
puts "I'm in init_fireruby()"
puts "param1="+param1.to_s
puts "param2="+param2.to_s
puts "param3="+param3.to_s
caller_ptr = Fiddle::Pointer.new(param2)
$h = Fiddle::Function.new(caller_ptr, [ Fiddle::TYPE_VOIDP], Fiddle::TYPE_VOID)
end

class DOM
def initialize(id)
@id = id
end
def addEventListener(name, &block)
key = "#{@id}#{name}"
$dom_events[key] = block
$jsregevent.call(@id, JSON({'name' => name, 'key' => key }))
end
alias add_event_listener addEventListener
def removeEventListener(name)
# remove any block at this time
key = "#{@id}#{name}"
$dom_events.delete(key)
$jsrmvevent.call(@id, JSON({'name' => name, 'key' => key }))
end
def to_s
"_XUL::ELEMENT::#{@id}"
end
alias remove_event_listener removeEventListener
def method_missing(name, *args)
begin
param = {}
param['args'] = args
if name.to_s[-1, 1] == '='
param['name'] = name.to_s[0...-1]
v = $jssetter.call(@id, JSON(param)).to_s
else
param['name'] = name.to_s
v = $jsfun.call(@id, JSON(param)).to_s
return DOM.new($1) if v =~ /\A_XUL::ELEMENT::(.+)\Z/
end
return v
rescue
return 'error:' + $!.to_s
end
end
end

$timer_events = {}
def timer_callback(key, cb)
blk = $timer_events[key]
if blk
blk.call()
if cb == 'setTimeout'
$timer_events.delete(key)
end
end
end

class Window < DOM
def initialize(id)
super(id)
end
def set_timeout(msec, &blk)
timer_func('setTimeout', msec, blk)
end
def set_interval(msec, &blk)
timer_func('setInterval', msec, blk)
end
def clear_interval(id)
if id =~ /\A([^:]+):(.*)\Z/
$timer_events.delete($2)
$jsfun.call('window', JSON({'name' => 'clearInterval', 'args' => [ $1 ] }))
end
''
end
private
def timer_func(funname, msec, blk)
key = Random.rand.to_s
$timer_events[key] = blk
fun =<<EOFUNC
var args = VALUE_ARRAY(2);
args[0].value = rb_str_new_cstr('#{key}');
args[1].value = rb_str_new_cstr('#{funname}');
rb_funcall(obj_class, rb_intern('timer_callback'), 2, args);
EOFUNC
$jsfun.call('window', JSON({'name' => funname,
'args' => [ fun, msec ]})).to_s + ':' + key
end
end

class DOM
@@document = DOM.new('document')
@@window = Window.new('window')
def self.document()
@@document
end
def self.document=(xul)
@@document.write(xul)
end
def self.window()
@@window
end
end

3 changes: 2 additions & 1 deletion chrome/content/main.xul
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

<textbox id="scrtext" multiline="true" rows="8" cols="80"/>
<separator/>
<button label="eval" oncommand="callRuby();"/>
<button label="eval" oncommand="make_call_to_ruby();"/>
<button label="Test responsiveness" oncommand="alert('It\'s responsive');"/>
<separator/>
<description id="dispa" style="height:60%;width:90%">
</description>
Expand Down
Loading