Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/browser/components/shell/   (Firefox Browser Version 153.0.1©)  Datei vom 27.6.2026 mit Größe 27 kB image not shown  

Quelle  nsGNOMEShellService.cpp

  Sprache: C
 

/* 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 "mozilla/Preferences.h"
#include "mozilla/widget/GSettings.h"
#include "nsAppRunner.h"
#include "nsCOMPtr.h"
#include "nsGNOMEShellService.h"
#include "nsShellService.h"
#include "nsIFile.h"
#include "nsIProperties.h"
#include "nsDirectoryServiceDefs.h"
#include "prenv.h"
#include "nsString.h"
#include "nsIGIOService.h"
#include "nsIStringBundle.h"
#include "nsServiceManagerUtils.h"
#include "nsIImageLoadingContent.h"
#include "nsIINIParser.h"
#include "imgIRequest.h"
#include "imgIContainer.h"
#include "mozilla/Components.h"
#include "mozilla/GRefPtr.h"
#include "mozilla/GUniquePtr.h"
#include "mozilla/WidgetUtilsGtk.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Promise.h"
#include "nsImageToPixbuf.h"
#include "nsXULAppAPI.h"

#ifdef MOZ_ENABLE_DBUS
#  include "nsWindow.h"
#  include "WidgetUtils.h"
#  include "mozilla/widget/AsyncDBus.h"
#endif

#include <glib.h>
#include <gio/gio.h>
#include <gdk/gdk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <stdlib.h>

using namespace mozilla;

struct ProtocolAssociation {
  const char* name;
  bool essential;
};

struct MimeTypeAssociation {
  const char* mimeType;
  const char* extensions;
};

static const ProtocolAssociation appProtocols[] = {
    // clang-format off
  { "http",   true     },
  { "https",  true     },
  { "chrome"false }
    // clang-format on
};

static const MimeTypeAssociation appTypes[] = {
    // clang-format off
  { "text/html",             "htm html shtml" },
  { "application/xhtml+xml""xhtml xht"      }
    // clang-format on
};

#define kDesktopBGSchema "org.gnome.desktop.background"_ns
#define kDesktopColorGSKey "primary-color"_ns

nsresult nsGNOMEShellService::Init() {
  nsresult rv;

#ifdef MOZ_ENABLE_DBUS
  if (widget::IsGnomeDesktopEnvironment() &&
      Preferences::GetBool("browser.gnome-search-provider.enabled"false)) {
    mSearchProvider.Startup();
  }
#endif

  // Check G_BROKEN_FILENAMES.  If it's set, then filenames in glib use
  // the locale encoding.  If it's not set, they use UTF-8.
  mUseLocaleFilenames = PR_GetEnv("G_BROKEN_FILENAMES") != nullptr;

  if (GetAppPathFromLauncher()) return NS_OK;

  nsCOMPtr<nsIProperties> dirSvc(
      do_GetService("@mozilla.org/file/directory_service;1"));
  NS_ENSURE_TRUE(dirSvc, NS_ERROR_NOT_AVAILABLE);

  nsCOMPtr<nsIFile> appPath;
  rv = dirSvc->Get(XRE_EXECUTABLE_FILE, NS_GET_IID(nsIFile),
                   getter_AddRefs(appPath));
  NS_ENSURE_SUCCESS(rv, rv);

  return appPath->GetNativePath(mAppPath);
}

NS_IMPL_ISUPPORTS(nsGNOMEShellService, nsIGNOMEShellService, nsIShellService,
                  nsIToolkitShellService)

bool nsGNOMEShellService::GetAppPathFromLauncher() {
  gchar* tmp;

  const char* launcher = PR_GetEnv("MOZ_APP_LAUNCHER");
  if (!launcher) return false;

  if (g_path_is_absolute(launcher)) {
    mAppPath = launcher;
    tmp = g_path_get_basename(launcher);
    gchar* fullpath = g_find_program_in_path(tmp);
    if (fullpath && mAppPath.Equals(fullpath)) mAppIsInPath = true;
    g_free(fullpath);
  } else {
    tmp = g_find_program_in_path(launcher);
    if (!tmp) return false;
    mAppPath = tmp;
    mAppIsInPath = true;
  }

  g_free(tmp);
  return true;
}

bool nsGNOMEShellService::KeyMatchesAppName(const char* aKeyValue) const {
  gchar* commandPath;
  if (mUseLocaleFilenames) {
    gchar* nativePath =
        g_filename_from_utf8(aKeyValue, -1, nullptr, nullptr, nullptr);
    if (!nativePath) {
      NS_ERROR("Error converting path to filesystem encoding");
      return false;
    }

    commandPath = g_find_program_in_path(nativePath);
    g_free(nativePath);
  } else {
    commandPath = g_find_program_in_path(aKeyValue);
  }

  if (!commandPath) return false;

  bool matches = mAppPath.Equals(commandPath);
  g_free(commandPath);
  return matches;
}

bool nsGNOMEShellService::CheckHandlerMatchesAppName(
    const nsACString& handler) const {
  gint argc;
  gchar** argv;
  nsAutoCString command(handler);

  // The string will be something of the form: [/path/to/]browser "%s"
  // We want to remove all of the parameters and get just the binary name.

  if (g_shell_parse_argv(command.get(), &argc, &argv, nullptr) && argc > 0) {
    command.Assign(argv[0]);
    g_strfreev(argv);
  }

  if (!KeyMatchesAppName(command.get()))
    return false;  // the handler is set to another app

  return true;
}

NS_IMETHODIMP
nsGNOMEShellService::IsDefaultBrowser(bool aForAllTypes,
                                      bool* aIsDefaultBrowser) {
  *aIsDefaultBrowser = false;

  if (widget::IsRunningUnderSnap()) {
    const gchar* argv[] = {"xdg-settings""check""default-web-browser",
                           (MOZ_APP_NAME ".desktop"), nullptr};
    GSpawnFlags flags = static_cast<GSpawnFlags>(G_SPAWN_SEARCH_PATH |
                                                 G_SPAWN_STDERR_TO_DEV_NULL);
    gchar* output = nullptr;
    gint exit_status = 0;
    if (!g_spawn_sync(nullptr, (gchar**)argv, nullptr, flags, nullptr, nullptr,
                      &output, nullptr, &exit_status, nullptr)) {
      return NS_OK;
    }
    if (exit_status != 0) {
      g_free(output);
      return NS_OK;
    }
    if (strcmp(output, "yes\n") == 0) {
      *aIsDefaultBrowser = true;
    }
    g_free(output);
    return NS_OK;
  }

  nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
  nsAutoCString handler;
  nsCOMPtr<nsIGIOMimeApp> gioApp;

  for (auto appProtocol : appProtocols) {
    if (!appProtocol.essential) continue;

    if (!IsDefaultForSchemeHelper(nsDependentCString(appProtocol.name),
                                  giovfs)) {
      return NS_OK;
    }
  }

  *aIsDefaultBrowser = true;

  return NS_OK;
}

bool nsGNOMEShellService::IsDefaultForSchemeHelper(
    const nsACString& aScheme, nsIGIOService* giovfs) const {
  nsCOMPtr<nsIGIOService> gioService;
  if (!giovfs) {
    gioService = do_GetService(NS_GIOSERVICE_CONTRACTID);
    giovfs = gioService.get();
  }

  if (!giovfs) {
    return false;
  }

  nsCOMPtr<nsIGIOMimeApp> gioApp;
  nsCOMPtr<nsIHandlerApp> handlerApp;
  giovfs->GetAppForURIScheme(aScheme, getter_AddRefs(handlerApp));
  gioApp = do_QueryInterface(handlerApp);
  if (!gioApp) {
    return false;
  }

  nsAutoCString handler;
  gioApp->GetCommand(handler);
  return CheckHandlerMatchesAppName(handler);
}

NS_IMETHODIMP
nsGNOMEShellService::IsDefaultForScheme(const nsACString& aScheme,
                                        bool* aIsDefaultBrowser) {
  *aIsDefaultBrowser = IsDefaultForSchemeHelper(aScheme, nullptr);
  return NS_OK;
}

NS_IMETHODIMP
nsGNOMEShellService::SetDefaultBrowser(bool aForAllUsers) {
#ifdef DEBUG
  if (aForAllUsers)
    NS_WARNING(
        "Setting the default browser for all users is not yet supported");
#endif

  if (widget::IsRunningUnderSnap()) {
    const gchar* argv[] = {"xdg-settings""set""default-web-browser",
                           (MOZ_APP_NAME ".desktop"), nullptr};
    GSpawnFlags flags = static_cast<GSpawnFlags>(G_SPAWN_SEARCH_PATH |
                                                 G_SPAWN_STDOUT_TO_DEV_NULL |
                                                 G_SPAWN_STDERR_TO_DEV_NULL);
    g_spawn_sync(nullptr, (gchar**)argv, nullptr, flags, nullptr, nullptr,
                 nullptr, nullptr, nullptr, nullptr);
    return NS_OK;
  }

  nsCOMPtr<nsIGIOService> giovfs = do_GetService(NS_GIOSERVICE_CONTRACTID);
  if (giovfs) {
    nsresult rv;
    nsCOMPtr<nsIStringBundleService> bundleService =
        components::StringBundle::Service(&rv);
    NS_ENSURE_SUCCESS(rv, rv);

    nsCOMPtr<nsIStringBundle> brandBundle;
    rv = bundleService->CreateBundle(SHELL_BRAND_PROPERTIES_URI,
                                     getter_AddRefs(brandBundle));
    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->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 (auto appProtocol : appProtocols) {
      appInfo->SetAsDefaultForURIScheme(nsDependentCString(appProtocol.name));
    }

    // set handler for .html and xhtml files and MIME types:
    // Add mime types for html, xhtml extension and set app to just created
    // appinfo.
    for (auto appType : appTypes) {
      appInfo->SetAsDefaultForMimeType(nsDependentCString(appType.mimeType));
      appInfo->SetAsDefaultForFileExtensions(
          nsDependentCString(appType.extensions));
    }
  }

  nsCOMPtr<nsIPrefBranch> prefs(do_GetService(NS_PREFSERVICE_CONTRACTID));
  if (prefs) {
    (void)prefs->SetBoolPref(PREF_CHECKDEFAULTBROWSER, true);
    // Reset the number of times the dialog should be shown
    // before it is silenced.
    (void)prefs->SetIntPref(PREF_DEFAULTBROWSERCHECKCOUNT, 0);
  }

  return NS_OK;
}

NS_IMETHODIMP
nsGNOMEShellService::GetCanSetDesktopBackground(bool* aResult) {
  // setting desktop background is currently only supported
  // for Gnome or desktops using the same GSettings keys
  if (widget::IsGnomeDesktopEnvironment()) {
    *aResult = true;
    return NS_OK;
  }

  *aResult = !!getenv("GNOME_DESKTOP_SESSION_ID");
  return NS_OK;
}

static nsresult WriteImage(const nsCString& aPath, imgIContainer* aImage) {
  RefPtr<GdkPixbuf> pixbuf = nsImageToPixbuf::ImageToPixbuf(aImage);
  if (!pixbuf) {
    return NS_ERROR_NOT_AVAILABLE;
  }

  gboolean res = gdk_pixbuf_save(pixbuf, aPath.get(), "png", nullptr, nullptr);
  return res ? NS_OK : NS_ERROR_FAILURE;
}

NS_IMETHODIMP
nsGNOMEShellService::SetDesktopBackground(dom::Element* aElement,
                                          int32_t aPosition,
                                          const nsACString& aImageName) {
  nsCOMPtr<nsIImageLoadingContent> imageContent = do_QueryInterface(aElement);
  if (!imageContent) {
    return NS_ERROR_FAILURE;
  }

  // get the image container
  nsCOMPtr<imgIRequest> request;
  imageContent->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
                           getter_AddRefs(request));
  if (!request) {
    return NS_ERROR_FAILURE;
  }
  nsCOMPtr<imgIContainer> container;
  request->GetImage(getter_AddRefs(container));
  if (!container) {
    return NS_ERROR_FAILURE;
  }

  // Set desktop wallpaper filling style
  nsAutoCString options;
  if (aPosition == BACKGROUND_TILE)
    options.AssignLiteral("wallpaper");
  else if (aPosition == BACKGROUND_STRETCH)
    options.AssignLiteral("stretched");
  else if (aPosition == BACKGROUND_FILL)
    options.AssignLiteral("zoom");
  else if (aPosition == BACKGROUND_FIT)
    options.AssignLiteral("scaled");
  else if (aPosition == BACKGROUND_SPAN)
    options.AssignLiteral("spanned");
  else
    options.AssignLiteral("centered");

  // Write the background file to the home directory.
  nsAutoCString filePath(PR_GetEnv("HOME"));
  nsAutoString brandName;

  // get the product brand name from localized strings
  if (nsCOMPtr<nsIStringBundleService> bundleService =
          components::StringBundle::Service()) {
    nsCOMPtr<nsIStringBundle> brandBundle;
    bundleService->CreateBundle(SHELL_BRAND_PROPERTIES_URI,
                                getter_AddRefs(brandBundle));
    if (bundleService) {
      brandBundle->GetStringFromName("brandShortName", brandName);
    }
  }

  // build the file name
  filePath.Append('/');
  filePath.Append(NS_ConvertUTF16toUTF8(brandName));
  filePath.AppendLiteral("_wallpaper.png");

  // write the image to a file in the home dir
  MOZ_TRY(WriteImage(filePath, container));

  widget::GSettings::Collection bgSettings(kDesktopBGSchema);
  if (!bgSettings) {
    return NS_ERROR_FAILURE;
  }

  GUniquePtr<gchar> fileURI(
      g_filename_to_uri(filePath.get(), nullptr, nullptr));
  if (!fileURI) {
    return NS_ERROR_FAILURE;
  }

  bgSettings.SetString("picture-options"_ns, options);
  bgSettings.SetString("picture-uri"_ns, nsDependentCString(fileURI.get()));
  bgSettings.SetString("picture-uri-dark"_ns,
                       nsDependentCString(fileURI.get()));
  return NS_OK;
}

#define COLOR_16_TO_8_BIT(_c) ((_c) >> 8)
#define COLOR_8_TO_16_BIT(_c) ((_c) << 8 | (_c))

NS_IMETHODIMP
nsGNOMEShellService::GetDesktopBackgroundColor(uint32_t* aColor) {
  nsAutoCString background;
  widget::GSettings::GetString(kDesktopBGSchema, kDesktopColorGSKey,
                               background);
  if (background.IsEmpty()) {
    *aColor = 0;
    return NS_OK;
  }

  GdkColor color;
  gboolean success = gdk_color_parse(background.get(), &color);

  NS_ENSURE_TRUE(success, NS_ERROR_FAILURE);

  *aColor = COLOR_16_TO_8_BIT(color.red) << 16 |
            COLOR_16_TO_8_BIT(color.green) << 8 | COLOR_16_TO_8_BIT(color.blue);
  return NS_OK;
}

static void ColorToCString(uint32_t aColor, nsCString& aResult) {
  // The #rrrrggggbbbb format is used to match gdk_color_to_string()
  aResult.SetLength(13);
  char* buf = aResult.BeginWriting();
  if (!buf) return;

  uint16_t red = COLOR_8_TO_16_BIT((aColor >> 16) & 0xff);
  uint16_t green = COLOR_8_TO_16_BIT((aColor >> 8) & 0xff);
  uint16_t blue = COLOR_8_TO_16_BIT(aColor & 0xff);

  snprintf(buf, 14"#%04x%04x%04x", red, green, blue);
}

NS_IMETHODIMP
nsGNOMEShellService::SetDesktopBackgroundColor(uint32_t aColor) {
  NS_ASSERTION(aColor <= 0xffffff, "aColor has extra bits");
  nsAutoCString colorString;
  ColorToCString(aColor, colorString);

  widget::GSettings::Collection bgSettings(kDesktopBGSchema);
  if (bgSettings) {
    bgSettings.SetString(kDesktopColorGSKey, colorString);
    return NS_OK;
  }

  return NS_ERROR_FAILURE;
}

NS_IMETHODIMP
nsGNOMEShellService::GetGSettingsString(const nsACString& aSchema,
                                        const nsACString& aKey,
                                        nsACString& aResult) {
  widget::GSettings::GetString(PromiseFlatCString(aSchema),
                               PromiseFlatCString(aKey), aResult);
  return NS_OK;
}

NS_IMETHODIMP
nsGNOMEShellService::SetGSettingsString(const nsACString& aSchema,
                                        const nsACString& aKey,
                                        const nsACString& aValue) {
  widget::GSettings::Collection settings(PromiseFlatCString(aSchema));
  if (!settings) {
    return NS_ERROR_FAILURE;
  }
  if (!settings.SetString(PromiseFlatCString(aKey),
                          PromiseFlatCString(aValue))) {
    return NS_ERROR_FAILURE;
  }
  return NS_OK;
}

NS_IMETHODIMP nsGNOMEShellService::GetArgv0(nsACString& output) {
  output.Assign(gArgc <= 0 ? "" : gArgv[0]);
  return NS_OK;
}

NS_IMETHODIMP nsGNOMEShellService::GetGlibPrgname(nsACString& output) {
  output.Assign(g_get_prgname());
  return NS_OK;
}

NS_IMETHODIMP nsGNOMEShellService::GetDesktopEntryStatus(
    const nsACString& aDesktopId,
    nsIGNOMEShellService::DesktopEntryStatus* aResult) {
  NS_ENSURE_ARG_POINTER(aResult);

  RefPtr<GDesktopAppInfo> appinfo =
      dont_AddRef(g_desktop_app_info_new(PromiseFlatCString(aDesktopId).get()));
  if (!appinfo) {
    *aResult = nsIGNOMEShellService::DESKTOP_ENTRY_ABSENT;
  } else if (g_app_info_should_show(G_APP_INFO(appinfo.get()))) {
    *aResult = nsIGNOMEShellService::DESKTOP_ENTRY_VISIBLE;
  } else {
    *aResult = nsIGNOMEShellService::DESKTOP_ENTRY_INVISIBLE;
  }

  return NS_OK;
}

using GIconPromise = MozPromise<RefPtr<GIcon>, GUniquePtr<GError>, true>;
class AsyncGIconReader {
 public:
  // This may be freed by the background thread.
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncGIconReader);

  explicit AsyncGIconReader(const nsCString& aPath) { mPath.Assign(aPath); }

  RefPtr<GIconPromise> Start() {
    RefPtr<GIconPromise> promise = mHolder.Ensure(__func__);
    MOZ_ASSERT(!mHolder.IsEmpty());

    NS_DispatchBackgroundTask(
        NS_NewRunnableFunction(
            __func__,
            [this, inst = RefPtr{this}] {
              char* content = nullptr;
              size_t length = 0;
              GUniquePtr<GError> error;
              if (!g_file_get_contents(mPath.get(), &content, &length,
                                       getter_Transfers(error))) {
                mHolder.Reject(std::move(error), __func__);
                return;
              }

              GBytes* bytes = g_bytes_new_take(content, length);
              // Note that this doesn't decode the image and only puts the
              // bytes into a new container that serializes over D-Bus.
              RefPtr<GIcon> icon = dont_AddRef(g_bytes_icon_new(bytes));
              g_clear_pointer(&bytes, g_bytes_unref);

              mHolder.Resolve(std::move(icon), __func__);
            }),
        NS_DISPATCH_EVENT_MAY_BLOCK);

    return promise.forget();
  }

 private:
  MozPromiseHolder<GIconPromise> mHolder;
  nsCString mPath;

  ~AsyncGIconReader() = default;
};

#ifdef MOZ_ENABLE_DBUS
static RefPtr<widget::DBusProxyPromise> CreateDynamicLauncherProxy() {
  return widget::CreateDBusProxyForBus(
      G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, nullptr,
      "org.freedesktop.portal.Desktop""/org/freedesktop/portal/desktop",
      "org.freedesktop.portal.DynamicLauncher");
}
#endif

NS_IMETHODIMP nsGNOMEShellService::RequestInstallDynamicLauncher(
    const nsACString& aEntryId, nsIINIParserWriter* aDesktopEntry,
    mozIDOMWindowProxy* aWindow, JSContext* aCx, dom::Promise** aPromise) {
  MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());

#ifdef MOZ_ENABLE_DBUS
  ErrorResult rv;
  RefPtr<dom::Promise> promise =
      dom::Promise::Create(xpc::CurrentNativeGlobal(aCx), rv);
  if (MOZ_UNLIKELY(rv.Failed())) {
    return rv.StealNSResult();
  }

  nsWindow* window = nullptr;
  if (aWindow) {
    auto* parent = nsPIDOMWindowOuter::From(aWindow);
    RefPtr<nsIWidget> widget =
        mozilla::widget::WidgetUtils::DOMWindowToWidget(parent);
    NS_ENSURE_TRUE(widget, NS_ERROR_FAILURE);

    window = nsWindow::FromWidget(widget);
  }

  nsCOMPtr<nsIINIParser> entryINI(do_QueryInterface(aDesktopEntry));
  NS_ENSURE_ARG(entryINI);

  nsCString entryName;
  nsCString entryIcon;
  nsCString entryContent;
  MOZ_TRY(entryINI->GetString("Desktop Entry"_ns, "Name"_ns, entryName));
  MOZ_TRY(entryINI->GetString("Desktop Entry"_ns, "Icon"_ns, entryIcon));
  MOZ_TRY(aDesktopEntry->WriteToString(entryContent));

  auto* target = GetCurrentSerialEventTarget();

  // MozPromise doesn't seem to support ::All with different types, so make one
  // type to contain them all.
  using DynamicLauncherPromise =
      MozPromise<Variant<RefPtr<GDBusProxy>, RefPtr<GIcon>, nsCString>,
                 GUniquePtr<GError>, true>;

  RefPtr<DynamicLauncherPromise> dbusProxyPromise =
      CreateDynamicLauncherProxy()->Map(
          target, __func__,
          [](RefPtr<GDBusProxy>&& proxy)
              -> DynamicLauncherPromise::ResolveValueType {
            return AsVariant(std::move(proxy));
          });

  RefPtr<AsyncGIconReader> reader = new AsyncGIconReader(entryIcon);
  RefPtr<DynamicLauncherPromise> iconPromise = reader->Start()->Map(
      target, __func__,
      [](RefPtr<GIcon>&& icon) -> DynamicLauncherPromise::ResolveValueType {
        return AsVariant(std::move(icon));
      });

  RefPtr<DynamicLauncherPromise> exportPromise =
      (window
           ? window->ExportHandle()
           : nsWindow::ExportHandlePromise::CreateAndResolve(""_ns, __func__))
          ->Then(
              GetCurrentSerialEventTarget(), __func__,
              [](nsWindow::ExportHandlePromise::ResolveOrRejectValue&& aValue) {
                if (aValue.IsResolve()) {
                  return DynamicLauncherPromise::CreateAndResolve(
                      AsVariant(aValue.ResolveValue()), __func__);
                }

                NS_WARNING("Failed to export window for DynamicLauncher");
                return DynamicLauncherPromise::CreateAndResolve(
                    AsVariant(EmptyCString()), __func__);
              });

  nsTArray<RefPtr<DynamicLauncherPromise>> promises = {
      RefPtr(dbusProxyPromise), RefPtr(iconPromise), RefPtr(exportPromise)};
  DynamicLauncherPromise::All(target, promises)
      ->Then(
          target, __func__,
          [target = nsCOMPtr{target}, entryId = nsCString(aEntryId),
           entryContent = std::move(entryContent),
           entryName = std::move(entryName)](
              DynamicLauncherPromise::AllPromiseType::ResolveOrRejectValue&&
                  aValue) {
            if (aValue.IsReject()) {
              return widget::DBusCallPromise::AllPromiseType::CreateAndReject(
                  std::move(aValue.RejectValue()), __func__);
            }

            auto values = aValue.ResolveValue();
            RefPtr<GDBusProxy> proxy =
                std::move(values[0].template as<RefPtr<GDBusProxy>>());
            RefPtr<GIcon> icon = values[1].template as<RefPtr<GIcon>>();
            nsCString exportedWindow = values[2].template as<nsCString>();

            nsAutoCString token;
            widget::MakePortalRequestToken("DynamicLauncher"_ns, token);

            nsAutoCString requestPath;
            widget::GetPortalRequestPath(proxy.get(), token, requestPath);

            auto holder =
                std::make_shared<MozPromiseHolder<widget::DBusCallPromise>>();
            RefPtr<widget::DBusCallPromise> installPromise =
                holder->Ensure(__func__);

            GVariantDict options;
            g_variant_dict_init(&options, nullptr);
            g_variant_dict_insert(&options, "handle_token""s", token.get());

            RefPtr<GVariant> args = dont_AddRef(g_variant_ref_sink(
                g_variant_new("(ssv@a{sv})",        //
                              exportedWindow.get(), /* parent window */
                              entryName.get(),      /* name of entry */
                              g_icon_serialize(G_ICON(icon.get())), /* icon */
                              g_variant_dict_end(&options)))); /* options */

            auto subscription = std::make_shared<unsigned>(0);
            *subscription = widget::OnDBusPortalResponse(
                G_DBUS_PROXY(proxy.get()), token,
                [target = nsCOMPtr{target}, entryId = std::move(entryId),
                 entryContent, proxy, holder, subscription](GVariant* variant) {
                  *subscription = 0;

                  unsigned response = 2;  // '2' indicates 'other error'
                  RefPtr<GVariant> options = nullptr;
                  g_variant_get(variant, "(u@a{sv})", &response,
                                options.StartAssignment());
                  if (response != 0) {
                    holder->Reject(GUniquePtr<GError>(g_error_new(
                                       G_IO_ERROR, G_IO_ERROR_FAILED,
                                       "Response was non-zero")),
                                   __func__);
                    return;
                  }

                  const char* responseToken;
                  if (!g_variant_lookup(options, "token""&s",
                                        &responseToken)) {
                    holder->Reject(
                        GUniquePtr<GError>(g_error_new(
                            G_IO_ERROR, G_IO_ERROR_FAILED,
                            "No token was provided from the portal")),
                        __func__);
                    return;
                  }

                  nsPrintfCString entryIdWithExtension("%s.desktop",
                                                       entryId.get());
                  RefPtr<GVariant> args = dont_AddRef(g_variant_ref_sink(
                      g_variant_new("(sssa{sv})", responseToken,
                                    entryIdWithExtension.get(),
                                    entryContent.get(), nullptr)));

                  widget::DBusProxyCall(proxy.get(), "Install", args,
                                        G_DBUS_CALL_FLAGS_NONE, -1)
                      ->Then(target, __func__,
                             [holder = std::move(holder)](
                                 widget::DBusCallPromise::ResolveOrRejectValue&&
                                     aValue) {
                               holder->ResolveOrReject(std::move(aValue),
                                                       __func__);
                             });
                });

            RefPtr<widget::DBusCallPromise> prepareInstallPromise =
                widget::DBusProxyCall(G_DBUS_PROXY(proxy.get()),
                                      "PrepareInstall", args,
                                      G_DBUS_CALL_FLAGS_NONE, -1)
                    ->MapErr(target, __func__,
                             [subscriptionptr = std::move(subscription), proxy,
                              holder](GUniquePtr<GError>&& err) {
                               if (*subscriptionptr) {
                                 g_dbus_connection_signal_unsubscribe(
                                     g_dbus_proxy_get_connection(proxy.get()),
                                     *subscriptionptr);
                               }

                               holder->Reject(
                                   GUniquePtr<GError>(g_error_copy(err.get())),
                                   __func__);
                               return std::move(err);
                             });

            nsTArray<RefPtr<widget::DBusCallPromise>> promises = {
                prepareInstallPromise, installPromise};
            return widget::DBusCallPromise::All(target, promises);
          })
      ->Then(target, __func__,
             [promise](
                 widget::DBusCallPromise::AllPromiseType::ResolveOrRejectValue&&
                     aValue) {
               if (aValue.IsReject()) {
                 nsDependentCString message(aValue.RejectValue()->message);
                 promise->MaybeRejectWithOperationError(message);
               } else {
                 promise->MaybeResolveWithUndefined();
               }
             });

  promise.forget(aPromise);
  return NS_OK;
