mirror of
https://github.com/wez/wezterm.git
synced 2024-11-09 22:15:15 +03:00
Detect mouse leaving the window (#1679)
* Detect mouse leaving the window * Implement leave * Use new API * Fix mouse leave * Fix mouse leave on Wayland * Mouse leave on X11 * Detect mouse leaving window on macOS * Fix example refs: #1434
This commit is contained in:
parent
3b05dac0c6
commit
aaad2be606
@ -837,6 +837,10 @@ impl TermWindow {
|
||||
self.mouse_event_impl(event, window);
|
||||
Ok(true)
|
||||
}
|
||||
WindowEvent::MouseLeave => {
|
||||
self.mouse_leave_impl(window);
|
||||
Ok(true)
|
||||
}
|
||||
WindowEvent::Resized {
|
||||
dimensions,
|
||||
window_state,
|
||||
|
@ -199,6 +199,11 @@ impl super::TermWindow {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mouse_leave_impl(&mut self, context: &dyn WindowOps) {
|
||||
self.current_mouse_event = None;
|
||||
context.invalidate();
|
||||
}
|
||||
|
||||
fn drag_split(
|
||||
&mut self,
|
||||
mut item: UIItem,
|
||||
|
@ -80,7 +80,8 @@ impl MyWindow {
|
||||
WindowEvent::AppearanceChanged(_)
|
||||
| WindowEvent::AdviseDeadKeyStatus(_)
|
||||
| WindowEvent::Notification(_)
|
||||
| WindowEvent::FocusChanged(_) => {}
|
||||
| WindowEvent::FocusChanged(_)
|
||||
| WindowEvent::MouseLeave => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -168,6 +168,7 @@ pub enum WindowEvent {
|
||||
KeyEvent(KeyEvent),
|
||||
|
||||
MouseEvent(MouseEvent),
|
||||
MouseLeave,
|
||||
|
||||
AppearanceChanged(Appearance),
|
||||
|
||||
|
@ -414,6 +414,7 @@ impl Window {
|
||||
screen_changed: false,
|
||||
gl_context_pair: None,
|
||||
text_cursor_position: Rect::new(Point::new(0, 0), Size::new(0, 0)),
|
||||
tracking_rect_tag: 0,
|
||||
hscroll_remainder: 0.,
|
||||
vscroll_remainder: 0.,
|
||||
last_wheel: Instant::now(),
|
||||
@ -1045,6 +1046,7 @@ struct Inner {
|
||||
screen_changed: bool,
|
||||
gl_context_pair: Option<GlContextPair>,
|
||||
text_cursor_position: Rect,
|
||||
tracking_rect_tag: NSInteger,
|
||||
hscroll_remainder: f64,
|
||||
vscroll_remainder: f64,
|
||||
last_wheel: Instant,
|
||||
@ -1679,6 +1681,35 @@ impl WindowView {
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn update_tracking_areas(this: &mut Object, _sel: Sel) {
|
||||
let frame = unsafe { NSView::frame(this as *mut _) };
|
||||
|
||||
if let Some(this) = Self::get_this(this) {
|
||||
let mut inner = this.inner.borrow_mut();
|
||||
if let Some(ref view) = inner.view_id {
|
||||
let view = view.load();
|
||||
if view.is_null() {
|
||||
return;
|
||||
}
|
||||
|
||||
let tag = inner.tracking_rect_tag;
|
||||
if tag != 0 {
|
||||
unsafe {
|
||||
let () = msg_send![*view, removeTrackingRect: tag];
|
||||
}
|
||||
}
|
||||
|
||||
let rect = NSRect::new(
|
||||
NSPoint::new(0.0, 0.0),
|
||||
NSSize::new(frame.size.width, frame.size.height),
|
||||
);
|
||||
inner.tracking_rect_tag = unsafe {
|
||||
msg_send![*view, addTrackingRect: rect owner: *view userData: nil assumeInside: NO]
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn window_should_close(this: &mut Object, _sel: Sel, _id: id) -> BOOL {
|
||||
unsafe {
|
||||
let () = msg_send![this, setNeedsDisplay: YES];
|
||||
@ -1881,6 +1912,16 @@ impl WindowView {
|
||||
Self::mouse_common(this, nsevent, MouseEventKind::Move);
|
||||
}
|
||||
|
||||
extern "C" fn mouse_exited(this: &mut Object, _sel: Sel, _nsevent: id) {
|
||||
if let Some(myself) = Self::get_this(this) {
|
||||
myself
|
||||
.inner
|
||||
.borrow_mut()
|
||||
.events
|
||||
.dispatch(WindowEvent::MouseLeave);
|
||||
}
|
||||
}
|
||||
|
||||
fn key_common(this: &mut Object, nsevent: id, key_is_down: bool) {
|
||||
let is_a_repeat = unsafe { nsevent.isARepeat() == YES };
|
||||
let chars = unsafe { nsstring_to_str(nsevent.characters()) };
|
||||
@ -2443,6 +2484,10 @@ impl WindowView {
|
||||
sel!(scrollWheel:),
|
||||
Self::scroll_wheel as extern "C" fn(&mut Object, Sel, id),
|
||||
);
|
||||
cls.add_method(
|
||||
sel!(mouseExited:),
|
||||
Self::mouse_exited as extern "C" fn(&mut Object, Sel, id),
|
||||
);
|
||||
|
||||
cls.add_method(
|
||||
sel!(keyDown:),
|
||||
@ -2468,6 +2513,11 @@ impl WindowView {
|
||||
Self::view_did_change_effective_appearance as extern "C" fn(&mut Object, Sel),
|
||||
);
|
||||
|
||||
cls.add_method(
|
||||
sel!(updateTrackingAreas),
|
||||
Self::update_tracking_areas as extern "C" fn(&mut Object, Sel),
|
||||
);
|
||||
|
||||
// NSTextInputClient
|
||||
|
||||
cls.add_method(
|
||||
|
@ -104,6 +104,7 @@ pub struct PendingMouse {
|
||||
surface_coords: Option<(f64, f64)>,
|
||||
button: Vec<(MousePress, ButtonState)>,
|
||||
scroll: Option<(f64, f64)>,
|
||||
in_window: bool,
|
||||
}
|
||||
|
||||
impl PendingMouse {
|
||||
@ -114,6 +115,7 @@ impl PendingMouse {
|
||||
button: vec![],
|
||||
scroll: None,
|
||||
surface_coords: None,
|
||||
in_window: false,
|
||||
}))
|
||||
}
|
||||
|
||||
@ -126,8 +128,15 @@ impl PendingMouse {
|
||||
.lock()
|
||||
.unwrap()
|
||||
.update_last_serial(serial);
|
||||
self.in_window = true;
|
||||
false
|
||||
}
|
||||
PointerEvent::Leave { .. } => {
|
||||
let changed = self.in_window;
|
||||
self.surface_coords = None;
|
||||
self.in_window = false;
|
||||
changed
|
||||
}
|
||||
PointerEvent::Motion {
|
||||
surface_x,
|
||||
surface_y,
|
||||
@ -204,6 +213,10 @@ impl PendingMouse {
|
||||
pub fn scroll(pending: &Arc<Mutex<Self>>) -> Option<(f64, f64)> {
|
||||
pending.lock().unwrap().scroll.take()
|
||||
}
|
||||
|
||||
pub fn in_window(pending: &Arc<Mutex<Self>>) -> bool {
|
||||
pending.lock().unwrap().in_window
|
||||
}
|
||||
}
|
||||
|
||||
impl PointerDispatcher {
|
||||
|
@ -537,6 +537,11 @@ impl WaylandWindowInner {
|
||||
self.events.dispatch(WindowEvent::MouseEvent(event));
|
||||
}
|
||||
}
|
||||
|
||||
if !PendingMouse::in_window(&pending_mouse) {
|
||||
self.events.dispatch(WindowEvent::MouseLeave);
|
||||
self.refresh_frame();
|
||||
}
|
||||
}
|
||||
|
||||
fn get_dpi_factor(&self) -> i32 {
|
||||
|
@ -61,6 +61,7 @@ pub(crate) struct WindowInner {
|
||||
in_size_move: bool,
|
||||
dead_pending: Option<(Modifiers, u32)>,
|
||||
saved_placement: Option<WINDOWPLACEMENT>,
|
||||
track_mouse_leave: bool,
|
||||
|
||||
keyboard_info: KeyboardLayoutInfo,
|
||||
appearance: Appearance,
|
||||
@ -415,6 +416,7 @@ impl Window {
|
||||
in_size_move: false,
|
||||
dead_pending: None,
|
||||
saved_placement: None,
|
||||
track_mouse_leave: false,
|
||||
config: config.clone(),
|
||||
}));
|
||||
|
||||
@ -1133,6 +1135,21 @@ unsafe fn mouse_button(hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM) ->
|
||||
|
||||
unsafe fn mouse_move(hwnd: HWND, _msg: UINT, wparam: WPARAM, lparam: LPARAM) -> Option<LRESULT> {
|
||||
if let Some(inner) = rc_from_hwnd(hwnd) {
|
||||
let mut inner = inner.borrow_mut();
|
||||
|
||||
if !inner.track_mouse_leave {
|
||||
inner.track_mouse_leave = true;
|
||||
|
||||
let mut trk = TRACKMOUSEEVENT {
|
||||
cbSize: std::mem::size_of::<TRACKMOUSEEVENT>() as u32,
|
||||
dwFlags: TME_LEAVE,
|
||||
hwndTrack: hwnd,
|
||||
dwHoverTime: 0,
|
||||
};
|
||||
|
||||
inner.track_mouse_leave = TrackMouseEvent(&mut trk) == winapi::shared::minwindef::TRUE;
|
||||
}
|
||||
|
||||
let (modifiers, mouse_buttons) = mods_and_buttons(wparam);
|
||||
let coords = mouse_coords(lparam);
|
||||
let event = MouseEvent {
|
||||
@ -1143,10 +1160,20 @@ unsafe fn mouse_move(hwnd: HWND, _msg: UINT, wparam: WPARAM, lparam: LPARAM) ->
|
||||
modifiers,
|
||||
};
|
||||
|
||||
inner
|
||||
.borrow_mut()
|
||||
.events
|
||||
.dispatch(WindowEvent::MouseEvent(event));
|
||||
inner.events.dispatch(WindowEvent::MouseEvent(event));
|
||||
Some(0)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn mouse_leave(hwnd: HWND, _msg: UINT, _wparam: WPARAM, _lparam: LPARAM) -> Option<LRESULT> {
|
||||
if let Some(inner) = rc_from_hwnd(hwnd) {
|
||||
let mut inner = inner.borrow_mut();
|
||||
|
||||
inner.track_mouse_leave = false;
|
||||
inner.events.dispatch(WindowEvent::MouseLeave);
|
||||
|
||||
Some(0)
|
||||
} else {
|
||||
None
|
||||
@ -2000,6 +2027,7 @@ unsafe fn do_wnd_proc(hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM) ->
|
||||
WM_SETTINGCHANGE => apply_theme(hwnd),
|
||||
WM_IME_COMPOSITION => ime_composition(hwnd, msg, wparam, lparam),
|
||||
WM_MOUSEMOVE => mouse_move(hwnd, msg, wparam, lparam),
|
||||
WM_MOUSELEAVE => mouse_leave(hwnd, msg, wparam, lparam),
|
||||
WM_MOUSEHWHEEL | WM_MOUSEWHEEL => mouse_wheel(hwnd, msg, wparam, lparam),
|
||||
WM_LBUTTONDBLCLK | WM_RBUTTONDBLCLK | WM_MBUTTONDBLCLK | WM_LBUTTONDOWN | WM_LBUTTONUP
|
||||
| WM_RBUTTONDOWN | WM_RBUTTONUP | WM_MBUTTONDOWN | WM_MBUTTONUP => {
|
||||
|
@ -138,6 +138,10 @@ fn window_id_from_event(event: &xcb::GenericEvent) -> Option<xcb::xproto::Window
|
||||
let msg: &xcb::FocusOutEvent = unsafe { xcb::cast_event(event) };
|
||||
Some(msg.event())
|
||||
}
|
||||
xcb::LEAVE_NOTIFY => {
|
||||
let msg: &xcb::LeaveNotifyEvent = unsafe { xcb::cast_event(event) };
|
||||
Some(msg.event())
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -414,6 +414,9 @@ impl XWindowInner {
|
||||
log::trace!("Calling focus_change(false)");
|
||||
self.events.dispatch(WindowEvent::FocusChanged(false));
|
||||
}
|
||||
xcb::LEAVE_NOTIFY => {
|
||||
self.events.dispatch(WindowEvent::MouseLeave);
|
||||
}
|
||||
_ => {
|
||||
eprintln!("unhandled: {:x}", r);
|
||||
}
|
||||
@ -825,6 +828,7 @@ impl XWindow {
|
||||
| xcb::EVENT_MASK_BUTTON_PRESS
|
||||
| xcb::EVENT_MASK_BUTTON_RELEASE
|
||||
| xcb::EVENT_MASK_POINTER_MOTION
|
||||
| xcb::EVENT_MASK_LEAVE_WINDOW
|
||||
| xcb::EVENT_MASK_BUTTON_MOTION
|
||||
| xcb::EVENT_MASK_KEY_RELEASE
|
||||
| xcb::EVENT_MASK_PROPERTY_CHANGE
|
||||
|
Loading…
Reference in New Issue
Block a user