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,
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)]
|
||||||
|
|
|
||||||
|
|
@ -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>,
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)]
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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>,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
26
src/dbus.rs
26
src/dbus.rs
|
|
@ -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> {
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
22
src/state.rs
22
src/state.rs
|
|
@ -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())));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 };
|
||||||
|
|
|
||||||
|
|
@ -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) => {
|
||||||
|
|
|
||||||
|
|
@ -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,
|
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
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 vec_ext;
|
||||||
pub mod vecstorage;
|
pub mod vecstorage;
|
||||||
pub mod windows;
|
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,
|
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),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
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