query
On this page

makeDesktopItem

pkgs.makeDesktopItem

Functor
Docs pulled from | This Revision | 10 minutes ago

No reference documentation found yet.

Contribute now!


Contribute
Enhance the ecosystem with your expertise! Contribute to fill the gaps in documentation. Your input can make a difference.

Noogle detected

This is a Functor

Learn about functors

Implementation

The following is the current implementation of this function.

{
    name, # The name of the desktop file
    destination ? "/share/applications",
    type ? "Application",
    # version is hardcoded
    desktopName, # The name of the application
    genericName ? null,
    noDisplay ? null,
    comment ? null,
    icon ? null,
    # we don't support the Hidden key - if you don't need something, just don't install it
    onlyShowIn ? [ ],
    notShowIn ? [ ],
    dbusActivatable ? null,
    tryExec ? null,
    exec ? null,
    path ? null,
    terminal ? null,
    actions ? { }, # An attrset of [internal name] -> { name, exec?, icon? }
    mimeTypes ? [ ], # The spec uses "MimeType" as singular, use plural here to signify list-ness
    categories ? [ ],
    implements ? [ ],
    keywords ? [ ],
    startupNotify ? null,
    startupWMClass ? null,
    url ? null,
    prefersNonDefaultGPU ? null,
    # not supported until version 1.5, which is not supported by our desktop-file-utils as of 2022-02-23
    # singleMainWindow ? null,
    extraConfig ? { }, # Additional values to be added literally to the final item, e.g. vendor extensions
  }:
  let
    # There are multiple places in the FDO spec that make "boolean" values actually tristate,
    # e.g. StartupNotify, where "unset" is literally defined as "do something reasonable".
    # So, handle null values separately.
    boolOrNullToString =
      value:
      if value == null then
        null
      else if builtins.isBool value then
        lib.boolToString value
      else
        throw "makeDesktopItem: value must be a boolean or null!";

    # Multiple values are represented as one string, joined by semicolons.
    # Technically, it's possible to escape semicolons in values with \;, but this is currently not implemented.
    renderList =
      key: value:
      if !builtins.isList value then
        throw "makeDesktopItem: value for ${key} must be a list!"
      else if builtins.any (item: lib.hasInfix ";" item) value then
        throw "makeDesktopItem: values in ${key} list must not contain semicolons!"
      else if value == [ ] then
        null
      else
        builtins.concatStringsSep ";" value;

    # The [Desktop Entry] section of the desktop file, as an attribute set.
    # Please keep in spec order.
    mainSection = {
      "Type" = type;
      "Version" = "1.4";
      "Name" = desktopName;
      "GenericName" = genericName;
      "NoDisplay" = boolOrNullToString noDisplay;
      "Comment" = comment;
      "Icon" = icon;
      "OnlyShowIn" = renderList "onlyShowIn" onlyShowIn;
      "NotShowIn" = renderList "notShowIn" notShowIn;
      "DBusActivatable" = boolOrNullToString dbusActivatable;
      "TryExec" = tryExec;
      "Exec" = exec;
      "Path" = path;
      "Terminal" = boolOrNullToString terminal;
      "Actions" = renderList "actions" (builtins.attrNames actions);
      "MimeType" = renderList "mimeTypes" mimeTypes;
      "Categories" = renderList "categories" categories;
      "Implements" = renderList "implements" implements;
      "Keywords" = renderList "keywords" keywords;
      "StartupNotify" = boolOrNullToString startupNotify;
      "StartupWMClass" = startupWMClass;
      "URL" = url;
      "PrefersNonDefaultGPU" = boolOrNullToString prefersNonDefaultGPU;
      # "SingleMainWindow" = boolOrNullToString singleMainWindow;
    } // extraConfig;

    # Render a single attribute pair to a Key=Value line.
    # FIXME: this isn't entirely correct for arbitrary strings, as some characters
    # need to be escaped. There are currently none in nixpkgs though, so this is OK.
    renderLine = name: value: if value != null then "${name}=${value}" else null;

    # Render a full section of the file from an attrset.
    # Null values are intentionally left out.
    renderSection =
      sectionName: attrs:
      lib.pipe attrs [
        (lib.mapAttrsToList renderLine)
        (builtins.filter (v: v != null))
        (builtins.concatStringsSep "\n")
        (section: ''
          [${sectionName}]
          ${section}
        '')
      ];

    mainSectionRendered = renderSection "Desktop Entry" mainSection;

    # Convert from javaCase names as used in Nix to PascalCase as used in the spec.
    preprocessAction =
      {
        name,
        icon ? null,
        exec ? null,
      }:
      {
        "Name" = name;
        "Icon" = icon;
        "Exec" = exec;
      };
    renderAction = name: attrs: renderSection "Desktop Action ${name}" (preprocessAction attrs);
    actionsRendered = lib.mapAttrsToList renderAction actions;

    extension = if type == "Directory" then "directory" else "desktop";
    content = [ mainSectionRendered ] ++ actionsRendered;
  in
  writeTextFile {
    name = "${name}.${extension}";
    destination = "${destination}/${name}.${extension}";
    text = builtins.concatStringsSep "\n" content;
    checkPhase = ''${buildPackages.desktop-file-utils}/bin/desktop-file-validate "$target"'';
  }