gjs r22 - in trunk: . modules
- From: jobi svn gnome org
- To: svn-commits-list gnome org
- Subject: gjs r22 - in trunk: . modules
- Date: Mon, 13 Oct 2008 21:54:01 +0000 (UTC)
Author: jobi
Date: Mon Oct 13 21:54:01 2008
New Revision: 22
URL: http://svn.gnome.org/viewvc/gjs?rev=22&view=rev
Log:
Add a GMainLoop wrapper module
Added:
trunk/modules/mainloop.c
trunk/modules/mainloop.h
Modified:
trunk/Makefile-modules.am
Modified: trunk/Makefile-modules.am
==============================================================================
--- trunk/Makefile-modules.am (original)
+++ trunk/Makefile-modules.am Mon Oct 13 21:54:01 2008
@@ -1,6 +1,6 @@
dist_gjsjs_DATA += modules/lang.js
-gjsnative_LTLIBRARIES += gi.la
+gjsnative_LTLIBRARIES += gi.la mainloop.la
JS_NATIVE_MODULE_CFLAGS = \
$(AM_CFLAGS) \
@@ -24,3 +24,17 @@
gi_la_SOURCES = \
modules/gi.h \
modules/gi.c
+
+mainloop_la_CFLAGS = \
+ $(JS_NATIVE_MODULE_CFLAGS) \
+ $(GOBJECT_INTROSPECTION_CFLAGS)
+mainloop_la_LIBADD = \
+ libgjs-gi.la \
+ $(JS_NATIVE_MODULE_LIBADD) \
+ $(GOBJECT_INTROSPECTION_LIBS)
+mainloop_la_LDFLAGS = \
+ $(JS_NATIVE_MODULE_LDFLAGS)
+
+mainloop_la_SOURCES = \
+ modules/mainloop.h \
+ modules/mainloop.c
Added: trunk/modules/mainloop.c
==============================================================================
--- (empty file)
+++ trunk/modules/mainloop.c Mon Oct 13 21:54:01 2008
@@ -0,0 +1,414 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (c) 2008 litl, LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "mainloop.h"
+#include <gjs/gjs.h>
+
+#include "../gi/closure.h"
+
+#include <util/log.h>
+
+#include <glib.h>
+
+#include <jsapi.h>
+
+static GHashTable *pending_main_loops;
+
+static JSBool
+gjs_main_loop_quit(JSContext *context,
+ JSObject *obj,
+ uintN argc,
+ jsval *argv,
+ jsval *retval)
+{
+ const char *cancel_id;
+ GMainLoop *main_loop;
+
+ if (argc != 1 ||
+ !JSVAL_IS_STRING(argv[0])) {
+ gjs_throw(context, "quit() takes one arg, the cancel id");
+ return JS_FALSE;
+ }
+
+ cancel_id = gjs_string_get_ascii_checked(context, argv[0]);
+ if (cancel_id == NULL)
+ return JS_FALSE;
+
+ main_loop = g_hash_table_lookup(pending_main_loops, cancel_id);
+
+ if (!main_loop) {
+ gjs_throw(context, "No main loop with this id");
+ return JS_FALSE;
+ }
+
+ g_hash_table_remove(pending_main_loops, cancel_id);
+
+ if (!g_main_loop_is_running(main_loop)) {
+ gjs_throw(context, "Main loop was stopped already");
+ return JS_FALSE;
+ }
+
+ gjs_debug(GJS_DEBUG_MAINLOOP,
+ "main loop %s quitting in context %p",
+ cancel_id,
+ context);
+
+ g_main_loop_quit(main_loop);
+ return JS_TRUE;
+}
+
+static JSBool
+gjs_main_loop_run(JSContext *context,
+ JSObject *obj,
+ uintN argc,
+ jsval *argv,
+ jsval *retval)
+{
+ const char *cancel_id;
+ GMainLoop *main_loop;
+
+ if (argc != 1 ||
+ !JSVAL_IS_STRING(argv[0])) {
+ gjs_throw(context, "run() takes one arg, the cancel id");
+ return JS_FALSE;
+ }
+
+ cancel_id = gjs_string_get_ascii_checked(context, argv[0]);
+ if (cancel_id == NULL)
+ return JS_FALSE;
+
+ main_loop = g_hash_table_lookup(pending_main_loops, cancel_id);
+
+ if (!main_loop) {
+ main_loop = g_main_loop_new(NULL, FALSE);
+ g_hash_table_replace(pending_main_loops, g_strdup(cancel_id), main_loop);
+ } else {
+ g_object_ref(main_loop);
+ }
+
+ gjs_debug(GJS_DEBUG_MAINLOOP,
+ "main loop %s being run in context %p",
+ cancel_id,
+ context);
+
+ g_main_loop_run(main_loop);
+ g_main_loop_unref(main_loop);
+ return JS_TRUE;
+}
+
+static gboolean
+closure_source_func(void *data)
+{
+ jsval retval;
+ GClosure *closure;
+ JSBool bool_val;
+ JSContext *context;
+
+ closure = data;
+
+ context = gjs_closure_get_context(closure);
+ if (context == NULL) {
+ /* closure is invalid now */
+ return FALSE;
+ }
+
+ retval = JSVAL_VOID;
+ JS_AddRoot(context, &retval);
+
+ gjs_closure_invoke(closure,
+ 0, NULL,
+ &retval);
+
+ /* ValueToBoolean pretty much always succeeds, just as
+ * JavaScript always makes some sense of any value in
+ * an "if (value) {}" context.
+ */
+ if (!JS_ValueToBoolean(gjs_closure_get_context(closure),
+ retval, &bool_val))
+ bool_val = FALSE;
+
+ JS_RemoveRoot(context, &retval);
+
+ return bool_val;
+}
+
+static void
+closure_destroy_notify(void *data)
+{
+ GClosure *closure;
+
+ closure = data;
+
+ g_closure_invalidate(closure);
+ g_closure_unref(closure);
+}
+
+static void
+closure_invalidated(gpointer data,
+ GClosure *closure)
+{
+ /* We may be invalidated because the source was removed and
+ * destroy notify called, or we may be invalidated for an external
+ * reason like JSContext destroy, in which case removing the
+ * source here will call our destroy notify.
+ *
+ * If we're invalidated due to the source being removed, then
+ * removing it here will be a no-op.
+ */
+ g_source_remove(GPOINTER_TO_UINT(data));
+}
+
+static JSBool
+gjs_timeout_add(JSContext *context,
+ JSObject *obj,
+ uintN argc,
+ jsval *argv,
+ jsval *retval)
+{
+ GClosure *closure;
+ guint interval;
+ guint id;
+
+ /* Best I can tell, there is no way to know if argv[1] is really
+ * callable other than to just try it. Checking whether it's a
+ * function will not detect native objects that provide
+ * JSClass::call, for example.
+ */
+
+ if (argc != 2) {
+ gjs_throw(context, "timeout_add() takes two args, the interval and the timeout callback");
+ return JS_FALSE;
+ }
+
+ if (!JSVAL_IS_INT(argv[0])) {
+ gjs_throw(context, "The interval for timeout_add must be an integer");
+ return JS_FALSE;
+ }
+
+ if (!JSVAL_IS_OBJECT(argv[1])) {
+ gjs_throw(context, "The callback for timeout_add is not callable");
+ return JS_FALSE;
+ }
+
+ closure = gjs_closure_new(context, JSVAL_TO_OBJECT(argv[1]), "timeout");
+ if (closure == NULL)
+ return JS_FALSE;
+
+ g_closure_ref(closure);
+ g_closure_sink(closure);
+
+ interval = JSVAL_TO_INT(argv[0]);
+
+ id = g_timeout_add_full(G_PRIORITY_DEFAULT,
+ interval,
+ closure_source_func,
+ closure,
+ closure_destroy_notify);
+
+ /* this is needed to remove the timeout if the JSContext is
+ * destroyed.
+ */
+ g_closure_add_invalidate_notifier(closure, GUINT_TO_POINTER(id),
+ closure_invalidated);
+
+ if (!JS_NewNumberValue(context, id, retval))
+ return JS_FALSE;
+
+ return JS_TRUE;
+}
+
+static JSBool
+gjs_timeout_add_seconds(JSContext *context,
+ JSObject *obj,
+ uintN argc,
+ jsval *argv,
+ jsval *retval)
+{
+ GClosure *closure;
+ guint interval;
+ guint id;
+
+ /* Best I can tell, there is no way to know if argv[1] is really
+ * callable other than to just try it. Checking whether it's a
+ * function will not detect native objects that provide
+ * JSClass::call, for example.
+ */
+
+ if (argc != 2) {
+ gjs_throw(context, "timeout_add_seconds() takes two args, the interval and the timeout callback");
+ return JS_FALSE;
+ }
+
+ if (!JSVAL_IS_INT(argv[0])) {
+ gjs_throw(context, "The interval for timeout_add_seconds must be an integer");
+ return JS_FALSE;
+ }
+
+ if (!JSVAL_IS_OBJECT(argv[1])) {
+ gjs_throw(context, "The callback for timeout_add_seconds is not callable");
+ return JS_FALSE;
+ }
+
+ closure = gjs_closure_new(context, JSVAL_TO_OBJECT(argv[1]), "timeout_seconds");
+ if (closure == NULL)
+ return JS_FALSE;
+
+ g_closure_ref(closure);
+ g_closure_sink(closure);
+
+ interval = JSVAL_TO_INT(argv[0]);
+
+ id = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT,
+ interval,
+ closure_source_func,
+ closure,
+ closure_destroy_notify);
+
+ /* this is needed to remove the timeout if the JSContext is
+ * destroyed.
+ */
+ g_closure_add_invalidate_notifier(closure, GUINT_TO_POINTER(id),
+ closure_invalidated);
+
+ if (!JS_NewNumberValue(context, id, retval))
+ return JS_FALSE;
+
+ return JS_TRUE;
+}
+
+static JSBool
+gjs_idle_add(JSContext *context,
+ JSObject *obj,
+ uintN argc,
+ jsval *argv,
+ jsval *retval)
+{
+ GClosure *closure;
+ guint id;
+
+ /* Best I can tell, there is no way to know if argv[0] is really
+ * callable other than to just try it. Checking whether it's a
+ * function will not detect native objects that provide
+ * JSClass::call, for example.
+ */
+
+ if (argc != 1 ||
+ !JSVAL_IS_OBJECT(argv[0])) {
+ gjs_throw(context, "idle_add() takes one arg, the idle callback");
+ return JS_FALSE;
+ }
+
+ closure = gjs_closure_new(context, JSVAL_TO_OBJECT(argv[0]), "idle");
+ if (closure == NULL)
+ return JS_FALSE;
+
+ g_closure_ref(closure);
+ g_closure_sink(closure);
+
+ id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
+ closure_source_func,
+ closure,
+ closure_destroy_notify);
+
+ /* this is needed to remove the idle if the JSContext is
+ * destroyed.
+ */
+ g_closure_add_invalidate_notifier(closure, GUINT_TO_POINTER(id),
+ closure_invalidated);
+
+ if (!JS_NewNumberValue(context, id, retval))
+ return JS_FALSE;
+
+ return JS_TRUE;
+}
+
+static JSBool
+gjs_source_remove(JSContext *context,
+ JSObject *obj,
+ uintN argc,
+ jsval *argv,
+ jsval *retval)
+{
+ gboolean success;
+
+ if (argc != 1 ||
+ !JSVAL_IS_INT(argv[0])) {
+ gjs_throw(context, "source_remove() takes one arg, the integer source id");
+ return JS_FALSE;
+ }
+
+ success = g_source_remove(JSVAL_TO_INT(argv[0]));
+
+ *retval = BOOLEAN_TO_JSVAL(success);
+
+ return JS_TRUE;
+}
+
+JSBool
+gjs_define_mainloop_stuff(JSContext *context,
+ JSObject *module_obj)
+{
+ // FIXME this should be per JSObject, and we should free it when
+ // the object is finalized
+ pending_main_loops = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
+
+ if (!JS_DefineFunction(context, module_obj,
+ "run",
+ gjs_main_loop_run,
+ 1, GJS_MODULE_PROP_FLAGS))
+ return JS_FALSE;
+
+ if (!JS_DefineFunction(context, module_obj,
+ "quit",
+ gjs_main_loop_quit,
+ 1, GJS_MODULE_PROP_FLAGS))
+ return JS_FALSE;
+
+ if (!JS_DefineFunction(context, module_obj,
+ "idle_add",
+ gjs_idle_add,
+ 1, GJS_MODULE_PROP_FLAGS))
+ return JS_FALSE;
+
+ if (!JS_DefineFunction(context, module_obj,
+ "timeout_add",
+ gjs_timeout_add,
+ 2, GJS_MODULE_PROP_FLAGS))
+ return JS_FALSE;
+
+ if (!JS_DefineFunction(context, module_obj,
+ "timeout_add_seconds",
+ gjs_timeout_add_seconds,
+ 2, GJS_MODULE_PROP_FLAGS))
+ return JS_FALSE;
+
+ if (!JS_DefineFunction(context, module_obj,
+ "source_remove",
+ gjs_source_remove,
+ 1, GJS_MODULE_PROP_FLAGS))
+ return JS_FALSE;
+
+ return JS_TRUE;
+}
+
+GJS_REGISTER_NATIVE_MODULE("mainloop", gjs_define_mainloop_stuff)
Added: trunk/modules/mainloop.h
==============================================================================
--- (empty file)
+++ trunk/modules/mainloop.h Mon Oct 13 21:54:01 2008
@@ -0,0 +1,39 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (c) 2008 litl, LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef __GJS_MAINLOOP_H__
+#define __GJS_MAINLOOP_H__
+
+#include <config.h>
+#include <glib.h>
+
+#include <jsapi.h>
+
+G_BEGIN_DECLS
+
+JSBool gjs_define_mainloop_stuff (JSContext *context,
+ JSObject *in_object);
+
+G_END_DECLS
+
+#endif /* __GJS_MAINLOOP_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]