autocommit 2022-04-14 19:52:11 CEST
This commit is contained in:
parent
35ddfbcbe3
commit
5f13954dbc
27 changed files with 556 additions and 312 deletions
|
|
@ -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,
|
||||
},
|
||||
},
|
||||
quit,
|
||||
quit, set_env,
|
||||
status::set_status,
|
||||
switch_to_vt,
|
||||
Axis::{Horizontal, Vertical},
|
||||
|
|
@ -143,6 +143,7 @@ pub fn configure() {
|
|||
timer.on_tick(update_status);
|
||||
}
|
||||
|
||||
set_env("GTK_THEME", "Adwaita:dark");
|
||||
Command::new("mako").spawn();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -318,6 +318,10 @@ impl Client {
|
|||
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) {
|
||||
self.send(&ClientMessage::SetStatus { status });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -221,6 +221,10 @@ pub enum ClientMessage<'a> {
|
|||
initial: Option<Duration>,
|
||||
periodic: Option<Duration>,
|
||||
},
|
||||
SetEnv {
|
||||
key: &'a str,
|
||||
val: &'a str,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Debug)]
|
||||
|
|
|
|||
|
|
@ -56,6 +56,10 @@ pub fn switch_to_vt(n: u32) {
|
|||
get!().switch_to_vt(n)
|
||||
}
|
||||
|
||||
pub fn set_env(key: &str, val: &str) {
|
||||
get!().set_env(key, val);
|
||||
}
|
||||
|
||||
pub struct Command {
|
||||
prog: String,
|
||||
args: Vec<String>,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use {
|
|||
thiserror::Error,
|
||||
uapi::{c, format_ustr, Errno, OwnedFd, Ustring},
|
||||
};
|
||||
use crate::utils::xrd::xrd;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum AcceptorError {
|
||||
|
|
@ -115,9 +116,9 @@ fn bind_socket(
|
|||
}
|
||||
|
||||
fn allocate_socket() -> Result<AllocatedSocket, AcceptorError> {
|
||||
let xrd = match std::env::var("XDG_RUNTIME_DIR") {
|
||||
Ok(d) => d,
|
||||
Err(_) => return Err(AcceptorError::XrdNotSet),
|
||||
let xrd = match xrd() {
|
||||
Some(d) => d,
|
||||
_ => return Err(AcceptorError::XrdNotSet),
|
||||
};
|
||||
let mut fds = [None, None];
|
||||
for fd in &mut fds {
|
||||
|
|
@ -145,7 +146,7 @@ fn allocate_socket() -> Result<AllocatedSocket, AcceptorError> {
|
|||
}
|
||||
|
||||
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()?;
|
||||
log::info!("bound to socket {}", socket.path.display());
|
||||
for fd in [&socket.secure, &socket.insecure] {
|
||||
|
|
@ -170,6 +171,8 @@ impl Acceptor {
|
|||
state
|
||||
.el
|
||||
.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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
use {
|
||||
crate::{
|
||||
async_engine::SpawnedFuture,
|
||||
fixed::Fixed,
|
||||
ifs::wl_seat::wl_pointer::{CONTINUOUS, FINGER, HORIZONTAL_SCROLL, VERTICAL_SCROLL, WHEEL},
|
||||
video::drm::ConnectorType,
|
||||
},
|
||||
std::{
|
||||
error::Error,
|
||||
fmt::{Debug, Display, Formatter},
|
||||
rc::Rc,
|
||||
},
|
||||
|
|
@ -14,6 +16,8 @@ linear_ids!(ConnectorIds, ConnectorId);
|
|||
linear_ids!(InputDeviceIds, InputDeviceId);
|
||||
|
||||
pub trait Backend {
|
||||
fn run(self: Rc<Self>) -> SpawnedFuture<Result<(), Box<dyn Error>>>;
|
||||
|
||||
fn switch_to(&self, vtnr: u32) {
|
||||
let _ = vtnr;
|
||||
}
|
||||
|
|
@ -21,6 +25,14 @@ pub trait Backend {
|
|||
fn set_idle(&self, idle: bool) {
|
||||
let _ = idle;
|
||||
}
|
||||
|
||||
fn supports_idle(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn is_freestanding(&self) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
|
||||
|
|
|
|||
|
|
@ -1,14 +1,20 @@
|
|||
use std::error::Error;
|
||||
use {
|
||||
crate::{
|
||||
async_engine::SpawnedFuture,
|
||||
backend::{Backend, Connector, ConnectorEvent, ConnectorId, ConnectorKernelId},
|
||||
video::drm::ConnectorType,
|
||||
},
|
||||
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 id: ConnectorId,
|
||||
|
|
|
|||
|
|
@ -4,13 +4,13 @@ mod video;
|
|||
|
||||
use {
|
||||
crate::{
|
||||
async_engine::{AsyncError, AsyncFd, Phase},
|
||||
async_engine::{AsyncError, AsyncFd, SpawnedFuture},
|
||||
backend::{
|
||||
Backend, InputDevice, InputDeviceAccelProfile, InputDeviceCapability, InputDeviceId,
|
||||
InputEvent, KeyState,
|
||||
},
|
||||
backends::metal::video::{MetalDrmDevice, PendingDrmDevice},
|
||||
dbus::DbusError,
|
||||
dbus::{DbusError, SignalHandler},
|
||||
libinput::{
|
||||
consts::{
|
||||
AccelProfile, LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE,
|
||||
|
|
@ -25,7 +25,6 @@ use {
|
|||
logind::{LogindError, Session},
|
||||
render::RenderError,
|
||||
state::State,
|
||||
tasks::idle,
|
||||
udev::{Udev, UdevError, UdevMonitor},
|
||||
utils::{
|
||||
clonecell::{CloneCell, UnsafeCellCloneSafe},
|
||||
|
|
@ -42,6 +41,7 @@ use {
|
|||
},
|
||||
std::{
|
||||
cell::{Cell, RefCell},
|
||||
error::Error,
|
||||
ffi::{CStr, CString},
|
||||
future::pending,
|
||||
mem,
|
||||
|
|
@ -67,8 +67,6 @@ pub enum MetalError {
|
|||
LibInput(#[from] LibInputError),
|
||||
#[error("Dupfd failed")]
|
||||
Dup(#[source] crate::utils::oserror::OsError),
|
||||
#[error("Metal backend terminated unexpectedly")]
|
||||
UnexpectedTermination,
|
||||
#[error("Could not create GBM device")]
|
||||
GbmDevice(#[source] GbmError),
|
||||
#[error("Could not update the drm properties")]
|
||||
|
|
@ -99,20 +97,17 @@ pub enum MetalError {
|
|||
CreateEncoder(#[source] DrmError),
|
||||
#[error(transparent)]
|
||||
DrmError(#[from] DrmError),
|
||||
#[error("Could not create an async fd for the drm fd")]
|
||||
CreateDrmAsyncFd(#[source] AsyncError),
|
||||
}
|
||||
|
||||
pub async fn run(state: Rc<State>) -> MetalError {
|
||||
match run_(state).await {
|
||||
Err(e) => e,
|
||||
_ => MetalError::UnexpectedTermination,
|
||||
}
|
||||
#[error("Could not create an async fd")]
|
||||
CreateAsyncFd(#[source] AsyncError),
|
||||
#[error("Could not create device-paused signal handler")]
|
||||
DevicePauseSignalHandler(#[source] DbusError),
|
||||
#[error("Could not create device-resumed signal handler")]
|
||||
DeviceResumeSignalHandler(#[source] DbusError),
|
||||
}
|
||||
|
||||
linear_ids!(DrmIds, DrmId);
|
||||
|
||||
struct MetalBackend {
|
||||
pub struct MetalBackend {
|
||||
state: Rc<State>,
|
||||
udev: Rc<Udev>,
|
||||
monitor: Rc<UdevMonitor>,
|
||||
|
|
@ -122,9 +117,30 @@ struct MetalBackend {
|
|||
device_holder: Rc<DeviceHolder>,
|
||||
session: Session,
|
||||
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 {
|
||||
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) {
|
||||
self.session.switch_to(vtnr, move |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() {
|
||||
Ok(s) => s,
|
||||
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.enable_receiving()?;
|
||||
let libinput = Rc::new(LibInput::new(device_holder.clone())?);
|
||||
let monitor_fd = match uapi::fcntl_dupfd_cloexec(monitor.fd(), 0) {
|
||||
Ok(m) => state.eng.fd(&Rc::new(m)).unwrap(),
|
||||
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 monitor_fd = dup_async_fd(&state, monitor.fd())?;
|
||||
let libinput_fd = dup_async_fd(&state, libinput.fd())?;
|
||||
let metal = Rc::new(MetalBackend {
|
||||
state: state.clone(),
|
||||
udev,
|
||||
|
|
@ -204,31 +232,28 @@ async fn run_(state: Rc<State>) -> Result<(), MetalError> {
|
|||
device_holder,
|
||||
session,
|
||||
drm_ids: Default::default(),
|
||||
pause_handler: Default::default(),
|
||||
resume_handler: Default::default(),
|
||||
});
|
||||
let _pause_handler = {
|
||||
metal.pause_handler.set(Some({
|
||||
let mtl = metal.clone();
|
||||
metal
|
||||
.session
|
||||
.on_pause(move |p| mtl.handle_device_pause(p))
|
||||
.unwrap()
|
||||
};
|
||||
let _resume_handler = {
|
||||
let sh = metal.session.on_pause(move |p| mtl.handle_device_pause(p));
|
||||
match sh {
|
||||
Ok(sh) => sh,
|
||||
Err(e) => return Err(MetalError::DevicePauseSignalHandler(e)),
|
||||
}
|
||||
}));
|
||||
metal.resume_handler.set(Some({
|
||||
let mtl = metal.clone();
|
||||
metal
|
||||
let sh = metal
|
||||
.session
|
||||
.on_resume(move |p| mtl.handle_device_resume(p))
|
||||
.unwrap()
|
||||
};
|
||||
let _monitor = state.eng.spawn(metal.clone().monitor_devices());
|
||||
let _events = state.eng.spawn(metal.clone().handle_libinput_events());
|
||||
if let Err(e) = metal.enumerate_devices() {
|
||||
return Err(MetalError::Enumerate(Box::new(e)));
|
||||
}
|
||||
state.backend.set(Some(metal.clone()));
|
||||
let _idle = state
|
||||
.eng
|
||||
.spawn2(Phase::PostLayout, idle(state.clone(), metal.clone()));
|
||||
pending().await
|
||||
.on_resume(move |p| mtl.handle_device_resume(p));
|
||||
match sh {
|
||||
Ok(sh) => sh,
|
||||
Err(e) => return Err(MetalError::DeviceResumeSignalHandler(e)),
|
||||
}
|
||||
}));
|
||||
Ok(metal)
|
||||
}
|
||||
|
||||
struct MetalInputDevice {
|
||||
|
|
|
|||
|
|
@ -540,7 +540,7 @@ impl MetalBackend {
|
|||
};
|
||||
let async_fd = match self.state.eng.fd(master.fd()) {
|
||||
Ok(f) => f,
|
||||
Err(e) => return Err(MetalError::CreateDrmAsyncFd(e)),
|
||||
Err(e) => return Err(MetalError::CreateAsyncFd(e)),
|
||||
};
|
||||
|
||||
let dev = Rc::new(MetalDrmDeviceStatic {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use std::error::Error;
|
||||
use {
|
||||
crate::{
|
||||
async_engine::{Phase, SpawnedFuture},
|
||||
|
|
@ -51,6 +52,7 @@ use {
|
|||
borrow::Cow,
|
||||
cell::{Cell, RefCell},
|
||||
collections::VecDeque,
|
||||
future::pending,
|
||||
rc::Rc,
|
||||
},
|
||||
thiserror::Error,
|
||||
|
|
@ -106,16 +108,137 @@ pub enum XBackendError {
|
|||
QueryDevice(#[source] XconError),
|
||||
}
|
||||
|
||||
pub struct XBackend {
|
||||
_data: Rc<XBackendData>,
|
||||
_events: SpawnedFuture<()>,
|
||||
_present: SpawnedFuture<()>,
|
||||
_grab: SpawnedFuture<()>,
|
||||
pub async fn create(state: &Rc<State>) -> Result<Rc<XBackend>, XBackendError> {
|
||||
let c = match Xcon::connect(state.eng.clone()).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(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>,
|
||||
c: Rc<Xcon>,
|
||||
outputs: CopyHashMap<u32, Rc<XOutput>>,
|
||||
|
|
@ -130,141 +253,21 @@ struct XBackendData {
|
|||
}
|
||||
|
||||
impl XBackend {
|
||||
pub async fn run(state: &Rc<State>) -> Result<Rc<Self>, XBackendError> {
|
||||
let c = match Xcon::connect(state.eng.clone()).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));
|
||||
}
|
||||
}
|
||||
async fn run(self: Rc<Self>) -> Result<(), XBackendError> {
|
||||
self.query_devices(INPUT_DEVICE_ALL_MASTER).await?;
|
||||
|
||||
let data = Rc::new(XBackendData {
|
||||
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?;
|
||||
data.query_devices(INPUT_DEVICE_ALL_MASTER).await?;
|
||||
let _events = self.state.eng.spawn(self.clone().event_handler());
|
||||
let _grab = self.state.eng.spawn(self.clone().grab_handler());
|
||||
let _present = self
|
||||
.state
|
||||
.eng
|
||||
.spawn2(Phase::Present, self.clone().present_handler());
|
||||
|
||||
let slf = Rc::new(Self {
|
||||
_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,
|
||||
});
|
||||
self.state.set_render_ctx(&self.ctx);
|
||||
|
||||
state.set_render_ctx(&ctx);
|
||||
state.backend.set(Some(slf.clone()));
|
||||
|
||||
Ok(slf)
|
||||
pending().await
|
||||
}
|
||||
}
|
||||
|
||||
impl XBackendData {
|
||||
async fn event_handler(self: Rc<Self>) {
|
||||
loop {
|
||||
let event = self.c.event().await;
|
||||
|
|
@ -856,7 +859,7 @@ impl XBackendData {
|
|||
|
||||
struct XOutput {
|
||||
id: ConnectorId,
|
||||
_backend: Rc<XBackendData>,
|
||||
_backend: Rc<XBackend>,
|
||||
window: u32,
|
||||
events: SyncQueue<ConnectorEvent>,
|
||||
width: Cell<i32>,
|
||||
|
|
@ -908,7 +911,7 @@ impl Connector for XOutput {
|
|||
struct XSeat {
|
||||
kb_id: InputDeviceId,
|
||||
mouse_id: InputDeviceId,
|
||||
backend: Rc<XBackendData>,
|
||||
backend: Rc<XBackend>,
|
||||
kb: u16,
|
||||
mouse: u16,
|
||||
removed: Cell<bool>,
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ pub struct SetLogArgs {
|
|||
level: CliLogLevel,
|
||||
}
|
||||
|
||||
#[derive(ArgEnum, Debug, Copy, Clone, Hash)]
|
||||
#[derive(ArgEnum, Debug, Copy, Clone, Hash, Eq, PartialEq)]
|
||||
pub enum CliBackend {
|
||||
X11,
|
||||
Metal,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
use {
|
||||
crate::{
|
||||
acceptor::{Acceptor, AcceptorError},
|
||||
async_engine::{AsyncEngine, AsyncError, Phase},
|
||||
backend,
|
||||
backends::dummy::DummyOutput,
|
||||
cli::{GlobalArgs, RunArgs},
|
||||
async_engine::{AsyncEngine, AsyncError, Phase, SpawnedFuture},
|
||||
backend::{self, Backend},
|
||||
backends::{dummy::DummyOutput, metal, x},
|
||||
cli::{CliBackend, GlobalArgs, RunArgs},
|
||||
client::Clients,
|
||||
clientmem::{self, ClientMemError},
|
||||
config::ConfigProxy,
|
||||
|
|
@ -29,13 +29,17 @@ use {
|
|||
},
|
||||
wheel::{Wheel, WheelError},
|
||||
xkbcommon::XkbContext,
|
||||
xwayland,
|
||||
},
|
||||
ahash::AHashSet,
|
||||
forker::ForkerProxy,
|
||||
std::{cell::Cell, ops::Deref, rc::Rc, sync::Arc, time::Duration},
|
||||
thiserror::Error,
|
||||
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;
|
||||
|
||||
|
|
@ -45,7 +49,7 @@ pub fn start_compositor(global: GlobalArgs, args: RunArgs) {
|
|||
Err(e) => fatal!("Could not create a forker process: {}", ErrorFmt(e)),
|
||||
};
|
||||
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);
|
||||
log::error!("A fatal error occurred: {}", e);
|
||||
eprintln!("A fatal error occurred: {}", e);
|
||||
|
|
@ -73,7 +77,14 @@ enum MainError {
|
|||
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();
|
||||
leaks::init();
|
||||
render::init()?;
|
||||
|
|
@ -88,7 +99,7 @@ fn main_(forker: Rc<ForkerProxy>, logger: Arc<Logger>, _args: &RunArgs) -> Resul
|
|||
let node_ids = NodeIds::default();
|
||||
let state = Rc::new(State {
|
||||
xkb_ctx,
|
||||
backend: Default::default(),
|
||||
backend: CloneCell::new(Rc::new(DummyBackend)),
|
||||
forker: Default::default(),
|
||||
default_keymap: xkb_keymap,
|
||||
eng: engine.clone(),
|
||||
|
|
@ -126,77 +137,23 @@ fn main_(forker: Rc<ForkerProxy>, logger: Arc<Logger>, _args: &RunArgs) -> Resul
|
|||
idle: IdleState {
|
||||
input: Default::default(),
|
||||
change: Default::default(),
|
||||
timeout: Cell::new(Duration::from_secs(10)),
|
||||
timeout: Cell::new(Duration::from_secs(10 * 60)),
|
||||
timeout_changed: Default::default(),
|
||||
},
|
||||
run_args,
|
||||
xwayland: XWaylandState {
|
||||
enabled: Cell::new(true),
|
||||
handler: Default::default(),
|
||||
},
|
||||
socket_path: Default::default(),
|
||||
});
|
||||
{
|
||||
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()));
|
||||
create_dummy_output(&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");
|
||||
let _xwayland = engine.spawn(xwayland::manage(state.clone()));
|
||||
let _backend = engine.spawn(tasks::start_backend(state.clone()));
|
||||
let config = ConfigProxy::default(&state);
|
||||
state.config.set(Some(Rc::new(config)));
|
||||
let _compositor = engine.spawn(start_compositor3(state.clone()));
|
||||
el.run()?;
|
||||
drop(_xwayland);
|
||||
state.clients.clear();
|
||||
for (_, seat) in state.globals.seats.lock().deref() {
|
||||
seat.clear();
|
||||
|
|
@ -205,6 +162,83 @@ fn main_(forker: Rc<ForkerProxy>, logger: Arc<Logger>, _args: &RunArgs) -> Resul
|
|||
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() {
|
||||
let res = OsError::tri(|| {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -172,6 +172,12 @@ impl ConfigProxyHandler {
|
|||
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(
|
||||
&self,
|
||||
timer: jay_config::Timer,
|
||||
|
|
@ -654,10 +660,7 @@ impl ConfigProxyHandler {
|
|||
}
|
||||
|
||||
fn handle_switch_to(&self, vtnr: u32) {
|
||||
match self.state.backend.get() {
|
||||
Some(b) => b.switch_to(vtnr),
|
||||
_ => log::warn!("Cannot switch to VT {}: Backend has not yet started", vtnr),
|
||||
}
|
||||
self.state.backend.get().switch_to(vtnr);
|
||||
}
|
||||
|
||||
fn handle_toggle_floating(&self, seat: Seat) -> Result<(), CphError> {
|
||||
|
|
@ -877,6 +880,7 @@ impl ConfigProxyHandler {
|
|||
} => self
|
||||
.handle_program_timer(timer, initial, periodic)
|
||||
.wrn("program_timer")?,
|
||||
ClientMessage::SetEnv { key, val } => self.handle_set_env(key, val),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
26
src/dbus.rs
26
src/dbus.rs
|
|
@ -30,6 +30,7 @@ use {
|
|||
thiserror::Error,
|
||||
uapi::OwnedFd,
|
||||
};
|
||||
use crate::utils::xrd::{xrd, XRD};
|
||||
|
||||
mod auth;
|
||||
mod dynamic_type;
|
||||
|
|
@ -108,6 +109,8 @@ pub enum DbusError {
|
|||
InvalidBoolValue,
|
||||
#[error("Signature is empty")]
|
||||
EmptySignature,
|
||||
#[error("The session bus address is not set")]
|
||||
SessionBusAddressNotSet,
|
||||
#[error("Server does not support FD passing")]
|
||||
UnixFd,
|
||||
#[error("Server message has a different endianess than ourselves")]
|
||||
|
|
@ -128,13 +131,25 @@ efrom!(DbusError, AsyncError);
|
|||
pub struct Dbus {
|
||||
eng: Rc<AsyncEngine>,
|
||||
system: Rc<DbusHolder>,
|
||||
session: Rc<DbusHolder>,
|
||||
user_path: Option<String>,
|
||||
}
|
||||
|
||||
impl Dbus {
|
||||
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 {
|
||||
eng: eng.clone(),
|
||||
system: Rc::new(DbusHolder::new(run_toplevel)),
|
||||
session: Rc::new(DbusHolder::new(run_toplevel)),
|
||||
user_path,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -142,6 +157,15 @@ impl Dbus {
|
|||
self.system
|
||||
.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 {
|
||||
|
|
@ -211,7 +235,7 @@ const NO_AUTO_START: u8 = 0x2;
|
|||
const ALLOW_INTERACTIVE_AUTHORIZATION: u8 = 0x4;
|
||||
|
||||
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)]
|
||||
struct Headers<'a> {
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ use {
|
|||
thiserror::Error,
|
||||
uapi::{c, pipe2, Errno, Fd, IntoUstr, OwnedFd, UstrPtr},
|
||||
};
|
||||
use crate::compositor::{DISPLAY, WAYLAND_DISPLAY};
|
||||
|
||||
pub struct ForkerProxy {
|
||||
pidfd: Rc<OwnedFd>,
|
||||
|
|
@ -297,8 +298,8 @@ struct Forker {
|
|||
impl Forker {
|
||||
fn handle(ppid: c::pid_t, socket: OwnedFd) -> ! {
|
||||
env::set_var("XDG_SESSION_TYPE", "wayland");
|
||||
env::remove_var("DISPLAY");
|
||||
env::remove_var("WAYLAND_DISPLAY");
|
||||
env::remove_var(DISPLAY);
|
||||
env::remove_var(WAYLAND_DISPLAY);
|
||||
setup_name("the ol' forker");
|
||||
setup_deathsig(ppid);
|
||||
reset_signals();
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ mod wire_xcon;
|
|||
mod xcon;
|
||||
mod xkbcommon;
|
||||
mod xwayland;
|
||||
mod user_session;
|
||||
|
||||
fn main() {
|
||||
cli::main();
|
||||
|
|
|
|||
22
src/state.rs
22
src/state.rs
|
|
@ -5,6 +5,7 @@ use {
|
|||
Backend, BackendEvent, Connector, ConnectorId, ConnectorIds, InputDevice,
|
||||
InputDeviceId, InputDeviceIds, MonitorInfo,
|
||||
},
|
||||
cli::RunArgs,
|
||||
client::{Client, Clients},
|
||||
config::ConfigProxy,
|
||||
cursor::ServerCursors,
|
||||
|
|
@ -30,6 +31,7 @@ use {
|
|||
},
|
||||
wheel::Wheel,
|
||||
xkbcommon::{XkbContext, XkbKeymap},
|
||||
xwayland,
|
||||
},
|
||||
ahash::AHashMap,
|
||||
jay_config::Direction,
|
||||
|
|
@ -43,7 +45,7 @@ use {
|
|||
|
||||
pub struct State {
|
||||
pub xkb_ctx: XkbContext,
|
||||
pub backend: CloneCell<Option<Rc<dyn Backend>>>,
|
||||
pub backend: CloneCell<Rc<dyn Backend>>,
|
||||
pub forker: CloneCell<Option<Rc<ForkerProxy>>>,
|
||||
pub default_keymap: Rc<XkbKeymap>,
|
||||
pub eng: Rc<AsyncEngine>,
|
||||
|
|
@ -79,6 +81,14 @@ pub struct State {
|
|||
pub outputs: CopyHashMap<ConnectorId, Rc<OutputData>>,
|
||||
pub status: CloneCell<Rc<String>>,
|
||||
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 {
|
||||
|
|
@ -305,4 +315,14 @@ impl State {
|
|||
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())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ mod connector;
|
|||
mod idle;
|
||||
mod input_device;
|
||||
mod slow_clients;
|
||||
mod start_backend;
|
||||
|
||||
pub use idle::idle;
|
||||
use {
|
||||
crate::{
|
||||
state::State,
|
||||
|
|
@ -12,7 +12,6 @@ use {
|
|||
},
|
||||
std::rc::Rc,
|
||||
};
|
||||
pub use {idle::idle, start_backend::start_backend};
|
||||
|
||||
pub async fn handle_backend_events(state: Rc<State>) {
|
||||
let mut beh = BackendEventHandler { state };
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ use {
|
|||
};
|
||||
|
||||
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) {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -38,6 +38,8 @@ use {
|
|||
thiserror::Error,
|
||||
uapi::{c, format_ustr},
|
||||
};
|
||||
use crate::compositor::WAYLAND_DISPLAY;
|
||||
use crate::utils::xrd::xrd;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ToolClientError {
|
||||
|
|
@ -133,11 +135,11 @@ impl ToolClient {
|
|||
Ok(e) => e,
|
||||
Err(e) => return Err(ToolClientError::CreateEngine(e)),
|
||||
};
|
||||
let xrd = match std::env::var("XDG_RUNTIME_DIR") {
|
||||
Ok(d) => d,
|
||||
Err(_) => return Err(ToolClientError::XrdNotSet),
|
||||
let xrd = match xrd() {
|
||||
Some(d) => d,
|
||||
_ => return Err(ToolClientError::XrdNotSet),
|
||||
};
|
||||
let wd = match std::env::var("WAYLAND_DISPLAY") {
|
||||
let wd = match std::env::var(WAYLAND_DISPLAY) {
|
||||
Ok(d) => d,
|
||||
Err(_) => return Err(ToolClientError::WaylandDisplayNotSet),
|
||||
};
|
||||
|
|
|
|||
54
src/user_session.rs
Normal file
54
src/user_session.rs
Normal 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(())
|
||||
}
|
||||
|
|
@ -27,3 +27,4 @@ pub mod vasprintf;
|
|||
pub mod vec_ext;
|
||||
pub mod vecstorage;
|
||||
pub mod windows;
|
||||
pub mod xrd;
|
||||
|
|
|
|||
5
src/utils/xrd.rs
Normal file
5
src/utils/xrd.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
pub const XRD: &str = "XDG_RUNTIME_DIR";
|
||||
|
||||
pub fn xrd() -> Option<String> {
|
||||
std::env::var(XRD).ok()
|
||||
}
|
||||
|
|
@ -47,6 +47,7 @@ use {
|
|||
thiserror::Error,
|
||||
uapi::{c, OwnedFd},
|
||||
};
|
||||
use crate::compositor::DISPLAY;
|
||||
|
||||
pub mod consts;
|
||||
mod formatter;
|
||||
|
|
@ -885,7 +886,7 @@ impl XconData {
|
|||
}
|
||||
|
||||
fn parse_display() -> Result<u32, XconError> {
|
||||
let display = match std::env::var("DISPLAY") {
|
||||
let display = match std::env::var(DISPLAY) {
|
||||
Ok(d) => d,
|
||||
_ => return Err(XconError::DisplayNotSet),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ use {
|
|||
thiserror::Error,
|
||||
uapi::{c, pipe2, Errno, OwnedFd},
|
||||
};
|
||||
use crate::compositor::DISPLAY;
|
||||
use crate::user_session::import_environment;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
enum XWaylandError {
|
||||
|
|
@ -92,10 +94,15 @@ pub async fn manage(state: Rc<State>) {
|
|||
};
|
||||
if let Err(e) = uapi::listen(socket.raw(), 4096) {
|
||||
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!("Waiting for connection attempt");
|
||||
if state.backend.get().is_freestanding() {
|
||||
import_environment(&state, DISPLAY, &display);
|
||||
}
|
||||
let res = XWaylandError::tria(async {
|
||||
state.eng.fd(&socket)?.readable().await?;
|
||||
Ok(())
|
||||
|
|
@ -111,7 +118,7 @@ pub async fn manage(state: Rc<State>) {
|
|||
} else {
|
||||
log::warn!("Xwayland exited unexpectedly");
|
||||
}
|
||||
forker.unsetenv(b"DISPLAY");
|
||||
forker.unsetenv(DISPLAY.as_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
4
wire-dbus/org.freedesktop.systemd1.Manager.txt
Normal file
4
wire-dbus/org.freedesktop.systemd1.Manager.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
fn SetEnvironment(
|
||||
names: array(string),
|
||||
) {
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue