diff --git a/browser-plugin/browser-plugin.c b/browser-plugin/browser-plugin.c index 6daea9963..b47b41c0e 100644 --- a/browser-plugin/browser-plugin.c +++ b/browser-plugin/browser-plugin.c @@ -41,7 +41,7 @@ "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 4 +#define PLUGIN_API_VERSION 5 typedef struct { GDBusProxy *proxy; @@ -489,6 +489,12 @@ parse_args (const gchar *format_str, *(gboolean *) arg_location = NPVARIANT_TO_BOOLEAN (arg); break; + + case 'o': + if (!NPVARIANT_IS_OBJECT (arg)) + goto out; + + *(NPObject **) arg_location = NPVARIANT_TO_OBJECT (arg); } } @@ -580,6 +586,53 @@ plugin_enable_extension (PluginObject *obj, return ret; } +typedef struct _AsyncClosure AsyncClosure; + +struct _AsyncClosure { + PluginObject *obj; + NPObject *callback; + NPObject *errback; +}; + +static void +install_extension_cb (GObject *proxy, + GAsyncResult *async_res, + gpointer user_data) +{ + AsyncClosure *async_closure = (AsyncClosure *) user_data; + GError *error = NULL; + GVariant *res; + NPVariant args[1]; + NPVariant result = { NPVariantType_Void }; + NPObject *callback; + + res = g_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), async_res, &error); + + if (res == NULL) + { + if (g_dbus_error_is_remote_error (error)) + g_dbus_error_strip_remote_error (error); + STRINGZ_TO_NPVARIANT (error->message, args[0]); + callback = async_closure->errback; + } + else + { + char *string_result; + g_variant_get (res, "(&s)", &string_result); + STRINGZ_TO_NPVARIANT (string_result, args[0]); + callback = async_closure->callback; + } + + funcs.invokeDefault (async_closure->obj->instance, + callback, args, 1, &result); + + funcs.releasevariantvalue (&result); + + funcs.releaseobject (async_closure->callback); + funcs.releaseobject (async_closure->errback); + g_slice_free (AsyncClosure, async_closure); +} + static gboolean plugin_install_extension (PluginObject *obj, uint32_t argc, @@ -587,18 +640,25 @@ plugin_install_extension (PluginObject *obj, NPVariant *result) { gchar *uuid; + NPObject *callback, *errback; + AsyncClosure *async_closure; - if (!parse_args ("u", argc, argv, &uuid)) + if (!parse_args ("uoo", argc, argv, &uuid, &callback, &errback)) return FALSE; + async_closure = g_slice_new (AsyncClosure); + async_closure->obj = obj; + async_closure->callback = funcs.retainobject (callback); + async_closure->errback = funcs.retainobject (errback); + g_dbus_proxy_call (obj->proxy, "InstallRemoteExtension", g_variant_new ("(s)", uuid), G_DBUS_CALL_FLAGS_NONE, -1, /* timeout */ NULL, /* cancellable */ - NULL, /* callback */ - NULL /* user_data */); + install_extension_cb, + async_closure); g_free (uuid); diff --git a/js/ui/extensionDownloader.js b/js/ui/extensionDownloader.js index e9f49524c..1d4c46847 100644 --- a/js/ui/extensionDownloader.js +++ b/js/ui/extensionDownloader.js @@ -22,7 +22,7 @@ const REPOSITORY_URL_INFO = REPOSITORY_URL_BASE + '/extension-info/'; let _httpSession; -function installExtensionFromUUID(uuid) { +function installExtensionFromUUID(uuid, invocation) { let params = { uuid: uuid, shell_version: Config.PACKAGE_VERSION }; @@ -31,6 +31,7 @@ function installExtensionFromUUID(uuid) { _httpSession.queue_message(message, function(session, message) { if (message.status_code != Soup.KnownStatusCode.OK) { ExtensionSystem.logExtensionError(uuid, 'downloading info: ' + message.status_code); + invocation.return_dbus_error('org.gnome.Shell.DownloadInfoError', message.status_code.toString()); return; } @@ -39,10 +40,11 @@ function installExtensionFromUUID(uuid) { info = JSON.parse(message.response_body.data); } catch (e) { ExtensionSystem.logExtensionError(uuid, 'parsing info: ' + e); + invocation.return_dbus_error('org.gnome.Shell.ParseInfoError', e.toString()); return; } - let dialog = new InstallExtensionDialog(uuid, info); + let dialog = new InstallExtensionDialog(uuid, info, invocation); dialog.open(global.get_current_time()); }); } @@ -63,9 +65,9 @@ function uninstallExtensionFromUUID(uuid) { return true; } -function gotExtensionZipFile(session, message, uuid) { +function gotExtensionZipFile(session, message, uuid, callback, errback) { if (message.status_code != Soup.KnownStatusCode.OK) { - ExtensionSystem.logExtensionError(uuid, 'downloading extension: ' + message.status_code); + errback('DownloadExtensionError', message.status_code); return; } @@ -74,7 +76,7 @@ function gotExtensionZipFile(session, message, uuid) { if (!dir.query_exists(null)) dir.make_directory_with_parents(null); } catch (e) { - ExtensionSystem.logExtensionError(uuid, 'Could not create extension directory'); + errback('CreateExtensionDirectoryError', e); return; } @@ -89,7 +91,7 @@ function gotExtensionZipFile(session, message, uuid) { null); if (!success) { - ExtensionSystem.logExtensionError(uuid, 'extract: could not extract'); + errback('ExtractExtensionError'); return; } @@ -97,8 +99,7 @@ function gotExtensionZipFile(session, message, uuid) { GLib.spawn_close_pid(pid); if (status != 0) { - ExtensionSystem.logExtensionError(uuid, 'extract: could not extract'); - invocation.return_dbus_error('org.gnome.Shell.ExtractExtensionError', ''); + errback('ExtractExtensionError'); return; } @@ -111,6 +112,7 @@ function gotExtensionZipFile(session, message, uuid) { let extension = ExtensionUtils.createExtensionObject(uuid, dir, ExtensionUtils.ExtensionType.PER_USER); ExtensionSystem.loadExtension(extension); + callback(); }); } @@ -118,11 +120,12 @@ const InstallExtensionDialog = new Lang.Class({ Name: 'InstallExtensionDialog', Extends: ModalDialog.ModalDialog, - _init: function(uuid, info) { + _init: function(uuid, info, invocation) { this.parent({ styleClass: 'extension-dialog' }); this._uuid = uuid; this._info = info; + this._invocation = invocation; this.setButtons([{ label: _("Cancel"), action: Lang.bind(this, this._onCancelButtonPressed), @@ -147,34 +150,27 @@ const InstallExtensionDialog = new Lang.Class({ _onCancelButtonPressed: function(button, event) { this.close(global.get_current_time()); - - // Even though the extension is already "uninstalled", send through - // a state-changed signal for any users who want to know if the install - // went through correctly -- using proper async DBus would block more - // traditional clients like the plugin - let meta = { uuid: this._uuid, - state: ExtensionSystem.ExtensionState.UNINSTALLED, - error: '' }; - - _signals.emit('extension-state-changed', meta); + this._invocation.return_value(GLib.Variant.new('(s)', ['cancelled'])); }, _onInstallButtonPressed: function(button, event) { - let state = { uuid: this._uuid, - state: ExtensionSystem.ExtensionState.DOWNLOADING, - error: '' }; - - _signals.emit('extension-state-changed', state); - let params = { shell_version: Config.PACKAGE_VERSION }; let url = REPOSITORY_URL_DOWNLOAD.format(this._uuid); let message = Soup.form_request_new_from_hash('GET', url, params); - _httpSession.queue_message(message, - Lang.bind(this, function(session, message) { - gotExtensionZipFile(session, message, this._uuid); - })); + let invocation = this._invocation; + function errback(code, message) { + invocation.return_dbus_error('org.gnome.Shell.' + code, message ? message.toString() : ''); + } + + function callback() { + invocation.return_value(GLib.Variant.new('(s)', 'successful')); + } + + _httpSession.queue_message(message, Lang.bind(this, function(session, message) { + gotExtensionZipFile(session, message, this._uuid, callback, errback); + })); this.close(global.get_current_time()); } diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js index 910d5cfc8..e402cabbb 100644 --- a/js/ui/shellDBus.js +++ b/js/ui/shellDBus.js @@ -202,6 +202,7 @@ const GnomeShellExtensionsIface = + @@ -285,8 +286,8 @@ const GnomeShellExtensions = new Lang.Class({ return extension.errors; }, - InstallRemoteExtension: function(uuid) { - ExtensionDownloader.installExtensionFromUUID(uuid); + InstallRemoteExtensionAsync: function([uuid], invocation) { + return ExtensionDownloader.installExtensionFromUUID(uuid, invocation); }, UninstallExtension: function(uuid) {