Skip to content

Commit 18bd912

Browse files
committed
draft
1 parent 468c7b8 commit 18bd912

File tree

4 files changed

+106
-59
lines changed

4 files changed

+106
-59
lines changed

examples/editor.js

+1
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ const execute = function(command) {
153153

154154

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

src/closure.cc

+13-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#include <glib.h>
2-
#include <nan.h>
2+
// #include <nan.h>
33

44
#include "debug.h"
55
#include "function.h"
@@ -13,9 +13,10 @@ namespace GNodeJS {
1313
struct Closure {
1414
GClosure base;
1515
Persistent<Function> persistent;
16-
GISignalInfo* info;
16+
GIBaseInfo* info;
1717

1818
~Closure() {
19+
persistent.Reset();
1920
if (info)
2021
g_base_info_unref(info);
2122
}
@@ -40,7 +41,7 @@ void Closure::Marshal(GClosure *base,
4041
HandleScope scope(isolate);
4142
Local<Context> context = Context::New(isolate);
4243
Context::Scope context_scope(context);
43-
Nan::TryCatch try_catch;
44+
// Nan::TryCatch try_catch;
4445

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

@@ -78,12 +79,14 @@ void Closure::Marshal(GClosure *base,
7879
}
7980
}
8081
else {
81-
auto stackTrace = try_catch.StackTrace();
82-
if (!stackTrace.IsEmpty())
83-
printf("%s\n", *Nan::Utf8String(stackTrace.ToLocalChecked()));
84-
else
85-
printf("%s\n", *Nan::Utf8String(try_catch.Exception()));
86-
exit(1);
82+
log("did throw");
83+
/* auto stackTrace = try_catch.StackTrace();
84+
* if (!stackTrace.IsEmpty())
85+
* printf("%s\n", *Nan::Utf8String(stackTrace.ToLocalChecked()));
86+
* else
87+
* printf("%s\n", *Nan::Utf8String(try_catch.Exception()));
88+
* exit(1); */
89+
// try_catch.ReThrow();
8790
}
8891

8992
#ifndef __linux__
@@ -96,7 +99,7 @@ void Closure::Invalidated(gpointer data, GClosure *base) {
9699
closure->~Closure();
97100
}
98101

99-
GClosure *MakeClosure(Isolate *isolate, Local<Function> function, GISignalInfo* info) {
102+
GClosure *MakeClosure(Isolate *isolate, Local<Function> function, GIBaseInfo* info) {
100103
Closure *closure = (Closure *) g_closure_new_simple (sizeof (*closure), NULL);
101104
closure->persistent.Reset(isolate, function);
102105
closure->info = info;

src/loop.cc

+69-49
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,93 @@
1+
/*
2+
* Taken from https://github.com/endlessm/eos-knowledge-content-node/blob/master/src/mainloop.cc
3+
* Relicensed in https://github.com/Place1/node-gir/issues/24
4+
*/
5+
16
#include <glib.h>
27
#include <uv.h>
38

49
#include "loop.h"
510
#include "util.h"
611

7-
/* Integration for the GLib main loop and uv's main loop */
8-
9-
/* The way that this works is that we take uv's loop and nest it inside GLib's
10-
* mainloop, since nesting GLib inside uv seems to be fairly impossible until
11-
* either uv allows external sources to drive prepare/check, or until GLib
12-
* exposes an epoll fd to wait on... */
12+
using namespace v8;
1313

1414
namespace GNodeJS {
1515

16-
struct uv_loop_source {
17-
GSource source;
18-
uv_loop_t *loop;
16+
struct ThreadData {
17+
uv_thread_t thread_handle;
18+
uv_mutex_t mutex_handle;
19+
uv_async_t async_handle;
20+
GPollFD *fds;
21+
gint nfds;
1922
};
2023

21-
static gboolean uv_loop_source_prepare (GSource *base, int *timeout) {
22-
struct uv_loop_source *source = (struct uv_loop_source *) base;
23-
uv_update_time (source->loop);
24+
/*
25+
* GLibs mainloop is not easy to embed directly right now. So rather then
26+
* embedding glib's mainloop inside libuvs mainloop, we are running glibs
27+
* mainloop in a separate thread. However we still want to be able to callback
28+
* into v8 javascript context from glib async code, so we call the dispatch
29+
* phase of glibs mainloop back on libuvs main thread. The flow is something
30+
* like
31+
*
32+
* glib thread: poll for events
33+
* glib thread: got events. wakeup libuv thread and lock
34+
* libuv thread: dispatch glib events
35+
* libuv thread: unlock glib thread
36+
* glib thread: poll for events
37+
* ...
38+
*
39+
* If in the future glib moves to epoll to drive its mainloop, we could easily
40+
* embed it inside of libuvs mainloop on the same thread, by polling on a single
41+
* fd. See https://bugzilla.gnome.org/show_bug.cgi?id=156048
42+
*/
43+
static void DispatchGLibMainloop (uv_async_t *async_handle) {
44+
ThreadData *data = (ThreadData *)async_handle->data;
45+
GMainContext *context = g_main_context_default ();
46+
g_main_context_acquire (context);
47+
g_main_context_dispatch (context);
48+
g_main_context_release (context);
49+
uv_mutex_unlock (&data->mutex_handle);
50+
}
2451

25-
bool loop_alive = uv_loop_alive (source->loop);
52+
static void IterateGLibMainloop (ThreadData *data) {
53+
GMainContext *context = g_main_context_default ();
54+
gint max_priority, timeout;
55+
g_main_context_prepare (context, &max_priority);
2656

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

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

37-
if (t == 0)
38-
return TRUE;
39-
else
40-
return FALSE;
41-
}
66+
gboolean some_ready = g_main_context_check (context, max_priority, data->fds, data->nfds);
4267

43-
static gboolean uv_loop_source_dispatch (GSource *base, GSourceFunc callback, gpointer user_data) {
44-
struct uv_loop_source *source = (struct uv_loop_source *) base;
45-
uv_run (source->loop, UV_RUN_NOWAIT);
46-
Util::CallNextTickCallback();
47-
return G_SOURCE_CONTINUE;
68+
if (some_ready) {
69+
g_main_context_release (context);
70+
uv_async_send(&data->async_handle);
71+
uv_mutex_lock (&data->mutex_handle);
72+
g_main_context_acquire (context);
73+
}
4874
}
4975

50-
static GSourceFuncs uv_loop_source_funcs = {
51-
uv_loop_source_prepare,
52-
NULL,
53-
uv_loop_source_dispatch,
54-
NULL,
55-
56-
NULL, NULL,
57-
};
58-
59-
static GSource *uv_loop_source_new (uv_loop_t *loop) {
60-
struct uv_loop_source *source = (struct uv_loop_source *) g_source_new (&uv_loop_source_funcs, sizeof (*source));
61-
source->loop = loop;
62-
g_source_add_unix_fd (&source->source,
63-
uv_backend_fd (loop),
64-
(GIOCondition) (G_IO_IN | G_IO_OUT | G_IO_ERR));
65-
return &source->source;
76+
static void RunGLibMainloop (ThreadData *data) {
77+
g_main_context_acquire (g_main_context_default ());
78+
uv_mutex_lock (&data->mutex_handle);
79+
while (uv_loop_alive (uv_default_loop ()))
80+
IterateGLibMainloop(data);
81+
delete data;
6682
}
6783

6884
void StartLoop() {
69-
GSource *source = uv_loop_source_new (uv_default_loop ());
70-
g_source_attach (source, NULL);
85+
ThreadData *data = new ThreadData();
86+
uv_mutex_init (&data->mutex_handle);
87+
uv_async_init (uv_default_loop (), &data->async_handle, DispatchGLibMainloop);
88+
data->async_handle.data = data;
89+
90+
uv_thread_create (&data->thread_handle, (uv_thread_cb)RunGLibMainloop, data);
7191
}
7292

7393
};

tests/loop.js

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* loop.js
3+
*/
4+
5+
6+
const gi = require('../lib/')
7+
const Gtk = gi.require('Gtk', '3.0')
8+
9+
gi.startLoop()
10+
Gtk.init()
11+
12+
setTimeout(() => {
13+
console.log('timeout')
14+
}, 1000)
15+
16+
const promise = new Promise(resolve => resolve('promise resolved'))
17+
promise.then(result => console.log(result))
18+
19+
setTimeout(() => {
20+
console.log('quit')
21+
Gtk.mainQuit()
22+
}, 5000)
23+
Gtk.main()

0 commit comments

Comments
 (0)