2013-02-28 18:55:02 +00:00
|
|
|
/*
|
2013-09-09 16:37:33 +00:00
|
|
|
* This file is part of mpv video player.
|
2013-02-28 18:55:02 +00:00
|
|
|
*
|
Relicense some non-MPlayer source files to LGPL 2.1 or later
This covers source files which were added in mplayer2 and mpv times
only, and where all code is covered by LGPL relicensing agreements.
There are probably more files to which this applies, but I'm being
conservative here.
A file named ao_sdl.c exists in MPlayer too, but the mpv one is a
complete rewrite, and was added some time after the original ao_sdl.c
was removed. The same applies to vo_sdl.c, for which the SDL2 API is
radically different in addition (MPlayer supports SDL 1.2 only).
common.c contains only code written by me. But common.h is a strange
case: although it originally was named mp_common.h and exists in MPlayer
too, by now it contains only definitions written by uau and me. The
exceptions are the CONTROL_ defines - thus not changing the license of
common.h yet.
codec_tags.c contained once large tables generated from MPlayer's
codecs.conf, but all of these tables were removed.
From demux_playlist.c I'm removing a code fragment from someone who was
not asked; this probably could be done later (see commit 15dccc37).
misc.c is a bit complicated to reason about (it was split off mplayer.c
and thus contains random functions out of this file), but actually all
functions have been added post-MPlayer. Except get_relative_time(),
which was written by uau, but looks similar to 3 different versions of
something similar in each of the Unix/win32/OSX timer source files. I'm
not sure what that means in regards to copyright, so I've just moved it
into another still-GPL source file for now.
screenshot.c once had some minor parts of MPlayer's vf_screenshot.c, but
they're all gone.
2016-01-19 17:36:06 +00:00
|
|
|
* mpv is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
2013-02-28 18:55:02 +00:00
|
|
|
*
|
2013-09-09 16:37:33 +00:00
|
|
|
* mpv is distributed in the hope that it will be useful,
|
2013-02-28 18:55:02 +00:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
Relicense some non-MPlayer source files to LGPL 2.1 or later
This covers source files which were added in mplayer2 and mpv times
only, and where all code is covered by LGPL relicensing agreements.
There are probably more files to which this applies, but I'm being
conservative here.
A file named ao_sdl.c exists in MPlayer too, but the mpv one is a
complete rewrite, and was added some time after the original ao_sdl.c
was removed. The same applies to vo_sdl.c, for which the SDL2 API is
radically different in addition (MPlayer supports SDL 1.2 only).
common.c contains only code written by me. But common.h is a strange
case: although it originally was named mp_common.h and exists in MPlayer
too, by now it contains only definitions written by uau and me. The
exceptions are the CONTROL_ defines - thus not changing the license of
common.h yet.
codec_tags.c contained once large tables generated from MPlayer's
codecs.conf, but all of these tables were removed.
From demux_playlist.c I'm removing a code fragment from someone who was
not asked; this probably could be done later (see commit 15dccc37).
misc.c is a bit complicated to reason about (it was split off mplayer.c
and thus contains random functions out of this file), but actually all
functions have been added post-MPlayer. Except get_relative_time(),
which was written by uau, but looks similar to 3 different versions of
something similar in each of the Unix/win32/OSX timer source files. I'm
not sure what that means in regards to copyright, so I've just moved it
into another still-GPL source file for now.
screenshot.c once had some minor parts of MPlayer's vf_screenshot.c, but
they're all gone.
2016-01-19 17:36:06 +00:00
|
|
|
* GNU Lesser General Public License for more details.
|
2013-02-28 18:55:02 +00:00
|
|
|
*
|
Relicense some non-MPlayer source files to LGPL 2.1 or later
This covers source files which were added in mplayer2 and mpv times
only, and where all code is covered by LGPL relicensing agreements.
There are probably more files to which this applies, but I'm being
conservative here.
A file named ao_sdl.c exists in MPlayer too, but the mpv one is a
complete rewrite, and was added some time after the original ao_sdl.c
was removed. The same applies to vo_sdl.c, for which the SDL2 API is
radically different in addition (MPlayer supports SDL 1.2 only).
common.c contains only code written by me. But common.h is a strange
case: although it originally was named mp_common.h and exists in MPlayer
too, by now it contains only definitions written by uau and me. The
exceptions are the CONTROL_ defines - thus not changing the license of
common.h yet.
codec_tags.c contained once large tables generated from MPlayer's
codecs.conf, but all of these tables were removed.
From demux_playlist.c I'm removing a code fragment from someone who was
not asked; this probably could be done later (see commit 15dccc37).
misc.c is a bit complicated to reason about (it was split off mplayer.c
and thus contains random functions out of this file), but actually all
functions have been added post-MPlayer. Except get_relative_time(),
which was written by uau, but looks similar to 3 different versions of
something similar in each of the Unix/win32/OSX timer source files. I'm
not sure what that means in regards to copyright, so I've just moved it
into another still-GPL source file for now.
screenshot.c once had some minor parts of MPlayer's vf_screenshot.c, but
they're all gone.
2016-01-19 17:36:06 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
|
2013-02-28 18:55:02 +00:00
|
|
|
*/
|
|
|
|
|
2018-10-10 17:59:04 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <limits.h>
|
2013-05-01 13:41:33 +00:00
|
|
|
#include <poll.h>
|
2013-02-28 18:55:02 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <linux/input.h>
|
2019-10-10 19:14:40 +00:00
|
|
|
#include <time.h>
|
2013-12-17 01:39:45 +00:00
|
|
|
#include "common/msg.h"
|
2019-10-14 17:16:42 +00:00
|
|
|
#include "options/m_config.h"
|
2017-10-01 20:16:49 +00:00
|
|
|
#include "input/input.h"
|
|
|
|
#include "input/keycodes.h"
|
2016-07-21 11:25:30 +00:00
|
|
|
#include "osdep/io.h"
|
2013-02-28 18:55:02 +00:00
|
|
|
#include "osdep/timer.h"
|
2017-10-01 20:16:49 +00:00
|
|
|
#include "win_state.h"
|
|
|
|
#include "wayland_common.h"
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2018-04-23 14:10:40 +00:00
|
|
|
// Generated from xdg-shell.xml
|
2019-06-21 22:03:31 +00:00
|
|
|
#include "generated/wayland/xdg-shell.h"
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
// Generated from idle-inhibit-unstable-v1.xml
|
2020-06-04 18:13:59 +00:00
|
|
|
#include "generated/wayland/idle-inhibit-unstable-v1.h"
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2018-11-07 12:53:46 +00:00
|
|
|
// Generated from xdg-decoration-unstable-v1.xml
|
2020-06-04 18:13:59 +00:00
|
|
|
#include "generated/wayland/xdg-decoration-unstable-v1.h"
|
2018-11-07 12:53:46 +00:00
|
|
|
|
2019-10-10 19:14:40 +00:00
|
|
|
// Generated from presentation-time.xml
|
2019-06-21 22:03:31 +00:00
|
|
|
#include "generated/wayland/presentation-time.h"
|
2019-10-10 19:14:40 +00:00
|
|
|
|
2019-10-14 17:16:42 +00:00
|
|
|
#define OPT_BASE_STRUCT struct wayland_opts
|
|
|
|
const struct m_sub_options wayland_conf = {
|
|
|
|
.opts = (const struct m_option[]) {
|
options: change option macros and all option declarations
Change all OPT_* macros such that they don't define the entire m_option
initializer, and instead expand only to a part of it, which sets certain
fields. This requires changing almost every option declaration, because
they all use these macros. A declaration now always starts with
{"name", ...
followed by designated initializers only (possibly wrapped in macros).
The OPT_* macros now initialize the .offset and .type fields only,
sometimes also .priv and others.
I think this change makes the option macros less tricky. The old code
had to stuff everything into macro arguments (and attempted to allow
setting arbitrary fields by letting the user pass designated
initializers in the vararg parts). Some of this was made messy due to
C99 and C11 not allowing 0-sized varargs with ',' removal. It's also
possible that this change is pointless, other than cosmetic preferences.
Not too happy about some things. For example, the OPT_CHOICE()
indentation I applied looks a bit ugly.
Much of this change was done with regex search&replace, but some places
required manual editing. In particular, code in "obscure" areas (which I
didn't include in compilation) might be broken now.
In wayland_common.c the author of some option declarations confused the
flags parameter with the default value (though the default value was
also properly set below). I fixed this with this change.
2020-03-14 20:28:01 +00:00
|
|
|
{"wayland-disable-vsync", OPT_FLAG(disable_vsync)},
|
|
|
|
{"wayland-edge-pixels-pointer", OPT_INT(edge_pixels_pointer),
|
|
|
|
M_RANGE(0, INT_MAX)},
|
|
|
|
{"wayland-edge-pixels-touch", OPT_INT(edge_pixels_touch),
|
|
|
|
M_RANGE(0, INT_MAX)},
|
2019-10-14 17:16:42 +00:00
|
|
|
{0},
|
|
|
|
},
|
|
|
|
.size = sizeof(struct wayland_opts),
|
|
|
|
.defaults = &(struct wayland_opts) {
|
|
|
|
.disable_vsync = false,
|
2019-11-26 23:36:35 +00:00
|
|
|
.edge_pixels_pointer = 10,
|
|
|
|
.edge_pixels_touch = 64,
|
2019-10-14 17:16:42 +00:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2019-02-15 11:52:15 +00:00
|
|
|
static void xdg_wm_base_ping(void *data, struct xdg_wm_base *wm_base, uint32_t serial)
|
2017-10-01 20:16:49 +00:00
|
|
|
{
|
2019-02-15 11:52:15 +00:00
|
|
|
xdg_wm_base_pong(wm_base, serial);
|
2017-10-01 20:16:49 +00:00
|
|
|
}
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2019-02-15 11:52:15 +00:00
|
|
|
static const struct xdg_wm_base_listener xdg_wm_base_listener = {
|
|
|
|
xdg_wm_base_ping,
|
2017-10-01 20:16:49 +00:00
|
|
|
};
|
|
|
|
|
2017-10-22 04:45:23 +00:00
|
|
|
static int spawn_cursor(struct vo_wayland_state *wl)
|
|
|
|
{
|
|
|
|
if (wl->allocated_cursor_scale == wl->scaling) /* Reuse if size is identical */
|
|
|
|
return 0;
|
|
|
|
else if (wl->cursor_theme)
|
|
|
|
wl_cursor_theme_destroy(wl->cursor_theme);
|
|
|
|
|
2018-10-10 17:59:04 +00:00
|
|
|
const char *size_str = getenv("XCURSOR_SIZE");
|
|
|
|
int size = 32;
|
|
|
|
if (size_str != NULL) {
|
|
|
|
errno = 0;
|
|
|
|
char *end;
|
|
|
|
long size_long = strtol(size_str, &end, 10);
|
|
|
|
if (!*end && !errno && size_long > 0 && size_long <= INT_MAX)
|
|
|
|
size = (int)size_long;
|
|
|
|
}
|
|
|
|
|
|
|
|
wl->cursor_theme = wl_cursor_theme_load(NULL, size*wl->scaling, wl->shm);
|
2017-10-22 04:45:23 +00:00
|
|
|
if (!wl->cursor_theme) {
|
|
|
|
MP_ERR(wl, "Unable to load cursor theme!\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
wl->default_cursor = wl_cursor_theme_get_cursor(wl->cursor_theme, "left_ptr");
|
|
|
|
if (!wl->default_cursor) {
|
|
|
|
MP_ERR(wl, "Unable to load cursor theme!\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
wl->allocated_cursor_scale = wl->scaling;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-10-22 05:39:51 +00:00
|
|
|
static int set_cursor_visibility(struct vo_wayland_state *wl, bool on)
|
2017-10-01 20:16:49 +00:00
|
|
|
{
|
2019-02-04 10:27:49 +00:00
|
|
|
wl->cursor_visible = on;
|
2017-10-01 20:16:49 +00:00
|
|
|
if (on) {
|
2017-10-22 04:45:23 +00:00
|
|
|
if (spawn_cursor(wl))
|
|
|
|
return VO_FALSE;
|
|
|
|
struct wl_cursor_image *img = wl->default_cursor->images[0];
|
|
|
|
struct wl_buffer *buffer = wl_cursor_image_get_buffer(img);
|
2017-10-01 20:16:49 +00:00
|
|
|
if (!buffer)
|
2017-10-09 01:08:36 +00:00
|
|
|
return VO_FALSE;
|
2017-10-01 20:16:49 +00:00
|
|
|
wl_pointer_set_cursor(wl->pointer, wl->pointer_id, wl->cursor_surface,
|
2017-10-22 04:45:23 +00:00
|
|
|
img->hotspot_x/wl->scaling, img->hotspot_y/wl->scaling);
|
|
|
|
wl_surface_set_buffer_scale(wl->cursor_surface, wl->scaling);
|
2017-10-01 20:16:49 +00:00
|
|
|
wl_surface_attach(wl->cursor_surface, buffer, 0, 0);
|
2017-10-22 04:45:23 +00:00
|
|
|
wl_surface_damage(wl->cursor_surface, 0, 0, img->width, img->height);
|
2017-10-01 20:16:49 +00:00
|
|
|
wl_surface_commit(wl->cursor_surface);
|
|
|
|
} else {
|
|
|
|
wl_pointer_set_cursor(wl->pointer, wl->pointer_id, NULL, 0, 0);
|
|
|
|
}
|
2017-10-09 01:08:36 +00:00
|
|
|
return VO_TRUE;
|
2017-10-01 20:16:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void pointer_handle_enter(void *data, struct wl_pointer *pointer,
|
|
|
|
uint32_t serial, struct wl_surface *surface,
|
|
|
|
wl_fixed_t sx, wl_fixed_t sy)
|
|
|
|
{
|
|
|
|
struct vo_wayland_state *wl = data;
|
|
|
|
|
|
|
|
wl->pointer = pointer;
|
|
|
|
wl->pointer_id = serial;
|
|
|
|
|
2019-02-04 10:27:49 +00:00
|
|
|
set_cursor_visibility(wl, wl->cursor_visible);
|
2017-10-01 20:16:49 +00:00
|
|
|
mp_input_put_key(wl->vo->input_ctx, MP_KEY_MOUSE_ENTER);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pointer_handle_leave(void *data, struct wl_pointer *pointer,
|
|
|
|
uint32_t serial, struct wl_surface *surface)
|
|
|
|
{
|
|
|
|
struct vo_wayland_state *wl = data;
|
|
|
|
mp_input_put_key(wl->vo->input_ctx, MP_KEY_MOUSE_LEAVE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void pointer_handle_motion(void *data, struct wl_pointer *pointer,
|
|
|
|
uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
|
|
|
|
{
|
|
|
|
struct vo_wayland_state *wl = data;
|
|
|
|
|
|
|
|
wl->mouse_x = wl_fixed_to_int(sx) * wl->scaling;
|
|
|
|
wl->mouse_y = wl_fixed_to_int(sy) * wl->scaling;
|
2019-11-25 23:52:53 +00:00
|
|
|
wl->mouse_unscaled_x = sx;
|
|
|
|
wl->mouse_unscaled_y = sy;
|
2017-10-01 20:16:49 +00:00
|
|
|
|
2020-08-02 21:45:06 +00:00
|
|
|
if (!wl->state_changed) {
|
|
|
|
mp_input_set_mouse_pos(wl->vo->input_ctx, wl->mouse_x, wl->mouse_y);
|
|
|
|
}
|
|
|
|
wl->state_changed = false;
|
2017-10-01 20:16:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void window_move(struct vo_wayland_state *wl, uint32_t serial)
|
|
|
|
{
|
|
|
|
if (wl->xdg_toplevel)
|
2018-04-23 14:10:40 +00:00
|
|
|
xdg_toplevel_move(wl->xdg_toplevel, wl->seat, serial);
|
2017-10-01 20:16:49 +00:00
|
|
|
}
|
|
|
|
|
2019-11-25 23:52:53 +00:00
|
|
|
static int check_for_resize(struct vo_wayland_state *wl, wl_fixed_t x_w, wl_fixed_t y_w,
|
|
|
|
int edge_pixels, enum xdg_toplevel_resize_edge *edge)
|
|
|
|
{
|
2019-12-02 00:55:52 +00:00
|
|
|
if (wl->touch_entries || wl->vo_opts->fullscreen || wl->vo_opts->window_maximized)
|
2019-11-25 23:52:53 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
int pos[2] = { wl_fixed_to_double(x_w), wl_fixed_to_double(y_w) };
|
|
|
|
int left_edge = pos[0] < edge_pixels;
|
|
|
|
int top_edge = pos[1] < edge_pixels;
|
|
|
|
int right_edge = pos[0] > (mp_rect_w(wl->geometry) - edge_pixels);
|
|
|
|
int bottom_edge = pos[1] > (mp_rect_h(wl->geometry) - edge_pixels);
|
|
|
|
|
|
|
|
if (left_edge) {
|
|
|
|
*edge = XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
|
|
|
|
if (top_edge)
|
|
|
|
*edge = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
|
|
|
|
else if (bottom_edge)
|
|
|
|
*edge = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
|
|
|
|
} else if (right_edge) {
|
|
|
|
*edge = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
|
|
|
|
if (top_edge)
|
|
|
|
*edge = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
|
|
|
|
else if (bottom_edge)
|
|
|
|
*edge = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
|
|
|
|
} else if (top_edge) {
|
|
|
|
*edge = XDG_TOPLEVEL_RESIZE_EDGE_TOP;
|
|
|
|
} else if (bottom_edge) {
|
|
|
|
*edge = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
|
|
|
|
} else {
|
|
|
|
*edge = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
|
|
|
|
uint32_t serial, uint32_t time, uint32_t button,
|
|
|
|
uint32_t state)
|
|
|
|
{
|
|
|
|
struct vo_wayland_state *wl = data;
|
|
|
|
|
|
|
|
state = state == WL_POINTER_BUTTON_STATE_PRESSED ? MP_KEY_STATE_DOWN
|
|
|
|
: MP_KEY_STATE_UP;
|
|
|
|
|
2019-07-11 14:02:33 +00:00
|
|
|
switch (button) {
|
|
|
|
case BTN_LEFT:
|
|
|
|
button = MP_MBTN_LEFT;
|
|
|
|
break;
|
|
|
|
case BTN_MIDDLE:
|
|
|
|
button = MP_MBTN_MID;
|
|
|
|
break;
|
|
|
|
case BTN_RIGHT:
|
|
|
|
button = MP_MBTN_RIGHT;
|
|
|
|
break;
|
|
|
|
case BTN_SIDE:
|
|
|
|
button = MP_MBTN_BACK;
|
|
|
|
break;
|
|
|
|
case BTN_EXTRA:
|
|
|
|
button = MP_MBTN_FORWARD;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
button = 0;
|
|
|
|
break;
|
|
|
|
}
|
2017-10-01 20:16:49 +00:00
|
|
|
|
2019-07-11 14:02:33 +00:00
|
|
|
if (button) {
|
|
|
|
mp_input_put_key(wl->vo->input_ctx, button | state);
|
|
|
|
}
|
2017-10-01 20:16:49 +00:00
|
|
|
|
|
|
|
if (!mp_input_test_dragging(wl->vo->input_ctx, wl->mouse_x, wl->mouse_y) &&
|
2019-11-25 23:52:53 +00:00
|
|
|
(button == MP_MBTN_LEFT) && (state == MP_KEY_STATE_DOWN)) {
|
|
|
|
uint32_t edges;
|
|
|
|
// Implement an edge resize zone if there are no decorations
|
|
|
|
if (!wl->xdg_toplevel_decoration &&
|
|
|
|
check_for_resize(wl, wl->mouse_unscaled_x, wl->mouse_unscaled_y,
|
2019-11-26 23:36:35 +00:00
|
|
|
wl->opts->edge_pixels_pointer, &edges))
|
2019-11-25 23:52:53 +00:00
|
|
|
xdg_toplevel_resize(wl->xdg_toplevel, wl->seat, serial, edges);
|
|
|
|
else
|
|
|
|
window_move(wl, serial);
|
2020-04-23 19:49:18 +00:00
|
|
|
// Explictly send an UP event after the client finishes a move/resize
|
|
|
|
mp_input_put_key(wl->vo->input_ctx, button | MP_KEY_STATE_UP);
|
2019-11-25 23:52:53 +00:00
|
|
|
}
|
2017-10-01 20:16:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void pointer_handle_axis(void *data, struct wl_pointer *wl_pointer,
|
|
|
|
uint32_t time, uint32_t axis, wl_fixed_t value)
|
|
|
|
{
|
|
|
|
struct vo_wayland_state *wl = data;
|
2020-03-18 18:14:50 +00:00
|
|
|
|
|
|
|
double val = wl_fixed_to_double(value) < 0 ? -1 : 1;
|
2017-10-01 20:16:49 +00:00
|
|
|
switch (axis) {
|
|
|
|
case WL_POINTER_AXIS_VERTICAL_SCROLL:
|
|
|
|
if (value > 0)
|
|
|
|
mp_input_put_wheel(wl->vo->input_ctx, MP_WHEEL_DOWN, +val);
|
|
|
|
if (value < 0)
|
|
|
|
mp_input_put_wheel(wl->vo->input_ctx, MP_WHEEL_UP, -val);
|
|
|
|
break;
|
|
|
|
case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
|
|
|
|
if (value > 0)
|
|
|
|
mp_input_put_wheel(wl->vo->input_ctx, MP_WHEEL_RIGHT, +val);
|
|
|
|
if (value < 0)
|
|
|
|
mp_input_put_wheel(wl->vo->input_ctx, MP_WHEEL_LEFT, -val);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct wl_pointer_listener pointer_listener = {
|
|
|
|
pointer_handle_enter,
|
|
|
|
pointer_handle_leave,
|
|
|
|
pointer_handle_motion,
|
|
|
|
pointer_handle_button,
|
|
|
|
pointer_handle_axis,
|
|
|
|
};
|
|
|
|
|
|
|
|
static void touch_handle_down(void *data, struct wl_touch *wl_touch,
|
|
|
|
uint32_t serial, uint32_t time, struct wl_surface *surface,
|
|
|
|
int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
|
|
|
|
{
|
|
|
|
struct vo_wayland_state *wl = data;
|
|
|
|
|
2018-04-23 14:10:40 +00:00
|
|
|
enum xdg_toplevel_resize_edge edge;
|
2019-11-26 23:36:35 +00:00
|
|
|
if (check_for_resize(wl, x_w, y_w, wl->opts->edge_pixels_touch, &edge)) {
|
2017-10-01 20:16:49 +00:00
|
|
|
wl->touch_entries = 0;
|
2018-04-23 14:10:40 +00:00
|
|
|
xdg_toplevel_resize(wl->xdg_toplevel, wl->seat, serial, edge);
|
2017-10-01 20:16:49 +00:00
|
|
|
return;
|
|
|
|
} else if (wl->touch_entries) {
|
|
|
|
wl->touch_entries = 0;
|
2018-04-23 14:10:40 +00:00
|
|
|
xdg_toplevel_move(wl->xdg_toplevel, wl->seat, serial);
|
2017-10-01 20:16:49 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
wl->touch_entries = 1;
|
|
|
|
|
|
|
|
wl->mouse_x = wl_fixed_to_int(x_w) * wl->scaling;
|
|
|
|
wl->mouse_y = wl_fixed_to_int(y_w) * wl->scaling;
|
|
|
|
|
|
|
|
mp_input_set_mouse_pos(wl->vo->input_ctx, wl->mouse_x, wl->mouse_y);
|
|
|
|
mp_input_put_key(wl->vo->input_ctx, MP_MBTN_LEFT | MP_KEY_STATE_DOWN);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void touch_handle_up(void *data, struct wl_touch *wl_touch,
|
|
|
|
uint32_t serial, uint32_t time, int32_t id)
|
|
|
|
{
|
|
|
|
struct vo_wayland_state *wl = data;
|
|
|
|
|
|
|
|
wl->touch_entries = 0;
|
|
|
|
|
|
|
|
mp_input_put_key(wl->vo->input_ctx, MP_MBTN_LEFT | MP_KEY_STATE_UP);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void touch_handle_motion(void *data, struct wl_touch *wl_touch,
|
|
|
|
uint32_t time, int32_t id, wl_fixed_t x_w, wl_fixed_t y_w)
|
|
|
|
{
|
|
|
|
struct vo_wayland_state *wl = data;
|
|
|
|
|
|
|
|
wl->mouse_x = wl_fixed_to_int(x_w) * wl->scaling;
|
|
|
|
wl->mouse_y = wl_fixed_to_int(y_w) * wl->scaling;
|
|
|
|
|
|
|
|
mp_input_set_mouse_pos(wl->vo->input_ctx, wl->mouse_x, wl->mouse_y);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void touch_handle_frame(void *data, struct wl_touch *wl_touch)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void touch_handle_cancel(void *data, struct wl_touch *wl_touch)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct wl_touch_listener touch_listener = {
|
|
|
|
touch_handle_down,
|
|
|
|
touch_handle_up,
|
|
|
|
touch_handle_motion,
|
|
|
|
touch_handle_frame,
|
|
|
|
touch_handle_cancel,
|
|
|
|
};
|
2015-03-22 00:47:27 +00:00
|
|
|
|
2013-07-18 15:35:28 +00:00
|
|
|
static const struct mp_keymap keymap[] = {
|
2017-10-01 20:16:49 +00:00
|
|
|
/* Special keys */
|
2013-07-18 15:35:28 +00:00
|
|
|
{XKB_KEY_Pause, MP_KEY_PAUSE}, {XKB_KEY_Escape, MP_KEY_ESC},
|
|
|
|
{XKB_KEY_BackSpace, MP_KEY_BS}, {XKB_KEY_Tab, MP_KEY_TAB},
|
|
|
|
{XKB_KEY_Return, MP_KEY_ENTER}, {XKB_KEY_Menu, MP_KEY_MENU},
|
|
|
|
{XKB_KEY_Print, MP_KEY_PRINT},
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
/* Cursor keys */
|
2013-07-18 15:35:28 +00:00
|
|
|
{XKB_KEY_Left, MP_KEY_LEFT}, {XKB_KEY_Right, MP_KEY_RIGHT},
|
|
|
|
{XKB_KEY_Up, MP_KEY_UP}, {XKB_KEY_Down, MP_KEY_DOWN},
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
/* Navigation keys */
|
2013-07-18 15:35:28 +00:00
|
|
|
{XKB_KEY_Insert, MP_KEY_INSERT}, {XKB_KEY_Delete, MP_KEY_DELETE},
|
|
|
|
{XKB_KEY_Home, MP_KEY_HOME}, {XKB_KEY_End, MP_KEY_END},
|
|
|
|
{XKB_KEY_Page_Up, MP_KEY_PAGE_UP}, {XKB_KEY_Page_Down, MP_KEY_PAGE_DOWN},
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
/* F-keys */
|
|
|
|
{XKB_KEY_F1, MP_KEY_F + 1}, {XKB_KEY_F2, MP_KEY_F + 2},
|
|
|
|
{XKB_KEY_F3, MP_KEY_F + 3}, {XKB_KEY_F4, MP_KEY_F + 4},
|
|
|
|
{XKB_KEY_F5, MP_KEY_F + 5}, {XKB_KEY_F6, MP_KEY_F + 6},
|
|
|
|
{XKB_KEY_F7, MP_KEY_F + 7}, {XKB_KEY_F8, MP_KEY_F + 8},
|
|
|
|
{XKB_KEY_F9, MP_KEY_F + 9}, {XKB_KEY_F10, MP_KEY_F +10},
|
|
|
|
{XKB_KEY_F11, MP_KEY_F +11}, {XKB_KEY_F12, MP_KEY_F +12},
|
2013-07-18 15:35:28 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
/* Numpad independent of numlock */
|
|
|
|
{XKB_KEY_KP_Subtract, '-'}, {XKB_KEY_KP_Add, '+'},
|
2013-07-18 15:35:28 +00:00
|
|
|
{XKB_KEY_KP_Multiply, '*'}, {XKB_KEY_KP_Divide, '/'},
|
|
|
|
{XKB_KEY_KP_Enter, MP_KEY_KPENTER},
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
/* Numpad with numlock */
|
2013-07-18 15:35:28 +00:00
|
|
|
{XKB_KEY_KP_0, MP_KEY_KP0}, {XKB_KEY_KP_1, MP_KEY_KP1},
|
|
|
|
{XKB_KEY_KP_2, MP_KEY_KP2}, {XKB_KEY_KP_3, MP_KEY_KP3},
|
|
|
|
{XKB_KEY_KP_4, MP_KEY_KP4}, {XKB_KEY_KP_5, MP_KEY_KP5},
|
|
|
|
{XKB_KEY_KP_6, MP_KEY_KP6}, {XKB_KEY_KP_7, MP_KEY_KP7},
|
|
|
|
{XKB_KEY_KP_8, MP_KEY_KP8}, {XKB_KEY_KP_9, MP_KEY_KP9},
|
|
|
|
{XKB_KEY_KP_Decimal, MP_KEY_KPDEC}, {XKB_KEY_KP_Separator, MP_KEY_KPDEC},
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
/* Numpad without numlock */
|
2013-07-18 15:35:28 +00:00
|
|
|
{XKB_KEY_KP_Insert, MP_KEY_KPINS}, {XKB_KEY_KP_End, MP_KEY_KP1},
|
|
|
|
{XKB_KEY_KP_Down, MP_KEY_KP2}, {XKB_KEY_KP_Page_Down, MP_KEY_KP3},
|
|
|
|
{XKB_KEY_KP_Left, MP_KEY_KP4}, {XKB_KEY_KP_Begin, MP_KEY_KP5},
|
|
|
|
{XKB_KEY_KP_Right, MP_KEY_KP6}, {XKB_KEY_KP_Home, MP_KEY_KP7},
|
|
|
|
{XKB_KEY_KP_Up, MP_KEY_KP8}, {XKB_KEY_KP_Page_Up, MP_KEY_KP9},
|
|
|
|
{XKB_KEY_KP_Delete, MP_KEY_KPDEL},
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
/* Multimedia keys */
|
2014-11-29 17:38:24 +00:00
|
|
|
{XKB_KEY_XF86MenuKB, MP_KEY_MENU},
|
|
|
|
{XKB_KEY_XF86AudioPlay, MP_KEY_PLAY}, {XKB_KEY_XF86AudioPause, MP_KEY_PAUSE},
|
|
|
|
{XKB_KEY_XF86AudioStop, MP_KEY_STOP},
|
|
|
|
{XKB_KEY_XF86AudioPrev, MP_KEY_PREV}, {XKB_KEY_XF86AudioNext, MP_KEY_NEXT},
|
|
|
|
{XKB_KEY_XF86AudioRewind, MP_KEY_REWIND},
|
|
|
|
{XKB_KEY_XF86AudioForward, MP_KEY_FORWARD},
|
|
|
|
{XKB_KEY_XF86AudioMute, MP_KEY_MUTE},
|
|
|
|
{XKB_KEY_XF86AudioLowerVolume, MP_KEY_VOLUME_DOWN},
|
|
|
|
{XKB_KEY_XF86AudioRaiseVolume, MP_KEY_VOLUME_UP},
|
|
|
|
{XKB_KEY_XF86HomePage, MP_KEY_HOMEPAGE}, {XKB_KEY_XF86WWW, MP_KEY_WWW},
|
|
|
|
{XKB_KEY_XF86Mail, MP_KEY_MAIL}, {XKB_KEY_XF86Favorites, MP_KEY_FAVORITES},
|
|
|
|
{XKB_KEY_XF86Search, MP_KEY_SEARCH}, {XKB_KEY_XF86Sleep, MP_KEY_SLEEP},
|
|
|
|
|
2013-07-18 15:35:28 +00:00
|
|
|
{0, 0}
|
|
|
|
};
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
static void keyboard_handle_keymap(void *data, struct wl_keyboard *wl_keyboard,
|
|
|
|
uint32_t format, int32_t fd, uint32_t size)
|
2013-02-28 18:55:02 +00:00
|
|
|
{
|
2013-07-18 15:35:28 +00:00
|
|
|
struct vo_wayland_state *wl = data;
|
2013-02-28 18:55:02 +00:00
|
|
|
char *map_str;
|
|
|
|
|
2013-07-18 15:35:28 +00:00
|
|
|
if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
|
2013-02-28 18:55:02 +00:00
|
|
|
close(fd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
|
|
|
|
if (map_str == MAP_FAILED) {
|
|
|
|
close(fd);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
wl->xkb_keymap = xkb_keymap_new_from_string(wl->xkb_context, map_str,
|
|
|
|
XKB_KEYMAP_FORMAT_TEXT_V1, 0);
|
2013-02-28 18:55:02 +00:00
|
|
|
|
|
|
|
munmap(map_str, size);
|
|
|
|
close(fd);
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
if (!wl->xkb_keymap) {
|
2013-09-12 14:29:13 +00:00
|
|
|
MP_ERR(wl, "failed to compile keymap\n");
|
2013-02-28 18:55:02 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
wl->xkb_state = xkb_state_new(wl->xkb_keymap);
|
|
|
|
if (!wl->xkb_state) {
|
2013-09-12 14:29:13 +00:00
|
|
|
MP_ERR(wl, "failed to create XKB state\n");
|
2017-10-01 20:16:49 +00:00
|
|
|
xkb_keymap_unref(wl->xkb_keymap);
|
|
|
|
wl->xkb_keymap = NULL;
|
2013-02-28 18:55:02 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
static void keyboard_handle_enter(void *data, struct wl_keyboard *wl_keyboard,
|
|
|
|
uint32_t serial, struct wl_surface *surface,
|
2013-02-28 18:55:02 +00:00
|
|
|
struct wl_array *keys)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
static void keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard,
|
|
|
|
uint32_t serial, struct wl_surface *surface)
|
2013-02-28 18:55:02 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
static bool create_input(struct vo_wayland_state *wl)
|
|
|
|
{
|
2017-10-09 01:08:36 +00:00
|
|
|
wl->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
2017-10-01 20:16:49 +00:00
|
|
|
|
|
|
|
if (!wl->xkb_context) {
|
|
|
|
MP_ERR(wl, "failed to initialize input: check xkbcommon\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int lookupkey(int key)
|
|
|
|
{
|
|
|
|
const char *passthrough_keys = " -+*/<>`~!@#$%^&()_{}:;\"\',.?\\|=[]";
|
|
|
|
|
|
|
|
int mpkey = 0;
|
|
|
|
if ((key >= 'a' && key <= 'z') || (key >= 'A' && key <= 'Z') ||
|
|
|
|
(key >= '0' && key <= '9') ||
|
|
|
|
(key > 0 && key < 256 && strchr(passthrough_keys, key)))
|
|
|
|
mpkey = key;
|
|
|
|
|
|
|
|
if (!mpkey)
|
|
|
|
mpkey = lookup_keymap_table(keymap, key);
|
|
|
|
|
|
|
|
return mpkey;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard,
|
|
|
|
uint32_t serial, uint32_t time, uint32_t key,
|
2013-02-28 18:55:02 +00:00
|
|
|
uint32_t state)
|
|
|
|
{
|
|
|
|
struct vo_wayland_state *wl = data;
|
|
|
|
|
2015-01-12 15:41:00 +00:00
|
|
|
uint32_t code = code = key + 8;
|
2017-10-01 20:16:49 +00:00
|
|
|
xkb_keysym_t sym = xkb_state_key_get_one_sym(wl->xkb_state, code);
|
2015-01-12 15:41:00 +00:00
|
|
|
|
|
|
|
int mpmod = state == WL_KEYBOARD_KEY_STATE_PRESSED ? MP_KEY_STATE_DOWN
|
|
|
|
: MP_KEY_STATE_UP;
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
static const char *mod_names[] = {
|
|
|
|
XKB_MOD_NAME_SHIFT,
|
|
|
|
XKB_MOD_NAME_CTRL,
|
|
|
|
XKB_MOD_NAME_ALT,
|
|
|
|
XKB_MOD_NAME_LOGO,
|
|
|
|
0,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int mods[] = {
|
|
|
|
MP_KEY_MODIFIER_SHIFT,
|
|
|
|
MP_KEY_MODIFIER_CTRL,
|
|
|
|
MP_KEY_MODIFIER_ALT,
|
|
|
|
MP_KEY_MODIFIER_META,
|
|
|
|
0,
|
|
|
|
};
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2015-01-12 15:41:00 +00:00
|
|
|
for (int n = 0; mods[n]; n++) {
|
2017-10-01 20:16:49 +00:00
|
|
|
xkb_mod_index_t index = xkb_keymap_mod_get_index(wl->xkb_keymap, mod_names[n]);
|
|
|
|
if (!xkb_state_mod_index_is_consumed(wl->xkb_state, code, index)
|
|
|
|
&& xkb_state_mod_index_is_active(wl->xkb_state, index,
|
2015-01-12 15:41:00 +00:00
|
|
|
XKB_STATE_MODS_DEPRESSED))
|
|
|
|
mpmod |= mods[n];
|
|
|
|
}
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2015-01-12 15:41:00 +00:00
|
|
|
int mpkey = lookupkey(sym);
|
|
|
|
if (mpkey) {
|
|
|
|
mp_input_put_key(wl->vo->input_ctx, mpkey | mpmod);
|
|
|
|
} else {
|
2017-10-01 20:16:49 +00:00
|
|
|
char s[128];
|
2015-01-12 15:41:00 +00:00
|
|
|
if (xkb_keysym_to_utf8(sym, s, sizeof(s)) > 0)
|
|
|
|
mp_input_put_key_utf8(wl->vo->input_ctx, mpmod, bstr0(s));
|
2013-02-28 18:55:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
static void keyboard_handle_modifiers(void *data, struct wl_keyboard *wl_keyboard,
|
|
|
|
uint32_t serial, uint32_t mods_depressed,
|
|
|
|
uint32_t mods_latched, uint32_t mods_locked,
|
2013-02-28 18:55:02 +00:00
|
|
|
uint32_t group)
|
|
|
|
{
|
2013-07-18 15:35:28 +00:00
|
|
|
struct vo_wayland_state *wl = data;
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
xkb_state_update_mask(wl->xkb_state, mods_depressed, mods_latched,
|
|
|
|
mods_locked, 0, 0, group);
|
2013-02-28 18:55:02 +00:00
|
|
|
}
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
static void keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard,
|
|
|
|
int32_t rate, int32_t delay)
|
2014-09-19 15:38:24 +00:00
|
|
|
{
|
|
|
|
struct vo_wayland_state *wl = data;
|
2019-11-30 02:00:49 +00:00
|
|
|
if (wl->vo_opts->native_keyrepeat)
|
2014-09-19 15:38:24 +00:00
|
|
|
mp_input_set_repeat_info(wl->vo->input_ctx, rate, delay);
|
|
|
|
}
|
|
|
|
|
2014-01-08 15:15:26 +00:00
|
|
|
static const struct wl_keyboard_listener keyboard_listener = {
|
2013-02-28 18:55:02 +00:00
|
|
|
keyboard_handle_keymap,
|
|
|
|
keyboard_handle_enter,
|
|
|
|
keyboard_handle_leave,
|
|
|
|
keyboard_handle_key,
|
2014-09-19 15:38:24 +00:00
|
|
|
keyboard_handle_modifiers,
|
2017-10-01 20:16:49 +00:00
|
|
|
keyboard_handle_repeat_info,
|
2013-02-28 18:55:02 +00:00
|
|
|
};
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
static void seat_handle_caps(void *data, struct wl_seat *seat,
|
|
|
|
enum wl_seat_capability caps)
|
2013-02-28 18:55:02 +00:00
|
|
|
{
|
|
|
|
struct vo_wayland_state *wl = data;
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
if ((caps & WL_SEAT_CAPABILITY_POINTER) && !wl->pointer) {
|
|
|
|
wl->pointer = wl_seat_get_pointer(seat);
|
|
|
|
wl_pointer_add_listener(wl->pointer, &pointer_listener, wl);
|
|
|
|
} else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && wl->pointer) {
|
|
|
|
wl_pointer_destroy(wl->pointer);
|
|
|
|
wl->pointer = NULL;
|
|
|
|
}
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !wl->keyboard) {
|
|
|
|
wl->keyboard = wl_seat_get_keyboard(seat);
|
|
|
|
wl_keyboard_add_listener(wl->keyboard, &keyboard_listener, wl);
|
|
|
|
} else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && wl->keyboard) {
|
|
|
|
wl_keyboard_destroy(wl->keyboard);
|
|
|
|
wl->keyboard = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !wl->touch) {
|
|
|
|
wl->touch = wl_seat_get_touch(seat);
|
|
|
|
wl_touch_set_user_data(wl->touch, wl);
|
|
|
|
wl_touch_add_listener(wl->touch, &touch_listener, wl);
|
|
|
|
} else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && wl->touch) {
|
|
|
|
wl_touch_destroy(wl->touch);
|
|
|
|
wl->touch = NULL;
|
|
|
|
}
|
2013-02-28 18:55:02 +00:00
|
|
|
}
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
static const struct wl_seat_listener seat_listener = {
|
|
|
|
seat_handle_caps,
|
|
|
|
};
|
|
|
|
|
|
|
|
static void output_handle_geometry(void *data, struct wl_output *wl_output,
|
|
|
|
int32_t x, int32_t y, int32_t phys_width,
|
|
|
|
int32_t phys_height, int32_t subpixel,
|
|
|
|
const char *make, const char *model,
|
|
|
|
int32_t transform)
|
2013-02-28 18:55:02 +00:00
|
|
|
{
|
2017-10-01 20:16:49 +00:00
|
|
|
struct vo_wayland_output *output = data;
|
2017-10-09 01:08:36 +00:00
|
|
|
output->make = talloc_strdup(output->wl, make);
|
|
|
|
output->model = talloc_strdup(output->wl, model);
|
2017-10-01 20:16:49 +00:00
|
|
|
output->geometry.x0 = x;
|
|
|
|
output->geometry.y0 = y;
|
2017-10-09 01:08:36 +00:00
|
|
|
output->phys_width = phys_width;
|
|
|
|
output->phys_height = phys_height;
|
2013-02-28 18:55:02 +00:00
|
|
|
}
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
static void output_handle_mode(void *data, struct wl_output *wl_output,
|
|
|
|
uint32_t flags, int32_t width,
|
|
|
|
int32_t height, int32_t refresh)
|
2013-02-28 18:55:02 +00:00
|
|
|
{
|
2017-10-01 20:16:49 +00:00
|
|
|
struct vo_wayland_output *output = data;
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
/* Only save current mode */
|
2017-10-09 01:08:36 +00:00
|
|
|
if (!(flags & WL_OUTPUT_MODE_CURRENT))
|
2017-10-01 20:16:49 +00:00
|
|
|
return;
|
2016-05-30 17:34:31 +00:00
|
|
|
|
2017-10-09 01:08:36 +00:00
|
|
|
output->geometry.x1 = width;
|
|
|
|
output->geometry.y1 = height;
|
2017-10-01 20:16:49 +00:00
|
|
|
output->flags = flags;
|
|
|
|
output->refresh_rate = (double)refresh * 0.001;
|
|
|
|
}
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
static void output_handle_done(void* data, struct wl_output *wl_output)
|
|
|
|
{
|
2017-10-09 01:08:36 +00:00
|
|
|
struct vo_wayland_output *o = data;
|
|
|
|
|
|
|
|
o->geometry.x1 += o->geometry.x0;
|
|
|
|
o->geometry.y1 += o->geometry.y0;
|
|
|
|
|
|
|
|
MP_VERBOSE(o->wl, "Registered output %s %s (0x%x):\n"
|
|
|
|
"\tx: %dpx, y: %dpx\n"
|
|
|
|
"\tw: %dpx (%dmm), h: %dpx (%dmm)\n"
|
|
|
|
"\tscale: %d\n"
|
|
|
|
"\tHz: %f\n", o->make, o->model, o->id, o->geometry.x0,
|
|
|
|
o->geometry.y0, mp_rect_w(o->geometry), o->phys_width,
|
|
|
|
mp_rect_h(o->geometry), o->phys_height, o->scale, o->refresh_rate);
|
2020-03-15 17:42:33 +00:00
|
|
|
|
|
|
|
o->wl->pending_vo_events |= VO_EVENT_WIN_STATE;
|
2013-02-28 18:55:02 +00:00
|
|
|
}
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
static void output_handle_scale(void* data, struct wl_output *wl_output,
|
|
|
|
int32_t factor)
|
2013-02-28 18:55:02 +00:00
|
|
|
{
|
2017-10-01 20:16:49 +00:00
|
|
|
struct vo_wayland_output *output = data;
|
2017-10-22 05:39:51 +00:00
|
|
|
if (!factor) {
|
|
|
|
MP_ERR(output->wl, "Invalid output scale given by the compositor!\n");
|
|
|
|
return;
|
|
|
|
}
|
2017-10-01 20:16:49 +00:00
|
|
|
output->scale = factor;
|
|
|
|
}
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
static const struct wl_output_listener output_listener = {
|
|
|
|
output_handle_geometry,
|
|
|
|
output_handle_mode,
|
|
|
|
output_handle_done,
|
|
|
|
output_handle_scale,
|
|
|
|
};
|
2017-03-17 06:25:32 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
static void data_offer_handle_offer(void *data, struct wl_data_offer *offer,
|
|
|
|
const char *mime_type)
|
|
|
|
{
|
|
|
|
struct vo_wayland_state *wl = data;
|
|
|
|
int score = mp_event_get_mime_type_score(wl->vo->input_ctx, mime_type);
|
|
|
|
if (score > wl->dnd_mime_score) {
|
|
|
|
wl->dnd_mime_score = score;
|
|
|
|
talloc_free(wl->dnd_mime_type);
|
|
|
|
wl->dnd_mime_type = talloc_strdup(wl, mime_type);
|
|
|
|
MP_VERBOSE(wl, "Given DND offer with mime type %s\n", wl->dnd_mime_type);
|
|
|
|
}
|
|
|
|
}
|
2017-03-17 06:25:32 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
static void data_offer_source_actions(void *data, struct wl_data_offer *offer, uint32_t source_actions)
|
|
|
|
{
|
2013-09-24 16:53:24 +00:00
|
|
|
|
2013-02-28 18:55:02 +00:00
|
|
|
}
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
static void data_offer_action(void *data, struct wl_data_offer *wl_data_offer, uint32_t dnd_action)
|
2013-02-28 18:55:02 +00:00
|
|
|
{
|
|
|
|
struct vo_wayland_state *wl = data;
|
2017-10-01 20:16:49 +00:00
|
|
|
wl->dnd_action = dnd_action & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY ?
|
|
|
|
DND_REPLACE : DND_APPEND;
|
|
|
|
MP_VERBOSE(wl, "DND action is %s\n",
|
|
|
|
wl->dnd_action == DND_REPLACE ? "DND_REPLACE" : "DND_APPEND");
|
2013-02-28 18:55:02 +00:00
|
|
|
}
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
static const struct wl_data_offer_listener data_offer_listener = {
|
|
|
|
data_offer_handle_offer,
|
|
|
|
data_offer_source_actions,
|
|
|
|
data_offer_action,
|
2013-02-28 18:55:02 +00:00
|
|
|
};
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
static void data_device_handle_data_offer(void *data, struct wl_data_device *wl_ddev,
|
|
|
|
struct wl_data_offer *id)
|
2013-02-28 18:55:02 +00:00
|
|
|
{
|
|
|
|
struct vo_wayland_state *wl = data;
|
2017-10-01 20:16:49 +00:00
|
|
|
if (wl->dnd_offer)
|
|
|
|
wl_data_offer_destroy(wl->dnd_offer);
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
wl->dnd_offer = id;
|
|
|
|
wl_data_offer_add_listener(id, &data_offer_listener, wl);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void data_device_handle_enter(void *data, struct wl_data_device *wl_ddev,
|
|
|
|
uint32_t serial, struct wl_surface *surface,
|
|
|
|
wl_fixed_t x, wl_fixed_t y,
|
|
|
|
struct wl_data_offer *id)
|
|
|
|
{
|
|
|
|
struct vo_wayland_state *wl = data;
|
|
|
|
if (wl->dnd_offer != id) {
|
|
|
|
MP_FATAL(wl, "DND offer ID mismatch!\n");
|
|
|
|
return;
|
2013-02-28 18:55:02 +00:00
|
|
|
}
|
2017-10-01 20:16:49 +00:00
|
|
|
|
|
|
|
wl_data_offer_set_actions(id, WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY |
|
|
|
|
WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE,
|
|
|
|
WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY);
|
|
|
|
|
|
|
|
wl_data_offer_accept(id, serial, wl->dnd_mime_type);
|
|
|
|
|
|
|
|
MP_VERBOSE(wl, "Accepting DND offer with mime type %s\n", wl->dnd_mime_type);
|
2013-02-28 18:55:02 +00:00
|
|
|
}
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
static void data_device_handle_leave(void *data, struct wl_data_device *wl_ddev)
|
2014-09-19 15:38:24 +00:00
|
|
|
{
|
|
|
|
struct vo_wayland_state *wl = data;
|
2017-10-01 20:16:49 +00:00
|
|
|
|
|
|
|
if (wl->dnd_offer) {
|
|
|
|
if (wl->dnd_fd != -1)
|
|
|
|
return;
|
|
|
|
wl_data_offer_destroy(wl->dnd_offer);
|
|
|
|
wl->dnd_offer = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
MP_VERBOSE(wl, "Releasing DND offer with mime type %s\n", wl->dnd_mime_type);
|
|
|
|
|
|
|
|
talloc_free(wl->dnd_mime_type);
|
|
|
|
wl->dnd_mime_type = NULL;
|
|
|
|
wl->dnd_mime_score = 0;
|
2014-09-19 15:38:24 +00:00
|
|
|
}
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
static void data_device_handle_motion(void *data, struct wl_data_device *wl_ddev,
|
|
|
|
uint32_t time, wl_fixed_t x, wl_fixed_t y)
|
|
|
|
{
|
|
|
|
struct vo_wayland_state *wl = data;
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
wl_data_offer_accept(wl->dnd_offer, time, wl->dnd_mime_type);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void data_device_handle_drop(void *data, struct wl_data_device *wl_ddev)
|
2013-02-28 18:55:02 +00:00
|
|
|
{
|
|
|
|
struct vo_wayland_state *wl = data;
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
int pipefd[2];
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
if (pipe2(pipefd, O_CLOEXEC) == -1) {
|
|
|
|
MP_ERR(wl, "Failed to create dnd pipe!\n");
|
|
|
|
return;
|
2013-02-28 18:55:02 +00:00
|
|
|
}
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
MP_VERBOSE(wl, "Receiving DND offer with mime %s\n", wl->dnd_mime_type);
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
wl_data_offer_receive(wl->dnd_offer, wl->dnd_mime_type, pipefd[1]);
|
|
|
|
close(pipefd[1]);
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
wl->dnd_fd = pipefd[0];
|
2020-07-29 23:13:59 +00:00
|
|
|
wl_data_offer_finish(wl->dnd_offer);
|
2017-10-01 20:16:49 +00:00
|
|
|
}
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
static void data_device_handle_selection(void *data, struct wl_data_device *wl_ddev,
|
|
|
|
struct wl_data_offer *id)
|
|
|
|
{
|
|
|
|
}
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
static const struct wl_data_device_listener data_device_listener = {
|
|
|
|
data_device_handle_data_offer,
|
|
|
|
data_device_handle_enter,
|
|
|
|
data_device_handle_leave,
|
|
|
|
data_device_handle_motion,
|
|
|
|
data_device_handle_drop,
|
|
|
|
data_device_handle_selection,
|
|
|
|
};
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2017-10-09 01:08:36 +00:00
|
|
|
static void surface_handle_enter(void *data, struct wl_surface *wl_surface,
|
|
|
|
struct wl_output *output)
|
|
|
|
{
|
|
|
|
struct vo_wayland_state *wl = data;
|
|
|
|
wl->current_output = NULL;
|
|
|
|
|
|
|
|
struct vo_wayland_output *o;
|
|
|
|
wl_list_for_each(o, &wl->output_list, link) {
|
|
|
|
if (o->output == output) {
|
|
|
|
wl->current_output = o;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
wl->current_output->has_surface = true;
|
|
|
|
if (wl->scaling != wl->current_output->scale)
|
|
|
|
wl->pending_vo_events |= VO_EVENT_RESIZE;
|
|
|
|
wl->scaling = wl->current_output->scale;
|
|
|
|
|
|
|
|
MP_VERBOSE(wl, "Surface entered output %s %s (0x%x), scale = %i\n", o->make,
|
|
|
|
o->model, o->id, wl->scaling);
|
|
|
|
|
|
|
|
wl->pending_vo_events |= VO_EVENT_WIN_STATE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void surface_handle_leave(void *data, struct wl_surface *wl_surface,
|
|
|
|
struct wl_output *output)
|
|
|
|
{
|
|
|
|
struct vo_wayland_state *wl = data;
|
|
|
|
|
|
|
|
struct vo_wayland_output *o;
|
|
|
|
wl_list_for_each(o, &wl->output_list, link) {
|
|
|
|
if (o->output == output) {
|
|
|
|
o->has_surface = false;
|
|
|
|
wl->pending_vo_events |= VO_EVENT_WIN_STATE;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct wl_surface_listener surface_listener = {
|
|
|
|
surface_handle_enter,
|
|
|
|
surface_handle_leave,
|
|
|
|
};
|
|
|
|
|
2019-10-10 19:14:40 +00:00
|
|
|
static void pres_set_clockid(void *data, struct wp_presentation *pres,
|
|
|
|
uint32_t clockid)
|
|
|
|
{
|
|
|
|
struct vo_wayland_state *wl = data;
|
|
|
|
|
2020-05-18 15:54:18 +00:00
|
|
|
if (clockid == CLOCK_MONOTONIC)
|
|
|
|
wl->presentation = pres;
|
2019-10-10 19:14:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static const struct wp_presentation_listener pres_listener = {
|
|
|
|
pres_set_clockid,
|
|
|
|
};
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
static void registry_handle_add(void *data, struct wl_registry *reg, uint32_t id,
|
|
|
|
const char *interface, uint32_t ver)
|
|
|
|
{
|
|
|
|
int found = 1;
|
|
|
|
struct vo_wayland_state *wl = data;
|
|
|
|
|
2018-05-15 19:57:08 +00:00
|
|
|
if (!strcmp(interface, wl_compositor_interface.name) && (ver >= 3) && found++) {
|
|
|
|
wl->compositor = wl_registry_bind(reg, id, &wl_compositor_interface, 3);
|
2017-10-09 01:08:36 +00:00
|
|
|
wl->surface = wl_compositor_create_surface(wl->compositor);
|
2017-10-22 04:45:23 +00:00
|
|
|
wl->cursor_surface = wl_compositor_create_surface(wl->compositor);
|
2017-10-09 01:08:36 +00:00
|
|
|
wl_surface_add_listener(wl->surface, &surface_listener, wl);
|
2017-10-01 20:16:49 +00:00
|
|
|
}
|
2013-07-18 15:35:28 +00:00
|
|
|
|
2017-10-11 18:47:03 +00:00
|
|
|
if (!strcmp(interface, wl_output_interface.name) && (ver >= 2) && found++) {
|
2017-10-01 20:16:49 +00:00
|
|
|
struct vo_wayland_output *output = talloc_zero(wl, struct vo_wayland_output);
|
|
|
|
|
2017-10-11 18:47:03 +00:00
|
|
|
output->wl = wl;
|
|
|
|
output->id = id;
|
2017-10-22 05:39:51 +00:00
|
|
|
output->scale = 1;
|
2017-10-11 18:47:03 +00:00
|
|
|
output->output = wl_registry_bind(reg, id, &wl_output_interface, 2);
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2013-05-02 18:56:59 +00:00
|
|
|
wl_output_add_listener(output->output, &output_listener, output);
|
2017-10-01 20:16:49 +00:00
|
|
|
wl_list_insert(&wl->output_list, &output->link);
|
2013-02-28 18:55:02 +00:00
|
|
|
}
|
|
|
|
|
2018-04-23 14:10:40 +00:00
|
|
|
if (!strcmp(interface, xdg_wm_base_interface.name) && found++) {
|
2018-05-15 19:20:16 +00:00
|
|
|
ver = MPMIN(ver, 2); /* We can use either 1 or 2 */
|
2019-02-15 11:52:15 +00:00
|
|
|
wl->wm_base = wl_registry_bind(reg, id, &xdg_wm_base_interface, ver);
|
|
|
|
xdg_wm_base_add_listener(wl->wm_base, &xdg_wm_base_listener, wl);
|
2017-10-01 20:16:49 +00:00
|
|
|
}
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2017-10-04 01:21:26 +00:00
|
|
|
if (!strcmp(interface, wl_seat_interface.name) && found++) {
|
2017-10-01 20:16:49 +00:00
|
|
|
wl->seat = wl_registry_bind(reg, id, &wl_seat_interface, 1);
|
|
|
|
wl_seat_add_listener(wl->seat, &seat_listener, wl);
|
|
|
|
}
|
2014-01-04 12:48:50 +00:00
|
|
|
|
2017-10-04 01:21:26 +00:00
|
|
|
if (!strcmp(interface, wl_shm_interface.name) && found++) {
|
2017-10-01 20:16:49 +00:00
|
|
|
wl->shm = wl_registry_bind(reg, id, &wl_shm_interface, 1);
|
2013-02-28 18:55:02 +00:00
|
|
|
}
|
2014-01-28 12:07:00 +00:00
|
|
|
|
2017-10-04 01:21:26 +00:00
|
|
|
if (!strcmp(interface, wl_data_device_manager_interface.name) && (ver >= 3) && found++) {
|
2017-10-01 20:16:49 +00:00
|
|
|
wl->dnd_devman = wl_registry_bind(reg, id, &wl_data_device_manager_interface, 3);
|
|
|
|
}
|
|
|
|
|
2018-11-07 12:53:46 +00:00
|
|
|
if (!strcmp(interface, zxdg_decoration_manager_v1_interface.name) && found++) {
|
|
|
|
wl->xdg_decoration_manager = wl_registry_bind(reg, id, &zxdg_decoration_manager_v1_interface, 1);
|
|
|
|
}
|
|
|
|
|
2019-10-10 19:14:40 +00:00
|
|
|
if (!strcmp(interface, wp_presentation_interface.name) && found++) {
|
|
|
|
wl->presentation = wl_registry_bind(reg, id, &wp_presentation_interface, 1);
|
|
|
|
wp_presentation_add_listener(wl->presentation, &pres_listener, wl);
|
|
|
|
}
|
|
|
|
|
2017-10-04 01:21:26 +00:00
|
|
|
if (!strcmp(interface, zwp_idle_inhibit_manager_v1_interface.name) && found++) {
|
2017-10-01 20:16:49 +00:00
|
|
|
wl->idle_inhibit_manager = wl_registry_bind(reg, id, &zwp_idle_inhibit_manager_v1_interface, 1);
|
2014-01-28 12:07:00 +00:00
|
|
|
}
|
2017-10-01 20:16:49 +00:00
|
|
|
|
|
|
|
if (found > 1)
|
2017-10-11 18:47:03 +00:00
|
|
|
MP_VERBOSE(wl, "Registered for protocol %s\n", interface);
|
2013-02-28 18:55:02 +00:00
|
|
|
}
|
|
|
|
|
2017-10-09 01:08:36 +00:00
|
|
|
static void remove_output(struct vo_wayland_output *out)
|
2013-02-28 18:55:02 +00:00
|
|
|
{
|
2017-10-09 01:08:36 +00:00
|
|
|
if (!out)
|
|
|
|
return;
|
2017-10-01 20:16:49 +00:00
|
|
|
|
2017-10-09 01:08:36 +00:00
|
|
|
MP_VERBOSE(out->wl, "Deregistering output %s %s (0x%x)\n", out->make,
|
|
|
|
out->model, out->id);
|
|
|
|
wl_list_remove(&out->link);
|
|
|
|
talloc_free(out->make);
|
|
|
|
talloc_free(out->model);
|
|
|
|
talloc_free(out);
|
|
|
|
return;
|
2013-02-28 18:55:02 +00:00
|
|
|
}
|
|
|
|
|
2017-10-09 01:08:36 +00:00
|
|
|
static void registry_handle_remove(void *data, struct wl_registry *reg, uint32_t id)
|
2013-02-28 18:55:02 +00:00
|
|
|
{
|
2017-10-01 20:16:49 +00:00
|
|
|
struct vo_wayland_state *wl = data;
|
2017-10-09 01:08:36 +00:00
|
|
|
struct vo_wayland_output *output, *tmp;
|
|
|
|
wl_list_for_each_safe(output, tmp, &wl->output_list, link) {
|
|
|
|
if (output->id == id) {
|
|
|
|
remove_output(output);
|
2017-10-01 20:16:49 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2013-02-28 18:55:02 +00:00
|
|
|
}
|
|
|
|
|
2017-10-09 01:08:36 +00:00
|
|
|
static const struct wl_registry_listener registry_listener = {
|
|
|
|
registry_handle_add,
|
|
|
|
registry_handle_remove,
|
2017-10-01 20:16:49 +00:00
|
|
|
};
|
|
|
|
|
2018-04-23 14:10:40 +00:00
|
|
|
static void handle_surface_config(void *data, struct xdg_surface *surface,
|
2017-10-01 20:16:49 +00:00
|
|
|
uint32_t serial)
|
2014-08-06 10:41:33 +00:00
|
|
|
{
|
2018-04-23 14:10:40 +00:00
|
|
|
xdg_surface_ack_configure(surface, serial);
|
2014-08-06 10:41:33 +00:00
|
|
|
}
|
|
|
|
|
2018-04-23 14:10:40 +00:00
|
|
|
static const struct xdg_surface_listener xdg_surface_listener = {
|
2017-10-01 20:16:49 +00:00
|
|
|
handle_surface_config,
|
|
|
|
};
|
|
|
|
|
2018-04-23 14:10:40 +00:00
|
|
|
static void handle_toplevel_config(void *data, struct xdg_toplevel *toplevel,
|
2017-10-01 20:16:49 +00:00
|
|
|
int32_t width, int32_t height, struct wl_array *states)
|
2014-08-06 10:41:33 +00:00
|
|
|
{
|
2017-10-01 20:16:49 +00:00
|
|
|
struct vo_wayland_state *wl = data;
|
2019-11-30 02:00:49 +00:00
|
|
|
struct mp_vo_opts *vo_opts = wl->vo_opts;
|
2017-10-01 20:16:49 +00:00
|
|
|
struct mp_rect old_geometry = wl->geometry;
|
|
|
|
|
2020-02-06 02:47:10 +00:00
|
|
|
bool found_fullscreen = false;
|
|
|
|
bool found_maximized = false;
|
2020-01-12 00:32:36 +00:00
|
|
|
bool is_maximized = vo_opts->window_maximized;
|
|
|
|
bool is_fullscreen = vo_opts->fullscreen;
|
2018-04-23 14:10:40 +00:00
|
|
|
enum xdg_toplevel_state *state;
|
2017-10-09 01:08:36 +00:00
|
|
|
wl_array_for_each(state, states) {
|
|
|
|
switch (*state) {
|
2018-04-23 14:10:40 +00:00
|
|
|
case XDG_TOPLEVEL_STATE_FULLSCREEN:
|
2020-02-06 02:47:10 +00:00
|
|
|
found_fullscreen = true;
|
2017-10-09 01:08:36 +00:00
|
|
|
break;
|
2018-04-23 14:10:40 +00:00
|
|
|
case XDG_TOPLEVEL_STATE_RESIZING:
|
2017-10-09 01:08:36 +00:00
|
|
|
wl->pending_vo_events |= VO_EVENT_LIVE_RESIZING;
|
|
|
|
break;
|
2018-04-23 14:10:40 +00:00
|
|
|
case XDG_TOPLEVEL_STATE_ACTIVATED:
|
2019-11-30 02:00:49 +00:00
|
|
|
/*
|
|
|
|
* If we get an ACTIVATED state, we know it cannot be
|
2020-02-06 02:47:10 +00:00
|
|
|
* minimized, but it may not have been minimized
|
2019-11-30 02:00:49 +00:00
|
|
|
* previously, so we can't detect the exact state.
|
|
|
|
*/
|
|
|
|
vo_opts->window_minimized = false;
|
|
|
|
m_config_cache_write_opt(wl->vo_opts_cache,
|
|
|
|
&vo_opts->window_minimized);
|
2017-10-09 01:08:36 +00:00
|
|
|
break;
|
2018-05-15 19:20:16 +00:00
|
|
|
case XDG_TOPLEVEL_STATE_TILED_TOP:
|
|
|
|
case XDG_TOPLEVEL_STATE_TILED_LEFT:
|
|
|
|
case XDG_TOPLEVEL_STATE_TILED_RIGHT:
|
|
|
|
case XDG_TOPLEVEL_STATE_TILED_BOTTOM:
|
|
|
|
case XDG_TOPLEVEL_STATE_MAXIMIZED:
|
2020-02-06 02:47:10 +00:00
|
|
|
found_maximized = true;
|
2018-05-15 19:20:16 +00:00
|
|
|
break;
|
2017-10-01 20:16:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-06 02:47:10 +00:00
|
|
|
is_maximized = found_maximized;
|
|
|
|
is_fullscreen = found_fullscreen;
|
2019-12-02 00:55:52 +00:00
|
|
|
vo_opts->fullscreen = is_fullscreen;
|
|
|
|
m_config_cache_write_opt(wl->vo_opts_cache, &vo_opts->fullscreen);
|
2019-11-30 02:00:49 +00:00
|
|
|
vo_opts->window_maximized = is_maximized;
|
|
|
|
m_config_cache_write_opt(wl->vo_opts_cache, &vo_opts->window_maximized);
|
|
|
|
|
2020-02-06 02:47:10 +00:00
|
|
|
int old_toplevel_width = wl->toplevel_width;
|
|
|
|
int old_toplevel_height = wl->toplevel_height;
|
|
|
|
wl->toplevel_width = width;
|
|
|
|
wl->toplevel_height = height;
|
|
|
|
|
2017-10-05 14:34:48 +00:00
|
|
|
if (!(wl->pending_vo_events & VO_EVENT_LIVE_RESIZING))
|
|
|
|
vo_query_and_reset_events(wl->vo, VO_EVENT_LIVE_RESIZING);
|
|
|
|
|
2020-02-06 02:47:10 +00:00
|
|
|
if (old_toplevel_width == wl->toplevel_width && old_toplevel_height == wl->toplevel_height)
|
|
|
|
return;
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
if (width > 0 && height > 0) {
|
2019-12-02 00:55:52 +00:00
|
|
|
if (!is_fullscreen && !is_maximized) {
|
2019-11-30 02:00:49 +00:00
|
|
|
if (wl->vo_opts->keepaspect && wl->vo_opts->keepaspect_window) {
|
2020-02-12 18:26:24 +00:00
|
|
|
if (abs(wl->toplevel_width - old_toplevel_width) > abs(wl->toplevel_height - old_toplevel_height)) {
|
|
|
|
double scale_factor = (double)width / wl->reduced_width;
|
|
|
|
width = wl->reduced_width * scale_factor;
|
|
|
|
} else {
|
|
|
|
double scale_factor = (double)height / wl->reduced_height;
|
|
|
|
height = wl->reduced_height * scale_factor;
|
|
|
|
}
|
2017-10-01 20:16:49 +00:00
|
|
|
}
|
|
|
|
wl->window_size.x0 = 0;
|
|
|
|
wl->window_size.y0 = 0;
|
|
|
|
wl->window_size.x1 = width;
|
|
|
|
wl->window_size.y1 = height;
|
|
|
|
}
|
|
|
|
wl->geometry.x0 = 0;
|
|
|
|
wl->geometry.y0 = 0;
|
|
|
|
wl->geometry.x1 = width;
|
|
|
|
wl->geometry.y1 = height;
|
|
|
|
} else {
|
|
|
|
wl->geometry = wl->window_size;
|
|
|
|
}
|
|
|
|
|
2017-10-09 01:08:36 +00:00
|
|
|
if (mp_rect_equals(&old_geometry, &wl->geometry))
|
|
|
|
return;
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
MP_VERBOSE(wl, "Resizing due to xdg from %ix%i to %ix%i\n",
|
|
|
|
mp_rect_w(old_geometry)*wl->scaling, mp_rect_h(old_geometry)*wl->scaling,
|
|
|
|
mp_rect_w(wl->geometry)*wl->scaling, mp_rect_h(wl->geometry)*wl->scaling);
|
|
|
|
|
|
|
|
wl->pending_vo_events |= VO_EVENT_RESIZE;
|
2020-08-02 21:45:06 +00:00
|
|
|
wl->state_changed = true;
|
2014-08-06 10:41:33 +00:00
|
|
|
}
|
|
|
|
|
2018-04-23 14:10:40 +00:00
|
|
|
static void handle_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel)
|
2014-08-06 10:41:33 +00:00
|
|
|
{
|
2017-10-05 15:43:44 +00:00
|
|
|
struct vo_wayland_state *wl = data;
|
|
|
|
mp_input_put_key(wl->vo->input_ctx, MP_KEY_CLOSE_WIN);
|
2014-08-06 10:41:33 +00:00
|
|
|
}
|
|
|
|
|
2018-04-23 14:10:40 +00:00
|
|
|
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
|
2017-10-01 20:16:49 +00:00
|
|
|
handle_toplevel_config,
|
|
|
|
handle_toplevel_close,
|
|
|
|
};
|
|
|
|
|
2017-10-09 01:08:36 +00:00
|
|
|
static int create_xdg_surface(struct vo_wayland_state *wl)
|
2013-05-07 18:51:09 +00:00
|
|
|
{
|
2019-02-15 11:52:15 +00:00
|
|
|
wl->xdg_surface = xdg_wm_base_get_xdg_surface(wl->wm_base, wl->surface);
|
2018-04-23 14:10:40 +00:00
|
|
|
xdg_surface_add_listener(wl->xdg_surface, &xdg_surface_listener, wl);
|
2013-08-23 09:29:09 +00:00
|
|
|
|
2018-04-23 14:10:40 +00:00
|
|
|
wl->xdg_toplevel = xdg_surface_get_toplevel(wl->xdg_surface);
|
|
|
|
xdg_toplevel_add_listener(wl->xdg_toplevel, &xdg_toplevel_listener, wl);
|
2013-08-23 09:29:09 +00:00
|
|
|
|
2020-08-12 14:41:56 +00:00
|
|
|
if (!wl->xdg_surface || !wl->xdg_toplevel)
|
|
|
|
return 1;
|
2017-10-01 20:16:49 +00:00
|
|
|
return 0;
|
2013-05-07 18:51:09 +00:00
|
|
|
}
|
|
|
|
|
2020-01-04 21:51:09 +00:00
|
|
|
static void set_border_decorations(struct vo_wayland_state *wl, int state)
|
2013-02-28 18:55:02 +00:00
|
|
|
{
|
2019-12-03 13:48:06 +00:00
|
|
|
if (!wl->xdg_toplevel_decoration) {
|
|
|
|
wl->vo_opts->border = false;
|
|
|
|
m_config_cache_write_opt(wl->vo_opts_cache,
|
|
|
|
&wl->vo_opts->border);
|
2020-01-04 21:51:09 +00:00
|
|
|
return;
|
2019-12-03 13:48:06 +00:00
|
|
|
}
|
2018-11-10 18:45:58 +00:00
|
|
|
|
|
|
|
enum zxdg_toplevel_decoration_v1_mode mode;
|
|
|
|
if (state) {
|
|
|
|
MP_VERBOSE(wl, "Enabling server decorations\n");
|
|
|
|
mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE;
|
|
|
|
} else {
|
|
|
|
MP_VERBOSE(wl, "Disabling server decorations\n");
|
|
|
|
mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
|
2017-10-09 01:08:36 +00:00
|
|
|
}
|
2018-11-10 18:45:58 +00:00
|
|
|
zxdg_toplevel_decoration_v1_set_mode(wl->xdg_toplevel_decoration, mode);
|
2017-10-01 20:16:49 +00:00
|
|
|
}
|
2014-01-07 00:06:28 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
int vo_wayland_init(struct vo *vo)
|
|
|
|
{
|
|
|
|
vo->wl = talloc_zero(NULL, struct vo_wayland_state);
|
|
|
|
struct vo_wayland_state *wl = vo->wl;
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
*wl = (struct vo_wayland_state) {
|
|
|
|
.display = wl_display_connect(NULL),
|
|
|
|
.vo = vo,
|
|
|
|
.log = mp_log_new(wl, vo->log, "wayland"),
|
|
|
|
.scaling = 1,
|
|
|
|
.wakeup_pipe = {-1, -1},
|
|
|
|
.dnd_fd = -1,
|
2019-02-04 10:27:49 +00:00
|
|
|
.cursor_visible = true,
|
2019-11-30 02:00:49 +00:00
|
|
|
.vo_opts_cache = m_config_cache_alloc(wl, vo->global, &vo_sub_opts),
|
2017-10-01 20:16:49 +00:00
|
|
|
};
|
2019-11-30 02:00:49 +00:00
|
|
|
wl->vo_opts = wl->vo_opts_cache->opts;
|
2013-09-10 16:33:43 +00:00
|
|
|
|
2017-10-12 22:14:05 +00:00
|
|
|
wl_list_init(&wl->output_list);
|
|
|
|
|
2019-10-03 13:19:12 +00:00
|
|
|
if (!wl->display)
|
2013-02-28 18:55:02 +00:00
|
|
|
return false;
|
|
|
|
|
2019-10-03 13:19:12 +00:00
|
|
|
if (create_input(wl))
|
2017-10-01 20:16:49 +00:00
|
|
|
return false;
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
wl->registry = wl_display_get_registry(wl->display);
|
|
|
|
wl_registry_add_listener(wl->registry, ®istry_listener, wl);
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
/* Do a roundtrip to run the registry */
|
|
|
|
wl_display_roundtrip(wl->display);
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2019-02-15 11:52:15 +00:00
|
|
|
if (!wl->wm_base) {
|
2017-10-05 14:34:48 +00:00
|
|
|
MP_FATAL(wl, "Compositor doesn't support the required %s protocol!\n",
|
2018-04-23 14:10:40 +00:00
|
|
|
xdg_wm_base_interface.name);
|
2017-10-05 14:34:48 +00:00
|
|
|
return false;
|
|
|
|
}
|
2017-10-01 20:16:49 +00:00
|
|
|
|
2017-10-11 18:47:03 +00:00
|
|
|
if (!wl_list_length(&wl->output_list)) {
|
|
|
|
MP_FATAL(wl, "No outputs found or compositor doesn't support %s (ver. 2)\n",
|
|
|
|
wl_output_interface.name);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-10-22 04:45:23 +00:00
|
|
|
/* Can't be initialized during registry due to multi-protocol dependence */
|
2019-10-03 13:19:12 +00:00
|
|
|
if (create_xdg_surface(wl))
|
2017-10-01 20:16:49 +00:00
|
|
|
return false;
|
2014-01-08 19:58:32 +00:00
|
|
|
|
2019-12-30 21:22:02 +00:00
|
|
|
const char *xdg_current_desktop = getenv("XDG_CURRENT_DESKTOP");
|
|
|
|
if (xdg_current_desktop != NULL && strstr(xdg_current_desktop, "GNOME"))
|
|
|
|
MP_WARN(wl, "GNOME's wayland compositor is known to have many serious issues with mpv. Switch to GNOME's xorg session for the best experience.\n");
|
|
|
|
|
2019-10-21 13:30:55 +00:00
|
|
|
if (wl->dnd_devman && wl->seat) {
|
2017-10-01 20:16:49 +00:00
|
|
|
wl->dnd_ddev = wl_data_device_manager_get_data_device(wl->dnd_devman, wl->seat);
|
|
|
|
wl_data_device_add_listener(wl->dnd_ddev, &data_device_listener, wl);
|
2019-10-21 13:30:55 +00:00
|
|
|
} else if (!wl->dnd_devman) {
|
2017-10-09 01:08:36 +00:00
|
|
|
MP_VERBOSE(wl, "Compositor doesn't support the %s (ver. 3) protocol!\n",
|
|
|
|
wl_data_device_manager_interface.name);
|
2017-10-01 20:16:49 +00:00
|
|
|
}
|
2014-06-15 12:46:27 +00:00
|
|
|
|
2019-10-10 19:14:40 +00:00
|
|
|
if (wl->presentation) {
|
|
|
|
wl->sync = talloc_zero_array(wl, struct vo_wayland_sync, 1);
|
|
|
|
struct vo_wayland_sync sync = {0, 0, 0, 0};
|
|
|
|
wl->sync[0] = sync;
|
|
|
|
wl->sync_size += 1;
|
|
|
|
} else {
|
|
|
|
MP_VERBOSE(wl, "Compositor doesn't support the %s protocol!\n",
|
|
|
|
wp_presentation_interface.name);
|
|
|
|
}
|
|
|
|
|
2018-11-07 12:53:46 +00:00
|
|
|
if (wl->xdg_decoration_manager) {
|
|
|
|
wl->xdg_toplevel_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(wl->xdg_decoration_manager, wl->xdg_toplevel);
|
2019-12-02 00:55:52 +00:00
|
|
|
set_border_decorations(wl, wl->vo_opts->border);
|
2017-10-09 01:08:36 +00:00
|
|
|
} else {
|
2019-12-03 13:48:06 +00:00
|
|
|
wl->vo_opts->border = false;
|
|
|
|
m_config_cache_write_opt(wl->vo_opts_cache,
|
|
|
|
&wl->vo_opts->border);
|
2018-11-10 18:45:58 +00:00
|
|
|
MP_VERBOSE(wl, "Compositor doesn't support the %s protocol!\n",
|
2018-11-07 12:53:46 +00:00
|
|
|
zxdg_decoration_manager_v1_interface.name);
|
2017-10-01 20:16:49 +00:00
|
|
|
}
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2017-10-09 01:08:36 +00:00
|
|
|
if (!wl->idle_inhibit_manager)
|
|
|
|
MP_VERBOSE(wl, "Compositor doesn't support the %s protocol!\n",
|
|
|
|
zwp_idle_inhibit_manager_v1_interface.name);
|
|
|
|
|
2019-10-14 17:16:42 +00:00
|
|
|
wl->opts = mp_get_config_group(wl, wl->vo->global, &wayland_conf);
|
2017-10-01 20:16:49 +00:00
|
|
|
wl->display_fd = wl_display_get_fd(wl->display);
|
|
|
|
mp_make_wakeup_pipe(wl->wakeup_pipe);
|
2014-01-08 19:58:32 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
return true;
|
2013-02-28 18:55:02 +00:00
|
|
|
}
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
void vo_wayland_uninit(struct vo *vo)
|
2013-02-28 18:55:02 +00:00
|
|
|
{
|
2017-10-01 20:16:49 +00:00
|
|
|
struct vo_wayland_state *wl = vo->wl;
|
2017-10-07 19:49:03 +00:00
|
|
|
if (!wl)
|
|
|
|
return;
|
2014-01-28 12:07:00 +00:00
|
|
|
|
2017-10-11 18:47:03 +00:00
|
|
|
mp_input_put_key(wl->vo->input_ctx, MP_INPUT_RELEASE_ALL);
|
|
|
|
|
2019-05-26 04:10:12 +00:00
|
|
|
if (wl->current_output && wl->current_output->output)
|
2019-05-13 13:47:13 +00:00
|
|
|
wl_output_destroy(wl->current_output->output);
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
if (wl->cursor_theme)
|
|
|
|
wl_cursor_theme_destroy(wl->cursor_theme);
|
2014-08-18 20:00:39 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
if (wl->cursor_surface)
|
|
|
|
wl_surface_destroy(wl->cursor_surface);
|
2014-08-06 10:41:33 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
if (wl->xkb_context)
|
|
|
|
xkb_context_unref(wl->xkb_context);
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2019-05-13 13:47:13 +00:00
|
|
|
if (wl->xkb_state)
|
|
|
|
xkb_state_unref(wl->xkb_state);
|
|
|
|
|
|
|
|
if (wl->xkb_keymap)
|
|
|
|
xkb_keymap_unref(wl->xkb_keymap);
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
if (wl->idle_inhibitor)
|
|
|
|
zwp_idle_inhibitor_v1_destroy(wl->idle_inhibitor);
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
if (wl->idle_inhibit_manager)
|
|
|
|
zwp_idle_inhibit_manager_v1_destroy(wl->idle_inhibit_manager);
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2019-02-15 11:52:15 +00:00
|
|
|
if (wl->wm_base)
|
|
|
|
xdg_wm_base_destroy(wl->wm_base);
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
if (wl->shm)
|
|
|
|
wl_shm_destroy(wl->shm);
|
2014-01-08 19:58:32 +00:00
|
|
|
|
2019-05-13 13:47:13 +00:00
|
|
|
if (wl->dnd_ddev)
|
|
|
|
wl_data_device_destroy(wl->dnd_ddev);
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
if (wl->dnd_devman)
|
|
|
|
wl_data_device_manager_destroy(wl->dnd_devman);
|
2015-03-22 00:47:27 +00:00
|
|
|
|
2019-08-07 14:26:24 +00:00
|
|
|
if (wl->dnd_offer)
|
|
|
|
wl_data_offer_destroy(wl->dnd_offer);
|
|
|
|
|
2018-11-07 12:53:46 +00:00
|
|
|
if (wl->xdg_toplevel_decoration)
|
|
|
|
zxdg_toplevel_decoration_v1_destroy(wl->xdg_toplevel_decoration);
|
|
|
|
|
|
|
|
if (wl->xdg_decoration_manager)
|
|
|
|
zxdg_decoration_manager_v1_destroy(wl->xdg_decoration_manager);
|
|
|
|
|
2019-05-13 13:47:13 +00:00
|
|
|
if (wl->xdg_toplevel)
|
|
|
|
xdg_toplevel_destroy(wl->xdg_toplevel);
|
|
|
|
|
|
|
|
if (wl->xdg_surface)
|
|
|
|
xdg_surface_destroy(wl->xdg_surface);
|
|
|
|
|
|
|
|
if (wl->compositor)
|
|
|
|
wl_compositor_destroy(wl->compositor);
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
if (wl->surface)
|
|
|
|
wl_surface_destroy(wl->surface);
|
2014-08-06 10:41:33 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
if (wl->frame_callback)
|
|
|
|
wl_callback_destroy(wl->frame_callback);
|
2014-08-13 20:32:22 +00:00
|
|
|
|
2019-10-10 19:14:40 +00:00
|
|
|
if (wl->presentation)
|
|
|
|
wp_presentation_destroy(wl->presentation);
|
|
|
|
|
2019-05-13 13:47:13 +00:00
|
|
|
if (wl->pointer)
|
|
|
|
wl_pointer_destroy(wl->pointer);
|
|
|
|
|
|
|
|
if (wl->keyboard)
|
|
|
|
wl_keyboard_destroy(wl->keyboard);
|
|
|
|
|
|
|
|
if (wl->seat)
|
|
|
|
wl_seat_destroy(wl->seat);
|
|
|
|
|
|
|
|
if (wl->registry)
|
|
|
|
wl_registry_destroy(wl->registry);
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
if (wl->display) {
|
|
|
|
close(wl_display_get_fd(wl->display));
|
|
|
|
wl_display_disconnect(wl->display);
|
|
|
|
}
|
2013-08-19 12:07:17 +00:00
|
|
|
|
2017-10-09 01:08:36 +00:00
|
|
|
struct vo_wayland_output *output, *tmp;
|
|
|
|
wl_list_for_each_safe(output, tmp, &wl->output_list, link)
|
|
|
|
remove_output(output);
|
|
|
|
|
|
|
|
talloc_free(wl->dnd_mime_type);
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
for (int n = 0; n < 2; n++)
|
|
|
|
close(wl->wakeup_pipe[n]);
|
|
|
|
talloc_free(wl);
|
|
|
|
vo->wl = NULL;
|
2013-07-18 15:35:28 +00:00
|
|
|
}
|
|
|
|
|
2020-03-06 18:15:21 +00:00
|
|
|
static bool find_output(struct vo_wayland_state *wl, int index)
|
2013-07-18 15:35:28 +00:00
|
|
|
{
|
2017-10-01 20:16:49 +00:00
|
|
|
int screen_id = 0;
|
2020-03-06 18:15:21 +00:00
|
|
|
struct vo_wayland_output *output = NULL;
|
|
|
|
struct vo_wayland_output *fallback_output = NULL;
|
2017-10-09 01:08:36 +00:00
|
|
|
wl_list_for_each(output, &wl->output_list, link) {
|
2020-03-06 18:15:21 +00:00
|
|
|
if (screen_id == 0)
|
|
|
|
fallback_output = output;
|
2017-10-09 01:08:36 +00:00
|
|
|
if (index == screen_id++)
|
2020-03-06 18:15:21 +00:00
|
|
|
wl->current_output = output;
|
2013-02-28 18:55:02 +00:00
|
|
|
}
|
2020-03-06 18:15:21 +00:00
|
|
|
if (!wl->current_output) {
|
|
|
|
if (!fallback_output) {
|
|
|
|
MP_ERR(wl, "Screen index %i not found/unavailable!\n", index);
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
MP_WARN(wl, "Screen index %i not found/unavailable! Falling back to screen 0!\n", index);
|
|
|
|
wl->current_output = fallback_output;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
2013-02-28 18:55:02 +00:00
|
|
|
}
|
|
|
|
|
2020-02-12 18:26:24 +00:00
|
|
|
static void greatest_common_divisor(struct vo_wayland_state *wl, int a, int b) {
|
|
|
|
// euclidean algorithm
|
|
|
|
int larger;
|
|
|
|
int smaller;
|
|
|
|
if (a > b) {
|
|
|
|
larger = a;
|
|
|
|
smaller = b;
|
|
|
|
} else {
|
|
|
|
larger = b;
|
|
|
|
smaller = a;
|
|
|
|
}
|
|
|
|
int remainder = larger - smaller * floor(larger/smaller);
|
|
|
|
if (remainder == 0) {
|
|
|
|
wl->gcd = smaller;
|
|
|
|
} else {
|
|
|
|
greatest_common_divisor(wl, smaller, remainder);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
int vo_wayland_reconfig(struct vo *vo)
|
2013-02-28 18:55:02 +00:00
|
|
|
{
|
2017-10-01 20:16:49 +00:00
|
|
|
struct vo_wayland_state *wl = vo->wl;
|
|
|
|
|
|
|
|
MP_VERBOSE(wl, "Reconfiguring!\n");
|
|
|
|
|
2019-10-02 03:09:46 +00:00
|
|
|
if (!wl->current_output) {
|
2017-10-09 01:08:36 +00:00
|
|
|
int idx = 0;
|
2019-12-02 00:55:52 +00:00
|
|
|
if (wl->vo_opts->fullscreen && (wl->vo_opts->fsscreen_id >= 0))
|
|
|
|
idx = wl->vo_opts->fsscreen_id;
|
2020-03-06 18:15:21 +00:00
|
|
|
if (find_output(wl, idx))
|
2020-02-13 01:20:03 +00:00
|
|
|
return false;
|
2020-03-06 18:15:21 +00:00
|
|
|
if (!wl->vo_opts->hidpi_window_scale)
|
|
|
|
wl->current_output->scale = 1;
|
|
|
|
wl->scaling = wl->current_output->scale;
|
2013-08-26 16:35:57 +00:00
|
|
|
}
|
2014-01-08 19:58:32 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
struct vo_win_geometry geo;
|
2020-02-13 01:20:03 +00:00
|
|
|
struct mp_rect screenrc = wl->current_output->geometry;
|
2017-10-01 20:16:49 +00:00
|
|
|
vo_calc_window_geometry(vo, &screenrc, &geo);
|
|
|
|
vo_apply_window_geometry(vo, &geo);
|
2014-01-08 20:49:18 +00:00
|
|
|
|
2020-03-06 18:15:21 +00:00
|
|
|
if (!wl->configured) {
|
2018-05-15 19:20:16 +00:00
|
|
|
wl->geometry.x0 = 0;
|
|
|
|
wl->geometry.y0 = 0;
|
|
|
|
wl->geometry.x1 = vo->dwidth / wl->scaling;
|
|
|
|
wl->geometry.y1 = vo->dheight / wl->scaling;
|
|
|
|
wl->window_size = wl->geometry;
|
|
|
|
}
|
|
|
|
|
2020-02-12 18:26:24 +00:00
|
|
|
greatest_common_divisor(wl, vo->dwidth, vo->dheight);
|
|
|
|
wl->reduced_width = vo->dwidth / wl->gcd;
|
|
|
|
wl->reduced_height = vo->dheight / wl->gcd;
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2020-03-06 18:15:21 +00:00
|
|
|
if (wl->vo_opts->fullscreen && wl->vo_opts->fsscreen_id < 0) {
|
|
|
|
xdg_toplevel_set_fullscreen(wl->xdg_toplevel, NULL);
|
|
|
|
} else if (wl->vo_opts->fullscreen && wl->vo_opts->fsscreen_id >= 0) {
|
|
|
|
xdg_toplevel_set_fullscreen(wl->xdg_toplevel, wl->current_output->output);
|
2014-09-03 19:30:19 +00:00
|
|
|
}
|
|
|
|
|
2020-01-12 01:36:55 +00:00
|
|
|
if (wl->vo_opts->window_maximized)
|
|
|
|
xdg_toplevel_set_maximized(wl->xdg_toplevel);
|
|
|
|
|
|
|
|
if (wl->vo_opts->window_minimized)
|
|
|
|
xdg_toplevel_set_minimized(wl->xdg_toplevel);
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
wl_surface_set_buffer_scale(wl->surface, wl->scaling);
|
|
|
|
wl_surface_commit(wl->surface);
|
2017-10-09 01:08:36 +00:00
|
|
|
wl->pending_vo_events |= VO_EVENT_RESIZE;
|
|
|
|
if (!wl->configured) {
|
2017-10-22 05:39:51 +00:00
|
|
|
if (spawn_cursor(wl))
|
|
|
|
return false;
|
2017-10-09 01:08:36 +00:00
|
|
|
wl_display_roundtrip(wl->display);
|
|
|
|
wl->configured = true;
|
|
|
|
}
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2013-05-16 14:43:34 +00:00
|
|
|
return true;
|
2013-02-28 18:55:02 +00:00
|
|
|
}
|
|
|
|
|
2017-10-09 01:08:36 +00:00
|
|
|
static int set_screensaver_inhibitor(struct vo_wayland_state *wl, int state)
|
2013-02-28 18:55:02 +00:00
|
|
|
{
|
2017-10-01 20:16:49 +00:00
|
|
|
if (!wl->idle_inhibit_manager)
|
2017-10-09 01:08:36 +00:00
|
|
|
return VO_NOTIMPL;
|
2017-10-01 20:16:49 +00:00
|
|
|
if (state == (!!wl->idle_inhibitor))
|
2017-10-09 01:08:36 +00:00
|
|
|
return VO_TRUE;
|
2017-10-01 20:16:49 +00:00
|
|
|
if (state) {
|
|
|
|
MP_VERBOSE(wl, "Enabling idle inhibitor\n");
|
|
|
|
struct zwp_idle_inhibit_manager_v1 *mgr = wl->idle_inhibit_manager;
|
|
|
|
wl->idle_inhibitor = zwp_idle_inhibit_manager_v1_create_inhibitor(mgr, wl->surface);
|
|
|
|
} else {
|
|
|
|
MP_VERBOSE(wl, "Disabling the idle inhibitor\n");
|
|
|
|
zwp_idle_inhibitor_v1_destroy(wl->idle_inhibitor);
|
2018-02-09 19:01:22 +00:00
|
|
|
wl->idle_inhibitor = NULL;
|
2017-10-01 20:16:49 +00:00
|
|
|
}
|
2017-10-09 01:08:36 +00:00
|
|
|
return VO_TRUE;
|
2017-10-01 20:16:49 +00:00
|
|
|
}
|
2017-09-16 04:24:57 +00:00
|
|
|
|
2020-01-04 21:51:09 +00:00
|
|
|
static void toggle_fullscreen(struct vo_wayland_state *wl)
|
2017-10-01 20:16:49 +00:00
|
|
|
{
|
2017-10-09 01:08:36 +00:00
|
|
|
if (!wl->xdg_toplevel)
|
2020-01-04 21:51:09 +00:00
|
|
|
return;
|
2020-03-06 18:15:21 +00:00
|
|
|
if (wl->vo_opts->fullscreen && wl->vo_opts->fsscreen_id < 0) {
|
2018-04-23 14:10:40 +00:00
|
|
|
xdg_toplevel_set_fullscreen(wl->xdg_toplevel, NULL);
|
2020-03-06 18:15:21 +00:00
|
|
|
} else if (wl->vo_opts->fullscreen && wl->vo_opts->fsscreen_id >= 0) {
|
|
|
|
find_output(wl, wl->vo_opts->fsscreen_id);
|
|
|
|
xdg_toplevel_set_fullscreen(wl->xdg_toplevel, wl->current_output->output);
|
|
|
|
} else {
|
2019-12-02 00:55:52 +00:00
|
|
|
xdg_toplevel_unset_fullscreen(wl->xdg_toplevel);
|
2020-03-06 18:15:21 +00:00
|
|
|
}
|
2013-02-28 18:55:02 +00:00
|
|
|
}
|
|
|
|
|
2020-01-04 21:51:09 +00:00
|
|
|
static void toggle_maximized(struct vo_wayland_state *wl)
|
2019-11-26 00:47:44 +00:00
|
|
|
{
|
|
|
|
if (!wl->xdg_toplevel)
|
2020-01-04 21:51:09 +00:00
|
|
|
return;
|
2019-11-30 02:00:49 +00:00
|
|
|
if (wl->vo_opts->window_maximized)
|
2019-11-26 00:47:44 +00:00
|
|
|
xdg_toplevel_set_maximized(wl->xdg_toplevel);
|
2019-11-30 02:00:49 +00:00
|
|
|
else
|
|
|
|
xdg_toplevel_unset_maximized(wl->xdg_toplevel);
|
2019-11-26 00:47:44 +00:00
|
|
|
}
|
|
|
|
|
2020-01-04 21:51:09 +00:00
|
|
|
static void do_minimize(struct vo_wayland_state *wl)
|
2019-11-26 00:47:44 +00:00
|
|
|
{
|
|
|
|
if (!wl->xdg_toplevel)
|
2020-01-04 21:51:09 +00:00
|
|
|
return;
|
2019-11-30 02:00:49 +00:00
|
|
|
if (wl->vo_opts->window_minimized)
|
|
|
|
xdg_toplevel_set_minimized(wl->xdg_toplevel);
|
2019-11-26 00:47:44 +00:00
|
|
|
}
|
|
|
|
|
2020-08-12 14:41:56 +00:00
|
|
|
static int update_window_title(struct vo_wayland_state *wl, const char *title)
|
2013-02-28 18:55:02 +00:00
|
|
|
{
|
2017-10-09 01:08:36 +00:00
|
|
|
if (!wl->xdg_toplevel)
|
|
|
|
return VO_NOTAVAIL;
|
2018-04-23 14:10:40 +00:00
|
|
|
xdg_toplevel_set_title(wl->xdg_toplevel, title);
|
2017-10-09 01:08:36 +00:00
|
|
|
return VO_TRUE;
|
2013-02-28 18:55:02 +00:00
|
|
|
}
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
static void check_dnd_fd(struct vo_wayland_state *wl)
|
2013-02-28 18:55:02 +00:00
|
|
|
{
|
2017-10-01 20:16:49 +00:00
|
|
|
if (wl->dnd_fd == -1)
|
2013-02-28 18:55:02 +00:00
|
|
|
return;
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
struct pollfd fdp = { wl->dnd_fd, POLLIN | POLLERR | POLLHUP, 0 };
|
|
|
|
if (poll(&fdp, 1, 0) <= 0)
|
|
|
|
return;
|
2013-02-28 18:55:02 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
if (fdp.revents & POLLIN) {
|
|
|
|
ptrdiff_t offset = 0;
|
|
|
|
size_t data_read = 0;
|
|
|
|
const size_t chunk_size = 1;
|
|
|
|
uint8_t *buffer = ta_zalloc_size(wl, chunk_size);
|
|
|
|
if (!buffer)
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
while ((data_read = read(wl->dnd_fd, buffer + offset, chunk_size)) > 0) {
|
|
|
|
offset += data_read;
|
|
|
|
buffer = ta_realloc_size(wl, buffer, offset + chunk_size);
|
|
|
|
memset(buffer + offset, 0, chunk_size);
|
|
|
|
if (!buffer)
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
MP_VERBOSE(wl, "Read %td bytes from the DND fd\n", offset);
|
|
|
|
|
|
|
|
struct bstr file_list = bstr0(buffer);
|
|
|
|
mp_event_drop_mime_data(wl->vo->input_ctx, wl->dnd_mime_type,
|
|
|
|
file_list, wl->dnd_action);
|
|
|
|
talloc_free(buffer);
|
|
|
|
end:
|
|
|
|
talloc_free(wl->dnd_mime_type);
|
|
|
|
wl->dnd_mime_type = NULL;
|
|
|
|
wl->dnd_mime_score = 0;
|
2013-02-28 18:55:02 +00:00
|
|
|
}
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
if (fdp.revents & (POLLIN | POLLERR | POLLHUP)) {
|
|
|
|
close(wl->dnd_fd);
|
|
|
|
wl->dnd_fd = -1;
|
2013-02-28 18:55:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
static char **get_displays_spanned(struct vo_wayland_state *wl)
|
2013-02-28 18:55:02 +00:00
|
|
|
{
|
2017-10-01 20:16:49 +00:00
|
|
|
char **names = NULL;
|
|
|
|
int displays_spanned = 0;
|
2013-02-28 18:55:02 +00:00
|
|
|
struct vo_wayland_output *output;
|
2017-10-09 01:08:36 +00:00
|
|
|
wl_list_for_each(output, &wl->output_list, link) {
|
2017-10-01 20:16:49 +00:00
|
|
|
if (output->has_surface)
|
|
|
|
MP_TARRAY_APPEND(NULL, names, displays_spanned,
|
|
|
|
talloc_strdup(NULL, output->model));
|
2013-02-28 18:55:02 +00:00
|
|
|
}
|
2017-10-01 20:16:49 +00:00
|
|
|
MP_TARRAY_APPEND(NULL, names, displays_spanned, NULL);
|
|
|
|
return names;
|
2013-02-28 18:55:02 +00:00
|
|
|
}
|
|
|
|
|
2016-07-21 12:28:58 +00:00
|
|
|
int vo_wayland_control(struct vo *vo, int *events, int request, void *arg)
|
2013-05-15 16:17:18 +00:00
|
|
|
{
|
2017-10-01 20:16:49 +00:00
|
|
|
struct vo_wayland_state *wl = vo->wl;
|
2019-11-30 02:00:49 +00:00
|
|
|
struct mp_vo_opts *opts = wl->vo_opts;
|
2017-10-01 20:16:49 +00:00
|
|
|
wl_display_dispatch_pending(wl->display);
|
2013-05-19 11:04:59 +00:00
|
|
|
|
2013-05-15 16:17:18 +00:00
|
|
|
switch (request) {
|
2017-10-09 01:08:36 +00:00
|
|
|
case VOCTRL_CHECK_EVENTS: {
|
|
|
|
check_dnd_fd(wl);
|
|
|
|
*events |= wl->pending_vo_events;
|
|
|
|
wl->pending_vo_events = 0;
|
|
|
|
return VO_TRUE;
|
|
|
|
}
|
2019-11-30 02:00:49 +00:00
|
|
|
case VOCTRL_VO_OPTS_CHANGED: {
|
|
|
|
void *opt;
|
|
|
|
while (m_config_cache_get_next_changed(wl->vo_opts_cache, &opt)) {
|
|
|
|
if (opt == &opts->fullscreen)
|
2020-01-04 21:51:09 +00:00
|
|
|
toggle_fullscreen(wl);
|
2019-11-30 02:00:49 +00:00
|
|
|
if (opt == &opts->window_minimized)
|
2020-01-04 21:51:09 +00:00
|
|
|
do_minimize(wl);
|
2019-11-30 02:00:49 +00:00
|
|
|
if (opt == &opts->window_maximized)
|
2020-01-04 21:51:09 +00:00
|
|
|
toggle_maximized(wl);
|
2019-12-02 00:55:52 +00:00
|
|
|
if (opt == &opts->border)
|
2020-01-04 21:51:09 +00:00
|
|
|
set_border_decorations(wl, opts->border);
|
2019-11-30 02:00:49 +00:00
|
|
|
}
|
|
|
|
return VO_TRUE;
|
|
|
|
}
|
2017-10-09 01:08:36 +00:00
|
|
|
case VOCTRL_GET_DISPLAY_NAMES: {
|
|
|
|
*(char ***)arg = get_displays_spanned(wl);
|
|
|
|
return VO_TRUE;
|
|
|
|
}
|
|
|
|
case VOCTRL_GET_UNFS_WINDOW_SIZE: {
|
|
|
|
int *s = arg;
|
|
|
|
s[0] = mp_rect_w(wl->geometry)*wl->scaling;
|
|
|
|
s[1] = mp_rect_h(wl->geometry)*wl->scaling;
|
|
|
|
return VO_TRUE;
|
|
|
|
}
|
|
|
|
case VOCTRL_SET_UNFS_WINDOW_SIZE: {
|
|
|
|
int *s = arg;
|
2019-12-02 00:55:52 +00:00
|
|
|
if (!wl->vo_opts->fullscreen && !wl->vo_opts->window_maximized) {
|
2017-10-09 01:08:36 +00:00
|
|
|
wl->geometry.x0 = 0;
|
|
|
|
wl->geometry.y0 = 0;
|
|
|
|
wl->geometry.x1 = s[0]/wl->scaling;
|
|
|
|
wl->geometry.y1 = s[1]/wl->scaling;
|
2020-02-06 02:47:10 +00:00
|
|
|
wl->window_size = wl->geometry;
|
2017-10-09 01:08:36 +00:00
|
|
|
wl->pending_vo_events |= VO_EVENT_RESIZE;
|
2017-10-01 20:16:49 +00:00
|
|
|
}
|
2017-10-09 01:08:36 +00:00
|
|
|
return VO_TRUE;
|
|
|
|
}
|
|
|
|
case VOCTRL_GET_DISPLAY_FPS: {
|
|
|
|
if (!wl->current_output)
|
|
|
|
return VO_NOTAVAIL;
|
|
|
|
*(double *)arg = wl->current_output->refresh_rate;
|
|
|
|
return VO_TRUE;
|
|
|
|
}
|
|
|
|
case VOCTRL_UPDATE_WINDOW_TITLE:
|
2020-08-12 14:41:56 +00:00
|
|
|
return update_window_title(wl, (const char *)arg);
|
2017-10-09 01:08:36 +00:00
|
|
|
case VOCTRL_SET_CURSOR_VISIBILITY:
|
2020-01-12 00:32:36 +00:00
|
|
|
if (!wl->pointer)
|
|
|
|
return VO_NOTAVAIL;
|
2017-10-09 01:08:36 +00:00
|
|
|
return set_cursor_visibility(wl, *(bool *)arg);
|
|
|
|
case VOCTRL_KILL_SCREENSAVER:
|
|
|
|
return set_screensaver_inhibitor(wl, true);
|
|
|
|
case VOCTRL_RESTORE_SCREENSAVER:
|
|
|
|
return set_screensaver_inhibitor(wl, false);
|
2013-05-15 16:17:18 +00:00
|
|
|
}
|
2013-05-16 14:43:34 +00:00
|
|
|
|
2017-10-01 20:16:49 +00:00
|
|
|
return VO_NOTIMPL;
|
2015-08-19 19:41:26 +00:00
|
|
|
}
|
|
|
|
|
2019-10-10 19:14:40 +00:00
|
|
|
void vo_wayland_sync_shift(struct vo_wayland_state *wl)
|
|
|
|
{
|
|
|
|
for (int i = wl->sync_size - 1; i > 0; --i) {
|
|
|
|
wl->sync[i] = wl->sync[i-1];
|
|
|
|
}
|
|
|
|
struct vo_wayland_sync sync = {0, 0, 0, 0};
|
|
|
|
wl->sync[0] = sync;
|
|
|
|
}
|
|
|
|
|
|
|
|
int last_available_sync(struct vo_wayland_state *wl)
|
|
|
|
{
|
|
|
|
for (int i = wl->sync_size - 1; i > -1; --i) {
|
|
|
|
if (!wl->sync[i].filled)
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void queue_new_sync(struct vo_wayland_state *wl)
|
|
|
|
{
|
|
|
|
wl->sync_size += 1;
|
|
|
|
wl->sync = talloc_realloc(wl, wl->sync, struct vo_wayland_sync, wl->sync_size);
|
|
|
|
vo_wayland_sync_shift(wl);
|
|
|
|
wl->sync[0].sbc = wl->user_sbc;
|
|
|
|
}
|
|
|
|
|
|
|
|
void wayland_sync_swap(struct vo_wayland_state *wl)
|
|
|
|
{
|
|
|
|
int index = wl->sync_size - 1;
|
2020-04-09 16:17:03 +00:00
|
|
|
int64_t mp_time = mp_time_us();
|
2019-10-10 19:14:40 +00:00
|
|
|
|
|
|
|
wl->last_skipped_vsyncs = 0;
|
|
|
|
|
2020-04-09 16:17:03 +00:00
|
|
|
// If these are the same, presentation feedback has not been received.
|
|
|
|
// This will happen if the window is obscured/hidden in some way. Update
|
|
|
|
// the values based on the difference in mp_time.
|
2019-10-10 19:14:40 +00:00
|
|
|
if (wl->sync[index].ust == wl->last_ust && wl->last_ust) {
|
2020-04-09 16:17:03 +00:00
|
|
|
wl->sync[index].ust += mp_time - wl->sync[index].last_mp_time;
|
2019-10-10 19:14:40 +00:00
|
|
|
wl->sync[index].msc += 1;
|
|
|
|
wl->sync[index].sbc += 1;
|
|
|
|
}
|
2020-04-09 16:17:03 +00:00
|
|
|
wl->sync[index].last_mp_time = mp_time;
|
2019-10-10 19:14:40 +00:00
|
|
|
|
|
|
|
int64_t ust_passed = wl->sync[index].ust ? wl->sync[index].ust - wl->last_ust: 0;
|
|
|
|
wl->last_ust = wl->sync[index].ust;
|
|
|
|
int64_t msc_passed = wl->sync[index].msc ? wl->sync[index].msc - wl->last_msc: 0;
|
|
|
|
wl->last_msc = wl->sync[index].msc;
|
|
|
|
int64_t sbc_passed = wl->sync[index].sbc ? wl->sync[index].sbc - wl->last_sbc: 0;
|
|
|
|
wl->last_sbc = wl->sync[index].sbc;
|
|
|
|
|
|
|
|
if (msc_passed && ust_passed)
|
|
|
|
wl->vsync_duration = ust_passed / msc_passed;
|
|
|
|
|
|
|
|
if (sbc_passed) {
|
|
|
|
struct timespec ts;
|
|
|
|
if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint64_t now_monotonic = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000;
|
2020-04-09 16:17:03 +00:00
|
|
|
uint64_t ust_mp_time = mp_time - (now_monotonic - wl->sync[index].ust);
|
2019-10-10 19:14:40 +00:00
|
|
|
wl->last_sbc_mp_time = ust_mp_time;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!wl->sync[index].sbc)
|
|
|
|
return;
|
|
|
|
|
|
|
|
wl->last_queue_display_time = wl->last_sbc_mp_time + sbc_passed*wl->vsync_duration;
|
|
|
|
}
|
|
|
|
|
2016-07-21 11:25:30 +00:00
|
|
|
void vo_wayland_wakeup(struct vo *vo)
|
2015-08-19 19:41:26 +00:00
|
|
|
{
|
2017-10-01 20:16:49 +00:00
|
|
|
struct vo_wayland_state *wl = vo->wl;
|
2016-07-21 11:25:30 +00:00
|
|
|
(void)write(wl->wakeup_pipe[1], &(char){0}, 1);
|
|
|
|
}
|
2015-08-19 19:41:26 +00:00
|
|
|
|
2020-01-30 17:19:22 +00:00
|
|
|
void vo_wayland_wait_frame(struct vo_wayland_state *wl)
|
2019-10-07 20:58:36 +00:00
|
|
|
{
|
|
|
|
struct pollfd fds[1] = {
|
|
|
|
{.fd = wl->display_fd, .events = POLLIN },
|
|
|
|
};
|
|
|
|
|
|
|
|
double vblank_time = 1e6 / wl->current_output->refresh_rate;
|
2020-01-30 17:19:22 +00:00
|
|
|
int64_t finish_time = mp_time_us() + vblank_time;
|
2019-10-07 20:58:36 +00:00
|
|
|
|
2019-10-10 19:14:40 +00:00
|
|
|
while (wl->frame_wait && finish_time > mp_time_us()) {
|
2019-10-07 20:58:36 +00:00
|
|
|
|
2020-02-07 05:54:57 +00:00
|
|
|
int poll_time = ceil((double)(finish_time - mp_time_us()) / 1000);
|
2019-10-07 20:58:36 +00:00
|
|
|
if (poll_time < 0) {
|
|
|
|
poll_time = 0;
|
|
|
|
}
|
|
|
|
|
2020-02-07 05:54:57 +00:00
|
|
|
while (wl_display_prepare_read(wl->display) != 0)
|
|
|
|
wl_display_dispatch_pending(wl->display);
|
|
|
|
wl_display_flush(wl->display);
|
|
|
|
|
2019-10-07 20:58:36 +00:00
|
|
|
poll(fds, 1, poll_time);
|
|
|
|
|
2020-07-30 20:21:57 +00:00
|
|
|
if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
|
|
|
|
wl_display_cancel_read(wl->display);
|
|
|
|
} else {
|
|
|
|
wl_display_read_events(wl->display);
|
|
|
|
}
|
|
|
|
|
|
|
|
wl_display_dispatch_pending(wl->display);
|
2019-10-07 20:58:36 +00:00
|
|
|
}
|
2020-07-30 20:21:57 +00:00
|
|
|
|
|
|
|
if (wl_display_get_error(wl->display) == 0)
|
|
|
|
wl_display_roundtrip(wl->display);
|
2019-10-07 20:58:36 +00:00
|
|
|
}
|
|
|
|
|
2016-07-21 11:25:30 +00:00
|
|
|
void vo_wayland_wait_events(struct vo *vo, int64_t until_time_us)
|
|
|
|
{
|
2017-10-01 20:16:49 +00:00
|
|
|
struct vo_wayland_state *wl = vo->wl;
|
|
|
|
|
|
|
|
if (wl->display_fd == -1)
|
|
|
|
return;
|
2015-08-19 19:41:26 +00:00
|
|
|
|
2016-07-21 11:25:30 +00:00
|
|
|
struct pollfd fds[2] = {
|
2017-10-01 20:16:49 +00:00
|
|
|
{.fd = wl->display_fd, .events = POLLIN },
|
|
|
|
{.fd = wl->wakeup_pipe[0], .events = POLLIN },
|
2016-07-21 11:25:30 +00:00
|
|
|
};
|
2015-08-19 19:41:26 +00:00
|
|
|
|
2016-07-21 11:25:30 +00:00
|
|
|
int64_t wait_us = until_time_us - mp_time_us();
|
2016-08-26 18:22:33 +00:00
|
|
|
int timeout_ms = MPCLAMP((wait_us + 999) / 1000, 0, 10000);
|
2015-08-19 19:41:26 +00:00
|
|
|
|
2020-07-29 15:05:07 +00:00
|
|
|
while (wl_display_prepare_read(wl->display) != 0)
|
|
|
|
wl_display_dispatch_pending(wl->display);
|
|
|
|
wl_display_flush(wl->display);
|
2016-07-29 01:30:07 +00:00
|
|
|
|
2016-07-21 11:25:30 +00:00
|
|
|
poll(fds, 2, timeout_ms);
|
2015-08-19 19:41:26 +00:00
|
|
|
|
2016-07-29 01:30:07 +00:00
|
|
|
if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
|
2017-10-01 20:16:49 +00:00
|
|
|
MP_FATAL(wl, "Error occurred on the display fd, closing\n");
|
2020-07-29 15:05:07 +00:00
|
|
|
wl_display_cancel_read(wl->display);
|
2017-10-01 20:16:49 +00:00
|
|
|
close(wl->display_fd);
|
|
|
|
wl->display_fd = -1;
|
2016-07-21 11:25:30 +00:00
|
|
|
mp_input_put_key(vo->input_ctx, MP_KEY_CLOSE_WIN);
|
2020-07-29 15:05:07 +00:00
|
|
|
} else {
|
|
|
|
wl_display_read_events(wl->display);
|
2016-07-21 11:25:30 +00:00
|
|
|
}
|
2016-07-29 01:30:07 +00:00
|
|
|
|
|
|
|
if (fds[0].revents & POLLIN)
|
2020-07-30 20:21:57 +00:00
|
|
|
wl_display_dispatch_pending(wl->display);
|
2016-07-29 01:30:07 +00:00
|
|
|
|
|
|
|
if (fds[1].revents & POLLIN)
|
|
|
|
mp_flush_wakeup_pipe(wl->wakeup_pipe[0]);
|
2015-08-19 19:41:26 +00:00
|
|
|
}
|