First attempt at an extension interface.

This commit is contained in:
Christian Dywan 2008-05-02 22:30:26 +02:00
parent b354aed640
commit 7039d48e48
4 changed files with 647 additions and 249 deletions

View file

@ -54,15 +54,34 @@ midori_addons_class_init (MidoriAddonsClass* class)
g_type_class_add_private (class, sizeof (MidoriAddonsPrivate)); 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 static void
midori_addons_button_add_clicked_cb (GtkToolItem* toolitem, midori_addons_button_add_clicked_cb (GtkToolItem* toolitem,
MidoriAddons* addons) MidoriAddons* addons)
{ {
MidoriAddonsPrivate* priv = addons->priv;
GtkWidget* dialog = gtk_message_dialog_new ( GtkWidget* dialog = gtk_message_dialog_new (
GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (addons))), GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (addons))),
GTK_DIALOG_DESTROY_WITH_PARENT, GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, 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_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (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 static void
midori_addons_init (MidoriAddons* addons) 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); gtk_box_pack_start (GTK_BOX (addons), priv->treeview, TRUE, TRUE, 0);
} }
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++)
{
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);
}
}
}
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 static JSValueRef
_js_class_get_property_cb (JSContextRef js_context, _js_info_call_as_function_cb (JSContextRef js_context,
JSObjectRef js_object, JSObjectRef js_function,
JSStringRef js_property, JSObjectRef js_this,
size_t n_arguments,
const JSValueRef js_arguments[],
JSValueRef* js_exception) JSValueRef* js_exception)
{ {
GObject* object = JSObjectGetPrivate (js_object); if (n_arguments > 0) {
JSValueRef js_result = NULL; JSStringRef js_string = JSValueToStringCopy (
if (object) js_context, js_arguments[0], NULL);
{
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); gchar* string = _js_string_utf8 (js_string);
g_object_set (object, property, string, NULL); // FIXME: Do we want to print this somewhere else?
printf ("console.info: %s\n", string);
g_free (string); g_free (string);
JSStringRelease (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 result;
}
static JSObjectRef return JSValueMakeUndefined (js_context);
_js_object_new (JSContextRef js_context,
GObject* 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;
// js_class_def.staticFunctions = JSStaticFunction*;
JSClassRef js_class = JSClassCreate (&js_class_def);
return JSObjectMake (js_context, js_class, object);
} }
static void static void
_js_object_set_property (JSContextRef js_context, _midori_addons_extensions_main (MidoriAddons* addons,
JSObjectRef js_object, GtkWidget* web_widget)
const gchar* name,
JSValueRef js_value)
{ {
JSStringRef js_name = JSStringCreateWithUTF8CString (name); MidoriAddonsPrivate* priv = addons->priv;
JSObjectSetProperty(js_context, js_object, js_name, js_value,
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 ("console");
JSClassRef js_class = JSClassCreate (&js_class_def);
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); kJSPropertyAttributeNone, NULL);
JSStringRelease (js_name); JSStringRelease (js_info);
} _js_object_set_property (js_context,
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), JSContextGetGlobalObject (js_context),
NULL, 0, &js_exception); "console", js_console);
if (!js_value && exception)
{
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 GtkWidget* browser = gtk_widget_get_toplevel (GTK_WIDGET (web_widget));
_js_document_load_script_file (JSContextRef js_context, if (GTK_WIDGET_TOPLEVEL (browser))
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)) // FIXME: Midori should be backed up by a real GObject
result = TRUE; JSClassDefinition js_class_def = kJSClassDefinitionEmpty;
g_free (script); 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);
} }
else
{
*exception = g_strdup (error->message);
g_error_free (error);
}
return result;
}
static const gchar* _folder_for_kind (MidoriAddonKind kind) // FIXME: We want to honor system installed addons as well
{ gchar* addon_path = g_build_filename (g_get_user_data_dir (), PACKAGE_NAME,
switch (kind) _folder_for_kind (priv->kind), NULL);
GDir* addon_dir = g_dir_open (addon_path, 0, NULL);
if (addon_dir)
{ {
case MIDORI_ADDON_EXTENSIONS: const gchar* filename;
return "extensions"; while ((filename = g_dir_read_name (addon_dir)))
case MIDORI_ADDON_USER_SCRIPTS: {
return "scripts"; gchar* fullname = g_build_filename (addon_path, filename, NULL);
case MIDORI_ADDON_USER_STYLES: gchar* exception = NULL;
return "styles"; _js_document_load_script_file (js_context, fullname, &exception);
default: if (exception)
return NULL; // 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 static void
@ -392,13 +660,6 @@ midori_web_widget_window_object_cleared_cb (GtkWidget* web_widget,
{ {
MidoriAddonsPrivate* priv = addons->priv; 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 // FIXME: We want to honor system installed addons as well
gchar* addon_path = g_build_filename (g_get_user_data_dir (), PACKAGE_NAME, gchar* addon_path = g_build_filename (g_get_user_data_dir (), PACKAGE_NAME,
_folder_for_kind (priv->kind), NULL); _folder_for_kind (priv->kind), NULL);
@ -453,7 +714,9 @@ midori_addons_new (GtkWidget* web_widget,
MidoriAddonsPrivate* priv = addons->priv; MidoriAddonsPrivate* priv = addons->priv;
priv->kind = kind; 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_signal_connect (web_widget, "window-object-cleared",
G_CALLBACK (midori_web_widget_window_object_cleared_cb), addons); G_CALLBACK (midori_web_widget_window_object_cleared_cb), addons);

View file

@ -81,6 +81,10 @@ enum
{ {
PROP_0, PROP_0,
PROP_MENUBAR,
PROP_NAVIGATIONBAR,
PROP_TAB,
PROP_STATUSBAR,
PROP_SETTINGS, PROP_SETTINGS,
PROP_STATUSBAR_TEXT, PROP_STATUSBAR_TEXT,
PROP_TRASH PROP_TRASH
@ -595,6 +599,62 @@ midori_browser_class_init (MidoriBrowserClass* class)
GParamFlags flags = G_PARAM_READWRITE | G_PARAM_CONSTRUCT; 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 * MidoriBrowser::settings
* *
@ -607,7 +667,7 @@ midori_browser_class_init (MidoriBrowserClass* class)
PROP_SETTINGS, PROP_SETTINGS,
g_param_spec_object ( g_param_spec_object (
"settings", "settings",
"Settings", _("Settings"),
_("The associated settings"), _("The associated settings"),
MIDORI_TYPE_WEB_SETTINGS, MIDORI_TYPE_WEB_SETTINGS,
G_PARAM_READWRITE)); G_PARAM_READWRITE));
@ -627,7 +687,7 @@ midori_browser_class_init (MidoriBrowserClass* class)
PROP_STATUSBAR_TEXT, PROP_STATUSBAR_TEXT,
g_param_spec_string ( g_param_spec_string (
"statusbar-text", "statusbar-text",
"Statusbar Text", _("Statusbar Text"),
_("The text that is displayed in the statusbar"), _("The text that is displayed in the statusbar"),
"", "",
flags)); flags));
@ -646,7 +706,7 @@ midori_browser_class_init (MidoriBrowserClass* class)
PROP_TRASH, PROP_TRASH,
g_param_spec_object ( g_param_spec_object (
"trash", "trash",
"Trash", _("Trash"),
_("The trash, collecting recently closed tabs and windows"), _("The trash, collecting recently closed tabs and windows"),
MIDORI_TYPE_TRASH, MIDORI_TYPE_TRASH,
G_PARAM_READWRITE)); G_PARAM_READWRITE));
@ -697,7 +757,7 @@ static void
_action_tab_close_activate (GtkAction* action, _action_tab_close_activate (GtkAction* action,
MidoriBrowser* browser) 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); GtkWidget* scrolled = _midori_browser_scrolled_for_child (browser, widget);
gtk_widget_destroy (scrolled); gtk_widget_destroy (scrolled);
} }
@ -2651,14 +2711,7 @@ midori_browser_init (MidoriBrowser* browser)
priv->panel_pageholder, NULL, priv->panel_pageholder, NULL,
GTK_STOCK_CONVERT, _("Pageholder")); GTK_STOCK_CONVERT, _("Pageholder"));
// Addons // Userscripts
/*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"));*/
panel = midori_addons_new (GTK_WIDGET (browser), MIDORI_ADDON_USER_SCRIPTS); panel = midori_addons_new (GTK_WIDGET (browser), MIDORI_ADDON_USER_SCRIPTS);
gtk_widget_show (panel); gtk_widget_show (panel);
toolbar = midori_addons_get_toolbar (MIDORI_ADDONS (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), midori_panel_append_page (MIDORI_PANEL (priv->panel),
panel, toolbar, panel, toolbar,
"", _("Userscripts")); "", _("Userscripts"));
// Userstyles
/*panel = midori_addons_new (GTK_WIDGET (browser), MIDORI_ADDON_USER_STYLES); /*panel = midori_addons_new (GTK_WIDGET (browser), MIDORI_ADDON_USER_STYLES);
gtk_widget_show (panel); gtk_widget_show (panel);
toolbar = midori_addons_get_toolbar (MIDORI_ADDONS (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, gtk_box_pack_start (GTK_BOX (priv->statusbar), priv->progressbar,
FALSE, FALSE, 3); 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); g_object_unref (ui_manager);
} }
@ -2921,6 +2984,9 @@ midori_browser_set_property (GObject* object,
switch (prop_id) switch (prop_id)
{ {
case PROP_TAB:
midori_browser_set_current_tab (browser, g_value_get_object (value));
break;
case PROP_STATUSBAR_TEXT: case PROP_STATUSBAR_TEXT:
_midori_browser_set_statusbar_text (browser, g_value_get_string (value)); _midori_browser_set_statusbar_text (browser, g_value_get_string (value));
break; break;
@ -2962,6 +3028,18 @@ midori_browser_get_property (GObject* object,
switch (prop_id) 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: case PROP_STATUSBAR_TEXT:
g_value_set_string (value, priv->statusbar_text); g_value_set_string (value, priv->statusbar_text);
break; break;
@ -3217,7 +3295,6 @@ midori_browser_set_current_page (MidoriBrowser* browser,
gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), n); gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), n);
GtkWidget* scrolled = gtk_notebook_get_nth_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); 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) if (widget && MIDORI_IS_WEB_VIEW (widget)
&& !strcmp (midori_web_view_get_display_uri ( && !strcmp (midori_web_view_get_display_uri (
MIDORI_WEB_VIEW (widget)), "")) 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. * 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* 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); g_return_val_if_fail (MIDORI_IS_BROWSER (browser), NULL);
MidoriBrowserPrivate* priv = browser->priv; MidoriBrowserPrivate* priv = browser->priv;
gint n = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook)); gint n = gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->notebook));
if (n >= 0)
{
GtkWidget* widget = _midori_browser_child_for_scrolled (browser, GtkWidget* widget = _midori_browser_child_for_scrolled (browser,
gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook), n)); gtk_notebook_get_nth_page (GTK_NOTEBOOK (priv->notebook), n));
return widget; 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); 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; return MIDORI_IS_WEB_VIEW (web_view) ? web_view : NULL;
} }

View file

@ -95,9 +95,16 @@ void
midori_browser_set_current_page (MidoriBrowser* browser, midori_browser_set_current_page (MidoriBrowser* browser,
gint n); gint n);
GtkWidget* gint
midori_browser_get_current_page (MidoriBrowser* browser); 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* GtkWidget*
midori_browser_get_current_web_view (MidoriBrowser* browser); midori_browser_get_current_web_view (MidoriBrowser* browser);

View file

@ -463,7 +463,7 @@ midori_web_settings_class_init (MidoriWebSettingsClass* class)
"close-buttons-on-tabs", "close-buttons-on-tabs",
_("Close Buttons on Tabs"), _("Close Buttons on Tabs"),
_("Whether tabs have close buttons"), _("Whether tabs have close buttons"),
FALSE, TRUE,
flags)); flags));
g_object_class_install_property (gobject_class, g_object_class_install_property (gobject_class,