Files
niri/src/niri.rs
T

246 lines
7.9 KiB
Rust
Raw Normal View History

2023-08-09 11:03:38 +04:00
use std::os::unix::io::AsRawFd;
use std::sync::Arc;
use std::time::Duration;
2023-08-10 09:57:13 +04:00
use smithay::backend::renderer::element::render_elements;
2023-08-10 14:27:09 +04:00
use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement};
2023-08-10 09:57:13 +04:00
use smithay::backend::renderer::ImportAll;
use smithay::desktop::space::{space_render_elements, SpaceRenderElements};
2023-08-11 08:22:34 +04:00
use smithay::desktop::{PopupManager, Space, Window, WindowSurfaceType};
2023-08-09 11:03:38 +04:00
use smithay::input::keyboard::XkbConfig;
use smithay::input::{Seat, SeatState};
use smithay::output::Output;
use smithay::reexports::calloop::generic::Generic;
use smithay::reexports::calloop::{Interest, LoopHandle, LoopSignal, Mode, PostAction};
2023-08-10 17:17:17 +04:00
use smithay::reexports::wayland_protocols::xdg::shell::server::xdg_toplevel::WmCapabilities;
2023-08-09 11:03:38 +04:00
use smithay::reexports::wayland_server::backend::{ClientData, ClientId, DisconnectReason};
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
use smithay::reexports::wayland_server::{Display, DisplayHandle};
use smithay::utils::{Logical, Point};
use smithay::wayland::compositor::{CompositorClientState, CompositorState};
use smithay::wayland::data_device::DataDeviceState;
use smithay::wayland::output::OutputManagerState;
use smithay::wayland::shell::xdg::XdgShellState;
use smithay::wayland::shm::ShmState;
use smithay::wayland::socket::ListeningSocketSource;
use crate::backend::Backend;
use crate::LoopData;
pub struct Niri {
pub start_time: std::time::Instant,
pub event_loop: LoopHandle<'static, LoopData>,
pub stop_signal: LoopSignal,
pub display_handle: DisplayHandle,
pub space: Space<Window>,
// Smithay state.
pub compositor_state: CompositorState,
pub xdg_shell_state: XdgShellState,
pub shm_state: ShmState,
pub output_manager_state: OutputManagerState,
pub seat_state: SeatState<Self>,
pub data_device_state: DataDeviceState,
2023-08-11 08:22:34 +04:00
pub popups: PopupManager,
2023-08-09 11:03:38 +04:00
pub seat: Seat<Self>,
pub output: Option<Output>,
2023-08-10 09:58:26 +04:00
2023-08-10 14:27:09 +04:00
pub pointer_buffer: SolidColorBuffer,
2023-08-10 09:58:26 +04:00
// Set to `true` if there's a redraw queued on the event loop. Reset to `false` in redraw()
// which means that you cannot queue more than one redraw at once.
pub redraw_queued: bool,
pub waiting_for_vblank: bool,
2023-08-09 11:03:38 +04:00
}
impl Niri {
pub fn new(
event_loop: LoopHandle<'static, LoopData>,
stop_signal: LoopSignal,
display: &mut Display<Self>,
seat_name: String,
) -> Self {
let start_time = std::time::Instant::now();
let display_handle = display.handle();
let compositor_state = CompositorState::new::<Self>(&display_handle);
2023-08-10 17:17:17 +04:00
let xdg_shell_state = XdgShellState::new_with_capabilities::<Self>(
&display_handle,
[
WmCapabilities::Fullscreen,
WmCapabilities::Maximize,
WmCapabilities::WindowMenu,
],
);
2023-08-09 11:03:38 +04:00
let shm_state = ShmState::new::<Self>(&display_handle, vec![]);
let output_manager_state = OutputManagerState::new_with_xdg_output::<Self>(&display_handle);
let mut seat_state = SeatState::new();
let data_device_state = DataDeviceState::new::<Self>(&display_handle);
let mut seat: Seat<Self> = seat_state.new_wl_seat(&display_handle, seat_name);
// FIXME: get Xkb and repeat interval from GNOME dconf.
let xkb = XkbConfig {
layout: "us,ru",
options: Some("grp:win_space_toggle".to_owned()),
..Default::default()
};
seat.add_keyboard(xkb, 400, 30).unwrap();
2023-08-09 11:03:38 +04:00
seat.add_pointer();
let space = Space::default();
let socket_source = ListeningSocketSource::new_auto().unwrap();
let socket_name = socket_source.socket_name().to_os_string();
event_loop
.insert_source(socket_source, move |client, _, data| {
if let Err(err) = data
.display_handle
.insert_client(client, Arc::new(ClientState::default()))
{
error!("error inserting client: {err}");
}
})
.unwrap();
std::env::set_var("WAYLAND_DISPLAY", &socket_name);
info!(
"listening on Wayland socket: {}",
socket_name.to_string_lossy()
);
let display_source = Generic::new(
display.backend().poll_fd().as_raw_fd(),
Interest::READ,
Mode::Level,
);
event_loop
.insert_source(display_source, |_, _, data| {
data.display.dispatch_clients(&mut data.niri).unwrap();
Ok(PostAction::Continue)
})
.unwrap();
2023-08-10 14:27:09 +04:00
let pointer_buffer = SolidColorBuffer::new((16, 16), [1., 0.8, 0., 1.]);
2023-08-09 11:03:38 +04:00
Self {
start_time,
event_loop,
stop_signal,
display_handle,
space,
compositor_state,
xdg_shell_state,
shm_state,
output_manager_state,
seat_state,
data_device_state,
2023-08-11 08:22:34 +04:00
popups: PopupManager::default(),
2023-08-09 11:03:38 +04:00
seat,
output: None,
2023-08-10 14:27:09 +04:00
pointer_buffer,
2023-08-10 09:58:26 +04:00
redraw_queued: false,
waiting_for_vblank: false,
2023-08-09 11:03:38 +04:00
}
}
pub fn surface_under(
2023-08-09 11:03:38 +04:00
&self,
pos: Point<f64, Logical>,
2023-08-09 11:03:38 +04:00
) -> Option<(WlSurface, Point<i32, Logical>)> {
self.space
.element_under(pos)
.and_then(|(window, location)| {
window
.surface_under(pos - location.to_f64(), WindowSurfaceType::ALL)
.map(|(s, p)| (s, p + location))
})
}
2023-08-10 09:58:26 +04:00
/// Schedules an immediate redraw if one is not already scheduled.
pub fn queue_redraw(&mut self) {
if self.redraw_queued || self.waiting_for_vblank {
return;
}
self.redraw_queued = true;
2023-08-10 14:06:32 +04:00
// Timer::immediate() adds a millisecond of delay for some reason.
// This should be fixed in calloop v0.11: https://github.com/Smithay/calloop/issues/142
self.event_loop.insert_idle(|data| {
let backend: &mut dyn Backend = if let Some(tty) = &mut data.tty {
tty
} else {
data.winit.as_mut().unwrap()
};
data.niri.redraw(backend);
});
2023-08-10 09:58:26 +04:00
}
fn redraw(&mut self, backend: &mut dyn Backend) {
2023-08-10 14:12:20 +04:00
let _span = tracy_client::span!("redraw");
2023-08-10 09:58:26 +04:00
assert!(self.redraw_queued);
assert!(!self.waiting_for_vblank);
self.redraw_queued = false;
2023-08-09 11:03:38 +04:00
let elements = space_render_elements(
backend.renderer(),
[&self.space],
self.output.as_ref().unwrap(),
1.,
)
.unwrap();
2023-08-10 09:57:13 +04:00
let mut elements: Vec<_> = elements
.into_iter()
.map(OutputRenderElements::from)
.collect();
elements.insert(
0,
2023-08-10 14:27:09 +04:00
OutputRenderElements::Pointer(SolidColorRenderElement::from_buffer(
&self.pointer_buffer,
self.seat
.get_pointer()
.unwrap()
.current_location()
.to_physical_precise_round(1.),
1.,
1.,
2023-08-10 09:57:13 +04:00
)),
);
2023-08-09 11:03:38 +04:00
backend.render(self, &elements);
let output = self.output.as_ref().unwrap();
self.space.elements().for_each(|window| {
window.send_frame(
output,
self.start_time.elapsed(),
Some(Duration::ZERO),
|_, _| Some(output.clone()),
)
});
}
}
2023-08-10 09:57:13 +04:00
render_elements! {
pub OutputRenderElements<R, E> where R: ImportAll;
2023-08-11 11:38:12 +04:00
Space = SpaceRenderElements<R, E>,
2023-08-10 09:57:13 +04:00
Pointer = SolidColorRenderElement,
}
2023-08-09 11:03:38 +04:00
#[derive(Default)]
pub struct ClientState {
pub compositor_state: CompositorClientState,
}
impl ClientData for ClientState {
fn initialized(&self, _client_id: ClientId) {}
fn disconnected(&self, _client_id: ClientId, _reason: DisconnectReason) {}
}