Compare commits

...

23 commits

Author SHA1 Message Date
7d9d67e0b2 chore: fige Cargo.lock (epoch-1.10.0, [patch] locaux)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 07:02:21 +02:00
e8b1ad1da8 merge: epoch-1.10.0 d'upstream
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 07:00:06 +02:00
Michael Aaron Murphy
8093b59bb1 Epoch 1.10.0 version update
[x] Generated by cosmic-epoch scripts/version-update.sh
2026-10-06 21:22:57 +02:00
Josh Megnauth
8b6cd49f4c Fix building without systemd + minor clippy
Some of the feature gates were out of date for builds precluding
systemd, logind, or both. I also cleaned up the systemd/logind gates in
general as well as fixed a few very minor clippy lints.
2026-10-05 13:17:51 -06:00
Christoph Dalski
a692a3006a fix: pass systemd user env vars to cosmic-session
Read the env vars of the systemd user manager before cosmic-comp starts and pass them to it.

fixes #171
2026-10-02 19:04:49 +02:00
Jeremy Soller
ad097e98ec COSMIC policy update
Generated by cosmic-epoch scripts/policy-update.sh. Uses `policy_nobuild` branch to avoid package builds as it contains no code changes.
2026-09-30 09:56:15 -06:00
Jim Witte
70f9b96ca6 fix: preserve configured SSH_AUTH_SOCK 2026-09-28 21:55:05 +02:00
a73b324002 chore: fige Cargo.lock (epoch-1.9.0, [patch] locaux)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 21:03:54 +02:00
d1f2851ec7 merge: epoch-1.9.0 d'upstream
# Conflicts:
#	Cargo.lock
#	Cargo.toml
#	data/cosmic-mimeapps.list
2026-09-24 20:50:58 +02:00
Ashley Wulber
1e4f10b582 Recommend cosmic-viewer and set as default image viewer 2026-09-23 13:41:35 -04:00
r0chd
81dd888ec9 Fix compilation error when autostart feature is enabled without systemd 2026-09-22 10:06:52 -06:00
r0chd
2e0ee1b796 update flake.lock 2026-09-22 10:06:52 -06:00
Jeremy Soller
b712061806 Add cosmic-osk 2026-09-21 13:47:17 -06:00
Christoph Dalski
2770d1155a fix: login shell path interpreted as string by modern shells
The single quotes around the login shell path are interpreted as string by modern shells like nushell.
The exec call breaks.

Tested locally with nushell.

Fixes: #221
2026-09-16 22:02:14 +02:00
Michael Aaron Murphy
cd90a03e3f Epoch 1.9.0 version update
Generated by cosmic-epoch scripts/version-update.sh
2026-09-15 18:44:47 +02:00
Vukašin Vojinović
3ccf897693 feat: set COSMIC_VERSION env var 2026-09-09 18:32:01 +02:00
Vukašin Vojinović
d02ced6297 feat: add version argument 2026-09-09 18:32:01 +02:00
7a4f481ea0 chore: fige Cargo.lock (reordonnancement patch.unused par cargo) 2026-09-04 10:48:53 +02:00
4904c346e8 chore: fige Cargo.lock tel que resolu apres le merge 1.7.0
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 07:58:50 +02:00
e1d2eb535b Merge tag 'epoch-1.7.0' into local/yoda-main
Epoch 1.7.0
2026-08-27 07:49:24 +02:00
fa2d2a40ce session: plafonne les trames pre-rendues par le pilote NVIDIA
Passe __GL_MaxFramesAllowed=1 a cosmic-comp lorsque /proc/driver/nvidia
existe. Sans cela le pilote laisse grossir sa file de trames pre-rendues,
ce qui ajoute de la latence a l'affichage (smithay#1562, cosmic-comp#1179).

La variable n'est ajoutee que sur machine NVIDIA ; ailleurs l'environnement
transmis reste le seul COSMIC_SESSION_SOCK.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-21 09:54:33 +02:00
Hugo Osvaldo Barrera
3bdf11741a Fix hardcoded values for XDG_RUNTIME_DIR
Remove hardcoded values and use the proper backing environment variable
instead.
2026-08-19 16:32:48 -06:00
Hugo Osvaldo Barrera
3e2f7368d0 start-cosmic: use sh
Nothing else is cosmic uses bash, so it's only a dependency for a single
script.

Rewrite start-cosmic as a shell script, dropping the dependency on bash.

No AI/LLM-generated code is included in this PR.
2026-08-19 14:16:43 -06:00
14 changed files with 499 additions and 567 deletions

View file

