floating: Allow dragging windows into stacks
This commit is contained in:
parent
e9c5266509
commit
9ca5edc836
4 changed files with 97 additions and 42 deletions
|
|
@ -293,33 +293,28 @@ impl PointerGrab<State> for MoveGrab {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.previous == ManagedLayer::Tiling {
|
let indicator_location = state
|
||||||
let indicator_location = state
|
.common
|
||||||
.common
|
.shell
|
||||||
.shell
|
.stacking_indicator(¤t_output, self.previous);
|
||||||
.active_space(¤t_output)
|
if indicator_location.is_some() != grab_state.stacking_indicator.is_some() {
|
||||||
.tiling_layer
|
grab_state.stacking_indicator = indicator_location.map(|geo| {
|
||||||
.stacking_indicator();
|
let element = stack_hover(
|
||||||
|
state.common.event_loop_handle.clone(),
|
||||||
if indicator_location.is_some() != grab_state.stacking_indicator.is_some() {
|
geo.size.as_logical(),
|
||||||
grab_state.stacking_indicator = indicator_location.map(|geo| {
|
state.common.theme.clone(),
|
||||||
let element = stack_hover(
|
);
|
||||||
state.common.event_loop_handle.clone(),
|
for output in &self.window_outputs {
|
||||||
geo.size.as_logical(),
|
element.output_enter(
|
||||||
state.common.theme.clone(),
|
output,
|
||||||
|
Rectangle::from_loc_and_size(
|
||||||
|
(0, 0),
|
||||||
|
output.geometry().size.as_logical(),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
for output in &self.window_outputs {
|
}
|
||||||
element.output_enter(
|
(element, geo.loc.as_logical())
|
||||||
output,
|
});
|
||||||
Rectangle::from_loc_and_size(
|
|
||||||
(0, 0),
|
|
||||||
output.geometry().size.as_logical(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
(element, geo.loc.as_logical())
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
drop(borrow);
|
drop(borrow);
|
||||||
|
|
@ -566,13 +561,11 @@ impl Drop for MoveGrab {
|
||||||
grab_state.window.geometry().size.as_global(),
|
grab_state.window.geometry().size.as_global(),
|
||||||
));
|
));
|
||||||
let workspace = state.common.shell.active_space_mut(&output);
|
let workspace = state.common.shell.active_space_mut(&output);
|
||||||
workspace.floating_layer.map_internal(
|
let (window, location) = workspace.floating_layer.drop_window(
|
||||||
grab_state.window,
|
grab_state.window,
|
||||||
Some(window_location.to_local(&workspace.output)),
|
window_location.to_local(&workspace.output),
|
||||||
None,
|
|
||||||
);
|
);
|
||||||
|
Some((window, location.to_global(&output)))
|
||||||
Some((window.clone(), window_location))
|
|
||||||
}
|
}
|
||||||
ManagedLayer::Sticky => {
|
ManagedLayer::Sticky => {
|
||||||
grab_state.window.set_geometry(Rectangle::from_loc_and_size(
|
grab_state.window.set_geometry(Rectangle::from_loc_and_size(
|
||||||
|
|
@ -580,13 +573,11 @@ impl Drop for MoveGrab {
|
||||||
grab_state.window.geometry().size.as_global(),
|
grab_state.window.geometry().size.as_global(),
|
||||||
));
|
));
|
||||||
let set = state.common.shell.workspaces.sets.get_mut(&output).unwrap();
|
let set = state.common.shell.workspaces.sets.get_mut(&output).unwrap();
|
||||||
set.sticky_layer.map_internal(
|
let (window, location) = set
|
||||||
grab_state.window,
|
.sticky_layer
|
||||||
Some(window_location.to_local(&output)),
|
.drop_window(grab_state.window, window_location.to_local(&output));
|
||||||
None,
|
|
||||||
);
|
|
||||||
|
|
||||||
Some((window.clone(), window_location))
|
Some((window, location.to_global(&output)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -27,11 +27,14 @@ use crate::{
|
||||||
shell::{
|
shell::{
|
||||||
element::{
|
element::{
|
||||||
resize_indicator::ResizeIndicator,
|
resize_indicator::ResizeIndicator,
|
||||||
stack::{CosmicStackRenderElement, MoveResult as StackMoveResult},
|
stack::{CosmicStackRenderElement, MoveResult as StackMoveResult, TAB_HEIGHT},
|
||||||
window::CosmicWindowRenderElement,
|
window::CosmicWindowRenderElement,
|
||||||
CosmicMapped, CosmicMappedRenderElement, CosmicWindow,
|
CosmicMapped, CosmicMappedRenderElement, CosmicWindow,
|
||||||
},
|
},
|
||||||
focus::{target::KeyboardFocusTarget, FocusStackMut},
|
focus::{
|
||||||
|
target::{KeyboardFocusTarget, PointerFocusTarget},
|
||||||
|
FocusStackMut,
|
||||||
|
},
|
||||||
grabs::{ReleaseMode, ResizeEdge},
|
grabs::{ReleaseMode, ResizeEdge},
|
||||||
CosmicSurface, Direction, MoveResult, ResizeDirection, ResizeMode,
|
CosmicSurface, Direction, MoveResult, ResizeDirection, ResizeMode,
|
||||||
},
|
},
|
||||||
|
|
@ -50,6 +53,7 @@ pub struct FloatingLayout {
|
||||||
pub(crate) space: Space<CosmicMapped>,
|
pub(crate) space: Space<CosmicMapped>,
|
||||||
spawn_order: Vec<CosmicMapped>,
|
spawn_order: Vec<CosmicMapped>,
|
||||||
tiling_animations: HashMap<CosmicMapped, (Instant, Rectangle<i32, Local>)>,
|
tiling_animations: HashMap<CosmicMapped, (Instant, Rectangle<i32, Local>)>,
|
||||||
|
hovered_stack: Option<(CosmicMapped, Rectangle<i32, Local>)>,
|
||||||
dirty: AtomicBool,
|
dirty: AtomicBool,
|
||||||
pub theme: cosmic::Theme,
|
pub theme: cosmic::Theme,
|
||||||
}
|
}
|
||||||
|
|
@ -449,10 +453,53 @@ impl FloatingLayout {
|
||||||
was_unmaped
|
was_unmaped
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn drop_window(
|
||||||
|
&mut self,
|
||||||
|
window: CosmicMapped,
|
||||||
|
position: Point<i32, Local>,
|
||||||
|
) -> (CosmicMapped, Point<i32, Local>) {
|
||||||
|
if let Some((mapped, geo)) = self.hovered_stack.take() {
|
||||||
|
let stack = mapped.stack_ref().unwrap();
|
||||||
|
for surface in window.windows().map(|s| s.0) {
|
||||||
|
stack.add_window(surface, None);
|
||||||
|
}
|
||||||
|
(mapped, geo.loc)
|
||||||
|
} else {
|
||||||
|
self.map_internal(window.clone(), Some(position), None);
|
||||||
|
(window, position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn element_geometry(&self, elem: &CosmicMapped) -> Option<Rectangle<i32, Local>> {
|
pub fn element_geometry(&self, elem: &CosmicMapped) -> Option<Rectangle<i32, Local>> {
|
||||||
self.space.element_geometry(elem).map(RectExt::as_local)
|
self.space.element_geometry(elem).map(RectExt::as_local)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn element_under(
|
||||||
|
&mut self,
|
||||||
|
location: Point<f64, Local>,
|
||||||
|
) -> Option<(PointerFocusTarget, Point<i32, Local>)> {
|
||||||
|
let res = self
|
||||||
|
.space
|
||||||
|
.element_under(location.as_logical())
|
||||||
|
.map(|(mapped, p)| (mapped.clone(), p.as_local()));
|
||||||
|
if let Some((mapped, _)) = res.as_ref() {
|
||||||
|
let geometry = self.space.element_geometry(mapped).unwrap();
|
||||||
|
let offset = location.y.round() as i32 - geometry.loc.y;
|
||||||
|
if mapped.is_stack() && offset.is_positive() && offset <= TAB_HEIGHT {
|
||||||
|
self.hovered_stack = Some((mapped.clone(), geometry.as_local()));
|
||||||
|
} else {
|
||||||
|
self.hovered_stack.take();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.hovered_stack.take();
|
||||||
|
}
|
||||||
|
res.map(|(m, p)| (m.into(), p))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stacking_indicator(&self) -> Option<Rectangle<i32, Local>> {
|
||||||
|
self.hovered_stack.as_ref().map(|(_, geo)| geo.clone())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn resize_request(
|
pub fn resize_request(
|
||||||
&mut self,
|
&mut self,
|
||||||
mapped: &CosmicMapped,
|
mapped: &CosmicMapped,
|
||||||
|
|
|
||||||
|
|
@ -1510,6 +1510,25 @@ impl Shell {
|
||||||
(self.resize_mode.clone(), self.resize_indicator.clone())
|
(self.resize_mode.clone(), self.resize_indicator.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn stacking_indicator(
|
||||||
|
&self,
|
||||||
|
output: &Output,
|
||||||
|
layer: ManagedLayer,
|
||||||
|
) -> Option<Rectangle<i32, Local>> {
|
||||||
|
match layer {
|
||||||
|
ManagedLayer::Sticky => self
|
||||||
|
.workspaces
|
||||||
|
.sets
|
||||||
|
.get(output)
|
||||||
|
.and_then(|set| set.sticky_layer.stacking_indicator()),
|
||||||
|
ManagedLayer::Floating => self
|
||||||
|
.active_space(output)
|
||||||
|
.floating_layer
|
||||||
|
.stacking_indicator(),
|
||||||
|
ManagedLayer::Tiling => self.active_space(output).tiling_layer.stacking_indicator(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn refresh(&mut self) {
|
pub fn refresh(&mut self) {
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
puffin::profile_function!();
|
puffin::profile_function!();
|
||||||
|
|
|
||||||
|
|
@ -424,9 +424,7 @@ impl Workspace {
|
||||||
) -> Option<(PointerFocusTarget, Point<i32, Global>)> {
|
) -> Option<(PointerFocusTarget, Point<i32, Global>)> {
|
||||||
let location = location.to_local(&self.output);
|
let location = location.to_local(&self.output);
|
||||||
self.floating_layer
|
self.floating_layer
|
||||||
.space
|
.element_under(location)
|
||||||
.element_under(location.as_logical())
|
|
||||||
.map(|(mapped, p)| (mapped.clone().into(), p.as_local()))
|
|
||||||
.or_else(|| self.tiling_layer.element_under(location, overview))
|
.or_else(|| self.tiling_layer.element_under(location, overview))
|
||||||
.map(|(m, p)| (m, p.to_global(&self.output)))
|
.map(|(m, p)| (m, p.to_global(&self.output)))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue