state: Move shell behind RwLock

This commit is contained in:
Victoria Brekenfeld 2024-04-10 15:49:08 +02:00 • committed by Victoria Brekenfeld
parent 647deb81f1
commit 5d5a510691
45 changed files with 2657 additions and 2097 deletions

View file

@ -26,66 +26,57 @@ use smithay::{
};
use std::sync::Mutex;
impl State {
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| {
fn toplevel_ensure_initial_configure(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(popup: &PopupKind) {
if let PopupKind::Xdg(ref popup) = popup {
let initial_configure_sent = with_states(popup.wl_surface(), |states| {
states
.data_map
.get::<Mutex<XdgToplevelSurfaceRoleAttributes>>()
.get::<Mutex<XdgPopupSurfaceRoleAttributes>>()
.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();
// NOTE: This should never fail as the initial configure is always
// allowed.
popup.send_configure().expect("initial configure failed");
}
initial_configure_sent
}
}
fn xdg_popup_ensure_initial_configure(&mut self, popup: &PopupKind) {
if 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");
}
}
}
fn layer_surface_check_inital_configure(surface: &LayerSurface) -> bool {
// 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
});
fn layer_surface_ensure_inital_configure(&mut self, surface: &LayerSurface) -> bool {
// 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 {
// compute initial dimensions by mapping
if let Some(target) = self.common.shell.map_layer(&surface) {
let seat = self.common.shell.seats.last_active().clone();
Shell::set_focus(self, Some(&target), &seat, None);
}
surface.layer_surface().send_configure();
}
initial_configure_sent
}
initial_configure_sent
}
pub fn client_compositor_state<'a>(client: &'a Client) -> &'a CompositorClientState {
@ -147,48 +138,67 @@ impl CompositorHandler for State {
// first load the buffer for various smithay helper functions (which also initializes the RendererSurfaceState)
on_commit_buffer_handler::<Self>(surface);
// and refresh smithays internal state
self.common.on_commit(surface);
let mut shell = self.common.shell.write().unwrap();
// schedule a new render
if let Some(output) = shell.visible_output_for_surface(surface) {
self.backend
.schedule_render(&self.common.event_loop_handle, &output);
}
// handle initial configure events and map windows if necessary
if let Some((window, _, _)) = self
.common
.shell
if let Some((window, _, _)) = shell
.pending_windows
.iter()
.find(|(window, _, _)| window.wl_surface().as_ref() == Some(surface))
.cloned()
{
if let Some(toplevel) = window.0.toplevel() {
if self.toplevel_ensure_initial_configure(&toplevel)
if toplevel_ensure_initial_configure(&toplevel)
&& with_renderer_surface_state(&surface, |state| state.buffer().is_some())
.unwrap_or(false)
{
window.on_commit();
if let Some(target) = self.common.shell.map_window(
let res = shell.map_window(
&window,
&mut self.common.toplevel_info_state,
&mut self.common.workspace_state,
&self.common.event_loop_handle,
&self.common.theme,
) {
let seat = self.common.shell.seats.last_active().clone();
);
if let Some(target) = res {
let seat = shell.seats.last_active().clone();
std::mem::drop(shell);
Shell::set_focus(self, Some(&target), &seat, None);
return;
}
}
}
}
if let Some((layer_surface, _, _)) = self
.common
.shell
if let Some((layer_surface, _, _)) = shell
.pending_layers
.iter()
.find(|(layer_surface, _, _)| layer_surface.wl_surface() == surface)
.cloned()
{
if !self.layer_surface_ensure_inital_configure(&layer_surface) {
if !layer_surface_check_inital_configure(&layer_surface) {
// compute initial dimensions by mapping
if let Some(target) = shell.map_layer(&layer_surface) {
let seat = shell.seats.last_active().clone();
std::mem::drop(shell);
Shell::set_focus(self, Some(&target), &seat, None);
}
layer_surface.layer_surface().send_configure();
return;
}
};
if let Some(popup) = self.common.shell.popups.find_popup(surface) {
self.xdg_popup_ensure_initial_configure(&popup);
if let Some(popup) = self.common.popups.find_popup(surface) {
xdg_popup_ensure_initial_configure(&popup);
return;
}
if with_renderer_surface_state(surface, |state| state.buffer().is_none()).unwrap_or(false) {
@ -197,7 +207,7 @@ impl CompositorHandler for State {
// session-lock disallows null commits
// if it was a move-grab?
let seat = self.common.shell.seats.last_active().clone();
let seat = shell.seats.last_active().clone();
let moved_window = seat
.user_data()
.get::<SeatMoveGrabState>()
@ -228,9 +238,11 @@ impl CompositorHandler for State {
stack.remove_idx(i);
}
} else {
std::mem::drop(shell);
seat.get_pointer()
.unwrap()
.unset_grab(self, SERIAL_COUNTER.next_serial(), 0);
return;
}
}
@ -247,21 +259,16 @@ impl CompositorHandler for State {
// 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(element) = self.common.shell.element_for_surface(surface).cloned() {
if let Some(element) = shell.element_for_surface(surface).cloned() {
crate::shell::layout::floating::ResizeSurfaceGrab::apply_resize_to_location(
element.clone(),
&mut self.common.shell,
&mut *shell,
);
}
}
// and refresh smithays internal state
self.common.shell.on_commit(surface);
// re-arrange layer-surfaces (commits may change size and positioning)
let layer_output = self
.common
.shell
let layer_output = shell
.outputs()
.find(|o| {
let map = layer_map_for_output(o);
@ -269,18 +276,13 @@ impl CompositorHandler for State {
.is_some()
})
.cloned();
if let Some(output) = layer_output {
let changed = layer_map_for_output(&output).arrange();
if changed {
self.common.shell.workspaces.recalculate();
shell.workspaces.recalculate();
}
}
// schedule a new render
if let Some(output) = self.common.shell.visible_output_for_surface(surface) {
self.backend
.schedule_render(&self.common.event_loop_handle, &output);
}
}
}

View file

@ -54,86 +54,85 @@ impl PreferredDecorationMode {
}
}
impl State {
pub fn new_decoration(mapped: &CosmicMapped, surface: &WlSurface) -> KdeMode {
if mapped.is_stack() {
if let Some((window, _)) = mapped
.windows()
.find(|(window, _)| window.wl_surface().as_ref() == Some(surface))
{
if let Some(toplevel) = window.0.toplevel() {
toplevel.with_pending_state(|state| {
state.decoration_mode = Some(XdgMode::ServerSide)
});
toplevel.send_configure();
}
}
KdeMode::Server
} else {
if let Some((window, _)) = mapped
.windows()
.find(|(window, _)| window.wl_surface().as_ref() == Some(surface))
{
if let Some(toplevel) = window.0.toplevel() {
toplevel.with_pending_state(|state| {
state.decoration_mode = Some(XdgMode::ClientSide)
});
toplevel.send_configure();
}
}
KdeMode::Client
}
}
pub fn request_mode(mapped: &CosmicMapped, surface: &WlSurface, mode: XdgMode) {
pub fn new_decoration(mapped: &CosmicMapped, surface: &WlSurface) -> KdeMode {
if mapped.is_stack() {
if let Some((window, _)) = mapped
.windows()
.find(|(window, _)| window.wl_surface().as_ref() == Some(surface))
{
if let Some(toplevel) = window.0.toplevel() {
PreferredDecorationMode::update(&window.0, Some(mode));
toplevel.with_pending_state(|state| {
state.decoration_mode = Some(mode);
});
toplevel
.with_pending_state(|state| state.decoration_mode = Some(XdgMode::ServerSide));
toplevel.send_configure();
}
}
}
pub fn unset_mode(mapped: &CosmicMapped, surface: &WlSurface) {
KdeMode::Server
} else {
if let Some((window, _)) = mapped
.windows()
.find(|(window, _)| window.wl_surface().as_ref() == Some(surface))
{
if let Some(toplevel) = window.0.toplevel() {
PreferredDecorationMode::update(&window.0, None);
toplevel.with_pending_state(|state| {
state.decoration_mode = None;
});
toplevel
.with_pending_state(|state| state.decoration_mode = Some(XdgMode::ClientSide));
toplevel.send_configure();
}
}
KdeMode::Client
}
}
pub fn request_mode(mapped: &CosmicMapped, surface: &WlSurface, mode: XdgMode) {
if let Some((window, _)) = mapped
.windows()
.find(|(window, _)| window.wl_surface().as_ref() == Some(surface))
{
if let Some(toplevel) = window.0.toplevel() {
PreferredDecorationMode::update(&window.0, Some(mode));
toplevel.with_pending_state(|state| {
state.decoration_mode = Some(mode);
});
toplevel.send_configure();
}
}
}
pub fn unset_mode(mapped: &CosmicMapped, surface: &WlSurface) {
if let Some((window, _)) = mapped
.windows()
.find(|(window, _)| window.wl_surface().as_ref() == Some(surface))
{
if let Some(toplevel) = window.0.toplevel() {
PreferredDecorationMode::update(&window.0, None);
toplevel.with_pending_state(|state| {
state.decoration_mode = None;
});
toplevel.send_configure();
}
}
}
impl XdgDecorationHandler for State {
fn new_decoration(&mut self, toplevel: ToplevelSurface) {
if let Some(mapped) = self.common.shell.element_for_surface(toplevel.wl_surface()) {
State::new_decoration(mapped, toplevel.wl_surface());
let shell = self.common.shell.read().unwrap();
if let Some(mapped) = shell.element_for_surface(toplevel.wl_surface()) {
new_decoration(mapped, toplevel.wl_surface());
}
}
fn request_mode(&mut self, toplevel: ToplevelSurface, mode: XdgMode) {
if let Some(mapped) = self.common.shell.element_for_surface(toplevel.wl_surface()) {
State::request_mode(mapped, toplevel.wl_surface(), mode);
let shell = self.common.shell.read().unwrap();
if let Some(mapped) = shell.element_for_surface(toplevel.wl_surface()) {
request_mode(mapped, toplevel.wl_surface(), mode);
} else {
toplevel.with_pending_state(|state| state.decoration_mode = Some(mode));
}
}
fn unset_mode(&mut self, toplevel: ToplevelSurface) {
if let Some(mapped) = self.common.shell.element_for_surface(toplevel.wl_surface()) {
State::unset_mode(mapped, toplevel.wl_surface())
let shell = self.common.shell.read().unwrap();
if let Some(mapped) = shell.element_for_surface(toplevel.wl_surface()) {
unset_mode(mapped, toplevel.wl_surface())
}
}
}
@ -144,8 +143,9 @@ impl KdeDecorationHandler for State {
}
fn new_decoration(&mut self, surface: &WlSurface, decoration: &OrgKdeKwinServerDecoration) {
if let Some(mapped) = self.common.shell.element_for_surface(surface) {
let mode = State::new_decoration(mapped, surface);
let shell = self.common.shell.read().unwrap();
if let Some(mapped) = shell.element_for_surface(surface) {
let mode = new_decoration(mapped, surface);
decoration.mode(mode);
}
}
@ -157,9 +157,10 @@ impl KdeDecorationHandler for State {
mode: WEnum<KdeMode>,
) {
if let WEnum::Value(mode) = mode {
let shell = self.common.shell.read().unwrap();
// TODO: We need to store this value until it gets mapped and apply it then, if it is not mapped yet.
if let Some(mapped) = self.common.shell.element_for_surface(surface) {
State::request_mode(
if let Some(mapped) = shell.element_for_surface(surface) {
request_mode(
mapped,
surface,
match mode {
@ -173,8 +174,9 @@ impl KdeDecorationHandler for State {
}
fn release(&mut self, _decoration: &OrgKdeKwinServerDecoration, surface: &WlSurface) {
if let Some(mapped) = self.common.shell.element_for_surface(surface) {
State::unset_mode(mapped, surface)
let shell = self.common.shell.read().unwrap();
if let Some(mapped) = shell.element_for_surface(surface) {
unset_mode(mapped, surface)
}
}
}

View file

@ -41,11 +41,21 @@ impl FractionalScaleHandler for State {
.or_else(|| {
self.common
.shell
.read()
.unwrap()
.visible_output_for_surface(&surface)
.cloned()
})
})
.unwrap_or_else(|| self.common.shell.seats.last_active().active_output());
.unwrap_or_else(|| {
self.common
.shell
.read()
.unwrap()
.seats
.last_active()
.active_output()
});
with_states(&surface, |states| {
with_fractional_scale(states, |fractional_scale| {

View file

@ -12,12 +12,7 @@ use tracing::warn;
impl InputMethodHandler for State {
fn new_popup(&mut self, surface: PopupSurface) {
if let Err(err) = self
.common
.shell
.popups
.track_popup(PopupKind::from(surface))
{
if let Err(err) = self.common.popups.track_popup(PopupKind::from(surface)) {
warn!("Failed to track popup: {}", err);
}
}
@ -31,6 +26,8 @@ impl InputMethodHandler for State {
fn parent_geometry(&self, parent: &WlSurface) -> Rectangle<i32, smithay::utils::Logical> {
self.common
.shell
.read()
.unwrap()
.element_for_surface(parent)
.map(|e| e.geometry())
.unwrap_or_default()

View file

@ -16,7 +16,7 @@ use smithay::{
impl WlrLayerShellHandler for State {
fn shell_state(&mut self) -> &mut WlrLayerShellState {
&mut self.common.shell.layer_shell_state
&mut self.common.layer_shell_state
}
fn new_layer_surface(
@ -26,24 +26,22 @@ impl WlrLayerShellHandler for State {
_layer: Layer,
namespace: String,
) {
let seat = self.common.shell.seats.last_active().clone();
let mut shell = self.common.shell.write().unwrap();
let seat = shell.seats.last_active().clone();
let output = wl_output
.as_ref()
.and_then(Output::from_resource)
.unwrap_or_else(|| seat.active_output());
self.common.shell.pending_layers.push((
LayerSurface::new(surface, namespace),
output,
seat,
));
shell
.pending_layers
.push((LayerSurface::new(surface, namespace), output, seat));
}
fn new_popup(&mut self, _parent: WlrLayerSurface, popup: PopupSurface) {
self.common.shell.unconstrain_popup(&popup);
self.common.shell.read().unwrap().unconstrain_popup(&popup);
if popup.send_configure().is_ok() {
self.common
.shell
.popups
.track_popup(PopupKind::from(popup))
.unwrap();
@ -51,9 +49,8 @@ impl WlrLayerShellHandler for State {
}
fn layer_destroyed(&mut self, surface: WlrLayerSurface) {
let maybe_output = self
.common
.shell
let mut shell = self.common.shell.write().unwrap();
let maybe_output = shell
.outputs()
.find(|o| {
let map = layer_map_for_output(o);
@ -72,7 +69,7 @@ impl WlrLayerShellHandler for State {
map.unmap_layer(&layer);
}
self.common.shell.workspaces.recalculate();
shell.workspaces.recalculate();
self.backend
.schedule_render(&self.common.event_loop_handle, &output);

View file

@ -82,12 +82,16 @@ impl State {
}
}
if let Err(err) = self.backend.apply_config_for_output(
let mut shell = self.common.shell.write().unwrap();
let res = self.backend.apply_config_for_output(
output,
test_only,
&mut self.common.shell,
&mut *shell,
&self.common.event_loop_handle,
) {
&mut self.common.workspace_state.update(),
&self.common.xdg_activation_state,
);
if let Err(err) = res {
warn!(
?err,
"Failed to apply config to {}. Resetting",
@ -106,8 +110,10 @@ impl State {
if let Err(err) = self.backend.apply_config_for_output(
output,
false,
&mut self.common.shell,
&mut *shell,
&self.common.event_loop_handle,
&mut self.common.workspace_state.update(),
&self.common.xdg_activation_state,
) {
error!(?err, "Failed to reset output config for {}.", output.name(),);
}
@ -115,6 +121,9 @@ impl State {
}
return false;
}
std::mem::drop(shell);
self.common.refresh();
}
for output in conf

View file

@ -52,8 +52,9 @@ impl ScreencopyHandler for State {
.upgrade()
.and_then(|output| constraints_for_output(&output, &mut self.backend)),
ImageSourceData::Workspace(handle) => {
let workspace = self.common.shell.workspaces.space_for_handle(&handle)?;
constraints_for_output(workspace.output(), &mut self.backend)
let shell = self.common.shell.read().unwrap();
let output = shell.workspaces.space_for_handle(&handle)?.output();
constraints_for_output(output, &mut self.backend)
}
ImageSourceData::Toplevel(window) => {
constraints_for_toplevel(window, &mut self.backend)
@ -65,6 +66,8 @@ impl ScreencopyHandler for State {
let size = if let Some((geometry, _)) = self
.common
.shell
.read()
.unwrap()
.seats
.last_active()
.cursor_geometry((0.0, 0.0), self.common.clock.now())
@ -98,8 +101,8 @@ impl ScreencopyHandler for State {
output.add_session(session);
}
ImageSourceData::Workspace(handle) => {
let Some(workspace) = self.common.shell.workspaces.space_for_handle_mut(&handle)
else {
let mut shell = self.common.shell.write().unwrap();
let Some(workspace) = shell.workspaces.space_for_handle_mut(&handle) else {
session.stop();
return;
};
@ -127,7 +130,14 @@ impl ScreencopyHandler for State {
}
fn new_cursor_session(&mut self, session: CursorSession) {
let (pointer_loc, pointer_size, hotspot) = {
let seat = self.common.shell.seats.last_active();
let seat = self
.common
.shell
.read()
.unwrap()
.seats
.last_active()
.clone();
let pointer = seat.get_pointer().unwrap();
let pointer_loc = pointer.current_location().to_i32_round().as_global();
@ -183,8 +193,8 @@ impl ScreencopyHandler for State {
output.add_cursor_session(session);
}
ImageSourceData::Workspace(handle) => {
let Some(workspace) = self.common.shell.workspaces.space_for_handle_mut(&handle)
else {
let mut shell = self.common.shell.write().unwrap();
let Some(workspace) = shell.workspaces.space_for_handle_mut(&handle) else {
session.stop();
return;
};
@ -215,9 +225,10 @@ impl ScreencopyHandler for State {
workspace.add_cursor_session(session);
}
ImageSourceData::Toplevel(mut toplevel) => {
if let Some(element) = self.common.shell.element_for_surface(&toplevel) {
let shell = self.common.shell.read().unwrap();
if let Some(element) = shell.element_for_surface(&toplevel) {
if element.has_active_window(&toplevel) {
if let Some(workspace) = self.common.shell.space_for(element) {
if let Some(workspace) = shell.space_for(element) {
if let Some(geometry) = workspace.element_geometry(element) {
let mut surface_geo = element.active_window_geometry().as_local();
surface_geo.loc += geometry.loc;
@ -268,12 +279,20 @@ impl ScreencopyHandler for State {
return;
}
let seat = self.common.shell.seats.last_active().clone();
let seat = self
.common
.shell
.read()
.unwrap()
.seats
.last_active()
.clone();
render_cursor_to_buffer(self, &session, frame, &seat);
}
fn frame_aborted(&mut self, frame: Frame) {
for mut output in self.common.shell.outputs().cloned() {
let shell = self.common.shell.read().unwrap();
for mut output in shell.outputs().cloned() {
output.remove_frame(&frame)
}
}
@ -286,7 +305,13 @@ impl ScreencopyHandler for State {
}
}
ImageSourceData::Workspace(handle) => {
if let Some(workspace) = self.common.shell.workspaces.space_for_handle_mut(&handle)
if let Some(workspace) = self
.common
.shell
.write()
.unwrap()
.workspaces
.space_for_handle_mut(&handle)
{
workspace.remove_session(session)
}
@ -304,7 +329,13 @@ impl ScreencopyHandler for State {
}
}
ImageSourceData::Workspace(handle) => {
if let Some(workspace) = self.common.shell.workspaces.space_for_handle_mut(&handle)
if let Some(workspace) = self
.common
.shell
.write()
.unwrap()
.workspaces
.space_for_handle_mut(&handle)
{
workspace.remove_cursor_session(session)
}

View file

@ -189,18 +189,16 @@ pub fn render_workspace_to_buffer(
#[cfg(feature = "debug")]
puffin::profile_function!();
let Some(workspace) = state.common.shell.workspaces.space_for_handle(&handle) else {
let shell = state.common.shell.read().unwrap();
let Some(workspace) = shell.workspaces.space_for_handle(&handle) else {
session.stop();
return;
};
let output = workspace.output().clone();
let idx = state
.common
.shell
.workspaces
.idx_for_handle(&output, &handle)
.unwrap();
let idx = shell.workspaces.idx_for_handle(&output, &handle).unwrap();
std::mem::drop(shell);
let mode = output
.current_mode()
.map(|mode| mode.size.to_logical(1).to_buffer(1, Transform::Normal));
@ -286,7 +284,7 @@ pub fn render_workspace_to_buffer(
dt,
age,
additional_damage,
&common.shell,
&*common.shell.read().unwrap(),
&common.config,
&common.theme,
common.clock.now(),
@ -314,7 +312,7 @@ pub fn render_workspace_to_buffer(
dt,
age,
additional_damage,
&common.shell,
&*common.shell.read().unwrap(),
&common.config,
&common.theme,
common.clock.now(),
@ -535,21 +533,23 @@ pub fn render_window_to_buffer(
.map(Into::<WindowCaptureElement<R>>::into),
);
let seat = common.shell.seats.last_active().clone();
if let Some(location) = {
if let Some(mapped) = common.shell.element_for_surface(window) {
mapped.cursor_position(&seat).and_then(|mut p| {
p -= mapped.active_window_offset().to_f64();
if p.x < 0. || p.y < 0. {
None
} else {
Some(p)
}
})
} else {
None
}
} {
let shell = common.shell.read().unwrap();
let seat = shell.seats.last_active().clone();
let location = if let Some(mapped) = shell.element_for_surface(window) {
mapped.cursor_position(&seat).and_then(|mut p| {
p -= mapped.active_window_offset().to_f64();
if p.x < 0. || p.y < 0. {
None
} else {
Some(p)
}
})
} else {
None
};
std::mem::drop(shell);
if let Some(location) = location {
if draw_cursor {
elements.extend(
cursor::draw_cursor(

View file

@ -20,7 +20,6 @@ impl SelectionHandler for State {
) {
if let Some(xwm) = self
.common
.shell
.xwayland_state
.as_mut()
.and_then(|xstate| xstate.xwm.as_mut())
@ -45,7 +44,6 @@ impl SelectionHandler for State {
) {
if let Some(xwm) = self
.common
.shell
.xwayland_state
.as_mut()
.and_then(|xstate| xstate.xwm.as_mut())

View file

@ -18,8 +18,10 @@ impl SessionLockHandler for State {
}
fn lock(&mut self, locker: SessionLocker) {
let mut shell = self.common.shell.write().unwrap();
// Reject lock if sesion lock exists and is still valid
if let Some(session_lock) = self.common.shell.session_lock.as_ref() {
if let Some(session_lock) = shell.session_lock.as_ref() {
if self
.common
.display_handle
@ -32,28 +34,30 @@ impl SessionLockHandler for State {
let ext_session_lock = locker.ext_session_lock().clone();
locker.lock();
self.common.shell.session_lock = Some(SessionLock {
shell.session_lock = Some(SessionLock {
ext_session_lock,
surfaces: HashMap::new(),
});
for output in self.common.shell.outputs() {
for output in shell.outputs() {
self.backend
.schedule_render(&self.common.event_loop_handle, &output);
}
}
fn unlock(&mut self) {
self.common.shell.session_lock = None;
let mut shell = self.common.shell.write().unwrap();
shell.session_lock = None;
for output in self.common.shell.outputs() {
for output in shell.outputs() {
self.backend
.schedule_render(&self.common.event_loop_handle, &output);
}
}
fn new_surface(&mut self, lock_surface: LockSurface, wl_output: WlOutput) {
if let Some(session_lock) = &mut self.common.shell.session_lock {
let mut shell = self.common.shell.write().unwrap();
if let Some(session_lock) = &mut shell.session_lock {
if let Some(output) = Output::from_resource(&wl_output) {
lock_surface.with_pending_state(|states| {
let size = output.geometry().size;

View file

@ -14,10 +14,10 @@ impl ToplevelInfoHandler for State {
type Window = CosmicSurface;
fn toplevel_info_state(&self) -> &ToplevelInfoState<State, Self::Window> {
&self.common.shell.toplevel_info_state
&self.common.toplevel_info_state
}
fn toplevel_info_state_mut(&mut self) -> &mut ToplevelInfoState<State, Self::Window> {
&mut self.common.shell.toplevel_info_state
&mut self.common.toplevel_info_state
}
}

View file

@ -15,15 +15,15 @@ use crate::{
wayland::protocols::{
toplevel_info::ToplevelInfoHandler,
toplevel_management::{
delegate_toplevel_management, ManagementWindow, ToplevelManagementHandler,
ToplevelManagementState,
delegate_toplevel_management, toplevel_rectangle_for, ManagementWindow,
ToplevelManagementHandler, ToplevelManagementState,
},
},
};
impl ToplevelManagementHandler for State {
fn toplevel_management_state(&mut self) -> &mut ToplevelManagementState {
&mut self.common.shell.toplevel_management_state
&mut self.common.toplevel_management_state
}
fn activate(
@ -33,17 +33,10 @@ impl ToplevelManagementHandler for State {
seat: Option<Seat<Self>>,
) {
self.unminimize(dh, window);
for output in self
.common
.shell
.outputs()
.cloned()
.collect::<Vec<_>>()
.iter()
{
let maybe = self
.common
.shell
let mut shell = self.common.shell.write().unwrap();
for output in shell.outputs().cloned().collect::<Vec<_>>().iter() {
let maybe = shell
.workspaces
.spaces_for_output(output)
.enumerate()
@ -53,19 +46,22 @@ impl ToplevelManagementHandler for State {
.any(|w| &w == window)
});
if let Some((idx, workspace)) = maybe {
let seat = seat.unwrap_or(self.common.shell.seats.last_active().clone());
let seat = seat.unwrap_or(shell.seats.last_active().clone());
let mapped = workspace
.mapped()
.find(|m| m.windows().any(|(w, _)| &w == window))
.unwrap()
.clone();
let _ = self.common.shell.activate(
let _ = shell.activate(
&output,
idx as usize,
WorkspaceDelta::new_shortcut(),
&mut self.common.workspace_state.update(),
); // TODO: Move pointer?
mapped.focus_window(window);
std::mem::drop(shell);
Shell::set_focus(self, Some(&mapped.clone().into()), &seat, None);
return;
}
@ -83,16 +79,12 @@ impl ToplevelManagementHandler for State {
workspace: ZcosmicWorkspaceHandleV1,
_output: Output,
) {
let Some(to_handle) = self
.common
.shell
.workspace_state
.get_workspace_handle(&workspace)
else {
let Some(to_handle) = self.common.workspace_state.get_workspace_handle(&workspace) else {
return;
};
let from_workspace = self.common.shell.workspaces.spaces().find(|w| {
let mut shell = self.common.shell.write().unwrap();
let from_workspace = shell.workspaces.spaces().find(|w| {
w.mapped()
.flat_map(|m| m.windows().map(|(s, _)| s))
.any(|w| &w == window)
@ -104,15 +96,18 @@ impl ToplevelManagementHandler for State {
.unwrap()
.clone();
let from_handle = from_workspace.handle;
let seat = self.common.shell.seats.last_active().clone();
if let Some((target, _)) = self.common.shell.move_window(
let seat = shell.seats.last_active().clone();
let res = shell.move_window(
Some(&seat),
&mapped,
&from_handle,
&to_handle,
false,
None,
) {
&mut self.common.workspace_state.update(),
);
if let Some((target, _)) = res {
std::mem::drop(shell);
Shell::set_focus(self, Some(&target), &seat, None);
}
return;
@ -125,29 +120,19 @@ impl ToplevelManagementHandler for State {
window: &<Self as ToplevelInfoHandler>::Window,
output: Option<Output>,
) {
let seat = self.common.shell.seats.last_active().clone();
if let Some(mapped) = self.common.shell.element_for_surface(window).cloned() {
let mut shell = self.common.shell.write().unwrap();
let seat = shell.seats.last_active().clone();
if let Some(mapped) = shell.element_for_surface(window).cloned() {
if let Some(output) = output {
let from = self
.common
.shell
.toplevel_management_state
.minimize_rectangle(&output, window);
let workspace = self.common.shell.workspaces.active_mut(&output);
let from = minimize_rectangle(&output, window);
let workspace = shell.workspaces.active_mut(&output);
workspace.fullscreen_request(window, None, from, &seat);
} else if let Some((output, handle)) = self
.common
.shell
} else if let Some((output, handle)) = shell
.space_for(&mapped)
.map(|workspace| (workspace.output.clone(), workspace.handle.clone()))
{
let from = self
.common
.shell
.toplevel_management_state
.minimize_rectangle(&output, window);
self.common
.shell
let from = minimize_rectangle(&output, window);
shell
.workspaces
.space_for_handle_mut(&handle)
.unwrap()
@ -161,20 +146,19 @@ impl ToplevelManagementHandler for State {
_dh: &DisplayHandle,
window: &<Self as ToplevelInfoHandler>::Window,
) {
if let Some(mapped) = self.common.shell.element_for_surface(window).cloned() {
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
let mut shell = self.common.shell.write().unwrap();
if let Some(mapped) = shell.element_for_surface(window).cloned() {
if let Some(workspace) = shell.space_for_mut(&mapped) {
if let Some((layer, previous_workspace)) = workspace.unfullscreen_request(window) {
let old_handle = workspace.handle.clone();
let new_workspace_handle = self
.common
.shell
let new_workspace_handle = shell
.workspaces
.space_for_handle(&previous_workspace)
.is_some()
.then_some(previous_workspace)
.unwrap_or(old_handle); // if the workspace doesn't exist anymore, we can still remap on the right layer
self.common.shell.remap_unfullscreened_window(
shell.remap_unfullscreened_window(
mapped,
&old_handle,
&new_workspace_handle,
@ -186,30 +170,34 @@ impl ToplevelManagementHandler for State {
}
fn maximize(&mut self, _dh: &DisplayHandle, window: &<Self as ToplevelInfoHandler>::Window) {
if let Some(mapped) = self.common.shell.element_for_surface(window).cloned() {
let seat = self.common.shell.seats.last_active().clone();
self.common.shell.maximize_request(&mapped, &seat);
let mut shell = self.common.shell.write().unwrap();
if let Some(mapped) = shell.element_for_surface(window).cloned() {
let seat = shell.seats.last_active().clone();
shell.maximize_request(&mapped, &seat);
}
}
fn unmaximize(&mut self, _dh: &DisplayHandle, window: &<Self as ToplevelInfoHandler>::Window) {
if let Some(mapped) = self.common.shell.element_for_surface(window).cloned() {
self.common.shell.unmaximize_request(&mapped);
let mut shell = self.common.shell.write().unwrap();
if let Some(mapped) = shell.element_for_surface(window).cloned() {
shell.unmaximize_request(&mapped);
}
}
fn minimize(&mut self, _dh: &DisplayHandle, window: &<Self as ToplevelInfoHandler>::Window) {
if let Some(mapped) = self.common.shell.element_for_surface(window).cloned() {
let mut shell = self.common.shell.write().unwrap();
if let Some(mapped) = shell.element_for_surface(window).cloned() {
if !mapped.is_stack() || &mapped.active_window() == window {
self.common.shell.minimize_request(&mapped);
shell.minimize_request(&mapped);
}
}
}
fn unminimize(&mut self, _dh: &DisplayHandle, window: &<Self as ToplevelInfoHandler>::Window) {
if let Some(mut mapped) = self.common.shell.element_for_surface(window).cloned() {
let seat = self.common.shell.seats.last_active().clone();
self.common.shell.unminimize_request(&mapped, &seat);
let mut shell = self.common.shell.write().unwrap();
if let Some(mut mapped) = shell.element_for_surface(window).cloned() {
let seat = shell.seats.last_active().clone();
shell.unminimize_request(&mapped, &seat);
if mapped.is_stack() {
mapped.stack_ref_mut().unwrap().set_active(window);
}
@ -223,43 +211,29 @@ impl ManagementWindow for CosmicSurface {
}
}
pub trait ToplevelManagementExt {
fn minimize_rectangle(
&mut self,
output: &Output,
window: &CosmicSurface,
) -> Rectangle<i32, Local>;
}
impl ToplevelManagementExt for ToplevelManagementState {
fn minimize_rectangle(
&mut self,
output: &Output,
window: &CosmicSurface,
) -> Rectangle<i32, Local> {
self.rectangle_for(window)
.find_map(|(surface, relative)| {
let map = layer_map_for_output(output);
let layer = map.layer_for_surface(&surface, WindowSurfaceType::ALL);
layer.and_then(|s| map.layer_geometry(s)).map(|local| {
Rectangle::from_loc_and_size(
Point::from((local.loc.x + relative.loc.x, local.loc.y + relative.loc.y)),
relative.size,
)
})
})
.unwrap_or_else(|| {
let output_size = output.geometry().size;
pub fn minimize_rectangle(output: &Output, window: &CosmicSurface) -> Rectangle<i32, Local> {
toplevel_rectangle_for(window)
.find_map(|(surface, relative)| {
let map = layer_map_for_output(output);
let layer = map.layer_for_surface(&surface, WindowSurfaceType::ALL);
layer.and_then(|s| map.layer_geometry(s)).map(|local| {
Rectangle::from_loc_and_size(
Point::from((
(output_size.w / 2) - 100,
output_size.h - (output_size.h / 3) - 50,
)),
Size::from((200, 100)),
Point::from((local.loc.x + relative.loc.x, local.loc.y + relative.loc.y)),
relative.size,
)
})
.as_local()
}
})
.unwrap_or_else(|| {
let output_size = output.geometry().size;
Rectangle::from_loc_and_size(
Point::from((
(output_size.w / 2) - 100,
output_size.h - (output_size.h / 3) - 50,
)),
Size::from((200, 100)),
)
})
.as_local()
}
delegate_toplevel_management!(State);

View file

@ -21,17 +21,18 @@ impl WorkspaceClientHandler for ClientState {
impl WorkspaceHandler for State {
type Client = ClientState;
fn workspace_state(&self) -> &WorkspaceState<Self> {
&self.common.shell.workspace_state
&self.common.workspace_state
}
fn workspace_state_mut(&mut self) -> &mut WorkspaceState<Self> {
&mut self.common.shell.workspace_state
&mut self.common.workspace_state
}
fn commit_requests(&mut self, _dh: &DisplayHandle, requests: Vec<Request>) {
for request in requests.into_iter() {
match request {
Request::Activate(handle) => {
let maybe = self.common.shell.workspaces.iter().find_map(|(o, set)| {
let mut shell = self.common.shell.write().unwrap();
let maybe = shell.workspaces.iter().find_map(|(o, set)| {
set.workspaces
.iter()
.position(|w| w.handle == handle)
@ -39,22 +40,20 @@ impl WorkspaceHandler for State {
});
if let Some((output, idx)) = maybe {
let _ = self.common.shell.activate(
let _ = shell.activate(
&output,
idx,
WorkspaceDelta::new_shortcut(),
); // TODO: move cursor?
&mut self.common.workspace_state.update(),
);
// TODO: move cursor?
}
}
Request::SetTilingState { workspace, state } => {
let seat = self.common.shell.seats.last_active().clone();
if let Some(workspace) = self
.common
.shell
.workspaces
.space_for_handle_mut(&workspace)
{
let mut guard = self.common.shell.workspace_state.update();
let mut shell = self.common.shell.write().unwrap();
let seat = shell.seats.last_active().clone();
if let Some(workspace) = shell.workspaces.space_for_handle_mut(&workspace) {
let mut guard = self.common.workspace_state.update();
workspace.set_tiling(
match state.into_result() {
Ok(TilingState::FloatingOnly) => false,

View file

@ -1,3 +1,6 @@
use crate::{shell::ActivationKey, state::ClientState, utils::prelude::*};
use crate::{state::State, wayland::protocols::workspace::WorkspaceHandle};
use cosmic_protocols::workspace::v1::server::zcosmic_workspace_handle_v1::State as WState;
use smithay::{
delegate_xdg_activation,
input::Seat,
@ -8,9 +11,6 @@ use smithay::{
};
use tracing::debug;
use crate::{shell::ActivationKey, state::ClientState, utils::prelude::*};
use crate::{state::State, wayland::protocols::workspace::WorkspaceHandle};
#[derive(Debug, Clone, Copy)]
pub enum ActivationContext {
UrgentOnly,
@ -19,7 +19,7 @@ pub enum ActivationContext {
impl XdgActivationHandler for State {
fn activation_state(&mut self) -> &mut XdgActivationState {
&mut self.common.shell.xdg_activation_state
&mut self.common.xdg_activation_state
}
fn token_created(&mut self, token: XdgActivationToken, data: XdgActivationTokenData) -> bool {
@ -41,7 +41,8 @@ impl XdgActivationHandler for State {
{
if let Some(seat) = data.serial.and_then(|(_, seat)| Seat::from_resource(&seat)) {
let output = seat.active_output();
let workspace = self.common.shell.active_space_mut(&output);
let mut shell = self.common.shell.write().unwrap();
let workspace = shell.active_space_mut(&output);
workspace.pending_tokens.insert(token.clone());
let handle = workspace.handle;
data.user_data
@ -84,7 +85,8 @@ impl XdgActivationHandler for State {
if valid {
let output = seat.active_output();
let workspace = self.common.shell.active_space_mut(&output);
let mut shell = self.common.shell.write().unwrap();
let workspace = shell.active_space_mut(&output);
workspace.pending_tokens.insert(token.clone());
let handle = workspace.handle;
data.user_data
@ -105,24 +107,24 @@ impl XdgActivationHandler for State {
surface: WlSurface,
) {
if let Some(context) = token_data.user_data.get::<ActivationContext>() {
if let Some(element) = self.common.shell.element_for_surface(&surface).cloned() {
let mut shell = self.common.shell.write().unwrap();
if let Some(element) = shell.element_for_surface(&surface).cloned() {
match context {
ActivationContext::UrgentOnly => {
if let Some((workspace, _output)) =
self.common.shell.workspace_for_surface(&surface)
{
self.common.shell.set_urgent(&workspace);
if let Some((workspace, _output)) = shell.workspace_for_surface(&surface) {
let mut workspace_guard = self.common.workspace_state.update();
workspace_guard.add_workspace_state(&workspace, WState::Urgent);
}
}
ActivationContext::Workspace(workspace) => {
let seat = self.common.shell.seats.last_active().clone();
let seat = shell.seats.last_active().clone();
let current_output = seat.active_output();
if element.is_minimized() {
self.common.shell.unminimize_request(&element, &seat);
shell.unminimize_request(&element, &seat);
}
let current_workspace = self.common.shell.active_space_mut(&current_output);
let current_workspace = shell.active_space_mut(&current_output);
let in_current_workspace = current_workspace
.floating_layer
@ -152,21 +154,19 @@ impl XdgActivationHandler for State {
if workspace == &current_workspace.handle || in_current_workspace {
let target = element.into();
std::mem::drop(shell);
Shell::set_focus(self, Some(&target), &seat, None);
} else if let Some(w) = self
.common
.shell
.space_for(&element)
.map(|w| w.handle.clone())
} else if let Some(w) = shell.space_for(&element).map(|w| w.handle.clone())
{
self.common.shell.append_focus_stack(&element, &seat);
self.common.shell.set_urgent(&w);
shell.append_focus_stack(&element, &seat);
let mut workspace_guard = self.common.workspace_state.update();
workspace_guard.add_workspace_state(&w, WState::Urgent);
}
}
}
} else {
self.common
.shell
shell
.pending_activations
.insert(ActivationKey::Wayland(surface), context.clone());
}

View file

@ -3,6 +3,7 @@
use crate::{
shell::{element::CosmicWindow, grabs::ReleaseMode, CosmicMapped, CosmicSurface, ManagedLayer},
utils::prelude::*,
wayland::protocols::toplevel_info::{toplevel_enter_output, toplevel_enter_workspace},
};
use smithay::{
delegate_xdg_shell,
@ -29,7 +30,7 @@ use smithay::{
use std::cell::Cell;
use tracing::warn;
use super::{compositor::client_compositor_state, toplevel_management::ToplevelManagementExt};
use super::{compositor::client_compositor_state, toplevel_management::minimize_rectangle};
pub mod popup;
@ -37,13 +38,14 @@ pub type PopupGrabData = Cell<Option<PopupGrab<State>>>;
impl XdgShellHandler for State {
fn xdg_shell_state(&mut self) -> &mut XdgShellState {
&mut self.common.shell.xdg_shell_state
&mut self.common.xdg_shell_state
}
fn new_toplevel(&mut self, surface: ToplevelSurface) {
let seat = self.common.shell.seats.last_active().clone();
let mut shell = self.common.shell.write().unwrap();
let seat = shell.seats.last_active().clone();
let window = CosmicSurface::from(surface);
self.common.shell.pending_windows.push((window, seat, None));
shell.pending_windows.push((window, seat, None));
// We will position the window after the first commit, when we know its size hints
}
@ -55,11 +57,14 @@ impl XdgShellHandler for State {
if surface.get_parent_surface().is_some() {
// let other shells deal with their popups
self.common.shell.unconstrain_popup(&surface);
self.common
.shell
.read()
.unwrap()
.unconstrain_popup(&surface);
if surface.send_configure().is_ok() {
self.common
.shell
.popups
.track_popup(PopupKind::from(surface))
.unwrap();
@ -70,16 +75,18 @@ impl XdgShellHandler for State {
fn grab(&mut self, surface: PopupSurface, seat: WlSeat, serial: Serial) {
let seat = Seat::from_resource(&seat).unwrap();
let kind = PopupKind::Xdg(surface);
if let Some(root) = find_popup_root_surface(&kind)
.ok()
.and_then(|root| self.common.shell.element_for_surface(&root))
{
let target = root.clone().into();
let ret = self
.common
let maybe_root = find_popup_root_surface(&kind).ok().and_then(|root| {
self.common
.shell
.popups
.grab_popup(target, kind, &seat, serial);
.read()
.unwrap()
.element_for_surface(&root)
.cloned()
});
if let Some(root) = maybe_root {
let target = root.into();
let ret = self.common.popups.grab_popup(target, kind, &seat, serial);
if let Ok(mut grab) = ret {
if let Some(keyboard) = seat.get_keyboard() {
@ -128,7 +135,11 @@ impl XdgShellHandler for State {
state.positioner = positioner;
});
self.common.shell.unconstrain_popup(&surface);
self.common
.shell
.read()
.unwrap()
.unconstrain_popup(&surface);
surface.send_repositioned(token);
if let Err(err) = surface.send_configure() {
warn!(
@ -140,14 +151,26 @@ impl XdgShellHandler for State {
fn move_request(&mut self, surface: ToplevelSurface, seat: WlSeat, serial: Serial) {
let seat = Seat::from_resource(&seat).unwrap();
Shell::move_request(
self,
let mut shell = self.common.shell.write().unwrap();
if let Some((grab, focus)) = shell.move_request(
surface.wl_surface(),
&seat,
serial,
ReleaseMode::NoMouseButtons,
false,
)
&self.common.config,
&self.common.event_loop_handle,
&self.common.xdg_activation_state,
) {
std::mem::drop(shell);
if grab.is_touch_grab() {
seat.get_touch().unwrap().set_grab(self, grab, serial);
} else {
seat.get_pointer()
.unwrap()
.set_grab(self, grab, serial, focus)
}
}
}
fn resize_request(
@ -158,70 +181,60 @@ impl XdgShellHandler for State {
edges: xdg_toplevel::ResizeEdge,
) {
let seat = Seat::from_resource(&seat).unwrap();
Shell::resize_request(self, surface.wl_surface(), &seat, serial, edges.into())
let mut shell = self.common.shell.write().unwrap();
if let Some((grab, focus)) =
shell.resize_request(surface.wl_surface(), &seat, serial, edges.into())
{
std::mem::drop(shell);
if grab.is_touch_grab() {
seat.get_touch().unwrap().set_grab(self, grab, serial)
} else {
seat.get_pointer()
.unwrap()
.set_grab(self, grab, serial, focus)
}
}
}
fn minimize_request(&mut self, surface: ToplevelSurface) {
if let Some(mapped) = self
.common
.shell
.element_for_surface(surface.wl_surface())
.cloned()
{
let mut shell = self.common.shell.write().unwrap();
if let Some(mapped) = shell.element_for_surface(surface.wl_surface()).cloned() {
if !mapped.is_stack()
|| mapped.active_window().wl_surface().as_ref() == Some(surface.wl_surface())
{
self.common.shell.minimize_request(&mapped)
shell.minimize_request(&mapped)
}
}
}
fn maximize_request(&mut self, surface: ToplevelSurface) {
if let Some(mapped) = self
.common
.shell
.element_for_surface(surface.wl_surface())
.cloned()
{
let seat = self.common.shell.seats.last_active().clone();
self.common.shell.maximize_request(&mapped, &seat)
let mut shell = self.common.shell.write().unwrap();
if let Some(mapped) = shell.element_for_surface(surface.wl_surface()).cloned() {
let seat = shell.seats.last_active().clone();
shell.maximize_request(&mapped, &seat)
}
}
fn unmaximize_request(&mut self, surface: ToplevelSurface) {
if let Some(mapped) = self
.common
.shell
.element_for_surface(surface.wl_surface())
.cloned()
{
self.common.shell.unmaximize_request(&mapped);
let mut shell = self.common.shell.write().unwrap();
if let Some(mapped) = shell.element_for_surface(surface.wl_surface()).cloned() {
shell.unmaximize_request(&mapped);
}
}
fn fullscreen_request(&mut self, surface: ToplevelSurface, output: Option<WlOutput>) {
let seat = self.common.shell.seats.last_active().clone();
let mut shell = self.common.shell.write().unwrap();
let seat = shell.seats.last_active().clone();
let active_output = seat.active_output();
let output = output
.as_ref()
.and_then(Output::from_resource)
.unwrap_or_else(|| active_output.clone());
if let Some(mapped) = self
.common
.shell
.element_for_surface(surface.wl_surface())
.cloned()
{
let from = self
.common
.shell
.toplevel_management_state
.minimize_rectangle(&output, &mapped.active_window());
if let Some(mapped) = shell.element_for_surface(surface.wl_surface()).cloned() {
let from = minimize_rectangle(&output, &mapped.active_window());
if let Some(set) = self
.common
.shell
if let Some(set) = shell
.workspaces
.sets
.values_mut()
@ -248,19 +261,13 @@ impl XdgShellHandler for State {
mapped
};
let workspace_handle = self.common.shell.active_space(&output).handle.clone();
let workspace_handle = shell.active_space(&output).handle.clone();
for (window, _) in mapped.windows() {
self.common
.shell
.toplevel_info_state
.toplevel_enter_output(&window, &output);
self.common
.shell
.toplevel_info_state
.toplevel_enter_workspace(&window, &workspace_handle);
toplevel_enter_output(&window, &output);
toplevel_enter_workspace(&window, &workspace_handle);
}
let workspace = self.common.shell.active_space_mut(&output);
let workspace = shell.active_space_mut(&output);
workspace.floating_layer.map(mapped.clone(), None);
workspace.fullscreen_request(
@ -269,7 +276,7 @@ impl XdgShellHandler for State {
from,
&seat,
);
} else if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
} else if let Some(workspace) = shell.space_for_mut(&mapped) {
if workspace.output != output {
let (mapped, layer) = if mapped
.stack_ref()
@ -300,19 +307,13 @@ impl XdgShellHandler for State {
};
let handle = workspace.handle.clone();
let workspace_handle = self.common.shell.active_space(&output).handle.clone();
let workspace_handle = shell.active_space(&output).handle.clone();
for (window, _) in mapped.windows() {
self.common
.shell
.toplevel_info_state
.toplevel_enter_output(&window, &output);
self.common
.shell
.toplevel_info_state
.toplevel_enter_workspace(&window, &workspace_handle);
toplevel_enter_output(&window, &output);
toplevel_enter_workspace(&window, &workspace_handle);
}
let workspace = self.common.shell.active_space_mut(&output);
let workspace = shell.active_space_mut(&output);
workspace.floating_layer.map(mapped.clone(), None);
workspace.fullscreen_request(
@ -330,9 +331,7 @@ impl XdgShellHandler for State {
}
}
} else {
if let Some(o) = self
.common
.shell
if let Some(o) = shell
.pending_windows
.iter_mut()
.find(|(s, _, _)| s.wl_surface().as_ref() == Some(surface.wl_surface()))
@ -344,29 +343,23 @@ impl XdgShellHandler for State {
}
fn unfullscreen_request(&mut self, surface: ToplevelSurface) {
if let Some(mapped) = self
.common
.shell
.element_for_surface(surface.wl_surface())
.cloned()
{
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
let mut shell = self.common.shell.write().unwrap();
if let Some(mapped) = shell.element_for_surface(surface.wl_surface()).cloned() {
if let Some(workspace) = shell.space_for_mut(&mapped) {
let (window, _) = mapped
.windows()
.find(|(w, _)| w.wl_surface().as_ref() == Some(surface.wl_surface()))
.unwrap();
if let Some((layer, previous_workspace)) = workspace.unfullscreen_request(&window) {
let old_handle = workspace.handle.clone();
let new_workspace_handle = self
.common
.shell
let new_workspace_handle = shell
.workspaces
.space_for_handle(&previous_workspace)
.is_some()
.then_some(previous_workspace)
.unwrap_or(old_handle); // if the workspace doesn't exist anymore, we can still remap on the right layer
self.common.shell.remap_unfullscreened_window(
shell.remap_unfullscreened_window(
mapped,
&old_handle,
&new_workspace_handle,
@ -378,20 +371,26 @@ impl XdgShellHandler for State {
}
fn toplevel_destroyed(&mut self, surface: ToplevelSurface) {
let seat = self.common.shell.seats.last_active().clone();
self.common.shell.unmap_surface(surface.wl_surface(), &seat);
let (output, clients) = {
let mut shell = self.common.shell.write().unwrap();
let seat = shell.seats.last_active().clone();
shell.unmap_surface(
surface.wl_surface(),
&seat,
&mut self.common.toplevel_info_state,
);
let output = self
.common
.shell
.visible_output_for_surface(surface.wl_surface())
.cloned();
if let Some(output) = output.as_ref() {
self.common.shell.refresh_active_space(output);
}
let output = shell
.visible_output_for_surface(surface.wl_surface())
.cloned();
if let Some(output) = output.as_ref() {
shell.refresh_active_space(output, &self.common.xdg_activation_state);
}
// animations might be unblocked now
(output, shell.update_animations())
};
// animations might be unblocked now
let clients = self.common.shell.update_animations();
{
let dh = self.common.display_handle.clone();
for client in clients.values() {
@ -418,7 +417,23 @@ impl XdgShellHandler for State {
})
.unwrap_or_default()
.loc;
Shell::menu_request(self, surface.wl_surface(), &seat, serial, location, false)
let shell = self.common.shell.read().unwrap();
let res = shell.menu_request(
surface.wl_surface(),
&seat,
serial,
location,
false,
&self.common.config,
&self.common.event_loop_handle,
);
if let Some((grab, focus)) = res {
std::mem::drop(shell);
seat.get_pointer()
.unwrap()
.set_grab(self, grab, serial, focus)
}
}
}

View file

@ -11,10 +11,12 @@ impl XWaylandKeyboardGrabHandler for State {
let element = self
.common
.shell
.read()
.unwrap()
.workspaces
.spaces()
.find_map(|x| x.element_for_surface(surface))?;
Some(KeyboardFocusTarget::Element(element.clone()))
.find_map(|x| x.element_for_surface(surface).cloned())?;
Some(KeyboardFocusTarget::Element(element))
}
}
delegate_xwayland_keyboard_grab!(State);

View file

@ -185,6 +185,30 @@ where
}
}
pub fn toplevel_enter_output(toplevel: &impl Window, output: &Output) {
if let Some(state) = toplevel.user_data().get::<ToplevelState>() {
state.lock().unwrap().outputs.push(output.clone());
}
}
pub fn toplevel_leave_output(toplevel: &impl Window, output: &Output) {
if let Some(state) = toplevel.user_data().get::<ToplevelState>() {
state.lock().unwrap().outputs.retain(|o| o != output);
}
}
pub fn toplevel_enter_workspace(toplevel: &impl Window, workspace: &WorkspaceHandle) {
if let Some(state) = toplevel.user_data().get::<ToplevelState>() {
state.lock().unwrap().workspaces.push(workspace.clone());
}
}
pub fn toplevel_leave_workspace(toplevel: &impl Window, workspace: &WorkspaceHandle) {
if let Some(state) = toplevel.user_data().get::<ToplevelState>() {
state.lock().unwrap().workspaces.retain(|w| w != workspace);
}
}
impl<D, W> ToplevelInfoState<D, W>
where
D: GlobalDispatch<ZcosmicToplevelInfoV1, ToplevelInfoGlobalData>
@ -223,30 +247,6 @@ where
self.toplevels.push(toplevel.clone());
}
pub fn toplevel_enter_output(&mut self, toplevel: &W, output: &Output) {
if let Some(state) = toplevel.user_data().get::<ToplevelState>() {
state.lock().unwrap().outputs.push(output.clone());
}
}
pub fn toplevel_leave_output(&mut self, toplevel: &W, output: &Output) {
if let Some(state) = toplevel.user_data().get::<ToplevelState>() {
state.lock().unwrap().outputs.retain(|o| o != output);
}
}
pub fn toplevel_enter_workspace(&mut self, toplevel: &W, workspace: &WorkspaceHandle) {
if let Some(state) = toplevel.user_data().get::<ToplevelState>() {
state.lock().unwrap().workspaces.push(workspace.clone());
}
}
pub fn toplevel_leave_workspace(&mut self, toplevel: &W, workspace: &WorkspaceHandle) {
if let Some(state) = toplevel.user_data().get::<ToplevelState>() {
state.lock().unwrap().workspaces.retain(|w| w != workspace);
}
}
pub fn remove_toplevel(&mut self, toplevel: &W) {
if let Some(state) = toplevel.user_data().get::<ToplevelState>() {
let mut state_inner = state.lock().unwrap();

View file

@ -71,6 +71,29 @@ where
}
}
pub fn toplevel_rectangle_for(
window: &impl ManagementWindow,
) -> impl Iterator<Item = (WlSurface, Rectangle<i32, Logical>)> {
if let Some(state) = window.user_data().get::<ToplevelState>() {
let mut state = state.lock().unwrap();
state
.rectangles
.retain(|(surface, _)| surface.upgrade().is_ok());
Some(
state
.rectangles
.iter()
.map(|(surface, rect)| (surface.upgrade().unwrap(), *rect))
.collect::<Vec<_>>()
.into_iter(),
)
.into_iter()
.flatten()
} else {
None.into_iter().flatten()
}
}
pub struct ToplevelManagerGlobalData {
filter: Box<dyn for<'a> Fn(&'a Client) -> bool + Send + Sync>,
}
@ -102,30 +125,6 @@ impl ToplevelManagementState {
}
}
pub fn rectangle_for(
&mut self,
window: &impl ManagementWindow,
) -> impl Iterator<Item = (WlSurface, Rectangle<i32, Logical>)> {
if let Some(state) = window.user_data().get::<ToplevelState>() {
let mut state = state.lock().unwrap();
state
.rectangles
.retain(|(surface, _)| surface.upgrade().is_ok());
Some(
state
.rectangles
.iter()
.map(|(surface, rect)| (surface.upgrade().unwrap(), *rect))
.collect::<Vec<_>>()
.into_iter(),
)
.into_iter()
.flatten()
} else {
None.into_iter().flatten()
}
}
pub fn global_id(&self) -> GlobalId {
self.global.clone()
}