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 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 {
|
impl Ferese {
|
||||||
pub fn process_input_event<I: InputBackend>(&mut self, event: InputEvent<I>) {
|
pub fn process_input_event<I: InputBackend>(&mut self, event: InputEvent<I>) {
|
||||||
@@ -279,6 +290,12 @@ impl Ferese {
|
|||||||
InputEvent::PointerButton { event, .. } => {
|
InputEvent::PointerButton { event, .. } => {
|
||||||
let pointer = self.seat.get_pointer().expect("seat has a pointer");
|
let pointer = self.seat.get_pointer().expect("seat has a pointer");
|
||||||
let serial = SERIAL_COUNTER.next_serial();
|
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
|
// Native popup_done destroys Iced's window immediately. For
|
||||||
// effects-capable shell popups, release input now but defer
|
// effects-capable shell popups, release input now but defer
|
||||||
@@ -337,6 +354,7 @@ impl Ferese {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if event.state() == ButtonState::Pressed && !pointer.is_grabbed() {
|
if event.state() == ButtonState::Pressed && !pointer.is_grabbed() {
|
||||||
|
self.hover_focus_blocked = None;
|
||||||
self.focus_window_at(pointer.current_location(), serial, true);
|
self.focus_window_at(pointer.current_location(), serial, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,6 +368,9 @@ impl Ferese {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
pointer.frame(self);
|
pointer.frame(self);
|
||||||
|
if event.state() == ButtonState::Released {
|
||||||
|
self.hover_focus_blocked = released_over_another_window;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
InputEvent::PointerAxis { event, .. } => {
|
InputEvent::PointerAxis { event, .. } => {
|
||||||
let source = event.source();
|
let source = event.source();
|
||||||
@@ -624,8 +645,19 @@ impl Ferese {
|
|||||||
{
|
{
|
||||||
return;
|
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;
|
return;
|
||||||
};
|
};
|
||||||
if self.window_ids.get(&window).copied() == self.focused_window {
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
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]
|
#[test]
|
||||||
fn escape_closes_only_an_active_overview() {
|
fn escape_closes_only_an_active_overview() {
|
||||||
|
|||||||
+17
-3
@@ -147,6 +147,7 @@ pub struct Ferese {
|
|||||||
viewport_coupled_widths: HashMap<WindowId, (WorkspaceId, AnimatedValue)>,
|
viewport_coupled_widths: HashMap<WindowId, (WorkspaceId, AnimatedValue)>,
|
||||||
pending_column_width_cycles: HashSet<WindowId>,
|
pending_column_width_cycles: HashSet<WindowId>,
|
||||||
pub focused_window: Option<WindowId>,
|
pub focused_window: Option<WindowId>,
|
||||||
|
pub(crate) hover_focus_blocked: Option<WindowId>,
|
||||||
column_width_presets: Vec<ColumnWidth>,
|
column_width_presets: Vec<ColumnWidth>,
|
||||||
gap_config: GapConfig,
|
gap_config: GapConfig,
|
||||||
pub(crate) input_settings: InputSettings,
|
pub(crate) input_settings: InputSettings,
|
||||||
@@ -360,6 +361,7 @@ impl Ferese {
|
|||||||
viewport_coupled_widths: HashMap::new(),
|
viewport_coupled_widths: HashMap::new(),
|
||||||
pending_column_width_cycles: HashSet::new(),
|
pending_column_width_cycles: HashSet::new(),
|
||||||
focused_window: None,
|
focused_window: None,
|
||||||
|
hover_focus_blocked: None,
|
||||||
column_width_presets: config.column_width_presets,
|
column_width_presets: config.column_width_presets,
|
||||||
gap_config: config.gap_config,
|
gap_config: config.gap_config,
|
||||||
input_settings: config.input_settings,
|
input_settings: config.input_settings,
|
||||||
@@ -862,11 +864,23 @@ impl Ferese {
|
|||||||
|
|
||||||
let visual = self.presented_window_rect(*id)?;
|
let visual = self.presented_window_rect(*id)?;
|
||||||
let caption_height = if overview_active { 34.0 } else { 0.0 };
|
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.y >= visual.y
|
||||||
&& position.x < visual.x + visual.width
|
&& position.x < visual.x + visual.width
|
||||||
&& position.y < visual.y + visual.height + caption_height)
|
&& position.y < visual.y + visual.height + caption_height;
|
||||||
.then_some(window.clone())
|
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 {
|
if overview_active {
|
||||||
|
|||||||
Reference in new issue
Block a user