1
0
Fork 0
forked from wry/wry
wry/src/compositor.rs
2022-04-05 18:28:42 +02:00

186 lines
7.1 KiB
Rust

use crate::acceptor::{Acceptor, AcceptorError};
use crate::async_engine::{AsyncEngine, AsyncError, Phase};
use crate::backends::dummy::DummyOutput;
use crate::cli::{GlobalArgs, RunArgs};
use crate::client::Clients;
use crate::clientmem::ClientMemError;
use crate::config::ConfigProxy;
use crate::dbus::Dbus;
use crate::event_loop::{EventLoop, EventLoopError};
use crate::globals::Globals;
use crate::ifs::wl_output::WlOutputGlobal;
use crate::ifs::wl_surface::NoneSurfaceExt;
use crate::logger::Logger;
use crate::render::RenderError;
use crate::sighand::SighandError;
use crate::state::{ConnectorData, State};
use crate::tree::{
container_layout, container_render_data, float_layout, float_titles, DisplayNode, NodeIds,
OutputNode, WorkspaceNode,
};
use crate::utils::clonecell::CloneCell;
use crate::utils::errorfmt::ErrorFmt;
use crate::utils::fdcloser::FdCloser;
use crate::utils::queue::AsyncQueue;
use crate::utils::run_toplevel::RunToplevel;
use crate::wheel::{Wheel, WheelError};
use crate::xkbcommon::XkbContext;
use crate::{backend, clientmem, forker, leaks, render, sighand, tasks, xwayland};
use forker::ForkerProxy;
use std::cell::Cell;
use std::ops::Deref;
use std::rc::Rc;
use std::sync::Arc;
use thiserror::Error;
pub fn start_compositor(global: GlobalArgs, args: RunArgs) {
let forker = match ForkerProxy::create() {
Ok(f) => Rc::new(f),
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) {
let e = ErrorFmt(e);
log::error!("A fatal error occurred: {}", e);
eprintln!("A fatal error occurred: {}", e);
eprintln!("See {} for more details.", logger.path());
std::process::exit(1);
}
}
#[derive(Debug, Error)]
enum MainError {
#[error("The client acceptor caused an error")]
AcceptorError(#[from] AcceptorError),
#[error("The event loop caused an error")]
EventLoopError(#[from] EventLoopError),
#[error("The signal handler caused an error")]
SighandError(#[from] SighandError),
#[error("The clientmem subsystem caused an error")]
ClientmemError(#[from] ClientMemError),
#[error("The timer subsystem caused an error")]
WheelError(#[from] WheelError),
#[error("The async subsystem caused an error")]
AsyncError(#[from] AsyncError),
#[error("The render backend caused an error")]
RenderError(#[from] RenderError),
}
fn main_(forker: Rc<ForkerProxy>, logger: Arc<Logger>, _args: &RunArgs) -> Result<(), MainError> {
leaks::init();
render::init()?;
clientmem::init()?;
let el = EventLoop::new()?;
sighand::install(&el)?;
let xkb_ctx = XkbContext::new().unwrap();
let xkb_keymap = xkb_ctx.keymap_from_str(include_str!("keymap.xkb")).unwrap();
let wheel = Wheel::install(&el)?;
let engine = AsyncEngine::install(&el, &wheel)?;
let (_run_toplevel_future, run_toplevel) = RunToplevel::install(&engine);
let node_ids = NodeIds::default();
let state = Rc::new(State {
xkb_ctx,
backend: Default::default(),
forker: Default::default(),
default_keymap: xkb_keymap,
eng: engine.clone(),
el: el.clone(),
render_ctx: Default::default(),
cursors: Default::default(),
wheel,
clients: Clients::new(),
globals: Globals::new(),
connector_ids: Default::default(),
root: Rc::new(DisplayNode::new(node_ids.next())),
workspaces: Default::default(),
dummy_output: Default::default(),
node_ids,
backend_events: AsyncQueue::new(),
seat_ids: Default::default(),
seat_queue: Default::default(),
slow_clients: AsyncQueue::new(),
none_surface_ext: Rc::new(NoneSurfaceExt),
tree_changed_sent: Cell::new(false),
config: Default::default(),
input_device_ids: Default::default(),
input_device_handlers: Default::default(),
theme: Default::default(),
pending_container_layout: Default::default(),
pending_container_render_data: Default::default(),
pending_float_layout: Default::default(),
pending_float_titles: Default::default(),
dbus: Dbus::new(&engine, &run_toplevel),
fdcloser: FdCloser::new(),
logger,
connectors: 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() }),
monitor_info: Default::default(),
handler: Cell::new(None),
node: Default::default()
}),
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,
});
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(),
});
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 config = ConfigProxy::default(&state);
state.config.set(Some(Rc::new(config)));
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)?;
forker.setenv(b"WAYLAND_DISPLAY", 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()));
el.run()?;
drop(_xwayland);
state.clients.clear();
for (_, seat) in state.globals.seats.lock().deref() {
seat.clear();
}
leaks::log_leaked();
Ok(())
}