Compare commits

...

18 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
14 changed files with 475 additions and 548 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

602
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

@ -24,7 +24,7 @@ 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
# `-l`: start $SHELL as a login shell so it sources the user's profile. # `-l`: start $SHELL as a login shell so it sources the user's profile.
exec "${SHELL}" -l -c "'${0}' --in-login-shell" exec "${SHELL}" -l -c "${0} --in-login-shell"
fi fi
fi fi
@ -66,13 +66,14 @@ if [ -d "$XDG_RUNTIME_DIR/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 "$XDG_RUNTIME_DIR/gcr/ssh" ]; then if [ -S "$XDG_RUNTIME_DIR/gcr/ssh" ]; then
export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/gcr/ssh" export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/gcr/ssh"
elif [ -S "$XDG_RUNTIME_DIR/keyring/ssh" ]; then elif [ -S "$XDG_RUNTIME_DIR/keyring/ssh" ]; then
export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/keyring/ssh" export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/keyring/ssh"
fi
fi fi
fi fi

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,13 +120,15 @@ 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 = vec![( let mut comp_env = env;
comp_env.push((
"COSMIC_SESSION_SOCK".to_string(), "COSMIC_SESSION_SOCK".to_string(),
comp.as_raw_fd().to_string(), comp.as_raw_fd().to_string(),
)]; ));
// NVIDIA keeps a growing pool of pre-rendered compositor frames // NVIDIA keeps a growing pool of pre-rendered compositor frames
// (smithay#1562 / cosmic-comp#1179). Cap it to a single buffer. // (smithay#1562 / cosmic-comp#1179). Cap it to a single buffer.
if std::path::Path::new("/proc/driver/nvidia").exists() { if std::path::Path::new("/proc/driver/nvidia").exists() {

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?;