diff --git a/crates/drag_and_drop/src/drag_and_drop.rs b/crates/drag_and_drop/src/drag_and_drop.rs index 6365b423d5..5e4dbb4684 100644 --- a/crates/drag_and_drop/src/drag_and_drop.rs +++ b/crates/drag_and_drop/src/drag_and_drop.rs @@ -9,6 +9,7 @@ use gpui::{ }; struct State { + window_id: usize, position: Vector2F, region_offset: Vector2F, payload: Rc, @@ -18,6 +19,7 @@ struct State { impl Clone for State { fn clone(&self) -> Self { Self { + window_id: self.window_id.clone(), position: self.position.clone(), region_offset: self.region_offset.clone(), payload: self.payload.clone(), @@ -46,11 +48,18 @@ impl DragAndDrop { } } - pub fn currently_dragged(&self) -> Option<(Vector2F, Rc)> { + pub fn currently_dragged(&self, window_id: usize) -> Option<(Vector2F, Rc)> { self.currently_dragged.as_ref().and_then( |State { - position, payload, .. + position, + payload, + window_id: window_dragged_from, + .. }| { + if &window_id != window_dragged_from { + return None; + } + payload .clone() .downcast::() @@ -66,6 +75,7 @@ impl DragAndDrop { cx: &mut EventContext, render: Rc) -> ElementBox>, ) { + let window_id = cx.window_id(); cx.update_global::(|this, cx| { let region_offset = if let Some(previous_state) = this.currently_dragged.as_ref() { previous_state.region_offset @@ -74,6 +84,7 @@ impl DragAndDrop { }; this.currently_dragged = Some(State { + window_id, region_offset, position: event.position, payload, @@ -91,34 +102,46 @@ impl DragAndDrop { pub fn render(cx: &mut RenderContext) -> Option { let currently_dragged = cx.global::().currently_dragged.clone(); - currently_dragged.map( + currently_dragged.and_then( |State { + window_id, region_offset, position, payload, render, }| { + if cx.window_id() != window_id { + return None; + } + let position = position + region_offset; - MouseEventHandler::new::(0, cx, |_, cx| { - Container::new(render(payload, cx)) - .with_margin_left(position.x()) - .with_margin_top(position.y()) - .aligned() - .top() - .left() - .boxed() - }) - .with_cursor_style(CursorStyle::Arrow) - .on_up(MouseButton::Left, |_, cx| { - cx.defer(|cx| { - cx.update_global::(|this, _| this.currently_dragged.take()); - }); - cx.propogate_event(); - }) - // Don't block hover events or invalidations - .with_hoverable(false) - .boxed() + Some( + MouseEventHandler::new::(0, cx, |_, cx| { + Container::new(render(payload, cx)) + .with_margin_left(position.x()) + .with_margin_top(position.y()) + .aligned() + .top() + .left() + .boxed() + }) + .with_cursor_style(CursorStyle::Arrow) + .on_up(MouseButton::Left, |_, cx| { + cx.defer(|cx| { + cx.update_global::(|this, _| this.currently_dragged.take()); + }); + cx.propogate_event(); + }) + .on_up_out(MouseButton::Left, |_, cx| { + cx.defer(|cx| { + cx.update_global::(|this, _| this.currently_dragged.take()); + }); + }) + // Don't block hover events or invalidations + .with_hoverable(false) + .boxed(), + ) }, ) } diff --git a/crates/gpui/src/platform/event.rs b/crates/gpui/src/platform/event.rs index b7631aac4b..3e0fe4a53a 100644 --- a/crates/gpui/src/platform/event.rs +++ b/crates/gpui/src/platform/event.rs @@ -89,6 +89,20 @@ pub struct MouseMovedEvent { pub shift: bool, } +impl MouseMovedEvent { + pub fn to_button_event(&self, button: MouseButton) -> MouseButtonEvent { + MouseButtonEvent { + position: self.position, + button: self.pressed_button.unwrap_or(button), + ctrl: self.ctrl, + alt: self.alt, + shift: self.shift, + cmd: self.cmd, + click_count: 0, + } + } +} + #[derive(Clone, Debug)] pub enum Event { KeyDown(KeyDownEvent), diff --git a/crates/gpui/src/presenter.rs b/crates/gpui/src/presenter.rs index c1de513aa3..cad8b3519f 100644 --- a/crates/gpui/src/presenter.rs +++ b/crates/gpui/src/presenter.rs @@ -310,7 +310,23 @@ impl Presenter { prev_mouse_position: self.mouse_position, platform_event: e.clone(), })); + } else if let Some(clicked_button) = self.clicked_button { + // Mouse up event happened outside the current window. Simulate mouse up button event + let button_event = e.to_button_event(clicked_button); + events_to_send.push(MouseRegionEvent::Up(UpRegionEvent { + region: Default::default(), + platform_event: button_event.clone(), + })); + events_to_send.push(MouseRegionEvent::UpOut(UpOutRegionEvent { + region: Default::default(), + platform_event: button_event.clone(), + })); + events_to_send.push(MouseRegionEvent::Click(ClickRegionEvent { + region: Default::default(), + platform_event: button_event.clone(), + })); } + events_to_send.push(MouseRegionEvent::Move(MoveRegionEvent { region: Default::default(), platform_event: e.clone(), diff --git a/crates/workspace/src/pane.rs b/crates/workspace/src/pane.rs index f88b723bdf..d1ee6530ed 100644 --- a/crates/workspace/src/pane.rs +++ b/crates/workspace/src/pane.rs @@ -1256,7 +1256,7 @@ impl Pane { fn handle_dropped_item(pane: &WeakViewHandle, index: usize, cx: &mut EventContext) { if let Some((_, dragged_item)) = cx .global::>() - .currently_dragged::() + .currently_dragged::(cx.window_id) { cx.dispatch_action(MoveItem { item_id: dragged_item.item.id(), @@ -1277,7 +1277,7 @@ impl Pane { if hovered && cx .global::>() - .currently_dragged::() + .currently_dragged::(cx.window_id()) .is_some() { Some(theme.workspace.tab_bar.drop_target_overlay_color)