summaryrefslogtreecommitdiffstats
path: root/video/out/wayland_common.c
diff options
context:
space:
mode:
Diffstat (limited to 'video/out/wayland_common.c')
-rw-r--r--video/out/wayland_common.c356
1 files changed, 79 insertions, 277 deletions
diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c
index 0e44dddef6..d4b7a1eecc 100644
--- a/video/out/wayland_common.c
+++ b/video/out/wayland_common.c
@@ -40,6 +40,7 @@
#include "vo.h"
#include "win_state.h"
+#include "osdep/io.h"
#include "osdep/timer.h"
#include "input/input.h"
@@ -57,7 +58,7 @@ static void schedule_resize(struct vo_wayland_state *wl,
int32_t width,
int32_t height);
-static void vo_wayland_fullscreen (struct vo *vo);
+static void vo_wayland_fullscreen(struct vo *vo);
static const struct wl_callback_listener frame_listener;
@@ -140,6 +141,9 @@ static void ssurface_handle_configure(void *data,
int32_t height)
{
struct vo_wayland_state *wl = data;
+ float win_aspect = wl->window.aspect;
+ if (!wl->window.is_fullscreen)
+ width = win_aspect * height;
schedule_resize(wl, edges, width, height);
}
@@ -225,7 +229,7 @@ static void surface_handle_enter(void *data,
}
}
- wl->window.events |= VO_EVENT_WIN_STATE;
+ wl->window.events |= VO_EVENT_WIN_STATE | VO_EVENT_RESIZE;
}
static void surface_handle_leave(void *data,
@@ -521,104 +525,9 @@ static const struct wl_seat_listener seat_listener = {
seat_handle_name,
};
-static void data_offer_handle_offer(void *data,
- struct wl_data_offer *offer,
- const char *mime_type)
-{
- struct vo_wayland_state *wl = data;
- if (strcmp(mime_type, "text/uri-list") != 0)
- MP_VERBOSE(wl, "unsupported mime type for drag and drop: %s\n", mime_type);
-}
-
-static const struct wl_data_offer_listener data_offer_listener = {
- data_offer_handle_offer,
-};
-
-static void data_device_handle_data_offer(void *data,
- struct wl_data_device *wl_data_device,
- struct wl_data_offer *id)
-{
- struct vo_wayland_state *wl = data;
- if (wl->input.offer) {
- MP_DBG(wl, "There is already a dnd entry point.\n");
- wl_data_offer_destroy(wl->input.offer);
- }
-
- wl->input.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_data_device,
- 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->input.offer != id)
- MP_FATAL(wl, "Fatal dnd error (Please report this issue)\n");
-
- wl_data_offer_accept(id, serial, "text/uri-list");
-}
-
-static void data_device_handle_leave(void *data,
- struct wl_data_device *wl_data_device)
-{
- struct vo_wayland_state *wl = data;
- if (wl->input.offer) {
- wl_data_offer_destroy(wl->input.offer);
- wl->input.offer = NULL;
- }
- // dnd fd is closed on POLLHUP
-}
-
-static void data_device_handle_motion(void *data,
- struct wl_data_device *wl_data_device,
- uint32_t time,
- wl_fixed_t x,
- wl_fixed_t y)
-{
-}
-
-static void data_device_handle_drop(void *data,
- struct wl_data_device *wl_data_device)
-{
- struct vo_wayland_state *wl = data;
-
- int pipefd[2];
-
- if (pipe(pipefd) == -1) {
- MP_FATAL(wl, "can't create pipe for dnd communication\n");
- return;
- }
-
- wl->input.dnd_fd = pipefd[0];
- wl_data_offer_receive(wl->input.offer, "text/uri-list", pipefd[1]);
- close(pipefd[1]);
-}
-
-static void data_device_handle_selection(void *data,
- struct wl_data_device *wl_data_device,
- struct wl_data_offer *id)
-{
-}
-
-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
-};
-
-static void registry_handle_global (void *data,
- struct wl_registry *reg,
- uint32_t id,
- const char *interface,
- uint32_t version)
+static void registry_handle_global(void *data, struct wl_registry *reg,
+ uint32_t id, const char *interface,
+ uint32_t version)
{
struct vo_wayland_state *wl = data;
@@ -653,22 +562,11 @@ static void registry_handle_global (void *data,
wl_list_insert(&wl->display.output_list, &output->link);
}
- else if (strcmp(interface, "wl_data_device_manager") == 0) {
-
- wl->input.devman = wl_registry_bind(reg,
- id,
- &wl_data_device_manager_interface,
- 1);
- }
-
else if (strcmp(interface, "wl_seat") == 0) {
wl->input.seat = wl_registry_bind(reg, id, &wl_seat_interface, 4);
wl_seat_add_listener(wl->input.seat, &seat_listener, wl);
- wl->input.datadev = wl_data_device_manager_get_data_device(
- wl->input.devman, wl->input.seat);
- wl_data_device_add_listener(wl->input.datadev, &data_device_listener, wl);
}
else if (strcmp(interface, "wl_subcompositor") == 0) {
@@ -678,9 +576,9 @@ static void registry_handle_global (void *data,
}
}
-static void registry_handle_global_remove (void *data,
- struct wl_registry *registry,
- uint32_t id)
+static void registry_handle_global_remove(void *data,
+ struct wl_registry *registry,
+ uint32_t id)
{
}
@@ -767,11 +665,13 @@ static void schedule_resize(struct vo_wayland_state *wl,
MP_DBG(wl, "schedule resize: %dx%d\n", width, height);
- if (width < minimum_size)
- width = minimum_size;
-
- if (height < minimum_size)
- height = minimum_size;
+ width = MPMAX(minimum_size, width);
+ height = MPMAX(minimum_size, height);
+ if (wl->display.current_output) {
+ int scale = wl->display.current_output->scale;
+ width = MPMIN(width, wl->display.current_output->width /scale);
+ height = MPMIN(height, wl->display.current_output->height/scale);
+ }
// don't keep the aspect ration in fullscreen mode, because the compositor
// shows the desktop in the border regions if the video has not the same
@@ -807,9 +707,7 @@ static void schedule_resize(struct vo_wayland_state *wl,
wl->window.sh_height = height;
wl->window.sh_x = x;
wl->window.sh_y = y;
- wl->window.events |= VO_EVENT_WIN_STATE | VO_EVENT_RESIZE;
- wl->vo->dwidth = width;
- wl->vo->dheight = height;
+ wl->window.events |= VO_EVENT_RESIZE;
}
static void frame_callback(void *data,
@@ -833,17 +731,13 @@ static void frame_callback(void *data,
wl_callback_add_listener(wl->frame.callback, &frame_listener, wl);
wl_surface_commit(wl->window.video_surface);
-
- wl->frame.last_us = mp_time_us();
- wl->frame.pending = true;
- wl->frame.dropping = false;
}
static const struct wl_callback_listener frame_listener = {
frame_callback
};
-static bool create_display (struct vo_wayland_state *wl)
+static bool create_display(struct vo_wayland_state *wl)
{
if (wl->vo->probing && !getenv("XDG_RUNTIME_DIR"))
return false;
@@ -868,7 +762,7 @@ static bool create_display (struct vo_wayland_state *wl)
return true;
}
-static void destroy_display (struct vo_wayland_state *wl)
+static void destroy_display(struct vo_wayland_state *wl)
{
struct vo_wayland_output *output = NULL;
struct vo_wayland_output *tmp = NULL;
@@ -902,7 +796,7 @@ static void destroy_display (struct vo_wayland_state *wl)
}
}
-static bool create_window (struct vo_wayland_state *wl)
+static bool create_window(struct vo_wayland_state *wl)
{
wl->window.video_surface =
wl_compositor_create_surface(wl->display.compositor);
@@ -929,7 +823,7 @@ static bool create_window (struct vo_wayland_state *wl)
return true;
}
-static void destroy_window (struct vo_wayland_state *wl)
+static void destroy_window(struct vo_wayland_state *wl)
{
if (wl->window.shell_surface)
wl_shell_surface_destroy(wl->window.shell_surface);
@@ -941,7 +835,7 @@ static void destroy_window (struct vo_wayland_state *wl)
wl_callback_destroy(wl->frame.callback);
}
-static bool create_cursor (struct vo_wayland_state *wl)
+static bool create_cursor(struct vo_wayland_state *wl)
{
if (!wl->display.shm) {
MP_ERR(wl->vo, "no shm interface available\n");
@@ -961,7 +855,7 @@ static bool create_cursor (struct vo_wayland_state *wl)
return true;
}
-static void destroy_cursor (struct vo_wayland_state *wl)
+static void destroy_cursor(struct vo_wayland_state *wl)
{
if (wl->cursor.theme)
wl_cursor_theme_destroy(wl->cursor.theme);
@@ -970,7 +864,7 @@ static void destroy_cursor (struct vo_wayland_state *wl)
wl_surface_destroy(wl->cursor.surface);
}
-static bool create_input (struct vo_wayland_state *wl)
+static bool create_input(struct vo_wayland_state *wl)
{
wl->input.xkb.context = xkb_context_new(0);
@@ -979,12 +873,10 @@ static bool create_input (struct vo_wayland_state *wl)
return false;
}
- wl->input.dnd_fd = -1;
-
return true;
}
-static void destroy_input (struct vo_wayland_state *wl)
+static void destroy_input(struct vo_wayland_state *wl)
{
if (wl->input.keyboard) {
wl_keyboard_destroy(wl->input.keyboard);
@@ -998,24 +890,21 @@ static void destroy_input (struct vo_wayland_state *wl)
if (wl->input.pointer)
wl_pointer_destroy(wl->input.pointer);
- if (wl->input.datadev)
- wl_data_device_destroy(wl->input.datadev);
-
- if (wl->input.devman)
- wl_data_device_manager_destroy(wl->input.devman);
-
if (wl->input.seat)
wl_seat_destroy(wl->input.seat);
}
/*** mplayer2 interface ***/
-int vo_wayland_init (struct vo *vo)
+int vo_wayland_init(struct vo *vo)
{
vo->wayland = talloc_zero(NULL, struct vo_wayland_state);
struct vo_wayland_state *wl = vo->wayland;
- wl->vo = vo;
- wl->log = mp_log_new(wl, vo->log, "wayland");
+ *wl = (struct vo_wayland_state){
+ .vo = vo,
+ .log = mp_log_new(wl, vo->log, "wayland"),
+ .wakeup_pipe = {-1, -1},
+ };
wl_list_init(&wl->display.output_list);
@@ -1045,23 +934,25 @@ int vo_wayland_init (struct vo *vo)
o->refresh_rate / 1000.0f);
}
- vo->event_fd = wl->display.display_fd;
+ mp_make_wakeup_pipe(wl->wakeup_pipe);
return true;
}
-void vo_wayland_uninit (struct vo *vo)
+void vo_wayland_uninit(struct vo *vo)
{
struct vo_wayland_state *wl = vo->wayland;
destroy_cursor(wl);
destroy_window(wl);
destroy_display(wl);
destroy_input(wl);
+ for (int n = 0; n < 2; n++)
+ close(wl->wakeup_pipe[n]);
talloc_free(wl);
vo->wayland = NULL;
}
-static void vo_wayland_ontop (struct vo *vo)
+static void vo_wayland_ontop(struct vo *vo)
{
struct vo_wayland_state *wl = vo->wayland;
MP_DBG(wl, "going ontop\n");
@@ -1070,7 +961,7 @@ static void vo_wayland_ontop (struct vo *vo)
schedule_resize(wl, 0, wl->window.width, wl->window.height);
}
-static void vo_wayland_fullscreen (struct vo *vo)
+static void vo_wayland_fullscreen(struct vo *vo)
{
struct vo_wayland_state *wl = vo->wayland;
if (!wl->display.shell)
@@ -1083,6 +974,9 @@ static void vo_wayland_fullscreen (struct vo *vo)
wl->window.is_fullscreen = true;
wl->window.p_width = wl->window.width;
wl->window.p_height = wl->window.height;
+ if (wl->display.current_output)
+ schedule_resize(wl, 0, wl->display.current_output->width,
+ wl->display.current_output->height);
wl_shell_surface_set_fullscreen(wl->window.shell_surface,
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
0, fs_output);
@@ -1096,112 +990,6 @@ static void vo_wayland_fullscreen (struct vo *vo)
}
}
-static int vo_wayland_poll (struct vo *vo, int timeout_msecs)
-{
- struct vo_wayland_state *wl = vo->wayland;
- struct wl_display *dp = wl->display.display;
-
- wl_display_dispatch_pending(dp);
- wl_display_flush(dp);
-
- struct pollfd fd = {
- wl->display.display_fd,
- POLLIN | POLLOUT | POLLERR | POLLHUP,
- 0
- };
-
- /* wl_display_dispatch is blocking
- * wl_dipslay_dispatch_pending is non-blocking but does not read from the fd
- *
- * when pausing no input events get queued so we have to check if there
- * are events to read from the file descriptor through poll */
- int polled;
- if ((polled = poll(&fd, 1, timeout_msecs)) > 0) {
- if (fd.revents & POLLERR || fd.revents & POLLHUP) {
- MP_FATAL(wl, "error occurred on the display fd: "
- "closing file descriptor\n");
- close(wl->display.display_fd);
- mp_input_put_key(vo->input_ctx, MP_KEY_CLOSE_WIN);
- }
- if (fd.revents & POLLIN)
- wl_display_dispatch(dp);
- if (fd.revents & POLLOUT)
- wl_display_flush(dp);
- }
-
- return polled;
-}
-
-static int vo_wayland_check_events (struct vo *vo)
-{
- struct vo_wayland_state *wl = vo->wayland;
-
- vo_wayland_poll(vo, 0);
-
- /* If drag & drop was ended poll the file descriptor from the offer if
- * there is data to read.
- * We only accept the mime type text/uri-list.
- */
- if (wl->input.dnd_fd != -1) {
- struct pollfd fd = {
- wl->input.dnd_fd,
- POLLIN | POLLERR | POLLHUP,
- 0
- };
-
- if (poll(&fd, 1, 0) > 0) {
- if (fd.revents & POLLERR) {
- MP_ERR(wl, "error occurred on the drag&drop fd\n");
- close(wl->input.dnd_fd);
- wl->input.dnd_fd = -1;
- }
-
- if (fd.revents & POLLIN) {
- int const to_read = 2048;
- char *buffer = malloc(to_read);
- size_t buffer_len = to_read;
- size_t str_len = 0;
- int has_read = 0;
-
- if (!buffer)
- goto fail;
-
- while (0 < (has_read = read(fd.fd, buffer+str_len, to_read))) {
- if (buffer_len + to_read < buffer_len) {
- MP_ERR(wl, "Integer overflow while reading from fd\n");
- break;
- }
-
- str_len += has_read;
- buffer_len += to_read;
- void *ptr = realloc(buffer, buffer_len);
- if (!ptr)
- break;
- buffer = ptr;
-
- if (has_read < to_read) {
- buffer[str_len] = 0;
- struct bstr file_list = bstr0(buffer);
- mp_event_drop_mime_data(vo->input_ctx, "text/uri-list",
- file_list, DND_REPLACE);
- break;
- }
- }
- fail:
- free(buffer);
- }
-
- if (fd.revents & POLLHUP) {
- close(wl->input.dnd_fd);
- wl->input.dnd_fd = -1;
- }
- }
- }
-
- // window events are reset by the resizing code
- return wl->window.events;
-}
-
static void vo_wayland_update_screeninfo(struct vo *vo, struct mp_rect *screenrc)
{
struct vo_wayland_state *wl = vo->wayland;
@@ -1245,14 +1033,15 @@ static void vo_wayland_update_screeninfo(struct vo *vo, struct mp_rect *screenrc
wl->window.fs_height = screenrc->y1;
}
-int vo_wayland_control (struct vo *vo, int *events, int request, void *arg)
+int vo_wayland_control(struct vo *vo, int *events, int request, void *arg)
{
struct vo_wayland_state *wl = vo->wayland;
wl_display_dispatch_pending(wl->display.display);
switch (request) {
case VOCTRL_CHECK_EVENTS:
- *events |= vo_wayland_check_events(vo);
+ *events |= wl->window.events;
+ wl->window.events = 0;
return VO_TRUE;
case VOCTRL_FULLSCREEN:
vo->opts->fullscreen = !vo->opts->fullscreen;
@@ -1262,9 +1051,11 @@ int vo_wayland_control (struct vo *vo, int *events, int request, void *arg)
vo_wayland_ontop(vo);
return VO_TRUE;
case VOCTRL_GET_UNFS_WINDOW_SIZE: {
- int *s = arg;
- s[0] = wl->window.width;
- s[1] = wl->window.height;
+ int *s = arg, scale = 1;
+ if (wl->display.current_output)
+ scale = wl->display.current_output->scale;
+ s[0] = scale*wl->window.width;
+ s[1] = scale*wl->window.height;
return VO_TRUE;
}
case VOCTRL_SET_UNFS_WINDOW_SIZE: {
@@ -1300,7 +1091,7 @@ int vo_wayland_control (struct vo *vo, int *events, int request, void *arg)
return VO_NOTIMPL;
}
-bool vo_wayland_config (struct vo *vo)
+bool vo_wayland_config(struct vo *vo)
{
struct vo_wayland_state *wl = vo->wayland;
@@ -1331,29 +1122,40 @@ void vo_wayland_request_frame(struct vo *vo, void *data, vo_wayland_frame_cb cb)
frame_callback(wl, NULL, 0);
}
-bool vo_wayland_wait_frame(struct vo *vo)
+void vo_wayland_wakeup(struct vo *vo)
{
struct vo_wayland_state *wl = vo->wayland;
+ (void)write(wl->wakeup_pipe[1], &(char){0}, 1);
+}
- if (!wl->frame.callback || wl->frame.dropping)
- return false;
+void vo_wayland_wait_events(struct vo *vo, int64_t until_time_us)
+{
+ struct vo_wayland_state *wl = vo->wayland;
+ struct wl_display *dp = wl->display.display;
- // If mpv isn't receiving frame callbacks (for 100ms), this usually means that
- // mpv window is not visible and compositor tells kindly to not draw anything.
- while (!wl->frame.pending) {
- int64_t timeout = wl->frame.last_us + (100 * 1000) - mp_time_us();
+ struct pollfd fds[2] = {
+ {.fd = wl->display.display_fd, .events = POLLIN },
+ {.fd = wl->wakeup_pipe[0], .events = POLLIN },
+ };
- if (timeout <= 0)
- break;
+ int64_t wait_us = until_time_us - mp_time_us();
+ int timeout_ms = MPCLAMP((wait_us + 500) / 1000, 0, 10000);
- if (vo_wayland_poll(vo, timeout) <= 0)
- break;
+ wl_display_dispatch_pending(dp);
+ wl_display_flush(dp);
+
+ poll(fds, 2, timeout_ms);
+
+ if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
+ MP_FATAL(wl, "error occurred on the display fd: "
+ "closing file descriptor\n");
+ close(wl->display.display_fd);
+ mp_input_put_key(vo->input_ctx, MP_KEY_CLOSE_WIN);
}
- wl->frame.dropping = !wl->frame.pending;
- wl->frame.pending = false;
+ if (fds[0].revents & POLLIN)
+ wl_display_dispatch(dp);
- // Return false if the frame callback was not received
- // Handler should act accordingly.
- return !wl->frame.dropping;
+ if (fds[1].revents & POLLIN)
+ mp_flush_wakeup_pipe(wl->wakeup_pipe[0]);
}