diff options
-rw-r--r-- | DOCS/man/input.rst | 3 | ||||
-rw-r--r-- | player/command.c | 17 | ||||
-rw-r--r-- | player/command.h | 1 | ||||
-rw-r--r-- | player/playloop.c | 2 | ||||
-rw-r--r-- | video/out/vo.h | 5 | ||||
-rw-r--r-- | video/out/wayland_common.c | 20 | ||||
-rw-r--r-- | video/out/wayland_common.h | 3 | ||||
-rw-r--r-- | video/out/x11_common.c | 6 |
8 files changed, 56 insertions, 1 deletions
diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst index 739f5f1022..18027ce17a 100644 --- a/DOCS/man/input.rst +++ b/DOCS/man/input.rst @@ -2439,6 +2439,9 @@ Property list since setting the option, and the window size was not restricted in other ways. The property is unavailable if no video is active. +``focused`` + Whether the window has focus. Currently works only on X11 and Wayland. + ``display-names`` Names of the displays that the mpv window covers. On X11, these are the xrandr names (LVDS1, HDMI1, DP1, VGA1, etc.). On Windows, these diff --git a/player/command.c b/player/command.c index 5b9e8bcbb4..723996d9be 100644 --- a/player/command.c +++ b/player/command.c @@ -2410,6 +2410,21 @@ static int mp_property_hidpi_scale(void *ctx, struct m_property *prop, return m_property_double_ro(action, arg, cmd->cached_window_scale); } +static int mp_property_focused(void *ctx, struct m_property *prop, + int action, void *arg) +{ + MPContext *mpctx = ctx; + struct vo *vo = mpctx->video_out; + if (!vo) + return M_PROPERTY_UNAVAILABLE; + + bool focused; + if (vo_control(vo, VOCTRL_GET_FOCUSED, &focused) < 1) + return M_PROPERTY_UNAVAILABLE; + + return m_property_flag_ro(action, arg, focused); +} + static int mp_property_display_names(void *ctx, struct m_property *prop, int action, void *arg) { @@ -3593,6 +3608,7 @@ static const struct m_property mp_properties_base[] = { PROPERTY_BITRATE("audio-bitrate", false, STREAM_AUDIO), PROPERTY_BITRATE("sub-bitrate", false, STREAM_SUB), + {"focused", mp_property_focused}, {"display-names", mp_property_display_names}, {"display-fps", mp_property_display_fps}, {"estimated-display-fps", mp_property_estimated_display_fps}, @@ -3676,6 +3692,7 @@ static const char *const *const mp_event_property_change[] = { "osd-par", "osd-dimensions"), E(MP_EVENT_WIN_STATE, "display-names", "display-fps"), E(MP_EVENT_WIN_STATE2, "display-hidpi-scale"), + E(MP_EVENT_FOCUS, "focused"), E(MP_EVENT_CHANGE_PLAYLIST, "playlist", "playlist-pos", "playlist-pos-1", "playlist-count", "playlist/count", "playlist-current-pos", "playlist-playing-pos"), diff --git a/player/command.h b/player/command.h index 17e0726b0b..c47ed40f1d 100644 --- a/player/command.h +++ b/player/command.h @@ -98,6 +98,7 @@ enum { MP_EVENT_WIN_RESIZE, MP_EVENT_WIN_STATE, MP_EVENT_WIN_STATE2, + MP_EVENT_FOCUS, MP_EVENT_CHANGE_PLAYLIST, MP_EVENT_CORE_IDLE, MP_EVENT_DURATION_UPDATE, diff --git a/player/playloop.c b/player/playloop.c index ddd3f6dbdb..44ccb4819b 100644 --- a/player/playloop.c +++ b/player/playloop.c @@ -844,6 +844,8 @@ static void handle_vo_events(struct MPContext *mpctx) mp_notify(mpctx, MP_EVENT_WIN_STATE, NULL); if (events & VO_EVENT_DPI) mp_notify(mpctx, MP_EVENT_WIN_STATE2, NULL); + if (events & VO_EVENT_FOCUS) + mp_notify(mpctx, MP_EVENT_FOCUS, NULL); } static void handle_sstep(struct MPContext *mpctx) diff --git a/video/out/vo.h b/video/out/vo.h index 1b7a239798..5deb99a6f1 100644 --- a/video/out/vo.h +++ b/video/out/vo.h @@ -48,10 +48,11 @@ enum { // Special thing for encode mode (vo_driver.initially_blocked). // Part of VO_EVENTS_USER to make vo_is_ready_for_frame() work properly. VO_EVENT_INITIAL_UNBLOCK = 1 << 7, + VO_EVENT_FOCUS = 1 << 8, // Set of events the player core may be interested in. VO_EVENTS_USER = VO_EVENT_RESIZE | VO_EVENT_WIN_STATE | VO_EVENT_DPI | - VO_EVENT_INITIAL_UNBLOCK, + VO_EVENT_INITIAL_UNBLOCK | VO_EVENT_FOCUS, }; enum mp_voctrl { @@ -99,6 +100,8 @@ enum mp_voctrl { VOCTRL_GET_UNFS_WINDOW_SIZE, // int[2] (w/h) VOCTRL_SET_UNFS_WINDOW_SIZE, // int[2] (w/h) + VOCTRL_GET_FOCUSED, // bool* + // char *** (NULL terminated array compatible with CONF_TYPE_STRING_LIST) // names for displays the window is on VOCTRL_GET_DISPLAY_NAMES, diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c index a79c8aa8ca..c6c0e342c9 100644 --- a/video/out/wayland_common.c +++ b/video/out/wayland_common.c @@ -447,11 +447,15 @@ static void keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys) { + struct vo_wayland_state *wl = data; + wl->has_keyboard_input = true; } static void keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface) { + struct vo_wayland_state *wl = data; + wl->has_keyboard_input = false; } static bool create_input(struct vo_wayland_state *wl) @@ -951,6 +955,7 @@ static void handle_toplevel_config(void *data, struct xdg_toplevel *toplevel, bool is_maximized = false; bool is_fullscreen = false; + bool is_activated = false; enum xdg_toplevel_state *state; wl_array_for_each(state, states) { switch (*state) { @@ -961,6 +966,7 @@ static void handle_toplevel_config(void *data, struct xdg_toplevel *toplevel, wl->pending_vo_events |= VO_EVENT_LIVE_RESIZING; break; case XDG_TOPLEVEL_STATE_ACTIVATED: + is_activated = true; /* * If we get an ACTIVATED state, we know it cannot be * minimized, but it may not have been minimized @@ -992,6 +998,16 @@ static void handle_toplevel_config(void *data, struct xdg_toplevel *toplevel, m_config_cache_write_opt(wl->vo_opts_cache, &vo_opts->window_maximized); } + if (wl->activated != is_activated) { + wl->activated = is_activated; + if ((!wl->focused && wl->activated && wl->has_keyboard_input) || + (wl->focused && !wl->activated)) + { + wl->focused = !wl->focused; + wl->pending_vo_events |= VO_EVENT_FOCUS; + } + } + if (!(wl->pending_vo_events & VO_EVENT_LIVE_RESIZING)) vo_query_and_reset_events(wl->vo, VO_EVENT_LIVE_RESIZING); @@ -1544,6 +1560,10 @@ int vo_wayland_control(struct vo *vo, int *events, int request, void *arg) } return VO_TRUE; } + case VOCTRL_GET_FOCUSED: { + *(bool *)arg = wl->focused; + return VO_TRUE; + } case VOCTRL_GET_DISPLAY_NAMES: { *(char ***)arg = get_displays_spanned(wl); return VO_TRUE; diff --git a/video/out/wayland_common.h b/video/out/wayland_common.h index 65f7cbf3e5..7eec7be2d5 100644 --- a/video/out/wayland_common.h +++ b/video/out/wayland_common.h @@ -76,6 +76,9 @@ struct vo_wayland_state { bool frame_wait; bool state_change; bool toplevel_configured; + bool activated; + bool has_keyboard_input; + bool focused; int wakeup_pipe[2]; int pending_vo_events; int mouse_x; diff --git a/video/out/x11_common.c b/video/out/x11_common.c index 461ff378d0..92b3539aca 100644 --- a/video/out/x11_common.c +++ b/video/out/x11_common.c @@ -1128,11 +1128,13 @@ void vo_x11_check_events(struct vo *vo) case FocusIn: x11->has_focus = true; vo_update_cursor(vo); + x11->pending_vo_events |= VO_EVENT_FOCUS; break; case FocusOut: release_all_keys(vo); x11->has_focus = false; vo_update_cursor(vo); + x11->pending_vo_events |= VO_EVENT_FOCUS; break; case KeyRelease: release_all_keys(vo); @@ -1878,6 +1880,10 @@ int vo_x11_control(struct vo *vo, int *events, int request, void *arg) } return VO_TRUE; } + case VOCTRL_GET_FOCUSED: { + *(bool *)arg = x11->has_focus; + return VO_TRUE; + } case VOCTRL_GET_DISPLAY_NAMES: { if (!x11->pseudo_mapped) return VO_FALSE; |