Permalink
Browse files

Fix build on node v0.5.2+

  • Loading branch information...
1 parent 5376bc7 commit d5c8fc1651c37483bd27288b67a37dcd7eab26c4 @mscdex committed Aug 1, 2011
Showing with 126 additions and 21 deletions.
  1. +7 −2 examples/colors.js
  2. +18 −13 ncurses.cc
  3. +95 −0 ncurses.js
  4. +1 −1 package.json
  5. +5 −5 wscript
View
9 examples/colors.js
@@ -8,7 +8,12 @@ function pad(num) {
num = '0' + num;
return num;
}
-var w = new nc.Window();
+var w = new nc.Window(),
+ tmo;
+w.on('inputChar', function() {
+ clearTimeout(tmo);
+ w.close();
+});
nc.showCursor = false;
if (nc.hasColors) {
var color = 0, pair = 1, breakout = false;
@@ -26,7 +31,7 @@ if (nc.hasColors) {
break;
}
w.refresh();
- setTimeout(function() { w.close(); }, 5000);
+ tmo = setTimeout(function() { w.close(); }, 5000);
} else {
w.close();
console.log('Sorry, this example requires a terminal capable of displaying color.');
View
31 ncurses.cc
@@ -13,7 +13,7 @@
#include <cursesp.h>
#include <node.h>
-#include <node_events.h>
+#include <node_object_wrap.h>
#include <assert.h>
#include <stdlib.h>
@@ -39,7 +39,7 @@ typedef struct {
static panel_node* head_panel = NULL;
static MyPanel* topmost_panel = NULL;
-static Persistent<String> inputChar_symbol;
+static Persistent<String> emit_symbol;
static Persistent<Object> ACS_Chars;
static Persistent<Object> Keys;
static Persistent<Object> Attrs;
@@ -306,19 +306,15 @@ bool MyPanel::echoInput_ = false;
bool MyPanel::showCursor_ = true;
bool MyPanel::isRaw_ = false;
-class Window : public EventEmitter {
+class Window : public ObjectWrap {
public:
static void Initialize (Handle<Object> target) {
HandleScope scope;
Local<FunctionTemplate> t = FunctionTemplate::New(New);
-
- t->Inherit(EventEmitter::constructor_template);
t->InstanceTemplate()->SetInternalFieldCount(1);
t->SetClassName(String::NewSymbol("Window"));
- inputChar_symbol = NODE_PSYMBOL("inputChar");
-
/* Panel-specific methods */
// TODO: color_set?, overlay, overwrite
NODE_SET_PROTOTYPE_METHOD(t, "clearok", Clearok);
@@ -428,6 +424,8 @@ class Window : public EventEmitter {
NODE_SET_METHOD(target, "dup2", Dup2);
NODE_SET_METHOD(target, "dup", Dup);
+ emit_symbol = NODE_PSYMBOL("emit");
+
target->Set(String::NewSymbol("Window"), t->GetFunction());
}
@@ -666,6 +664,7 @@ class Window : public EventEmitter {
win->Wrap(args.This());
//if (doRef)
win->Ref();
+
return args.This();
}
@@ -2064,13 +2063,13 @@ class Window : public EventEmitter {
return scope.Close(Integer::New(wincounter));
}
- Window() : EventEmitter() {
+ Window() : ObjectWrap() {
panel_ = NULL;
this->init();
assert(panel_ != NULL);
}
- Window(int nlines, int ncols, int begin_y, int begin_x) : EventEmitter() {
+ Window(int nlines, int ncols, int begin_y, int begin_x) : ObjectWrap() {
panel_ = NULL;
this->init(nlines, ncols, begin_y, begin_x);
assert(panel_ != NULL);
@@ -2086,6 +2085,7 @@ class Window : public EventEmitter {
private:
void Event (int revents) {
+ HandleScope scope;
if (revents & EV_ERROR)
return;
@@ -2101,10 +2101,14 @@ class Window : public EventEmitter {
return;
}
tmp[0] = chr;
- Local<Value> vChr[2];
- vChr[0] = String::New(tmp);
- vChr[1] = Integer::New(chr);
- topmost_panel->getWindow()->Emit(inputChar_symbol, 2, vChr);
+ Local<Value> vChr[3];
+ vChr[0] = String::New("inputChar");
+ vChr[1] = String::New(tmp);
+ vChr[2] = Integer::New(chr);
+ Local<Value> emit_v = handle_->Get(emit_symbol);
+ if (!emit_v->IsFunction()) return;
+ Local<Function> emit = Local<Function>::Cast(emit_v);
+ emit->Call(handle_, 3, vChr);
@bnoordhuis
bnoordhuis added a line comment Aug 1, 2011

Wrap the call in a TryCatch. If the callback throws and you don't handle it at the call site, you'll get all kinds of hard to track down bugs.

TryCatch tc;
emit->Call(handle_, 3, vChr);
if (tc.HasCaught()) {
  // propagate error
}
@mscdex
Owner
mscdex added a line comment Aug 1, 2011

Hrmm... well, I'd guess I'd emit an error event in this case then? However, I'd have to wrap that call in a TryCatch also, and so on and so on, causing an endless chain.

@bnoordhuis
bnoordhuis added a line comment Aug 1, 2011

If you don't want to handle the error yourself, call node::FatalException(tc);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
}
}
}
@@ -2116,6 +2120,7 @@ class Window : public EventEmitter {
}
MyPanel *panel_;
+
};
extern "C" void
View
95 ncurses.js
@@ -0,0 +1,95 @@
+var EventEmitter = require('events').EventEmitter,
+ addon = require('./ncurses_addon');
+
+extend(true, addon.Window.prototype, EventEmitter.prototype);
+
+module.exports = addon;
+
+/**
+ * Adopted from jquery's extend method. Under the terms of MIT License.
+ *
+ * http://code.jquery.com/jquery-1.4.2.js
+ *
+ * Modified by Brian White to use Array.isArray instead of the custom isArray
+ * method
+ */
+function extend() {
+ // copy reference to target object
+ var target = arguments[0] || {},
+ i = 1,
+ length = arguments.length,
+ deep = false,
+ options,
+ name,
+ src,
+ copy;
+
+ // Handle a deep copy situation
+ if (typeof target === "boolean") {
+ deep = target;
+ target = arguments[1] || {};
+ // skip the boolean and the target
+ i = 2;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if (typeof target !== "object" && !typeof target === 'function')
+ target = {};
+
+ var isPlainObject = function(obj) {
+ // Must be an Object.
+ // Because of IE, we also have to check the presence of the constructor
+ // property.
+ // Make sure that DOM nodes and window objects don't pass through, as well
+ if (!obj || toString.call(obj) !== "[object Object]" || obj.nodeType
+ || obj.setInterval)
+ return false;
+
+ var has_own_constructor = hasOwnProperty.call(obj, "constructor");
+ var has_is_prop_of_method = hasOwnProperty.call(obj.constructor.prototype,
+ "isPrototypeOf");
+ // Not own constructor property must be Object
+ if (obj.constructor && !has_own_constructor && !has_is_prop_of_method)
+ return false;
+
+ // Own properties are enumerated firstly, so to speed up,
+ // if last one is own, then all properties are own.
+
+ var last_key;
+ for (key in obj)
+ last_key = key;
+
+ return typeof last_key === "undefined" || hasOwnProperty.call(obj, last_key);
+ };
+
+
+ for (; i < length; i++) {
+ // Only deal with non-null/undefined values
+ if ((options = arguments[i]) !== null) {
+ // Extend the base object
+ for (name in options) {
+ src = target[name];
+ copy = options[name];
+
+ // Prevent never-ending loop
+ if (target === copy)
+ continue;
+
+ // Recurse if we're merging object literal values or arrays
+ if (deep && copy && (isPlainObject(copy) || Array.isArray(copy))) {
+ var clone = src && (isPlainObject(src) || Array.isArray(src)
+ ? src : (Array.isArray(copy) ? [] : {}));
+
+ // Never move original objects, clone them
+ target[name] = extend(deep, clone, copy);
+
+ // Don't bring in undefined values
+ } else if (typeof copy !== "undefined")
+ target[name] = copy;
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+};
View
2 package.json
@@ -1,5 +1,5 @@
{ "name": "ncurses",
- "version": "0.2.0",
+ "version": "0.2.1",
"author": "Brian White <mscdex@mscdex.net>",
"description": "An ncurses binding for node.js",
"scripts": { "preinstall": "node-waf configure build" },
View
10 wscript
@@ -14,7 +14,7 @@ def set_options(opt):
def configure(conf):
conf.check_tool('compiler_cxx')
conf.check_tool('node_addon')
-
+
# ugly hack to append -fPIC for x64
hack = ""
if (conf.env['DEST_CPU'] == 'x86_64'):
@@ -35,7 +35,7 @@ def build(bld):
conf.fatal("Building ncurses failed.")
else:
obj = bld.new_task_gen('cxx', 'shlib', 'node_addon')
- obj.target = 'ncurses'
+ obj.target = 'ncurses_addon'
obj.source = 'ncurses.cc'
obj.includes = [ncursesdir + '/include', ncursesdir + '/c++']
obj.cxxflags = ['-O2']
@@ -45,7 +45,7 @@ def shutdown():
# HACK to get ncurses.node out of build directory.
# better way to do this?
if Options.commands['clean']:
- if exists('ncurses.node'): unlink('ncurses.node')
+ if exists('ncurses_addon.node'): unlink('ncurses_addon.node')
else:
- if exists('build/default/ncurses.node') and not exists('ncurses.node'):
- symlink('build/default/ncurses.node', 'ncurses.node')
+ if exists('build/default/ncurses_addon.node') and not exists('ncurses_addon.node'):
+ symlink('build/default/ncurses_addon.node', 'ncurses_addon.node')

3 comments on commit d5c8fc1

@TooTallNate

This seems like overkill to me. Couldn't you just do something like:

var EventEmitter = require('events').EventEmitter,
    addon = require('./ncurses_addon');
addon.Window.prototype.__proto__ = EventEmitter.prototype;

Also, I believe currently your Window instances will fail an instanceof EventEmitter check...

@mscdex
Owner

IIRC setting the prototype directly will wipe out any prototype methods you have defined in C++ land right?

@TooTallNate
Please sign in to comment.