shell: Move seats into shell
This commit is contained in:
parent
1216cd0b67
commit
647deb81f1
31 changed files with 824 additions and 883 deletions
|
|
@ -48,7 +48,6 @@ use smithay::{
|
||||||
udev::{all_gpus, primary_gpu, UdevBackend, UdevEvent},
|
udev::{all_gpus, primary_gpu, UdevBackend, UdevEvent},
|
||||||
},
|
},
|
||||||
desktop::utils::OutputPresentationFeedback,
|
desktop::utils::OutputPresentationFeedback,
|
||||||
input::Seat,
|
|
||||||
output::{Mode as OutputMode, Output, OutputNoMode, PhysicalProperties, Subpixel},
|
output::{Mode as OutputMode, Output, OutputNoMode, PhysicalProperties, Subpixel},
|
||||||
reexports::{
|
reexports::{
|
||||||
calloop::{
|
calloop::{
|
||||||
|
|
@ -324,12 +323,10 @@ pub fn init_backend(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let seats = state.common.seats().cloned().collect::<Vec<_>>();
|
|
||||||
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,
|
||||||
seats.into_iter(),
|
|
||||||
&state.common.event_loop_handle,
|
&state.common.event_loop_handle,
|
||||||
);
|
);
|
||||||
for surface in state
|
for surface in state
|
||||||
|
|
@ -701,12 +698,10 @@ impl State {
|
||||||
self.common
|
self.common
|
||||||
.output_configuration_state
|
.output_configuration_state
|
||||||
.add_heads(wl_outputs.iter());
|
.add_heads(wl_outputs.iter());
|
||||||
let seats = self.common.seats().cloned().collect::<Vec<_>>();
|
|
||||||
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,
|
||||||
seats.into_iter(),
|
|
||||||
&self.common.event_loop_handle,
|
&self.common.event_loop_handle,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -836,12 +831,10 @@ impl State {
|
||||||
self.common
|
self.common
|
||||||
.output_configuration_state
|
.output_configuration_state
|
||||||
.add_heads(outputs_added.iter());
|
.add_heads(outputs_added.iter());
|
||||||
let seats = self.common.seats().cloned().collect::<Vec<_>>();
|
|
||||||
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,
|
||||||
seats.iter().cloned(),
|
|
||||||
&self.common.event_loop_handle,
|
&self.common.event_loop_handle,
|
||||||
);
|
);
|
||||||
// Don't remove the outputs, before potentially new ones have been initialized.
|
// Don't remove the outputs, before potentially new ones have been initialized.
|
||||||
|
|
@ -849,9 +842,7 @@ impl State {
|
||||||
// If we have 0 outputs at some point, we won't quit, but shell doesn't know where to move
|
// If we have 0 outputs at some point, we won't quit, but shell doesn't know where to move
|
||||||
// windows and workspaces to.
|
// windows and workspaces to.
|
||||||
for output in outputs_removed {
|
for output in outputs_removed {
|
||||||
self.common
|
self.common.shell.remove_output(&output);
|
||||||
.shell
|
|
||||||
.remove_output(&output, seats.iter().cloned());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
@ -896,18 +887,14 @@ impl State {
|
||||||
.output_configuration_state
|
.output_configuration_state
|
||||||
.remove_heads(outputs_removed.iter());
|
.remove_heads(outputs_removed.iter());
|
||||||
|
|
||||||
let seats = self.common.seats().cloned().collect::<Vec<_>>();
|
|
||||||
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
|
self.common.shell.remove_output(&output);
|
||||||
.shell
|
|
||||||
.remove_output(&output, seats.iter().cloned());
|
|
||||||
}
|
}
|
||||||
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,
|
||||||
seats.into_iter(),
|
|
||||||
&self.common.event_loop_handle,
|
&self.common.event_loop_handle,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1201,7 +1188,10 @@ impl Surface {
|
||||||
let mut elements = workspace_elements(
|
let mut elements = workspace_elements(
|
||||||
Some(&render_node),
|
Some(&render_node),
|
||||||
&mut renderer,
|
&mut renderer,
|
||||||
state,
|
&state.shell,
|
||||||
|
&state.config,
|
||||||
|
&state.theme,
|
||||||
|
state.clock.now(),
|
||||||
&self.output,
|
&self.output,
|
||||||
previous_workspace,
|
previous_workspace,
|
||||||
workspace,
|
workspace,
|
||||||
|
|
@ -1497,7 +1487,6 @@ impl KmsState {
|
||||||
pub fn apply_config_for_output(
|
pub fn apply_config_for_output(
|
||||||
&mut self,
|
&mut self,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
seats: impl Iterator<Item = Seat<State>>,
|
|
||||||
shell: &mut Shell,
|
shell: &mut Shell,
|
||||||
test_only: bool,
|
test_only: bool,
|
||||||
loop_handle: &LoopHandle<'_, State>,
|
loop_handle: &LoopHandle<'_, State>,
|
||||||
|
|
@ -1520,7 +1509,7 @@ impl KmsState {
|
||||||
|
|
||||||
if !output_config.enabled {
|
if !output_config.enabled {
|
||||||
if !test_only {
|
if !test_only {
|
||||||
shell.remove_output(output, seats);
|
shell.remove_output(output);
|
||||||
if surface.surface.take().is_some() {
|
if surface.surface.take().is_some() {
|
||||||
// just drop it
|
// just drop it
|
||||||
surface.pending = false;
|
surface.pending = false;
|
||||||
|
|
|
||||||
|
|
@ -48,14 +48,14 @@ pub fn init_backend_auto(
|
||||||
.outputs()
|
.outputs()
|
||||||
.next()
|
.next()
|
||||||
.with_context(|| "Backend initialized without output")?;
|
.with_context(|| "Backend initialized without output")?;
|
||||||
let initial_seat = crate::input::add_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.add_seat(initial_seat);
|
state.common.shell.seats.add_seat(initial_seat);
|
||||||
}
|
}
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,14 +12,15 @@ use std::{
|
||||||
use crate::debug::fps_ui;
|
use crate::debug::fps_ui;
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::render::element::DamageElement,
|
backend::render::element::DamageElement,
|
||||||
|
config::Config,
|
||||||
shell::{
|
shell::{
|
||||||
focus::target::WindowGroup,
|
focus::target::WindowGroup,
|
||||||
grabs::{SeatMenuGrabState, SeatMoveGrabState},
|
grabs::{SeatMenuGrabState, SeatMoveGrabState},
|
||||||
layout::tiling::ANIMATION_DURATION,
|
layout::tiling::ANIMATION_DURATION,
|
||||||
CosmicMapped, CosmicMappedRenderElement, OverviewMode, SessionLock, Trigger,
|
CosmicMapped, CosmicMappedRenderElement, OverviewMode, SeatExt, SessionLock, Trigger,
|
||||||
WorkspaceDelta, WorkspaceRenderElement,
|
WorkspaceDelta, WorkspaceRenderElement,
|
||||||
},
|
},
|
||||||
state::{Common, Fps},
|
state::Fps,
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
wayland::{
|
wayland::{
|
||||||
handlers::{
|
handlers::{
|
||||||
|
|
@ -30,6 +31,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use cosmic::Theme;
|
||||||
use cosmic_comp_config::workspace::WorkspaceLayout;
|
use cosmic_comp_config::workspace::WorkspaceLayout;
|
||||||
use keyframe::{ease, functions::EaseInOutCubic};
|
use keyframe::{ease, functions::EaseInOutCubic};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
|
|
@ -56,7 +58,7 @@ use smithay::{
|
||||||
},
|
},
|
||||||
desktop::{layer_map_for_output, PopupManager},
|
desktop::{layer_map_for_output, PopupManager},
|
||||||
output::{Output, OutputNoMode},
|
output::{Output, OutputNoMode},
|
||||||
utils::{IsAlive, Logical, Point, Rectangle, Scale, Transform},
|
utils::{IsAlive, Logical, Monotonic, Point, Rectangle, Scale, Time, Transform},
|
||||||
wayland::{
|
wayland::{
|
||||||
dmabuf::get_dmabuf,
|
dmabuf::get_dmabuf,
|
||||||
shell::wlr_layer::Layer,
|
shell::wlr_layer::Layer,
|
||||||
|
|
@ -387,7 +389,9 @@ pub enum CursorMode {
|
||||||
#[profiling::function]
|
#[profiling::function]
|
||||||
pub fn cursor_elements<'frame, R>(
|
pub fn cursor_elements<'frame, R>(
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
state: &Common,
|
shell: &Shell,
|
||||||
|
theme: &Theme,
|
||||||
|
now: Time<Monotonic>,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
mode: CursorMode,
|
mode: CursorMode,
|
||||||
exclude_dnd_icon: bool,
|
exclude_dnd_icon: bool,
|
||||||
|
|
@ -400,7 +404,7 @@ where
|
||||||
let scale = output.current_scale().fractional_scale();
|
let scale = output.current_scale().fractional_scale();
|
||||||
let mut elements = Vec::new();
|
let mut elements = Vec::new();
|
||||||
|
|
||||||
for seat in state.seats() {
|
for seat in shell.seats.iter() {
|
||||||
let pointer = match seat.get_pointer() {
|
let pointer = match seat.get_pointer() {
|
||||||
Some(ptr) => ptr,
|
Some(ptr) => ptr,
|
||||||
None => continue,
|
None => continue,
|
||||||
|
|
@ -414,7 +418,7 @@ where
|
||||||
seat,
|
seat,
|
||||||
location,
|
location,
|
||||||
scale.into(),
|
scale.into(),
|
||||||
state.clock.now(),
|
now,
|
||||||
mode != CursorMode::NotDefault,
|
mode != CursorMode::NotDefault,
|
||||||
)
|
)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
@ -438,7 +442,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let theme = state.theme.cosmic();
|
let theme = theme.cosmic();
|
||||||
if let Some(grab_elements) = seat
|
if let Some(grab_elements) = seat
|
||||||
.user_data()
|
.user_data()
|
||||||
.get::<SeatMoveGrabState>()
|
.get::<SeatMoveGrabState>()
|
||||||
|
|
@ -469,7 +473,10 @@ where
|
||||||
pub fn workspace_elements<R>(
|
pub fn workspace_elements<R>(
|
||||||
_gpu: Option<&DrmNode>,
|
_gpu: Option<&DrmNode>,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
state: &mut Common,
|
shell: &Shell,
|
||||||
|
config: &Config,
|
||||||
|
theme: &Theme,
|
||||||
|
now: Time<Monotonic>,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
previous: Option<(WorkspaceHandle, usize, WorkspaceDelta)>,
|
previous: Option<(WorkspaceHandle, usize, WorkspaceDelta)>,
|
||||||
current: (WorkspaceHandle, usize),
|
current: (WorkspaceHandle, usize),
|
||||||
|
|
@ -486,7 +493,9 @@ where
|
||||||
{
|
{
|
||||||
let mut elements = cursor_elements(
|
let mut elements = cursor_elements(
|
||||||
renderer,
|
renderer,
|
||||||
state,
|
shell,
|
||||||
|
theme,
|
||||||
|
now,
|
||||||
output,
|
output,
|
||||||
cursor_mode,
|
cursor_mode,
|
||||||
exclude_workspace_overview,
|
exclude_workspace_overview,
|
||||||
|
|
@ -500,7 +509,8 @@ where
|
||||||
if let Some(fps) = _fps.as_mut() {
|
if let Some(fps) = _fps.as_mut() {
|
||||||
let fps_overlay = fps_ui(
|
let fps_overlay = fps_ui(
|
||||||
_gpu,
|
_gpu,
|
||||||
state,
|
shell,
|
||||||
|
theme,
|
||||||
renderer.glow_renderer_mut(),
|
renderer.glow_renderer_mut(),
|
||||||
*fps,
|
*fps,
|
||||||
Rectangle::from_loc_and_size(
|
Rectangle::from_loc_and_size(
|
||||||
|
|
@ -516,7 +526,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
// If session locked, only show session lock surfaces
|
// If session locked, only show session lock surfaces
|
||||||
if let Some(session_lock) = &state.shell.session_lock {
|
if let Some(session_lock) = &shell.session_lock {
|
||||||
elements.extend(
|
elements.extend(
|
||||||
session_lock_elements(renderer, output, session_lock)
|
session_lock_elements(renderer, output, session_lock)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
@ -525,15 +535,13 @@ where
|
||||||
return Ok(elements);
|
return Ok(elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
let theme = state.theme.cosmic();
|
let theme = theme.cosmic();
|
||||||
|
let overview = shell.overview_mode();
|
||||||
let overview = state.shell.overview_mode();
|
let (resize_mode, resize_indicator) = shell.resize_mode();
|
||||||
let (resize_mode, resize_indicator) = state.shell.resize_mode();
|
|
||||||
let resize_indicator = resize_indicator.map(|indicator| (resize_mode, indicator));
|
let resize_indicator = resize_indicator.map(|indicator| (resize_mode, indicator));
|
||||||
let swap_tree = if let OverviewMode::Started(Trigger::KeyboardSwap(_, desc), _) = &overview.0 {
|
let swap_tree = if let OverviewMode::Started(Trigger::KeyboardSwap(_, desc), _) = &overview.0 {
|
||||||
if current.0 != desc.handle {
|
if current.0 != desc.handle {
|
||||||
state
|
shell
|
||||||
.shell
|
|
||||||
.workspaces
|
.workspaces
|
||||||
.space_for_handle(&desc.handle)
|
.space_for_handle(&desc.handle)
|
||||||
.map(|w| w.tiling_layer.tree())
|
.map(|w| w.tiling_layer.tree())
|
||||||
|
|
@ -548,7 +556,7 @@ where
|
||||||
overview.1.map(|indicator| (indicator, swap_tree)),
|
overview.1.map(|indicator| (indicator, swap_tree)),
|
||||||
);
|
);
|
||||||
|
|
||||||
let last_active_seat = state.last_active_seat().clone();
|
let last_active_seat = shell.seats.last_active();
|
||||||
let move_active = last_active_seat
|
let move_active = last_active_seat
|
||||||
.user_data()
|
.user_data()
|
||||||
.get::<SeatMoveGrabState>()
|
.get::<SeatMoveGrabState>()
|
||||||
|
|
@ -559,12 +567,7 @@ where
|
||||||
let output_size = output.geometry().size;
|
let output_size = output.geometry().size;
|
||||||
let output_scale = output.current_scale().fractional_scale();
|
let output_scale = output.current_scale().fractional_scale();
|
||||||
|
|
||||||
let set = state
|
let set = shell.workspaces.sets.get(output).ok_or(OutputNoMode)?;
|
||||||
.shell
|
|
||||||
.workspaces
|
|
||||||
.sets
|
|
||||||
.get(output)
|
|
||||||
.ok_or(OutputNoMode)?;
|
|
||||||
let workspace = set
|
let workspace = set
|
||||||
.workspaces
|
.workspaces
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -593,7 +596,7 @@ where
|
||||||
Vec::new()
|
Vec::new()
|
||||||
};
|
};
|
||||||
|
|
||||||
let active_hint = if state.config.cosmic_conf.active_hint {
|
let active_hint = if config.cosmic_conf.active_hint {
|
||||||
theme.active_hint as u8
|
theme.active_hint as u8
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
|
|
@ -603,8 +606,7 @@ where
|
||||||
// they need to be over sticky windows, because they could be popups of sticky windows,
|
// they need to be over sticky windows, because they could be popups of sticky windows,
|
||||||
// and we can't differenciate that.
|
// and we can't differenciate that.
|
||||||
elements.extend(
|
elements.extend(
|
||||||
state
|
shell
|
||||||
.shell
|
|
||||||
.override_redirect_windows
|
.override_redirect_windows
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|or| {
|
.filter(|or| {
|
||||||
|
|
@ -653,7 +655,7 @@ where
|
||||||
};
|
};
|
||||||
|
|
||||||
let current_focus = (!move_active && is_active_space)
|
let current_focus = (!move_active && is_active_space)
|
||||||
.then_some(&last_active_seat)
|
.then_some(last_active_seat)
|
||||||
.map(|seat| workspace.focus_stack.get(seat));
|
.map(|seat| workspace.focus_stack.get(seat));
|
||||||
|
|
||||||
let (w_elements, p_elements) = set.sticky_layer.render(
|
let (w_elements, p_elements) = set.sticky_layer.render(
|
||||||
|
|
@ -683,10 +685,9 @@ where
|
||||||
|
|
||||||
let offset = match previous.as_ref() {
|
let offset = match previous.as_ref() {
|
||||||
Some((previous, previous_idx, start)) => {
|
Some((previous, previous_idx, start)) => {
|
||||||
let layout = state.config.cosmic_conf.workspaces.workspace_layout;
|
let layout = config.cosmic_conf.workspaces.workspace_layout;
|
||||||
|
|
||||||
let workspace = state
|
let workspace = shell
|
||||||
.shell
|
|
||||||
.workspaces
|
.workspaces
|
||||||
.space_for_handle(&previous)
|
.space_for_handle(&previous)
|
||||||
.ok_or(OutputNoMode)?;
|
.ok_or(OutputNoMode)?;
|
||||||
|
|
@ -724,7 +725,7 @@ where
|
||||||
let (w_elements, p_elements) = workspace
|
let (w_elements, p_elements) = workspace
|
||||||
.render::<R>(
|
.render::<R>(
|
||||||
renderer,
|
renderer,
|
||||||
(!move_active && is_active_space).then_some(&last_active_seat),
|
(!move_active && is_active_space).then_some(last_active_seat),
|
||||||
overview.clone(),
|
overview.clone(),
|
||||||
resize_indicator.clone(),
|
resize_indicator.clone(),
|
||||||
active_hint,
|
active_hint,
|
||||||
|
|
@ -953,7 +954,10 @@ pub fn render_output<'d, R, Target, OffTarget>(
|
||||||
target: Target,
|
target: Target,
|
||||||
damage_tracker: &'d mut OutputDamageTracker,
|
damage_tracker: &'d mut OutputDamageTracker,
|
||||||
age: usize,
|
age: usize,
|
||||||
state: &mut Common,
|
shell: &Shell,
|
||||||
|
config: &Config,
|
||||||
|
theme: &Theme,
|
||||||
|
now: Time<Monotonic>,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
cursor_mode: CursorMode,
|
cursor_mode: CursorMode,
|
||||||
fps: Option<&mut Fps>,
|
fps: Option<&mut Fps>,
|
||||||
|
|
@ -975,8 +979,8 @@ where
|
||||||
WorkspaceRenderElement<R>: RenderElement<R>,
|
WorkspaceRenderElement<R>: RenderElement<R>,
|
||||||
Target: Clone,
|
Target: Clone,
|
||||||
{
|
{
|
||||||
let (previous_workspace, workspace) = state.shell.workspaces.active(output);
|
let (previous_workspace, workspace) = shell.workspaces.active(output);
|
||||||
let (previous_idx, idx) = state.shell.workspaces.active_num(output);
|
let (previous_idx, idx) = shell.workspaces.active_num(output);
|
||||||
let previous_workspace = previous_workspace
|
let previous_workspace = previous_workspace
|
||||||
.zip(previous_idx)
|
.zip(previous_idx)
|
||||||
.map(|((w, start), idx)| (w.handle, idx, start));
|
.map(|((w, start), idx)| (w.handle, idx, start));
|
||||||
|
|
@ -989,7 +993,10 @@ where
|
||||||
damage_tracker,
|
damage_tracker,
|
||||||
age,
|
age,
|
||||||
None,
|
None,
|
||||||
state,
|
shell,
|
||||||
|
config,
|
||||||
|
theme,
|
||||||
|
now,
|
||||||
output,
|
output,
|
||||||
previous_workspace,
|
previous_workspace,
|
||||||
workspace,
|
workspace,
|
||||||
|
|
@ -1081,7 +1088,7 @@ where
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
)? {
|
)? {
|
||||||
frame.success(output.current_transform(), damage, state.clock.now());
|
frame.success(output.current_transform(), damage, now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1099,7 +1106,10 @@ pub fn render_workspace<'d, R, Target, OffTarget>(
|
||||||
damage_tracker: &'d mut OutputDamageTracker,
|
damage_tracker: &'d mut OutputDamageTracker,
|
||||||
age: usize,
|
age: usize,
|
||||||
additional_damage: Option<Vec<Rectangle<i32, Logical>>>,
|
additional_damage: Option<Vec<Rectangle<i32, Logical>>>,
|
||||||
state: &mut Common,
|
shell: &Shell,
|
||||||
|
config: &Config,
|
||||||
|
theme: &Theme,
|
||||||
|
now: Time<Monotonic>,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
previous: Option<(WorkspaceHandle, usize, WorkspaceDelta)>,
|
previous: Option<(WorkspaceHandle, usize, WorkspaceDelta)>,
|
||||||
current: (WorkspaceHandle, usize),
|
current: (WorkspaceHandle, usize),
|
||||||
|
|
@ -1136,7 +1146,10 @@ where
|
||||||
let mut elements: Vec<CosmicElement<R>> = workspace_elements(
|
let mut elements: Vec<CosmicElement<R>> = workspace_elements(
|
||||||
gpu,
|
gpu,
|
||||||
renderer,
|
renderer,
|
||||||
state,
|
shell,
|
||||||
|
config,
|
||||||
|
theme,
|
||||||
|
now,
|
||||||
output,
|
output,
|
||||||
previous,
|
previous,
|
||||||
current,
|
current,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::render,
|
backend::render,
|
||||||
config::OutputConfig,
|
config::OutputConfig,
|
||||||
input::Devices,
|
shell::{Devices, SeatExt},
|
||||||
state::{BackendData, Common},
|
state::{BackendData, Common},
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
};
|
};
|
||||||
|
|
@ -63,7 +63,10 @@ impl WinitState {
|
||||||
surface.clone(),
|
surface.clone(),
|
||||||
&mut self.damage_tracker,
|
&mut self.damage_tracker,
|
||||||
age,
|
age,
|
||||||
state,
|
&state.shell,
|
||||||
|
&state.config,
|
||||||
|
&state.theme,
|
||||||
|
state.clock.now(),
|
||||||
&self.output,
|
&self.output,
|
||||||
CursorMode::NotDefault,
|
CursorMode::NotDefault,
|
||||||
#[cfg(not(feature = "debug"))]
|
#[cfg(not(feature = "debug"))]
|
||||||
|
|
@ -198,8 +201,7 @@ pub fn init_backend(
|
||||||
}
|
}
|
||||||
PumpStatus::Exit(_) => {
|
PumpStatus::Exit(_) => {
|
||||||
let output = state.backend.winit().output.clone();
|
let output = state.backend.winit().output.clone();
|
||||||
let seats = state.common.seats().cloned().collect::<Vec<_>>();
|
state.common.shell.remove_output(&output);
|
||||||
state.common.shell.remove_output(&output, seats.into_iter());
|
|
||||||
if let Some(token) = token.take() {
|
if let Some(token) = token.take() {
|
||||||
event_loop_handle.remove(token);
|
event_loop_handle.remove(token);
|
||||||
}
|
}
|
||||||
|
|
@ -225,12 +227,10 @@ pub fn init_backend(
|
||||||
.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.shell.add_output(&output);
|
||||||
let seats = state.common.seats().cloned().collect::<Vec<_>>();
|
|
||||||
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,
|
||||||
seats.iter().cloned(),
|
|
||||||
&state.common.event_loop_handle,
|
&state.common.event_loop_handle,
|
||||||
);
|
);
|
||||||
state.launch_xwayland(None);
|
state.launch_xwayland(None);
|
||||||
|
|
@ -299,7 +299,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.seats().cloned().collect::<Vec<_>>().iter() {
|
for seat in self.common.shell.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);
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::render,
|
backend::render,
|
||||||
config::OutputConfig,
|
config::OutputConfig,
|
||||||
input::Devices,
|
shell::{Devices, SeatExt},
|
||||||
state::{BackendData, Common},
|
state::{BackendData, Common},
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
};
|
};
|
||||||
|
|
@ -222,7 +222,10 @@ impl Surface {
|
||||||
buffer.clone(),
|
buffer.clone(),
|
||||||
&mut self.damage_tracker,
|
&mut self.damage_tracker,
|
||||||
age as usize,
|
age as usize,
|
||||||
state,
|
&state.shell,
|
||||||
|
&state.config,
|
||||||
|
&state.theme,
|
||||||
|
state.clock.now(),
|
||||||
&self.output,
|
&self.output,
|
||||||
render::CursorMode::NotDefault,
|
render::CursorMode::NotDefault,
|
||||||
#[cfg(not(feature = "debug"))]
|
#[cfg(not(feature = "debug"))]
|
||||||
|
|
@ -362,12 +365,10 @@ pub fn init_backend(
|
||||||
.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.shell.add_output(&output);
|
||||||
let seats = state.common.seats().cloned().collect::<Vec<_>>();
|
|
||||||
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,
|
||||||
seats.iter().cloned(),
|
|
||||||
&state.common.event_loop_handle,
|
&state.common.event_loop_handle,
|
||||||
);
|
);
|
||||||
state.launch_xwayland(None);
|
state.launch_xwayland(None);
|
||||||
|
|
@ -394,10 +395,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
|
state.common.shell.remove_output(&output);
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.remove_output(&output, seats.iter().cloned());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
X11Event::Resized {
|
X11Event::Resized {
|
||||||
|
|
@ -506,7 +504,7 @@ impl State {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let device = event.device();
|
let device = event.device();
|
||||||
for seat in self.common.seats().cloned().collect::<Vec<_>>().iter() {
|
for seat in self.common.shell.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);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ use crate::{
|
||||||
};
|
};
|
||||||
use cosmic_config::{ConfigGet, CosmicConfigEntry};
|
use cosmic_config::{ConfigGet, CosmicConfigEntry};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use smithay::input::Seat;
|
|
||||||
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,10 +276,8 @@ impl Config {
|
||||||
output_state: &mut OutputConfigurationState<State>,
|
output_state: &mut OutputConfigurationState<State>,
|
||||||
backend: &mut BackendData,
|
backend: &mut BackendData,
|
||||||
shell: &mut Shell,
|
shell: &mut Shell,
|
||||||
seats: impl Iterator<Item = Seat<State>>,
|
|
||||||
loop_handle: &LoopHandle<'_, State>,
|
loop_handle: &LoopHandle<'_, State>,
|
||||||
) {
|
) {
|
||||||
let seats = seats.collect::<Vec<_>>();
|
|
||||||
let outputs = output_state.outputs().collect::<Vec<_>>();
|
let outputs = output_state.outputs().collect::<Vec<_>>();
|
||||||
let mut infos = outputs
|
let mut infos = outputs
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -311,13 +308,9 @@ impl Config {
|
||||||
.get::<RefCell<OutputConfig>>()
|
.get::<RefCell<OutputConfig>>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.borrow_mut() = output_config;
|
.borrow_mut() = output_config;
|
||||||
if let Err(err) = backend.apply_config_for_output(
|
if let Err(err) =
|
||||||
&output,
|
backend.apply_config_for_output(&output, false, shell, loop_handle)
|
||||||
false,
|
{
|
||||||
shell,
|
|
||||||
seats.iter().cloned(),
|
|
||||||
loop_handle,
|
|
||||||
) {
|
|
||||||
warn!(
|
warn!(
|
||||||
?err,
|
?err,
|
||||||
"Failed to set new config for output {}.",
|
"Failed to set new config for output {}.",
|
||||||
|
|
@ -346,13 +339,9 @@ impl Config {
|
||||||
.get::<RefCell<OutputConfig>>()
|
.get::<RefCell<OutputConfig>>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.borrow_mut() = output_config;
|
.borrow_mut() = output_config;
|
||||||
if let Err(err) = backend.apply_config_for_output(
|
if let Err(err) =
|
||||||
&output,
|
backend.apply_config_for_output(&output, false, shell, loop_handle)
|
||||||
false,
|
{
|
||||||
shell,
|
|
||||||
seats.iter().cloned(),
|
|
||||||
loop_handle,
|
|
||||||
) {
|
|
||||||
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 {
|
||||||
|
|
@ -368,13 +357,9 @@ 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) = backend.apply_config_for_output(
|
if let Err(err) =
|
||||||
&output,
|
backend.apply_config_for_output(&output, false, shell, loop_handle)
|
||||||
false,
|
{
|
||||||
shell,
|
|
||||||
seats.iter().cloned(),
|
|
||||||
loop_handle,
|
|
||||||
) {
|
|
||||||
warn!(
|
warn!(
|
||||||
?err,
|
?err,
|
||||||
"Failed to set new config for output {}.",
|
"Failed to set new config for output {}.",
|
||||||
|
|
@ -533,7 +518,8 @@ 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");
|
||||||
for seat in state.common.seats().cloned().collect::<Vec<_>>().iter() {
|
let seats = state.common.shell.seats.iter().cloned().collect::<Vec<_>>();
|
||||||
|
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)) {
|
||||||
error!(?err, "Failed to load provided xkb config");
|
error!(?err, "Failed to load provided xkb config");
|
||||||
|
|
@ -567,26 +553,14 @@ fn config_changed(config: cosmic_config::Config, keys: Vec<String>, state: &mut
|
||||||
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;
|
||||||
let seats: Vec<_> = state.common.seats().cloned().collect();
|
state.common.shell.update_autotile(new);
|
||||||
let mut guard = state.common.shell.workspace_state.update();
|
|
||||||
state
|
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.workspaces
|
|
||||||
.update_autotile(new, &mut guard, seats);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"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;
|
||||||
let seats: Vec<_> = state.common.seats().cloned().collect();
|
state.common.shell.update_autotile_behavior(new);
|
||||||
let mut guard = state.common.shell.workspace_state.update();
|
|
||||||
state
|
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.workspaces
|
|
||||||
.update_autotile_behavior(new, &mut guard, seats);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"active_hint" => {
|
"active_hint" => {
|
||||||
|
|
|
||||||
335
src/input/mod.rs
335
src/input/mod.rs
|
|
@ -1,21 +1,20 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::render::cursor::CursorState,
|
config::{Action, KeyModifiers, KeyPattern},
|
||||||
config::{xkb_config_to_wl, Action, Config, KeyModifiers, KeyPattern},
|
|
||||||
input::gestures::{GestureState, SwipeAction},
|
input::gestures::{GestureState, SwipeAction},
|
||||||
shell::{
|
shell::{
|
||||||
focus::{
|
focus::{
|
||||||
target::{KeyboardFocusTarget, PointerFocusTarget},
|
target::{KeyboardFocusTarget, PointerFocusTarget},
|
||||||
FocusDirection,
|
FocusDirection,
|
||||||
},
|
},
|
||||||
grabs::{ReleaseMode, ResizeEdge, SeatMenuGrabState, SeatMoveGrabState},
|
grabs::{ReleaseMode, ResizeEdge},
|
||||||
layout::{
|
layout::{
|
||||||
floating::ResizeGrabMarker,
|
floating::ResizeGrabMarker,
|
||||||
tiling::{SwapWindowGrab, TilingLayout},
|
tiling::{SwapWindowGrab, TilingLayout},
|
||||||
},
|
},
|
||||||
Direction, FocusResult, InvalidWorkspaceIndex, MoveResult, OverviewMode, ResizeDirection,
|
Direction, FocusResult, InvalidWorkspaceIndex, MoveResult, OverviewMode, ResizeDirection,
|
||||||
ResizeMode, Trigger, WorkspaceDelta,
|
ResizeMode, SeatExt, Trigger, WorkspaceDelta,
|
||||||
},
|
},
|
||||||
state::Common,
|
state::Common,
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
|
|
@ -40,20 +39,19 @@ use smithay::{
|
||||||
WindowSurfaceType,
|
WindowSurfaceType,
|
||||||
},
|
},
|
||||||
input::{
|
input::{
|
||||||
keyboard::{FilterResult, KeysymHandle, LedState, XkbConfig},
|
keyboard::{FilterResult, KeysymHandle},
|
||||||
pointer::{
|
pointer::{
|
||||||
AxisFrame, ButtonEvent, CursorImageStatus, GestureHoldBeginEvent, GestureHoldEndEvent,
|
AxisFrame, ButtonEvent, GestureHoldBeginEvent, GestureHoldEndEvent,
|
||||||
GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent,
|
GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent,
|
||||||
GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent,
|
GestureSwipeBeginEvent, GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent,
|
||||||
RelativeMotionEvent,
|
RelativeMotionEvent,
|
||||||
},
|
},
|
||||||
touch::{DownEvent, MotionEvent as TouchMotionEvent, UpEvent},
|
touch::{DownEvent, MotionEvent as TouchMotionEvent, UpEvent},
|
||||||
Seat, SeatState,
|
Seat,
|
||||||
},
|
},
|
||||||
output::Output,
|
output::Output,
|
||||||
reexports::{
|
reexports::{
|
||||||
input::Device as InputDevice,
|
input::Device as InputDevice, wayland_server::protocol::wl_shm::Format as ShmFormat,
|
||||||
wayland_server::{protocol::wl_shm::Format as ShmFormat, DisplayHandle},
|
|
||||||
},
|
},
|
||||||
utils::{Point, Serial, SERIAL_COUNTER},
|
utils::{Point, Serial, SERIAL_COUNTER},
|
||||||
wayland::{
|
wayland::{
|
||||||
|
|
@ -67,47 +65,23 @@ use smithay::{
|
||||||
};
|
};
|
||||||
#[cfg(not(feature = "debug"))]
|
#[cfg(not(feature = "debug"))]
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
use tracing::{error, trace, warn};
|
use tracing::{error, trace};
|
||||||
use xkbcommon::xkb::{Keycode, Keysym};
|
use xkbcommon::xkb::{Keycode, Keysym};
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
any::Any,
|
any::Any,
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
collections::HashMap,
|
|
||||||
os::unix::process::CommandExt,
|
os::unix::process::CommandExt,
|
||||||
thread,
|
thread,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
crate::utils::id_gen!(next_seat_id, SEAT_ID, SEAT_IDS);
|
|
||||||
|
|
||||||
pub mod gestures;
|
pub mod gestures;
|
||||||
|
|
||||||
#[repr(transparent)]
|
|
||||||
pub struct SeatId(pub usize);
|
|
||||||
pub struct ActiveOutput(pub RefCell<Output>);
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct SupressedKeys(RefCell<Vec<(Keycode, Option<RegistrationToken>)>>);
|
pub struct SupressedKeys(RefCell<Vec<(Keycode, Option<RegistrationToken>)>>);
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct ModifiersShortcutQueue(RefCell<Option<KeyPattern>>);
|
pub struct ModifiersShortcutQueue(RefCell<Option<KeyPattern>>);
|
||||||
#[derive(Default)]
|
|
||||||
pub struct Devices {
|
|
||||||
capabilities: RefCell<HashMap<String, Vec<DeviceCapability>>>,
|
|
||||||
// Used for updating keyboard leds on kms backend
|
|
||||||
keyboards: RefCell<Vec<InputDevice>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for SeatId {
|
|
||||||
fn default() -> SeatId {
|
|
||||||
SeatId(next_seat_id())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for SeatId {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
SEAT_IDS.lock().unwrap().remove(&self.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SupressedKeys {
|
impl SupressedKeys {
|
||||||
fn add(&self, keysym: &KeysymHandle, token: impl Into<Option<RegistrationToken>>) {
|
fn add(&self, keysym: &KeysymHandle, token: impl Into<Option<RegistrationToken>>) {
|
||||||
|
|
@ -156,105 +130,6 @@ impl ModifiersShortcutQueue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Devices {
|
|
||||||
fn add_device<D: Device + 'static>(&self, device: &D) -> Vec<DeviceCapability> {
|
|
||||||
let id = device.id();
|
|
||||||
let mut map = self.capabilities.borrow_mut();
|
|
||||||
let caps = [
|
|
||||||
DeviceCapability::Keyboard,
|
|
||||||
DeviceCapability::Pointer,
|
|
||||||
DeviceCapability::TabletTool,
|
|
||||||
]
|
|
||||||
.iter()
|
|
||||||
.cloned()
|
|
||||||
.filter(|c| device.has_capability(*c))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let new_caps = caps
|
|
||||||
.iter()
|
|
||||||
.cloned()
|
|
||||||
.filter(|c| map.values().flatten().all(|has| *c != *has))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
map.insert(id, caps);
|
|
||||||
|
|
||||||
if device.has_capability(DeviceCapability::Keyboard) {
|
|
||||||
if let Some(device) = <dyn Any>::downcast_ref::<InputDevice>(device) {
|
|
||||||
self.keyboards.borrow_mut().push(device.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
new_caps
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn has_device<D: Device>(&self, device: &D) -> bool {
|
|
||||||
self.capabilities.borrow().contains_key(&device.id())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_device<D: Device>(&self, device: &D) -> Vec<DeviceCapability> {
|
|
||||||
let id = device.id();
|
|
||||||
|
|
||||||
let mut keyboards = self.keyboards.borrow_mut();
|
|
||||||
if let Some(idx) = keyboards.iter().position(|x| x.id() == id) {
|
|
||||||
keyboards.remove(idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut map = self.capabilities.borrow_mut();
|
|
||||||
map.remove(&id)
|
|
||||||
.unwrap_or(Vec::new())
|
|
||||||
.into_iter()
|
|
||||||
.filter(|c| map.values().flatten().all(|has| *c != *has))
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn update_led_state(&self, led_state: LedState) {
|
|
||||||
for keyboard in self.keyboards.borrow_mut().iter_mut() {
|
|
||||||
keyboard.led_update(led_state.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_seat(
|
|
||||||
dh: &DisplayHandle,
|
|
||||||
seat_state: &mut SeatState<State>,
|
|
||||||
output: &Output,
|
|
||||||
config: &Config,
|
|
||||||
name: String,
|
|
||||||
) -> Seat<State> {
|
|
||||||
let mut seat = seat_state.new_wl_seat(dh, name);
|
|
||||||
let userdata = seat.user_data();
|
|
||||||
userdata.insert_if_missing(SeatId::default);
|
|
||||||
userdata.insert_if_missing(Devices::default);
|
|
||||||
userdata.insert_if_missing(SupressedKeys::default);
|
|
||||||
userdata.insert_if_missing(ModifiersShortcutQueue::default);
|
|
||||||
userdata.insert_if_missing(SeatMoveGrabState::default);
|
|
||||||
userdata.insert_if_missing(SeatMenuGrabState::default);
|
|
||||||
userdata.insert_if_missing(CursorState::default);
|
|
||||||
userdata.insert_if_missing(|| ActiveOutput(RefCell::new(output.clone())));
|
|
||||||
userdata.insert_if_missing(|| RefCell::new(CursorImageStatus::default_named()));
|
|
||||||
|
|
||||||
// A lot of clients bind keyboard and pointer unconditionally once on launch..
|
|
||||||
// Initial clients might race the compositor on adding periheral and
|
|
||||||
// end up in a state, where they are not able to receive input.
|
|
||||||
// Additionally a lot of clients don't handle keyboards/pointer objects being
|
|
||||||
// removed very well either and we don't want to crash applications, because the
|
|
||||||
// user is replugging their keyboard or mouse.
|
|
||||||
//
|
|
||||||
// So instead of doing the right thing (and initialize these capabilities as matching
|
|
||||||
// devices appear), we have to surrender to reality and just always expose a keyboard and pointer.
|
|
||||||
let conf = config.xkb_config();
|
|
||||||
if let Err(err) = seat.add_keyboard(xkb_config_to_wl(&conf), 600, 25) {
|
|
||||||
warn!(
|
|
||||||
?err,
|
|
||||||
"Failed to load provided xkb config. Trying default...",
|
|
||||||
);
|
|
||||||
seat.add_keyboard(XkbConfig::default(), 600, 25)
|
|
||||||
.expect("Failed to load xkb configuration files");
|
|
||||||
}
|
|
||||||
seat.add_pointer();
|
|
||||||
seat.add_touch();
|
|
||||||
|
|
||||||
seat
|
|
||||||
}
|
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
pub fn process_input_event<B: InputBackend>(
|
pub fn process_input_event<B: InputBackend>(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
|
@ -266,10 +141,8 @@ impl State {
|
||||||
use smithay::backend::input::Event;
|
use smithay::backend::input::Event;
|
||||||
match event {
|
match event {
|
||||||
InputEvent::DeviceAdded { device } => {
|
InputEvent::DeviceAdded { device } => {
|
||||||
let seat = &mut self.common.last_active_seat();
|
let seat = &mut self.common.shell.seats.last_active();
|
||||||
let userdata = seat.user_data();
|
for cap in seat.devices().add_device(&device) {
|
||||||
let devices = userdata.get::<Devices>().unwrap();
|
|
||||||
for cap in devices.add_device(&device) {
|
|
||||||
match cap {
|
match cap {
|
||||||
DeviceCapability::TabletTool => {
|
DeviceCapability::TabletTool => {
|
||||||
seat.tablet_seat().add_tablet::<Self>(
|
seat.tablet_seat().add_tablet::<Self>(
|
||||||
|
|
@ -287,9 +160,8 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::DeviceRemoved { device } => {
|
InputEvent::DeviceRemoved { device } => {
|
||||||
for seat in &mut self.common.seats() {
|
for seat in &mut self.common.shell.seats.iter() {
|
||||||
let userdata = seat.user_data();
|
let devices = seat.devices();
|
||||||
let devices = userdata.get::<Devices>().unwrap();
|
|
||||||
if devices.has_device(&device) {
|
if devices.has_device(&device) {
|
||||||
for cap in devices.remove_device(&device) {
|
for cap in devices.remove_device(&device) {
|
||||||
match cap {
|
match cap {
|
||||||
|
|
@ -314,7 +186,7 @@ impl State {
|
||||||
|
|
||||||
let loop_handle = self.common.event_loop_handle.clone();
|
let loop_handle = self.common.event_loop_handle.clone();
|
||||||
|
|
||||||
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
|
if let Some(seat) = self.common.shell.seats.for_device(&event.device()).cloned() {
|
||||||
let userdata = seat.user_data();
|
let userdata = seat.user_data();
|
||||||
|
|
||||||
let current_output = seat.active_output();
|
let current_output = seat.active_output();
|
||||||
|
|
@ -383,7 +255,7 @@ impl State {
|
||||||
if let Some(focus) = TilingLayout::swap_trees(&mut old_workspace.tiling_layer, Some(&mut new_workspace.tiling_layer), &old_descriptor, &new_descriptor, &mut data.common.shell.toplevel_info_state) {
|
if let Some(focus) = TilingLayout::swap_trees(&mut old_workspace.tiling_layer, Some(&mut new_workspace.tiling_layer), &old_descriptor, &new_descriptor, &mut data.common.shell.toplevel_info_state) {
|
||||||
let seat = seat.clone();
|
let seat = seat.clone();
|
||||||
data.common.event_loop_handle.insert_idle(move |state| {
|
data.common.event_loop_handle.insert_idle(move |state| {
|
||||||
Common::set_focus(state, Some(&focus), &seat, None);
|
Shell::set_focus(state, Some(&focus), &seat, None);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
old_workspace.refresh_focus_stack();
|
old_workspace.refresh_focus_stack();
|
||||||
|
|
@ -396,7 +268,7 @@ impl State {
|
||||||
std::mem::drop(spaces);
|
std::mem::drop(spaces);
|
||||||
let seat = seat.clone();
|
let seat = seat.clone();
|
||||||
data.common.event_loop_handle.insert_idle(move |state| {
|
data.common.event_loop_handle.insert_idle(move |state| {
|
||||||
Common::set_focus(state, Some(&focus), &seat, None);
|
Shell::set_focus(state, Some(&focus), &seat, None);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
workspace.refresh_focus_stack();
|
workspace.refresh_focus_stack();
|
||||||
|
|
@ -414,7 +286,7 @@ impl State {
|
||||||
if let Some(focus) = TilingLayout::move_tree(&mut old_workspace.tiling_layer, &mut new_workspace.tiling_layer, &new_workspace.handle, &seat, new_workspace.focus_stack.get(&seat).iter(), old_descriptor, &mut data.common.shell.toplevel_info_state) {
|
if let Some(focus) = TilingLayout::move_tree(&mut old_workspace.tiling_layer, &mut new_workspace.tiling_layer, &new_workspace.handle, &seat, new_workspace.focus_stack.get(&seat).iter(), old_descriptor, &mut data.common.shell.toplevel_info_state) {
|
||||||
let seat = seat.clone();
|
let seat = seat.clone();
|
||||||
data.common.event_loop_handle.insert_idle(move |state| {
|
data.common.event_loop_handle.insert_idle(move |state| {
|
||||||
Common::set_focus(state, Some(&focus), &seat, None);
|
Shell::set_focus(state, Some(&focus), &seat, None);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
old_workspace.refresh_focus_stack();
|
old_workspace.refresh_focus_stack();
|
||||||
|
|
@ -633,7 +505,7 @@ impl State {
|
||||||
InputEvent::PointerMotion { event, .. } => {
|
InputEvent::PointerMotion { event, .. } => {
|
||||||
use smithay::backend::input::PointerMotionEvent;
|
use smithay::backend::input::PointerMotionEvent;
|
||||||
|
|
||||||
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
|
if let Some(seat) = self.common.shell.seats.for_device(&event.device()).cloned() {
|
||||||
let current_output = seat.active_output();
|
let current_output = seat.active_output();
|
||||||
|
|
||||||
let mut position = seat.get_pointer().unwrap().current_location().as_global();
|
let mut position = seat.get_pointer().unwrap().current_location().as_global();
|
||||||
|
|
@ -831,7 +703,7 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::PointerMotionAbsolute { event, .. } => {
|
InputEvent::PointerMotionAbsolute { event, .. } => {
|
||||||
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
|
if let Some(seat) = self.common.shell.seats.for_device(&event.device()).cloned() {
|
||||||
let output = seat.active_output();
|
let output = seat.active_output();
|
||||||
let geometry = output.geometry();
|
let geometry = output.geometry();
|
||||||
let position = geometry.loc.to_f64()
|
let position = geometry.loc.to_f64()
|
||||||
|
|
@ -891,7 +763,7 @@ impl State {
|
||||||
InputEvent::PointerButton { event, .. } => {
|
InputEvent::PointerButton { event, .. } => {
|
||||||
use smithay::backend::input::{ButtonState, PointerButtonEvent};
|
use smithay::backend::input::{ButtonState, PointerButtonEvent};
|
||||||
|
|
||||||
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
|
if let Some(seat) = self.common.shell.seats.for_device(&event.device()).cloned() {
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
if self.common.seats().position(|x| x == &seat).unwrap() == 0
|
if self.common.seats().position(|x| x == &seat).unwrap() == 0
|
||||||
&& self.common.egui.active
|
&& self.common.egui.active
|
||||||
|
|
@ -1033,7 +905,7 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Common::set_focus(self, under.as_ref(), &seat, Some(serial));
|
Shell::set_focus(self, under.as_ref(), &seat, Some(serial));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let OverviewMode::Started(Trigger::Pointer(action_button), _) =
|
if let OverviewMode::Started(Trigger::Pointer(action_button), _) =
|
||||||
|
|
@ -1067,7 +939,7 @@ impl State {
|
||||||
1.0
|
1.0
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
if let Some(seat) = self.common.shell.seats.for_device(&event.device()) {
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
if self.common.seats().position(|x| x == seat).unwrap() == 0
|
if self.common.seats().position(|x| x == seat).unwrap() == 0
|
||||||
&& self.common.egui.active
|
&& self.common.egui.active
|
||||||
|
|
@ -1121,7 +993,7 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::GestureSwipeBegin { event, .. } => {
|
InputEvent::GestureSwipeBegin { event, .. } => {
|
||||||
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
if let Some(seat) = self.common.shell.seats.for_device(&event.device()) {
|
||||||
if event.fingers() >= 3 {
|
if event.fingers() >= 3 {
|
||||||
self.common.gesture_state = Some(GestureState::new(event.fingers()));
|
self.common.gesture_state = Some(GestureState::new(event.fingers()));
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1139,7 +1011,7 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::GestureSwipeUpdate { event, .. } => {
|
InputEvent::GestureSwipeUpdate { event, .. } => {
|
||||||
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
|
if let Some(seat) = self.common.shell.seats.for_device(&event.device()).cloned() {
|
||||||
let mut activate_action: Option<SwipeAction> = None;
|
let mut activate_action: Option<SwipeAction> = None;
|
||||||
if let Some(ref mut gesture_state) = self.common.gesture_state {
|
if let Some(ref mut gesture_state) = self.common.gesture_state {
|
||||||
let first_update = gesture_state.update(
|
let first_update = gesture_state.update(
|
||||||
|
|
@ -1210,7 +1082,7 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::GestureSwipeEnd { event, .. } => {
|
InputEvent::GestureSwipeEnd { event, .. } => {
|
||||||
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
|
if let Some(seat) = self.common.shell.seats.for_device(&event.device()).cloned() {
|
||||||
if let Some(ref gesture_state) = self.common.gesture_state {
|
if let Some(ref gesture_state) = self.common.gesture_state {
|
||||||
match gesture_state.action {
|
match gesture_state.action {
|
||||||
Some(SwipeAction::NextWorkspace) | Some(SwipeAction::PrevWorkspace) => {
|
Some(SwipeAction::NextWorkspace) | Some(SwipeAction::PrevWorkspace) => {
|
||||||
|
|
@ -1246,7 +1118,7 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::GesturePinchBegin { event, .. } => {
|
InputEvent::GesturePinchBegin { event, .. } => {
|
||||||
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
if let Some(seat) = self.common.shell.seats.for_device(&event.device()) {
|
||||||
let serial = SERIAL_COUNTER.next_serial();
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
let pointer = seat.get_pointer().unwrap();
|
let pointer = seat.get_pointer().unwrap();
|
||||||
pointer.gesture_pinch_begin(
|
pointer.gesture_pinch_begin(
|
||||||
|
|
@ -1260,7 +1132,7 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::GesturePinchUpdate { event, .. } => {
|
InputEvent::GesturePinchUpdate { event, .. } => {
|
||||||
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
if let Some(seat) = self.common.shell.seats.for_device(&event.device()) {
|
||||||
let pointer = seat.get_pointer().unwrap();
|
let pointer = seat.get_pointer().unwrap();
|
||||||
pointer.gesture_pinch_update(
|
pointer.gesture_pinch_update(
|
||||||
self,
|
self,
|
||||||
|
|
@ -1274,7 +1146,7 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::GesturePinchEnd { event, .. } => {
|
InputEvent::GesturePinchEnd { event, .. } => {
|
||||||
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
if let Some(seat) = self.common.shell.seats.for_device(&event.device()) {
|
||||||
let serial = SERIAL_COUNTER.next_serial();
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
let pointer = seat.get_pointer().unwrap();
|
let pointer = seat.get_pointer().unwrap();
|
||||||
pointer.gesture_pinch_end(
|
pointer.gesture_pinch_end(
|
||||||
|
|
@ -1288,7 +1160,7 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::GestureHoldBegin { event, .. } => {
|
InputEvent::GestureHoldBegin { event, .. } => {
|
||||||
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
if let Some(seat) = self.common.shell.seats.for_device(&event.device()) {
|
||||||
let serial = SERIAL_COUNTER.next_serial();
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
let pointer = seat.get_pointer().unwrap();
|
let pointer = seat.get_pointer().unwrap();
|
||||||
pointer.gesture_hold_begin(
|
pointer.gesture_hold_begin(
|
||||||
|
|
@ -1302,7 +1174,7 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::GestureHoldEnd { event, .. } => {
|
InputEvent::GestureHoldEnd { event, .. } => {
|
||||||
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
if let Some(seat) = self.common.shell.seats.for_device(&event.device()) {
|
||||||
let serial = SERIAL_COUNTER.next_serial();
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
let pointer = seat.get_pointer().unwrap();
|
let pointer = seat.get_pointer().unwrap();
|
||||||
pointer.gesture_hold_end(
|
pointer.gesture_hold_end(
|
||||||
|
|
@ -1316,7 +1188,7 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::TouchDown { event, .. } => {
|
InputEvent::TouchDown { event, .. } => {
|
||||||
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
|
if let Some(seat) = self.common.shell.seats.for_device(&event.device()).cloned() {
|
||||||
let Some(output) =
|
let Some(output) =
|
||||||
mapped_output_for_device(&self.common, &event.device()).cloned()
|
mapped_output_for_device(&self.common, &event.device()).cloned()
|
||||||
else {
|
else {
|
||||||
|
|
@ -1348,7 +1220,7 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::TouchMotion { event, .. } => {
|
InputEvent::TouchMotion { event, .. } => {
|
||||||
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
|
if let Some(seat) = self.common.shell.seats.for_device(&event.device()).cloned() {
|
||||||
let Some(output) =
|
let Some(output) =
|
||||||
mapped_output_for_device(&self.common, &event.device()).cloned()
|
mapped_output_for_device(&self.common, &event.device()).cloned()
|
||||||
else {
|
else {
|
||||||
|
|
@ -1388,7 +1260,7 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
if let Some(seat) = self.common.shell.seats.for_device(&event.device()) {
|
||||||
let serial = SERIAL_COUNTER.next_serial();
|
let serial = SERIAL_COUNTER.next_serial();
|
||||||
let touch = seat.get_touch().unwrap();
|
let touch = seat.get_touch().unwrap();
|
||||||
touch.up(
|
touch.up(
|
||||||
|
|
@ -1402,19 +1274,19 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::TouchCancel { event, .. } => {
|
InputEvent::TouchCancel { event, .. } => {
|
||||||
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
if let Some(seat) = self.common.shell.seats.for_device(&event.device()) {
|
||||||
let touch = seat.get_touch().unwrap();
|
let touch = seat.get_touch().unwrap();
|
||||||
touch.cancel(self);
|
touch.cancel(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::TouchFrame { event, .. } => {
|
InputEvent::TouchFrame { event, .. } => {
|
||||||
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
if let Some(seat) = self.common.shell.seats.for_device(&event.device()) {
|
||||||
let touch = seat.get_touch().unwrap();
|
let touch = seat.get_touch().unwrap();
|
||||||
touch.frame(self);
|
touch.frame(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::TabletToolAxis { event, .. } => {
|
InputEvent::TabletToolAxis { event, .. } => {
|
||||||
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
|
if let Some(seat) = self.common.shell.seats.for_device(&event.device()).cloned() {
|
||||||
let Some(output) =
|
let Some(output) =
|
||||||
mapped_output_for_device(&self.common, &event.device()).cloned()
|
mapped_output_for_device(&self.common, &event.device()).cloned()
|
||||||
else {
|
else {
|
||||||
|
|
@ -1477,7 +1349,7 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::TabletToolProximity { event, .. } => {
|
InputEvent::TabletToolProximity { event, .. } => {
|
||||||
if let Some(seat) = self.common.seat_with_device(&event.device()).cloned() {
|
if let Some(seat) = self.common.shell.seats.for_device(&event.device()).cloned() {
|
||||||
let Some(output) =
|
let Some(output) =
|
||||||
mapped_output_for_device(&self.common, &event.device()).cloned()
|
mapped_output_for_device(&self.common, &event.device()).cloned()
|
||||||
else {
|
else {
|
||||||
|
|
@ -1530,7 +1402,7 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::TabletToolTip { event, .. } => {
|
InputEvent::TabletToolTip { event, .. } => {
|
||||||
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
if let Some(seat) = self.common.shell.seats.for_device(&event.device()) {
|
||||||
if let Some(tool) = seat.tablet_seat().get_tool(&event.tool()) {
|
if let Some(tool) = seat.tablet_seat().get_tool(&event.tool()) {
|
||||||
match event.tip_state() {
|
match event.tip_state() {
|
||||||
TabletToolTipState::Down => {
|
TabletToolTipState::Down => {
|
||||||
|
|
@ -1544,7 +1416,7 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputEvent::TabletToolButton { event, .. } => {
|
InputEvent::TabletToolButton { event, .. } => {
|
||||||
if let Some(seat) = self.common.seat_with_device(&event.device()) {
|
if let Some(seat) = self.common.shell.seats.for_device(&event.device()) {
|
||||||
if let Some(tool) = seat.tablet_seat().get_tool(&event.tool()) {
|
if let Some(tool) = seat.tablet_seat().get_tool(&event.tool()) {
|
||||||
tool.button(
|
tool.button(
|
||||||
event.button(),
|
event.button(),
|
||||||
|
|
@ -1688,14 +1560,15 @@ impl State {
|
||||||
Action::MoveToWorkspace(x) | Action::SendToWorkspace(x) => x - 1,
|
Action::MoveToWorkspace(x) | Action::SendToWorkspace(x) => x - 1,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
let _ = Shell::move_current_window(
|
if let Ok(Some((target, _point))) = self.common.shell.move_current_window(
|
||||||
self,
|
|
||||||
seat,
|
seat,
|
||||||
¤t_output,
|
¤t_output,
|
||||||
(¤t_output, Some(workspace as usize)),
|
(¤t_output, Some(workspace as usize)),
|
||||||
follow,
|
follow,
|
||||||
None,
|
None,
|
||||||
);
|
) {
|
||||||
|
Shell::set_focus(self, Some(&target), seat, None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
x @ Action::MoveToLastWorkspace | x @ Action::SendToLastWorkspace => {
|
x @ Action::MoveToLastWorkspace | x @ Action::SendToLastWorkspace => {
|
||||||
let current_output = seat.active_output();
|
let current_output = seat.active_output();
|
||||||
|
|
@ -1705,14 +1578,15 @@ impl State {
|
||||||
.workspaces
|
.workspaces
|
||||||
.len(¤t_output)
|
.len(¤t_output)
|
||||||
.saturating_sub(1);
|
.saturating_sub(1);
|
||||||
let _ = Shell::move_current_window(
|
if let Ok(Some((target, _point))) = self.common.shell.move_current_window(
|
||||||
self,
|
|
||||||
seat,
|
seat,
|
||||||
¤t_output,
|
¤t_output,
|
||||||
(¤t_output, Some(workspace as usize)),
|
(¤t_output, Some(workspace as usize)),
|
||||||
matches!(x, Action::MoveToLastWorkspace),
|
matches!(x, Action::MoveToLastWorkspace),
|
||||||
None,
|
None,
|
||||||
);
|
) {
|
||||||
|
Shell::set_focus(self, Some(&target), seat, None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
x @ Action::MoveToNextWorkspace | x @ Action::SendToNextWorkspace => {
|
x @ Action::MoveToNextWorkspace | x @ Action::SendToNextWorkspace => {
|
||||||
let current_output = seat.active_output();
|
let current_output = seat.active_output();
|
||||||
|
|
@ -1723,32 +1597,34 @@ impl State {
|
||||||
.active_num(¤t_output)
|
.active_num(¤t_output)
|
||||||
.1
|
.1
|
||||||
.saturating_add(1);
|
.saturating_add(1);
|
||||||
if Shell::move_current_window(
|
match self.common.shell.move_current_window(
|
||||||
self,
|
|
||||||
seat,
|
seat,
|
||||||
¤t_output,
|
¤t_output,
|
||||||
(¤t_output, Some(workspace as usize)),
|
(¤t_output, Some(workspace as usize)),
|
||||||
matches!(x, Action::MoveToNextWorkspace),
|
matches!(x, Action::MoveToNextWorkspace),
|
||||||
direction,
|
direction,
|
||||||
)
|
) {
|
||||||
.is_err()
|
Ok(Some((target, _point))) => {
|
||||||
&& propagate
|
Shell::set_focus(self, Some(&target), seat, None);
|
||||||
{
|
|
||||||
if let Some(inferred) = pattern.inferred_direction() {
|
|
||||||
self.handle_action(
|
|
||||||
if matches!(x, Action::MoveToNextWorkspace) {
|
|
||||||
Action::MoveToOutput(inferred)
|
|
||||||
} else {
|
|
||||||
Action::SendToOutput(inferred)
|
|
||||||
},
|
|
||||||
seat,
|
|
||||||
serial,
|
|
||||||
time,
|
|
||||||
pattern,
|
|
||||||
direction,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
Err(_) if propagate => {
|
||||||
|
if let Some(inferred) = pattern.inferred_direction() {
|
||||||
|
self.handle_action(
|
||||||
|
if matches!(x, Action::MoveToNextWorkspace) {
|
||||||
|
Action::MoveToOutput(inferred)
|
||||||
|
} else {
|
||||||
|
Action::SendToOutput(inferred)
|
||||||
|
},
|
||||||
|
seat,
|
||||||
|
serial,
|
||||||
|
time,
|
||||||
|
pattern,
|
||||||
|
direction,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
x @ Action::MoveToPreviousWorkspace | x @ Action::SendToPreviousWorkspace => {
|
x @ Action::MoveToPreviousWorkspace | x @ Action::SendToPreviousWorkspace => {
|
||||||
|
|
@ -1761,32 +1637,34 @@ impl State {
|
||||||
.1
|
.1
|
||||||
.saturating_sub(1);
|
.saturating_sub(1);
|
||||||
// TODO: Possibly move to prev output, if idx < 0
|
// TODO: Possibly move to prev output, if idx < 0
|
||||||
if Shell::move_current_window(
|
match self.common.shell.move_current_window(
|
||||||
self,
|
|
||||||
seat,
|
seat,
|
||||||
¤t_output,
|
¤t_output,
|
||||||
(¤t_output, Some(workspace as usize)),
|
(¤t_output, Some(workspace as usize)),
|
||||||
matches!(x, Action::MoveToPreviousWorkspace),
|
matches!(x, Action::MoveToPreviousWorkspace),
|
||||||
direction,
|
direction,
|
||||||
)
|
) {
|
||||||
.is_err()
|
Ok(Some((target, _point))) => {
|
||||||
&& propagate
|
Shell::set_focus(self, Some(&target), seat, None);
|
||||||
{
|
|
||||||
if let Some(inferred) = pattern.inferred_direction() {
|
|
||||||
self.handle_action(
|
|
||||||
if matches!(x, Action::MoveToPreviousWorkspace) {
|
|
||||||
Action::MoveToOutput(inferred)
|
|
||||||
} else {
|
|
||||||
Action::SendToOutput(inferred)
|
|
||||||
},
|
|
||||||
seat,
|
|
||||||
serial,
|
|
||||||
time,
|
|
||||||
pattern,
|
|
||||||
direction,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
Err(_) if propagate => {
|
||||||
|
if let Some(inferred) = pattern.inferred_direction() {
|
||||||
|
self.handle_action(
|
||||||
|
if matches!(x, Action::MoveToPreviousWorkspace) {
|
||||||
|
Action::MoveToOutput(inferred)
|
||||||
|
} else {
|
||||||
|
Action::SendToOutput(inferred)
|
||||||
|
},
|
||||||
|
seat,
|
||||||
|
serial,
|
||||||
|
time,
|
||||||
|
pattern,
|
||||||
|
direction,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action::SwitchOutput(direction) => {
|
Action::SwitchOutput(direction) => {
|
||||||
|
|
@ -1949,14 +1827,14 @@ impl State {
|
||||||
.cloned();
|
.cloned();
|
||||||
|
|
||||||
if let Some(next_output) = next_output {
|
if let Some(next_output) = next_output {
|
||||||
if let Ok(Some(new_pos)) = Shell::move_current_window(
|
if let Ok(Some((target, new_pos))) = self.common.shell.move_current_window(
|
||||||
self,
|
|
||||||
seat,
|
seat,
|
||||||
¤t_output,
|
¤t_output,
|
||||||
(&next_output, None),
|
(&next_output, None),
|
||||||
is_move_action,
|
is_move_action,
|
||||||
Some(direction),
|
Some(direction),
|
||||||
) {
|
) {
|
||||||
|
Shell::set_focus(self, Some(&target), seat, None);
|
||||||
if let Some(ptr) = seat.get_pointer() {
|
if let Some(ptr) = seat.get_pointer() {
|
||||||
ptr.motion(
|
ptr.motion(
|
||||||
self,
|
self,
|
||||||
|
|
@ -2011,14 +1889,14 @@ impl State {
|
||||||
.next()
|
.next()
|
||||||
.cloned();
|
.cloned();
|
||||||
if let Some(next_output) = next_output {
|
if let Some(next_output) = next_output {
|
||||||
if let Ok(Some(new_pos)) = Shell::move_current_window(
|
if let Ok(Some((target, new_pos))) = self.common.shell.move_current_window(
|
||||||
self,
|
|
||||||
seat,
|
seat,
|
||||||
¤t_output,
|
¤t_output,
|
||||||
(&next_output, None),
|
(&next_output, None),
|
||||||
matches!(x, Action::MoveToNextOutput),
|
matches!(x, Action::MoveToNextOutput),
|
||||||
direction,
|
direction,
|
||||||
) {
|
) {
|
||||||
|
Shell::set_focus(self, Some(&target), seat, None);
|
||||||
if let Some(ptr) = seat.get_pointer() {
|
if let Some(ptr) = seat.get_pointer() {
|
||||||
ptr.motion(
|
ptr.motion(
|
||||||
self,
|
self,
|
||||||
|
|
@ -2046,14 +1924,14 @@ impl State {
|
||||||
.next()
|
.next()
|
||||||
.cloned();
|
.cloned();
|
||||||
if let Some(prev_output) = prev_output {
|
if let Some(prev_output) = prev_output {
|
||||||
if let Ok(Some(new_pos)) = Shell::move_current_window(
|
if let Ok(Some((target, new_pos))) = self.common.shell.move_current_window(
|
||||||
self,
|
|
||||||
seat,
|
seat,
|
||||||
¤t_output,
|
¤t_output,
|
||||||
(&prev_output, None),
|
(&prev_output, None),
|
||||||
matches!(x, Action::MoveToPreviousOutput),
|
matches!(x, Action::MoveToPreviousOutput),
|
||||||
direction,
|
direction,
|
||||||
) {
|
) {
|
||||||
|
Shell::set_focus(self, Some(&target), seat, None);
|
||||||
if let Some(ptr) = seat.get_pointer() {
|
if let Some(ptr) = seat.get_pointer() {
|
||||||
ptr.motion(
|
ptr.motion(
|
||||||
self,
|
self,
|
||||||
|
|
@ -2146,7 +2024,7 @@ impl State {
|
||||||
}
|
}
|
||||||
FocusResult::Handled => {}
|
FocusResult::Handled => {}
|
||||||
FocusResult::Some(target) => {
|
FocusResult::Some(target) => {
|
||||||
Common::set_focus(self, Some(&target), seat, None);
|
Shell::set_focus(self, Some(&target), seat, None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2162,7 +2040,7 @@ impl State {
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
MoveResult::ShiftFocus(shift) => {
|
MoveResult::ShiftFocus(shift) => {
|
||||||
Common::set_focus(self, Some(&shift), seat, None);
|
Shell::set_focus(self, Some(&shift), seat, None);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let current_output = seat.active_output();
|
let current_output = seat.active_output();
|
||||||
|
|
@ -2241,7 +2119,7 @@ impl State {
|
||||||
}
|
}
|
||||||
Action::ToggleStacking => {
|
Action::ToggleStacking => {
|
||||||
if let Some(new_focus) = self.common.shell.toggle_stacking_focused(seat) {
|
if let Some(new_focus) = self.common.shell.toggle_stacking_focused(seat) {
|
||||||
Common::set_focus(self, Some(&new_focus), seat, Some(serial));
|
Shell::set_focus(self, Some(&new_focus), seat, Some(serial));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Action::ToggleTiling => {
|
Action::ToggleTiling => {
|
||||||
|
|
@ -2251,13 +2129,9 @@ impl State {
|
||||||
) {
|
) {
|
||||||
let autotile = !self.common.config.cosmic_conf.autotile;
|
let autotile = !self.common.config.cosmic_conf.autotile;
|
||||||
self.common.config.cosmic_conf.autotile = autotile;
|
self.common.config.cosmic_conf.autotile = autotile;
|
||||||
let seats: Vec<_> = self.common.seats().cloned().collect();
|
self.common
|
||||||
let mut guard = self.common.shell.workspace_state.update();
|
.shell
|
||||||
self.common.shell.workspaces.update_autotile(
|
.update_autotile(self.common.config.cosmic_conf.autotile);
|
||||||
self.common.config.cosmic_conf.autotile,
|
|
||||||
&mut guard,
|
|
||||||
seats,
|
|
||||||
);
|
|
||||||
let config = self.common.config.cosmic_helper.clone();
|
let config = self.common.config.cosmic_helper.clone();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
if let Err(err) = config.set("autotile", autotile) {
|
if let Err(err) = config.set("autotile", autotile) {
|
||||||
|
|
@ -2277,8 +2151,7 @@ impl State {
|
||||||
workspace.toggle_floating_window_focused(seat);
|
workspace.toggle_floating_window_focused(seat);
|
||||||
}
|
}
|
||||||
Action::ToggleSticky => {
|
Action::ToggleSticky => {
|
||||||
let seats = self.common.seats().cloned().collect::<Vec<_>>();
|
self.common.shell.toggle_sticky_current(seat);
|
||||||
self.common.shell.toggle_sticky_current(seats.iter(), seat);
|
|
||||||
}
|
}
|
||||||
Action::Spawn(command) => {
|
Action::Spawn(command) => {
|
||||||
let (token, data) = self
|
let (token, data) = self
|
||||||
|
|
@ -2288,7 +2161,7 @@ impl State {
|
||||||
.create_external_token(None);
|
.create_external_token(None);
|
||||||
let (token, data) = (token.clone(), data.clone());
|
let (token, data) = (token.clone(), data.clone());
|
||||||
|
|
||||||
let seat = self.common.last_active_seat();
|
let seat = self.common.shell.seats.last_active();
|
||||||
let output = seat.active_output();
|
let output = seat.active_output();
|
||||||
let workspace = self.common.shell.active_space_mut(&output);
|
let workspace = self.common.shell.active_space_mut(&output);
|
||||||
workspace.pending_tokens.insert(token.clone());
|
workspace.pending_tokens.insert(token.clone());
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,7 @@ use std::{env, ffi::OsString, os::unix::process::CommandExt, process, sync::Arc}
|
||||||
use tracing::{error, info, warn};
|
use tracing::{error, info, warn};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
state::BackendData, utils::prelude::SeatExt,
|
shell::SeatExt, state::BackendData, wayland::handlers::compositor::client_compositor_state,
|
||||||
wayland::handlers::compositor::client_compositor_state,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod backend;
|
pub mod backend;
|
||||||
|
|
@ -181,7 +180,9 @@ fn init_wayland_display(
|
||||||
.insert_source(source, |client_stream, _, state| {
|
.insert_source(source, |client_stream, _, state| {
|
||||||
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(&state.common.last_active_seat().active_output()),
|
.target_node_for_output(
|
||||||
|
&state.common.shell.seats.last_active().active_output(),
|
||||||
|
),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ use super::{
|
||||||
floating::{ResizeState, TiledCorners},
|
floating::{ResizeState, TiledCorners},
|
||||||
tiling::NodeDesc,
|
tiling::NodeDesc,
|
||||||
},
|
},
|
||||||
Direction, ManagedLayer,
|
Direction, ManagedLayer, SeatExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
space_elements! {
|
space_elements! {
|
||||||
|
|
|
||||||
|
|
@ -416,7 +416,7 @@ impl Program for CosmicWindowInternal {
|
||||||
if let Some(mapped) =
|
if let Some(mapped) =
|
||||||
state.common.shell.element_for_surface(&surface).cloned()
|
state.common.shell.element_for_surface(&surface).cloned()
|
||||||
{
|
{
|
||||||
let seat = state.common.last_active_seat().clone();
|
let seat = state.common.shell.seats.last_active().clone();
|
||||||
state.common.shell.maximize_toggle(&mapped, &seat)
|
state.common.shell.maximize_toggle(&mapped, &seat)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ use tracing::{debug, trace};
|
||||||
|
|
||||||
use self::target::{KeyboardFocusTarget, WindowGroup};
|
use self::target::{KeyboardFocusTarget, WindowGroup};
|
||||||
|
|
||||||
use super::layout::floating::FloatingLayout;
|
use super::{layout::floating::FloatingLayout, SeatExt};
|
||||||
|
|
||||||
pub mod target;
|
pub mod target;
|
||||||
|
|
||||||
|
|
@ -99,43 +99,10 @@ impl ActiveFocus {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Shell {
|
impl Shell {
|
||||||
pub fn append_focus_stack(state: &mut State, mapped: &CosmicMapped, active_seat: &Seat<State>) {
|
|
||||||
if mapped.is_minimized() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update FocusStack and notify layouts about new focus (if any window)
|
|
||||||
let workspace = state.common.shell.space_for_mut(&mapped);
|
|
||||||
let workspace = if workspace.is_none() {
|
|
||||||
state
|
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.active_space_mut(&active_seat.active_output())
|
|
||||||
} else {
|
|
||||||
workspace.unwrap()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut focus_stack = workspace.focus_stack.get_mut(active_seat);
|
|
||||||
if Some(mapped) != focus_stack.last() {
|
|
||||||
trace!(?mapped, "Focusing window.");
|
|
||||||
focus_stack.append(&mapped);
|
|
||||||
// also remove popup grabs, if we are switching focus
|
|
||||||
if let Some(mut popup_grab) = active_seat
|
|
||||||
.user_data()
|
|
||||||
.get::<PopupGrabData>()
|
|
||||||
.and_then(|x| x.take())
|
|
||||||
{
|
|
||||||
if !popup_grab.has_ended() {
|
|
||||||
popup_grab.ungrab(PopupUngrabStrategy::All);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_focus(
|
pub fn set_focus(
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
target: Option<&KeyboardFocusTarget>,
|
target: Option<&KeyboardFocusTarget>,
|
||||||
active_seat: &Seat<State>,
|
seat: &Seat<State>,
|
||||||
serial: Option<Serial>,
|
serial: Option<Serial>,
|
||||||
) {
|
) {
|
||||||
let element = match target {
|
let element = match target {
|
||||||
|
|
@ -150,23 +117,57 @@ impl Shell {
|
||||||
if mapped.is_minimized() {
|
if mapped.is_minimized() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Self::append_focus_stack(state, &mapped, active_seat);
|
state.common.shell.append_focus_stack(&mapped, seat);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update keyboard focus
|
// update keyboard focus
|
||||||
if let Some(keyboard) = active_seat.get_keyboard() {
|
if let Some(keyboard) = seat.get_keyboard() {
|
||||||
ActiveFocus::set(active_seat, target.cloned());
|
ActiveFocus::set(seat, target.cloned());
|
||||||
keyboard.set_focus(
|
keyboard.set_focus(
|
||||||
state,
|
state,
|
||||||
target.cloned(),
|
target.cloned(),
|
||||||
serial.unwrap_or_else(|| SERIAL_COUNTER.next_serial()),
|
serial.unwrap_or_else(|| SERIAL_COUNTER.next_serial()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.common.shell.update_active();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_active<'a, 'b>(&mut self, seats: impl Iterator<Item = &'a Seat<State>>) {
|
pub fn append_focus_stack(&mut self, mapped: &CosmicMapped, seat: &Seat<State>) {
|
||||||
|
if mapped.is_minimized() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update FocusStack and notify layouts about new focus (if any window)
|
||||||
|
let workspace = self.space_for_mut(&mapped);
|
||||||
|
let workspace = if workspace.is_none() {
|
||||||
|
self.active_space_mut(&seat.active_output())
|
||||||
|
} else {
|
||||||
|
workspace.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut focus_stack = workspace.focus_stack.get_mut(seat);
|
||||||
|
if Some(mapped) != focus_stack.last() {
|
||||||
|
trace!(?mapped, "Focusing window.");
|
||||||
|
focus_stack.append(&mapped);
|
||||||
|
// also remove popup grabs, if we are switching focus
|
||||||
|
if let Some(mut popup_grab) = seat
|
||||||
|
.user_data()
|
||||||
|
.get::<PopupGrabData>()
|
||||||
|
.and_then(|x| x.take())
|
||||||
|
{
|
||||||
|
if !popup_grab.has_ended() {
|
||||||
|
popup_grab.ungrab(PopupUngrabStrategy::All);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_active<'a, 'b>(&mut self) {
|
||||||
// update activate status
|
// update activate status
|
||||||
let focused_windows = seats
|
let focused_windows = self
|
||||||
|
.seats
|
||||||
|
.iter()
|
||||||
.flat_map(|seat| {
|
.flat_map(|seat| {
|
||||||
if matches!(
|
if matches!(
|
||||||
seat.get_keyboard().unwrap().current_focus(),
|
seat.get_keyboard().unwrap().current_focus(),
|
||||||
|
|
@ -231,20 +232,16 @@ fn raise_with_children(floating_layer: &mut FloatingLayout, focused: &CosmicMapp
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Common {
|
impl Common {
|
||||||
pub fn set_focus(
|
|
||||||
state: &mut State,
|
|
||||||
target: Option<&KeyboardFocusTarget>,
|
|
||||||
active_seat: &Seat<State>,
|
|
||||||
serial: Option<Serial>,
|
|
||||||
) {
|
|
||||||
Shell::set_focus(state, target, active_seat, serial);
|
|
||||||
let seats = state.common.seats().cloned().collect::<Vec<_>>();
|
|
||||||
state.common.shell.update_active(seats.iter());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn refresh_focus(state: &mut State) {
|
pub fn refresh_focus(state: &mut State) {
|
||||||
let seats = state.common.seats().cloned().collect::<Vec<_>>();
|
for seat in state
|
||||||
for seat in seats {
|
.common
|
||||||
|
.shell
|
||||||
|
.seats
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.into_iter()
|
||||||
|
{
|
||||||
let output = seat.active_output();
|
let output = seat.active_output();
|
||||||
if !state.common.shell.outputs().any(|o| o == &output) {
|
if !state.common.shell.outputs().any(|o| o == &output) {
|
||||||
seat.set_active_output(&state.common.shell.outputs().next().unwrap());
|
seat.set_active_output(&state.common.shell.outputs().next().unwrap());
|
||||||
|
|
@ -254,7 +251,7 @@ impl Common {
|
||||||
|
|
||||||
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(state, &seat, &output, target) {
|
if focus_target_is_valid(&mut state.common.shell, &seat, &output, target) {
|
||||||
continue; // Focus is valid
|
continue; // Focus is valid
|
||||||
} else {
|
} else {
|
||||||
trace!("Wrong Window, focus fixup");
|
trace!("Wrong Window, focus fixup");
|
||||||
|
|
@ -312,7 +309,7 @@ impl Common {
|
||||||
}
|
}
|
||||||
|
|
||||||
// update keyboard focus
|
// update keyboard focus
|
||||||
let target = update_focus_target(state, &seat, &output);
|
let target = update_focus_target(&state.common.shell, &seat, &output);
|
||||||
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());
|
||||||
|
|
@ -321,25 +318,24 @@ impl Common {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let seats = state.common.seats().cloned().collect::<Vec<_>>();
|
state.common.shell.update_active()
|
||||||
state.common.shell.update_active(seats.iter())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focus_target_is_valid(
|
fn focus_target_is_valid(
|
||||||
state: &mut State,
|
shell: &mut Shell,
|
||||||
seat: &Seat<State>,
|
seat: &Seat<State>,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
target: KeyboardFocusTarget,
|
target: KeyboardFocusTarget,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// If a session lock is active, only lock surfaces can be focused
|
// If a session lock is active, only lock surfaces can be focused
|
||||||
if state.common.shell.session_lock.is_some() {
|
if shell.session_lock.is_some() {
|
||||||
return matches!(target, KeyboardFocusTarget::LockSurface(_));
|
return matches!(target, KeyboardFocusTarget::LockSurface(_));
|
||||||
}
|
}
|
||||||
|
|
||||||
// If an exclusive layer shell surface exists (on any output), only exclusive
|
// If an exclusive layer shell surface exists (on any output), only exclusive
|
||||||
// shell surfaces can have focus, on the highest layer with exclusive surfaces.
|
// shell surfaces can have focus, on the highest layer with exclusive surfaces.
|
||||||
if let Some(layer) = exclusive_layer_surface_layer(state) {
|
if let Some(layer) = exclusive_layer_surface_layer(shell) {
|
||||||
return if let KeyboardFocusTarget::LayerSurface(layer_surface) = target {
|
return if let KeyboardFocusTarget::LayerSurface(layer_surface) = target {
|
||||||
let data = layer_surface.cached_state();
|
let data = layer_surface.cached_state();
|
||||||
(data.keyboard_interactivity, data.layer) == (KeyboardInteractivity::Exclusive, layer)
|
(data.keyboard_interactivity, data.layer) == (KeyboardInteractivity::Exclusive, layer)
|
||||||
|
|
@ -350,9 +346,7 @@ fn focus_target_is_valid(
|
||||||
|
|
||||||
match target {
|
match target {
|
||||||
KeyboardFocusTarget::Element(mapped) => {
|
KeyboardFocusTarget::Element(mapped) => {
|
||||||
let is_sticky = state
|
let is_sticky = shell
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.workspaces
|
.workspaces
|
||||||
.sets
|
.sets
|
||||||
.get(output)
|
.get(output)
|
||||||
|
|
@ -361,13 +355,13 @@ fn focus_target_is_valid(
|
||||||
.mapped()
|
.mapped()
|
||||||
.any(|m| m == &mapped);
|
.any(|m| m == &mapped);
|
||||||
|
|
||||||
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);
|
||||||
let is_in_focus_stack = focus_stack.last().map(|m| m == &mapped).unwrap_or(false);
|
let is_in_focus_stack = focus_stack.last().map(|m| m == &mapped).unwrap_or(false);
|
||||||
let has_fullscreen = workspace.get_fullscreen().is_some();
|
let has_fullscreen = workspace.get_fullscreen().is_some();
|
||||||
|
|
||||||
if is_sticky && !is_in_focus_stack {
|
if is_sticky && !is_in_focus_stack {
|
||||||
Shell::append_focus_stack(state, &mapped, seat);
|
shell.append_focus_stack(&mapped, seat);
|
||||||
}
|
}
|
||||||
|
|
||||||
(is_sticky || is_in_focus_stack) && !has_fullscreen
|
(is_sticky || is_in_focus_stack) && !has_fullscreen
|
||||||
|
|
@ -375,16 +369,14 @@ fn focus_target_is_valid(
|
||||||
KeyboardFocusTarget::LayerSurface(layer) => {
|
KeyboardFocusTarget::LayerSurface(layer) => {
|
||||||
layer_map_for_output(&output).layers().any(|l| l == &layer)
|
layer_map_for_output(&output).layers().any(|l| l == &layer)
|
||||||
}
|
}
|
||||||
KeyboardFocusTarget::Group(WindowGroup { node, .. }) => state
|
KeyboardFocusTarget::Group(WindowGroup { node, .. }) => shell
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.workspaces
|
.workspaces
|
||||||
.active(&output)
|
.active(&output)
|
||||||
.1
|
.1
|
||||||
.tiling_layer
|
.tiling_layer
|
||||||
.has_node(&node),
|
.has_node(&node),
|
||||||
KeyboardFocusTarget::Fullscreen(window) => {
|
KeyboardFocusTarget::Fullscreen(window) => {
|
||||||
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);
|
||||||
|
|
||||||
focus_stack
|
focus_stack
|
||||||
|
|
@ -399,17 +391,17 @@ fn focus_target_is_valid(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_focus_target(
|
fn update_focus_target(
|
||||||
state: &State,
|
shell: &Shell,
|
||||||
seat: &Seat<State>,
|
seat: &Seat<State>,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
) -> Option<KeyboardFocusTarget> {
|
) -> Option<KeyboardFocusTarget> {
|
||||||
if let Some(session_lock) = &state.common.shell.session_lock {
|
if let Some(session_lock) = &shell.session_lock {
|
||||||
session_lock
|
session_lock
|
||||||
.surfaces
|
.surfaces
|
||||||
.get(output)
|
.get(output)
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(KeyboardFocusTarget::from)
|
.map(KeyboardFocusTarget::from)
|
||||||
} else if let Some(layer) = exclusive_layer_surface_layer(state) {
|
} else if let Some(layer) = exclusive_layer_surface_layer(shell) {
|
||||||
layer_map_for_output(output)
|
layer_map_for_output(output)
|
||||||
.layers()
|
.layers()
|
||||||
.find(|layer_surface| {
|
.find(|layer_surface| {
|
||||||
|
|
@ -419,12 +411,10 @@ fn update_focus_target(
|
||||||
})
|
})
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(KeyboardFocusTarget::from)
|
.map(KeyboardFocusTarget::from)
|
||||||
} else if let Some(surface) = state.common.shell.active_space(&output).get_fullscreen() {
|
} else if let Some(surface) = shell.active_space(&output).get_fullscreen() {
|
||||||
Some(KeyboardFocusTarget::Fullscreen(surface.clone()))
|
Some(KeyboardFocusTarget::Fullscreen(surface.clone()))
|
||||||
} else {
|
} else {
|
||||||
state
|
shell
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.active_space(&output)
|
.active_space(&output)
|
||||||
.focus_stack
|
.focus_stack
|
||||||
.get(&seat)
|
.get(&seat)
|
||||||
|
|
@ -436,9 +426,9 @@ fn update_focus_target(
|
||||||
|
|
||||||
// Get the top-most layer, if any, with at least one surface with exclusive keyboard interactivity.
|
// Get the top-most layer, if any, with at least one surface with exclusive keyboard interactivity.
|
||||||
// Only considers surface in `Top` or `Overlay` layer.
|
// Only considers surface in `Top` or `Overlay` layer.
|
||||||
fn exclusive_layer_surface_layer(state: &State) -> Option<Layer> {
|
fn exclusive_layer_surface_layer(shell: &Shell) -> Option<Layer> {
|
||||||
let mut layer = None;
|
let mut layer = None;
|
||||||
for output in state.common.shell.outputs() {
|
for output in shell.outputs() {
|
||||||
for layer_surface in layer_map_for_output(output).layers() {
|
for layer_surface in layer_map_for_output(output).layers() {
|
||||||
let data = layer_surface.cached_state();
|
let data = layer_surface.cached_state();
|
||||||
if data.keyboard_interactivity == KeyboardInteractivity::Exclusive {
|
if data.keyboard_interactivity == KeyboardInteractivity::Exclusive {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use crate::{
|
||||||
shell::{
|
shell::{
|
||||||
element::{CosmicMapped, CosmicStack, CosmicWindow},
|
element::{CosmicMapped, CosmicStack, CosmicWindow},
|
||||||
layout::tiling::ResizeForkTarget,
|
layout::tiling::ResizeForkTarget,
|
||||||
CosmicSurface,
|
CosmicSurface, SeatExt,
|
||||||
},
|
},
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
wayland::handlers::{screencopy::SessionHolder, xdg_shell::popup::get_popup_toplevel},
|
wayland::handlers::{screencopy::SessionHolder, xdg_shell::popup::get_popup_toplevel},
|
||||||
|
|
|
||||||
|
|
@ -8,21 +8,21 @@ use crate::{
|
||||||
grabs::ReleaseMode,
|
grabs::ReleaseMode,
|
||||||
CosmicSurface, Shell,
|
CosmicSurface, Shell,
|
||||||
},
|
},
|
||||||
state::{Common, State},
|
state::State,
|
||||||
utils::{prelude::SeatExt, screenshot::screenshot_window},
|
utils::{prelude::SeatExt, screenshot::screenshot_window},
|
||||||
};
|
};
|
||||||
|
|
||||||
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.last_active_seat().clone();
|
let seat = state.common.shell.seats.last_active().clone();
|
||||||
if let Some(new_focus) = state.common.shell.toggle_stacking(mapped) {
|
if let Some(new_focus) = state.common.shell.toggle_stacking(mapped) {
|
||||||
Common::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.last_active_seat().clone();
|
let seat = state.common.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) = state.common.shell.space_for(mapped) else {
|
||||||
return;
|
return;
|
||||||
|
|
@ -46,20 +46,21 @@ fn move_prev_workspace(state: &mut State, mapped: &CosmicMapped) {
|
||||||
.map(|s| s.handle)
|
.map(|s| s.handle)
|
||||||
});
|
});
|
||||||
if let Some(prev_handle) = maybe_handle {
|
if let Some(prev_handle) = maybe_handle {
|
||||||
Shell::move_window(
|
if let Some((target, _)) = state.common.shell.move_window(
|
||||||
state,
|
|
||||||
Some(&seat),
|
Some(&seat),
|
||||||
mapped,
|
mapped,
|
||||||
¤t_handle,
|
¤t_handle,
|
||||||
&prev_handle,
|
&prev_handle,
|
||||||
true,
|
true,
|
||||||
None,
|
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.last_active_seat().clone();
|
let seat = state.common.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) = state.common.shell.space_for(mapped) else {
|
||||||
return;
|
return;
|
||||||
|
|
@ -76,15 +77,16 @@ 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 {
|
||||||
Shell::move_window(
|
if let Some((target, _point)) = state.common.shell.move_window(
|
||||||
state,
|
|
||||||
Some(&seat),
|
Some(&seat),
|
||||||
mapped,
|
mapped,
|
||||||
¤t_handle,
|
¤t_handle,
|
||||||
&next_handle,
|
&next_handle,
|
||||||
true,
|
true,
|
||||||
None,
|
None,
|
||||||
);
|
) {
|
||||||
|
Shell::set_focus(state, Some(&target), &seat, None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -112,7 +114,7 @@ pub fn tab_items(
|
||||||
)
|
)
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
let seat = state.common.last_active_seat().clone();
|
let seat = state.common.shell.seats.last_active();
|
||||||
let output = seat.active_output();
|
let output = seat.active_output();
|
||||||
let workspace = state.common.shell.workspaces.active_mut(&output);
|
let workspace = state.common.shell.workspaces.active_mut(&output);
|
||||||
if is_tiled {
|
if is_tiled {
|
||||||
|
|
@ -125,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);
|
||||||
|
|
@ -204,7 +206,7 @@ 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.last_active_seat().clone();
|
let seat = state.common.shell.seats.last_active().clone();
|
||||||
state.common.shell.maximize_toggle(&mapped, &seat);
|
state.common.shell.maximize_toggle(&mapped, &seat);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
@ -215,7 +217,7 @@ 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.last_active_seat().clone();
|
let seat = state.common.shell.seats.last_active().clone();
|
||||||
if let Some(ws) = state.common.shell.space_for_mut(&tile_clone) {
|
if let Some(ws) = state.common.shell.space_for_mut(&tile_clone) {
|
||||||
ws.toggle_floating_window(&seat, &tile_clone);
|
ws.toggle_floating_window(&seat, &tile_clone);
|
||||||
}
|
}
|
||||||
|
|
@ -236,7 +238,7 @@ 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.last_active_seat().clone();
|
let seat = state.common.shell.seats.last_active().clone();
|
||||||
Shell::move_request(state, &surface, &seat, None, ReleaseMode::Click, false);
|
Shell::move_request(state, &surface, &seat, None, ReleaseMode::Click, false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -247,7 +249,7 @@ 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.last_active_seat().clone();
|
let seat = state.common.shell.seats.last_active().clone();
|
||||||
Shell::menu_resize_request(state, &resize_clone, &seat, ResizeEdge::TOP);
|
Shell::menu_resize_request(state, &resize_clone, &seat, ResizeEdge::TOP);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
@ -255,7 +257,7 @@ pub fn window_items(
|
||||||
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.last_active_seat().clone();
|
let seat = state.common.shell.seats.last_active().clone();
|
||||||
Shell::menu_resize_request(state, &resize_clone, &seat, ResizeEdge::LEFT);
|
Shell::menu_resize_request(state, &resize_clone, &seat, ResizeEdge::LEFT);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
@ -263,7 +265,7 @@ pub fn window_items(
|
||||||
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.last_active_seat().clone();
|
let seat = state.common.shell.seats.last_active().clone();
|
||||||
Shell::menu_resize_request(state, &resize_clone, &seat, ResizeEdge::RIGHT);
|
Shell::menu_resize_request(state, &resize_clone, &seat, ResizeEdge::RIGHT);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
@ -271,7 +273,7 @@ pub fn window_items(
|
||||||
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.last_active_seat().clone();
|
let seat = state.common.shell.seats.last_active().clone();
|
||||||
Shell::menu_resize_request(state, &resize_clone, &seat, ResizeEdge::BOTTOM);
|
Shell::menu_resize_request(state, &resize_clone, &seat, ResizeEdge::BOTTOM);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
@ -299,12 +301,8 @@ 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.last_active_seat().clone();
|
let seat = state.common.shell.seats.last_active().clone();
|
||||||
let seats = state.common.seats().cloned().collect::<Vec<_>>();
|
state.common.shell.toggle_sticky(&seat, &mapped);
|
||||||
state
|
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.toggle_sticky(seats.iter(), &seat, &mapped);
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.toggled(is_sticky),
|
.toggled(is_sticky),
|
||||||
|
|
|
||||||
|
|
@ -40,10 +40,11 @@ use smithay::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
shell::focus::target::PointerFocusTarget,
|
shell::focus::target::PointerFocusTarget,
|
||||||
|
shell::SeatExt,
|
||||||
state::State,
|
state::State,
|
||||||
utils::{
|
utils::{
|
||||||
iced::{IcedElement, Program},
|
iced::{IcedElement, Program},
|
||||||
prelude::{Global, OutputExt, PointGlobalExt, PointLocalExt, SeatExt, SizeExt},
|
prelude::{Global, OutputExt, PointGlobalExt, PointLocalExt, SizeExt},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -215,7 +216,7 @@ 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.last_active_seat();
|
let seat = state.common.shell.seats.last_active();
|
||||||
let grab_state = seat
|
let grab_state = seat
|
||||||
.user_data()
|
.user_data()
|
||||||
.get::<SeatMenuGrabState>()
|
.get::<SeatMenuGrabState>()
|
||||||
|
|
@ -300,7 +301,7 @@ 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.last_active_seat();
|
let seat = state.common.shell.seats.last_active();
|
||||||
let grab_state = seat
|
let grab_state = seat
|
||||||
.user_data()
|
.user_data()
|
||||||
.get::<SeatMenuGrabState>()
|
.get::<SeatMenuGrabState>()
|
||||||
|
|
|
||||||
|
|
@ -846,7 +846,7 @@ impl Drop for MoveGrab {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Common::set_focus(
|
Shell::set_focus(
|
||||||
state,
|
state,
|
||||||
Some(&KeyboardFocusTarget::from(mapped)),
|
Some(&KeyboardFocusTarget::from(mapped)),
|
||||||
&seat,
|
&seat,
|
||||||
|
|
|
||||||
359
src/shell/mod.rs
359
src/shell/mod.rs
|
|
@ -1,4 +1,5 @@
|
||||||
use calloop::LoopHandle;
|
use calloop::LoopHandle;
|
||||||
|
use cosmic::Theme;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
|
|
@ -72,8 +73,10 @@ pub mod element;
|
||||||
pub mod focus;
|
pub mod focus;
|
||||||
pub mod grabs;
|
pub mod grabs;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
|
mod seats;
|
||||||
mod workspace;
|
mod workspace;
|
||||||
pub use self::element::{CosmicMapped, CosmicMappedRenderElement, CosmicSurface};
|
pub use self::element::{CosmicMapped, CosmicMappedRenderElement, CosmicSurface};
|
||||||
|
pub use self::seats::*;
|
||||||
pub use self::workspace::*;
|
pub use self::workspace::*;
|
||||||
use self::{
|
use self::{
|
||||||
element::{
|
element::{
|
||||||
|
|
@ -199,6 +202,7 @@ pub struct Shell {
|
||||||
pub pending_activations: HashMap<ActivationKey, ActivationContext>,
|
pub pending_activations: HashMap<ActivationKey, ActivationContext>,
|
||||||
pub override_redirect_windows: Vec<X11Surface>,
|
pub override_redirect_windows: Vec<X11Surface>,
|
||||||
pub session_lock: Option<SessionLock>,
|
pub session_lock: Option<SessionLock>,
|
||||||
|
pub seats: Seats,
|
||||||
|
|
||||||
// wayland_state
|
// wayland_state
|
||||||
pub layer_shell_state: WlrLayerShellState,
|
pub layer_shell_state: WlrLayerShellState,
|
||||||
|
|
@ -650,10 +654,10 @@ impl Workspaces {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_output(
|
pub fn remove_output<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
seats: impl Iterator<Item = Seat<State>>,
|
seats: impl Iterator<Item = &'a Seat<State>>,
|
||||||
workspace_state: &mut WorkspaceUpdateGuard<'_, State>,
|
workspace_state: &mut WorkspaceUpdateGuard<'_, State>,
|
||||||
toplevel_info_state: &mut ToplevelInfoState<State, CosmicSurface>,
|
toplevel_info_state: &mut ToplevelInfoState<State, CosmicSurface>,
|
||||||
xdg_activation_state: &XdgActivationState,
|
xdg_activation_state: &XdgActivationState,
|
||||||
|
|
@ -1024,21 +1028,22 @@ impl Workspaces {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_autotile_behavior(
|
fn update_autotile_behavior<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
behavior: TileBehavior,
|
behavior: TileBehavior,
|
||||||
guard: &mut WorkspaceUpdateGuard<'_, State>,
|
guard: &mut WorkspaceUpdateGuard<'_, State>,
|
||||||
seats: Vec<Seat<State>>,
|
seats: impl Iterator<Item = &'a Seat<State>>,
|
||||||
) {
|
) {
|
||||||
self.autotile_behavior = behavior;
|
self.autotile_behavior = behavior;
|
||||||
self.apply_tile_change(guard, seats);
|
self.apply_tile_change(guard, seats);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_tile_change(
|
fn apply_tile_change<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
guard: &mut WorkspaceUpdateGuard<'_, State>,
|
guard: &mut WorkspaceUpdateGuard<'_, State>,
|
||||||
seats: Vec<Seat<State>>,
|
seats: impl Iterator<Item = &'a Seat<State>>,
|
||||||
) {
|
) {
|
||||||
|
let seats = seats.cloned().collect::<Vec<_>>();
|
||||||
for (_, set) in &mut self.sets {
|
for (_, set) in &mut self.sets {
|
||||||
set.tiling_enabled = self.autotile;
|
set.tiling_enabled = self.autotile;
|
||||||
|
|
||||||
|
|
@ -1056,11 +1061,11 @@ impl Workspaces {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_autotile(
|
fn update_autotile<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
autotile: bool,
|
autotile: bool,
|
||||||
guard: &mut WorkspaceUpdateGuard<'_, State>,
|
guard: &mut WorkspaceUpdateGuard<'_, State>,
|
||||||
seats: Vec<Seat<State>>,
|
seats: impl Iterator<Item = &'a Seat<State>>,
|
||||||
) {
|
) {
|
||||||
self.autotile = autotile;
|
self.autotile = autotile;
|
||||||
self.apply_tile_change(guard, seats);
|
self.apply_tile_change(guard, seats);
|
||||||
|
|
@ -1105,6 +1110,7 @@ impl Shell {
|
||||||
Shell {
|
Shell {
|
||||||
popups: PopupManager::default(),
|
popups: PopupManager::default(),
|
||||||
workspaces: Workspaces::new(config, theme.clone()),
|
workspaces: Workspaces::new(config, theme.clone()),
|
||||||
|
seats: Seats::new(),
|
||||||
|
|
||||||
pending_windows: Vec::new(),
|
pending_windows: Vec::new(),
|
||||||
pending_layers: Vec::new(),
|
pending_layers: Vec::new(),
|
||||||
|
|
@ -1139,10 +1145,10 @@ impl Shell {
|
||||||
self.refresh(); // fixes indicies of any moved workspaces
|
self.refresh(); // fixes indicies of any moved workspaces
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_output(&mut self, output: &Output, seats: impl Iterator<Item = Seat<State>>) {
|
pub fn remove_output(&mut self, output: &Output) {
|
||||||
self.workspaces.remove_output(
|
self.workspaces.remove_output(
|
||||||
output,
|
output,
|
||||||
seats,
|
self.seats.iter(),
|
||||||
&mut self.workspace_state.update(),
|
&mut self.workspace_state.update(),
|
||||||
&mut self.toplevel_info_state,
|
&mut self.toplevel_info_state,
|
||||||
&self.xdg_activation_state,
|
&self.xdg_activation_state,
|
||||||
|
|
@ -1601,11 +1607,10 @@ impl Shell {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn overview_mode(&mut self) -> (OverviewMode, Option<SwapIndicator>) {
|
pub fn overview_mode(&self) -> (OverviewMode, Option<SwapIndicator>) {
|
||||||
if let OverviewMode::Ended(_, timestamp) = self.overview_mode {
|
if let OverviewMode::Ended(_, timestamp) = self.overview_mode {
|
||||||
if Instant::now().duration_since(timestamp) > ANIMATION_DURATION {
|
if Instant::now().duration_since(timestamp) > ANIMATION_DURATION {
|
||||||
self.overview_mode = OverviewMode::None;
|
return (OverviewMode::None, None);
|
||||||
self.swap_indicator = None;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1641,11 +1646,10 @@ impl Shell {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resize_mode(&mut self) -> (ResizeMode, Option<ResizeIndicator>) {
|
pub fn resize_mode(&self) -> (ResizeMode, Option<ResizeIndicator>) {
|
||||||
if let ResizeMode::Ended(timestamp, _) = self.resize_mode {
|
if let ResizeMode::Ended(timestamp, _) = self.resize_mode {
|
||||||
if Instant::now().duration_since(timestamp) > ANIMATION_DURATION {
|
if Instant::now().duration_since(timestamp) > ANIMATION_DURATION {
|
||||||
self.resize_mode = ResizeMode::None;
|
return (ResizeMode::None, None);
|
||||||
self.resize_indicator = None;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1673,6 +1677,19 @@ impl Shell {
|
||||||
|
|
||||||
#[profiling::function]
|
#[profiling::function]
|
||||||
pub fn refresh(&mut self) {
|
pub fn refresh(&mut self) {
|
||||||
|
if let OverviewMode::Ended(_, timestamp) = self.overview_mode {
|
||||||
|
if Instant::now().duration_since(timestamp) > ANIMATION_DURATION {
|
||||||
|
self.overview_mode = OverviewMode::None;
|
||||||
|
self.swap_indicator = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let ResizeMode::Ended(timestamp, _) = self.resize_mode {
|
||||||
|
if Instant::now().duration_since(timestamp) > ANIMATION_DURATION {
|
||||||
|
self.resize_mode = ResizeMode::None;
|
||||||
|
self.resize_indicator = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.popups.cleanup();
|
self.popups.cleanup();
|
||||||
|
|
||||||
self.xdg_activation_state.retain_tokens(|_, data| {
|
self.xdg_activation_state.retain_tokens(|_, data| {
|
||||||
|
|
@ -1764,23 +1781,24 @@ impl Shell {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_window(state: &mut State, window: &CosmicSurface) {
|
#[must_use]
|
||||||
let pos = state
|
pub fn map_window(
|
||||||
.common
|
&mut self,
|
||||||
.shell
|
window: &CosmicSurface,
|
||||||
|
evlh: &LoopHandle<'static, State>,
|
||||||
|
theme: &Theme,
|
||||||
|
) -> Option<KeyboardFocusTarget> {
|
||||||
|
let pos = self
|
||||||
.pending_windows
|
.pending_windows
|
||||||
.iter()
|
.iter()
|
||||||
.position(|(w, _, _)| w == window)
|
.position(|(w, _, _)| w == window)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let (window, seat, output) = state.common.shell.pending_windows.remove(pos);
|
let (window, seat, output) = self.pending_windows.remove(pos);
|
||||||
|
|
||||||
let parent_is_sticky = if let Some(toplevel) = window.0.toplevel() {
|
let parent_is_sticky = if let Some(toplevel) = window.0.toplevel() {
|
||||||
if let Some(parent) = toplevel.parent() {
|
if let Some(parent) = toplevel.parent() {
|
||||||
if let Some(elem) = state.common.shell.element_for_surface(&parent) {
|
if let Some(elem) = self.element_for_surface(&parent) {
|
||||||
state
|
self.workspaces
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.workspaces
|
|
||||||
.sets
|
.sets
|
||||||
.values()
|
.values()
|
||||||
.any(|set| set.sticky_layer.mapped().any(|m| m == elem))
|
.any(|set| set.sticky_layer.mapped().any(|m| m == elem))
|
||||||
|
|
@ -1794,11 +1812,7 @@ impl Shell {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
let pending_activation = state
|
let pending_activation = self.pending_activations.remove(&(&window).into());
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.pending_activations
|
|
||||||
.remove(&(&window).into());
|
|
||||||
let workspace_handle = match pending_activation {
|
let workspace_handle = match pending_activation {
|
||||||
Some(ActivationContext::Workspace(handle)) => Some(handle),
|
Some(ActivationContext::Workspace(handle)) => Some(handle),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
|
@ -1809,22 +1823,16 @@ impl Shell {
|
||||||
|
|
||||||
// this is beyond stupid, just to make the borrow checker happy
|
// this is beyond stupid, just to make the borrow checker happy
|
||||||
let workspace = if let Some(handle) = workspace_handle.filter(|handle| {
|
let workspace = if let Some(handle) = workspace_handle.filter(|handle| {
|
||||||
state
|
self.workspaces
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.workspaces
|
|
||||||
.spaces()
|
.spaces()
|
||||||
.any(|space| &space.handle == handle)
|
.any(|space| &space.handle == handle)
|
||||||
}) {
|
}) {
|
||||||
state
|
self.workspaces
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.workspaces
|
|
||||||
.spaces_mut()
|
.spaces_mut()
|
||||||
.find(|space| space.handle == handle)
|
.find(|space| space.handle == handle)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
} else {
|
} else {
|
||||||
state.common.shell.workspaces.active_mut(&output)
|
self.workspaces.active_mut(&output)
|
||||||
};
|
};
|
||||||
if output != workspace.output {
|
if output != workspace.output {
|
||||||
output = workspace.output.clone();
|
output = workspace.output.clone();
|
||||||
|
|
@ -1832,57 +1840,34 @@ impl Shell {
|
||||||
|
|
||||||
if let Some((mapped, layer, previous_workspace)) = workspace.remove_fullscreen() {
|
if let Some((mapped, layer, previous_workspace)) = workspace.remove_fullscreen() {
|
||||||
let old_handle = workspace.handle.clone();
|
let old_handle = workspace.handle.clone();
|
||||||
let new_workspace_handle = state
|
let new_workspace_handle = self
|
||||||
.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);
|
.unwrap_or(old_handle);
|
||||||
|
|
||||||
state.common.shell.remap_unfullscreened_window(
|
self.remap_unfullscreened_window(mapped, &old_handle, &new_workspace_handle, layer);
|
||||||
mapped,
|
|
||||||
&old_handle,
|
|
||||||
&new_workspace_handle,
|
|
||||||
layer,
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let active_handle = state.common.shell.workspaces.active(&output).1.handle;
|
let active_handle = self.active_space(&output).handle;
|
||||||
let workspace = if let Some(handle) = workspace_handle.filter(|handle| {
|
let workspace = if let Some(handle) = workspace_handle.filter(|handle| {
|
||||||
state
|
self.workspaces
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.workspaces
|
|
||||||
.spaces()
|
.spaces()
|
||||||
.any(|space| &space.handle == handle)
|
.any(|space| &space.handle == handle)
|
||||||
}) {
|
}) {
|
||||||
state
|
self.workspaces
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.workspaces
|
|
||||||
.spaces_mut()
|
.spaces_mut()
|
||||||
.find(|space| space.handle == handle)
|
.find(|space| space.handle == handle)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
} else {
|
} else {
|
||||||
state.common.shell.workspaces.active_mut(&output)
|
self.workspaces.active_mut(&output)
|
||||||
};
|
};
|
||||||
|
|
||||||
state
|
self.toplevel_info_state.new_toplevel(&window, &self.workspace_state);
|
||||||
.common
|
self.toplevel_info_state
|
||||||
.shell
|
|
||||||
.toplevel_info_state
|
|
||||||
.new_toplevel(&window, &state.common.shell.workspace_state);
|
|
||||||
state
|
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.toplevel_info_state
|
|
||||||
.toplevel_enter_output(&window, &output);
|
.toplevel_enter_output(&window, &output);
|
||||||
state
|
self.toplevel_info_state
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.toplevel_info_state
|
|
||||||
.toplevel_enter_workspace(&window, &workspace.handle);
|
.toplevel_enter_workspace(&window, &workspace.handle);
|
||||||
|
|
||||||
let workspace_output = workspace.output.clone();
|
let workspace_output = workspace.output.clone();
|
||||||
|
|
@ -1899,16 +1884,16 @@ impl Shell {
|
||||||
{
|
{
|
||||||
focused.stack_ref().unwrap().add_window(window, None);
|
focused.stack_ref().unwrap().add_window(window, None);
|
||||||
if was_activated {
|
if was_activated {
|
||||||
state.common.shell.set_urgent(&workspace_handle);
|
self.set_urgent(&workspace_handle);
|
||||||
}
|
}
|
||||||
return;
|
return None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mapped = CosmicMapped::from(CosmicWindow::new(
|
let mapped = CosmicMapped::from(CosmicWindow::new(
|
||||||
window.clone(),
|
window.clone(),
|
||||||
state.common.event_loop_handle.clone(),
|
evlh.clone(),
|
||||||
state.common.theme.clone(),
|
theme.clone(),
|
||||||
));
|
));
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
{
|
{
|
||||||
|
|
@ -1935,9 +1920,7 @@ impl Shell {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !parent_is_sticky && should_be_fullscreen {
|
if !parent_is_sticky && should_be_fullscreen {
|
||||||
let from = state
|
let from = self
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.toplevel_management_state
|
.toplevel_management_state
|
||||||
.minimize_rectangle(&output, &mapped.active_window());
|
.minimize_rectangle(&output, &mapped.active_window());
|
||||||
|
|
||||||
|
|
@ -1945,37 +1928,34 @@ impl Shell {
|
||||||
}
|
}
|
||||||
|
|
||||||
if parent_is_sticky {
|
if parent_is_sticky {
|
||||||
let seats = state.common.seats().cloned().collect::<Vec<_>>();
|
self.toggle_sticky(&seat, &mapped);
|
||||||
state
|
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.toggle_sticky(seats.iter(), &seat, &mapped);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (workspace_output == seat.active_output() && active_handle == workspace_handle)
|
let new_target = if (workspace_output == seat.active_output()
|
||||||
|
&& active_handle == workspace_handle)
|
||||||
|| parent_is_sticky
|
|| parent_is_sticky
|
||||||
{
|
{
|
||||||
// TODO: enforce focus stealing prevention by also checking the same rules as for the else case.
|
// TODO: enforce focus stealing prevention by also checking the same rules as for the else case.
|
||||||
Shell::set_focus(
|
Some(KeyboardFocusTarget::from(mapped.clone()))
|
||||||
state,
|
} else {
|
||||||
Some(&KeyboardFocusTarget::from(mapped.clone())),
|
if workspace_empty || was_activated || should_be_fullscreen {
|
||||||
&seat,
|
self.append_focus_stack(&mapped, &seat);
|
||||||
None,
|
self.set_urgent(&workspace_handle);
|
||||||
);
|
}
|
||||||
} else if workspace_empty || was_activated || should_be_fullscreen {
|
None
|
||||||
Shell::append_focus_stack(state, &mapped, &seat);
|
};
|
||||||
state.common.shell.set_urgent(&workspace_handle);
|
|
||||||
|
let active_space = self.active_space(&output);
|
||||||
|
for mapped in active_space.mapped() {
|
||||||
|
self.update_reactive_popups(mapped);
|
||||||
}
|
}
|
||||||
|
|
||||||
let active_space = state.common.shell.active_space(&output);
|
new_target
|
||||||
for mapped in active_space.mapped() {
|
|
||||||
state.common.shell.update_reactive_popups(mapped);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_override_redirect(state: &mut State, window: X11Surface) {
|
pub fn map_override_redirect(&mut self, window: X11Surface) {
|
||||||
let geo = window.geometry();
|
let geo = window.geometry();
|
||||||
for (output, overlap) in state.common.shell.outputs().cloned().filter_map(|o| {
|
for (output, overlap) in self.outputs().cloned().filter_map(|o| {
|
||||||
o.geometry()
|
o.geometry()
|
||||||
.as_logical()
|
.as_logical()
|
||||||
.intersection(geo)
|
.intersection(geo)
|
||||||
|
|
@ -1984,18 +1964,17 @@ impl Shell {
|
||||||
window.output_enter(&output, overlap);
|
window.output_enter(&output, overlap);
|
||||||
}
|
}
|
||||||
|
|
||||||
state.common.shell.override_redirect_windows.push(window);
|
self.override_redirect_windows.push(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_layer(state: &mut State, layer_surface: &LayerSurface) {
|
#[must_use]
|
||||||
let pos = state
|
pub fn map_layer(&mut self, layer_surface: &LayerSurface) -> Option<KeyboardFocusTarget> {
|
||||||
.common
|
let pos = self
|
||||||
.shell
|
|
||||||
.pending_layers
|
.pending_layers
|
||||||
.iter()
|
.iter()
|
||||||
.position(|(l, _, _)| l == layer_surface)
|
.position(|(l, _, _)| l == layer_surface)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let (layer_surface, output, seat) = state.common.shell.pending_layers.remove(pos);
|
let (layer_surface, output, _seat) = self.pending_layers.remove(pos);
|
||||||
|
|
||||||
let wants_focus = {
|
let wants_focus = {
|
||||||
with_states(layer_surface.wl_surface(), |states| {
|
with_states(layer_surface.wl_surface(), |states| {
|
||||||
|
|
@ -2009,13 +1988,11 @@ impl Shell {
|
||||||
let mut map = layer_map_for_output(&output);
|
let mut map = layer_map_for_output(&output);
|
||||||
map.map_layer(&layer_surface).unwrap();
|
map.map_layer(&layer_surface).unwrap();
|
||||||
}
|
}
|
||||||
for workspace in state.common.shell.workspaces.spaces_mut() {
|
for workspace in self.workspaces.spaces_mut() {
|
||||||
workspace.tiling_layer.recalculate();
|
workspace.tiling_layer.recalculate();
|
||||||
}
|
}
|
||||||
|
|
||||||
if wants_focus {
|
wants_focus.then(|| layer_surface.into())
|
||||||
Shell::set_focus(state, Some(&layer_surface.into()), &seat, None)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unmap_surface<S>(&mut self, surface: &S, seat: &Seat<State>)
|
pub fn unmap_surface<S>(&mut self, surface: &S, seat: &Seat<State>)
|
||||||
|
|
@ -2101,83 +2078,50 @@ impl Shell {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn move_window(
|
pub fn move_window(
|
||||||
state: &mut State,
|
&mut self,
|
||||||
seat: Option<&Seat<State>>,
|
seat: Option<&Seat<State>>,
|
||||||
mapped: &CosmicMapped,
|
mapped: &CosmicMapped,
|
||||||
from: &WorkspaceHandle,
|
from: &WorkspaceHandle,
|
||||||
to: &WorkspaceHandle,
|
to: &WorkspaceHandle,
|
||||||
follow: bool,
|
follow: bool,
|
||||||
direction: Option<Direction>,
|
direction: Option<Direction>,
|
||||||
) -> Option<Point<i32, Global>> {
|
) -> Option<(KeyboardFocusTarget, Point<i32, Global>)> {
|
||||||
let from_output = state
|
let from_output = self.workspaces.space_for_handle(from)?.output.clone();
|
||||||
.common
|
let to_output = self.workspaces.space_for_handle(to)?.output.clone();
|
||||||
.shell
|
|
||||||
.workspaces
|
|
||||||
.space_for_handle(from)?
|
|
||||||
.output
|
|
||||||
.clone();
|
|
||||||
let to_output = state
|
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.workspaces
|
|
||||||
.space_for_handle(to)?
|
|
||||||
.output
|
|
||||||
.clone();
|
|
||||||
|
|
||||||
let from_workspace = state
|
let from_workspace = self.workspaces.space_for_handle_mut(from).unwrap(); // checked above
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.workspaces
|
|
||||||
.space_for_handle_mut(from)
|
|
||||||
.unwrap(); // checked above
|
|
||||||
let window_state = from_workspace.unmap(mapped)?;
|
let window_state = from_workspace.unmap(mapped)?;
|
||||||
let elements = from_workspace.mapped().cloned().collect::<Vec<_>>();
|
let elements = from_workspace.mapped().cloned().collect::<Vec<_>>();
|
||||||
|
|
||||||
for (toplevel, _) in mapped.windows() {
|
for (toplevel, _) in mapped.windows() {
|
||||||
state
|
self.toplevel_info_state
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.toplevel_info_state
|
|
||||||
.toplevel_leave_workspace(&toplevel, from);
|
.toplevel_leave_workspace(&toplevel, from);
|
||||||
if from_output != to_output {
|
if from_output != to_output {
|
||||||
state
|
self.toplevel_info_state
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.toplevel_info_state
|
|
||||||
.toplevel_leave_output(&toplevel, &from_output);
|
.toplevel_leave_output(&toplevel, &from_output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for mapped in elements.into_iter() {
|
for mapped in elements.into_iter() {
|
||||||
state.common.shell.update_reactive_popups(&mapped);
|
self.update_reactive_popups(&mapped);
|
||||||
}
|
}
|
||||||
let new_pos = if follow {
|
let new_pos = if follow {
|
||||||
if let Some(seat) = seat {
|
if let Some(seat) = seat {
|
||||||
seat.set_active_output(&to_output);
|
seat.set_active_output(&to_output);
|
||||||
}
|
}
|
||||||
state
|
self.workspaces
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.workspaces
|
|
||||||
.idx_for_handle(&to_output, to)
|
.idx_for_handle(&to_output, to)
|
||||||
.and_then(|to_idx| {
|
.and_then(|to_idx| {
|
||||||
state
|
self.activate(&to_output, to_idx, WorkspaceDelta::new_shortcut())
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.activate(&to_output, to_idx, WorkspaceDelta::new_shortcut())
|
|
||||||
.unwrap()
|
.unwrap()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let any_seat = seat.unwrap_or(state.common.last_active_seat()).clone();
|
let any_seat = seat.unwrap_or(self.seats.last_active()).clone();
|
||||||
let mut to_workspace = state
|
let mut to_workspace = self.workspaces.space_for_handle_mut(to).unwrap(); // checked above
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.workspaces
|
|
||||||
.space_for_handle_mut(to)
|
|
||||||
.unwrap(); // checked above
|
|
||||||
let focus_stack = seat.map(|seat| to_workspace.focus_stack.get(&seat));
|
let focus_stack = seat.map(|seat| to_workspace.focus_stack.get(&seat));
|
||||||
if window_state.layer == ManagedLayer::Floating || !to_workspace.tiling_enabled {
|
if window_state.layer == ManagedLayer::Floating || !to_workspace.tiling_enabled {
|
||||||
to_workspace.floating_layer.map(mapped.clone(), None);
|
to_workspace.floating_layer.map(mapped.clone(), None);
|
||||||
|
|
@ -2194,34 +2138,25 @@ impl Shell {
|
||||||
if let Some((mapped, layer, previous_workspace)) = to_workspace.remove_fullscreen()
|
if let Some((mapped, layer, previous_workspace)) = to_workspace.remove_fullscreen()
|
||||||
{
|
{
|
||||||
let old_handle = to.clone();
|
let old_handle = to.clone();
|
||||||
let new_workspace_handle = state
|
let new_workspace_handle = self
|
||||||
.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);
|
.unwrap_or(old_handle);
|
||||||
|
|
||||||
state.common.shell.remap_unfullscreened_window(
|
self.remap_unfullscreened_window(
|
||||||
mapped,
|
mapped,
|
||||||
&old_handle,
|
&old_handle,
|
||||||
&new_workspace_handle,
|
&new_workspace_handle,
|
||||||
layer,
|
layer,
|
||||||
);
|
);
|
||||||
to_workspace = state
|
to_workspace = self.workspaces.space_for_handle_mut(to).unwrap();
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.workspaces
|
|
||||||
.space_for_handle_mut(to)
|
|
||||||
.unwrap();
|
|
||||||
// checked above
|
// checked above
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let from = state
|
let from = self
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.toplevel_management_state
|
.toplevel_management_state
|
||||||
.minimize_rectangle(&to_output, &mapped.active_window());
|
.minimize_rectangle(&to_output, &mapped.active_window());
|
||||||
|
|
||||||
|
|
@ -2241,58 +2176,43 @@ impl Shell {
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
{
|
{
|
||||||
state.common.shell.update_reactive_popups(&mapped);
|
self.update_reactive_popups(&mapped);
|
||||||
}
|
}
|
||||||
for (toplevel, _) in mapped.windows() {
|
for (toplevel, _) in mapped.windows() {
|
||||||
if from_output != to_output {
|
if from_output != to_output {
|
||||||
state
|
self.toplevel_info_state
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.toplevel_info_state
|
|
||||||
.toplevel_enter_output(&toplevel, &to_output);
|
.toplevel_enter_output(&toplevel, &to_output);
|
||||||
}
|
}
|
||||||
state
|
self.toplevel_info_state
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.toplevel_info_state
|
|
||||||
.toplevel_enter_workspace(&toplevel, to);
|
.toplevel_enter_workspace(&toplevel, to);
|
||||||
}
|
}
|
||||||
|
|
||||||
if follow {
|
new_pos.map(|pos| (focus_target, pos))
|
||||||
if let Some(seat) = seat {
|
|
||||||
Common::set_focus(state, Some(&focus_target), &seat, None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
new_pos
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn move_current_window(
|
pub fn move_current_window(
|
||||||
state: &mut State,
|
&mut self,
|
||||||
seat: &Seat<State>,
|
seat: &Seat<State>,
|
||||||
from_output: &Output,
|
from_output: &Output,
|
||||||
to: (&Output, Option<usize>),
|
to: (&Output, Option<usize>),
|
||||||
follow: bool,
|
follow: bool,
|
||||||
direction: Option<Direction>,
|
direction: Option<Direction>,
|
||||||
) -> Result<Option<Point<i32, Global>>, InvalidWorkspaceIndex> {
|
) -> Result<Option<(KeyboardFocusTarget, Point<i32, Global>)>, InvalidWorkspaceIndex> {
|
||||||
let (to_output, to_idx) = to;
|
let (to_output, to_idx) = to;
|
||||||
let to_idx = to_idx.unwrap_or(state.common.shell.workspaces.active_num(to_output).1);
|
let to_idx = to_idx.unwrap_or(self.workspaces.active_num(to_output).1);
|
||||||
|
|
||||||
if from_output == to_output
|
if from_output == to_output && to_idx == self.workspaces.active_num(from_output).1 {
|
||||||
&& to_idx == state.common.shell.workspaces.active_num(from_output).1
|
|
||||||
{
|
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let to = state
|
let to = self
|
||||||
.common
|
|
||||||
.shell
|
|
||||||
.workspaces
|
.workspaces
|
||||||
.get(to_idx, to_output)
|
.get(to_idx, to_output)
|
||||||
.map(|ws| ws.handle)
|
.map(|ws| ws.handle)
|
||||||
.ok_or(InvalidWorkspaceIndex)?;
|
.ok_or(InvalidWorkspaceIndex)?;
|
||||||
|
|
||||||
let from_workspace = state.common.shell.workspaces.active_mut(from_output);
|
let from_workspace = self.workspaces.active_mut(from_output);
|
||||||
let maybe_window = from_workspace.focus_stack.get(seat).last().cloned();
|
let maybe_window = from_workspace.focus_stack.get(seat).last().cloned();
|
||||||
|
|
||||||
let Some(mapped) = maybe_window else {
|
let Some(mapped) = maybe_window else {
|
||||||
|
|
@ -2301,15 +2221,7 @@ impl Shell {
|
||||||
|
|
||||||
let from = from_workspace.handle;
|
let from = from_workspace.handle;
|
||||||
|
|
||||||
Ok(Shell::move_window(
|
Ok(self.move_window(Some(seat), &mapped, &from, &to, follow, direction))
|
||||||
state,
|
|
||||||
Some(seat),
|
|
||||||
&mapped,
|
|
||||||
&from,
|
|
||||||
&to,
|
|
||||||
follow,
|
|
||||||
direction,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_reactive_popups(&self, mapped: &CosmicMapped) {
|
pub fn update_reactive_popups(&self, mapped: &CosmicMapped) {
|
||||||
|
|
@ -2467,9 +2379,8 @@ impl Shell {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let seats = state.common.seats().cloned().collect::<Vec<_>>();
|
|
||||||
for workspace in state.common.shell.workspaces.spaces_mut() {
|
for workspace in state.common.shell.workspaces.spaces_mut() {
|
||||||
for seat in seats.iter() {
|
for seat in state.common.shell.seats.iter() {
|
||||||
let mut stack = workspace.focus_stack.get_mut(seat);
|
let mut stack = workspace.focus_stack.get_mut(seat);
|
||||||
stack.remove(&old_mapped);
|
stack.remove(&old_mapped);
|
||||||
}
|
}
|
||||||
|
|
@ -2673,6 +2584,7 @@ impl Shell {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn next_focus<'a>(&mut self, direction: FocusDirection, seat: &Seat<State>) -> FocusResult {
|
pub fn next_focus<'a>(&mut self, direction: FocusDirection, seat: &Seat<State>) -> FocusResult {
|
||||||
let overview = self.overview_mode().0;
|
let overview = self.overview_mode().0;
|
||||||
let output = seat.active_output();
|
let output = seat.active_output();
|
||||||
|
|
@ -2804,6 +2716,7 @@ impl Shell {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn move_current_element<'a>(
|
pub fn move_current_element<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
direction: Direction,
|
direction: Direction,
|
||||||
|
|
@ -3270,6 +3183,7 @@ impl Shell {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn toggle_stacking(&mut self, window: &CosmicMapped) -> Option<KeyboardFocusTarget> {
|
pub fn toggle_stacking(&mut self, window: &CosmicMapped) -> Option<KeyboardFocusTarget> {
|
||||||
if let Some(set) = self
|
if let Some(set) = self
|
||||||
.workspaces
|
.workspaces
|
||||||
|
|
@ -3291,6 +3205,7 @@ impl Shell {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn toggle_stacking_focused(&mut self, seat: &Seat<State>) -> Option<KeyboardFocusTarget> {
|
pub fn toggle_stacking_focused(&mut self, seat: &Seat<State>) -> Option<KeyboardFocusTarget> {
|
||||||
let set = self.workspaces.sets.get_mut(&seat.active_output()).unwrap();
|
let set = self.workspaces.sets.get_mut(&seat.active_output()).unwrap();
|
||||||
let workspace = &mut set.workspaces[set.active];
|
let workspace = &mut set.workspaces[set.active];
|
||||||
|
|
@ -3315,16 +3230,10 @@ impl Shell {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toggle_sticky<'a>(
|
pub fn toggle_sticky<'a>(&mut self, seat: &Seat<State>, mapped: &CosmicMapped) {
|
||||||
&mut self,
|
|
||||||
seats: impl Iterator<Item = &'a Seat<State>>,
|
|
||||||
seat: &Seat<State>,
|
|
||||||
mapped: &CosmicMapped,
|
|
||||||
) {
|
|
||||||
// clean from focus-stacks
|
// clean from focus-stacks
|
||||||
let seats = seats.collect::<Vec<_>>();
|
|
||||||
for workspace in self.workspaces.spaces_mut() {
|
for workspace in self.workspaces.spaces_mut() {
|
||||||
for seat in seats.iter() {
|
for seat in self.seats.iter() {
|
||||||
let mut stack = workspace.focus_stack.get_mut(seat);
|
let mut stack = workspace.focus_stack.get_mut(seat);
|
||||||
stack.remove(mapped);
|
stack.remove(mapped);
|
||||||
}
|
}
|
||||||
|
|
@ -3393,18 +3302,16 @@ impl Shell {
|
||||||
_ => workspace.floating_layer.map(mapped.clone(), geometry.loc),
|
_ => workspace.floating_layer.map(mapped.clone(), geometry.loc),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.append_focus_stack(&mapped, seat);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toggle_sticky_current<'a>(
|
pub fn toggle_sticky_current<'a>(&mut self, seat: &Seat<State>) {
|
||||||
&mut self,
|
|
||||||
seats: impl Iterator<Item = &'a Seat<State>>,
|
|
||||||
seat: &Seat<State>,
|
|
||||||
) {
|
|
||||||
let set = self.workspaces.sets.get_mut(&seat.active_output()).unwrap();
|
let set = self.workspaces.sets.get_mut(&seat.active_output()).unwrap();
|
||||||
let workspace = &mut set.workspaces[set.active];
|
let workspace = &mut set.workspaces[set.active];
|
||||||
let maybe_window = workspace.focus_stack.get(seat).iter().next().cloned();
|
let maybe_window = workspace.focus_stack.get(seat).iter().next().cloned();
|
||||||
if let Some(mapped) = maybe_window {
|
if let Some(mapped) = maybe_window {
|
||||||
self.toggle_sticky(seats, seat, &mapped);
|
self.toggle_sticky(seat, &mapped);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3419,6 +3326,18 @@ impl Shell {
|
||||||
let mut workspace_guard = self.workspace_state.update();
|
let mut workspace_guard = self.workspace_state.update();
|
||||||
workspace_guard.add_workspace_state(workspace, WState::Urgent);
|
workspace_guard.add_workspace_state(workspace, WState::Urgent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_autotile(&mut self, autotile: bool) {
|
||||||
|
let mut guard = self.workspace_state.update();
|
||||||
|
self.workspaces
|
||||||
|
.update_autotile(autotile, &mut guard, self.seats.iter())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_autotile_behavior(&mut self, behavior: TileBehavior) {
|
||||||
|
let mut guard = self.workspace_state.update();
|
||||||
|
self.workspaces
|
||||||
|
.update_autotile_behavior(behavior, &mut guard, self.seats.iter())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn workspace_set_idx<'a>(
|
fn workspace_set_idx<'a>(
|
||||||
|
|
|
||||||
306
src/shell/seats.rs
Normal file
306
src/shell/seats.rs
Normal file
|
|
@ -0,0 +1,306 @@
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
use std::{any::Any, cell::RefCell, collections::HashMap, sync::Mutex, time::Duration};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
backend::render::cursor::{CursorShape, CursorState},
|
||||||
|
config::{xkb_config_to_wl, Config},
|
||||||
|
input::{ModifiersShortcutQueue, SupressedKeys},
|
||||||
|
state::State,
|
||||||
|
};
|
||||||
|
use smithay::{
|
||||||
|
backend::input::{Device, DeviceCapability},
|
||||||
|
desktop::utils::bbox_from_surface_tree,
|
||||||
|
input::{
|
||||||
|
keyboard::{LedState, XkbConfig},
|
||||||
|
pointer::{CursorIcon, CursorImageAttributes, CursorImageStatus},
|
||||||
|
Seat, SeatState,
|
||||||
|
},
|
||||||
|
output::Output,
|
||||||
|
reexports::{input::Device as InputDevice, wayland_server::DisplayHandle},
|
||||||
|
utils::{Buffer, IsAlive, Monotonic, Point, Rectangle, Time, Transform},
|
||||||
|
wayland::compositor::with_states,
|
||||||
|
};
|
||||||
|
use tracing::warn;
|
||||||
|
|
||||||
|
use super::grabs::{SeatMenuGrabState, SeatMoveGrabState};
|
||||||
|
|
||||||
|
crate::utils::id_gen!(next_seat_id, SEAT_ID, SEAT_IDS);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Seats {
|
||||||
|
seats: Vec<Seat<State>>,
|
||||||
|
last_active: Option<Seat<State>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Seats {
|
||||||
|
pub fn new() -> Seats {
|
||||||
|
Seats {
|
||||||
|
seats: Vec::new(),
|
||||||
|
last_active: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_seat(&mut self, seat: Seat<State>) {
|
||||||
|
if self.seats.is_empty() {
|
||||||
|
self.last_active = Some(seat.clone());
|
||||||
|
}
|
||||||
|
self.seats.push(seat);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_seat(&mut self, seat: &Seat<State>) {
|
||||||
|
self.seats.retain(|s| s != seat);
|
||||||
|
if self.seats.is_empty() {
|
||||||
|
self.last_active = None;
|
||||||
|
} else if self.last_active.as_ref().is_some_and(|s| s == seat) {
|
||||||
|
self.last_active = Some(self.seats[0].clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter(&self) -> impl Iterator<Item = &Seat<State>> {
|
||||||
|
self.seats.iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn last_active(&self) -> &Seat<State> {
|
||||||
|
self.last_active.as_ref().expect("No seat?")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_last_active(&mut self, seat: &Seat<State>) {
|
||||||
|
self.last_active = Some(seat.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn for_device<D: Device>(&self, device: &D) -> Option<&Seat<State>> {
|
||||||
|
self.iter().find(|seat| {
|
||||||
|
let userdata = seat.user_data();
|
||||||
|
let devices = userdata.get::<Devices>().unwrap();
|
||||||
|
devices.has_device(device)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Devices {
|
||||||
|
pub fn add_device<D: Device + 'static>(&self, device: &D) -> Vec<DeviceCapability> {
|
||||||
|
let id = device.id();
|
||||||
|
let mut map = self.capabilities.borrow_mut();
|
||||||
|
let caps = [
|
||||||
|
DeviceCapability::Keyboard,
|
||||||
|
DeviceCapability::Pointer,
|
||||||
|
DeviceCapability::TabletTool,
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.filter(|c| device.has_capability(*c))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let new_caps = caps
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.filter(|c| map.values().flatten().all(|has| *c != *has))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
map.insert(id, caps);
|
||||||
|
|
||||||
|
if device.has_capability(DeviceCapability::Keyboard) {
|
||||||
|
if let Some(device) = <dyn Any>::downcast_ref::<InputDevice>(device) {
|
||||||
|
self.keyboards.borrow_mut().push(device.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new_caps
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_device<D: Device>(&self, device: &D) -> bool {
|
||||||
|
self.capabilities.borrow().contains_key(&device.id())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_device<D: Device>(&self, device: &D) -> Vec<DeviceCapability> {
|
||||||
|
let id = device.id();
|
||||||
|
|
||||||
|
let mut keyboards = self.keyboards.borrow_mut();
|
||||||
|
if let Some(idx) = keyboards.iter().position(|x| x.id() == id) {
|
||||||
|
keyboards.remove(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut map = self.capabilities.borrow_mut();
|
||||||
|
map.remove(&id)
|
||||||
|
.unwrap_or(Vec::new())
|
||||||
|
.into_iter()
|
||||||
|
.filter(|c| map.values().flatten().all(|has| *c != *has))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_led_state(&self, led_state: LedState) {
|
||||||
|
for keyboard in self.keyboards.borrow_mut().iter_mut() {
|
||||||
|
keyboard.led_update(led_state.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Devices {
|
||||||
|
capabilities: RefCell<HashMap<String, Vec<DeviceCapability>>>,
|
||||||
|
// Used for updating keyboard leds on kms backend
|
||||||
|
keyboards: RefCell<Vec<InputDevice>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SeatId {
|
||||||
|
fn default() -> SeatId {
|
||||||
|
SeatId(next_seat_id())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for SeatId {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
SEAT_IDS.lock().unwrap().remove(&self.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
struct SeatId(pub usize);
|
||||||
|
struct ActiveOutput(pub RefCell<Output>);
|
||||||
|
|
||||||
|
pub fn create_seat(
|
||||||
|
dh: &DisplayHandle,
|
||||||
|
seat_state: &mut SeatState<State>,
|
||||||
|
output: &Output,
|
||||||
|
config: &Config,
|
||||||
|
name: String,
|
||||||
|
) -> Seat<State> {
|
||||||
|
let mut seat = seat_state.new_wl_seat(dh, name);
|
||||||
|
let userdata = seat.user_data();
|
||||||
|
userdata.insert_if_missing(SeatId::default);
|
||||||
|
userdata.insert_if_missing(Devices::default);
|
||||||
|
userdata.insert_if_missing(SupressedKeys::default);
|
||||||
|
userdata.insert_if_missing(ModifiersShortcutQueue::default);
|
||||||
|
userdata.insert_if_missing(SeatMoveGrabState::default);
|
||||||
|
userdata.insert_if_missing(SeatMenuGrabState::default);
|
||||||
|
userdata.insert_if_missing(CursorState::default);
|
||||||
|
userdata.insert_if_missing(|| ActiveOutput(RefCell::new(output.clone())));
|
||||||
|
userdata.insert_if_missing(|| RefCell::new(CursorImageStatus::default_named()));
|
||||||
|
|
||||||
|
// A lot of clients bind keyboard and pointer unconditionally once on launch..
|
||||||
|
// Initial clients might race the compositor on adding periheral and
|
||||||
|
// end up in a state, where they are not able to receive input.
|
||||||
|
// Additionally a lot of clients don't handle keyboards/pointer objects being
|
||||||
|
// removed very well either and we don't want to crash applications, because the
|
||||||
|
// user is replugging their keyboard or mouse.
|
||||||
|
//
|
||||||
|
// So instead of doing the right thing (and initialize these capabilities as matching
|
||||||
|
// devices appear), we have to surrender to reality and just always expose a keyboard and pointer.
|
||||||
|
let conf = config.xkb_config();
|
||||||
|
if let Err(err) = seat.add_keyboard(xkb_config_to_wl(&conf), 600, 25) {
|
||||||
|
warn!(
|
||||||
|
?err,
|
||||||
|
"Failed to load provided xkb config. Trying default...",
|
||||||
|
);
|
||||||
|
seat.add_keyboard(XkbConfig::default(), 600, 25)
|
||||||
|
.expect("Failed to load xkb configuration files");
|
||||||
|
}
|
||||||
|
seat.add_pointer();
|
||||||
|
seat.add_touch();
|
||||||
|
|
||||||
|
seat
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait SeatExt {
|
||||||
|
fn id(&self) -> usize;
|
||||||
|
|
||||||
|
fn active_output(&self) -> Output;
|
||||||
|
fn set_active_output(&self, output: &Output);
|
||||||
|
fn devices(&self) -> &Devices;
|
||||||
|
|
||||||
|
fn cursor_geometry(
|
||||||
|
&self,
|
||||||
|
loc: impl Into<Point<f64, Buffer>>,
|
||||||
|
time: Time<Monotonic>,
|
||||||
|
) -> Option<(Rectangle<i32, Buffer>, Point<i32, Buffer>)>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SeatExt for Seat<State> {
|
||||||
|
fn id(&self) -> usize {
|
||||||
|
self.user_data().get::<SeatId>().unwrap().0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn active_output(&self) -> Output {
|
||||||
|
self.user_data()
|
||||||
|
.get::<ActiveOutput>()
|
||||||
|
.map(|x| x.0.borrow().clone())
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_active_output(&self, output: &Output) {
|
||||||
|
*self
|
||||||
|
.user_data()
|
||||||
|
.get::<ActiveOutput>()
|
||||||
|
.unwrap()
|
||||||
|
.0
|
||||||
|
.borrow_mut() = output.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn devices(&self) -> &Devices {
|
||||||
|
self.user_data().get::<Devices>().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cursor_geometry(
|
||||||
|
&self,
|
||||||
|
loc: impl Into<Point<f64, Buffer>>,
|
||||||
|
time: Time<Monotonic>,
|
||||||
|
) -> Option<(Rectangle<i32, Buffer>, Point<i32, Buffer>)> {
|
||||||
|
let location = loc.into().to_i32_round();
|
||||||
|
|
||||||
|
let cursor_status = self
|
||||||
|
.user_data()
|
||||||
|
.get::<RefCell<CursorImageStatus>>()
|
||||||
|
.map(|cell| {
|
||||||
|
let mut cursor_status = cell.borrow_mut();
|
||||||
|
if let CursorImageStatus::Surface(ref surface) = *cursor_status {
|
||||||
|
if !surface.alive() {
|
||||||
|
*cursor_status = CursorImageStatus::default_named();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cursor_status.clone()
|
||||||
|
})
|
||||||
|
.unwrap_or(CursorImageStatus::default_named());
|
||||||
|
|
||||||
|
match cursor_status {
|
||||||
|
CursorImageStatus::Surface(surface) => {
|
||||||
|
let hotspot = with_states(&surface, |states| {
|
||||||
|
states
|
||||||
|
.data_map
|
||||||
|
.get::<Mutex<CursorImageAttributes>>()
|
||||||
|
.unwrap()
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.hotspot
|
||||||
|
});
|
||||||
|
let geo = bbox_from_surface_tree(&surface, (location.x, location.y));
|
||||||
|
let buffer_geo = Rectangle::from_loc_and_size(
|
||||||
|
(geo.loc.x, geo.loc.y),
|
||||||
|
geo.size.to_buffer(1, Transform::Normal),
|
||||||
|
);
|
||||||
|
Some((buffer_geo, (hotspot.x, hotspot.y).into()))
|
||||||
|
}
|
||||||
|
CursorImageStatus::Named(CursorIcon::Default) => {
|
||||||
|
let seat_userdata = self.user_data();
|
||||||
|
seat_userdata.insert_if_missing(CursorState::default);
|
||||||
|
let state = seat_userdata.get::<CursorState>().unwrap();
|
||||||
|
let frame = state
|
||||||
|
.cursors
|
||||||
|
.get(&CursorShape::Default)
|
||||||
|
.unwrap()
|
||||||
|
.get_image(1, Into::<Duration>::into(time).as_millis() as u32);
|
||||||
|
|
||||||
|
Some((
|
||||||
|
Rectangle::from_loc_and_size(
|
||||||
|
location,
|
||||||
|
(frame.width as i32, frame.height as i32),
|
||||||
|
),
|
||||||
|
(frame.xhot as i32, frame.yhot as i32).into(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
CursorImageStatus::Named(_) => {
|
||||||
|
// TODO: Handle for `cursor_shape_v1` protocol
|
||||||
|
None
|
||||||
|
}
|
||||||
|
CursorImageStatus::Hidden => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
49
src/state.rs
49
src/state.rs
|
|
@ -3,9 +3,8 @@
|
||||||
use crate::{
|
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, Devices},
|
input::gestures::GestureState,
|
||||||
shell::{grabs::SeatMoveGrabState, Shell},
|
shell::{grabs::SeatMoveGrabState, SeatExt, Shell},
|
||||||
utils::prelude::*,
|
|
||||||
wayland::protocols::{
|
wayland::protocols::{
|
||||||
drm::WlDrmState, image_source::ImageSourceState,
|
drm::WlDrmState, image_source::ImageSourceState,
|
||||||
output_configuration::OutputConfigurationState, screencopy::ScreencopyState,
|
output_configuration::OutputConfigurationState, screencopy::ScreencopyState,
|
||||||
|
|
@ -25,7 +24,6 @@ use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
allocator::dmabuf::Dmabuf,
|
allocator::dmabuf::Dmabuf,
|
||||||
drm::DrmNode,
|
drm::DrmNode,
|
||||||
input::Device,
|
|
||||||
renderer::{
|
renderer::{
|
||||||
element::{
|
element::{
|
||||||
default_primary_scanout_output_compare, utils::select_dmabuf_feedback,
|
default_primary_scanout_output_compare, utils::select_dmabuf_feedback,
|
||||||
|
|
@ -44,7 +42,7 @@ use smithay::{
|
||||||
with_surfaces_surface_tree, OutputPresentationFeedback,
|
with_surfaces_surface_tree, OutputPresentationFeedback,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
input::{pointer::CursorImageStatus, Seat, 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},
|
||||||
|
|
@ -149,10 +147,7 @@ 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 output_conf: ConfigurationManager,
|
|
||||||
pub shell: Shell,
|
pub shell: Shell,
|
||||||
seats: Vec<Seat<State>>,
|
|
||||||
last_active_seat: Option<Seat<State>>,
|
|
||||||
|
|
||||||
pub clock: Clock<Monotonic>,
|
pub clock: Clock<Monotonic>,
|
||||||
pub should_stop: bool,
|
pub should_stop: bool,
|
||||||
|
|
@ -229,12 +224,11 @@ impl BackendData {
|
||||||
output: &Output,
|
output: &Output,
|
||||||
test_only: bool,
|
test_only: bool,
|
||||||
shell: &mut Shell,
|
shell: &mut Shell,
|
||||||
seats: impl Iterator<Item = Seat<State>>,
|
|
||||||
loop_handle: &LoopHandle<'_, State>,
|
loop_handle: &LoopHandle<'_, State>,
|
||||||
) -> 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(output, seats, shell, test_only, loop_handle)
|
state.apply_config_for_output(output, shell, test_only, loop_handle)
|
||||||
}
|
}
|
||||||
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),
|
||||||
|
|
@ -411,8 +405,6 @@ impl State {
|
||||||
|
|
||||||
shell,
|
shell,
|
||||||
|
|
||||||
seats: Vec::new(),
|
|
||||||
last_active_seat: None,
|
|
||||||
local_offset,
|
local_offset,
|
||||||
|
|
||||||
clock,
|
clock,
|
||||||
|
|
@ -495,38 +487,6 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Common {
|
impl Common {
|
||||||
pub fn add_seat(&mut self, seat: Seat<State>) {
|
|
||||||
if self.seats.is_empty() {
|
|
||||||
self.last_active_seat = Some(seat.clone());
|
|
||||||
}
|
|
||||||
self.seats.push(seat);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn remove_seat(&mut self, seat: &Seat<State>) {
|
|
||||||
self.seats.retain(|s| s != seat);
|
|
||||||
if self.seats.is_empty() {
|
|
||||||
self.last_active_seat = None;
|
|
||||||
} else if self.last_active_seat() == seat {
|
|
||||||
self.last_active_seat = Some(self.seats[0].clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn seats(&self) -> impl Iterator<Item = &Seat<State>> {
|
|
||||||
self.seats.iter()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn seat_with_device<D: Device>(&self, device: &D) -> Option<&Seat<State>> {
|
|
||||||
self.seats().find(|seat| {
|
|
||||||
let userdata = seat.user_data();
|
|
||||||
let devices = userdata.get::<Devices>().unwrap();
|
|
||||||
devices.has_device(device)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn last_active_seat(&self) -> &Seat<State> {
|
|
||||||
self.last_active_seat.as_ref().expect("No seat?")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn send_frames(
|
pub fn send_frames(
|
||||||
&self,
|
&self,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
|
|
@ -573,6 +533,7 @@ impl Common {
|
||||||
}
|
}
|
||||||
|
|
||||||
for seat in self
|
for seat in self
|
||||||
|
.shell
|
||||||
.seats
|
.seats
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|seat| &seat.active_output() == output)
|
.filter(|seat| &seat.active_output() == output)
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,10 @@
|
||||||
use std::{cell::RefCell, sync::Mutex, time::Duration};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
backend::render::cursor::{CursorShape, CursorState},
|
|
||||||
input::{ActiveOutput, SeatId},
|
|
||||||
};
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
desktop::utils::bbox_from_surface_tree,
|
|
||||||
input::{
|
|
||||||
pointer::{CursorIcon, CursorImageAttributes, CursorImageStatus},
|
|
||||||
Seat,
|
|
||||||
},
|
|
||||||
output::Output,
|
output::Output,
|
||||||
utils::{Buffer, IsAlive, Monotonic, Point, Rectangle, Time, Transform},
|
utils::{Rectangle, Transform},
|
||||||
wayland::compositor::with_states,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use super::geometry::*;
|
pub use super::geometry::*;
|
||||||
pub use crate::shell::{Shell, Workspace};
|
pub use crate::shell::{SeatExt, Shell, Workspace};
|
||||||
pub use crate::state::{Common, State};
|
pub use crate::state::{Common, State};
|
||||||
pub use crate::wayland::handlers::xdg_shell::popup::update_reactive_popups;
|
pub use crate::wayland::handlers::xdg_shell::popup::update_reactive_popups;
|
||||||
|
|
||||||
|
|
@ -40,102 +28,3 @@ impl OutputExt for Output {
|
||||||
.as_global()
|
.as_global()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait SeatExt {
|
|
||||||
fn id(&self) -> usize;
|
|
||||||
|
|
||||||
fn active_output(&self) -> Output;
|
|
||||||
fn set_active_output(&self, output: &Output);
|
|
||||||
fn cursor_geometry(
|
|
||||||
&self,
|
|
||||||
loc: impl Into<Point<f64, Buffer>>,
|
|
||||||
time: Time<Monotonic>,
|
|
||||||
) -> Option<(Rectangle<i32, Buffer>, Point<i32, Buffer>)>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SeatExt for Seat<State> {
|
|
||||||
fn id(&self) -> usize {
|
|
||||||
self.user_data().get::<SeatId>().unwrap().0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn active_output(&self) -> Output {
|
|
||||||
self.user_data()
|
|
||||||
.get::<ActiveOutput>()
|
|
||||||
.map(|x| x.0.borrow().clone())
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_active_output(&self, output: &Output) {
|
|
||||||
*self
|
|
||||||
.user_data()
|
|
||||||
.get::<ActiveOutput>()
|
|
||||||
.unwrap()
|
|
||||||
.0
|
|
||||||
.borrow_mut() = output.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cursor_geometry(
|
|
||||||
&self,
|
|
||||||
loc: impl Into<Point<f64, Buffer>>,
|
|
||||||
time: Time<Monotonic>,
|
|
||||||
) -> Option<(Rectangle<i32, Buffer>, Point<i32, Buffer>)> {
|
|
||||||
let location = loc.into().to_i32_round();
|
|
||||||
|
|
||||||
let cursor_status = self
|
|
||||||
.user_data()
|
|
||||||
.get::<RefCell<CursorImageStatus>>()
|
|
||||||
.map(|cell| {
|
|
||||||
let mut cursor_status = cell.borrow_mut();
|
|
||||||
if let CursorImageStatus::Surface(ref surface) = *cursor_status {
|
|
||||||
if !surface.alive() {
|
|
||||||
*cursor_status = CursorImageStatus::default_named();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cursor_status.clone()
|
|
||||||
})
|
|
||||||
.unwrap_or(CursorImageStatus::default_named());
|
|
||||||
|
|
||||||
match cursor_status {
|
|
||||||
CursorImageStatus::Surface(surface) => {
|
|
||||||
let hotspot = with_states(&surface, |states| {
|
|
||||||
states
|
|
||||||
.data_map
|
|
||||||
.get::<Mutex<CursorImageAttributes>>()
|
|
||||||
.unwrap()
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.hotspot
|
|
||||||
});
|
|
||||||
let geo = bbox_from_surface_tree(&surface, (location.x, location.y));
|
|
||||||
let buffer_geo = Rectangle::from_loc_and_size(
|
|
||||||
(geo.loc.x, geo.loc.y),
|
|
||||||
geo.size.to_buffer(1, Transform::Normal),
|
|
||||||
);
|
|
||||||
Some((buffer_geo, (hotspot.x, hotspot.y).into()))
|
|
||||||
}
|
|
||||||
CursorImageStatus::Named(CursorIcon::Default) => {
|
|
||||||
let seat_userdata = self.user_data();
|
|
||||||
seat_userdata.insert_if_missing(CursorState::default);
|
|
||||||
let state = seat_userdata.get::<CursorState>().unwrap();
|
|
||||||
let frame = state
|
|
||||||
.cursors
|
|
||||||
.get(&CursorShape::Default)
|
|
||||||
.unwrap()
|
|
||||||
.get_image(1, Into::<Duration>::into(time).as_millis() as u32);
|
|
||||||
|
|
||||||
Some((
|
|
||||||
Rectangle::from_loc_and_size(
|
|
||||||
location,
|
|
||||||
(frame.width as i32, frame.height as i32),
|
|
||||||
),
|
|
||||||
(frame.xhot as i32, frame.yhot as i32).into(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
CursorImageStatus::Named(_) => {
|
|
||||||
// TODO: Handle for `cursor_shape_v1` protocol
|
|
||||||
None
|
|
||||||
}
|
|
||||||
CursorImageStatus::Hidden => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,10 @@ impl State {
|
||||||
});
|
});
|
||||||
if !initial_configure_sent {
|
if !initial_configure_sent {
|
||||||
// compute initial dimensions by mapping
|
// compute initial dimensions by mapping
|
||||||
Shell::map_layer(self, &surface);
|
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();
|
surface.layer_surface().send_configure();
|
||||||
}
|
}
|
||||||
initial_configure_sent
|
initial_configure_sent
|
||||||
|
|
@ -159,7 +162,14 @@ impl CompositorHandler for State {
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
{
|
{
|
||||||
window.on_commit();
|
window.on_commit();
|
||||||
Shell::map_window(self, &window);
|
if let Some(target) = self.common.shell.map_window(
|
||||||
|
&window,
|
||||||
|
&self.common.event_loop_handle,
|
||||||
|
&self.common.theme,
|
||||||
|
) {
|
||||||
|
let seat = self.common.shell.seats.last_active().clone();
|
||||||
|
Shell::set_focus(self, Some(&target), &seat, None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -187,7 +197,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.last_active_seat().clone();
|
let seat = self.common.shell.seats.last_active().clone();
|
||||||
let moved_window = seat
|
let moved_window = seat
|
||||||
.user_data()
|
.user_data()
|
||||||
.get::<SeatMoveGrabState>()
|
.get::<SeatMoveGrabState>()
|
||||||
|
|
|
||||||
|
|
@ -45,10 +45,7 @@ impl FractionalScaleHandler for State {
|
||||||
.cloned()
|
.cloned()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| self.common.shell.seats.last_active().active_output());
|
||||||
let seat = self.common.last_active_seat();
|
|
||||||
seat.active_output()
|
|
||||||
});
|
|
||||||
|
|
||||||
with_states(&surface, |states| {
|
with_states(&surface, |states| {
|
||||||
with_fractional_scale(states, |fractional_scale| {
|
with_fractional_scale(states, |fractional_scale| {
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ impl WlrLayerShellHandler for State {
|
||||||
_layer: Layer,
|
_layer: Layer,
|
||||||
namespace: String,
|
namespace: String,
|
||||||
) {
|
) {
|
||||||
let seat = self.common.last_active_seat().clone();
|
let seat = self.common.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)
|
||||||
|
|
|
||||||
|
|
@ -82,12 +82,10 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let seats = self.common.seats().cloned().collect::<Vec<_>>();
|
|
||||||
if let Err(err) = self.backend.apply_config_for_output(
|
if let Err(err) = self.backend.apply_config_for_output(
|
||||||
output,
|
output,
|
||||||
test_only,
|
test_only,
|
||||||
&mut self.common.shell,
|
&mut self.common.shell,
|
||||||
seats.iter().cloned(),
|
|
||||||
&self.common.event_loop_handle,
|
&self.common.event_loop_handle,
|
||||||
) {
|
) {
|
||||||
warn!(
|
warn!(
|
||||||
|
|
@ -109,7 +107,6 @@ impl State {
|
||||||
output,
|
output,
|
||||||
false,
|
false,
|
||||||
&mut self.common.shell,
|
&mut self.common.shell,
|
||||||
seats.iter().cloned(),
|
|
||||||
&self.common.event_loop_handle,
|
&self.common.event_loop_handle,
|
||||||
) {
|
) {
|
||||||
error!(?err, "Failed to reset output config for {}.", output.name(),);
|
error!(?err, "Failed to reset output config for {}.", output.name(),);
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,9 @@ impl ScreencopyHandler for State {
|
||||||
fn capture_cursor_source(&mut self, _source: &ImageSourceData) -> Option<BufferConstraints> {
|
fn capture_cursor_source(&mut self, _source: &ImageSourceData) -> Option<BufferConstraints> {
|
||||||
let size = if let Some((geometry, _)) = self
|
let size = if let Some((geometry, _)) = self
|
||||||
.common
|
.common
|
||||||
.last_active_seat()
|
.shell
|
||||||
|
.seats
|
||||||
|
.last_active()
|
||||||
.cursor_geometry((0.0, 0.0), self.common.clock.now())
|
.cursor_geometry((0.0, 0.0), self.common.clock.now())
|
||||||
{
|
{
|
||||||
geometry.size
|
geometry.size
|
||||||
|
|
@ -125,7 +127,7 @@ 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.last_active_seat();
|
let seat = self.common.shell.seats.last_active();
|
||||||
|
|
||||||
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();
|
||||||
|
|
@ -266,7 +268,7 @@ impl ScreencopyHandler for State {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let seat = self.common.last_active_seat().clone();
|
let seat = self.common.shell.seats.last_active().clone();
|
||||||
render_cursor_to_buffer(self, &session, frame, &seat);
|
render_cursor_to_buffer(self, &session, frame, &seat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -286,7 +286,10 @@ pub fn render_workspace_to_buffer(
|
||||||
dt,
|
dt,
|
||||||
age,
|
age,
|
||||||
additional_damage,
|
additional_damage,
|
||||||
common,
|
&common.shell,
|
||||||
|
&common.config,
|
||||||
|
&common.theme,
|
||||||
|
common.clock.now(),
|
||||||
&output,
|
&output,
|
||||||
None,
|
None,
|
||||||
handle,
|
handle,
|
||||||
|
|
@ -311,7 +314,10 @@ pub fn render_workspace_to_buffer(
|
||||||
dt,
|
dt,
|
||||||
age,
|
age,
|
||||||
additional_damage,
|
additional_damage,
|
||||||
common,
|
&common.shell,
|
||||||
|
&common.config,
|
||||||
|
&common.theme,
|
||||||
|
common.clock.now(),
|
||||||
&output,
|
&output,
|
||||||
None,
|
None,
|
||||||
handle,
|
handle,
|
||||||
|
|
@ -529,7 +535,7 @@ pub fn render_window_to_buffer(
|
||||||
.map(Into::<WindowCaptureElement<R>>::into),
|
.map(Into::<WindowCaptureElement<R>>::into),
|
||||||
);
|
);
|
||||||
|
|
||||||
let seat = common.last_active_seat().clone();
|
let seat = common.shell.seats.last_active().clone();
|
||||||
if let Some(location) = {
|
if let Some(location) = {
|
||||||
if let Some(mapped) = common.shell.element_for_surface(window) {
|
if let Some(mapped) = common.shell.element_for_surface(window) {
|
||||||
mapped.cursor_position(&seat).and_then(|mut p| {
|
mapped.cursor_position(&seat).and_then(|mut p| {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
input::Devices,
|
|
||||||
shell::focus::target::{KeyboardFocusTarget, PointerFocusTarget},
|
shell::focus::target::{KeyboardFocusTarget, PointerFocusTarget},
|
||||||
|
shell::Devices,
|
||||||
state::State,
|
state::State,
|
||||||
};
|
};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ 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.last_active_seat().clone());
|
let seat = seat.unwrap_or(self.common.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))
|
||||||
|
|
@ -66,7 +66,7 @@ impl ToplevelManagementHandler for State {
|
||||||
WorkspaceDelta::new_shortcut(),
|
WorkspaceDelta::new_shortcut(),
|
||||||
); // TODO: Move pointer?
|
); // TODO: Move pointer?
|
||||||
mapped.focus_window(window);
|
mapped.focus_window(window);
|
||||||
Common::set_focus(self, Some(&mapped.clone().into()), &seat, None);
|
Shell::set_focus(self, Some(&mapped.clone().into()), &seat, None);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -104,7 +104,17 @@ impl ToplevelManagementHandler for State {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.clone();
|
.clone();
|
||||||
let from_handle = from_workspace.handle;
|
let from_handle = from_workspace.handle;
|
||||||
let _ = Shell::move_window(self, None, &mapped, &from_handle, &to_handle, false, None);
|
let seat = self.common.shell.seats.last_active().clone();
|
||||||
|
if let Some((target, _)) = self.common.shell.move_window(
|
||||||
|
Some(&seat),
|
||||||
|
&mapped,
|
||||||
|
&from_handle,
|
||||||
|
&to_handle,
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
) {
|
||||||
|
Shell::set_focus(self, Some(&target), &seat, None);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -115,7 +125,7 @@ impl ToplevelManagementHandler for State {
|
||||||
window: &<Self as ToplevelInfoHandler>::Window,
|
window: &<Self as ToplevelInfoHandler>::Window,
|
||||||
output: Option<Output>,
|
output: Option<Output>,
|
||||||
) {
|
) {
|
||||||
let seat = self.common.last_active_seat().clone();
|
let seat = self.common.shell.seats.last_active().clone();
|
||||||
if let Some(mapped) = self.common.shell.element_for_surface(window).cloned() {
|
if let Some(mapped) = self.common.shell.element_for_surface(window).cloned() {
|
||||||
if let Some(output) = output {
|
if let Some(output) = output {
|
||||||
let from = self
|
let from = self
|
||||||
|
|
@ -177,7 +187,7 @@ 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() {
|
if let Some(mapped) = self.common.shell.element_for_surface(window).cloned() {
|
||||||
let seat = self.common.last_active_seat().clone();
|
let seat = self.common.shell.seats.last_active().clone();
|
||||||
self.common.shell.maximize_request(&mapped, &seat);
|
self.common.shell.maximize_request(&mapped, &seat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -198,7 +208,7 @@ impl ToplevelManagementHandler for State {
|
||||||
|
|
||||||
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() {
|
if let Some(mut mapped) = self.common.shell.element_for_surface(window).cloned() {
|
||||||
let seat = self.common.last_active_seat().clone();
|
let seat = self.common.shell.seats.last_active().clone();
|
||||||
self.common.shell.unminimize_request(&mapped, &seat);
|
self.common.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);
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ impl WorkspaceHandler for State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Request::SetTilingState { workspace, state } => {
|
Request::SetTilingState { workspace, state } => {
|
||||||
let seat = self.common.last_active_seat().clone();
|
let seat = self.common.shell.seats.last_active().clone();
|
||||||
if let Some(workspace) = self
|
if let Some(workspace) = self
|
||||||
.common
|
.common
|
||||||
.shell
|
.shell
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ impl XdgActivationHandler for State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ActivationContext::Workspace(workspace) => {
|
ActivationContext::Workspace(workspace) => {
|
||||||
let seat = self.common.last_active_seat().clone();
|
let seat = self.common.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() {
|
||||||
|
|
@ -159,7 +159,7 @@ impl XdgActivationHandler for State {
|
||||||
.space_for(&element)
|
.space_for(&element)
|
||||||
.map(|w| w.handle.clone())
|
.map(|w| w.handle.clone())
|
||||||
{
|
{
|
||||||
Shell::append_focus_stack(self, &element, &seat);
|
self.common.shell.append_focus_stack(&element, &seat);
|
||||||
self.common.shell.set_urgent(&w);
|
self.common.shell.set_urgent(&w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ impl XdgShellHandler for State {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_toplevel(&mut self, surface: ToplevelSurface) {
|
fn new_toplevel(&mut self, surface: ToplevelSurface) {
|
||||||
let seat = self.common.last_active_seat().clone();
|
let seat = self.common.shell.seats.last_active().clone();
|
||||||
let window = CosmicSurface::from(surface);
|
let window = CosmicSurface::from(surface);
|
||||||
self.common.shell.pending_windows.push((window, seat, None));
|
self.common.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
|
||||||
|
|
@ -90,7 +90,7 @@ impl XdgShellHandler for State {
|
||||||
grab.ungrab(PopupUngrabStrategy::All);
|
grab.ungrab(PopupUngrabStrategy::All);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Common::set_focus(self, grab.current_grab().as_ref(), &seat, Some(serial));
|
Shell::set_focus(self, grab.current_grab().as_ref(), &seat, Some(serial));
|
||||||
keyboard.set_grab(PopupKeyboardGrab::new(&grab), serial);
|
keyboard.set_grab(PopupKeyboardGrab::new(&grab), serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -183,7 +183,7 @@ impl XdgShellHandler for State {
|
||||||
.element_for_surface(surface.wl_surface())
|
.element_for_surface(surface.wl_surface())
|
||||||
.cloned()
|
.cloned()
|
||||||
{
|
{
|
||||||
let seat = self.common.last_active_seat().clone();
|
let seat = self.common.shell.seats.last_active().clone();
|
||||||
self.common.shell.maximize_request(&mapped, &seat)
|
self.common.shell.maximize_request(&mapped, &seat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -200,7 +200,7 @@ impl XdgShellHandler for State {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fullscreen_request(&mut self, surface: ToplevelSurface, output: Option<WlOutput>) {
|
fn fullscreen_request(&mut self, surface: ToplevelSurface, output: Option<WlOutput>) {
|
||||||
let seat = self.common.last_active_seat().clone();
|
let seat = self.common.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()
|
||||||
|
|
@ -378,7 +378,7 @@ impl XdgShellHandler for State {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn toplevel_destroyed(&mut self, surface: ToplevelSurface) {
|
fn toplevel_destroyed(&mut self, surface: ToplevelSurface) {
|
||||||
let seat = self.common.last_active_seat().clone();
|
let seat = self.common.shell.seats.last_active().clone();
|
||||||
self.common.shell.unmap_surface(surface.wl_surface(), &seat);
|
self.common.shell.unmap_surface(surface.wl_surface(), &seat);
|
||||||
|
|
||||||
let output = self
|
let output = self
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@ 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.last_active_seat().get_keyboard() {
|
if let Some(keyboard) = self.shell.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,7 +146,7 @@ impl Common {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_x11_stacking_order(&mut self) {
|
pub fn update_x11_stacking_order(&mut self) {
|
||||||
let active_output = self.last_active_seat().active_output();
|
let active_output = self.shell.seats.last_active().active_output();
|
||||||
if let Some(xwm) = self
|
if let Some(xwm) = self
|
||||||
.shell
|
.shell
|
||||||
.xwayland_state
|
.xwayland_state
|
||||||
|
|
@ -254,7 +254,7 @@ impl XwmHandler for State {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let seat = self.common.last_active_seat().clone();
|
let seat = self.common.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| {
|
||||||
|
|
@ -308,7 +308,14 @@ impl XwmHandler for State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Shell::map_window(self, &window);
|
if let Some(target) = self.common.shell.map_window(
|
||||||
|
&window,
|
||||||
|
&self.common.event_loop_handle,
|
||||||
|
&self.common.theme,
|
||||||
|
) {
|
||||||
|
let seat = self.common.shell.seats.last_active().clone();
|
||||||
|
Shell::set_focus(self, Some(&target), &seat, None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -322,7 +329,7 @@ impl XwmHandler for State {
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Shell::map_override_redirect(self, window)
|
self.common.shell.map_override_redirect(window)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unmapped_window(&mut self, _xwm: XwmId, window: X11Surface) {
|
fn unmapped_window(&mut self, _xwm: XwmId, window: X11Surface) {
|
||||||
|
|
@ -332,7 +339,7 @@ impl XwmHandler for State {
|
||||||
.override_redirect_windows
|
.override_redirect_windows
|
||||||
.retain(|or| or != &window);
|
.retain(|or| or != &window);
|
||||||
} else {
|
} else {
|
||||||
let seat = self.common.last_active_seat().clone();
|
let seat = self.common.shell.seats.last_active().clone();
|
||||||
self.common.shell.unmap_surface(&window, &seat);
|
self.common.shell.unmap_surface(&window, &seat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -459,14 +466,14 @@ 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.last_active_seat().clone();
|
let seat = self.common.shell.seats.last_active().clone();
|
||||||
Shell::resize_request(self, &wl_surface, &seat, None, resize_edge.into())
|
Shell::resize_request(self, &wl_surface, &seat, None, resize_edge.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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.last_active_seat().clone();
|
let seat = self.common.shell.seats.last_active().clone();
|
||||||
Shell::move_request(
|
Shell::move_request(
|
||||||
self,
|
self,
|
||||||
&wl_surface,
|
&wl_surface,
|
||||||
|
|
@ -480,7 +487,7 @@ impl XwmHandler for State {
|
||||||
|
|
||||||
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() {
|
if let Some(mapped) = self.common.shell.element_for_surface(&window).cloned() {
|
||||||
let seat = self.common.last_active_seat().clone();
|
let seat = self.common.shell.seats.last_active().clone();
|
||||||
self.common.shell.maximize_request(&mapped, &seat);
|
self.common.shell.maximize_request(&mapped, &seat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -501,7 +508,7 @@ impl XwmHandler for State {
|
||||||
|
|
||||||
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() {
|
if let Some(mut mapped) = self.common.shell.element_for_surface(&window).cloned() {
|
||||||
let seat = self.common.last_active_seat().clone();
|
let seat = self.common.shell.seats.last_active().clone();
|
||||||
self.common.shell.unminimize_request(&mapped, &seat);
|
self.common.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));
|
||||||
|
|
@ -513,7 +520,7 @@ 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.last_active_seat().clone();
|
let seat = self.common.shell.seats.last_active().clone();
|
||||||
if let Some(mapped) = self.common.shell.element_for_surface(&window).cloned() {
|
if let Some(mapped) = self.common.shell.element_for_surface(&window).cloned() {
|
||||||
if let Some((output, handle)) = self
|
if let Some((output, handle)) = self
|
||||||
.common
|
.common
|
||||||
|
|
@ -539,7 +546,7 @@ impl XwmHandler for State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let output = self.common.last_active_seat().active_output();
|
let output = seat.active_output();
|
||||||
if let Some(o) = self
|
if let Some(o) = self
|
||||||
.common
|
.common
|
||||||
.shell
|
.shell
|
||||||
|
|
@ -573,7 +580,7 @@ impl XwmHandler for State {
|
||||||
mime_type: String,
|
mime_type: String,
|
||||||
fd: OwnedFd,
|
fd: OwnedFd,
|
||||||
) {
|
) {
|
||||||
let seat = self.common.last_active_seat();
|
let seat = self.common.shell.seats.last_active();
|
||||||
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) {
|
||||||
|
|
@ -602,7 +609,7 @@ 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.last_active_seat();
|
let seat = self.common.shell.seats.last_active();
|
||||||
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)
|
||||||
|
|
@ -615,7 +622,7 @@ 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.seats() {
|
for seat in self.common.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) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue