1
0
Fork 0
forked from wry/wry

autocommit 2022-04-14 19:52:11 CEST

This commit is contained in:
Julian Orth 2022-04-14 19:52:11 +02:00
parent 35ddfbcbe3
commit 5f13954dbc
27 changed files with 556 additions and 312 deletions

View file

@ -18,7 +18,7 @@ use {
SYM_F23, SYM_F24, SYM_F25, SYM_F3, SYM_F4, SYM_F5, SYM_F6, SYM_F7, SYM_F8, SYM_F9, SYM_F23, SYM_F24, SYM_F25, SYM_F3, SYM_F4, SYM_F5, SYM_F6, SYM_F7, SYM_F8, SYM_F9,
}, },
}, },
quit, quit, set_env,
status::set_status, status::set_status,
switch_to_vt, switch_to_vt,
Axis::{Horizontal, Vertical}, Axis::{Horizontal, Vertical},
@ -143,6 +143,7 @@ pub fn configure() {
timer.on_tick(update_status); timer.on_tick(update_status);
} }
set_env("GTK_THEME", "Adwaita:dark");
Command::new("mako").spawn(); Command::new("mako").spawn();
} }

View file

@ -318,6 +318,10 @@ impl Client {
self.send(&ClientMessage::SetMono { seat, mono }); self.send(&ClientMessage::SetMono { seat, mono });
} }
pub fn set_env(&self, key: &str, val: &str) {
self.send(&ClientMessage::SetEnv { key, val });
}
pub fn set_status(&self, status: &str) { pub fn set_status(&self, status: &str) {
self.send(&ClientMessage::SetStatus { status }); self.send(&ClientMessage::SetStatus { status });
} }

View file

@ -221,6 +221,10 @@ pub enum ClientMessage<'a> {
initial: Option<Duration>, initial: Option<Duration>,
periodic: Option<Duration>, periodic: Option<Duration>,
}, },
SetEnv {
key: &'a str,
val: &'a str,
},
} }
#[derive(Encode, Decode, Debug)] #[derive(Encode, Decode, Debug)]

View file

