Fix compositor output routing and pointer hints; format imports

This commit is contained in:
Samuel Onoja committed 2026-09-30 06:39:58 +01:00
1 parent 88e4f3c135
commit 46509f880a
108 files changed
+3682 -8371

No files matched your search

+11 -27
View File
@@ -1,14 +1,11 @@
mod prompt;
mod session;
use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use serde::{Deserialize, Serialize};
use std::{
collections::HashMap,
sync::{
Arc, Mutex,
atomic::{AtomicBool, Ordering},
},
};
use zbus::zvariant::{OwnedValue, Value};
const AGENT_PATH: &str = "/dev/ferese/PolkitAgent";
@@ -45,9 +42,8 @@ impl Agent {
cookie: String,
identities: Vec<Identity>,
) -> zbus::fdo::Result<()> {
let uid = choose_identity(&identities).ok_or_else(|| {
zbus::fdo::Error::Failed("No supported authentication identity".into())
})?;
let uid = choose_identity(&identities)
.ok_or_else(|| zbus::fdo::Error::Failed("No supported authentication identity".into()))?;
let cancelled = Arc::new(AtomicBool::new(false));
{
@@ -60,9 +56,7 @@ impl Agent {
let result = tokio::task::spawn_blocking({
let cookie = cookie.clone();
move || {
session::authenticate(uid, message.chars().take(240).collect(), cookie, cancelled)
}
move || session::authenticate(uid, message.chars().take(240).collect(), cookie, cancelled)
})
.await
.map_err(|error| zbus::fdo::Error::Failed(error.to_string()))?;
@@ -116,10 +110,7 @@ fn session_subject() -> Result<(String, HashMap<String, Value<'static>>), String
.map_err(|error| error.to_string())?;
let mut details = HashMap::new();
details.insert("pid".to_owned(), Value::from(std::process::id()));
details.insert(
"uid".to_owned(),
Value::from(unsafe { libc::geteuid() } as i32),
);
details.insert("uid".to_owned(), Value::from(unsafe { libc::geteuid() } as i32));
details.insert("start-time".to_owned(), Value::from(started));
Ok(("unix-process".into(), details))
}
@@ -130,15 +121,11 @@ async fn run_agent() -> Result<(), Box<dyn std::error::Error>> {
.serve_at(AGENT_PATH, Agent::default())?
.build()
.await?;
let authority =
zbus::Proxy::new(&connection, AUTHORITY, AUTHORITY_PATH, AUTHORITY_INTERFACE).await?;
let authority = zbus::Proxy::new(&connection, AUTHORITY, AUTHORITY_PATH, AUTHORITY_INTERFACE).await?;
let locale = std::env::var("LANG").unwrap_or_default();
authority
.call::<_, _, ()>(
"RegisterAuthenticationAgent",
&(subject, locale, AGENT_PATH),
)
.call::<_, _, ()>("RegisterAuthenticationAgent", &(subject, locale, AGENT_PATH))
.await?;
std::future::pending::<()>().await;
@@ -174,9 +161,6 @@ mod tests {
HashMap::from([("uid".to_owned(), OwnedValue::from(uid))]),
)
};
assert_eq!(
choose_identity(&[identity(0), identity(current)]),
Some(current)
);
assert_eq!(choose_identity(&[identity(0), identity(current)]), Some(current));
}
}
+25 -56
View File
@@ -1,19 +1,16 @@
use crate::PromptEvent;
use cosmic::{
Element,
app::{Core, Settings, Task},
iced::{Alignment, Color, Length, Size, Subscription, window},
theme,
widget::{self, button, column, container, row},
};
use std::{
collections::VecDeque,
io::{BufRead, BufReader, Write},
sync::{Arc, Mutex},
time::Duration,
};
use std::collections::VecDeque;
use std::io::{BufRead, BufReader, Write};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use cosmic::app::{Core, Settings, Task};
use cosmic::iced::{Alignment, Color, Length, Size, Subscription, window};
use cosmic::widget::{button, column, container, row};
use cosmic::{Element, theme, widget};
use zeroize::{Zeroize, Zeroizing};
use crate::PromptEvent;
#[derive(Clone)]
struct Appearance {
surface: Color,
@@ -103,9 +100,7 @@ fn content_height(description: &str, status: Option<&str>) -> f32 {
.lines()
.map(|line| line.chars().count().div_ceil(48).max(1))
.sum();
let status_height = status.map_or(0, |message| {
14 + 18 * message.chars().count().div_ceil(48).clamp(1, 3)
});
let status_height = status.map_or(0, |message| 14 + 18 * message.chars().count().div_ceil(48).clamp(1, 3));
(214 + 18 * lines.saturating_sub(1) + status_height).min(360) as f32
}
@@ -163,10 +158,7 @@ fn focus() -> Task<Message> {
impl Prompt {
fn resize_to_content(&mut self) -> Task<Message> {
let height = content_height(
&self.description,
self.error.as_deref().or(self.info.as_deref()),
);
let height = content_height(&self.description, self.error.as_deref().or(self.info.as_deref()));
if (height - self.height).abs() < 1.0 {
return Task::none();
}
@@ -180,12 +172,7 @@ impl Prompt {
impl cosmic::Application for Prompt {
type Executor = cosmic::executor::Default;
type Flags = (
Arc<Mutex<VecDeque<PromptEvent>>>,
String,
String,
Appearance,
);
type Flags = (Arc<Mutex<VecDeque<PromptEvent>>>, String, String, Appearance);
type Message = Message;
const APP_ID: &'static str = "dev.ferese.Authentication";
@@ -198,21 +185,14 @@ impl cosmic::Application for Prompt {
}
fn style(&self) -> Option<cosmic::iced::theme::Style> {
Some(
self.appearance
.palette()
.application_style(if self.material.is_some() {
cosmic::iced::Color::TRANSPARENT
} else {
self.appearance.surface
}),
)
Some(self.appearance.palette().application_style(if self.material.is_some() {
cosmic::iced::Color::TRANSPARENT
} else {
self.appearance.surface
}))
}
fn init(
mut core: Core,
(incoming, description, user, appearance): Self::Flags,
) -> (Self, Task<Message>) {
fn init(mut core: Core, (incoming, description, user, appearance): Self::Flags) -> (Self, Task<Message>) {
core.window.show_headerbar = false;
core.window.border_padding = Some(0);
core.window.content_container = false;
@@ -257,11 +237,8 @@ impl cosmic::Application for Prompt {
fn update(&mut self, message: Message) -> Task<Message> {
match message {
Message::WindowOpened(id) => {
return cosmic::iced::window::run(
id,
ferese_theme::material::ModalMaterial::attach,
)
.map(|result| cosmic::Action::App(Message::MaterialAttached(result)));
return cosmic::iced::window::run(id, ferese_theme::material::ModalMaterial::attach)
.map(|result| cosmic::Action::App(Message::MaterialAttached(result)));
}
Message::MaterialAttached(result) => {
self.material = result.ok();
@@ -323,9 +300,7 @@ impl cosmic::Application for Prompt {
.id(widget::Id::new("auth-response"))
.font(palette.font)
.padding([7, 12])
.style(ferese_theme::controls::authentication_input(
palette.palette(),
));
.style(ferese_theme::controls::authentication_input(palette.palette()));
if !self.echo {
input = input.password();
}
@@ -347,10 +322,7 @@ impl cosmic::Application for Prompt {
.height(40)
.center_x(40)
.center_y(40)
.class(ferese_theme::controls::surface(
palette.accent.scale_alpha(0.13),
12.,
)),
.class(ferese_theme::controls::surface(palette.accent.scale_alpha(0.13), 12.,)),
column![
ferese_theme::text("Authentication required", palette.font).size(18),
ferese_theme::text(format!("Confirm as {}", self.user), palette.font)
@@ -384,10 +356,7 @@ impl cosmic::Application for Prompt {
body = body.push(
row![
button::custom(ferese_theme::text("Cancel", palette.font).size(13))
.class(ferese_theme::controls::button_style(
palette.palette(),
false
))
.class(ferese_theme::controls::button_style(palette.palette(), false))
.padding([8, 14])
.on_press(Message::Cancel),
action
+24 -58
View File
@@ -1,19 +1,17 @@
use crate::PromptEvent;
use std::ffi::{CStr, CString, c_char, c_int, c_void};
use std::io::{BufRead, BufReader, BufWriter, Write};
use std::process::{Child, ChildStdin, Command, Stdio};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::Sender;
use std::sync::{Arc, mpsc};
use std::time::Duration;
use glib::gobject_ffi;
use libloading::Library;
use std::{
ffi::{CStr, CString, c_char, c_int, c_void},
io::{BufRead, BufReader, BufWriter, Write},
process::{Child, ChildStdin, Command, Stdio},
sync::{
Arc,
atomic::{AtomicBool, Ordering},
mpsc::{self, Sender},
},
time::Duration,
};
use zeroize::Zeroize;
use crate::PromptEvent;
enum SessionEvent {
Request(String, bool),
Info(String),
@@ -38,21 +36,15 @@ impl Api {
unsafe {
let agent = Library::new("libpolkit-agent-1.so.0").map_err(|e| e.to_string())?;
let polkit = Library::new("libpolkit-gobject-1.so.0").map_err(|e| e.to_string())?;
let user_new = *polkit
.get(b"polkit_unix_user_new\0")
.map_err(|e| e.to_string())?;
let session_new = *agent
.get(b"polkit_agent_session_new\0")
.map_err(|e| e.to_string())?;
let user_new = *polkit.get(b"polkit_unix_user_new\0").map_err(|e| e.to_string())?;
let session_new = *agent.get(b"polkit_agent_session_new\0").map_err(|e| e.to_string())?;
let initiate = *agent
.get(b"polkit_agent_session_initiate\0")
.map_err(|e| e.to_string())?;
let response = *agent
.get(b"polkit_agent_session_response\0")
.map_err(|e| e.to_string())?;
let cancel = *agent
.get(b"polkit_agent_session_cancel\0")
.map_err(|e| e.to_string())?;
let cancel = *agent.get(b"polkit_agent_session_cancel\0").map_err(|e| e.to_string())?;
Ok(Self {
_agent: agent,
@@ -72,9 +64,7 @@ pub fn check() -> Result<(), String> {
}
fn username(uid: u32) -> String {
let output = Command::new("getent")
.args(["passwd", &uid.to_string()])
.output();
let output = Command::new("getent").args(["passwd", &uid.to_string()]).output();
output
.ok()
.filter(|output| output.status.success())
@@ -122,32 +112,21 @@ fn prompt_process(
Ok((child, writer, rx))
}
unsafe extern "C" fn request(
_session: Object,
prompt: *const c_char,
echo: c_int,
data: *mut c_void,
) {
unsafe extern "C" fn request(_session: Object, prompt: *const c_char, echo: c_int, data: *mut c_void) {
let tx = unsafe { &*(data as *const Sender<SessionEvent>) };
let prompt = unsafe { CStr::from_ptr(prompt) }
.to_string_lossy()
.into_owned();
let prompt = unsafe { CStr::from_ptr(prompt) }.to_string_lossy().into_owned();
let _ = tx.send(SessionEvent::Request(prompt, echo != 0));
}
unsafe extern "C" fn info(_session: Object, text: *const c_char, data: *mut c_void) {
let tx = unsafe { &*(data as *const Sender<SessionEvent>) };
let text = unsafe { CStr::from_ptr(text) }
.to_string_lossy()
.into_owned();
let text = unsafe { CStr::from_ptr(text) }.to_string_lossy().into_owned();
let _ = tx.send(SessionEvent::Info(text));
}
unsafe extern "C" fn error(_session: Object, text: *const c_char, data: *mut c_void) {
let tx = unsafe { &*(data as *const Sender<SessionEvent>) };
let text = unsafe { CStr::from_ptr(text) }
.to_string_lossy()
.into_owned();
let text = unsafe { CStr::from_ptr(text) }.to_string_lossy().into_owned();
let _ = tx.send(SessionEvent::Error(text));
}
@@ -156,12 +135,7 @@ unsafe extern "C" fn completed(_session: Object, success: c_int, data: *mut c_vo
let _ = tx.send(SessionEvent::Completed(success != 0));
}
unsafe fn connect(
session: Object,
name: &'static CStr,
callback: gobject_ffi::GCallback,
data: *mut c_void,
) {
unsafe fn connect(session: Object, name: &'static CStr, callback: gobject_ffi::GCallback, data: *mut c_void) {
unsafe {
gobject_ffi::g_signal_connect_data(
session.cast(),
@@ -215,7 +189,7 @@ fn run_session(
unsafe extern "C" fn(Object, *const c_char, *mut c_void),
unsafe extern "C" fn(),
>(
info as unsafe extern "C" fn(Object, *const c_char, *mut c_void),
info as unsafe extern "C" fn(Object, *const c_char, *mut c_void)
)),
signal_data,
);
@@ -226,7 +200,7 @@ fn run_session(
unsafe extern "C" fn(Object, *const c_char, *mut c_void),
unsafe extern "C" fn(),
>(
error as unsafe extern "C" fn(Object, *const c_char, *mut c_void),
error as unsafe extern "C" fn(Object, *const c_char, *mut c_void)
)),
signal_data,
);
@@ -237,7 +211,7 @@ fn run_session(
unsafe extern "C" fn(Object, c_int, *mut c_void),
unsafe extern "C" fn(),
>(
completed as unsafe extern "C" fn(Object, c_int, *mut c_void),
completed as unsafe extern "C" fn(Object, c_int, *mut c_void)
)),
signal_data,
);
@@ -276,10 +250,7 @@ fn run_session(
_ => {}
}
}
if !stopped
&& (cancelled.load(Ordering::Acquire)
|| child.try_wait().map_err(|e| e.to_string())?.is_some())
{
if !stopped && (cancelled.load(Ordering::Acquire) || child.try_wait().map_err(|e| e.to_string())?.is_some()) {
unsafe { (api.cancel)(session) };
stopped = true;
}
@@ -293,12 +264,7 @@ fn run_session(
Ok(outcome.filter(|_| !stopped))
}
pub fn authenticate(
uid: u32,
message: String,
cookie: String,
cancelled: Arc<AtomicBool>,
) -> Result<bool, String> {
pub fn authenticate(uid: u32, message: String, cookie: String, cancelled: Arc<AtomicBool>) -> Result<bool, String> {
let api = Api::load()?;
let cookie = CString::new(cookie).map_err(|_| "Invalid authentication cookie")?;
let context = glib::MainContext::new();