2024-01-24 02:41:06 +00:00
|
|
|
# This module supports both the built-in and systemd-managed desktop sessions
|
|
|
|
# for simplicity's sake and it is up to the user to configure one or the other
|
|
|
|
# (or both but in practice, the user will make use only one of them at a time
|
|
|
|
# so it's pointless). It also requires a lot of boilerplate which explains its
|
|
|
|
# size.
|
2024-01-23 03:31:20 +00:00
|
|
|
{ config, lib, pkgs, utils, ... }:
|
2024-01-03 15:30:55 +00:00
|
|
|
|
|
|
|
let
|
|
|
|
cfg = config.programs.gnome-session;
|
2024-01-23 03:31:20 +00:00
|
|
|
|
2024-06-25 14:41:17 +00:00
|
|
|
# The gnome-session config files uses one from GLib. See the following link
|
|
|
|
# at <https://docs.gtk.org/glib/struct.KeyFile.html> for details about the
|
|
|
|
# keyfile formatting and possibly the Desktop Entry specification at
|
|
|
|
# <https://freedesktop.org/wiki/Specifications/desktop-entry-spec>.
|
2024-07-30 10:28:37 +00:00
|
|
|
glibKeyfileFormat = {
|
2024-06-25 14:41:17 +00:00
|
|
|
type = with lib.types;
|
2024-06-22 14:30:48 +00:00
|
|
|
let
|
2024-06-25 14:41:17 +00:00
|
|
|
valueType = oneOf [
|
|
|
|
bool
|
|
|
|
float
|
|
|
|
int
|
|
|
|
str
|
|
|
|
(listOf valueType)
|
|
|
|
] // {
|
2024-07-30 10:28:37 +00:00
|
|
|
description = "GLib keyfile atom (bool, int, float, string, or a list of the previous atoms)";
|
2024-06-25 14:41:17 +00:00
|
|
|
};
|
2024-06-22 14:30:48 +00:00
|
|
|
in
|
2024-06-25 14:41:17 +00:00
|
|
|
attrsOf (attrsOf valueType);
|
2024-07-30 10:28:37 +00:00
|
|
|
|
|
|
|
generate = name: value:
|
|
|
|
pkgs.callPackage ({ writeText }:
|
|
|
|
writeText name (lib.generators.toDconfINI value));
|
2024-06-22 14:30:48 +00:00
|
|
|
};
|
|
|
|
|
2024-01-23 03:31:20 +00:00
|
|
|
# The bulk of the work. Pretty much the main purpose of this module.
|
|
|
|
sessionPackages = lib.mapAttrsToList
|
2024-05-17 02:43:17 +00:00
|
|
|
(_: session:
|
2024-01-23 03:31:20 +00:00
|
|
|
let
|
2024-06-22 14:30:48 +00:00
|
|
|
gnomeSession = glibKeyfileFormat.generate "session-${session.name}" session.settings;
|
2024-01-23 03:31:20 +00:00
|
|
|
|
2024-07-30 10:28:37 +00:00
|
|
|
# For now, we set this as a static template since there's not much
|
|
|
|
# things to configure especially for a desktop session anyways.
|
2024-01-23 03:31:20 +00:00
|
|
|
displaySession = ''
|
|
|
|
[Desktop Entry]
|
2024-06-25 14:41:17 +00:00
|
|
|
Name=${session.fullName}
|
2024-01-23 03:31:20 +00:00
|
|
|
Comment=${session.description}
|
2024-05-17 02:43:17 +00:00
|
|
|
Exec="@out@/libexec/${session.name}-session"
|
2024-01-23 03:31:20 +00:00
|
|
|
Type=Application
|
2024-06-25 14:41:17 +00:00
|
|
|
DesktopNames=${lib.concatStringsSep ";" session.desktopNames}
|
2024-01-23 03:31:20 +00:00
|
|
|
'';
|
|
|
|
|
2024-07-30 10:28:37 +00:00
|
|
|
# Similarly to the desktop session template, this is also set as a
|
|
|
|
# static template.
|
2024-01-23 03:31:20 +00:00
|
|
|
sessionScript = ''
|
|
|
|
#!${pkgs.runtimeShell}
|
|
|
|
|
|
|
|
# gnome-session is also looking for RequiredComponents in here.
|
|
|
|
XDG_CONFIG_DIRS=@out@/etc/xdg''${XDG_CONFIG_DIRS:-:$XDG_CONFIG_DIRS}
|
|
|
|
|
|
|
|
# We'll have to force gnome-session to detect our session.
|
|
|
|
XDG_DATA_DIRS=@out@/share''${XDG_DATA_DIRS:-:$XDG_DATA_DIRS}
|
|
|
|
|
|
|
|
${lib.getExe' cfg.package "gnome-session"} ${lib.escapeShellArgs session.extraArgs}
|
|
|
|
'';
|
|
|
|
|
2024-06-05 08:28:46 +00:00
|
|
|
installDesktopFiles =
|
2024-01-23 03:31:20 +00:00
|
|
|
lib.mapAttrsToList
|
|
|
|
(name: component:
|
|
|
|
let
|
2024-06-05 08:28:46 +00:00
|
|
|
desktopPackage = pkgs.makeDesktopItem component.desktopConfig;
|
2024-01-23 03:31:20 +00:00
|
|
|
in
|
|
|
|
''
|
|
|
|
install -Dm0644 ${desktopPackage}/share/applications/*.desktop -t $out/share/applications
|
|
|
|
'')
|
|
|
|
session.components;
|
|
|
|
in
|
2024-06-22 14:30:48 +00:00
|
|
|
pkgs.runCommand "${session.name}-desktop-session-files"
|
2024-01-23 03:31:20 +00:00
|
|
|
{
|
|
|
|
env = {
|
|
|
|
inherit (session) fullName;
|
|
|
|
};
|
|
|
|
inherit displaySession gnomeSession sessionScript;
|
2024-06-22 14:30:48 +00:00
|
|
|
passAsFile = [ "displaySession" "sessionScript" ];
|
2024-05-17 02:43:17 +00:00
|
|
|
passthru.providedSessions = [ session.name ];
|
2024-01-23 03:31:20 +00:00
|
|
|
}
|
|
|
|
''
|
2024-05-17 02:43:17 +00:00
|
|
|
SESSION_SCRIPT="$out/libexec/${session.name}-session"
|
2024-01-23 03:31:20 +00:00
|
|
|
install -Dm0755 "$sessionScriptPath" "$SESSION_SCRIPT"
|
|
|
|
substituteAllInPlace "$SESSION_SCRIPT"
|
|
|
|
|
2024-05-17 02:43:17 +00:00
|
|
|
GNOME_SESSION_FILE="$out/share/gnome-session/sessions/${session.name}.session"
|
2024-06-22 14:30:48 +00:00
|
|
|
install -Dm0644 "$gnomeSession" "$GNOME_SESSION_FILE"
|
2024-01-23 03:31:20 +00:00
|
|
|
|
2024-06-22 14:29:19 +00:00
|
|
|
DISPLAY_SESSION_FILE="$out/share/wayland-sessions/${session.name}.desktop"
|
|
|
|
install -Dm0644 "$displaySessionPath" "$DISPLAY_SESSION_FILE"
|
2024-06-25 14:41:17 +00:00
|
|
|
substituteAllInPlace "$DISPLAY_SESSION_FILE"
|
2024-01-23 03:31:20 +00:00
|
|
|
|
2024-06-05 08:28:46 +00:00
|
|
|
${lib.concatStringsSep "\n" installDesktopFiles}
|
2024-01-23 03:31:20 +00:00
|
|
|
''
|
|
|
|
)
|
|
|
|
cfg.sessions;
|
|
|
|
|
2024-03-07 07:54:04 +00:00
|
|
|
sessionSystemdUnits = lib.concatMapAttrs
|
2024-05-17 02:43:17 +00:00
|
|
|
(_: session:
|
2024-01-23 03:31:20 +00:00
|
|
|
let
|
|
|
|
inherit (utils.systemdUtils.lib)
|
|
|
|
pathToUnit serviceToUnit targetToUnit timerToUnit socketToUnit;
|
2024-04-24 13:05:45 +00:00
|
|
|
|
|
|
|
mkSystemdUnits = name: component: {
|
2024-08-21 10:51:57 +00:00
|
|
|
"${component.id}.service" = serviceToUnit component.systemd.serviceUnit;
|
|
|
|
"${component.id}.target" = targetToUnit component.systemd.targetUnit;
|
|
|
|
} // lib.optionalAttrs (component.systemd.socketUnit != null) {
|
|
|
|
"${component.id}.socket" = socketToUnit component.systemd.socketUnit;
|
|
|
|
} // lib.optionalAttrs (component.systemd.timerUnit != null) {
|
|
|
|
"${component.id}.timer" = timerToUnit component.systemd.timerUnit;
|
|
|
|
} // lib.optionalAttrs (component.systemd.pathUnit != null) {
|
|
|
|
"${component.id}.path" = pathToUnit component.systemd.pathUnit;
|
2024-04-24 13:05:45 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
componentsUnits = lib.concatMapAttrs mkSystemdUnits session.components;
|
2024-01-23 03:31:20 +00:00
|
|
|
in
|
|
|
|
componentsUnits // {
|
2024-08-21 10:51:57 +00:00
|
|
|
"gnome-session@${session.name}.target" = targetToUnit session.systemd.targetUnit;
|
2024-01-23 03:31:20 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
cfg.sessions;
|
2024-01-03 15:30:55 +00:00
|
|
|
in
|
|
|
|
{
|
|
|
|
options.programs.gnome-session = {
|
|
|
|
package = lib.mkOption {
|
|
|
|
type = lib.types.package;
|
|
|
|
default = pkgs.gnome.gnome-session;
|
|
|
|
defaultText = "pkgs.gnome.gnome-session";
|
|
|
|
description = ''
|
|
|
|
The package containing gnome-session binary and systemd units. This
|
2024-01-06 10:56:07 +00:00
|
|
|
module will use the `gnome-session` executable for the generated
|
2024-01-03 15:30:55 +00:00
|
|
|
session script.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
sessions = lib.mkOption {
|
2024-01-23 03:31:20 +00:00
|
|
|
type = with lib.types; attrsOf (submoduleWith {
|
2024-06-25 14:41:17 +00:00
|
|
|
specialArgs = { inherit utils glibKeyfileFormat pkgs; };
|
2024-01-23 03:31:20 +00:00
|
|
|
modules = [ ./submodules/session-type.nix ];
|
2024-07-09 15:19:09 +00:00
|
|
|
shorthandOnlyDefinesConfig = true;
|
2024-01-23 03:31:20 +00:00
|
|
|
});
|
2024-01-03 15:30:55 +00:00
|
|
|
description = ''
|
|
|
|
A set of desktop sessions to be created with
|
|
|
|
{manpage}`gnome-session(1)`. This gnome-session configuration generates
|
|
|
|
both the `.desktop` file and systemd units to be able to support both
|
|
|
|
the built-in and the systemd-managed GNOME session.
|
2024-01-02 12:26:36 +00:00
|
|
|
|
|
|
|
Each of the attribute name will be used as the identifier of the
|
2024-01-20 09:22:49 +00:00
|
|
|
desktop environment.
|
|
|
|
|
|
|
|
::: {.tip}
|
2024-01-26 10:02:03 +00:00
|
|
|
While you can make identifiers in any way, it is encouraged to stick to
|
|
|
|
a naming scheme. The recommended method is a reverse DNS-like scheme
|
|
|
|
preferably with a domain name you own (e.g.,
|
|
|
|
`com.example.MoseyBranch`).
|
2024-01-20 09:22:49 +00:00
|
|
|
:::
|
2024-01-03 15:30:55 +00:00
|
|
|
'';
|
|
|
|
default = { };
|
|
|
|
example = lib.literalExpression ''
|
|
|
|
{
|
2024-01-06 10:56:07 +00:00
|
|
|
"gnome-minimal" = let
|
|
|
|
sessionCfg = config.programs.gnome-session.sessions."gnome-minimal";
|
|
|
|
in
|
|
|
|
{
|
|
|
|
fullName = "GNOME (minimal)";
|
|
|
|
description = "Minimal GNOME session";
|
|
|
|
display = [ "wayland" "xorg" ];
|
|
|
|
extraArgs = [ "--systemd" ];
|
|
|
|
|
|
|
|
requiredComponents =
|
|
|
|
let
|
|
|
|
gsdComponents =
|
|
|
|
builtins.map
|
|
|
|
(gsdc: "org.gnome.SettingsDaemon.''${gsdc}")
|
|
|
|
[
|
|
|
|
"A11ySettings"
|
|
|
|
"Color"
|
|
|
|
"Housekeeping"
|
|
|
|
"Power"
|
|
|
|
"Keyboard"
|
|
|
|
"Sound"
|
|
|
|
"Wacom"
|
|
|
|
"XSettings"
|
|
|
|
];
|
|
|
|
in
|
|
|
|
gsdComponents ++ [ "org.gnome.Shell" ];
|
|
|
|
|
|
|
|
targetUnit = {
|
|
|
|
requires = [ "org.gnome.Shell.target" ];
|
|
|
|
wants = builtins.map (c: "''${c}.target") (lib.lists.remove "org.gnome.Shell" sessionCfg.requiredComponents);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2024-01-02 12:26:36 +00:00
|
|
|
"one.foodogsquared.SimpleWay" = {
|
2024-01-04 09:34:46 +00:00
|
|
|
fullName = "Simple Way";
|
|
|
|
description = "A desktop environment featuring Sway window manager.";
|
2024-01-06 10:56:07 +00:00
|
|
|
display = [ "wayland" ];
|
|
|
|
extraArgs = [ "--systemd" ];
|
|
|
|
|
2024-01-03 15:30:55 +00:00
|
|
|
components = {
|
2024-01-03 03:53:14 +00:00
|
|
|
# This unit is intended to start with gnome-session.
|
2024-01-03 15:30:55 +00:00
|
|
|
window-manager = {
|
|
|
|
script = '''
|
2024-01-06 10:56:07 +00:00
|
|
|
''${lib.getExe' config.programs.sway.package "sway"} --config ''${./config/sway/config}
|
2024-01-03 15:30:55 +00:00
|
|
|
''';
|
|
|
|
description = "An i3 clone for Wayland.";
|
2024-01-06 10:56:07 +00:00
|
|
|
|
|
|
|
serviceUnit = {
|
|
|
|
serviceConfig = {
|
|
|
|
Type = "notify";
|
|
|
|
NotifyAccess = "all";
|
|
|
|
OOMScoreAdjust = -1000;
|
|
|
|
};
|
|
|
|
|
|
|
|
unitConfig = {
|
|
|
|
OnFailure = [ "gnome-session-shutdown.target" ];
|
|
|
|
OnFailureJobMode = "replace-irreversibly";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
targetUnit = {
|
|
|
|
requisite = [ "gnome-session-initialized.target" ];
|
|
|
|
partOf = [ "gnome-session-initialized.target" ];
|
|
|
|
before = [ "gnome-session-initialized.target" ];
|
|
|
|
};
|
2024-01-03 15:30:55 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
desktop-widgets = {
|
|
|
|
script = '''
|
2024-01-06 10:56:07 +00:00
|
|
|
''${lib.getExe' pkgs.ags "ags"} --config ''${./config/ags/config.js}
|
2024-01-03 15:30:55 +00:00
|
|
|
''';
|
|
|
|
description = "A desktop widget system using layer-shell protocol.";
|
2024-01-06 10:56:07 +00:00
|
|
|
|
|
|
|
serviceUnit = {
|
|
|
|
serviceConfig = {
|
|
|
|
OOMScoreAdjust = -1000;
|
|
|
|
};
|
|
|
|
|
|
|
|
path = with pkgs; [ ags ];
|
|
|
|
|
|
|
|
startLimitBurst = 5;
|
|
|
|
startLimitIntervalSec = 15;
|
|
|
|
};
|
|
|
|
|
|
|
|
targetUnit = {
|
|
|
|
requisite = [ "gnome-session-initialized.target" ];
|
|
|
|
partOf = [ "gnome-session-initialized.target" ];
|
|
|
|
before = [ "gnome-session-initialized.target" ];
|
|
|
|
};
|
2024-01-03 15:30:55 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
auth-agent = {
|
2024-01-06 10:56:07 +00:00
|
|
|
script = "''${pkgs.polkit_gnome}/libexec/polkit-gnome-authentication-agent-1";
|
|
|
|
description = "Authentication agent";
|
|
|
|
|
|
|
|
serviceUnit = {
|
|
|
|
startLimitBurst = 5;
|
|
|
|
startLimitIntervalSec = 15;
|
|
|
|
};
|
|
|
|
|
|
|
|
targetUnit = {
|
|
|
|
partOf = [
|
|
|
|
"gnome-session.target"
|
|
|
|
"graphical-session.target"
|
|
|
|
];
|
|
|
|
requisite = [ "gnome-session.target" ];
|
|
|
|
after = [ "gnome-session.target" ];
|
|
|
|
};
|
2024-01-03 15:30:55 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2024-03-07 07:54:27 +00:00
|
|
|
config = lib.mkIf (cfg.sessions != { }) {
|
2024-01-23 03:31:20 +00:00
|
|
|
# Install all of the desktop session files.
|
2024-04-17 05:33:36 +00:00
|
|
|
services.displayManager.sessionPackages = sessionPackages;
|
2024-01-23 03:31:20 +00:00
|
|
|
environment.systemPackages = [ cfg.package ] ++ sessionPackages;
|
2024-01-03 15:30:55 +00:00
|
|
|
|
2024-01-23 03:31:20 +00:00
|
|
|
# Make sure it is searchable within gnome-session.
|
|
|
|
environment.pathsToLink = [ "/share/gnome-session" ];
|
2024-01-03 15:30:55 +00:00
|
|
|
|
2024-01-23 03:31:20 +00:00
|
|
|
# Import those systemd units from gnome-session as well.
|
|
|
|
systemd.packages = [ cfg.package ];
|
2024-01-24 02:41:06 +00:00
|
|
|
|
|
|
|
# We could include the systemd units in the desktop session package (which
|
|
|
|
# is more elegant and surprisingly trivial) but this requires
|
|
|
|
# reimplementing parts of nixpkgs systemd-lib and we're lazy bastards so
|
|
|
|
# no.
|
2024-03-07 07:54:04 +00:00
|
|
|
systemd.user.units = sessionSystemdUnits;
|
2024-01-23 03:31:20 +00:00
|
|
|
};
|
2024-01-03 15:30:55 +00:00
|
|
|
}
|