2022-07-04 15:26:26 +02:00
|
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
|
|
2022-07-04 16:00:29 +02:00
|
|
|
use crate::{state::BackendData, utils::prelude::*};
|
2022-07-04 15:26:26 +02:00
|
|
|
use smithay::{
|
2022-07-07 19:45:04 +02:00
|
|
|
backend::renderer::utils::{on_commit_buffer_handler, with_renderer_surface_state},
|
2022-07-04 16:00:29 +02:00
|
|
|
delegate_compositor,
|
2022-07-05 18:46:38 +02:00
|
|
|
desktop::{layer_map_for_output, Kind, LayerSurface, PopupKind, WindowSurfaceType},
|
2022-07-04 16:00:29 +02:00
|
|
|
reexports::wayland_server::{protocol::wl_surface::WlSurface, DisplayHandle},
|
2022-07-04 15:26:26 +02:00
|
|
|
wayland::{
|
2022-07-04 16:00:29 +02:00
|
|
|
compositor::{with_states, CompositorHandler, CompositorState},
|
2022-07-04 15:26:26 +02:00
|
|
|
shell::{
|
2022-07-04 16:00:29 +02:00
|
|
|
wlr_layer::LayerSurfaceAttributes,
|
2022-07-04 15:26:26 +02:00
|
|
|
xdg::{
|
2022-07-04 16:00:29 +02:00
|
|
|
ToplevelSurface, XdgPopupSurfaceRoleAttributes, XdgToplevelSurfaceRoleAttributes,
|
2022-07-04 15:26:26 +02:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
};
|
2022-07-04 16:00:29 +02:00
|
|
|
use std::sync::Mutex;
|
2022-07-04 15:26:26 +02:00
|
|
|
|
|
|
|
|
impl State {
|
|
|
|
|
fn early_import_surface(&mut self, dh: &DisplayHandle, surface: &WlSurface) {
|
|
|
|
|
let mut import_nodes = std::collections::HashSet::new();
|
|
|
|
|
for output in self.common.shell.outputs_for_surface(&surface) {
|
|
|
|
|
if let BackendData::Kms(ref mut kms_state) = &mut self.backend {
|
|
|
|
|
if let Some(target) = kms_state.target_node_for_output(&output) {
|
|
|
|
|
if import_nodes.insert(target) {
|
2022-07-04 16:00:29 +02:00
|
|
|
kms_state.try_early_import(
|
|
|
|
|
dh,
|
|
|
|
|
surface,
|
|
|
|
|
&output,
|
|
|
|
|
target,
|
|
|
|
|
&self.common.shell,
|
|
|
|
|
);
|
2022-07-04 15:26:26 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-07-04 16:00:29 +02:00
|
|
|
self.backend
|
2022-07-04 15:26:26 +02:00
|
|
|
.schedule_render(&self.common.event_loop_handle, &output);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn toplevel_ensure_initial_configure(&mut self, toplevel: &ToplevelSurface) -> bool {
|
|
|
|
|
// send the initial configure if relevant
|
|
|
|
|
let initial_configure_sent = with_states(toplevel.wl_surface(), |states| {
|
|
|
|
|
states
|
|
|
|
|
.data_map
|
|
|
|
|
.get::<Mutex<XdgToplevelSurfaceRoleAttributes>>()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.lock()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.initial_configure_sent
|
|
|
|
|
});
|
|
|
|
|
if !initial_configure_sent {
|
|
|
|
|
// TODO: query expected size from shell (without inserting and mapping)
|
|
|
|
|
toplevel.with_pending_state(|states| states.size = None);
|
|
|
|
|
toplevel.send_configure();
|
|
|
|
|
}
|
|
|
|
|
initial_configure_sent
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn xdg_popup_ensure_initial_configure(&mut self, popup: &PopupKind) {
|
|
|
|
|
let PopupKind::Xdg(ref popup) = popup;
|
|
|
|
|
let initial_configure_sent = with_states(popup.wl_surface(), |states| {
|
|
|
|
|
states
|
|
|
|
|
.data_map
|
|
|
|
|
.get::<Mutex<XdgPopupSurfaceRoleAttributes>>()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.lock()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.initial_configure_sent
|
|
|
|
|
});
|
|
|
|
|
if !initial_configure_sent {
|
|
|
|
|
// NOTE: This should never fail as the initial configure is always
|
|
|
|
|
// allowed.
|
|
|
|
|
popup.send_configure().expect("initial configure failed");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-05 18:46:38 +02:00
|
|
|
fn layer_surface_ensure_inital_configure(
|
|
|
|
|
&mut self,
|
|
|
|
|
surface: &LayerSurface,
|
|
|
|
|
dh: &DisplayHandle,
|
|
|
|
|
) -> bool {
|
2022-07-04 15:26:26 +02:00
|
|
|
// send the initial configure if relevant
|
|
|
|
|
let initial_configure_sent = with_states(surface.wl_surface(), |states| {
|
|
|
|
|
states
|
|
|
|
|
.data_map
|
|
|
|
|
.get::<Mutex<LayerSurfaceAttributes>>()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.lock()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.initial_configure_sent
|
|
|
|
|
});
|
|
|
|
|
if !initial_configure_sent {
|
2022-07-05 20:43:30 +02:00
|
|
|
// compute initial dimensions by mapping
|
|
|
|
|
self.common.shell.map_layer(&surface, dh);
|
|
|
|
|
// this will also send a configure
|
2022-07-04 15:26:26 +02:00
|
|
|
}
|
|
|
|
|
initial_configure_sent
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl CompositorHandler for State {
|
|
|
|
|
fn compositor_state(&mut self) -> &mut CompositorState {
|
|
|
|
|
&mut self.common.compositor_state
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn commit(&mut self, dh: &DisplayHandle, surface: &WlSurface) {
|
2022-07-18 18:31:50 +02:00
|
|
|
// first load the buffer for various smithay helper functions
|
2022-07-06 23:41:11 +02:00
|
|
|
on_commit_buffer_handler(surface);
|
|
|
|
|
|
2022-07-18 18:31:50 +02:00
|
|
|
// then handle initial configure events and map windows if necessary
|
2022-07-04 16:00:29 +02:00
|
|
|
if let Some((window, seat)) = self
|
|
|
|
|
.common
|
|
|
|
|
.shell
|
|
|
|
|
.pending_windows
|
|
|
|
|
.iter()
|
|
|
|
|
.find(|(window, _)| window.toplevel().wl_surface() == surface)
|
|
|
|
|
.cloned()
|
|
|
|
|
{
|
2022-07-04 15:26:26 +02:00
|
|
|
match window.toplevel() {
|
|
|
|
|
Kind::Xdg(toplevel) => {
|
2022-07-06 23:41:11 +02:00
|
|
|
if self.toplevel_ensure_initial_configure(&toplevel)
|
|
|
|
|
&& with_renderer_surface_state(&surface, |state| {
|
|
|
|
|
state.wl_buffer().is_some()
|
|
|
|
|
})
|
|
|
|
|
{
|
2022-07-04 15:26:26 +02:00
|
|
|
let output = active_output(&seat, &self.common);
|
2022-07-06 23:35:17 +02:00
|
|
|
self.common.shell.map_window(&window, &output, dh);
|
2022-07-04 15:26:26 +02:00
|
|
|
} else {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-04 16:00:29 +02:00
|
|
|
if let Some((layer_surface, _, _)) = self
|
|
|
|
|
.common
|
|
|
|
|
.shell
|
|
|
|
|
.pending_layers
|
|
|
|
|
.iter()
|
|
|
|
|
.find(|(layer_surface, _, _)| layer_surface.wl_surface() == surface)
|
|
|
|
|
.cloned()
|
|
|
|
|
{
|
2022-07-05 20:43:30 +02:00
|
|
|
if !self.layer_surface_ensure_inital_configure(&layer_surface, dh) {
|
2022-07-04 15:26:26 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if let Some(popup) = self.common.shell.popups.find_popup(surface) {
|
|
|
|
|
self.xdg_popup_ensure_initial_configure(&popup);
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-18 18:31:50 +02:00
|
|
|
// at last handle some special cases, like grabs and changing layer surfaces
|
|
|
|
|
|
2022-07-04 15:26:26 +02:00
|
|
|
// If we would re-position the window inside the grab we would get a weird jittery animation.
|
|
|
|
|
// We only want to resize once the client has acknoledged & commited the new size,
|
|
|
|
|
// so we need to carefully track the state through different handlers.
|
|
|
|
|
if let Some((space, window)) =
|
|
|
|
|
self.common
|
|
|
|
|
.shell
|
2022-07-11 22:39:56 +02:00
|
|
|
.space_for_window_mut(surface)
|
2022-07-04 15:26:26 +02:00
|
|
|
.and_then(|workspace| {
|
|
|
|
|
workspace
|
|
|
|
|
.space
|
|
|
|
|
.window_for_surface(surface, WindowSurfaceType::TOPLEVEL)
|
|
|
|
|
.cloned()
|
|
|
|
|
.map(|window| (&mut workspace.space, window))
|
|
|
|
|
})
|
|
|
|
|
{
|
2022-07-04 16:00:29 +02:00
|
|
|
let new_location =
|
|
|
|
|
crate::shell::layout::floating::ResizeSurfaceGrab::apply_resize_state(
|
|
|
|
|
&window,
|
|
|
|
|
space.window_location(&window).unwrap(),
|
|
|
|
|
window.geometry().size,
|
|
|
|
|
);
|
2022-07-04 15:26:26 +02:00
|
|
|
if let Some(location) = new_location {
|
2022-07-07 19:45:04 +02:00
|
|
|
space.map_window(
|
|
|
|
|
&window,
|
|
|
|
|
location,
|
|
|
|
|
crate::shell::layout::floating::FLOATING_INDEX,
|
|
|
|
|
true,
|
|
|
|
|
);
|
2022-07-05 18:46:38 +02:00
|
|
|
for window in space.windows() {
|
|
|
|
|
update_reactive_popups(space, window);
|
|
|
|
|
}
|
2022-07-04 15:26:26 +02:00
|
|
|
}
|
|
|
|
|
}
|
2022-07-04 16:00:29 +02:00
|
|
|
|
2022-07-18 18:31:50 +02:00
|
|
|
// We need to know every potential output for importing to the right gpu and scheduling a render,
|
|
|
|
|
// so call this only after every potential surface map operation has been done.
|
|
|
|
|
self.early_import_surface(dh, surface);
|
|
|
|
|
|
|
|
|
|
// and refresh smithays internal state
|
|
|
|
|
self.common.shell.popups.commit(surface);
|
|
|
|
|
for workspace in &self.common.shell.spaces {
|
|
|
|
|
workspace.space.commit(surface);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// re-arrange layer-surfaces (commits may change size and positioning)
|
2022-07-05 20:43:30 +02:00
|
|
|
if let Some(output) = self.common.shell.outputs().find(|o| {
|
|
|
|
|
let map = layer_map_for_output(o);
|
2022-07-05 18:46:38 +02:00
|
|
|
map.layer_for_surface(surface, WindowSurfaceType::ALL)
|
|
|
|
|
.is_some()
|
2022-07-05 20:43:30 +02:00
|
|
|
}) {
|
|
|
|
|
layer_map_for_output(output).arrange(dh);
|
|
|
|
|
}
|
2022-07-04 15:26:26 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delegate_compositor!(State);
|