#else
  return NS_ERROR_FAILURE;
#endif
}

NS_IMETHODIMP nsGNOMEShellService::RequestUninstallDynamicLauncher(
    const nsACString& aEntryId, JSContext* aCx, dom::Promise** aPromise) {
  MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
#ifdef MOZ_ENABLE_DBUS
  ErrorResult rv;
  RefPtr<dom::Promise> promise =
      dom::Promise::Create(xpc::CurrentNativeGlobal(aCx), rv);
  if (MOZ_UNLIKELY(rv.Failed())) {
    return rv.StealNSResult();
  }

  nsCString entryId = PromiseFlatCString(aEntryId);
  nsPrintfCString entryIdWithExtension("%s.desktop", entryId.get());

  CreateDynamicLauncherProxy()
      ->Then(
          GetCurrentSerialEventTarget(), __func__,
          [entryIdWithExtension](const RefPtr<GDBusProxy>& aProxy) {
            RefPtr<GVariant> args =
                dont_AddRef(g_variant_ref_sink(g_variant_new(
                    "(sa{sv})", entryIdWithExtension.get(), nullptr)));
            return widget::DBusProxyCall(aProxy.get(), "Uninstall", args,
                                         G_DBUS_CALL_FLAGS_NONE, -1);
          },
          [](GUniquePtr<GError>&& error) {
            return widget::DBusCallPromise::CreateAndReject(std::move(error),
                                                            __func__);
          })
      ->Then(GetCurrentSerialEventTarget(), __func__,
             [promise](widget::DBusCallPromise::ResolveOrRejectValue&& aValue) {
               if (aValue.IsReject()) {
                 nsDependentCString message(aValue.RejectValue()->message);
                 promise->MaybeRejectWithOperationError(message);
               } else {
                 promise->MaybeResolveWithUndefined();
               }
             });

  promise.forget(aPromise);
  return NS_OK;
#else
  return NS_ERROR_FAILURE;
#endif
}

Messung V0.5 in Prozent
C=83 H=98 G=90

¤ Dauer der Verarbeitung: 0.11 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.