From 09aa82db498149dbd7d12b256ea8fec73b08eb99 Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Mon, 19 Nov 2018 17:34:18 +0100 Subject: [PATCH] wayland: Add wayland MetaSelectionSource implementation This object represents a Wayland selection owner. In order to invert the FD direction (we hand an output fd, but want an inpu fd), create an intermediate pipe so we can then create a GInputStream on top of it. https://gitlab.gnome.org/GNOME/mutter/merge_requests/320 --- src/meson.build | 2 + .../meta-selection-source-wayland-private.h | 46 +++++ src/wayland/meta-selection-source-wayland.c | 162 ++++++++++++++++++ 3 files changed, 210 insertions(+) create mode 100644 src/wayland/meta-selection-source-wayland-private.h create mode 100644 src/wayland/meta-selection-source-wayland.c diff --git a/src/meson.build b/src/meson.build index c9c872cc3..b5e8835ab 100644 --- a/src/meson.build +++ b/src/meson.build @@ -454,6 +454,8 @@ if have_wayland 'wayland/meta-pointer-confinement-wayland.h', 'wayland/meta-pointer-lock-wayland.c', 'wayland/meta-pointer-lock-wayland.h', + 'wayland/meta-selection-source-wayland.c', + 'wayland/meta-selection-source-wayland-private.h', 'wayland/meta-wayland-actor-surface.c', 'wayland/meta-wayland-actor-surface.h', 'wayland/meta-wayland-buffer.c', diff --git a/src/wayland/meta-selection-source-wayland-private.h b/src/wayland/meta-selection-source-wayland-private.h new file mode 100644 index 000000000..5976271cf --- /dev/null +++ b/src/wayland/meta-selection-source-wayland-private.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2018 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Author: Carlos Garnacho + */ + +#ifndef META_SELECTION_SOURCE_WAYLAND_H +#define META_SELECTION_SOURCE_WAYLAND_H + +#include + +#include "core/meta-selection-source.h" + +#define META_TYPE_SELECTION_SOURCE_WAYLAND (meta_selection_source_wayland_get_type ()) + +G_DECLARE_FINAL_TYPE (MetaSelectionSourceWayland, + meta_selection_source_wayland, + META, SELECTION_SOURCE_WAYLAND, + MetaSelectionSource) + +typedef void (* MetaWaylandSendFunc) (struct wl_resource *resource, + const char *mimetype, + int fd); +typedef void (* MetaWaylandCancelFunc) (struct wl_resource *resource); + +MetaSelectionSource * meta_selection_source_wayland_new (struct wl_resource *resource, + GList *mime_types, + MetaWaylandSendFunc send_func, + MetaWaylandCancelFunc cancel_func); + +#endif /* META_SELECTION_SOURCE_WAYLAND_H */ diff --git a/src/wayland/meta-selection-source-wayland.c b/src/wayland/meta-selection-source-wayland.c new file mode 100644 index 000000000..7031c911e --- /dev/null +++ b/src/wayland/meta-selection-source-wayland.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2018 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Author: Carlos Garnacho + */ + +#include "config.h" + +#include +#include + +#include "wayland/meta-selection-source-wayland-private.h" + +struct _MetaSelectionSourceWayland +{ + MetaSelectionSource parent_instance; + GList *mimetypes; + MetaWaylandSendFunc send_func; + MetaWaylandCancelFunc cancel_func; + struct wl_resource *resource; +}; + +G_DEFINE_TYPE (MetaSelectionSourceWayland, meta_selection_source_wayland, + META_TYPE_SELECTION_SOURCE) + +static void +meta_selection_source_wayland_finalize (GObject *object) +{ + MetaSelectionSourceWayland *source_wayland = META_SELECTION_SOURCE_WAYLAND (object); + + g_list_free_full (source_wayland->mimetypes, g_free); + + G_OBJECT_CLASS (meta_selection_source_wayland_parent_class)->finalize (object); +} + +static void +meta_selection_source_wayland_read_async (MetaSelectionSource *source, + const gchar *mimetype, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + MetaSelectionSourceWayland *source_wayland = META_SELECTION_SOURCE_WAYLAND (source); + GInputStream *stream; + GTask *task; + int pipe_fds[2]; + + if (!g_unix_open_pipe (pipe_fds, FD_CLOEXEC, NULL)) + { + g_task_report_new_error (source, callback, user_data, + meta_selection_source_wayland_read_async, + G_IO_ERROR, G_IO_ERROR_FAILED, + "Could not open pipe to read wayland selection"); + return; + } + + if (!g_unix_set_fd_nonblocking (pipe_fds[0], TRUE, NULL) || + !g_unix_set_fd_nonblocking (pipe_fds[1], TRUE, NULL)) + { + g_task_report_new_error (source, callback, user_data, + meta_selection_source_wayland_read_async, + G_IO_ERROR, G_IO_ERROR_FAILED, + "Could not make pipe nonblocking"); + close (pipe_fds[0]); + close (pipe_fds[1]); + return; + } + + task = g_task_new (source, cancellable, callback, user_data); + g_task_set_source_tag (task, meta_selection_source_wayland_read_async); + + stream = g_unix_input_stream_new (pipe_fds[0], TRUE); + source_wayland->send_func (source_wayland->resource, mimetype, pipe_fds[1]); + close (pipe_fds[1]); + + g_task_return_pointer (task, stream, g_object_unref); + g_object_unref (task); +} + +static GInputStream * +meta_selection_source_wayland_read_finish (MetaSelectionSource *source, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (g_task_is_valid (result, source), FALSE); + g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == + meta_selection_source_wayland_read_async, FALSE); + + return g_task_propagate_pointer (G_TASK (result), error); +} + +static GList * +meta_selection_source_wayland_get_mimetypes (MetaSelectionSource *source) +{ + MetaSelectionSourceWayland *source_wayland = META_SELECTION_SOURCE_WAYLAND (source); + + return g_list_copy_deep (source_wayland->mimetypes, + (GCopyFunc) g_strdup, NULL); +} + +static void +meta_selection_source_wayland_deactivated (MetaSelectionSource *source) +{ + MetaSelectionSourceWayland *source_wayland = + META_SELECTION_SOURCE_WAYLAND (source); + + source_wayland->cancel_func (source_wayland->resource); + META_SELECTION_SOURCE_CLASS (meta_selection_source_wayland_parent_class)->deactivated (source); +} + +static void +meta_selection_source_wayland_class_init (MetaSelectionSourceWaylandClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + MetaSelectionSourceClass *source_class = META_SELECTION_SOURCE_CLASS (klass); + + object_class->finalize = meta_selection_source_wayland_finalize; + + source_class->deactivated = meta_selection_source_wayland_deactivated; + + source_class->read_async = meta_selection_source_wayland_read_async; + source_class->read_finish = meta_selection_source_wayland_read_finish; + source_class->get_mimetypes = meta_selection_source_wayland_get_mimetypes; +} + +static void +meta_selection_source_wayland_init (MetaSelectionSourceWayland *source) +{ +} + +MetaSelectionSource * +meta_selection_source_wayland_new (struct wl_resource *resource, + GList *mime_types, + MetaWaylandSendFunc send_func, + MetaWaylandCancelFunc cancel_func) +{ + MetaSelectionSourceWayland *source_wayland; + + source_wayland = g_object_new (META_TYPE_SELECTION_SOURCE_WAYLAND, NULL); + source_wayland->mimetypes = g_list_copy_deep (mime_types, + (GCopyFunc) g_strdup, NULL); + source_wayland->send_func = send_func; + source_wayland->cancel_func = cancel_func; + source_wayland->resource = resource; + + return META_SELECTION_SOURCE (source_wayland); +}