Skip to content

Commit

Permalink
draft
Browse files Browse the repository at this point in the history
  • Loading branch information
romgrk committed Jul 16, 2018
1 parent 18c936b commit 7085caf
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 59 deletions.
1 change: 1 addition & 0 deletions examples/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ const execute = function(command) {


textView.on('key-press-event', function(event) {
Gdk.test_error()
let keyname = Gdk.keyvalName(event.keyval);
let label = Gtk.acceleratorGetLabel(event.keyval, event.state);

Expand Down
23 changes: 13 additions & 10 deletions src/closure.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#include <glib.h>
#include <nan.h>
// #include <nan.h>

#include "debug.h"
#include "function.h"
Expand All @@ -13,9 +13,10 @@ namespace GNodeJS {
struct Closure {
GClosure base;
Persistent<Function> persistent;
GISignalInfo* info;
GIBaseInfo* info;

~Closure() {
persistent.Reset();
if (info)
g_base_info_unref(info);
}
Expand All @@ -40,7 +41,7 @@ void Closure::Marshal(GClosure *base,
HandleScope scope(isolate);
Local<Context> context = Context::New(isolate);
Context::Scope context_scope(context);
Nan::TryCatch try_catch;
// Nan::TryCatch try_catch;

Local<Function> func = Local<Function>::New(isolate, closure->persistent);

Expand Down Expand Up @@ -76,12 +77,14 @@ void Closure::Marshal(GClosure *base,
}
}
else {
auto stackTrace = try_catch.StackTrace();
if (!stackTrace.IsEmpty())
printf("%s\n", *Nan::Utf8String(stackTrace.ToLocalChecked()));
else
printf("%s\n", *Nan::Utf8String(try_catch.Exception()));
exit(1);
log("did throw");
/* auto stackTrace = try_catch.StackTrace();
* if (!stackTrace.IsEmpty())
* printf("%s\n", *Nan::Utf8String(stackTrace.ToLocalChecked()));
* else
* printf("%s\n", *Nan::Utf8String(try_catch.Exception()));
* exit(1); */
// try_catch.ReThrow();
}

#ifndef __linux__
Expand All @@ -94,7 +97,7 @@ void Closure::Invalidated(gpointer data, GClosure *base) {
closure->~Closure();
}

GClosure *MakeClosure(Isolate *isolate, Local<Function> function, GISignalInfo* info) {
GClosure *MakeClosure(Isolate *isolate, Local<Function> function, GIBaseInfo* info) {
Closure *closure = (Closure *) g_closure_new_simple (sizeof (*closure), NULL);
closure->persistent.Reset(isolate, function);
closure->info = info;
Expand Down
118 changes: 69 additions & 49 deletions src/loop.cc
Original file line number Diff line number Diff line change
@@ -1,73 +1,93 @@
/*
* Taken from https://github.com/endlessm/eos-knowledge-content-node/blob/master/src/mainloop.cc
* Relicensed in https://github.com/Place1/node-gir/issues/24
*/

#include <glib.h>
#include <uv.h>

#include "loop.h"
#include "util.h"

/* Integration for the GLib main loop and uv's main loop */

/* The way that this works is that we take uv's loop and nest it inside GLib's
* mainloop, since nesting GLib inside uv seems to be fairly impossible until
* either uv allows external sources to drive prepare/check, or until GLib
* exposes an epoll fd to wait on... */
using namespace v8;

namespace GNodeJS {

struct uv_loop_source {
GSource source;
uv_loop_t *loop;
struct ThreadData {
uv_thread_t thread_handle;
uv_mutex_t mutex_handle;
uv_async_t async_handle;
GPollFD *fds;
gint nfds;
};

static gboolean uv_loop_source_prepare (GSource *base, int *timeout) {
struct uv_loop_source *source = (struct uv_loop_source *) base;
uv_update_time (source->loop);
/*
* GLibs mainloop is not easy to embed directly right now. So rather then
* embedding glib's mainloop inside libuvs mainloop, we are running glibs
* mainloop in a separate thread. However we still want to be able to callback
* into v8 javascript context from glib async code, so we call the dispatch
* phase of glibs mainloop back on libuvs main thread. The flow is something
* like
*
* glib thread: poll for events
* glib thread: got events. wakeup libuv thread and lock
* libuv thread: dispatch glib events
* libuv thread: unlock glib thread
* glib thread: poll for events
* ...
*
* If in the future glib moves to epoll to drive its mainloop, we could easily
* embed it inside of libuvs mainloop on the same thread, by polling on a single
* fd. See https://bugzilla.gnome.org/show_bug.cgi?id=156048
*/
static void DispatchGLibMainloop (uv_async_t *async_handle) {
ThreadData *data = (ThreadData *)async_handle->data;
GMainContext *context = g_main_context_default ();
g_main_context_acquire (context);
g_main_context_dispatch (context);
g_main_context_release (context);
uv_mutex_unlock (&data->mutex_handle);
}

bool loop_alive = uv_loop_alive (source->loop);
static void IterateGLibMainloop (ThreadData *data) {
GMainContext *context = g_main_context_default ();
gint max_priority, timeout;
g_main_context_prepare (context, &max_priority);

/* If the loop is dead, we can simply sleep forever until a GTK+ source
* (presumably) wakes us back up again. */
if (!loop_alive)
return FALSE;
gint nfds;
while ((nfds = g_main_context_query (context, max_priority, &timeout, data->fds, data->nfds)) > data->nfds) {
delete[] data->fds;
data->fds = new GPollFD[nfds];
data->nfds = nfds;
}

/* Otherwise, check the timeout. If the timeout is 0, that means we're
* ready to go. Otherwise, keep sleeping until the timeout happens again. */
int t = uv_backend_timeout (source->loop);
*timeout = t;
g_poll (data->fds, data->nfds, timeout);

if (t == 0)
return TRUE;
else
return FALSE;
}
gboolean some_ready = g_main_context_check (context, max_priority, data->fds, data->nfds);

static gboolean uv_loop_source_dispatch (GSource *base, GSourceFunc callback, gpointer user_data) {
struct uv_loop_source *source = (struct uv_loop_source *) base;
uv_run (source->loop, UV_RUN_NOWAIT);
Util::CallNextTickCallback();
return G_SOURCE_CONTINUE;
if (some_ready) {
g_main_context_release (context);
uv_async_send(&data->async_handle);
uv_mutex_lock (&data->mutex_handle);
g_main_context_acquire (context);
}
}

static GSourceFuncs uv_loop_source_funcs = {
uv_loop_source_prepare,
NULL,
uv_loop_source_dispatch,
NULL,

NULL, NULL,
};

static GSource *uv_loop_source_new (uv_loop_t *loop) {
struct uv_loop_source *source = (struct uv_loop_source *) g_source_new (&uv_loop_source_funcs, sizeof (*source));
source->loop = loop;
g_source_add_unix_fd (&source->source,
uv_backend_fd (loop),
(GIOCondition) (G_IO_IN | G_IO_OUT | G_IO_ERR));
return &source->source;
static void RunGLibMainloop (ThreadData *data) {
g_main_context_acquire (g_main_context_default ());
uv_mutex_lock (&data->mutex_handle);
while (uv_loop_alive (uv_default_loop ()))
IterateGLibMainloop(data);
delete data;
}

void StartLoop() {
GSource *source = uv_loop_source_new (uv_default_loop ());
g_source_attach (source, NULL);
ThreadData *data = new ThreadData();
uv_mutex_init (&data->mutex_handle);
uv_async_init (uv_default_loop (), &data->async_handle, DispatchGLibMainloop);
data->async_handle.data = data;

uv_thread_create (&data->thread_handle, (uv_thread_cb)RunGLibMainloop, data);
}

};
23 changes: 23 additions & 0 deletions tests/loop.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* loop.js
*/


const gi = require('../lib/')
const Gtk = gi.require('Gtk', '3.0')

gi.startLoop()
Gtk.init()

setTimeout(() => {
console.log('timeout')
}, 1000)

const promise = new Promise(resolve => resolve('promise resolved'))
promise.then(result => console.log(result))

setTimeout(() => {
console.log('quit')
Gtk.mainQuit()
}, 5000)
Gtk.main()

0 comments on commit 7085caf

Please sign in to comment.