@ -1,8 +1,10 @@
- [ ] I have disclosed use of any AI generated code in my commit messages. Replace this text with a description of your changes, and why these changes are important. Read and acknowledge the list below. PRs without a completed checkbox will be closed.
- If you are using an LLM, and do not fully understand the changes it is making to the code base, do not create a PR.
- In our experience, AI generated code often results in overly complex code that lacks enough context for a proper fix or feature inclusion. This results in considerably longer code reviews. Due to this, AI authored or partially authored PRs may be closed without comment.
- [ ] I understand these changes in full and will be able to respond to review comments.
- [ ] My change is accurately described in the commit message.
- [ ] My contribution is tested and working as described.
- [ ] I have read the [Developer Certificate of Origin](https://developercertificate.org/) and certify my contribution under its conditions.
---
- I have not included any LLM (also known as AI) generated content in this PR, including code, comments, and descriptions.
- I understand these changes in full and will be able to respond to review comments.
- My change is accurately described in the commit message.
- My contribution is tested and working as described.
- I have read the [Developer Certificate of Origin](https://developercertificate.org/) and certify my contribution under its conditions.
- [ ] I have read and followed all of the above requirements. For more information, see our [contributor guide](https://github.com/pop-os/pop/blob/master/CONTRIBUTING.md).

14
.github/workflows/require-checklist.yml vendored Normal file
View file

@ -0,0 +1,14 @@
# From https://github.com/mheap/require-checklist-action, license MIT
name: Require Checklist
on:
pull_request:
types: [opened, edited, synchronize]
jobs:
job1:
runs-on: ubuntu-latest
steps:
- uses: mheap/require-checklist-action@v2
with:
requireChecklist: true

610
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
[package] [package]
name = "cosmic-session" name = "cosmic-session"
description = "The session manager for the COSMIC desktop environment" description = "The session manager for the COSMIC desktop environment"
version = "1.3.0" version = "1.10.0"
license = "GPL-3.0-only" license = "GPL-3.0-only"
edition = "2024" edition = "2024"
rust-version = "1.93" rust-version = "1.93"
@ -46,6 +46,6 @@ logind-zbus = { version = "5.3.2", optional = true }
[features] [features]
systemd = ["dep:zbus_systemd", "dep:tracing-journald"] systemd = ["dep:zbus_systemd", "dep:tracing-journald"]
logind = ["systemd", "logind-zbus"] logind = ["dep:logind-zbus"]
default = ["logind"] default = ["logind", "systemd"]
autostart = ["dep:shell-words", "dep:dirs", "dep:freedesktop-desktop-entry"] autostart = ["dep:shell-words", "dep:dirs", "dep:freedesktop-desktop-entry"]

70
cargo.just Normal file
View file

@ -0,0 +1,70 @@
cargo-target-dir := env('CARGO_TARGET_DIR', 'target')
# Compile with debug profile
[no-cd]
build-debug *args:
cargo build {{args}}
# Compile with release profile
[no-cd]
build-release *args: (build-debug '--release' args)
# Compile with a vendored tarball
[no-cd]
build-vendored *args: vendor-extract (build-release '--frozen --offline' args)
# Check for errors and linter warnings
[no-cd]
check *args:
cargo clippy --all-features {{args}} -- -W clippy::pedantic
# Runs a check with JSON message format for IDE integration
[no-cd]
check-json: (check '--message-format=json')
# Remove Cargo build artifacts
[no-cd]
clean:
cargo clean
# Also remove .cargo and vendored dependencies
[no-cd]
clean-dist: clean
rm -rf .cargo vendor vendor.tar target
# Run the application for testing purposes
[no-cd]
run *args:
cargo run {{args}}
# Run `cargo test`
[no-cd]
test *args:
cargo test {{args}}
# Vendor Cargo dependencies locally
[no-cd]
vendor:
#!/usr/bin/env bash
mkdir -p .cargo
cargo vendor --locked | head -n -1 > .cargo/config.toml
echo 'directory = "vendor"' >> .cargo/config.toml
echo >> .cargo/config.toml
echo '[env]' >> .cargo/config.toml
if [ -n "${SOURCE_DATE_EPOCH}" ]
then
source_date="$(date -d "@${SOURCE_DATE_EPOCH}" "+%Y-%m-%d")"
echo "VERGEN_GIT_COMMIT_DATE = \"${source_date}\"" >> .cargo/config.toml
fi
if [ -n "${SOURCE_GIT_HASH}" ]
then
echo "VERGEN_GIT_SHA = \"${SOURCE_GIT_HASH}\"" >> .cargo/config.toml
fi
tar pcf vendor.tar .cargo vendor
rm -rf .cargo vendor
# Extracts vendored dependencies
[no-cd]
vendor-extract:
rm -rf vendor
tar pxf vendor.tar

View file

@ -1,4 +1,4 @@
#!/bin/bash #!/bin/sh
set -e set -e
@ -23,8 +23,8 @@ fi
if [ -n "${SHELL}" ]; then if [ -n "${SHELL}" ]; then
# --in-login-shell: our flag to indicate that we don't need to recurse any further # --in-login-shell: our flag to indicate that we don't need to recurse any further
if [ "${1}" != "--in-login-shell" ]; then if [ "${1}" != "--in-login-shell" ]; then
# `exec -l`: like `login`, prefixes $SHELL with a hyphen to start a login shell # `-l`: start $SHELL as a login shell so it sources the user's profile.
exec bash -c "exec -l '${SHELL}' -c '${0} --in-login-shell'" exec "${SHELL}" -l -c "${0} --in-login-shell"
fi fi
fi fi
@ -42,7 +42,7 @@ export DCONF_PROFILE=cosmic
# Set the QT platform theme to CuteCosmic. Fallback to qt6ct if CuteCosmic is not installed. # Set the QT platform theme to CuteCosmic. Fallback to qt6ct if CuteCosmic is not installed.
if [ -z "$QT_QPA_PLATFORMTHEME" ]; then if [ -z "$QT_QPA_PLATFORMTHEME" ]; then
export QT_QPA_PLATFORMTHEME=cosmic export QT_QPA_PLATFORMTHEME=cosmic
for QT_PLUGIN_PATH in /usr/lib{*,/*}/qt6/plugins; do for QT_PLUGIN_PATH in /usr/lib*/qt6/plugins /usr/lib/*/qt6/plugins; do
if [ -f "${QT_PLUGIN_PATH}/platformthemes/libcutecosmictheme.so" ]; then if [ -f "${QT_PLUGIN_PATH}/platformthemes/libcutecosmictheme.so" ]; then
# CuteCosmic found, no need for a fallback. # CuteCosmic found, no need for a fallback.
export QT_QPA_PLATFORMTHEME=cosmic export QT_QPA_PLATFORMTHEME=cosmic
@ -56,8 +56,8 @@ if [ -z "$QT_QPA_PLATFORMTHEME" ]; then
fi fi
# Start gnome keyring components if the daemon is active # Start gnome keyring components if the daemon is active
# -> check if /run/user/$UID/keyring exists # -> check if $XDG_RUNTIME_DIR/keyring exists
if [ -d "/run/user/$(id -u)/keyring" ]; then if [ -d "$XDG_RUNTIME_DIR/keyring" ]; then
# Use PATH lookup instead of hardcoding /usr/bin # Use PATH lookup instead of hardcoding /usr/bin
if command -v gnome-keyring-daemon >/dev/null 2>&1; then if command -v gnome-keyring-daemon >/dev/null 2>&1; then
@ -66,13 +66,14 @@ if [ -d "/run/user/$(id -u)/keyring" ]; then
echo "gnome-keyring-daemon not found in PATH" >&2 echo "gnome-keyring-daemon not found in PATH" >&2
fi fi
# Only set SSH_AUTH_SOCK if the socket actually exists. Either # Preserve an SSH agent configured by the user. Otherwise, use a
# set the correct one, or don't set one at all. Don't set the # Gnome Keyring SSH socket if one exists.
# wrong value. if [ -z "$SSH_AUTH_SOCK" ]; then
if [ -S "/run/user/$(id -u)/gcr/ssh" ]; then if [ -S "$XDG_RUNTIME_DIR/gcr/ssh" ]; then
export SSH_AUTH_SOCK="/run/user/$(id -u)/gcr/ssh" export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/gcr/ssh"
elif [ -S "/run/user/$(id -u)/keyring/ssh" ]; then elif [ -S "$XDG_RUNTIME_DIR/keyring/ssh" ]; then
export SSH_AUTH_SOCK="/run/user/$(id -u)/keyring/ssh" export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/keyring/ssh"
fi
fi fi
fi fi
@ -84,30 +85,26 @@ if command -v systemctl >/dev/null; then
# For environment variables already imported into the user's # For environment variables already imported into the user's
# session, if the value imported differs from the value in this # session, if the value imported differs from the value in this
# environment, update it. # environment, update it.
mapfile -t existing_env_vars < <(systemctl --user show-environment) systemctl --user show-environment | while IFS= read -r env_var; do
for env_var in "${existing_env_vars[@]}"; do
env_var_name="${env_var%%=*}" env_var_name="${env_var%%=*}"
env_var_value=${!env_var_name:-} env_var_value="$(printenv "${env_var_name}" || true)"
# Skip current iteration if the environment variable's value # Skip current iteration if the environment variable's value
# in the current envionment is unset. # in the current envionment is unset.
if [[ -z "${env_var_value}" ]]; then if [ -z "${env_var_value}" ]; then
continue continue
fi fi
env_var_val_str_to_compare="${env_var_name}=${env_var_value}" # Skip updating variables where systemd already holds this exact value.
env_var_val_str_to_compare_ansi_c_quoted="${env_var_name}=\$'$(printf '%q' "${env_var_value}")'" if [ "${env_var}" = "${env_var_name}=${env_var_value}" ]; then
if [[ "${env_var}" == "${env_var_val_str_to_compare}" ]]; then
continue
elif [[ "${env_var}" == "${env_var_val_str_to_compare_ansi_c_quoted}" ]]; then
continue continue
fi fi
systemctl --user import-environment "${env_var_name}" ||: systemctl --user import-environment "${env_var_name}" || true
done done
fi fi
# Run cosmic-session # Run cosmic-session
if [[ -z "${DBUS_SESSION_BUS_ADDRESS}" ]]; then if [ -z "${DBUS_SESSION_BUS_ADDRESS}" ]; then
exec /usr/bin/dbus-run-session -- /usr/bin/cosmic-session exec /usr/bin/dbus-run-session -- /usr/bin/cosmic-session
else else
exec /usr/bin/cosmic-session exec /usr/bin/cosmic-session

12
debian/changelog vendored
View file

@ -1,3 +1,15 @@
cosmic-session (1.10.0) noble; urgency=medium
* Epoch 1.10.0 version update
-- Michael Murphy <michael@mmurphy.dev> Mon, 05 Oct 2026 21:26:30 +0200
cosmic-session (1.9.0) noble; urgency=medium
* Epoch 1.9.0 version update
-- Michael Murphy <michael@mmurphy.dev> Mon, 14 Sep 2026 17:54:45 +0200
cosmic-session (1.0.0) noble; urgency=medium cosmic-session (1.0.0) noble; urgency=medium
* Initial release * Initial release

2
debian/control vendored
View file

@ -27,6 +27,7 @@ Depends:
cosmic-launcher, cosmic-launcher,
cosmic-notifications, cosmic-notifications,
cosmic-osd, cosmic-osd,
cosmic-osk,
cosmic-panel, cosmic-panel,
cosmic-randr, cosmic-randr,
cosmic-screenshot, cosmic-screenshot,
@ -46,6 +47,7 @@ Recommends:
cosmic-player, cosmic-player,
cosmic-store, cosmic-store,
cosmic-term, cosmic-term,
cosmic-viewer,
cosmic-wallpapers, cosmic-wallpapers,
orca, orca,
system-config-printer, system-config-printer,

6
debian/source/options vendored Normal file
View file

@ -0,0 +1,6 @@
tar-ignore=.github
tar-ignore=target/.rustc_info.json
tar-ignore=target/CACHEDIR.TAG
tar-ignore=target/debug
tar-ignore=target/release
tar-ignore=vendor

41
flake.lock generated
View file

@ -1,17 +1,12 @@
{ {
"nodes": { "nodes": {
"crane": { "crane": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": { "locked": {
"lastModified": 1702141249, "lastModified": 1788465171,
"narHash": "sha256-8wDpJKbDTDqFmyJfNEJOLrHYDoEzCjCbmz+lSRoU3CI=", "narHash": "sha256-Y1/TTVXjYXGF068IThQH9fPSZ0SIE74PABlUxnWTUH0=",
"owner": "ipetkov", "owner": "ipetkov",
"repo": "crane", "repo": "crane",
"rev": "62fc1a0cbe144c1014d956e603d56bf1ffe69c7d", "rev": "eb35abda9f232cc6610b1d1e3200d15c49b7ac54",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -28,11 +23,11 @@
"rust-analyzer-src": "rust-analyzer-src" "rust-analyzer-src": "rust-analyzer-src"
}, },
"locked": { "locked": {
"lastModified": 1702189261, "lastModified": 1788865058,
"narHash": "sha256-TN6gE1eZddDhAoRrScV6Wji1Nk3uqMIDjGwN5ZesAZk=", "narHash": "sha256-ZkvwEHlSa46BkODMEwHCEh9hlUC2igneJ+noEUn9ww4=",
"owner": "nix-community", "owner": "nix-community",
"repo": "fenix", "repo": "fenix",
"rev": "cae060dbaf53430bb2b549ced0affd54d40e6cee", "rev": "9efa138447c5773995d98d9aafa9eba4982aceab",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -46,11 +41,11 @@
"systems": "systems" "systems": "systems"
}, },
"locked": { "locked": {
"lastModified": 1701680307, "lastModified": 1731533236,
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725", "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -61,11 +56,11 @@
}, },
"nix-filter": { "nix-filter": {
"locked": { "locked": {
"lastModified": 1701697642, "lastModified": 1757882181,
"narHash": "sha256-L217WytWZHSY8GW9Gx1A64OnNctbuDbfslaTEofXXRw=", "narHash": "sha256-+cCxYIh2UNalTz364p+QYmWHs0P+6wDhiWR4jDIKQIU=",
"owner": "numtide", "owner": "numtide",
"repo": "nix-filter", "repo": "nix-filter",
"rev": "c843418ecfd0344ecb85844b082ff5675e02c443", "rev": "59c44d1909c72441144b93cf0f054be7fe764de5",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -76,11 +71,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1702206697, "lastModified": 1788865024,
"narHash": "sha256-vE9oEx3Y8TO5MnWwFlmopjHd1JoEBno+EhsfUCq5iR8=", "narHash": "sha256-3YkAzvtt4LoE11IcBDzPshIF3fJ0aIoILqE7dAg8CLI=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "29d6c96900b9b576c2fb89491452f283aa979819", "rev": "422d1ae605d7fcd9896412b37dc065c456c0eefb",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -102,11 +97,11 @@
"rust-analyzer-src": { "rust-analyzer-src": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1702153490, "lastModified": 1788794694,
"narHash": "sha256-F98s0+mUHtqiUk9iCApPTy23YMLmcKqTfsShpIPB40Q=", "narHash": "sha256-FROpcpM2ELawfxhW8cWuz8m3dp/0EFAFCiK+AbNw95w=",
"owner": "rust-lang", "owner": "rust-lang",
"repo": "rust-analyzer", "repo": "rust-analyzer",
"rev": "9d87a23cdef6087c1a0c97980949e2310271a941", "rev": "48d839420745124e85140234ce783ccd90dab24e",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -7,7 +7,6 @@
nix-filter.url = "github:numtide/nix-filter"; nix-filter.url = "github:numtide/nix-filter";
crane = { crane = {
url = "github:ipetkov/crane"; url = "github:ipetkov/crane";
inputs.nixpkgs.follows = "nixpkgs";
}; };
fenix = { fenix = {
url = "github:nix-community/fenix"; url = "github:nix-community/fenix";
@ -19,7 +18,7 @@
flake-utils.lib.eachSystem [ "x86_64-linux" "aarch64-linux" ] (system: flake-utils.lib.eachSystem [ "x86_64-linux" "aarch64-linux" ] (system:
let let
pkgs = nixpkgs.legacyPackages.${system}; pkgs = nixpkgs.legacyPackages.${system};
craneLib = crane.lib.${system}.overrideToolchain fenix.packages.${system}.stable.toolchain; craneLib = (crane.mkLib pkgs).overrideToolchain fenix.packages.${system}.stable.toolchain;
pkgDef = { pkgDef = {
nativeBuildInputs = with pkgs; [ just pkg-config autoPatchelfHook ]; nativeBuildInputs = with pkgs; [ just pkg-config autoPatchelfHook ];
@ -47,7 +46,7 @@
inherit cosmic-session; inherit cosmic-session;
}; };
packages.default = cosmic-session.overrideAttrs (oldAttrs: rec { packages.default = cosmic-session.overrideAttrs (oldAttrs: {
buildPhase = '' buildPhase = ''
just prefix=$out xdp_cosmic=/run/current-system/sw/bin/xdg-desktop-portal-cosmic build just prefix=$out xdp_cosmic=/run/current-system/sw/bin/xdg-desktop-portal-cosmic build
''; '';

View file

@ -99,6 +99,7 @@ pub fn run_compositor(
process_manager: &ProcessManager, process_manager: &ProcessManager,
exec: String, exec: String,
args: Vec<String>, args: Vec<String>,
env: Vec<(String, String)>,
_token: CancellationToken, _token: CancellationToken,
env_tx: oneshot::Sender<HashMap<String, String>>, env_tx: oneshot::Sender<HashMap<String, String>>,
session_dbus_tx: mpsc::Sender<SessionRequest>, session_dbus_tx: mpsc::Sender<SessionRequest>,
@ -119,15 +120,26 @@ pub fn run_compositor(
OwnedFd::from(std_stream) OwnedFd::from(std_stream)
}; };
mark_as_not_cloexec(&comp).expect("Failed to mark fd as not cloexec"); mark_as_not_cloexec(&comp).expect("Failed to mark fd as not cloexec");
Ok(tokio::spawn(async move { Ok(tokio::spawn(async move {
// Create a new process handler for cosmic-comp, with our compositor socket's // Create a new process handler for cosmic-comp, with our compositor socket's
// file descriptor as the `COSMIC_SESSION_SOCK` environment variable. // file descriptor as the `COSMIC_SESSION_SOCK` environment variable.
let mut comp_env = env;
comp_env.push((
"COSMIC_SESSION_SOCK".to_string(),
comp.as_raw_fd().to_string(),
));
// NVIDIA keeps a growing pool of pre-rendered compositor frames
// (smithay#1562 / cosmic-comp#1179). Cap it to a single buffer.
if std::path::Path::new("/proc/driver/nvidia").exists() {
comp_env.push(("__GL_MaxFramesAllowed".to_string(), "1".to_string()));
}
process_manager process_manager
.start_process( .start_process(
Process::new() Process::new()
.with_executable(exec) .with_executable(exec)
.with_args(args) .with_args(args)
.with_env([("COSMIC_SESSION_SOCK", comp.as_raw_fd().to_string())]) .with_env(comp_env)
.with_on_exit(move |pman, _, err_code, _will_restart| { .with_on_exit(move |pman, _, err_code, _will_restart| {
let session_dbus_tx = session_dbus_tx.clone(); let session_dbus_tx = session_dbus_tx.clone();
async move { async move {

View file

@ -7,6 +7,7 @@ mod comp;
mod notifications; mod notifications;
mod process; mod process;
mod service; mod service;
#[cfg(feature = "systemd")]
mod systemd; mod systemd;
use color_eyre::Result; use color_eyre::Result;
@ -15,17 +16,13 @@ use launch_pad::ProcessManager;
use launch_pad::process::Process; use launch_pad::process::Process;
use service::SessionRequest; use service::SessionRequest;
use std::borrow::Cow; use std::borrow::Cow;
#[cfg(feature = "autostart")]
use std::collections::HashSet;
use std::env; use std::env;
use std::os::fd::AsRawFd; use std::os::fd::AsRawFd;
#[cfg(feature = "autostart")]
use std::path::PathBuf;
#[cfg(feature = "autostart")]
use std::process::{Command, Stdio};
use std::sync::Arc; use std::sync::Arc;
#[cfg(any(feature = "autostart", feature = "systemd"))]
use std::{path::Path, sync::OnceLock};
#[cfg(feature = "systemd")] #[cfg(feature = "systemd")]
use systemd::{get_systemd_env, is_systemd_used, spawn_scope}; use systemd::{get_systemd_env, spawn_scope};
use tokio::signal::unix::{SignalKind, signal}; use tokio::signal::unix::{SignalKind, signal};
use tokio::sync::mpsc::{Receiver, Sender}; use tokio::sync::mpsc::{Receiver, Sender};
use tokio::sync::{Mutex, oneshot}; use tokio::sync::{Mutex, oneshot};
@ -35,17 +32,30 @@ use tracing::Instrument;
use tracing::metadata::LevelFilter; use tracing::metadata::LevelFilter;
use tracing_subscriber::prelude::*; use tracing_subscriber::prelude::*;
use tracing_subscriber::{EnvFilter, fmt}; use tracing_subscriber::{EnvFilter, fmt};
#[cfg(feature = "autostart")]
use {
std::collections::HashSet,
std::path::PathBuf,
std::process::{Command, Stdio},
};
use crate::notifications::{ use crate::notifications::{
DAEMON_NOTIFICATIONS_FD, PANEL_NOTIFICATIONS_FD, notifications_process, DAEMON_NOTIFICATIONS_FD, PANEL_NOTIFICATIONS_FD, notifications_process,
}; };
#[cfg(feature = "autostart")] #[cfg(feature = "autostart")]
const AUTOSTART_DIR: &'static str = "autostart"; const AUTOSTART_DIR: &str = "autostart";
#[cfg(feature = "autostart")] #[cfg(feature = "autostart")]
const ENVIRONMENT_NAME: &'static str = "COSMIC"; const ENVIRONMENT_NAME: &str = "COSMIC";
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]
async fn main() -> Result<()> { async fn main() -> Result<()> {
if let Some(arg) = env::args().nth(1)
&& (arg == "--version" || arg == "-V")
{
println!("cosmic-session {}", env!("CARGO_PKG_VERSION"));
return Ok(());
}
color_eyre::install().wrap_err("failed to install color_eyre error handler")?; color_eyre::install().wrap_err("failed to install color_eyre error handler")?;
let trace = tracing_subscriber::registry(); let trace = tracing_subscriber::registry();
@ -135,10 +145,20 @@ async fn start(
.await; .await;
let token = CancellationToken::new(); let token = CancellationToken::new();
let (env_tx, env_rx) = oneshot::channel(); let (env_tx, env_rx) = oneshot::channel();
#[cfg(feature = "systemd")]
let systemd_env = if *is_systemd_used() {
get_systemd_env().await
} else {
Vec::new()
};
#[cfg(not(feature = "systemd"))]
let systemd_env = Vec::new();
let compositor_handle = comp::run_compositor( let compositor_handle = comp::run_compositor(
&process_manager, &process_manager,
executable.clone(), executable.clone(),
args, args,
systemd_env.clone(),
token.child_token(), token.child_token(),
env_tx, env_tx,
session_tx, session_tx,
@ -156,69 +176,49 @@ async fn start(
); );
// now that cosmic-comp is ready, set XDG_SESSION_TYPE=wayland for new processes // now that cosmic-comp is ready, set XDG_SESSION_TYPE=wayland for new processes
env_vars.push(("XDG_SESSION_TYPE".to_string(), "wayland".to_string())); env_vars.extend(
systemd_env
.into_iter()
.chain([("XDG_SESSION_TYPE".to_string(), "wayland".to_string())]),
);
#[cfg(feature = "systemd")]
systemd::set_systemd_environment("XDG_SESSION_TYPE", "wayland").await; systemd::set_systemd_environment("XDG_SESSION_TYPE", "wayland").await;
// expose the session version
env_vars.push((
"COSMIC_VERSION".to_string(),
env!("CARGO_PKG_VERSION").to_string(),
));
#[cfg(feature = "systemd")] #[cfg(feature = "systemd")]
let _inhibit_fd = if *is_systemd_used() { systemd::set_systemd_environment("COSMIC_VERSION", env!("CARGO_PKG_VERSION")).await;
match get_systemd_env().await {
Ok(env) => { #[cfg(feature = "logind")]
for systemd_env in env { let _inhibit_fd = match zbus::Connection::system().await {
// Only update the envvar if unset Ok(connection) => match logind_zbus::manager::ManagerProxy::new(&connection).await {
if std::env::var_os(&systemd_env.key).is_none() { Ok(proxy) => match proxy
// Blacklist of envvars that we shouldn't touch (taken from KDE) .inhibit(
if (!systemd_env.key.starts_with("XDG_") logind_zbus::manager::InhibitType::HandlePowerKey,
|| systemd_env.key == "XDG_DATA_DIRS" "Cosmic Session",
|| systemd_env.key == "XDG_CONFIG_DIRS") "Show confirmation dialog.",
&& systemd_env.key != "DISPLAY" "block",
&& systemd_env.key != "XAUTHORITY" )
&& systemd_env.key != "WAYLAND_DISPLAY" .await
&& systemd_env.key != "WAYLAND_SOCKET" {
&& systemd_env.key != "_" Ok(fd) => Some(fd),
&& systemd_env.key != "SHELL"
&& systemd_env.key != "SHLVL"
{
env_vars.push((systemd_env.key, systemd_env.value));
}
}
}
}
Err(err) => {
warn!("Failed to sync systemd environment {}.", err);
}
};
#[cfg(feature = "logind")]
match zbus::Connection::system().await {
Ok(connection) => match logind_zbus::manager::ManagerProxy::new(&connection).await {
Ok(proxy) => match proxy
.inhibit(
logind_zbus::manager::InhibitType::HandlePowerKey,
"Cosmic Session",
"Show confirmation dialog.",
"block",
)
.await
{
Ok(fd) => Some(fd),
Err(err) => {
error!("Failed to inhibit power key {err:?}");
None
}
},
Err(err) => { Err(err) => {
error!("Failed to connect to logind manager {err:?}"); error!("Failed to inhibit power key {err:?}");
None None
} }
}, },
Err(err) => { Err(err) => {
error!("Failed to connect to system dbus {err:?}"); error!("Failed to connect to logind manager {err:?}");
None None
} }
},
Err(err) => {
error!("Failed to connect to system dbus {err:?}");
None
} }
#[cfg(not(feature = "logind"))]
None
} else {
None
}; };
let (settings_exit_tx, settings_exit_rx) = oneshot::channel(); let (settings_exit_tx, settings_exit_rx) = oneshot::channel();
@ -245,8 +245,10 @@ async fn start(
// - cosmic-comp is ready // - cosmic-comp is ready
// - we've set any related variables // - we've set any related variables
// - cosmic-settings-daemon is ready // - cosmic-settings-daemon is ready
#[cfg(feature = "systemd")]
systemd::start_systemd_target().await; systemd::start_systemd_target().await;
// Always stop the target when the process exits or panics. // Always stop the target when the process exits or panics.
#[cfg(feature = "systemd")]
scopeguard::defer! { scopeguard::defer! {
systemd::stop_systemd_target(); systemd::stop_systemd_target();
} }
@ -324,6 +326,9 @@ async fn start(
let span = info_span!(parent: None, "cosmic-osd"); let span = info_span!(parent: None, "cosmic-osd");
start_component("cosmic-osd", span, &process_manager, &env_vars).await; start_component("cosmic-osd", span, &process_manager, &env_vars).await;
let span = info_span!(parent: None, "cosmic-osk");
start_component("cosmic-osk", span, &process_manager, &env_vars).await;
let span = info_span!(parent: None, "cosmic-bg"); let span = info_span!(parent: None, "cosmic-bg");
start_component("cosmic-bg", span, &process_manager, &env_vars).await; start_component("cosmic-bg", span, &process_manager, &env_vars).await;
@ -376,17 +381,17 @@ async fn start(
} }
// skip if we have an OnlyShowIn entry that doesn't include COSMIC // skip if we have an OnlyShowIn entry that doesn't include COSMIC
if let Some(only_show_in) = entry.only_show_in() { if let Some(only_show_in) = entry.only_show_in()
if !only_show_in.contains(&ENVIRONMENT_NAME) { && !only_show_in.contains(&ENVIRONMENT_NAME)
continue; {
} continue;
} }
// ... OR we have a NotShowIn entry that includes COSMIC // ... OR we have a NotShowIn entry that includes COSMIC
if let Some(not_show_in) = entry.not_show_in() { if let Some(not_show_in) = entry.not_show_in()
if not_show_in.contains(&ENVIRONMENT_NAME) { && not_show_in.contains(&ENVIRONMENT_NAME)
continue; {
} continue;
} }
info!( info!(
@ -405,7 +410,7 @@ async fn start(
.collect::<Vec<_>>(); .collect::<Vec<_>>();
// escape them // escape them
let escaped_args = shell_words::split(&*filtered_args.join(" ")); let escaped_args = shell_words::split(&filtered_args.join(" "));
if let Ok(args) = escaped_args { if let Ok(args) = escaped_args {
info!("trying to start {} {}", program_name, args.join(" ")); info!("trying to start {} {}", program_name, args.join(" "));
@ -647,3 +652,11 @@ async fn start_component(
error!("failed to start {}: {}", cmd, err); error!("failed to start {}: {}", cmd, err);
} }
} }
/// Determine if systemd is used as the init system. This should work on all
/// linux distributions.
#[cfg(any(feature = "autostart", feature = "systemd"))]
fn is_systemd_used() -> &'static bool {
static IS_SYSTEMD_USED: OnceLock<bool> = OnceLock::new();
IS_SYSTEMD_USED.get_or_init(|| Path::new("/run/systemd/system").exists())
}

View file

@ -1,28 +1,9 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use std::path::Path;
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
use std::sync::OnceLock;
use zbus::Connection; use zbus::Connection;
use zbus::zvariant::{Array, OwnedValue}; use zbus::zvariant::{Array, OwnedValue};
#[derive(Debug)]
pub struct EnvVar {
pub key: String,
pub value: String,
}
impl From<(&str, &str)> for EnvVar {
fn from(val: (&str, &str)) -> Self {
EnvVar {
key: val.0.to_owned(),
value: val.1.to_owned(),
}
}
}
#[cfg(feature = "systemd")]
use zbus_systemd::systemd1::ManagerProxy as SystemdManagerProxy; use zbus_systemd::systemd1::ManagerProxy as SystemdManagerProxy;
pub async fn set_systemd_environment(key: &str, value: &str) { pub async fn set_systemd_environment(key: &str, value: &str) {
@ -46,29 +27,44 @@ pub fn stop_systemd_target() {
) )
} }
/// Determine if systemd is used as the init system. This should work on all async fn load_systemd_env() -> zbus::Result<Vec<String>> {
/// linux distributions.
pub fn is_systemd_used() -> &'static bool {
static IS_SYSTEMD_USED: OnceLock<bool> = OnceLock::new();
IS_SYSTEMD_USED.get_or_init(|| Path::new("/run/systemd/system").exists())
}
#[cfg(feature = "systemd")]
pub async fn get_systemd_env() -> Result<Vec<EnvVar>, zbus::Error> {
let connection = Connection::session().await?; let connection = Connection::session().await?;
let systemd_manager = SystemdManagerProxy::new(&connection).await?; let systemd_manager = SystemdManagerProxy::new(&connection).await?;
let systemd_env = systemd_manager.environment().await?; systemd_manager.environment().await
}
let mut out: Vec<EnvVar> = Vec::new();
for i in systemd_env { /// Get the systemd user manager environment variables.
if let Some(b) = i.split_once("=") { pub async fn get_systemd_env() -> Vec<(String, String)> {
out.push(b.into()); match load_systemd_env().await {
} Ok(env) => {
} env.iter()
Ok(out) // split into key value pairs
.filter_map(|var| var.split_once("="))
.filter(|&(key, _value)| {
// Only update the envvar if unset
std::env::var_os(key).is_none()
// Blocklist of envvars that we shouldn't touch (taken from KDE)
&& (!key.starts_with("XDG_")
|| key == "XDG_DATA_DIRS"
|| key == "XDG_CONFIG_DIRS")
&& key != "DISPLAY"
&& key != "XAUTHORITY"
&& key != "WAYLAND_DISPLAY"
&& key != "WAYLAND_SOCKET"
&& key != "_"
&& key != "SHELL"
&& key != "SHLVL"
})
.map(|(key, value)| (key.to_owned(), value.to_owned()))
.collect()
}
Err(err) => {
warn!("Failed to sync systemd environment {}.", err);
Vec::new()
}
}
} }
#[cfg(feature = "systemd")]
/// Spawn a systemd scope unit with the given name and PIDs. /// Spawn a systemd scope unit with the given name and PIDs.
pub async fn spawn_scope(mut command: String, pids: Vec<u32>) -> Result<(), zbus::Error> { pub async fn spawn_scope(mut command: String, pids: Vec<u32>) -> Result<(), zbus::Error> {
let connection = Connection::session().await?; let connection = Connection::session().await?;