mirror of
https://github.com/foo-dogsquared/nixos-config.git
synced 2025-01-31 04:58:01 +00:00
programs/gnome-session: init
This commit is contained in:
parent
eaf95b5686
commit
3331c03a08
@ -9,6 +9,7 @@ let
|
||||
./programs/blender.nix
|
||||
./programs/cardboard-wm.nix
|
||||
./programs/distrobox.nix
|
||||
./programs/gnome-session
|
||||
./programs/kiwmi.nix
|
||||
./programs/pop-launcher.nix
|
||||
./programs/wezterm.nix
|
||||
|
463
modules/nixos/programs/gnome-session/default.nix
Normal file
463
modules/nixos/programs/gnome-session/default.nix
Normal file
@ -0,0 +1,463 @@
|
||||
{ config, lib, pkgs, utils, ... }:
|
||||
|
||||
# TODO: Generate the systemd units and place them in the desktop session package.
|
||||
let
|
||||
cfg = config.programs.gnome-session;
|
||||
|
||||
componentsType = { name, config, options, session, ... }: {
|
||||
options = {
|
||||
description = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "One-sentence description of the component.";
|
||||
default = "";
|
||||
example = "Desktop widgets";
|
||||
};
|
||||
|
||||
script = lib.mkOption {
|
||||
type = lib.types.lines;
|
||||
description = ''
|
||||
The script of the component. Take note this will be wrapped in a
|
||||
script for proper integration with `gnome-session`.
|
||||
'';
|
||||
};
|
||||
|
||||
desktopConfig = lib.mkOption {
|
||||
type = lib.types.attrs;
|
||||
description = ''
|
||||
The configuration for the gnome-session desktop file. For more
|
||||
information, look into `makeDesktopItem` nixpkgs builder.
|
||||
|
||||
You should configure this is if you use the built-in service
|
||||
management to be able to customize the session.
|
||||
|
||||
::: {.note}
|
||||
This module appends several options for the desktop item builder such
|
||||
as the script path and `X-GNOME-HiddenUnderSystemd` which is set to
|
||||
`true`.
|
||||
:::
|
||||
'';
|
||||
default = { };
|
||||
example = {
|
||||
extraConfig = {
|
||||
X-GNOME-Autostart-Phase = "WindowManager";
|
||||
X-GNOME-AutoRestart = "true";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
serviceConfig = lib.mkOption {
|
||||
type = lib.types.attrsOf utils.systemdUtils.unitOptions.unitOption;
|
||||
description = ''
|
||||
systemd service configuration to be used in
|
||||
{option}`systemd.user.services.<name>`.
|
||||
|
||||
This should be configured if the session is managed by systemd.
|
||||
'';
|
||||
default = {};
|
||||
};
|
||||
|
||||
targetConfig = lib.mkOption {
|
||||
type = lib.types.attrsOf utils.systemdUtils.unitOptions.unitOption;
|
||||
description = ''
|
||||
systemd target configuration to be used in
|
||||
{option}`systemd.user.target.<name>`.
|
||||
|
||||
This should be configured if the session is managed by systemd.
|
||||
'';
|
||||
default = {};
|
||||
};
|
||||
|
||||
id = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
The identifier of the component used in generating filenames for its
|
||||
`.desktop` files and as part of systemd unit names.
|
||||
'';
|
||||
defaultText = "$${session.name}.$${name}";
|
||||
readOnly = true;
|
||||
};
|
||||
|
||||
scriptPackage = lib.mkOption {
|
||||
type = lib.types.package;
|
||||
readOnly = true;
|
||||
internal = true;
|
||||
description = ''
|
||||
The package containing a wrapped script of the component script.
|
||||
'';
|
||||
};
|
||||
|
||||
desktopPackage = lib.mkOption {
|
||||
type = lib.types.package;
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
description = ''
|
||||
A package containing the desktop item set with
|
||||
{option}`desktopSessions.gnome-session.sessions.<name>.components.<name>.desktopConfig`.
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
id = "${session.prefix}.${name}";
|
||||
|
||||
# Setting some recommendation and requirements for systemd-managed
|
||||
# gnome-session components.
|
||||
serviceConfig = {
|
||||
script = lib.mkAfter "${config.scriptPackage}/bin/${session.prefix}-${name}-script";
|
||||
description = lib.mkDefault config.description;
|
||||
|
||||
path = [ cfg.package ];
|
||||
serviceConfig = {
|
||||
Slice = lib.mkDefault "session.slice";
|
||||
Restart = lib.mkDefault "on-failure";
|
||||
TimeoutStopSec = lib.mkDefault 5;
|
||||
};
|
||||
unitConfig = {
|
||||
# Units managed by gnome-session are required to have CollectMode=
|
||||
# set to this value.
|
||||
CollectMode = lib.mkForce "inactive-or-failed";
|
||||
RefuseManualStart = lib.mkDefault true;
|
||||
RefuseManualStop = lib.mkDefault true;
|
||||
};
|
||||
};
|
||||
|
||||
targetConfig = {
|
||||
description = lib.mkDefault config.description;
|
||||
documentation = [
|
||||
"man:gnome-session(1)"
|
||||
"man:systemd.special(7)"
|
||||
];
|
||||
unitConfig.CollectMode = lib.mkForce "inactive-or-failed";
|
||||
};
|
||||
|
||||
scriptPackage = pkgs.writeShellApplication {
|
||||
name = "${session.prefix}-${name}-script";
|
||||
runtimeInputs = [ cfg.package pkgs.dbus ];
|
||||
text = ''
|
||||
DESKTOP_AUTOSTART_ID="''${DESKTOP_AUTOSTART_ID:-}"
|
||||
echo "$DESKTOP_AUTOSTART_ID"
|
||||
test -n "$DESKTOP_AUTOSTART_ID" && {
|
||||
dbus-send --print-reply --session \
|
||||
--dest=org.gnome.SessionManager "/org/gnome/SessionManager" \
|
||||
org.gnome.SessionManager.RegisterClient \
|
||||
"string:${name}" "string:$DESKTOP_AUTOSTART_ID"
|
||||
}
|
||||
|
||||
${config.script}
|
||||
'';
|
||||
};
|
||||
|
||||
desktopPackage =
|
||||
let
|
||||
defaultDesktopConfig = config.desktopConfig // {
|
||||
name = config.id;
|
||||
desktopName = "${session.fullName} - ${config.description}";
|
||||
exec = config.scriptPackage;
|
||||
noDisplay = true;
|
||||
onlyShowIn = [ "X-${session.fullName}" ];
|
||||
};
|
||||
|
||||
# Basically, more default desktop configuration.
|
||||
applicableDesktopConfig = {
|
||||
# More information can be found in gnome-session(1) manual page.
|
||||
extraConfig = {
|
||||
X-GNOME-AutoRestart = "false";
|
||||
X-GNOME-Autostart-Notify = "true";
|
||||
X-GNOME-Autostart-Phase = "Application";
|
||||
X-GNOME-HiddenUnderSystemd = "true";
|
||||
};
|
||||
};
|
||||
in
|
||||
pkgs.makeDesktopItem
|
||||
(lib.attrsets.recursiveUpdate
|
||||
applicableDesktopConfig
|
||||
defaultDesktopConfig);
|
||||
};
|
||||
};
|
||||
|
||||
sessionType = { name, config, options, ... }: {
|
||||
options = {
|
||||
fullName = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "The (formal) name of the desktop environment.";
|
||||
default = name;
|
||||
example = "Mosey Branch";
|
||||
};
|
||||
|
||||
prefix = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
The identifier of the desktop environment. While it can be in any
|
||||
style, it is encouraged to use a reverse DNS-like scheme.
|
||||
'';
|
||||
example = "com.example.MoseyBranch";
|
||||
};
|
||||
|
||||
description = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = ''
|
||||
A one-sentence description of the desktop environment.
|
||||
'';
|
||||
default = "${config.fullName} desktop environment";
|
||||
defaultText = lib.literalExpression "$${<name>.fullName} desktop environment";
|
||||
example = "A desktop environment featuring a scrolling compositor.";
|
||||
};
|
||||
|
||||
components = lib.mkOption {
|
||||
type = with lib.types; attrsOf (submoduleWith {
|
||||
specialArgs.session = config;
|
||||
modules = [ componentsType ];
|
||||
});
|
||||
description = ''
|
||||
The individual components to be launched with the desktop session. It
|
||||
is heavily patterned after gnome-session.
|
||||
'';
|
||||
default = { };
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
window-manager = {
|
||||
script = '''
|
||||
$${lib.getExe' config.programs.sway.package "sway"}
|
||||
''';
|
||||
description = "An i3 clone for Wayland.";
|
||||
};
|
||||
|
||||
desktop-widgets.script = '''
|
||||
$${lib.getExe' pkgs.ags "ags"} --config $${./config.js}
|
||||
''';
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
extraArgs = lib.mkOption {
|
||||
type = with lib.types; listOf str;
|
||||
description = ''
|
||||
A list of arguments to be added for the session script.
|
||||
|
||||
::: {.note}
|
||||
An argument `--session=<name>` will always be appended into the
|
||||
script.
|
||||
:::
|
||||
'';
|
||||
default = [ "--systemd" ];
|
||||
example = [
|
||||
"--builtin"
|
||||
"--disable-acceleration-check"
|
||||
];
|
||||
};
|
||||
|
||||
targetConfig = lib.mkOption {
|
||||
type = lib.types.attrsOf utils.systemdUtils.unitOptions.unitOption;
|
||||
description = ''
|
||||
systemd target configuration to be used in
|
||||
{option}`systemd.user.target."gnome-session@<name>"`.
|
||||
|
||||
This should be configured if the session is managed by systemd and
|
||||
you want to control the session further (which is recommended since
|
||||
this module don't know what components are more important, etc.).
|
||||
'';
|
||||
default = {
|
||||
description = "${config.fullName} desktop environment";
|
||||
wants = lib.mapAttrsToList (_: component: "${component.id}.target") config.components;
|
||||
};
|
||||
defaultText = ''
|
||||
{
|
||||
description = "$${config.fullName} desktop environment";
|
||||
wants = ... # All of the components.
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
sessionPackage = lib.mkOption {
|
||||
type = lib.types.package;
|
||||
description = ''
|
||||
The collective package containing everything (except the systemd
|
||||
units) desktop-related files such as the Wayland session file,
|
||||
gnome-session `.session` file, and the components `.desktop` file.
|
||||
'';
|
||||
internal = true;
|
||||
readOnly = true;
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
sessionPackage =
|
||||
let
|
||||
installDesktops = lib.mapAttrsToList
|
||||
(_: p: ''
|
||||
install -Dm0644 ${p.desktopPackage}/share/applications/*.desktop -t $out/share/applications
|
||||
'')
|
||||
config.components;
|
||||
|
||||
requiredComponents = lib.mapAttrsToList
|
||||
(_: component: component.id)
|
||||
config.components;
|
||||
|
||||
gnomeSession = pkgs.writeText "${name}-gnome-session" ''
|
||||
[GNOME Session]
|
||||
Name=${config.fullName} session
|
||||
RequiredComponents=${lib.concatStringsSep ";" requiredComponents};
|
||||
'';
|
||||
|
||||
waylandSession = pkgs.writeText "${name}-wayland-session" ''
|
||||
[Desktop Entry]
|
||||
Name=${config.fullName}
|
||||
Comment=${config.description}
|
||||
Exec=@out@/libexec/${name}-session
|
||||
Type=Application
|
||||
'';
|
||||
|
||||
sessionScript = pkgs.writeShellScript "${name}-session" ''
|
||||
# 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 config.extraArgs} --session=${name}
|
||||
'';
|
||||
in
|
||||
pkgs.runCommandLocal "${name}-gnome-session"
|
||||
{ passthru.providedSessions = [ name ]; }
|
||||
''
|
||||
SESSION_SCRIPT="$out/libexec/${name}-session"
|
||||
GNOME_SESSION_FILE="$out/share/gnome-session/sessions/${name}.session"
|
||||
WAYLAND_SESSION_FILE="$out/share/wayland-sessions/${name}.desktop"
|
||||
|
||||
install -Dm0755 "${sessionScript}" "$SESSION_SCRIPT"
|
||||
substituteAllInPlace "$SESSION_SCRIPT"
|
||||
|
||||
install -Dm0644 "${gnomeSession}" "$GNOME_SESSION_FILE"
|
||||
substituteAllInPlace "$GNOME_SESSION_FILE"
|
||||
|
||||
install -Dm0644 "${waylandSession}" "$WAYLAND_SESSION_FILE"
|
||||
substituteAllInPlace "$WAYLAND_SESSION_FILE"
|
||||
|
||||
${lib.concatStringsSep "\n" installDesktops}
|
||||
'';
|
||||
};
|
||||
};
|
||||
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
|
||||
also contains the `gnome-session` executable used for the generated
|
||||
session script.
|
||||
'';
|
||||
};
|
||||
|
||||
sessions = lib.mkOption {
|
||||
type = with lib.types; attrsOf (submodule sessionType);
|
||||
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.
|
||||
'';
|
||||
default = { };
|
||||
example = lib.literalExpression ''
|
||||
{
|
||||
simple-way = {
|
||||
prefix = "one.foodogsquared.SimpleWay";
|
||||
components = {
|
||||
window-manager = {
|
||||
script = '''
|
||||
$${lib.getExe' config.programs.sway.package "sway"}
|
||||
''';
|
||||
description = "An i3 clone for Wayland.";
|
||||
};
|
||||
|
||||
desktop-widgets = {
|
||||
script = '''
|
||||
$${lib.getExe' pkgs.ags "ags"} --config $${./config.js}
|
||||
''';
|
||||
description = "A desktop widget system using layer-shell protocol.";
|
||||
};
|
||||
|
||||
auth-agent = {
|
||||
script = '''
|
||||
$${lib.getExe' pkgs.polkit_gnome "polkit-gnome-authentication-agent-1"}
|
||||
''';
|
||||
description = "Polkit authentication agent";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf (cfg.sessions != { })
|
||||
(
|
||||
let
|
||||
sessionPackages = lib.mapAttrsToList
|
||||
(_: session:
|
||||
session.sessionPackage)
|
||||
cfg.sessions;
|
||||
|
||||
generateServiceBundle = acc: name: session:
|
||||
let
|
||||
services =
|
||||
lib.mapAttrs'
|
||||
generateComponentService
|
||||
session.components;
|
||||
|
||||
generateComponentService = name: component:
|
||||
let
|
||||
serviceConfig = lib.mkMerge [
|
||||
{
|
||||
before = [ "${component.id}.target" ];
|
||||
partOf = [ "${component.id}.target" ];
|
||||
}
|
||||
component.serviceConfig
|
||||
];
|
||||
in
|
||||
lib.nameValuePair component.id serviceConfig;
|
||||
in
|
||||
acc // services;
|
||||
|
||||
generateTargetBundle = acc: name: session:
|
||||
let
|
||||
targets =
|
||||
lib.mapAttrs'
|
||||
generateComponentTarget
|
||||
session.components;
|
||||
|
||||
generateComponentTarget = name: component:
|
||||
let
|
||||
targetConfig = lib.mkMerge [
|
||||
{
|
||||
wants = [ "${component.id}.service" ];
|
||||
}
|
||||
component.targetConfig
|
||||
];
|
||||
in
|
||||
lib.nameValuePair component.id targetConfig;
|
||||
in
|
||||
acc // targets // {
|
||||
"gnome-session@${name}" = session.targetConfig;
|
||||
};
|
||||
in
|
||||
{
|
||||
# Install all of the desktop session files.
|
||||
services.xserver.displayManager.sessionPackages = sessionPackages;
|
||||
environment.systemPackages = sessionPackages;
|
||||
|
||||
# Make sure it is searchable within gnome-session.
|
||||
environment.pathsToLink = [ "/share/gnome-session" ];
|
||||
|
||||
# Import those systemd units from gnome-session as well.
|
||||
systemd.packages = [ cfg.package ]; #++ sessionPackages;
|
||||
|
||||
# Most importantly for systemd-managed gnome-session sessions, generate
|
||||
# those services.
|
||||
systemd.user.services = lib.foldlAttrs generateServiceBundle { } cfg.sessions;
|
||||
systemd.user.targets = lib.foldlAttrs generateTargetBundle { } cfg.sessions;
|
||||
}
|
||||
);
|
||||
}
|
Loading…
Reference in New Issue
Block a user