First attempt at an extension interface.
This commit is contained in:
parent
b354aed640
commit
7039d48e48
4 changed files with 647 additions and 249 deletions
|
@ -54,15 +54,34 @@ midori_addons_class_init (MidoriAddonsClass* class)
|
|||
g_type_class_add_private (class, sizeof (MidoriAddonsPrivate));
|
||||
}
|
||||
|
||||
static const
|
||||
gchar* _folder_for_kind (MidoriAddonKind kind)
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case MIDORI_ADDON_EXTENSIONS:
|
||||
return "extensions";
|
||||
case MIDORI_ADDON_USER_SCRIPTS:
|
||||
return "scripts";
|
||||
case MIDORI_ADDON_USER_STYLES:
|
||||
return "styles";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
midori_addons_button_add_clicked_cb (GtkToolItem* toolitem,
|
||||
MidoriAddons* addons)
|
||||
{
|
||||
MidoriAddonsPrivate* priv = addons->priv;
|
||||
|
||||
GtkWidget* dialog = gtk_message_dialog_new (
|
||||
GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (addons))),
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE,
|
||||
"Put scripts in the folder ~/.local/share/midori/scripts");
|
||||
"Put scripts in the folder ~/.local/share/midori/%s",
|
||||
_folder_for_kind (priv->kind));
|
||||
gtk_dialog_run (GTK_DIALOG (dialog));
|
||||
gtk_widget_destroy (dialog);
|
||||
}
|
||||
|
@ -119,6 +138,401 @@ midori_addons_treeview_row_activated_cb (GtkTreeView* treeview,
|
|||
}*/
|
||||
}
|
||||
|
||||
static gchar*
|
||||
_js_string_utf8 (JSStringRef js_string)
|
||||
{
|
||||
size_t size_utf8 = JSStringGetMaximumUTF8CStringSize (js_string);
|
||||
gchar* string_utf8 = (gchar*)g_malloc (size_utf8);
|
||||
JSStringGetUTF8CString (js_string, string_utf8, size_utf8);
|
||||
return string_utf8;
|
||||
}
|
||||
|
||||
static void
|
||||
_js_class_get_property_names_cb (JSContextRef js_context,
|
||||
JSObjectRef js_object,
|
||||
JSPropertyNameAccumulatorRef js_properties)
|
||||
{
|
||||
GObject* object = JSObjectGetPrivate (js_object);
|
||||
if (object)
|
||||
{
|
||||
guint n_properties;
|
||||
GParamSpec** pspecs = g_object_class_list_properties (
|
||||
G_OBJECT_GET_CLASS (object), &n_properties);
|
||||
gint i;
|
||||
for (i = 0; i < n_properties; i++)
|
||||
{
|
||||
const gchar* property = g_param_spec_get_name (pspecs[i]);
|
||||
JSStringRef js_property = JSStringCreateWithUTF8CString (property);
|
||||
JSPropertyNameAccumulatorAddName (js_properties, js_property);
|
||||
JSStringRelease (js_property);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
_js_class_has_property_cb (JSContextRef js_context,
|
||||
JSObjectRef js_object,
|
||||
JSStringRef js_property)
|
||||
{
|
||||
bool result = false;
|
||||
gchar* property = _js_string_utf8 (js_property);
|
||||
GObject* object = JSObjectGetPrivate (js_object);
|
||||
if (object)
|
||||
{
|
||||
if (g_object_class_find_property (G_OBJECT_GET_CLASS (object),
|
||||
property))
|
||||
result = true;
|
||||
}
|
||||
else if (js_object == JSContextGetGlobalObject (js_context))
|
||||
{
|
||||
gchar* property = _js_string_utf8 (js_property);
|
||||
GType type = g_type_from_name (property);
|
||||
result = type ? type : false;
|
||||
}
|
||||
g_free (property);
|
||||
return result;
|
||||
}
|
||||
|
||||
static JSObjectRef
|
||||
_js_object_new (JSContextRef js_context,
|
||||
gpointer object);
|
||||
|
||||
static void
|
||||
_js_object_set_property (JSContextRef js_context,
|
||||
JSObjectRef js_object,
|
||||
const gchar* name,
|
||||
JSValueRef js_value)
|
||||
{
|
||||
JSStringRef js_name = JSStringCreateWithUTF8CString (name);
|
||||
JSObjectSetProperty(js_context, js_object, js_name, js_value,
|
||||
kJSPropertyAttributeNone, NULL);
|
||||
JSStringRelease (js_name);
|
||||
}
|
||||
|
||||
static JSObjectRef
|
||||
_js_object_call_as_constructor_cb (JSContextRef js_context,
|
||||
JSObjectRef js_object,
|
||||
size_t n_arguments,
|
||||
const JSValueRef js_arguments[],
|
||||
JSValueRef* js_exception)
|
||||
{
|
||||
gchar* type_name = JSObjectGetPrivate (js_object);
|
||||
if (type_name)
|
||||
{
|
||||
GType type = g_type_from_name (type_name);
|
||||
if (type)
|
||||
{
|
||||
GObject* object = g_object_new (type, NULL);
|
||||
JSObjectRef js_object = _js_object_new (js_context, object);
|
||||
return js_object;
|
||||
}
|
||||
}
|
||||
return JSValueMakeNull (js_context);
|
||||
}
|
||||
|
||||
static JSValueRef
|
||||
_js_class_get_property_cb (JSContextRef js_context,
|
||||
JSObjectRef js_object,
|
||||
JSStringRef js_property,
|
||||
JSValueRef* js_exception)
|
||||
{
|
||||
if (js_object == JSContextGetGlobalObject (js_context))
|
||||
{
|
||||
gchar* property = _js_string_utf8 (js_property);
|
||||
GType type = g_type_from_name (property);
|
||||
if (type)
|
||||
{
|
||||
JSClassDefinition js_class_def = kJSClassDefinitionEmpty;
|
||||
js_class_def.className = g_strdup (property);
|
||||
js_class_def.callAsConstructor = _js_object_call_as_constructor_cb;
|
||||
JSClassRef js_class = JSClassCreate (&js_class_def);
|
||||
return JSObjectMake (js_context, js_class, property);
|
||||
}
|
||||
g_free (property);
|
||||
return JSValueMakeNull (js_context);
|
||||
}
|
||||
GObject* object = JSObjectGetPrivate (js_object);
|
||||
JSValueRef js_result = NULL;
|
||||
if (object)
|
||||
{
|
||||
gchar* property = _js_string_utf8 (js_property);
|
||||
GParamSpec* pspec = g_object_class_find_property (
|
||||
G_OBJECT_GET_CLASS (object), property);
|
||||
if (!pspec)
|
||||
{
|
||||
gchar* message = g_strdup_printf (_("%s has no property '%s'"),
|
||||
KATZE_OBJECT_NAME (object), property);
|
||||
JSStringRef js_message = JSStringCreateWithUTF8CString (message);
|
||||
*js_exception = JSValueMakeString (js_context, js_message);
|
||||
JSStringRelease (js_message);
|
||||
g_free (message);
|
||||
g_free (property);
|
||||
return JSValueMakeNull (js_context);
|
||||
}
|
||||
if (!(pspec->flags & G_PARAM_READABLE))
|
||||
{
|
||||
g_free (property);
|
||||
return JSValueMakeUndefined (js_context);
|
||||
}
|
||||
GType type = G_PARAM_SPEC_TYPE (pspec);
|
||||
if (type == G_TYPE_PARAM_STRING)
|
||||
{
|
||||
gchar* value;
|
||||
g_object_get (object, property, &value, NULL);
|
||||
if (value)
|
||||
{
|
||||
JSStringRef js_string = JSStringCreateWithUTF8CString (value);
|
||||
js_result = JSValueMakeString (js_context, js_string);
|
||||
}
|
||||
}
|
||||
else if (type == G_TYPE_PARAM_INT
|
||||
|| type == G_TYPE_PARAM_UINT)
|
||||
{
|
||||
gint value;
|
||||
g_object_get (object, property, &value, NULL);
|
||||
js_result = JSValueMakeNumber (js_context, value);
|
||||
}
|
||||
else if (type == G_TYPE_PARAM_BOOLEAN)
|
||||
{
|
||||
gboolean value;
|
||||
g_object_get (object, property, &value, NULL);
|
||||
js_result = JSValueMakeBoolean (js_context, value ? true : false);
|
||||
}
|
||||
else if (type == G_TYPE_PARAM_OBJECT)
|
||||
{
|
||||
GObject* value;
|
||||
g_object_get (object, property, &value, NULL);
|
||||
if (value)
|
||||
js_result = _js_object_new (js_context, value);
|
||||
}
|
||||
else if (type == G_TYPE_PARAM_ENUM)
|
||||
{
|
||||
gint value;
|
||||
g_object_get (object, property, &value, NULL);
|
||||
js_result = JSValueMakeNumber (js_context, value);
|
||||
}
|
||||
else
|
||||
js_result = JSValueMakeUndefined (js_context);
|
||||
g_free (property);
|
||||
}
|
||||
return js_result ? js_result : JSValueMakeNull (js_context);
|
||||
}
|
||||
|
||||
static bool
|
||||
_js_class_set_property_cb (JSContextRef js_context,
|
||||
JSObjectRef js_object,
|
||||
JSStringRef js_property,
|
||||
JSValueRef js_value,
|
||||
JSValueRef* js_exception)
|
||||
{
|
||||
GObject* object = JSObjectGetPrivate (js_object);
|
||||
bool result = false;
|
||||
if (object)
|
||||
{
|
||||
gchar* property = _js_string_utf8 (js_property);
|
||||
GParamSpec* pspec = g_object_class_find_property (
|
||||
G_OBJECT_GET_CLASS (object), property);
|
||||
if (!pspec)
|
||||
{
|
||||
gchar* message = g_strdup_printf (_("%s has no property '%s'"),
|
||||
KATZE_OBJECT_NAME (object), property);
|
||||
JSStringRef js_message = JSStringCreateWithUTF8CString (message);
|
||||
*js_exception = JSValueMakeString (js_context, js_message);
|
||||
JSStringRelease (js_message);
|
||||
g_free (message);
|
||||
g_free (property);
|
||||
return false;
|
||||
}
|
||||
if (!(pspec->flags & G_PARAM_WRITABLE))
|
||||
{
|
||||
g_free (property);
|
||||
return false;
|
||||
}
|
||||
GType type = G_PARAM_SPEC_TYPE (pspec);
|
||||
if (type == G_TYPE_PARAM_STRING)
|
||||
{
|
||||
JSStringRef js_string_value = JSValueToStringCopy (js_context,
|
||||
js_value, js_exception);
|
||||
if (js_string_value)
|
||||
{
|
||||
gchar* string_value = _js_string_utf8 (js_string_value);
|
||||
g_object_set (object, property, string_value, NULL);
|
||||
g_free (string_value);
|
||||
}
|
||||
}
|
||||
else if (type == G_TYPE_PARAM_INT
|
||||
|| type == G_TYPE_PARAM_UINT)
|
||||
{
|
||||
int value = JSValueToNumber (js_context, js_value,
|
||||
js_exception);
|
||||
g_object_set (object, property, value, NULL);
|
||||
}
|
||||
else if (type == G_TYPE_PARAM_BOOLEAN)
|
||||
{
|
||||
bool value = JSValueToBoolean (js_context, js_value);
|
||||
g_object_set (object, property, value ? TRUE : FALSE, NULL);
|
||||
}
|
||||
else if (type == G_TYPE_PARAM_OBJECT)
|
||||
{
|
||||
JSObjectRef js_object_value = JSValueToObject (
|
||||
js_context, js_value, NULL);
|
||||
GObject* object_value = JSObjectGetPrivate (js_object_value);
|
||||
if (object_value)
|
||||
g_object_set (object, property, object_value, NULL);
|
||||
else
|
||||
{
|
||||
gchar* message = g_strdup_printf (_("%s cannot be assigned to %s.%s"),
|
||||
"[object]", KATZE_OBJECT_NAME (object), property);
|
||||
JSStringRef js_message = JSStringCreateWithUTF8CString (message);
|
||||
*js_exception = JSValueMakeString (js_context, js_message);
|
||||
JSStringRelease (js_message);
|
||||
g_free (message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gchar* message = g_strdup_printf (_("%s.%s cannot be accessed"),
|
||||
KATZE_OBJECT_NAME (object), property);
|
||||
JSStringRef js_message = JSStringCreateWithUTF8CString (message);
|
||||
*js_exception = JSValueMakeString (js_context, js_message);
|
||||
JSStringRelease (js_message);
|
||||
g_free (message);
|
||||
}
|
||||
g_free (property);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static JSValueRef
|
||||
_js_foo_call_as_function_cb (JSContextRef js_context,
|
||||
JSObjectRef js_function,
|
||||
JSObjectRef js_this,
|
||||
size_t n_arguments,
|
||||
const JSValueRef js_arguments[],
|
||||
JSValueRef* js_exception)
|
||||
{
|
||||
GObject* object = JSObjectGetPrivate (js_this);
|
||||
if (object)
|
||||
{
|
||||
if (!n_arguments)
|
||||
{
|
||||
gtk_widget_show (GTK_WIDGET (object));
|
||||
}
|
||||
else if (n_arguments == 1)
|
||||
{
|
||||
JSObjectRef js_arg1 = JSValueToObject (
|
||||
js_context, js_arguments[0], NULL);
|
||||
GObject* arg1 = JSObjectGetPrivate (js_arg1);
|
||||
if (arg1)
|
||||
gtk_container_add (GTK_CONTAINER (object), GTK_WIDGET (arg1));
|
||||
}
|
||||
}
|
||||
|
||||
return JSValueMakeUndefined (js_context);
|
||||
}
|
||||
|
||||
static void
|
||||
_js_foo_add_function (JSContextRef js_context,
|
||||
JSObjectRef js_object,
|
||||
const gchar* func)
|
||||
{
|
||||
JSStringRef js_func = JSStringCreateWithUTF8CString (func);
|
||||
JSObjectRef js_function = JSObjectMakeFunctionWithCallback (
|
||||
js_context, js_func, _js_foo_call_as_function_cb);
|
||||
JSStringRelease (js_func);
|
||||
_js_object_set_property (js_context, js_object, func, js_function);
|
||||
}
|
||||
|
||||
static JSObjectRef
|
||||
_js_object_new (JSContextRef js_context,
|
||||
gpointer object)
|
||||
{
|
||||
JSClassDefinition js_class_def = kJSClassDefinitionEmpty;
|
||||
js_class_def.className = g_strdup (KATZE_OBJECT_NAME (object));
|
||||
js_class_def.getPropertyNames = _js_class_get_property_names_cb;
|
||||
js_class_def.hasProperty = _js_class_has_property_cb;
|
||||
js_class_def.getProperty = _js_class_get_property_cb;
|
||||
js_class_def.setProperty = _js_class_set_property_cb;
|
||||
JSClassRef js_class = JSClassCreate (&js_class_def);
|
||||
JSObjectRef js_object = JSObjectMake (js_context, js_class, object);
|
||||
if (GTK_IS_WIDGET (object))
|
||||
{
|
||||
_js_foo_add_function (js_context, js_object, "show");
|
||||
}
|
||||
if (GTK_IS_CONTAINER (object))
|
||||
{
|
||||
_js_foo_add_function (js_context, js_object, "add");
|
||||
}
|
||||
return js_object;
|
||||
}
|
||||
|
||||
static JSValueRef
|
||||
_js_eval (JSContextRef js_context,
|
||||
const gchar* script,
|
||||
gchar** exception)
|
||||
{
|
||||
JSStringRef js_script = JSStringCreateWithUTF8CString (script);
|
||||
JSValueRef js_exception = NULL;
|
||||
JSValueRef js_value = JSEvaluateScript (js_context, js_script,
|
||||
JSContextGetGlobalObject (js_context), NULL, 0, &js_exception);
|
||||
if (!js_value && exception)
|
||||
{
|
||||
JSStringRef js_message = JSValueToStringCopy (js_context,
|
||||
js_exception, NULL);
|
||||
*exception = _js_string_utf8 (js_message);
|
||||
JSStringRelease (js_message);
|
||||
js_value = JSValueMakeNull (js_context);
|
||||
}
|
||||
JSStringRelease (js_script);
|
||||
return js_value;
|
||||
}
|
||||
|
||||
static bool
|
||||
_js_check_syntax (JSContextRef js_context,
|
||||
const gchar* script,
|
||||
const gchar* source_id,
|
||||
int line,
|
||||
gchar** exception)
|
||||
{
|
||||
JSStringRef js_script = JSStringCreateWithUTF8CString (script);
|
||||
JSStringRef js_source_id = JSStringCreateWithUTF8CString (source_id);
|
||||
JSValueRef js_exception = NULL;
|
||||
bool result = JSCheckScriptSyntax (js_context, js_script, js_source_id,
|
||||
line, &js_exception);
|
||||
if (!result && exception)
|
||||
{
|
||||
JSStringRef js_message = JSValueToStringCopy (js_context,
|
||||
js_exception, NULL);
|
||||
*exception = _js_string_utf8 (js_message);
|
||||
JSStringRelease (js_message);
|
||||
}
|
||||
JSStringRelease (js_source_id);
|
||||
JSStringRelease (js_script);
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_js_document_load_script_file (JSContextRef js_context,
|
||||
const gchar* filename,
|
||||
gchar** exception)
|
||||
{
|
||||
gboolean result = FALSE;
|
||||
gchar* script;
|
||||
GError* error = NULL;
|
||||
if (g_file_get_contents (filename, &script, NULL, &error))
|
||||
{
|
||||
if (_js_eval (js_context, script, exception))
|
||||
result = TRUE;
|
||||
g_free (script);
|
||||
}
|
||||
else
|
||||
{
|
||||
*exception = g_strdup (error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
midori_addons_init (MidoriAddons* addons)
|
||||
{
|
||||
|
@ -150,237 +564,91 @@ midori_addons_init (MidoriAddons* addons)
|
|||
gtk_box_pack_start (GTK_BOX (addons), priv->treeview, TRUE, TRUE, 0);
|
||||
}
|
||||
|
||||
static gchar*
|
||||
_js_string_utf8 (JSStringRef js_string)
|
||||
static JSValueRef
|
||||
_js_info_call_as_function_cb (JSContextRef js_context,
|
||||
JSObjectRef js_function,
|
||||
JSObjectRef js_this,
|
||||
size_t n_arguments,
|
||||
const JSValueRef js_arguments[],
|
||||
JSValueRef* js_exception)
|
||||
{
|
||||
size_t size_utf8 = JSStringGetMaximumUTF8CStringSize (js_string);
|
||||
gchar* string_utf8 = (gchar*)g_malloc (size_utf8);
|
||||
JSStringGetUTF8CString (js_string, string_utf8, size_utf8);
|
||||
return string_utf8;
|
||||
if (n_arguments > 0) {
|
||||
JSStringRef js_string = JSValueToStringCopy (
|
||||
js_context, js_arguments[0], NULL);
|
||||
gchar* string = _js_string_utf8 (js_string);
|
||||
// FIXME: Do we want to print this somewhere else?
|
||||
printf ("console.info: %s\n", string);
|
||||
g_free (string);
|
||||
JSStringRelease (js_string);
|
||||
}
|
||||
|
||||
return JSValueMakeUndefined (js_context);
|
||||
}
|
||||
|
||||
static void
|
||||
_js_class_get_property_names_cb (JSContextRef js_context,
|
||||
JSObjectRef js_object,
|
||||
JSPropertyNameAccumulatorRef js_properties)
|
||||
_midori_addons_extensions_main (MidoriAddons* addons,
|
||||
GtkWidget* web_widget)
|
||||
{
|
||||
GObject* object = JSObjectGetPrivate (js_object);
|
||||
if (object)
|
||||
{
|
||||
guint n_properties;
|
||||
GParamSpec** pspecs = g_object_class_list_properties (
|
||||
G_OBJECT_GET_CLASS (object), &n_properties);
|
||||
gint i;
|
||||
for (i = 0; i < n_properties; i++)
|
||||
{
|
||||
GType type = G_PARAM_SPEC_TYPE (pspecs[i]);
|
||||
const gchar* property = g_param_spec_get_name (pspecs[i]);
|
||||
JSStringRef js_property = JSStringCreateWithUTF8CString (property);
|
||||
JSPropertyNameAccumulatorAddName (js_properties, js_property);
|
||||
JSStringRelease (js_property);
|
||||
}
|
||||
}
|
||||
}
|
||||
MidoriAddonsPrivate* priv = addons->priv;
|
||||
|
||||
static bool
|
||||
_js_class_has_property_cb (JSContextRef js_context,
|
||||
JSObjectRef js_object,
|
||||
JSStringRef js_property)
|
||||
{
|
||||
GObject* object = JSObjectGetPrivate (js_object);
|
||||
bool result = false;
|
||||
if (object)
|
||||
{
|
||||
gchar* property = _js_string_utf8 (js_property);
|
||||
if (g_object_class_find_property (G_OBJECT_GET_CLASS (object),
|
||||
property))
|
||||
result = true;
|
||||
g_free (property);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static JSValueRef
|
||||
_js_class_get_property_cb (JSContextRef js_context,
|
||||
JSObjectRef js_object,
|
||||
JSStringRef js_property,
|
||||
JSValueRef* js_exception)
|
||||
{
|
||||
GObject* object = JSObjectGetPrivate (js_object);
|
||||
JSValueRef js_result = NULL;
|
||||
if (object)
|
||||
{
|
||||
gchar* property = _js_string_utf8 (js_property);
|
||||
GParamSpec* pspec = g_object_class_find_property (
|
||||
G_OBJECT_GET_CLASS (object), property);
|
||||
if (!pspec)
|
||||
{
|
||||
gchar* message = g_strdup_printf (_("%s has no property '%s'"),
|
||||
KATZE_OBJECT_NAME (object), property);
|
||||
JSStringRef js_message = JSStringCreateWithUTF8CString (message);
|
||||
*js_exception = JSValueMakeString (js_context, js_message);
|
||||
JSStringRelease (js_message);
|
||||
g_free (message);
|
||||
}
|
||||
GType type = G_PARAM_SPEC_TYPE (pspec);
|
||||
if (type == G_TYPE_PARAM_STRING)
|
||||
{
|
||||
gchar* value;
|
||||
g_object_get (object, property, &value, NULL);
|
||||
JSStringRef js_string = JSStringCreateWithUTF8CString (value);
|
||||
js_result = JSValueMakeString (js_context, js_string);
|
||||
}
|
||||
else
|
||||
{
|
||||
gchar* message = g_strdup_printf (_("%s.%s cannot be accessed"),
|
||||
KATZE_OBJECT_NAME (object), property);
|
||||
JSStringRef js_message = JSStringCreateWithUTF8CString (message);
|
||||
*js_exception = JSValueMakeString (js_context, js_message);
|
||||
JSStringRelease (js_message);
|
||||
g_free (message);
|
||||
}
|
||||
g_free (property);
|
||||
}
|
||||
return js_result;
|
||||
}
|
||||
|
||||
static bool
|
||||
_js_class_set_property_cb (JSContextRef js_context,
|
||||
JSObjectRef js_object,
|
||||
JSStringRef js_property,
|
||||
JSValueRef js_value,
|
||||
JSValueRef* js_exception)
|
||||
{
|
||||
GObject* object = JSObjectGetPrivate (js_object);
|
||||
bool result = false;
|
||||
if (object)
|
||||
{
|
||||
gchar* property = _js_string_utf8 (js_property);
|
||||
GParamSpec* pspec = g_object_class_find_property (
|
||||
G_OBJECT_GET_CLASS (object), property);
|
||||
if (!pspec)
|
||||
{
|
||||
gchar* message = g_strdup_printf (_("%s has no property '%s'"),
|
||||
KATZE_OBJECT_NAME (object), property);
|
||||
JSStringRef js_message = JSStringCreateWithUTF8CString (message);
|
||||
*js_exception = JSValueMakeString (js_context, js_message);
|
||||
JSStringRelease (js_message);
|
||||
g_free (message);
|
||||
}
|
||||
if (!(pspec->flags & G_PARAM_WRITABLE))
|
||||
{
|
||||
g_free (property);
|
||||
return false;
|
||||
}
|
||||
GType type = G_PARAM_SPEC_TYPE (pspec);
|
||||
if (type == G_TYPE_PARAM_STRING)
|
||||
{
|
||||
JSStringRef js_string = JSValueToStringCopy (js_context, js_value,
|
||||
js_exception);
|
||||
if (js_string)
|
||||
{
|
||||
gchar* string = _js_string_utf8 (js_string);
|
||||
g_object_set (object, property, string, NULL);
|
||||
g_free (string);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gchar* message = g_strdup_printf (_("%s.%s cannot be accessed"),
|
||||
KATZE_OBJECT_NAME (object), property);
|
||||
JSStringRef js_message = JSStringCreateWithUTF8CString (message);
|
||||
*js_exception = JSValueMakeString (js_context, js_message);
|
||||
JSStringRelease (js_message);
|
||||
g_free (message);
|
||||
}
|
||||
g_free (property);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static JSObjectRef
|
||||
_js_object_new (JSContextRef js_context,
|
||||
GObject* object)
|
||||
{
|
||||
JSClassDefinition js_global_def = kJSClassDefinitionEmpty;
|
||||
js_global_def.getPropertyNames = _js_class_get_property_names_cb;
|
||||
js_global_def.hasProperty = _js_class_has_property_cb;
|
||||
js_global_def.getProperty = _js_class_get_property_cb;
|
||||
JSClassRef js_global_class = JSClassCreate (&js_global_def);
|
||||
JSGlobalContextRef js_context = JSGlobalContextCreate (js_global_class);
|
||||
JSClassDefinition js_class_def = kJSClassDefinitionEmpty;
|
||||
js_class_def.className = g_strdup (KATZE_OBJECT_NAME (object));
|
||||
js_class_def.getPropertyNames = _js_class_get_property_names_cb;
|
||||
js_class_def.hasProperty = _js_class_has_property_cb;
|
||||
js_class_def.getProperty = _js_class_get_property_cb;
|
||||
js_class_def.setProperty = _js_class_set_property_cb;
|
||||
// js_class_def.staticFunctions = JSStaticFunction*;
|
||||
js_class_def.className = g_strdup ("console");
|
||||
JSClassRef js_class = JSClassCreate (&js_class_def);
|
||||
return JSObjectMake (js_context, js_class, object);
|
||||
}
|
||||
JSObjectRef js_console = JSObjectMake (js_context, js_class, NULL);
|
||||
JSStringRef js_info = JSStringCreateWithUTF8CString ("info");
|
||||
JSObjectRef js_info_function = JSObjectMakeFunctionWithCallback (
|
||||
js_context, js_info, _js_info_call_as_function_cb);
|
||||
JSObjectSetProperty (js_context, js_console, js_info, js_info_function,
|
||||
kJSPropertyAttributeNone, NULL);
|
||||
JSStringRelease (js_info);
|
||||
_js_object_set_property (js_context,
|
||||
JSContextGetGlobalObject (js_context),
|
||||
"console", js_console);
|
||||
|
||||
static void
|
||||
_js_object_set_property (JSContextRef js_context,
|
||||
JSObjectRef js_object,
|
||||
const gchar* name,
|
||||
JSValueRef js_value)
|
||||
{
|
||||
JSStringRef js_name = JSStringCreateWithUTF8CString (name);
|
||||
JSObjectSetProperty(js_context, js_object, js_name, js_value,
|
||||
kJSPropertyAttributeNone, NULL);
|
||||
JSStringRelease (js_name);
|
||||
}
|
||||
GtkWidget* browser = gtk_widget_get_toplevel (GTK_WIDGET (web_widget));
|
||||
if (GTK_WIDGET_TOPLEVEL (browser))
|
||||
{
|
||||
// FIXME: Midori should be backed up by a real GObject
|
||||
JSClassDefinition js_class_def = kJSClassDefinitionEmpty;
|
||||
js_class_def.className = g_strdup ("Midori");
|
||||
JSClassRef js_class = JSClassCreate (&js_class_def);
|
||||
JSObjectRef js_midori = JSObjectMake (js_context, js_class, NULL);
|
||||
_js_object_set_property (js_context,
|
||||
JSContextGetGlobalObject (js_context),
|
||||
"midori", js_midori);
|
||||
JSObjectRef js_browser = _js_object_new (js_context, browser);
|
||||
_js_object_set_property (js_context,
|
||||
js_midori,
|
||||
"browser", js_browser);
|
||||
}
|
||||
|
||||
static JSValueRef
|
||||
_js_eval (JSContextRef js_context,
|
||||
const gchar* script,
|
||||
gchar** exception)
|
||||
{
|
||||
JSStringRef js_script = JSStringCreateWithUTF8CString (script);
|
||||
JSValueRef js_exception;
|
||||
JSValueRef js_value = JSEvaluateScript (js_context, js_script,
|
||||
JSContextGetGlobalObject (js_context),
|
||||
NULL, 0, &js_exception);
|
||||
if (!js_value && exception)
|
||||
// FIXME: We want to honor system installed addons as well
|
||||
gchar* addon_path = g_build_filename (g_get_user_data_dir (), PACKAGE_NAME,
|
||||
_folder_for_kind (priv->kind), NULL);
|
||||
GDir* addon_dir = g_dir_open (addon_path, 0, NULL);
|
||||
if (addon_dir)
|
||||
{
|
||||
JSStringRef js_message = JSValueToStringCopy (js_context,
|
||||
js_exception, NULL);
|
||||
*exception = _js_string_utf8 (js_message);
|
||||
JSStringRelease (js_message);
|
||||
}
|
||||
JSStringRelease (js_script);
|
||||
return js_value;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_js_document_load_script_file (JSContextRef js_context,
|
||||
const gchar* filename,
|
||||
gchar** exception)
|
||||
{
|
||||
gboolean result = FALSE;
|
||||
gchar* script;
|
||||
GError* error = NULL;
|
||||
if (g_file_get_contents (filename, &script, NULL, &error))
|
||||
{
|
||||
if (_js_eval (js_context, script, exception))
|
||||
result = TRUE;
|
||||
g_free (script);
|
||||
}
|
||||
else
|
||||
{
|
||||
*exception = g_strdup (error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static const gchar* _folder_for_kind (MidoriAddonKind kind)
|
||||
{
|
||||
switch (kind)
|
||||
{
|
||||
case MIDORI_ADDON_EXTENSIONS:
|
||||
return "extensions";
|
||||
case MIDORI_ADDON_USER_SCRIPTS:
|
||||
return "scripts";
|
||||
case MIDORI_ADDON_USER_STYLES:
|
||||
return "styles";
|
||||
default:
|
||||
return NULL;
|
||||
const gchar* filename;
|
||||
while ((filename = g_dir_read_name (addon_dir)))
|
||||
{
|
||||
gchar* fullname = g_build_filename (addon_path, filename, NULL);
|
||||
gchar* exception = NULL;
|
||||
_js_document_load_script_file (js_context, fullname, &exception);
|
||||
if (exception)
|
||||
// FIXME: Do we want to print this somewhere else?
|
||||
// FIXME Convert the filename to UTF8
|
||||
printf ("%s - Exception: %s\n", filename, exception);
|
||||
g_free (fullname);
|
||||
}
|
||||
g_dir_close (addon_dir);
|
||||
}
|
||||
JSGlobalContextRelease (js_context);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -392,13 +660,6 @@ midori_web_widget_window_object_cleared_cb (GtkWidget* web_widget,
|
|||
{
|
||||
MidoriAddonsPrivate* priv = addons->priv;
|
||||
|
||||
GObject* settings;
|
||||
g_object_get (web_widget, "settings", &settings, NULL);
|
||||
JSObjectRef js_settings = _js_object_new (js_context, settings);
|
||||
_js_object_set_property (js_context,
|
||||
JSContextGetGlobalObject (js_context),
|
||||
KATZE_OBJECT_NAME (settings), js_settings);
|
||||
|
||||
// FIXME: We want to honor system installed addons as well
|
||||
gchar* addon_path = g_build_filename (g_get_user_data_dir (), PACKAGE_NAME,
|
||||
_folder_for_kind (priv->kind), NULL);
|
||||
|
@ -453,7 +714,9 @@ midori_addons_new (GtkWidget* web_widget,
|
|||
MidoriAddonsPrivate* priv = addons->priv;
|
||||
priv->kind = kind;
|
||||
|
||||
if (kind == MIDORI_ADDON_USER_SCRIPTS)
|
||||
if (kind == MIDORI_ADDON_EXTENSIONS)
|
||||
_midori_addons_extensions_main (addons, web_widget);
|
||||
else if (kind == MIDORI_ADDON_USER_SCRIPTS)
|
||||
g_signal_connect (web_widget, "window-object-cleared",
|
||||
G_CALLBACK (midori_web_widget_window_object_cleared_cb), addons);
|
||||
|
||||
|
|
|
@ -81,6 +81,10 @@ enum
|
|||
{
|
||||
PROP_0,
|
||||
|
||||
PROP_MENUBAR,
|
||||
PROP_NAVIGATIONBAR,
|
||||
PROP_TAB,
|
||||
PROP_STATUSBAR,
|
||||
PROP_SETTINGS,
|
||||
PROP_STATUSBAR_TEXT,
|
||||
PROP_TRASH
|
||||
|
@ -595,6 +599,62 @@ midori_browser_class_init (MidoriBrowserClass* class)
|
|||
|
||||
GParamFlags flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT;
|
||||
|
||||
/**
|
||||
* MidoriBrowser::menubar
|
||||
*
|
||||
* The menubar.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_MENUBAR,
|
||||
g_param_spec_object (
|
||||
"menubar",
|
||||
_("Menubar"),
|
||||
_("The menubar"),
|
||||
GTK_TYPE_MENU_BAR,
|
||||
G_PARAM_READABLE));
|
||||
|
||||
/**
|
||||
* MidoriBrowser::navigationbar
|
||||
*
|
||||
* The navigationbar.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_NAVIGATIONBAR,
|
||||
g_param_spec_object (
|
||||
"navigationbar",
|
||||
_("Navigationbar"),
|
||||
_("The navigationbar"),
|
||||
GTK_TYPE_TOOLBAR,
|
||||
G_PARAM_READABLE));
|
||||
|
||||
/**
|
||||
* MidoriBrowser::tab
|
||||
*
|
||||
* The current tab.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_TAB,
|
||||
g_param_spec_object (
|
||||
"tab",
|
||||
_("Tab"),
|
||||
_("The current tab"),
|
||||
GTK_TYPE_WIDGET,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* MidoriBrowser::statusbar
|
||||
*
|
||||
* The statusbar.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_STATUSBAR,
|
||||
g_param_spec_object (
|
||||
"statusbar",
|
||||
_("Statusbar"),
|
||||
_("The statusbar"),
|
||||
GTK_TYPE_STATUSBAR,
|
||||
G_PARAM_READABLE));
|
||||
|
||||
/**
|
||||
* MidoriBrowser::settings
|
||||
*
|
||||
|
@ -607,7 +667,7 @@ midori_browser_class_init (MidoriBrowserClass* class)
|
|||
PROP_SETTINGS,
|
||||
g_param_spec_object (
|
||||
"settings",
|
||||
"Settings",
|
||||
_("Settings"),
|
||||
_("The associated settings"),
|
||||
MIDORI_TYPE_WEB_SETTINGS,
|
||||
G_PARAM_READWRITE));
|
||||
|
@ -627,7 +687,7 @@ midori_browser_class_init (MidoriBrowserClass* class)
|
|||
PROP_STATUSBAR_TEXT,
|
||||
g_param_spec_string (
|
||||
"statusbar-text",
|
||||
"Statusbar Text",
|
||||
_("Statusbar Text"),
|
||||
_("The text that is displayed in the statusbar"),
|
||||
"",
|
||||
flags));
|
||||
|
@ -646,7 +706,7 @@ midori_browser_class_init (MidoriBrowserClass* class)
|
|||
PROP_TRASH,
|
||||
g_param_spec_object (
|
||||
"trash",
|
||||
"Trash",
|
||||
_("Trash"),
|
||||
_("The trash, collecting recently closed tabs and windows"),
|
||||
MIDORI_TYPE_TRASH,
|
||||
G_PARAM_READWRITE));
|
||||
|
@ -697,7 +757,7 @@ static void
|
|||
_action_tab_close_activate (GtkAction* action,
|
||||
MidoriBrowser* browser)
|
||||
{
|
||||
GtkWidget* widget = midori_browser_get_current_page (browser);
|
||||
GtkWidget* widget = midori_browser_get_current_tab (browser);
|
||||
GtkWidget* scrolled = _midori_browser_scrolled_for_child (browser, widget);
|
||||
gtk_widget_destroy (scrolled);
|
||||
}
|
||||
|
@ -2651,14 +2711,7 @@ midori_browser_init (MidoriBrowser* browser)
|
|||
priv->panel_pageholder, NULL,
|
||||
GTK_STOCK_CONVERT, _("Pageholder"));
|
||||
|
||||
// Addons
|
||||
/*panel = midori_addons_new (GTK_WIDGET (browser), MIDORI_ADDON_EXTENSIONS);
|
||||
gtk_widget_show (panel);
|
||||
toolbar = midori_addons_get_toolbar (MIDORI_ADDONS (panel));
|
||||
gtk_widget_show (toolbar);
|
||||
midori_panel_append_page (MIDORI_PANEL (priv->panel),
|
||||
panel, toolbar,
|
||||
"", _("Extensions"));*/
|
||||
// Userscripts
|
||||
panel = midori_addons_new (GTK_WIDGET (browser), MIDORI_ADDON_USER_SCRIPTS);
|
||||
gtk_widget_show (panel);
|
||||
toolbar = midori_addons_get_toolbar (MIDORI_ADDONS (panel));
|
||||
|
@ -2666,6 +2719,7 @@ midori_browser_init (MidoriBrowser* browser)
|
|||
midori_panel_append_page (MIDORI_PANEL (priv->panel),
|
||||
panel, toolbar,
|
||||
"", _("Userscripts"));
|
||||
// Userstyles
|
||||
/*panel = midori_addons_new (GTK_WIDGET (browser), MIDORI_ADDON_USER_STYLES);
|
||||
gtk_widget_show (panel);
|
||||
toolbar = midori_addons_get_toolbar (MIDORI_ADDONS (panel));
|
||||
|
@ -2750,6 +2804,15 @@ midori_browser_init (MidoriBrowser* browser)
|
|||
gtk_box_pack_start (GTK_BOX (priv->statusbar), priv->progressbar,
|
||||
FALSE, FALSE, 3);
|
||||
|
||||
// Extensions
|
||||
panel = midori_addons_new (GTK_WIDGET (browser), MIDORI_ADDON_EXTENSIONS);
|
||||
gtk_widget_show (panel);
|
||||
toolbar = midori_addons_get_toolbar (MIDORI_ADDONS (panel));
|
||||
gtk_widget_show (toolbar);
|
||||
midori_panel_append_page (MIDORI_PANEL (priv->panel),
|
||||
panel, toolbar,
|
||||
"", _("Extensions"));
|
||||
|
||||
g_object_unref (ui_manager);
|
||||
}
|
||||
|
||||
|
@ -2921,6 +2984,9 @@ midori_browser_set_property (GObject* object,
|
|||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_TAB:
|
||||
midori_browser_set_current_tab (browser, g_value_get_object (value));
|
||||
break;
|
||||
case PROP_STATUSBAR_TEXT:
|
||||
_midori_browser_set_statusbar_text (browser, g_value_get_string (value));
|
||||
break;
|
||||
|
@ -2962,6 +3028,18 @@ midori_browser_get_property (GObject* object,
|
|||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_MENUBAR:
|
||||
g_value_set_object (value, priv->menubar);
|
||||
break;
|
||||
case PROP_NAVIGATIONBAR:
|
||||
g_value_set_object (value, priv->navigationbar);
|
||||
break;
|
||||
case PROP_TAB:
|
||||
g_value_set_object (value, midori_browser_get_current_tab (browser));
|
||||
break;
|
||||
case PROP_STATUSBAR:
|
||||
g_value_set_object (value, priv->statusbar);
|
||||
break;
|
||||
case PROP_STATUSBAR_TEXT:
|
||||
g_value_set_string (value, priv->statusbar_text);
|
||||
break;
|
||||
|
@ -3217,7 +3295,6 @@ midori_browser_set_current_page (MidoriBrowser* browser,
|
|||
gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), n);
|
||||
GtkWidget* scrolled = gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook), n);
|
||||
GtkWidget* widget = _midori_browser_child_for_scrolled (browser, scrolled);
|
||||
printf ("_nth_page: %s\n", G_OBJECT_CLASS_NAME (G_OBJECT_GET_CLASS (widget)));
|
||||
if (widget && MIDORI_IS_WEB_VIEW (widget)
|
||||
&& !strcmp (midori_web_view_get_display_uri (
|
||||
MIDORI_WEB_VIEW (widget)), ""))
|
||||
|
@ -3234,19 +3311,70 @@ midori_browser_set_current_page (MidoriBrowser* browser,
|
|||
*
|
||||
* If there is no page present at all, %NULL is returned.
|
||||
*
|
||||
* Return value: the selected page, or %NULL
|
||||
* Return value: the selected page, or -1
|
||||
**/
|
||||
gint
|
||||
midori_browser_get_current_page (MidoriBrowser* browser)
|
||||
{
|
||||
g_return_val_if_fail (MIDORI_IS_BROWSER (browser), -1);
|
||||
|
||||
MidoriBrowserPrivate* priv = browser->priv;
|
||||
|
||||
return gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
|
||||
}
|
||||
|
||||
/**
|
||||
* midori_browser_set_current_tab:
|
||||
* @browser: a #MidoriBrowser
|
||||
* @widget: a #GtkWidget
|
||||
*
|
||||
* Switches to the page containing @widget.
|
||||
*
|
||||
* The widget will also grab the focus automatically.
|
||||
**/
|
||||
void
|
||||
midori_browser_set_current_tab (MidoriBrowser* browser,
|
||||
GtkWidget* widget)
|
||||
{
|
||||
MidoriBrowserPrivate* priv = browser->priv;
|
||||
|
||||
GtkWidget* scrolled = _midori_browser_scrolled_for_child (browser, widget);
|
||||
gint n = gtk_notebook_page_num (GTK_NOTEBOOK (priv->notebook), scrolled);
|
||||
gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), n);
|
||||
if (widget && MIDORI_IS_WEB_VIEW (widget)
|
||||
&& !strcmp (midori_web_view_get_display_uri (
|
||||
MIDORI_WEB_VIEW (widget)), ""))
|
||||
gtk_widget_grab_focus (priv->location);
|
||||
else
|
||||
gtk_widget_grab_focus (widget);
|
||||
}
|
||||
|
||||
/**
|
||||
* midori_browser_get_current_tab:
|
||||
* @browser: a #MidoriBrowser
|
||||
*
|
||||
* Retrieves the currently selected tab.
|
||||
*
|
||||
* If there is no tab present at all, %NULL is returned.
|
||||
*
|
||||
* Return value: the selected tab, or %NULL
|
||||
**/
|
||||
GtkWidget*
|
||||
midori_browser_get_current_page (MidoriBrowser* browser)
|
||||
midori_browser_get_current_tab (MidoriBrowser* browser)
|
||||
{
|
||||
g_return_val_if_fail (MIDORI_IS_BROWSER (browser), NULL);
|
||||
|
||||
MidoriBrowserPrivate* priv = browser->priv;
|
||||
|
||||
gint n = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
|
||||
GtkWidget* widget = _midori_browser_child_for_scrolled (browser,
|
||||
gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook), n));
|
||||
return widget;
|
||||
if (n >= 0)
|
||||
{
|
||||
GtkWidget* widget = _midori_browser_child_for_scrolled (browser,
|
||||
gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook), n));
|
||||
return widget;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3267,7 +3395,7 @@ midori_browser_get_current_web_view (MidoriBrowser* browser)
|
|||
{
|
||||
g_return_val_if_fail (MIDORI_IS_BROWSER (browser), NULL);
|
||||
|
||||
GtkWidget* web_view = midori_browser_get_current_page (browser);
|
||||
GtkWidget* web_view = midori_browser_get_current_tab (browser);
|
||||
return MIDORI_IS_WEB_VIEW (web_view) ? web_view : NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -95,9 +95,16 @@ void
|
|||
midori_browser_set_current_page (MidoriBrowser* browser,
|
||||
gint n);
|
||||
|
||||
GtkWidget*
|
||||
gint
|
||||
midori_browser_get_current_page (MidoriBrowser* browser);
|
||||
|
||||
void
|
||||
midori_browser_set_current_tab (MidoriBrowser* browser,
|
||||
GtkWidget* widget);
|
||||
|
||||
GtkWidget*
|
||||
midori_browser_get_current_tab (MidoriBrowser* browser);
|
||||
|
||||
GtkWidget*
|
||||
midori_browser_get_current_web_view (MidoriBrowser* browser);
|
||||
|
||||
|
|
|
@ -463,7 +463,7 @@ midori_web_settings_class_init (MidoriWebSettingsClass* class)
|
|||
"close-buttons-on-tabs",
|
||||
_("Close Buttons on Tabs"),
|
||||
_("Whether tabs have close buttons"),
|
||||
FALSE,
|
||||
TRUE,
|
||||
flags));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
|
|
Loading…
Reference in a new issue