diff options
Diffstat (limited to 'video/out/wayland_common.c')
-rw-r--r-- | video/out/wayland_common.c | 432 |
1 files changed, 140 insertions, 292 deletions
diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c index b1f08fce4d..b3bc65d2ff 100644 --- a/video/out/wayland_common.c +++ b/video/out/wayland_common.c @@ -26,19 +26,16 @@ #include <inttypes.h> #include <limits.h> #include <assert.h> -#include <fcntl.h> +#include <poll.h> #include <unistd.h> #include <sys/mman.h> -#include <sys/epoll.h> -#include <sys/timerfd.h> #include <linux/input.h> #include "config.h" #include "core/bstr.h" #include "core/options.h" #include "core/mp_msg.h" -#include "core/mp_fifo.h" #include "libavutil/common.h" #include "talloc.h" @@ -57,13 +54,16 @@ #define MOD_ALT_MASK 0x02 #define MOD_CONTROL_MASK 0x04 -#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) - static int lookupkey(int key); static void hide_cursor(struct vo_wayland_state * wl); static void show_cursor(struct vo_wayland_state * wl); +static void resize_window(struct vo_wayland_state *wl, + uint32_t edges, + int32_t width, + int32_t height); +static void vo_wayland_fullscreen (struct vo *vo); /*** wayland interface ***/ @@ -75,16 +75,6 @@ static void ssurface_handle_ping(void *data, wl_shell_surface_pong(shell_surface, serial); } -static void ssurface_schedule_resize(struct vo_wayland_window *window, - int32_t width, - int32_t height) -{ - window->pending_width = width; - window->pending_height = height; - window->resize_needed = 1; - window->events |= VO_EVENT_RESIZE; -} - static void ssurface_handle_configure(void *data, struct wl_shell_surface *shell_surface, uint32_t edges, @@ -92,9 +82,7 @@ static void ssurface_handle_configure(void *data, int32_t height) { struct vo_wayland_state *wl = data; - - wl->window->edges = edges; - ssurface_schedule_resize(wl->window, width, height); + resize_window(wl, edges, width, height); } static void ssurface_handle_popup_done(void *data, @@ -142,20 +130,14 @@ static void output_handle_mode(void *data, int32_t height, int32_t refresh) { - struct vo_wayland_display *d = data; - struct vo_wayland_output *output; + struct vo_wayland_output *output = data; - wl_list_for_each(output, &d->output_list, link) { - if (wl_output == output->output) { - output->width = width; - output->height = height; - if (flags) - output->flags = flags; - } - } + if (!output) + return; - /* one output is enough */ - d->output_mode_received = 1; + output->width = width; + output->height = height; + output->flags = flags; } const struct wl_output_listener output_listener = { @@ -219,15 +201,10 @@ static void keyboard_handle_keymap(void *data, int32_t fd, uint32_t size) { - struct vo_wayland_input *input = ((struct vo_wayland_state *) data)->input; + struct vo_wayland_input *input; char *map_str; - if(!data) { - close(fd); - return; - } - - if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + if(!data || format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { close(fd); return; } @@ -238,8 +215,9 @@ static void keyboard_handle_keymap(void *data, return; } - input->xkb.keymap = xkb_map_new_from_string(input->xkb.context, - map_str, XKB_KEYMAP_FORMAT_TEXT_V1, 0); + input = ((struct vo_wayland_state *) data)->input; + input->xkb.keymap = xkb_keymap_new_from_buffer(input->xkb.context, + map_str, size, XKB_KEYMAP_FORMAT_TEXT_V1, 0); munmap(map_str, size); close(fd); @@ -256,13 +234,6 @@ static void keyboard_handle_keymap(void *data, input->xkb.keymap = NULL; return; } - - input->xkb.control_mask = - 1 << xkb_map_mod_get_index(input->xkb.keymap, "Control"); - input->xkb.alt_mask = - 1 << xkb_map_mod_get_index(input->xkb.keymap, "Mod1"); - input->xkb.shift_mask = - 1 << xkb_map_mod_get_index(input->xkb.keymap, "Shift"); } static void keyboard_handle_enter(void *data, @@ -290,60 +261,24 @@ static void keyboard_handle_key(void *data, struct vo_wayland_state *wl = data; struct vo_wayland_input *input = wl->input; uint32_t code, num_syms; - - struct itimerspec its = {{0, 0}, {0, 0}}; + int mpkey; const xkb_keysym_t *syms; xkb_keysym_t sym; - xkb_mod_mask_t mask; code = key + 8; num_syms = xkb_key_get_syms(input->xkb.state, code, &syms); - mask = xkb_state_serialize_mods(input->xkb.state, - XKB_STATE_DEPRESSED | XKB_STATE_LATCHED); - - input->modifiers = 0; - if (mask & input->xkb.control_mask) - input->modifiers |= MOD_CONTROL_MASK; - if (mask & input->xkb.alt_mask) - input->modifiers |= MOD_ALT_MASK; - if (mask & input->xkb.shift_mask) - input->modifiers |= MOD_SHIFT_MASK; - sym = XKB_KEY_NoSymbol; if (num_syms == 1) sym = syms[0]; - if (sym != XKB_KEY_NoSymbol && state == WL_KEYBOARD_KEY_STATE_PRESSED) { - int mpkey = lookupkey(sym); - if (mpkey) - mplayer_put_key(wl->vo->key_fifo, mpkey); + if (sym != XKB_KEY_NoSymbol && (mpkey = lookupkey(sym))) { + if (state == WL_KEYBOARD_KEY_STATE_PRESSED) + mp_input_put_key(wl->vo->input_ctx, mpkey | MP_KEY_STATE_DOWN); + else + mp_input_put_key(wl->vo->input_ctx, mpkey | MP_KEY_STATE_UP); } - - if (state == WL_KEYBOARD_KEY_STATE_RELEASED && key == input->repeat.key) { - input->repeat.sym = 0; - input->repeat.key = 0; - input->repeat.time = 0; - } - else if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { - if (input->repeat.key == key) { - its.it_interval.tv_sec = 0; - its.it_interval.tv_nsec = 20 * 1000 * 1000; - its.it_value.tv_sec = 0; - its.it_value.tv_nsec = 100 * 1000 * 1000; - } - else { - input->repeat.sym = sym; - input->repeat.key = key; - input->repeat.time = time; - its.it_interval.tv_sec = 0; - its.it_interval.tv_nsec = 25 * 1000 * 1000; - its.it_value.tv_sec = 0; - its.it_value.tv_nsec = 400 * 1000 * 1000; - } - } - timerfd_settime(input->repeat.timer_fd, 0, &its, NULL); } static void keyboard_handle_modifiers(void *data, @@ -384,13 +319,8 @@ static void pointer_handle_enter(void *data, /* Release the left button on pointer enter again * because after moving the shell surface no release event is sent */ - mplayer_put_key(wl->vo->key_fifo, MP_MOUSE_BTN0); - - if (wl->window->type == TYPE_FULLSCREEN || wl->vo->opts->cursor_autohide_delay == -2) - hide_cursor(wl); - else if (display->cursor.default_cursor) { - show_cursor(wl); - } + mp_input_put_key(wl->vo->input_ctx, MP_MOUSE_BTN0 | MP_KEY_STATE_UP); + show_cursor(wl); } static void pointer_handle_leave(void *data, @@ -398,6 +328,8 @@ static void pointer_handle_leave(void *data, 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, @@ -407,24 +339,11 @@ static void pointer_handle_motion(void *data, wl_fixed_t sy_w) { struct vo_wayland_state *wl = data; - struct vo_wayland_display * display = wl->display; - display->cursor.pointer = pointer; + wl->display->cursor.pointer = pointer; - if (wl->window->type == TYPE_FULLSCREEN) { - show_cursor(wl); - - struct itimerspec its; - int ms = wl->vo->opts->cursor_autohide_delay; - int sec = ms / 1000; - ms %= 1000; - - its.it_interval.tv_sec = 0; - its.it_interval.tv_nsec = 100 * 1000 * 1000; - its.it_value.tv_sec = sec; - its.it_value.tv_nsec = ms * 1000 * 1000; - timerfd_settime(display->cursor.timer_fd, 0, &its, NULL); - } + vo_mouse_movement(wl->vo, wl_fixed_to_int(sx_w), + wl_fixed_to_int(sy_w)); } static void pointer_handle_button(void *data, @@ -436,12 +355,12 @@ static void pointer_handle_button(void *data, { struct vo_wayland_state *wl = data; - mplayer_put_key(wl->vo->key_fifo, MP_MOUSE_BTN0 + (button - BTN_LEFT) | - ((state == WL_POINTER_BUTTON_STATE_PRESSED) ? MP_KEY_STATE_DOWN : 0)); + mp_input_put_key(wl->vo->input_ctx, MP_MOUSE_BTN0 + (button - BTN_LEFT) | + ((state == WL_POINTER_BUTTON_STATE_PRESSED) + ? MP_KEY_STATE_DOWN : MP_KEY_STATE_UP)); if ((button == BTN_LEFT) && (state == WL_POINTER_BUTTON_STATE_PRESSED)) wl_shell_surface_move(wl->window->shell_surface, wl->input->seat, serial); - } static void pointer_handle_axis(void *data, @@ -454,9 +373,9 @@ static void pointer_handle_axis(void *data, if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) { if (value > 0) - mplayer_put_key(wl->vo->key_fifo, MP_MOUSE_BTN4); + mp_input_put_key(wl->vo->input_ctx, MP_MOUSE_BTN4); if (value < 0) - mplayer_put_key(wl->vo->key_fifo, MP_MOUSE_BTN3); + mp_input_put_key(wl->vo->input_ctx, MP_MOUSE_BTN3); } } @@ -550,7 +469,7 @@ static void registry_handle_global (void *data, &wl_output_interface, 1); - wl_output_add_listener(output->output, &output_listener, d); + wl_output_add_listener(output->output, &output_listener, output); wl_list_insert(&d->output_list, &output->link); } @@ -579,40 +498,6 @@ static const struct wl_registry_listener registry_listener = { /*** internal functions ***/ -static int set_cloexec_or_close(int fd) -{ - long flags; - - if (fd == -1) - return -1; - - if ((flags = fcntl(fd, F_GETFD)) == -1) - goto err; - - if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) - goto err; - - return fd; - -err: - close(fd); - return -1; -} - -static int os_epoll_create_cloexec(void) -{ - int fd; - -#ifdef EPOLL_CLOEXEC - if ((fd = epoll_create1(EPOLL_CLOEXEC)) >= 0) - return fd; - if (errno != EINVAL) - return -1; -#endif - - return set_cloexec_or_close(epoll_create(1)); -} - static int lookupkey(int key) { static const char *passthrough_keys @@ -634,7 +519,7 @@ static int lookupkey(int key) static void hide_cursor (struct vo_wayland_state *wl) { struct vo_wayland_display *display = wl->display; - if (!display->cursor.pointer || wl->vo->opts->cursor_autohide_delay == -1) + if (!display->cursor.pointer) return; wl_pointer_set_cursor(display->cursor.pointer, display->cursor.serial, @@ -644,7 +529,7 @@ static void hide_cursor (struct vo_wayland_state *wl) static void show_cursor (struct vo_wayland_state *wl) { struct vo_wayland_display *display = wl->display; - if (!display->cursor.pointer || wl->vo->opts->cursor_autohide_delay == -2) + if (!display->cursor.pointer) return; struct wl_buffer *buffer; @@ -660,75 +545,20 @@ static void show_cursor (struct vo_wayland_state *wl) wl_surface_commit(display->cursor.surface); } -static void -display_watch_fd(struct vo_wayland_display *display, - int fd, uint32_t events, struct vo_wayland_task *task) -{ - struct epoll_event ep; - - if (display->epoll_fd < 0) { - mp_msg(MSGT_VO, MSGL_WARN, "[wayland] Could not watch fd\n"); - return; - } - - ep.events = events; - ep.data.ptr = task; - epoll_ctl(display->epoll_fd, EPOLL_CTL_ADD, fd, &ep); -} - -static void display_handle_data(struct vo_wayland_task *task, - uint32_t events, - struct vo_wayland_state *wl) +static void resize_window(struct vo_wayland_state *wl, + uint32_t edges, + int32_t width, + int32_t height) { - struct vo_wayland_display *display = wl->display; - struct epoll_event ep; - int ret; - - if (events & EPOLLERR || events & EPOLLHUP) - exit(-1); - - if (events & EPOLLIN) { - ret = wl_display_dispatch(display->display); - if (ret == -1) - exit(-1); + struct vo_wayland_window *w = wl->window; + if (w->resize_func && w->resize_func_data) { + w->resize_func(wl, edges, width, height, w->resize_func_data); + w->events |= VO_EVENT_RESIZE; } - - if (events & EPOLLOUT) { - ret = wl_display_flush(display->display); - if (ret == 0) { - ep.events = EPOLLIN | EPOLLERR | EPOLLHUP; - ep.data.ptr = &display->display_task; - epoll_ctl(display->epoll_fd, EPOLL_CTL_MOD, - display->display_fd, &ep); - } else if (ret == -1 && errno != EAGAIN) - exit(-1); - } -} - -static void cursor_timer_func(struct vo_wayland_task *task, - uint32_t events, - struct vo_wayland_state *wl) -{ - if (wl->window->type == TYPE_FULLSCREEN) - hide_cursor(wl); + else + mp_msg(MSGT_VO, MSGL_WARN, "[wayland] No resizing possible!\n"); } -static void keyboard_timer_func(struct vo_wayland_task *task, - uint32_t events, - struct vo_wayland_state *wl) -{ - struct vo_wayland_input *input = wl->input; - uint64_t exp; - - if (read(input->repeat.timer_fd, &exp, sizeof exp) != sizeof exp) - /* If we change the timer between the fd becoming - * readable and getting here, there'll be nothing to - * read and we get EAGAIN. */ - return; - - keyboard_handle_key(wl, input->keyboard, 0, input->repeat.time, - input->repeat.key, WL_KEYBOARD_KEY_STATE_PRESSED); -} static bool create_display (struct vo_wayland_state *wl) { @@ -754,11 +584,7 @@ static bool create_display (struct vo_wayland_state *wl) d->cursor.surface = wl_compositor_create_surface(d->compositor); - d->epoll_fd = os_epoll_create_cloexec(); d->display_fd = wl_display_get_fd(d->display); - d->display_task.run = display_handle_data; - display_watch_fd(d, d->display_fd, EPOLLIN | EPOLLERR | EPOLLHUP, - &d->display_task); return true; } @@ -804,9 +630,6 @@ static void create_window (struct vo_wayland_state *wl) static void destroy_window (struct vo_wayland_state *wl) { - if (wl->window->callback) - wl_callback_destroy(wl->window->callback); - wl_shell_surface_destroy(wl->window->shell_surface); wl_surface_destroy(wl->window->surface); } @@ -839,29 +662,6 @@ static void destroy_input (struct vo_wayland_state *wl) xkb_context_unref(wl->input->xkb.context); } -static void create_timers (struct vo_wayland_state *wl) -{ - struct vo_wayland_display *d = wl->display; - struct vo_wayland_input *i = wl->input; - - d->cursor.task.run = cursor_timer_func; - d->cursor.timer_fd = timerfd_create(CLOCK_MONOTONIC, - TFD_CLOEXEC | TFD_NONBLOCK); - display_watch_fd(d, d->cursor.timer_fd, EPOLLIN, &d->cursor.task); - - i->repeat.task.run = keyboard_timer_func; - i->repeat.timer_fd = timerfd_create(CLOCK_MONOTONIC, - TFD_CLOEXEC | TFD_NONBLOCK); - display_watch_fd(d, i->repeat.timer_fd, EPOLLIN, &i->repeat.task); -} - -static void destroy_timers (struct vo_wayland_state *wl) -{ - close(wl->input->repeat.timer_fd); - close(wl->display->cursor.timer_fd); -} - - /*** mplayer2 interface ***/ int vo_wayland_init (struct vo *vo) @@ -877,18 +677,15 @@ int vo_wayland_init (struct vo *vo) return false; } - create_timers(wl); - vo->event_fd = wl->display->epoll_fd; + vo->event_fd = wl->display->display_fd; create_window(wl); - vo_wayland_update_window_title(vo); - return 1; + return true; } void vo_wayland_uninit (struct vo *vo) { struct vo_wayland_state *wl = vo->wayland; - destroy_timers(wl); destroy_input(wl); destroy_window(wl); destroy_display(wl); @@ -896,7 +693,7 @@ void vo_wayland_uninit (struct vo *vo) vo->wayland = NULL; } -void vo_wayland_ontop (struct vo *vo) +static void vo_wayland_ontop (struct vo *vo) { struct vo_wayland_state *wl = vo->wayland; @@ -910,7 +707,7 @@ void vo_wayland_ontop (struct vo *vo) wl_shell_surface_set_toplevel(wl->window->shell_surface); } -void vo_wayland_border (struct vo *vo) +static void vo_wayland_border (struct vo *vo) { /* wayland clienst have to do the decorations themself * (client side decorations) but there is no such code implement nor @@ -921,7 +718,7 @@ void vo_wayland_border (struct vo *vo) */ } -void vo_wayland_fullscreen (struct vo *vo) +static void vo_wayland_fullscreen (struct vo *vo) { struct vo_wayland_state *wl = vo->wayland; if (!wl->window || !wl->display->shell) @@ -938,65 +735,58 @@ void vo_wayland_fullscreen (struct vo *vo) wl->window->type = TYPE_FULLSCREEN; vo->opts->fs = true; - - hide_cursor(wl); } else { wl_shell_surface_set_toplevel(wl->window->shell_surface); - ssurface_schedule_resize(wl->window, wl->window->p_width, - wl->window->p_height); + resize_window(wl, 0, wl->window->p_width, wl->window->p_height); wl->window->type = TYPE_TOPLEVEL; vo->opts->fs = false; - - show_cursor(wl); } } -int vo_wayland_check_events (struct vo *vo) +static int vo_wayland_check_events (struct vo *vo) { - struct vo_wayland_task *task; struct vo_wayland_state *wl = vo->wayland; - int i, ret, count; - struct epoll_event ep[16]; - - wl_display_dispatch_pending(wl->display->display); - - ret = wl_display_flush(wl->display->display); - - if (ret < 0 && errno == EAGAIN) { - ep[0].events = EPOLLIN | EPOLLOUT | EPOLLERR | EPOLLHUP; - ep[0].data.ptr = NULL; + struct wl_display *dp = wl->display->display; + int ret; - epoll_ctl(wl->display->epoll_fd, EPOLL_CTL_MOD, - wl->display->display_fd, &ep[0]); - } - else if (ret < 0) { - return 0; - } + wl_display_dispatch_pending(dp); + wl_display_flush(dp); - count = epoll_wait(wl->display->epoll_fd, ep, ARRAY_LENGTH(ep), 1); + struct pollfd fd = { + wl->display->display_fd, + POLLIN | POLLOUT | POLLERR | POLLHUP, + 0 + }; - for (i = 0; i < count; i++) { - task = ep[i].data.ptr; - task->run(task, ep[i].events, wl); + /* 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 */ + if (poll(&fd, 1, 0) > 0) { + if (fd.revents & POLLERR || fd.revents & POLLHUP) + mp_msg(MSGT_VO, MSGL_ERR, "[wayland] error occurred on fd\n"); + if (fd.revents & POLLIN) + wl_display_dispatch(dp); + if (fd.revents & POLLOUT) + wl_display_flush(dp); } ret = wl->window->events; - wl->window->events = 0; return ret; } -void vo_wayland_update_screeninfo (struct vo *vo) +static void vo_wayland_update_screeninfo (struct vo *vo) { struct vo_wayland_state *wl = vo->wayland; struct mp_vo_opts *opts = vo->opts; + bool mode_received = false; wl_display_roundtrip(wl->display->display); - if (!wl->display->output_mode_received) - mp_msg(MSGT_VO, MSGL_ERR, "[wayland] no output mode detected\n"); vo->xinerama_x = vo->xinerama_y = 0; @@ -1007,6 +797,11 @@ void vo_wayland_update_screeninfo (struct vo *vo) struct vo_wayland_output *fsscreen_output = NULL; wl_list_for_each_reverse(output, &wl->display->output_list, link) { + if (!output || !output->width) + continue; + + mode_received = true; + if (opts->fsscreen_id == screen_id) fsscreen_output = output; @@ -1016,6 +811,11 @@ void vo_wayland_update_screeninfo (struct vo *vo) screen_id++; } + if (!mode_received) { + mp_msg(MSGT_VO, MSGL_ERR, "[wayland] no output mode detected\n"); + return; + } + if (fsscreen_output) { wl->display->fs_output = fsscreen_output->output; opts->screenwidth = fsscreen_output->width; @@ -1033,9 +833,57 @@ void vo_wayland_update_screeninfo (struct vo *vo) aspect_save_screenres(vo, opts->screenwidth, opts->screenheight); } -void vo_wayland_update_window_title(struct vo *vo) +int vo_wayland_control (struct vo *vo, int *events, int request, void *arg) { - struct vo_wayland_window *w = vo->wayland->window; - wl_shell_surface_set_title(w->shell_surface, vo_get_window_title(vo)); + 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); + return VO_TRUE; + case VOCTRL_FULLSCREEN: + vo_wayland_fullscreen(vo); + *events |= VO_EVENT_RESIZE; + return VO_TRUE; + case VOCTRL_ONTOP: + vo_wayland_ontop(vo); + return VO_TRUE; + case VOCTRL_BORDER: + vo_wayland_border(vo); + *events |= VO_EVENT_RESIZE; + return VO_TRUE; + case VOCTRL_UPDATE_SCREENINFO: + vo_wayland_update_screeninfo(vo); + return VO_TRUE; + case VOCTRL_SET_CURSOR_VISIBILITY: + if (*(bool *)arg) { + if (!wl->display->cursor.visible) + show_cursor(wl); + } + else { + if (wl->display->cursor.visible) + hide_cursor(wl); + } + wl->display->cursor.visible = *(bool *)arg; + return VO_TRUE; + case VOCTRL_UPDATE_WINDOW_TITLE: + wl_shell_surface_set_title(wl->window->shell_surface, (char *) arg); + return VO_TRUE; + } + return VO_NOTIMPL; } +bool vo_wayland_config (struct vo *vo, uint32_t d_width, + uint32_t d_height, uint32_t flags) +{ + struct vo_wayland_window *w = vo->wayland->window; + + w->width = d_width; + w->height = d_height; + + if ((VOFLAG_FULLSCREEN & flags) && w->type != TYPE_FULLSCREEN) + vo_wayland_fullscreen(vo); + + return true; +} |