summaryrefslogtreecommitdiffstats
path: root/video/out/wayland_common.c
diff options
context:
space:
mode:
authorAlexander Preisinger <alexander.preisinger@gmail.com>2014-01-04 13:48:50 +0100
committerAlexander Preisinger <alexander.preisinger@gmail.com>2014-01-04 13:48:50 +0100
commit8f241998c03938b3c159f54c9a87c928808f19f9 (patch)
treeb4ebf4fe1f8bfc652e0d5db98366c9a5bfdc99cf /video/out/wayland_common.c
parent7041d8cd3735c3832cc2ce7ed62467c25c37f511 (diff)
downloadmpv-8f241998c03938b3c159f54c9a87c928808f19f9.tar.bz2
mpv-8f241998c03938b3c159f54c9a87c928808f19f9.tar.xz
wayland: implement dropping files on the VO window
Needs some proper testing.
Diffstat (limited to 'video/out/wayland_common.c')
-rw-r--r--video/out/wayland_common.c187
1 files changed, 185 insertions, 2 deletions
diff --git a/video/out/wayland_common.c b/video/out/wayland_common.c
index 1a4414da3d..ae2b480b4a 100644
--- a/video/out/wayland_common.c
+++ b/video/out/wayland_common.c
@@ -465,6 +465,99 @@ static const struct wl_seat_listener seat_listener = {
seat_handle_capabilities,
};
+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_ERR(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 *registry,
uint32_t id,
@@ -502,11 +595,22 @@ 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, 1);
-
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);
}
}
@@ -629,6 +733,29 @@ static void shedule_resize(struct vo_wayland_state *wl,
wl->vo->dheight = height;
}
+// stolen from x11 code
+// The data is in the form of the mimetype text/uri-list.
+static bool dnd_handle_drop_data(struct vo *vo, bstr data)
+{
+ void *tmp = talloc_new(NULL);
+ int num_files = 0;
+ char **files = NULL;
+
+ while (data.len) {
+ bstr line = bstr_getline(data, &data);
+ line = bstr_strip_linebreaks(line);
+ if (bstr_startswith0(line, "#"))
+ continue;
+
+ char *s = bstrto0(tmp, line);
+ MP_TARRAY_APPEND(tmp, files, num_files, s);
+
+ }
+ vo_drop_files(vo, num_files, files);
+
+ talloc_free(tmp);
+ return num_files > 0;
+}
static bool create_display (struct vo_wayland_state *wl)
{
@@ -731,6 +858,8 @@ static bool create_input (struct vo_wayland_state *wl)
return false;
}
+ wl->input.dnd_fd = -1;
+
return true;
}
@@ -746,9 +875,14 @@ 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 ***/
@@ -863,6 +997,55 @@ static int vo_wayland_check_events (struct vo *vo)
wl_display_flush(dp);
}
+ /* 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) {
+ fd.fd = wl->input.dnd_fd;
+ fd.events = POLLIN | POLLHUP | POLLERR;
+
+ if (poll(&fd, 1, 0) > 0) {
+ if (fd.revents & POLLERR) {
+ MP_ERR(wl, "error occured 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;
+
+ while (0 < (has_read = read(fd.fd, buffer, to_read))) {
+ if (buffer_len + to_read < buffer_len) {
+ MP_ERR(wl, "Integer overflow while reading from fd\n");
+ free(buffer);
+ break;
+ }
+
+ str_len += has_read;
+ buffer_len += to_read;
+ buffer = realloc(buffer, buffer_len);
+
+ if (has_read < to_read) {
+ buffer[str_len] = 0;
+ struct bstr file_list = bstr0(buffer);
+ dnd_handle_drop_data(wl->vo, file_list);
+ break;
+ }
+ }
+ }
+
+ 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;
}