nixpkgs mirror (for testing) github.com/NixOS/nixpkgs
nix
at devShellTools-shell 207 lines 8.1 kB view raw
1{ 2 lib, 3 writeTextFile, 4 buildPackages, 5}: 6 7/** 8 A utility builder to create a desktop entry file at a predetermined location (by default, $out/share/applications). 9 10 # Examples 11 12 ```nix 13 makeDesktopItem { 14 name = "Eclipse"; 15 exec = "eclipse"; 16 icon = "eclipse"; 17 comment = "Integrated Development Environment"; 18 desktopName = "Eclipse IDE"; 19 genericName = "Integrated Development Environment"; 20 categories = [ "Development" ]; 21 } 22 => «derivation /nix/store/sh017x5n50i2qwns2na1sxdp7zb2zgcw-Eclipse.desktop.drv» 23 ``` 24 25 # Type 26 27 ``` 28 makeDesktopItem :: AttrSet -> Derivation 29 ``` 30 31 # Input 32 33 `attrs` 34 35 : An AttrSet with the following definitions. See https://specifications.freedesktop.org/desktop-entry-spec/1.4/recognized-keys.html#id-1.7.6 for definitions. 36 37 - `name` (string): The name of the desktop file (excluding the .desktop or .directory file extensions) 38 - `destination` (string): The directory that will contain the desktop entry file (Default: "/share/applications") 39 - `type` ("Application" | "Link" | "Directory"): The `Type` of the desktop entry 40 - `desktopName` (string): The `Name` of the desktop entry 41 - `genericName` (string): The `GenericName` of the desktop entry 42 - `noDisplay` (bool): The `NoDisplay` of the desktop entry 43 - `comment` (string): The `Comment` of the desktop entry 44 - `icon` (string): The `Icon` of the desktop entry 45 - `onlyShowIn` (string[]): The `OnlyShowIn` of the desktop entry 46 - `notShowIn` (string[]): The `NotShowIn` of the desktop entry 47 - `dbusActivatable` (bool): The `DBusActivatable` of the desktop entry 48 - `tryExec` (string): The `TryExec` of the desktop entry 49 - `exec` (string): The `Exec` of the desktop entry 50 - `path` (string): The `Path` of the desktop entry 51 - `terminal` (bool): The `Terminal` of the desktop entry 52 - `actions` (AttrSet): An attrset of [internal name] -> { name, exec?, icon? } representing the `Actions` of the desktop entry 53 - `mimeTypes` (string[]): The `MimeType` of the desktop entry 54 - `categories` (string[]): The `Categories` of the desktop entry; see https://specifications.freedesktop.org/menu-spec/1.0/category-registry.html for possible values 55 - `implements` (string[]): The `Implements` of the desktop entry 56 - `keywords` (string[]): The `Keywords` of the desktop entry 57 - `startupNotify` (bool): The `StartupNotify` of the desktop entry 58 - `startupWMClass` (string): The `StartupWMClass` of the desktop entry 59 - `url` (string): The `URL` of the Link-type desktop entry 60 - `prefersNonDefaultGPU` (bool): The `PrefersNonDefaultGPU` (non-standard) of the desktop entry 61 - `extraConfig` (AttrSet): Additional values to be added literally to the final item, e.g. vendor extensions 62 63 # Output 64 65 A derivation that contains the output desktop entry file. 66 67 # Developer Note 68 69 All possible values are as defined by the spec, version 1.4. 70 Please keep in spec order for easier maintenance. 71 When adding a new value, don't forget to update the Version field below! 72 See https://specifications.freedesktop.org/desktop-entry-spec/latest 73*/ 74lib.makeOverridable ( 75 { 76 name, # The name of the desktop file 77 destination ? "/share/applications", 78 type ? "Application", 79 # version is hardcoded 80 desktopName, # The name of the application 81 genericName ? null, 82 noDisplay ? null, 83 comment ? null, 84 icon ? null, 85 # we don't support the Hidden key - if you don't need something, just don't install it 86 onlyShowIn ? [ ], 87 notShowIn ? [ ], 88 dbusActivatable ? null, 89 tryExec ? null, 90 exec ? null, 91 path ? null, 92 terminal ? null, 93 actions ? { }, # An attrset of [internal name] -> { name, exec?, icon? } 94 mimeTypes ? [ ], # The spec uses "MimeType" as singular, use plural here to signify list-ness 95 categories ? [ ], 96 implements ? [ ], 97 keywords ? [ ], 98 startupNotify ? null, 99 startupWMClass ? null, 100 url ? null, 101 prefersNonDefaultGPU ? null, 102 # not supported until version 1.5, which is not supported by our desktop-file-utils as of 2022-02-23 103 # singleMainWindow ? null, 104 extraConfig ? { }, # Additional values to be added literally to the final item, e.g. vendor extensions 105 }: 106 let 107 # There are multiple places in the FDO spec that make "boolean" values actually tristate, 108 # e.g. StartupNotify, where "unset" is literally defined as "do something reasonable". 109 # So, handle null values separately. 110 boolOrNullToString = 111 value: 112 if value == null then 113 null 114 else if builtins.isBool value then 115 lib.boolToString value 116 else 117 throw "makeDesktopItem: value must be a boolean or null!"; 118 119 # Multiple values are represented as one string, joined by semicolons. 120 # Technically, it's possible to escape semicolons in values with \;, but this is currently not implemented. 121 renderList = 122 key: value: 123 if !builtins.isList value then 124 throw "makeDesktopItem: value for ${key} must be a list!" 125 else if builtins.any (item: lib.hasInfix ";" item) value then 126 throw "makeDesktopItem: values in ${key} list must not contain semicolons!" 127 else if value == [ ] then 128 null 129 else 130 builtins.concatStringsSep ";" value; 131 132 # The [Desktop Entry] section of the desktop file, as an attribute set. 133 # Please keep in spec order. 134 mainSection = { 135 "Type" = type; 136 "Version" = "1.4"; 137 "Name" = desktopName; 138 "GenericName" = genericName; 139 "NoDisplay" = boolOrNullToString noDisplay; 140 "Comment" = comment; 141 "Icon" = icon; 142 "OnlyShowIn" = renderList "onlyShowIn" onlyShowIn; 143 "NotShowIn" = renderList "notShowIn" notShowIn; 144 "DBusActivatable" = boolOrNullToString dbusActivatable; 145 "TryExec" = tryExec; 146 "Exec" = exec; 147 "Path" = path; 148 "Terminal" = boolOrNullToString terminal; 149 "Actions" = renderList "actions" (builtins.attrNames actions); 150 "MimeType" = renderList "mimeTypes" mimeTypes; 151 "Categories" = renderList "categories" categories; 152 "Implements" = renderList "implements" implements; 153 "Keywords" = renderList "keywords" keywords; 154 "StartupNotify" = boolOrNullToString startupNotify; 155 "StartupWMClass" = startupWMClass; 156 "URL" = url; 157 "PrefersNonDefaultGPU" = boolOrNullToString prefersNonDefaultGPU; 158 # "SingleMainWindow" = boolOrNullToString singleMainWindow; 159 } 160 // extraConfig; 161 162 # Render a single attribute pair to a Key=Value line. 163 # FIXME: this isn't entirely correct for arbitrary strings, as some characters 164 # need to be escaped. There are currently none in nixpkgs though, so this is OK. 165 renderLine = name: value: if value != null then "${name}=${value}" else null; 166 167 # Render a full section of the file from an attrset. 168 # Null values are intentionally left out. 169 renderSection = 170 sectionName: attrs: 171 lib.pipe attrs [ 172 (lib.mapAttrsToList renderLine) 173 (builtins.filter (v: v != null)) 174 (builtins.concatStringsSep "\n") 175 (section: '' 176 [${sectionName}] 177 ${section} 178 '') 179 ]; 180 181 mainSectionRendered = renderSection "Desktop Entry" mainSection; 182 183 # Convert from javaCase names as used in Nix to PascalCase as used in the spec. 184 preprocessAction = 185 { 186 name, 187 icon ? null, 188 exec ? null, 189 }: 190 { 191 "Name" = name; 192 "Icon" = icon; 193 "Exec" = exec; 194 }; 195 renderAction = name: attrs: renderSection "Desktop Action ${name}" (preprocessAction attrs); 196 actionsRendered = lib.mapAttrsToList renderAction actions; 197 198 extension = if type == "Directory" then "directory" else "desktop"; 199 content = [ mainSectionRendered ] ++ actionsRendered; 200 in 201 writeTextFile { 202 name = "${name}.${extension}"; 203 destination = "${destination}/${name}.${extension}"; 204 text = builtins.concatStringsSep "\n" content; 205 checkPhase = ''${buildPackages.desktop-file-utils}/bin/desktop-file-validate "$target"''; 206 } 207)