[bug#77266,v3,1/2] gnu: Merge xorg configurations when extending.

Message ID 20250420062123.22442-2-ian@retrospec.tv
State New
Headers
Series gnu: Merge xorg configurations when extending. |

Commit Message

Ian Eure April 20, 2025, 6:21 a.m. UTC
  Configuration for xorg is embedded in the various display-manager
configuration records, and extension support is factored out into the
`handle-xorg-configuration' macro.  However, the extension mechanism replaces
the existing xorg-configuration with the supplied one, making it impossible to
compose configuration from multiple sources.  This patch adds a procedure to
merge two xorg-configuration records, and calls it within
handle-xorg-configuration, allowing the config to be built piecemeal.

* gnu/services/xorg.scm (merge-xorg-configurations): New variable.
(handle-xorg-configuration): Merge xorg configs.
* doc/guix.texi (X Window): Document xorg-configuration composition.

Change-Id: I20e9db911eef5d4efe98fdf382f3084e4defc1ba
---
 doc/guix.texi         | 49 +++++++++++++++++++++++++++++++++++++++++--
 gnu/services/xorg.scm | 42 ++++++++++++++++++++++++++++++-------
 2 files changed, 82 insertions(+), 9 deletions(-)
  

Comments

Ludovic Courtès April 21, 2025, 10:12 p.m. UTC | #1
Hi,

Ian Eure <ian@retrospec.tv> writes:

> Configuration for xorg is embedded in the various display-manager
> configuration records, and extension support is factored out into the
> `handle-xorg-configuration' macro.  However, the extension mechanism replaces
> the existing xorg-configuration with the supplied one, making it impossible to
> compose configuration from multiple sources.  This patch adds a procedure to
> merge two xorg-configuration records, and calls it within
> handle-xorg-configuration, allowing the config to be built piecemeal.
>
> * gnu/services/xorg.scm (merge-xorg-configurations): New variable.
> (handle-xorg-configuration): Merge xorg configs.
> * doc/guix.texi (X Window): Document xorg-configuration composition.
>
> Change-Id: I20e9db911eef5d4efe98fdf382f3084e4defc1ba
> +   (append
> +       (list (service gdm-service-type)
> +          %xorg-intel-service
> +          %xorg-keyboard-service)

Nitpick: indentation is off.  :-)

>  (define (xorg-configuration->file config)
>    "Compute an Xorg configuration file corresponding to CONFIG, an
>  <xorg-configuration> record."
> @@ -334,9 +362,12 @@ (define (expand modules)
>                             port)
>                    (newline port)))
>  
> -              (for-each (lambda (config)
> -                          (display config port))
> -                        '#$(xorg-configuration-extra-config config))))))
> +              (for-each
> +               (lambda (config)
> +                 (display config port)
> +                 (newline port))
> +               (delete-duplicates
> +                '#$(xorg-configuration-extra-config config)))))))

I think ‘delete-duplicates’ should be used for drivers, modules, and
fonts, but not for ‘extra-config’ (which is merely a string).

Does that make sense?

Thanks,
Ludo’.
  

Patch

diff --git a/doc/guix.texi b/doc/guix.texi
index eebc1a1590..02150eb497 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -138,6 +138,7 @@  Copyright @copyright{} 2024 45mg@*
 Copyright @copyright{} 2025 Sören Tempel@*
 Copyright @copyright{} 2025 Rostislav Svoboda@*
 Copyright @copyright{} 2025 Zacchaeus@*
+Copyright @copyright{} 2025 Ian Eure@*
 
 Permission is granted to copy, distribute and/or modify this document
 under the terms of the GNU Free Documentation License, Version 1.3 or
@@ -24916,8 +24917,52 @@  Tell the log-in manager (of type @var{login-manager-service-type}) to use
 @var{config}, an @code{<xorg-configuration>} record.
 
 Since the Xorg configuration is embedded in the log-in manager's
-configuration---e.g., @code{gdm-configuration}---this procedure provides a
-shorthand to set the Xorg configuration.
+configuration---e.g., @code{gdm-configuration}---this procedure provides
+a shorthand to set the Xorg configuration.
+
+In addition to @code{set-xorg-configuration}, you may extend your log-in
+manager’s service-type to provide reusable, partial configurations,
+which are concatenated to create the final Xorg configuration:
+
+@lisp
+;; A service which configures Intel video drivers.
+(define %xorg-intel-service
+  (simple-service
+   'xorg-intel
+   gdm-service-type
+   (xorg-configuration
+    (modules (list xf86-video-intel))
+    (drivers '("intel"))
+    (extra-config
+    "
+    Section \"Device\"
+        Identifier \"Intel GPU\"
+        Driver \"intel\"
+        Option \"TearFree\" \"true\"
+    EndSection"))))
+
+;; A service which configures the keyboard.
+(define %xorg-keyboard-service
+  (simple-service
+   'xorg-keyboard
+   gdm-service-type
+   (xorg-configuration
+    (keyboard-layout
+     (keyboard-layout "us" #:options '("ctrl:nocaps"))))))
+
+(operating-system
+  (services
+   (append
+       (list (service gdm-service-type)
+          %xorg-intel-service
+          %xorg-keyboard-service)
+    %base-services))
+  @dots{})
+@end lisp
+
+Service extension and @code{set-xorg-configuration} can each be used
+seperately, or in conjunction.
+
 @end deffn
 
 @deffn {Procedure} xorg-start-command [config]
diff --git a/gnu/services/xorg.scm b/gnu/services/xorg.scm
index bef05b9bb9..cb933693b7 100644
--- a/gnu/services/xorg.scm
+++ b/gnu/services/xorg.scm
@@ -209,6 +209,34 @@  (define-record-type* <xorg-configuration>
   (server-arguments xorg-configuration-server-arguments ;list of strings
                     (default %default-xorg-server-arguments)))
 
+(define (merge-xorg-configurations a b)
+  (let ((configs (list b a)))           ; Prefer later configurations.
+    (xorg-configuration
+     (modules
+      (append-map xorg-configuration-modules configs))
+     (fonts
+      (append-map xorg-configuration-fonts configs))
+     (drivers
+      (append-map xorg-configuration-drivers configs))
+     (resolutions
+      (append-map xorg-configuration-resolutions configs))
+     (extra-config (append-map xorg-configuration-extra-config configs))
+     ;; Prefer the more recently set layout.
+     (keyboard-layout (or (xorg-configuration-keyboard-layout b)
+                          (xorg-configuration-keyboard-layout a)
+                          #f))
+     (server
+      ;; Prefer the non-default server.
+      (if (eq? xorg-server (xorg-configuration-server a))
+          (xorg-configuration-server b)
+          (xorg-configuration-server a)))
+     (server-arguments
+      ;; Prefer the non-default arguments.
+      (if (eq? %default-xorg-server-arguments
+             (xorg-configuration-server-arguments a))
+          (xorg-configuration-server-arguments b)
+          (xorg-configuration-server-arguments a))))))
+
 (define (xorg-configuration->file config)
   "Compute an Xorg configuration file corresponding to CONFIG, an
 <xorg-configuration> record."
@@ -334,9 +362,12 @@  (define (expand modules)
                            port)
                   (newline port)))
 
-              (for-each (lambda (config)
-                          (display config port))
-                        '#$(xorg-configuration-extra-config config))))))
+              (for-each
+               (lambda (config)
+                 (display config port)
+                 (newline port))
+               (delete-duplicates
+                '#$(xorg-configuration-extra-config config)))))))
 
     (computed-file "xserver.conf" build)))
 
@@ -628,10 +659,7 @@  (define-syntax handle-xorg-configuration
     ((_ configuration-record service-type-definition)
      (service-type
        (inherit service-type-definition)
-       (compose (lambda (extensions)
-                  (match extensions
-                    (() #f)
-                    ((config . _) config))))
+       (compose (cut reduce merge-xorg-configurations #f <>))
        (extend (lambda (config xorg-configuration)
                  (if xorg-configuration
                      (configuration-record