input: deal with spurious X11 LeaveNotify events

If the mpv window is unfocus, clicking on the OSC should focus the
window (done by the window manager) and allow interaction with the OSC.
But somehow X sends a spurious LeaveNotify event, immediately followed
by an EnterNotify event. This happens at least with IceWM. The result is
that the OSC will disappear (due to receiving MOUSE_LEAVE). The OSC will
stay invisible, because EnterNotify isn't handled, and there's nothing
that could make the OSC appear again.

Solve this by handling EnterNotify. We cause a redundant MOUSE_MOVE
event to be sent, which triggers the code to make the OSC visible. We
have to remove the code from input.c, which ignores redundant mouse move
events.

Since the code ignoring redundant mouse move events is still needed on
Windows, move that code to w32_common.c. The need for this is documented
in the code, also see commit 03fd2fe. (The original idea was to save
some code by having this code in the core, but now it turns out that
this didn't quite work out.)
This commit is contained in:
wm4 2013-08-31 21:21:05 +02:00
parent 11d2f723d5
commit 0c7978cf9c
4 changed files with 21 additions and 10 deletions

View File

@ -1647,12 +1647,6 @@ void mp_input_put_axis(struct input_ctx *ictx, int direction, double value)
void mp_input_set_mouse_pos(struct input_ctx *ictx, int x, int y) void mp_input_set_mouse_pos(struct input_ctx *ictx, int x, int y)
{ {
input_lock(ictx); input_lock(ictx);
// we're already there
if (ictx->mouse_vo_x == x && ictx->mouse_vo_y == y) {
input_unlock(ictx);
return;
}
mp_msg(MSGT_INPUT, MSGL_DBG2, "input: mouse move %d/%d\n", x, y); mp_msg(MSGT_INPUT, MSGL_DBG2, "input: mouse move %d/%d\n", x, y);
ictx->mouse_event_counter++; ictx->mouse_event_counter++;

View File

@ -231,11 +231,21 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
w32->tracking = FALSE; w32->tracking = FALSE;
mp_input_put_key(vo->input_ctx, MP_KEY_MOUSE_LEAVE); mp_input_put_key(vo->input_ctx, MP_KEY_MOUSE_LEAVE);
break; break;
case WM_MOUSEMOVE: case WM_MOUSEMOVE: {
if (!w32->tracking) if (!w32->tracking)
w32->tracking = TrackMouseEvent(&w32->trackEvent);; w32->tracking = TrackMouseEvent(&w32->trackEvent);
vo_mouse_movement(vo, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); // Windows can send spurious mouse events, which would make the mpv
// core unhide the mouse cursor on completely unrelated events. See:
// https://blogs.msdn.com/b/oldnewthing/archive/2003/10/01/55108.aspx
int x = GET_X_LPARAM(lParam);
int y = GET_Y_LPARAM(lParam);
if (x != w32->mouse_x || y != w32->mouse_y) {
w32->mouse_x = x;
w32->mouse_y = y;
vo_mouse_movement(vo, x, y);
}
break; break;
}
case WM_LBUTTONDOWN: case WM_LBUTTONDOWN:
mouse_button = MP_MOUSE_BTN0 | MP_KEY_STATE_DOWN; mouse_button = MP_MOUSE_BTN0 | MP_KEY_STATE_DOWN;
break; break;

View File

@ -52,6 +52,9 @@ struct vo_w32_state {
BOOL tracking; BOOL tracking;
TRACKMOUSEEVENT trackEvent; TRACKMOUSEEVENT trackEvent;
int mouse_x;
int mouse_y;
}; };
struct vo; struct vo;

View File

@ -769,6 +769,9 @@ int vo_x11_check_events(struct vo *vo)
case MotionNotify: case MotionNotify:
vo_mouse_movement(vo, Event.xmotion.x, Event.xmotion.y); vo_mouse_movement(vo, Event.xmotion.x, Event.xmotion.y);
break; break;
case EnterNotify:
vo_mouse_movement(vo, Event.xcrossing.x, Event.xcrossing.y);
break;
case LeaveNotify: case LeaveNotify:
mp_input_put_key(vo->input_ctx, MP_KEY_MOUSE_LEAVE); mp_input_put_key(vo->input_ctx, MP_KEY_MOUSE_LEAVE);
break; break;
@ -1007,7 +1010,8 @@ static void vo_x11_map_window(struct vo *vo, int x, int y, int w, int h)
StructureNotifyMask | ExposureMask | StructureNotifyMask | ExposureMask |
KeyPressMask | KeyReleaseMask | KeyPressMask | KeyReleaseMask |
ButtonPressMask | ButtonReleaseMask | ButtonPressMask | ButtonReleaseMask |
PointerMotionMask | LeaveWindowMask); PointerMotionMask | EnterWindowMask |
LeaveWindowMask);
XMapWindow(x11->display, x11->window); XMapWindow(x11->display, x11->window);
vo_x11_clearwindow(vo, x11->window); vo_x11_clearwindow(vo, x11->window);
} }