SeedValue seed_gtk_builder_connect_signals(SeedContext ctx, SeedObject function, SeedObject this_object, gsize argument_count, const SeedValue arguments[], SeedException *exception) { builder_ud ud; GtkBuilder *b; CHECK_ARG_COUNT("GtkBuilder.connect_signals", 1); if (!seed_value_is_object (ctx, arguments[0])) { seed_make_exception (ctx, exception, "TypeError", "connect_signals expects one object as the first argument"); return seed_make_undefined (ctx); } b = GTK_BUILDER (seed_value_to_object (ctx, this_object, exception)); ud.ctx = ctx; ud.obj = arguments[0]; if (argument_count == 2) ud.user_data = arguments[1]; else ud.user_data = NULL; gtk_builder_connect_signals_full(b, seed_builder_connect_func, &ud); return seed_make_undefined (ctx); }
static gboolean seed_ffi_set_signature (SeedContext ctx, SeedObject this_object, SeedString property_name, SeedValue value, SeedException *exception) { seed_ffi_function_priv *priv = seed_object_get_private (this_object); if (priv->signature_obj) { seed_make_exception (ctx, exception, "FFIError", "Can not reset signature of function once set"); return FALSE; } else if (!seed_value_is_object (ctx, value)) { seed_make_exception (ctx, exception, "FFIError", "Signature must be an object"); return FALSE; } else { if (!seed_ffi_build_signature (ctx, priv, (SeedObject) value, exception)) return FALSE; } return TRUE; }
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); }
static gboolean seed_cairo_surface_set_fallback_resolution(SeedContext ctx, SeedObject this_object, SeedString property_name, SeedValue value, SeedException *exception) { cairo_surface_t *surf; gdouble x, y; SeedValue jsx, jsy; CHECK_THIS_BOOL(); if (!seed_value_is_object (ctx, value)) { seed_make_exception(ctx, exception, "ArgumentError", "Cairo.Surface.fallback_resolution must be an array [x,y]"); return FALSE; } jsx = seed_object_get_property_at_index (ctx, (SeedObject) value, 0, exception); jsy = seed_object_get_property_at_index (ctx, (SeedObject) value, 1, exception); surf = seed_object_to_cairo_surface (ctx, this_object, exception); x = seed_value_to_double (ctx, jsx, exception); y = seed_value_to_double (ctx, jsy, exception); cairo_surface_set_fallback_resolution (surf, x, y); return TRUE; }
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 DBusMessage * build_reply_from_jsval(SeedContext ctx, const char *signature, const char *sender, dbus_uint32_t serial, SeedValue rval, SeedException *exception) { DBusMessage *reply; DBusMessageIter arg_iter; DBusSignatureIter sig_iter; gboolean marshalled = FALSE; reply = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN); dbus_message_set_destination(reply, sender); dbus_message_set_reply_serial(reply, serial); dbus_message_set_no_reply(reply, TRUE); dbus_message_iter_init_append(reply, &arg_iter); if (seed_value_is_undefined (ctx, rval) || g_str_equal(signature, "")) { /* We don't want to send anything in these cases so skip the * marshalling altogether. */ return reply; } dbus_signature_iter_init(&sig_iter, signature); if (signature_has_one_element(signature)) { marshalled = seed_js_one_value_to_dbus(ctx, rval, &arg_iter, &sig_iter, exception); } else { if (!seed_value_is_object (ctx, rval)) { g_warning("Signature has multiple items but return value is not an array"); return reply; } marshalled = seed_js_values_to_dbus(ctx, 0, rval, &arg_iter, &sig_iter, exception); } if (!marshalled) { /* replace our planned reply with an error */ dbus_message_unref(reply); if (!dbus_reply_from_exception_and_sender(ctx, sender, serial, &reply, exception)) g_warning ("conversion of dbus return value failed but no exception was set?"); } return reply; }
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 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; }
gboolean seed_value_to_cairo_matrix (SeedContext ctx, SeedValue value, cairo_matrix_t *matrix, SeedException *exception) { if (!seed_value_is_object (ctx, value)) return FALSE; matrix->xx = seed_value_to_double (ctx, seed_object_get_property_at_index (ctx, (SeedObject) value, 0, exception), exception); matrix->yx = seed_value_to_double (ctx, seed_object_get_property_at_index (ctx, (SeedObject) value, 1, exception), exception); matrix->xy = seed_value_to_double (ctx, seed_object_get_property_at_index (ctx, (SeedObject) value, 2, exception), exception); matrix->yy = seed_value_to_double (ctx, seed_object_get_property_at_index (ctx, (SeedObject) value, 3, exception), exception); matrix->x0 = seed_value_to_double (ctx, seed_object_get_property_at_index (ctx, (SeedObject) value, 4, exception), exception); matrix->y0 = seed_value_to_double (ctx, seed_object_get_property_at_index (ctx, (SeedObject) value, 5, exception), exception); 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 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 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_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; }
static DBusMessage* invoke_js_from_dbus(SeedContext ctx, DBusMessage *method_call, SeedObject this_obj, SeedObject method_obj, SeedException *exception) { DBusMessage *reply; int argc; SeedValue *argv; SeedValue rval; DBusMessageIter arg_iter; GArray *values; const char *signature; reply = NULL; dbus_message_iter_init(method_call, &arg_iter); if (!seed_js_values_from_dbus(ctx, &arg_iter, &values, exception)) { if (!dbus_reply_from_exception(ctx, method_call, &reply, exception)) g_warning("conversion of dbus method arg failed but no exception was set?"); return reply; } argc = values->len; argv = (SeedValue *)values->data; seed_js_add_dbus_props(ctx, method_call, argv[0], exception); rval = seed_object_call (ctx, method_obj, NULL, argc, argv, exception); if (!seed_value_is_null (ctx, *exception) && seed_value_is_object (ctx, *exception)) { g_warning("dbus method invocation failed"); if (!dbus_reply_from_exception(ctx, method_call, &reply, exception)) g_warning("dbus method invocation failed but no exception was set?"); goto out; } if (dbus_reply_from_exception(ctx, method_call, &reply, exception)) { g_warning("Closure invocation succeeded but an exception was set?"); goto out; } if (!signature_from_method(ctx, method_obj, &signature, exception)) { if (!dbus_reply_from_exception(ctx, method_call, &reply, exception)) g_warning("dbus method invocation failed but no exception was set?"); goto out; } reply = build_reply_from_jsval(ctx, signature, dbus_message_get_sender(method_call), dbus_message_get_serial(method_call), rval, exception); out: g_array_free(values, TRUE); if (reply) g_warning ("Sending %s reply to dbus method %s", dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_METHOD_RETURN ? "normal" : "error", dbus_message_get_member(method_call)); else g_warning ("Failed to create reply to dbus method %s", dbus_message_get_member(method_call)); return reply; }