Open alyaeanyx opened 2 years ago
This would also be great to work with Pantheon since we don't have the users settings. (cc @NixOS/pantheon)
We could use something like users.users.<name>.avatar
. Is there a standard how this is called?
We can specify an image there that we have in our configuration directory and every DE can use it, which might need DE specific code.
Related issues:
Doesn't ~/.face
also work? Seems reasonably declarative...
Instead of patching can you please open a feature request upstream?
Doesn't
~/.face
also work? Seems reasonably declarative...
Yes, that seems like something that could be integrated easily into home-manager. However, according to my understanding, the accountsservice user files (/var/lib/AccountsService/users/<username>
) need to have an Icon
entry specifying /home/<username>/.face
as the user profile picture, which is not the case by default on my GNOME install. And even apart from that, there seem to be permission issues with it (https://github.com/NixOS/nixpkgs/issues/73976)
https://wiki.archlinux.org/title/SDDM#User_icon_(avatar) suggests using ACLs in the case of sddm
. Presumably that would work with other software as well.
I'd love to see this supported. I had tried a handful of things but couldn't get my icon to display in GDM. Currently making use of home-manager to add ~/.face
which works in a GNOME session at least.
Something like:
boot.postBootCommands = let
gdm_user_conf = ''
[User]
Session=
XSession=
Icon=${./path/to/your/icon}
SystemAccount=false
'';
in ''
echo '${gdm_user_conf}' > /var/lib/AccountsService/users/USERNAME_HERE
'';
works for me, even if it may be a bit hacky. Maybe it could be cleaned into a NixOS option like
services.xserver.displayManager.gdm.user_icons = {
name0 = ./path/to/icon0;
name1 = ./path/to/icon1;
};
I used @litchipi's code to make a module suitable for multi-user installs. I thought I'd share it so it might help others.
It adds an option users.users.<name>.icon
where we can provide a path to an image file that is to be used:
{ lib, config, ...}:
let
userOptions = with lib; {
options.icon = mkOption { type = types.nullOr types.path; default = null; };
};
mkGdmUserConf = icon: ''
[User]
Session=
XSession=
Icon=${icon}
SystemAccount=false
'';
userList = with lib; filter (entry: entry.icon != null) (mapAttrsToList (name: value: { inherit name; icon = value.icon; }) config.users.users);
mkBootCommand = entry: "echo -e '${mkGdmUserConf entry.icon}' > /var/lib/AccountsService/users/${entry.name}\n";
bootCommands = map mkBootCommand userList;
in
{
options = {
users.users = with lib; with types; mkOption {
type = attrsOf (submodule userOptions);
};
};
config = lib.mkIf config.services.xserver.displayManager.gdm.enable {
boot.postBootCommands = with lib; strings.concatStrings bootCommands;
};
}
It's interesting that the Arch Wiki recommends this as one of the options:
Alternatively, create the image file as /home/username/.face and skip the next step if the defaults already point to the user home directory path
Of course, this won't work since the home directory won't be readable. Does it expect the user to chmod 755
their home directory, or is there something I'm missing here?
Of course, this won't work since the home directory won't be readable. Does it expect the user to
chmod 755
their home directory, or is there something I'm missing here?
AccountsService runs as root so it can see the icon just fine. But GDM can't. In theory AccountsService could copy .face
into /var/lib/AccountsService/icons
but it doesn't seem to do that currently.
Here is another approach which avoids writing anything to /var/lib
:
{config, lib, pkgs, ...}: let
inherit (lib) types;
iconOptions.options.icon = lib.mkOption {
type = types.nullOr types.path;
default = null;
};
users = lib.filterAttrs (_: value: value.icon != null) config.users.users;
iconLinks = lib.mapAttrsToList (name: value: "ln -s ${value.icon} ${name}") users;
icons = pkgs.runCommand "user-icons" {} ''
mkdir $out
cd $out
${builtins.concatStringsSep "\n" iconLinks}
'';
templateText = lib.generators.toINI {} {
User.Icon = "${icons}/\${USER}";
};
templateFile = pkgs.writeText "user-template" templateText;
templateDir = "share/accountsservice/user-templates";
templates = pkgs.runCommand "user-templates" { meta.priority = 0; } ''
mkdir -p $out/${templateDir}
cd $out/${templateDir}
ln -s ${templateFile} administrator
ln -s ${templateFile} standard
'';
in {
options.users.users = lib.mkOption {
type = types.attrsOf (types.submodule iconOptions);
};
config.environment.systemPackages = [templates];
}
It creates an icons
package with links name -> users.users.${name}.icon
, then uses this feature to set the default icon to ${icons}/$USER
. That's in the nix store so it should be world-readable.
This issue has been mentioned on NixOS Discourse. There might be relevant details there:
https://discourse.nixos.org/t/setting-the-user-profile-image-under-gnome/36233/1
It's interesting that the Arch Wiki recommends this as one of the options:
Alternatively, create the image file as /home/username/.face and skip the next step if the defaults already point to the user home directory path
Of course, this won't work since the home directory won't be readable. Does it expect the user to
chmod 755
their home directory, or is there something I'm missing here?
You don't need chmod 755
. More precisely, it does not need write permission in home
folder. It needs only exec permission, so chmod 711
.
PS: @jonathan-conder your solution seems nice. Why don't you implement it as module in Nixpkgs?
Currently, user profile pictures as they are used in Gnome cannot be reasonably changed. The interface used for changing user icons in the Gnome system settings is unreliable (seems to only work for the preset icons). The only way to change them at all is to manually put them into
/var/lib/AccountsService/icons
.My ideas to make declarative user icons possible are:
accountsservice
to point the user icon dir to an immutable location in/etc
/var/lib/AccountsService/icons