831099cca5
Add two new APIs, "launchExtensionPrefs" to let SweetTooth let the user launch the extension preferences tool directly from the browser. To allow SweetTooth to check if an extension can be configured, add a new key to the 'metadata', 'hasPrefs', which is returned by the GetExtensionInfo/ ListExtensions DBus methods. https://bugzilla.gnome.org/show_bug.cgi?id=668429
947 lines
24 KiB
C
947 lines
24 KiB
C
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
|
/*
|
|
* Copyright (C) 2011 Red Hat
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
* 02111-1307, USA.
|
|
*
|
|
* Authors:
|
|
* Jasper St. Pierre <jstpierre@mecheye.net>
|
|
* Giovanni Campagna <scampa.giovanni@gmail.com>
|
|
*/
|
|
|
|
#include <string.h>
|
|
|
|
#define XP_UNIX 1
|
|
|
|
#include "npapi/npapi.h"
|
|
#include "npapi/npruntime.h"
|
|
#include "npapi/npfunctions.h"
|
|
|
|
#include <glib.h>
|
|
#include <gio/gio.h>
|
|
#include <json-glib/json-glib.h>
|
|
|
|
#define ORIGIN "extensions.gnome.org"
|
|
#define PLUGIN_NAME "Gnome Shell Integration"
|
|
#define PLUGIN_DESCRIPTION "This plugin provides integration with Gnome Shell " \
|
|
"for live extension enabling and disabling. " \
|
|
"It can be used only by extensions.gnome.org"
|
|
#define PLUGIN_MIME_STRING "application/x-gnome-shell-integration::Gnome Shell Integration Dummy Content-Type";
|
|
|
|
#define PLUGIN_API_VERSION 3
|
|
|
|
typedef struct {
|
|
GDBusProxy *proxy;
|
|
} PluginData;
|
|
|
|
static NPNetscapeFuncs funcs;
|
|
|
|
static inline gchar *
|
|
get_string_property (NPP instance,
|
|
NPObject *obj,
|
|
const char *name)
|
|
{
|
|
NPVariant result = { NPVariantType_Void };
|
|
NPString result_str;
|
|
gchar *result_copy;
|
|
|
|
result_copy = NULL;
|
|
|
|
if (!funcs.getproperty (instance, obj,
|
|
funcs.getstringidentifier (name),
|
|
&result))
|
|
goto out;
|
|
|
|
if (!NPVARIANT_IS_STRING (result))
|
|
goto out;
|
|
|
|
result_str = NPVARIANT_TO_STRING (result);
|
|
result_copy = g_strndup (result_str.UTF8Characters, result_str.UTF8Length);
|
|
|
|
out:
|
|
funcs.releasevariantvalue (&result);
|
|
return result_copy;
|
|
}
|
|
|
|
static gboolean
|
|
check_origin_and_protocol (NPP instance)
|
|
{
|
|
gboolean ret = FALSE;
|
|
NPError error;
|
|
NPObject *window = NULL;
|
|
NPVariant document = { NPVariantType_Void };
|
|
NPVariant location = { NPVariantType_Void };
|
|
gchar *hostname = NULL;
|
|
gchar *protocol = NULL;
|
|
|
|
error = funcs.getvalue (instance, NPNVWindowNPObject, &window);
|
|
if (error != NPERR_NO_ERROR)
|
|
goto out;
|
|
|
|
if (!funcs.getproperty (instance, window,
|
|
funcs.getstringidentifier ("document"),
|
|
&document))
|
|
goto out;
|
|
|
|
if (!NPVARIANT_IS_OBJECT (document))
|
|
goto out;
|
|
|
|
if (!funcs.getproperty (instance, NPVARIANT_TO_OBJECT (document),
|
|
funcs.getstringidentifier ("location"),
|
|
&location))
|
|
goto out;
|
|
|
|
if (!NPVARIANT_IS_OBJECT (document))
|
|
goto out;
|
|
|
|
hostname = get_string_property (instance,
|
|
NPVARIANT_TO_OBJECT (location),
|
|
"hostname");
|
|
|
|
if (g_strcmp0 (hostname, ORIGIN))
|
|
{
|
|
g_debug ("origin does not match, is %s",
|
|
hostname);
|
|
|
|
goto out;
|
|
}
|
|
|
|
protocol = get_string_property (instance,
|
|
NPVARIANT_TO_OBJECT (location),
|
|
"protocol");
|
|
|
|
if (g_strcmp0 (protocol, "https:") != 0)
|
|
{
|
|
g_debug ("protocol does not match, is %s",
|
|
protocol);
|
|
|
|
goto out;
|
|
}
|
|
|
|
ret = TRUE;
|
|
|
|
out:
|
|
g_free (protocol);
|
|
g_free (hostname);
|
|
|
|
funcs.releasevariantvalue (&location);
|
|
funcs.releasevariantvalue (&document);
|
|
|
|
if (window != NULL)
|
|
funcs.releaseobject (window);
|
|
return ret;
|
|
}
|
|
|
|
/* =============== public entry points =================== */
|
|
|
|
NPError
|
|
NP_Initialize(NPNetscapeFuncs *pfuncs, NPPluginFuncs *plugin)
|
|
{
|
|
/* global initialization routine, called once when plugin
|
|
is loaded */
|
|
|
|
g_debug ("plugin loaded");
|
|
|
|
memcpy (&funcs, pfuncs, sizeof (funcs));
|
|
|
|
plugin->size = sizeof(NPPluginFuncs);
|
|
plugin->newp = NPP_New;
|
|
plugin->destroy = NPP_Destroy;
|
|
plugin->getvalue = NPP_GetValue;
|
|
|
|
return NPERR_NO_ERROR;
|
|
}
|
|
|
|
NPError
|
|
NP_Shutdown(void)
|
|
{
|
|
return NPERR_NO_ERROR;
|
|
}
|
|
|
|
const char*
|
|
NP_GetMIMEDescription(void)
|
|
{
|
|
return PLUGIN_MIME_STRING;
|
|
}
|
|
|
|
NPError
|
|
NP_GetValue(void *instance,
|
|
NPPVariable variable,
|
|
void *value)
|
|
{
|
|
switch (variable) {
|
|
case NPPVpluginNameString:
|
|
*(char**)value = PLUGIN_NAME;
|
|
break;
|
|
case NPPVpluginDescriptionString:
|
|
*(char**)value = PLUGIN_DESCRIPTION;
|
|
break;
|
|
default:
|
|
;
|
|
}
|
|
|
|
return NPERR_NO_ERROR;
|
|
}
|
|
|
|
NPError
|
|
NPP_New(NPMIMEType mimetype,
|
|
NPP instance,
|
|
uint16_t mode,
|
|
int16_t argc,
|
|
char **argn,
|
|
char **argv,
|
|
NPSavedData *saved)
|
|
{
|
|
/* instance initialization function */
|
|
PluginData *data;
|
|
GError *error = NULL;
|
|
|
|
g_debug ("plugin created");
|
|
|
|
if (!check_origin_and_protocol (instance))
|
|
return NPERR_GENERIC_ERROR;
|
|
|
|
data = g_slice_new (PluginData);
|
|
instance->pdata = data;
|
|
|
|
data->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
|
|
G_DBUS_PROXY_FLAGS_NONE,
|
|
NULL, /* interface info */
|
|
"org.gnome.Shell",
|
|
"/org/gnome/Shell",
|
|
"org.gnome.Shell",
|
|
NULL, /* GCancellable */
|
|
&error);
|
|
if (!data->proxy)
|
|
{
|
|
/* ignore error if the shell is not running, otherwise warn */
|
|
if (error->domain != G_DBUS_ERROR ||
|
|
error->code != G_DBUS_ERROR_NAME_HAS_NO_OWNER)
|
|
{
|
|
g_warning ("Failed to set up Shell proxy: %s", error->message);
|
|
}
|
|
g_clear_error (&error);
|
|
return NPERR_GENERIC_ERROR;
|
|
}
|
|
|
|
g_debug ("plugin created successfully");
|
|
|
|
return NPERR_NO_ERROR;
|
|
}
|
|
|
|
NPError
|
|
NPP_Destroy(NPP instance,
|
|
NPSavedData **saved)
|
|
{
|
|
/* instance finalization function */
|
|
|
|
PluginData *data = instance->pdata;
|
|
|
|
g_debug ("plugin destroyed");
|
|
|
|
g_object_unref (data->proxy);
|
|
|
|
g_slice_free (PluginData, data);
|
|
|
|
return NPERR_NO_ERROR;
|
|
}
|
|
|
|
/* =================== scripting interface =================== */
|
|
|
|
typedef struct {
|
|
NPObject parent;
|
|
NPP instance;
|
|
GDBusProxy *proxy;
|
|
NPObject *listener;
|
|
NPObject *restart_listener;
|
|
gint signal_id;
|
|
guint watch_name_id;
|
|
} PluginObject;
|
|
|
|
static void
|
|
on_shell_signal (GDBusProxy *proxy,
|
|
gchar *sender_name,
|
|
gchar *signal_name,
|
|
GVariant *parameters,
|
|
gpointer user_data)
|
|
{
|
|
PluginObject *obj = user_data;
|
|
|
|
if (strcmp (signal_name, "ExtensionStatusChanged") == 0)
|
|
{
|
|
gchar *uuid;
|
|
gint32 status;
|
|
gchar *error;
|
|
NPVariant args[3];
|
|
NPVariant result = { NPVariantType_Void };
|
|
|
|
g_variant_get (parameters, "(sis)", &uuid, &status, &error);
|
|
STRINGZ_TO_NPVARIANT (uuid, args[0]);
|
|
INT32_TO_NPVARIANT (status, args[1]);
|
|
STRINGZ_TO_NPVARIANT (error, args[2]);
|
|
|
|
funcs.invokeDefault (obj->instance, obj->listener,
|
|
args, 3, &result);
|
|
|
|
funcs.releasevariantvalue (&result);
|
|
g_free (uuid);
|
|
g_free (error);
|
|
}
|
|
}
|
|
|
|
static void
|
|
on_shell_appeared (GDBusConnection *connection,
|
|
const gchar *name,
|
|
const gchar *name_owner,
|
|
gpointer user_data)
|
|
{
|
|
PluginObject *obj = (PluginObject*) user_data;
|
|
|
|
if (obj->restart_listener)
|
|
{
|
|
NPVariant result = { NPVariantType_Void };
|
|
|
|
funcs.invokeDefault (obj->instance, obj->restart_listener,
|
|
NULL, 0, &result);
|
|
|
|
funcs.releasevariantvalue (&result);
|
|
}
|
|
}
|
|
|
|
static NPObject *
|
|
plugin_object_allocate (NPP instance,
|
|
NPClass *klass)
|
|
{
|
|
PluginData *data = instance->pdata;
|
|
PluginObject *obj = g_slice_new0 (PluginObject);
|
|
|
|
obj->instance = instance;
|
|
obj->proxy = g_object_ref (data->proxy);
|
|
obj->signal_id = g_signal_connect (obj->proxy, "g-signal",
|
|
G_CALLBACK (on_shell_signal), obj);
|
|
|
|
obj->watch_name_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
|
|
"org.gnome.Shell",
|
|
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
|
on_shell_appeared,
|
|
NULL,
|
|
obj,
|
|
NULL);
|
|
|
|
g_debug ("plugin object created");
|
|
|
|
return (NPObject*)obj;
|
|
}
|
|
|
|
static void
|
|
plugin_object_deallocate (NPObject *npobj)
|
|
{
|
|
PluginObject *obj = (PluginObject*)npobj;
|
|
|
|
g_signal_handler_disconnect (obj->proxy, obj->signal_id);
|
|
g_object_unref (obj->proxy);
|
|
|
|
if (obj->listener)
|
|
funcs.releaseobject (obj->listener);
|
|
|
|
if (obj->watch_name_id)
|
|
g_bus_unwatch_name (obj->watch_name_id);
|
|
|
|
g_debug ("plugin object destroyed");
|
|
|
|
g_slice_free (PluginObject, obj);
|
|
}
|
|
|
|
static NPIdentifier api_version_id;
|
|
static NPIdentifier shell_version_id;
|
|
static NPIdentifier get_info_id;
|
|
static NPIdentifier list_extensions_id;
|
|
static NPIdentifier enable_extension_id;
|
|
static NPIdentifier install_extension_id;
|
|
static NPIdentifier uninstall_extension_id;
|
|
static NPIdentifier onextension_changed_id;
|
|
static NPIdentifier onrestart_id;
|
|
static NPIdentifier get_errors_id;
|
|
static NPIdentifier launch_extension_prefs_id;
|
|
|
|
static bool
|
|
plugin_object_has_method (NPObject *npobj,
|
|
NPIdentifier name)
|
|
{
|
|
return (name == get_info_id ||
|
|
name == list_extensions_id ||
|
|
name == enable_extension_id ||
|
|
name == install_extension_id ||
|
|
name == uninstall_extension_id ||
|
|
name == get_errors_id ||
|
|
name == launch_extension_prefs_id);
|
|
}
|
|
|
|
static inline gboolean
|
|
uuid_is_valid (const gchar *uuid)
|
|
{
|
|
gsize i;
|
|
|
|
for (i = 0; uuid[i]; i ++)
|
|
{
|
|
gchar c = uuid[i];
|
|
if (c < 32 || c >= 127)
|
|
return FALSE;
|
|
|
|
switch (c)
|
|
{
|
|
case '&':
|
|
case '<':
|
|
case '>':
|
|
case '/':
|
|
case '\\':
|
|
return FALSE;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
jsonify_variant (GVariant *variant,
|
|
NPVariant *result)
|
|
{
|
|
gboolean ret;
|
|
GVariant *real_value;
|
|
JsonNode *root;
|
|
JsonGenerator *generator;
|
|
gsize json_length;
|
|
gchar *json;
|
|
gchar *buffer;
|
|
|
|
ret = TRUE;
|
|
|
|
/* DBus methods can return multiple values,
|
|
* but we're only interested in the first. */
|
|
g_variant_get (variant, "(@*)", &real_value);
|
|
|
|
root = json_gvariant_serialize (real_value);
|
|
|
|
generator = json_generator_new ();
|
|
json_generator_set_root (generator, root);
|
|
json = json_generator_to_data (generator, &json_length);
|
|
|
|
buffer = funcs.memalloc (json_length + 1);
|
|
if (!buffer)
|
|
{
|
|
ret = FALSE;
|
|
goto out;
|
|
}
|
|
|
|
strcpy (buffer, json);
|
|
|
|
STRINGN_TO_NPVARIANT (buffer, json_length, *result);
|
|
|
|
out:
|
|
g_variant_unref (variant);
|
|
g_variant_unref (real_value);
|
|
json_node_free (root);
|
|
g_free (json);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static gboolean
|
|
plugin_list_extensions (PluginObject *obj,
|
|
NPVariant *result)
|
|
{
|
|
GError *error = NULL;
|
|
GVariant *res;
|
|
|
|
res = g_dbus_proxy_call_sync (obj->proxy,
|
|
"ListExtensions",
|
|
NULL, /* parameters */
|
|
G_DBUS_CALL_FLAGS_NONE,
|
|
-1, /* timeout */
|
|
NULL, /* cancellable */
|
|
&error);
|
|
|
|
if (!res)
|
|
{
|
|
g_warning ("Failed to retrieve extension list: %s", error->message);
|
|
g_error_free (error);
|
|
return FALSE;
|
|
}
|
|
|
|
return jsonify_variant (res, result);
|
|
}
|
|
|
|
static gboolean
|
|
plugin_enable_extension (PluginObject *obj,
|
|
NPString uuid,
|
|
gboolean enabled)
|
|
{
|
|
gchar *uuid_str = g_strndup (uuid.UTF8Characters, uuid.UTF8Length);
|
|
if (!uuid_is_valid (uuid_str))
|
|
{
|
|
g_free (uuid_str);
|
|
return FALSE;
|
|
}
|
|
|
|
g_dbus_proxy_call (obj->proxy,
|
|
(enabled ? "EnableExtension" : "DisableExtension"),
|
|
g_variant_new ("(s)", uuid_str),
|
|
G_DBUS_CALL_FLAGS_NONE,
|
|
-1, /* timeout */
|
|
NULL, /* cancellable */
|
|
NULL, /* callback */
|
|
NULL /* user_data */);
|
|
|
|
g_free (uuid_str);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
plugin_install_extension (PluginObject *obj,
|
|
NPString uuid,
|
|
NPString version_tag)
|
|
{
|
|
gchar *uuid_str = g_strndup (uuid.UTF8Characters, uuid.UTF8Length);
|
|
gchar *version_tag_str;
|
|
|
|
if (!uuid_is_valid (uuid_str))
|
|
{
|
|
g_free (uuid_str);
|
|
return FALSE;
|
|
}
|
|
|
|
version_tag_str = g_strndup (version_tag.UTF8Characters,
|
|
version_tag.UTF8Length);
|
|
|
|
g_dbus_proxy_call (obj->proxy,
|
|
"InstallRemoteExtension",
|
|
g_variant_new ("(ss)",
|
|
uuid_str,
|
|
version_tag_str),
|
|
G_DBUS_CALL_FLAGS_NONE,
|
|
-1, /* timeout */
|
|
NULL, /* cancellable */
|
|
NULL, /* callback */
|
|
NULL /* user_data */);
|
|
|
|
g_free (uuid_str);
|
|
g_free (version_tag_str);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
plugin_uninstall_extension (PluginObject *obj,
|
|
NPString uuid,
|
|
NPVariant *result)
|
|
{
|
|
GError *error = NULL;
|
|
GVariant *res;
|
|
gchar *uuid_str;
|
|
|
|
uuid_str = g_strndup (uuid.UTF8Characters, uuid.UTF8Length);
|
|
if (!uuid_is_valid (uuid_str))
|
|
{
|
|
g_free (uuid_str);
|
|
return FALSE;
|
|
}
|
|
|
|
res = g_dbus_proxy_call_sync (obj->proxy,
|
|
"UninstallExtension",
|
|
g_variant_new ("(s)",
|
|
uuid_str),
|
|
G_DBUS_CALL_FLAGS_NONE,
|
|
-1, /* timeout */
|
|
NULL, /* cancellable */
|
|
&error);
|
|
|
|
g_free (uuid_str);
|
|
|
|
if (!res)
|
|
{
|
|
g_warning ("Failed to uninstall extension: %s", error->message);
|
|
g_error_free (error);
|
|
return FALSE;
|
|
}
|
|
|
|
return jsonify_variant (res, result);
|
|
}
|
|
|
|
static gboolean
|
|
plugin_get_info (PluginObject *obj,
|
|
NPString uuid,
|
|
NPVariant *result)
|
|
{
|
|
GError *error = NULL;
|
|
GVariant *res;
|
|
gchar *uuid_str;
|
|
|
|
uuid_str = g_strndup (uuid.UTF8Characters, uuid.UTF8Length);
|
|
if (!uuid_is_valid (uuid_str))
|
|
{
|
|
g_free (uuid_str);
|
|
return FALSE;
|
|
}
|
|
|
|
res = g_dbus_proxy_call_sync (obj->proxy,
|
|
"GetExtensionInfo",
|
|
g_variant_new ("(s)", uuid_str),
|
|
G_DBUS_CALL_FLAGS_NONE,
|
|
-1, /* timeout */
|
|
NULL, /* cancellable */
|
|
&error);
|
|
|
|
g_free (uuid_str);
|
|
|
|
if (!res)
|
|
{
|
|
g_warning ("Failed to retrieve extension metadata: %s", error->message);
|
|
g_error_free (error);
|
|
return FALSE;
|
|
}
|
|
|
|
return jsonify_variant (res, result);
|
|
}
|
|
|
|
static gboolean
|
|
plugin_get_errors (PluginObject *obj,
|
|
NPString uuid,
|
|
NPVariant *result)
|
|
{
|
|
GError *error = NULL;
|
|
GVariant *res;
|
|
gchar *uuid_str;
|
|
|
|
uuid_str = g_strndup (uuid.UTF8Characters, uuid.UTF8Length);
|
|
if (!uuid_is_valid (uuid_str))
|
|
{
|
|
g_free (uuid_str);
|
|
return FALSE;
|
|
}
|
|
|
|
res = g_dbus_proxy_call_sync (obj->proxy,
|
|
"GetExtensionErrors",
|
|
g_variant_new ("(s)", uuid_str),
|
|
G_DBUS_CALL_FLAGS_NONE,
|
|
-1, /* timeout */
|
|
NULL, /* cancellable */
|
|
&error);
|
|
|
|
g_free (uuid_str);
|
|
|
|
if (!res)
|
|
{
|
|
g_warning ("Failed to retrieve errors: %s", error->message);
|
|
g_error_free (error);
|
|
return FALSE;
|
|
}
|
|
|
|
return jsonify_variant (res, result);
|
|
}
|
|
|
|
static gboolean
|
|
plugin_launch_extension_prefs (PluginObject *obj,
|
|
NPString uuid,
|
|
NPVariant *result)
|
|
{
|
|
gchar *uuid_str;
|
|
|
|
uuid_str = g_strndup (uuid.UTF8Characters, uuid.UTF8Length);
|
|
if (!uuid_is_valid (uuid_str))
|
|
{
|
|
g_free (uuid_str);
|
|
return FALSE;
|
|
}
|
|
|
|
g_dbus_proxy_call (obj->proxy,
|
|
"LaunchExtensionPrefs",
|
|
g_variant_new ("(s)", uuid_str),
|
|
G_DBUS_CALL_FLAGS_NONE,
|
|
-1, /* timeout */
|
|
NULL, /* cancellable */
|
|
NULL, /* callback */
|
|
NULL /* user_data */);
|
|
|
|
g_free (uuid_str);
|
|
return TRUE;
|
|
}
|
|
|
|
static int
|
|
plugin_get_api_version (PluginObject *obj,
|
|
NPVariant *result)
|
|
{
|
|
INT32_TO_NPVARIANT (PLUGIN_API_VERSION, *result);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
plugin_get_shell_version (PluginObject *obj,
|
|
NPVariant *result)
|
|
{
|
|
GVariant *res;
|
|
const gchar *version;
|
|
gsize length;
|
|
gchar *buffer;
|
|
gboolean ret;
|
|
|
|
ret = TRUE;
|
|
|
|
res = g_dbus_proxy_get_cached_property (obj->proxy,
|
|
"ShellVersion");
|
|
|
|
if (res == NULL)
|
|
{
|
|
g_warning ("Failed to grab shell version.");
|
|
version = "-1";
|
|
}
|
|
else
|
|
{
|
|
g_variant_get (res, "&s", &version);
|
|
}
|
|
|
|
length = strlen (version);
|
|
buffer = funcs.memalloc (length + 1);
|
|
if (!buffer)
|
|
{
|
|
ret = FALSE;
|
|
goto out;
|
|
}
|
|
strcpy (buffer, version);
|
|
|
|
STRINGN_TO_NPVARIANT (buffer, length, *result);
|
|
|
|
out:
|
|
if (res)
|
|
g_variant_unref (res);
|
|
return ret;
|
|
}
|
|
|
|
static bool
|
|
plugin_object_invoke (NPObject *npobj,
|
|
NPIdentifier name,
|
|
const NPVariant *args,
|
|
uint32_t argc,
|
|
NPVariant *result)
|
|
{
|
|
PluginObject *obj;
|
|
|
|
g_debug ("invoking plugin object method");
|
|
|
|
obj = (PluginObject*) npobj;
|
|
|
|
VOID_TO_NPVARIANT (*result);
|
|
|
|
if (!plugin_object_has_method (npobj, name))
|
|
return FALSE;
|
|
|
|
if (name == list_extensions_id)
|
|
return plugin_list_extensions (obj, result);
|
|
else if (name == get_info_id)
|
|
{
|
|
if (!NPVARIANT_IS_STRING(args[0])) return FALSE;
|
|
|
|
return plugin_get_info (obj, NPVARIANT_TO_STRING(args[0]), result);
|
|
}
|
|
else if (name == enable_extension_id)
|
|
{
|
|
if (!NPVARIANT_IS_STRING(args[0])) return FALSE;
|
|
if (!NPVARIANT_IS_BOOLEAN(args[1])) return FALSE;
|
|
|
|
return plugin_enable_extension (obj,
|
|
NPVARIANT_TO_STRING(args[0]),
|
|
NPVARIANT_TO_BOOLEAN(args[1]));
|
|
}
|
|
else if (name == install_extension_id)
|
|
{
|
|
if (!NPVARIANT_IS_STRING(args[0])) return FALSE;
|
|
if (!NPVARIANT_IS_STRING(args[1])) return FALSE;
|
|
|
|
return plugin_install_extension (obj,
|
|
NPVARIANT_TO_STRING(args[0]),
|
|
NPVARIANT_TO_STRING(args[1]));
|
|
}
|
|
else if (name == uninstall_extension_id)
|
|
{
|
|
if (!NPVARIANT_IS_STRING(args[0])) return FALSE;
|
|
|
|
return plugin_uninstall_extension (obj,
|
|
NPVARIANT_TO_STRING(args[0]),
|
|
result);
|
|
}
|
|
else if (name == get_errors_id)
|
|
{
|
|
if (!NPVARIANT_IS_STRING(args[0])) return FALSE;
|
|
|
|
return plugin_get_errors (obj,
|
|
NPVARIANT_TO_STRING(args[0]),
|
|
result);
|
|
}
|
|
else if (name == launch_extension_prefs_id)
|
|
{
|
|
if (!NPVARIANT_IS_STRING(args[0])) return FALSE;
|
|
|
|
return plugin_launch_extension_prefs (obj,
|
|
NPVARIANT_TO_STRING(args[0]),
|
|
result);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static bool
|
|
plugin_object_has_property (NPObject *npobj,
|
|
NPIdentifier name)
|
|
{
|
|
return (name == onextension_changed_id ||
|
|
name == onrestart_id ||
|
|
name == api_version_id ||
|
|
name == shell_version_id);
|
|
}
|
|
|
|
static bool
|
|
plugin_object_get_property (NPObject *npobj,
|
|
NPIdentifier name,
|
|
NPVariant *result)
|
|
{
|
|
PluginObject *obj;
|
|
|
|
if (!plugin_object_has_property (npobj, name))
|
|
return FALSE;
|
|
|
|
obj = (PluginObject*) npobj;
|
|
if (name == api_version_id)
|
|
return plugin_get_api_version (obj, result);
|
|
else if (name == shell_version_id)
|
|
return plugin_get_shell_version (obj, result);
|
|
else if (name == onextension_changed_id)
|
|
{
|
|
if (obj->listener)
|
|
OBJECT_TO_NPVARIANT (obj->listener, *result);
|
|
else
|
|
NULL_TO_NPVARIANT (*result);
|
|
}
|
|
else if (name == onrestart_id)
|
|
{
|
|
if (obj->restart_listener)
|
|
OBJECT_TO_NPVARIANT (obj->restart_listener, *result);
|
|
else
|
|
NULL_TO_NPVARIANT (*result);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static bool
|
|
plugin_object_set_callback (NPObject **listener,
|
|
const NPVariant *value)
|
|
{
|
|
if (!NPVARIANT_IS_OBJECT (*value) && !NPVARIANT_IS_NULL (*value))
|
|
return FALSE;
|
|
|
|
if (*listener)
|
|
funcs.releaseobject (*listener);
|
|
*listener = NULL;
|
|
|
|
if (NPVARIANT_IS_OBJECT (*value))
|
|
{
|
|
*listener = NPVARIANT_TO_OBJECT (*value);
|
|
funcs.retainobject (*listener);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static bool
|
|
plugin_object_set_property (NPObject *npobj,
|
|
NPIdentifier name,
|
|
const NPVariant *value)
|
|
{
|
|
PluginObject *obj;
|
|
|
|
obj = (PluginObject *)npobj;
|
|
|
|
if (name == onextension_changed_id)
|
|
return plugin_object_set_callback (&obj->listener, value);
|
|
|
|
if (name == onrestart_id)
|
|
return plugin_object_set_callback (&obj->restart_listener, value);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static NPClass plugin_class = {
|
|
NP_CLASS_STRUCT_VERSION,
|
|
plugin_object_allocate,
|
|
plugin_object_deallocate,
|
|
NULL, /* invalidate */
|
|
plugin_object_has_method,
|
|
plugin_object_invoke,
|
|
NULL, /* invoke default */
|
|
plugin_object_has_property,
|
|
plugin_object_get_property,
|
|
plugin_object_set_property,
|
|
NULL, /* remove property */
|
|
NULL, /* enumerate */
|
|
NULL, /* construct */
|
|
};
|
|
|
|
static void
|
|
init_methods_and_properties (void)
|
|
{
|
|
/* this is the JS public API; it is manipulated through NPIdentifiers for speed */
|
|
api_version_id = funcs.getstringidentifier ("apiVersion");
|
|
shell_version_id = funcs.getstringidentifier ("shellVersion");
|
|
|
|
get_info_id = funcs.getstringidentifier ("getExtensionInfo");
|
|
list_extensions_id = funcs.getstringidentifier ("listExtensions");
|
|
enable_extension_id = funcs.getstringidentifier ("setExtensionEnabled");
|
|
install_extension_id = funcs.getstringidentifier ("installExtension");
|
|
uninstall_extension_id = funcs.getstringidentifier ("uninstallExtension");
|
|
get_errors_id = funcs.getstringidentifier ("getExtensionErrors");
|
|
launch_extension_prefs_id = funcs.getstringidentifier ("launchExtensionPrefs");
|
|
|
|
onrestart_id = funcs.getstringidentifier ("onshellrestart");
|
|
onextension_changed_id = funcs.getstringidentifier ("onchange");
|
|
}
|
|
|
|
NPError
|
|
NPP_GetValue(NPP instance,
|
|
NPPVariable variable,
|
|
void *value)
|
|
{
|
|
g_debug ("NPP_GetValue called");
|
|
|
|
switch (variable) {
|
|
case NPPVpluginScriptableNPObject:
|
|
g_debug ("creating scriptable object");
|
|
init_methods_and_properties ();
|
|
|
|
*(NPObject**)value = funcs.createobject (instance, &plugin_class);
|
|
break;
|
|
|
|
case NPPVpluginNeedsXEmbed:
|
|
*(bool *)value = TRUE;
|
|
break;
|
|
|
|
default:
|
|
;
|
|
}
|
|
|
|
return NPERR_NO_ERROR;
|
|
}
|