Add D-Bus session and system services
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::time::Duration;
|
||||
use zbus::Connection;
|
||||
|
||||
static SLEEP_ACTIVE: AtomicBool = AtomicBool::new(false);
|
||||
static SHUTDOWN_FIRED: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
const ACPI_SLEEP_PATH: &str = "/scheme/acpi/sleep";
|
||||
const ACPI_SHUTDOWN_PATH: &str = "/scheme/acpi/shutdown";
|
||||
const POLL_INTERVAL: Duration = Duration::from_secs(5);
|
||||
|
||||
fn read_acpi_flag(path: &str) -> bool {
|
||||
match std::fs::read_to_string(path) {
|
||||
Ok(content) => {
|
||||
let trimmed = content.trim().to_lowercase();
|
||||
!trimmed.is_empty() && trimmed != "0"
|
||||
}
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn watch_and_emit(connection: Connection) {
|
||||
loop {
|
||||
tokio::time::sleep(POLL_INTERVAL).await;
|
||||
|
||||
let sleep_now = tokio::task::spawn_blocking(|| read_acpi_flag(ACPI_SLEEP_PATH))
|
||||
.await
|
||||
.unwrap_or(false);
|
||||
|
||||
let was_sleeping = SLEEP_ACTIVE.load(Ordering::Relaxed);
|
||||
|
||||
if sleep_now && !was_sleeping {
|
||||
SLEEP_ACTIVE.store(true, Ordering::Relaxed);
|
||||
let _ = connection.emit_signal(
|
||||
None::<&str>,
|
||||
"/org/freedesktop/login1",
|
||||
"org.freedesktop.login1.Manager",
|
||||
"PrepareForSleep",
|
||||
&true,
|
||||
).await;
|
||||
} else if !sleep_now && was_sleeping {
|
||||
SLEEP_ACTIVE.store(false, Ordering::Relaxed);
|
||||
let _ = connection.emit_signal(
|
||||
None::<&str>,
|
||||
"/org/freedesktop/login1",
|
||||
"org.freedesktop.login1.Manager",
|
||||
"PrepareForSleep",
|
||||
&false,
|
||||
).await;
|
||||
}
|
||||
|
||||
let shutdown_now = tokio::task::spawn_blocking(|| read_acpi_flag(ACPI_SHUTDOWN_PATH))
|
||||
.await
|
||||
.unwrap_or(false);
|
||||
|
||||
if shutdown_now && !SHUTDOWN_FIRED.load(Ordering::Relaxed) {
|
||||
SHUTDOWN_FIRED.store(true, Ordering::Relaxed);
|
||||
let _ = connection.emit_signal(
|
||||
None::<&str>,
|
||||
"/org/freedesktop/login1",
|
||||
"org.freedesktop.login1.Manager",
|
||||
"PrepareForShutdown",
|
||||
&true,
|
||||
).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
use std::{collections::HashMap, fs::File, io};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DeviceMap {
|
||||
static_paths: HashMap<(u32, u32), String>,
|
||||
}
|
||||
|
||||
impl DeviceMap {
|
||||
pub fn new() -> Self {
|
||||
let static_paths = HashMap::from([
|
||||
((226, 0), String::from("/scheme/drm/card0")),
|
||||
((226, 1), String::from("/scheme/drm/card1")),
|
||||
((13, 64), String::from("/dev/input/event0")),
|
||||
((13, 65), String::from("/dev/input/event1")),
|
||||
((13, 66), String::from("/dev/input/event2")),
|
||||
((13, 67), String::from("/dev/input/event3")),
|
||||
((29, 0), String::from("/dev/fb0")),
|
||||
((1, 1), String::from("/scheme/null")),
|
||||
((1, 5), String::from("/scheme/zero")),
|
||||
((1, 8), String::from("/scheme/rand")),
|
||||
]);
|
||||
|
||||
Self { static_paths }
|
||||
}
|
||||
|
||||
pub fn resolve(&self, major: u32, minor: u32) -> Option<String> {
|
||||
if let Some(path) = self.static_paths.get(&(major, minor)) {
|
||||
return Some(path.clone());
|
||||
}
|
||||
|
||||
match (major, minor) {
|
||||
(13, minor) if minor >= 68 => Some(format!("/dev/input/event{}", minor - 64)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open_device(&self, major: u32, minor: u32) -> io::Result<File> {
|
||||
let Some(path) = self.resolve(major, minor) else {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
format!("no Red Bear device mapping for major={major}, minor={minor}"),
|
||||
));
|
||||
};
|
||||
|
||||
File::open(path)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
mod acpi_watcher;
|
||||
mod device_map;
|
||||
mod manager;
|
||||
mod seat;
|
||||
mod session;
|
||||
|
||||
use std::{
|
||||
env,
|
||||
error::Error,
|
||||
process,
|
||||
};
|
||||
|
||||
use device_map::DeviceMap;
|
||||
use manager::LoginManager;
|
||||
use seat::LoginSeat;
|
||||
use session::LoginSession;
|
||||
use tokio::runtime::Builder as RuntimeBuilder;
|
||||
use zbus::{
|
||||
Address,
|
||||
connection::Builder as ConnectionBuilder,
|
||||
zvariant::OwnedObjectPath,
|
||||
};
|
||||
|
||||
const BUS_NAME: &str = "org.freedesktop.login1";
|
||||
const MANAGER_PATH: &str = "/org/freedesktop/login1";
|
||||
const SESSION_PATH: &str = "/org/freedesktop/login1/session/c1";
|
||||
const SEAT_PATH: &str = "/org/freedesktop/login1/seat/seat0";
|
||||
const USER_PATH: &str = "/org/freedesktop/login1/user/0";
|
||||
|
||||
enum Command {
|
||||
Run,
|
||||
Help,
|
||||
}
|
||||
|
||||
fn usage() -> &'static str {
|
||||
"Usage: redbear-sessiond [--help]"
|
||||
}
|
||||
|
||||
fn parse_args() -> Result<Command, String> {
|
||||
let mut args = env::args().skip(1);
|
||||
|
||||
match args.next() {
|
||||
None => Ok(Command::Run),
|
||||
Some(arg) if arg == "--help" || arg == "-h" => {
|
||||
if args.next().is_some() {
|
||||
return Err(String::from("unexpected extra arguments after --help"));
|
||||
}
|
||||
|
||||
Ok(Command::Help)
|
||||
}
|
||||
Some(arg) => Err(format!("unrecognized argument '{arg}'")),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_object_path(path: &str) -> Result<OwnedObjectPath, Box<dyn Error>> {
|
||||
Ok(OwnedObjectPath::try_from(path.to_owned())?)
|
||||
}
|
||||
|
||||
fn system_connection_builder() -> Result<ConnectionBuilder<'static>, Box<dyn Error>> {
|
||||
if let Ok(address) = env::var("DBUS_STARTER_ADDRESS") {
|
||||
Ok(ConnectionBuilder::address(Address::try_from(address.as_str())?)?)
|
||||
} else {
|
||||
Ok(ConnectionBuilder::system()?)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(unix, not(target_os = "redox")))]
|
||||
async fn wait_for_shutdown() -> Result<(), Box<dyn Error>> {
|
||||
use tokio::signal::unix::{SignalKind, signal};
|
||||
|
||||
let mut terminate = signal(SignalKind::terminate())?;
|
||||
|
||||
tokio::select! {
|
||||
_ = terminate.recv() => Ok(()),
|
||||
_ = tokio::signal::ctrl_c() => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
async fn wait_for_shutdown() -> Result<(), Box<dyn Error>> {
|
||||
std::future::pending::<()>().await;
|
||||
#[allow(unreachable_code)]
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(all(not(unix), not(target_os = "redox")))]
|
||||
async fn wait_for_shutdown() -> Result<(), Box<dyn Error>> {
|
||||
tokio::signal::ctrl_c().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn run_daemon() -> Result<(), Box<dyn Error>> {
|
||||
eprintln!("redbear-sessiond: startup begin");
|
||||
let session_path = parse_object_path(SESSION_PATH)?;
|
||||
let seat_path = parse_object_path(SEAT_PATH)?;
|
||||
let user_path = parse_object_path(USER_PATH)?;
|
||||
eprintln!("redbear-sessiond: object paths parsed");
|
||||
|
||||
let session = LoginSession::new(seat_path.clone(), user_path, DeviceMap::new());
|
||||
let seat = LoginSeat::new(session_path.clone());
|
||||
let manager = LoginManager::new(session_path, seat_path);
|
||||
|
||||
eprintln!("redbear-sessiond: starter address={:?}", env::var("DBUS_STARTER_ADDRESS").ok());
|
||||
eprintln!("redbear-sessiond: building D-Bus connection");
|
||||
let connection = system_connection_builder()?
|
||||
.name(BUS_NAME)?
|
||||
.serve_at(MANAGER_PATH, manager)?
|
||||
.serve_at(SESSION_PATH, session)?
|
||||
.serve_at(SEAT_PATH, seat)?
|
||||
.build()
|
||||
.await?;
|
||||
|
||||
eprintln!("redbear-sessiond: registered {BUS_NAME} on the system bus");
|
||||
|
||||
tokio::spawn(acpi_watcher::watch_and_emit(connection.clone()));
|
||||
|
||||
wait_for_shutdown().await?;
|
||||
eprintln!("redbear-sessiond: received shutdown signal, exiting cleanly");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
match parse_args() {
|
||||
Ok(Command::Help) => {
|
||||
println!("{}", usage());
|
||||
}
|
||||
Ok(Command::Run) => {
|
||||
let runtime = match RuntimeBuilder::new_multi_thread().enable_all().build() {
|
||||
Ok(runtime) => runtime,
|
||||
Err(err) => {
|
||||
eprintln!("redbear-sessiond: failed to create tokio runtime: {err}");
|
||||
process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(err) = runtime.block_on(run_daemon()) {
|
||||
eprintln!("redbear-sessiond: fatal error: {err}");
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("redbear-sessiond: {err}");
|
||||
eprintln!("{}", usage());
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
use zbus::{
|
||||
fdo,
|
||||
interface,
|
||||
object_server::SignalEmitter,
|
||||
zvariant::OwnedObjectPath,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct LoginManager {
|
||||
session_id: String,
|
||||
session_path: OwnedObjectPath,
|
||||
seat_id: String,
|
||||
seat_path: OwnedObjectPath,
|
||||
}
|
||||
|
||||
impl LoginManager {
|
||||
pub fn new(session_path: OwnedObjectPath, seat_path: OwnedObjectPath) -> Self {
|
||||
Self {
|
||||
session_id: String::from("c1"),
|
||||
session_path,
|
||||
seat_id: String::from("seat0"),
|
||||
seat_path,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[interface(name = "org.freedesktop.login1.Manager")]
|
||||
impl LoginManager {
|
||||
fn get_session(&self, id: &str) -> fdo::Result<OwnedObjectPath> {
|
||||
if id == self.session_id {
|
||||
return Ok(self.session_path.clone());
|
||||
}
|
||||
|
||||
Err(fdo::Error::Failed(format!("unknown login1 session '{id}'")))
|
||||
}
|
||||
|
||||
fn list_sessions(&self) -> fdo::Result<Vec<(String, u32, String, String, OwnedObjectPath)>> {
|
||||
Ok(vec![(
|
||||
self.session_id.clone(),
|
||||
0,
|
||||
String::from("root"),
|
||||
self.seat_id.clone(),
|
||||
self.session_path.clone(),
|
||||
)])
|
||||
}
|
||||
|
||||
fn get_seat(&self, id: &str) -> fdo::Result<OwnedObjectPath> {
|
||||
if id == self.seat_id {
|
||||
return Ok(self.seat_path.clone());
|
||||
}
|
||||
|
||||
Err(fdo::Error::Failed(format!("unknown login1 seat '{id}'")))
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "IdleHint")]
|
||||
fn idle_hint(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "IdleSinceHint")]
|
||||
fn idle_since_hint(&self) -> u64 {
|
||||
0
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "IdleSinceHintMonotonic")]
|
||||
fn idle_since_hint_monotonic(&self) -> u64 {
|
||||
0
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "BlockInhibited")]
|
||||
fn block_inhibited(&self) -> String {
|
||||
String::new()
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "DelayInhibited")]
|
||||
fn delay_inhibited(&self) -> String {
|
||||
String::new()
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "InhibitDelayMaxUSec")]
|
||||
fn inhibit_delay_max_usec(&self) -> u64 {
|
||||
0
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "HandleLidSwitch")]
|
||||
fn handle_lid_switch(&self) -> String {
|
||||
String::from("ignore")
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "HandlePowerKey")]
|
||||
fn handle_power_key(&self) -> String {
|
||||
String::from("poweroff")
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "PreparingForSleep")]
|
||||
fn preparing_for_sleep(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "PreparingForShutdown")]
|
||||
fn preparing_for_shutdown(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[zbus(signal, name = "PrepareForSleep")]
|
||||
async fn prepare_for_sleep(signal_emitter: &SignalEmitter<'_>, before: bool) -> zbus::Result<()>;
|
||||
|
||||
#[zbus(signal, name = "PrepareForShutdown")]
|
||||
async fn prepare_for_shutdown(
|
||||
signal_emitter: &SignalEmitter<'_>,
|
||||
before: bool,
|
||||
) -> zbus::Result<()>;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
use std::sync::Mutex;
|
||||
|
||||
use zbus::{fdo, interface, zvariant::OwnedObjectPath};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LoginSeat {
|
||||
id: String,
|
||||
session_id: String,
|
||||
session_path: OwnedObjectPath,
|
||||
last_requested_vt: Mutex<u32>,
|
||||
}
|
||||
|
||||
impl LoginSeat {
|
||||
pub fn new(session_path: OwnedObjectPath) -> Self {
|
||||
Self {
|
||||
id: String::from("seat0"),
|
||||
session_id: String::from("c1"),
|
||||
session_path,
|
||||
last_requested_vt: Mutex::new(1),
|
||||
}
|
||||
}
|
||||
|
||||
fn last_requested_vt(&self) -> fdo::Result<std::sync::MutexGuard<'_, u32>> {
|
||||
self.last_requested_vt
|
||||
.lock()
|
||||
.map_err(|_| fdo::Error::Failed(String::from("seat VT state is poisoned")))
|
||||
}
|
||||
}
|
||||
|
||||
#[interface(name = "org.freedesktop.login1.Seat")]
|
||||
impl LoginSeat {
|
||||
fn switch_to(&mut self, vt: u32) -> fdo::Result<()> {
|
||||
let mut last_requested_vt = self.last_requested_vt()?;
|
||||
*last_requested_vt = vt;
|
||||
eprintln!(
|
||||
"redbear-sessiond: SwitchTo requested for seat {} -> vt {vt} (delegated to inputd -A externally)",
|
||||
self.id
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "Id")]
|
||||
fn id(&self) -> String {
|
||||
self.id.clone()
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "ActiveSession")]
|
||||
fn active_session(&self) -> (String, OwnedObjectPath) {
|
||||
(self.session_id.clone(), self.session_path.clone())
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "Sessions")]
|
||||
fn sessions(&self) -> Vec<(String, OwnedObjectPath)> {
|
||||
vec![(self.session_id.clone(), self.session_path.clone())]
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "CanGraphical")]
|
||||
fn can_graphical(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "CanTTY")]
|
||||
fn can_tty(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "IdleHint")]
|
||||
fn idle_hint(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
os::fd::OwnedFd as StdOwnedFd,
|
||||
process,
|
||||
sync::Mutex,
|
||||
};
|
||||
|
||||
use zbus::{
|
||||
fdo,
|
||||
interface,
|
||||
object_server::SignalEmitter,
|
||||
zvariant::{Fd, OwnedFd, OwnedObjectPath},
|
||||
};
|
||||
|
||||
use crate::device_map::DeviceMap;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LoginSession {
|
||||
id: String,
|
||||
seat_id: String,
|
||||
seat_path: OwnedObjectPath,
|
||||
user_uid: u32,
|
||||
user_path: OwnedObjectPath,
|
||||
leader: u32,
|
||||
device_map: DeviceMap,
|
||||
controlled: Mutex<bool>,
|
||||
taken_devices: Mutex<HashSet<(u32, u32)>>,
|
||||
}
|
||||
|
||||
impl LoginSession {
|
||||
pub fn new(
|
||||
seat_path: OwnedObjectPath,
|
||||
user_path: OwnedObjectPath,
|
||||
device_map: DeviceMap,
|
||||
) -> Self {
|
||||
Self {
|
||||
id: String::from("c1"),
|
||||
seat_id: String::from("seat0"),
|
||||
seat_path,
|
||||
user_uid: 0,
|
||||
user_path,
|
||||
leader: process::id(),
|
||||
device_map,
|
||||
controlled: Mutex::new(false),
|
||||
taken_devices: Mutex::new(HashSet::new()),
|
||||
}
|
||||
}
|
||||
|
||||
fn control_state(&self) -> fdo::Result<std::sync::MutexGuard<'_, bool>> {
|
||||
self.controlled
|
||||
.lock()
|
||||
.map_err(|_| fdo::Error::Failed(String::from("login1 control state is poisoned")))
|
||||
}
|
||||
|
||||
fn taken_devices(&self) -> fdo::Result<std::sync::MutexGuard<'_, HashSet<(u32, u32)>>> {
|
||||
self.taken_devices
|
||||
.lock()
|
||||
.map_err(|_| fdo::Error::Failed(String::from("login1 device state is poisoned")))
|
||||
}
|
||||
}
|
||||
|
||||
#[interface(name = "org.freedesktop.login1.Session")]
|
||||
impl LoginSession {
|
||||
fn activate(&self) -> fdo::Result<()> {
|
||||
eprintln!("redbear-sessiond: Activate requested for session {}", self.id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn take_control(&self, force: bool) -> fdo::Result<()> {
|
||||
let mut controlled = self.control_state()?;
|
||||
*controlled = true;
|
||||
eprintln!(
|
||||
"redbear-sessiond: TakeControl requested for session {} (force={force})",
|
||||
self.id
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn release_control(&self) -> fdo::Result<()> {
|
||||
let mut controlled = self.control_state()?;
|
||||
*controlled = false;
|
||||
eprintln!("redbear-sessiond: ReleaseControl requested for session {}", self.id);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn take_device(&self, major: u32, minor: u32) -> fdo::Result<OwnedFd> {
|
||||
let file = self
|
||||
.device_map
|
||||
.open_device(major, minor)
|
||||
.map_err(|err| fdo::Error::Failed(format!("TakeDevice({major}, {minor}) failed: {err}")))?;
|
||||
|
||||
let mut taken_devices = self.taken_devices()?;
|
||||
taken_devices.insert((major, minor));
|
||||
|
||||
let owned_fd: StdOwnedFd = file.into();
|
||||
eprintln!(
|
||||
"redbear-sessiond: TakeDevice granted for session {} -> ({major}, {minor})",
|
||||
self.id
|
||||
);
|
||||
|
||||
Ok(OwnedFd::from(owned_fd))
|
||||
}
|
||||
|
||||
fn release_device(&self, major: u32, minor: u32) -> fdo::Result<()> {
|
||||
let mut taken_devices = self.taken_devices()?;
|
||||
taken_devices.remove(&(major, minor));
|
||||
eprintln!(
|
||||
"redbear-sessiond: ReleaseDevice requested for session {} -> ({major}, {minor})",
|
||||
self.id
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn pause_device_complete(&self, major: u32, minor: u32) -> fdo::Result<()> {
|
||||
eprintln!(
|
||||
"redbear-sessiond: PauseDeviceComplete received for session {} -> ({major}, {minor})",
|
||||
self.id
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "Active")]
|
||||
fn active(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "Remote")]
|
||||
fn remote(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "Type")]
|
||||
fn kind(&self) -> String {
|
||||
String::from("wayland")
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "Class")]
|
||||
fn class(&self) -> String {
|
||||
String::from("user")
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "Service")]
|
||||
fn service(&self) -> String {
|
||||
String::from("redbear")
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "Desktop")]
|
||||
fn desktop(&self) -> String {
|
||||
String::from("KDE")
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "Display")]
|
||||
fn display(&self) -> String {
|
||||
String::new()
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "Id")]
|
||||
fn id(&self) -> String {
|
||||
self.id.clone()
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "State")]
|
||||
fn state(&self) -> String {
|
||||
String::from("online")
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "Seat")]
|
||||
fn seat(&self) -> (String, OwnedObjectPath) {
|
||||
(self.seat_id.clone(), self.seat_path.clone())
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "User")]
|
||||
fn user(&self) -> (u32, OwnedObjectPath) {
|
||||
(self.user_uid, self.user_path.clone())
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "VTNr")]
|
||||
fn vt_nr(&self) -> u32 {
|
||||
1
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "Leader")]
|
||||
fn leader(&self) -> u32 {
|
||||
self.leader
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "Audit")]
|
||||
fn audit(&self) -> String {
|
||||
String::new()
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "TTY")]
|
||||
fn tty(&self) -> String {
|
||||
String::new()
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "RemoteUser")]
|
||||
fn remote_user(&self) -> String {
|
||||
String::new()
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "RemoteHost")]
|
||||
fn remote_host(&self) -> String {
|
||||
String::new()
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "IdleHint")]
|
||||
fn idle_hint(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[zbus(property(emits_changed_signal = "const"), name = "LockedHint")]
|
||||
fn locked_hint(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[zbus(signal, name = "PauseDevice")]
|
||||
async fn pause_device(
|
||||
signal_emitter: &SignalEmitter<'_>,
|
||||
major: u32,
|
||||
minor: u32,
|
||||
kind: String,
|
||||
) -> zbus::Result<()>;
|
||||
|
||||
#[zbus(signal, name = "ResumeDevice")]
|
||||
async fn resume_device(
|
||||
signal_emitter: &SignalEmitter<'_>,
|
||||
major: u32,
|
||||
minor: u32,
|
||||
fd: Fd<'_>,
|
||||
) -> zbus::Result<()>;
|
||||
}
|
||||
Reference in New Issue
Block a user