(define-module (ruther home services gtk)
#:use-module (gnu services configuration)
#:use-module (gnu services)
#:use-module (guix packages)
#:use-module (guix gexp)
#:use-module (guix build-system trivial)
#:use-module (gnu home services)
#:use-module (ruther home services dconf)
#:export (home-gtk-configuration
gtk-theme-configuration
home-gtk-service-type))
(define (maybe-string? str)
(or (nil? str)
(string? str)))
(define (maybe-package? pkg)
(or (nil? pkg)
(package? pkg)))
(define-configuration/no-serialization gtk-theme-configuration
(package (maybe-package #f) "The package to add to profile, including theme {name}")
(name (maybe-string #f) "Name of the theme")
(size (integer 16) "Size of the pointer. Applies only for cursor-theme"))
(define-configuration/no-serialization home-gtk-configuration
(gtk-theme
(gtk-theme-configuration (gtk-theme-configuration))
"The theme")
(icon-theme
(gtk-theme-configuration (gtk-theme-configuration))
"The icon theme")
(cursor-theme
(gtk-theme-configuration (gtk-theme-configuration))
"The cursor theme")
(font-name
(maybe-string #f)
"Name of the font to use"))
(define* (serialize-field name value #:key (gtk2? #f))
(if gtk2?
(format #f "~a = \"~a\"~%" name value)
(format #f "~a = ~a~%" name value)))
(define* (serialize-cons field #:key (gtk2? #f))
(serialize-field (car field) (cdr field) #:gtk2? gtk2?))
(define (gtk4-css-import-file theme-package theme-name)
`("gtk.css"
"@import url(\"file://" ,theme-package "/share/themes/" ,theme-name "/gtk-4.0/gtk.css\");"))
(define (map-gtk-configuration-to-gtk-config config)
(filter (lambda (x) (not (nil? (cdr x))))
`((gtk-theme-name . ,(gtk-theme-configuration-name (home-gtk-configuration-gtk-theme config)))
(gtk-icon-theme-name . ,(gtk-theme-configuration-name (home-gtk-configuration-icon-theme config)))
(gtk-cursor-theme-name . ,(gtk-theme-configuration-name (home-gtk-configuration-cursor-theme config)))
(gtk-cursor-theme-size . ,(gtk-theme-configuration-size (home-gtk-configuration-cursor-theme config)))
(gtk-font-name . ,(home-gtk-configuration-font-name config)))))
(define* (serialize-gtk-config config #:key (gtk2? #f))
(let* ((mapped (map-gtk-configuration-to-gtk-config config))
(serialized (map (lambda (x) (serialize-cons x #:gtk2? gtk2?)) mapped)))
(if gtk2?
serialized
(cons* "[Settings]\n"
serialized))))
(define (add-gtk-theme-packages config)
(filter
(lambda (x) (not (nil? x)))
(list
(gtk-theme-configuration-package (home-gtk-configuration-gtk-theme config))
(gtk-theme-configuration-package (home-gtk-configuration-icon-theme config))
(gtk-theme-configuration-package (home-gtk-configuration-cursor-theme config))
(if (nil? (gtk-theme-configuration-name (home-gtk-configuration-cursor-theme config)))
'()
(package
(name "default-icon-inherits")
(version "0.0.0")
(source #f)
(build-system trivial-build-system)
(home-page #f)
(synopsis #f)
(description #f)
(license #f)
(arguments
(list
#:builder
(with-imported-modules
'((guix build utils))
#~(begin
(use-modules (guix build utils))
(mkdir-p (string-append #$output "/share/icons/default"))
(call-with-output-file (string-append #$output "/share/icons/default/index.theme")
(lambda (port)
(format port
"[Icon Theme]~%Name=Default~%Comment=Default cursor theme~%Inherits=~a~%"
#$(gtk-theme-configuration-name (home-gtk-configuration-cursor-theme config))))))))))))))
(define (add-xcursor-environment config)
(let* ((cursor-theme (home-gtk-configuration-cursor-theme config))
(cursor-name (gtk-theme-configuration-name cursor-theme))
(cursor-package (gtk-theme-configuration-package cursor-theme))
(cursor-size (gtk-theme-configuration-size cursor-theme)))
(if (nil? cursor-name)
'()
`(("GTK2_RC_FILES" . "$HOME/.gtkrc-2.0")
("XCURSOR_THEME" . ,cursor-name)
("XCURSOR_SIZE" . ,(format #f "~a" cursor-size)))))) ;; TODO: this path should not be hardcoded here
(define (add-gtk-config-file config)
(append
`((".gtkrc-2.0"
,(apply mixed-text-file (cons* "gtkrc-2.0" (serialize-gtk-config config #:gtk2? #t))))
(".config/gtk-3.0/settings.ini"
,(apply mixed-text-file (cons* "settings.ini" (serialize-gtk-config config))))
(".config/gtk-4.0/settings.ini"
,(apply mixed-text-file (cons* "settings.ini" (serialize-gtk-config config)))))
(if (nil? (gtk-theme-configuration-package (home-gtk-configuration-gtk-theme config)))
'()
`((".config/gtk-4.0/gtk.css"
,(apply mixed-text-file (gtk4-css-import-file
(gtk-theme-configuration-package (home-gtk-configuration-gtk-theme config))
(gtk-theme-configuration-name (home-gtk-configuration-gtk-theme config)))))))))
(define (add-gtk-dconf-config config)
(let* ((data `((font-name . ,(home-gtk-configuration-font-name config))
(gtk-theme . ,(gtk-theme-configuration-name (home-gtk-configuration-gtk-theme config)))
(cursor-theme . ,(gtk-theme-configuration-name (home-gtk-configuration-cursor-theme config)))
(icon-theme . ,(gtk-theme-configuration-name (home-gtk-configuration-icon-theme config)))))
(filtered-data (filter (lambda (x) (not (nil? (cdr x)))) data)))
`((org/gnome/desktop/interface
,filtered-data))))
(define-public home-gtk-service-type
(service-type (name 'home-gtk)
(extensions
(list (service-extension
home-files-service-type
add-gtk-config-file)
(service-extension
home-dconf-service-type
add-gtk-dconf-config)
(service-extension
home-profile-service-type
add-gtk-theme-packages)
(service-extension
home-environment-variables-service-type
add-xcursor-environment)))
(description "Create gtk theme configuration files for gtk2 and gtk3")))