summary refs log tree commit diff
diff options
context:
space:
mode:
authorworldofpeace <worldofpeace@protonmail.ch>2019-11-13 22:14:42 -0500
committerworldofpeace <worldofpeace@protonmail.ch>2019-11-22 17:47:03 -0500
commitd8b50bfe47004c7b68f17e1f43a6fa4c4c159be4 (patch)
tree607c0cf607e30cefe2f76a284eda499d1f32d602
parenta20db2bcd34c6ab3dcd71fc33e087e6bf12b0492 (diff)
downloadnixpkgs-d8b50bfe47004c7b68f17e1f43a6fa4c4c159be4.tar
nixpkgs-d8b50bfe47004c7b68f17e1f43a6fa4c4c159be4.tar.gz
nixpkgs-d8b50bfe47004c7b68f17e1f43a6fa4c4c159be4.tar.bz2
nixpkgs-d8b50bfe47004c7b68f17e1f43a6fa4c4c159be4.tar.lz
nixpkgs-d8b50bfe47004c7b68f17e1f43a6fa4c4c159be4.tar.xz
nixpkgs-d8b50bfe47004c7b68f17e1f43a6fa4c4c159be4.tar.zst
nixpkgs-d8b50bfe47004c7b68f17e1f43a6fa4c4c159be4.zip
nixos/gdm: make desktopManager.default work
Unfortunately, you can't configure the default user-session
with GDM like lightdm. I've opened a feature request [0]
but I'd like to be able to do this now.

We use a GObject Python script using bindings to AccountsService
to achieve this. I'm hoping the reliable heuristic for session names
is the file's basename. We also have some special logic for which
method to use to set the default session. It seems set_x_session is
deprecated, and thusly the XSession key, but if that method isn't used
when it's an xsession it won't be the default in GDM.

[0]: https://gitlab.gnome.org/GNOME/gdm/issues/535
-rw-r--r--nixos/modules/services/x11/display-managers/gdm.nix40
-rwxr-xr-xnixos/modules/services/x11/display-managers/set-session.py85
2 files changed, 125 insertions, 0 deletions
diff --git a/nixos/modules/services/x11/display-managers/gdm.nix b/nixos/modules/services/x11/display-managers/gdm.nix
index e5990aec4b9..0af9ccfcf3e 100644
--- a/nixos/modules/services/x11/display-managers/gdm.nix
+++ b/nixos/modules/services/x11/display-managers/gdm.nix
@@ -31,6 +31,44 @@ let
     load-module module-position-event-sounds
   '';
 
+  dmDefault = config.services.xserver.desktopManager.default;
+  wmDefault = config.services.xserver.windowManager.default;
+  hasDefaultUserSession = dmDefault != "none" || wmDefault != "none";
+  defaultSessionName = dmDefault + optionalString (wmDefault != "none") ("+" + wmDefault);
+
+  setSessionScript = pkgs.python3.pkgs.buildPythonApplication {
+    name = "set-session";
+
+    format = "other";
+
+    src = ./set-session.py;
+
+    dontUnpack = true;
+
+    strictDeps = false;
+
+    nativeBuildInputs = with pkgs; [
+      wrapGAppsHook
+      gobject-introspection
+    ];
+
+    buildInputs = with pkgs; [
+      accountsservice
+      glib
+    ];
+
+    propagatedBuildInputs = with pkgs.python3.pkgs; [
+      pygobject3
+      ordered-set
+    ];
+
+    installPhase = ''
+      mkdir -p $out/bin
+      cp $src $out/bin/set-session
+      chmod +x $out/bin/set-session
+    '';
+  };
+
 in
 
 {
@@ -156,6 +194,8 @@ in
           cat - > /run/gdm/.config/gnome-initial-setup-done <<- EOF
           yes
           EOF
+        '' + optionalString hasDefaultUserSession ''
+          ${setSessionScript}/bin/set-session ${defaultSessionName}
         '';
       };
 
diff --git a/nixos/modules/services/x11/display-managers/set-session.py b/nixos/modules/services/x11/display-managers/set-session.py
new file mode 100755
index 00000000000..1c0810fadbf
--- /dev/null
+++ b/nixos/modules/services/x11/display-managers/set-session.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+
+import gi, argparse, os, logging, sys
+
+gi.require_version("AccountsService", "1.0")
+from gi.repository import AccountsService, GLib
+from ordered_set import OrderedSet
+
+
+def get_session_file(session):
+    system_data_dirs = GLib.get_system_data_dirs()
+
+    session_dirs = OrderedSet(
+        os.path.join(data_dir, session)
+        for data_dir in system_data_dirs
+        for session in {"wayland-sessions", "xsessions"}
+    )
+
+    session_files = OrderedSet(
+        os.path.join(dir, session + ".desktop")
+        for dir in session_dirs
+        if os.path.exists(os.path.join(dir, session + ".desktop"))
+    )
+
+    # Deal with duplicate wayland-sessions and xsessions.
+    # Needed for the situation in gnome-session, where there's
+    # a xsession named the same as a wayland session.
+    if any(map(is_session_wayland, session_files)):
+        session_files = OrderedSet(
+            session for session in session_files if is_session_wayland(session)
+        )
+    else:
+        session_files = OrderedSet(
+            session for session in session_files if is_session_xsession(session)
+        )
+
+    if len(session_files) == 0:
+        logging.warning("No session files are found.")
+        sys.exit(0)
+    else:
+        return session_files[0]
+
+
+def is_session_xsession(session_file):
+    return "/xsessions/" in session_file
+
+
+def is_session_wayland(session_file):
+    return "/wayland-sessions/" in session_file
+
+
+def main():
+    parser = argparse.ArgumentParser(
+        description="Set session type for all normal users."
+    )
+    parser.add_argument("session", help="Name of session to set.")
+
+    args = parser.parse_args()
+
+    session = getattr(args, "session")
+    session_file = get_session_file(session)
+
+    user_manager = AccountsService.UserManager.get_default()
+    users = user_manager.list_users()
+
+    for user in users:
+        if user.is_system_account():
+            continue
+        else:
+            if is_session_wayland(session_file):
+                logging.debug(
+                    f"Setting session name: {session}, as we found the existing wayland-session: {session_file}"
+                )
+                user.set_session(session)
+            elif is_session_xsession(session_file):
+                logging.debug(
+                    f"Setting session name: {session}, as we found the existing xsession: {session_file}"
+                )
+                user.set_x_session(session)
+            else:
+                raise Exception(f"Couldn't figure out session type for {session_file}")
+
+
+if __name__ == "__main__":
+    main()