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

View file

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

View file

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

View file

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

View file

@ -3,10 +3,13 @@
use crate::{ use crate::{
shell::Shell, shell::Shell,
state::{BackendData, State}, state::{BackendData, State},
wayland::protocols::output_configuration::OutputConfigurationState, wayland::protocols::{
output_configuration::OutputConfigurationState, workspace::WorkspaceUpdateGuard,
},
}; };
use cosmic_config::{ConfigGet, CosmicConfigEntry}; use cosmic_config::{ConfigGet, CosmicConfigEntry};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use smithay::wayland::xdg_activation::XdgActivationState;
pub use smithay::{ pub use smithay::{
backend::input::KeyState, backend::input::KeyState,
input::keyboard::{keysyms as KeySyms, Keysym, ModifiersState}, input::keyboard::{keysyms as KeySyms, Keysym, ModifiersState},
@ -277,6 +280,8 @@ impl Config {
backend: &mut BackendData, backend: &mut BackendData,
shell: &mut Shell, shell: &mut Shell,
loop_handle: &LoopHandle<'_, State>, loop_handle: &LoopHandle<'_, State>,
workspace_state: &mut WorkspaceUpdateGuard<'_, State>,
xdg_activation_state: &XdgActivationState,
) { ) {
let outputs = output_state.outputs().collect::<Vec<_>>(); let outputs = output_state.outputs().collect::<Vec<_>>();
let mut infos = outputs let mut infos = outputs
@ -308,9 +313,14 @@ impl Config {
.get::<RefCell<OutputConfig>>() .get::<RefCell<OutputConfig>>()
.unwrap() .unwrap()
.borrow_mut() = output_config; .borrow_mut() = output_config;
if let Err(err) = if let Err(err) = backend.apply_config_for_output(
backend.apply_config_for_output(&output, false, shell, loop_handle) &output,
{ false,
shell,
loop_handle,
workspace_state,
xdg_activation_state,
) {
warn!( warn!(
?err, ?err,
"Failed to set new config for output {}.", "Failed to set new config for output {}.",
@ -339,9 +349,14 @@ impl Config {
.get::<RefCell<OutputConfig>>() .get::<RefCell<OutputConfig>>()
.unwrap() .unwrap()
.borrow_mut() = output_config; .borrow_mut() = output_config;
if let Err(err) = if let Err(err) = backend.apply_config_for_output(
backend.apply_config_for_output(&output, false, shell, loop_handle) &output,
{ false,
shell,
loop_handle,
workspace_state,
xdg_activation_state,
) {
error!(?err, "Failed to reset config for output {}.", output.name()); error!(?err, "Failed to reset config for output {}.", output.name());
} else { } else {
if enabled { if enabled {
@ -357,9 +372,14 @@ impl Config {
self.write_outputs(output_state.outputs()); self.write_outputs(output_state.outputs());
} else { } else {
for output in outputs { for output in outputs {
if let Err(err) = if let Err(err) = backend.apply_config_for_output(
backend.apply_config_for_output(&output, false, shell, loop_handle) &output,
{ false,
shell,
loop_handle,
workspace_state,
xdg_activation_state,
) {
warn!( warn!(
?err, ?err,
"Failed to set new config for output {}.", "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() { match key.as_str() {
"xkb_config" => { "xkb_config" => {
let value = get_config::<XkbConfig>(&config, "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() { for seat in seats.into_iter() {
if let Some(keyboard) = seat.get_keyboard() { if let Some(keyboard) = seat.get_keyboard() {
if let Err(err) = keyboard.set_xkb_config(state, xkb_config_to_wl(&value)) { 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" => { "workspaces" => {
state.common.config.cosmic_conf.workspaces = state.common.config.cosmic_conf.workspaces =
get_config::<WorkspaceConfig>(&config, "workspaces"); get_config::<WorkspaceConfig>(&config, "workspaces");
state.common.shell.update_config(&state.common.config); state.common.update_config();
} }
"autotile" => { "autotile" => {
let new = get_config::<bool>(&config, "autotile"); let new = get_config::<bool>(&config, "autotile");
if new != state.common.config.cosmic_conf.autotile { if new != state.common.config.cosmic_conf.autotile {
state.common.config.cosmic_conf.autotile = new; 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" => { "autotile_behavior" => {
let new = get_config::<TileBehavior>(&config, "autotile_behavior"); let new = get_config::<TileBehavior>(&config, "autotile_behavior");
if new != state.common.config.cosmic_conf.autotile_behavior { if new != state.common.config.cosmic_conf.autotile_behavior {
state.common.config.cosmic_conf.autotile_behavior = new; 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" => { "active_hint" => {
let new = get_config::<bool>(&config, "active_hint"); let new = get_config::<bool>(&config, "active_hint");
if new != state.common.config.cosmic_conf.active_hint { if new != state.common.config.cosmic_conf.active_hint {
state.common.config.cosmic_conf.active_hint = new; 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 // run the event loop
event_loop.run(None, &mut state, |state| { event_loop.run(None, &mut state, |state| {
// shall we shut down? // 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"); info!("Shutting down");
state.common.event_loop_signal.stop(); state.common.event_loop_signal.stop();
state.common.event_loop_signal.wakeup(); state.common.event_loop_signal.wakeup();
@ -100,29 +109,25 @@ fn main() -> Result<()> {
} }
// trigger routines // 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(); let dh = state.common.display_handle.clone();
for client in clients.values() { for client in clients.values() {
client_compositor_state(&client).blocker_cleared(state, &dh); client_compositor_state(&client).blocker_cleared(state, &dh);
} }
} }
state.common.shell.refresh(); state.common.refresh();
state::Common::refresh_focus(state); state::Common::refresh_focus(state);
state.common.update_x11_stacking_order(); state.common.update_x11_stacking_order();
if state.common.shell.animations_going() { {
for output in state let shell = state.common.shell.read().unwrap();
.common if shell.animations_going() {
.shell for output in shell.outputs().cloned().collect::<Vec<_>>().into_iter() {
.outputs() state
.cloned() .backend
.collect::<Vec<_>>() .schedule_render(&state.common.event_loop_handle, &output);
.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 { let node = match &state.backend {
BackendData::Kms(kms_state) if kms_state.auto_assign => kms_state BackendData::Kms(kms_state) if kms_state.auto_assign => kms_state
.target_node_for_output( .target_node_for_output(
&state.common.shell.seats.last_active().active_output(), &state
.common
.shell
.read()
.unwrap()
.seats
.last_active()
.active_output(),
), ),
_ => None, _ => None,
}; };

View file

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

View file

@ -5,7 +5,7 @@ use crate::{
focus::{target::PointerFocusTarget, FocusDirection}, focus::{target::PointerFocusTarget, FocusDirection},
grabs::{ReleaseMode, ResizeEdge}, grabs::{ReleaseMode, ResizeEdge},
layout::tiling::NodeDesc, layout::tiling::NodeDesc,
Direction, Shell, Direction,
}, },
state::State, state::State,
utils::{ utils::{
@ -664,14 +664,25 @@ impl Program for CosmicStackInternal {
let active = self.active.load(Ordering::SeqCst); let active = self.active.load(Ordering::SeqCst);
if let Some(surface) = self.windows.lock().unwrap()[active].wl_surface() { if let Some(surface) = self.windows.lock().unwrap()[active].wl_surface() {
loop_handle.insert_idle(move |state| { loop_handle.insert_idle(move |state| {
Shell::move_request( let res = state.common.shell.write().unwrap().move_request(
state,
&surface, &surface,
&seat, &seat,
serial, serial,
ReleaseMode::NoMouseButtons, ReleaseMode::NoMouseButtons,
false, 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; *self.potential_drag.lock().unwrap() = None;
if let Some(surface) = self.windows.lock().unwrap().get(idx).cloned() { if let Some(surface) = self.windows.lock().unwrap().get(idx).cloned() {
loop_handle.insert_idle(move |state| { 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); mapped.stack_ref().unwrap().set_active(&surface);
} }
}); });
@ -703,11 +720,10 @@ impl Program for CosmicStackInternal {
let active = self.active.load(Ordering::SeqCst); let active = self.active.load(Ordering::SeqCst);
if let Some(surface) = self.windows.lock().unwrap()[active].wl_surface() { if let Some(surface) = self.windows.lock().unwrap()[active].wl_surface() {
loop_handle.insert_idle(move |state| { loop_handle.insert_idle(move |state| {
if let Some(mapped) = let shell = state.common.shell.read().unwrap();
state.common.shell.element_for_surface(&surface).cloned() if let Some(mapped) = shell.element_for_surface(&surface).cloned() {
{
let position = if let Some((output, set)) = 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.mapped().any(|m| m == &mapped)
}) { }) {
set.sticky_layer set.sticky_layer
@ -715,9 +731,7 @@ impl Program for CosmicStackInternal {
.unwrap() .unwrap()
.loc .loc
.to_global(output) .to_global(output)
} else if let Some(workspace) = } else if let Some(workspace) = shell.space_for(&mapped) {
state.common.shell.space_for_mut(&mapped)
{
let Some(elem_geo) = workspace.element_geometry(&mapped) else { let Some(elem_geo) = workspace.element_geometry(&mapped) else {
return; return;
}; };
@ -732,14 +746,22 @@ impl Program for CosmicStackInternal {
.current_location() .current_location()
.to_i32_round(); .to_i32_round();
cursor.y -= TAB_HEIGHT; cursor.y -= TAB_HEIGHT;
Shell::menu_request( let res = shell.menu_request(
state,
&surface, &surface,
&seat, &seat,
serial, serial,
cursor - position.as_logical(), cursor - position.as_logical(),
true, 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((seat, serial)) = self.last_seat.lock().unwrap().clone() {
if let Some(surface) = self.windows.lock().unwrap()[idx].wl_surface() { if let Some(surface) = self.windows.lock().unwrap()[idx].wl_surface() {
loop_handle.insert_idle(move |state| { loop_handle.insert_idle(move |state| {
if let Some(mapped) = let shell = state.common.shell.read().unwrap();
state.common.shell.element_for_surface(&surface).cloned() if let Some(mapped) = shell.element_for_surface(&surface).cloned() {
{ if let Some(workspace) = shell.space_for(&mapped) {
if let Some(workspace) = state.common.shell.space_for_mut(&mapped) {
let Some(elem_geo) = workspace.element_geometry(&mapped) else { let Some(elem_geo) = workspace.element_geometry(&mapped) else {
return; return;
}; };
let position = elem_geo.loc.to_global(&workspace.output); let position = elem_geo.loc.to_global(&workspace.output);
let mut cursor = seat let mut cursor = seat
.get_pointer() .get_pointer()
.unwrap() .unwrap()
.current_location() .current_location()
.to_i32_round(); .to_i32_round();
cursor.y -= TAB_HEIGHT; cursor.y -= TAB_HEIGHT;
Shell::menu_request( let res = shell.menu_request(
state,
&surface, &surface,
&seat, &seat,
serial, serial,
cursor - position.as_logical(), cursor - position.as_logical(),
false, 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()) .with_program(|p| p.windows.lock().unwrap().get(dragged_out).cloned())
{ {
let seat = seat.clone(); let seat = seat.clone();
let serial = event.serial;
surface.try_force_undecorated(false); surface.try_force_undecorated(false);
surface.send_configure(); surface.send_configure();
if let Some(surface) = surface.wl_surface() { if let Some(surface) = surface.wl_surface() {
let _ = data.common.event_loop_handle.insert_idle(move |state| { let _ = data.common.event_loop_handle.insert_idle(move |state| {
Shell::move_request( let res = state.common.shell.write().unwrap().move_request(
state,
&surface, &surface,
&seat, &seat,
None, serial,
ReleaseMode::NoMouseButtons, ReleaseMode::NoMouseButtons,
true, 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; return;
}; };
self.0.loop_handle().insert_idle(move |state| { self.0.loop_handle().insert_idle(move |state| {
Shell::resize_request( let res = state.common.shell.write().unwrap().resize_request(
state,
&surface, &surface,
&seat, &seat,
serial, serial,
@ -1236,7 +1277,16 @@ impl PointerTarget<State> for CosmicStack {
Focus::ResizeRight => ResizeEdge::RIGHT, Focus::ResizeRight => ResizeEdge::RIGHT,
Focus::Header => unreachable!(), 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 => {} None => {}
@ -1279,14 +1329,25 @@ impl PointerTarget<State> for CosmicStack {
surface.send_configure(); surface.send_configure();
if let Some(surface) = surface.wl_surface() { if let Some(surface) = surface.wl_surface() {
let _ = data.common.event_loop_handle.insert_idle(move |state| { let _ = data.common.event_loop_handle.insert_idle(move |state| {
Shell::move_request( let res = state.common.shell.write().unwrap().move_request(
state,
&surface, &surface,
&seat, &seat,
None, serial,
ReleaseMode::NoMouseButtons, ReleaseMode::NoMouseButtons,
true, 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::{ shell::{
focus::target::PointerFocusTarget, focus::target::PointerFocusTarget,
grabs::{ReleaseMode, ResizeEdge}, grabs::{ReleaseMode, ResizeEdge},
Shell,
}, },
state::State, state::State,
utils::{ utils::{
@ -387,14 +386,25 @@ impl Program for CosmicWindowInternal {
if let Some((seat, serial)) = self.last_seat.lock().unwrap().clone() { if let Some((seat, serial)) = self.last_seat.lock().unwrap().clone() {
if let Some(surface) = self.window.wl_surface() { if let Some(surface) = self.window.wl_surface() {
loop_handle.insert_idle(move |state| { loop_handle.insert_idle(move |state| {
Shell::move_request( let res = state.common.shell.write().unwrap().move_request(
state,
&surface, &surface,
&seat, &seat,
serial, serial,
ReleaseMode::NoMouseButtons, ReleaseMode::NoMouseButtons,
false, 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 => { Message::Minimize => {
if let Some(surface) = self.window.wl_surface() { if let Some(surface) = self.window.wl_surface() {
loop_handle.insert_idle(move |state| { loop_handle.insert_idle(move |state| {
if let Some(mapped) = let mut shell = state.common.shell.write().unwrap();
state.common.shell.element_for_surface(&surface).cloned() if let Some(mapped) = shell.element_for_surface(&surface).cloned() {
{ shell.minimize_request(&mapped)
state.common.shell.minimize_request(&mapped)
} }
}); });
} }
@ -413,11 +422,10 @@ impl Program for CosmicWindowInternal {
Message::Maximize => { Message::Maximize => {
if let Some(surface) = self.window.wl_surface() { if let Some(surface) = self.window.wl_surface() {
loop_handle.insert_idle(move |state| { loop_handle.insert_idle(move |state| {
if let Some(mapped) = let mut shell = state.common.shell.write().unwrap();
state.common.shell.element_for_surface(&surface).cloned() if let Some(mapped) = shell.element_for_surface(&surface).cloned() {
{ let seat = shell.seats.last_active().clone();
let seat = state.common.shell.seats.last_active().clone(); shell.maximize_toggle(&mapped, &seat)
state.common.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((seat, serial)) = self.last_seat.lock().unwrap().clone() {
if let Some(surface) = self.window.wl_surface() { if let Some(surface) = self.window.wl_surface() {
loop_handle.insert_idle(move |state| { loop_handle.insert_idle(move |state| {
if let Some(mapped) = let shell = state.common.shell.read().unwrap();
state.common.shell.element_for_surface(&surface).cloned() if let Some(mapped) = shell.element_for_surface(&surface).cloned() {
{
let position = if let Some((output, set)) = 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.mapped().any(|m| m == &mapped)
}) { }) {
set.sticky_layer set.sticky_layer
@ -439,9 +446,7 @@ impl Program for CosmicWindowInternal {
.unwrap() .unwrap()
.loc .loc
.to_global(output) .to_global(output)
} else if let Some(workspace) = } else if let Some(workspace) = shell.space_for(&mapped) {
state.common.shell.space_for_mut(&mapped)
{
let Some(elem_geo) = workspace.element_geometry(&mapped) else { let Some(elem_geo) = workspace.element_geometry(&mapped) else {
return; return;
}; };
@ -450,20 +455,24 @@ impl Program for CosmicWindowInternal {
return; return;
}; };
let mut cursor = seat let pointer = seat.get_pointer().unwrap();
.get_pointer() let mut cursor = pointer.current_location().to_i32_round();
.unwrap()
.current_location()
.to_i32_round();
cursor.y -= SSD_HEIGHT; cursor.y -= SSD_HEIGHT;
Shell::menu_request(
state, let res = shell.menu_request(
&surface, &surface,
&seat, &seat,
serial, serial,
cursor - position.as_logical(), cursor - position.as_logical(),
false, 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; return;
}; };
self.0.loop_handle().insert_idle(move |state| { self.0.loop_handle().insert_idle(move |state| {
Shell::resize_request( let res = state.common.shell.write().unwrap().resize_request(
state,
&surface, &surface,
&seat, &seat,
serial, serial,
@ -750,7 +758,17 @@ impl PointerTarget<State> for CosmicWindow {
Focus::ResizeRight => ResizeEdge::RIGHT, Focus::ResizeRight => ResizeEdge::RIGHT,
Focus::Header => unreachable!(), 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 => {} None => {}

View file

@ -107,9 +107,13 @@ impl Shell {
) { ) {
let element = match target { let element = match target {
Some(KeyboardFocusTarget::Element(mapped)) => Some(mapped.clone()), Some(KeyboardFocusTarget::Element(mapped)) => Some(mapped.clone()),
Some(KeyboardFocusTarget::Fullscreen(window)) => { Some(KeyboardFocusTarget::Fullscreen(window)) => state
state.common.shell.element_for_surface(window).cloned() .common
} .shell
.read()
.unwrap()
.element_for_surface(window)
.cloned(),
_ => None, _ => None,
}; };
@ -117,7 +121,12 @@ impl Shell {
if mapped.is_minimized() { if mapped.is_minimized() {
return; return;
} }
state.common.shell.append_focus_stack(&mapped, seat); state
.common
.shell
.write()
.unwrap()
.append_focus_stack(&mapped, seat);
} }
// update keyboard focus // 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>) { 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 { impl Common {
pub fn refresh_focus(state: &mut State) { pub fn refresh_focus(state: &mut State) {
for seat in state let seats = state
.common .common
.shell .shell
.read()
.unwrap()
.seats .seats
.iter() .iter()
.cloned() .cloned()
.collect::<Vec<_>>() .collect::<Vec<_>>();
.into_iter() for seat in seats.into_iter() {
{ let mut shell = state.common.shell.write().unwrap();
let output = seat.active_output(); let output = seat.active_output();
if !state.common.shell.outputs().any(|o| o == &output) { if !shell.outputs().any(|o| o == &output) {
seat.set_active_output(&state.common.shell.outputs().next().unwrap()); seat.set_active_output(&shell.outputs().next().unwrap());
continue; continue;
} }
let last_known_focus = ActiveFocus::get(&seat); let last_known_focus = ActiveFocus::get(&seat);
if let Some(target) = last_known_focus { if let Some(target) = last_known_focus {
if target.alive() { 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 continue; // Focus is valid
} else { } else {
trace!("Wrong Window, focus fixup"); trace!("Wrong Window, focus fixup");
@ -266,6 +277,8 @@ impl Common {
if !popup_grab.has_ended() { if !popup_grab.has_ended() {
if let Some(new) = popup_grab.current_grab() { if let Some(new) = popup_grab.current_grab() {
trace!("restore focus to previous popup grab"); trace!("restore focus to previous popup grab");
std::mem::drop(shell);
if let Some(keyboard) = seat.get_keyboard() { if let Some(keyboard) = seat.get_keyboard() {
keyboard.set_focus( keyboard.set_focus(
state, state,
@ -285,7 +298,7 @@ impl Common {
trace!("Surface dead, focus fixup"); trace!("Surface dead, focus fixup");
} }
} else { } else {
let workspace = state.common.shell.active_space(&output); let workspace = shell.active_space(&output);
let focus_stack = workspace.focus_stack.get(&seat); let focus_stack = workspace.focus_stack.get(&seat);
if focus_stack.last().is_none() { if focus_stack.last().is_none() {
@ -309,7 +322,9 @@ impl Common {
} }
// update keyboard focus // 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() { if let Some(keyboard) = seat.get_keyboard() {
debug!("Restoring focus to {:?}", target.as_ref()); debug!("Restoring focus to {:?}", target.as_ref());
keyboard.set_focus(state, target.clone(), SERIAL_COUNTER.next_serial()); 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 { match &self {
PointerFocusTarget::WlSurface { PointerFocusTarget::WlSurface {
toplevel: Some(PointerFocusToplevel::Surface(surface)), toplevel: Some(PointerFocusToplevel::Surface(surface)),
@ -142,12 +142,7 @@ impl PointerFocusTarget {
toplevel: Some(PointerFocusToplevel::Popup(PopupKind::Xdg(popup))), toplevel: Some(PointerFocusToplevel::Popup(PopupKind::Xdg(popup))),
.. ..
} => get_popup_toplevel(popup) } => get_popup_toplevel(popup)
.and_then(|s| { .and_then(|s| shell.element_for_surface(&s).map(|mapped| (mapped, s)))
data.common
.shell
.element_for_surface(&s)
.map(|mapped| (mapped, s))
})
.and_then(|(m, s)| { .and_then(|(m, s)| {
m.windows() m.windows()
.find(|(w, _)| w.wl_surface().map(|s2| s == s2).unwrap_or(false)) .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 { impl PointerTarget<State> for PointerFocusTarget {
fn enter(&self, seat: &Seat<State>, data: &mut State, event: &PointerMotionEvent) { 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() { for session in element.cursor_sessions() {
session.set_cursor_pos(Some( session.set_cursor_pos(Some(
event event
@ -238,7 +234,8 @@ impl PointerTarget<State> for PointerFocusTarget {
} }
} }
fn motion(&self, seat: &Seat<State>, data: &mut State, event: &PointerMotionEvent) { 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() { for session in element.cursor_sessions() {
session.set_cursor_pos(Some( session.set_cursor_pos(Some(
event event
@ -308,7 +305,8 @@ impl PointerTarget<State> for PointerFocusTarget {
} }
} }
fn leave(&self, seat: &Seat<State>, data: &mut State, serial: Serial, time: u32) { 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() { for session in element.cursor_sessions() {
session.set_cursor_pos(None); session.set_cursor_pos(None);
session.set_cursor_hotspot((0, 0)); 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::{ use crate::{
config::{Action, StaticConfig}, config::{Action, StaticConfig},
@ -6,7 +6,7 @@ use crate::{
shell::{ shell::{
element::{CosmicMapped, CosmicWindow}, element::{CosmicMapped, CosmicWindow},
grabs::ReleaseMode, grabs::ReleaseMode,
CosmicSurface, Shell, CosmicSurface, PointGlobalExt, Shell,
}, },
state::State, state::State,
utils::{prelude::SeatExt, screenshot::screenshot_window}, utils::{prelude::SeatExt, screenshot::screenshot_window},
@ -15,61 +15,57 @@ use crate::{
use super::{Item, ResizeEdge}; use super::{Item, ResizeEdge};
fn toggle_stacking(state: &mut State, mapped: &CosmicMapped) { fn toggle_stacking(state: &mut State, mapped: &CosmicMapped) {
let seat = state.common.shell.seats.last_active().clone(); let mut shell = state.common.shell.write().unwrap();
if let Some(new_focus) = state.common.shell.toggle_stacking(mapped) { 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); Shell::set_focus(state, Some(&new_focus), &seat, None);
} }
} }
fn move_prev_workspace(state: &mut State, mapped: &CosmicMapped) { 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 (current_handle, output) = {
let Some(ws) = state.common.shell.space_for(mapped) else { let Some(ws) = shell.space_for(mapped) else {
return; return;
}; };
(ws.handle, ws.output.clone()) (ws.handle, ws.output.clone())
}; };
let maybe_handle = state let maybe_handle = shell
.common
.shell
.workspaces .workspaces
.spaces_for_output(&output) .spaces_for_output(&output)
.enumerate() .enumerate()
.find_map(|(i, space)| (space.handle == current_handle).then_some(i)) .find_map(|(i, space)| (space.handle == current_handle).then_some(i))
.and_then(|i| i.checked_sub(1)) .and_then(|i| i.checked_sub(1))
.and_then(|i| { .and_then(|i| shell.workspaces.get(i, &output).map(|s| s.handle));
state
.common
.shell
.workspaces
.get(i, &output)
.map(|s| s.handle)
});
if let Some(prev_handle) = maybe_handle { if let Some(prev_handle) = maybe_handle {
if let Some((target, _)) = state.common.shell.move_window( let res = shell.move_window(
Some(&seat), Some(&seat),
mapped, mapped,
&current_handle, &current_handle,
&prev_handle, &prev_handle,
true, true,
None, None,
) { &mut state.common.workspace_state.update(),
);
if let Some((target, _)) = res {
std::mem::drop(shell);
Shell::set_focus(state, Some(&target), &seat, None); Shell::set_focus(state, Some(&target), &seat, None);
} }
} }
} }
fn move_next_workspace(state: &mut State, mapped: &CosmicMapped) { 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 (current_handle, output) = {
let Some(ws) = state.common.shell.space_for(mapped) else { let Some(ws) = shell.space_for(mapped) else {
return; return;
}; };
(ws.handle, ws.output.clone()) (ws.handle, ws.output.clone())
}; };
let maybe_handle = state let maybe_handle = shell
.common
.shell
.workspaces .workspaces
.spaces_for_output(&output) .spaces_for_output(&output)
.skip_while(|space| space.handle != current_handle) .skip_while(|space| space.handle != current_handle)
@ -77,14 +73,17 @@ fn move_next_workspace(state: &mut State, mapped: &CosmicMapped) {
.next() .next()
.map(|space| space.handle); .map(|space| space.handle);
if let Some(next_handle) = maybe_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), Some(&seat),
mapped, mapped,
&current_handle, &current_handle,
&next_handle, &next_handle,
true, true,
None, 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) Shell::set_focus(state, Some(&target), &seat, None)
} }
} }
@ -114,9 +113,10 @@ pub fn tab_items(
) )
.into(); .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 output = seat.active_output();
let workspace = state.common.shell.workspaces.active_mut(&output); let workspace = shell.workspaces.active_mut(&output);
if is_tiled { if is_tiled {
for mapped in workspace for mapped in workspace
.mapped() .mapped()
@ -127,7 +127,7 @@ pub fn tab_items(
{ {
workspace.unmaximize_request(&mapped); workspace.unmaximize_request(&mapped);
} }
let focus_stack = workspace.focus_stack.get(seat); let focus_stack = workspace.focus_stack.get(&seat);
workspace workspace
.tiling_layer .tiling_layer
.map(mapped, Some(focus_stack.iter()), None); .map(mapped, Some(focus_stack.iter()), None);
@ -197,7 +197,12 @@ pub fn window_items(
Item::new(fl!("window-menu-minimize"), move |handle| { Item::new(fl!("window-menu-minimize"), move |handle| {
let mapped = minimize_clone.clone(); let mapped = minimize_clone.clone();
let _ = handle.insert_idle(move |state| { 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)), .shortcut(config.get_shortcut_for_action(&Action::Minimize)),
@ -206,8 +211,9 @@ pub fn window_items(
Item::new(fl!("window-menu-maximize"), move |handle| { Item::new(fl!("window-menu-maximize"), move |handle| {
let mapped = maximize_clone.clone(); let mapped = maximize_clone.clone();
let _ = handle.insert_idle(move |state| { let _ = handle.insert_idle(move |state| {
let seat = state.common.shell.seats.last_active().clone(); let mut shell = state.common.shell.write().unwrap();
state.common.shell.maximize_toggle(&mapped, &seat); let seat = shell.seats.last_active().clone();
shell.maximize_toggle(&mapped, &seat);
}); });
}) })
.shortcut(config.get_shortcut_for_action(&Action::Maximize)) .shortcut(config.get_shortcut_for_action(&Action::Maximize))
@ -217,8 +223,9 @@ pub fn window_items(
Item::new(fl!("window-menu-tiled"), move |handle| { Item::new(fl!("window-menu-tiled"), move |handle| {
let tile_clone = tile_clone.clone(); let tile_clone = tile_clone.clone();
let _ = handle.insert_idle(move |state| { let _ = handle.insert_idle(move |state| {
let seat = state.common.shell.seats.last_active().clone(); let mut shell = state.common.shell.write().unwrap();
if let Some(ws) = state.common.shell.space_for_mut(&tile_clone) { let seat = shell.seats.last_active().clone();
if let Some(ws) = shell.space_for_mut(&tile_clone) {
ws.toggle_floating_window(&seat, &tile_clone); ws.toggle_floating_window(&seat, &tile_clone);
} }
}); });
@ -238,8 +245,36 @@ pub fn window_items(
let move_clone = move_clone.clone(); let move_clone = move_clone.clone();
let _ = handle.insert_idle(move |state| { let _ = handle.insert_idle(move |state| {
if let Some(surface) = move_clone.wl_surface() { if let Some(surface) = move_clone.wl_surface() {
let seat = state.common.shell.seats.last_active().clone(); let mut shell = state.common.shell.write().unwrap();
Shell::move_request(state, &surface, &seat, None, ReleaseMode::Click, false); 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| { Item::new(fl!("window-menu-resize-edge-top"), move |handle| {
let resize_clone = resize_top_clone.clone(); let resize_clone = resize_top_clone.clone();
let _ = handle.insert_idle(move |state| { let _ = handle.insert_idle(move |state| {
let seat = state.common.shell.seats.last_active().clone(); let mut shell = state.common.shell.write().unwrap();
Shell::menu_resize_request(state, &resize_clone, &seat, ResizeEdge::TOP); 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)), .disabled(!possible_resizes.contains(ResizeEdge::TOP)),
Item::new(fl!("window-menu-resize-edge-left"), move |handle| { Item::new(fl!("window-menu-resize-edge-left"), move |handle| {
let resize_clone = resize_left_clone.clone(); let resize_clone = resize_left_clone.clone();
let _ = handle.insert_idle(move |state| { let _ = handle.insert_idle(move |state| {
let seat = state.common.shell.seats.last_active().clone(); let mut shell = state.common.shell.write().unwrap();
Shell::menu_resize_request(state, &resize_clone, &seat, ResizeEdge::LEFT); 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)), .disabled(!possible_resizes.contains(ResizeEdge::LEFT)),
Item::new(fl!("window-menu-resize-edge-right"), move |handle| { Item::new(fl!("window-menu-resize-edge-right"), move |handle| {
let resize_clone = resize_right_clone.clone(); let resize_clone = resize_right_clone.clone();
let _ = handle.insert_idle(move |state| { let _ = handle.insert_idle(move |state| {
let seat = state.common.shell.seats.last_active().clone(); let mut shell = state.common.shell.write().unwrap();
Shell::menu_resize_request(state, &resize_clone, &seat, ResizeEdge::RIGHT); 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)), .disabled(!possible_resizes.contains(ResizeEdge::RIGHT)),
Item::new(fl!("window-menu-resize-edge-bottom"), move |handle| { Item::new(fl!("window-menu-resize-edge-bottom"), move |handle| {
let resize_clone = resize_bottom_clone.clone(); let resize_clone = resize_bottom_clone.clone();
let _ = handle.insert_idle(move |state| { let _ = handle.insert_idle(move |state| {
let seat = state.common.shell.seats.last_active().clone(); let mut shell = state.common.shell.write().unwrap();
Shell::menu_resize_request(state, &resize_clone, &seat, ResizeEdge::BOTTOM); 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)), .disabled(!possible_resizes.contains(ResizeEdge::BOTTOM)),
@ -301,8 +426,9 @@ pub fn window_items(
Item::new(fl!("window-menu-sticky"), move |handle| { Item::new(fl!("window-menu-sticky"), move |handle| {
let mapped = sticky_clone.clone(); let mapped = sticky_clone.clone();
let _ = handle.insert_idle(move |state| { let _ = handle.insert_idle(move |state| {
let seat = state.common.shell.seats.last_active().clone(); let mut shell = state.common.shell.write().unwrap();
state.common.shell.toggle_sticky(&seat, &mapped); let seat = shell.seats.last_active().clone();
shell.toggle_sticky(&seat, &mapped);
}); });
}) })
.toggled(is_sticky), .toggled(is_sticky),

View file

@ -216,7 +216,14 @@ impl Program for ContextMenu {
if let Some(Item::Submenu { items, .. }) = self.items.get_mut(idx) { if let Some(Item::Submenu { items, .. }) = self.items.get_mut(idx) {
let items = items.clone(); let items = items.clone();
let _ = loop_handle.insert_idle(move |state| { 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 let grab_state = seat
.user_data() .user_data()
.get::<SeatMenuGrabState>() .get::<SeatMenuGrabState>()
@ -301,7 +308,14 @@ impl Program for ContextMenu {
Message::ItemLeft(idx, _) => { Message::ItemLeft(idx, _) => {
if let Some(Item::Submenu { .. }) = self.items.get_mut(idx) { if let Some(Item::Submenu { .. }) = self.items.get_mut(idx) {
let _ = loop_handle.insert_idle(|state| { 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 let grab_state = seat
.user_data() .user_data()
.get::<SeatMenuGrabState>() .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 { impl PointerGrab<State> for ResizeGrab {
fn motion( fn motion(
&mut self, &mut self,

View file

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

View file

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

View file

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

View file

@ -39,7 +39,7 @@ impl KeyboardGrab<State> for SwapWindowGrab {
serial: Serial, serial: Serial,
time: u32, 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); handle.unset_grab(data, serial, false);
return; return;

View file

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

View file

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

View file

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

View file

@ -14,7 +14,6 @@ pub fn ready(state: &State) {
"DISPLAY", "DISPLAY",
&state &state
.common .common
.shell
.xwayland_state .xwayland_state
.as_ref() .as_ref()
.map(|s| format!(":{}", s.display)) .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 { if theme.theme_type != new_theme.theme_type {
*theme = new_theme; *theme = new_theme;
state.common.shell.set_theme(theme.clone()); let mut workspace_guard = state.common.workspace_state.update();
state.common.shell.workspaces.spaces().for_each(|s| { state.common.shell.write().unwrap().set_theme(
s.mapped().for_each(|m| { theme.clone(),
m.update_theme(theme.clone()); &state.common.xdg_activation_state,
m.force_redraw(); &mut workspace_guard,
}) );
});
} }
}) { }) {
tracing::error!("{e}"); tracing::error!("{e}");

View file

@ -26,66 +26,57 @@ use smithay::{
}; };
use std::sync::Mutex; use std::sync::Mutex;
impl State { fn toplevel_ensure_initial_configure(toplevel: &ToplevelSurface) -> bool {
fn toplevel_ensure_initial_configure(&mut self, toplevel: &ToplevelSurface) -> bool { // send the initial configure if relevant
// send the initial configure if relevant let initial_configure_sent = with_states(toplevel.wl_surface(), |states| {
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 states
.data_map .data_map
.get::<Mutex<XdgToplevelSurfaceRoleAttributes>>() .get::<Mutex<XdgPopupSurfaceRoleAttributes>>()
.unwrap() .unwrap()
.lock() .lock()
.unwrap() .unwrap()
.initial_configure_sent .initial_configure_sent
}); });
if !initial_configure_sent { if !initial_configure_sent {
// TODO: query expected size from shell (without inserting and mapping) // NOTE: This should never fail as the initial configure is always
toplevel.with_pending_state(|states| states.size = None); // allowed.
toplevel.send_configure(); popup.send_configure().expect("initial configure failed");
} }
initial_configure_sent
} }
}
fn xdg_popup_ensure_initial_configure(&mut self, popup: &PopupKind) { fn layer_surface_check_inital_configure(surface: &LayerSurface) -> bool {
if let PopupKind::Xdg(ref popup) = popup { // send the initial configure if relevant
let initial_configure_sent = with_states(popup.wl_surface(), |states| { let initial_configure_sent = with_states(surface.wl_surface(), |states| {
states states
.data_map .data_map
.get::<Mutex<XdgPopupSurfaceRoleAttributes>>() .get::<Mutex<LayerSurfaceAttributes>>()
.unwrap() .unwrap()
.lock() .lock()
.unwrap() .unwrap()
.initial_configure_sent .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_ensure_inital_configure(&mut self, surface: &LayerSurface) -> bool { initial_configure_sent
// 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
}
} }
pub fn client_compositor_state<'a>(client: &'a Client) -> &'a CompositorClientState { 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) // first load the buffer for various smithay helper functions (which also initializes the RendererSurfaceState)
on_commit_buffer_handler::<Self>(surface); 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 // handle initial configure events and map windows if necessary
if let Some((window, _, _)) = self if let Some((window, _, _)) = shell
.common
.shell
.pending_windows .pending_windows
.iter() .iter()
.find(|(window, _, _)| window.wl_surface().as_ref() == Some(surface)) .find(|(window, _, _)| window.wl_surface().as_ref() == Some(surface))
.cloned() .cloned()
{ {
if let Some(toplevel) = window.0.toplevel() { 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()) && with_renderer_surface_state(&surface, |state| state.buffer().is_some())
.unwrap_or(false) .unwrap_or(false)
{ {
window.on_commit(); window.on_commit();
if let Some(target) = self.common.shell.map_window( let res = shell.map_window(
&window, &window,
&mut self.common.toplevel_info_state,
&mut self.common.workspace_state,
&self.common.event_loop_handle, &self.common.event_loop_handle,
&self.common.theme, );
) { if let Some(target) = res {
let seat = self.common.shell.seats.last_active().clone(); let seat = shell.seats.last_active().clone();
std::mem::drop(shell);
Shell::set_focus(self, Some(&target), &seat, None); Shell::set_focus(self, Some(&target), &seat, None);
return;
} }
} }
} }
} }
if let Some((layer_surface, _, _)) = self if let Some((layer_surface, _, _)) = shell
.common
.shell
.pending_layers .pending_layers
.iter() .iter()
.find(|(layer_surface, _, _)| layer_surface.wl_surface() == surface) .find(|(layer_surface, _, _)| layer_surface.wl_surface() == surface)
.cloned() .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; return;
} }
}; };
if let Some(popup) = self.common.shell.popups.find_popup(surface) { if let Some(popup) = self.common.popups.find_popup(surface) {
self.xdg_popup_ensure_initial_configure(&popup); xdg_popup_ensure_initial_configure(&popup);
return;
} }
if with_renderer_surface_state(surface, |state| state.buffer().is_none()).unwrap_or(false) { 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 // session-lock disallows null commits
// if it was a move-grab? // 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 let moved_window = seat
.user_data() .user_data()
.get::<SeatMoveGrabState>() .get::<SeatMoveGrabState>()
@ -228,9 +238,11 @@ impl CompositorHandler for State {
stack.remove_idx(i); stack.remove_idx(i);
} }
} else { } else {
std::mem::drop(shell);
seat.get_pointer() seat.get_pointer()
.unwrap() .unwrap()
.unset_grab(self, SERIAL_COUNTER.next_serial(), 0); .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. // 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, // 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. // 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( crate::shell::layout::floating::ResizeSurfaceGrab::apply_resize_to_location(
element.clone(), 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) // re-arrange layer-surfaces (commits may change size and positioning)
let layer_output = self let layer_output = shell
.common
.shell
.outputs() .outputs()
.find(|o| { .find(|o| {
let map = layer_map_for_output(o); let map = layer_map_for_output(o);
@ -269,18 +276,13 @@ impl CompositorHandler for State {
.is_some() .is_some()
}) })
.cloned(); .cloned();
if let Some(output) = layer_output { if let Some(output) = layer_output {
let changed = layer_map_for_output(&output).arrange(); let changed = layer_map_for_output(&output).arrange();
if changed { 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 {
pub fn new_decoration(mapped: &CosmicMapped, surface: &WlSurface) -> KdeMode { if mapped.is_stack() {
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) {
if let Some((window, _)) = mapped if let Some((window, _)) = mapped
.windows() .windows()
.find(|(window, _)| window.wl_surface().as_ref() == Some(surface)) .find(|(window, _)| window.wl_surface().as_ref() == Some(surface))
{ {
if let Some(toplevel) = window.0.toplevel() { if let Some(toplevel) = window.0.toplevel() {
PreferredDecorationMode::update(&window.0, Some(mode)); toplevel
toplevel.with_pending_state(|state| { .with_pending_state(|state| state.decoration_mode = Some(XdgMode::ServerSide));
state.decoration_mode = Some(mode);
});
toplevel.send_configure(); toplevel.send_configure();
} }
} }
} KdeMode::Server
} else {
pub fn unset_mode(mapped: &CosmicMapped, surface: &WlSurface) {
if let Some((window, _)) = mapped if let Some((window, _)) = mapped
.windows() .windows()
.find(|(window, _)| window.wl_surface().as_ref() == Some(surface)) .find(|(window, _)| window.wl_surface().as_ref() == Some(surface))
{ {
if let Some(toplevel) = window.0.toplevel() { if let Some(toplevel) = window.0.toplevel() {
PreferredDecorationMode::update(&window.0, None); toplevel
toplevel.with_pending_state(|state| { .with_pending_state(|state| state.decoration_mode = Some(XdgMode::ClientSide));
state.decoration_mode = None;
});
toplevel.send_configure(); 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 { impl XdgDecorationHandler for State {
fn new_decoration(&mut self, toplevel: ToplevelSurface) { fn new_decoration(&mut self, toplevel: ToplevelSurface) {
if let Some(mapped) = self.common.shell.element_for_surface(toplevel.wl_surface()) { let shell = self.common.shell.read().unwrap();
State::new_decoration(mapped, toplevel.wl_surface()); 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) { fn request_mode(&mut self, toplevel: ToplevelSurface, mode: XdgMode) {
if let Some(mapped) = self.common.shell.element_for_surface(toplevel.wl_surface()) { let shell = self.common.shell.read().unwrap();
State::request_mode(mapped, toplevel.wl_surface(), mode); if let Some(mapped) = shell.element_for_surface(toplevel.wl_surface()) {
request_mode(mapped, toplevel.wl_surface(), mode);
} else { } else {
toplevel.with_pending_state(|state| state.decoration_mode = Some(mode)); toplevel.with_pending_state(|state| state.decoration_mode = Some(mode));
} }
} }
fn unset_mode(&mut self, toplevel: ToplevelSurface) { fn unset_mode(&mut self, toplevel: ToplevelSurface) {
if let Some(mapped) = self.common.shell.element_for_surface(toplevel.wl_surface()) { let shell = self.common.shell.read().unwrap();
State::unset_mode(mapped, toplevel.wl_surface()) 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) { fn new_decoration(&mut self, surface: &WlSurface, decoration: &OrgKdeKwinServerDecoration) {
if let Some(mapped) = self.common.shell.element_for_surface(surface) { let shell = self.common.shell.read().unwrap();
let mode = State::new_decoration(mapped, surface); if let Some(mapped) = shell.element_for_surface(surface) {
let mode = new_decoration(mapped, surface);
decoration.mode(mode); decoration.mode(mode);
} }
} }
@ -157,9 +157,10 @@ impl KdeDecorationHandler for State {
mode: WEnum<KdeMode>, mode: WEnum<KdeMode>,
) { ) {
if let WEnum::Value(mode) = mode { 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. // 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) { if let Some(mapped) = shell.element_for_surface(surface) {
State::request_mode( request_mode(
mapped, mapped,
surface, surface,
match mode { match mode {
@ -173,8 +174,9 @@ impl KdeDecorationHandler for State {
} }
fn release(&mut self, _decoration: &OrgKdeKwinServerDecoration, surface: &WlSurface) { fn release(&mut self, _decoration: &OrgKdeKwinServerDecoration, surface: &WlSurface) {
if let Some(mapped) = self.common.shell.element_for_surface(surface) { let shell = self.common.shell.read().unwrap();
State::unset_mode(mapped, surface) 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(|| { .or_else(|| {
self.common self.common
.shell .shell
.read()
.unwrap()
.visible_output_for_surface(&surface) .visible_output_for_surface(&surface)
.cloned() .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_states(&surface, |states| {
with_fractional_scale(states, |fractional_scale| { with_fractional_scale(states, |fractional_scale| {

View file

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

View file

@ -16,7 +16,7 @@ use smithay::{
impl WlrLayerShellHandler for State { impl WlrLayerShellHandler for State {
fn shell_state(&mut self) -> &mut WlrLayerShellState { fn shell_state(&mut self) -> &mut WlrLayerShellState {
&mut self.common.shell.layer_shell_state &mut self.common.layer_shell_state
} }
fn new_layer_surface( fn new_layer_surface(
@ -26,24 +26,22 @@ impl WlrLayerShellHandler for State {
_layer: Layer, _layer: Layer,
namespace: String, 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 let output = wl_output
.as_ref() .as_ref()
.and_then(Output::from_resource) .and_then(Output::from_resource)
.unwrap_or_else(|| seat.active_output()); .unwrap_or_else(|| seat.active_output());
self.common.shell.pending_layers.push(( shell
LayerSurface::new(surface, namespace), .pending_layers
output, .push((LayerSurface::new(surface, namespace), output, seat));
seat,
));
} }
fn new_popup(&mut self, _parent: WlrLayerSurface, popup: PopupSurface) { 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() { if popup.send_configure().is_ok() {
self.common self.common
.shell
.popups .popups
.track_popup(PopupKind::from(popup)) .track_popup(PopupKind::from(popup))
.unwrap(); .unwrap();
@ -51,9 +49,8 @@ impl WlrLayerShellHandler for State {
} }
fn layer_destroyed(&mut self, surface: WlrLayerSurface) { fn layer_destroyed(&mut self, surface: WlrLayerSurface) {
let maybe_output = self let mut shell = self.common.shell.write().unwrap();
.common let maybe_output = shell
.shell
.outputs() .outputs()
.find(|o| { .find(|o| {
let map = layer_map_for_output(o); let map = layer_map_for_output(o);
@ -72,7 +69,7 @@ impl WlrLayerShellHandler for State {
map.unmap_layer(&layer); map.unmap_layer(&layer);
} }
self.common.shell.workspaces.recalculate(); shell.workspaces.recalculate();
self.backend self.backend
.schedule_render(&self.common.event_loop_handle, &output); .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, output,
test_only, test_only,
&mut self.common.shell, &mut *shell,
&self.common.event_loop_handle, &self.common.event_loop_handle,
) { &mut self.common.workspace_state.update(),
&self.common.xdg_activation_state,
);
if let Err(err) = res {
warn!( warn!(
?err, ?err,
"Failed to apply config to {}. Resetting", "Failed to apply config to {}. Resetting",
@ -106,8 +110,10 @@ impl State {
if let Err(err) = self.backend.apply_config_for_output( if let Err(err) = self.backend.apply_config_for_output(
output, output,
false, false,
&mut self.common.shell, &mut *shell,
&self.common.event_loop_handle, &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(),); error!(?err, "Failed to reset output config for {}.", output.name(),);
} }
@ -115,6 +121,9 @@ impl State {
} }
return false; return false;
} }
std::mem::drop(shell);
self.common.refresh();
} }
for output in conf for output in conf

View file

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

View file

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

View file

@ -20,7 +20,6 @@ impl SelectionHandler for State {
) { ) {
if let Some(xwm) = self if let Some(xwm) = self
.common .common
.shell
.xwayland_state .xwayland_state
.as_mut() .as_mut()
.and_then(|xstate| xstate.xwm.as_mut()) .and_then(|xstate| xstate.xwm.as_mut())
@ -45,7 +44,6 @@ impl SelectionHandler for State {
) { ) {
if let Some(xwm) = self if let Some(xwm) = self
.common .common
.shell
.xwayland_state .xwayland_state
.as_mut() .as_mut()
.and_then(|xstate| xstate.xwm.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) { fn lock(&mut self, locker: SessionLocker) {
let mut shell = self.common.shell.write().unwrap();
// Reject lock if sesion lock exists and is still valid // 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 if self
.common .common
.display_handle .display_handle
@ -32,28 +34,30 @@ impl SessionLockHandler for State {
let ext_session_lock = locker.ext_session_lock().clone(); let ext_session_lock = locker.ext_session_lock().clone();
locker.lock(); locker.lock();
self.common.shell.session_lock = Some(SessionLock { shell.session_lock = Some(SessionLock {
ext_session_lock, ext_session_lock,
surfaces: HashMap::new(), surfaces: HashMap::new(),
}); });
for output in self.common.shell.outputs() { for output in shell.outputs() {
self.backend self.backend
.schedule_render(&self.common.event_loop_handle, &output); .schedule_render(&self.common.event_loop_handle, &output);
} }
} }
fn unlock(&mut self) { 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 self.backend
.schedule_render(&self.common.event_loop_handle, &output); .schedule_render(&self.common.event_loop_handle, &output);
} }
} }
fn new_surface(&mut self, lock_surface: LockSurface, wl_output: WlOutput) { 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) { if let Some(output) = Output::from_resource(&wl_output) {
lock_surface.with_pending_state(|states| { lock_surface.with_pending_state(|states| {
let size = output.geometry().size; let size = output.geometry().size;

View file

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

View file

@ -21,17 +21,18 @@ impl WorkspaceClientHandler for ClientState {
impl WorkspaceHandler for State { impl WorkspaceHandler for State {
type Client = ClientState; type Client = ClientState;
fn workspace_state(&self) -> &WorkspaceState<Self> { fn workspace_state(&self) -> &WorkspaceState<Self> {
&self.common.shell.workspace_state &self.common.workspace_state
} }
fn workspace_state_mut(&mut self) -> &mut WorkspaceState<Self> { 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>) { fn commit_requests(&mut self, _dh: &DisplayHandle, requests: Vec<Request>) {
for request in requests.into_iter() { for request in requests.into_iter() {
match request { match request {
Request::Activate(handle) => { 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 set.workspaces
.iter() .iter()
.position(|w| w.handle == handle) .position(|w| w.handle == handle)
@ -39,22 +40,20 @@ impl WorkspaceHandler for State {
}); });
if let Some((output, idx)) = maybe { if let Some((output, idx)) = maybe {
let _ = self.common.shell.activate( let _ = shell.activate(
&output, &output,
idx, idx,
WorkspaceDelta::new_shortcut(), WorkspaceDelta::new_shortcut(),
); // TODO: move cursor? &mut self.common.workspace_state.update(),
);
// TODO: move cursor?
} }
} }
Request::SetTilingState { workspace, state } => { Request::SetTilingState { workspace, state } => {
let seat = self.common.shell.seats.last_active().clone(); let mut shell = self.common.shell.write().unwrap();
if let Some(workspace) = self let seat = shell.seats.last_active().clone();
.common if let Some(workspace) = shell.workspaces.space_for_handle_mut(&workspace) {
.shell let mut guard = self.common.workspace_state.update();
.workspaces
.space_for_handle_mut(&workspace)
{
let mut guard = self.common.shell.workspace_state.update();
workspace.set_tiling( workspace.set_tiling(
match state.into_result() { match state.into_result() {
Ok(TilingState::FloatingOnly) => false, 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::{ use smithay::{
delegate_xdg_activation, delegate_xdg_activation,
input::Seat, input::Seat,
@ -8,9 +11,6 @@ use smithay::{
}; };
use tracing::debug; use tracing::debug;
use crate::{shell::ActivationKey, state::ClientState, utils::prelude::*};
use crate::{state::State, wayland::protocols::workspace::WorkspaceHandle};
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum ActivationContext { pub enum ActivationContext {
UrgentOnly, UrgentOnly,
@ -19,7 +19,7 @@ pub enum ActivationContext {
impl XdgActivationHandler for State { impl XdgActivationHandler for State {
fn activation_state(&mut self) -> &mut XdgActivationState { 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 { 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)) { if let Some(seat) = data.serial.and_then(|(_, seat)| Seat::from_resource(&seat)) {
let output = seat.active_output(); 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()); workspace.pending_tokens.insert(token.clone());
let handle = workspace.handle; let handle = workspace.handle;
data.user_data data.user_data
@ -84,7 +85,8 @@ impl XdgActivationHandler for State {
if valid { if valid {
let output = seat.active_output(); 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()); workspace.pending_tokens.insert(token.clone());
let handle = workspace.handle; let handle = workspace.handle;
data.user_data data.user_data
@ -105,24 +107,24 @@ impl XdgActivationHandler for State {
surface: WlSurface, surface: WlSurface,
) { ) {
if let Some(context) = token_data.user_data.get::<ActivationContext>() { 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 { match context {
ActivationContext::UrgentOnly => { ActivationContext::UrgentOnly => {
if let Some((workspace, _output)) = if let Some((workspace, _output)) = shell.workspace_for_surface(&surface) {
self.common.shell.workspace_for_surface(&surface) let mut workspace_guard = self.common.workspace_state.update();
{ workspace_guard.add_workspace_state(&workspace, WState::Urgent);
self.common.shell.set_urgent(&workspace);
} }
} }
ActivationContext::Workspace(workspace) => { 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(); let current_output = seat.active_output();
if element.is_minimized() { 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 let in_current_workspace = current_workspace
.floating_layer .floating_layer
@ -152,21 +154,19 @@ impl XdgActivationHandler for State {
if workspace == &current_workspace.handle || in_current_workspace { if workspace == &current_workspace.handle || in_current_workspace {
let target = element.into(); let target = element.into();
std::mem::drop(shell);
Shell::set_focus(self, Some(&target), &seat, None); Shell::set_focus(self, Some(&target), &seat, None);
} else if let Some(w) = self } else if let Some(w) = shell.space_for(&element).map(|w| w.handle.clone())
.common
.shell
.space_for(&element)
.map(|w| w.handle.clone())
{ {
self.common.shell.append_focus_stack(&element, &seat); shell.append_focus_stack(&element, &seat);
self.common.shell.set_urgent(&w); let mut workspace_guard = self.common.workspace_state.update();
workspace_guard.add_workspace_state(&w, WState::Urgent);
} }
} }
} }
} else { } else {
self.common shell
.shell
.pending_activations .pending_activations
.insert(ActivationKey::Wayland(surface), context.clone()); .insert(ActivationKey::Wayland(surface), context.clone());
} }

View file

@ -3,6 +3,7 @@
use crate::{ use crate::{
shell::{element::CosmicWindow, grabs::ReleaseMode, CosmicMapped, CosmicSurface, ManagedLayer}, shell::{element::CosmicWindow, grabs::ReleaseMode, CosmicMapped, CosmicSurface, ManagedLayer},
utils::prelude::*, utils::prelude::*,
wayland::protocols::toplevel_info::{toplevel_enter_output, toplevel_enter_workspace},
}; };
use smithay::{ use smithay::{
delegate_xdg_shell, delegate_xdg_shell,
@ -29,7 +30,7 @@ use smithay::{
use std::cell::Cell; use std::cell::Cell;
use tracing::warn; 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; pub mod popup;
@ -37,13 +38,14 @@ pub type PopupGrabData = Cell<Option<PopupGrab<State>>>;
impl XdgShellHandler for State { impl XdgShellHandler for State {
fn xdg_shell_state(&mut self) -> &mut XdgShellState { 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) { 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); 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 // 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() { if surface.get_parent_surface().is_some() {
// let other shells deal with their popups // 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() { if surface.send_configure().is_ok() {
self.common self.common
.shell
.popups .popups
.track_popup(PopupKind::from(surface)) .track_popup(PopupKind::from(surface))
.unwrap(); .unwrap();
@ -70,16 +75,18 @@ impl XdgShellHandler for State {
fn grab(&mut self, surface: PopupSurface, seat: WlSeat, serial: Serial) { fn grab(&mut self, surface: PopupSurface, seat: WlSeat, serial: Serial) {
let seat = Seat::from_resource(&seat).unwrap(); let seat = Seat::from_resource(&seat).unwrap();
let kind = PopupKind::Xdg(surface); let kind = PopupKind::Xdg(surface);
if let Some(root) = find_popup_root_surface(&kind) let maybe_root = find_popup_root_surface(&kind).ok().and_then(|root| {
.ok() self.common
.and_then(|root| self.common.shell.element_for_surface(&root))
{
let target = root.clone().into();
let ret = self
.common
.shell .shell
.popups .read()
.grab_popup(target, kind, &seat, serial); .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 Ok(mut grab) = ret {
if let Some(keyboard) = seat.get_keyboard() { if let Some(keyboard) = seat.get_keyboard() {
@ -128,7 +135,11 @@ impl XdgShellHandler for State {
state.positioner = positioner; state.positioner = positioner;
}); });
self.common.shell.unconstrain_popup(&surface); self.common
.shell
.read()
.unwrap()
.unconstrain_popup(&surface);
surface.send_repositioned(token); surface.send_repositioned(token);
if let Err(err) = surface.send_configure() { if let Err(err) = surface.send_configure() {
warn!( warn!(
@ -140,14 +151,26 @@ impl XdgShellHandler for State {
fn move_request(&mut self, surface: ToplevelSurface, seat: WlSeat, serial: Serial) { fn move_request(&mut self, surface: ToplevelSurface, seat: WlSeat, serial: Serial) {
let seat = Seat::from_resource(&seat).unwrap(); let seat = Seat::from_resource(&seat).unwrap();
Shell::move_request( let mut shell = self.common.shell.write().unwrap();
self, if let Some((grab, focus)) = shell.move_request(
surface.wl_surface(), surface.wl_surface(),
&seat, &seat,
serial, serial,
ReleaseMode::NoMouseButtons, ReleaseMode::NoMouseButtons,
false, 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( fn resize_request(
@ -158,70 +181,60 @@ impl XdgShellHandler for State {
edges: xdg_toplevel::ResizeEdge, edges: xdg_toplevel::ResizeEdge,
) { ) {
let seat = Seat::from_resource(&seat).unwrap(); 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) { fn minimize_request(&mut self, surface: ToplevelSurface) {
if let Some(mapped) = self let mut shell = self.common.shell.write().unwrap();
.common if let Some(mapped) = shell.element_for_surface(surface.wl_surface()).cloned() {
.shell
.element_for_surface(surface.wl_surface())
.cloned()
{
if !mapped.is_stack() if !mapped.is_stack()
|| mapped.active_window().wl_surface().as_ref() == Some(surface.wl_surface()) || 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) { fn maximize_request(&mut self, surface: ToplevelSurface) {
if let Some(mapped) = self let mut shell = self.common.shell.write().unwrap();
.common if let Some(mapped) = shell.element_for_surface(surface.wl_surface()).cloned() {
.shell let seat = shell.seats.last_active().clone();
.element_for_surface(surface.wl_surface()) shell.maximize_request(&mapped, &seat)
.cloned()
{
let seat = self.common.shell.seats.last_active().clone();
self.common.shell.maximize_request(&mapped, &seat)
} }
} }
fn unmaximize_request(&mut self, surface: ToplevelSurface) { fn unmaximize_request(&mut self, surface: ToplevelSurface) {
if let Some(mapped) = self let mut shell = self.common.shell.write().unwrap();
.common if let Some(mapped) = shell.element_for_surface(surface.wl_surface()).cloned() {
.shell shell.unmaximize_request(&mapped);
.element_for_surface(surface.wl_surface())
.cloned()
{
self.common.shell.unmaximize_request(&mapped);
} }
} }
fn fullscreen_request(&mut self, surface: ToplevelSurface, output: Option<WlOutput>) { 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 active_output = seat.active_output();
let output = output let output = output
.as_ref() .as_ref()
.and_then(Output::from_resource) .and_then(Output::from_resource)
.unwrap_or_else(|| active_output.clone()); .unwrap_or_else(|| active_output.clone());
if let Some(mapped) = self if let Some(mapped) = shell.element_for_surface(surface.wl_surface()).cloned() {
.common let from = minimize_rectangle(&output, &mapped.active_window());
.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(set) = self if let Some(set) = shell
.common
.shell
.workspaces .workspaces
.sets .sets
.values_mut() .values_mut()
@ -248,19 +261,13 @@ impl XdgShellHandler for State {
mapped 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() { for (window, _) in mapped.windows() {
self.common toplevel_enter_output(&window, &output);
.shell toplevel_enter_workspace(&window, &workspace_handle);
.toplevel_info_state
.toplevel_enter_output(&window, &output);
self.common
.shell
.toplevel_info_state
.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.floating_layer.map(mapped.clone(), None);
workspace.fullscreen_request( workspace.fullscreen_request(
@ -269,7 +276,7 @@ impl XdgShellHandler for State {
from, from,
&seat, &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 { if workspace.output != output {
let (mapped, layer) = if mapped let (mapped, layer) = if mapped
.stack_ref() .stack_ref()
@ -300,19 +307,13 @@ impl XdgShellHandler for State {
}; };
let handle = workspace.handle.clone(); 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() { for (window, _) in mapped.windows() {
self.common toplevel_enter_output(&window, &output);
.shell toplevel_enter_workspace(&window, &workspace_handle);
.toplevel_info_state
.toplevel_enter_output(&window, &output);
self.common
.shell
.toplevel_info_state
.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.floating_layer.map(mapped.clone(), None);
workspace.fullscreen_request( workspace.fullscreen_request(
@ -330,9 +331,7 @@ impl XdgShellHandler for State {
} }
} }
} else { } else {
if let Some(o) = self if let Some(o) = shell
.common
.shell
.pending_windows .pending_windows
.iter_mut() .iter_mut()
.find(|(s, _, _)| s.wl_surface().as_ref() == Some(surface.wl_surface())) .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) { fn unfullscreen_request(&mut self, surface: ToplevelSurface) {
if let Some(mapped) = self let mut shell = self.common.shell.write().unwrap();
.common if let Some(mapped) = shell.element_for_surface(surface.wl_surface()).cloned() {
.shell if let Some(workspace) = shell.space_for_mut(&mapped) {
.element_for_surface(surface.wl_surface())
.cloned()
{
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
let (window, _) = mapped let (window, _) = mapped
.windows() .windows()
.find(|(w, _)| w.wl_surface().as_ref() == Some(surface.wl_surface())) .find(|(w, _)| w.wl_surface().as_ref() == Some(surface.wl_surface()))
.unwrap(); .unwrap();
if let Some((layer, previous_workspace)) = workspace.unfullscreen_request(&window) { if let Some((layer, previous_workspace)) = workspace.unfullscreen_request(&window) {
let old_handle = workspace.handle.clone(); let old_handle = workspace.handle.clone();
let new_workspace_handle = self let new_workspace_handle = shell
.common
.shell
.workspaces .workspaces
.space_for_handle(&previous_workspace) .space_for_handle(&previous_workspace)
.is_some() .is_some()
.then_some(previous_workspace) .then_some(previous_workspace)
.unwrap_or(old_handle); // if the workspace doesn't exist anymore, we can still remap on the right layer .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, mapped,
&old_handle, &old_handle,
&new_workspace_handle, &new_workspace_handle,
@ -378,20 +371,26 @@ impl XdgShellHandler for State {
} }
fn toplevel_destroyed(&mut self, surface: ToplevelSurface) { fn toplevel_destroyed(&mut self, surface: ToplevelSurface) {
let seat = self.common.shell.seats.last_active().clone(); let (output, clients) = {
self.common.shell.unmap_surface(surface.wl_surface(), &seat); 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 let output = shell
.common .visible_output_for_surface(surface.wl_surface())
.shell .cloned();
.visible_output_for_surface(surface.wl_surface()) if let Some(output) = output.as_ref() {
.cloned(); shell.refresh_active_space(output, &self.common.xdg_activation_state);
if let Some(output) = output.as_ref() { }
self.common.shell.refresh_active_space(output);
} // 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(); let dh = self.common.display_handle.clone();
for client in clients.values() { for client in clients.values() {
@ -418,7 +417,23 @@ impl XdgShellHandler for State {
}) })
.unwrap_or_default() .unwrap_or_default()
.loc; .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 let element = self
.common .common
.shell .shell
.read()
.unwrap()
.workspaces .workspaces
.spaces() .spaces()
.find_map(|x| x.element_for_surface(surface))?; .find_map(|x| x.element_for_surface(surface).cloned())?;
Some(KeyboardFocusTarget::Element(element.clone())) Some(KeyboardFocusTarget::Element(element))
} }
} }
delegate_xwayland_keyboard_grab!(State); 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> impl<D, W> ToplevelInfoState<D, W>
where where
D: GlobalDispatch<ZcosmicToplevelInfoV1, ToplevelInfoGlobalData> D: GlobalDispatch<ZcosmicToplevelInfoV1, ToplevelInfoGlobalData>
@ -223,30 +247,6 @@ where
self.toplevels.push(toplevel.clone()); 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) { pub fn remove_toplevel(&mut self, toplevel: &W) {
if let Some(state) = toplevel.user_data().get::<ToplevelState>() { if let Some(state) = toplevel.user_data().get::<ToplevelState>() {
let mut state_inner = state.lock().unwrap(); 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 { pub struct ToplevelManagerGlobalData {
filter: Box<dyn for<'a> Fn(&'a Client) -> bool + Send + Sync>, 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 { pub fn global_id(&self) -> GlobalId {
self.global.clone() self.global.clone()
} }

View file

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