From dc230feace74253361b072a411ce6578141f4ea0 Mon Sep 17 00:00:00 2001 From: Fabio Scotto di Santolo Date: Wed, 1 Jul 2026 23:48:11 +0200 Subject: [PATCH] Add XFCE optional desktop --- AGENTS.md | 10 +- README.md | 16 +- ansible/inventory/group_vars/desktop.yml | 29 +++ ansible/inventory/group_vars/void.yml | 23 ++ ansible/roles/packages_void/tasks/main.yml | 80 ++++--- .../profile_desktop_common/tasks/main.yml | 12 +- .../roles/profile_desktop_kde/tasks/main.yml | 8 +- .../roles/profile_desktop_xfce/tasks/main.yml | 223 ++++++++++++++++++ .../templates/lightdm-gtk-greeter.conf.j2 | 7 + .../templates/lightdm-xfce.conf.j2 | 3 + .../templates/terminalrc.j2 | 15 ++ .../templates/xfce4-desktop.xml.j2 | 18 ++ .../templates/xfwm4.xml.j2 | 21 ++ .../templates/xsettings.xml.j2 | 20 ++ ansible/roles/services_runit/tasks/main.yml | 72 ++++-- ansible/site.yml | 1 + dotfiles/desktop/.config/Thunar/uca.xfce.xml | 15 ++ .../xfce4-keyboard-shortcuts.xml | 33 +++ .../xfce-perchannel-xml/xfce4-notifyd.xml | 11 + .../xfce-perchannel-xml/xfce4-panel.xml | 57 +++++ .../xfce4-power-manager.xml | 9 + .../xfce-perchannel-xml/xfce4-session.xml | 12 + dotfiles/desktop/.emacs.d/init.el | 1 + dotfiles/desktop/.emacs.d/lisp/core/modal.el | 16 ++ .../.local/share/backgrounds/xfce-dark.svg | 4 + 25 files changed, 642 insertions(+), 74 deletions(-) create mode 100644 ansible/roles/profile_desktop_xfce/tasks/main.yml create mode 100644 ansible/roles/profile_desktop_xfce/templates/lightdm-gtk-greeter.conf.j2 create mode 100644 ansible/roles/profile_desktop_xfce/templates/lightdm-xfce.conf.j2 create mode 100644 ansible/roles/profile_desktop_xfce/templates/terminalrc.j2 create mode 100644 ansible/roles/profile_desktop_xfce/templates/xfce4-desktop.xml.j2 create mode 100644 ansible/roles/profile_desktop_xfce/templates/xfwm4.xml.j2 create mode 100644 ansible/roles/profile_desktop_xfce/templates/xsettings.xml.j2 create mode 100644 dotfiles/desktop/.config/Thunar/uca.xfce.xml create mode 100644 dotfiles/desktop/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-keyboard-shortcuts.xml create mode 100644 dotfiles/desktop/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-notifyd.xml create mode 100644 dotfiles/desktop/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-panel.xml create mode 100644 dotfiles/desktop/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-power-manager.xml create mode 100644 dotfiles/desktop/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-session.xml create mode 100644 dotfiles/desktop/.emacs.d/lisp/core/modal.el create mode 100644 dotfiles/desktop/.local/share/backgrounds/xfce-dark.svg diff --git a/AGENTS.md b/AGENTS.md index c49adaa..b7d813a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -52,7 +52,7 @@ Ansible-driven personal infrastructure repo for Void desktops, Linux workstation - Use `no_log: true` for secret-bearing task inputs or outputs. ## Desktop Notes -- `desktop_environment` selects the mutually exclusive `minimal` (default) or `kde` desktop mode. `profile_desktop_common` owns shared bootstrap; the minimal mode uses `profile_desktop_sway` and `profile_desktop_hyprland`, while `profile_desktop_kde` owns KDE-specific defaults and cleanup. `desktop_sessions_enabled` and `desktop_default_session` apply only to the minimal mode. +- `desktop_environment` selects the mutually exclusive `minimal` (default), `xfce`, or `kde` desktop mode. `profile_desktop_common` owns shared bootstrap; the minimal mode uses `profile_desktop_sway` and `profile_desktop_hyprland`, `profile_desktop_xfce` owns the reproducible XFCE setup, and `profile_desktop_kde` owns KDE-specific defaults and cleanup. `desktop_sessions_enabled` and `desktop_default_session` apply only to the minimal mode. - `.emacs.d` is deployed by a dedicated `profile_desktop_common` task tagged `emacs`. - NTFS filesystem support is provided by `ntfs-3g` in `ansible/inventory/group_vars/void.yml`. - Void user services are managed by `turnstile` and live under `dotfiles/desktop/.config/service/`. @@ -60,17 +60,17 @@ Ansible-driven personal infrastructure repo for Void desktops, Linux workstation - Critical session entrypoints: - `dotfiles/desktop/.config/sway/config` plus `host.conf` and `session-env` deployed via `host_sway_dotfiles` (sway / Wayland) - `dotfiles/desktop/.config/hypr/hyprland.conf` plus `host.conf` and `session-env` deployed via `host_hyprland_dotfiles` (Hyprland / Wayland) -- Do not switch or restart a display manager during a playbook run from an active graphical session. Changing between `emptty` and SDDM requires an explicit run from another TTY/SSH session with `desktop_allow_display_manager_switch=true`. +- Do not switch or restart a display manager during a playbook run from an active graphical session. Changing among `emptty`, LightDM, and SDDM requires an explicit run from another TTY/SSH session with `desktop_allow_display_manager_switch=true`. Apply managed XFCE XML while logged out of XFCE so `xfconfd` cannot overwrite it from its in-memory state. - `nymph` is a Void laptop with NVIDIA Optimus, running sway (Wayland) and Hyprland (Wayland); host-specific tasks in `profile_desktop_host/tasks/nymph.yml` handle GRUB NVIDIA cmdline params, `prime-run` wrapper, and the WirePlumber camera priority config. Multi-monitor on sway is driven by `kanshi` (config deployed via `host_sway_dotfiles`), and on Hyprland by host-specific Hyprland monitor/workspace rules. ## Void Package And Dotfile Bucket Rules The Void desktop package lists in `ansible/inventory/group_vars/void.yml` are kept disjoint by role: - `void_packages_base` — system runtime only (init/services, kernel, audio core, networking, filesystem, firewall, hardware daemons, runit logging). -- `desktop_common_packages` — GUI infrastructure shared by minimal and KDE modes. -- `desktop_minimal_packages` / `desktop_kde_packages` — mutually exclusive applications, integration components, and display managers. +- `desktop_common_packages` — GUI infrastructure shared by all desktop modes. +- `desktop_minimal_packages` / `desktop_xfce_packages` / `desktop_kde_packages` — mutually exclusive applications, integration components, and display managers. Packages required by more than one exclusive mode may be repeated; cleanup subtracts the selected mode before removing inactive packages. - `desktop_sway_packages` / `desktop_hyprland_packages` — binaries specific to each session. Cross-WM packages used by both (such as `dunst`, `rofi`, and `foot`) are intentionally duplicated in the two lists. `profile_packages` in the same file is cross-distro and is overridden by `group_vars/server.yml` and the workstation group vars; do not move desktop-specific Void entries through it. -The dotfile vars follow the same split: `desktop_common_dotfiles` carries mode-independent content, while `desktop_minimal_dotfiles` carries Thunar, Udiskie, and minimal MIME defaults. KDE uses its own MIME defaults. `desktop_void_dotfiles` remains reserved for files that need the Void runtime. +The dotfile vars follow the same split: `desktop_common_dotfiles` carries mode-independent content, `desktop_minimal_dotfiles` carries Thunar, Udiskie, and minimal MIME defaults, and `desktop_xfce_dotfiles` carries XFCE state. KDE uses its own MIME defaults. `desktop_void_dotfiles` remains reserved for files that need the Void runtime. ## Workstation Notes - Native Linux workstation hosts can combine `workstation_host_linux` with an OS-specific dev group. diff --git a/README.md b/README.md index 8f62a4d..66f1961 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,7 @@ Sistema operativo: Modalita desktop: - `minimal`: sway (Wayland) + Hyprland (Wayland), gestite da `emptty` +- `xfce`: XFCE puro con look scuro e sobrio, gestito da LightDM - `kde`: KDE Plasma, gestito da SDDM Macchine: @@ -80,18 +81,20 @@ Macchine: - `ikaros` - `nymph` -Queste macchine condividono la stessa configurazione base desktop e vengono mantenute allineate tramite Ansible. `desktop_environment` seleziona in modo esclusivo `minimal` (default) oppure `kde`. Nella modalita minimale Sway/SwayFX e Hyprland sono installate in parallelo e selezionabili da `emptty`; `desktop_default_session` decide quale sessione viene preselezionata al login. +Queste macchine condividono la stessa configurazione base desktop e vengono mantenute allineate tramite Ansible. `desktop_environment` seleziona in modo esclusivo `minimal` (default), `xfce` oppure `kde`. Nella modalita minimale Sway/SwayFX e Hyprland sono installate in parallelo e selezionabili da `emptty`; `desktop_default_session` decide quale sessione viene preselezionata al login. XFCE usa direttamente la sessione `xfce` tramite LightDM. Lo stato attuale del profilo desktop include, tra le altre cose: - dotfiles comuni e desktop - sessioni sway e Hyprland su entrambi gli host in modalita `minimal` - KDE Plasma con applicazioni KDE curate e SDDM disponibile come alternativa esclusiva +- XFCE con pannello, keybinding, terminale, tema e workspace dichiarativi, LightDM e Thunderbird come client grafico principale - `emptty` con default host-specific in modalita `minimal`, con session file Wayland esposti per `sway` e `hyprland` - pacchetti Void Linux e servizi runit; le liste pacchetti Void desktop sono separate per criterio: - `void_packages_base` per il runtime sistema (init, kernel, audio core, networking, firewall, hw daemons) - - `desktop_common_packages` per l'infrastruttura condivisa dalle due modalita + - `desktop_common_packages` per l'infrastruttura condivisa dalle modalita - `desktop_minimal_packages` per applicazioni GTK/XFCE e `emptty` + - `desktop_xfce_packages` per XFCE, LightDM e le relative integrazioni - `desktop_kde_packages` per Plasma, SDDM e le applicazioni KDE equivalenti - `desktop_sway_packages` e `desktop_hyprland_packages` per i binari specifici di ciascuna sessione - `turnstile` per i servizi utente, inclusi `emacs` e `ssh-agent` @@ -355,7 +358,7 @@ Allo stato attuale questo comando: - per `workstation_host_linux` applica il layer host Linux GNOME - per `workstation_dev_wsl` applica pacchetti Ubuntu, servizi systemd, profilo dev comune e tweak WSL dedicati - per gli host `ubuntu_server` applica pacchetti Ubuntu, servizi systemd, profilo server, UFW, dotfiles e template dedicati -- non riavvia automaticamente `emptty`; le modifiche al display manager vanno applicate manualmente da SSH o da una TTY separata +- non riavvia automaticamente il display manager; i passaggi tra `emptty`, LightDM e SDDM vanno applicati da SSH o da una TTY separata - carica `secrets/vault.yml` solo se presente - carica `secrets/vault.local.yml` solo se presente, dopo `vault.yml`, cosi gli override locali hanno precedenza @@ -397,13 +400,13 @@ Per vedere l'elenco reale aggiornato dei tag disponibili: ansible-playbook ansible/site.yml --list-tags ``` -Per attivare KDE su un host, impostare `desktop_environment: kde` nei relativi `host_vars` ed eseguire prima un dry run. Il primo play configura KDE ma, se `emptty` e ancora attivo, rinvia il cambio del display manager. Da una TTY o sessione SSH separata, applicare quindi il passaggio esplicito: +Per attivare XFCE o KDE su un host, impostare rispettivamente `desktop_environment: xfce` o `desktop_environment: kde` nei relativi `host_vars` ed eseguire prima un dry run. Il primo play configura il profilo ma, se un altro display manager e ancora attivo, rinvia il cambio. Da una TTY o sessione SSH separata, con la sessione grafica chiusa, applicare quindi il passaggio esplicito: ```bash ansible-playbook ansible/site.yml --limit -e desktop_allow_display_manager_switch=true ``` -La stessa procedura vale in senso inverso per tornare a `minimal`. +La stessa procedura vale per ogni passaggio tra `minimal`, `xfce` e `kde`. Gli XML XFCE sono autorevoli: applicare i relativi aggiornamenti mentre XFCE e disconnesso evita che `xfconfd` ripristini lo stato in memoria. Allo stato attuale `ansible/site.yml` espone questi tag: @@ -417,8 +420,9 @@ Allo stato attuale `ansible/site.yml` espone questi tag: | `dotfiles:server` | dotfiles dedicati al profilo server | server | | `dotfiles:workstation` | dotfiles dedicati alle workstation | workstation Linux, WSL | | `emptty` | gestione display manager `emptty` | desktop Void | -| `display-manager` | selezione protetta tra `emptty` e SDDM | desktop Void | +| `display-manager` | selezione protetta tra `emptty`, LightDM e SDDM | desktop Void | | `kde` | profilo KDE Plasma e relativa pulizia | desktop Void | +| `xfce` | profilo XFCE, LightDM e relativa pulizia | desktop Void | | `gnome` | configurazione host GNOME | workstation host Linux, parte desktop | | `sway` | sessione/configurazione sway / SwayFX (Wayland) | desktop Void | | `hyprland` | sessione/configurazione Hyprland (Wayland) | desktop Void | diff --git a/ansible/inventory/group_vars/desktop.yml b/ansible/inventory/group_vars/desktop.yml index d21fc67..2f970d8 100644 --- a/ansible/inventory/group_vars/desktop.yml +++ b/ansible/inventory/group_vars/desktop.yml @@ -4,6 +4,11 @@ desktop_protonmail_bridge_cert_path: ~/.var/app/ch.protonmail.protonmail-bridge/ desktop_environment: minimal desktop_allow_display_manager_switch: false +desktop_display_manager_by_environment: + minimal: emptty + xfce: lightdm + kde: sddm + desktop_sessions_enabled: - sway - hyprland @@ -236,6 +241,30 @@ desktop_hyprland_dotfiles: dest: .config/foot/ mode: preserve +desktop_xfce_dotfiles: + - name: XFCE configuration + src: .config/xfce4/ + dest: .config/xfce4/ + mode: preserve + - name: XFCE Thunar custom actions + src: .config/Thunar/uca.xfce.xml + dest: .config/Thunar/uca.xml + mode: "0644" + - name: XFCE dark desktop background + src: .local/share/backgrounds/xfce-dark.svg + dest: .local/share/backgrounds/xfce-dark.svg + mode: "0644" + +desktop_xfce_managed_paths: + - .config/xfce4 + - .local/share/backgrounds/xfce-dark.svg + +xfce_theme_gtk: Yaru-blue-dark +xfce_theme_icons: Papirus-Dark +xfce_theme_wm: Greybird-dark +xfce_font_ui: Liberation Sans 10 +xfce_font_monospace: Liberation Mono 11 + desktop_flatpak_packages: - be.alexandervanhee.gradia - ch.protonmail.protonmail-bridge diff --git a/ansible/inventory/group_vars/void.yml b/ansible/inventory/group_vars/void.yml index 2cd2638..23bfe14 100644 --- a/ansible/inventory/group_vars/void.yml +++ b/ansible/inventory/group_vars/void.yml @@ -157,6 +157,29 @@ desktop_kde_packages: - skanpage - spectacle +desktop_xfce_packages: + - blueman + - gnome-keyring + - greybird-themes + - gvfs + - gvfs-cdda + - gvfs-mtp + - gvfs-smb + - lightdm + - lightdm-gtk-greeter + - network-manager-applet + - papirus-icon-theme + - seahorse + - thunar-archive-plugin + - xarchiver + - xdg-desktop-portal-gtk + - xfce4 + - xfce4-clipman-plugin + - xfce4-pulseaudio-plugin + - xfce4-screenshooter + - xfce4-whiskermenu-plugin + - xorg + desktop_sway_packages: - cliphist - dunst diff --git a/ansible/roles/packages_void/tasks/main.yml b/ansible/roles/packages_void/tasks/main.yml index facab6b..78c31ce 100644 --- a/ansible/roles/packages_void/tasks/main.yml +++ b/ansible/roles/packages_void/tasks/main.yml @@ -46,21 +46,20 @@ update_cache: false upgrade: true -- name: Install packages on Void Linux +- name: Select packages for the configured desktop environment tags: [packages] - community.general.xbps: - name: >- + ansible.builtin.set_fact: + packages_void_selected_desktop_packages: >- {{ ( - (common_packages | default([])) - + (void_packages_base | default([])) - + (profile_packages | default([])) - + (desktop_common_packages | default([])) - + ( - (desktop_minimal_packages | default([])) - if (desktop_environment | default('minimal')) == 'minimal' + (desktop_minimal_packages | default([])) + if (desktop_environment | default('minimal')) == 'minimal' + else ( + (desktop_xfce_packages | default([])) + if (desktop_environment | default('minimal')) == 'xfce' else (desktop_kde_packages | default([])) ) + ) + ( (desktop_sway_packages | default([])) if ( @@ -77,6 +76,37 @@ ) else [] ) + | unique + }} + +- name: Calculate packages owned only by inactive desktop environments + tags: [packages] + ansible.builtin.set_fact: + packages_void_inactive_desktop_packages: >- + {{ + ( + (desktop_minimal_packages | default([])) + + (desktop_sway_packages | default([])) + + (desktop_hyprland_packages | default([])) + + (desktop_xfce_packages | default([])) + + (desktop_kde_packages | default([])) + ) + | unique + | difference(packages_void_selected_desktop_packages) + | difference(desktop_display_manager_by_environment.values() | list) + }} + +- name: Install packages on Void Linux + tags: [packages] + community.general.xbps: + name: >- + {{ + ( + (common_packages | default([])) + + (void_packages_base | default([])) + + (profile_packages | default([])) + + (desktop_common_packages | default([])) + + (packages_void_selected_desktop_packages | default([])) + (host_packages | default([])) ) | unique @@ -87,36 +117,20 @@ - name: Check whether the selected display manager is active tags: [packages, display-manager] ansible.builtin.stat: - path: >- - /var/service/{{ 'sddm' if (desktop_environment | default('minimal')) == 'kde' else 'emptty' }} + path: "/var/service/{{ desktop_display_manager_by_environment[desktop_environment | default('minimal')] }}" register: packages_void_selected_display_manager - name: Remove packages managed by the inactive desktop environment tags: [packages] community.general.xbps: - name: >- - {{ - ( - ( - (desktop_minimal_packages | default([])) - | reject('equalto', 'emptty') - | list - ) - + (desktop_sway_packages | default([])) - + (desktop_hyprland_packages | default([])) - ) - if (desktop_environment | default('minimal')) == 'kde' - else ( - (desktop_kde_packages | default([])) - | reject('equalto', 'sddm') - | list - ) - }} + name: "{{ packages_void_inactive_desktop_packages }}" state: absent update_cache: false - when: >- - packages_void_selected_display_manager.stat.exists - or (desktop_allow_display_manager_switch | default(false)) + when: + - (packages_void_inactive_desktop_packages | default([])) | length > 0 + - >- + packages_void_selected_display_manager.stat.exists + or (desktop_allow_display_manager_switch | default(false)) - name: Remove host-absent packages on Void Linux tags: [packages] diff --git a/ansible/roles/profile_desktop_common/tasks/main.yml b/ansible/roles/profile_desktop_common/tasks/main.yml index 8b50e51..07db78f 100644 --- a/ansible/roles/profile_desktop_common/tasks/main.yml +++ b/ansible/roles/profile_desktop_common/tasks/main.yml @@ -3,18 +3,18 @@ tags: [always] ansible.builtin.assert: that: - - (desktop_environment | default('minimal')) in ['minimal', 'kde'] + - (desktop_environment | default('minimal')) in ['minimal', 'xfce', 'kde'] - >- - (desktop_environment | default('minimal')) == 'kde' + (desktop_environment | default('minimal')) != 'minimal' or (desktop_sessions_enabled | default([]) | length > 0) - >- - (desktop_environment | default('minimal')) == 'kde' + (desktop_environment | default('minimal')) != 'minimal' or (desktop_sessions_enabled | default([]) | difference(['sway', 'hyprland']) | length == 0) - >- - (desktop_environment | default('minimal')) == 'kde' + (desktop_environment | default('minimal')) != 'minimal' or desktop_default_session in (desktop_sessions_enabled | default([])) fail_msg: >- - desktop_environment must be minimal or kde. Minimal desktops also require + desktop_environment must be minimal, xfce, or kde. Minimal desktops also require desktop_default_session to be included in desktop_sessions_enabled. - name: Configure elogind to suspend on lid close @@ -475,7 +475,7 @@ owner: root group: root mode: "0644" - when: (desktop_environment | default('minimal')) == 'minimal' + when: (desktop_environment | default('minimal')) in ['minimal', 'xfce'] - name: Remove minimal Qt theme override for KDE tags: [theme] diff --git a/ansible/roles/profile_desktop_kde/tasks/main.yml b/ansible/roles/profile_desktop_kde/tasks/main.yml index 2891991..f917ca8 100644 --- a/ansible/roles/profile_desktop_kde/tasks/main.yml +++ b/ansible/roles/profile_desktop_kde/tasks/main.yml @@ -21,7 +21,11 @@ ansible.builtin.file: path: "{{ user_home }}/{{ item }}" state: absent - loop: "{{ desktop_minimal_managed_paths | default([]) }}" + loop: >- + {{ + (desktop_minimal_managed_paths | default([])) + + (desktop_xfce_managed_paths | default([])) + }} loop_control: label: "{{ item }}" when: @@ -36,6 +40,7 @@ loop: - /etc/xdg/xdg-desktop-portal/hyprland-portals.conf - /etc/xdg/xdg-desktop-portal/sway-portals.conf + - /etc/xdg/xdg-desktop-portal/xfce-portals.conf when: - (desktop_environment | default('minimal')) == 'kde' - profile_desktop_kde_sddm_service.stat.exists @@ -47,6 +52,7 @@ state: absent loop: - /etc/emptty + - /etc/lightdm/lightdm.conf.d/50-xfce.conf - /usr/local/bin/start-hyprland-session - /usr/local/bin/start-sway when: diff --git a/ansible/roles/profile_desktop_xfce/tasks/main.yml b/ansible/roles/profile_desktop_xfce/tasks/main.yml new file mode 100644 index 0000000..e596bd7 --- /dev/null +++ b/ansible/roles/profile_desktop_xfce/tasks/main.yml @@ -0,0 +1,223 @@ +--- +- name: Inspect configured desktop display manager for XFCE cleanup gates + tags: [always, packages, services, xfce, display-manager] + ansible.builtin.stat: + path: "/var/service/{{ desktop_display_manager_by_environment[desktop_environment | default('minimal')] }}" + register: profile_desktop_xfce_selected_display_manager + +- name: Ensure XFCE user configuration directories exist + tags: [dotfiles, dotfiles:desktop, xfce] + ansible.builtin.file: + path: "{{ item }}" + state: directory + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "0755" + loop: + - "{{ user_home }}/.config/xfce4" + - "{{ user_home }}/.config/xfce4/terminal" + - "{{ user_home }}/.config/xfce4/xfconf" + - "{{ user_home }}/.config/xfce4/xfconf/xfce-perchannel-xml" + - "{{ user_home }}/.config/Thunar" + - "{{ user_home }}/.local/share/backgrounds" + when: (desktop_environment | default('minimal')) == 'xfce' + +- name: Copy XFCE desktop dotfiles + tags: [dotfiles, dotfiles:desktop, xfce] + ansible.builtin.copy: + src: "{{ playbook_dir }}/../dotfiles/desktop/{{ item.src }}" + dest: "{{ user_home }}/{{ item.dest }}" + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "{{ item.mode }}" + loop: "{{ desktop_xfce_dotfiles | default([]) }}" + loop_control: + label: "{{ item.dest }}" + when: (desktop_environment | default('minimal')) == 'xfce' + +- name: Render XFCE themed configuration + tags: [dotfiles, dotfiles:desktop, xfce] + ansible.builtin.template: + src: "{{ item.src }}" + dest: "{{ user_home }}/{{ item.dest }}" + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "0644" + loop: + - src: xsettings.xml.j2 + dest: .config/xfce4/xfconf/xfce-perchannel-xml/xsettings.xml + - src: xfwm4.xml.j2 + dest: .config/xfce4/xfconf/xfce-perchannel-xml/xfwm4.xml + - src: xfce4-desktop.xml.j2 + dest: .config/xfce4/xfconf/xfce-perchannel-xml/xfce4-desktop.xml + - src: terminalrc.j2 + dest: .config/xfce4/terminal/terminalrc + loop_control: + label: "{{ item.dest }}" + when: (desktop_environment | default('minimal')) == 'xfce' + +- name: Copy XFCE MIME application defaults + tags: [dotfiles, dotfiles:desktop, xfce] + ansible.builtin.copy: + src: "{{ playbook_dir }}/../dotfiles/desktop/.config/mimeapps.list" + dest: "{{ user_home }}/.config/mimeapps.list" + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "0644" + when: (desktop_environment | default('minimal')) == 'xfce' + +- name: Make Thunderbird the XFCE mail handler + tags: [dotfiles, dotfiles:desktop, xfce] + community.general.ini_file: + path: "{{ user_home }}/.config/mimeapps.list" + section: "{{ item.section }}" + option: x-scheme-handler/mailto + value: "{{ item.value }}" + no_extra_spaces: true + owner: "{{ username }}" + group: "{{ user_group }}" + mode: "0644" + loop: + - section: Default Applications + value: org.mozilla.Thunderbird.desktop + - section: Added Associations + value: org.mozilla.Thunderbird.desktop; + when: (desktop_environment | default('minimal')) == 'xfce' + +- name: Ensure LightDM configuration directories exist + tags: [packages, services, xfce, display-manager] + ansible.builtin.file: + path: "{{ item }}" + state: directory + owner: root + group: root + mode: "0755" + loop: + - /etc/lightdm + - /etc/lightdm/lightdm.conf.d + when: (desktop_environment | default('minimal')) == 'xfce' + +- name: Configure LightDM for the XFCE session + tags: [packages, services, xfce, display-manager] + ansible.builtin.template: + src: lightdm-xfce.conf.j2 + dest: /etc/lightdm/lightdm.conf.d/50-xfce.conf + owner: root + group: root + mode: "0644" + register: profile_desktop_xfce_lightdm_config + when: (desktop_environment | default('minimal')) == 'xfce' + +- name: Configure the LightDM GTK greeter + tags: [packages, services, xfce, display-manager] + ansible.builtin.template: + src: lightdm-gtk-greeter.conf.j2 + dest: /etc/lightdm/lightdm-gtk-greeter.conf + owner: root + group: root + mode: "0644" + register: profile_desktop_xfce_lightdm_greeter_config + when: (desktop_environment | default('minimal')) == 'xfce' + +- name: Report deferred LightDM configuration activation + tags: [packages, services, xfce, display-manager] + ansible.builtin.debug: + msg: >- + LightDM configuration changed. Apply the display-manager switch or restart + LightDM from a TTY or SSH session; it is not restarted automatically. + when: + - (desktop_environment | default('minimal')) == 'xfce' + - >- + profile_desktop_xfce_lightdm_config is changed + or profile_desktop_xfce_lightdm_greeter_config is changed + +- name: Manage gnome-keyring auth hook for LightDM + tags: [packages, services, xfce] + ansible.builtin.lineinfile: + path: /etc/pam.d/lightdm + insertafter: EOF + line: "auth optional pam_gnome_keyring.so" + state: present + when: (desktop_environment | default('minimal')) == 'xfce' + +- name: Manage gnome-keyring session hook for LightDM + tags: [packages, services, xfce] + ansible.builtin.lineinfile: + path: /etc/pam.d/lightdm + insertafter: EOF + line: "session optional pam_gnome_keyring.so auto_start" + state: present + when: (desktop_environment | default('minimal')) == 'xfce' + +- name: Ensure XFCE portal configuration directory exists + tags: [packages, services, xfce, portal] + ansible.builtin.file: + path: /etc/xdg/xdg-desktop-portal + state: directory + owner: root + group: root + mode: "0755" + when: (desktop_environment | default('minimal')) == 'xfce' + +- name: Configure xdg-desktop-portal preferences for XFCE + tags: [packages, services, xfce, portal] + ansible.builtin.copy: + dest: /etc/xdg/xdg-desktop-portal/xfce-portals.conf + content: | + [preferred] + default=gtk + owner: root + group: root + mode: "0644" + when: (desktop_environment | default('minimal')) == 'xfce' + +- name: Remove minimal desktop user configuration after switching to XFCE + tags: [dotfiles, dotfiles:desktop, xfce] + ansible.builtin.file: + path: "{{ user_home }}/{{ item }}" + state: absent + loop: "{{ desktop_minimal_managed_paths | default([]) | difference(['.config/Thunar']) }}" + loop_control: + label: "{{ item }}" + when: + - (desktop_environment | default('minimal')) == 'xfce' + - profile_desktop_xfce_selected_display_manager.stat.exists + +- name: Remove minimal portal preferences and session launchers after switching to XFCE + tags: [packages, services, xfce, portal, display-manager] + ansible.builtin.file: + path: "{{ item }}" + state: absent + loop: + - /etc/xdg/xdg-desktop-portal/hyprland-portals.conf + - /etc/xdg/xdg-desktop-portal/sway-portals.conf + - /etc/emptty + - /usr/local/bin/start-hyprland-session + - /usr/local/bin/start-sway + when: + - (desktop_environment | default('minimal')) == 'xfce' + - profile_desktop_xfce_selected_display_manager.stat.exists + +- name: Remove XFCE user configuration after switching to another profile + tags: [dotfiles, dotfiles:desktop, xfce] + ansible.builtin.file: + path: "{{ user_home }}/{{ item }}" + state: absent + loop: "{{ desktop_xfce_managed_paths | default([]) }}" + loop_control: + label: "{{ item }}" + when: + - (desktop_environment | default('minimal')) != 'xfce' + - profile_desktop_xfce_selected_display_manager.stat.exists + +- name: Remove inactive XFCE portal and LightDM profile configuration + tags: [packages, services, xfce, portal, display-manager] + ansible.builtin.file: + path: "{{ item }}" + state: absent + loop: + - /etc/xdg/xdg-desktop-portal/xfce-portals.conf + - /etc/lightdm/lightdm.conf.d/50-xfce.conf + when: + - (desktop_environment | default('minimal')) != 'xfce' + - profile_desktop_xfce_selected_display_manager.stat.exists diff --git a/ansible/roles/profile_desktop_xfce/templates/lightdm-gtk-greeter.conf.j2 b/ansible/roles/profile_desktop_xfce/templates/lightdm-gtk-greeter.conf.j2 new file mode 100644 index 0000000..185e49f --- /dev/null +++ b/ansible/roles/profile_desktop_xfce/templates/lightdm-gtk-greeter.conf.j2 @@ -0,0 +1,7 @@ +[greeter] +theme-name={{ xfce_theme_gtk }} +icon-theme-name={{ xfce_theme_icons }} +font-name={{ xfce_font_ui }} +background=#050505 +clock-format=%a %d %b, %H:%M +indicators=~host;~spacer;~clock;~spacer;~session;~power diff --git a/ansible/roles/profile_desktop_xfce/templates/lightdm-xfce.conf.j2 b/ansible/roles/profile_desktop_xfce/templates/lightdm-xfce.conf.j2 new file mode 100644 index 0000000..2bc5b61 --- /dev/null +++ b/ansible/roles/profile_desktop_xfce/templates/lightdm-xfce.conf.j2 @@ -0,0 +1,3 @@ +[Seat:*] +greeter-session=lightdm-gtk-greeter +user-session=xfce diff --git a/ansible/roles/profile_desktop_xfce/templates/terminalrc.j2 b/ansible/roles/profile_desktop_xfce/templates/terminalrc.j2 new file mode 100644 index 0000000..6c1a9d2 --- /dev/null +++ b/ansible/roles/profile_desktop_xfce/templates/terminalrc.j2 @@ -0,0 +1,15 @@ +[Configuration] +FontName={{ xfce_font_monospace }} +MiscUseSystemFont=FALSE +MiscMenubarDefault=FALSE +MiscToolbarDefault=FALSE +MiscBordersDefault=TRUE +ScrollingLines=10000 +BackgroundMode=TERMINAL_BACKGROUND_SOLID +ColorForeground=#d8d8d8 +ColorBackground=#050505 +ColorCursor=#d8d8d8 +ColorSelection=#d8d8d8 +ColorSelectionUseDefault=FALSE +ColorSelectionBackground=#3a5f7f +ColorPalette=#050505;#8f3f3f;#5f7f5f;#8f7f3f;#3a5f7f;#6f4f7f;#3f7f7f;#d8d8d8;#777777;#bf5f5f;#7f9f7f;#af9f5f;#5f7f9f;#8f6f9f;#5f9f9f;#ffffff diff --git a/ansible/roles/profile_desktop_xfce/templates/xfce4-desktop.xml.j2 b/ansible/roles/profile_desktop_xfce/templates/xfce4-desktop.xml.j2 new file mode 100644 index 0000000..ce71ee9 --- /dev/null +++ b/ansible/roles/profile_desktop_xfce/templates/xfce4-desktop.xml.j2 @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/ansible/roles/profile_desktop_xfce/templates/xfwm4.xml.j2 b/ansible/roles/profile_desktop_xfce/templates/xfwm4.xml.j2 new file mode 100644 index 0000000..5dec9cf --- /dev/null +++ b/ansible/roles/profile_desktop_xfce/templates/xfwm4.xml.j2 @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/ansible/roles/profile_desktop_xfce/templates/xsettings.xml.j2 b/ansible/roles/profile_desktop_xfce/templates/xsettings.xml.j2 new file mode 100644 index 0000000..269aa4b --- /dev/null +++ b/ansible/roles/profile_desktop_xfce/templates/xsettings.xml.j2 @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/ansible/roles/services_runit/tasks/main.yml b/ansible/roles/services_runit/tasks/main.yml index c2cd538..3a4ed6f 100644 --- a/ansible/roles/services_runit/tasks/main.yml +++ b/ansible/roles/services_runit/tasks/main.yml @@ -19,47 +19,70 @@ tags: [services, packages, display-manager] ansible.builtin.set_fact: services_runit_desktop_display_manager_service: >- - {{ 'sddm' if (desktop_environment | default('minimal')) == 'kde' else 'emptty' }} - services_runit_inactive_display_manager_service: >- - {{ 'emptty' if (desktop_environment | default('minimal')) == 'kde' else 'sddm' }} + {{ desktop_display_manager_by_environment[desktop_environment | default('minimal')] }} + services_runit_inactive_display_manager_services: >- + {{ + desktop_display_manager_by_environment.values() + | list + | difference([desktop_display_manager_by_environment[desktop_environment | default('minimal')]]) + }} when: "'desktop' in group_names" -- name: Inspect desktop display manager services +- name: Inspect selected desktop display manager service + tags: [services, packages, display-manager] + ansible.builtin.stat: + path: "/var/service/{{ services_runit_desktop_display_manager_service }}" + register: services_runit_selected_display_manager_link + when: "'desktop' in group_names" + +- name: Inspect inactive desktop display manager services tags: [services, packages, display-manager] ansible.builtin.stat: path: "/var/service/{{ item }}" - loop: - - "{{ services_runit_desktop_display_manager_service }}" - - "{{ services_runit_inactive_display_manager_service }}" + loop: "{{ services_runit_inactive_display_manager_services }}" loop_control: label: "{{ item }}" - register: services_runit_display_manager_links + register: services_runit_inactive_display_manager_links + when: "'desktop' in group_names" + +- name: Record active inactive desktop display managers + tags: [services, packages, display-manager] + ansible.builtin.set_fact: + services_runit_active_inactive_display_managers: >- + {{ + services_runit_inactive_display_manager_links.results + | selectattr('stat.exists') + | map(attribute='item') + | list + }} when: "'desktop' in group_names" - name: Report deferred desktop display manager switch tags: [services, packages, display-manager] ansible.builtin.debug: msg: >- - {{ desktop_environment }} is configured, but {{ services_runit_inactive_display_manager_service }} - is still active. Re-run from a TTY or SSH session with + {{ desktop_environment }} is configured, but + {{ services_runit_active_inactive_display_managers | join(', ') }} is still active. + Re-run from a TTY or SSH session with -e desktop_allow_display_manager_switch=true to switch safely to {{ services_runit_desktop_display_manager_service }}. when: - "'desktop' in group_names" - - services_runit_display_manager_links.results[1].stat.exists - - not (services_runit_display_manager_links.results[0].stat.exists) + - (services_runit_active_inactive_display_managers | length) > 0 - not (desktop_allow_display_manager_switch | default(false)) -- name: Disable inactive desktop display manager +- name: Disable inactive desktop display managers tags: [services, packages, display-manager] ansible.builtin.file: - path: "/var/service/{{ services_runit_inactive_display_manager_service }}" + path: "/var/service/{{ item }}" state: absent + loop: "{{ services_runit_active_inactive_display_managers }}" + loop_control: + label: "{{ item }}" register: services_runit_display_manager_disabled when: - "'desktop' in group_names" - - services_runit_display_manager_links.results[1].stat.exists - - not (services_runit_display_manager_links.results[0].stat.exists) + - (services_runit_active_inactive_display_managers | length) > 0 - desktop_allow_display_manager_switch | default(false) - name: Enable selected desktop display manager @@ -71,22 +94,25 @@ register: services_runit_display_manager_enabled when: - "'desktop' in group_names" - - not (services_runit_display_manager_links.results[0].stat.exists) + - not services_runit_selected_display_manager_link.stat.exists - >- - not (services_runit_display_manager_links.results[1].stat.exists) + (services_runit_active_inactive_display_managers | length) == 0 or (desktop_allow_display_manager_switch | default(false)) -- name: Remove inactive desktop display manager package after switching +- name: Remove inactive desktop display manager packages after switching tags: [services, packages, display-manager] community.general.xbps: - name: "{{ services_runit_inactive_display_manager_service }}" + name: "{{ item }}" state: absent update_cache: false + loop: "{{ services_runit_inactive_display_manager_services }}" + loop_control: + label: "{{ item }}" when: - "'desktop' in group_names" - >- - services_runit_display_manager_links.results[0].stat.exists + services_runit_selected_display_manager_link.stat.exists or (services_runit_display_manager_enabled is defined and services_runit_display_manager_enabled is changed) - >- - not (services_runit_display_manager_links.results[1].stat.exists) - or (services_runit_display_manager_disabled is defined and services_runit_display_manager_disabled is changed) + (services_runit_active_inactive_display_managers | length) == 0 + or (desktop_allow_display_manager_switch | default(false)) diff --git a/ansible/site.yml b/ansible/site.yml index 53314dc..a6ddef3 100644 --- a/ansible/site.yml +++ b/ansible/site.yml @@ -27,6 +27,7 @@ - profile_desktop_sway - profile_desktop_hyprland - profile_desktop_kde + - profile_desktop_xfce - profile_desktop_host - hosts: workstation_dev_fedora diff --git a/dotfiles/desktop/.config/Thunar/uca.xfce.xml b/dotfiles/desktop/.config/Thunar/uca.xfce.xml new file mode 100644 index 0000000..cfb3df4 --- /dev/null +++ b/dotfiles/desktop/.config/Thunar/uca.xfce.xml @@ -0,0 +1,15 @@ + + + + utilities-terminal + Open Terminal Here + + xfce-open-terminal-here + xfce4-terminal --working-directory %f + Open xfce4-terminal in this directory + + * + + + + diff --git a/dotfiles/desktop/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-keyboard-shortcuts.xml b/dotfiles/desktop/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-keyboard-shortcuts.xml new file mode 100644 index 0000000..4b7720e --- /dev/null +++ b/dotfiles/desktop/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-keyboard-shortcuts.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dotfiles/desktop/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-notifyd.xml b/dotfiles/desktop/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-notifyd.xml new file mode 100644 index 0000000..f8f2a50 --- /dev/null +++ b/dotfiles/desktop/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-notifyd.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/dotfiles/desktop/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-panel.xml b/dotfiles/desktop/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-panel.xml new file mode 100644 index 0000000..619abc1 --- /dev/null +++ b/dotfiles/desktop/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-panel.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dotfiles/desktop/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-power-manager.xml b/dotfiles/desktop/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-power-manager.xml new file mode 100644 index 0000000..8150f38 --- /dev/null +++ b/dotfiles/desktop/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-power-manager.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/dotfiles/desktop/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-session.xml b/dotfiles/desktop/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-session.xml new file mode 100644 index 0000000..dcfd5f1 --- /dev/null +++ b/dotfiles/desktop/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-session.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/dotfiles/desktop/.emacs.d/init.el b/dotfiles/desktop/.emacs.d/init.el index 9bd8b91..8f89275 100644 --- a/dotfiles/desktop/.emacs.d/init.el +++ b/dotfiles/desktop/.emacs.d/init.el @@ -12,6 +12,7 @@ 'core/performance 'core/editor 'core/keybindings + 'core/modal 'core/buffer ;; Tools diff --git a/dotfiles/desktop/.emacs.d/lisp/core/modal.el b/dotfiles/desktop/.emacs.d/lisp/core/modal.el new file mode 100644 index 0000000..7115916 --- /dev/null +++ b/dotfiles/desktop/.emacs.d/lisp/core/modal.el @@ -0,0 +1,16 @@ +;;; modal.el --- Vim motions for the desktop Emacs profile -*- lexical-binding: t; -*- + +(use-package evil + :ensure t + :init + (setq evil-want-C-u-scroll t + evil-want-C-i-jump nil + evil-undo-system 'undo-redo) + :config + (evil-mode 1) + (evil-define-key '(normal visual motion) 'global + (kbd "SPC") fscotto/leader-map)) + +(provide 'modal) + +;;; modal.el ends here diff --git a/dotfiles/desktop/.local/share/backgrounds/xfce-dark.svg b/dotfiles/desktop/.local/share/backgrounds/xfce-dark.svg new file mode 100644 index 0000000..fd5a8b8 --- /dev/null +++ b/dotfiles/desktop/.local/share/backgrounds/xfce-dark.svg @@ -0,0 +1,4 @@ + + + +