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
|
||||
.common
|
||||
.shell
|
||||
.active_space(¤t_output)
|
||||
.tiling_layer
|
||||
.stacking_indicator();
|
||||
|
||||
if indicator_location.is_some() != grab_state.stacking_indicator.is_some() {
|
||||
grab_state.stacking_indicator = indicator_location.map(|geo| {
|
||||
let element = stack_hover(
|
||||
state.common.event_loop_handle.clone(),
|
||||
geo.size.as_logical(),
|
||||
state.common.theme.clone(),
|
||||
let indicator_location = state
|
||||
.common
|
||||
.shell
|
||||
.stacking_indicator(¤t_output, self.previous);
|
||||
if indicator_location.is_some() != grab_state.stacking_indicator.is_some() {
|
||||
grab_state.stacking_indicator = indicator_location.map(|geo| {
|
||||
let element = stack_hover(
|
||||
state.common.event_loop_handle.clone(),
|
||||
geo.size.as_logical(),
|
||||
state.common.theme.clone(),
|
||||
);
|
||||
for output in &self.window_outputs {
|
||||
element.output_enter(
|
||||
output,
|
||||
Rectangle::from_loc_and_size(
|
||||
(0, 0),
|
||||
output.geometry().size.as_logical(),
|
||||
),
|
||||
);
|
||||
for output in &self.window_outputs {
|
||||
element.output_enter(
|
||||
output,
|
||||
Rectangle::from_loc_and_size(
|
||||
(0, 0),
|
||||
output.geometry().size.as_logical(),
|
||||
),
|
||||
);
|
||||
}
|
||||
(element, geo.loc.as_logical())
|
||||
});
|
||||
}
|
||||
}
|
||||
(element, geo.loc.as_logical())
|
||||
});
|
||||
}
|
||||
}
|
||||
drop(borrow);
|
||||
|
|
@ -566,13 +561,11 @@ impl Drop for MoveGrab {
|
|||
grab_state.window.geometry().size.as_global(),
|
||||
));
|
||||
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,
|
||||
Some(window_location.to_local(&workspace.output)),
|
||||
None,
|
||||
window_location.to_local(&workspace.output),
|
||||
);
|
||||
|
||||
Some((window.clone(), window_location))
|
||||
Some((window, location.to_global(&output)))
|
||||
}
|
||||
ManagedLayer::Sticky => {
|
||||
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(),
|
||||
));
|
||||
let set = state.common.shell.workspaces.sets.get_mut(&output).unwrap();
|
||||
set.sticky_layer.map_internal(
|
||||
grab_state.window,
|
||||
Some(window_location.to_local(&output)),
|
||||
None,
|
||||
);
|
||||
let (window, location) = set
|
||||
.sticky_layer
|
||||
.drop_window(grab_state.window, window_location.to_local(&output));
|
||||
|
||||
Some((window.clone(), window_location))
|
||||
Some((window, location.to_global(&output)))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -27,11 +27,14 @@ use crate::{
|
|||
shell::{
|
||||
element::{
|
||||
resize_indicator::ResizeIndicator,
|
||||
stack::{CosmicStackRenderElement, MoveResult as StackMoveResult},
|
||||
stack::{CosmicStackRenderElement, MoveResult as StackMoveResult, TAB_HEIGHT},
|
||||
window::CosmicWindowRenderElement,
|
||||
CosmicMapped, CosmicMappedRenderElement, CosmicWindow,
|
||||
},
|
||||
focus::{target::KeyboardFocusTarget, FocusStackMut},
|
||||
focus::{
|
||||
target::{KeyboardFocusTarget, PointerFocusTarget},
|
||||
FocusStackMut,
|
||||
},
|
||||
grabs::{ReleaseMode, ResizeEdge},
|
||||
CosmicSurface, Direction, MoveResult, ResizeDirection, ResizeMode,
|
||||
},
|
||||
|
|
@ -50,6 +53,7 @@ pub struct FloatingLayout {
|
|||
pub(crate) space: Space<CosmicMapped>,
|
||||
spawn_order: Vec<CosmicMapped>,
|
||||
tiling_animations: HashMap<CosmicMapped, (Instant, Rectangle<i32, Local>)>,
|
||||
hovered_stack: Option<(CosmicMapped, Rectangle<i32, Local>)>,
|
||||
dirty: AtomicBool,
|
||||
pub theme: cosmic::Theme,
|
||||
}
|
||||
|
|
@ -449,10 +453,53 @@ impl FloatingLayout {
|
|||
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>> {
|
||||
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(
|
||||
&mut self,
|
||||
mapped: &CosmicMapped,
|
||||
|
|
|
|||
|
|
@ -1510,6 +1510,25 @@ impl Shell {
|
|||
(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) {
|
||||
#[cfg(feature = "debug")]
|
||||
puffin::profile_function!();
|
||||
|
|
|
|||
|
|
@ -424,9 +424,7 @@ impl Workspace {
|
|||
) -> Option<(PointerFocusTarget, Point<i32, Global>)> {
|
||||
let location = location.to_local(&self.output);
|
||||
self.floating_layer
|
||||
.space
|
||||
.element_under(location.as_logical())
|
||||
.map(|(mapped, p)| (mapped.clone().into(), p.as_local()))
|
||||
.element_under(location)
|
||||
.or_else(|| self.tiling_layer.element_under(location, overview))
|
||||
.map(|(m, p)| (m, p.to_global(&self.output)))
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue