// Is this going to leak later? static gboolean signature_from_method(SeedContext ctx, SeedObject method_obj, const char **signature, SeedException *exception) { SeedValue signature_value; if ((signature_value = seed_object_get_property(ctx, method_obj, "outSignature"))) { *signature = seed_value_to_string (ctx, signature_value, exception); if (*signature == NULL) { return FALSE; } } else { /* We default to a{sv} */ *signature = "a{sv}"; } return TRUE; }
static void peas_extension_seed_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { PeasExtensionSeed *sexten = PEAS_EXTENSION_SEED (object); SeedValue seed_value; SeedException exc = NULL; gchar *prop_name; /* Don't add properties as they could shadow the instance's */ prop_name = convert_property_name (pspec->name); seed_value = seed_object_get_property (sexten->js_context, sexten->js_object, prop_name); g_free (prop_name); seed_value_to_gvalue (sexten->js_context, seed_value, pspec->value_type, value, &exc); if (exc != NULL) { gchar *exc_string; exc_string = seed_exception_to_string (sexten->js_context, exc); g_warning ("Seed Exception: %s", exc_string); g_free (exc_string); } }
static SeedObject find_js_property_by_path(SeedContext ctx, SeedObject root_obj, const gchar *path) { gchar **elements; gint i; SeedObject obj; elements = g_strsplit(path, "/", -1); obj = root_obj; /* g_strsplit returns empty string for the first * '/' so we start with elements[1] */ for (i = 1; elements[i] != NULL; ++i) { obj = seed_object_get_property(ctx, obj, elements[i]); if (seed_value_is_undefined (ctx, obj) || !seed_value_is_object (ctx, obj)) { obj = NULL; break; } } g_strfreev(elements); return obj; }
static void test_extension_seed_plugin_info (PeasEngine *engine) { PeasPluginInfo *info; PeasExtension *extension; PeasExtensionSeed *sexten; SeedValue seed_value; GValue gvalue = { 0 }; info = peas_engine_get_plugin_info (engine, "extension-seed"); g_assert (peas_engine_load_plugin (engine, info)); extension = peas_engine_create_extension (engine, info, INTROSPECTION_TYPE_CALLABLE, NULL); g_assert (PEAS_IS_EXTENSION (extension)); sexten = (PeasExtensionSeed *) extension; seed_value = seed_object_get_property (sexten->js_context, sexten->js_object, "plugin_info"); g_assert (seed_value_to_gvalue (sexten->js_context, seed_value, PEAS_TYPE_PLUGIN_INFO, &gvalue, NULL)); g_assert (g_value_get_boxed (&gvalue) == info); g_value_unset (&gvalue); g_object_unref (extension); }
static void seed_builder_connect_func (GtkBuilder *builder, GObject *object, const gchar *signal_name, const gchar *handler_name, GObject *connect_object, GConnectFlags flags, gpointer user_data) { SeedContext ctx; SeedObject obj, func; builder_ud *priv = (builder_ud *)user_data; GClosure *closure; ctx = priv->ctx; obj = priv->obj; func = seed_object_get_property (ctx, obj, handler_name); if (!seed_value_is_object (ctx, func) || !seed_value_is_function (ctx, func)) return; closure = seed_closure_new (ctx, func, priv->user_data, "signal handler (GtkBuilder)"); if (connect_object != NULL) g_object_watch_closure (connect_object, closure); g_signal_connect_closure (object, signal_name, closure, FALSE); }
SeedObject gjs_compat_define_gi_stuff(SeedEngine* eng) { SeedContext context = eng->context; SeedObject module; gboolean ret; module = seed_make_object(context, seed_create_class(&system_def), NULL); SeedValue seed = seed_object_get_property(context, eng->global, "Seed"); SeedValue argv = seed_object_get_property(context, seed, "argv"); ret = seed_object_set_property( context, module, "version", (SeedValue) seed_value_from_int(context, GJS_COMPAT_VERSION, NULL)); return module; }
/** * seed_exception_get_line: * @ctx: A #SeedContext. * @exception: A reference to a #SeedException. * * Retrieves the line number the given exception was thrown from; keep in mind * that exceptions created from C have an undefined line number. * * Return value: A #guint representing the line number from which @exception * was thrown. * */ guint seed_exception_get_line (JSContextRef ctx, JSValueRef e) { JSValueRef line; g_assert ((e)); if (!JSValueIsObject (ctx, e)) return 0; line = seed_object_get_property (ctx, (JSObjectRef) e, "line"); return seed_value_to_uint (ctx, line, NULL); }
/** * seed_exception_get_file: * @ctx: A #SeedContext. * @exception: A reference to a #SeedException. * * Retrieves the file name the given exception was thrown from; keep in mind * that exceptions created from C have an undefined file name. * * Return value: A #gchar* representing the name of the file from which * @exception was thrown. * */ gchar * seed_exception_get_file (JSContextRef ctx, JSValueRef e) { JSValueRef line; g_assert ((e)); if (!JSValueIsObject (ctx, e)) return 0; line = seed_object_get_property (ctx, (JSObjectRef) e, "sourceURL"); return seed_value_to_string (ctx, line, 0); }
/** * seed_exception_get_message: * @ctx: A #SeedContext. * @exception: A reference to a #SeedException. * * Retrieves the message of the given exception; this should be a * human-readable string describing the exception enough that a developer * could utilize the message in order to determine where to look to debug * the problem. * * Return value: A #gchar* representing the detailed message of @exception. * */ gchar * seed_exception_get_message (JSContextRef ctx, JSValueRef e) { JSValueRef name; g_assert ((e)); if (!JSValueIsObject (ctx, e)) return 0; name = seed_object_get_property (ctx, (JSObjectRef) e, "message"); return seed_value_to_string (ctx, name, NULL); }
static gboolean find_method(SeedContext ctx, SeedObject obj, const gchar *method_name, SeedValue *method_value) { *method_value = seed_object_get_property (ctx, obj, method_name); if (seed_value_is_undefined (ctx, *method_value) || !seed_value_is_object (ctx, *method_value)) return FALSE; return TRUE; }
static gboolean seed_ffi_build_signature (SeedContext ctx, seed_ffi_function_priv *priv, SeedObject sig, SeedException *exception) { SeedObject arguments; SeedValue ret_type_ref, length_ref; guint length, i; arguments = seed_object_get_property (ctx, sig, "arguments"); ret_type_ref = seed_object_get_property (ctx, sig, "returns"); if (!seed_value_is_object (ctx, arguments)) { seed_make_exception (ctx, exception, "FFIError", "Signature arguments member must be an array describing argument types"); return FALSE; } length_ref = seed_object_get_property (ctx, arguments, "length"); length = seed_value_to_uint (ctx, length_ref, exception); priv->n_args = length; priv->args = g_slice_alloc (length * sizeof (GType)); for (i = 0; i < length; i++) { SeedValue type = seed_object_get_property_at_index (ctx, arguments, i, exception); priv->args[i] = seed_value_to_int (ctx, type, exception); } priv->ret_val = seed_value_to_int (ctx, ret_type_ref, exception); priv->signature_obj = sig; seed_value_protect (ctx, sig); return TRUE; }
static gboolean dbus_reply_from_exception_and_sender(SeedContext ctx, const gchar *sender, dbus_uint32_t serial, DBusMessage **reply_p, SeedException *exception) { SeedValue name_val; gchar *s; const gchar *name = NULL; *reply_p = NULL; if (seed_value_is_undefined (ctx, *exception) || seed_value_is_null (ctx, *exception) || !seed_value_is_object (ctx, *exception)) return FALSE; name_val = seed_object_get_property(ctx, *exception, "dbusErrorName"); name = seed_value_to_string (ctx, name_val, NULL); s = seed_exception_to_string (ctx, *exception); g_warning("JS exception we will send as dbus reply to %s: %s", sender, s); *reply_p = dbus_message_new(DBUS_MESSAGE_TYPE_ERROR); dbus_message_set_destination(*reply_p, sender); dbus_message_set_reply_serial(*reply_p, serial); dbus_message_set_no_reply(*reply_p, TRUE); dbus_message_set_error_name(*reply_p, name ? name : DBUS_ERROR_FAILED); if (s != NULL) { DBusMessageIter iter; dbus_message_iter_init_append(*reply_p, &iter); if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &s)) { dbus_message_unref(*reply_p); g_free(s); return FALSE; } g_free(s); } return TRUE; }
static gboolean peas_plugin_loader_seed_provides_extension (PeasPluginLoader *loader, PeasPluginInfo *info, GType exten_type) { PeasPluginLoaderSeed *sloader = PEAS_PLUGIN_LOADER_SEED (loader); SeedInfo *sinfo; SeedValue extension; sinfo = (SeedInfo *) g_hash_table_lookup (sloader->loaded_plugins, info); extension = seed_object_get_property (sinfo->context, sinfo->extensions, g_type_name (exten_type)); return extension && seed_value_is_object (sinfo->context, extension); }
static gboolean peas_plugin_loader_seed_load (PeasPluginLoader *loader, PeasPluginInfo *info) { PeasPluginLoaderSeed *sloader = PEAS_PLUGIN_LOADER_SEED (loader); SeedContext context; gchar *script; SeedException exc = NULL; SeedObject global, extensions; SeedInfo *sinfo; context = seed_context_create (seed->group, NULL); seed_prepare_global_context (context); script = get_script_for_plugin_info (info, context); seed_simple_evaluate (context, script, &exc); g_free (script); if (exc) { gchar *exc_string = seed_exception_to_string (context, exc); g_warning ("Seed Exception: %s", exc_string); g_free (exc_string); seed_context_unref (context); return FALSE; } global = seed_context_get_global_object (context); extensions = seed_object_get_property (context, global, "extensions"); if (seed_value_is_object (context, extensions)) { sinfo = (SeedInfo *) g_slice_new (SeedInfo); sinfo->context = context; sinfo->extensions = extensions; seed_context_ref (context); seed_value_protect (context, extensions); g_hash_table_insert (sloader->loaded_plugins, info, sinfo); } seed_context_unref (context); return TRUE; }
gulong seed_gobject_signal_connect (JSContextRef ctx, const gchar * signal_name, GObject * on_obj, JSObjectRef func, JSObjectRef this_obj, JSObjectRef user_data) { GSignalQuery query; GClosure *closure; if (g_str_has_prefix (signal_name, "notify::")) g_signal_query (g_signal_lookup ("notify", G_OBJECT_TYPE (on_obj)), &query); else g_signal_query (g_signal_lookup (signal_name, G_OBJECT_TYPE (on_obj)), &query); #ifdef SEED_ENABLE_DEBUG { guint function_arity = seed_value_to_uint (ctx, seed_object_get_property (ctx, func, "length"), NULL); if (function_arity != query.n_params) { SEED_MARK (); SEED_NOTE (SIGNAL, "Connecting signal: %s. Function has arity %d, signal expects %d", query.signal_name, function_arity, query.n_params); SEED_MARK (); } } #endif closure = seed_closure_new_for_signal (ctx, func, user_data, "signal handler", query.signal_id); // This seems wrong... ((SeedClosure *) closure)->return_type = query.return_type; return g_signal_connect_closure (on_obj, signal_name, closure, FALSE); }
static SeedValue async_call_callback(SeedContext ctx, SeedObject function, SeedObject this_object, gsize argument_count, const SeedValue arguments[], SeedException *exception) { DBusConnection *connection; DBusBusType which_bus; DBusMessage *reply; const char *sender; dbus_uint32_t serial; SeedValue prop_value, retval; const char *signature; gboolean thrown; retval = seed_make_undefined (ctx); reply = NULL; thrown = FALSE; prop_value = seed_object_get_property (ctx, function, "_dbusSender"); sender = seed_value_to_string (ctx, prop_value, exception); if (!sender) return FALSE; prop_value = seed_object_get_property(ctx, function, "_dbusSerial"); serial = seed_value_to_uint (ctx, prop_value, exception); prop_value = seed_object_get_property(ctx, function, "_dbusBusType"); which_bus = seed_value_to_int(ctx, prop_value, exception); /* From now we have enough information to * send the exception back to the callee so we'll do so */ prop_value = seed_object_get_property(ctx, function, "_dbusOutSignature"); signature = seed_value_to_string (ctx, prop_value, exception); if (!signature) return FALSE; if (argument_count != 1) { seed_make_exception(ctx, exception, "ArgumentError", "The callback to async DBus calls takes one argument, " "the return value or array of return values"); thrown = TRUE; goto out; } reply = build_reply_from_jsval(ctx, signature, sender, serial, arguments[0], exception); out: if (!reply && thrown) { if (!dbus_reply_from_exception_and_sender(ctx, sender, serial, &reply, exception)) g_warning("dbus method invocation failed but no exception was set?"); } if (reply) { big_dbus_add_bus_weakref(which_bus, &connection); if (!connection) { seed_make_exception(ctx, exception, "DBusError", "We were disconnected from the bus before the callback " "to some async remote call was called"); dbus_message_unref(reply); big_dbus_remove_bus_weakref(which_bus, &connection); return FALSE; } dbus_connection_send(connection, reply, NULL); big_dbus_remove_bus_weakref(which_bus, &connection); dbus_message_unref(reply); } return retval; }
static PeasExtension * peas_plugin_loader_seed_create_extension (PeasPluginLoader *loader, PeasPluginInfo *info, GType exten_type, guint n_parameters, GParameter *parameters) { PeasPluginLoaderSeed *sloader = PEAS_PLUGIN_LOADER_SEED (loader); SeedInfo *sinfo; SeedValue extension_ctor, extension; guint i, j; SeedValue value; GValue gvalue = { 0 }; GArray *interfaces; gchar **property_names; sinfo = (SeedInfo *) g_hash_table_lookup (sloader->loaded_plugins, info); /* FIXME: instantiate new object and pass the parameters */ extension_ctor = seed_object_get_property (sinfo->context, sinfo->extensions, g_type_name (exten_type)); if (!extension_ctor || seed_value_is_undefined (sinfo->context, extension_ctor) || seed_value_is_null (sinfo->context, extension_ctor)) return NULL; if (!seed_value_is_object (sinfo->context, extension_ctor)) { g_warning ("Extension '%s' in plugin '%s' is not a Seed object", g_type_name (exten_type), peas_plugin_info_get_module_name (info)); return NULL; } /* Instantiate the ctor object into a new specific object. */ extension = JSObjectCallAsConstructor (sinfo->context, extension_ctor, 0, NULL, NULL); if (extension == NULL) { #ifndef PEAS_DISABLE_DEPRECATED_FEATURES gchar **property_names; g_warning ("DEPRECATION WARNING: Extension '%s' in plugin '%s' is not a valid " "constructor function. Support for extension initialization by array " "copy will be dropped soon.", g_type_name (exten_type), peas_plugin_info_get_module_name (info)); extension = seed_make_object (sinfo->context, NULL, NULL); property_names = seed_object_copy_property_names (sinfo->context, extension_ctor); for (i = 0; property_names[i] != NULL; i++) { SeedValue value; value = seed_object_get_property (sinfo->context, extension_ctor, property_names[i]); seed_object_set_property (sinfo->context, extension, property_names[i], value); } g_strfreev (property_names); #else g_warning ("Extension '%s' in plugin '%s' is not a valid constructor", g_type_name (exten_type), peas_plugin_info_get_module_name (info)); return NULL; #endif } /* Set the properties as well, cannot use * g_object_set_property() because it may be construct-only */ for (i = 0; i < n_parameters; i++) { gchar *key; /* We want to normalize the property names to have a '_' instead of the * conventional '-', to make them accessible through this.property_name */ key = g_strdup (parameters[i].name); for (j = 0; key[j] != '\0'; j++) { if (key[j] == '-') key[j] = '_'; } value = seed_value_from_gvalue (sinfo->context, ¶meters[i].value, NULL); seed_object_set_property (sinfo->context, extension, key, value); g_free (key); } /* Set the plugin info as an attribute of the instance */ g_value_init (&gvalue, PEAS_TYPE_PLUGIN_INFO); g_value_set_boxed (&gvalue, info); value = seed_value_from_gvalue (sinfo->context, &gvalue, NULL); seed_object_set_property (sinfo->context, extension, "plugin_info", value); g_value_unset (&gvalue); /* Do not add exten_type as it will be added below */ interfaces = g_array_new (TRUE, FALSE, sizeof (GType)); property_names = seed_object_copy_property_names (sinfo->context, sinfo->extensions); for (i = 0; property_names[i] != NULL; ++i) { gchar *property_name = property_names[i]; SeedValue *prop_extension_ctor; GType the_type; prop_extension_ctor = seed_object_get_property (sinfo->context, sinfo->extensions, property_name); if (prop_extension_ctor != extension_ctor) continue; if (!seed_value_is_object (sinfo->context, extension_ctor)) { g_warning ("Extension '%s' in plugin '%s' is not a Seed object", property_name, peas_plugin_info_get_module_name (info)); continue; } the_type = peas_gi_get_type_from_name (property_name); if (the_type == G_TYPE_INVALID) { g_warning ("Could not find GType for '%s', " "did you forget to import it?", property_name); } else { g_array_append_val (interfaces, the_type); } } g_array_sort (interfaces, (GCompareFunc) prerequisites_sort); g_strfreev (property_names); return peas_extension_seed_new (exten_type, (GType *) g_array_free (interfaces, FALSE), sinfo->context, extension); }
static gboolean peas_plugin_loader_seed_load (PeasPluginLoader *loader, PeasPluginInfo *info) { PeasPluginLoaderSeed *sloader = PEAS_PLUGIN_LOADER_SEED (loader); gchar *filename; gchar *content; GError *error = NULL; SeedContext context; SeedScript *script; SeedException exc = NULL; SeedObject global, extensions; SeedInfo *sinfo; filename = get_script_filename_for_plugin_info (info); g_debug ("Seed script filename is '%s'", filename); if (!g_file_get_contents (filename, &content, NULL, &error)) { g_warning ("Error: %s", error->message); g_error_free (error); g_free (filename); return FALSE; } context = seed_context_create (seed->group, NULL); seed_prepare_global_context (context); script = seed_make_script (context, content, filename, 0); seed_evaluate (context, script, NULL); exc = seed_script_exception (script); seed_script_destroy (script); g_free (content); g_free (filename); if (exc) { gchar *exc_string = seed_exception_to_string (context, exc); g_warning ("Seed Exception: %s", exc_string); g_free (exc_string); seed_context_unref (context); return FALSE; } global = seed_context_get_global_object (context); extensions = seed_object_get_property (context, global, "extensions"); if (seed_value_is_object (context, extensions)) { sinfo = (SeedInfo *) g_slice_new (SeedInfo); sinfo->context = context; sinfo->extensions = extensions; seed_value_protect (context, extensions); g_hash_table_insert (sloader->loaded_plugins, info, sinfo); return TRUE; } else { g_warning ("extensions is not an object in plugin '%s'", peas_plugin_info_get_module_name (info)); seed_context_unref (context); return FALSE; } }
static gboolean peas_extension_seed_call (PeasExtensionWrapper *exten, const gchar *method_name, GIArgument *args, GIArgument *retval) { PeasExtensionSeed *sexten = PEAS_EXTENSION_SEED (exten); GType exten_type; SeedValue js_method; GICallableInfo *func_info; gint n_args, i; SeedValue *js_in_args; OutArg *out_args; SeedValue js_ret, val; SeedException exc = NULL; gchar *exc_string; gint n_in_args = 0; gint n_out_args = 0; GIArgument argument; g_return_val_if_fail (sexten->js_context != NULL, FALSE); g_return_val_if_fail (sexten->js_object != NULL, FALSE); exten_type = peas_extension_wrapper_get_extension_type (exten); /* Fetch the JS method we want to call */ js_method = seed_object_get_property (sexten->js_context, sexten->js_object, method_name); if (seed_value_is_undefined (sexten->js_context, js_method)) { g_warning ("Method '%s.%s' is not defined", g_type_name (exten_type), method_name); return FALSE; } /* We want to display an error if the method is defined but is not a function. */ if (!seed_value_is_function (sexten->js_context, js_method)) { g_warning ("Method '%s.%s' is not a function", g_type_name (exten_type), method_name); return FALSE; } /* Prepare the arguments */ func_info = peas_gi_get_method_info (exten_type, method_name); if (func_info == NULL) return FALSE; n_args = g_callable_info_get_n_args (func_info); g_return_val_if_fail (n_args >= 0, FALSE); js_in_args = g_newa (SeedValue, n_args); out_args = g_newa (OutArg, n_args + 1); /* We put the return value first in the out tuple, as it seems to be * the common behaviour for GI-based bindings */ g_callable_info_load_return_type (func_info, &out_args[0].type_info); if (g_type_info_get_tag (&out_args[0].type_info) != GI_TYPE_TAG_VOID) out_args[n_out_args++].ptr = &retval->v_pointer; /* Handle the other arguments */ for (i = 0; i < n_args && exc == NULL; i++) { GIArgInfo arg_info; GIDirection direction; g_callable_info_load_arg (func_info, i, &arg_info); direction = g_arg_info_get_direction (&arg_info); g_arg_info_load_type (&arg_info, &out_args[n_out_args].type_info); if (direction == GI_DIRECTION_IN) { js_in_args[n_in_args++] = seed_value_from_gi_argument (sexten->js_context, &args[i], &out_args[n_out_args].type_info, &exc); } if (direction == GI_DIRECTION_INOUT) { GIArgument arg; peas_gi_pointer_to_argument (&out_args[n_out_args].type_info, args[i].v_pointer, &arg); js_in_args[n_in_args++] = seed_value_from_gi_argument (sexten->js_context, &arg, &out_args[n_out_args].type_info, &exc); } if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) out_args[n_out_args++].ptr = args[i].v_pointer; } if (exc != NULL) goto cleanup; js_ret = seed_object_call (sexten->js_context, js_method, sexten->js_object, n_in_args, js_in_args, &exc); if (exc != NULL) goto cleanup; if (n_out_args == 1) { if (seed_value_to_gi_argument (sexten->js_context, js_ret, &out_args[0].type_info, &argument, &exc)) { peas_gi_argument_to_pointer (&out_args[0].type_info, &argument, out_args[0].ptr); } } else if (n_out_args > 0 && seed_value_is_object (sexten->js_context, js_ret)) { for (i = 0; i < n_out_args && exc == NULL; i++) { val = seed_object_get_property_at_index (sexten->js_context, js_ret, i, exc); if (exc == NULL && seed_value_to_gi_argument (sexten->js_context, val, &out_args[i].type_info, &argument, &exc)) { peas_gi_argument_to_pointer (&out_args[i].type_info, &argument, out_args[i].ptr); } } } cleanup: g_base_info_unref ((GIBaseInfo *) func_info); if (exc == NULL) return TRUE; exc_string = seed_exception_to_string (sexten->js_context, exc); g_warning ("Seed Exception: %s", exc_string); g_free (exc_string); return FALSE; }