toolkit/system/gnome/nsGIOService.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/system/gnome/nsGIOService.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,494 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#include "nsGIOService.h"
    1.10 +#include "nsStringAPI.h"
    1.11 +#include "nsIURI.h"
    1.12 +#include "nsTArray.h"
    1.13 +#include "nsIStringEnumerator.h"
    1.14 +#include "nsAutoPtr.h"
    1.15 +
    1.16 +#include <gio/gio.h>
    1.17 +#include <gtk/gtk.h>
    1.18 +#ifdef MOZ_ENABLE_DBUS
    1.19 +#include <dbus/dbus-glib.h>
    1.20 +#include <dbus/dbus-glib-lowlevel.h>
    1.21 +#endif
    1.22 +
    1.23 +
    1.24 +char *
    1.25 +get_content_type_from_mime_type(const char *mimeType)
    1.26 +{
    1.27 +  GList* contentTypes = g_content_types_get_registered();
    1.28 +  GList* ct_ptr = contentTypes;
    1.29 +  char* foundContentType = nullptr;
    1.30 +
    1.31 +  while (ct_ptr) {
    1.32 +    char *mimeTypeFromContentType =  g_content_type_get_mime_type((char*)ct_ptr->data);
    1.33 +    if (strcmp(mimeTypeFromContentType, mimeType) == 0) {
    1.34 +      foundContentType = g_strdup((char*)ct_ptr->data);
    1.35 +      g_free(mimeTypeFromContentType);
    1.36 +      break;
    1.37 +    }
    1.38 +    g_free(mimeTypeFromContentType);
    1.39 +    ct_ptr = ct_ptr->next;
    1.40 +  }
    1.41 +  g_list_foreach(contentTypes, (GFunc) g_free, nullptr);
    1.42 +  g_list_free(contentTypes);
    1.43 +  return foundContentType;
    1.44 +}
    1.45 +
    1.46 +class nsGIOMimeApp MOZ_FINAL : public nsIGIOMimeApp
    1.47 +{
    1.48 +public:
    1.49 +  NS_DECL_ISUPPORTS
    1.50 +  NS_DECL_NSIGIOMIMEAPP
    1.51 +
    1.52 +  nsGIOMimeApp(GAppInfo* aApp) : mApp(aApp) {}
    1.53 +  ~nsGIOMimeApp() { g_object_unref(mApp); }
    1.54 +
    1.55 +private:
    1.56 +  GAppInfo *mApp;
    1.57 +};
    1.58 +
    1.59 +NS_IMPL_ISUPPORTS(nsGIOMimeApp, nsIGIOMimeApp)
    1.60 +
    1.61 +NS_IMETHODIMP
    1.62 +nsGIOMimeApp::GetId(nsACString& aId)
    1.63 +{
    1.64 +  aId.Assign(g_app_info_get_id(mApp));
    1.65 +  return NS_OK;
    1.66 +}
    1.67 +
    1.68 +NS_IMETHODIMP
    1.69 +nsGIOMimeApp::GetName(nsACString& aName)
    1.70 +{
    1.71 +  aName.Assign(g_app_info_get_name(mApp));
    1.72 +  return NS_OK;
    1.73 +}
    1.74 +
    1.75 +NS_IMETHODIMP
    1.76 +nsGIOMimeApp::GetCommand(nsACString& aCommand)
    1.77 +{
    1.78 +  const char *cmd = g_app_info_get_commandline(mApp);
    1.79 +  if (!cmd)
    1.80 +    return NS_ERROR_FAILURE;
    1.81 +  aCommand.Assign(cmd);
    1.82 +  return NS_OK;
    1.83 +}
    1.84 +
    1.85 +NS_IMETHODIMP
    1.86 +nsGIOMimeApp::GetExpectsURIs(int32_t* aExpects)
    1.87 +{
    1.88 +  *aExpects = g_app_info_supports_uris(mApp);
    1.89 +  return NS_OK;
    1.90 +}
    1.91 +
    1.92 +NS_IMETHODIMP
    1.93 +nsGIOMimeApp::Launch(const nsACString& aUri)
    1.94 +{
    1.95 +  GList uris = { 0 };
    1.96 +  PromiseFlatCString flatUri(aUri);
    1.97 +  uris.data = const_cast<char*>(flatUri.get());
    1.98 +
    1.99 +  GError *error = nullptr;
   1.100 +  gboolean result = g_app_info_launch_uris(mApp, &uris, nullptr, &error);
   1.101 +
   1.102 +  if (!result) {
   1.103 +    g_warning("Cannot launch application: %s", error->message);
   1.104 +    g_error_free(error);
   1.105 +    return NS_ERROR_FAILURE;
   1.106 +  }
   1.107 +
   1.108 +  return NS_OK;
   1.109 +}
   1.110 +
   1.111 +class GIOUTF8StringEnumerator MOZ_FINAL : public nsIUTF8StringEnumerator
   1.112 +{
   1.113 +public:
   1.114 +  GIOUTF8StringEnumerator() : mIndex(0) { }
   1.115 +  ~GIOUTF8StringEnumerator() { }
   1.116 +
   1.117 +  NS_DECL_ISUPPORTS
   1.118 +  NS_DECL_NSIUTF8STRINGENUMERATOR
   1.119 +
   1.120 +  nsTArray<nsCString> mStrings;
   1.121 +  uint32_t            mIndex;
   1.122 +};
   1.123 +
   1.124 +NS_IMPL_ISUPPORTS(GIOUTF8StringEnumerator, nsIUTF8StringEnumerator)
   1.125 +
   1.126 +NS_IMETHODIMP
   1.127 +GIOUTF8StringEnumerator::HasMore(bool* aResult)
   1.128 +{
   1.129 +  *aResult = mIndex < mStrings.Length();
   1.130 +  return NS_OK;
   1.131 +}
   1.132 +
   1.133 +NS_IMETHODIMP
   1.134 +GIOUTF8StringEnumerator::GetNext(nsACString& aResult)
   1.135 +{
   1.136 +  if (mIndex >= mStrings.Length())
   1.137 +    return NS_ERROR_UNEXPECTED;
   1.138 +
   1.139 +  aResult.Assign(mStrings[mIndex]);
   1.140 +  ++mIndex;
   1.141 +  return NS_OK;
   1.142 +}
   1.143 +
   1.144 +NS_IMETHODIMP
   1.145 +nsGIOMimeApp::GetSupportedURISchemes(nsIUTF8StringEnumerator** aSchemes)
   1.146 +{
   1.147 +  *aSchemes = nullptr;
   1.148 +
   1.149 +  nsRefPtr<GIOUTF8StringEnumerator> array = new GIOUTF8StringEnumerator();
   1.150 +  NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY);
   1.151 +
   1.152 +  GVfs *gvfs = g_vfs_get_default();
   1.153 +
   1.154 +  if (!gvfs) {
   1.155 +    g_warning("Cannot get GVfs object.");
   1.156 +    return NS_ERROR_OUT_OF_MEMORY;
   1.157 +  }
   1.158 +
   1.159 +  const gchar* const * uri_schemes = g_vfs_get_supported_uri_schemes(gvfs);
   1.160 +
   1.161 +  while (*uri_schemes != nullptr) {
   1.162 +    if (!array->mStrings.AppendElement(*uri_schemes)) {
   1.163 +      return NS_ERROR_OUT_OF_MEMORY;
   1.164 +    }
   1.165 +    uri_schemes++;
   1.166 +  }
   1.167 +
   1.168 +  NS_ADDREF(*aSchemes = array);
   1.169 +  return NS_OK;
   1.170 +}
   1.171 +
   1.172 +NS_IMETHODIMP
   1.173 +nsGIOMimeApp::SetAsDefaultForMimeType(nsACString const& aMimeType)
   1.174 +{
   1.175 +  char *content_type =
   1.176 +    get_content_type_from_mime_type(PromiseFlatCString(aMimeType).get());
   1.177 +  if (!content_type)
   1.178 +    return NS_ERROR_FAILURE;
   1.179 +  GError *error = nullptr;
   1.180 +  g_app_info_set_as_default_for_type(mApp,
   1.181 +                                     content_type,
   1.182 +                                     &error);
   1.183 +  if (error) {
   1.184 +    g_warning("Cannot set application as default for MIME type (%s): %s",
   1.185 +              PromiseFlatCString(aMimeType).get(),
   1.186 +              error->message);
   1.187 +    g_error_free(error);
   1.188 +    g_free(content_type);
   1.189 +    return NS_ERROR_FAILURE;
   1.190 +  }
   1.191 +
   1.192 +  g_free(content_type);
   1.193 +  return NS_OK;
   1.194 +}
   1.195 +/**
   1.196 + * Set default application for files with given extensions
   1.197 + * @param fileExts string of space separated extensions
   1.198 + * @return NS_OK when application was set as default for given extensions,
   1.199 + * NS_ERROR_FAILURE otherwise
   1.200 + */
   1.201 +NS_IMETHODIMP
   1.202 +nsGIOMimeApp::SetAsDefaultForFileExtensions(nsACString const& fileExts)
   1.203 +{
   1.204 +  GError *error = nullptr;
   1.205 +  char *extensions = g_strdup(PromiseFlatCString(fileExts).get());
   1.206 +  char *ext_pos = extensions;
   1.207 +  char *space_pos;
   1.208 +
   1.209 +  while ( (space_pos = strchr(ext_pos, ' ')) || (*ext_pos != '\0') ) {
   1.210 +    if (space_pos) {
   1.211 +      *space_pos = '\0';
   1.212 +    }
   1.213 +    g_app_info_set_as_default_for_extension(mApp, ext_pos, &error);
   1.214 +    if (error) {
   1.215 +      g_warning("Cannot set application as default for extension (%s): %s",
   1.216 +                ext_pos,
   1.217 +                error->message);
   1.218 +      g_error_free(error);
   1.219 +      g_free(extensions);
   1.220 +      return NS_ERROR_FAILURE;
   1.221 +    }
   1.222 +    if (space_pos) {
   1.223 +      ext_pos = space_pos + 1;
   1.224 +    } else {
   1.225 +      *ext_pos = '\0';
   1.226 +    }
   1.227 +  }
   1.228 +  g_free(extensions);
   1.229 +  return NS_OK;
   1.230 +}
   1.231 +
   1.232 +/**
   1.233 + * Set default application for URI's of a particular scheme
   1.234 + * @param aURIScheme string containing the URI scheme
   1.235 + * @return NS_OK when application was set as default for URI scheme,
   1.236 + * NS_ERROR_FAILURE otherwise
   1.237 + */
   1.238 +NS_IMETHODIMP
   1.239 +nsGIOMimeApp::SetAsDefaultForURIScheme(nsACString const& aURIScheme)
   1.240 +{
   1.241 +  GError *error = nullptr;
   1.242 +  nsAutoCString contentType("x-scheme-handler/");
   1.243 +  contentType.Append(aURIScheme);
   1.244 +
   1.245 +  g_app_info_set_as_default_for_type(mApp,
   1.246 +                                     contentType.get(),
   1.247 +                                     &error);
   1.248 +  if (error) {
   1.249 +    g_warning("Cannot set application as default for URI scheme (%s): %s",
   1.250 +              PromiseFlatCString(aURIScheme).get(),
   1.251 +              error->message);
   1.252 +    g_error_free(error);
   1.253 +    return NS_ERROR_FAILURE;
   1.254 +  }
   1.255 +
   1.256 +  return NS_OK;
   1.257 +}
   1.258 +
   1.259 +NS_IMPL_ISUPPORTS(nsGIOService, nsIGIOService)
   1.260 +
   1.261 +NS_IMETHODIMP
   1.262 +nsGIOService::GetMimeTypeFromExtension(const nsACString& aExtension,
   1.263 +                                             nsACString& aMimeType)
   1.264 +{
   1.265 +  nsAutoCString fileExtToUse("file.");
   1.266 +  fileExtToUse.Append(aExtension);
   1.267 +
   1.268 +  gboolean result_uncertain;
   1.269 +  char *content_type = g_content_type_guess(fileExtToUse.get(),
   1.270 +                                            nullptr,
   1.271 +                                            0,
   1.272 +                                            &result_uncertain);
   1.273 +  if (!content_type)
   1.274 +    return NS_ERROR_FAILURE;
   1.275 +
   1.276 +  char *mime_type = g_content_type_get_mime_type(content_type);
   1.277 +  if (!mime_type) {
   1.278 +    g_free(content_type);
   1.279 +    return NS_ERROR_FAILURE;
   1.280 +  }
   1.281 +
   1.282 +  aMimeType.Assign(mime_type);
   1.283 +
   1.284 +  g_free(mime_type);
   1.285 +  g_free(content_type);
   1.286 +
   1.287 +  return NS_OK;
   1.288 +}
   1.289 +// used in nsGNOMERegistry
   1.290 +// -----------------------------------------------------------------------------
   1.291 +NS_IMETHODIMP
   1.292 +nsGIOService::GetAppForURIScheme(const nsACString& aURIScheme,
   1.293 +                                 nsIGIOMimeApp** aApp)
   1.294 +{
   1.295 +  *aApp = nullptr;
   1.296 +
   1.297 +  GAppInfo *app_info = g_app_info_get_default_for_uri_scheme(
   1.298 +                          PromiseFlatCString(aURIScheme).get());
   1.299 +  if (app_info) {
   1.300 +    nsGIOMimeApp *mozApp = new nsGIOMimeApp(app_info);
   1.301 +    NS_ADDREF(*aApp = mozApp);
   1.302 +  } else {
   1.303 +    return NS_ERROR_FAILURE;
   1.304 +  }
   1.305 +  return NS_OK;
   1.306 +}
   1.307 +
   1.308 +NS_IMETHODIMP
   1.309 +nsGIOService::GetAppForMimeType(const nsACString& aMimeType,
   1.310 +                                nsIGIOMimeApp**   aApp)
   1.311 +{
   1.312 +  *aApp = nullptr;
   1.313 +  char *content_type =
   1.314 +    get_content_type_from_mime_type(PromiseFlatCString(aMimeType).get());
   1.315 +  if (!content_type)
   1.316 +    return NS_ERROR_FAILURE;
   1.317 +
   1.318 +  GAppInfo *app_info = g_app_info_get_default_for_type(content_type, false);
   1.319 +  if (app_info) {
   1.320 +    nsGIOMimeApp *mozApp = new nsGIOMimeApp(app_info);
   1.321 +    NS_ENSURE_TRUE(mozApp, NS_ERROR_OUT_OF_MEMORY);
   1.322 +    NS_ADDREF(*aApp = mozApp);
   1.323 +  } else {
   1.324 +    g_free(content_type);
   1.325 +    return NS_ERROR_FAILURE;
   1.326 +  }
   1.327 +  g_free(content_type);
   1.328 +  return NS_OK;
   1.329 +}
   1.330 +
   1.331 +NS_IMETHODIMP
   1.332 +nsGIOService::GetDescriptionForMimeType(const nsACString& aMimeType,
   1.333 +                                              nsACString& aDescription)
   1.334 +{
   1.335 +  char *content_type =
   1.336 +    get_content_type_from_mime_type(PromiseFlatCString(aMimeType).get());
   1.337 +  if (!content_type)
   1.338 +    return NS_ERROR_FAILURE;
   1.339 +
   1.340 +  char *desc = g_content_type_get_description(content_type);
   1.341 +  if (!desc) {
   1.342 +    g_free(content_type);
   1.343 +    return NS_ERROR_FAILURE;
   1.344 +  }
   1.345 +
   1.346 +  aDescription.Assign(desc);
   1.347 +  g_free(content_type);
   1.348 +  g_free(desc);
   1.349 +  return NS_OK;
   1.350 +}
   1.351 +
   1.352 +NS_IMETHODIMP
   1.353 +nsGIOService::ShowURI(nsIURI* aURI)
   1.354 +{
   1.355 +  nsAutoCString spec;
   1.356 +  aURI->GetSpec(spec);
   1.357 +  GError *error = nullptr;
   1.358 +  if (!g_app_info_launch_default_for_uri(spec.get(), nullptr, &error)) {
   1.359 +    g_warning("Could not launch default application for URI: %s", error->message);
   1.360 +    g_error_free(error);
   1.361 +    return NS_ERROR_FAILURE;
   1.362 +  }
   1.363 +  return NS_OK;
   1.364 +}
   1.365 +
   1.366 +NS_IMETHODIMP
   1.367 +nsGIOService::ShowURIForInput(const nsACString& aUri)
   1.368 +{
   1.369 +  GFile *file = g_file_new_for_commandline_arg(PromiseFlatCString(aUri).get());
   1.370 +  char* spec = g_file_get_uri(file);
   1.371 +  nsresult rv = NS_ERROR_FAILURE;
   1.372 +  GError *error = nullptr;
   1.373 +
   1.374 +  g_app_info_launch_default_for_uri(spec, nullptr, &error);
   1.375 +  if (error) {
   1.376 +    g_warning("Cannot launch default application: %s", error->message);
   1.377 +    g_error_free(error);
   1.378 +  } else {
   1.379 +    rv = NS_OK;
   1.380 +  }
   1.381 +  g_object_unref(file);
   1.382 +  g_free(spec);
   1.383 +
   1.384 +  return rv;
   1.385 +}
   1.386 +
   1.387 +NS_IMETHODIMP
   1.388 +nsGIOService::OrgFreedesktopFileManager1ShowItems(const nsACString& aPath)
   1.389 +{
   1.390 +#ifndef MOZ_ENABLE_DBUS
   1.391 +  return NS_ERROR_FAILURE;
   1.392 +#else
   1.393 +  GError* error = nullptr;
   1.394 +  static bool org_freedesktop_FileManager1_exists = true;
   1.395 +
   1.396 +  if (!org_freedesktop_FileManager1_exists) {
   1.397 +    return NS_ERROR_NOT_AVAILABLE;
   1.398 +  }
   1.399 +
   1.400 +  DBusGConnection* dbusGConnection = dbus_g_bus_get(DBUS_BUS_SESSION, &error);
   1.401 +
   1.402 +  if (!dbusGConnection) {
   1.403 +    if (error) {
   1.404 +      g_printerr("Failed to open connection to session bus: %s\n", error->message);
   1.405 +      g_error_free(error);
   1.406 +    }
   1.407 +    return NS_ERROR_FAILURE;
   1.408 +  }
   1.409 +
   1.410 +  char *uri = g_filename_to_uri(PromiseFlatCString(aPath).get(), nullptr, nullptr);
   1.411 +  if (uri == nullptr) {
   1.412 +    return NS_ERROR_FAILURE;
   1.413 +  }
   1.414 +
   1.415 +  DBusConnection* dbusConnection = dbus_g_connection_get_connection(dbusGConnection);
   1.416 +  // Make sure we do not exit the entire program if DBus connection get lost.
   1.417 +  dbus_connection_set_exit_on_disconnect(dbusConnection, false);
   1.418 +
   1.419 +  DBusGProxy* dbusGProxy = dbus_g_proxy_new_for_name(dbusGConnection,
   1.420 +                                                     "org.freedesktop.FileManager1",
   1.421 +                                                     "/org/freedesktop/FileManager1",
   1.422 +                                                     "org.freedesktop.FileManager1");
   1.423 +
   1.424 +  const char *uris[2] = { uri, nullptr };
   1.425 +  gboolean rv_dbus_call = dbus_g_proxy_call (dbusGProxy, "ShowItems", nullptr, G_TYPE_STRV, uris,
   1.426 +                                             G_TYPE_STRING, "", G_TYPE_INVALID, G_TYPE_INVALID);
   1.427 +
   1.428 +  g_object_unref(dbusGProxy);
   1.429 +  dbus_g_connection_unref(dbusGConnection);
   1.430 +  g_free(uri);
   1.431 +
   1.432 +  if (!rv_dbus_call) {
   1.433 +    org_freedesktop_FileManager1_exists = false;
   1.434 +    return NS_ERROR_NOT_AVAILABLE;
   1.435 +  }
   1.436 +
   1.437 +  return NS_OK;
   1.438 +#endif
   1.439 +}
   1.440 +
   1.441 +/**
   1.442 + * Create or find already existing application info for specified command
   1.443 + * and application name.
   1.444 + * @param cmd command to execute
   1.445 + * @param appName application name
   1.446 + * @param appInfo location where created GAppInfo is stored
   1.447 + * @return NS_OK when object is created, NS_ERROR_FAILURE otherwise.
   1.448 + */
   1.449 +NS_IMETHODIMP
   1.450 +nsGIOService::CreateAppFromCommand(nsACString const& cmd,
   1.451 +                                   nsACString const& appName,
   1.452 +                                   nsIGIOMimeApp**   appInfo)
   1.453 +{
   1.454 +  GError *error = nullptr;
   1.455 +  *appInfo = nullptr;
   1.456 +
   1.457 +  GAppInfo *app_info = nullptr, *app_info_from_list = nullptr;
   1.458 +  GList *apps = g_app_info_get_all();
   1.459 +  GList *apps_p = apps;
   1.460 +
   1.461 +  // Try to find relevant and existing GAppInfo in all installed application
   1.462 +  // We do this by comparing each GAppInfo's executable with out own
   1.463 +  while (apps_p) {
   1.464 +    app_info_from_list = (GAppInfo*) apps_p->data;
   1.465 +    if (!app_info) {
   1.466 +      // If the executable is not absolute, get it's full path
   1.467 +      char *executable = g_find_program_in_path(g_app_info_get_executable(app_info_from_list));
   1.468 +
   1.469 +      if (executable && strcmp(executable, PromiseFlatCString(cmd).get()) == 0) {
   1.470 +        g_object_ref (app_info_from_list);
   1.471 +        app_info = app_info_from_list;
   1.472 +      }
   1.473 +      g_free(executable);
   1.474 +    }
   1.475 +
   1.476 +    g_object_unref(app_info_from_list);
   1.477 +    apps_p = apps_p->next;
   1.478 +  }
   1.479 +  g_list_free(apps);
   1.480 +
   1.481 +  if (!app_info) {
   1.482 +    app_info = g_app_info_create_from_commandline(PromiseFlatCString(cmd).get(),
   1.483 +                                                  PromiseFlatCString(appName).get(),
   1.484 +                                                  G_APP_INFO_CREATE_SUPPORTS_URIS,
   1.485 +                                                  &error);
   1.486 +  }
   1.487 +
   1.488 +  if (!app_info) {
   1.489 +    g_warning("Cannot create application info from command: %s", error->message);
   1.490 +    g_error_free(error);
   1.491 +    return NS_ERROR_FAILURE;
   1.492 +  }
   1.493 +  nsGIOMimeApp *mozApp = new nsGIOMimeApp(app_info);
   1.494 +  NS_ENSURE_TRUE(mozApp, NS_ERROR_OUT_OF_MEMORY);
   1.495 +  NS_ADDREF(*appInfo = mozApp);
   1.496 +  return NS_OK;
   1.497 +}

mercurial