Compare commits
12 commits
da592cc15e
...
495e591dc6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
495e591dc6 | ||
|
|
17cf4485a9 | ||
|
|
673e4c949b | ||
|
|
a77aaa1904 | ||
|
|
56f0115952 | ||
|
|
9a55864e81 | ||
|
|
02a4c58c3d | ||
|
|
af9aaf9c1a | ||
|
|
59b48b5b3b | ||
|
|
618624bcc0 | ||
|
|
a823516ebd | ||
|
|
42752142e3 |
10 changed files with 687 additions and 993 deletions
15
.zed/settings.json
Normal file
15
.zed/settings.json
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"format_on_save": "on",
|
||||||
|
"lsp": {
|
||||||
|
"rust-analyzer": {
|
||||||
|
"initialization_options": {
|
||||||
|
"check": {
|
||||||
|
"command": "clippy",
|
||||||
|
},
|
||||||
|
"rustfmt": {
|
||||||
|
"extraArgs": ["+nightly"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
1461
Cargo.lock
generated
1461
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
17
Cargo.toml
17
Cargo.toml
|
|
@ -4,25 +4,21 @@ description = "The session manager for the COSMIC desktop environment"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
license = "GPL-3.0-only"
|
license = "GPL-3.0-only"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
rust-version = "1.85"
|
rust-version = "1.93"
|
||||||
authors = ["Lucy <lucy@system76.com>"]
|
authors = ["Lucy <lucy@system76.com>"]
|
||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
async-signals = "0.5"
|
|
||||||
color-eyre = "0.6"
|
color-eyre = "0.6"
|
||||||
futures-util = "0.3"
|
futures-util = "0.3"
|
||||||
cosmic-dbus-a11y = { git = "https://github.com/pop-os/dbus-settings-bindings" }
|
cosmic-dbus-a11y = { git = "https://github.com/pop-os/dbus-settings-bindings" }
|
||||||
freedesktop-desktop-entry = { version = "0.7.14", optional = true }
|
freedesktop-desktop-entry = { version = "0.8", optional = true }
|
||||||
shell-words = { version = "1.1.0", optional = true }
|
shell-words = { version = "1.1.1", optional = true }
|
||||||
dirs = { version = "6.0.0", optional = true }
|
dirs = { version = "6.0.0", optional = true }
|
||||||
itertools = "0.14"
|
|
||||||
launch-pad = { git = "https://github.com/pop-os/launch-pad" }
|
launch-pad = { git = "https://github.com/pop-os/launch-pad" }
|
||||||
libc = "0.2"
|
|
||||||
log-panics = { version = "2", features = ["with-backtrace"] }
|
log-panics = { version = "2", features = ["with-backtrace"] }
|
||||||
rustix = "1.0"
|
rustix = "1.1"
|
||||||
scopeguard = "1"
|
scopeguard = "1"
|
||||||
sendfd = { version = "0.4", features = ["tokio"] }
|
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
tokio = { version = "1", features = [
|
tokio = { version = "1", features = [
|
||||||
|
|
@ -38,15 +34,14 @@ tokio = { version = "1", features = [
|
||||||
"sync",
|
"sync",
|
||||||
"time",
|
"time",
|
||||||
] }
|
] }
|
||||||
zbus_systemd = { version = "0.25701.0", optional = true, features = [
|
zbus_systemd = { version = "0.26000.0", optional = true, features = [
|
||||||
"systemd1",
|
"systemd1",
|
||||||
] }
|
] }
|
||||||
tokio-util = "0.7"
|
tokio-util = "0.7"
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-journald = { version = "0.3", optional = true }
|
tracing-journald = { version = "0.3", optional = true }
|
||||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||||
zbus = { version = "5.10.0", default-features = false, features = ["tokio"] }
|
zbus = { version = "5.14.0", default-features = false, features = ["tokio"] }
|
||||||
cosmic-notifications-util = { git = "https://github.com/pop-os/cosmic-notifications" }
|
|
||||||
logind-zbus = { version = "5.3.2", optional = true }
|
logind-zbus = { version = "5.3.2", optional = true }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ if [ -n "${SHELL}" ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export XDG_CURRENT_DESKTOP="${XDG_CURRENT_DESKTOP:=COSMIC}"
|
export XDG_CURRENT_DESKTOP="${XDG_CURRENT_DESKTOP:=COSMIC}"
|
||||||
|
export XDG_SESSION_DESKTOP="${XDG_SESSION_DESKTOP:=COSMIC}"
|
||||||
export XDG_SESSION_TYPE="${XDG_SESSION_TYPE:=wayland}"
|
export XDG_SESSION_TYPE="${XDG_SESSION_TYPE:=wayland}"
|
||||||
export _JAVA_AWT_WM_NONREPARENTING=1
|
export _JAVA_AWT_WM_NONREPARENTING=1
|
||||||
export GDK_BACKEND=wayland,x11
|
export GDK_BACKEND=wayland,x11
|
||||||
|
|
@ -38,6 +39,22 @@ export QT_AUTO_SCREEN_SCALE_FACTOR=1
|
||||||
export QT_ENABLE_HIGHDPI_SCALING=1
|
export QT_ENABLE_HIGHDPI_SCALING=1
|
||||||
export DCONF_PROFILE=cosmic
|
export DCONF_PROFILE=cosmic
|
||||||
|
|
||||||
|
# Set the QT platform theme to CuteCosmic. Fallback to qt6ct if CuteCosmic is not installed.
|
||||||
|
if [ -z "$QT_QPA_PLATFORMTHEME" ]; then
|
||||||
|
export QT_QPA_PLATFORMTHEME=cosmic
|
||||||
|
for QT_PLUGIN_PATH in /usr/lib{*,/*}/qt6/plugins; do
|
||||||
|
if [ -f "${QT_PLUGIN_PATH}/platformthemes/libcutecosmictheme.so" ]; then
|
||||||
|
# CuteCosmic found, no need for a fallback.
|
||||||
|
export QT_QPA_PLATFORMTHEME=cosmic
|
||||||
|
break
|
||||||
|
elif [ -f "${QT_PLUGIN_PATH}/platformthemes/libqt6ct.so" ] || [ -f "${QT_PLUGIN_PATH}/platformthemes/libqt5ct.so" ]; then
|
||||||
|
# Fallback to qt6ct, but keep looking for CuteCosmic.
|
||||||
|
# Note that "qt5ct" is compatible with both qt5ct and qt6ct.
|
||||||
|
export QT_QPA_PLATFORMTHEME=qt5ct
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
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 /run/user/$UID/keyring exists
|
||||||
if [ -d "/run/user/$(id -u)/keyring" ]; then
|
if [ -d "/run/user/$(id -u)/keyring" ]; then
|
||||||
|
|
@ -69,16 +86,23 @@ if command -v systemctl >/dev/null; then
|
||||||
# environment, update it.
|
# environment, update it.
|
||||||
mapfile -t existing_env_vars < <(systemctl --user show-environment)
|
mapfile -t existing_env_vars < <(systemctl --user show-environment)
|
||||||
for env_var in "${existing_env_vars[@]}"; do
|
for env_var in "${existing_env_vars[@]}"; do
|
||||||
env_var_name="$(echo "${env_var}" | awk -F '=' '{print $1}')"
|
env_var_name="${env_var%%=*}"
|
||||||
env_var_val_str_to_compare="${env_var_name}=${!env_var_name:-}"
|
env_var_value=${!env_var_name:-}
|
||||||
|
|
||||||
if [[ "${env_var}" != "${env_var_val_str_to_compare}" ]]; then
|
# Skip current iteration if the environment variable's value
|
||||||
# Update only if the value in current environment is non-empty
|
# in the current envionment is unset.
|
||||||
env_var_unassigned_str="${env_var_name}="
|
if [[ -z "${env_var_value}" ]]; then
|
||||||
if [[ "${env_var_val_str_to_compare}" != "${env_var_unassigned_str}" ]]; then
|
continue
|
||||||
systemctl --user import-environment "${env_var_name}" ||:
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
env_var_val_str_to_compare="${env_var_name}=${env_var_value}"
|
||||||
|
env_var_val_str_to_compare_ansi_c_quoted="${env_var_name}=\$'$(printf '%q' "${env_var_value}")'"
|
||||||
|
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
|
||||||
|
fi
|
||||||
|
systemctl --user import-environment "${env_var_name}" ||:
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
||||||
1
debian/control
vendored
1
debian/control
vendored
|
|
@ -12,6 +12,7 @@ Homepage: https://github.com/pop-os/cosmic-session
|
||||||
|
|
||||||
Package: cosmic-session
|
Package: cosmic-session
|
||||||
Architecture: amd64 arm64
|
Architecture: amd64 arm64
|
||||||
|
Conflicts: seatd
|
||||||
Depends:
|
Depends:
|
||||||
${misc:Depends},
|
${misc:Depends},
|
||||||
${shlibs:Depends},
|
${shlibs:Depends},
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use_field_init_shorthand = true
|
||||||
# Unstable formatting options below; remove if you REALLY don't wanna use `cargo +nightly fmt`
|
# Unstable formatting options below; remove if you REALLY don't wanna use `cargo +nightly fmt`
|
||||||
format_code_in_doc_comments = true
|
format_code_in_doc_comments = true
|
||||||
format_strings = true
|
format_strings = true
|
||||||
imports_granularity = "Crate"
|
imports_granularity = "Module"
|
||||||
normalize_comments = true
|
normalize_comments = true
|
||||||
reorder_impl_items = true
|
reorder_impl_items = true
|
||||||
wrap_comments = true
|
wrap_comments = true
|
||||||
20
src/comp.rs
20
src/comp.rs
|
|
@ -1,17 +1,19 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
use color_eyre::eyre::{Result, WrapErr};
|
use color_eyre::eyre::{Result, WrapErr};
|
||||||
use launch_pad::{ProcessManager, process::Process};
|
use launch_pad::ProcessManager;
|
||||||
|
use launch_pad::process::Process;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{collections::HashMap, os::unix::prelude::*};
|
use std::collections::HashMap;
|
||||||
use tokio::{
|
use std::os::unix::prelude::*;
|
||||||
io::AsyncReadExt,
|
use tokio::io::AsyncReadExt;
|
||||||
net::{UnixStream, unix::OwnedReadHalf},
|
use tokio::net::UnixStream;
|
||||||
sync::{mpsc, oneshot},
|
use tokio::net::unix::OwnedReadHalf;
|
||||||
task::JoinHandle,
|
use tokio::sync::{mpsc, oneshot};
|
||||||
};
|
use tokio::task::JoinHandle;
|
||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
|
|
||||||
use crate::{process::mark_as_not_cloexec, service::SessionRequest};
|
use crate::process::mark_as_not_cloexec;
|
||||||
|
use crate::service::SessionRequest;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "snake_case", tag = "message")]
|
#[serde(rename_all = "snake_case", tag = "message")]
|
||||||
|
|
|
||||||
84
src/main.rs
84
src/main.rs
|
|
@ -9,36 +9,36 @@ mod process;
|
||||||
mod service;
|
mod service;
|
||||||
mod systemd;
|
mod systemd;
|
||||||
|
|
||||||
use async_signals::Signals;
|
use color_eyre::Result;
|
||||||
use color_eyre::{Result, eyre::WrapErr};
|
use color_eyre::eyre::WrapErr;
|
||||||
use cosmic_notifications_util::{DAEMON_NOTIFICATIONS_FD, PANEL_NOTIFICATIONS_FD};
|
use launch_pad::ProcessManager;
|
||||||
use futures_util::StreamExt;
|
use launch_pad::process::Process;
|
||||||
#[cfg(feature = "autostart")]
|
|
||||||
use itertools::Itertools;
|
|
||||||
use launch_pad::{ProcessManager, process::Process};
|
|
||||||
use service::SessionRequest;
|
use service::SessionRequest;
|
||||||
|
use std::borrow::Cow;
|
||||||
#[cfg(feature = "autostart")]
|
#[cfg(feature = "autostart")]
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
use std::env;
|
||||||
|
use std::os::fd::AsRawFd;
|
||||||
#[cfg(feature = "autostart")]
|
#[cfg(feature = "autostart")]
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
#[cfg(feature = "autostart")]
|
#[cfg(feature = "autostart")]
|
||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
use std::{borrow::Cow, env, os::fd::AsRawFd, sync::Arc};
|
use std::sync::Arc;
|
||||||
#[cfg(feature = "systemd")]
|
#[cfg(feature = "systemd")]
|
||||||
use systemd::{get_systemd_env, is_systemd_used, spawn_scope};
|
use systemd::{get_systemd_env, is_systemd_used, spawn_scope};
|
||||||
use tokio::{
|
use tokio::signal::unix::{SignalKind, signal};
|
||||||
sync::{
|
use tokio::sync::mpsc::{Receiver, Sender};
|
||||||
Mutex,
|
use tokio::sync::{Mutex, oneshot};
|
||||||
mpsc::{Receiver, Sender},
|
use tokio::time::Duration;
|
||||||
oneshot,
|
|
||||||
},
|
|
||||||
time::Duration,
|
|
||||||
};
|
|
||||||
use tokio_util::sync::CancellationToken;
|
use tokio_util::sync::CancellationToken;
|
||||||
use tracing::{Instrument, metadata::LevelFilter};
|
use tracing::Instrument;
|
||||||
use tracing_subscriber::{EnvFilter, fmt, prelude::*};
|
use tracing::metadata::LevelFilter;
|
||||||
|
use tracing_subscriber::prelude::*;
|
||||||
|
use tracing_subscriber::{EnvFilter, fmt};
|
||||||
|
|
||||||
use crate::notifications::notifications_process;
|
use crate::notifications::{
|
||||||
|
DAEMON_NOTIFICATIONS_FD, PANEL_NOTIFICATIONS_FD, notifications_process,
|
||||||
|
};
|
||||||
#[cfg(feature = "autostart")]
|
#[cfg(feature = "autostart")]
|
||||||
const AUTOSTART_DIR: &'static str = "autostart";
|
const AUTOSTART_DIR: &'static str = "autostart";
|
||||||
#[cfg(feature = "autostart")]
|
#[cfg(feature = "autostart")]
|
||||||
|
|
@ -165,7 +165,7 @@ async fn start(
|
||||||
Ok(env) => {
|
Ok(env) => {
|
||||||
for systemd_env in env {
|
for systemd_env in env {
|
||||||
// Only update the envvar if unset
|
// Only update the envvar if unset
|
||||||
if std::env::var_os(&systemd_env.key) == None {
|
if std::env::var_os(&systemd_env.key).is_none() {
|
||||||
// Blacklist of envvars that we shouldn't touch (taken from KDE)
|
// Blacklist of envvars that we shouldn't touch (taken from KDE)
|
||||||
if (!systemd_env.key.starts_with("XDG_")
|
if (!systemd_env.key.starts_with("XDG_")
|
||||||
|| systemd_env.key == "XDG_DATA_DIRS"
|
|| systemd_env.key == "XDG_DATA_DIRS"
|
||||||
|
|
@ -244,10 +244,8 @@ async fn start(
|
||||||
.instrument(stderr_span)
|
.instrument(stderr_span)
|
||||||
})
|
})
|
||||||
.with_on_exit(move |_, _, _, will_restart| {
|
.with_on_exit(move |_, _, _, will_restart| {
|
||||||
if !will_restart {
|
if !will_restart && let Some(tx) = settings_exit_tx.lock().unwrap().take() {
|
||||||
if let Some(tx) = settings_exit_tx.lock().unwrap().take() {
|
_ = tx.send(());
|
||||||
_ = tx.send(());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
async {}
|
async {}
|
||||||
}),
|
}),
|
||||||
|
|
@ -415,7 +413,9 @@ async fn start(
|
||||||
|
|
||||||
if let Some(program_name) = exec_words.next() {
|
if let Some(program_name) = exec_words.next() {
|
||||||
// filter out any placeholder args, since we might not be able to deal with them
|
// filter out any placeholder args, since we might not be able to deal with them
|
||||||
let filtered_args = exec_words.filter(|s| !s.starts_with("%")).collect_vec();
|
let filtered_args = exec_words
|
||||||
|
.filter(|s| !s.starts_with("%"))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
// escape them
|
// escape them
|
||||||
let escaped_args = shell_words::split(&*filtered_args.join(" "));
|
let escaped_args = shell_words::split(&*filtered_args.join(" "));
|
||||||
|
|
@ -457,7 +457,8 @@ async fn start(
|
||||||
info!("started {} programs", dedupe.len());
|
info!("started {} programs", dedupe.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut signals = Signals::new(vec![libc::SIGTERM, libc::SIGINT]).unwrap();
|
let mut sigterm = signal(SignalKind::terminate()).expect("Failed to bind SIGTERM handler");
|
||||||
|
let mut sigint = signal(SignalKind::interrupt()).expect("Failed to bind SIGINT handler");
|
||||||
let mut status = Status::Exited;
|
let mut status = Status::Exited;
|
||||||
let session_dbus_rx_next = session_rx.recv();
|
let session_dbus_rx_next = session_rx.recv();
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
|
|
@ -475,12 +476,11 @@ async fn start(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
signal = signals.next() => match signal {
|
_ = sigterm.recv() => {
|
||||||
Some(libc::SIGTERM | libc::SIGINT) => {
|
info!("EXITING: received SIGTERM request to terminate");
|
||||||
info!("EXITING: received request to terminate");
|
},
|
||||||
}
|
_ = sigint.recv() => {
|
||||||
Some(signal) => unreachable!("EXITING: received unhandled signal {}", signal),
|
info!("EXITING: received SIGINT request to terminate");
|
||||||
None => {},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -534,17 +534,15 @@ async fn start_component(
|
||||||
})
|
})
|
||||||
.with_on_start(move |pman, pkey, _will_restart| async move {
|
.with_on_start(move |pman, pkey, _will_restart| async move {
|
||||||
#[cfg(feature = "systemd")]
|
#[cfg(feature = "systemd")]
|
||||||
if *is_systemd_used() {
|
if *is_systemd_used()
|
||||||
if let Ok((innr_cmd, Some(pid))) = pman.get_exe_and_pid(pkey).await {
|
&& let Ok((innr_cmd, Some(pid))) = pman.get_exe_and_pid(pkey).await
|
||||||
if let Err(err) = spawn_scope(innr_cmd.clone(), vec![pid]).await {
|
&& let Err(err) = spawn_scope(innr_cmd.clone(), vec![pid]).await
|
||||||
warn!(
|
{
|
||||||
"Failed to spawn scope for {}. Creating transient unit failed \
|
warn!(
|
||||||
with {}",
|
"Failed to spawn scope for {}. Creating transient unit failed with {}",
|
||||||
innr_cmd, err
|
innr_cmd, err
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.with_on_exit(move |mut _pman, _key, err_code, _will_restart| {
|
.with_on_exit(move |mut _pman, _key, err_code, _will_restart| {
|
||||||
if let Some(err) = err_code {
|
if let Some(err) = err_code {
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,17 @@
|
||||||
use color_eyre::{Result, eyre::Context};
|
use color_eyre::Result;
|
||||||
use cosmic_notifications_util::{DAEMON_NOTIFICATIONS_FD, PANEL_NOTIFICATIONS_FD};
|
use color_eyre::eyre::Context;
|
||||||
use launch_pad::{ProcessKey, process::Process};
|
use launch_pad::ProcessKey;
|
||||||
|
use launch_pad::process::Process;
|
||||||
use rustix::fd::AsRawFd;
|
use rustix::fd::AsRawFd;
|
||||||
use std::{
|
use std::os::fd::OwnedFd;
|
||||||
os::{fd::OwnedFd, unix::net::UnixStream},
|
use std::os::unix::net::UnixStream;
|
||||||
sync::Arc,
|
use std::sync::Arc;
|
||||||
};
|
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
use tracing::Instrument;
|
use tracing::Instrument;
|
||||||
|
|
||||||
|
pub const PANEL_NOTIFICATIONS_FD: &str = "PANEL_NOTIFICATIONS_FD";
|
||||||
|
pub const DAEMON_NOTIFICATIONS_FD: &str = "DAEMON_NOTIFICATIONS_FD";
|
||||||
|
|
||||||
pub fn create_socket() -> Result<(OwnedFd, OwnedFd)> {
|
pub fn create_socket() -> Result<(OwnedFd, OwnedFd)> {
|
||||||
// Create a new pair of unnamed Unix sockets
|
// Create a new pair of unnamed Unix sockets
|
||||||
let (sock_1, sock_2) = UnixStream::pair().wrap_err("failed to create socket pair")?;
|
let (sock_1, sock_2) = UnixStream::pair().wrap_err("failed to create socket pair")?;
|
||||||
|
|
@ -26,6 +29,7 @@ pub fn create_socket() -> Result<(OwnedFd, OwnedFd)> {
|
||||||
Ok((OwnedFd::from(sock_1), OwnedFd::from(sock_2)))
|
Ok((OwnedFd::from(sock_1), OwnedFd::from(sock_2)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn notifications_process(
|
pub fn notifications_process(
|
||||||
span: tracing::Span,
|
span: tracing::Span,
|
||||||
cmd: &'static str,
|
cmd: &'static str,
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,11 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use std::{
|
use std::path::Path;
|
||||||
path::Path,
|
use std::process::{Command, Stdio};
|
||||||
process::{Command, Stdio},
|
use std::sync::OnceLock;
|
||||||
sync::OnceLock,
|
|
||||||
};
|
|
||||||
|
|
||||||
use zbus::{
|
use zbus::Connection;
|
||||||
Connection,
|
use zbus::zvariant::{Array, OwnedValue};
|
||||||
zvariant::{Array, OwnedValue},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct EnvVar {
|
pub struct EnvVar {
|
||||||
|
|
@ -17,11 +13,11 @@ pub struct EnvVar {
|
||||||
pub value: String,
|
pub value: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<EnvVar> for (&str, &str) {
|
impl From<(&str, &str)> for EnvVar {
|
||||||
fn into(self) -> EnvVar {
|
fn from(val: (&str, &str)) -> Self {
|
||||||
EnvVar {
|
EnvVar {
|
||||||
key: self.0.to_owned(),
|
key: val.0.to_owned(),
|
||||||
value: self.1.to_owned(),
|
value: val.1.to_owned(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue