Bug 1297686 - List GIO handlers in protocol handler list in handlers dialog and in preferences, r?paolo
The nsGIOService now provides GetAppsForURIScheme which is used to append handlers
for specific scheme in handler list dialog (toolkit/mozapps/handling/content/dialog.js)
and also in Applications section in preferences. In case the default system handler
or user added handler has same name as one of the GIO handlers, the GIO handler
is not appended. The check for not adding handler is by using handler name.
The nsGIOMimeApp class now implements nsIHandlerApp interface. Instead overloaded
GetName methods (nsCString and nsString) we now use nsString variant everywhere.
This require change of nsGNOMERegistry::GetFromType which if fact leads to code
simplification.
The implementation of nsGNOMEShellService::SetDefaultBrowser has been changed
because implementation of CreateAppFromCommand has changed.
The CreateAppFromCommand no longer tries to find the application,
for that FindAppFromCommand has been introduced.
MozReview-Commit-ID: KmfFWRPqV3
--- a/browser/components/preferences/in-content/main.js
+++ b/browser/components/preferences/in-content/main.js
@@ -1696,16 +1696,19 @@ var gMainPane = {
return this._isValidHandlerExecutable(aHandlerApp.executable);
if (aHandlerApp instanceof Ci.nsIWebHandlerApp)
return aHandlerApp.uriTemplate;
if (aHandlerApp instanceof Ci.nsIWebContentHandlerInfo)
return aHandlerApp.uri;
+ if (aHandlerApp instanceof Ci.nsIGIOMimeApp)
+ return aHandlerApp.command;
+
return false;
},
_isValidHandlerExecutable(aExecutable) {
let leafName;
if (AppConstants.platform == "win") {
leafName = `${AppConstants.MOZ_APP_NAME}.exe`;
} else if (AppConstants.platform == "macosx") {
@@ -1833,16 +1836,56 @@ var gMainPane = {
// Attach the handler app object to the menu item so we can use it
// to make changes to the datastore when the user selects the item.
menuItem.handlerApp = possibleApp;
menuPopup.appendChild(menuItem);
possibleAppMenuItems.push(menuItem);
}
+ // Add gio handlers
+ if (Cc["@mozilla.org/gio-service;1"]) {
+ let gIOSvc = Cc["@mozilla.org/gio-service;1"].
+ getService(Ci.nsIGIOService);
+ var gioApps = gIOSvc.getAppsForURIScheme(typeItem.type);
+ let enumerator = gioApps.enumerate();
+ let possibleHandlers = handlerInfo.possibleApplicationHandlers
+ while (enumerator.hasMoreElements()) {
+ let handler = enumerator.getNext().QueryInterface(Ci.nsIHandlerApp);
+ // OS handler share the same name, it's most likely the same app, skipping...
+ if (handler.name == handlerInfo.defaultDescription) {
+ continue;
+ }
+ // Check if the handler is already in possibleHandlers
+ let appAlreadyInHandlers = false;
+ for (let i = possibleHandlers.length - 1; i >= 0; --i) {
+ let app = possibleHandlers.queryElementAt(i, Ci.nsIHandlerApp);
+ // nsGIOMimeApp::Equals is able to compare with nsILocalHandlerApp
+ if (handler.equals(app)) {
+ appAlreadyInHandlers = true;
+ break;
+ }
+ }
+ if (!appAlreadyInHandlers) {
+ let menuItem = document.createElement("menuitem");
+ menuItem.setAttribute("action", Ci.nsIHandlerInfo.useHelperApp);
+ let label = this._prefsBundle.getFormattedString("useApp", [handler.name]);
+ menuItem.setAttribute("label", label);
+ menuItem.setAttribute("tooltiptext", label);
+ menuItem.setAttribute("image", this._getIconURLForHandlerApp(handler));
+
+ // Attach the handler app object to the menu item so we can use it
+ // to make changes to the datastore when the user selects the item.
+ menuItem.handlerApp = handler;
+
+ menuPopup.appendChild(menuItem);
+ possibleAppMenuItems.push(menuItem);
+ }
+ }
+ }
// Create a menu item for the plugin.
if (handlerInfo.pluginName) {
var pluginMenuItem = document.createElement("menuitem");
pluginMenuItem.setAttribute("action", kActionUsePlugin);
let label = this._prefsBundle.getFormattedString("usePluginIn",
[handlerInfo.pluginName,
this._brandShortName]);
--- a/browser/components/shell/nsGNOMEShellService.cpp
+++ b/browser/components/shell/nsGNOMEShellService.cpp
@@ -289,20 +289,25 @@ nsGNOMEShellService::SetDefaultBrowser(b
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString brandShortName;
brandBundle->GetStringFromName("brandShortName", brandShortName);
// use brandShortName as the application id.
NS_ConvertUTF16toUTF8 id(brandShortName);
nsCOMPtr<nsIGIOMimeApp> appInfo;
- rv = giovfs->CreateAppFromCommand(mAppPath,
- id,
- getter_AddRefs(appInfo));
- NS_ENSURE_SUCCESS(rv, rv);
+ rv = giovfs->FindAppFromCommand(mAppPath, getter_AddRefs(appInfo));
+ if (NS_FAILED(rv)) {
+ // Application was not found in the list of installed applications provided
+ // by OS. Fallback to create appInfo from command and name.
+ rv = giovfs->CreateAppFromCommand(mAppPath,
+ id,
+ getter_AddRefs(appInfo));
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
// set handler for the protocols
for (unsigned int i = 0; i < ArrayLength(appProtocols); ++i) {
if (appProtocols[i].essential || aClaimAllTypes) {
appInfo->SetAsDefaultForURIScheme(nsDependentCString(appProtocols[i].name));
}
}
--- a/toolkit/mozapps/handling/content/dialog.js
+++ b/toolkit/mozapps/handling/content/dialog.js
@@ -128,18 +128,20 @@ var dialog = {
// and users won't visit the handler's URL template, they'll only
// visit URLs derived from that template (i.e. with %s in the template
// replaced by the URL of the content being handled).
elm.setAttribute("image", uri.prePath + "/favicon.ico");
}
elm.setAttribute("description", uri.prePath);
} else if (app instanceof Ci.nsIDBusHandlerApp) {
elm.setAttribute("description", app.method);
- } else
+ } else if (!(app instanceof Ci.nsIGIOMimeApp)) {
+ // We support GIO application handler, but no action required there
throw "unknown handler type";
+ }
items.insertBefore(elm, this._itemChoose);
if (preferredHandler && app == preferredHandler)
this.selectedItem = elm;
}
if (this._handlerInfo.hasDefaultHandler) {
let elm = document.createElement("richlistitem");
@@ -147,16 +149,49 @@ var dialog = {
elm.id = "os-default-handler";
elm.setAttribute("name", this._handlerInfo.defaultDescription);
items.insertBefore(elm, items.firstChild);
if (this._handlerInfo.preferredAction ==
Ci.nsIHandlerInfo.useSystemDefault)
this.selectedItem = elm;
}
+
+ // Add gio handlers
+ if (Cc["@mozilla.org/gio-service;1"]) {
+ let gIOSvc = Cc["@mozilla.org/gio-service;1"]
+ .getService(Ci.nsIGIOService);
+ var gioApps = gIOSvc.getAppsForURIScheme(this._URI.scheme);
+ let enumerator = gioApps.enumerate();
+ while (enumerator.hasMoreElements()) {
+ let handler = enumerator.getNext().QueryInterface(Ci.nsIHandlerApp);
+ // OS handler share the same name, it's most likely the same app, skipping...
+ if (handler.name == this._handlerInfo.defaultDescription) {
+ continue;
+ }
+ // Check if the handler is already in possibleHandlers
+ let appAlreadyInHandlers = false;
+ for (let i = possibleHandlers.length - 1; i >= 0; --i) {
+ let app = possibleHandlers.queryElementAt(i, Ci.nsIHandlerApp);
+ // nsGIOMimeApp::Equals is able to compare with nsILocalHandlerApp
+ if (handler.equals(app)) {
+ appAlreadyInHandlers = true;
+ break;
+ }
+ }
+ if (!appAlreadyInHandlers) {
+ let elm = document.createElement("richlistitem");
+ elm.setAttribute("type", "handler");
+ elm.setAttribute("name", handler.name);
+ elm.obj = handler;
+ items.insertBefore(elm, this._itemChoose);
+ }
+ }
+ }
+
items.ensureSelectedElementIsVisible();
},
/**
* Brings up a filepicker and allows a user to choose an application.
*/
chooseApplication: function chooseApplication() {
var bundle = document.getElementById("base-strings");
--- a/toolkit/system/gnome/nsGIOService.cpp
+++ b/toolkit/system/gnome/nsGIOService.cpp
@@ -4,52 +4,87 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsGIOService.h"
#include "nsString.h"
#include "nsIURI.h"
#include "nsTArray.h"
#include "nsIStringEnumerator.h"
#include "nsAutoPtr.h"
+#include "nsIMIMEInfo.h"
+#include "nsComponentManagerUtils.h"
+#include "nsArray.h"
+#include "nsIFile.h"
#include <gio/gio.h>
#include <gtk/gtk.h>
#ifdef MOZ_ENABLE_DBUS
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
#endif
+/**
+ * Get command without any additional arguments
+ * @param aCommandWithArguments full commandline input string
+ * @param aCommand string for storing command without arguments
+ * @return NS_ERROR_FAILURE when unable to parse commandline
+ */
+static nsresult
+GetCommandFromCommandline(nsACString const& aCommandWithArguments, nsACString& aCommand) {
+ GError *error = nullptr;
+ gchar **argv = nullptr;
+ if (!g_shell_parse_argv(aCommandWithArguments.BeginReading(), nullptr, &argv, &error) ||
+ !argv[0]) {
+ g_warning("Cannot parse command with arguments: %s", error->message);
+ g_error_free(error);
+ g_strfreev(argv);
+ return NS_ERROR_FAILURE;
+ }
+ aCommand.Assign(argv[0]);
+ g_strfreev(argv);
+ return NS_OK;
+}
+
class nsGIOMimeApp final : public nsIGIOMimeApp
{
public:
NS_DECL_ISUPPORTS
+ NS_DECL_NSIHANDLERAPP
NS_DECL_NSIGIOMIMEAPP
explicit nsGIOMimeApp(GAppInfo* aApp) : mApp(aApp) {}
private:
~nsGIOMimeApp() { g_object_unref(mApp); }
GAppInfo *mApp;
};
-NS_IMPL_ISUPPORTS(nsGIOMimeApp, nsIGIOMimeApp)
+NS_IMPL_ISUPPORTS(nsGIOMimeApp, nsIGIOMimeApp, nsIHandlerApp)
NS_IMETHODIMP
nsGIOMimeApp::GetId(nsACString& aId)
{
aId.Assign(g_app_info_get_id(mApp));
return NS_OK;
}
NS_IMETHODIMP
-nsGIOMimeApp::GetName(nsACString& aName)
+nsGIOMimeApp::GetName(nsAString& aName)
{
- aName.Assign(g_app_info_get_name(mApp));
+ aName.Assign(NS_ConvertUTF8toUTF16(g_app_info_get_name(mApp)));
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGIOMimeApp::SetName(const nsAString& aName)
+{
+ // We don't implement SetName because we're using mGIOMimeApp instance for
+ // obtaining application name
return NS_OK;
}
NS_IMETHODIMP
nsGIOMimeApp::GetCommand(nsACString& aCommand)
{
const char *cmd = g_app_info_get_commandline(mApp);
if (!cmd)
@@ -79,16 +114,81 @@ nsGIOMimeApp::Launch(const nsACString& a
g_warning("Cannot launch application: %s", error->message);
g_error_free(error);
return NS_ERROR_FAILURE;
}
return NS_OK;
}
+NS_IMETHODIMP
+nsGIOMimeApp::GetDetailedDescription(nsAString& aDetailedDescription)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsGIOMimeApp::SetDetailedDescription(const nsAString& aDetailedDescription)
+{
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+nsGIOMimeApp::Equals(nsIHandlerApp* aHandlerApp, bool* _retval)
+{
+ if (!aHandlerApp)
+ return NS_ERROR_FAILURE;
+
+ // Compare with nsILocalHandlerApp instance by name
+ nsCOMPtr<nsILocalHandlerApp> localHandlerApp = do_QueryInterface(aHandlerApp);
+ if (localHandlerApp) {
+ nsAutoString theirName;
+ nsAutoString thisName;
+ GetName(thisName);
+ localHandlerApp->GetName(theirName);
+ *_retval = thisName.Equals(theirName);
+ return NS_OK;
+ }
+
+ // Compare with nsIGIOMimeApp instance by command with stripped arguments
+ nsCOMPtr<nsIGIOMimeApp> gioMimeApp = do_QueryInterface(aHandlerApp);
+ if (gioMimeApp) {
+ nsAutoCString thisCommandline, thisCommand;
+ nsresult rv = GetCommand(thisCommandline);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = GetCommandFromCommandline(thisCommandline,
+ thisCommand);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ nsAutoCString theirCommandline, theirCommand;
+ gioMimeApp->GetCommand(theirCommandline);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = GetCommandFromCommandline(theirCommandline,
+ theirCommand);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ *_retval = thisCommand.Equals(theirCommand);
+ return NS_OK;
+ }
+
+ // We can only compare with nsILocalHandlerApp and nsGIOMimeApp
+ *_retval = false;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsGIOMimeApp::LaunchWithURI(nsIURI* aUri, nsIInterfaceRequestor* aRequestor)
+{
+ nsCString uri_string;
+ aUri->GetSpec(uri_string);
+ return Launch(uri_string);
+}
+
class GIOUTF8StringEnumerator final : public nsIUTF8StringEnumerator
{
~GIOUTF8StringEnumerator() = default;
public:
GIOUTF8StringEnumerator() : mIndex(0) { }
NS_DECL_ISUPPORTS
@@ -278,16 +378,43 @@ nsGIOService::GetAppForURIScheme(const n
NS_ADDREF(*aApp = mozApp);
} else {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
NS_IMETHODIMP
+nsGIOService::GetAppsForURIScheme(const nsACString& aURIScheme,
+ nsIMutableArray** aResult)
+{
+ nsCOMPtr<nsIMutableArray> handlersArray =
+ do_CreateInstance(NS_ARRAY_CONTRACTID);
+
+ nsAutoCString contentType("x-scheme-handler/");
+ contentType.Append(aURIScheme);
+
+ GList* appInfoList = g_app_info_get_all_for_type(contentType.get());
+ // g_app_info_get_all_for_type returns NULL when no appinfo is found
+ // or error occurs (contentType is NULL). We are fine with empty app list
+ // and we're sure that contentType is not NULL, so we won't return failure.
+ if (appInfoList) {
+ GList* appInfo = appInfoList;
+ while (appInfo) {
+ nsCOMPtr<nsIGIOMimeApp> mimeApp = new nsGIOMimeApp(G_APP_INFO(appInfo->data));
+ handlersArray->AppendElement(mimeApp);
+ appInfo = appInfo->next;
+ }
+ g_list_free(appInfoList);
+ }
+ NS_ADDREF(*aResult = handlersArray);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
nsGIOService::GetAppForMimeType(const nsACString& aMimeType,
nsIGIOMimeApp** aApp)
{
*aApp = nullptr;
char *content_type =
g_content_type_from_mime_type(PromiseFlatCString(aMimeType).get());
if (!content_type)
return NS_ERROR_FAILURE;
@@ -412,64 +539,101 @@ nsGIOService::OrgFreedesktopFileManager1
return NS_ERROR_NOT_AVAILABLE;
}
return NS_OK;
#endif
}
/**
- * Create or find already existing application info for specified command
- * and application name.
- * @param cmd command to execute
- * @param appName application name
- * @param appInfo location where created GAppInfo is stored
- * @return NS_OK when object is created, NS_ERROR_FAILURE otherwise.
+ * Find GIO Mime App from given commandline.
+ * This is different from CreateAppFromCommand because instead of creating the
+ * GIO Mime App in case it's not found in the GIO application list, the method
+ * returns error.
+ * @param aCmd command with parameters used to start the application
+ * @return NS_OK when application is found, NS_ERROR_NOT_AVAILABLE otherwise
*/
NS_IMETHODIMP
-nsGIOService::CreateAppFromCommand(nsACString const& cmd,
- nsACString const& appName,
- nsIGIOMimeApp** appInfo)
+nsGIOService::FindAppFromCommand(nsACString const& aCmd,
+ nsIGIOMimeApp** aAppInfo)
{
- GError *error = nullptr;
- *appInfo = nullptr;
-
GAppInfo *app_info = nullptr, *app_info_from_list = nullptr;
GList *apps = g_app_info_get_all();
GList *apps_p = apps;
// Try to find relevant and existing GAppInfo in all installed application
// We do this by comparing each GAppInfo's executable with out own
while (apps_p) {
app_info_from_list = (GAppInfo*) apps_p->data;
if (!app_info) {
// If the executable is not absolute, get it's full path
char *executable = g_find_program_in_path(g_app_info_get_executable(app_info_from_list));
- if (executable && strcmp(executable, PromiseFlatCString(cmd).get()) == 0) {
+ if (executable && strcmp(executable, PromiseFlatCString(aCmd).get()) == 0) {
g_object_ref (app_info_from_list);
app_info = app_info_from_list;
}
g_free(executable);
}
g_object_unref(app_info_from_list);
apps_p = apps_p->next;
}
g_list_free(apps);
-
- if (!app_info) {
- app_info = g_app_info_create_from_commandline(PromiseFlatCString(cmd).get(),
- PromiseFlatCString(appName).get(),
- G_APP_INFO_CREATE_SUPPORTS_URIS,
- &error);
+ if (app_info) {
+ nsGIOMimeApp* app = new nsGIOMimeApp(app_info);
+ NS_ENSURE_TRUE(app, NS_ERROR_OUT_OF_MEMORY);
+ NS_ADDREF(*aAppInfo = app);
+ return NS_OK;
}
+ *aAppInfo = nullptr;
+ return NS_ERROR_NOT_AVAILABLE;
+}
+
+/**
+ * Create application info for specified command and application name.
+ * Command arguments are ignored and the "%u" is always added.
+ * @param cmd command to execute
+ * @param appName application name
+ * @param appInfo location where created GAppInfo is stored
+ * @return NS_OK when object is created, NS_ERROR_FILE_NOT_FOUND when executable
+ * is not found in the system path or NS_ERROR_FAILURE otherwise.
+ */
+NS_IMETHODIMP
+nsGIOService::CreateAppFromCommand(nsACString const& cmd,
+ nsACString const& appName,
+ nsIGIOMimeApp** appInfo)
+{
+ GError *error = nullptr;
+ *appInfo = nullptr;
+
+ // Using G_APP_INFO_CREATE_SUPPORTS_URIS calling g_app_info_create_from_commandline
+ // appends %u to the cmd even when cmd already contains this parameter.
+ // To avoid that we're going to remove arguments before passing to it.
+ nsAutoCString commandWithoutArgs;
+ nsresult rv = GetCommandFromCommandline(cmd,
+ commandWithoutArgs);
+ NS_ENSURE_SUCCESS(rv, rv);
+ GAppInfo *app_info = g_app_info_create_from_commandline(
+ commandWithoutArgs.BeginReading(),
+ PromiseFlatCString(appName).get(),
+ G_APP_INFO_CREATE_SUPPORTS_URIS,
+ &error);
if (!app_info) {
g_warning("Cannot create application info from command: %s", error->message);
g_error_free(error);
return NS_ERROR_FAILURE;
}
+
+ // Check if executable exist in path
+ gchar* executableWithFullPath =
+ g_find_program_in_path(commandWithoutArgs.BeginReading());
+ if (!executableWithFullPath) {
+ return NS_ERROR_FILE_NOT_FOUND;
+ }
+ g_free(executableWithFullPath);
+
nsGIOMimeApp *mozApp = new nsGIOMimeApp(app_info);
NS_ENSURE_TRUE(mozApp, NS_ERROR_OUT_OF_MEMORY);
NS_ADDREF(*appInfo = mozApp);
return NS_OK;
}
--- a/uriloader/exthandler/nsHandlerService-json.js
+++ b/uriloader/exthandler/nsHandlerService-json.js
@@ -426,16 +426,21 @@ HandlerService.prototype = {
} else if (handler instanceof Ci.nsIDBusHandlerApp) {
return {
name: handler.name,
service: handler.service,
method: handler.method,
objectPath: handler.objectPath,
dBusInterface: handler.dBusInterface,
};
+ } else if (handler instanceof Ci.nsIGIOMimeApp) {
+ return {
+ name: handler.name,
+ command: handler.command,
+ };
}
// If the handler is an unknown handler type, return null.
// Android default application handler is the case.
return null;
},
/**
* @param handlerObj
@@ -462,16 +467,25 @@ HandlerService.prototype = {
handlerApp.uriTemplate = handlerObj.uriTemplate;
} else if ("service" in handlerObj) {
handlerApp = Cc["@mozilla.org/uriloader/dbus-handler-app;1"]
.createInstance(Ci.nsIDBusHandlerApp);
handlerApp.service = handlerObj.service;
handlerApp.method = handlerObj.method;
handlerApp.objectPath = handlerObj.objectPath;
handlerApp.dBusInterface = handlerObj.dBusInterface;
+ } else if ("command" in handlerObj &&
+ "@mozilla.org/gio-service;1" in Cc) {
+ try {
+ handlerApp = Cc["@mozilla.org/gio-service;1"]
+ .getService(Ci.nsIGIOService)
+ .createAppFromCommand(handlerObj.command, handlerObj.name);
+ } catch (ex) {
+ return null;
+ }
} else {
return null;
}
handlerApp.name = handlerObj.name;
return handlerApp;
},
--- a/uriloader/exthandler/tests/unit/test_handlerService_json.js
+++ b/uriloader/exthandler/tests/unit/test_handlerService_json.js
@@ -131,8 +131,65 @@ add_task(async function test_migration_r
// Repeat the migration with the JSON file present.
await unloadHandlerStore();
await unloadHandlerStoreRDF();
Services.prefs.setBoolPref("gecko.handlerService.migrated", false);
await assertAllHandlerInfosMatchDefaultHandlers();
do_check_true(Services.prefs.getBoolPref("gecko.handlerService.migrated"));
});
+
+/**
+ * Test saving and reloading an instance of nsIGIOMimeApp.
+ */
+add_task(async function test_store_gioHandlerApp() {
+ if (!("@mozilla.org/gio-service;1" in Cc)) {
+ do_print("Skipping test because it does not apply to this platform.");
+ return;
+ }
+
+ // Create dummy exec file that following won't fail because file not found error
+ let dummyHandlerFile = FileUtils.getFile("TmpD", ["dummyHandler"]);
+ dummyHandlerFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt("777", 8));
+
+ // Set up an nsIGIOMimeApp instance for testing.
+ let handlerApp = Cc["@mozilla.org/gio-service;1"]
+ .getService(Ci.nsIGIOService)
+ .createAppFromCommand(dummyHandlerFile.path, "Dummy GIO handler");
+ let expectedGIOMimeHandlerApp = {
+ name: handlerApp.name,
+ command: handlerApp.command,
+ };
+
+ await deleteHandlerStore();
+
+ let handlerInfo = getKnownHandlerInfo("example/new");
+ handlerInfo.preferredApplicationHandler = handlerApp;
+ handlerInfo.possibleApplicationHandlers.appendElement(handlerApp);
+ handlerInfo.possibleApplicationHandlers.appendElement(webHandlerApp);
+ gHandlerService.store(handlerInfo);
+
+ await unloadHandlerStore();
+
+ let actualHandlerInfo = HandlerServiceTestUtils.getHandlerInfo("example/new");
+ HandlerServiceTestUtils.assertHandlerInfoMatches(actualHandlerInfo, {
+ type: "example/new",
+ preferredAction: Ci.nsIHandlerInfo.saveToDisk,
+ alwaysAskBeforeHandling: false,
+ preferredApplicationHandler: expectedGIOMimeHandlerApp,
+ possibleApplicationHandlers: [expectedGIOMimeHandlerApp, webHandlerApp],
+ });
+
+ await OS.File.remove(dummyHandlerFile.path);
+
+ // After removing dummyHandlerFile, the handler should disappear from the
+ // list of possibleApplicationHandlers and preferredAppHandler should be null.
+ actualHandlerInfo = HandlerServiceTestUtils.getHandlerInfo("example/new");
+ HandlerServiceTestUtils.assertHandlerInfoMatches(actualHandlerInfo, {
+ type: "example/new",
+ preferredAction: Ci.nsIHandlerInfo.saveToDisk,
+ alwaysAskBeforeHandling: false,
+ preferredApplicationHandler: null,
+ possibleApplicationHandlers: [webHandlerApp],
+ });
+
+});
+
--- a/uriloader/exthandler/unix/nsGNOMERegistry.cpp
+++ b/uriloader/exthandler/unix/nsGNOMERegistry.cpp
@@ -39,24 +39,21 @@ nsGNOMERegistry::LoadURL(nsIURI *aURL)
/* static */ void
nsGNOMERegistry::GetAppDescForScheme(const nsACString& aScheme,
nsAString& aDesc)
{
nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
if (!giovfs)
return;
- nsAutoCString name;
nsCOMPtr<nsIGIOMimeApp> app;
if (NS_FAILED(giovfs->GetAppForURIScheme(aScheme, getter_AddRefs(app))))
return;
- app->GetName(name);
-
- CopyUTF8toUTF16(name, aDesc);
+ app->GetName(aDesc);
}
/* static */ already_AddRefed<nsMIMEInfoBase>
nsGNOMERegistry::GetFromExtension(const nsACString& aFileExt)
{
nsAutoCString mimeType;
nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
@@ -80,30 +77,30 @@ nsGNOMERegistry::GetFromExtension(const
}
/* static */ already_AddRefed<nsMIMEInfoBase>
nsGNOMERegistry::GetFromType(const nsACString& aMIMEType)
{
RefPtr<nsMIMEInfoUnix> mimeInfo = new nsMIMEInfoUnix(aMIMEType);
NS_ENSURE_TRUE(mimeInfo, nullptr);
- nsAutoCString name;
+ nsAutoString name;
nsAutoCString description;
nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
if (!giovfs) {
return nullptr;
}
nsCOMPtr<nsIGIOMimeApp> gioHandlerApp;
if (NS_FAILED(giovfs->GetAppForMimeType(aMIMEType, getter_AddRefs(gioHandlerApp))) ||
!gioHandlerApp) {
return nullptr;
}
gioHandlerApp->GetName(name);
giovfs->GetDescriptionForMimeType(aMIMEType, description);
- mimeInfo->SetDefaultDescription(NS_ConvertUTF8toUTF16(name));
+ mimeInfo->SetDefaultDescription(name);
mimeInfo->SetPreferredAction(nsIMIMEInfo::useSystemDefault);
mimeInfo->SetDescription(NS_ConvertUTF8toUTF16(description));
return mimeInfo.forget();
}
--- a/xpcom/system/nsIGIOService.idl
+++ b/xpcom/system/nsIGIOService.idl
@@ -1,31 +1,32 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
+#include "nsIMIMEInfo.idl"
interface nsIUTF8StringEnumerator;
interface nsIURI;
+interface nsIMutableArray;
/* nsIGIOMimeApp holds information about an application that is looked up
with nsIGIOService::GetAppForMimeType. */
// 66009894-9877-405b-9321-bf30420e34e6 prev uuid
-[scriptable, uuid(ca6bad0c-8a48-48ac-82c7-27bb8f510fbe)]
-interface nsIGIOMimeApp : nsISupports
+[scriptable, uuid(ca6bad0c-8a48-48ac-82c7-27bb8f510fbe)]
+interface nsIGIOMimeApp : nsIHandlerApp
{
const long EXPECTS_URIS = 0;
const long EXPECTS_PATHS = 1;
const long EXPECTS_URIS_FOR_NON_FILES = 2;
readonly attribute AUTF8String id;
- readonly attribute AUTF8String name;
readonly attribute AUTF8String command;
readonly attribute long expectsURIs; // see constants above
readonly attribute nsIUTF8StringEnumerator supportedURISchemes;
void launch(in AUTF8String uri);
void setAsDefaultForMimeType(in AUTF8String mimeType);
void setAsDefaultForFileExtensions(in AUTF8String extensions);
void setAsDefaultForURIScheme(in AUTF8String uriScheme);
@@ -52,23 +53,29 @@ interface nsIGIOService : nsISupports
/* Obtain the MIME type registered for an extension. The extension
should not include a leading dot. */
AUTF8String getMimeTypeFromExtension(in AUTF8String extension);
/* Obtain the preferred application for opening a given URI scheme */
nsIGIOMimeApp getAppForURIScheme(in AUTF8String aURIScheme);
+ /* Obtain list of application capable of opening given URI scheme */
+ nsIMutableArray getAppsForURIScheme(in AUTF8String aURIScheme);
+
/* Obtain the preferred application for opening a given MIME type */
nsIGIOMimeApp getAppForMimeType(in AUTF8String mimeType);
- /* Obtain the preferred application for opening a given MIME type */
- nsIGIOMimeApp createAppFromCommand(in AUTF8String cmd,
+ /* Create application info for given command and name */
+ nsIGIOMimeApp createAppFromCommand(in AUTF8String cmd,
in AUTF8String appName);
+ /* Find the application info by given command */
+ nsIGIOMimeApp findAppFromCommand(in AUTF8String cmd);
+
/* Obtain a description for the given MIME type */
AUTF8String getDescriptionForMimeType(in AUTF8String mimeType);
/*** Misc. methods ***/
/* Open the given URI in the default application */
void showURI(in nsIURI uri);
[noscript] void showURIForInput(in ACString uri);