Keep drag source focused until pointer leaves release window
This commit is contained in:
1 parent
96e1b6ac5a
commit
7b6e592cb4
2 files changed
+67
-5
No files matched your search
+50
-2
@@ -25,6 +25,17 @@ use smithay::{
|
||||
};
|
||||
|
||||
use crate::{Ferese, config::BindingAction};
|
||||
use ferese_layout::WindowId;
|
||||
|
||||
fn hover_blocked_after_drag(blocked: &mut Option<WindowId>, target: Option<WindowId>) -> bool {
|
||||
if let Some(window) = *blocked {
|
||||
if target == Some(window) {
|
||||
return true;
|
||||
}
|
||||
*blocked = None;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
impl Ferese {
|
||||
pub fn process_input_event<I: InputBackend>(&mut self, event: InputEvent<I>) {
|
||||
@@ -279,6 +290,12 @@ impl Ferese {
|
||||
InputEvent::PointerButton { event, .. } => {
|
||||
let pointer = self.seat.get_pointer().expect("seat has a pointer");
|
||||
let serial = SERIAL_COUNTER.next_serial();
|
||||
let released_over_another_window = (event.state() == ButtonState::Released
|
||||
&& pointer.is_grabbed())
|
||||
.then(|| self.window_under_visual(pointer.current_location()))
|
||||
.flatten()
|
||||
.and_then(|window| self.window_ids.get(&window).copied())
|
||||
.filter(|window| Some(*window) != self.focused_window);
|
||||
|
||||
// Native popup_done destroys Iced's window immediately. For
|
||||
// effects-capable shell popups, release input now but defer
|
||||
@@ -337,6 +354,7 @@ impl Ferese {
|
||||
}
|
||||
|
||||
if event.state() == ButtonState::Pressed && !pointer.is_grabbed() {
|
||||
self.hover_focus_blocked = None;
|
||||
self.focus_window_at(pointer.current_location(), serial, true);
|
||||
}
|
||||
|
||||
@@ -350,6 +368,9 @@ impl Ferese {
|
||||
},
|
||||
);
|
||||
pointer.frame(self);
|
||||
if event.state() == ButtonState::Released {
|
||||
self.hover_focus_blocked = released_over_another_window;
|
||||
}
|
||||
}
|
||||
InputEvent::PointerAxis { event, .. } => {
|
||||
let source = event.source();
|
||||
@@ -624,8 +645,19 @@ impl Ferese {
|
||||
{
|
||||
return;
|
||||
}
|
||||
if self.layer_under(position).is_some() {
|
||||
self.hover_focus_blocked = None;
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(window) = self.window_under_visual(position) else {
|
||||
let window = self.window_under_visual(position);
|
||||
let target = window
|
||||
.as_ref()
|
||||
.and_then(|window| self.window_ids.get(window).copied());
|
||||
if hover_blocked_after_drag(&mut self.hover_focus_blocked, target) {
|
||||
return;
|
||||
}
|
||||
let Some(window) = window else {
|
||||
return;
|
||||
};
|
||||
if self.window_ids.get(&window).copied() == self.focused_window {
|
||||
@@ -797,7 +829,23 @@ fn overview_escape(symbol: u32, overview_active: bool) -> bool {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{emergency_shortcut_escape, overview_escape, virtual_terminal};
|
||||
use super::{
|
||||
WindowId, emergency_shortcut_escape, hover_blocked_after_drag, overview_escape,
|
||||
virtual_terminal,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn drag_release_does_not_turn_motion_inside_the_same_window_into_hover_focus() {
|
||||
let selected = WindowId(1);
|
||||
let other = WindowId(2);
|
||||
let mut blocked = Some(other);
|
||||
|
||||
assert!(hover_blocked_after_drag(&mut blocked, Some(other)));
|
||||
assert!(hover_blocked_after_drag(&mut blocked, Some(other)));
|
||||
assert!(!hover_blocked_after_drag(&mut blocked, Some(selected)));
|
||||
assert_eq!(blocked, None);
|
||||
assert!(!hover_blocked_after_drag(&mut blocked, Some(other)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn escape_closes_only_an_active_overview() {
|
||||
|
||||
+17
-3
@@ -147,6 +147,7 @@ pub struct Ferese {
|
||||
viewport_coupled_widths: HashMap<WindowId, (WorkspaceId, AnimatedValue)>,
|
||||
pending_column_width_cycles: HashSet<WindowId>,
|
||||
pub focused_window: Option<WindowId>,
|
||||
pub(crate) hover_focus_blocked: Option<WindowId>,
|
||||
column_width_presets: Vec<ColumnWidth>,
|
||||
gap_config: GapConfig,
|
||||
pub(crate) input_settings: InputSettings,
|
||||
@@ -360,6 +361,7 @@ impl Ferese {
|
||||
viewport_coupled_widths: HashMap::new(),
|
||||
pending_column_width_cycles: HashSet::new(),
|
||||
focused_window: None,
|
||||
hover_focus_blocked: None,
|
||||
column_width_presets: config.column_width_presets,
|
||||
gap_config: config.gap_config,
|
||||
input_settings: config.input_settings,
|
||||
@@ -862,11 +864,23 @@ impl Ferese {
|
||||
|
||||
let visual = self.presented_window_rect(*id)?;
|
||||
let caption_height = if overview_active { 34.0 } else { 0.0 };
|
||||
(position.x >= visual.x
|
||||
let inside_visual = position.x >= visual.x
|
||||
&& position.y >= visual.y
|
||||
&& position.x < visual.x + visual.width
|
||||
&& position.y < visual.y + visual.height + caption_height)
|
||||
.then_some(window.clone())
|
||||
&& position.y < visual.y + visual.height + caption_height;
|
||||
if !inside_visual {
|
||||
return None;
|
||||
}
|
||||
|
||||
if !overview_active {
|
||||
let (source_x, source_y) =
|
||||
self.inverse_presented_window_point(*id, position.x, position.y)?;
|
||||
let source_point =
|
||||
Point::from((source_x, source_y)) + window.geometry().loc.to_f64();
|
||||
window.surface_under(source_point, WindowSurfaceType::ALL)?;
|
||||
}
|
||||
|
||||
Some(window.clone())
|
||||
};
|
||||
|
||||
if overview_active {
|
||||
|
||||
Reference in new issue
Block a user