2023-08-13 12:46:53 +04:00
|
|
|
use std::collections::hash_map::Entry;
|
|
|
|
|
|
|
|
|
|
use smithay::backend::renderer::utils::{on_commit_buffer_handler, with_renderer_surface_state};
|
2023-09-06 11:56:50 +04:00
|
|
|
use smithay::input::pointer::CursorImageStatus;
|
2023-09-03 14:22:04 +04:00
|
|
|
use smithay::reexports::calloop::Interest;
|
2023-08-07 19:45:55 +04:00
|
|
|
use smithay::reexports::wayland_server::protocol::wl_buffer;
|
|
|
|
|
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
|
2023-09-03 14:22:04 +04:00
|
|
|
use smithay::reexports::wayland_server::{Client, Resource};
|
2023-08-07 19:45:55 +04:00
|
|
|
use smithay::wayland::buffer::BufferHandler;
|
|
|
|
|
use smithay::wayland::compositor::{
|
2023-10-26 00:15:46 +04:00
|
|
|
add_blocker, add_pre_commit_hook, get_parent, is_sync_subsurface, send_surface_state,
|
|
|
|
|
with_states, BufferAssignment, CompositorClientState, CompositorHandler, CompositorState,
|
|
|
|
|
SurfaceAttributes,
|
2023-08-07 19:44:40 +04:00
|
|
|
};
|
2023-09-03 14:22:04 +04:00
|
|
|
use smithay::wayland::dmabuf::get_dmabuf;
|
2023-08-07 19:45:55 +04:00
|
|
|
use smithay::wayland::shm::{ShmHandler, ShmState};
|
|
|
|
|
use smithay::{delegate_compositor, delegate_shm};
|
2023-08-07 19:44:40 +04:00
|
|
|
|
2023-09-03 14:10:02 +04:00
|
|
|
use crate::niri::{ClientState, State};
|
2023-12-24 17:38:13 +04:00
|
|
|
use crate::utils::clone2;
|
2023-08-07 19:44:40 +04:00
|
|
|
|
2023-09-03 14:10:02 +04:00
|
|
|
impl CompositorHandler for State {
|
2023-08-07 19:44:40 +04:00
|
|
|
fn compositor_state(&mut self) -> &mut CompositorState {
|
2023-09-03 14:10:02 +04:00
|
|
|
&mut self.niri.compositor_state
|
2023-08-07 19:44:40 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn client_compositor_state<'a>(&self, client: &'a Client) -> &'a CompositorClientState {
|
|
|
|
|
&client.get_data::<ClientState>().unwrap().compositor_state
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-26 00:15:46 +04:00
|
|
|
fn new_subsurface(&mut self, surface: &WlSurface, parent: &WlSurface) {
|
2023-12-19 13:29:22 +04:00
|
|
|
let mut root = parent.clone();
|
|
|
|
|
while let Some(parent) = get_parent(&root) {
|
|
|
|
|
root = parent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if let Some(output) = self.niri.output_for_root(&root) {
|
2023-10-26 00:15:46 +04:00
|
|
|
let scale = output.current_scale().integer_scale();
|
|
|
|
|
let transform = output.current_transform();
|
|
|
|
|
with_states(surface, |data| {
|
|
|
|
|
send_surface_state(surface, data, scale, transform);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-03 14:22:04 +04:00
|
|
|
fn new_surface(&mut self, surface: &WlSurface) {
|
|
|
|
|
add_pre_commit_hook::<Self, _>(surface, move |state, _dh, surface| {
|
|
|
|
|
let maybe_dmabuf = with_states(surface, |surface_data| {
|
|
|
|
|
surface_data
|
|
|
|
|
.cached_state
|
|
|
|
|
.pending::<SurfaceAttributes>()
|
|
|
|
|
.buffer
|
|
|
|
|
.as_ref()
|
|
|
|
|
.and_then(|assignment| match assignment {
|
|
|
|
|
BufferAssignment::NewBuffer(buffer) => get_dmabuf(buffer).ok(),
|
|
|
|
|
_ => None,
|
|
|
|
|
})
|
|
|
|
|
});
|
|
|
|
|
if let Some(dmabuf) = maybe_dmabuf {
|
|
|
|
|
if let Ok((blocker, source)) = dmabuf.generate_blocker(Interest::READ) {
|
|
|
|
|
let client = surface.client().unwrap();
|
|
|
|
|
let res = state
|
|
|
|
|
.niri
|
|
|
|
|
.event_loop
|
2023-09-24 17:30:06 +04:00
|
|
|
.insert_source(source, move |_, _, state| {
|
|
|
|
|
let display_handle = state.niri.display_handle.clone();
|
|
|
|
|
state
|
2023-09-03 14:22:04 +04:00
|
|
|
.client_compositor_state(&client)
|
2023-09-24 17:30:06 +04:00
|
|
|
.blocker_cleared(state, &display_handle);
|
2023-09-03 14:22:04 +04:00
|
|
|
Ok(())
|
|
|
|
|
});
|
|
|
|
|
if res.is_ok() {
|
|
|
|
|
add_blocker(surface, blocker);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-07 19:44:40 +04:00
|
|
|
fn commit(&mut self, surface: &WlSurface) {
|
2023-08-15 18:17:12 +04:00
|
|
|
let _span = tracy_client::span!("CompositorHandler::commit");
|
2023-08-10 14:12:20 +04:00
|
|
|
|
2023-08-07 19:44:40 +04:00
|
|
|
on_commit_buffer_handler::<Self>(surface);
|
2024-01-03 18:16:20 +04:00
|
|
|
self.backend.early_import(surface);
|
2023-08-13 12:46:53 +04:00
|
|
|
|
|
|
|
|
if is_sync_subsurface(surface) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut root_surface = surface.clone();
|
|
|
|
|
while let Some(parent) = get_parent(&root_surface) {
|
|
|
|
|
root_surface = parent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if surface == &root_surface {
|
|
|
|
|
// This is a root surface commit. It might have mapped a previously-unmapped toplevel.
|
2023-09-03 14:10:02 +04:00
|
|
|
if let Entry::Occupied(entry) = self.niri.unmapped_windows.entry(surface.clone()) {
|
2023-08-13 12:46:53 +04:00
|
|
|
let is_mapped =
|
2024-02-08 13:51:54 +04:00
|
|
|
with_renderer_surface_state(surface, |state| state.buffer().is_some())
|
|
|
|
|
.unwrap_or_else(|| {
|
|
|
|
|
error!("no renderer surface state even though we use commit handler");
|
|
|
|
|
false
|
|
|
|
|
});
|
2023-08-13 12:46:53 +04:00
|
|
|
|
|
|
|
|
if is_mapped {
|
|
|
|
|
// The toplevel got mapped.
|
|
|
|
|
let window = entry.remove();
|
|
|
|
|
window.on_commit();
|
|
|
|
|
|
2024-02-07 10:49:01 +04:00
|
|
|
let parent = window
|
|
|
|
|
.toplevel()
|
|
|
|
|
.parent()
|
|
|
|
|
.and_then(|parent| self.niri.layout.find_window_and_output(&parent))
|
|
|
|
|
.map(|(win, _)| win.clone());
|
|
|
|
|
|
|
|
|
|
let win = window.clone();
|
|
|
|
|
|
|
|
|
|
// Open dialogs immediately to the right of their parent window.
|
|
|
|
|
let output = if let Some(p) = parent {
|
|
|
|
|
self.niri.layout.add_window_right_of(&p, win, None, false)
|
|
|
|
|
} else {
|
|
|
|
|
self.niri.layout.add_window(win, None, false)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if let Some(output) = output.cloned() {
|
2024-02-07 11:32:02 +04:00
|
|
|
self.niri.layout.start_open_animation_for_window(&window);
|
2023-09-12 19:41:50 +04:00
|
|
|
self.niri.queue_redraw(output);
|
|
|
|
|
}
|
2023-08-13 12:46:53 +04:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The toplevel remains unmapped.
|
2024-02-13 12:39:17 +04:00
|
|
|
let window = entry.get().clone();
|
|
|
|
|
self.send_initial_configure_if_needed(&window);
|
2023-08-13 12:46:53 +04:00
|
|
|
return;
|
2023-08-07 19:44:40 +04:00
|
|
|
}
|
2023-08-13 12:46:53 +04:00
|
|
|
|
|
|
|
|
// This is a commit of a previously-mapped root or a non-toplevel root.
|
2023-12-24 17:38:13 +04:00
|
|
|
if let Some(win_out) = self.niri.layout.find_window_and_output(surface) {
|
|
|
|
|
let (window, output) = clone2(win_out);
|
|
|
|
|
|
2023-08-07 19:44:40 +04:00
|
|
|
window.on_commit();
|
2023-08-13 12:46:53 +04:00
|
|
|
|
|
|
|
|
// This is a commit of a previously-mapped toplevel.
|
|
|
|
|
let is_mapped =
|
2024-02-08 13:51:54 +04:00
|
|
|
with_renderer_surface_state(surface, |state| state.buffer().is_some())
|
|
|
|
|
.unwrap_or_else(|| {
|
|
|
|
|
error!("no renderer surface state even though we use commit handler");
|
|
|
|
|
false
|
|
|
|
|
});
|
2023-08-13 12:46:53 +04:00
|
|
|
|
|
|
|
|
if !is_mapped {
|
|
|
|
|
// The toplevel got unmapped.
|
2023-10-05 09:25:07 +04:00
|
|
|
self.niri.layout.remove_window(&window);
|
2023-09-03 14:10:02 +04:00
|
|
|
self.niri.unmapped_windows.insert(surface.clone(), window);
|
|
|
|
|
self.niri.queue_redraw(output);
|
2023-08-13 12:46:53 +04:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The toplevel remains mapped.
|
2023-10-05 09:25:07 +04:00
|
|
|
self.niri.layout.update_window(&window);
|
2023-08-13 12:46:53 +04:00
|
|
|
|
2023-12-19 20:56:00 +04:00
|
|
|
// Popup placement depends on window size which might have changed.
|
|
|
|
|
self.update_reactive_popups(&window, &output);
|
|
|
|
|
|
2023-09-03 14:10:02 +04:00
|
|
|
self.niri.queue_redraw(output);
|
2023-08-13 12:46:53 +04:00
|
|
|
return;
|
2023-08-07 19:44:40 +04:00
|
|
|
}
|
|
|
|
|
|
2023-08-13 12:46:53 +04:00
|
|
|
// This is a commit of a non-toplevel root.
|
|
|
|
|
}
|
2023-08-10 09:58:26 +04:00
|
|
|
|
2023-08-13 12:46:53 +04:00
|
|
|
// This is a commit of a non-root or a non-toplevel root.
|
2023-10-05 09:25:07 +04:00
|
|
|
let root_window_output = self.niri.layout.find_window_and_output(&root_surface);
|
2023-12-24 17:38:13 +04:00
|
|
|
if let Some((window, output)) = root_window_output.map(clone2) {
|
2023-08-13 12:46:53 +04:00
|
|
|
window.on_commit();
|
2023-10-05 09:25:07 +04:00
|
|
|
self.niri.layout.update_window(&window);
|
2023-09-03 14:10:02 +04:00
|
|
|
self.niri.queue_redraw(output);
|
2023-08-13 12:46:53 +04:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This might be a popup.
|
|
|
|
|
self.popups_handle_commit(surface);
|
2023-09-03 14:10:02 +04:00
|
|
|
if let Some(popup) = self.niri.popups.find_popup(surface) {
|
2023-12-19 13:29:22 +04:00
|
|
|
if let Some(output) = self.output_for_popup(&popup) {
|
2023-12-24 17:38:13 +04:00
|
|
|
self.niri.queue_redraw(output.clone());
|
2023-08-13 12:46:53 +04:00
|
|
|
}
|
|
|
|
|
}
|
2023-08-15 12:49:26 +04:00
|
|
|
|
|
|
|
|
// This might be a layer-shell surface.
|
|
|
|
|
self.layer_shell_handle_commit(surface);
|
2023-09-06 11:56:50 +04:00
|
|
|
|
|
|
|
|
// This might be a cursor surface.
|
2023-10-29 14:04:38 +04:00
|
|
|
if matches!(&self.niri.cursor_manager.cursor_image(), CursorImageStatus::Surface(s) if s == surface)
|
|
|
|
|
{
|
2023-09-06 11:56:50 +04:00
|
|
|
// FIXME: granular redraws for cursors.
|
|
|
|
|
self.niri.queue_redraw_all();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This might be a DnD icon surface.
|
|
|
|
|
if self.niri.dnd_icon.as_ref() == Some(surface) {
|
|
|
|
|
// FIXME: granular redraws for cursors.
|
|
|
|
|
self.niri.queue_redraw_all();
|
|
|
|
|
}
|
2023-10-13 13:30:11 +04:00
|
|
|
|
|
|
|
|
// This might be a lock surface.
|
|
|
|
|
if self.niri.is_locked() {
|
|
|
|
|
for (output, state) in &self.niri.output_state {
|
|
|
|
|
if let Some(lock_surface) = &state.lock_surface {
|
|
|
|
|
if lock_surface.wl_surface() == surface {
|
|
|
|
|
self.niri.queue_redraw(output.clone());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-08-07 19:44:40 +04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-03 14:10:02 +04:00
|
|
|
impl BufferHandler for State {
|
2023-08-07 19:44:40 +04:00
|
|
|
fn buffer_destroyed(&mut self, _buffer: &wl_buffer::WlBuffer) {}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-03 14:10:02 +04:00
|
|
|
impl ShmHandler for State {
|
2023-08-07 19:44:40 +04:00
|
|
|
fn shm_state(&self) -> &ShmState {
|
2023-09-03 14:10:02 +04:00
|
|
|
&self.niri.shm_state
|
2023-08-07 19:44:40 +04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-03 14:10:02 +04:00
|
|
|
delegate_compositor!(State);
|
|
|
|
|
delegate_shm!(State);
|