@ -56,6 +56,10 @@ pub fn switch_to_vt(n: u32) {
get!().switch_to_vt(n) get!().switch_to_vt(n)
} }
pub fn set_env(key: &str, val: &str) {
get!().set_env(key, val);
}
pub struct Command { pub struct Command {
prog: String, prog: String,
args: Vec<String>, args: Vec<String>,

View file

@ -9,6 +9,7 @@ use {
thiserror::Error, thiserror::Error,
uapi::{c, format_ustr, Errno, OwnedFd, Ustring}, uapi::{c, format_ustr, Errno, OwnedFd, Ustring},
}; };
use crate::utils::xrd::xrd;
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum AcceptorError { pub enum AcceptorError {
@ -115,9 +116,9 @@ fn bind_socket(
} }
fn allocate_socket() -> Result<AllocatedSocket, AcceptorError> { fn allocate_socket() -> Result<AllocatedSocket, AcceptorError> {
let xrd = match std::env::var("XDG_RUNTIME_DIR") { let xrd = match xrd() {
Ok(d) => d, Some(d) => d,
Err(_) => return Err(AcceptorError::XrdNotSet), _ => return Err(AcceptorError::XrdNotSet),
}; };
let mut fds = [None, None]; let mut fds = [None, None];
for fd in &mut fds { for fd in &mut fds {
@ -145,7 +146,7 @@ fn allocate_socket() -> Result<AllocatedSocket, AcceptorError> {
} }
impl Acceptor { impl Acceptor {
pub fn install(state: &Rc<State>) -> Result<Ustring, AcceptorError> { pub fn install(state: &Rc<State>) -> Result<Rc<String>, AcceptorError> {
let socket = allocate_socket()?; let socket = allocate_socket()?;
log::info!("bound to socket {}", socket.path.display()); log::info!("bound to socket {}", socket.path.display());
for fd in [&socket.secure, &socket.insecure] { for fd in [&socket.secure, &socket.insecure] {
@ -170,6 +171,8 @@ impl Acceptor {
state state
.el .el
.insert(id2, Some(acc.socket.secure.raw()), c::EPOLLIN, acc)?; .insert(id2, Some(acc.socket.secure.raw()), c::EPOLLIN, acc)?;
let name = Rc::new(name.display().to_string());
state.socket_path.set(name.clone());
Ok(name) Ok(name)
} }
} }

View file

@ -1,10 +1,12 @@
use { use {
crate::{ crate::{
async_engine::SpawnedFuture,
fixed::Fixed, fixed::Fixed,
ifs::wl_seat::wl_pointer::{CONTINUOUS, FINGER, HORIZONTAL_SCROLL, VERTICAL_SCROLL, WHEEL}, ifs::wl_seat::wl_pointer::{CONTINUOUS, FINGER, HORIZONTAL_SCROLL, VERTICAL_SCROLL, WHEEL},
video::drm::ConnectorType, video::drm::ConnectorType,
}, },
std::{ std::{
error::Error,
fmt::{Debug, Display, Formatter}, fmt::{Debug, Display, Formatter},
rc::Rc, rc::Rc,
}, },
@ -14,6 +16,8 @@ linear_ids!(ConnectorIds, ConnectorId);
linear_ids!(InputDeviceIds, InputDeviceId); linear_ids!(InputDeviceIds, InputDeviceId);
pub trait Backend { pub trait Backend {
fn run(self: Rc<Self>) -> SpawnedFuture<Result<(), Box<dyn Error>>>;
fn switch_to(&self, vtnr: u32) { fn switch_to(&self, vtnr: u32) {
let _ = vtnr; let _ = vtnr;
} }
@ -21,6 +25,14 @@ pub trait Backend {
fn set_idle(&self, idle: bool) { fn set_idle(&self, idle: bool) {
let _ = idle; let _ = idle;
} }
fn supports_idle(&self) -> bool {
false
}
fn is_freestanding(&self) -> bool {
false
}
} }
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]

View file

@ -1,14 +1,20 @@
use std::error::Error;
use { use {
crate::{ crate::{
async_engine::SpawnedFuture,
backend::{Backend, Connector, ConnectorEvent, ConnectorId, ConnectorKernelId}, backend::{Backend, Connector, ConnectorEvent, ConnectorId, ConnectorKernelId},
video::drm::ConnectorType, video::drm::ConnectorType,
}, },
std::rc::Rc, std::rc::Rc,
}; };
pub struct DummyBackend {} pub struct DummyBackend;
impl Backend for DummyBackend {} impl Backend for DummyBackend {
fn run(self: Rc<Self>) -> SpawnedFuture<Result<(), Box<dyn Error>>> {
unreachable!();
}
}
pub struct DummyOutput { pub struct DummyOutput {
pub id: ConnectorId, pub id: ConnectorId,

View file

@ -4,13 +4,13 @@ mod video;
use { use {
crate::{ crate::{
async_engine::{AsyncError, AsyncFd, Phase}, async_engine::{AsyncError, AsyncFd, SpawnedFuture},
backend::{ backend::{
Backend, InputDevice, InputDeviceAccelProfile, InputDeviceCapability, InputDeviceId, Backend, InputDevice, InputDeviceAccelProfile, InputDeviceCapability, InputDeviceId,
InputEvent, KeyState, InputEvent, KeyState,
}, },
backends::metal::video::{MetalDrmDevice, PendingDrmDevice}, backends::metal::video::{MetalDrmDevice, PendingDrmDevice},
dbus::DbusError, dbus::{DbusError, SignalHandler},
libinput::{ libinput::{
consts::{ consts::{
AccelProfile, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE, AccelProfile, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
@ -25,7 +25,6 @@ use {
logind::{LogindError, Session}, logind::{LogindError, Session},
render::RenderError, render::RenderError,
state::State, state::State,
tasks::idle,
udev::{Udev, UdevError, UdevMonitor}, udev::{Udev, UdevError, UdevMonitor},
utils::{ utils::{
clonecell::{CloneCell, UnsafeCellCloneSafe}, clonecell::{CloneCell, UnsafeCellCloneSafe},
@ -42,6 +41,7 @@ use {
}, },
std::{ std::{
cell::{Cell, RefCell}, cell::{Cell, RefCell},
error::Error,
ffi::{CStr, CString}, ffi::{CStr, CString},
future::pending, future::pending,
mem, mem,
@ -67,8 +67,6 @@ pub enum MetalError {
LibInput(#[from] LibInputError), LibInput(#[from] LibInputError),
#[error("Dupfd failed")] #[error("Dupfd failed")]
Dup(#[source] crate::utils::oserror::OsError), Dup(#[source] crate::utils::oserror::OsError),
#[error("Metal backend terminated unexpectedly")]
UnexpectedTermination,
#[error("Could not create GBM device")] #[error("Could not create GBM device")]
GbmDevice(#[source] GbmError), GbmDevice(#[source] GbmError),
#[error("Could not update the drm properties")] #[error("Could not update the drm properties")]
@ -99,20 +97,17 @@ pub enum MetalError {
CreateEncoder(#[source] DrmError), CreateEncoder(#[source] DrmError),
#[error(transparent)] #[error(transparent)]
DrmError(#[from] DrmError), DrmError(#[from] DrmError),
#[error("Could not create an async fd for the drm fd")] #[error("Could not create an async fd")]
CreateDrmAsyncFd(#[source] AsyncError), CreateAsyncFd(#[source] AsyncError),
} #[error("Could not create device-paused signal handler")]
DevicePauseSignalHandler(#[source] DbusError),
pub async fn run(state: Rc<State>) -> MetalError { #[error("Could not create device-resumed signal handler")]
match run_(state).await { DeviceResumeSignalHandler(#[source] DbusError),
Err(e) => e,
_ => MetalError::UnexpectedTermination,
}
} }
linear_ids!(DrmIds, DrmId); linear_ids!(DrmIds, DrmId);
struct MetalBackend { pub struct MetalBackend {
state: Rc<State>, state: Rc<State>,
udev: Rc<Udev>, udev: Rc<Udev>,
monitor: Rc<UdevMonitor>, monitor: Rc<UdevMonitor>,
@ -122,9 +117,30 @@ struct MetalBackend {
device_holder: Rc<DeviceHolder>, device_holder: Rc<DeviceHolder>,
session: Session, session: Session,
drm_ids: DrmIds, drm_ids: DrmIds,
pause_handler: Cell<Option<SignalHandler>>,
resume_handler: Cell<Option<SignalHandler>>,
}
impl MetalBackend {
async fn run(self: Rc<Self>) -> Result<(), MetalError> {
let _monitor = self.state.eng.spawn(self.clone().monitor_devices());
let _events = self.state.eng.spawn(self.clone().handle_libinput_events());
if let Err(e) = self.enumerate_devices() {
return Err(MetalError::Enumerate(Box::new(e)));
}
pending().await
}
} }
impl Backend for MetalBackend { impl Backend for MetalBackend {
fn run(self: Rc<Self>) -> SpawnedFuture<Result<(), Box<dyn Error>>> {
let slf = self.clone();
self.state.eng.spawn(async move {
slf.run().await?;
Ok(())
})
}
fn switch_to(&self, vtnr: u32) { fn switch_to(&self, vtnr: u32) {
self.session.switch_to(vtnr, move |res| { self.session.switch_to(vtnr, move |res| {
if let Err(e) = res { if let Err(e) = res {
@ -160,9 +176,27 @@ impl Backend for MetalBackend {
} }
} }
} }
fn supports_idle(&self) -> bool {
true
}
fn is_freestanding(&self) -> bool {
true
}
} }
async fn run_(state: Rc<State>) -> Result<(), MetalError> { fn dup_async_fd(state: &Rc<State>, fd: c::c_int) -> Result<AsyncFd, MetalError> {
match uapi::fcntl_dupfd_cloexec(fd, 0) {
Ok(m) => match state.eng.fd(&Rc::new(m)) {
Ok(fd) => Ok(fd),
Err(e) => Err(MetalError::CreateAsyncFd(e)),
},
Err(e) => Err(MetalError::Dup(e.into())),
}
}
pub async fn create(state: &Rc<State>) -> Result<Rc<MetalBackend>, MetalError> {
let socket = match state.dbus.system() { let socket = match state.dbus.system() {
Ok(s) => s, Ok(s) => s,
Err(e) => return Err(MetalError::DbusSystemSocket(e)), Err(e) => return Err(MetalError::DbusSystemSocket(e)),
@ -186,14 +220,8 @@ async fn run_(state: Rc<State>) -> Result<(), MetalError> {
monitor.add_match_subsystem_devtype(Some("drm"), None)?; monitor.add_match_subsystem_devtype(Some("drm"), None)?;
monitor.enable_receiving()?; monitor.enable_receiving()?;
let libinput = Rc::new(LibInput::new(device_holder.clone())?); let libinput = Rc::new(LibInput::new(device_holder.clone())?);
let monitor_fd = match uapi::fcntl_dupfd_cloexec(monitor.fd(), 0) { let monitor_fd = dup_async_fd(&state, monitor.fd())?;
Ok(m) => state.eng.fd(&Rc::new(m)).unwrap(), let libinput_fd = dup_async_fd(&state, libinput.fd())?;
Err(e) => return Err(MetalError::Dup(e.into())),
};
let libinput_fd = match uapi::fcntl_dupfd_cloexec(libinput.fd(), 0) {
Ok(m) => state.eng.fd(&Rc::new(m)).unwrap(),
Err(e) => return Err(MetalError::Dup(e.into())),
};
let metal = Rc::new(MetalBackend { let metal = Rc::new(MetalBackend {
state: state.clone(), state: state.clone(),
udev, udev,
@ -204,31 +232,28 @@ async fn run_(state: Rc<State>) -> Result<(), MetalError> {
device_holder, device_holder,
session, session,
drm_ids: Default::default(), drm_ids: Default::default(),
pause_handler: Default::default(),
resume_handler: Default::default(),
}); });
let _pause_handler = { metal.pause_handler.set(Some({
let mtl = metal.clone(); let mtl = metal.clone();
metal let sh = metal.session.on_pause(move |p| mtl.handle_device_pause(p));
.session match sh {
.on_pause(move |p| mtl.handle_device_pause(p)) Ok(sh) => sh,
.unwrap() Err(e) => return Err(MetalError::DevicePauseSignalHandler(e)),
}; }
let _resume_handler = { }));
metal.resume_handler.set(Some({
let mtl = metal.clone(); let mtl = metal.clone();
metal let sh = metal
.session .session
.on_resume(move |p| mtl.handle_device_resume(p)) .on_resume(move |p| mtl.handle_device_resume(p));
.unwrap() match sh {
}; Ok(sh) => sh,
let _monitor = state.eng.spawn(metal.clone().monitor_devices()); Err(e) => return Err(MetalError::DeviceResumeSignalHandler(e)),
let _events = state.eng.spawn(metal.clone().handle_libinput_events()); }
if let Err(e) = metal.enumerate_devices() { }));
return Err(MetalError::Enumerate(Box::new(e))); Ok(metal)
}
state.backend.set(Some(metal.clone()));
let _idle = state
.eng
.spawn2(Phase::PostLayout, idle(state.clone(), metal.clone()));
pending().await
} }
struct MetalInputDevice { struct MetalInputDevice {

View file

@ -540,7 +540,7 @@ impl MetalBackend {
}; };
let async_fd = match self.state.eng.fd(master.fd()) { let async_fd = match self.state.eng.fd(master.fd()) {
Ok(f) => f, Ok(f) => f,
Err(e) => return Err(MetalError::CreateDrmAsyncFd(e)), Err(e) => return Err(MetalError::CreateAsyncFd(e)),
}; };
let dev = Rc::new(MetalDrmDeviceStatic { let dev = Rc::new(MetalDrmDeviceStatic {

View file

@ -1,3 +1,4 @@
use std::error::Error;
use { use {
crate::{ crate::{
async_engine::{Phase, SpawnedFuture}, async_engine::{Phase, SpawnedFuture},
@ -51,6 +52,7 @@ use {
borrow::Cow, borrow::Cow,
cell::{Cell, RefCell}, cell::{Cell, RefCell},
collections::VecDeque, collections::VecDeque,
future::pending,
rc::Rc, rc::Rc,
}, },
thiserror::Error, thiserror::Error,
@ -106,16 +108,137 @@ pub enum XBackendError {
QueryDevice(#[source] XconError), QueryDevice(#[source] XconError),
} }
pub struct XBackend { pub async fn create(state: &Rc<State>) -> Result<Rc<XBackend>, XBackendError> {
_data: Rc<XBackendData>, let c = match Xcon::connect(state.eng.clone()).await {
_events: SpawnedFuture<()>, Ok(c) => c,
_present: SpawnedFuture<()>, Err(e) => return Err(XBackendError::CannotConnect(e)),
_grab: SpawnedFuture<()>, };
if let Err(e) = c
.call(&XiQueryVersion {
major_version: 2,
minor_version: 2,
})
.await
{
return Err(XBackendError::EnableXinput(e));
}
if let Err(e) = c
.call(&Dri3QueryVersion {
major_version: 1,
minor_version: 0,
})
.await
{
return Err(XBackendError::EnableDri3(e));
}
if let Err(e) = c
.call(&PresentQueryVersion {
major_version: 1,
minor_version: 0,
})
.await
{
return Err(XBackendError::EnablePresent(e));
}
if let Err(e) = c
.call(&XkbUseExtension {
wanted_major: 1,
wanted_minor: 0,
})
.await
{
return Err(XBackendError::EnableXkb(e));
}
let root = c.setup().screens[0].root;
let drm = {
let res = c
.call(&Dri3Open {
drawable: root,
provider: 0,
})
.await;
match res {
Ok(r) => Drm::reopen(r.get().device_fd.raw(), false)?,
Err(e) => return Err(XBackendError::DriOpen(e)),
}
};
let gbm = GbmDevice::new(&drm)?;
let ctx = match RenderContext::from_drm_device(&drm) {
Ok(r) => Rc::new(r),
Err(e) => return Err(XBackendError::CreateEgl(e)),
};
let cursor = {
let cp = CreatePixmap {
depth: 1,
pid: c.generate_id()?,
drawable: root,
width: 1,
height: 1,
};
if let Err(e) = c.call(&cp).await {
return Err(XBackendError::CreatePixmap(e));
}
let cc = CreateCursor {
cid: c.generate_id()?,
source: cp.pid,
mask: cp.pid,
fore_red: 0,
fore_green: 0,
fore_blue: 0,
back_red: 0,
back_green: 0,
back_blue: 0,
x: 0,
y: 0,
};
if let Err(e) = c.call(&cc).await {
return Err(XBackendError::CreateCursor(e));
}
c.call(&FreePixmap { pixmap: cp.pid });
cc.cid
};
{
let se = XiSelectEvents {
window: c.setup().screens[0].root,
masks: Cow::Borrowed(&[XiEventMask {
deviceid: INPUT_DEVICE_ALL,
mask: &[XI_EVENT_MASK_HIERARCHY],
}]),
};
if let Err(e) = c.call(&se).await {
return Err(XBackendError::SelectHierarchyEvents(e));
}
}
let data = Rc::new(XBackend {
state: state.clone(),
c,
outputs: Default::default(),
seats: Default::default(),
mouse_seats: Default::default(),
ctx: ctx.clone(),
gbm,
cursor,
root,
scheduled_present: Default::default(),
grab_requests: Default::default(),
});
data.add_output().await?;
Ok(data)
} }
impl Backend for XBackend {} impl Backend for XBackend {
fn run(self: Rc<Self>) -> SpawnedFuture<Result<(), Box<dyn Error>>> {
let slf = self.clone();
self.state.eng.spawn(async move {
slf.run().await?;
Ok(())
})
}
}
struct XBackendData { pub struct XBackend {
state: Rc<State>, state: Rc<State>,
c: Rc<Xcon>, c: Rc<Xcon>,
outputs: CopyHashMap<u32, Rc<XOutput>>, outputs: CopyHashMap<u32, Rc<XOutput>>,
@ -130,141 +253,21 @@ struct XBackendData {
} }
impl XBackend { impl XBackend {
pub async fn run(state: &Rc<State>) -> Result<Rc<Self>, XBackendError> { async fn run(self: Rc<Self>) -> Result<(), XBackendError> {
let c = match Xcon::connect(state.eng.clone()).await { self.query_devices(INPUT_DEVICE_ALL_MASTER).await?;
Ok(c) => c,
Err(e) => return Err(XBackendError::CannotConnect(e)),
};
if let Err(e) = c
.call(&XiQueryVersion {
major_version: 2,
minor_version: 2,
})
.await
{
return Err(XBackendError::EnableXinput(e));
}
if let Err(e) = c
.call(&Dri3QueryVersion {
major_version: 1,
minor_version: 0,
})
.await
{
return Err(XBackendError::EnableDri3(e));
}
if let Err(e) = c
.call(&PresentQueryVersion {
major_version: 1,
minor_version: 0,
})
.await
{
return Err(XBackendError::EnablePresent(e));
}
if let Err(e) = c
.call(&XkbUseExtension {
wanted_major: 1,
wanted_minor: 0,
})
.await
{
return Err(XBackendError::EnableXkb(e));
}
let root = c.setup().screens[0].root;
let drm = {
let res = c
.call(&Dri3Open {
drawable: root,
provider: 0,
})
.await;
match res {
Ok(r) => Drm::reopen(r.get().device_fd.raw(), false)?,
Err(e) => return Err(XBackendError::DriOpen(e)),
}
};
let gbm = GbmDevice::new(&drm)?;
let ctx = match RenderContext::from_drm_device(&drm) {
Ok(r) => Rc::new(r),
Err(e) => return Err(XBackendError::CreateEgl(e)),
};
let cursor = {
let cp = CreatePixmap {
depth: 1,
pid: c.generate_id()?,
drawable: root,
width: 1,
height: 1,
};
if let Err(e) = c.call(&cp).await {
return Err(XBackendError::CreatePixmap(e));
}
let cc = CreateCursor {
cid: c.generate_id()?,
source: cp.pid,
mask: cp.pid,
fore_red: 0,
fore_green: 0,
fore_blue: 0,
back_red: 0,
back_green: 0,
back_blue: 0,
x: 0,
y: 0,
};
if let Err(e) = c.call(&cc).await {
return Err(XBackendError::CreateCursor(e));
}
c.call(&FreePixmap { pixmap: cp.pid });
cc.cid
};
{
let se = XiSelectEvents {
window: c.setup().screens[0].root,
masks: Cow::Borrowed(&[XiEventMask {
deviceid: INPUT_DEVICE_ALL,
mask: &[XI_EVENT_MASK_HIERARCHY],
}]),
};
if let Err(e) = c.call(&se).await {
return Err(XBackendError::SelectHierarchyEvents(e));
}
}
let data = Rc::new(XBackendData { let _events = self.state.eng.spawn(self.clone().event_handler());
state: state.clone(), let _grab = self.state.eng.spawn(self.clone().grab_handler());
c, let _present = self
outputs: Default::default(), .state
seats: Default::default(), .eng
mouse_seats: Default::default(), .spawn2(Phase::Present, self.clone().present_handler());
ctx: ctx.clone(),
gbm,
cursor,
root,
scheduled_present: Default::default(),
grab_requests: Default::default(),
});
data.add_output().await?;
data.query_devices(INPUT_DEVICE_ALL_MASTER).await?;
let slf = Rc::new(Self { self.state.set_render_ctx(&self.ctx);
_events: state.eng.spawn(data.clone().event_handler()),
_grab: state.eng.spawn(data.clone().grab_handler()),
_present: state
.eng
.spawn2(Phase::Present, data.clone().present_handler()),
_data: data,
});
state.set_render_ctx(&ctx); pending().await
state.backend.set(Some(slf.clone()));
Ok(slf)
} }
}
impl XBackendData {
async fn event_handler(self: Rc<Self>) { async fn event_handler(self: Rc<Self>) {
loop { loop {
let event = self.c.event().await; let event = self.c.event().await;
@ -856,7 +859,7 @@ impl XBackendData {
struct XOutput { struct XOutput {
id: ConnectorId, id: ConnectorId,
_backend: Rc<XBackendData>, _backend: Rc<XBackend>,
window: u32, window: u32,
events: SyncQueue<ConnectorEvent>, events: SyncQueue<ConnectorEvent>,
width: Cell<i32>, width: Cell<i32>,
@ -908,7 +911,7 @@ impl Connector for XOutput {
struct XSeat { struct XSeat {
kb_id: InputDeviceId, kb_id: InputDeviceId,
mouse_id: InputDeviceId, mouse_id: InputDeviceId,
backend: Rc<XBackendData>, backend: Rc<XBackend>,
kb: u16, kb: u16,
mouse: u16, mouse: u16,
removed: Cell<bool>, removed: Cell<bool>,

View file

@ -87,7 +87,7 @@ pub struct SetLogArgs {
level: CliLogLevel, level: CliLogLevel,
} }
#[derive(ArgEnum, Debug, Copy, Clone, Hash)] #[derive(ArgEnum, Debug, Copy, Clone, Hash, Eq, PartialEq)]
pub enum CliBackend { pub enum CliBackend {
X11, X11,
Metal, Metal,

View file

@ -1,10 +1,10 @@
use { use {
crate::{ crate::{
acceptor::{Acceptor, AcceptorError}, acceptor::{Acceptor, AcceptorError},
async_engine::{AsyncEngine, AsyncError, Phase}, async_engine::{AsyncEngine, AsyncError, Phase, SpawnedFuture},
backend, backend::{self, Backend},
backends::dummy::DummyOutput, backends::{dummy::DummyOutput, metal, x},
cli::{GlobalArgs, RunArgs}, cli::{CliBackend, GlobalArgs, RunArgs},
client::Clients, client::Clients,
clientmem::{self, ClientMemError}, clientmem::{self, ClientMemError},
config::ConfigProxy, config::ConfigProxy,
@ -29,13 +29,17 @@ use {
}, },
wheel::{Wheel, WheelError}, wheel::{Wheel, WheelError},
xkbcommon::XkbContext, xkbcommon::XkbContext,
xwayland,
}, },
ahash::AHashSet,
forker::ForkerProxy, forker::ForkerProxy,
std::{cell::Cell, ops::Deref, rc::Rc, sync::Arc, time::Duration}, std::{cell::Cell, ops::Deref, rc::Rc, sync::Arc, time::Duration},
thiserror::Error, thiserror::Error,
uapi::c, uapi::c,
}; };
use crate::backends::dummy::DummyBackend;
use crate::state::XWaylandState;
use crate::tasks::idle;
use crate::user_session::import_environment;
pub const MAX_EXTENTS: i32 = (1 << 22) - 1; pub const MAX_EXTENTS: i32 = (1 << 22) - 1;
@ -45,7 +49,7 @@ pub fn start_compositor(global: GlobalArgs, args: RunArgs) {
Err(e) => fatal!("Could not create a forker process: {}", ErrorFmt(e)), Err(e) => fatal!("Could not create a forker process: {}", ErrorFmt(e)),
}; };
let logger = Logger::install_compositor(global.log_level.into()); let logger = Logger::install_compositor(global.log_level.into());
if let Err(e) = main_(forker, logger.clone(), &args) { if let Err(e) = start_compositor2(forker, logger.clone(), args) {
let e = ErrorFmt(e); let e = ErrorFmt(e);
log::error!("A fatal error occurred: {}", e); log::error!("A fatal error occurred: {}", e);
eprintln!("A fatal error occurred: {}", e); eprintln!("A fatal error occurred: {}", e);
@ -73,7 +77,14 @@ enum MainError {
RenderError(#[from] RenderError), RenderError(#[from] RenderError),
} }
fn main_(forker: Rc<ForkerProxy>, logger: Arc<Logger>, _args: &RunArgs) -> Result<(), MainError> { pub const WAYLAND_DISPLAY: &str = "WAYLAND_DISPLAY";
pub const DISPLAY: &str = "DISPLAY";
fn start_compositor2(
forker: Rc<ForkerProxy>,
logger: Arc<Logger>,
run_args: RunArgs,
) -> Result<(), MainError> {
init_fd_limit(); init_fd_limit();
leaks::init(); leaks::init();
render::init()?; render::init()?;
@ -88,7 +99,7 @@ fn main_(forker: Rc<ForkerProxy>, logger: Arc<Logger>, _args: &RunArgs) -> Resul
let node_ids = NodeIds::default(); let node_ids = NodeIds::default();
let state = Rc::new(State { let state = Rc::new(State {
xkb_ctx, xkb_ctx,
backend: Default::default(), backend: CloneCell::new(Rc::new(DummyBackend)),
forker: Default::default(), forker: Default::default(),
default_keymap: xkb_keymap, default_keymap: xkb_keymap,
eng: engine.clone(), eng: engine.clone(),
@ -126,77 +137,23 @@ fn main_(forker: Rc<ForkerProxy>, logger: Arc<Logger>, _args: &RunArgs) -> Resul
idle: IdleState { idle: IdleState {
input: Default::default(), input: Default::default(),
change: Default::default(), change: Default::default(),
timeout: Cell::new(Duration::from_secs(10)), timeout: Cell::new(Duration::from_secs(10 * 60)),
timeout_changed: Default::default(), timeout_changed: Default::default(),
}, },
run_args,
xwayland: XWaylandState {
enabled: Cell::new(true),
handler: Default::default(),
},
socket_path: Default::default(),
}); });
{ create_dummy_output(&state);
let dummy_output = Rc::new(OutputNode {
id: state.node_ids.next(),
global: Rc::new(WlOutputGlobal::new(
state.globals.name(),
&Rc::new(ConnectorData {
connector: Rc::new(DummyOutput {
id: state.connector_ids.next(),
}),
handler: Cell::new(None),
connected: Cell::new(true),
name: "Dummy".to_string(),
}),
0,
&backend::Mode {
width: 0,
height: 0,
refresh_rate_millihz: 0,
},
"none",
"none",
0,
0,
)),
workspaces: Default::default(),
workspace: Default::default(),
seat_state: Default::default(),
layers: Default::default(),
render_data: Default::default(),
state: state.clone(),
is_dummy: true,
status: Default::default(),
});
let dummy_workspace = Rc::new(WorkspaceNode {
id: state.node_ids.next(),
output: CloneCell::new(dummy_output.clone()),
position: Default::default(),
container: Default::default(),
stacked: Default::default(),
seat_state: Default::default(),
name: "dummy".to_string(),
output_link: Default::default(),
visible: Cell::new(false),
});
dummy_workspace.output_link.set(Some(
dummy_output.workspaces.add_last(dummy_workspace.clone()),
));
dummy_output.show_workspace(&dummy_workspace);
state.dummy_output.set(Some(dummy_output));
}
forker.install(&state);
let _global_event_handler = engine.spawn(tasks::handle_backend_events(state.clone()));
let _slow_client_handler = engine.spawn(tasks::handle_slow_clients(state.clone()));
let _container_do_layout = engine.spawn2(Phase::Layout, container_layout(state.clone()));
let _container_render_titles =
engine.spawn2(Phase::PostLayout, container_render_data(state.clone()));
let _float_do_layout = engine.spawn2(Phase::Layout, float_layout(state.clone()));
let _float_render_titles = engine.spawn2(Phase::PostLayout, float_titles(state.clone()));
let socket_path = Acceptor::install(&state)?; let socket_path = Acceptor::install(&state)?;
forker.setenv(b"WAYLAND_DISPLAY", socket_path.as_bytes()); forker.install(&state);
forker.setenv(WAYLAND_DISPLAY.as_bytes(), socket_path.as_bytes());
forker.setenv(b"_JAVA_AWT_WM_NONREPARENTING", b"1"); forker.setenv(b"_JAVA_AWT_WM_NONREPARENTING", b"1");
let _xwayland = engine.spawn(xwayland::manage(state.clone())); let _compositor = engine.spawn(start_compositor3(state.clone()));
let _backend = engine.spawn(tasks::start_backend(state.clone()));
let config = ConfigProxy::default(&state);
state.config.set(Some(Rc::new(config)));
el.run()?; el.run()?;
drop(_xwayland);
state.clients.clear(); state.clients.clear();
for (_, seat) in state.globals.seats.lock().deref() { for (_, seat) in state.globals.seats.lock().deref() {
seat.clear(); seat.clear();
@ -205,6 +162,83 @@ fn main_(forker: Rc<ForkerProxy>, logger: Arc<Logger>, _args: &RunArgs) -> Resul
Ok(()) Ok(())
} }
async fn start_compositor3(state: Rc<State>) {
let backend = match create_backend(&state).await {
Some(b) => b,
_ => {
log::error!("Could not create a backend");
state.el.stop();
return;
}
};
state.backend.set(backend.clone());
if backend.is_freestanding() {
import_environment(&state, WAYLAND_DISPLAY, &state.socket_path.get());
}
let config = ConfigProxy::default(&state);
state.config.set(Some(Rc::new(config)));
let _geh = start_global_event_handlers(&state, &backend);
state.start_xwayland();
match backend.run().await {
Err(e) => log::error!("Backend failed: {}", ErrorFmt(e.deref())),
_ => log::error!("Backend stopped without an error"),
}
state.el.stop();
}
fn start_global_event_handlers(state: &Rc<State>, backend: &Rc<dyn Backend>) -> Vec<SpawnedFuture<()>> {
let eng = &state.eng;
let mut res = vec![];
res.push(eng.spawn(tasks::handle_backend_events(state.clone())));
res.push(eng.spawn(tasks::handle_slow_clients(state.clone())));
res.push(eng.spawn2(Phase::Layout, container_layout(state.clone())));
res.push(eng.spawn2(Phase::PostLayout, container_render_data(state.clone())));
res.push(eng.spawn2(Phase::Layout, float_layout(state.clone())));
res.push(eng.spawn2(Phase::PostLayout, float_titles(state.clone())));
res.push(eng.spawn2(Phase::PostLayout, idle(state.clone(), backend.clone())));
res
}
async fn create_backend(state: &Rc<State>) -> Option<Rc<dyn Backend>> {
let mut backends = &state.run_args.backends[..];
if backends.is_empty() {
backends = &[CliBackend::X11, CliBackend::Metal];
}
let mut tried_backends = AHashSet::new();
for &backend in backends {
if !tried_backends.insert(backend) {
continue;
}
match backend {
CliBackend::X11 => {
log::info!("Trying to create X backend");
match x::create(state).await {
Ok(b) => return Some(b),
Err(e) => {
log::error!("Could not create X backend: {}", ErrorFmt(e));
}
}
}
CliBackend::Metal => {
log::info!("Trying to create metal backend");
match metal::create(state).await {
Ok(b) => return Some(b),
Err(e) => {
log::error!("Could not create metal backend: {}", ErrorFmt(e));
}
}
}
}
}
None
}
fn init_fd_limit() { fn init_fd_limit() {
let res = OsError::tri(|| { let res = OsError::tri(|| {
let mut cur = uapi::getrlimit(c::RLIMIT_NOFILE as _)?; let mut cur = uapi::getrlimit(c::RLIMIT_NOFILE as _)?;
@ -223,3 +257,54 @@ fn init_fd_limit() {
log::warn!("Could not increase file descriptor limit: {}", ErrorFmt(e)); log::warn!("Could not increase file descriptor limit: {}", ErrorFmt(e));
} }
} }
fn create_dummy_output(state: &Rc<State>) {
let dummy_output = Rc::new(OutputNode {
id: state.node_ids.next(),
global: Rc::new(WlOutputGlobal::new(
state.globals.name(),
&Rc::new(ConnectorData {
connector: Rc::new(DummyOutput {
id: state.connector_ids.next(),
}),
handler: Cell::new(None),
connected: Cell::new(true),
name: "Dummy".to_string(),
}),
0,
&backend::Mode {
width: 0,
height: 0,
refresh_rate_millihz: 0,
},
"none",
"none",
0,
0,
)),
workspaces: Default::default(),
workspace: Default::default(),
seat_state: Default::default(),
layers: Default::default(),
render_data: Default::default(),
state: state.clone(),
is_dummy: true,
status: Default::default(),
});
let dummy_workspace = Rc::new(WorkspaceNode {
id: state.node_ids.next(),
output: CloneCell::new(dummy_output.clone()),
position: Default::default(),
container: Default::default(),
stacked: Default::default(),
seat_state: Default::default(),
name: "dummy".to_string(),
output_link: Default::default(),
visible: Cell::new(false),
});
dummy_workspace.output_link.set(Some(
dummy_output.workspaces.add_last(dummy_workspace.clone()),
));
dummy_output.show_workspace(&dummy_workspace);
state.dummy_output.set(Some(dummy_output));
}

View file

@ -172,6 +172,12 @@ impl ConfigProxyHandler {
Ok(()) Ok(())
} }
fn handle_set_env(&self, key: &str, val: &str) {
if let Some(f) = self.state.forker.get() {
f.setenv(key.as_bytes(), val.as_bytes());
}
}
fn handle_program_timer( fn handle_program_timer(
&self, &self,
timer: jay_config::Timer, timer: jay_config::Timer,
@ -654,10 +660,7 @@ impl ConfigProxyHandler {
} }
fn handle_switch_to(&self, vtnr: u32) { fn handle_switch_to(&self, vtnr: u32) {
match self.state.backend.get() { self.state.backend.get().switch_to(vtnr);
Some(b) => b.switch_to(vtnr),
_ => log::warn!("Cannot switch to VT {}: Backend has not yet started", vtnr),
}
} }
fn handle_toggle_floating(&self, seat: Seat) -> Result<(), CphError> { fn handle_toggle_floating(&self, seat: Seat) -> Result<(), CphError> {
@ -877,6 +880,7 @@ impl ConfigProxyHandler {
} => self } => self
.handle_program_timer(timer, initial, periodic) .handle_program_timer(timer, initial, periodic)
.wrn("program_timer")?, .wrn("program_timer")?,
ClientMessage::SetEnv { key, val } => self.handle_set_env(key, val),
} }
Ok(()) Ok(())
} }

View file

@ -30,6 +30,7 @@ use {
thiserror::Error, thiserror::Error,
uapi::OwnedFd, uapi::OwnedFd,
}; };
use crate::utils::xrd::{xrd, XRD};
mod auth; mod auth;
mod dynamic_type; mod dynamic_type;
@ -108,6 +109,8 @@ pub enum DbusError {
InvalidBoolValue, InvalidBoolValue,
#[error("Signature is empty")] #[error("Signature is empty")]
EmptySignature, EmptySignature,
#[error("The session bus address is not set")]
SessionBusAddressNotSet,
#[error("Server does not support FD passing")] #[error("Server does not support FD passing")]
UnixFd, UnixFd,
#[error("Server message has a different endianess than ourselves")] #[error("Server message has a different endianess than ourselves")]
@ -128,13 +131,25 @@ efrom!(DbusError, AsyncError);
pub struct Dbus { pub struct Dbus {
eng: Rc<AsyncEngine>, eng: Rc<AsyncEngine>,
system: Rc<DbusHolder>, system: Rc<DbusHolder>,
session: Rc<DbusHolder>,
user_path: Option<String>,
} }
impl Dbus { impl Dbus {
pub fn new(eng: &Rc<AsyncEngine>, run_toplevel: &Rc<RunToplevel>) -> Self { pub fn new(eng: &Rc<AsyncEngine>, run_toplevel: &Rc<RunToplevel>) -> Self {
let user_path = match xrd() {
Some(path) => Some(format!("{}/bus", path)),
_ => {
log::warn!("{} is not set", XRD);
None
}
};
log::info!("dbus path = {:?}", user_path);
Self { Self {
eng: eng.clone(), eng: eng.clone(),
system: Rc::new(DbusHolder::new(run_toplevel)), system: Rc::new(DbusHolder::new(run_toplevel)),
session: Rc::new(DbusHolder::new(run_toplevel)),
user_path,
} }
} }
@ -142,6 +157,15 @@ impl Dbus {
self.system self.system
.get(&self.eng, "/var/run/dbus/system_bus_socket", "System bus") .get(&self.eng, "/var/run/dbus/system_bus_socket", "System bus")
} }
pub fn session(&self) -> Result<Rc<DbusSocket>, DbusError> {
let sba = match self.user_path.as_deref() {
None => return Err(DbusError::SessionBusAddressNotSet),
Some(sba) => sba,
};
self.session
.get(&self.eng, sba, "Session bus")
}
} }
unsafe trait ReplyHandler { unsafe trait ReplyHandler {
@ -211,7 +235,7 @@ const NO_AUTO_START: u8 = 0x2;
const ALLOW_INTERACTIVE_AUTHORIZATION: u8 = 0x4; const ALLOW_INTERACTIVE_AUTHORIZATION: u8 = 0x4;
pub const BUS_DEST: &str = "org.freedesktop.DBus"; pub const BUS_DEST: &str = "org.freedesktop.DBus";
pub const BUS_PATH: &str = "/org/freedesktop/dbus"; pub const BUS_PATH: &str = "/org/freedesktop/DBus";
#[derive(Default, Debug)] #[derive(Default, Debug)]
struct Headers<'a> { struct Headers<'a> {

View file

@ -35,6 +35,7 @@ use {
thiserror::Error, thiserror::Error,
uapi::{c, pipe2, Errno, Fd, IntoUstr, OwnedFd, UstrPtr}, uapi::{c, pipe2, Errno, Fd, IntoUstr, OwnedFd, UstrPtr},
}; };
use crate::compositor::{DISPLAY, WAYLAND_DISPLAY};
pub struct ForkerProxy { pub struct ForkerProxy {
pidfd: Rc<OwnedFd>, pidfd: Rc<OwnedFd>,
@ -297,8 +298,8 @@ struct Forker {
impl Forker { impl Forker {
fn handle(ppid: c::pid_t, socket: OwnedFd) -> ! { fn handle(ppid: c::pid_t, socket: OwnedFd) -> ! {
env::set_var("XDG_SESSION_TYPE", "wayland"); env::set_var("XDG_SESSION_TYPE", "wayland");
env::remove_var("DISPLAY"); env::remove_var(DISPLAY);
env::remove_var("WAYLAND_DISPLAY"); env::remove_var(WAYLAND_DISPLAY);
setup_name("the ol' forker"); setup_name("the ol' forker");
setup_deathsig(ppid); setup_deathsig(ppid);
reset_signals(); reset_signals();

View file

@ -78,6 +78,7 @@ mod wire_xcon;
mod xcon; mod xcon;
mod xkbcommon; mod xkbcommon;
mod xwayland; mod xwayland;
mod user_session;
fn main() { fn main() {
cli::main(); cli::main();

View file

@ -5,6 +5,7 @@ use {
Backend, BackendEvent, Connector, ConnectorId, ConnectorIds, InputDevice, Backend, BackendEvent, Connector, ConnectorId, ConnectorIds, InputDevice,
InputDeviceId, InputDeviceIds, MonitorInfo, InputDeviceId, InputDeviceIds, MonitorInfo,
}, },
cli::RunArgs,
client::{Client, Clients}, client::{Client, Clients},
config::ConfigProxy, config::ConfigProxy,
cursor::ServerCursors, cursor::ServerCursors,
@ -30,6 +31,7 @@ use {
}, },
wheel::Wheel, wheel::Wheel,
xkbcommon::{XkbContext, XkbKeymap}, xkbcommon::{XkbContext, XkbKeymap},
xwayland,
}, },
ahash::AHashMap, ahash::AHashMap,
jay_config::Direction, jay_config::Direction,
@ -43,7 +45,7 @@ use {
pub struct State { pub struct State {
pub xkb_ctx: XkbContext, pub xkb_ctx: XkbContext,
pub backend: CloneCell<Option<Rc<dyn Backend>>>, pub backend: CloneCell<Rc<dyn Backend>>,
pub forker: CloneCell<Option<Rc<ForkerProxy>>>, pub forker: CloneCell<Option<Rc<ForkerProxy>>>,
pub default_keymap: Rc<XkbKeymap>, pub default_keymap: Rc<XkbKeymap>,
pub eng: Rc<AsyncEngine>, pub eng: Rc<AsyncEngine>,
@ -79,6 +81,14 @@ pub struct State {
pub outputs: CopyHashMap<ConnectorId, Rc<OutputData>>, pub outputs: CopyHashMap<ConnectorId, Rc<OutputData>>,
pub status: CloneCell<Rc<String>>, pub status: CloneCell<Rc<String>>,
pub idle: IdleState, pub idle: IdleState,
pub run_args: RunArgs,
pub xwayland: XWaylandState,
pub socket_path: CloneCell<Rc<String>>,
}
pub struct XWaylandState {
pub enabled: Cell<bool>,
pub handler: RefCell<Option<SpawnedFuture<()>>>,
} }
pub struct IdleState { pub struct IdleState {
@ -305,4 +315,14 @@ impl State {
self.idle.change.trigger(); self.idle.change.trigger();
} }
} }
pub fn start_xwayland(self: &Rc<Self>) {
if !self.xwayland.enabled.get() {
return;
}
let mut handler = self.xwayland.handler.borrow_mut();
if handler.is_none() {
*handler = Some(self.eng.spawn(xwayland::manage(self.clone())));
}
}
} }

View file

@ -3,8 +3,8 @@ mod connector;
mod idle; mod idle;
mod input_device; mod input_device;
mod slow_clients; mod slow_clients;
mod start_backend;
pub use idle::idle;
use { use {
crate::{ crate::{
state::State, state::State,
@ -12,7 +12,6 @@ use {
}, },
std::rc::Rc, std::rc::Rc,
}; };
pub use {idle::idle, start_backend::start_backend};
pub async fn handle_backend_events(state: Rc<State>) { pub async fn handle_backend_events(state: Rc<State>) {
let mut beh = BackendEventHandler { state }; let mut beh = BackendEventHandler { state };

View file

@ -11,6 +11,9 @@ use {
}; };
pub async fn idle(state: Rc<State>, backend: Rc<dyn Backend>) { pub async fn idle(state: Rc<State>, backend: Rc<dyn Backend>) {
if !backend.supports_idle() {
return;
}
let timer = match state.eng.timer(c::CLOCK_MONOTONIC) { let timer = match state.eng.timer(c::CLOCK_MONOTONIC) {
Ok(t) => t, Ok(t) => t,
Err(e) => { Err(e) => {

View file

@ -1,29 +0,0 @@
use {
crate::{
backends::{metal, x::XBackend},
state::State,
utils::errorfmt::ErrorFmt,
},
std::{future::pending, rc::Rc},
};
pub async fn start_backend(state: Rc<State>) {
log::info!("Trying to start X backend");
// let e = match XorgBackend::new(&state) {
// Ok(b) => {
// state.backend.set(Some(b));
// pending().await
// }
// Err(e) => e,
// };
let e = match XBackend::run(&state).await {
Ok(_) => pending().await,
Err(e) => e,
};
log::warn!("Could not start X backend: {}", ErrorFmt(e));
log::info!("Trying to start metal backend");
let e = metal::run(state.clone()).await;
log::error!("Metal backend failed: {}", ErrorFmt(e));
log::warn!("Shutting down");
state.el.stop();
}

View file

@ -38,6 +38,8 @@ use {
thiserror::Error, thiserror::Error,
uapi::{c, format_ustr}, uapi::{c, format_ustr},
}; };
use crate::compositor::WAYLAND_DISPLAY;
use crate::utils::xrd::xrd;
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum ToolClientError { pub enum ToolClientError {
@ -133,11 +135,11 @@ impl ToolClient {
Ok(e) => e, Ok(e) => e,
Err(e) => return Err(ToolClientError::CreateEngine(e)), Err(e) => return Err(ToolClientError::CreateEngine(e)),
}; };
let xrd = match std::env::var("XDG_RUNTIME_DIR") { let xrd = match xrd() {
Ok(d) => d, Some(d) => d,
Err(_) => return Err(ToolClientError::XrdNotSet), _ => return Err(ToolClientError::XrdNotSet),
}; };
let wd = match std::env::var("WAYLAND_DISPLAY") { let wd = match std::env::var(WAYLAND_DISPLAY) {
Ok(d) => d, Ok(d) => d,
Err(_) => return Err(ToolClientError::WaylandDisplayNotSet), Err(_) => return Err(ToolClientError::WaylandDisplayNotSet),
}; };

54
src/user_session.rs Normal file
View file

@ -0,0 +1,54 @@
use std::borrow::Cow;
use std::rc::Rc;
use thiserror::Error;
use crate::dbus::{BUS_DEST, BUS_PATH, DbusError, DictEntry};
use crate::state::State;
use crate::utils::errorfmt::ErrorFmt;
use crate::wire_dbus::org;
const SYSTEMD_DEST: &str = "org.freedesktop.systemd1";
const SYSTEMD_PATH: &str = "/org/freedesktop/systemd1";
#[derive(Debug, Error)]
pub enum UserSessionError {
#[error("Could not access the user session bus")]
AcquireSessionBus(#[source] DbusError),
}
pub fn import_environment(state: &Rc<State>, key: &str, value: &str) {
if let Err(e) = import_environment_(state, key, value) {
log::error!("Could not import `{}={}` into the system environment: {}", key, value, ErrorFmt(e));
}
}
fn import_environment_(state: &Rc<State>, key: &str, value: &str) -> Result<(), UserSessionError> {
let session = match state.dbus.session() {
Ok(s) => s,
Err(e) => return Err(UserSessionError::AcquireSessionBus(e)),
};
let setting = format!("{}={}", key, value);
session.call(BUS_DEST, BUS_PATH, org::freedesktop::dbus::UpdateActivationEnvironment {
environment: Cow::Borrowed(&[DictEntry {
key: key.into(),
value: value.into(),
}])
}, {
let setting = setting.clone();
move |rep| {
if let Err(e) = rep {
log::error!("Could not import `{}` into the dbus environment: {}", setting, ErrorFmt(e));
}
}
});
session.call(SYSTEMD_DEST, SYSTEMD_PATH, org::freedesktop::systemd1::manager::SetEnvironment {
names: Cow::Borrowed(&[Cow::Borrowed(&setting)]),
}, {
let setting = setting.clone();
move |rep| {
if let Err(e) = rep {
log::error!("Could not import `{}` into the systemd environment: {}", setting, ErrorFmt(e));
}
}
});
Ok(())
}

View file

@ -27,3 +27,4 @@ pub mod vasprintf;
pub mod vec_ext; pub mod vec_ext;
pub mod vecstorage; pub mod vecstorage;
pub mod windows; pub mod windows;
pub mod xrd;

5
src/utils/xrd.rs Normal file
View file

@ -0,0 +1,5 @@
pub const XRD: &str = "XDG_RUNTIME_DIR";
pub fn xrd() -> Option<String> {
std::env::var(XRD).ok()
}

View file

@ -47,6 +47,7 @@ use {
thiserror::Error, thiserror::Error,
uapi::{c, OwnedFd}, uapi::{c, OwnedFd},
}; };
use crate::compositor::DISPLAY;
pub mod consts; pub mod consts;
mod formatter; mod formatter;
@ -885,7 +886,7 @@ impl XconData {
} }
fn parse_display() -> Result<u32, XconError> { fn parse_display() -> Result<u32, XconError> {
let display = match std::env::var("DISPLAY") { let display = match std::env::var(DISPLAY) {
Ok(d) => d, Ok(d) => d,
_ => return Err(XconError::DisplayNotSet), _ => return Err(XconError::DisplayNotSet),
}; };

View file

@ -21,6 +21,8 @@ use {
thiserror::Error, thiserror::Error,
uapi::{c, pipe2, Errno, OwnedFd}, uapi::{c, pipe2, Errno, OwnedFd},
}; };
use crate::compositor::DISPLAY;
use crate::user_session::import_environment;
#[derive(Debug, Error)] #[derive(Debug, Error)]
enum XWaylandError { enum XWaylandError {
@ -92,10 +94,15 @@ pub async fn manage(state: Rc<State>) {
}; };
if let Err(e) = uapi::listen(socket.raw(), 4096) { if let Err(e) = uapi::listen(socket.raw(), 4096) {
log::error!("Could not listen on the Xwayland socket: {}", ErrorFmt(e)); log::error!("Could not listen on the Xwayland socket: {}", ErrorFmt(e));
return;
} }
forker.setenv(b"DISPLAY", format!(":{}", xsocket.id).as_bytes()); let display = format!(":{}", xsocket.id);
forker.setenv(DISPLAY.as_bytes(), display.as_bytes());
log::info!("Allocated display :{} for Xwayland", xsocket.id); log::info!("Allocated display :{} for Xwayland", xsocket.id);
log::info!("Waiting for connection attempt"); log::info!("Waiting for connection attempt");
if state.backend.get().is_freestanding() {
import_environment(&state, DISPLAY, &display);
}
let res = XWaylandError::tria(async { let res = XWaylandError::tria(async {
state.eng.fd(&socket)?.readable().await?; state.eng.fd(&socket)?.readable().await?;
Ok(()) Ok(())
@ -111,7 +118,7 @@ pub async fn manage(state: Rc<State>) {
} else { } else {
log::warn!("Xwayland exited unexpectedly"); log::warn!("Xwayland exited unexpectedly");
} }
forker.unsetenv(b"DISPLAY"); forker.unsetenv(DISPLAY.as_bytes());
} }
} }

View file

@ -0,0 +1,4 @@
fn SetEnvironment(
names: array(string),
) {
}