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

@ -11,8 +11,9 @@ use crate::{
utils::prelude::*,
wayland::{
handlers::screencopy::{submit_buffer, FrameHolder, SessionData},
protocols::screencopy::{
FailureReason, Frame as ScreencopyFrame, Session as ScreencopySession,
protocols::{
screencopy::{FailureReason, Frame as ScreencopyFrame, Session as ScreencopySession},
workspace::WorkspaceUpdateGuard,
},
},
};
@ -76,6 +77,7 @@ use smithay::{
relative_pointer::RelativePointerManagerState,
seat::WaylandFocus,
shm::{shm_format_to_fourcc, with_buffer_contents},
xdg_activation::XdgActivationState,
},
};
use tracing::{error, info, trace, warn};
@ -202,7 +204,7 @@ pub fn init_backend(
state.backend.kms().input_devices.remove(device.name());
}
state.process_input_event(event, true);
for output in state.common.shell.outputs() {
for output in state.common.shell.read().unwrap().outputs() {
if let Err(err) = state.backend.kms().schedule_render(
&state.common.event_loop_handle,
output,
@ -326,9 +328,13 @@ pub fn init_backend(
state.common.config.read_outputs(
&mut state.common.output_configuration_state,
&mut state.backend,
&mut state.common.shell,
&mut state.common.shell.write().unwrap(),
&state.common.event_loop_handle,
&mut state.common.workspace_state.update(),
&state.common.xdg_activation_state,
);
state.common.refresh();
for surface in state
.backend
.kms()
@ -339,7 +345,7 @@ pub fn init_backend(
surface.scheduled = false;
surface.pending = false;
}
for output in state.common.shell.outputs() {
for output in state.common.shell.read().unwrap().outputs() {
if let Err(err) = state.backend.kms().schedule_render(
&state.common.event_loop_handle,
output,
@ -601,7 +607,7 @@ impl State {
let outputs = device.enumerate_surfaces()?.added; // There are no removed outputs on newly added devices
let mut wl_outputs = Vec::new();
let mut w = self.common.shell.global_space().size.w;
let mut w = self.common.shell.read().unwrap().global_space().size.w;
{
let backend = self.backend.kms();
backend
@ -701,9 +707,12 @@ impl State {
self.common.config.read_outputs(
&mut self.common.output_configuration_state,
&mut self.backend,
&mut self.common.shell,
&mut *self.common.shell.write().unwrap(),
&self.common.event_loop_handle,
&mut self.common.workspace_state.update(),
&self.common.xdg_activation_state,
);
self.common.refresh();
Ok(())
}
@ -720,7 +729,7 @@ impl State {
let backend = self.backend.kms();
if let Some(device) = backend.devices.get_mut(&drm_node) {
let changes = device.enumerate_surfaces()?;
let mut w = self.common.shell.global_space().size.w;
let mut w = self.common.shell.read().unwrap().global_space().size.w;
for crtc in changes.removed {
if let Some(pos) = device
.non_desktop_connectors
@ -831,18 +840,23 @@ impl State {
self.common
.output_configuration_state
.add_heads(outputs_added.iter());
self.common.config.read_outputs(
&mut self.common.output_configuration_state,
&mut self.backend,
&mut self.common.shell,
&self.common.event_loop_handle,
);
// Don't remove the outputs, before potentially new ones have been initialized.
// reading a new config means outputs might become enabled, that were previously disabled.
// If we have 0 outputs at some point, we won't quit, but shell doesn't know where to move
// windows and workspaces to.
for output in outputs_removed {
self.common.shell.remove_output(&output);
{
self.common.config.read_outputs(
&mut self.common.output_configuration_state,
&mut self.backend,
&mut *self.common.shell.write().unwrap(),
&self.common.event_loop_handle,
&mut self.common.workspace_state.update(),
&self.common.xdg_activation_state,
);
self.common.refresh();
// Don't remove the outputs, before potentially new ones have been initialized.
// reading a new config means outputs might become enabled, that were previously disabled.
// If we have 0 outputs at some point, we won't quit, but shell doesn't know where to move
// windows and workspaces to.
for output in outputs_removed {
self.common.remove_output(&output);
}
}
{
@ -889,14 +903,17 @@ impl State {
if self.backend.kms().session.is_active() {
for output in outputs_removed {
self.common.shell.remove_output(&output);
self.common.remove_output(&output);
}
self.common.config.read_outputs(
&mut self.common.output_configuration_state,
&mut self.backend,
&mut self.common.shell,
&mut *self.common.shell.write().unwrap(),
&self.common.event_loop_handle,
&mut self.common.workspace_state.update(),
&self.common.xdg_activation_state,
);
self.common.refresh();
} else {
self.common.output_configuration_state.update();
}
@ -1178,30 +1195,33 @@ impl Surface {
);
}
let (previous_workspace, workspace) = state.shell.workspaces.active(&self.output);
let (previous_idx, idx) = state.shell.workspaces.active_num(&self.output);
let previous_workspace = previous_workspace
.zip(previous_idx)
.map(|((w, start), idx)| (w.handle, idx, start));
let workspace = (workspace.handle, idx);
let mut elements = {
let shell = state.shell.read().unwrap();
let (previous_workspace, workspace) = shell.workspaces.active(&self.output);
let (previous_idx, idx) = shell.workspaces.active_num(&self.output);
let previous_workspace = previous_workspace
.zip(previous_idx)
.map(|((w, start), idx)| (w.handle, idx, start));
let workspace = (workspace.handle, idx);
let mut elements = workspace_elements(
Some(&render_node),
&mut renderer,
&state.shell,
&state.config,
&state.theme,
state.clock.now(),
&self.output,
previous_workspace,
workspace,
CursorMode::All,
&mut Some(&mut self.fps),
false,
)
.map_err(|err| {
anyhow::format_err!("Failed to accumulate elements for rendering: {:?}", err)
})?;
workspace_elements(
Some(&render_node),
&mut renderer,
&*shell,
&state.config,
&state.theme,
state.clock.now(),
&self.output,
previous_workspace,
workspace,
CursorMode::All,
&mut Some(&mut self.fps),
false,
)
.map_err(|err| {
anyhow::format_err!("Failed to accumulate elements for rendering: {:?}", err)
})?
};
self.fps.elements();
let frames: Vec<(
@ -1490,6 +1510,8 @@ impl KmsState {
shell: &mut Shell,
test_only: bool,
loop_handle: &LoopHandle<'_, State>,
workspace_state: &mut WorkspaceUpdateGuard<'_, State>,
xdg_activation_state: &XdgActivationState,
) -> Result<(), anyhow::Error> {
let recreated = if let Some(device) = self
.devices
@ -1509,7 +1531,12 @@ impl KmsState {
if !output_config.enabled {
if !test_only {
shell.remove_output(output);
shell.workspaces.remove_output(
output,
shell.seats.iter(),
workspace_state,
xdg_activation_state,
);
if surface.surface.take().is_some() {
// just drop it
surface.pending = false;
@ -1608,7 +1635,9 @@ impl KmsState {
surface.surface = Some(target);
true
};
shell.add_output(output);
shell
.workspaces
.add_output(output, workspace_state, xdg_activation_state);
res
} else {
false
@ -1748,7 +1777,7 @@ impl KmsState {
&surface.output,
backend.primary_node,
target_node,
&common.shell,
&*common.shell.read().unwrap(),
);
let result = if render_node != target_node {

View file

@ -45,17 +45,26 @@ pub fn init_backend_auto(
let output = state
.common
.shell
.read()
.unwrap()
.outputs()
.next()
.with_context(|| "Backend initialized without output")?;
.with_context(|| "Backend initialized without output")
.cloned()?;
let initial_seat = crate::shell::create_seat(
dh,
&mut state.common.seat_state,
output,
&output,
&state.common.config,
"seat-0".into(),
);
state.common.shell.seats.add_seat(initial_seat);
state
.common
.shell
.write()
.unwrap()
.seats
.add_seat(initial_seat);
}
res
}

View file

@ -63,7 +63,7 @@ impl WinitState {
surface.clone(),
&mut self.damage_tracker,
age,
&state.shell,
&*state.shell.read().unwrap(),
&state.config,
&state.theme,
state.clock.now(),
@ -201,7 +201,7 @@ pub fn init_backend(
}
PumpStatus::Exit(_) => {
let output = state.backend.winit().output.clone();
state.common.shell.remove_output(&output);
state.common.remove_output(&output);
if let Some(token) = token.take() {
event_loop_handle.remove(token);
}
@ -226,13 +226,21 @@ pub fn init_backend(
.common
.output_configuration_state
.add_heads(std::iter::once(&output));
state.common.shell.add_output(&output);
state.common.config.read_outputs(
&mut state.common.output_configuration_state,
&mut state.backend,
&mut state.common.shell,
&state.common.event_loop_handle,
);
{
state.common.add_output(&output);
let mut shell = state.common.shell.write().unwrap();
state.common.config.read_outputs(
&mut state.common.output_configuration_state,
&mut state.backend,
&mut *shell,
&state.common.event_loop_handle,
&mut state.common.workspace_state.update(),
&state.common.xdg_activation_state,
);
std::mem::drop(shell);
state.common.refresh();
}
state.launch_xwayland(None);
Ok(())
@ -299,7 +307,7 @@ impl State {
// here we can handle special cases for winit inputs
match event {
WinitEvent::Focus(true) => {
for seat in self.common.shell.seats.iter() {
for seat in self.common.shell.read().unwrap().seats.iter() {
let devices = seat.user_data().get::<Devices>().unwrap();
if devices.has_device(&WinitVirtualDevice) {
seat.set_active_output(&self.backend.winit().output);

View file

@ -222,7 +222,7 @@ impl Surface {
buffer.clone(),
&mut self.damage_tracker,
age as usize,
&state.shell,
&*state.shell.read().unwrap(),
&state.config,
&state.theme,
state.clock.now(),
@ -364,13 +364,21 @@ pub fn init_backend(
.common
.output_configuration_state
.add_heads(std::iter::once(&output));
state.common.shell.add_output(&output);
state.common.config.read_outputs(
&mut state.common.output_configuration_state,
&mut state.backend,
&mut state.common.shell,
&state.common.event_loop_handle,
);
{
state.common.add_output(&output);
let mut shell = state.common.shell.write().unwrap();
state.common.config.read_outputs(
&mut state.common.output_configuration_state,
&mut state.backend,
&mut *shell,
&state.common.event_loop_handle,
&mut state.common.workspace_state.update(),
&state.common.xdg_activation_state,
);
std::mem::drop(shell);
state.common.refresh();
}
state.launch_xwayland(None);
event_loop
@ -395,7 +403,7 @@ pub fn init_backend(
.surfaces
.retain(|s| s.window.id() != window_id);
for output in outputs_removed.into_iter() {
state.common.shell.remove_output(&output);
state.common.remove_output(&output);
}
}
X11Event::Resized {
@ -504,7 +512,7 @@ impl State {
.unwrap();
let device = event.device();
for seat in self.common.shell.seats.iter() {
for seat in self.common.shell.read().unwrap().seats.iter() {
let devices = seat.user_data().get::<Devices>().unwrap();
if devices.has_device(&device) {
seat.set_active_output(&output);
@ -518,7 +526,7 @@ impl State {
self.process_input_event(event, false);
// TODO actually figure out the output
for output in self.common.shell.outputs() {
for output in self.common.shell.read().unwrap().outputs() {
self.backend.x11().schedule_render(output);
}
}

View file

@ -3,10 +3,13 @@
use crate::{
shell::Shell,
state::{BackendData, State},
wayland::protocols::output_configuration::OutputConfigurationState,
wayland::protocols::{
output_configuration::OutputConfigurationState, workspace::WorkspaceUpdateGuard,
},
};
use cosmic_config::{ConfigGet, CosmicConfigEntry};
use serde::{Deserialize, Serialize};
use smithay::wayland::xdg_activation::XdgActivationState;
pub use smithay::{
backend::input::KeyState,
input::keyboard::{keysyms as KeySyms, Keysym, ModifiersState},
@ -277,6 +280,8 @@ impl Config {
backend: &mut BackendData,
shell: &mut Shell,
loop_handle: &LoopHandle<'_, State>,
workspace_state: &mut WorkspaceUpdateGuard<'_, State>,
xdg_activation_state: &XdgActivationState,
) {
let outputs = output_state.outputs().collect::<Vec<_>>();
let mut infos = outputs
@ -308,9 +313,14 @@ impl Config {
.get::<RefCell<OutputConfig>>()
.unwrap()
.borrow_mut() = output_config;
if let Err(err) =
backend.apply_config_for_output(&output, false, shell, loop_handle)
{
if let Err(err) = backend.apply_config_for_output(
&output,
false,
shell,
loop_handle,
workspace_state,
xdg_activation_state,
) {
warn!(
?err,
"Failed to set new config for output {}.",
@ -339,9 +349,14 @@ impl Config {
.get::<RefCell<OutputConfig>>()
.unwrap()
.borrow_mut() = output_config;
if let Err(err) =
backend.apply_config_for_output(&output, false, shell, loop_handle)
{
if let Err(err) = backend.apply_config_for_output(
&output,
false,
shell,
loop_handle,
workspace_state,
xdg_activation_state,
) {
error!(?err, "Failed to reset config for output {}.", output.name());
} else {
if enabled {
@ -357,9 +372,14 @@ impl Config {
self.write_outputs(output_state.outputs());
} else {
for output in outputs {
if let Err(err) =
backend.apply_config_for_output(&output, false, shell, loop_handle)
{
if let Err(err) = backend.apply_config_for_output(
&output,
false,
shell,
loop_handle,
workspace_state,
xdg_activation_state,
) {
warn!(
?err,
"Failed to set new config for output {}.",
@ -518,7 +538,15 @@ fn config_changed(config: cosmic_config::Config, keys: Vec<String>, state: &mut
match key.as_str() {
"xkb_config" => {
let value = get_config::<XkbConfig>(&config, "xkb_config");
let seats = state.common.shell.seats.iter().cloned().collect::<Vec<_>>();
let seats = state
.common
.shell
.read()
.unwrap()
.seats
.iter()
.cloned()
.collect::<Vec<_>>();
for seat in seats.into_iter() {
if let Some(keyboard) = seat.get_keyboard() {
if let Err(err) = keyboard.set_xkb_config(state, xkb_config_to_wl(&value)) {
@ -547,27 +575,41 @@ fn config_changed(config: cosmic_config::Config, keys: Vec<String>, state: &mut
"workspaces" => {
state.common.config.cosmic_conf.workspaces =
get_config::<WorkspaceConfig>(&config, "workspaces");
state.common.shell.update_config(&state.common.config);
state.common.update_config();
}
"autotile" => {
let new = get_config::<bool>(&config, "autotile");
if new != state.common.config.cosmic_conf.autotile {
state.common.config.cosmic_conf.autotile = new;
state.common.shell.update_autotile(new);
let mut shell = state.common.shell.write().unwrap();
let shell_ref = &mut *shell;
shell_ref.workspaces.update_autotile(
new,
&mut state.common.workspace_state.update(),
shell_ref.seats.iter(),
);
}
}
"autotile_behavior" => {
let new = get_config::<TileBehavior>(&config, "autotile_behavior");
if new != state.common.config.cosmic_conf.autotile_behavior {
state.common.config.cosmic_conf.autotile_behavior = new;
state.common.shell.update_autotile_behavior(new);
let mut shell = state.common.shell.write().unwrap();
let shell_ref = &mut *shell;
shell_ref.workspaces.update_autotile_behavior(
new,
&mut state.common.workspace_state.update(),
shell_ref.seats.iter(),
);
}
}
"active_hint" => {
let new = get_config::<bool>(&config, "active_hint");
if new != state.common.config.cosmic_conf.active_hint {
state.common.config.cosmic_conf.active_hint = new;
state.common.shell.update_config(&state.common.config);
state.common.update_config();
}
}
_ => {}

File diff suppressed because it is too large Load diff

View file

@ -92,7 +92,16 @@ fn main() -> Result<()> {
// run the event loop
event_loop.run(None, &mut state, |state| {
// shall we shut down?
if state.common.shell.outputs().next().is_none() || state.common.should_stop {
if state
.common
.shell
.read()
.unwrap()
.outputs()
.next()
.is_none()
|| state.common.should_stop
{
info!("Shutting down");
state.common.event_loop_signal.stop();
state.common.event_loop_signal.wakeup();
@ -100,29 +109,25 @@ fn main() -> Result<()> {
}
// trigger routines
let clients = state.common.shell.update_animations();
let clients = state.common.shell.write().unwrap().update_animations();
{
let dh = state.common.display_handle.clone();
for client in clients.values() {
client_compositor_state(&client).blocker_cleared(state, &dh);
}
}
state.common.shell.refresh();
state.common.refresh();
state::Common::refresh_focus(state);
state.common.update_x11_stacking_order();
if state.common.shell.animations_going() {
for output in state
.common
.shell
.outputs()
.cloned()
.collect::<Vec<_>>()
.into_iter()
{
state
.backend
.schedule_render(&state.common.event_loop_handle, &output);
{
let shell = state.common.shell.read().unwrap();
if shell.animations_going() {
for output in shell.outputs().cloned().collect::<Vec<_>>().into_iter() {
state
.backend
.schedule_render(&state.common.event_loop_handle, &output);
}
}
}
@ -181,7 +186,14 @@ fn init_wayland_display(
let node = match &state.backend {
BackendData::Kms(kms_state) if kms_state.auto_assign => kms_state
.target_node_for_output(
&state.common.shell.seats.last_active().active_output(),
&state
.common
.shell
.read()
.unwrap()
.seats
.last_active()
.active_output(),
),
_ => None,
};

View file

@ -70,13 +70,7 @@ pub fn get_env(state: &State) -> Result<HashMap<String, String>> {
.into_string()
.map_err(|_| anyhow!("wayland socket is no valid utf-8 string?"))?,
);
if let Some(display) = state
.common
.shell
.xwayland_state
.as_ref()
.map(|s| s.display)
{
if let Some(display) = state.common.xwayland_state.as_ref().map(|s| s.display) {
env.insert(String::from("DISPLAY"), format!(":{}", display));
}
Ok(env)

View file

@ -5,7 +5,7 @@ use crate::{
focus::{target::PointerFocusTarget, FocusDirection},
grabs::{ReleaseMode, ResizeEdge},
layout::tiling::NodeDesc,
Direction, Shell,
Direction,
},
state::State,
utils::{
@ -664,14 +664,25 @@ impl Program for CosmicStackInternal {
let active = self.active.load(Ordering::SeqCst);
if let Some(surface) = self.windows.lock().unwrap()[active].wl_surface() {
loop_handle.insert_idle(move |state| {
Shell::move_request(
state,
let res = state.common.shell.write().unwrap().move_request(
&surface,
&seat,
serial,
ReleaseMode::NoMouseButtons,
false,
&state.common.config,
&state.common.event_loop_handle,
&state.common.xdg_activation_state,
);
if let Some((grab, focus)) = res {
if grab.is_touch_grab() {
seat.get_touch().unwrap().set_grab(state, grab, serial);
} else {
seat.get_pointer()
.unwrap()
.set_grab(state, grab, serial, focus);
}
}
});
}
}
@ -683,7 +694,13 @@ impl Program for CosmicStackInternal {
*self.potential_drag.lock().unwrap() = None;
if let Some(surface) = self.windows.lock().unwrap().get(idx).cloned() {
loop_handle.insert_idle(move |state| {
if let Some(mapped) = state.common.shell.element_for_surface(&surface) {
if let Some(mapped) = state
.common
.shell
.read()
.unwrap()
.element_for_surface(&surface)
{
mapped.stack_ref().unwrap().set_active(&surface);
}
});
@ -703,11 +720,10 @@ impl Program for CosmicStackInternal {
let active = self.active.load(Ordering::SeqCst);
if let Some(surface) = self.windows.lock().unwrap()[active].wl_surface() {
loop_handle.insert_idle(move |state| {
if let Some(mapped) =
state.common.shell.element_for_surface(&surface).cloned()
{
let shell = state.common.shell.read().unwrap();
if let Some(mapped) = shell.element_for_surface(&surface).cloned() {
let position = if let Some((output, set)) =
state.common.shell.workspaces.sets.iter().find(|(_, set)| {
shell.workspaces.sets.iter().find(|(_, set)| {
set.sticky_layer.mapped().any(|m| m == &mapped)
}) {
set.sticky_layer
@ -715,9 +731,7 @@ impl Program for CosmicStackInternal {
.unwrap()
.loc
.to_global(output)
} else if let Some(workspace) =
state.common.shell.space_for_mut(&mapped)
{
} else if let Some(workspace) = shell.space_for(&mapped) {
let Some(elem_geo) = workspace.element_geometry(&mapped) else {
return;
};
@ -732,14 +746,22 @@ impl Program for CosmicStackInternal {
.current_location()
.to_i32_round();
cursor.y -= TAB_HEIGHT;
Shell::menu_request(
state,
let res = shell.menu_request(
&surface,
&seat,
serial,
cursor - position.as_logical(),
true,
&state.common.config,
&state.common.event_loop_handle,
);
std::mem::drop(shell);
if let Some((grab, focus)) = res {
seat.get_pointer()
.unwrap()
.set_grab(state, grab, serial, focus);
}
}
});
}
@ -749,28 +771,36 @@ impl Program for CosmicStackInternal {
if let Some((seat, serial)) = self.last_seat.lock().unwrap().clone() {
if let Some(surface) = self.windows.lock().unwrap()[idx].wl_surface() {
loop_handle.insert_idle(move |state| {
if let Some(mapped) =
state.common.shell.element_for_surface(&surface).cloned()
{
if let Some(workspace) = state.common.shell.space_for_mut(&mapped) {
let shell = state.common.shell.read().unwrap();
if let Some(mapped) = shell.element_for_surface(&surface).cloned() {
if let Some(workspace) = shell.space_for(&mapped) {
let Some(elem_geo) = workspace.element_geometry(&mapped) else {
return;
};
let position = elem_geo.loc.to_global(&workspace.output);
let mut cursor = seat
.get_pointer()
.unwrap()
.current_location()
.to_i32_round();
cursor.y -= TAB_HEIGHT;
Shell::menu_request(
state,
let res = shell.menu_request(
&surface,
&seat,
serial,
cursor - position.as_logical(),
false,
&state.common.config,
&state.common.event_loop_handle,
);
std::mem::drop(shell);
if let Some((grab, focus)) = res {
seat.get_pointer()
.unwrap()
.set_grab(state, grab, serial, focus);
}
}
}
});
@ -1175,18 +1205,30 @@ impl PointerTarget<State> for CosmicStack {
.with_program(|p| p.windows.lock().unwrap().get(dragged_out).cloned())
{
let seat = seat.clone();
let serial = event.serial;
surface.try_force_undecorated(false);
surface.send_configure();
if let Some(surface) = surface.wl_surface() {
let _ = data.common.event_loop_handle.insert_idle(move |state| {
Shell::move_request(
state,
let res = state.common.shell.write().unwrap().move_request(
&surface,
&seat,
None,
serial,
ReleaseMode::NoMouseButtons,
true,
)
&state.common.config,
&state.common.event_loop_handle,
&state.common.xdg_activation_state,
);
if let Some((grab, focus)) = res {
if grab.is_touch_grab() {
seat.get_touch().unwrap().set_grab(state, grab, serial);
} else {
seat.get_pointer()
.unwrap()
.set_grab(state, grab, serial, focus);
}
}
});
}
}
@ -1220,8 +1262,7 @@ impl PointerTarget<State> for CosmicStack {
return;
};
self.0.loop_handle().insert_idle(move |state| {
Shell::resize_request(
state,
let res = state.common.shell.write().unwrap().resize_request(
&surface,
&seat,
serial,
@ -1236,7 +1277,16 @@ impl PointerTarget<State> for CosmicStack {
Focus::ResizeRight => ResizeEdge::RIGHT,
Focus::Header => unreachable!(),
},
)
);
if let Some((grab, focus)) = res {
if grab.is_touch_grab() {
seat.get_touch().unwrap().set_grab(state, grab, serial);
} else {
seat.get_pointer()
.unwrap()
.set_grab(state, grab, serial, focus);
}
}
});
}
None => {}
@ -1279,14 +1329,25 @@ impl PointerTarget<State> for CosmicStack {
surface.send_configure();
if let Some(surface) = surface.wl_surface() {
let _ = data.common.event_loop_handle.insert_idle(move |state| {
Shell::move_request(
state,
let res = state.common.shell.write().unwrap().move_request(
&surface,
&seat,
None,
serial,
ReleaseMode::NoMouseButtons,
true,
)
&state.common.config,
&state.common.event_loop_handle,
&state.common.xdg_activation_state,
);
if let Some((grab, focus)) = res {
if grab.is_touch_grab() {
seat.get_touch().unwrap().set_grab(state, grab, serial);
} else {
seat.get_pointer()
.unwrap()
.set_grab(state, grab, serial, focus);
}
}
});
}
}

View file

@ -3,7 +3,6 @@ use crate::{
shell::{
focus::target::PointerFocusTarget,
grabs::{ReleaseMode, ResizeEdge},
Shell,
},
state::State,
utils::{
@ -387,14 +386,25 @@ impl Program for CosmicWindowInternal {
if let Some((seat, serial)) = self.last_seat.lock().unwrap().clone() {
if let Some(surface) = self.window.wl_surface() {
loop_handle.insert_idle(move |state| {
Shell::move_request(
state,
let res = state.common.shell.write().unwrap().move_request(
&surface,
&seat,
serial,
ReleaseMode::NoMouseButtons,
false,
&state.common.config,
&state.common.event_loop_handle,
&state.common.xdg_activation_state,
);
if let Some((grab, focus)) = res {
if grab.is_touch_grab() {
seat.get_touch().unwrap().set_grab(state, grab, serial);
} else {
seat.get_pointer()
.unwrap()
.set_grab(state, grab, serial, focus);
}
}
});
}
}
@ -402,10 +412,9 @@ impl Program for CosmicWindowInternal {
Message::Minimize => {
if let Some(surface) = self.window.wl_surface() {
loop_handle.insert_idle(move |state| {
if let Some(mapped) =
state.common.shell.element_for_surface(&surface).cloned()
{
state.common.shell.minimize_request(&mapped)
let mut shell = state.common.shell.write().unwrap();
if let Some(mapped) = shell.element_for_surface(&surface).cloned() {
shell.minimize_request(&mapped)
}
});
}
@ -413,11 +422,10 @@ impl Program for CosmicWindowInternal {
Message::Maximize => {
if let Some(surface) = self.window.wl_surface() {
loop_handle.insert_idle(move |state| {
if let Some(mapped) =
state.common.shell.element_for_surface(&surface).cloned()
{
let seat = state.common.shell.seats.last_active().clone();
state.common.shell.maximize_toggle(&mapped, &seat)
let mut shell = state.common.shell.write().unwrap();
if let Some(mapped) = shell.element_for_surface(&surface).cloned() {
let seat = shell.seats.last_active().clone();
shell.maximize_toggle(&mapped, &seat)
}
});
}
@ -427,11 +435,10 @@ impl Program for CosmicWindowInternal {
if let Some((seat, serial)) = self.last_seat.lock().unwrap().clone() {
if let Some(surface) = self.window.wl_surface() {
loop_handle.insert_idle(move |state| {
if let Some(mapped) =
state.common.shell.element_for_surface(&surface).cloned()
{
let shell = state.common.shell.read().unwrap();
if let Some(mapped) = shell.element_for_surface(&surface).cloned() {
let position = if let Some((output, set)) =
state.common.shell.workspaces.sets.iter().find(|(_, set)| {
shell.workspaces.sets.iter().find(|(_, set)| {
set.sticky_layer.mapped().any(|m| m == &mapped)
}) {
set.sticky_layer
@ -439,9 +446,7 @@ impl Program for CosmicWindowInternal {
.unwrap()
.loc
.to_global(output)
} else if let Some(workspace) =
state.common.shell.space_for_mut(&mapped)
{
} else if let Some(workspace) = shell.space_for(&mapped) {
let Some(elem_geo) = workspace.element_geometry(&mapped) else {
return;
};
@ -450,20 +455,24 @@ impl Program for CosmicWindowInternal {
return;
};
let mut cursor = seat
.get_pointer()
.unwrap()
.current_location()
.to_i32_round();
let pointer = seat.get_pointer().unwrap();
let mut cursor = pointer.current_location().to_i32_round();
cursor.y -= SSD_HEIGHT;
Shell::menu_request(
state,
let res = shell.menu_request(
&surface,
&seat,
serial,
cursor - position.as_logical(),
false,
&state.common.config,
&state.common.event_loop_handle,
);
std::mem::drop(shell);
if let Some((grab, focus)) = res {
pointer.set_grab(state, grab, serial, focus);
}
}
});
}
@ -734,8 +743,7 @@ impl PointerTarget<State> for CosmicWindow {
return;
};
self.0.loop_handle().insert_idle(move |state| {
Shell::resize_request(
state,
let res = state.common.shell.write().unwrap().resize_request(
&surface,
&seat,
serial,
@ -750,7 +758,17 @@ impl PointerTarget<State> for CosmicWindow {
Focus::ResizeRight => ResizeEdge::RIGHT,
Focus::Header => unreachable!(),
},
)
);
if let Some((grab, focus)) = res {
if grab.is_touch_grab() {
seat.get_touch().unwrap().set_grab(state, grab, serial);
} else {
seat.get_pointer()
.unwrap()
.set_grab(state, grab, serial, focus);
}
}
});
}
None => {}

View file

@ -107,9 +107,13 @@ impl Shell {
) {
let element = match target {
Some(KeyboardFocusTarget::Element(mapped)) => Some(mapped.clone()),
Some(KeyboardFocusTarget::Fullscreen(window)) => {
state.common.shell.element_for_surface(window).cloned()
}
Some(KeyboardFocusTarget::Fullscreen(window)) => state
.common
.shell
.read()
.unwrap()
.element_for_surface(window)
.cloned(),
_ => None,
};
@ -117,7 +121,12 @@ impl Shell {
if mapped.is_minimized() {
return;
}
state.common.shell.append_focus_stack(&mapped, seat);
state
.common
.shell
.write()
.unwrap()
.append_focus_stack(&mapped, seat);
}
// update keyboard focus
@ -130,7 +139,7 @@ impl Shell {
);
}
state.common.shell.update_active();
state.common.shell.write().unwrap().update_active();
}
pub fn append_focus_stack(&mut self, mapped: &CosmicMapped, seat: &Seat<State>) {
@ -233,25 +242,27 @@ fn raise_with_children(floating_layer: &mut FloatingLayout, focused: &CosmicMapp
impl Common {
pub fn refresh_focus(state: &mut State) {
for seat in state
let seats = state
.common
.shell
.read()
.unwrap()
.seats
.iter()
.cloned()
.collect::<Vec<_>>()
.into_iter()
{
.collect::<Vec<_>>();
for seat in seats.into_iter() {
let mut shell = state.common.shell.write().unwrap();
let output = seat.active_output();
if !state.common.shell.outputs().any(|o| o == &output) {
seat.set_active_output(&state.common.shell.outputs().next().unwrap());
if !shell.outputs().any(|o| o == &output) {
seat.set_active_output(&shell.outputs().next().unwrap());
continue;
}
let last_known_focus = ActiveFocus::get(&seat);
if let Some(target) = last_known_focus {
if target.alive() {
if focus_target_is_valid(&mut state.common.shell, &seat, &output, target) {
if focus_target_is_valid(&mut *shell, &seat, &output, target) {
continue; // Focus is valid
} else {
trace!("Wrong Window, focus fixup");
@ -266,6 +277,8 @@ impl Common {
if !popup_grab.has_ended() {
if let Some(new) = popup_grab.current_grab() {
trace!("restore focus to previous popup grab");
std::mem::drop(shell);
if let Some(keyboard) = seat.get_keyboard() {
keyboard.set_focus(
state,
@ -285,7 +298,7 @@ impl Common {
trace!("Surface dead, focus fixup");
}
} else {
let workspace = state.common.shell.active_space(&output);
let workspace = shell.active_space(&output);
let focus_stack = workspace.focus_stack.get(&seat);
if focus_stack.last().is_none() {
@ -309,7 +322,9 @@ impl Common {
}
// update keyboard focus
let target = update_focus_target(&state.common.shell, &seat, &output);
let target = update_focus_target(&*shell, &seat, &output);
std::mem::drop(shell);
if let Some(keyboard) = seat.get_keyboard() {
debug!("Restoring focus to {:?}", target.as_ref());
keyboard.set_focus(state, target.clone(), SERIAL_COUNTER.next_serial());
@ -318,7 +333,7 @@ impl Common {
}
}
state.common.shell.update_active()
state.common.shell.write().unwrap().update_active()
}
}

View file

@ -132,7 +132,7 @@ impl PointerFocusTarget {
}
}
pub fn toplevel(&self, data: &mut State) -> Option<CosmicSurface> {
pub fn toplevel(&self, shell: &Shell) -> Option<CosmicSurface> {
match &self {
PointerFocusTarget::WlSurface {
toplevel: Some(PointerFocusToplevel::Surface(surface)),
@ -142,12 +142,7 @@ impl PointerFocusTarget {
toplevel: Some(PointerFocusToplevel::Popup(PopupKind::Xdg(popup))),
..
} => get_popup_toplevel(popup)
.and_then(|s| {
data.common
.shell
.element_for_surface(&s)
.map(|mapped| (mapped, s))
})
.and_then(|s| shell.element_for_surface(&s).map(|mapped| (mapped, s)))
.and_then(|(m, s)| {
m.windows()
.find(|(w, _)| w.wl_surface().map(|s2| s == s2).unwrap_or(false))
@ -210,7 +205,8 @@ impl IsAlive for KeyboardFocusTarget {
impl PointerTarget<State> for PointerFocusTarget {
fn enter(&self, seat: &Seat<State>, data: &mut State, event: &PointerMotionEvent) {
if let Some(element) = self.toplevel(data) {
let toplevel = self.toplevel(&*data.common.shell.read().unwrap());
if let Some(element) = toplevel {
for session in element.cursor_sessions() {
session.set_cursor_pos(Some(
event
@ -238,7 +234,8 @@ impl PointerTarget<State> for PointerFocusTarget {
}
}
fn motion(&self, seat: &Seat<State>, data: &mut State, event: &PointerMotionEvent) {
if let Some(element) = self.toplevel(data) {
let toplevel = self.toplevel(&*data.common.shell.read().unwrap());
if let Some(element) = toplevel {
for session in element.cursor_sessions() {
session.set_cursor_pos(Some(
event
@ -308,7 +305,8 @@ impl PointerTarget<State> for PointerFocusTarget {
}
}
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial, time: u32) {
if let Some(element) = self.toplevel(data) {
let toplevel = self.toplevel(&*data.common.shell.read().unwrap());
if let Some(element) = toplevel {
for session in element.cursor_sessions() {
session.set_cursor_pos(None);
session.set_cursor_hotspot((0, 0));

View file

@ -1,4 +1,4 @@
use smithay::wayland::seat::WaylandFocus;
use smithay::{input::pointer::MotionEvent, utils::SERIAL_COUNTER, wayland::seat::WaylandFocus};
use crate::{
config::{Action, StaticConfig},
@ -6,7 +6,7 @@ use crate::{
shell::{
element::{CosmicMapped, CosmicWindow},
grabs::ReleaseMode,
CosmicSurface, Shell,
CosmicSurface, PointGlobalExt, Shell,
},
state::State,
utils::{prelude::SeatExt, screenshot::screenshot_window},
@ -15,61 +15,57 @@ use crate::{
use super::{Item, ResizeEdge};
fn toggle_stacking(state: &mut State, mapped: &CosmicMapped) {
let seat = state.common.shell.seats.last_active().clone();
if let Some(new_focus) = state.common.shell.toggle_stacking(mapped) {
let mut shell = state.common.shell.write().unwrap();
let seat = shell.seats.last_active().clone();
if let Some(new_focus) = shell.toggle_stacking(mapped) {
std::mem::drop(shell);
Shell::set_focus(state, Some(&new_focus), &seat, None);
}
}
fn move_prev_workspace(state: &mut State, mapped: &CosmicMapped) {
let seat = state.common.shell.seats.last_active().clone();
let mut shell = state.common.shell.write().unwrap();
let seat = shell.seats.last_active().clone();
let (current_handle, output) = {
let Some(ws) = state.common.shell.space_for(mapped) else {
let Some(ws) = shell.space_for(mapped) else {
return;
};
(ws.handle, ws.output.clone())
};
let maybe_handle = state
.common
.shell
let maybe_handle = shell
.workspaces
.spaces_for_output(&output)
.enumerate()
.find_map(|(i, space)| (space.handle == current_handle).then_some(i))
.and_then(|i| i.checked_sub(1))
.and_then(|i| {
state
.common
.shell
.workspaces
.get(i, &output)
.map(|s| s.handle)
});
.and_then(|i| shell.workspaces.get(i, &output).map(|s| s.handle));
if let Some(prev_handle) = maybe_handle {
if let Some((target, _)) = state.common.shell.move_window(
let res = shell.move_window(
Some(&seat),
mapped,
&current_handle,
&prev_handle,
true,
None,
) {
&mut state.common.workspace_state.update(),
);
if let Some((target, _)) = res {
std::mem::drop(shell);
Shell::set_focus(state, Some(&target), &seat, None);
}
}
}
fn move_next_workspace(state: &mut State, mapped: &CosmicMapped) {
let seat = state.common.shell.seats.last_active().clone();
let mut shell = state.common.shell.write().unwrap();
let seat = shell.seats.last_active().clone();
let (current_handle, output) = {
let Some(ws) = state.common.shell.space_for(mapped) else {
let Some(ws) = shell.space_for(mapped) else {
return;
};
(ws.handle, ws.output.clone())
};
let maybe_handle = state
.common
.shell
let maybe_handle = shell
.workspaces
.spaces_for_output(&output)
.skip_while(|space| space.handle != current_handle)
@ -77,14 +73,17 @@ fn move_next_workspace(state: &mut State, mapped: &CosmicMapped) {
.next()
.map(|space| space.handle);
if let Some(next_handle) = maybe_handle {
if let Some((target, _point)) = state.common.shell.move_window(
let res = shell.move_window(
Some(&seat),
mapped,
&current_handle,
&next_handle,
true,
None,
) {
&mut state.common.workspace_state.update(),
);
if let Some((target, _point)) = res {
std::mem::drop(shell);
Shell::set_focus(state, Some(&target), &seat, None)
}
}
@ -114,9 +113,10 @@ pub fn tab_items(
)
.into();
let seat = state.common.shell.seats.last_active();
let mut shell = state.common.shell.write().unwrap();
let seat = shell.seats.last_active().clone();
let output = seat.active_output();
let workspace = state.common.shell.workspaces.active_mut(&output);
let workspace = shell.workspaces.active_mut(&output);
if is_tiled {
for mapped in workspace
.mapped()
@ -127,7 +127,7 @@ pub fn tab_items(
{
workspace.unmaximize_request(&mapped);
}
let focus_stack = workspace.focus_stack.get(seat);
let focus_stack = workspace.focus_stack.get(&seat);
workspace
.tiling_layer
.map(mapped, Some(focus_stack.iter()), None);
@ -197,7 +197,12 @@ pub fn window_items(
Item::new(fl!("window-menu-minimize"), move |handle| {
let mapped = minimize_clone.clone();
let _ = handle.insert_idle(move |state| {
state.common.shell.minimize_request(&mapped);
state
.common
.shell
.write()
.unwrap()
.minimize_request(&mapped);
});
})
.shortcut(config.get_shortcut_for_action(&Action::Minimize)),
@ -206,8 +211,9 @@ pub fn window_items(
Item::new(fl!("window-menu-maximize"), move |handle| {
let mapped = maximize_clone.clone();
let _ = handle.insert_idle(move |state| {
let seat = state.common.shell.seats.last_active().clone();
state.common.shell.maximize_toggle(&mapped, &seat);
let mut shell = state.common.shell.write().unwrap();
let seat = shell.seats.last_active().clone();
shell.maximize_toggle(&mapped, &seat);
});
})
.shortcut(config.get_shortcut_for_action(&Action::Maximize))
@ -217,8 +223,9 @@ pub fn window_items(
Item::new(fl!("window-menu-tiled"), move |handle| {
let tile_clone = tile_clone.clone();
let _ = handle.insert_idle(move |state| {
let seat = state.common.shell.seats.last_active().clone();
if let Some(ws) = state.common.shell.space_for_mut(&tile_clone) {
let mut shell = state.common.shell.write().unwrap();
let seat = shell.seats.last_active().clone();
if let Some(ws) = shell.space_for_mut(&tile_clone) {
ws.toggle_floating_window(&seat, &tile_clone);
}
});
@ -238,8 +245,36 @@ pub fn window_items(
let move_clone = move_clone.clone();
let _ = handle.insert_idle(move |state| {
if let Some(surface) = move_clone.wl_surface() {
let seat = state.common.shell.seats.last_active().clone();
Shell::move_request(state, &surface, &seat, None, ReleaseMode::Click, false);
let mut shell = state.common.shell.write().unwrap();
let seat = shell.seats.last_active().clone();
let res = shell.move_request(
&surface,
&seat,
None,
ReleaseMode::Click,
false,
&state.common.config,
&state.common.event_loop_handle,
&state.common.xdg_activation_state,
);
std::mem::drop(shell);
if let Some((grab, focus)) = res {
if grab.is_touch_grab() {
seat.get_touch().unwrap().set_grab(
state,
grab,
SERIAL_COUNTER.next_serial(),
)
} else {
seat.get_pointer().unwrap().set_grab(
state,
grab,
SERIAL_COUNTER.next_serial(),
focus,
);
}
}
}
});
})),
@ -249,32 +284,122 @@ pub fn window_items(
Item::new(fl!("window-menu-resize-edge-top"), move |handle| {
let resize_clone = resize_top_clone.clone();
let _ = handle.insert_idle(move |state| {
let seat = state.common.shell.seats.last_active().clone();
Shell::menu_resize_request(state, &resize_clone, &seat, ResizeEdge::TOP);
let mut shell = state.common.shell.write().unwrap();
let seat = shell.seats.last_active().clone();
let res = shell.menu_resize_request(&resize_clone, &seat, ResizeEdge::TOP);
std::mem::drop(shell);
if let Some(((target, loc), (grab, focus))) = res {
let serial = SERIAL_COUNTER.next_serial();
if grab.is_touch_grab() {
seat.get_touch().unwrap().set_grab(state, grab, serial);
} else {
let pointer = seat.get_pointer().unwrap();
pointer.motion(
state,
target,
&MotionEvent {
location: loc.as_logical().to_f64(),
serial,
time: 0,
},
);
pointer.frame(state);
pointer.set_grab(state, grab, serial, focus);
}
}
});
})
.disabled(!possible_resizes.contains(ResizeEdge::TOP)),
Item::new(fl!("window-menu-resize-edge-left"), move |handle| {
let resize_clone = resize_left_clone.clone();
let _ = handle.insert_idle(move |state| {
let seat = state.common.shell.seats.last_active().clone();
Shell::menu_resize_request(state, &resize_clone, &seat, ResizeEdge::LEFT);
let mut shell = state.common.shell.write().unwrap();
let seat = shell.seats.last_active().clone();
let res = shell.menu_resize_request(&resize_clone, &seat, ResizeEdge::LEFT);
std::mem::drop(shell);
if let Some(((target, loc), (grab, focus))) = res {
let serial = SERIAL_COUNTER.next_serial();
if grab.is_touch_grab() {
seat.get_touch().unwrap().set_grab(state, grab, serial);
} else {
let pointer = seat.get_pointer().unwrap();
pointer.motion(
state,
target,
&MotionEvent {
location: loc.as_logical().to_f64(),
serial,
time: 0,
},
);
pointer.frame(state);
pointer.set_grab(state, grab, serial, focus);
}
}
});
})
.disabled(!possible_resizes.contains(ResizeEdge::LEFT)),
Item::new(fl!("window-menu-resize-edge-right"), move |handle| {
let resize_clone = resize_right_clone.clone();
let _ = handle.insert_idle(move |state| {
let seat = state.common.shell.seats.last_active().clone();
Shell::menu_resize_request(state, &resize_clone, &seat, ResizeEdge::RIGHT);
let mut shell = state.common.shell.write().unwrap();
let seat = shell.seats.last_active().clone();
let res =
shell.menu_resize_request(&resize_clone, &seat, ResizeEdge::RIGHT);
std::mem::drop(shell);
if let Some(((target, loc), (grab, focus))) = res {
let serial = SERIAL_COUNTER.next_serial();
if grab.is_touch_grab() {
seat.get_touch().unwrap().set_grab(state, grab, serial);
} else {
let pointer = seat.get_pointer().unwrap();
pointer.motion(
state,
target,
&MotionEvent {
location: loc.as_logical().to_f64(),
serial,
time: 0,
},
);
pointer.frame(state);
pointer.set_grab(state, grab, serial, focus);
}
}
});
})
.disabled(!possible_resizes.contains(ResizeEdge::RIGHT)),
Item::new(fl!("window-menu-resize-edge-bottom"), move |handle| {
let resize_clone = resize_bottom_clone.clone();
let _ = handle.insert_idle(move |state| {
let seat = state.common.shell.seats.last_active().clone();
Shell::menu_resize_request(state, &resize_clone, &seat, ResizeEdge::BOTTOM);
let mut shell = state.common.shell.write().unwrap();
let seat = shell.seats.last_active().clone();
let res =
shell.menu_resize_request(&resize_clone, &seat, ResizeEdge::BOTTOM);
std::mem::drop(shell);
if let Some(((target, loc), (grab, focus))) = res {
let serial = SERIAL_COUNTER.next_serial();
if grab.is_touch_grab() {
seat.get_touch().unwrap().set_grab(state, grab, serial);
} else {
let pointer = seat.get_pointer().unwrap();
pointer.motion(
state,
target,
&MotionEvent {
location: loc.as_logical().to_f64(),
serial,
time: 0,
},
);
pointer.frame(state);
pointer.set_grab(state, grab, serial, focus);
}
}
});
})
.disabled(!possible_resizes.contains(ResizeEdge::BOTTOM)),
@ -301,8 +426,9 @@ pub fn window_items(
Item::new(fl!("window-menu-sticky"), move |handle| {
let mapped = sticky_clone.clone();
let _ = handle.insert_idle(move |state| {
let seat = state.common.shell.seats.last_active().clone();
state.common.shell.toggle_sticky(&seat, &mapped);
let mut shell = state.common.shell.write().unwrap();
let seat = shell.seats.last_active().clone();
shell.toggle_sticky(&seat, &mapped);
});
})
.toggled(is_sticky),

View file

@ -216,7 +216,14 @@ impl Program for ContextMenu {
if let Some(Item::Submenu { items, .. }) = self.items.get_mut(idx) {
let items = items.clone();
let _ = loop_handle.insert_idle(move |state| {
let seat = state.common.shell.seats.last_active();
let seat = state
.common
.shell
.read()
.unwrap()
.seats
.last_active()
.clone();
let grab_state = seat
.user_data()
.get::<SeatMenuGrabState>()
@ -301,7 +308,14 @@ impl Program for ContextMenu {
Message::ItemLeft(idx, _) => {
if let Some(Item::Submenu { .. }) = self.items.get_mut(idx) {
let _ = loop_handle.insert_idle(|state| {
let seat = state.common.shell.seats.last_active();
let seat = state
.common
.shell
.read()
.unwrap()
.seats
.last_active()
.clone();
let grab_state = seat
.user_data()
.get::<SeatMenuGrabState>()

View file

@ -153,6 +153,15 @@ impl From<ResizeForkGrab> for ResizeGrab {
}
}
impl ResizeGrab {
pub fn is_touch_grab(&self) -> bool {
match self {
ResizeGrab::Floating(grab) => grab.is_touch_grab(),
ResizeGrab::Tiling(grab) => grab.is_touch_grab(),
}
}
}
impl PointerGrab<State> for ResizeGrab {
fn motion(
&mut self,

View file

@ -16,6 +16,7 @@ use crate::{
CosmicMapped, CosmicSurface, Direction, ManagedLayer,
},
utils::prelude::*,
wayland::protocols::toplevel_info::{toplevel_enter_output, toplevel_enter_workspace},
};
use calloop::LoopHandle;
@ -326,10 +327,10 @@ pub struct MoveGrab {
impl MoveGrab {
fn update_location(&mut self, state: &mut State, location: Point<f64, Logical>) {
let mut shell = state.common.shell.write().unwrap();
let Some(current_output) =
state
.common
.shell
shell
.outputs()
.find(|output| {
output.geometry().as_logical().overlaps_or_touches(
@ -341,9 +342,7 @@ impl MoveGrab {
return;
};
if self.cursor_output != current_output {
state
.common
.shell
shell
.workspaces
.active_mut(&self.cursor_output)
.tiling_layer
@ -362,7 +361,7 @@ impl MoveGrab {
let mut window_geo = self.window.geometry();
window_geo.loc += location.to_i32_round() + grab_state.window_offset;
for output in state.common.shell.outputs() {
for output in shell.outputs() {
if let Some(overlap) = output.geometry().as_logical().intersection(window_geo) {
if self.window_outputs.insert(output.clone()) {
self.window.output_enter(output, overlap);
@ -380,10 +379,7 @@ impl MoveGrab {
}
}
let indicator_location = state
.common
.shell
.stacking_indicator(&current_output, self.previous);
let indicator_location = shell.stacking_indicator(&current_output, self.previous);
if indicator_location.is_some() != grab_state.stacking_indicator.is_some() {
grab_state.stacking_indicator = indicator_location.map(|geo| {
let element = stack_hover(
@ -695,6 +691,13 @@ impl MoveGrab {
pub fn is_tiling_grab(&self) -> bool {
self.previous == ManagedLayer::Tiling
}
pub fn is_touch_grab(&self) -> bool {
match self.start_data {
GrabStartData::Touch(_) => true,
GrabStartData::Pointer(_) => false,
}
}
}
impl Drop for MoveGrab {
@ -716,23 +719,17 @@ impl Drop for MoveGrab {
if grab_state.window.alive() {
let window_location =
(grab_state.location.to_i32_round() + grab_state.window_offset).as_global();
let mut shell = state.common.shell.write().unwrap();
let workspace_handle = state.common.shell.active_space(&output).handle;
let workspace_handle = shell.active_space(&output).handle;
for old_output in window_outputs.iter().filter(|o| *o != &output) {
grab_state.window.output_leave(old_output);
}
for (window, _) in grab_state.window.windows() {
state
.common
.shell
.toplevel_info_state
.toplevel_enter_output(&window, &output);
toplevel_enter_output(&window, &output);
if previous != ManagedLayer::Sticky {
state
.common
.shell
.toplevel_info_state
.toplevel_enter_workspace(&window, &workspace_handle);
toplevel_enter_workspace(&window, &workspace_handle);
}
}
@ -742,19 +739,15 @@ impl Drop for MoveGrab {
window_location,
grab_state.window.geometry().size.as_global(),
));
let set = state.common.shell.workspaces.sets.get_mut(&output).unwrap();
let set = shell.workspaces.sets.get_mut(&output).unwrap();
let (window, location) = set
.sticky_layer
.drop_window(grab_state.window, window_location.to_local(&output));
Some((window, location.to_global(&output)))
}
ManagedLayer::Tiling
if state.common.shell.active_space(&output).tiling_enabled =>
{
let (window, location) = state
.common
.shell
ManagedLayer::Tiling if shell.active_space(&output).tiling_enabled => {
let (window, location) = shell
.active_space_mut(&output)
.tiling_layer
.drop_window(grab_state.window);
@ -765,8 +758,8 @@ impl Drop for MoveGrab {
window_location,
grab_state.window.geometry().size.as_global(),
));
let theme = state.common.shell.theme.clone();
let workspace = state.common.shell.active_space_mut(&output);
let theme = shell.theme.clone();
let workspace = shell.active_space_mut(&output);
let (window, location) = workspace.floating_layer.drop_window(
grab_state.window,
window_location.to_local(&workspace.output),
@ -775,7 +768,7 @@ impl Drop for MoveGrab {
if previous == ManagedLayer::Floating {
if let Some(sz) = grab_state.snapping_zone {
if sz == SnappingZone::Maximize {
state.common.shell.maximize_toggle(&window, &seat);
shell.maximize_toggle(&window, &seat);
} else {
let directions = match sz {
SnappingZone::Maximize => vec![],

View file

@ -123,6 +123,13 @@ impl ResizeSurfaceGrab {
false
}
pub fn is_touch_grab(&self) -> bool {
match self.start_data {
GrabStartData::Touch(_) => true,
GrabStartData::Pointer(_) => false,
}
}
}
impl PointerGrab<State> for ResizeSurfaceGrab {

View file

@ -218,7 +218,8 @@ impl ResizeForkGrab {
let delta = location - self.last_loc.as_logical();
if let Some(output) = self.output.upgrade() {
let tiling_layer = &mut data.common.shell.active_space_mut(&output).tiling_layer;
let mut shell = data.common.shell.write().unwrap();
let tiling_layer = &mut shell.active_space_mut(&output).tiling_layer;
let gaps = tiling_layer.gaps();
let tree = &mut tiling_layer.queue.trees.back_mut().unwrap().0;
@ -321,6 +322,13 @@ impl ResizeForkGrab {
}
false
}
pub fn is_touch_grab(&self) -> bool {
match self.start_data {
GrabStartData::Touch(_) => true,
GrabStartData::Pointer(_) => false,
}
}
}
impl PointerGrab<State> for ResizeForkGrab {

View file

@ -39,7 +39,7 @@ impl KeyboardGrab<State> for SwapWindowGrab {
serial: Serial,
time: u32,
) {
if !matches!(&data.common.shell.overview_mode, OverviewMode::Started(Trigger::KeyboardSwap(_, d), _) if d == &self.desc)
if !matches!(&data.common.shell.read().unwrap().overview_mode, OverviewMode::Started(Trigger::KeyboardSwap(_, d), _) if d == &self.desc)
{
handle.unset_grab(data, serial, false);
return;

View file

@ -28,7 +28,13 @@ use crate::{
utils::{prelude::*, tween::EaseRectangle},
wayland::{
handlers::xdg_shell::popup::get_popup_toplevel,
protocols::{toplevel_info::ToplevelInfoState, workspace::WorkspaceHandle},
protocols::{
toplevel_info::{
toplevel_enter_output, toplevel_enter_workspace, toplevel_leave_output,
toplevel_leave_workspace,
},
workspace::WorkspaceHandle,
},
},
};
@ -633,7 +639,6 @@ impl TilingLayout {
seat: &Seat<State>,
focus_stack: impl Iterator<Item = &'a CosmicMapped> + 'a,
desc: NodeDesc,
toplevel_info_state: &mut ToplevelInfoState<State, CosmicSurface>,
) -> Option<KeyboardFocusTarget> {
let this_handle = &desc.handle;
let mut this_tree = this.queue.trees.back().unwrap().0.copy_clone();
@ -662,13 +667,13 @@ impl TilingLayout {
mapped.output_leave(&this.output);
mapped.output_enter(&other.output, mapped.bbox());
for (ref surface, _) in mapped.windows() {
toplevel_info_state.toplevel_leave_output(surface, &this.output);
toplevel_info_state.toplevel_enter_output(surface, &other.output);
toplevel_leave_output(surface, &this.output);
toplevel_enter_output(surface, &other.output);
}
}
for (ref surface, _) in mapped.windows() {
toplevel_info_state.toplevel_leave_workspace(surface, this_handle);
toplevel_info_state.toplevel_enter_workspace(surface, other_handle);
toplevel_leave_workspace(surface, this_handle);
toplevel_enter_workspace(surface, other_handle);
}
mapped.set_tiled(true);
@ -725,13 +730,13 @@ impl TilingLayout {
mapped.output_leave(&this.output);
mapped.output_enter(&other.output, mapped.bbox());
for (ref surface, _) in mapped.windows() {
toplevel_info_state.toplevel_leave_output(surface, &this.output);
toplevel_info_state.toplevel_enter_output(surface, &other.output);
toplevel_leave_output(surface, &this.output);
toplevel_enter_output(surface, &other.output);
}
}
for (ref surface, _) in mapped.windows() {
toplevel_info_state.toplevel_leave_workspace(surface, this_handle);
toplevel_info_state.toplevel_enter_workspace(surface, other_handle);
toplevel_leave_workspace(surface, this_handle);
toplevel_enter_workspace(surface, other_handle);
}
*mapped.tiling_node_id.lock().unwrap() = Some(id.clone());
@ -759,15 +764,13 @@ impl TilingLayout {
mapped.output_leave(&this.output);
mapped.output_enter(&other.output, mapped.bbox());
for (ref surface, _) in mapped.windows() {
toplevel_info_state
.toplevel_leave_output(surface, &this.output);
toplevel_info_state
.toplevel_enter_output(surface, &other.output);
toplevel_leave_output(surface, &this.output);
toplevel_enter_output(surface, &other.output);
}
}
for (ref surface, _) in mapped.windows() {
toplevel_info_state.toplevel_leave_workspace(surface, this_handle);
toplevel_info_state.toplevel_enter_workspace(surface, other_handle);
toplevel_leave_workspace(surface, this_handle);
toplevel_enter_workspace(surface, other_handle);
}
*mapped.tiling_node_id.lock().unwrap() = Some(new_id.clone());
@ -806,7 +809,6 @@ impl TilingLayout {
mut other: Option<&mut Self>,
this_desc: &NodeDesc,
other_desc: &NodeDesc,
toplevel_info_state: &mut ToplevelInfoState<State, CosmicSurface>,
) -> Option<KeyboardFocusTarget> {
let other_output = other
.as_ref()
@ -860,13 +862,13 @@ impl TilingLayout {
mapped.output_leave(&other_output);
mapped.output_enter(&this.output, mapped.bbox());
for (ref surface, _) in mapped.windows() {
toplevel_info_state.toplevel_leave_output(surface, &other_output);
toplevel_info_state.toplevel_enter_output(surface, &this.output);
toplevel_leave_output(surface, &other_output);
toplevel_enter_output(surface, &this.output);
}
}
for (ref surface, _) in mapped.windows() {
toplevel_info_state.toplevel_leave_workspace(surface, &other_desc.handle);
toplevel_info_state.toplevel_enter_workspace(surface, &this_desc.handle);
toplevel_leave_workspace(surface, &other_desc.handle);
toplevel_enter_workspace(surface, &this_desc.handle);
}
*mapped.tiling_node_id.lock().unwrap() = Some(this_desc.node.clone());
}
@ -875,13 +877,13 @@ impl TilingLayout {
mapped.output_leave(&this.output);
mapped.output_enter(&other_output, mapped.bbox());
for (ref surface, _) in mapped.windows() {
toplevel_info_state.toplevel_leave_output(surface, &this.output);
toplevel_info_state.toplevel_enter_output(surface, &other_output);
toplevel_leave_output(surface, &this.output);
toplevel_enter_output(surface, &other_output);
}
}
for (ref surface, _) in mapped.windows() {
toplevel_info_state.toplevel_leave_workspace(surface, &this_desc.handle);
toplevel_info_state.toplevel_enter_workspace(surface, &other_desc.handle);
toplevel_leave_workspace(surface, &this_desc.handle);
toplevel_enter_workspace(surface, &other_desc.handle);
}
*mapped.tiling_node_id.lock().unwrap() = Some(other_desc.node.clone());
}
@ -914,17 +916,13 @@ impl TilingLayout {
mapped.output_leave(&this.output);
mapped.output_enter(&other_output, mapped.bbox());
for (ref surface, _) in mapped.windows() {
toplevel_info_state
.toplevel_leave_output(surface, &this.output);
toplevel_info_state
.toplevel_enter_output(surface, &other_output);
toplevel_leave_output(surface, &this.output);
toplevel_enter_output(surface, &other_output);
}
}
for (ref surface, _) in mapped.windows() {
toplevel_info_state
.toplevel_leave_workspace(surface, &this_desc.handle);
toplevel_info_state
.toplevel_enter_workspace(surface, &other_desc.handle);
toplevel_leave_workspace(surface, &this_desc.handle);
toplevel_enter_workspace(surface, &other_desc.handle);
}
*mapped.tiling_node_id.lock().unwrap() = Some(new_id.clone());
}
@ -964,17 +962,13 @@ impl TilingLayout {
mapped.output_leave(&other_output);
mapped.output_enter(&this.output, mapped.bbox());
for (ref surface, _) in mapped.windows() {
toplevel_info_state
.toplevel_leave_output(surface, &other_output);
toplevel_info_state
.toplevel_enter_output(surface, &this.output);
toplevel_leave_output(surface, &other_output);
toplevel_enter_output(surface, &this.output);
}
}
for (ref surface, _) in mapped.windows() {
toplevel_info_state
.toplevel_leave_workspace(surface, &other_desc.handle);
toplevel_info_state
.toplevel_enter_workspace(surface, &this_desc.handle);
toplevel_leave_workspace(surface, &other_desc.handle);
toplevel_enter_workspace(surface, &this_desc.handle);
}
*mapped.tiling_node_id.lock().unwrap() = Some(new_id.clone());
}
@ -1034,23 +1028,23 @@ impl TilingLayout {
if this.output != other_output {
surface.output_leave(&other_output);
surface.output_enter(&this.output, surface.bbox());
toplevel_info_state.toplevel_leave_output(&surface, &other_output);
toplevel_info_state.toplevel_enter_output(&surface, &this.output);
toplevel_leave_output(&surface, &other_output);
toplevel_enter_output(&surface, &this.output);
}
if this_desc.handle != other_desc.handle {
toplevel_info_state.toplevel_leave_workspace(&surface, &other_desc.handle);
toplevel_info_state.toplevel_enter_workspace(&surface, &this_desc.handle);
toplevel_leave_workspace(&surface, &other_desc.handle);
toplevel_enter_workspace(&surface, &this_desc.handle);
}
this_stack.add_window(surface, Some(this_idx + i));
}
if this.output != other_output {
this_surface.output_leave(&this.output);
toplevel_info_state.toplevel_leave_output(&this_surface, &this.output);
toplevel_info_state.toplevel_enter_output(&this_surface, &other_output);
toplevel_leave_output(this_surface, &this.output);
toplevel_enter_output(this_surface, &other_output);
}
if this_desc.handle != other_desc.handle {
toplevel_info_state.toplevel_leave_workspace(&this_surface, &this_desc.handle);
toplevel_info_state.toplevel_enter_workspace(&this_surface, &other_desc.handle);
toplevel_leave_workspace(this_surface, &this_desc.handle);
toplevel_enter_workspace(this_surface, &other_desc.handle);
}
this_stack.remove_window(&this_surface);
@ -1121,24 +1115,23 @@ impl TilingLayout {
if this.output != other_output {
surface.output_leave(&this.output);
surface.output_enter(&other_output, surface.bbox());
toplevel_info_state.toplevel_leave_output(&surface, &this.output);
toplevel_info_state.toplevel_enter_output(&surface, &other_output);
toplevel_leave_output(&surface, &this.output);
toplevel_enter_output(&surface, &other_output);
}
if this_desc.handle != other_desc.handle {
toplevel_info_state.toplevel_leave_workspace(&surface, &this_desc.handle);
toplevel_info_state.toplevel_enter_workspace(&surface, &other_desc.handle);
toplevel_leave_workspace(&surface, &this_desc.handle);
toplevel_enter_workspace(&surface, &other_desc.handle);
}
other_stack.add_window(surface, Some(other_idx + i));
}
if this.output != other_output {
other_surface.output_leave(&other_output);
toplevel_info_state.toplevel_leave_output(&other_surface, &other_output);
toplevel_info_state.toplevel_enter_output(&other_surface, &this.output);
toplevel_leave_output(other_surface, &other_output);
toplevel_enter_output(other_surface, &this.output);
}
if this_desc.handle != other_desc.handle {
toplevel_info_state
.toplevel_leave_workspace(&other_surface, &other_desc.handle);
toplevel_info_state.toplevel_enter_workspace(&other_surface, &this_desc.handle);
toplevel_leave_workspace(other_surface, &other_desc.handle);
toplevel_enter_workspace(other_surface, &this_desc.handle);
}
other_stack.remove_window(&other_surface);
@ -1205,17 +1198,16 @@ impl TilingLayout {
other_stack.add_window(this_surface.clone(), Some(other_idx));
if this.output != other_output {
toplevel_info_state.toplevel_leave_output(&this_surface, &this.output);
toplevel_info_state.toplevel_leave_output(&other_surface, &other_output);
toplevel_info_state.toplevel_enter_output(&this_surface, &other_output);
toplevel_info_state.toplevel_enter_output(&other_surface, &this.output);
toplevel_leave_output(this_surface, &this.output);
toplevel_leave_output(other_surface, &other_output);
toplevel_enter_output(this_surface, &other_output);
toplevel_enter_output(other_surface, &this.output);
}
if this_desc.handle != other_desc.handle {
toplevel_info_state.toplevel_leave_workspace(&this_surface, &this_desc.handle);
toplevel_info_state
.toplevel_leave_workspace(&other_surface, &other_desc.handle);
toplevel_info_state.toplevel_enter_workspace(&this_surface, &other_desc.handle);
toplevel_info_state.toplevel_enter_workspace(&other_surface, &this_desc.handle);
toplevel_leave_workspace(this_surface, &this_desc.handle);
toplevel_leave_workspace(other_surface, &other_desc.handle);
toplevel_enter_workspace(this_surface, &other_desc.handle);
toplevel_enter_workspace(other_surface, &this_desc.handle);
}
other_stack.remove_window(&other_surface);
@ -1802,7 +1794,7 @@ impl TilingLayout {
}
pub fn next_focus<'a>(
&mut self,
&self,
direction: FocusDirection,
seat: &Seat<State>,
focus_stack: impl Iterator<Item = &'a CosmicMapped> + 'a,

File diff suppressed because it is too large Load diff

View file

@ -206,6 +206,8 @@ pub trait SeatExt {
fn active_output(&self) -> Output;
fn set_active_output(&self, output: &Output);
fn devices(&self) -> &Devices;
fn supressed_keys(&self) -> &SupressedKeys;
fn modifiers_shortcut_queue(&self) -> &ModifiersShortcutQueue;
fn cursor_geometry(
&self,
@ -239,6 +241,14 @@ impl SeatExt for Seat<State> {
self.user_data().get::<Devices>().unwrap()
}
fn supressed_keys(&self) -> &SupressedKeys {
self.user_data().get::<SupressedKeys>().unwrap()
}
fn modifiers_shortcut_queue(&self) -> &ModifiersShortcutQueue {
self.user_data().get::<ModifiersShortcutQueue>().unwrap()
}
fn cursor_geometry(
&self,
loc: impl Into<Point<f64, Buffer>>,

View file

@ -12,7 +12,7 @@ use crate::{
wayland::{
handlers::screencopy::ScreencopySessions,
protocols::{
toplevel_info::ToplevelInfoState,
toplevel_info::{toplevel_enter_output, toplevel_leave_output},
workspace::{WorkspaceHandle, WorkspaceUpdateGuard},
},
},
@ -365,23 +365,19 @@ impl Workspace {
&self.output
}
pub fn set_output(
&mut self,
output: &Output,
toplevel_info: &mut ToplevelInfoState<State, CosmicSurface>,
) {
pub fn set_output(&mut self, output: &Output) {
self.tiling_layer.set_output(output);
self.floating_layer.set_output(output);
for mapped in self.mapped() {
for (surface, _) in mapped.windows() {
toplevel_info.toplevel_leave_output(&surface, &self.output);
toplevel_info.toplevel_enter_output(&surface, output);
toplevel_leave_output(&surface, &self.output);
toplevel_enter_output(&surface, output);
}
}
for window in self.minimized_windows.iter() {
for (surface, _) in window.window.windows() {
toplevel_info.toplevel_leave_output(&surface, &self.output);
toplevel_info.toplevel_enter_output(&surface, output);
toplevel_leave_output(&surface, &self.output);
toplevel_enter_output(&surface, output);
}
}
let output_name = output.name();

View file

@ -4,12 +4,17 @@ use crate::{
backend::{kms::KmsState, winit::WinitState, x11::X11State},
config::{Config, OutputConfig},
input::gestures::GestureState,
shell::{grabs::SeatMoveGrabState, SeatExt, Shell},
shell::{grabs::SeatMoveGrabState, CosmicSurface, SeatExt, Shell},
wayland::protocols::{
drm::WlDrmState, image_source::ImageSourceState,
output_configuration::OutputConfigurationState, screencopy::ScreencopyState,
workspace::WorkspaceClientState,
drm::WlDrmState,
image_source::ImageSourceState,
output_configuration::OutputConfigurationState,
screencopy::ScreencopyState,
toplevel_info::ToplevelInfoState,
toplevel_management::{ManagementCapabilities, ToplevelManagementState},
workspace::{WorkspaceClientState, WorkspaceState, WorkspaceUpdateGuard},
},
xwayland::XWaylandState,
};
use anyhow::Context;
use i18n_embed::{
@ -41,11 +46,13 @@ use smithay::{
take_presentation_feedback_surface_tree, update_surface_primary_scanout_output,
with_surfaces_surface_tree, OutputPresentationFeedback,
},
PopupManager,
},
input::{pointer::CursorImageStatus, SeatState},
output::{Mode as OutputMode, Output, Scale},
reexports::{
calloop::{LoopHandle, LoopSignal},
wayland_protocols::xdg::shell::server::xdg_toplevel::WmCapabilities,
wayland_protocols_misc::server_decoration::server::org_kde_kwin_server_decoration_manager::Mode,
wayland_server::{
backend::{ClientData, ClientId, DisconnectReason},
@ -71,12 +78,17 @@ use smithay::{
wlr_data_control::DataControlState,
},
session_lock::SessionLockManagerState,
shell::{kde::decoration::KdeDecorationState, xdg::decoration::XdgDecorationState},
shell::{
kde::decoration::KdeDecorationState,
wlr_layer::WlrLayerShellState,
xdg::{decoration::XdgDecorationState, XdgShellState},
},
shm::ShmState,
tablet_manager::TabletManagerState,
text_input::TextInputManagerState,
viewporter::ViewporterState,
virtual_keyboard::VirtualKeyboardManagerState,
xdg_activation::XdgActivationState,
xwayland_keyboard_grab::XWaylandKeyboardGrabState,
},
xwayland::XWaylandClientData,
@ -84,6 +96,7 @@ use smithay::{
use time::UtcOffset;
use tracing::error;
use std::sync::{Arc, RwLock};
use std::{cell::RefCell, ffi::OsString, time::Duration};
use std::{collections::VecDeque, time::Instant};
@ -147,7 +160,8 @@ pub struct Common {
pub event_loop_handle: LoopHandle<'static, State>,
pub event_loop_signal: LoopSignal,
pub shell: Shell,
pub popups: PopupManager,
pub shell: Arc<RwLock<Shell>>,
pub clock: Clock<Monotonic>,
pub should_stop: bool,
@ -179,6 +193,15 @@ pub struct Common {
pub viewporter_state: ViewporterState,
pub kde_decoration_state: KdeDecorationState,
pub xdg_decoration_state: XdgDecorationState,
// shell-related wayland state
pub xdg_shell_state: XdgShellState,
pub layer_shell_state: WlrLayerShellState,
pub toplevel_info_state: ToplevelInfoState<State, CosmicSurface>,
pub toplevel_management_state: ToplevelManagementState,
pub xdg_activation_state: XdgActivationState,
pub workspace_state: WorkspaceState<State>,
pub xwayland_state: Option<XWaylandState>,
}
#[derive(Debug)]
@ -225,11 +248,18 @@ impl BackendData {
test_only: bool,
shell: &mut Shell,
loop_handle: &LoopHandle<'_, State>,
workspace_state: &mut WorkspaceUpdateGuard<'_, State>,
xdg_activation_state: &XdgActivationState,
) -> Result<(), anyhow::Error> {
let result = match self {
BackendData::Kms(ref mut state) => {
state.apply_config_for_output(output, shell, test_only, loop_handle)
}
BackendData::Kms(ref mut state) => state.apply_config_for_output(
output,
shell,
test_only,
loop_handle,
workspace_state,
xdg_activation_state,
),
BackendData::Winit(ref mut state) => state.apply_config_for_output(output, test_only),
BackendData::X11(ref mut state) => state.apply_config_for_output(output, test_only),
_ => unreachable!("No backend set when applying output config"),
@ -389,7 +419,36 @@ impl State {
DataControlState::new::<Self, _>(dh, Some(&primary_selection_state), |_| true)
});
let shell = Shell::new(&config, dh);
let shell = Arc::new(RwLock::new(Shell::new(&config)));
let layer_shell_state = WlrLayerShellState::new_with_filter::<State, _>(
dh,
client_should_see_privileged_protocols,
);
let xdg_shell_state = XdgShellState::new_with_capabilities::<State>(
dh,
[
WmCapabilities::Fullscreen,
WmCapabilities::Maximize,
WmCapabilities::Minimize,
WmCapabilities::WindowMenu,
],
);
let xdg_activation_state = XdgActivationState::new::<State>(dh);
let toplevel_info_state =
ToplevelInfoState::new(dh, client_should_see_privileged_protocols);
let toplevel_management_state = ToplevelManagementState::new::<State, _>(
dh,
vec![
ManagementCapabilities::Close,
ManagementCapabilities::Activate,
ManagementCapabilities::Maximize,
ManagementCapabilities::Minimize,
ManagementCapabilities::MoveToWorkspace,
],
client_should_see_privileged_protocols,
);
let workspace_state = WorkspaceState::new(dh, client_should_see_privileged_protocols);
if let Err(err) = crate::dbus::init(&handle) {
tracing::warn!(?err, "Failed to initialize dbus handlers");
@ -403,6 +462,7 @@ impl State {
event_loop_handle: handle,
event_loop_signal: signal,
popups: PopupManager::default(),
shell,
local_offset,
@ -441,6 +501,13 @@ impl State {
wl_drm_state,
kde_decoration_state,
xdg_decoration_state,
xdg_shell_state,
layer_shell_state,
toplevel_info_state,
toplevel_management_state,
xdg_activation_state,
workspace_state,
xwayland_state: None,
},
backend: BackendData::Unset,
}
@ -495,8 +562,9 @@ impl Common {
) {
let time = self.clock.now();
let throttle = Some(Duration::from_secs(1));
let shell = self.shell.read().unwrap();
if let Some(session_lock) = self.shell.session_lock.as_ref() {
if let Some(session_lock) = shell.session_lock.as_ref() {
if let Some(lock_surface) = session_lock.surfaces.get(output) {
with_surfaces_surface_tree(lock_surface.wl_surface(), |_surface, states| {
with_fractional_scale(states, |fraction_scale| {
@ -532,8 +600,7 @@ impl Common {
}
}
for seat in self
.shell
for seat in shell
.seats
.iter()
.filter(|seat| &seat.active_output() == output)
@ -595,7 +662,7 @@ impl Common {
}
}
self.shell
shell
.workspaces
.sets
.get(output)
@ -636,7 +703,7 @@ impl Common {
}
});
let active = self.shell.active_space(output);
let active = shell.active_space(output);
active.mapped().for_each(|mapped| {
let window = mapped.active_window();
window.with_surfaces(|surface, states| {
@ -675,8 +742,7 @@ impl Common {
window.send_frame(output, time, throttle, |_, _| None);
});
for space in self
.shell
for space in shell
.workspaces
.spaces_for_output(output)
.filter(|w| w.handle != active.handle)
@ -691,7 +757,7 @@ impl Common {
})
}
self.shell.override_redirect_windows.iter().for_each(|or| {
shell.override_redirect_windows.iter().for_each(|or| {
if let Some(wl_surface) = or.wl_surface() {
with_surfaces_surface_tree(&wl_surface, |surface, states| {
let primary_scanout_output = update_surface_primary_scanout_output(
@ -780,8 +846,9 @@ impl Common {
render_element_states: &RenderElementStates,
) -> OutputPresentationFeedback {
let mut output_presentation_feedback = OutputPresentationFeedback::new(output);
let shell = self.shell.read().unwrap();
let active = self.shell.active_space(output);
let active = shell.active_space(output);
active.mapped().for_each(|mapped| {
mapped.active_window().take_presentation_feedback(
&mut output_presentation_feedback,
@ -792,7 +859,7 @@ impl Common {
);
});
self.shell.override_redirect_windows.iter().for_each(|or| {
shell.override_redirect_windows.iter().for_each(|or| {
if let Some(wl_surface) = or.wl_surface() {
take_presentation_feedback_surface_tree(
&wl_surface,

View file

@ -14,7 +14,6 @@ pub fn ready(state: &State) {
"DISPLAY",
&state
.common
.shell
.xwayland_state
.as_ref()
.map(|s| format!(":{}", s.display))

View file

@ -32,13 +32,12 @@ pub fn watch_theme(handle: LoopHandle<'_, State>) -> Result<(), cosmic_config::E
if theme.theme_type != new_theme.theme_type {
*theme = new_theme;
state.common.shell.set_theme(theme.clone());
state.common.shell.workspaces.spaces().for_each(|s| {
s.mapped().for_each(|m| {
m.update_theme(theme.clone());
m.force_redraw();
})
});
let mut workspace_guard = state.common.workspace_state.update();
state.common.shell.write().unwrap().set_theme(
theme.clone(),
&state.common.xdg_activation_state,
&mut workspace_guard,
);
}
}) {
tracing::error!("{e}");

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()
}

View file

@ -6,14 +6,14 @@ use crate::{
state::State,
utils::prelude::*,
wayland::handlers::{
toplevel_management::ToplevelManagementExt, xdg_activation::ActivationContext,
toplevel_management::minimize_rectangle, xdg_activation::ActivationContext,
},
};
use smithay::{
backend::drm::DrmNode,
desktop::space::SpaceElement,
reexports::x11rb::protocol::xproto::Window as X11Window,
utils::{Logical, Point, Rectangle, Size},
utils::{Logical, Point, Rectangle, Size, SERIAL_COUNTER},
wayland::{
selection::{
data_device::{
@ -45,7 +45,7 @@ pub struct XWaylandState {
impl State {
pub fn launch_xwayland(&mut self, render_node: Option<DrmNode>) {
if self.common.shell.xwayland_state.is_some() {
if self.common.xwayland_state.is_some() {
return;
}
@ -89,11 +89,11 @@ impl State {
);
}
let xwayland_state = data.common.shell.xwayland_state.as_mut().unwrap();
let xwayland_state = data.common.xwayland_state.as_mut().unwrap();
xwayland_state.xwm = Some(wm);
}
XWaylandEvent::Exited => {
if let Some(mut xwayland_state) = data.common.shell.xwayland_state.take() {
if let Some(mut xwayland_state) = data.common.xwayland_state.take() {
xwayland_state.xwm = None;
}
}
@ -118,7 +118,7 @@ impl State {
},
) {
Ok(display) => {
self.common.shell.xwayland_state = Some(XWaylandState {
self.common.xwayland_state = Some(XWaylandState {
xwayland,
xwm: None,
display,
@ -134,7 +134,14 @@ impl State {
impl Common {
fn is_x_focused(&self, xwm: XwmId) -> bool {
if let Some(keyboard) = self.shell.seats.last_active().get_keyboard() {
if let Some(keyboard) = self
.shell
.read()
.unwrap()
.seats
.last_active()
.get_keyboard()
{
if let Some(KeyboardFocusTarget::Element(mapped)) = keyboard.current_focus() {
if let Some(surface) = mapped.active_window().x11_surface() {
return surface.xwm_id().unwrap() == xwm;
@ -146,22 +153,21 @@ impl Common {
}
pub fn update_x11_stacking_order(&mut self) {
let active_output = self.shell.seats.last_active().active_output();
let shell = self.shell.read().unwrap();
let active_output = shell.seats.last_active().active_output();
if let Some(xwm) = self
.shell
.xwayland_state
.as_mut()
.and_then(|state| state.xwm.as_mut())
{
// front to back, given that is how the workspace enumerates
let order = self
.shell
let order = shell
.workspaces
.sets
.iter()
.filter(|(output, _)| *output == &active_output)
.chain(
self.shell
shell
.workspaces
.sets
.iter()
@ -233,7 +239,6 @@ impl Common {
impl XwmHandler for State {
fn xwm_state(&mut self, _xwm: XwmId) -> &mut X11Wm {
self.common
.shell
.xwayland_state
.as_mut()
.and_then(|state| state.xwm.as_mut())
@ -249,112 +254,100 @@ impl XwmHandler for State {
warn!(?window, ?err, "Failed to send Xwayland Mapped-Event",);
}
let mut shell = self.common.shell.write().unwrap();
let startup_id = window.startup_id();
if self.common.shell.element_for_surface(&window).is_some() {
if shell.element_for_surface(&window).is_some() {
return;
}
let seat = self.common.shell.seats.last_active().clone();
let seat = shell.seats.last_active().clone();
if let Some(context) = startup_id
.map(XdgActivationToken::from)
.and_then(|token| {
self.common
.shell
.xdg_activation_state
.data_for_token(&token)
})
.and_then(|token| self.common.xdg_activation_state.data_for_token(&token))
.and_then(|data| data.user_data.get::<ActivationContext>())
{
self.common.shell.pending_activations.insert(
shell.pending_activations.insert(
crate::shell::ActivationKey::X11(window.window_id()),
context.clone(),
);
}
let surface = CosmicSurface::from(window);
self.common
.shell
.pending_windows
.push((surface, seat, None));
shell.pending_windows.push((surface, seat, None));
}
fn map_window_notify(&mut self, _xwm: XwmId, surface: X11Surface) {
if let Some((window, _, _)) = self
.common
.shell
let mut shell = self.common.shell.write().unwrap();
if let Some((window, _, _)) = shell
.pending_windows
.iter()
.find(|(window, _, _)| window.x11_surface() == Some(&surface))
.cloned()
{
if !self
.common
.shell
if !shell
.pending_activations
.contains_key(&crate::shell::ActivationKey::X11(surface.window_id()))
{
if let Some(startup_id) = window.x11_surface().and_then(|x| x.startup_id()) {
if let Some(context) = self
.common
.shell
.xdg_activation_state
.data_for_token(&XdgActivationToken::from(startup_id))
.and_then(|data| data.user_data.get::<ActivationContext>())
{
self.common.shell.pending_activations.insert(
shell.pending_activations.insert(
crate::shell::ActivationKey::X11(surface.window_id()),
context.clone(),
);
}
}
}
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);
}
}
}
fn mapped_override_redirect_window(&mut self, _xwm: XwmId, window: X11Surface) {
if self
.common
.shell
let mut shell = self.common.shell.write().unwrap();
if shell
.override_redirect_windows
.iter()
.any(|or| or == &window)
{
return;
}
self.common.shell.map_override_redirect(window)
shell.map_override_redirect(window)
}
fn unmapped_window(&mut self, _xwm: XwmId, window: X11Surface) {
let mut shell = self.common.shell.write().unwrap();
if window.is_override_redirect() {
self.common
.shell
.override_redirect_windows
.retain(|or| or != &window);
shell.override_redirect_windows.retain(|or| or != &window);
} else {
let seat = self.common.shell.seats.last_active().clone();
self.common.shell.unmap_surface(&window, &seat);
let seat = shell.seats.last_active().clone();
shell.unmap_surface(&window, &seat, &mut self.common.toplevel_info_state);
}
let outputs = if let Some(wl_surface) = window.wl_surface() {
self.common
.shell
shell
.visible_output_for_surface(&wl_surface)
.into_iter()
.cloned()
.collect::<Vec<_>>()
} else {
self.common.shell.outputs().cloned().collect::<Vec<_>>()
shell.outputs().cloned().collect::<Vec<_>>()
};
for output in outputs.iter() {
self.common.shell.refresh_active_space(output);
shell.refresh_active_space(output, &self.common.xdg_activation_state);
}
for output in outputs.into_iter() {
@ -375,17 +368,15 @@ impl XwmHandler for State {
) {
// We only allow floating X11 windows to resize themselves. Nothing else
let mut current_geo = window.geometry();
if let Some(mapped) = self.common.shell.element_for_surface(&window) {
let is_floating = self
.common
.shell
let shell = self.common.shell.read().unwrap();
if let Some(mapped) = shell.element_for_surface(&window) {
let is_floating = shell
.workspaces
.sets
.values()
.any(|set| set.sticky_layer.mapped().any(|m| m == mapped))
|| self
.common
.shell
|| shell
.space_for(&mapped)
.filter(|space| space.is_floating(mapped))
.is_some();
@ -430,8 +421,9 @@ impl XwmHandler for State {
above: Option<X11Window>,
) {
if window.is_override_redirect() {
let mut shell = self.common.shell.write().unwrap();
if let Some(id) = above {
let or_windows = &mut self.common.shell.override_redirect_windows;
let or_windows = &mut shell.override_redirect_windows;
if let Some(own_pos) = or_windows.iter().position(|or| or == &window) {
let compare_pos = or_windows
.iter()
@ -445,7 +437,7 @@ impl XwmHandler for State {
}
let geo = window.geometry().as_global();
for (output, overlap) in self.common.shell.outputs().cloned().map(|o| {
for (output, overlap) in shell.outputs().cloned().map(|o| {
let intersection = o.geometry().intersection(geo);
(o, intersection)
}) {
@ -466,50 +458,88 @@ impl XwmHandler for State {
resize_edge: smithay::xwayland::xwm::ResizeEdge,
) {
if let Some(wl_surface) = window.wl_surface() {
let seat = self.common.shell.seats.last_active().clone();
Shell::resize_request(self, &wl_surface, &seat, None, resize_edge.into())
let mut shell = self.common.shell.write().unwrap();
let seat = shell.seats.last_active().clone();
if let Some((grab, focus)) =
shell.resize_request(&wl_surface, &seat, None, resize_edge.into())
{
std::mem::drop(shell);
if grab.is_touch_grab() {
seat.get_touch()
.unwrap()
.set_grab(self, grab, SERIAL_COUNTER.next_serial())
} else {
seat.get_pointer().unwrap().set_grab(
self,
grab,
SERIAL_COUNTER.next_serial(),
focus,
)
}
}
}
}
fn move_request(&mut self, _xwm: XwmId, window: X11Surface, _button: u32) {
if let Some(wl_surface) = window.wl_surface() {
let seat = self.common.shell.seats.last_active().clone();
Shell::move_request(
self,
let mut shell = self.common.shell.write().unwrap();
let seat = shell.seats.last_active().clone();
if let Some((grab, focus)) = shell.move_request(
&wl_surface,
&seat,
None,
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_COUNTER.next_serial())
} else {
seat.get_pointer().unwrap().set_grab(
self,
grab,
SERIAL_COUNTER.next_serial(),
focus,
)
}
}
}
}
fn maximize_request(&mut self, _xwm: XwmId, window: X11Surface) {
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_request(&mut self, _xwm: XwmId, window: X11Surface) {
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_request(&mut self, _xwm: XwmId, window: X11Surface) {
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().is_window(&window) {
self.common.shell.minimize_request(&mapped);
shell.minimize_request(&mapped);
}
}
}
fn unminimize_request(&mut self, _xwm: XwmId, window: X11Surface) {
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() {
let maybe_surface = mapped.windows().find(|(w, _)| w.is_window(&window));
if let Some((surface, _)) = maybe_surface {
@ -520,11 +550,10 @@ impl XwmHandler for State {
}
fn fullscreen_request(&mut self, _xwm: XwmId, window: X11Surface) {
let seat = self.common.shell.seats.last_active().clone();
if let Some(mapped) = self.common.shell.element_for_surface(&window).cloned() {
if let Some((output, handle)) = self
.common
.shell
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, handle)) = shell
.space_for(&mapped)
.map(|workspace| (workspace.output.clone(), workspace.handle.clone()))
{
@ -532,13 +561,8 @@ impl XwmHandler for State {
.windows()
.find(|(w, _)| w.x11_surface() == Some(&window))
{
let from = self
.common
.shell
.toplevel_management_state
.minimize_rectangle(&output, &surface);
self.common
.shell
let from = minimize_rectangle(&output, &surface);
shell
.workspaces
.space_for_handle_mut(&handle)
.unwrap()
@ -547,9 +571,7 @@ impl XwmHandler for State {
}
} else {
let output = seat.active_output();
if let Some(o) = self
.common
.shell
if let Some(o) = shell
.pending_windows
.iter_mut()
.find(|(s, _, _)| s.x11_surface() == Some(&window))
@ -561,8 +583,9 @@ impl XwmHandler for State {
}
fn unfullscreen_request(&mut self, _xwm: XwmId, window: X11Surface) {
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) {
let (window, _) = mapped
.windows()
.find(|(w, _)| w.x11_surface() == Some(&window))
@ -580,10 +603,17 @@ impl XwmHandler for State {
mime_type: String,
fd: OwnedFd,
) {
let seat = self.common.shell.seats.last_active();
let seat = self
.common
.shell
.read()
.unwrap()
.seats
.last_active()
.clone();
match selection {
SelectionTarget::Clipboard => {
if let Err(err) = request_data_device_client_selection(seat, mime_type, fd) {
if let Err(err) = request_data_device_client_selection(&seat, mime_type, fd) {
error!(
?err,
"Failed to request current wayland clipboard for Xwayland.",
@ -591,7 +621,7 @@ impl XwmHandler for State {
}
}
SelectionTarget::Primary => {
if let Err(err) = request_primary_client_selection(seat, mime_type, fd) {
if let Err(err) = request_primary_client_selection(&seat, mime_type, fd) {
error!(
?err,
"Failed to request current wayland primary selection for Xwayland.",
@ -609,7 +639,14 @@ impl XwmHandler for State {
trace!(?selection, ?mime_types, "Got Selection from Xwayland",);
if self.common.is_x_focused(xwm) {
let seat = self.common.shell.seats.last_active();
let seat = self
.common
.shell
.read()
.unwrap()
.seats
.last_active()
.clone();
match selection {
SelectionTarget::Clipboard => {
set_data_device_selection(&self.common.display_handle, &seat, mime_types, xwm)
@ -622,7 +659,8 @@ impl XwmHandler for State {
}
fn cleared_selection(&mut self, xwm: XwmId, selection: SelectionTarget) {
for seat in self.common.shell.seats.iter() {
let shell = self.common.shell.read().unwrap();
for seat in shell.seats.iter() {
match selection {
SelectionTarget::Clipboard => {
if current_data_device_selection_userdata(seat).as_deref() == Some(&xwm) {