Skip to content
This repository has been archived by the owner on Feb 20, 2023. It is now read-only.

Commit

Permalink
initial commit, minimal functionnality
Browse files Browse the repository at this point in the history
  • Loading branch information
olalonde committed Mar 1, 2011
0 parents commit 73e1e66
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 0 deletions.
26 changes: 26 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Copyright 2011, Olivier Lalonde. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Olivier Lalonde nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
THIS IS A WORK IN PROGRESS!!!

---

Part 1 (V8 extension) available here: [http://syskall.com/how-to-roll-out-your-own-javascript-api-with](http://syskall.com/how-to-roll-out-your-own-javascript-api-with)

## Install ##

node-waf configure && node-waf build

## References ##

https://www.cloudkick.com/blog/2010/aug/23/writing-nodejs-native-extensions/
https://github.com/pquerna/node-extension-examples
http://code.google.com/apis/v8/embed.html
irc.freenode.org #v8 #node.js
https://github.com/ncb000gt/node.bcrypt.js
https://github.com/joyent/node
1 change: 1 addition & 0 deletions TUTORIAL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Part 1 (V8 extension) available here: [http://syskall.com/how-to-roll-out-your-own-javascript-api-with](http://syskall.com/how-to-roll-out-your-own-javascript-api-with)
1 change: 1 addition & 0 deletions build/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*
7 changes: 7 additions & 0 deletions js/demo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
var notify = require("../build/default/gtknotify.node"); // node.js stuff

var notification = new notify.Notification();
//notification.icon = "terminal";
//notification.title = "Notification title";
notification.text = "Some text here...";
console.log(notification.send("yippi"));
115 changes: 115 additions & 0 deletions src/node_gtknotify.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#include <v8.h>
#include <node.h>
// We need those two libraries for the GTK+ notification
#include <gtkmm.h>
#include <libnotifymm.h>

// V8 documentation:
// Context: a context is an execution environment that allows separate, unrelated, JavaScript applications to run in a single instance of V8.
// must be explicitly specified
// Handles: Local (deleted when scope deleted),
// Persistent (deleted manually),
// Handle (parent class)
// Handle scope: a container that holds lots of handles.
// when handle scope's destructor is called (implicitly called when ~ called) all handles created within that scope are removed
// Template: A template is a blueprint for JavaScript functions and objects in a context (i.e. Google Chrome's DOM)
// Function template: A function template is the blueprint for a single function.
// Object templates: Each function template has an associated object template. accessors/interceptor C++ callbacks

// todo: remove "using namespace" for less confusion node vs v8
using namespace node;
using namespace v8;

class Gtknotify : node::ObjectWrap {
private:
public:
// Function template for notification()
static v8::Persistent<FunctionTemplate> persistent_function_template;

// Node: the target is the "module", it's where your extension will be loaded into
static void Init(Handle<Object> target) {
/* V8 PART */
// This scope will contain all local handles within this method (in other words, it will contain local_function_template)
v8::HandleScope scope;

// Map our function template to the C++ New() method
// Need to create local template first because that's what v8::FunctionTemplate::New returns

// irc convo
// <oli> anyone knows why you need to make a local function template before making it persistent?
// Local<FunctionTemplate> t = FunctionTemplate::New(New); s_ct = Persistent<FunctionTemplate>::New(t);
// <bradleymeck> oli mainly just readability, you *could* cast it as you assign to t
// <oli> I assume v8::FunctionTemplate::New returns a local handle
// <bradleymeck> it does, when im talking about casting here im talking about the v8 api cast not c cast
v8::Local<FunctionTemplate> local_function_template = v8::FunctionTemplate::New(New);

// Make our local function template persistent
persistent_function_template = v8::Persistent<FunctionTemplate>::New(local_function_template);
/* V8 doc:
Each JavaScript point object keeps a reference to the C++ object for which it is a wrapper with an internal field.
These fields are so named because they cannot be accessed from within JavaScript, they can only be accessed from C++ code.
An object can have any number of internal fields, the number of internal fields is set on the object template as follows: */
persistent_function_template->InstanceTemplate()->SetInternalFieldCount(1);
// Map our function template to a Javascript function name, so it can be called from Javascript: Notification()
persistent_function_template->SetClassName(v8::String::NewSymbol("Notification"));

/* NODE PART */
// Arguments: function template, JS method name, C++ method
// @see https://github.com/joyent/node/blob/v0.2.0/src/node.h#L34
NODE_SET_PROTOTYPE_METHOD(persistent_function_template, "send", Send);
// Add .notification() to the target, "module" so we expose our function as module.notification();
target->Set(String::NewSymbol("Notification"), persistent_function_template->GetFunction());
}

Gtknotify() {}

~Gtknotify() {}

// Called when our class is created (constructor function)
// Instantiates C++ object
static Handle<Value> New(const Arguments& args) {
HandleScope scope;
Gtknotify* gtknotify_instance = new Gtknotify();
// stores a reference to the C++ Gtknotify object inside the args.This() value
gtknotify_instance->Wrap(args.This()); // Inherited from node::ObjectWrap

// Once it is wrapped up, it returns args.This(), which is just like what the new operator does in Javascript,
// returning the this as an object.
return args.This();
}

static v8::Handle<Value> Send(const Arguments& args) {
v8::HandleScope scope;
// Extract C++ object reference from JS object passed as args.This()
Gtknotify* gtknotify_instance = node::ObjectWrap::Unwrap<Gtknotify>(args.This());
// todo: notify_instance->send();
//Local<String> result = String::New("Hello World");

// LIBNOTIFY
v8::String::Utf8Value str(args[0]); // Convert first argument to V8 String

Notify::init("Basic");
// Arguments: title, content, icon
Notify::Notification n("Alert", *str, "terminal"); // *str = c string
// Display notification
n.show();

return v8::Boolean::New(true);
}
};

// Why this?
v8::Persistent<FunctionTemplate> Gtknotify::persistent_function_template;

/* Thats it for actual interfacing with v8, finally we need to let Node.js know how to dynamically load our code.
Because a Node.js extension can be loaded at runtime from a shared object, we need a symbol that the dlsym function can find,
so we do the following: */
// @see http://www.freebsd.org/cgi/man.cgi?query=dlsym
// cause of name mangling in C++, we use extern C here
extern "C" {
static void init(Handle<Object> target) {
Gtknotify::Init(target);
}
// @see http://github.com/ry/node/blob/v0.2.0/src/node.h#L101
NODE_MODULE(gtknotify, init);
}
17 changes: 17 additions & 0 deletions wscript
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
def set_options(opt):
opt.tool_options("compiler_cxx")

def configure(conf):
conf.check_tool("compiler_cxx")
conf.check_tool("node_addon")
# @oli
conf.check_cfg(package='gtkmm-2.4', args='--cflags --libs', uselib_store='LIBGTKMM')
conf.check_cfg(package='libnotifymm-1.0', args='--cflags --libs', uselib_store='LIBNOTIFYMM')

def build(bld):
obj = bld.new_task_gen("cxx", "shlib", "node_addon")
obj.cxxflags = ["-g", "-D_FILE_OFFSET_BITS=64", "-D_LARGEFILE_SOURCE", "-Wall"]
obj.target = "gtknotify"
obj.source = "src/node_gtknotify.cpp"
# @oli
obj.uselib = ['LIBGTKMM', 'LIBNOTIFYMM']

0 comments on commit 73e1e66

Please sign in to comment.